From 47b3c5500eaca1abc591a1b48ca16aeed782736f Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Fri, 1 Jul 2022 20:19:15 +0000 Subject: [PATCH 001/150] Bug fixes, upgrades, code cleanup, and documentation updates Fixed bugs in asset chaincode and associated Fabric CLI. Updated protobuf languages bindings' version numbers. Updated instructions in testnet setup documentation. Added container names explicitly to Corda testnet docker compose files as required by the latest docker-compose version. Replaced 'go get with go install' in setup scripts as required by latest Go versions. Removed '.npmrc' credential files in container images (dockerfiles) for safety. Signed-off-by: VRamakrishna --- common/protos-java-kt/gradle.properties | 2 +- common/protos-js/package.json | 2 +- .../fabric-driver/fabricDriver.dockerfile | 1 + .../test-network/setup-local-docker.md | 4 +- .../test-network/setup-local.md | 4 +- .../test-network/setup-packages-docker.md | 4 +- .../test-network/setup-packages.md | 4 +- samples/fabric/fabric-cli/Dockerfile | 2 +- .../fabric-cli/scripts/getAssetStatus.sh | 16 +++-- .../src/commands/chaincode/query.ts | 7 +- .../fabric/fabric-cli/src/data/assets.json | 64 +++++++++++++++++++ .../fabric/simpleassettransfer/bondasset.go | 2 +- .../dev/Corda_Network/docker-compose.yml | 4 ++ .../dev/Corda_Network2/docker-compose.yml | 4 ++ tests/network-setups/fabric/dev/Makefile | 1 + .../fabric/dev/scripts/setupCC.sh | 2 +- 16 files changed, 102 insertions(+), 21 deletions(-) diff --git a/common/protos-java-kt/gradle.properties b/common/protos-java-kt/gradle.properties index f220c3bbc..bc60761f9 100644 --- a/common/protos-java-kt/gradle.properties +++ b/common/protos-java-kt/gradle.properties @@ -1,4 +1,4 @@ name=Interop Protos group=com.weaver -version=1.3.1 +version=1.3.2 kotlin.incremental=false diff --git a/common/protos-js/package.json b/common/protos-js/package.json index e6bf8939b..971e65e23 100644 --- a/common/protos-js/package.json +++ b/common/protos-js/package.json @@ -1,6 +1,6 @@ { "name": "@hyperledger-labs/weaver-protos-js", - "version": "1.3.1", + "version": "1.3.2", "description": "Interop protos for Node JS (Weaver)", "main": "index.js", "exports": { diff --git a/core/drivers/fabric-driver/fabricDriver.dockerfile b/core/drivers/fabric-driver/fabricDriver.dockerfile index bbd20114b..759589cd2 100644 --- a/core/drivers/fabric-driver/fabricDriver.dockerfile +++ b/core/drivers/fabric-driver/fabricDriver.dockerfile @@ -31,6 +31,7 @@ ADD .prettierrc . RUN npm run build RUN npm run postinstall +RUN rm /fabric-driver/.npmrc ARG GIT_URL LABEL org.opencontainers.image.source ${GIT_URL} diff --git a/docs/docs/external/getting-started/test-network/setup-local-docker.md b/docs/docs/external/getting-started/test-network/setup-local-docker.md index 377ca5e7f..3e5a72695 100644 --- a/docs/docs/external/getting-started/test-network/setup-local-docker.md +++ b/docs/docs/external/getting-started/test-network/setup-local-docker.md @@ -26,8 +26,8 @@ Before starting, make sure you have the following software installed on your hos - Curl: _install using package manager, like `apt` on Debian/Ubuntu Linux_ - Git: [sample instructions](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) - Docker: [sample instructions](https://docs.docker.com/engine/install/) (Latest version) -- Docker-Compose: [sample instructions](https://docs.docker.com/compose/install/) (Version 1.28.2 or above) -- Golang: [sample instructions](https://golang.org/dl/) (Version 1.17 or below) +- Docker-Compose: [sample instructions](https://docs.docker.com/compose/install/) (Version 1.28.2 or higher) +- Golang: [sample instructions](https://golang.org/dl/) (Version 1.16 or higher) - Java (JDK and JRE): [sample instructions](https://openjdk.java.net/install/) (Version 8) - Node.js and NPM: [sample instructions](https://nodejs.org/en/download/package-manager/) (Version 11 to Version 14 Supported) - Yarn: [sample instructions](https://classic.yarnpkg.com/en/docs/install/) diff --git a/docs/docs/external/getting-started/test-network/setup-local.md b/docs/docs/external/getting-started/test-network/setup-local.md index cd2f7518f..1e4ba9c3e 100644 --- a/docs/docs/external/getting-started/test-network/setup-local.md +++ b/docs/docs/external/getting-started/test-network/setup-local.md @@ -26,8 +26,8 @@ Before starting, make sure you have the following software installed on your hos - Curl: _install using package manager, like `apt` on Debian/Ubuntu Linux_ - Git: [sample instructions](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) - Docker: [sample instructions](https://docs.docker.com/engine/install/) (Latest version) -- Docker-Compose: [sample instructions](https://docs.docker.com/compose/install/) (Version 1.28.2 or above) -- Golang: [sample instructions](https://golang.org/dl/) (Version 1.17 or below) +- Docker-Compose: [sample instructions](https://docs.docker.com/compose/install/) (Version 1.28.2 or higher) +- Golang: [sample instructions](https://golang.org/dl/) (Version 1.16 or higher) - Java (JDK and JRE): [sample instructions](https://openjdk.java.net/install/) (Version 8) - Node.js and NPM: [sample instructions](https://nodejs.org/en/download/package-manager/) (Version 11 to Version 14 Supported) - Yarn: [sample instructions](https://classic.yarnpkg.com/en/docs/install/) diff --git a/docs/docs/external/getting-started/test-network/setup-packages-docker.md b/docs/docs/external/getting-started/test-network/setup-packages-docker.md index 38a0b2f34..7bfb4dc0c 100644 --- a/docs/docs/external/getting-started/test-network/setup-packages-docker.md +++ b/docs/docs/external/getting-started/test-network/setup-packages-docker.md @@ -26,8 +26,8 @@ Before starting, make sure you have the following software installed on your hos - Curl: _install using package manager, like `apt` on Debian/Ubuntu Linux_ - Git: [sample instructions](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) - Docker: [sample instructions](https://docs.docker.com/engine/install/) (Latest version) -- Docker-Compose: [sample instructions](https://docs.docker.com/compose/install/) (Version 1.28.2 or above) -- Golang: [sample instructions](https://golang.org/dl/) (Version 1.17 or below) +- Docker-Compose: [sample instructions](https://docs.docker.com/compose/install/) (Version 1.28.2 or higher) +- Golang: [sample instructions](https://golang.org/dl/) (Version 1.16 or higher) - Java (JDK and JRE): [sample instructions](https://openjdk.java.net/install/) (Version 8) - Node.js and NPM: [sample instructions](https://nodejs.org/en/download/package-manager/) (Version 11 to Version 14 Supported) - Yarn: [sample instructions](https://classic.yarnpkg.com/en/docs/install/) diff --git a/docs/docs/external/getting-started/test-network/setup-packages.md b/docs/docs/external/getting-started/test-network/setup-packages.md index 1ca02c8e5..46b0e5c4a 100644 --- a/docs/docs/external/getting-started/test-network/setup-packages.md +++ b/docs/docs/external/getting-started/test-network/setup-packages.md @@ -26,8 +26,8 @@ Before starting, make sure you have the following software installed on your hos - Curl: _install using package manager, like `apt` on Debian/Ubuntu Linux_ - Git: [sample instructions](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) - Docker: [sample instructions](https://docs.docker.com/engine/install/) (Latest version) -- Docker-Compose: [sample instructions](https://docs.docker.com/compose/install/) (Version 1.28.2 or above) -- Golang: [sample instructions](https://golang.org/dl/) (Version 1.17 or below) +- Docker-Compose: [sample instructions](https://docs.docker.com/compose/install/) (Version 1.28.2 or higher) +- Golang: [sample instructions](https://golang.org/dl/) (Version 1.16 or higher) - Java (JDK and JRE): [sample instructions](https://openjdk.java.net/install/) (Version 8) - Node.js and NPM: [sample instructions](https://nodejs.org/en/download/package-manager/) (Version 11 to Version 14 supported) - Yarn: [sample instructions](https://classic.yarnpkg.com/en/docs/install/) diff --git a/samples/fabric/fabric-cli/Dockerfile b/samples/fabric/fabric-cli/Dockerfile index 16b246c29..dde3be0f4 100644 --- a/samples/fabric/fabric-cli/Dockerfile +++ b/samples/fabric/fabric-cli/Dockerfile @@ -13,4 +13,4 @@ COPY .npmrc /root # RUN yarn RUN npm install RUN yarn link - +RUN rm /root/.npmrc diff --git a/samples/fabric/fabric-cli/scripts/getAssetStatus.sh b/samples/fabric/fabric-cli/scripts/getAssetStatus.sh index 66f10000c..4ef5adc42 100755 --- a/samples/fabric/fabric-cli/scripts/getAssetStatus.sh +++ b/samples/fabric/fabric-cli/scripts/getAssetStatus.sh @@ -1,9 +1,11 @@ -echo -e "\n\n############## Fabric network1 ################\n" -./bin/fabric-cli chaincode invoke --local-network=network1 --user=alice mychannel simpleasset GetMyAssets '[]' -./bin/fabric-cli chaincode invoke --local-network=network1 --user=bob mychannel simpleasset GetMyAssets '[]' +CC=$(cat config.json | jq -r .network1.chaincode) +echo -e "\n\n############## Fabric network1: $CC ################\n" +./bin/fabric-cli chaincode query --local-network=network1 --user=alice mychannel $CC GetMyAssets '[]' +./bin/fabric-cli chaincode query --local-network=network1 --user=bob mychannel $CC GetMyAssets '[]' if [ "$1" = "2" ]; then - echo -e "\n\n############## Fabric network2 ################\n" - ./bin/fabric-cli chaincode invoke --local-network=network2 --user=alice mychannel simpleasset GetMyWallet '[]' - ./bin/fabric-cli chaincode invoke --local-network=network2 --user=bob mychannel simpleasset GetMyWallet '[]' -fi \ No newline at end of file + CC=$(cat config.json | jq -r .network2.chaincode) + echo -e "\n\n############## Fabric network2: $CC ################\n" + ./bin/fabric-cli chaincode query --local-network=network2 --user=alice mychannel $CC GetMyWallet '[]' + ./bin/fabric-cli chaincode query --local-network=network2 --user=bob mychannel $CC GetMyWallet '[]' +fi diff --git a/samples/fabric/fabric-cli/src/commands/chaincode/query.ts b/samples/fabric/fabric-cli/src/commands/chaincode/query.ts index 356c95b69..d3dbee3c2 100644 --- a/samples/fabric/fabric-cli/src/commands/chaincode/query.ts +++ b/samples/fabric/fabric-cli/src/commands/chaincode/query.ts @@ -83,7 +83,12 @@ const command: GluegunCommand = { userid, true ) - logger.info(`Result from network query: ${result}`) + try { // If the result is a JSON + const resultJSON = JSON.stringify(JSON.parse(result), null, 4) + logger.info(`Result from network query: ${resultJSON}`) + } catch(err) { // If the result is not a JSON + logger.info(`Result from network query: ${result}`) + } } catch (err) { logger.error(`Error during fabric query: ${JSON.stringify(err)}`) } diff --git a/samples/fabric/fabric-cli/src/data/assets.json b/samples/fabric/fabric-cli/src/data/assets.json index bf80ddcd2..c00893177 100644 --- a/samples/fabric/fabric-cli/src/data/assets.json +++ b/samples/fabric/fabric-cli/src/data/assets.json @@ -14,5 +14,69 @@ "issuer": "treasury", "facevalue": "700", "maturitydate": "01 Jul 45 00:00 MST" + }, + "a05": { + "assetType": "bond01", + "id": "a05", + "owner": "alice", + "issuer": "treasury", + "facevalue": "300", + "maturitydate": "05 May 47 00:00 MST" + }, + "a06": { + "assetType": "bond01", + "id": "a06", + "owner": "bob", + "issuer": "treasury", + "facevalue": "300", + "maturitydate": "05 Mar 47 00:00 MST" + }, + "a07": { + "assetType": "bond02", + "id": "a07", + "owner": "alice", + "issuer": "treasury", + "facevalue": "900", + "maturitydate": "24 Nov 42 00:00 MST" + }, + "a08": { + "assetType": "bond02", + "id": "a08", + "owner": "bob", + "issuer": "treasury", + "facevalue": "100", + "maturitydate": "24 Dec 42 00:00 MST" + }, + "a09": { + "assetType": "bond02", + "id": "a09", + "owner": "alice", + "issuer": "treasury", + "facevalue": "500", + "maturitydate": "06 Apr 44 00:00 MST" + }, + "a10": { + "assetType": "bond02", + "id": "a10", + "owner": "bob", + "issuer": "treasury", + "facevalue": "800", + "maturitydate": "06 Aug 44 00:00 MST" + }, + "a11": { + "assetType": "bond03", + "id": "a11", + "owner": "alice", + "issuer": "treasury", + "facevalue": "200", + "maturitydate": "15 Jul 50 00:00 MST" + }, + "a12": { + "assetType": "bond03", + "id": "a12", + "owner": "bob", + "issuer": "treasury", + "facevalue": "700", + "maturitydate": "15 Jun 50 00:00 MST" } } diff --git a/samples/fabric/simpleassettransfer/bondasset.go b/samples/fabric/simpleassettransfer/bondasset.go index a76eac384..e85d6cc08 100644 --- a/samples/fabric/simpleassettransfer/bondasset.go +++ b/samples/fabric/simpleassettransfer/bondasset.go @@ -571,7 +571,7 @@ func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface var asset BondAsset err = json.Unmarshal(queryResponse.Value, &asset) if err != nil { - return nil, err + continue } assets = append(assets, &asset) } diff --git a/tests/network-setups/corda/dev/Corda_Network/docker-compose.yml b/tests/network-setups/corda/dev/Corda_Network/docker-compose.yml index 74821bc9c..479e01ed4 100644 --- a/tests/network-setups/corda/dev/Corda_Network/docker-compose.yml +++ b/tests/network-setups/corda/dev/Corda_Network/docker-compose.yml @@ -23,6 +23,7 @@ services: - 10003:10003 - 22022 image: corda/corda-zulu-java1.8-4.8.4 + container_name: corda_notary_1 partya: profiles: ["1-node", "2-nodes", "3-nodes"] volumes: @@ -41,6 +42,7 @@ services: - 10006:10003 - 22022 image: corda/corda-zulu-java1.8-4.8.4 + container_name: corda_partya_1 partyb: profiles: ["2-nodes", "3-nodes"] volumes: @@ -59,6 +61,7 @@ services: - 10009:10003 - 22022 image: corda/corda-zulu-java1.8-4.8.4 + container_name: corda_partyb_1 partyc: profiles: ["3-nodes"] volumes: @@ -77,3 +80,4 @@ services: - 10012:10003 - 22022 image: corda/corda-zulu-java1.8-4.8.4 + container_name: corda_partyc_1 diff --git a/tests/network-setups/corda/dev/Corda_Network2/docker-compose.yml b/tests/network-setups/corda/dev/Corda_Network2/docker-compose.yml index e9166ffef..b106643db 100644 --- a/tests/network-setups/corda/dev/Corda_Network2/docker-compose.yml +++ b/tests/network-setups/corda/dev/Corda_Network2/docker-compose.yml @@ -23,6 +23,7 @@ services: - 30003:10003 - 22022 image: corda/corda-zulu-java1.8-4.8.4 + container_name: corda_network2_notary_1 partya: profiles: ["1-node", "2-nodes", "3-nodes"] volumes: @@ -41,6 +42,7 @@ services: - 30006:10003 - 22022 image: corda/corda-zulu-java1.8-4.8.4 + container_name: corda_network2_partya_1 partyb: profiles: ["2-nodes", "3-nodes"] volumes: @@ -59,6 +61,7 @@ services: - 30009:10003 - 22022 image: corda/corda-zulu-java1.8-4.8.4 + container_name: corda_network2_partyb_1 partyc: profiles: ["3-nodes"] volumes: @@ -77,3 +80,4 @@ services: - 30012:10003 - 22022 image: corda/corda-zulu-java1.8-4.8.4 + container_name: corda_network2_partyc_1 diff --git a/tests/network-setups/fabric/dev/Makefile b/tests/network-setups/fabric/dev/Makefile index 41c84272f..279b9ce3d 100644 --- a/tests/network-setups/fabric/dev/Makefile +++ b/tests/network-setups/fabric/dev/Makefile @@ -118,6 +118,7 @@ remove-network2: .PHONY: clean clean: stop + +docker system prune -f || true +rm -rf bin || true +rm -rf config || true +rm .fabric-setup || true diff --git a/tests/network-setups/fabric/dev/scripts/setupCC.sh b/tests/network-setups/fabric/dev/scripts/setupCC.sh index e71f78c12..a2ad92423 100755 --- a/tests/network-setups/fabric/dev/scripts/setupCC.sh +++ b/tests/network-setups/fabric/dev/scripts/setupCC.sh @@ -13,7 +13,7 @@ OLD_GOPATH=$GOPATH export GOPATH=$TMP_PATH # Download interopcc and copy it into correct folder -go get -d "${INTEROPCC_MOD}" +go install "${INTEROPCC_MOD}@latest" cp -r $TMP_PATH/pkg/mod/github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/contracts/interop* $CHAINCODE_PATH/interop chmod -R +w $CHAINCODE_PATH/interop From 17e6ed605836fc871aebe236a2fa70070d5352ee Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Mon, 4 Jul 2022 19:12:40 +0000 Subject: [PATCH 002/150] Updating Protos version to 1.3.2 in the Corda modules Signed-off-by: VRamakrishna --- core/drivers/corda-driver/build.gradle | 2 +- core/network/corda-interop-app/constants.properties | 2 +- samples/corda/corda-simple-application/constants.properties | 2 +- tests/network-setups/corda/scripts/get-cordapps.sh | 2 +- tests/network-setups/corda/scripts/start-nodes.sh | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/drivers/corda-driver/build.gradle b/core/drivers/corda-driver/build.gradle index 27e12d535..6a9199545 100644 --- a/core/drivers/corda-driver/build.gradle +++ b/core/drivers/corda-driver/build.gradle @@ -10,7 +10,7 @@ buildscript { ext.corda_version = "4.8.4" ext.corda_core_version = "4.8.4" ext.arrow_version = "0.10.4" - ext.weaver_protos_version = "1.3.1" + ext.weaver_protos_version = "1.3.2" ext.weaver_corda_version = "1.2.9" repositories { diff --git a/core/network/corda-interop-app/constants.properties b/core/network/corda-interop-app/constants.properties index 5f777f595..32ec4b21c 100644 --- a/core/network/corda-interop-app/constants.properties +++ b/core/network/corda-interop-app/constants.properties @@ -11,4 +11,4 @@ slf4jVersion=1.7.25 nettyVersion=4.1.22.Final arrowVersion=0.10.4 -weaverVersion=1.3.1 +weaverVersion=1.3.2 diff --git a/samples/corda/corda-simple-application/constants.properties b/samples/corda/corda-simple-application/constants.properties index 026fb3954..e2e45a282 100644 --- a/samples/corda/corda-simple-application/constants.properties +++ b/samples/corda/corda-simple-application/constants.properties @@ -9,5 +9,5 @@ log4jVersion =2.16.0 platformVersion=10 slf4jVersion=1.7.25 nettyVersion=4.1.22.Final -weaverProtosVersion=1.3.1 +weaverProtosVersion=1.3.2 weaverCordaVersion=1.2.9 diff --git a/tests/network-setups/corda/scripts/get-cordapps.sh b/tests/network-setups/corda/scripts/get-cordapps.sh index e257c09fe..2d6e1bac9 100755 --- a/tests/network-setups/corda/scripts/get-cordapps.sh +++ b/tests/network-setups/corda/scripts/get-cordapps.sh @@ -4,7 +4,7 @@ directory=$(dirname $0) app=${1:-simple} local=$2 weaverCordaVersion="1.2.9" -weaverProtosVersion="1.3.1" +weaverProtosVersion="1.3.2" if [ "simple" = "$app" ]; then cordappPath=$directory/../../../../samples/corda/corda-simple-application diff --git a/tests/network-setups/corda/scripts/start-nodes.sh b/tests/network-setups/corda/scripts/start-nodes.sh index b69b172e2..703a7b873 100755 --- a/tests/network-setups/corda/scripts/start-nodes.sh +++ b/tests/network-setups/corda/scripts/start-nodes.sh @@ -10,7 +10,7 @@ houseTokenAppVersion="1.0" tokenVersion="1.2" weaverCordaVersion="1.2.9" -weaverProtosVersion="1.3.1" +weaverProtosVersion="1.3.2" parties="Notary PartyA PartyB PartyC" From d3258dbc1158424c23826c82f7125275e6893bb7 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Mon, 4 Jul 2022 19:21:29 +0000 Subject: [PATCH 003/150] Updated Protos dependency in Corda SDK to version 1.3.2 Signed-off-by: VRamakrishna --- sdks/corda/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdks/corda/build.gradle b/sdks/corda/build.gradle index e0d506854..c7217c98f 100644 --- a/sdks/corda/build.gradle +++ b/sdks/corda/build.gradle @@ -13,7 +13,7 @@ buildscript { ext.corda_gradle_plugins_version = "5.0.12" ext.log4j_version = "2.16.0" ext.slf4j_version = "1.7.25" - ext.weaver_protos_version = "1.3.1" + ext.weaver_protos_version = "1.3.2" ext.weaver_corda_version = "1.2.9" dependencies { From 4000579120d7e2aa623162e3bd17739169675da4 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Tue, 5 Jul 2022 10:45:45 +0530 Subject: [PATCH 004/150] deploy fabric pkgs always: attempt 1 Signed-off-by: sandeep.nishad1 --- .github/workflows/deploy_fabric-pkgs.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/deploy_fabric-pkgs.yml b/.github/workflows/deploy_fabric-pkgs.yml index ac2d7b204..47bf273bd 100644 --- a/.github/workflows/deploy_fabric-pkgs.yml +++ b/.github/workflows/deploy_fabric-pkgs.yml @@ -33,7 +33,7 @@ jobs: - name: Generate .npmrc run: | cp .npmrc.template .npmrc - sed -i "s//${{ secrets.GITHUB_TOKEN }}/g" .npmrc + #sed -i "s//${{ secrets.GITHUB_TOKEN }}/g" .npmrc cat .npmrc working-directory: common/protos-js @@ -48,7 +48,7 @@ jobs: working-directory: common/protos-js publish-sdk: - if: github.repository_owner == 'hyperledger-labs' + if: ${{ always() && (needs.publish-protos.result=='failure' || needs.publish-protos.result=='success') && github.repository_owner == 'hyperledger-labs' }} needs: [publish-protos] runs-on: ubuntu-latest steps: @@ -63,7 +63,7 @@ jobs: - name: Generate .npmrc run: | cp .npmrc.template .npmrc - sed -i "s//${{ secrets.GITHUB_TOKEN }}/g" .npmrc + #sed -i "s//${{ secrets.GITHUB_TOKEN }}/g" .npmrc cat .npmrc working-directory: sdks/fabric/interoperation-node-sdk @@ -76,7 +76,7 @@ jobs: working-directory: sdks/fabric/interoperation-node-sdk publish-driver: - if: github.repository_owner == 'hyperledger-labs' + if: ${{ always() && (needs.publish-protos.result=='failure' || needs.publish-protos.result=='success') && github.repository_owner == 'hyperledger-labs' }} needs: [publish-protos] runs-on: ubuntu-latest steps: @@ -93,7 +93,7 @@ jobs: - name: Generate .npmrc run: | cp .npmrc.template .npmrc - sed -i "s//${{ secrets.GITHUB_TOKEN }}/g" .npmrc + #sed -i "s//${{ secrets.GITHUB_TOKEN }}/g" .npmrc cat .npmrc working-directory: core/drivers/fabric-driver From 81ffd2db71181a929680e7adb7c0627409d7c388 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Tue, 5 Jul 2022 10:47:08 +0530 Subject: [PATCH 005/150] deploy fabric pkgs always: attempt 2 Signed-off-by: sandeep.nishad1 --- .github/workflows/deploy_fabric-pkgs.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy_fabric-pkgs.yml b/.github/workflows/deploy_fabric-pkgs.yml index 47bf273bd..69d2e00bf 100644 --- a/.github/workflows/deploy_fabric-pkgs.yml +++ b/.github/workflows/deploy_fabric-pkgs.yml @@ -14,7 +14,7 @@ on: jobs: publish-protos: - if: github.repository_owner == 'hyperledger-labs' + if: github.repository_owner == 'sanvenDev' runs-on: ubuntu-latest steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it @@ -48,7 +48,7 @@ jobs: working-directory: common/protos-js publish-sdk: - if: ${{ always() && (needs.publish-protos.result=='failure' || needs.publish-protos.result=='success') && github.repository_owner == 'hyperledger-labs' }} + if: ${{ always() && (needs.publish-protos.result=='failure' || needs.publish-protos.result=='success') && github.repository_owner == 'sanvenDev' }} needs: [publish-protos] runs-on: ubuntu-latest steps: @@ -76,7 +76,7 @@ jobs: working-directory: sdks/fabric/interoperation-node-sdk publish-driver: - if: ${{ always() && (needs.publish-protos.result=='failure' || needs.publish-protos.result=='success') && github.repository_owner == 'hyperledger-labs' }} + if: ${{ always() && (needs.publish-protos.result=='failure' || needs.publish-protos.result=='success') && github.repository_owner == 'sanvenDev' }} needs: [publish-protos] runs-on: ubuntu-latest steps: From f9da663b9a6a9d14ff373a5cf1f919c662c1d174 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Tue, 5 Jul 2022 10:49:40 +0530 Subject: [PATCH 006/150] deploy fabric pkgs always: attempt 3 Signed-off-by: sandeep.nishad1 --- .github/workflows/deploy_fabric-pkgs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy_fabric-pkgs.yml b/.github/workflows/deploy_fabric-pkgs.yml index 69d2e00bf..66165815e 100644 --- a/.github/workflows/deploy_fabric-pkgs.yml +++ b/.github/workflows/deploy_fabric-pkgs.yml @@ -48,7 +48,7 @@ jobs: working-directory: common/protos-js publish-sdk: - if: ${{ always() && (needs.publish-protos.result=='failure' || needs.publish-protos.result=='success') && github.repository_owner == 'sanvenDev' }} + if: ${{ always() && github.repository_owner == 'sanvenDev' }} needs: [publish-protos] runs-on: ubuntu-latest steps: @@ -76,7 +76,7 @@ jobs: working-directory: sdks/fabric/interoperation-node-sdk publish-driver: - if: ${{ always() && (needs.publish-protos.result=='failure' || needs.publish-protos.result=='success') && github.repository_owner == 'sanvenDev' }} + if: ${{ always() && github.repository_owner == 'sanvenDev' }} needs: [publish-protos] runs-on: ubuntu-latest steps: From c01d90198e3ff1b1cb8bd4ada3c4eec4eceac2b2 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Tue, 5 Jul 2022 13:09:43 +0000 Subject: [PATCH 007/150] Decoupled protobuf upgrades from other package upgrades in workflows Earlier, SDK and driver upgrades followed successful protobuf version upgrades. Signed-off-by: VRamakrishna --- .github/workflows/deploy_corda-pkgs.yml | 6 +++--- .github/workflows/deploy_fabric-pkgs.yml | 6 ++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/workflows/deploy_corda-pkgs.yml b/.github/workflows/deploy_corda-pkgs.yml index d88c91452..1f5420b14 100644 --- a/.github/workflows/deploy_corda-pkgs.yml +++ b/.github/workflows/deploy_corda-pkgs.yml @@ -41,6 +41,7 @@ jobs: publish-interop-app: + if: always() needs: publish-protos runs-on: ubuntu-latest steps: @@ -71,6 +72,7 @@ jobs: working-directory: core/network/corda-interop-app publish-sdk: + if: always() needs: [publish-protos, publish-interop-app] runs-on: ubuntu-latest steps: @@ -101,7 +103,7 @@ jobs: working-directory: sdks/corda publish-driver: - if: github.repository_owner == 'hyperledger-labs' + if: ${{ always() && github.repository_owner == 'hyperledger-labs' }} needs: [publish-protos, publish-interop-app, publish-sdk] runs-on: ubuntu-latest steps: @@ -127,5 +129,3 @@ jobs: - name: Build and Push run: make push-image working-directory: core/drivers/corda-driver - - \ No newline at end of file diff --git a/.github/workflows/deploy_fabric-pkgs.yml b/.github/workflows/deploy_fabric-pkgs.yml index ac2d7b204..2b3d27b1f 100644 --- a/.github/workflows/deploy_fabric-pkgs.yml +++ b/.github/workflows/deploy_fabric-pkgs.yml @@ -48,7 +48,7 @@ jobs: working-directory: common/protos-js publish-sdk: - if: github.repository_owner == 'hyperledger-labs' + if: ${{ always() && github.repository_owner == 'hyperledger-labs' }} needs: [publish-protos] runs-on: ubuntu-latest steps: @@ -76,7 +76,7 @@ jobs: working-directory: sdks/fabric/interoperation-node-sdk publish-driver: - if: github.repository_owner == 'hyperledger-labs' + if: ${{ always() && github.repository_owner == 'hyperledger-labs' }} needs: [publish-protos] runs-on: ubuntu-latest steps: @@ -100,5 +100,3 @@ jobs: - name: Build and Push run: make push-image working-directory: core/drivers/fabric-driver - - \ No newline at end of file From e612fa16cbd7324ae1516e558d30e6ad71c9dc7e Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Tue, 5 Jul 2022 17:21:48 +0000 Subject: [PATCH 008/150] Fixed parsing logic in asset transfer test workflows Signed-off-by: VRamakrishna --- .github/workflows/test_asset-transfer.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test_asset-transfer.yml b/.github/workflows/test_asset-transfer.yml index f84ea0d3f..d78f8e1a6 100644 --- a/.github/workflows/test_asset-transfer.yml +++ b/.github/workflows/test_asset-transfer.yml @@ -265,7 +265,8 @@ jobs: cat tmp.out ./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer ReadAsset '["bond01","a03"]' --local-network=network2 &> tmp.out - tail -n 1 tmp.out | grep "Result from network query: {\"type\":\"bond01\",\"id\":\"a03\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" + #tail -n 1 tmp.out | grep "Result from network query: {\"type\":\"bond01\",\"id\":\"a03\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" + tail -n 1 tmp.out | tr '\n' ' ' | grep "Result from network query: { \"type\": \"bond01\", \"id\": \"a03\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" cat tmp.out ./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=20 --type=bond --ref=a04 --data-file=src/data/assetsForTransfer.json &> tmp.out @@ -283,7 +284,8 @@ jobs: cat tmp.out ./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset '["bond01","a04"]' --local-network=network1 &> tmp.out - tail -n 1 tmp.out | grep "Result from network query: {\"type\":\"bond01\",\"id\":\"a04\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" + #tail -n 1 tmp.out | grep "Result from network query: {\"type\":\"bond01\",\"id\":\"a04\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" + tail -n 1 tmp.out | tr '\n' ' ' | grep "Result from network query: { \"type\": \"bond01\", \"id\": \"a04\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" cat tmp.out ./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer ReadAsset '["bond01","a04"]' --local-network=network2 &> tmp.out @@ -632,7 +634,8 @@ jobs: cat tmp.out ./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer ReadAsset '["bond01","a03"]' --local-network=network2 &> tmp.out - tail -n 1 tmp.out | grep "Result from network query: {\"type\":\"bond01\",\"id\":\"a03\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" + #tail -n 1 tmp.out | grep "Result from network query: {\"type\":\"bond01\",\"id\":\"a03\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" + tail -n 1 tmp.out | tr '\n' ' ' | grep "Result from network query: { \"type\": \"bond01\", \"id\": \"a03\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" cat tmp.out ./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=20 --type=bond --ref=a04 --data-file=src/data/assetsForTransfer.json &> tmp.out @@ -650,7 +653,8 @@ jobs: cat tmp.out ./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset '["bond01","a04"]' --local-network=network1 &> tmp.out - tail -n 1 tmp.out | grep "Result from network query: {\"type\":\"bond01\",\"id\":\"a04\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" + #tail -n 1 tmp.out | grep "Result from network query: {\"type\":\"bond01\",\"id\":\"a04\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" + tail -n 1 tmp.out | tr '\n' ' ' | grep "Result from network query: { \"type\": \"bond01\", \"id\": \"a04\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" cat tmp.out ./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer ReadAsset '["bond01","a04"]' --local-network=network2 &> tmp.out From 9e024230871de645eddd4b474394e1013db2b7c0 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Tue, 5 Jul 2022 17:41:15 +0000 Subject: [PATCH 009/150] Fixed bug in asset transfer workflow parsing logic Signed-off-by: VRamakrishna --- .github/workflows/test_asset-transfer.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test_asset-transfer.yml b/.github/workflows/test_asset-transfer.yml index d78f8e1a6..9effcdbc0 100644 --- a/.github/workflows/test_asset-transfer.yml +++ b/.github/workflows/test_asset-transfer.yml @@ -266,7 +266,7 @@ jobs: ./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer ReadAsset '["bond01","a03"]' --local-network=network2 &> tmp.out #tail -n 1 tmp.out | grep "Result from network query: {\"type\":\"bond01\",\"id\":\"a03\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" - tail -n 1 tmp.out | tr '\n' ' ' | grep "Result from network query: { \"type\": \"bond01\", \"id\": \"a03\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out | tr '\n' ' ' | grep "Result from network query: { \"type\": \"bond01\", \"id\": \"a03\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" cat tmp.out ./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=20 --type=bond --ref=a04 --data-file=src/data/assetsForTransfer.json &> tmp.out @@ -285,7 +285,7 @@ jobs: ./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset '["bond01","a04"]' --local-network=network1 &> tmp.out #tail -n 1 tmp.out | grep "Result from network query: {\"type\":\"bond01\",\"id\":\"a04\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" - tail -n 1 tmp.out | tr '\n' ' ' | grep "Result from network query: { \"type\": \"bond01\", \"id\": \"a04\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out | tr '\n' ' ' | grep "Result from network query: { \"type\": \"bond01\", \"id\": \"a04\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" cat tmp.out ./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer ReadAsset '["bond01","a04"]' --local-network=network2 &> tmp.out @@ -635,7 +635,7 @@ jobs: ./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer ReadAsset '["bond01","a03"]' --local-network=network2 &> tmp.out #tail -n 1 tmp.out | grep "Result from network query: {\"type\":\"bond01\",\"id\":\"a03\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" - tail -n 1 tmp.out | tr '\n' ' ' | grep "Result from network query: { \"type\": \"bond01\", \"id\": \"a03\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out | tr '\n' ' ' | grep "Result from network query: { \"type\": \"bond01\", \"id\": \"a03\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" cat tmp.out ./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=20 --type=bond --ref=a04 --data-file=src/data/assetsForTransfer.json &> tmp.out @@ -654,7 +654,7 @@ jobs: ./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset '["bond01","a04"]' --local-network=network1 &> tmp.out #tail -n 1 tmp.out | grep "Result from network query: {\"type\":\"bond01\",\"id\":\"a04\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" - tail -n 1 tmp.out | tr '\n' ' ' | grep "Result from network query: { \"type\": \"bond01\", \"id\": \"a04\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out | tr '\n' ' ' | grep "Result from network query: { \"type\": \"bond01\", \"id\": \"a04\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" cat tmp.out ./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer ReadAsset '["bond01","a04"]' --local-network=network2 &> tmp.out From 645ac9a1c17f826753e0c72f310cdc8d5f2d450e Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Wed, 6 Jul 2022 09:20:01 +0530 Subject: [PATCH 010/150] use network artifacts backup to instantiate the fabric networks Signed-off-by: sandeep.nishad1 --- tests/network-setups/.gitignore | 8 +++++++ tests/network-setups/fabric/dev/Makefile | 22 +++++++++++++----- .../channel-artifacts/Org1MSPanchors.tx | Bin .../channel-artifacts/mychannel.block | Bin .../network1/channel-artifacts/mychannel.tx | Bin .../fabric-ca/ordererOrg/IssuerPublicKey | Bin .../ordererOrg/IssuerRevocationPublicKey | 0 .../network1/fabric-ca/ordererOrg/ca-cert.pem | 0 .../fabric-ca/ordererOrg/fabric-ca-server.db | Bin ...f83ae4cd3c985349a51610e6f9a35e930ea11eb_sk | 0 .../msp/keystore/IssuerRevocationPrivateKey | 0 .../ordererOrg/msp/keystore/IssuerSecretKey | 0 ...d4ae87f718c65ca2ca3832c72423a3802b68c66_sk | 0 .../fabric-ca/ordererOrg/tls-cert.pem | 0 .../network1/fabric-ca/org1/IssuerPublicKey | Bin .../fabric-ca/org1/IssuerRevocationPublicKey | 0 .../network1/fabric-ca/org1/ca-cert.pem | 0 .../fabric-ca/org1/fabric-ca-server.db | Bin ...8a53afd1a529b416f42db95e8592bb820633e3e_sk | 0 .../msp/keystore/IssuerRevocationPrivateKey | 0 .../org1/msp/keystore/IssuerSecretKey | 0 ...0220190470e56a5318f27e6052850765098f1df_sk | 0 .../network1/fabric-ca/org1/tls-cert.pem | 0 .../network1.com/fabric-ca-client-config.yaml | 0 .../network1.com/msp/IssuerPublicKey | Bin .../msp/IssuerRevocationPublicKey | 0 ...localhost-9054-ca-orderer-network1-com.pem | 0 .../network1.com/msp/config.yaml | 0 ...55a872b6eca64b4de3bb7c41625d223c055b40b_sk | 0 .../network1.com/msp/signcerts/cert.pem | 0 .../tlscacerts/tlsca.network1.com-cert.pem | 0 .../orderer.network1.com/msp/IssuerPublicKey | Bin .../msp/IssuerRevocationPublicKey | 0 ...localhost-9054-ca-orderer-network1-com.pem | 0 .../orderer.network1.com/msp/config.yaml | 0 ...cc884be1a3bf58080c2fa71095838351616ed69_sk | 0 .../msp/signcerts/cert.pem | 0 .../tlscacerts/tlsca.network1.com-cert.pem | 0 .../orderer.network1.com/tls/IssuerPublicKey | Bin .../tls/IssuerRevocationPublicKey | 0 .../orderers/orderer.network1.com/tls/ca.crt | 0 ...d8815192305afa9716ad6d6377520659afda105_sk | 0 .../orderer.network1.com/tls/server.crt | 0 .../orderer.network1.com/tls/server.key | 0 .../tls/signcerts/cert.pem | 0 ...localhost-9054-ca-orderer-network1-com.pem | 0 .../Admin@network1.com/msp/IssuerPublicKey | Bin .../msp/IssuerRevocationPublicKey | 0 ...localhost-9054-ca-orderer-network1-com.pem | 0 .../users/Admin@network1.com/msp/config.yaml | 0 ...dde304d16d6b4733b290981ec9b52baaf9f5e5c_sk | 0 .../Admin@network1.com/msp/signcerts/cert.pem | 0 .../ca/ca.org1.network1.com-cert.pem | 0 .../connection-org1.docker.json | 0 .../org1.network1.com/connection-org1.json | 0 .../org1.network1.com/connection-org1.yaml | 0 .../fabric-ca-client-config.yaml | 0 .../org1.network1.com/msp/IssuerPublicKey | Bin .../msp/IssuerRevocationPublicKey | 0 .../localhost-7054-ca-org1-network1-com.pem | 0 .../org1.network1.com/msp/config.yaml | 0 ...fa4330bc2d45b0e12c2e5c42e4f7eadfe36164c_sk | 0 .../org1.network1.com/msp/signcerts/cert.pem | 0 .../org1.network1.com/msp/tlscacerts/ca.crt | 0 .../msp/IssuerPublicKey | Bin .../msp/IssuerRevocationPublicKey | 0 .../localhost-7054-ca-org1-network1-com.pem | 0 .../peer0.org1.network1.com/msp/config.yaml | 0 ...df4fd0e38469608ecb0f9c4f235e543c303d127_sk | 0 .../msp/signcerts/cert.pem | 0 .../tls/IssuerPublicKey | Bin .../tls/IssuerRevocationPublicKey | 0 .../peers/peer0.org1.network1.com/tls/ca.crt | 0 ...a90ce16937ec46dece2734ed9349d491a59e24d_sk | 0 .../peer0.org1.network1.com/tls/server.crt | 0 .../peer0.org1.network1.com/tls/server.key | 0 .../tls/signcerts/cert.pem | 0 ...ls-localhost-7054-ca-org1-network1-com.pem | 0 .../tlsca/tlsca.org1.network1.com-cert.pem | 0 .../msp/IssuerPublicKey | Bin .../msp/IssuerRevocationPublicKey | 0 .../localhost-7054-ca-org1-network1-com.pem | 0 .../Admin@org1.network1.com/msp/config.yaml | 0 ...27cc9960303200526435bc864bd96b3e82e819f_sk | 0 .../msp/signcerts/cert.pem | 0 .../msp/IssuerPublicKey | Bin .../msp/IssuerRevocationPublicKey | 0 .../localhost-7054-ca-org1-network1-com.pem | 0 ...6132512d9552ace941a60701c810771291b03ec_sk | 0 .../msp/signcerts/cert.pem | 0 .../system-genesis-block/genesis.block | Bin .../network1/wallet/user1.id | 0 .../channel-artifacts/Org1MSPanchors.tx | Bin .../channel-artifacts/mychannel.block | Bin .../network2/channel-artifacts/mychannel.tx | Bin .../fabric-ca/ordererOrg/IssuerPublicKey | Bin .../ordererOrg/IssuerRevocationPublicKey | 0 .../network2/fabric-ca/ordererOrg/ca-cert.pem | 0 .../fabric-ca/ordererOrg/fabric-ca-server.db | Bin ...beb757a7fdea932edc5ba3672d1fd1c0b087b13_sk | 0 .../msp/keystore/IssuerRevocationPrivateKey | 0 .../ordererOrg/msp/keystore/IssuerSecretKey | 0 ...233e6d0c2cdca9bd2a8e7f76f8365e9a96e52f8_sk | 0 .../fabric-ca/ordererOrg/tls-cert.pem | 0 .../network2/fabric-ca/org1/IssuerPublicKey | 0 .../fabric-ca/org1/IssuerRevocationPublicKey | 0 .../network2/fabric-ca/org1/ca-cert.pem | 0 .../fabric-ca/org1/fabric-ca-server.db | Bin ...781ff8a6a75f6fd974f25e9f674873feebd9ea1_sk | 0 .../msp/keystore/IssuerRevocationPrivateKey | 0 .../org1/msp/keystore/IssuerSecretKey | 0 ...733e49c3aa42209717522d2307fcf37d7cecaed_sk | 0 .../network2/fabric-ca/org1/tls-cert.pem | 0 .../network2.com/fabric-ca-client-config.yaml | 0 .../network2.com/msp/IssuerPublicKey | Bin .../msp/IssuerRevocationPublicKey | 0 ...localhost-8054-ca-orderer-network2-com.pem | 0 .../network2.com/msp/config.yaml | 0 ...b83ca7f217cd794857d1347dd27ad47f601cbe7_sk | 0 .../network2.com/msp/signcerts/cert.pem | 0 .../tlscacerts/tlsca.network2.com-cert.pem | 0 .../orderer.network2.com/msp/IssuerPublicKey | Bin .../msp/IssuerRevocationPublicKey | 0 ...localhost-8054-ca-orderer-network2-com.pem | 0 .../orderer.network2.com/msp/config.yaml | 0 ...d6e23bb09ed8f3165c7b9957c8761bd9695297f_sk | 0 .../msp/signcerts/cert.pem | 0 .../tlscacerts/tlsca.network2.com-cert.pem | 0 .../orderer.network2.com/tls/IssuerPublicKey | Bin .../tls/IssuerRevocationPublicKey | 0 .../orderers/orderer.network2.com/tls/ca.crt | 0 ...cdfa32801c8ae5fc26211ea4faff9ae6672bd35_sk | 0 .../orderer.network2.com/tls/server.crt | 0 .../orderer.network2.com/tls/server.key | 0 .../tls/signcerts/cert.pem | 0 ...localhost-8054-ca-orderer-network2-com.pem | 0 .../Admin@network2.com/msp/IssuerPublicKey | Bin .../msp/IssuerRevocationPublicKey | 0 ...localhost-8054-ca-orderer-network2-com.pem | 0 .../users/Admin@network2.com/msp/config.yaml | 0 ...2a005780753ee8529259598d515f6e14024fe8a_sk | 0 .../Admin@network2.com/msp/signcerts/cert.pem | 0 .../ca/ca.org1.network2.com-cert.pem | 0 .../connection-org1.docker.json | 0 .../org1.network2.com/connection-org1.json | 0 .../org1.network2.com/connection-org1.yaml | 0 .../fabric-ca-client-config.yaml | 0 .../org1.network2.com/msp/IssuerPublicKey | 0 .../msp/IssuerRevocationPublicKey | 0 .../localhost-5054-ca-org1-network2-com.pem | 0 .../org1.network2.com/msp/config.yaml | 0 ...6c33dd1edcbed4a5e599a116854e71eaf427e96_sk | 0 .../org1.network2.com/msp/signcerts/cert.pem | 0 .../org1.network2.com/msp/tlscacerts/ca.crt | 0 .../msp/IssuerPublicKey | 0 .../msp/IssuerRevocationPublicKey | 0 .../localhost-5054-ca-org1-network2-com.pem | 0 .../peer0.org1.network2.com/msp/config.yaml | 0 ...10ac4979b258a864c5778180cc43dda00ef02ad_sk | 0 .../msp/signcerts/cert.pem | 0 .../tls/IssuerPublicKey | 0 .../tls/IssuerRevocationPublicKey | 0 .../peers/peer0.org1.network2.com/tls/ca.crt | 0 ...fb0dc92a4099335a1b737e7380d5bbd5cbb57e6_sk | 0 .../peer0.org1.network2.com/tls/server.crt | 0 .../peer0.org1.network2.com/tls/server.key | 0 .../tls/signcerts/cert.pem | 0 ...ls-localhost-5054-ca-org1-network2-com.pem | 0 .../tlsca/tlsca.org1.network2.com-cert.pem | 0 .../msp/IssuerPublicKey | 0 .../msp/IssuerRevocationPublicKey | 0 .../localhost-5054-ca-org1-network2-com.pem | 0 .../Admin@org1.network2.com/msp/config.yaml | 0 ...08949aeb68fd089dec6d386f21ff361eccc2072_sk | 0 .../msp/signcerts/cert.pem | 0 .../msp/IssuerPublicKey | 0 .../msp/IssuerRevocationPublicKey | 0 .../localhost-5054-ca-org1-network2-com.pem | 0 ...682540ecb8ff59924b569c0dca624b478025f3d_sk | 0 .../msp/signcerts/cert.pem | 0 .../system-genesis-block/genesis.block | Bin .../network2/wallet/user1.id | 0 182 files changed, 24 insertions(+), 6 deletions(-) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/channel-artifacts/Org1MSPanchors.tx (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/channel-artifacts/mychannel.block (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/channel-artifacts/mychannel.tx (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/fabric-ca/ordererOrg/IssuerPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/fabric-ca/ordererOrg/IssuerRevocationPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/fabric-ca/ordererOrg/ca-cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/fabric-ca/ordererOrg/fabric-ca-server.db (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/fabric-ca/ordererOrg/msp/keystore/94255e346295ca5a0e3bb32e7f83ae4cd3c985349a51610e6f9a35e930ea11eb_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/fabric-ca/ordererOrg/msp/keystore/IssuerRevocationPrivateKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/fabric-ca/ordererOrg/msp/keystore/IssuerSecretKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/fabric-ca/ordererOrg/msp/keystore/d43d8da7496c8f02d534cd58cd4ae87f718c65ca2ca3832c72423a3802b68c66_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/fabric-ca/ordererOrg/tls-cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/fabric-ca/org1/IssuerPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/fabric-ca/org1/IssuerRevocationPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/fabric-ca/org1/ca-cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/fabric-ca/org1/fabric-ca-server.db (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/fabric-ca/org1/msp/keystore/5dfbce629e275090ced3e2e678a53afd1a529b416f42db95e8592bb820633e3e_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/fabric-ca/org1/msp/keystore/IssuerRevocationPrivateKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/fabric-ca/org1/msp/keystore/IssuerSecretKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/fabric-ca/org1/msp/keystore/cd392f2c72a2673ecdd5400bf0220190470e56a5318f27e6052850765098f1df_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/fabric-ca/org1/tls-cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/fabric-ca-client-config.yaml (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/msp/IssuerPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/msp/IssuerRevocationPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/msp/config.yaml (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/msp/keystore/ae13856d0a06478551748e67a55a872b6eca64b4de3bb7c41625d223c055b40b_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/msp/signcerts/cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/IssuerPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/IssuerRevocationPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/config.yaml (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/keystore/e77cc1ca55809c7a48c804fe7cc884be1a3bf58080c2fa71095838351616ed69_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/signcerts/cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/IssuerPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/IssuerRevocationPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/ca.crt (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/keystore/39f5127d7653c2b2fceef7ed6d8815192305afa9716ad6d6377520659afda105_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.crt (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.key (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/signcerts/cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/tlscacerts/tls-localhost-9054-ca-orderer-network1-com.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/IssuerPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/IssuerRevocationPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/config.yaml (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/keystore/d7ac31a822ab05c8800fd03bddde304d16d6b4733b290981ec9b52baaf9f5e5c_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/signcerts/cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/ca/ca.org1.network1.com-cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/connection-org1.docker.json (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/connection-org1.json (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/connection-org1.yaml (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/fabric-ca-client-config.yaml (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/msp/IssuerPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/msp/IssuerRevocationPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/msp/config.yaml (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/msp/keystore/198a5af9008e2b0127f3120a5fa4330bc2d45b0e12c2e5c42e4f7eadfe36164c_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/msp/signcerts/cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/msp/tlscacerts/ca.crt (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/IssuerPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/IssuerRevocationPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/config.yaml (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/keystore/085360b244a3d2dbf494a2390df4fd0e38469608ecb0f9c4f235e543c303d127_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/signcerts/cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/IssuerPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/IssuerRevocationPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/ca.crt (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/keystore/5ef7cb27d6b4866bc9d704c91a90ce16937ec46dece2734ed9349d491a59e24d_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/server.crt (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/server.key (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/signcerts/cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/tlscacerts/tls-localhost-7054-ca-org1-network1-com.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/tlsca/tlsca.org1.network1.com-cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/IssuerPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/IssuerRevocationPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/config.yaml (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/keystore/7a2bc768da5d5ecf5ba6e206e27cc9960303200526435bc864bd96b3e82e819f_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/signcerts/cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/IssuerPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/IssuerRevocationPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/keystore/43e1a75012fe2626d853745be6132512d9552ace941a60701c810771291b03ec_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/signcerts/cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/system-genesis-block/genesis.block (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network1/wallet/user1.id (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/channel-artifacts/Org1MSPanchors.tx (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/channel-artifacts/mychannel.block (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/channel-artifacts/mychannel.tx (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/fabric-ca/ordererOrg/IssuerPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/fabric-ca/ordererOrg/IssuerRevocationPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/fabric-ca/ordererOrg/ca-cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/fabric-ca/ordererOrg/fabric-ca-server.db (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/fabric-ca/ordererOrg/msp/keystore/4d66bd3a677d620e418fdb85cbeb757a7fdea932edc5ba3672d1fd1c0b087b13_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/fabric-ca/ordererOrg/msp/keystore/IssuerRevocationPrivateKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/fabric-ca/ordererOrg/msp/keystore/IssuerSecretKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/fabric-ca/ordererOrg/msp/keystore/e29c727a5c3adda2daa247431233e6d0c2cdca9bd2a8e7f76f8365e9a96e52f8_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/fabric-ca/ordererOrg/tls-cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/fabric-ca/org1/IssuerPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/fabric-ca/org1/IssuerRevocationPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/fabric-ca/org1/ca-cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/fabric-ca/org1/fabric-ca-server.db (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/fabric-ca/org1/msp/keystore/7d3e97c4644391d43429e1b9e781ff8a6a75f6fd974f25e9f674873feebd9ea1_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/fabric-ca/org1/msp/keystore/IssuerRevocationPrivateKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/fabric-ca/org1/msp/keystore/IssuerSecretKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/fabric-ca/org1/msp/keystore/ff63d3aee2f2cb882477e67de733e49c3aa42209717522d2307fcf37d7cecaed_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/fabric-ca/org1/tls-cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/fabric-ca-client-config.yaml (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/msp/IssuerPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/msp/IssuerRevocationPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/msp/config.yaml (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/msp/keystore/25ad3edad97423cb9ceba6b06b83ca7f217cd794857d1347dd27ad47f601cbe7_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/msp/signcerts/cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/msp/tlscacerts/tlsca.network2.com-cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/IssuerPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/IssuerRevocationPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/config.yaml (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/keystore/d30db3151430ff2c370f8f40cd6e23bb09ed8f3165c7b9957c8761bd9695297f_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/signcerts/cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/tlscacerts/tlsca.network2.com-cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/IssuerPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/IssuerRevocationPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/ca.crt (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/keystore/cc2fe89245d366799edfc39e8cdfa32801c8ae5fc26211ea4faff9ae6672bd35_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/server.crt (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/server.key (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/signcerts/cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/tlscacerts/tls-localhost-8054-ca-orderer-network2-com.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/IssuerPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/IssuerRevocationPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/config.yaml (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/keystore/8163fd4f80204f53f3149c20b2a005780753ee8529259598d515f6e14024fe8a_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/signcerts/cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/ca/ca.org1.network2.com-cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/connection-org1.docker.json (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/connection-org1.json (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/connection-org1.yaml (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/fabric-ca-client-config.yaml (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/msp/IssuerPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/msp/IssuerRevocationPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/msp/cacerts/localhost-5054-ca-org1-network2-com.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/msp/config.yaml (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/msp/keystore/3fec22439cf4be3c4f4a960276c33dd1edcbed4a5e599a116854e71eaf427e96_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/msp/signcerts/cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/msp/tlscacerts/ca.crt (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/IssuerPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/IssuerRevocationPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/cacerts/localhost-5054-ca-org1-network2-com.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/config.yaml (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/keystore/03bc2a06ccd3c6456e6aac3a010ac4979b258a864c5778180cc43dda00ef02ad_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/signcerts/cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/IssuerPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/IssuerRevocationPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/ca.crt (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/keystore/b921b2940a4a7cdb8dd8a4509fb0dc92a4099335a1b737e7380d5bbd5cbb57e6_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/server.crt (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/server.key (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/signcerts/cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/tlscacerts/tls-localhost-5054-ca-org1-network2-com.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/tlsca/tlsca.org1.network2.com-cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/IssuerPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/IssuerRevocationPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/cacerts/localhost-5054-ca-org1-network2-com.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/config.yaml (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/keystore/05e000f93c5285fb535f2d8d208949aeb68fd089dec6d386f21ff361eccc2072_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/signcerts/cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/IssuerPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/IssuerRevocationPublicKey (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/cacerts/localhost-5054-ca-org1-network2-com.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/keystore/0e6057bbf43121b51abad6a86682540ecb8ff59924b569c0dca624b478025f3d_sk (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/signcerts/cert.pem (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/system-genesis-block/genesis.block (100%) rename tests/network-setups/fabric/{shared => network-artifacts}/network2/wallet/user1.id (100%) diff --git a/tests/network-setups/.gitignore b/tests/network-setups/.gitignore index e636cb0a9..3fa3a9936 100644 --- a/tests/network-setups/.gitignore +++ b/tests/network-setups/.gitignore @@ -14,3 +14,11 @@ shared/charts/username *.tar.gz *.env fabric/dev/log.txt + +fabric/shared/*/ordererOrganizations +fabric/shared/*/peerOrganizations +fabric/shared/*/wallet/* +fabric/shared/*/system-genesis-block/* +fabric/shared/*/channel-artifacts +fabric/shared/*/fabric-ca/ordererOrg/* +fabric/shared/*/fabric-ca/org1/* \ No newline at end of file diff --git a/tests/network-setups/fabric/dev/Makefile b/tests/network-setups/fabric/dev/Makefile index 41c84272f..e17f59c69 100644 --- a/tests/network-setups/fabric/dev/Makefile +++ b/tests/network-setups/fabric/dev/Makefile @@ -7,9 +7,17 @@ E2E_CONFIDENTIALITY?=false .PHONY: all all: start + +.PHONY: artifacts-network1 +artifacts-network1: + cp -r ../network-artifacts/network1/* ../shared/network1/ + +.PHONY: artifacts-network2 +artifacts-network2: + cp -r ../network-artifacts/network2/* ../shared/network2/ .PHONY: start -start: start-network1 start-network2 +start: start-network1 start-network2 .PHONY: start-interop start-interop: start-interop-network1 start-interop-network2 @@ -18,22 +26,22 @@ start-interop: start-interop-network1 start-interop-network2 start-interop-local: start-interop-network1-local start-interop-network2-local .PHONY: start-network1 -start-network1: .fabric-setup setup-cc +start-network1: .fabric-setup artifacts-network1 setup-cc ./network.sh up createChannel -ca -nw network1 ./network.sh deployCC -ch $(CHAINCODE_NAME) -nw network1 .PHONY: start-network1-local -start-network1-local: .fabric-setup setup-cc-local +start-network1-local: .fabric-setup artifacts-network1 setup-cc-local ./network.sh up createChannel -ca -nw network1 ./network.sh deployCC -ch $(CHAINCODE_NAME) -nw network1 .PHONY: start-network2 -start-network2: .fabric-setup setup-cc +start-network2: .fabric-setup artifacts-network2 setup-cc ./network.sh up createChannel -ca -nw network2 ./network.sh deployCC -ch $(CHAINCODE_NAME) -nw network2 .PHONY: start-network2-local -start-network2-local: .fabric-setup setup-cc-local +start-network2-local: .fabric-setup artifacts-network2 setup-cc-local ./network.sh up createChannel -ca -nw network2 ./network.sh deployCC -ch $(CHAINCODE_NAME) -nw network2 @@ -111,13 +119,15 @@ remove: remove-network1 remove-network2 .PHONY: remove-network1 remove-network1: ./network.sh clean -nw network1 + rm -rf ../shared/network1/wallet/*.id .PHONY: remove-network2 remove-network2: ./network.sh clean -nw network2 + rm -rf ../shared/network2/wallet/*.id .PHONY: clean -clean: stop +clean: stop remove +rm -rf bin || true +rm -rf config || true +rm .fabric-setup || true diff --git a/tests/network-setups/fabric/shared/network1/channel-artifacts/Org1MSPanchors.tx b/tests/network-setups/fabric/network-artifacts/network1/channel-artifacts/Org1MSPanchors.tx similarity index 100% rename from tests/network-setups/fabric/shared/network1/channel-artifacts/Org1MSPanchors.tx rename to tests/network-setups/fabric/network-artifacts/network1/channel-artifacts/Org1MSPanchors.tx diff --git a/tests/network-setups/fabric/shared/network1/channel-artifacts/mychannel.block b/tests/network-setups/fabric/network-artifacts/network1/channel-artifacts/mychannel.block similarity index 100% rename from tests/network-setups/fabric/shared/network1/channel-artifacts/mychannel.block rename to tests/network-setups/fabric/network-artifacts/network1/channel-artifacts/mychannel.block diff --git a/tests/network-setups/fabric/shared/network1/channel-artifacts/mychannel.tx b/tests/network-setups/fabric/network-artifacts/network1/channel-artifacts/mychannel.tx similarity index 100% rename from tests/network-setups/fabric/shared/network1/channel-artifacts/mychannel.tx rename to tests/network-setups/fabric/network-artifacts/network1/channel-artifacts/mychannel.tx diff --git a/tests/network-setups/fabric/shared/network1/fabric-ca/ordererOrg/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/IssuerPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/fabric-ca/ordererOrg/IssuerPublicKey rename to tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/IssuerPublicKey diff --git a/tests/network-setups/fabric/shared/network1/fabric-ca/ordererOrg/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/IssuerRevocationPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/fabric-ca/ordererOrg/IssuerRevocationPublicKey rename to tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/IssuerRevocationPublicKey diff --git a/tests/network-setups/fabric/shared/network1/fabric-ca/ordererOrg/ca-cert.pem b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/ca-cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/fabric-ca/ordererOrg/ca-cert.pem rename to tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/ca-cert.pem diff --git a/tests/network-setups/fabric/shared/network1/fabric-ca/ordererOrg/fabric-ca-server.db b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/fabric-ca-server.db similarity index 100% rename from tests/network-setups/fabric/shared/network1/fabric-ca/ordererOrg/fabric-ca-server.db rename to tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/fabric-ca-server.db diff --git a/tests/network-setups/fabric/shared/network1/fabric-ca/ordererOrg/msp/keystore/94255e346295ca5a0e3bb32e7f83ae4cd3c985349a51610e6f9a35e930ea11eb_sk b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/94255e346295ca5a0e3bb32e7f83ae4cd3c985349a51610e6f9a35e930ea11eb_sk similarity index 100% rename from tests/network-setups/fabric/shared/network1/fabric-ca/ordererOrg/msp/keystore/94255e346295ca5a0e3bb32e7f83ae4cd3c985349a51610e6f9a35e930ea11eb_sk rename to tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/94255e346295ca5a0e3bb32e7f83ae4cd3c985349a51610e6f9a35e930ea11eb_sk diff --git a/tests/network-setups/fabric/shared/network1/fabric-ca/ordererOrg/msp/keystore/IssuerRevocationPrivateKey b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/IssuerRevocationPrivateKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/fabric-ca/ordererOrg/msp/keystore/IssuerRevocationPrivateKey rename to tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/IssuerRevocationPrivateKey diff --git a/tests/network-setups/fabric/shared/network1/fabric-ca/ordererOrg/msp/keystore/IssuerSecretKey b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/IssuerSecretKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/fabric-ca/ordererOrg/msp/keystore/IssuerSecretKey rename to tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/IssuerSecretKey diff --git a/tests/network-setups/fabric/shared/network1/fabric-ca/ordererOrg/msp/keystore/d43d8da7496c8f02d534cd58cd4ae87f718c65ca2ca3832c72423a3802b68c66_sk b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/d43d8da7496c8f02d534cd58cd4ae87f718c65ca2ca3832c72423a3802b68c66_sk similarity index 100% rename from tests/network-setups/fabric/shared/network1/fabric-ca/ordererOrg/msp/keystore/d43d8da7496c8f02d534cd58cd4ae87f718c65ca2ca3832c72423a3802b68c66_sk rename to tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/d43d8da7496c8f02d534cd58cd4ae87f718c65ca2ca3832c72423a3802b68c66_sk diff --git a/tests/network-setups/fabric/shared/network1/fabric-ca/ordererOrg/tls-cert.pem b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/tls-cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/fabric-ca/ordererOrg/tls-cert.pem rename to tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/tls-cert.pem diff --git a/tests/network-setups/fabric/shared/network1/fabric-ca/org1/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/IssuerPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/fabric-ca/org1/IssuerPublicKey rename to tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/IssuerPublicKey diff --git a/tests/network-setups/fabric/shared/network1/fabric-ca/org1/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/IssuerRevocationPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/fabric-ca/org1/IssuerRevocationPublicKey rename to tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/IssuerRevocationPublicKey diff --git a/tests/network-setups/fabric/shared/network1/fabric-ca/org1/ca-cert.pem b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/ca-cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/fabric-ca/org1/ca-cert.pem rename to tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/ca-cert.pem diff --git a/tests/network-setups/fabric/shared/network1/fabric-ca/org1/fabric-ca-server.db b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/fabric-ca-server.db similarity index 100% rename from tests/network-setups/fabric/shared/network1/fabric-ca/org1/fabric-ca-server.db rename to tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/fabric-ca-server.db diff --git a/tests/network-setups/fabric/shared/network1/fabric-ca/org1/msp/keystore/5dfbce629e275090ced3e2e678a53afd1a529b416f42db95e8592bb820633e3e_sk b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/5dfbce629e275090ced3e2e678a53afd1a529b416f42db95e8592bb820633e3e_sk similarity index 100% rename from tests/network-setups/fabric/shared/network1/fabric-ca/org1/msp/keystore/5dfbce629e275090ced3e2e678a53afd1a529b416f42db95e8592bb820633e3e_sk rename to tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/5dfbce629e275090ced3e2e678a53afd1a529b416f42db95e8592bb820633e3e_sk diff --git a/tests/network-setups/fabric/shared/network1/fabric-ca/org1/msp/keystore/IssuerRevocationPrivateKey b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/IssuerRevocationPrivateKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/fabric-ca/org1/msp/keystore/IssuerRevocationPrivateKey rename to tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/IssuerRevocationPrivateKey diff --git a/tests/network-setups/fabric/shared/network1/fabric-ca/org1/msp/keystore/IssuerSecretKey b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/IssuerSecretKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/fabric-ca/org1/msp/keystore/IssuerSecretKey rename to tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/IssuerSecretKey diff --git a/tests/network-setups/fabric/shared/network1/fabric-ca/org1/msp/keystore/cd392f2c72a2673ecdd5400bf0220190470e56a5318f27e6052850765098f1df_sk b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/cd392f2c72a2673ecdd5400bf0220190470e56a5318f27e6052850765098f1df_sk similarity index 100% rename from tests/network-setups/fabric/shared/network1/fabric-ca/org1/msp/keystore/cd392f2c72a2673ecdd5400bf0220190470e56a5318f27e6052850765098f1df_sk rename to tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/cd392f2c72a2673ecdd5400bf0220190470e56a5318f27e6052850765098f1df_sk diff --git a/tests/network-setups/fabric/shared/network1/fabric-ca/org1/tls-cert.pem b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/tls-cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/fabric-ca/org1/tls-cert.pem rename to tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/tls-cert.pem diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/fabric-ca-client-config.yaml b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/fabric-ca-client-config.yaml similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/fabric-ca-client-config.yaml rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/fabric-ca-client-config.yaml diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/IssuerPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/msp/IssuerPublicKey rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/IssuerPublicKey diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/IssuerRevocationPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/msp/IssuerRevocationPublicKey rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/IssuerRevocationPublicKey diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/msp/config.yaml b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/config.yaml similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/msp/config.yaml rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/config.yaml diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/msp/keystore/ae13856d0a06478551748e67a55a872b6eca64b4de3bb7c41625d223c055b40b_sk b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/keystore/ae13856d0a06478551748e67a55a872b6eca64b4de3bb7c41625d223c055b40b_sk similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/msp/keystore/ae13856d0a06478551748e67a55a872b6eca64b4de3bb7c41625d223c055b40b_sk rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/keystore/ae13856d0a06478551748e67a55a872b6eca64b4de3bb7c41625d223c055b40b_sk diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/signcerts/cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/msp/signcerts/cert.pem rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/signcerts/cert.pem diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/IssuerPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/IssuerPublicKey rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/IssuerPublicKey diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/IssuerRevocationPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/IssuerRevocationPublicKey rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/IssuerRevocationPublicKey diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/config.yaml b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/config.yaml similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/config.yaml rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/config.yaml diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/keystore/e77cc1ca55809c7a48c804fe7cc884be1a3bf58080c2fa71095838351616ed69_sk b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/keystore/e77cc1ca55809c7a48c804fe7cc884be1a3bf58080c2fa71095838351616ed69_sk similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/keystore/e77cc1ca55809c7a48c804fe7cc884be1a3bf58080c2fa71095838351616ed69_sk rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/keystore/e77cc1ca55809c7a48c804fe7cc884be1a3bf58080c2fa71095838351616ed69_sk diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/signcerts/cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/signcerts/cert.pem rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/signcerts/cert.pem diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/IssuerPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/IssuerPublicKey rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/IssuerPublicKey diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/IssuerRevocationPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/IssuerRevocationPublicKey rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/IssuerRevocationPublicKey diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/ca.crt b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/ca.crt similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/ca.crt rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/ca.crt diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/keystore/39f5127d7653c2b2fceef7ed6d8815192305afa9716ad6d6377520659afda105_sk b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/keystore/39f5127d7653c2b2fceef7ed6d8815192305afa9716ad6d6377520659afda105_sk similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/keystore/39f5127d7653c2b2fceef7ed6d8815192305afa9716ad6d6377520659afda105_sk rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/keystore/39f5127d7653c2b2fceef7ed6d8815192305afa9716ad6d6377520659afda105_sk diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.crt b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.crt similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.crt rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.crt diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.key b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.key similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.key rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.key diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/signcerts/cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/signcerts/cert.pem rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/signcerts/cert.pem diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/tlscacerts/tls-localhost-9054-ca-orderer-network1-com.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/tlscacerts/tls-localhost-9054-ca-orderer-network1-com.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/tlscacerts/tls-localhost-9054-ca-orderer-network1-com.pem rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/tlscacerts/tls-localhost-9054-ca-orderer-network1-com.pem diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/IssuerPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/IssuerPublicKey rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/IssuerPublicKey diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/IssuerRevocationPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/IssuerRevocationPublicKey rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/IssuerRevocationPublicKey diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/config.yaml b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/config.yaml similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/config.yaml rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/config.yaml diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/keystore/d7ac31a822ab05c8800fd03bddde304d16d6b4733b290981ec9b52baaf9f5e5c_sk b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/keystore/d7ac31a822ab05c8800fd03bddde304d16d6b4733b290981ec9b52baaf9f5e5c_sk similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/keystore/d7ac31a822ab05c8800fd03bddde304d16d6b4733b290981ec9b52baaf9f5e5c_sk rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/keystore/d7ac31a822ab05c8800fd03bddde304d16d6b4733b290981ec9b52baaf9f5e5c_sk diff --git a/tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/signcerts/cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/signcerts/cert.pem rename to tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/signcerts/cert.pem diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/ca/ca.org1.network1.com-cert.pem b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/ca/ca.org1.network1.com-cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/ca/ca.org1.network1.com-cert.pem rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/ca/ca.org1.network1.com-cert.pem diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.docker.json b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.docker.json similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.docker.json rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.docker.json diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.json similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.json diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.yaml b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.yaml similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.yaml rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.yaml diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/fabric-ca-client-config.yaml b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/fabric-ca-client-config.yaml similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/fabric-ca-client-config.yaml rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/fabric-ca-client-config.yaml diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/IssuerPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/msp/IssuerPublicKey rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/IssuerPublicKey diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/IssuerRevocationPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/msp/IssuerRevocationPublicKey rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/IssuerRevocationPublicKey diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/msp/config.yaml b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/config.yaml similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/msp/config.yaml rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/config.yaml diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/msp/keystore/198a5af9008e2b0127f3120a5fa4330bc2d45b0e12c2e5c42e4f7eadfe36164c_sk b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/keystore/198a5af9008e2b0127f3120a5fa4330bc2d45b0e12c2e5c42e4f7eadfe36164c_sk similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/msp/keystore/198a5af9008e2b0127f3120a5fa4330bc2d45b0e12c2e5c42e4f7eadfe36164c_sk rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/keystore/198a5af9008e2b0127f3120a5fa4330bc2d45b0e12c2e5c42e4f7eadfe36164c_sk diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/signcerts/cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/msp/signcerts/cert.pem rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/signcerts/cert.pem diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/msp/tlscacerts/ca.crt b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/tlscacerts/ca.crt similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/msp/tlscacerts/ca.crt rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/tlscacerts/ca.crt diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/IssuerPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/IssuerPublicKey rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/IssuerPublicKey diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/IssuerRevocationPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/IssuerRevocationPublicKey rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/IssuerRevocationPublicKey diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/config.yaml b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/config.yaml similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/config.yaml rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/config.yaml diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/keystore/085360b244a3d2dbf494a2390df4fd0e38469608ecb0f9c4f235e543c303d127_sk b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/keystore/085360b244a3d2dbf494a2390df4fd0e38469608ecb0f9c4f235e543c303d127_sk similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/keystore/085360b244a3d2dbf494a2390df4fd0e38469608ecb0f9c4f235e543c303d127_sk rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/keystore/085360b244a3d2dbf494a2390df4fd0e38469608ecb0f9c4f235e543c303d127_sk diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/signcerts/cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/signcerts/cert.pem rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/signcerts/cert.pem diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/IssuerPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/IssuerPublicKey rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/IssuerPublicKey diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/IssuerRevocationPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/IssuerRevocationPublicKey rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/IssuerRevocationPublicKey diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/ca.crt b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/ca.crt similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/ca.crt rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/ca.crt diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/keystore/5ef7cb27d6b4866bc9d704c91a90ce16937ec46dece2734ed9349d491a59e24d_sk b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/keystore/5ef7cb27d6b4866bc9d704c91a90ce16937ec46dece2734ed9349d491a59e24d_sk similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/keystore/5ef7cb27d6b4866bc9d704c91a90ce16937ec46dece2734ed9349d491a59e24d_sk rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/keystore/5ef7cb27d6b4866bc9d704c91a90ce16937ec46dece2734ed9349d491a59e24d_sk diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/server.crt b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/server.crt similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/server.crt rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/server.crt diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/server.key b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/server.key similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/server.key rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/server.key diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/signcerts/cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/signcerts/cert.pem rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/signcerts/cert.pem diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/tlscacerts/tls-localhost-7054-ca-org1-network1-com.pem b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/tlscacerts/tls-localhost-7054-ca-org1-network1-com.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/tlscacerts/tls-localhost-7054-ca-org1-network1-com.pem rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/tlscacerts/tls-localhost-7054-ca-org1-network1-com.pem diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/tlsca/tlsca.org1.network1.com-cert.pem b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/tlsca/tlsca.org1.network1.com-cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/tlsca/tlsca.org1.network1.com-cert.pem rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/tlsca/tlsca.org1.network1.com-cert.pem diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/IssuerPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/IssuerPublicKey rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/IssuerPublicKey diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/IssuerRevocationPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/IssuerRevocationPublicKey rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/IssuerRevocationPublicKey diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/config.yaml b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/config.yaml similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/config.yaml rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/config.yaml diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/keystore/7a2bc768da5d5ecf5ba6e206e27cc9960303200526435bc864bd96b3e82e819f_sk b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/keystore/7a2bc768da5d5ecf5ba6e206e27cc9960303200526435bc864bd96b3e82e819f_sk similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/keystore/7a2bc768da5d5ecf5ba6e206e27cc9960303200526435bc864bd96b3e82e819f_sk rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/keystore/7a2bc768da5d5ecf5ba6e206e27cc9960303200526435bc864bd96b3e82e819f_sk diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/signcerts/cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/signcerts/cert.pem rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/signcerts/cert.pem diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/IssuerPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/IssuerPublicKey rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/IssuerPublicKey diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/IssuerRevocationPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/IssuerRevocationPublicKey rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/IssuerRevocationPublicKey diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/keystore/43e1a75012fe2626d853745be6132512d9552ace941a60701c810771291b03ec_sk b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/keystore/43e1a75012fe2626d853745be6132512d9552ace941a60701c810771291b03ec_sk similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/keystore/43e1a75012fe2626d853745be6132512d9552ace941a60701c810771291b03ec_sk rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/keystore/43e1a75012fe2626d853745be6132512d9552ace941a60701c810771291b03ec_sk diff --git a/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/signcerts/cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/signcerts/cert.pem rename to tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/signcerts/cert.pem diff --git a/tests/network-setups/fabric/shared/network1/system-genesis-block/genesis.block b/tests/network-setups/fabric/network-artifacts/network1/system-genesis-block/genesis.block similarity index 100% rename from tests/network-setups/fabric/shared/network1/system-genesis-block/genesis.block rename to tests/network-setups/fabric/network-artifacts/network1/system-genesis-block/genesis.block diff --git a/tests/network-setups/fabric/shared/network1/wallet/user1.id b/tests/network-setups/fabric/network-artifacts/network1/wallet/user1.id similarity index 100% rename from tests/network-setups/fabric/shared/network1/wallet/user1.id rename to tests/network-setups/fabric/network-artifacts/network1/wallet/user1.id diff --git a/tests/network-setups/fabric/shared/network2/channel-artifacts/Org1MSPanchors.tx b/tests/network-setups/fabric/network-artifacts/network2/channel-artifacts/Org1MSPanchors.tx similarity index 100% rename from tests/network-setups/fabric/shared/network2/channel-artifacts/Org1MSPanchors.tx rename to tests/network-setups/fabric/network-artifacts/network2/channel-artifacts/Org1MSPanchors.tx diff --git a/tests/network-setups/fabric/shared/network2/channel-artifacts/mychannel.block b/tests/network-setups/fabric/network-artifacts/network2/channel-artifacts/mychannel.block similarity index 100% rename from tests/network-setups/fabric/shared/network2/channel-artifacts/mychannel.block rename to tests/network-setups/fabric/network-artifacts/network2/channel-artifacts/mychannel.block diff --git a/tests/network-setups/fabric/shared/network2/channel-artifacts/mychannel.tx b/tests/network-setups/fabric/network-artifacts/network2/channel-artifacts/mychannel.tx similarity index 100% rename from tests/network-setups/fabric/shared/network2/channel-artifacts/mychannel.tx rename to tests/network-setups/fabric/network-artifacts/network2/channel-artifacts/mychannel.tx diff --git a/tests/network-setups/fabric/shared/network2/fabric-ca/ordererOrg/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/IssuerPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/fabric-ca/ordererOrg/IssuerPublicKey rename to tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/IssuerPublicKey diff --git a/tests/network-setups/fabric/shared/network2/fabric-ca/ordererOrg/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/IssuerRevocationPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/fabric-ca/ordererOrg/IssuerRevocationPublicKey rename to tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/IssuerRevocationPublicKey diff --git a/tests/network-setups/fabric/shared/network2/fabric-ca/ordererOrg/ca-cert.pem b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/ca-cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/fabric-ca/ordererOrg/ca-cert.pem rename to tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/ca-cert.pem diff --git a/tests/network-setups/fabric/shared/network2/fabric-ca/ordererOrg/fabric-ca-server.db b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/fabric-ca-server.db similarity index 100% rename from tests/network-setups/fabric/shared/network2/fabric-ca/ordererOrg/fabric-ca-server.db rename to tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/fabric-ca-server.db diff --git a/tests/network-setups/fabric/shared/network2/fabric-ca/ordererOrg/msp/keystore/4d66bd3a677d620e418fdb85cbeb757a7fdea932edc5ba3672d1fd1c0b087b13_sk b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/4d66bd3a677d620e418fdb85cbeb757a7fdea932edc5ba3672d1fd1c0b087b13_sk similarity index 100% rename from tests/network-setups/fabric/shared/network2/fabric-ca/ordererOrg/msp/keystore/4d66bd3a677d620e418fdb85cbeb757a7fdea932edc5ba3672d1fd1c0b087b13_sk rename to tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/4d66bd3a677d620e418fdb85cbeb757a7fdea932edc5ba3672d1fd1c0b087b13_sk diff --git a/tests/network-setups/fabric/shared/network2/fabric-ca/ordererOrg/msp/keystore/IssuerRevocationPrivateKey b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/IssuerRevocationPrivateKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/fabric-ca/ordererOrg/msp/keystore/IssuerRevocationPrivateKey rename to tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/IssuerRevocationPrivateKey diff --git a/tests/network-setups/fabric/shared/network2/fabric-ca/ordererOrg/msp/keystore/IssuerSecretKey b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/IssuerSecretKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/fabric-ca/ordererOrg/msp/keystore/IssuerSecretKey rename to tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/IssuerSecretKey diff --git a/tests/network-setups/fabric/shared/network2/fabric-ca/ordererOrg/msp/keystore/e29c727a5c3adda2daa247431233e6d0c2cdca9bd2a8e7f76f8365e9a96e52f8_sk b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/e29c727a5c3adda2daa247431233e6d0c2cdca9bd2a8e7f76f8365e9a96e52f8_sk similarity index 100% rename from tests/network-setups/fabric/shared/network2/fabric-ca/ordererOrg/msp/keystore/e29c727a5c3adda2daa247431233e6d0c2cdca9bd2a8e7f76f8365e9a96e52f8_sk rename to tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/e29c727a5c3adda2daa247431233e6d0c2cdca9bd2a8e7f76f8365e9a96e52f8_sk diff --git a/tests/network-setups/fabric/shared/network2/fabric-ca/ordererOrg/tls-cert.pem b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/tls-cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/fabric-ca/ordererOrg/tls-cert.pem rename to tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/tls-cert.pem diff --git a/tests/network-setups/fabric/shared/network2/fabric-ca/org1/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/IssuerPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/fabric-ca/org1/IssuerPublicKey rename to tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/IssuerPublicKey diff --git a/tests/network-setups/fabric/shared/network2/fabric-ca/org1/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/IssuerRevocationPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/fabric-ca/org1/IssuerRevocationPublicKey rename to tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/IssuerRevocationPublicKey diff --git a/tests/network-setups/fabric/shared/network2/fabric-ca/org1/ca-cert.pem b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/ca-cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/fabric-ca/org1/ca-cert.pem rename to tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/ca-cert.pem diff --git a/tests/network-setups/fabric/shared/network2/fabric-ca/org1/fabric-ca-server.db b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/fabric-ca-server.db similarity index 100% rename from tests/network-setups/fabric/shared/network2/fabric-ca/org1/fabric-ca-server.db rename to tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/fabric-ca-server.db diff --git a/tests/network-setups/fabric/shared/network2/fabric-ca/org1/msp/keystore/7d3e97c4644391d43429e1b9e781ff8a6a75f6fd974f25e9f674873feebd9ea1_sk b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/7d3e97c4644391d43429e1b9e781ff8a6a75f6fd974f25e9f674873feebd9ea1_sk similarity index 100% rename from tests/network-setups/fabric/shared/network2/fabric-ca/org1/msp/keystore/7d3e97c4644391d43429e1b9e781ff8a6a75f6fd974f25e9f674873feebd9ea1_sk rename to tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/7d3e97c4644391d43429e1b9e781ff8a6a75f6fd974f25e9f674873feebd9ea1_sk diff --git a/tests/network-setups/fabric/shared/network2/fabric-ca/org1/msp/keystore/IssuerRevocationPrivateKey b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/IssuerRevocationPrivateKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/fabric-ca/org1/msp/keystore/IssuerRevocationPrivateKey rename to tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/IssuerRevocationPrivateKey diff --git a/tests/network-setups/fabric/shared/network2/fabric-ca/org1/msp/keystore/IssuerSecretKey b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/IssuerSecretKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/fabric-ca/org1/msp/keystore/IssuerSecretKey rename to tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/IssuerSecretKey diff --git a/tests/network-setups/fabric/shared/network2/fabric-ca/org1/msp/keystore/ff63d3aee2f2cb882477e67de733e49c3aa42209717522d2307fcf37d7cecaed_sk b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/ff63d3aee2f2cb882477e67de733e49c3aa42209717522d2307fcf37d7cecaed_sk similarity index 100% rename from tests/network-setups/fabric/shared/network2/fabric-ca/org1/msp/keystore/ff63d3aee2f2cb882477e67de733e49c3aa42209717522d2307fcf37d7cecaed_sk rename to tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/ff63d3aee2f2cb882477e67de733e49c3aa42209717522d2307fcf37d7cecaed_sk diff --git a/tests/network-setups/fabric/shared/network2/fabric-ca/org1/tls-cert.pem b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/tls-cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/fabric-ca/org1/tls-cert.pem rename to tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/tls-cert.pem diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/fabric-ca-client-config.yaml b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/fabric-ca-client-config.yaml similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/fabric-ca-client-config.yaml rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/fabric-ca-client-config.yaml diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/IssuerPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/msp/IssuerPublicKey rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/IssuerPublicKey diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/IssuerRevocationPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/msp/IssuerRevocationPublicKey rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/IssuerRevocationPublicKey diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/msp/config.yaml b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/config.yaml similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/msp/config.yaml rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/config.yaml diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/msp/keystore/25ad3edad97423cb9ceba6b06b83ca7f217cd794857d1347dd27ad47f601cbe7_sk b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/keystore/25ad3edad97423cb9ceba6b06b83ca7f217cd794857d1347dd27ad47f601cbe7_sk similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/msp/keystore/25ad3edad97423cb9ceba6b06b83ca7f217cd794857d1347dd27ad47f601cbe7_sk rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/keystore/25ad3edad97423cb9ceba6b06b83ca7f217cd794857d1347dd27ad47f601cbe7_sk diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/signcerts/cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/msp/signcerts/cert.pem rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/signcerts/cert.pem diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/msp/tlscacerts/tlsca.network2.com-cert.pem b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/tlscacerts/tlsca.network2.com-cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/msp/tlscacerts/tlsca.network2.com-cert.pem rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/tlscacerts/tlsca.network2.com-cert.pem diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/IssuerPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/IssuerPublicKey rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/IssuerPublicKey diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/IssuerRevocationPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/IssuerRevocationPublicKey rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/IssuerRevocationPublicKey diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/config.yaml b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/config.yaml similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/config.yaml rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/config.yaml diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/keystore/d30db3151430ff2c370f8f40cd6e23bb09ed8f3165c7b9957c8761bd9695297f_sk b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/keystore/d30db3151430ff2c370f8f40cd6e23bb09ed8f3165c7b9957c8761bd9695297f_sk similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/keystore/d30db3151430ff2c370f8f40cd6e23bb09ed8f3165c7b9957c8761bd9695297f_sk rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/keystore/d30db3151430ff2c370f8f40cd6e23bb09ed8f3165c7b9957c8761bd9695297f_sk diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/signcerts/cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/signcerts/cert.pem rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/signcerts/cert.pem diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/tlscacerts/tlsca.network2.com-cert.pem b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/tlscacerts/tlsca.network2.com-cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/tlscacerts/tlsca.network2.com-cert.pem rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/tlscacerts/tlsca.network2.com-cert.pem diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/IssuerPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/IssuerPublicKey rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/IssuerPublicKey diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/IssuerRevocationPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/IssuerRevocationPublicKey rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/IssuerRevocationPublicKey diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/ca.crt b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/ca.crt similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/ca.crt rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/ca.crt diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/keystore/cc2fe89245d366799edfc39e8cdfa32801c8ae5fc26211ea4faff9ae6672bd35_sk b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/keystore/cc2fe89245d366799edfc39e8cdfa32801c8ae5fc26211ea4faff9ae6672bd35_sk similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/keystore/cc2fe89245d366799edfc39e8cdfa32801c8ae5fc26211ea4faff9ae6672bd35_sk rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/keystore/cc2fe89245d366799edfc39e8cdfa32801c8ae5fc26211ea4faff9ae6672bd35_sk diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/server.crt b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/server.crt similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/server.crt rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/server.crt diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/server.key b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/server.key similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/server.key rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/server.key diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/signcerts/cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/signcerts/cert.pem rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/signcerts/cert.pem diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/tlscacerts/tls-localhost-8054-ca-orderer-network2-com.pem b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/tlscacerts/tls-localhost-8054-ca-orderer-network2-com.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/tlscacerts/tls-localhost-8054-ca-orderer-network2-com.pem rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/tlscacerts/tls-localhost-8054-ca-orderer-network2-com.pem diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/IssuerPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/IssuerPublicKey rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/IssuerPublicKey diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/IssuerRevocationPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/IssuerRevocationPublicKey rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/IssuerRevocationPublicKey diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/config.yaml b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/config.yaml similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/config.yaml rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/config.yaml diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/keystore/8163fd4f80204f53f3149c20b2a005780753ee8529259598d515f6e14024fe8a_sk b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/keystore/8163fd4f80204f53f3149c20b2a005780753ee8529259598d515f6e14024fe8a_sk similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/keystore/8163fd4f80204f53f3149c20b2a005780753ee8529259598d515f6e14024fe8a_sk rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/keystore/8163fd4f80204f53f3149c20b2a005780753ee8529259598d515f6e14024fe8a_sk diff --git a/tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/signcerts/cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/signcerts/cert.pem rename to tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/signcerts/cert.pem diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/ca/ca.org1.network2.com-cert.pem b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/ca/ca.org1.network2.com-cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/ca/ca.org1.network2.com-cert.pem rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/ca/ca.org1.network2.com-cert.pem diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.docker.json b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/connection-org1.docker.json similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.docker.json rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/connection-org1.docker.json diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/connection-org1.json similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/connection-org1.json diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.yaml b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/connection-org1.yaml similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.yaml rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/connection-org1.yaml diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/fabric-ca-client-config.yaml b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/fabric-ca-client-config.yaml similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/fabric-ca-client-config.yaml rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/fabric-ca-client-config.yaml diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/msp/IssuerPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/msp/IssuerPublicKey rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/msp/IssuerPublicKey diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/msp/IssuerRevocationPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/msp/IssuerRevocationPublicKey rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/msp/IssuerRevocationPublicKey diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/msp/cacerts/localhost-5054-ca-org1-network2-com.pem b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/msp/cacerts/localhost-5054-ca-org1-network2-com.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/msp/cacerts/localhost-5054-ca-org1-network2-com.pem rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/msp/cacerts/localhost-5054-ca-org1-network2-com.pem diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/msp/config.yaml b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/msp/config.yaml similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/msp/config.yaml rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/msp/config.yaml diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/msp/keystore/3fec22439cf4be3c4f4a960276c33dd1edcbed4a5e599a116854e71eaf427e96_sk b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/msp/keystore/3fec22439cf4be3c4f4a960276c33dd1edcbed4a5e599a116854e71eaf427e96_sk similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/msp/keystore/3fec22439cf4be3c4f4a960276c33dd1edcbed4a5e599a116854e71eaf427e96_sk rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/msp/keystore/3fec22439cf4be3c4f4a960276c33dd1edcbed4a5e599a116854e71eaf427e96_sk diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/msp/signcerts/cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/msp/signcerts/cert.pem rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/msp/signcerts/cert.pem diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/msp/tlscacerts/ca.crt b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/msp/tlscacerts/ca.crt similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/msp/tlscacerts/ca.crt rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/msp/tlscacerts/ca.crt diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/IssuerPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/IssuerPublicKey rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/IssuerPublicKey diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/IssuerRevocationPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/IssuerRevocationPublicKey rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/IssuerRevocationPublicKey diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/cacerts/localhost-5054-ca-org1-network2-com.pem b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/cacerts/localhost-5054-ca-org1-network2-com.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/cacerts/localhost-5054-ca-org1-network2-com.pem rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/cacerts/localhost-5054-ca-org1-network2-com.pem diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/config.yaml b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/config.yaml similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/config.yaml rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/config.yaml diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/keystore/03bc2a06ccd3c6456e6aac3a010ac4979b258a864c5778180cc43dda00ef02ad_sk b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/keystore/03bc2a06ccd3c6456e6aac3a010ac4979b258a864c5778180cc43dda00ef02ad_sk similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/keystore/03bc2a06ccd3c6456e6aac3a010ac4979b258a864c5778180cc43dda00ef02ad_sk rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/keystore/03bc2a06ccd3c6456e6aac3a010ac4979b258a864c5778180cc43dda00ef02ad_sk diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/signcerts/cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/signcerts/cert.pem rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/signcerts/cert.pem diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/IssuerPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/IssuerPublicKey rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/IssuerPublicKey diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/IssuerRevocationPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/IssuerRevocationPublicKey rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/IssuerRevocationPublicKey diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/ca.crt b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/ca.crt similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/ca.crt rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/ca.crt diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/keystore/b921b2940a4a7cdb8dd8a4509fb0dc92a4099335a1b737e7380d5bbd5cbb57e6_sk b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/keystore/b921b2940a4a7cdb8dd8a4509fb0dc92a4099335a1b737e7380d5bbd5cbb57e6_sk similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/keystore/b921b2940a4a7cdb8dd8a4509fb0dc92a4099335a1b737e7380d5bbd5cbb57e6_sk rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/keystore/b921b2940a4a7cdb8dd8a4509fb0dc92a4099335a1b737e7380d5bbd5cbb57e6_sk diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/server.crt b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/server.crt similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/server.crt rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/server.crt diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/server.key b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/server.key similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/server.key rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/server.key diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/signcerts/cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/signcerts/cert.pem rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/signcerts/cert.pem diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/tlscacerts/tls-localhost-5054-ca-org1-network2-com.pem b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/tlscacerts/tls-localhost-5054-ca-org1-network2-com.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/tlscacerts/tls-localhost-5054-ca-org1-network2-com.pem rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/tlscacerts/tls-localhost-5054-ca-org1-network2-com.pem diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/tlsca/tlsca.org1.network2.com-cert.pem b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/tlsca/tlsca.org1.network2.com-cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/tlsca/tlsca.org1.network2.com-cert.pem rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/tlsca/tlsca.org1.network2.com-cert.pem diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/IssuerPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/IssuerPublicKey rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/IssuerPublicKey diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/IssuerRevocationPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/IssuerRevocationPublicKey rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/IssuerRevocationPublicKey diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/cacerts/localhost-5054-ca-org1-network2-com.pem b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/cacerts/localhost-5054-ca-org1-network2-com.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/cacerts/localhost-5054-ca-org1-network2-com.pem rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/cacerts/localhost-5054-ca-org1-network2-com.pem diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/config.yaml b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/config.yaml similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/config.yaml rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/config.yaml diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/keystore/05e000f93c5285fb535f2d8d208949aeb68fd089dec6d386f21ff361eccc2072_sk b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/keystore/05e000f93c5285fb535f2d8d208949aeb68fd089dec6d386f21ff361eccc2072_sk similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/keystore/05e000f93c5285fb535f2d8d208949aeb68fd089dec6d386f21ff361eccc2072_sk rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/keystore/05e000f93c5285fb535f2d8d208949aeb68fd089dec6d386f21ff361eccc2072_sk diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/signcerts/cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/signcerts/cert.pem rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/signcerts/cert.pem diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/IssuerPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/IssuerPublicKey rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/IssuerPublicKey diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/IssuerRevocationPublicKey similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/IssuerRevocationPublicKey rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/IssuerRevocationPublicKey diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/cacerts/localhost-5054-ca-org1-network2-com.pem b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/cacerts/localhost-5054-ca-org1-network2-com.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/cacerts/localhost-5054-ca-org1-network2-com.pem rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/cacerts/localhost-5054-ca-org1-network2-com.pem diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/keystore/0e6057bbf43121b51abad6a86682540ecb8ff59924b569c0dca624b478025f3d_sk b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/keystore/0e6057bbf43121b51abad6a86682540ecb8ff59924b569c0dca624b478025f3d_sk similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/keystore/0e6057bbf43121b51abad6a86682540ecb8ff59924b569c0dca624b478025f3d_sk rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/keystore/0e6057bbf43121b51abad6a86682540ecb8ff59924b569c0dca624b478025f3d_sk diff --git a/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/signcerts/cert.pem similarity index 100% rename from tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/signcerts/cert.pem rename to tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/signcerts/cert.pem diff --git a/tests/network-setups/fabric/shared/network2/system-genesis-block/genesis.block b/tests/network-setups/fabric/network-artifacts/network2/system-genesis-block/genesis.block similarity index 100% rename from tests/network-setups/fabric/shared/network2/system-genesis-block/genesis.block rename to tests/network-setups/fabric/network-artifacts/network2/system-genesis-block/genesis.block diff --git a/tests/network-setups/fabric/shared/network2/wallet/user1.id b/tests/network-setups/fabric/network-artifacts/network2/wallet/user1.id similarity index 100% rename from tests/network-setups/fabric/shared/network2/wallet/user1.id rename to tests/network-setups/fabric/network-artifacts/network2/wallet/user1.id From a240a56131d1b0875deb4dd75a2be319c2508109 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Wed, 6 Jul 2022 09:22:23 +0530 Subject: [PATCH 011/150] update fabric/dev Makefile clean command Signed-off-by: sandeep.nishad1 --- tests/network-setups/fabric/dev/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/network-setups/fabric/dev/Makefile b/tests/network-setups/fabric/dev/Makefile index e17f59c69..f5c855e6a 100644 --- a/tests/network-setups/fabric/dev/Makefile +++ b/tests/network-setups/fabric/dev/Makefile @@ -127,7 +127,7 @@ remove-network2: rm -rf ../shared/network2/wallet/*.id .PHONY: clean -clean: stop remove +clean: remove +rm -rf bin || true +rm -rf config || true +rm .fabric-setup || true From e92ebc0e1f5af93a10195e9548cf311f30fda35b Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Wed, 6 Jul 2022 09:25:57 +0530 Subject: [PATCH 012/150] revert github workflow fabric pkgs Signed-off-by: sandeep.nishad1 --- .github/workflows/deploy_fabric-pkgs.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/deploy_fabric-pkgs.yml b/.github/workflows/deploy_fabric-pkgs.yml index 66165815e..ac2d7b204 100644 --- a/.github/workflows/deploy_fabric-pkgs.yml +++ b/.github/workflows/deploy_fabric-pkgs.yml @@ -14,7 +14,7 @@ on: jobs: publish-protos: - if: github.repository_owner == 'sanvenDev' + if: github.repository_owner == 'hyperledger-labs' runs-on: ubuntu-latest steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it @@ -33,7 +33,7 @@ jobs: - name: Generate .npmrc run: | cp .npmrc.template .npmrc - #sed -i "s//${{ secrets.GITHUB_TOKEN }}/g" .npmrc + sed -i "s//${{ secrets.GITHUB_TOKEN }}/g" .npmrc cat .npmrc working-directory: common/protos-js @@ -48,7 +48,7 @@ jobs: working-directory: common/protos-js publish-sdk: - if: ${{ always() && github.repository_owner == 'sanvenDev' }} + if: github.repository_owner == 'hyperledger-labs' needs: [publish-protos] runs-on: ubuntu-latest steps: @@ -63,7 +63,7 @@ jobs: - name: Generate .npmrc run: | cp .npmrc.template .npmrc - #sed -i "s//${{ secrets.GITHUB_TOKEN }}/g" .npmrc + sed -i "s//${{ secrets.GITHUB_TOKEN }}/g" .npmrc cat .npmrc working-directory: sdks/fabric/interoperation-node-sdk @@ -76,7 +76,7 @@ jobs: working-directory: sdks/fabric/interoperation-node-sdk publish-driver: - if: ${{ always() && github.repository_owner == 'sanvenDev' }} + if: github.repository_owner == 'hyperledger-labs' needs: [publish-protos] runs-on: ubuntu-latest steps: @@ -93,7 +93,7 @@ jobs: - name: Generate .npmrc run: | cp .npmrc.template .npmrc - #sed -i "s//${{ secrets.GITHUB_TOKEN }}/g" .npmrc + sed -i "s//${{ secrets.GITHUB_TOKEN }}/g" .npmrc cat .npmrc working-directory: core/drivers/fabric-driver From 31203308a8cab81b41219a00c057e1616e87bb22 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Wed, 6 Jul 2022 20:02:55 +0530 Subject: [PATCH 013/150] Protos updated for event subscription Signed-off-by: sandeep.nishad1 --- common/protos/common/events.proto | 3 ++- common/protos/relay/events.proto | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/common/protos/common/events.proto b/common/protos/common/events.proto index 6c69c0646..b7cdac80a 100644 --- a/common/protos/common/events.proto +++ b/common/protos/common/events.proto @@ -15,7 +15,8 @@ enum EventType { message EventMatcher { EventType type = 1; - string transaction_func = 2; + string event_name = 2; + string transaction_func = 3; } message EventSubscription { EventMatcher eventMatcher = 1; diff --git a/common/protos/relay/events.proto b/common/protos/relay/events.proto index 2373a831f..8216e4655 100644 --- a/common/protos/relay/events.proto +++ b/common/protos/relay/events.proto @@ -14,4 +14,7 @@ service EventSubscribe { // Src-relay based upon query (EventSubscription) forwards the same response (Ack) // from driver to the dest-relay by calling a new endpoint in dest-relay rpc SendSubscriptionStatus(common.ack.Ack) returns (common.ack.Ack) {} + // Src-driver status of event subscription (Ack) + // to the src-relay by calling a new endpoint in src-relay + rpc SendDriverSubscriptionStatus(common.ack.Ack) returns (common.ack.Ack) {} } From 9cb08b3d5264d9a6d72899b6421a7537dc0a304f Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Wed, 6 Jul 2022 20:03:45 +0530 Subject: [PATCH 014/150] Event subscription service APIs added to relay for both source and destination mode Signed-off-by: sandeep.nishad1 --- core/relay/Cargo.lock | 2 +- core/relay/Cargo.toml | 4 +- core/relay/config/Dummy_Relay.toml | 20 + core/relay/driver/driver.rs | 54 ++- core/relay/src/client.rs | 89 ++++- .../src/services/event_subscribe_service.rs | 351 +++++++++++++++++- core/relay/src/services/helpers.rs | 41 ++ core/relay/src/services/mod.rs | 1 + core/relay/src/services/network_service.rs | 230 +++++++++++- 9 files changed, 782 insertions(+), 10 deletions(-) create mode 100644 core/relay/src/services/helpers.rs diff --git a/core/relay/Cargo.lock b/core/relay/Cargo.lock index a4947ace3..8a017fe6b 100644 --- a/core/relay/Cargo.lock +++ b/core/relay/Cargo.lock @@ -882,7 +882,7 @@ checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" [[package]] name = "relay" -version = "0.0.1" +version = "1.4.0" dependencies = [ "base64 0.13.0", "bincode", diff --git a/core/relay/Cargo.toml b/core/relay/Cargo.toml index acb3e0289..3ed05c5e3 100644 --- a/core/relay/Cargo.toml +++ b/core/relay/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "relay" -version = "0.0.1" -authors = ["Antony Targett ", "Nick Waywood "] +version = "1.4.0" +authors = ["Antony Targett ", "Nick Waywood ", "Sandeep Nishad ) -> Result, Status> { - Err(tonic::Status::unimplemented("method not implemented")) + println!("Driver: Got a event subscription request from {:?}", request.remote_addr()); + let into_inner = request.into_inner().clone(); + let query = into_inner.query.clone().expect(""); + let request_id = query.clone().request_id.to_string(); + + let relay_port = self + .config_lock + .read() + .await + .get_str("port") + .expect("Port table does not exist"); + let relay_hostname = self + .config_lock + .read() + .await + .get_str("hostname") + .expect("Hostname table does not exist"); + let client_addr = format!("http://{}:{}", relay_hostname, relay_port); + println!("Remote relay... {:?}", client_addr.clone()); + let client_result = + relay::events::event_subscribe_client::EventSubscribeClient::connect(client_addr) + .await; + match client_result { + Ok(client) => { + // Sends Mocked payload back. + tokio::spawn(async move { + let my_time = time::Duration::from_millis(3000); + sleep(my_time); + let ack = Ack { + status: ack::Status::Ok as i32, + request_id: request_id, + message: "".to_string(), + }; + println!("Sending ack to remote relay... {:?}", ack.clone()); + let response = client.clone().send_driver_subscription_status(ack).await; + println!("Ack from remote relay={:?}", response); + }); + } + Err(e) => { + // TODO: Add better error handling (Attempt a few times?) + panic!("Failed to connect to client. Error: {}", e.to_string()); + } + } + + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: query.clone().request_id.to_string(), + message: "".to_string(), + }; + + return Ok(Response::new(reply)); } } diff --git a/core/relay/src/client.rs b/core/relay/src/client.rs index 5513cdd6b..04ec38591 100644 --- a/core/relay/src/client.rs +++ b/core/relay/src/client.rs @@ -3,7 +3,8 @@ mod relay_proto; use futures::future::{BoxFuture, FutureExt}; use pb::common::ack::ack; use pb::common::state::request_state; -use pb::networks::networks::{network_client::NetworkClient, GetStateMessage, NetworkQuery}; +use pb::common::events::{event_subscription_state, EventType, EventMatcher, EventPublication, event_publication}; +use pb::networks::networks::{network_client::NetworkClient, GetStateMessage, NetworkQuery, NetworkEventSubscription}; use relay_proto::get_url; use std::env; use std::thread::sleep; @@ -11,6 +12,12 @@ use std::time; #[tokio::main] async fn main() -> Result<(), Box> { + datasharing().await?; + event_suscribe().await?; + Ok(()) +} + +async fn datasharing() -> Result<(), Box> { let args: Vec = env::args().collect(); let net_addr = format!("http://{}", get_url(&args)); let mut network_client = NetworkClient::connect(net_addr).await?; @@ -35,7 +42,7 @@ async fn main() -> Result<(), Box> { Some(ack_status) => match ack_status { ack::Status::Ok => { poll_for_state(request_id.to_string(), network_client).await; - println!("Success!"); + println!("Data Sharing: Success!"); } ack::Status::Error => println!("An error occurred in request_state call"), }, @@ -71,3 +78,81 @@ fn poll_for_state( } .boxed() } + + +async fn event_suscribe() -> Result<(), Box> { + let args: Vec = env::args().collect(); + let net_addr = format!("http://{}", get_url(&args)); + let mut network_client = NetworkClient::connect(net_addr).await?; + // localhost:9081/Corda_Network/test + // {locationsegment}/{Network_id}/{query} + // localhost:9081/Corda_Network/mychannel:simplestate:read:TestState + let network_query = NetworkQuery { + policy: vec!["test".to_string()], + address: args[2].to_string(), + requesting_relay: "".to_string(), + requesting_network: "".to_string(), + requesting_org: "".to_string(), + certificate: "test".to_string(), + requestor_signature: "test".to_string(), + nonce: "test".to_string(), + confidential: false, + }; + let event_matcher = EventMatcher { + r#type: 0, + event_name: "test".to_string(), + transaction_func: "test".to_string(), + }; + let tmp = event_publication::PublicationTarget::AppUrl("abc".to_string()); + let event_publication_spec = EventPublication { + publication_target: std::option::Option::Some(tmp), + }; + let request = tonic::Request::new(NetworkEventSubscription { + event_matcher: std::option::Option::Some(event_matcher), + query: std::option::Option::Some(network_query), + event_publication_spec: std::option::Option::Some(event_publication_spec), + }); + let response = network_client.subscribe_event(request).await?; + println!("RESPONSE={:?}", response); + let request_id = &response.get_ref().request_id; + match ack::Status::from_i32(response.get_ref().status) { + Some(ack_status) => match ack_status { + ack::Status::Ok => { + poll_for_event_subscription(request_id.to_string(), network_client).await; + println!("Event Subscription: Success!"); + } + ack::Status::Error => println!("An error occurred in suscribe_event call"), + }, + None => println!("The returned Ack has no status"), + } + Ok(()) +} + +fn poll_for_event_subscription( + request_id: String, + mut network_client: NetworkClient, +) -> BoxFuture<'static, ()> { + async move { + sleep(time::Duration::from_millis(2000)); + let request = tonic::Request::new(GetStateMessage { + request_id: request_id.to_string(), + }); + let result = network_client.get_event_subscription_state(request).await; + match result { + Ok(response) => { + println!("Get Event Subscription State response: {:?}", response); + match event_subscription_state::Status::from_i32(response.get_ref().status) { + Some(request_status) => { + if request_status == event_subscription_state::Status::Pending { + poll_for_event_subscription(request_id, network_client).await; + } + } + None => println!("No status returned from get state request"), + }; + } + Err(error) => println!("Error getting state response"), + } + } + .boxed() +} + diff --git a/core/relay/src/services/event_subscribe_service.rs b/core/relay/src/services/event_subscribe_service.rs index f982d606b..74e95f198 100644 --- a/core/relay/src/services/event_subscribe_service.rs +++ b/core/relay/src/services/event_subscribe_service.rs @@ -1,13 +1,16 @@ // Internal generated modules use crate::pb::common::ack::{ack, Ack}; +use crate::pb::common::query::Query; use crate::pb::common::events::EventSubscription; use crate::pb::driver::driver::driver_communication_client::DriverCommunicationClient; use crate::pb::relay::events::event_subscribe_client::EventSubscribeClient; use crate::pb::relay::events::event_subscribe_server::EventSubscribe; +use crate::pb::common::events::{event_subscription_state, EventSubscriptionState}; // Internal modules use crate::db::Database; use crate::error::Error; use crate::relay_proto::{parse_address, LocationSegment}; +use crate::services::helpers::update_event_subscription_status; // external modules use config; use serde; @@ -38,10 +41,354 @@ pub struct Network { #[tonic::async_trait] impl EventSubscribe for EventSubscribeService { async fn subscribe_event(&self, request: Request) -> Result, Status> { - Err(tonic::Status::unimplemented("method not implemented")) + println!( + "Got a Event Subscription request from {:?} - {:?}", + request.remote_addr(), + request + ); + let event_subscription = request.into_inner().clone(); + let query = event_subscription.query.clone().expect("No query passed with EventSubscription request"); + let request_id = query.request_id.to_string(); + + let conf = self.config_lock.read().await; + // Database access/storage + let remote_db = Database { + db_path: conf.get_str("remote_db_path").unwrap(), + }; + match subscribe_event_helper(remote_db, request_id.to_string(), event_subscription, query, conf.clone()) { + Ok(ack) => { + let reply = Ok(Response::new(ack)); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + println!("EventSubscription from Driver failed."); + let reply = Ok(Response::new(Ack { + status: ack::Status::Error as i32, + request_id, + message: format!("Error: EventSubscription from Driver failed. {:?}", e), + })); + println!("Sending back Ack: {:?}\n", reply); + reply + } + } + } + + /// send_driver_subscription_status is run on the remote relay. Run when the driver sends the ack back to the remote relay + async fn send_driver_subscription_status( + &self, + request: Request, + ) -> Result, Status> { + let ack = request.into_inner().clone(); + let ack_clone = ack.clone(); + println!("Received Ack from driver: {:?}", ack_clone.request_id); + + let request_id = ack.request_id.to_string(); + let conf = self.config_lock.read().await; + // Database access/storage + let remote_db = Database { + db_path: conf.get_str("remote_db_path").unwrap(), + }; + + let result = + send_driver_subscription_status_helper(request_id.to_string(), remote_db, conf.clone(), ack); + match result { + Ok(resp) => { + let reply = Ok(resp); + println!("Sending back Ack to driver: {:?}\n", reply); + return reply; + } + Err(e) => { + // NOTE: No way to send another ack to Relay, if it reaches this error the next will also error. + let reply = Ok(Response::new(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: {:?}", e), + })); + println!("Sending back Ack to driver: {:?}\n", reply); + return reply; + } + } } async fn send_subscription_status(&self, request: Request) -> Result, Status> { - Err(tonic::Status::unimplemented("method not implemented")) + let request_ack = request.into_inner().clone(); + println!( + "Received Ack from remote relay for Event Subscription Request ID = {:?}", + request_ack.request_id + ); + let request_id = &request_ack.request_id.to_string(); + let conf = self.config_lock.read().await.clone(); + // Database access/storage + let db_path = conf.get_str("db_path").unwrap(); + + let result = send_subscription_status_helper(request_ack, request_id.clone().to_string(), db_path); + + match result { + Ok(_) => println!("Successfully set event subscription status in DB."), + Err(e) => println!("Setting value in DB failed: {:?}", e), + } + let reply = Ok(Response::new(Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "".to_string(), + })); + println!("Sending back Ack to remote relay: {:?}", reply); + reply + } + +} + + +/// request_state is run on the remote relay to retrieve the state that was +/// requested from the requesting relay +fn subscribe_event_helper( + remote_db: Database, + request_id: String, + event_subscription: EventSubscription, + query: Query, + conf: config::Config, +) -> Result { + let _set_query = remote_db + .set(&request_id.to_string(), &query) + .map_err(|e| Error::Simple(format!("DB Failure: {:?}", e)))?; + let parsed_address = parse_address(query.address.to_string())?; + // get the driver type from the networks map + let networks_table = conf + .get_table("networks") + .map_err(|e| Error::Simple(format!("Unable to find networks table. Error: {:?}", e)))?; + let network_table = networks_table + .get::(&parsed_address.network_id.to_string()) + .ok_or(Error::Simple(format!( + "Unable to find Network_id \"{}\" in config", + parsed_address.network_id.to_string() + )))?; + let network_type = network_table + .clone() + .try_into::() + .expect("Error in config file networks table") + .clone(); + // get the driver host:port from the drivers map + let drivers_table = conf + .get_table("drivers") + .map_err(|e| Error::Simple(format!("Unable to find driver table. Error: {:?}", e)))?; + let driver_table = drivers_table + .get::(&network_type.network) + .ok_or(Error::Simple(format!( + "Unable to find driver port for network: {}", + parsed_address.network_id.to_string() + )))?; + let driver_info = driver_table + .clone() + .try_into::() + .expect("Error in config file drivers table") + .clone(); + let port = driver_info.port.to_string(); + let hostname = driver_info.hostname.to_string(); + let tls = driver_info.tls; + let tlsca_cert_path = driver_info.tlsca_cert_path.to_string(); + spawn_driver_subscribe_event(event_subscription, hostname, port, tls, tlsca_cert_path, conf.clone()); + return Ok(Ack { + status: ack::Status::Ok as i32, + request_id, + message: "".to_string(), + }); +} + +// Function that starts a thread which sends the query information to the driver +fn spawn_driver_subscribe_event(event_subscription: EventSubscription, hostname: String, port: String, use_tls: bool, tlsca_cert_path: String, conf: config::Config) { + tokio::spawn(async move { + let result = spawn_driver_subscribe_event_helper(event_subscription.clone(), hostname, port, use_tls, tlsca_cert_path).await; + match result { + Ok(_) => { + // Do nothing + println!("Ack Ok from driver\n") + } + Err(e) => { + println!("Error sending event subscription request to driver: {:?}\n", e); + // In Error case we send an error_state to requesting relay. + let query = event_subscription.query.clone().expect("No query passed with EventSubscription request"); + let request_id = query.request_id.to_string(); + // Database access/storage + let remote_db = Database { + db_path: conf.get_str("remote_db_path").unwrap(), + }; + let error_ack = Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Driver Error: {:?}", e), + }; + let result = send_driver_subscription_status_helper( + request_id.to_string(), + remote_db, + conf.clone(), + error_ack, + ); + match result { + Ok(_) => { + println!( + "Driver's subscribe_event error successfully sent back to requesting relay" + ); + } + Err(e) => println!("Error sending Ack: {:?}", e), + } + } + } + }); +} + +async fn spawn_driver_subscribe_event_helper( + event_subscription: EventSubscription, + hostname: String, + port: String, + use_tls: bool, + tlsca_cert_path: String, +) -> Result<(), Error> { + let driver_address = format!("http://{}:{}", hostname, port); + let client; + if use_tls { + let pem = tokio::fs::read(tlsca_cert_path).await?; + let ca = Certificate::from_pem(pem); + + let tls = ClientTlsConfig::new() + .ca_certificate(ca) + .domain_name(hostname); + + let channel = Channel::from_shared(driver_address).unwrap() + .tls_config(tls) + .connect() + .await + .unwrap(); + + client = DriverCommunicationClient::new(channel); + } else { + client = DriverCommunicationClient::connect(driver_address).await?; + } + println!("Sending EventSubscription Request to driver: {:?}", event_subscription.clone()); + let ack = client + .clone() + .subscribe_event(event_subscription) + .await? + .into_inner(); + println!("Response ACK from driver={:?}\n", ack); + let status = ack::Status::from_i32(ack.status) + .ok_or(Error::Simple("Status from Driver error".to_string()))?; + match status { + ack::Status::Ok => { + // Do nothing + return Ok(()); + } + ack::Status::Error => Err(Error::Simple(format!("Error from driver: {}", ack.message))), } +} + + +/// send_driver_subscription_status is run on the remote relay. Runs when the driver sends the +/// ack back to the remote relay or if there was an error making the +/// suscribe_event gRPC call. +fn send_driver_subscription_status_helper( + request_id: String, + remote_db: Database, + conf: config::Config, + ack: Ack, +) -> Result, Error> { + let query: Query = remote_db + .get::(request_id.to_string()) + .map_err(|err| Error::GetQuery(format!("Failed to get query from db. Error: {:?}", err)))?; + let relays_table = conf.get_table("relays")?; + let relay_uri = relays_table + .get(&query.requesting_relay.to_string()) + .ok_or(Error::Simple("Relay name not found".to_string()))?; + let uri = relay_uri.clone().try_into::()?; + spawn_send_subscription_status( + ack, + uri.hostname.to_string(), + uri.port.to_string(), + uri.tls, + uri.tlsca_cert_path.to_string(), + ); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id, + message: "".to_string(), + }; + + return Ok(Response::new(reply)); +} + + +// spawn_send_subscription_status sends event subscription status from the remote relay back +// to the requesting relay. +// When it errors it currently logs to console. Needs improving +fn spawn_send_subscription_status(ack: Ack, requestor_host: String, requester_port: String, use_tls: bool, tlsca_cert_path: String) { + tokio::spawn(async move { + println!("Sending Subscription Status back to requesting relay: Request ID = {:?}", ack.request_id); + let client_addr = format!("http://{}:{}", requestor_host, requester_port); + if use_tls { + let pem = tokio::fs::read(tlsca_cert_path).await.unwrap(); + let ca = Certificate::from_pem(pem); + + let tls = ClientTlsConfig::new() + .ca_certificate(ca) + .domain_name(requestor_host); + + let channel = Channel::from_shared(client_addr).unwrap() + .tls_config(tls) + .connect() + .await + .unwrap(); + + let mut client_result = EventSubscribeClient::new(channel); + let response = client_result.send_subscription_status(ack).await; + println!("Response ACK from requesting relay={:?}\n", response); + } else { + let client_result = EventSubscribeClient::connect(client_addr).await; + match client_result { + Ok(client) => { + let response = client.clone().send_subscription_status(ack).await; + println!("Response ACK from requesting relay={:?}\n", response); + // Not returning anything here + } + Err(e) => { + // TODO: Add better error handling (Attempt a few times?) + println!( + "Failed to connect to client: ${:?}. Error: {}\n", + requester_port, + e.to_string() + ); + // TODO: Handle this error thorugh join handle after thread completes. + // Not actually returning anything here yet + } + } + } + }); +} +fn send_subscription_status_helper( + request_ack: Ack, + request_id: String, + db_path: String, +) -> Result<(), Error> { + match ack::Status::from_i32(request_ack.status) { + Some(status) => match status { + ack::Status::Ok => update_event_subscription_status( + request_id.to_string(), + event_subscription_state::Status::Success, + db_path.to_string(), + "".to_string(), + ), + ack::Status::Error => update_event_subscription_status( + request_id.to_string(), + event_subscription_state::Status::Error, + db_path.to_string(), + request_ack.message.to_string(), + ), + }, + None => update_event_subscription_status( + request_id.to_string(), + event_subscription_state::Status::Error, + db_path.to_string(), + "Status is not supported or is invalid".to_string(), + ), + }; + return Ok(()); } \ No newline at end of file diff --git a/core/relay/src/services/helpers.rs b/core/relay/src/services/helpers.rs new file mode 100644 index 000000000..8e02ead5f --- /dev/null +++ b/core/relay/src/services/helpers.rs @@ -0,0 +1,41 @@ +use crate::pb::common::events::{event_subscription_state, EventSubscriptionState}; +use crate::db::Database; + +// Locally scoped function to update request status in db. This function is +// called for the first time after an Ack is received from the remote relay. +// A locally created EventSubscriptionState with status PENDING or ERROR is stored. +// When a response is received from the remote relay it will write the +// returned EventSubscriptionState with status SUCCESS or ERROR. +pub fn update_event_subscription_status( + curr_request_id: String, + new_status: event_subscription_state::Status, + curr_db_path: String, + message: String, +) { + let db = Database { + db_path: curr_db_path, + }; + let result = db.get::(curr_request_id.clone()); + match result { + Ok(event_subscription_state) => { + + let target: EventSubscriptionState = EventSubscriptionState { + status: new_status as i32, + request_id: curr_request_id.clone(), + message: message.to_string(), + event_matcher: event_subscription_state.event_matcher.clone(), + event_publication_spec: event_subscription_state.event_publication_spec.clone(), + }; + + // Panic if this fails, atm the panic is just logged by the tokio runtime + db.set(&curr_request_id, &target) + .expect("Failed to insert into DB"); + println!("Successfully written EventSubscriptionState to database"); + println!("{:?}\n", db.get::(curr_request_id).unwrap()) + + }, + Err(e) => { + println!("EventSubscription Request not found. Error: {:?}", e); + }, + } +} \ No newline at end of file diff --git a/core/relay/src/services/mod.rs b/core/relay/src/services/mod.rs index 11bcbce30..a28cabe03 100644 --- a/core/relay/src/services/mod.rs +++ b/core/relay/src/services/mod.rs @@ -1,3 +1,4 @@ pub mod data_transfer_service; pub mod network_service; pub mod event_subscribe_service; +pub mod helpers; diff --git a/core/relay/src/services/network_service.rs b/core/relay/src/services/network_service.rs index 32655d27f..912534a74 100644 --- a/core/relay/src/services/network_service.rs +++ b/core/relay/src/services/network_service.rs @@ -1,12 +1,15 @@ // Internal generated modules use crate::pb::common::ack::{ack, Ack}; use crate::pb::common::query::Query; +use crate::pb::common::events::EventSubscription; use crate::pb::common::state::{request_state, RequestState}; use crate::pb::common::events::{event_subscription_state, EventSubscriptionState}; use crate::pb::networks::networks::network_server::Network; use crate::pb::networks::networks::{DbName, GetStateMessage, NetworkQuery, RelayDatabase, NetworkEventSubscription}; use crate::pb::relay::datatransfer::data_transfer_client::DataTransferClient; +use crate::pb::relay::events::event_subscribe_client::EventSubscribeClient; use crate::relay_proto::{parse_address, LocationSegment}; +use crate::services::helpers::update_event_subscription_status; // Internal modules use crate::db::Database; @@ -168,13 +171,109 @@ impl Network for NetworkService { // Subscribe Event Endpoints async fn subscribe_event(&self, request: Request) -> Result, Status> { - Err(tonic::Status::unimplemented("method not implemented")) + println!( + "Got a Network Event Subscription request from {:?} - {:?}", + request.remote_addr(), + request + ); + let conf = self.config_lock.read().await.clone(); + // Database access/storage + let db = Database { + db_path: conf.get_str("db_path").unwrap(), + }; + + let request_id = Uuid::new_v4(); + let network_event_subscription = request.into_inner().clone(); + + // Initial request state stored in DB. + let target: EventSubscriptionState = EventSubscriptionState { + status: event_subscription_state::Status::PendingAck as i32, + request_id: request_id.to_string(), + message: "".to_string(), + event_matcher: network_event_subscription.event_matcher.clone(), + event_publication_spec: network_event_subscription.event_publication_spec.clone() + }; + let message_insert = db.set(&request_id.to_string(), &target); + // Kept this as a match as the error case returns an Ok. + match message_insert { + Ok(_) => println!( + "Successfully stored NetworkEventSubscription in db with request_id: {}", + request_id.to_string() + ), + Err(e) => { + // Internal failure of sled. Send Error response + println!( + "Error storing NetworkEventSubscription in db for request_id: {}", + request_id.to_string() + ); + let reply = Ok(Response::new(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("{:?}", e), + })); + println!("Sending Ack back to network: {:?}\n", reply); + return reply; + } + } + + let network_query = network_event_subscription.query.clone().expect("No query passed with NetworkEventSubscription request"); + let parsed_address = parse_address(network_query.address.to_string()); + match parsed_address { + Ok(address) => { + // TODO: verify that host and port are valid + // Spawns a child process to handle sending request + spawn_send_event_subscription_request( + conf, + network_event_subscription, + request_id.to_string(), + address.location.hostname.to_string(), + address.location.port.to_string() + ); + // Send Ack back to network while request is happening in a thread + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "".to_string(), + }; + println!("Sending Ack back to network: {:?}\n", reply); + Ok(Response::new(reply)) + } + Err(e) => { + println!("Invalid Address"); + let reply = Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: {:?}", e), + }; + println!("Sending Ack back to network: {:?}\n", reply); + Ok(Response::new(reply)) + } + } } async fn get_event_subscription_state( &self, request: Request, ) -> Result, Status> { - Err(tonic::Status::unimplemented("method not implemented")) + println!("\nReceived GetEventSubscriptionState request from network: {:?}", request); + let conf = self.config_lock.read().await.clone(); + let db = Database { + db_path: conf.get_str("db_path").unwrap(), + }; + let result = db.get::(request.into_inner().request_id); + match result { + Ok(event_subscription_state) => { + println!("Sending back EventSubscriptionState to network: Request ID = {:?}, Status = {:?}", + event_subscription_state.request_id, + event_subscription_state.status + ); + + return Ok(Response::new(event_subscription_state)); + }, + Err(e) => Err(Status::new( + Code::NotFound, + format!("Event Subscription Request not found. Error: {:?}", e), + )), + } } } @@ -327,3 +426,130 @@ async fn data_transfer_call( let response = client.request_state(query_request).await?; Ok(response) } + +// Sends a request to the remote relay +fn spawn_send_event_subscription_request( + conf: config::Config, + network_event_subscription: NetworkEventSubscription, + request_id: String, + relay_host: String, + relay_port: String, +) { + println!("Sending EventSubscription to remote relay: {:?}:{:?}", relay_host, relay_port); + + // Spawning new thread to make the subscribe_event_call to remote relay + tokio::spawn(async move { + let db_path = conf.get_str("db_path").unwrap(); + + // Iterate through the relay entries in the configuration to find a match + let relays_table = conf.get_table("relays").unwrap(); + let mut relay_tls = false; + let mut relay_tlsca_cert_path = "".to_string(); + for (_relay_name, relay_spec) in relays_table { + let relay_uri = relay_spec.clone().try_into::().unwrap(); + if relay_host == relay_uri.hostname && relay_port == relay_uri.port { + relay_tls = relay_uri.tls; + relay_tlsca_cert_path = relay_uri.tlsca_cert_path; + } + } + + let result = suscribe_event_call( + conf.get_str("name").unwrap(), + relay_host, + relay_port, + network_event_subscription, + request_id.clone(), + relay_tls, + relay_tlsca_cert_path.to_string(), + ) + .await; + println!("Received Ack from remote relay: {:?}\n", result); + // Potentially clean up when more skilled at Rust. + // Updates the request in the DB depending on the response status from the remote relay + match result { + Ok(ack_response) => { + let ack_response_into_inner = ack_response.into_inner().clone(); + // This match first checks if the status is valid. + match ack::Status::from_i32(ack_response_into_inner.status) { + Some(status) => match status { + ack::Status::Ok => update_event_subscription_status( + request_id.to_string(), + event_subscription_state::Status::Pending, + db_path.to_string(), + "".to_string(), + ), + ack::Status::Error => update_event_subscription_status( + request_id.to_string(), + event_subscription_state::Status::Error, + db_path.to_string(), + ack_response_into_inner.message.to_string(), + ), + }, + None => update_event_subscription_status( + request_id.to_string(), + event_subscription_state::Status::Error, + db_path.to_string(), + "Status is not supported or is invalid".to_string(), + ), + } + } + Err(result_error) => update_event_subscription_status( + request_id.to_string(), + event_subscription_state::Status::Error, + db_path.to_string(), + format!("{:?}", result_error).to_string(), + ), + } + }); +} +// // Call to remote relay for the event subscription protocol. +async fn suscribe_event_call( + relay_name: String, + relay_host: String, + relay_port: String, + network_event_subscription: NetworkEventSubscription, + request_id: String, + use_tls: bool, + tlsca_cert_path: String, +) -> Result, Box> { + let client_addr = format!("http://{}:{}", relay_host, relay_port); + let mut client; + if use_tls { + let pem = tokio::fs::read(tlsca_cert_path).await?; + let ca = Certificate::from_pem(pem); + + let tls = ClientTlsConfig::new() + .ca_certificate(ca) + .domain_name(relay_host); + + let channel = Channel::from_shared(client_addr)? + .tls_config(tls) + .connect() + .await?; + + client = EventSubscribeClient::new(channel); + } else { + client = EventSubscribeClient::connect(client_addr).await?; + } + + let network_query = network_event_subscription.query.clone().expect("No query passed with NetworkEventSubscription request"); + let query: Query = Query { + policy: network_query.policy, + address: network_query.address, + requesting_relay: relay_name, + requesting_org: network_query.requesting_org, + requesting_network: network_query.requesting_network, + certificate: network_query.certificate, + requestor_signature: network_query.requestor_signature, + nonce: network_query.nonce, + request_id: request_id.to_string(), + confidential: network_query.confidential, + }; + let event_subscription_request = tonic::Request::new(EventSubscription { + event_matcher: network_event_subscription.event_matcher, + query: Some(query), + }); + println!("EventSubscription: {:?}", event_subscription_request); + let response = client.subscribe_event(event_subscription_request).await?; + Ok(response) +} From e0f95959b62ed0aa7083d8444cf6f345f12b72c8 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Wed, 6 Jul 2022 22:21:14 +0530 Subject: [PATCH 015/150] Relay docker version upgrade to 1.4.0; added relay test workflow Signed-off-by: sandeep.nishad1 --- .github/workflows/test_relay.yml | 49 ++++++++++++++++++++++++++++ core/relay/Makefile.variables.docker | 2 +- 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/test_relay.yml diff --git a/.github/workflows/test_relay.yml b/.github/workflows/test_relay.yml new file mode 100644 index 000000000..b36d7d1c3 --- /dev/null +++ b/.github/workflows/test_relay.yml @@ -0,0 +1,49 @@ +name: Unit Test Relay + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + relay: + # if: ${{ false }} + runs-on: ubuntu-latest + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + - name: Install RUST Toolchain minimal stable with clippy and rustfmt + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + components: rustfmt, clippy + + - name: Get Latest Relay Dependencies + run: | + cargo update -p nom + cargo update -p lexical-core + working-directory: core/relay + + - name: Use Protoc 3.15 + run: | + curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v3.15.6/protoc-3.15.6-linux-x86_64.zip + unzip protoc-3.15.6-linux-x86_64.zip -d protoc + + - name: Build Image + run: make + working-directory: core/relay + + - name: Run Dummy Relay + run: RELAY_CONFIG=config/Dummy_Relay.toml cargo run --bin server &> relay-dummy.out & + working-directory: core/relay + + - name: Run Dummy Driver + run: RELAY_CONFIG=config/Dummy_Relay.toml cargo run --bin dummy-driver &> driver-dummy.out & + working-directory: core/relay + + - name: Mock Client Test + run: cargo run --bin client 9085 localhost:9085/Dummy_Network/abc:abc:abc:abc + working-directory: core/relay \ No newline at end of file diff --git a/core/relay/Makefile.variables.docker b/core/relay/Makefile.variables.docker index 8f3a6a9a2..18f8c98d2 100644 --- a/core/relay/Makefile.variables.docker +++ b/core/relay/Makefile.variables.docker @@ -1,4 +1,4 @@ DOCKER_IMAGE_NAME ?= weaver-relay -DOCKER_TAG ?= 1.3.1 +DOCKER_TAG ?= 1.4.0 DOCKER_REGISTRY ?= ghcr.io/hyperledger-labs GIT_URL = https://github.com/hyperledger-labs/weaver-dlt-interoperability \ No newline at end of file From e76a6794b761bfba6c80d453e07d631ecbdcfe99 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Wed, 6 Jul 2022 22:28:56 +0530 Subject: [PATCH 016/150] protos-go updated to v1.3.2 Signed-off-by: sandeep.nishad1 --- common/protos-go/common/access_control.pb.go | 2 +- common/protos-go/common/ack.pb.go | 2 +- common/protos-go/common/asset_locks.pb.go | 2 +- common/protos-go/common/asset_transfer.pb.go | 2 +- common/protos-go/common/events.pb.go | 700 ++++++++++++++++++ common/protos-go/common/interop_payload.pb.go | 2 +- common/protos-go/common/membership.pb.go | 2 +- common/protos-go/common/proofs.pb.go | 2 +- common/protos-go/common/query.pb.go | 2 +- common/protos-go/common/state.pb.go | 2 +- .../common/verification_policy.pb.go | 2 +- common/protos-go/corda/view_data.pb.go | 2 +- common/protos-go/driver/driver.pb.go | 49 +- common/protos-go/driver/driver_grpc.pb.go | 46 +- common/protos-go/fabric/view_data.pb.go | 2 +- common/protos-go/identity/agent.pb.go | 2 +- common/protos-go/networks/networks.pb.go | 275 +++++-- common/protos-go/networks/networks_grpc.pb.go | 88 ++- common/protos-go/relay/datatransfer.pb.go | 2 +- .../protos-go/relay/datatransfer_grpc.pb.go | 4 - common/protos-go/relay/events.pb.go | 94 +++ common/protos-go/relay/events_grpc.pb.go | 184 +++++ 22 files changed, 1339 insertions(+), 129 deletions(-) create mode 100644 common/protos-go/common/events.pb.go create mode 100644 common/protos-go/relay/events.pb.go create mode 100644 common/protos-go/relay/events_grpc.pb.go diff --git a/common/protos-go/common/access_control.pb.go b/common/protos-go/common/access_control.pb.go index 828b91645..ac5fd10cf 100644 --- a/common/protos-go/common/access_control.pb.go +++ b/common/protos-go/common/access_control.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v3.15.6 +// protoc v3.17.3 // source: common/access_control.proto package common diff --git a/common/protos-go/common/ack.pb.go b/common/protos-go/common/ack.pb.go index 2b9639c20..5fbca51f0 100644 --- a/common/protos-go/common/ack.pb.go +++ b/common/protos-go/common/ack.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v3.15.6 +// protoc v3.17.3 // source: common/ack.proto package common diff --git a/common/protos-go/common/asset_locks.pb.go b/common/protos-go/common/asset_locks.pb.go index 9b9bc8838..49b35bc96 100644 --- a/common/protos-go/common/asset_locks.pb.go +++ b/common/protos-go/common/asset_locks.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v3.15.6 +// protoc v3.17.3 // source: common/asset_locks.proto package common diff --git a/common/protos-go/common/asset_transfer.pb.go b/common/protos-go/common/asset_transfer.pb.go index b2fc4628f..790802e65 100644 --- a/common/protos-go/common/asset_transfer.pb.go +++ b/common/protos-go/common/asset_transfer.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v3.15.6 +// protoc v3.17.3 // source: common/asset_transfer.proto package common diff --git a/common/protos-go/common/events.pb.go b/common/protos-go/common/events.pb.go new file mode 100644 index 000000000..9b2c160fe --- /dev/null +++ b/common/protos-go/common/events.pb.go @@ -0,0 +1,700 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.0 +// protoc v3.17.3 +// source: common/events.proto + +package common + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type EventType int32 + +const ( + EventType_LedgerState EventType = 0 + EventType_AssetLock EventType = 1 + EventType_AssetClaim EventType = 2 +) + +// Enum value maps for EventType. +var ( + EventType_name = map[int32]string{ + 0: "LedgerState", + 1: "AssetLock", + 2: "AssetClaim", + } + EventType_value = map[string]int32{ + "LedgerState": 0, + "AssetLock": 1, + "AssetClaim": 2, + } +) + +func (x EventType) Enum() *EventType { + p := new(EventType) + *p = x + return p +} + +func (x EventType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (EventType) Descriptor() protoreflect.EnumDescriptor { + return file_common_events_proto_enumTypes[0].Descriptor() +} + +func (EventType) Type() protoreflect.EnumType { + return &file_common_events_proto_enumTypes[0] +} + +func (x EventType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use EventType.Descriptor instead. +func (EventType) EnumDescriptor() ([]byte, []int) { + return file_common_events_proto_rawDescGZIP(), []int{0} +} + +type EventSubscriptionState_STATUS int32 + +const ( + // pending ACK from remote relay + EventSubscriptionState_PENDING_ACK EventSubscriptionState_STATUS = 0 + // Received ACK, waiting for event subscription confirmation from remote relay + EventSubscriptionState_PENDING EventSubscriptionState_STATUS = 1 + EventSubscriptionState_ERROR EventSubscriptionState_STATUS = 2 + EventSubscriptionState_SUCCESS EventSubscriptionState_STATUS = 3 +) + +// Enum value maps for EventSubscriptionState_STATUS. +var ( + EventSubscriptionState_STATUS_name = map[int32]string{ + 0: "PENDING_ACK", + 1: "PENDING", + 2: "ERROR", + 3: "SUCCESS", + } + EventSubscriptionState_STATUS_value = map[string]int32{ + "PENDING_ACK": 0, + "PENDING": 1, + "ERROR": 2, + "SUCCESS": 3, + } +) + +func (x EventSubscriptionState_STATUS) Enum() *EventSubscriptionState_STATUS { + p := new(EventSubscriptionState_STATUS) + *p = x + return p +} + +func (x EventSubscriptionState_STATUS) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (EventSubscriptionState_STATUS) Descriptor() protoreflect.EnumDescriptor { + return file_common_events_proto_enumTypes[1].Descriptor() +} + +func (EventSubscriptionState_STATUS) Type() protoreflect.EnumType { + return &file_common_events_proto_enumTypes[1] +} + +func (x EventSubscriptionState_STATUS) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use EventSubscriptionState_STATUS.Descriptor instead. +func (EventSubscriptionState_STATUS) EnumDescriptor() ([]byte, []int) { + return file_common_events_proto_rawDescGZIP(), []int{2, 0} +} + +type EventMatcher struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type EventType `protobuf:"varint,1,opt,name=type,proto3,enum=common.events.EventType" json:"type,omitempty"` + EventName string `protobuf:"bytes,2,opt,name=event_name,json=eventName,proto3" json:"event_name,omitempty"` + TransactionFunc string `protobuf:"bytes,3,opt,name=transaction_func,json=transactionFunc,proto3" json:"transaction_func,omitempty"` +} + +func (x *EventMatcher) Reset() { + *x = EventMatcher{} + if protoimpl.UnsafeEnabled { + mi := &file_common_events_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EventMatcher) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EventMatcher) ProtoMessage() {} + +func (x *EventMatcher) ProtoReflect() protoreflect.Message { + mi := &file_common_events_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EventMatcher.ProtoReflect.Descriptor instead. +func (*EventMatcher) Descriptor() ([]byte, []int) { + return file_common_events_proto_rawDescGZIP(), []int{0} +} + +func (x *EventMatcher) GetType() EventType { + if x != nil { + return x.Type + } + return EventType_LedgerState +} + +func (x *EventMatcher) GetEventName() string { + if x != nil { + return x.EventName + } + return "" +} + +func (x *EventMatcher) GetTransactionFunc() string { + if x != nil { + return x.TransactionFunc + } + return "" +} + +type EventSubscription struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + EventMatcher *EventMatcher `protobuf:"bytes,1,opt,name=eventMatcher,proto3" json:"eventMatcher,omitempty"` + Query *Query `protobuf:"bytes,2,opt,name=query,proto3" json:"query,omitempty"` +} + +func (x *EventSubscription) Reset() { + *x = EventSubscription{} + if protoimpl.UnsafeEnabled { + mi := &file_common_events_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EventSubscription) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EventSubscription) ProtoMessage() {} + +func (x *EventSubscription) ProtoReflect() protoreflect.Message { + mi := &file_common_events_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EventSubscription.ProtoReflect.Descriptor instead. +func (*EventSubscription) Descriptor() ([]byte, []int) { + return file_common_events_proto_rawDescGZIP(), []int{1} +} + +func (x *EventSubscription) GetEventMatcher() *EventMatcher { + if x != nil { + return x.EventMatcher + } + return nil +} + +func (x *EventSubscription) GetQuery() *Query { + if x != nil { + return x.Query + } + return nil +} + +type EventSubscriptionState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` + Status EventSubscriptionState_STATUS `protobuf:"varint,2,opt,name=status,proto3,enum=common.events.EventSubscriptionState_STATUS" json:"status,omitempty"` + Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"` + EventMatcher *EventMatcher `protobuf:"bytes,4,opt,name=eventMatcher,proto3" json:"eventMatcher,omitempty"` + EventPublicationSpec *EventPublication `protobuf:"bytes,5,opt,name=eventPublicationSpec,proto3" json:"eventPublicationSpec,omitempty"` +} + +func (x *EventSubscriptionState) Reset() { + *x = EventSubscriptionState{} + if protoimpl.UnsafeEnabled { + mi := &file_common_events_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EventSubscriptionState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EventSubscriptionState) ProtoMessage() {} + +func (x *EventSubscriptionState) ProtoReflect() protoreflect.Message { + mi := &file_common_events_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EventSubscriptionState.ProtoReflect.Descriptor instead. +func (*EventSubscriptionState) Descriptor() ([]byte, []int) { + return file_common_events_proto_rawDescGZIP(), []int{2} +} + +func (x *EventSubscriptionState) GetRequestId() string { + if x != nil { + return x.RequestId + } + return "" +} + +func (x *EventSubscriptionState) GetStatus() EventSubscriptionState_STATUS { + if x != nil { + return x.Status + } + return EventSubscriptionState_PENDING_ACK +} + +func (x *EventSubscriptionState) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *EventSubscriptionState) GetEventMatcher() *EventMatcher { + if x != nil { + return x.EventMatcher + } + return nil +} + +func (x *EventSubscriptionState) GetEventPublicationSpec() *EventPublication { + if x != nil { + return x.EventPublicationSpec + } + return nil +} + +type ContractTransaction struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DriverId string `protobuf:"bytes,1,opt,name=driverId,proto3" json:"driverId,omitempty"` + LedgerId string `protobuf:"bytes,2,opt,name=ledgerId,proto3" json:"ledgerId,omitempty"` + ContractId string `protobuf:"bytes,3,opt,name=contractId,proto3" json:"contractId,omitempty"` + Func string `protobuf:"bytes,4,opt,name=func,proto3" json:"func,omitempty"` + Args [][]byte `protobuf:"bytes,5,rep,name=args,proto3" json:"args,omitempty"` + ReplaceArgIndex uint64 `protobuf:"varint,6,opt,name=replaceArgIndex,proto3" json:"replaceArgIndex,omitempty"` +} + +func (x *ContractTransaction) Reset() { + *x = ContractTransaction{} + if protoimpl.UnsafeEnabled { + mi := &file_common_events_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ContractTransaction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContractTransaction) ProtoMessage() {} + +func (x *ContractTransaction) ProtoReflect() protoreflect.Message { + mi := &file_common_events_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ContractTransaction.ProtoReflect.Descriptor instead. +func (*ContractTransaction) Descriptor() ([]byte, []int) { + return file_common_events_proto_rawDescGZIP(), []int{3} +} + +func (x *ContractTransaction) GetDriverId() string { + if x != nil { + return x.DriverId + } + return "" +} + +func (x *ContractTransaction) GetLedgerId() string { + if x != nil { + return x.LedgerId + } + return "" +} + +func (x *ContractTransaction) GetContractId() string { + if x != nil { + return x.ContractId + } + return "" +} + +func (x *ContractTransaction) GetFunc() string { + if x != nil { + return x.Func + } + return "" +} + +func (x *ContractTransaction) GetArgs() [][]byte { + if x != nil { + return x.Args + } + return nil +} + +func (x *ContractTransaction) GetReplaceArgIndex() uint64 { + if x != nil { + return x.ReplaceArgIndex + } + return 0 +} + +type EventPublication struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to PublicationTarget: + // *EventPublication_Ctx + // *EventPublication_AppUrl + PublicationTarget isEventPublication_PublicationTarget `protobuf_oneof:"publication_target"` +} + +func (x *EventPublication) Reset() { + *x = EventPublication{} + if protoimpl.UnsafeEnabled { + mi := &file_common_events_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EventPublication) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EventPublication) ProtoMessage() {} + +func (x *EventPublication) ProtoReflect() protoreflect.Message { + mi := &file_common_events_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EventPublication.ProtoReflect.Descriptor instead. +func (*EventPublication) Descriptor() ([]byte, []int) { + return file_common_events_proto_rawDescGZIP(), []int{4} +} + +func (m *EventPublication) GetPublicationTarget() isEventPublication_PublicationTarget { + if m != nil { + return m.PublicationTarget + } + return nil +} + +func (x *EventPublication) GetCtx() *ContractTransaction { + if x, ok := x.GetPublicationTarget().(*EventPublication_Ctx); ok { + return x.Ctx + } + return nil +} + +func (x *EventPublication) GetAppUrl() string { + if x, ok := x.GetPublicationTarget().(*EventPublication_AppUrl); ok { + return x.AppUrl + } + return "" +} + +type isEventPublication_PublicationTarget interface { + isEventPublication_PublicationTarget() +} + +type EventPublication_Ctx struct { + Ctx *ContractTransaction `protobuf:"bytes,1,opt,name=ctx,proto3,oneof"` +} + +type EventPublication_AppUrl struct { + AppUrl string `protobuf:"bytes,2,opt,name=app_url,json=appUrl,proto3,oneof"` +} + +func (*EventPublication_Ctx) isEventPublication_PublicationTarget() {} + +func (*EventPublication_AppUrl) isEventPublication_PublicationTarget() {} + +var File_common_events_proto protoreflect.FileDescriptor + +var file_common_events_proto_rawDesc = []byte{ + 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x73, 0x1a, 0x12, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x71, 0x75, 0x65, + 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x86, 0x01, 0x0a, 0x0c, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x2c, 0x0a, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, + 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x75, 0x6e, + 0x63, 0x22, 0x7f, 0x0a, 0x11, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3f, 0x0a, 0x0c, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, + 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x52, 0x0c, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x29, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x05, 0x71, 0x75, 0x65, + 0x72, 0x79, 0x22, 0xed, 0x02, 0x0a, 0x16, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1d, 0x0a, + 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x44, 0x0a, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x2e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3f, 0x0a, 0x0c, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x52, + 0x0c, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x53, 0x0a, + 0x14, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x53, 0x70, 0x65, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x14, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x70, + 0x65, 0x63, 0x22, 0x3e, 0x0a, 0x06, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x12, 0x0f, 0x0a, 0x0b, + 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x41, 0x43, 0x4b, 0x10, 0x00, 0x12, 0x0b, 0x0a, + 0x07, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, + 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, + 0x10, 0x03, 0x22, 0xbf, 0x01, 0x0a, 0x13, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x72, + 0x69, 0x76, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x72, + 0x69, 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, + 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, + 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x49, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, + 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x75, 0x6e, 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x66, 0x75, 0x6e, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x67, 0x73, 0x18, 0x05, + 0x20, 0x03, 0x28, 0x0c, 0x52, 0x04, 0x61, 0x72, 0x67, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x72, 0x65, + 0x70, 0x6c, 0x61, 0x63, 0x65, 0x41, 0x72, 0x67, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x41, 0x72, 0x67, 0x49, + 0x6e, 0x64, 0x65, 0x78, 0x22, 0x7b, 0x0a, 0x10, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x03, 0x63, 0x74, 0x78, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x03, 0x63, 0x74, 0x78, + 0x12, 0x19, 0x0a, 0x07, 0x61, 0x70, 0x70, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x00, 0x52, 0x06, 0x61, 0x70, 0x70, 0x55, 0x72, 0x6c, 0x42, 0x14, 0x0a, 0x12, 0x70, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, + 0x74, 0x2a, 0x3b, 0x0a, 0x09, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0f, + 0x0a, 0x0b, 0x4c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x10, 0x00, 0x12, + 0x0d, 0x0a, 0x09, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x10, 0x01, 0x12, 0x0e, + 0x0a, 0x0a, 0x41, 0x73, 0x73, 0x65, 0x74, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x10, 0x02, 0x42, 0x72, + 0x0a, 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x73, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, + 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, + 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, + 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_common_events_proto_rawDescOnce sync.Once + file_common_events_proto_rawDescData = file_common_events_proto_rawDesc +) + +func file_common_events_proto_rawDescGZIP() []byte { + file_common_events_proto_rawDescOnce.Do(func() { + file_common_events_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_events_proto_rawDescData) + }) + return file_common_events_proto_rawDescData +} + +var file_common_events_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_common_events_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_common_events_proto_goTypes = []interface{}{ + (EventType)(0), // 0: common.events.EventType + (EventSubscriptionState_STATUS)(0), // 1: common.events.EventSubscriptionState.STATUS + (*EventMatcher)(nil), // 2: common.events.EventMatcher + (*EventSubscription)(nil), // 3: common.events.EventSubscription + (*EventSubscriptionState)(nil), // 4: common.events.EventSubscriptionState + (*ContractTransaction)(nil), // 5: common.events.ContractTransaction + (*EventPublication)(nil), // 6: common.events.EventPublication + (*Query)(nil), // 7: common.query.Query +} +var file_common_events_proto_depIdxs = []int32{ + 0, // 0: common.events.EventMatcher.type:type_name -> common.events.EventType + 2, // 1: common.events.EventSubscription.eventMatcher:type_name -> common.events.EventMatcher + 7, // 2: common.events.EventSubscription.query:type_name -> common.query.Query + 1, // 3: common.events.EventSubscriptionState.status:type_name -> common.events.EventSubscriptionState.STATUS + 2, // 4: common.events.EventSubscriptionState.eventMatcher:type_name -> common.events.EventMatcher + 6, // 5: common.events.EventSubscriptionState.eventPublicationSpec:type_name -> common.events.EventPublication + 5, // 6: common.events.EventPublication.ctx:type_name -> common.events.ContractTransaction + 7, // [7:7] is the sub-list for method output_type + 7, // [7:7] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 7, // [7:7] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name +} + +func init() { file_common_events_proto_init() } +func file_common_events_proto_init() { + if File_common_events_proto != nil { + return + } + file_common_query_proto_init() + if !protoimpl.UnsafeEnabled { + file_common_events_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EventMatcher); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_common_events_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EventSubscription); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_common_events_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EventSubscriptionState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_common_events_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ContractTransaction); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_common_events_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EventPublication); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_common_events_proto_msgTypes[4].OneofWrappers = []interface{}{ + (*EventPublication_Ctx)(nil), + (*EventPublication_AppUrl)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_common_events_proto_rawDesc, + NumEnums: 2, + NumMessages: 5, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_common_events_proto_goTypes, + DependencyIndexes: file_common_events_proto_depIdxs, + EnumInfos: file_common_events_proto_enumTypes, + MessageInfos: file_common_events_proto_msgTypes, + }.Build() + File_common_events_proto = out.File + file_common_events_proto_rawDesc = nil + file_common_events_proto_goTypes = nil + file_common_events_proto_depIdxs = nil +} diff --git a/common/protos-go/common/interop_payload.pb.go b/common/protos-go/common/interop_payload.pb.go index e35281390..bfbb902a6 100644 --- a/common/protos-go/common/interop_payload.pb.go +++ b/common/protos-go/common/interop_payload.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v3.15.6 +// protoc v3.17.3 // source: common/interop_payload.proto package common diff --git a/common/protos-go/common/membership.pb.go b/common/protos-go/common/membership.pb.go index 72d84d73d..98180bb7a 100644 --- a/common/protos-go/common/membership.pb.go +++ b/common/protos-go/common/membership.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v3.15.6 +// protoc v3.17.3 // source: common/membership.proto package common diff --git a/common/protos-go/common/proofs.pb.go b/common/protos-go/common/proofs.pb.go index 88f8792bb..8ef9cb5ce 100644 --- a/common/protos-go/common/proofs.pb.go +++ b/common/protos-go/common/proofs.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v3.15.6 +// protoc v3.17.3 // source: common/proofs.proto package common diff --git a/common/protos-go/common/query.pb.go b/common/protos-go/common/query.pb.go index 2697aa449..2a3567ef2 100644 --- a/common/protos-go/common/query.pb.go +++ b/common/protos-go/common/query.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v3.15.6 +// protoc v3.17.3 // source: common/query.proto package common diff --git a/common/protos-go/common/state.pb.go b/common/protos-go/common/state.pb.go index 97149ac7f..b69e94b65 100644 --- a/common/protos-go/common/state.pb.go +++ b/common/protos-go/common/state.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v3.15.6 +// protoc v3.17.3 // source: common/state.proto package common diff --git a/common/protos-go/common/verification_policy.pb.go b/common/protos-go/common/verification_policy.pb.go index d0d2b48a7..2a26bc03f 100644 --- a/common/protos-go/common/verification_policy.pb.go +++ b/common/protos-go/common/verification_policy.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v3.15.6 +// protoc v3.17.3 // source: common/verification_policy.proto package common diff --git a/common/protos-go/corda/view_data.pb.go b/common/protos-go/corda/view_data.pb.go index 99236aa7f..949d44160 100644 --- a/common/protos-go/corda/view_data.pb.go +++ b/common/protos-go/corda/view_data.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v3.15.6 +// protoc v3.17.3 // source: corda/view_data.proto package corda diff --git a/common/protos-go/driver/driver.pb.go b/common/protos-go/driver/driver.pb.go index 45ae3ba62..b9a157733 100644 --- a/common/protos-go/driver/driver.pb.go +++ b/common/protos-go/driver/driver.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v3.15.6 +// protoc v3.17.3 // source: driver/driver.proto package driver @@ -27,31 +27,40 @@ var file_driver_driver_proto_rawDesc = []byte{ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x1a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x61, 0x63, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x12, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x71, - 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0x53, 0x0a, 0x13, 0x44, 0x72, - 0x69, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x3c, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x72, 0x69, 0x76, - 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x0f, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, - 0x72, 0x0a, 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x64, 0x72, 0x69, 0x76, - 0x65, 0x72, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, - 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, - 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x64, 0x72, 0x69, - 0x76, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x13, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, + 0x9a, 0x01, 0x0a, 0x13, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x13, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x51, 0x75, 0x65, + 0x72, 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, + 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x45, 0x0a, 0x0e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x62, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, 0x72, 0x0a, 0x1f, + 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x73, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x5a, + 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, + 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, + 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, + 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var file_driver_driver_proto_goTypes = []interface{}{ - (*common.Query)(nil), // 0: common.query.Query - (*common.Ack)(nil), // 1: common.ack.Ack + (*common.Query)(nil), // 0: common.query.Query + (*common.EventSubscription)(nil), // 1: common.events.EventSubscription + (*common.Ack)(nil), // 2: common.ack.Ack } var file_driver_driver_proto_depIdxs = []int32{ 0, // 0: driver.driver.DriverCommunication.RequestDriverState:input_type -> common.query.Query - 1, // 1: driver.driver.DriverCommunication.RequestDriverState:output_type -> common.ack.Ack - 1, // [1:2] is the sub-list for method output_type - 0, // [0:1] is the sub-list for method input_type + 1, // 1: driver.driver.DriverCommunication.SubscribeEvent:input_type -> common.events.EventSubscription + 2, // 2: driver.driver.DriverCommunication.RequestDriverState:output_type -> common.ack.Ack + 2, // 3: driver.driver.DriverCommunication.SubscribeEvent:output_type -> common.ack.Ack + 2, // [2:4] is the sub-list for method output_type + 0, // [0:2] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name diff --git a/common/protos-go/driver/driver_grpc.pb.go b/common/protos-go/driver/driver_grpc.pb.go index 508e0d6ec..ae7e067f2 100644 --- a/common/protos-go/driver/driver_grpc.pb.go +++ b/common/protos-go/driver/driver_grpc.pb.go @@ -1,8 +1,4 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.2.0 -// - protoc v3.15.6 -// source: driver/driver.proto package driver @@ -23,9 +19,13 @@ const _ = grpc.SupportPackageIsVersion7 // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type DriverCommunicationClient interface { + // Data Sharing // the remote relay sends a RequestDriverState request to its driver with a // query defining the data it wants to receive RequestDriverState(ctx context.Context, in *common.Query, opts ...grpc.CallOption) (*common.Ack, error) + // Events Subscription + // the src-relay uses this endpoint to forward the event subscription request from dest-relay to driver + SubscribeEvent(ctx context.Context, in *common.EventSubscription, opts ...grpc.CallOption) (*common.Ack, error) } type driverCommunicationClient struct { @@ -45,13 +45,26 @@ func (c *driverCommunicationClient) RequestDriverState(ctx context.Context, in * return out, nil } +func (c *driverCommunicationClient) SubscribeEvent(ctx context.Context, in *common.EventSubscription, opts ...grpc.CallOption) (*common.Ack, error) { + out := new(common.Ack) + err := c.cc.Invoke(ctx, "/driver.driver.DriverCommunication/SubscribeEvent", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // DriverCommunicationServer is the server API for DriverCommunication service. // All implementations must embed UnimplementedDriverCommunicationServer // for forward compatibility type DriverCommunicationServer interface { + // Data Sharing // the remote relay sends a RequestDriverState request to its driver with a // query defining the data it wants to receive RequestDriverState(context.Context, *common.Query) (*common.Ack, error) + // Events Subscription + // the src-relay uses this endpoint to forward the event subscription request from dest-relay to driver + SubscribeEvent(context.Context, *common.EventSubscription) (*common.Ack, error) mustEmbedUnimplementedDriverCommunicationServer() } @@ -62,6 +75,9 @@ type UnimplementedDriverCommunicationServer struct { func (UnimplementedDriverCommunicationServer) RequestDriverState(context.Context, *common.Query) (*common.Ack, error) { return nil, status.Errorf(codes.Unimplemented, "method RequestDriverState not implemented") } +func (UnimplementedDriverCommunicationServer) SubscribeEvent(context.Context, *common.EventSubscription) (*common.Ack, error) { + return nil, status.Errorf(codes.Unimplemented, "method SubscribeEvent not implemented") +} func (UnimplementedDriverCommunicationServer) mustEmbedUnimplementedDriverCommunicationServer() {} // UnsafeDriverCommunicationServer may be embedded to opt out of forward compatibility for this service. @@ -93,6 +109,24 @@ func _DriverCommunication_RequestDriverState_Handler(srv interface{}, ctx contex return interceptor(ctx, in, info, handler) } +func _DriverCommunication_SubscribeEvent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(common.EventSubscription) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DriverCommunicationServer).SubscribeEvent(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/driver.driver.DriverCommunication/SubscribeEvent", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DriverCommunicationServer).SubscribeEvent(ctx, req.(*common.EventSubscription)) + } + return interceptor(ctx, in, info, handler) +} + // DriverCommunication_ServiceDesc is the grpc.ServiceDesc for DriverCommunication service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -104,6 +138,10 @@ var DriverCommunication_ServiceDesc = grpc.ServiceDesc{ MethodName: "RequestDriverState", Handler: _DriverCommunication_RequestDriverState_Handler, }, + { + MethodName: "SubscribeEvent", + Handler: _DriverCommunication_SubscribeEvent_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "driver/driver.proto", diff --git a/common/protos-go/fabric/view_data.pb.go b/common/protos-go/fabric/view_data.pb.go index ec2693250..838ad7129 100644 --- a/common/protos-go/fabric/view_data.pb.go +++ b/common/protos-go/fabric/view_data.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v3.15.6 +// protoc v3.17.3 // source: fabric/view_data.proto package fabric diff --git a/common/protos-go/identity/agent.pb.go b/common/protos-go/identity/agent.pb.go index d8ff0a15a..9349ceead 100644 --- a/common/protos-go/identity/agent.pb.go +++ b/common/protos-go/identity/agent.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v3.15.6 +// protoc v3.17.3 // source: identity/agent.proto package identity diff --git a/common/protos-go/networks/networks.pb.go b/common/protos-go/networks/networks.pb.go index fe425d87d..c7e4896b9 100644 --- a/common/protos-go/networks/networks.pb.go +++ b/common/protos-go/networks/networks.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v3.15.6 +// protoc v3.17.3 // source: networks/networks.proto package networks @@ -273,6 +273,69 @@ func (x *NetworkQuery) GetConfidential() bool { return false } +type NetworkEventSubscription struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + EventMatcher *common.EventMatcher `protobuf:"bytes,1,opt,name=eventMatcher,proto3" json:"eventMatcher,omitempty"` + Query *NetworkQuery `protobuf:"bytes,2,opt,name=query,proto3" json:"query,omitempty"` + EventPublicationSpec *common.EventPublication `protobuf:"bytes,3,opt,name=eventPublicationSpec,proto3" json:"eventPublicationSpec,omitempty"` +} + +func (x *NetworkEventSubscription) Reset() { + *x = NetworkEventSubscription{} + if protoimpl.UnsafeEnabled { + mi := &file_networks_networks_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NetworkEventSubscription) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetworkEventSubscription) ProtoMessage() {} + +func (x *NetworkEventSubscription) ProtoReflect() protoreflect.Message { + mi := &file_networks_networks_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NetworkEventSubscription.ProtoReflect.Descriptor instead. +func (*NetworkEventSubscription) Descriptor() ([]byte, []int) { + return file_networks_networks_proto_rawDescGZIP(), []int{4} +} + +func (x *NetworkEventSubscription) GetEventMatcher() *common.EventMatcher { + if x != nil { + return x.EventMatcher + } + return nil +} + +func (x *NetworkEventSubscription) GetQuery() *NetworkQuery { + if x != nil { + return x.Query + } + return nil +} + +func (x *NetworkEventSubscription) GetEventPublicationSpec() *common.EventPublication { + if x != nil { + return x.EventPublicationSpec + } + return nil +} + var File_networks_networks_proto protoreflect.FileDescriptor var file_networks_networks_proto_rawDesc = []byte{ @@ -281,65 +344,92 @@ var file_networks_networks_proto_rawDesc = []byte{ 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x1a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x61, 0x63, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x12, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x22, 0x1c, 0x0a, 0x06, 0x44, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x22, 0x8c, 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, - 0x73, 0x65, 0x12, 0x41, 0x0a, 0x05, 0x70, 0x61, 0x69, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x2b, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x44, 0x61, 0x74, 0x61, 0x62, - 0x61, 0x73, 0x65, 0x2e, 0x50, 0x61, 0x69, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, - 0x70, 0x61, 0x69, 0x72, 0x73, 0x1a, 0x38, 0x0a, 0x0a, 0x50, 0x61, 0x69, 0x72, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, - 0x30, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, - 0x64, 0x22, 0xce, 0x02, 0x0a, 0x0c, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x51, 0x75, 0x65, - 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, - 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, - 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x12, - 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x6e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x20, - 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x12, 0x2f, 0x0a, 0x13, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x5f, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x6f, 0x72, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4f, 0x72, 0x67, 0x12, 0x22, - 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x18, 0x09, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x61, 0x6c, 0x32, 0xed, 0x01, 0x0a, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x42, - 0x0a, 0x0c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1f, - 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, - 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, - 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x22, - 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x1a, 0x1a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x74, 0x61, 0x74, - 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x00, - 0x12, 0x50, 0x0a, 0x0f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, - 0x61, 0x73, 0x65, 0x12, 0x19, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, - 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x44, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x1a, 0x20, - 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x73, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, - 0x22, 0x00, 0x42, 0x78, 0x0a, 0x23, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, - 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x5a, 0x51, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, - 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, - 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, - 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, - 0x2d, 0x67, 0x6f, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x6f, 0x1a, 0x13, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1c, 0x0a, 0x06, 0x44, 0x62, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x8c, 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x44, + 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x05, 0x70, 0x61, 0x69, 0x72, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, + 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x50, 0x61, 0x69, 0x72, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x05, 0x70, 0x61, 0x69, 0x72, 0x73, 0x1a, 0x38, 0x0a, 0x0a, 0x50, 0x61, + 0x69, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x22, 0x30, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0xce, 0x02, 0x0a, 0x0c, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, + 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x52, + 0x65, 0x6c, 0x61, 0x79, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, + 0x6e, 0x67, 0x5f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x11, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x2f, 0x0a, 0x13, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x6f, 0x72, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x53, 0x69, 0x67, + 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x25, 0x0a, 0x0e, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x6f, 0x72, 0x67, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, + 0x4f, 0x72, 0x67, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x61, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xe7, 0x01, 0x0a, 0x18, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3f, 0x0a, 0x0c, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, + 0x63, 0x68, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x52, 0x0c, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, + 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x35, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x53, 0x0a, 0x14, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x53, 0x70, 0x65, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x14, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, + 0x63, 0x32, 0xa9, 0x03, 0x0a, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x42, 0x0a, + 0x0c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x2e, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x0f, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, + 0x00, 0x12, 0x4c, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x22, 0x2e, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x73, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x1a, 0x1a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x00, 0x12, + 0x50, 0x0a, 0x0f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, + 0x73, 0x65, 0x12, 0x19, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x44, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x1a, 0x20, 0x2e, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x73, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x22, + 0x00, 0x12, 0x50, 0x0a, 0x0e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x12, 0x2b, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, + 0x6b, 0x22, 0x00, 0x12, 0x68, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, + 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x12, 0x22, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x1a, 0x25, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x00, 0x42, 0x78, 0x0a, + 0x23, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x73, 0x5a, 0x51, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, + 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -354,29 +444,40 @@ func file_networks_networks_proto_rawDescGZIP() []byte { return file_networks_networks_proto_rawDescData } -var file_networks_networks_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_networks_networks_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_networks_networks_proto_goTypes = []interface{}{ - (*DbName)(nil), // 0: networks.networks.DbName - (*RelayDatabase)(nil), // 1: networks.networks.RelayDatabase - (*GetStateMessage)(nil), // 2: networks.networks.GetStateMessage - (*NetworkQuery)(nil), // 3: networks.networks.NetworkQuery - nil, // 4: networks.networks.RelayDatabase.PairsEntry - (*common.Ack)(nil), // 5: common.ack.Ack - (*common.RequestState)(nil), // 6: common.state.RequestState + (*DbName)(nil), // 0: networks.networks.DbName + (*RelayDatabase)(nil), // 1: networks.networks.RelayDatabase + (*GetStateMessage)(nil), // 2: networks.networks.GetStateMessage + (*NetworkQuery)(nil), // 3: networks.networks.NetworkQuery + (*NetworkEventSubscription)(nil), // 4: networks.networks.NetworkEventSubscription + nil, // 5: networks.networks.RelayDatabase.PairsEntry + (*common.EventMatcher)(nil), // 6: common.events.EventMatcher + (*common.EventPublication)(nil), // 7: common.events.EventPublication + (*common.Ack)(nil), // 8: common.ack.Ack + (*common.RequestState)(nil), // 9: common.state.RequestState + (*common.EventSubscriptionState)(nil), // 10: common.events.EventSubscriptionState } var file_networks_networks_proto_depIdxs = []int32{ - 4, // 0: networks.networks.RelayDatabase.pairs:type_name -> networks.networks.RelayDatabase.PairsEntry - 3, // 1: networks.networks.Network.RequestState:input_type -> networks.networks.NetworkQuery - 2, // 2: networks.networks.Network.GetState:input_type -> networks.networks.GetStateMessage - 0, // 3: networks.networks.Network.RequestDatabase:input_type -> networks.networks.DbName - 5, // 4: networks.networks.Network.RequestState:output_type -> common.ack.Ack - 6, // 5: networks.networks.Network.GetState:output_type -> common.state.RequestState - 1, // 6: networks.networks.Network.RequestDatabase:output_type -> networks.networks.RelayDatabase - 4, // [4:7] is the sub-list for method output_type - 1, // [1:4] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name + 5, // 0: networks.networks.RelayDatabase.pairs:type_name -> networks.networks.RelayDatabase.PairsEntry + 6, // 1: networks.networks.NetworkEventSubscription.eventMatcher:type_name -> common.events.EventMatcher + 3, // 2: networks.networks.NetworkEventSubscription.query:type_name -> networks.networks.NetworkQuery + 7, // 3: networks.networks.NetworkEventSubscription.eventPublicationSpec:type_name -> common.events.EventPublication + 3, // 4: networks.networks.Network.RequestState:input_type -> networks.networks.NetworkQuery + 2, // 5: networks.networks.Network.GetState:input_type -> networks.networks.GetStateMessage + 0, // 6: networks.networks.Network.RequestDatabase:input_type -> networks.networks.DbName + 4, // 7: networks.networks.Network.SubscribeEvent:input_type -> networks.networks.NetworkEventSubscription + 2, // 8: networks.networks.Network.GetEventSubscriptionState:input_type -> networks.networks.GetStateMessage + 8, // 9: networks.networks.Network.RequestState:output_type -> common.ack.Ack + 9, // 10: networks.networks.Network.GetState:output_type -> common.state.RequestState + 1, // 11: networks.networks.Network.RequestDatabase:output_type -> networks.networks.RelayDatabase + 8, // 12: networks.networks.Network.SubscribeEvent:output_type -> common.ack.Ack + 10, // 13: networks.networks.Network.GetEventSubscriptionState:output_type -> common.events.EventSubscriptionState + 9, // [9:14] is the sub-list for method output_type + 4, // [4:9] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name } func init() { file_networks_networks_proto_init() } @@ -433,6 +534,18 @@ func file_networks_networks_proto_init() { return nil } } + file_networks_networks_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NetworkEventSubscription); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -440,7 +553,7 @@ func file_networks_networks_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_networks_networks_proto_rawDesc, NumEnums: 0, - NumMessages: 5, + NumMessages: 6, NumExtensions: 0, NumServices: 1, }, diff --git a/common/protos-go/networks/networks_grpc.pb.go b/common/protos-go/networks/networks_grpc.pb.go index 6e963dc9e..33f4a42c3 100644 --- a/common/protos-go/networks/networks_grpc.pb.go +++ b/common/protos-go/networks/networks_grpc.pb.go @@ -1,8 +1,4 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.2.0 -// - protoc v3.15.6 -// source: networks/networks.proto package networks @@ -23,12 +19,18 @@ const _ = grpc.SupportPackageIsVersion7 // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type NetworkClient interface { + // Data Sharing endpoints // endpoint for a network to request remote relay state via local relay RequestState(ctx context.Context, in *NetworkQuery, opts ...grpc.CallOption) (*common.Ack, error) - // This rpc endpooint is for polling the local relay for request state. + // This rpc endpoint is for polling the local relay for request state. GetState(ctx context.Context, in *GetStateMessage, opts ...grpc.CallOption) (*common.RequestState, error) // NOTE: This rpc is just for debugging. RequestDatabase(ctx context.Context, in *DbName, opts ...grpc.CallOption) (*RelayDatabase, error) + // Event endpoints + // endpoint for a client to subscribe to event via local relay initiating subscription flow. + SubscribeEvent(ctx context.Context, in *NetworkEventSubscription, opts ...grpc.CallOption) (*common.Ack, error) + // This rpc endpoint is for polling the local relay for subscription state. + GetEventSubscriptionState(ctx context.Context, in *GetStateMessage, opts ...grpc.CallOption) (*common.EventSubscriptionState, error) } type networkClient struct { @@ -66,16 +68,40 @@ func (c *networkClient) RequestDatabase(ctx context.Context, in *DbName, opts .. return out, nil } +func (c *networkClient) SubscribeEvent(ctx context.Context, in *NetworkEventSubscription, opts ...grpc.CallOption) (*common.Ack, error) { + out := new(common.Ack) + err := c.cc.Invoke(ctx, "/networks.networks.Network/SubscribeEvent", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *networkClient) GetEventSubscriptionState(ctx context.Context, in *GetStateMessage, opts ...grpc.CallOption) (*common.EventSubscriptionState, error) { + out := new(common.EventSubscriptionState) + err := c.cc.Invoke(ctx, "/networks.networks.Network/GetEventSubscriptionState", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // NetworkServer is the server API for Network service. // All implementations must embed UnimplementedNetworkServer // for forward compatibility type NetworkServer interface { + // Data Sharing endpoints // endpoint for a network to request remote relay state via local relay RequestState(context.Context, *NetworkQuery) (*common.Ack, error) - // This rpc endpooint is for polling the local relay for request state. + // This rpc endpoint is for polling the local relay for request state. GetState(context.Context, *GetStateMessage) (*common.RequestState, error) // NOTE: This rpc is just for debugging. RequestDatabase(context.Context, *DbName) (*RelayDatabase, error) + // Event endpoints + // endpoint for a client to subscribe to event via local relay initiating subscription flow. + SubscribeEvent(context.Context, *NetworkEventSubscription) (*common.Ack, error) + // This rpc endpoint is for polling the local relay for subscription state. + GetEventSubscriptionState(context.Context, *GetStateMessage) (*common.EventSubscriptionState, error) mustEmbedUnimplementedNetworkServer() } @@ -92,6 +118,12 @@ func (UnimplementedNetworkServer) GetState(context.Context, *GetStateMessage) (* func (UnimplementedNetworkServer) RequestDatabase(context.Context, *DbName) (*RelayDatabase, error) { return nil, status.Errorf(codes.Unimplemented, "method RequestDatabase not implemented") } +func (UnimplementedNetworkServer) SubscribeEvent(context.Context, *NetworkEventSubscription) (*common.Ack, error) { + return nil, status.Errorf(codes.Unimplemented, "method SubscribeEvent not implemented") +} +func (UnimplementedNetworkServer) GetEventSubscriptionState(context.Context, *GetStateMessage) (*common.EventSubscriptionState, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetEventSubscriptionState not implemented") +} func (UnimplementedNetworkServer) mustEmbedUnimplementedNetworkServer() {} // UnsafeNetworkServer may be embedded to opt out of forward compatibility for this service. @@ -159,6 +191,42 @@ func _Network_RequestDatabase_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _Network_SubscribeEvent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(NetworkEventSubscription) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NetworkServer).SubscribeEvent(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/networks.networks.Network/SubscribeEvent", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NetworkServer).SubscribeEvent(ctx, req.(*NetworkEventSubscription)) + } + return interceptor(ctx, in, info, handler) +} + +func _Network_GetEventSubscriptionState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetStateMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NetworkServer).GetEventSubscriptionState(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/networks.networks.Network/GetEventSubscriptionState", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NetworkServer).GetEventSubscriptionState(ctx, req.(*GetStateMessage)) + } + return interceptor(ctx, in, info, handler) +} + // Network_ServiceDesc is the grpc.ServiceDesc for Network service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -178,6 +246,14 @@ var Network_ServiceDesc = grpc.ServiceDesc{ MethodName: "RequestDatabase", Handler: _Network_RequestDatabase_Handler, }, + { + MethodName: "SubscribeEvent", + Handler: _Network_SubscribeEvent_Handler, + }, + { + MethodName: "GetEventSubscriptionState", + Handler: _Network_GetEventSubscriptionState_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "networks/networks.proto", diff --git a/common/protos-go/relay/datatransfer.pb.go b/common/protos-go/relay/datatransfer.pb.go index 4f4ef98e4..67f9bcf72 100644 --- a/common/protos-go/relay/datatransfer.pb.go +++ b/common/protos-go/relay/datatransfer.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 -// protoc v3.15.6 +// protoc v3.17.3 // source: relay/datatransfer.proto package relay diff --git a/common/protos-go/relay/datatransfer_grpc.pb.go b/common/protos-go/relay/datatransfer_grpc.pb.go index 9a9d74e1f..55dbe950e 100644 --- a/common/protos-go/relay/datatransfer_grpc.pb.go +++ b/common/protos-go/relay/datatransfer_grpc.pb.go @@ -1,8 +1,4 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.2.0 -// - protoc v3.15.6 -// source: relay/datatransfer.proto package relay diff --git a/common/protos-go/relay/events.pb.go b/common/protos-go/relay/events.pb.go new file mode 100644 index 000000000..4c39dc72f --- /dev/null +++ b/common/protos-go/relay/events.pb.go @@ -0,0 +1,94 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.0 +// protoc v3.17.3 +// source: relay/events.proto + +package relay + +import ( + common "github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go/common" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +var File_relay_events_proto protoreflect.FileDescriptor + +var file_relay_events_proto_rawDesc = []byte{ + 0x0a, 0x12, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x2e, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x73, 0x1a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x61, 0x63, 0x6b, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x13, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xd9, 0x01, 0x0a, 0x0e, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x45, 0x0a, 0x0e, + 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x20, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, + 0x6b, 0x22, 0x00, 0x12, 0x3c, 0x0a, 0x16, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0f, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x1a, 0x0f, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, + 0x00, 0x12, 0x42, 0x0a, 0x1c, 0x53, 0x65, 0x6e, 0x64, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x53, + 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, + 0x63, 0x6b, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, + 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, 0x70, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, + 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, + 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x5a, 0x4e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, + 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, + 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, + 0x6f, 0x2f, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var file_relay_events_proto_goTypes = []interface{}{ + (*common.EventSubscription)(nil), // 0: common.events.EventSubscription + (*common.Ack)(nil), // 1: common.ack.Ack +} +var file_relay_events_proto_depIdxs = []int32{ + 0, // 0: relay.events.EventSubscribe.SubscribeEvent:input_type -> common.events.EventSubscription + 1, // 1: relay.events.EventSubscribe.SendSubscriptionStatus:input_type -> common.ack.Ack + 1, // 2: relay.events.EventSubscribe.SendDriverSubscriptionStatus:input_type -> common.ack.Ack + 1, // 3: relay.events.EventSubscribe.SubscribeEvent:output_type -> common.ack.Ack + 1, // 4: relay.events.EventSubscribe.SendSubscriptionStatus:output_type -> common.ack.Ack + 1, // 5: relay.events.EventSubscribe.SendDriverSubscriptionStatus:output_type -> common.ack.Ack + 3, // [3:6] is the sub-list for method output_type + 0, // [0:3] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_relay_events_proto_init() } +func file_relay_events_proto_init() { + if File_relay_events_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_relay_events_proto_rawDesc, + NumEnums: 0, + NumMessages: 0, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_relay_events_proto_goTypes, + DependencyIndexes: file_relay_events_proto_depIdxs, + }.Build() + File_relay_events_proto = out.File + file_relay_events_proto_rawDesc = nil + file_relay_events_proto_goTypes = nil + file_relay_events_proto_depIdxs = nil +} diff --git a/common/protos-go/relay/events_grpc.pb.go b/common/protos-go/relay/events_grpc.pb.go new file mode 100644 index 000000000..7f5c9404c --- /dev/null +++ b/common/protos-go/relay/events_grpc.pb.go @@ -0,0 +1,184 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. + +package relay + +import ( + context "context" + common "github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go/common" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// EventSubscribeClient is the client API for EventSubscribe service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type EventSubscribeClient interface { + // the dest-relay forwards the request from client as EventSubscription to the src-relay + SubscribeEvent(ctx context.Context, in *common.EventSubscription, opts ...grpc.CallOption) (*common.Ack, error) + // Src-relay based upon query (EventSubscription) forwards the same response (Ack) + // from driver to the dest-relay by calling a new endpoint in dest-relay + SendSubscriptionStatus(ctx context.Context, in *common.Ack, opts ...grpc.CallOption) (*common.Ack, error) + // Src-driver status of event subscription (Ack) + // to the src-relay by calling a new endpoint in src-relay + SendDriverSubscriptionStatus(ctx context.Context, in *common.Ack, opts ...grpc.CallOption) (*common.Ack, error) +} + +type eventSubscribeClient struct { + cc grpc.ClientConnInterface +} + +func NewEventSubscribeClient(cc grpc.ClientConnInterface) EventSubscribeClient { + return &eventSubscribeClient{cc} +} + +func (c *eventSubscribeClient) SubscribeEvent(ctx context.Context, in *common.EventSubscription, opts ...grpc.CallOption) (*common.Ack, error) { + out := new(common.Ack) + err := c.cc.Invoke(ctx, "/relay.events.EventSubscribe/SubscribeEvent", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *eventSubscribeClient) SendSubscriptionStatus(ctx context.Context, in *common.Ack, opts ...grpc.CallOption) (*common.Ack, error) { + out := new(common.Ack) + err := c.cc.Invoke(ctx, "/relay.events.EventSubscribe/SendSubscriptionStatus", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *eventSubscribeClient) SendDriverSubscriptionStatus(ctx context.Context, in *common.Ack, opts ...grpc.CallOption) (*common.Ack, error) { + out := new(common.Ack) + err := c.cc.Invoke(ctx, "/relay.events.EventSubscribe/SendDriverSubscriptionStatus", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// EventSubscribeServer is the server API for EventSubscribe service. +// All implementations must embed UnimplementedEventSubscribeServer +// for forward compatibility +type EventSubscribeServer interface { + // the dest-relay forwards the request from client as EventSubscription to the src-relay + SubscribeEvent(context.Context, *common.EventSubscription) (*common.Ack, error) + // Src-relay based upon query (EventSubscription) forwards the same response (Ack) + // from driver to the dest-relay by calling a new endpoint in dest-relay + SendSubscriptionStatus(context.Context, *common.Ack) (*common.Ack, error) + // Src-driver status of event subscription (Ack) + // to the src-relay by calling a new endpoint in src-relay + SendDriverSubscriptionStatus(context.Context, *common.Ack) (*common.Ack, error) + mustEmbedUnimplementedEventSubscribeServer() +} + +// UnimplementedEventSubscribeServer must be embedded to have forward compatible implementations. +type UnimplementedEventSubscribeServer struct { +} + +func (UnimplementedEventSubscribeServer) SubscribeEvent(context.Context, *common.EventSubscription) (*common.Ack, error) { + return nil, status.Errorf(codes.Unimplemented, "method SubscribeEvent not implemented") +} +func (UnimplementedEventSubscribeServer) SendSubscriptionStatus(context.Context, *common.Ack) (*common.Ack, error) { + return nil, status.Errorf(codes.Unimplemented, "method SendSubscriptionStatus not implemented") +} +func (UnimplementedEventSubscribeServer) SendDriverSubscriptionStatus(context.Context, *common.Ack) (*common.Ack, error) { + return nil, status.Errorf(codes.Unimplemented, "method SendDriverSubscriptionStatus not implemented") +} +func (UnimplementedEventSubscribeServer) mustEmbedUnimplementedEventSubscribeServer() {} + +// UnsafeEventSubscribeServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to EventSubscribeServer will +// result in compilation errors. +type UnsafeEventSubscribeServer interface { + mustEmbedUnimplementedEventSubscribeServer() +} + +func RegisterEventSubscribeServer(s grpc.ServiceRegistrar, srv EventSubscribeServer) { + s.RegisterService(&EventSubscribe_ServiceDesc, srv) +} + +func _EventSubscribe_SubscribeEvent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(common.EventSubscription) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EventSubscribeServer).SubscribeEvent(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/relay.events.EventSubscribe/SubscribeEvent", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EventSubscribeServer).SubscribeEvent(ctx, req.(*common.EventSubscription)) + } + return interceptor(ctx, in, info, handler) +} + +func _EventSubscribe_SendSubscriptionStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(common.Ack) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EventSubscribeServer).SendSubscriptionStatus(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/relay.events.EventSubscribe/SendSubscriptionStatus", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EventSubscribeServer).SendSubscriptionStatus(ctx, req.(*common.Ack)) + } + return interceptor(ctx, in, info, handler) +} + +func _EventSubscribe_SendDriverSubscriptionStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(common.Ack) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EventSubscribeServer).SendDriverSubscriptionStatus(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/relay.events.EventSubscribe/SendDriverSubscriptionStatus", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EventSubscribeServer).SendDriverSubscriptionStatus(ctx, req.(*common.Ack)) + } + return interceptor(ctx, in, info, handler) +} + +// EventSubscribe_ServiceDesc is the grpc.ServiceDesc for EventSubscribe service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var EventSubscribe_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "relay.events.EventSubscribe", + HandlerType: (*EventSubscribeServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SubscribeEvent", + Handler: _EventSubscribe_SubscribeEvent_Handler, + }, + { + MethodName: "SendSubscriptionStatus", + Handler: _EventSubscribe_SendSubscriptionStatus_Handler, + }, + { + MethodName: "SendDriverSubscriptionStatus", + Handler: _EventSubscribe_SendDriverSubscriptionStatus_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "relay/events.proto", +} From dcbc6250a30d90425535a23fa48c6a2506fca37e Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Wed, 6 Jul 2022 22:38:10 +0530 Subject: [PATCH 017/150] bump protos to v1.4.0 Signed-off-by: sandeep.nishad1 --- common/protos-java-kt/gradle.properties | 2 +- common/protos-js/package.json | 2 +- core/drivers/corda-driver/build.gradle | 2 +- core/network/corda-interop-app/constants.properties | 2 +- samples/corda/corda-simple-application/constants.properties | 2 +- sdks/corda/build.gradle | 2 +- tests/network-setups/corda/scripts/get-cordapps.sh | 2 +- tests/network-setups/corda/scripts/start-nodes.sh | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/common/protos-java-kt/gradle.properties b/common/protos-java-kt/gradle.properties index bc60761f9..c21b590dd 100644 --- a/common/protos-java-kt/gradle.properties +++ b/common/protos-java-kt/gradle.properties @@ -1,4 +1,4 @@ name=Interop Protos group=com.weaver -version=1.3.2 +version=1.4.0 kotlin.incremental=false diff --git a/common/protos-js/package.json b/common/protos-js/package.json index c017b2b12..177626667 100644 --- a/common/protos-js/package.json +++ b/common/protos-js/package.json @@ -1,6 +1,6 @@ { "name": "@hyperledger-labs/weaver-protos-js", - "version": "1.3.2", + "version": "1.4.0", "description": "Interop protos for Node JS (Weaver)", "main": "index.js", "exports": { diff --git a/core/drivers/corda-driver/build.gradle b/core/drivers/corda-driver/build.gradle index 6a9199545..89f90f9a1 100644 --- a/core/drivers/corda-driver/build.gradle +++ b/core/drivers/corda-driver/build.gradle @@ -10,7 +10,7 @@ buildscript { ext.corda_version = "4.8.4" ext.corda_core_version = "4.8.4" ext.arrow_version = "0.10.4" - ext.weaver_protos_version = "1.3.2" + ext.weaver_protos_version = "1.4.0" ext.weaver_corda_version = "1.2.9" repositories { diff --git a/core/network/corda-interop-app/constants.properties b/core/network/corda-interop-app/constants.properties index 32ec4b21c..d8993c173 100644 --- a/core/network/corda-interop-app/constants.properties +++ b/core/network/corda-interop-app/constants.properties @@ -11,4 +11,4 @@ slf4jVersion=1.7.25 nettyVersion=4.1.22.Final arrowVersion=0.10.4 -weaverVersion=1.3.2 +weaverVersion=1.4.0 diff --git a/samples/corda/corda-simple-application/constants.properties b/samples/corda/corda-simple-application/constants.properties index e2e45a282..2e55ff254 100644 --- a/samples/corda/corda-simple-application/constants.properties +++ b/samples/corda/corda-simple-application/constants.properties @@ -9,5 +9,5 @@ log4jVersion =2.16.0 platformVersion=10 slf4jVersion=1.7.25 nettyVersion=4.1.22.Final -weaverProtosVersion=1.3.2 +weaverProtosVersion=1.4.0 weaverCordaVersion=1.2.9 diff --git a/sdks/corda/build.gradle b/sdks/corda/build.gradle index c7217c98f..43a87b4b2 100644 --- a/sdks/corda/build.gradle +++ b/sdks/corda/build.gradle @@ -13,7 +13,7 @@ buildscript { ext.corda_gradle_plugins_version = "5.0.12" ext.log4j_version = "2.16.0" ext.slf4j_version = "1.7.25" - ext.weaver_protos_version = "1.3.2" + ext.weaver_protos_version = "1.4.0" ext.weaver_corda_version = "1.2.9" dependencies { diff --git a/tests/network-setups/corda/scripts/get-cordapps.sh b/tests/network-setups/corda/scripts/get-cordapps.sh index 2d6e1bac9..97863fe28 100755 --- a/tests/network-setups/corda/scripts/get-cordapps.sh +++ b/tests/network-setups/corda/scripts/get-cordapps.sh @@ -4,7 +4,7 @@ directory=$(dirname $0) app=${1:-simple} local=$2 weaverCordaVersion="1.2.9" -weaverProtosVersion="1.3.2" +weaverProtosVersion="1.4.0" if [ "simple" = "$app" ]; then cordappPath=$directory/../../../../samples/corda/corda-simple-application diff --git a/tests/network-setups/corda/scripts/start-nodes.sh b/tests/network-setups/corda/scripts/start-nodes.sh index 703a7b873..96e85fa4f 100755 --- a/tests/network-setups/corda/scripts/start-nodes.sh +++ b/tests/network-setups/corda/scripts/start-nodes.sh @@ -10,7 +10,7 @@ houseTokenAppVersion="1.0" tokenVersion="1.2" weaverCordaVersion="1.2.9" -weaverProtosVersion="1.3.2" +weaverProtosVersion="1.4.0" parties="Notary PartyA PartyB PartyC" From faafc01b436fda90684f828995a240edcf633525 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Wed, 6 Jul 2022 23:13:03 +0530 Subject: [PATCH 018/150] fix comment texts in relay source code Signed-off-by: sandeep.nishad1 --- core/relay/src/services/event_subscribe_service.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/relay/src/services/event_subscribe_service.rs b/core/relay/src/services/event_subscribe_service.rs index 74e95f198..dadd16ece 100644 --- a/core/relay/src/services/event_subscribe_service.rs +++ b/core/relay/src/services/event_subscribe_service.rs @@ -36,8 +36,8 @@ pub struct Network { network: String, } -/// DataTransferService is the gRPC server implementation that handles the logic for -/// communication of the data transfer protocol between two relays. +/// EventSubscribeService is the gRPC server implementation that handles the logic for +/// communicating event subscription request between two relays and driver. #[tonic::async_trait] impl EventSubscribe for EventSubscribeService { async fn subscribe_event(&self, request: Request) -> Result, Status> { @@ -139,7 +139,7 @@ impl EventSubscribe for EventSubscribeService { } -/// request_state is run on the remote relay to retrieve the state that was +/// subscribe_event is run on the remote relay to subscribe to the event that was /// requested from the requesting relay fn subscribe_event_helper( remote_db: Database, @@ -194,7 +194,7 @@ fn subscribe_event_helper( }); } -// Function that starts a thread which sends the query information to the driver +// Function that starts a thread which sends the event subscription request to the driver fn spawn_driver_subscribe_event(event_subscription: EventSubscription, hostname: String, port: String, use_tls: bool, tlsca_cert_path: String, conf: config::Config) { tokio::spawn(async move { let result = spawn_driver_subscribe_event_helper(event_subscription.clone(), hostname, port, use_tls, tlsca_cert_path).await; @@ -205,7 +205,7 @@ fn spawn_driver_subscribe_event(event_subscription: EventSubscription, hostname: } Err(e) => { println!("Error sending event subscription request to driver: {:?}\n", e); - // In Error case we send an error_state to requesting relay. + // In Error case we send an error_ack to requesting relay. let query = event_subscription.query.clone().expect("No query passed with EventSubscription request"); let request_id = query.request_id.to_string(); // Database access/storage From 18b7aa36dbdc697cbf2faee78d67acc24ac23cdd Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Thu, 7 Jul 2022 11:00:08 +0530 Subject: [PATCH 019/150] converted camelCase variable names in event protos to underscore Signed-off-by: sandeep.nishad1 --- common/protos/common/events.proto | 26 ++++++++++++++------------ common/protos/networks/networks.proto | 4 ++-- core/relay/src/client.rs | 4 +++- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/common/protos/common/events.proto b/common/protos/common/events.proto index b7cdac80a..e96dce116 100644 --- a/common/protos/common/events.proto +++ b/common/protos/common/events.proto @@ -8,18 +8,20 @@ option java_package = "com.weaver.protos.common.events"; option go_package = "github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go/common"; enum EventType { - LedgerState = 0; - AssetLock = 1; - AssetClaim = 2; + LEDGER_STATE = 0; + ASSET_LOCK = 1; + ASSET_CLAIM = 2; } message EventMatcher { - EventType type = 1; + EventType event_type = 1; string event_name = 2; - string transaction_func = 3; + string ledger_id = 3; + string contract_id = 4; + string transaction_func = 5; } message EventSubscription { - EventMatcher eventMatcher = 1; + EventMatcher event_matcher = 1; common.query.Query query = 2; } message EventSubscriptionState { @@ -34,17 +36,17 @@ message EventSubscriptionState { string request_id = 1; STATUS status = 2; string message = 3; - EventMatcher eventMatcher = 4; - EventPublication eventPublicationSpec = 5; + EventMatcher event_matcher = 4; + EventPublication event_publication_spec = 5; } message ContractTransaction { - string driverId = 1; - string ledgerId = 2; - string contractId = 3; + string driver_id = 1; + string ledger_id = 2; + string contract_id = 3; string func = 4; repeated bytes args = 5; - uint64 replaceArgIndex = 6; + uint64 replace_arg_index = 6; } message EventPublication { diff --git a/common/protos/networks/networks.proto b/common/protos/networks/networks.proto index c00792d64..4ea7ccdd3 100644 --- a/common/protos/networks/networks.proto +++ b/common/protos/networks/networks.proto @@ -51,7 +51,7 @@ message NetworkQuery { bool confidential = 9; } message NetworkEventSubscription { - common.events.EventMatcher eventMatcher = 1; + common.events.EventMatcher event_matcher = 1; NetworkQuery query = 2; - common.events.EventPublication eventPublicationSpec = 3; + common.events.EventPublication event_publication_spec = 3; } diff --git a/core/relay/src/client.rs b/core/relay/src/client.rs index 04ec38591..1d7b67e0c 100644 --- a/core/relay/src/client.rs +++ b/core/relay/src/client.rs @@ -99,8 +99,10 @@ async fn event_suscribe() -> Result<(), Box> { confidential: false, }; let event_matcher = EventMatcher { - r#type: 0, + event_type: 0, event_name: "test".to_string(), + ledger_id: "test".to_string(), + contract_id: "test".to_string(), transaction_func: "test".to_string(), }; let tmp = event_publication::PublicationTarget::AppUrl("abc".to_string()); From b9395a08a4b3d62904843fbaf863a3cc0631eaf5 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Thu, 7 Jul 2022 11:01:23 +0530 Subject: [PATCH 020/150] converted camelCase variable names in event protos to underscore Signed-off-by: sandeep.nishad1 --- common/protos-go/common/events.pb.go | 215 +++++++++++++---------- common/protos-go/networks/networks.pb.go | 101 +++++------ 2 files changed, 169 insertions(+), 147 deletions(-) diff --git a/common/protos-go/common/events.pb.go b/common/protos-go/common/events.pb.go index 9b2c160fe..0ffb99747 100644 --- a/common/protos-go/common/events.pb.go +++ b/common/protos-go/common/events.pb.go @@ -23,22 +23,22 @@ const ( type EventType int32 const ( - EventType_LedgerState EventType = 0 - EventType_AssetLock EventType = 1 - EventType_AssetClaim EventType = 2 + EventType_LEDGER_STATE EventType = 0 + EventType_ASSET_LOCK EventType = 1 + EventType_ASSET_CLAIM EventType = 2 ) // Enum value maps for EventType. var ( EventType_name = map[int32]string{ - 0: "LedgerState", - 1: "AssetLock", - 2: "AssetClaim", + 0: "LEDGER_STATE", + 1: "ASSET_LOCK", + 2: "ASSET_CLAIM", } EventType_value = map[string]int32{ - "LedgerState": 0, - "AssetLock": 1, - "AssetClaim": 2, + "LEDGER_STATE": 0, + "ASSET_LOCK": 1, + "ASSET_CLAIM": 2, } ) @@ -128,9 +128,11 @@ type EventMatcher struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Type EventType `protobuf:"varint,1,opt,name=type,proto3,enum=common.events.EventType" json:"type,omitempty"` + EventType EventType `protobuf:"varint,1,opt,name=event_type,json=eventType,proto3,enum=common.events.EventType" json:"event_type,omitempty"` EventName string `protobuf:"bytes,2,opt,name=event_name,json=eventName,proto3" json:"event_name,omitempty"` - TransactionFunc string `protobuf:"bytes,3,opt,name=transaction_func,json=transactionFunc,proto3" json:"transaction_func,omitempty"` + LedgerId string `protobuf:"bytes,3,opt,name=ledger_id,json=ledgerId,proto3" json:"ledger_id,omitempty"` + ContractId string `protobuf:"bytes,4,opt,name=contract_id,json=contractId,proto3" json:"contract_id,omitempty"` + TransactionFunc string `protobuf:"bytes,5,opt,name=transaction_func,json=transactionFunc,proto3" json:"transaction_func,omitempty"` } func (x *EventMatcher) Reset() { @@ -165,11 +167,11 @@ func (*EventMatcher) Descriptor() ([]byte, []int) { return file_common_events_proto_rawDescGZIP(), []int{0} } -func (x *EventMatcher) GetType() EventType { +func (x *EventMatcher) GetEventType() EventType { if x != nil { - return x.Type + return x.EventType } - return EventType_LedgerState + return EventType_LEDGER_STATE } func (x *EventMatcher) GetEventName() string { @@ -179,6 +181,20 @@ func (x *EventMatcher) GetEventName() string { return "" } +func (x *EventMatcher) GetLedgerId() string { + if x != nil { + return x.LedgerId + } + return "" +} + +func (x *EventMatcher) GetContractId() string { + if x != nil { + return x.ContractId + } + return "" +} + func (x *EventMatcher) GetTransactionFunc() string { if x != nil { return x.TransactionFunc @@ -191,7 +207,7 @@ type EventSubscription struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - EventMatcher *EventMatcher `protobuf:"bytes,1,opt,name=eventMatcher,proto3" json:"eventMatcher,omitempty"` + EventMatcher *EventMatcher `protobuf:"bytes,1,opt,name=event_matcher,json=eventMatcher,proto3" json:"event_matcher,omitempty"` Query *Query `protobuf:"bytes,2,opt,name=query,proto3" json:"query,omitempty"` } @@ -249,8 +265,8 @@ type EventSubscriptionState struct { RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` Status EventSubscriptionState_STATUS `protobuf:"varint,2,opt,name=status,proto3,enum=common.events.EventSubscriptionState_STATUS" json:"status,omitempty"` Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"` - EventMatcher *EventMatcher `protobuf:"bytes,4,opt,name=eventMatcher,proto3" json:"eventMatcher,omitempty"` - EventPublicationSpec *EventPublication `protobuf:"bytes,5,opt,name=eventPublicationSpec,proto3" json:"eventPublicationSpec,omitempty"` + EventMatcher *EventMatcher `protobuf:"bytes,4,opt,name=event_matcher,json=eventMatcher,proto3" json:"event_matcher,omitempty"` + EventPublicationSpec *EventPublication `protobuf:"bytes,5,opt,name=event_publication_spec,json=eventPublicationSpec,proto3" json:"event_publication_spec,omitempty"` } func (x *EventSubscriptionState) Reset() { @@ -325,12 +341,12 @@ type ContractTransaction struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - DriverId string `protobuf:"bytes,1,opt,name=driverId,proto3" json:"driverId,omitempty"` - LedgerId string `protobuf:"bytes,2,opt,name=ledgerId,proto3" json:"ledgerId,omitempty"` - ContractId string `protobuf:"bytes,3,opt,name=contractId,proto3" json:"contractId,omitempty"` + DriverId string `protobuf:"bytes,1,opt,name=driver_id,json=driverId,proto3" json:"driver_id,omitempty"` + LedgerId string `protobuf:"bytes,2,opt,name=ledger_id,json=ledgerId,proto3" json:"ledger_id,omitempty"` + ContractId string `protobuf:"bytes,3,opt,name=contract_id,json=contractId,proto3" json:"contract_id,omitempty"` Func string `protobuf:"bytes,4,opt,name=func,proto3" json:"func,omitempty"` Args [][]byte `protobuf:"bytes,5,rep,name=args,proto3" json:"args,omitempty"` - ReplaceArgIndex uint64 `protobuf:"varint,6,opt,name=replaceArgIndex,proto3" json:"replaceArgIndex,omitempty"` + ReplaceArgIndex uint64 `protobuf:"varint,6,opt,name=replace_arg_index,json=replaceArgIndex,proto3" json:"replace_arg_index,omitempty"` } func (x *ContractTransaction) Reset() { @@ -493,78 +509,83 @@ var file_common_events_proto_rawDesc = []byte{ 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0x12, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x71, 0x75, 0x65, - 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x86, 0x01, 0x0a, 0x0c, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x2c, 0x0a, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, - 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x76, 0x65, - 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x75, 0x6e, - 0x63, 0x22, 0x7f, 0x0a, 0x11, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3f, 0x0a, 0x0c, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, - 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x52, 0x0c, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x29, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, - 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x05, 0x71, 0x75, 0x65, - 0x72, 0x79, 0x22, 0xed, 0x02, 0x0a, 0x16, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1d, 0x0a, - 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x44, 0x0a, 0x06, - 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x2e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3f, 0x0a, 0x0c, - 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x52, - 0x0c, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x53, 0x0a, - 0x14, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x53, 0x70, 0x65, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x14, 0x65, 0x76, - 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x70, - 0x65, 0x63, 0x22, 0x3e, 0x0a, 0x06, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x12, 0x0f, 0x0a, 0x0b, - 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x41, 0x43, 0x4b, 0x10, 0x00, 0x12, 0x0b, 0x0a, - 0x07, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, - 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, - 0x10, 0x03, 0x22, 0xbf, 0x01, 0x0a, 0x13, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x72, - 0x69, 0x76, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x72, - 0x69, 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, - 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, - 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x49, 0x64, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, - 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x75, 0x6e, 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x66, 0x75, 0x6e, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x67, 0x73, 0x18, 0x05, - 0x20, 0x03, 0x28, 0x0c, 0x52, 0x04, 0x61, 0x72, 0x67, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x72, 0x65, - 0x70, 0x6c, 0x61, 0x63, 0x65, 0x41, 0x72, 0x67, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x0f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x41, 0x72, 0x67, 0x49, - 0x6e, 0x64, 0x65, 0x78, 0x22, 0x7b, 0x0a, 0x10, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x03, 0x63, 0x74, 0x78, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, - 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x03, 0x63, 0x74, 0x78, - 0x12, 0x19, 0x0a, 0x07, 0x61, 0x70, 0x70, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x48, 0x00, 0x52, 0x06, 0x61, 0x70, 0x70, 0x55, 0x72, 0x6c, 0x42, 0x14, 0x0a, 0x12, 0x70, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, - 0x74, 0x2a, 0x3b, 0x0a, 0x09, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0f, - 0x0a, 0x0b, 0x4c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x10, 0x00, 0x12, - 0x0d, 0x0a, 0x09, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x10, 0x01, 0x12, 0x0e, - 0x0a, 0x0a, 0x41, 0x73, 0x73, 0x65, 0x74, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x10, 0x02, 0x42, 0x72, - 0x0a, 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x73, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, - 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, - 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, - 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xcf, 0x01, 0x0a, 0x0c, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x37, 0x0a, 0x0a, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1f, + 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x49, 0x64, 0x12, + 0x29, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x66, + 0x75, 0x6e, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x75, 0x6e, 0x63, 0x22, 0x80, 0x01, 0x0a, 0x11, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x40, 0x0a, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, + 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, + 0x63, 0x68, 0x65, 0x72, 0x52, 0x0c, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, + 0x65, 0x72, 0x12, 0x29, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, + 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0xf0, 0x02, + 0x0a, 0x16, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x44, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x53, + 0x54, 0x41, 0x54, 0x55, 0x53, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, + 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x40, 0x0a, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x52, 0x0c, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x55, 0x0a, 0x16, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, + 0x70, 0x65, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x14, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, + 0x22, 0x3e, 0x0a, 0x06, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x45, + 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x41, 0x43, 0x4b, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x50, + 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, + 0x52, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x03, + 0x22, 0xc4, 0x01, 0x0a, 0x13, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x72, 0x69, 0x76, + 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x72, 0x69, + 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x5f, + 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, + 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, 0x69, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, + 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x75, 0x6e, 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x66, 0x75, 0x6e, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x67, 0x73, 0x18, + 0x05, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x04, 0x61, 0x72, 0x67, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x72, + 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x5f, 0x61, 0x72, 0x67, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x41, + 0x72, 0x67, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x7b, 0x0a, 0x10, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x03, 0x63, + 0x74, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, + 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x03, + 0x63, 0x74, 0x78, 0x12, 0x19, 0x0a, 0x07, 0x61, 0x70, 0x70, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x61, 0x70, 0x70, 0x55, 0x72, 0x6c, 0x42, 0x14, + 0x0a, 0x12, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x2a, 0x3e, 0x0a, 0x09, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x4c, 0x45, 0x44, 0x47, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, + 0x45, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x53, 0x53, 0x45, 0x54, 0x5f, 0x4c, 0x4f, 0x43, + 0x4b, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x53, 0x53, 0x45, 0x54, 0x5f, 0x43, 0x4c, 0x41, + 0x49, 0x4d, 0x10, 0x02, 0x42, 0x72, 0x0a, 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, + 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, + 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, + 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, + 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -592,12 +613,12 @@ var file_common_events_proto_goTypes = []interface{}{ (*Query)(nil), // 7: common.query.Query } var file_common_events_proto_depIdxs = []int32{ - 0, // 0: common.events.EventMatcher.type:type_name -> common.events.EventType - 2, // 1: common.events.EventSubscription.eventMatcher:type_name -> common.events.EventMatcher + 0, // 0: common.events.EventMatcher.event_type:type_name -> common.events.EventType + 2, // 1: common.events.EventSubscription.event_matcher:type_name -> common.events.EventMatcher 7, // 2: common.events.EventSubscription.query:type_name -> common.query.Query 1, // 3: common.events.EventSubscriptionState.status:type_name -> common.events.EventSubscriptionState.STATUS - 2, // 4: common.events.EventSubscriptionState.eventMatcher:type_name -> common.events.EventMatcher - 6, // 5: common.events.EventSubscriptionState.eventPublicationSpec:type_name -> common.events.EventPublication + 2, // 4: common.events.EventSubscriptionState.event_matcher:type_name -> common.events.EventMatcher + 6, // 5: common.events.EventSubscriptionState.event_publication_spec:type_name -> common.events.EventPublication 5, // 6: common.events.EventPublication.ctx:type_name -> common.events.ContractTransaction 7, // [7:7] is the sub-list for method output_type 7, // [7:7] is the sub-list for method input_type diff --git a/common/protos-go/networks/networks.pb.go b/common/protos-go/networks/networks.pb.go index c7e4896b9..95f19ae3d 100644 --- a/common/protos-go/networks/networks.pb.go +++ b/common/protos-go/networks/networks.pb.go @@ -278,9 +278,9 @@ type NetworkEventSubscription struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - EventMatcher *common.EventMatcher `protobuf:"bytes,1,opt,name=eventMatcher,proto3" json:"eventMatcher,omitempty"` + EventMatcher *common.EventMatcher `protobuf:"bytes,1,opt,name=event_matcher,json=eventMatcher,proto3" json:"event_matcher,omitempty"` Query *NetworkQuery `protobuf:"bytes,2,opt,name=query,proto3" json:"query,omitempty"` - EventPublicationSpec *common.EventPublication `protobuf:"bytes,3,opt,name=eventPublicationSpec,proto3" json:"eventPublicationSpec,omitempty"` + EventPublicationSpec *common.EventPublication `protobuf:"bytes,3,opt,name=event_publication_spec,json=eventPublicationSpec,proto3" json:"event_publication_spec,omitempty"` } func (x *NetworkEventSubscription) Reset() { @@ -380,56 +380,57 @@ var file_networks_networks_proto_rawDesc = []byte{ 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4f, 0x72, 0x67, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xe7, 0x01, 0x0a, 0x18, 0x4e, 0x65, 0x74, 0x77, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xea, 0x01, 0x0a, 0x18, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3f, 0x0a, 0x0c, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, - 0x63, 0x68, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x52, 0x0c, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, - 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x35, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x53, 0x0a, 0x14, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x61, + 0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x52, 0x0c, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, + 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x35, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, + 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x55, 0x0a, + 0x16, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x14, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x53, 0x70, 0x65, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x14, 0x65, 0x76, 0x65, - 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, - 0x63, 0x32, 0xa9, 0x03, 0x0a, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x42, 0x0a, - 0x0c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x2e, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x0f, - 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, - 0x00, 0x12, 0x4c, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x22, 0x2e, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x73, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x1a, 0x1a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, - 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x00, 0x12, - 0x50, 0x0a, 0x0f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, - 0x73, 0x65, 0x12, 0x19, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x44, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x1a, 0x20, 0x2e, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x73, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x22, - 0x00, 0x12, 0x50, 0x0a, 0x0e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x12, 0x2b, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, - 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, - 0x6b, 0x22, 0x00, 0x12, 0x68, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, - 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x53, 0x70, 0x65, 0x63, 0x32, 0xa9, 0x03, 0x0a, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x12, 0x42, 0x0a, 0x0c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x12, 0x1f, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, + 0x63, 0x6b, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x22, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x1a, 0x25, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, - 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x00, 0x42, 0x78, 0x0a, - 0x23, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x73, 0x5a, 0x51, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, - 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x6e, - 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x22, 0x00, 0x12, 0x50, 0x0a, 0x0f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, + 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x19, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, + 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x44, 0x62, 0x4e, 0x61, 0x6d, 0x65, + 0x1a, 0x20, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, + 0x73, 0x65, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x0e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, + 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2b, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, + 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x68, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x12, 0x22, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x25, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x00, + 0x42, 0x78, 0x0a, 0x23, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x5a, 0x51, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, + 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, + 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, + 0x6f, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( @@ -460,9 +461,9 @@ var file_networks_networks_proto_goTypes = []interface{}{ } var file_networks_networks_proto_depIdxs = []int32{ 5, // 0: networks.networks.RelayDatabase.pairs:type_name -> networks.networks.RelayDatabase.PairsEntry - 6, // 1: networks.networks.NetworkEventSubscription.eventMatcher:type_name -> common.events.EventMatcher + 6, // 1: networks.networks.NetworkEventSubscription.event_matcher:type_name -> common.events.EventMatcher 3, // 2: networks.networks.NetworkEventSubscription.query:type_name -> networks.networks.NetworkQuery - 7, // 3: networks.networks.NetworkEventSubscription.eventPublicationSpec:type_name -> common.events.EventPublication + 7, // 3: networks.networks.NetworkEventSubscription.event_publication_spec:type_name -> common.events.EventPublication 3, // 4: networks.networks.Network.RequestState:input_type -> networks.networks.NetworkQuery 2, // 5: networks.networks.Network.GetState:input_type -> networks.networks.GetStateMessage 0, // 6: networks.networks.Network.RequestDatabase:input_type -> networks.networks.DbName From cb8690138ea1743e72ea91e8b4803215c16f707c Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Thu, 7 Jul 2022 11:28:16 +0530 Subject: [PATCH 021/150] add delay before running relay client test in workflow Signed-off-by: sandeep.nishad1 --- .github/workflows/test_relay.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test_relay.yml b/.github/workflows/test_relay.yml index b36d7d1c3..6ce645de5 100644 --- a/.github/workflows/test_relay.yml +++ b/.github/workflows/test_relay.yml @@ -45,5 +45,8 @@ jobs: working-directory: core/relay - name: Mock Client Test - run: cargo run --bin client 9085 localhost:9085/Dummy_Network/abc:abc:abc:abc + run: | + echo "Waiting for Dummy Relay and Driver to come up" + sleep 30 + cargo run --bin client 9085 localhost:9085/Dummy_Network/abc:abc:abc:abc working-directory: core/relay \ No newline at end of file From 91195b1e05251483b03cca8d8e5a22036809b603 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Thu, 7 Jul 2022 11:40:53 +0530 Subject: [PATCH 022/150] Updated variable names in event matcher proto Signed-off-by: sandeep.nishad1 --- common/protos-go/common/events.pb.go | 170 ++++++++++++++------------- common/protos/common/events.proto | 10 +- 2 files changed, 92 insertions(+), 88 deletions(-) diff --git a/common/protos-go/common/events.pb.go b/common/protos-go/common/events.pb.go index 0ffb99747..ab82338c3 100644 --- a/common/protos-go/common/events.pb.go +++ b/common/protos-go/common/events.pb.go @@ -128,11 +128,11 @@ type EventMatcher struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - EventType EventType `protobuf:"varint,1,opt,name=event_type,json=eventType,proto3,enum=common.events.EventType" json:"event_type,omitempty"` - EventName string `protobuf:"bytes,2,opt,name=event_name,json=eventName,proto3" json:"event_name,omitempty"` - LedgerId string `protobuf:"bytes,3,opt,name=ledger_id,json=ledgerId,proto3" json:"ledger_id,omitempty"` - ContractId string `protobuf:"bytes,4,opt,name=contract_id,json=contractId,proto3" json:"contract_id,omitempty"` - TransactionFunc string `protobuf:"bytes,5,opt,name=transaction_func,json=transactionFunc,proto3" json:"transaction_func,omitempty"` + EventType EventType `protobuf:"varint,1,opt,name=event_type,json=eventType,proto3,enum=common.events.EventType" json:"event_type,omitempty"` + EventClassId string `protobuf:"bytes,2,opt,name=event_class_id,json=eventClassId,proto3" json:"event_class_id,omitempty"` + TransactionLedgerId string `protobuf:"bytes,3,opt,name=transaction_ledger_id,json=transactionLedgerId,proto3" json:"transaction_ledger_id,omitempty"` + TransactionContractId string `protobuf:"bytes,4,opt,name=transaction_contract_id,json=transactionContractId,proto3" json:"transaction_contract_id,omitempty"` + TransactionFunc string `protobuf:"bytes,5,opt,name=transaction_func,json=transactionFunc,proto3" json:"transaction_func,omitempty"` } func (x *EventMatcher) Reset() { @@ -174,23 +174,23 @@ func (x *EventMatcher) GetEventType() EventType { return EventType_LEDGER_STATE } -func (x *EventMatcher) GetEventName() string { +func (x *EventMatcher) GetEventClassId() string { if x != nil { - return x.EventName + return x.EventClassId } return "" } -func (x *EventMatcher) GetLedgerId() string { +func (x *EventMatcher) GetTransactionLedgerId() string { if x != nil { - return x.LedgerId + return x.TransactionLedgerId } return "" } -func (x *EventMatcher) GetContractId() string { +func (x *EventMatcher) GetTransactionContractId() string { if x != nil { - return x.ContractId + return x.TransactionContractId } return "" } @@ -509,83 +509,87 @@ var file_common_events_proto_rawDesc = []byte{ 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0x12, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x71, 0x75, 0x65, - 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xcf, 0x01, 0x0a, 0x0c, 0x45, 0x76, 0x65, + 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x84, 0x02, 0x0a, 0x0c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x37, 0x0a, 0x0a, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1f, - 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x49, 0x64, 0x12, - 0x29, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x66, - 0x75, 0x6e, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x75, 0x6e, 0x63, 0x22, 0x80, 0x01, 0x0a, 0x11, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x40, 0x0a, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, - 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, - 0x63, 0x68, 0x65, 0x72, 0x52, 0x0c, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, - 0x65, 0x72, 0x12, 0x29, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, - 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0xf0, 0x02, - 0x0a, 0x16, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x44, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x53, - 0x54, 0x41, 0x54, 0x55, 0x53, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, - 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x40, 0x0a, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, + 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6c, 0x61, 0x73, + 0x73, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x15, 0x74, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x5f, 0x69, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x49, 0x64, 0x12, 0x36, 0x0a, 0x17, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, + 0x63, 0x74, 0x49, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x75, 0x6e, 0x63, 0x22, + 0x80, 0x01, 0x0a, 0x11, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, + 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x52, 0x0c, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x29, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x05, 0x71, 0x75, 0x65, + 0x72, 0x79, 0x22, 0xf0, 0x02, 0x0a, 0x16, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1d, 0x0a, + 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x44, 0x0a, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x2e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x40, 0x0a, 0x0d, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, + 0x52, 0x0c, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x55, + 0x0a, 0x16, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x52, 0x0c, 0x65, 0x76, 0x65, - 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x55, 0x0a, 0x16, 0x65, 0x76, 0x65, - 0x6e, 0x74, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, - 0x70, 0x65, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x50, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x14, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, - 0x22, 0x3e, 0x0a, 0x06, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x45, - 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x41, 0x43, 0x4b, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x50, - 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, - 0x52, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x03, - 0x22, 0xc4, 0x01, 0x0a, 0x13, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x72, 0x69, 0x76, - 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x72, 0x69, - 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x5f, - 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, - 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, 0x69, - 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, - 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x75, 0x6e, 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x66, 0x75, 0x6e, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x67, 0x73, 0x18, - 0x05, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x04, 0x61, 0x72, 0x67, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x72, - 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x5f, 0x61, 0x72, 0x67, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x41, - 0x72, 0x67, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x7b, 0x0a, 0x10, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x03, 0x63, - 0x74, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, - 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x03, - 0x63, 0x74, 0x78, 0x12, 0x19, 0x0a, 0x07, 0x61, 0x70, 0x70, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x61, 0x70, 0x70, 0x55, 0x72, 0x6c, 0x42, 0x14, - 0x0a, 0x12, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x61, - 0x72, 0x67, 0x65, 0x74, 0x2a, 0x3e, 0x0a, 0x09, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x4c, 0x45, 0x44, 0x47, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, - 0x45, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x53, 0x53, 0x45, 0x54, 0x5f, 0x4c, 0x4f, 0x43, - 0x4b, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x53, 0x53, 0x45, 0x54, 0x5f, 0x43, 0x4c, 0x41, - 0x49, 0x4d, 0x10, 0x02, 0x42, 0x72, 0x0a, 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, - 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, - 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, - 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, - 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x14, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x53, 0x70, 0x65, 0x63, 0x22, 0x3e, 0x0a, 0x06, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x12, + 0x0f, 0x0a, 0x0b, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x41, 0x43, 0x4b, 0x10, 0x00, + 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, + 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, + 0x45, 0x53, 0x53, 0x10, 0x03, 0x22, 0xc4, 0x01, 0x0a, 0x13, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, + 0x63, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, + 0x09, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x65, + 0x64, 0x67, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, + 0x65, 0x64, 0x67, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x61, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x75, 0x6e, 0x63, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x75, 0x6e, 0x63, 0x12, 0x12, 0x0a, 0x04, + 0x61, 0x72, 0x67, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x04, 0x61, 0x72, 0x67, 0x73, + 0x12, 0x2a, 0x0a, 0x11, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x5f, 0x61, 0x72, 0x67, 0x5f, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x72, 0x65, 0x70, + 0x6c, 0x61, 0x63, 0x65, 0x41, 0x72, 0x67, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x7b, 0x0a, 0x10, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x36, 0x0a, 0x03, 0x63, 0x74, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, + 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x48, 0x00, 0x52, 0x03, 0x63, 0x74, 0x78, 0x12, 0x19, 0x0a, 0x07, 0x61, 0x70, 0x70, 0x5f, + 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x61, 0x70, 0x70, + 0x55, 0x72, 0x6c, 0x42, 0x14, 0x0a, 0x12, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2a, 0x3e, 0x0a, 0x09, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x4c, 0x45, 0x44, 0x47, 0x45, 0x52, + 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x53, 0x53, 0x45, + 0x54, 0x5f, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x53, 0x53, 0x45, + 0x54, 0x5f, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x10, 0x02, 0x42, 0x72, 0x0a, 0x1f, 0x63, 0x6f, 0x6d, + 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x5a, 0x4f, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, + 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, + 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, + 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/common/protos/common/events.proto b/common/protos/common/events.proto index e96dce116..f04d3bd19 100644 --- a/common/protos/common/events.proto +++ b/common/protos/common/events.proto @@ -14,11 +14,11 @@ enum EventType { } message EventMatcher { - EventType event_type = 1; - string event_name = 2; - string ledger_id = 3; - string contract_id = 4; - string transaction_func = 5; + EventType event_type = 1; + string event_class_id = 2; + string transaction_ledger_id = 3; + string transaction_contract_id = 4; + string transaction_func = 5; } message EventSubscription { EventMatcher event_matcher = 1; From d2186563cef253ed85450e06dbbe0738d9fbb900 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Thu, 7 Jul 2022 11:55:59 +0530 Subject: [PATCH 023/150] update event protos variable names in relay client Signed-off-by: sandeep.nishad1 --- core/relay/src/client.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/relay/src/client.rs b/core/relay/src/client.rs index 1d7b67e0c..adb347300 100644 --- a/core/relay/src/client.rs +++ b/core/relay/src/client.rs @@ -100,9 +100,9 @@ async fn event_suscribe() -> Result<(), Box> { }; let event_matcher = EventMatcher { event_type: 0, - event_name: "test".to_string(), - ledger_id: "test".to_string(), - contract_id: "test".to_string(), + event_class_id: "test".to_string(), + transaction_ledger_id: "test".to_string(), + transaction_contract_id: "test".to_string(), transaction_func: "test".to_string(), }; let tmp = event_publication::PublicationTarget::AppUrl("abc".to_string()); From 24a9256400171c5560a2b559d5f78868d2725b07 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Thu, 7 Jul 2022 16:15:03 +0530 Subject: [PATCH 024/150] added event subscription api in weaver sdk and a sample command in fabric-cli Signed-off-by: sandeep.nishad1 --- .../fabric-cli/src/commands/event-helper.ts | 24 +++ .../src/commands/event/suscribe-driver.ts | 125 ++++++++++++++ .../fabric-cli/src/data/event_sub_sample.json | 19 +++ sdks/fabric/interoperation-node-sdk/index.js | 1 + .../package-local.json | 2 +- .../interoperation-node-sdk/package.json | 4 +- .../src/EventsManager.ts | 155 ++++++++++++++++++ .../src/InteroperableHelper.ts | 1 + .../interoperation-node-sdk/src/Relay.ts | 151 +++++++++++++++++ .../interoperation-node-sdk/types/index.d.ts | 2 + 10 files changed, 481 insertions(+), 3 deletions(-) create mode 100644 samples/fabric/fabric-cli/src/commands/event-helper.ts create mode 100644 samples/fabric/fabric-cli/src/commands/event/suscribe-driver.ts create mode 100644 samples/fabric/fabric-cli/src/data/event_sub_sample.json create mode 100644 sdks/fabric/interoperation-node-sdk/src/EventsManager.ts diff --git a/samples/fabric/fabric-cli/src/commands/event-helper.ts b/samples/fabric/fabric-cli/src/commands/event-helper.ts new file mode 100644 index 000000000..15f2d095d --- /dev/null +++ b/samples/fabric/fabric-cli/src/commands/event-helper.ts @@ -0,0 +1,24 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import { GluegunCommand } from 'gluegun' +import { commandHelp } from '../helpers/helpers' + +const command: GluegunCommand = { + name: 'event', + alias: ['e'], + description: 'Event Subscription and receive', + run: async toolbox => { + const { print } = toolbox + print.info('Command does nothing by itself') + commandHelp(print, toolbox, 'fabric-cli event', '', [], command, [ + 'event' + ]) + return + } +} + +module.exports = command diff --git a/samples/fabric/fabric-cli/src/commands/event/suscribe-driver.ts b/samples/fabric/fabric-cli/src/commands/event/suscribe-driver.ts new file mode 100644 index 000000000..9ce8e2421 --- /dev/null +++ b/samples/fabric/fabric-cli/src/commands/event/suscribe-driver.ts @@ -0,0 +1,125 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import { GluegunCommand } from 'gluegun' +import { fabricHelper, getKeyAndCertForRemoteRequestbyUserName } from '../../helpers/fabric-functions' +import logger from '../../helpers/logger' +import { Utils, ICryptoKey } from 'fabric-common' +import { commandHelp, getNetworkConfig, handlePromise } from '../../helpers/helpers' +import { EventsManager } from '@hyperledger-labs/weaver-fabric-interop-sdk' +import { EventSubscriptionState, EventType } from "@hyperledger-labs/weaver-protos-js/common/events_pb"; +import * as fs from 'fs' +import * as path from 'path' + +const command: GluegunCommand = { + name: 'subscribe-driver', + alias: ['-sd'], + description: 'Initiate event subscribe for driver', + run: async toolbox => { + const { + print, + parameters: { options, array } + } = toolbox + if (options.help || options.h) { + commandHelp( + print, + toolbox, + `fabric-cli event subscribe --network= --user= src/data/event_sub_sample.json`, + 'fabric-cli event subscribe --network= --user= ', + [ + { + name: '--network', + description: + 'Local network for command. ' + }, + { + name: '--user', + description: + 'User for subscription. Default: relay' + }, + { + name: '--debug', + description: + 'Shows debug logs when running. Disabled by default. To enable --debug=true' + } + ], + command, + ['event', 'subscribe-driver'] + ) + return + } + console.log("Event Subscription") + if (options.debug === 'true') { + logger.level = 'debug' + logger.debug('Debugging is enabled') + } + if (array.length != 1) { + print.error('Not enough arguments supplied') + return + } + if (!options['user']) { + options['user'] = `relay` //Default user + } + + const networkName = options['network'] + const user = options['user'] + + const filepath = path.resolve(array[0]) + const data = JSON.parse(fs.readFileSync(filepath).toString()) + + const netConfig = getNetworkConfig(networkName) + if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { + throw new Error(`No valid config entry found for ${networkName}`) + } + + const { gateway, wallet, contract } = await fabricHelper({ + channel: netConfig.channelName, + contractName: process.env.DEFAULT_CHAINCODE ? process.env.DEFAULT_CHAINCODE : 'interop', + connProfilePath: netConfig.connProfilePath, + networkName, + mspId: netConfig.mspId, + logger, + discoveryEnabled: true, + userString: user + }) + + const [keyCert, keyCertError] = await handlePromise( + getKeyAndCertForRemoteRequestbyUserName(wallet, user) + ) + if (keyCertError) { + throw new Error(`Error getting key and cert ${keyCertError}`) + } + + const eventMatcher = EventsManager.createEventMatcher(data.event_matcher) + const eventPublicationSpec = EventsManager.createEventPublicationSpec(data.event_publication_spec) + + try { + const response = await EventsManager.subscribeRemoteEvent( + contract, + eventMatcher, + eventPublicationSpec, + networkName, + netConfig.mspId, + netConfig.relayEndpoint, + { address: data.view_address, Sign: true }, + keyCert + ) + + if (response.getStatus() == EventSubscriptionState.STATUS.SUCCESS) { + console.log("Event Subscription Status Success with requestId:", response.getRequestId()) + } else { + console.log("Unknown error") + } + } catch(e) { + console.log("Error: ", e.toString()) + } + + process.exit() + } +} + + +module.exports = command diff --git a/samples/fabric/fabric-cli/src/data/event_sub_sample.json b/samples/fabric/fabric-cli/src/data/event_sub_sample.json new file mode 100644 index 000000000..c8e2c29ac --- /dev/null +++ b/samples/fabric/fabric-cli/src/data/event_sub_sample.json @@ -0,0 +1,19 @@ +{ + "event_matcher": { + "event_type": 1, + "event_class_id": "", + "transaction_ledger_id": "mychannel" + "transaction_contract_id": "simplestate", + "transaction_func": "Create", + }, + "event_publication_spec": { + "args": [], + "contract_id": "simplestate", + "driver_id": "network2", + "func": "Create", + "ledger_id": "mychannel", + "replace_arg_index": "0" + }, + "view_address": "localhost:9083/Dummy_Network/mychannel:simplestate:Read:a", + "confidential": false +} \ No newline at end of file diff --git a/sdks/fabric/interoperation-node-sdk/index.js b/sdks/fabric/interoperation-node-sdk/index.js index 717d184ee..d6a3a08b6 100644 --- a/sdks/fabric/interoperation-node-sdk/index.js +++ b/sdks/fabric/interoperation-node-sdk/index.js @@ -26,3 +26,4 @@ module.exports.RelayHelper = require("./src/Relay.js"); module.exports.InteroperableHelper = require("./src/InteroperableHelper.js"); module.exports.AssetManager = require("./src/AssetManager.js"); module.exports.HashFunctions = require("./src/HashFunctions.js"); +module.exports.EventsManager = require("./src/EventsManager.js"); diff --git a/sdks/fabric/interoperation-node-sdk/package-local.json b/sdks/fabric/interoperation-node-sdk/package-local.json index a21b4bb97..b0e496c5a 100644 --- a/sdks/fabric/interoperation-node-sdk/package-local.json +++ b/sdks/fabric/interoperation-node-sdk/package-local.json @@ -6,7 +6,7 @@ "blockchain", "interoperability" ], - "version": "1.3.1", + "version": "1.4.0", "author": "V. Ramakrishna", "tag": "latest", "main": "build/index.js", diff --git a/sdks/fabric/interoperation-node-sdk/package.json b/sdks/fabric/interoperation-node-sdk/package.json index 6595ee5f3..ba17ba38e 100644 --- a/sdks/fabric/interoperation-node-sdk/package.json +++ b/sdks/fabric/interoperation-node-sdk/package.json @@ -6,7 +6,7 @@ "blockchain", "interoperability" ], - "version": "1.3.1", + "version": "1.4.0", "author": "V. Ramakrishna", "tag": "latest", "main": "build/index.js", @@ -29,7 +29,7 @@ "dependencies": { "@grpc/grpc-js": "^1.1.3", "@grpc/proto-loader": "^0.6.13", - "@hyperledger-labs/weaver-protos-js": "^1.3.1", + "@hyperledger-labs/weaver-protos-js": "^1.4.0", "elliptic": "^6.2.3", "fabric-common": "^2.2.8", "fabric-network": "^2.2.8", diff --git a/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts b/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts new file mode 100644 index 000000000..f5dd374ec --- /dev/null +++ b/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts @@ -0,0 +1,155 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * This file provides helper functions for interoperability operations. + **/ +/** End file docs */ + +import log4js from "log4js"; +import { v4 as uuidv4 } from "uuid"; +import { ICryptoKey } from "fabric-common"; +import { Contract } from "fabric-network"; +import eventsPb from "@hyperledger-labs/weaver-protos-js/common/events_pb"; +import { Relay } from "./Relay"; +import { InteropJSON } from "./types"; +import { getPolicyCriteriaForAddress, createAddress, signMessage } from "./InteroperableHelper"; +import * as helpers from "./helpers"; + +const logger = log4js.getLogger("EventsManager"); + +function createEventMatcher ({ + eventType, + eventClassId, + transactionLedgerId, + transactionContractId, + transactionFunc +}: { + eventType: eventsPb.EventType, + eventClassId: string, + transactionLedgerId: string, + transactionContractId: string, + transactionFunc: string +}): eventsPb.EventMatcher { + const eventMatcher = new eventsPb.EventMatcher() + eventMatcher.setEventType(eventType) + eventMatcher.setEventClassId(eventClassId) + eventMatcher.setTransactionLedgerId(transactionLedgerId) + eventMatcher.setTransactionContractId(transactionContractId) + eventMatcher.setTransactionFunc(transactionFunc) + return eventMatcher +} + + +function createEventPublicationSpec ({ + appUrl, + driverId, + channelId, + chaincodeId, + ccFunc, + ccArgs, + replaceArgIndex +}: { + appUrl?: string, + driverId?: string, + channelId?: string, + chaincodeId?: string, + ccFunc?: string, + ccArgs?: string[], + replaceArgIndex?: number, +}): eventsPb.EventPublication { + const eventPublicationSpec = new eventsPb.EventPublication() + if (appUrl) { + eventPublicationSpec.setAppUrl(appUrl) + } else { + const ctx = new eventsPb.ContractTransaction() + ctx.setDriverId(driverId) + ctx.setLedgerId(channelId) + ctx.setContractId(chaincodeId) + ctx.setFunc(ccFunc) + ctx.setArgsList(ccArgs) + ctx.setReplaceArgIndex(replaceArgIndex) + eventPublicationSpec.setCtx(ctx) + } + return eventPublicationSpec +} + +const subscribeRemoteEvent = async ( + interopContract: Contract, + eventMatcher: eventsPb.EventMatcher, + eventPublicationSpec: eventsPb.EventPublication, + networkID: string, + org: string, + localRelayEndpoint: string, + interopJSON: InteropJSON, + keyCert: { key: ICryptoKey; cert: any }, + useTls: boolean = false, + tlsRootCACertPaths?: Array, + confidential: boolean = false, +): Promise => { + logger.debug("Remote Event Subscription") + const { + address, + ChaincodeFunc, + ChaincodeID, + ChannelID, + RemoteEndpoint, + NetworkID: RemoteNetworkID, + Sign, + ccArgs: args, + } = interopJSON; + // Step 1 + const computedAddress = + address || + createAddress( + { ccFunc: ChaincodeFunc, contractName: ChaincodeID, channel: ChannelID, ccArgs: args }, + RemoteNetworkID, + RemoteEndpoint, + ); + + const [policyCriteria, policyCriteriaError] = await helpers.handlePromise( + getPolicyCriteriaForAddress(interopContract, computedAddress), + ); + if (policyCriteriaError) { + throw new Error(`InteropFlow failed to get policy criteria: ${policyCriteriaError}`); + } + + const relay = useTls ? new Relay(localRelayEndpoint, Relay.defaultTimeout, true, tlsRootCACertPaths) : new Relay(localRelayEndpoint); + const uuidValue = uuidv4(); + + logger.debug("Making event subscription call to relay for \ + event: ${eventMatcher} and publication spec: ${eventPublicationSpec}") + + const [relayResponse, relayResponseError] = await helpers.handlePromise( + relay.ProcessSuscribeEventRequest( + eventMatcher, + eventPublicationSpec, + computedAddress, + policyCriteria, + networkID, + keyCert.cert, + Sign ? signMessage(computedAddress + uuidValue, keyCert.key.toBytes()).toString("base64") : "", + uuidValue, + // Org is empty as the name is in the certs for + org, + confidential, + ), + ); + if (relayResponseError) { + throw new Error(`Event Subscription relay response error: ${relayResponseError}`); + } + + logger.debug(`Event Subscription Successfull: ${JSON.stringify(relayResponse)}`) + + return relayResponse +} + +export { + createEventMatcher, + createEventPublicationSpec, + subscribeRemoteEvent, +} + diff --git a/sdks/fabric/interoperation-node-sdk/src/InteroperableHelper.ts b/sdks/fabric/interoperation-node-sdk/src/InteroperableHelper.ts index b2a24ada5..2e5dbc67d 100644 --- a/sdks/fabric/interoperation-node-sdk/src/InteroperableHelper.ts +++ b/sdks/fabric/interoperation-node-sdk/src/InteroperableHelper.ts @@ -669,4 +669,5 @@ export { submitTransactionWithRemoteViews, getRemoteView, createFlowAddress, + createAddress, }; diff --git a/sdks/fabric/interoperation-node-sdk/src/Relay.ts b/sdks/fabric/interoperation-node-sdk/src/Relay.ts index b2760dbbc..e2e0a2a4f 100644 --- a/sdks/fabric/interoperation-node-sdk/src/Relay.ts +++ b/sdks/fabric/interoperation-node-sdk/src/Relay.ts @@ -13,6 +13,7 @@ import * as grpcJs from "@grpc/grpc-js"; import networksGrpcPb from "@hyperledger-labs/weaver-protos-js/networks/networks_grpc_pb"; import networksPb from "@hyperledger-labs/weaver-protos-js/networks/networks_pb"; import common_ack_pb from "@hyperledger-labs/weaver-protos-js/common/ack_pb"; +import eventsPb from "@hyperledger-labs/weaver-protos-js/common/events_pb"; import statePb from "@hyperledger-labs/weaver-protos-js/common/state_pb"; import * as helpers from "./helpers"; /** @@ -203,6 +204,156 @@ class Relay { return asJson ? state.toObject() : state; } + + /** + * SendEventSubscribeRequest to send a request to a remote network using gRPC and the relay. + * @returns {string} The ID of the request + */ + async SendEventSubscribeRequest( + eventMatcher: eventsPb.EventMatcher, + eventPublicationSpec: eventsPb.EventPublication, + address: string, + policy, + requestingNetwork: string, + certificate: string, + signature: string, + nonce: string, + org: string, + confidential: boolean, + ): Promise { + try { + const networkClient = new networksGrpcPb.NetworkClient( + this.getEndpoint(), + this._useTls ? + (this._tlsRootCACerts.length == 0 ? grpcJs.credentials.createSsl() : grpcJs.credentials.createSsl(Buffer.from(this._tlsRootCACerts))) : + grpcJs.credentials.createInsecure() + ); + const { + subscribeEvent, + }: { + subscribeEvent: (eventSubscription: networksPb.NetworkEventSubscription) => Promise; + } = helpers.promisifyAll(networkClient); + + const query = new networksPb.NetworkQuery(); + query.setPolicyList(policy); + query.setAddress(address); + query.setCertificate(certificate); + query.setNonce(nonce); + query.setRequestorSignature(signature); + query.setRequestingRelay(""); + query.setRequestingNetwork(requestingNetwork); + query.setRequestingOrg(org || ""); + query.setConfidential(confidential || false); + + const eventSubscription = new networksPb.NetworkEventSubscription(); + eventSubscription.setEventMatcher(eventMatcher); + eventSubscription.setQuery(query); + eventSubscription.setEventPublicationSpec(eventPublicationSpec); + + if (typeof subscribeEvent === "function") { + const [resp, error] = await helpers.handlePromise(subscribeEvent(eventSubscription)); + if (error) { + throw new Error(`Event Subscription error: ${error}`); + } + if (resp.getStatus() === common_ack_pb.Ack.STATUS.ERROR) { + throw new Error(`Event Subscription request received negative Ack error: ${resp.getMessage()}`); + } + return resp.getRequestId(); + } + throw new Error("Error with event subscription in NetworkClient"); + } catch (e) { + throw new Error(`Error with Network Client: ${e}`); + } + } + /** + * GetSubscriptionStatus is used to get the request from the local network + * @returns {object} The request object from the relay + */ + async GetEventSubscriptionState(requestId: string, asJson = true): Promise { + const networkClient = new networksGrpcPb.NetworkClient( + this.getEndpoint(), + this._useTls ? + (this._tlsRootCACerts.length == 0 ? grpcJs.credentials.createSsl() : grpcJs.credentials.createSsl(Buffer.from(this._tlsRootCACerts))) : + grpcJs.credentials.createInsecure() + ); + const { + getEventSubscriptionState, + }: { getEventSubscriptionState: (message: networksPb.GetStateMessage) => Promise } = helpers.promisifyAll( + networkClient, + ); + const getStateMessage = new networksPb.GetStateMessage(); + getStateMessage.setRequestId(requestId); + const [state, error] = await helpers.handlePromise(getEventSubscriptionState(getStateMessage)); + if (error) { + throw new Error(`Error: ${error}`); + } + + return asJson ? state.toObject() : state; + } + + async recursiveEventSubscriptionState(requestID: string, dateObj: Date): Promise { + const [state, error] = await helpers.handlePromise(this.GetEventSubscriptionState(requestID, false)); + if (error) { + throw new Error(`Get event subscription state error: ${error}`); + } + if ( + state.getStatus() === eventsPb.EventSubscriptionState.STATUS.PENDING || + state.getStatus() === eventsPb.EventSubscriptionState.STATUS.PENDING_ACK + ) { + if (dateObj.getTime() < Date.now()) { + throw new Error("Timeout: State is still pending."); + } else { + return await this.recursiveEventSubscriptionState(requestID, dateObj); + } + } else { + return state; + } + } + /** + * ProcessEventSubscriptionRequest sends a event subscription request to a remote network using gRPC and the relay and polls for a response on the local network + * Uses the timeout provided by the class. + * @returns {string} The state returned by the remote request + */ + async ProcessSuscribeEventRequest( + eventMatcher: eventsPb.EventMatcher, + eventPublicationSpec: eventsPb.EventPublication, + address: string, + policy, + requestingNetwork: string, + certificate: string, + signature: string, + nonce: string, + org: string, + confidential: boolean, + ): Promise { + try { + const [requestID, error] = await helpers.handlePromise( + this.SendEventSubscribeRequest(eventMatcher, eventPublicationSpec, address, policy, requestingNetwork, certificate, signature, nonce, org, confidential), + ); + if (error) { + throw new Error(`Request state error: ${error}`); + } + // Adds timout time to current time. + const dateObj = new Date(); + dateObj.setMilliseconds(dateObj.getMilliseconds() + this.timeoutTime); + //TODO: SLOW DOWN + const [finalState, stateError] = await helpers.handlePromise(this.recursiveEventSubscriptionState(requestID, dateObj)); + if (stateError) { + throw new Error(`Event Subscription error: ${stateError}`); + } + if (finalState.getStatus() === eventsPb.EventSubscriptionState.STATUS.ERROR) { + if (finalState.getMessage()) { + throw new Error(`Error during event subscription : ${finalState.getMessage()}`); + } + else { + throw new Error(`Error during event subscription : UNKNOWN REASON}`); + } + } + return finalState; + } catch (e) { + throw new Error(e); + } + } } diff --git a/sdks/fabric/interoperation-node-sdk/types/index.d.ts b/sdks/fabric/interoperation-node-sdk/types/index.d.ts index 5823ae3e4..742de52ec 100644 --- a/sdks/fabric/interoperation-node-sdk/types/index.d.ts +++ b/sdks/fabric/interoperation-node-sdk/types/index.d.ts @@ -16,3 +16,5 @@ import * as AssetManager from "../src/AssetManager"; export { AssetManager }; import * as HashFunctions from "../src/HashFunctions"; export { HashFunctions }; +import * as EventsManager from "../src/EventsManager"; +export { EventsManager }; From 88e15922840eb0a48251e3436a6a4590cbe3ef6d Mon Sep 17 00:00:00 2001 From: sannish Date: Thu, 7 Jul 2022 18:08:13 +0000 Subject: [PATCH 025/150] event sub sample json file typo fix Signed-off-by: sannish --- .../fabric/fabric-cli/src/data/event_sub_sample.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/samples/fabric/fabric-cli/src/data/event_sub_sample.json b/samples/fabric/fabric-cli/src/data/event_sub_sample.json index c8e2c29ac..4c1b2094f 100644 --- a/samples/fabric/fabric-cli/src/data/event_sub_sample.json +++ b/samples/fabric/fabric-cli/src/data/event_sub_sample.json @@ -2,18 +2,18 @@ "event_matcher": { "event_type": 1, "event_class_id": "", - "transaction_ledger_id": "mychannel" + "transaction_ledger_id": "mychannel", "transaction_contract_id": "simplestate", - "transaction_func": "Create", + "transaction_func": "Create" }, "event_publication_spec": { "args": [], "contract_id": "simplestate", - "driver_id": "network2", + "driver_id": "network1", "func": "Create", "ledger_id": "mychannel", "replace_arg_index": "0" }, - "view_address": "localhost:9083/Dummy_Network/mychannel:simplestate:Read:a", + "view_address": "localhost:9083/network2/mychannel:simplestate:Read:a", "confidential": false -} \ No newline at end of file +} From ee8612935c7e284437c96bdc53ecd6f530ba5c1d Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Fri, 8 Jul 2022 00:32:54 +0530 Subject: [PATCH 026/150] allowing fabric-cli to register on behalf of driver Signed-off-by: sandeep.nishad1 --- samples/fabric/fabric-cli/readme.md | 8 +++ .../src/commands/event/suscribe-driver.ts | 53 ++++++++++++++----- 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/samples/fabric/fabric-cli/readme.md b/samples/fabric/fabric-cli/readme.md index 28cba822d..18047735e 100644 --- a/samples/fabric/fabric-cli/readme.md +++ b/samples/fabric/fabric-cli/readme.md @@ -385,6 +385,14 @@ Below are the steps to exercise asset transfers from `network1` to `network2` us ./scripts/getTokenBalance.sh network2 bob ``` +## Event Subscription + +To suscribe for event, generate a JSON file like: [Sample Event Sub JSON](./src/data/event_sub_sample.json). Sample provided here assumes driver of `network1` is subscribing to an event of `network2`. + +Then run following command: +``` +./bin/fabric-cli event subscribe --network=network1 --driver src/data/event_sub_sample.json +``` ## NOTE diff --git a/samples/fabric/fabric-cli/src/commands/event/suscribe-driver.ts b/samples/fabric/fabric-cli/src/commands/event/suscribe-driver.ts index 9ce8e2421..d3b55ab1a 100644 --- a/samples/fabric/fabric-cli/src/commands/event/suscribe-driver.ts +++ b/samples/fabric/fabric-cli/src/commands/event/suscribe-driver.ts @@ -15,9 +15,9 @@ import * as fs from 'fs' import * as path from 'path' const command: GluegunCommand = { - name: 'subscribe-driver', + name: 'subscribe', alias: ['-sd'], - description: 'Initiate event subscribe for driver', + description: 'Initiate event subscribe', run: async toolbox => { const { print, @@ -27,8 +27,8 @@ const command: GluegunCommand = { commandHelp( print, toolbox, - `fabric-cli event subscribe --network= --user= src/data/event_sub_sample.json`, - 'fabric-cli event subscribe --network= --user= ', + `fabric-cli event subscribe --network= --user=user1 --driver src/data/event_sub_sample.json`, + 'fabric-cli event subscribe --network= --user= --driver ', [ { name: '--network', @@ -38,7 +38,12 @@ const command: GluegunCommand = { { name: '--user', description: - 'User for subscription. Default: relay' + 'User for subscription. Default: user1' + }, + { + name: '--driver', + description: + 'Flag to indicate subscribing on behalf of driver' }, { name: '--debug', @@ -47,21 +52,21 @@ const command: GluegunCommand = { } ], command, - ['event', 'subscribe-driver'] + ['event', 'subscribe'] ) return } console.log("Event Subscription") if (options.debug === 'true') { - logger.level = 'debug' - logger.debug('Debugging is enabled') + logger.level = 'debug' + logger.debug('Debugging is enabled') } if (array.length != 1) { - print.error('Not enough arguments supplied') - return + print.error('Not enough arguments supplied') + return } if (!options['user']) { - options['user'] = `relay` //Default user + options['user'] = `user1` //Default user } const networkName = options['network'] @@ -70,6 +75,20 @@ const command: GluegunCommand = { const filepath = path.resolve(array[0]) const data = JSON.parse(fs.readFileSync(filepath).toString()) + if (options['driver']) { + const walletPath = process.env.WALLET_PATH + ? process.env.WALLET_PATH + : path.join(__dirname, '../../', `wallet-${networkName}`) + const relayIdTargetPath = path.join(walletPath, 'relay.id') + if (!fs.existsSync(relayIdTargetPath)) { + const relayIdSrcPath = path.join(__dirname, '../../../../../../', 'core/drivers/fabric-driver/', `wallet-${networkName}`, 'relay.id') + fs.copyFile(relayIdSrcPath, relayIdTargetPath, (err) => { + if (err) throw err; + console.log('Relay id copied from fabric-driver directory'); + }); + } + } + const netConfig = getNetworkConfig(networkName) if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { throw new Error(`No valid config entry found for ${networkName}`) @@ -92,6 +111,16 @@ const command: GluegunCommand = { if (keyCertError) { throw new Error(`Error getting key and cert ${keyCertError}`) } + let cert = keyCert.cert + if (options['driver']) { + const [driverKeyCert, driverKeyCertError] = await handlePromise( + getKeyAndCertForRemoteRequestbyUserName(wallet, 'relay') + ) + if (driverKeyCertError) { + throw new Error(`Error getting key and cert ${driverKeyCertError}`) + } + cert = driverKeyCert.cert + } const eventMatcher = EventsManager.createEventMatcher(data.event_matcher) const eventPublicationSpec = EventsManager.createEventPublicationSpec(data.event_publication_spec) @@ -105,7 +134,7 @@ const command: GluegunCommand = { netConfig.mspId, netConfig.relayEndpoint, { address: data.view_address, Sign: true }, - keyCert + { key: keyCert.key, cert: cert } ) if (response.getStatus() == EventSubscriptionState.STATUS.SUCCESS) { From 0fb7606df169d8ea50a7897322ee0ee909c47792 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Fri, 8 Jul 2022 22:45:40 +0530 Subject: [PATCH 027/150] add fetch sign and cert from driver Signed-off-by: sandeep.nishad1 --- core/relay/driver/driver.rs | 16 ++ .../src/services/data_transfer_service.rs | 13 +- .../src/services/event_subscribe_service.rs | 13 +- core/relay/src/services/helpers.rs | 98 +++++++++ core/relay/src/services/mod.rs | 1 + core/relay/src/services/network_service.rs | 205 +++++++++++++++--- core/relay/src/services/types.rs | 14 ++ 7 files changed, 306 insertions(+), 54 deletions(-) create mode 100644 core/relay/src/services/types.rs diff --git a/core/relay/driver/driver.rs b/core/relay/driver/driver.rs index 1465ec1f2..060efad19 100644 --- a/core/relay/driver/driver.rs +++ b/core/relay/driver/driver.rs @@ -169,6 +169,22 @@ impl DriverCommunication for DriverCommunicationService { return Ok(Response::new(reply)); } + async fn request_signed_event_subscription_query(&self, request: Request) -> Result, Status> { + let received_query = request.into_inner().clone().query.expect("Err"); + let signed_query: Query = Query { + policy: received_query.policy, + address: received_query.address, + requesting_relay: received_query.requesting_relay, + requesting_org: received_query.requesting_org, + requesting_network: received_query.requesting_network, + certificate: "dummy-driver-certificate".to_string(), + requestor_signature: "dummy-driver-signature".to_string(), + nonce: received_query.nonce, + request_id: received_query.request_id, + confidential: received_query.confidential, + }; + return Ok(Response::new(signed_query)); + } } #[tokio::main] diff --git a/core/relay/src/services/data_transfer_service.rs b/core/relay/src/services/data_transfer_service.rs index 86db3af41..78e332dd3 100644 --- a/core/relay/src/services/data_transfer_service.rs +++ b/core/relay/src/services/data_transfer_service.rs @@ -9,6 +9,7 @@ use crate::pb::relay::datatransfer::data_transfer_server::DataTransfer; use crate::db::Database; use crate::error::Error; use crate::relay_proto::{parse_address, LocationSegment}; +use crate::services::types::{Driver, Network}; // external modules use config; use serde; @@ -21,18 +22,6 @@ use tonic::transport::{Certificate, Channel, ClientTlsConfig}; pub struct DataTransferService { pub config_lock: RwLock, } -#[derive(Clone, PartialEq, serde::Serialize, serde::Deserialize, Debug)] -pub struct Driver { - port: String, - hostname: String, - tls: bool, - tlsca_cert_path: String, -} - -#[derive(Clone, PartialEq, serde::Serialize, serde::Deserialize, Debug)] -pub struct Network { - network: String, -} /// DataTransferService is the gRPC server implementation that handles the logic for /// communication of the data transfer protocol between two relays. diff --git a/core/relay/src/services/event_subscribe_service.rs b/core/relay/src/services/event_subscribe_service.rs index dadd16ece..888ee5a06 100644 --- a/core/relay/src/services/event_subscribe_service.rs +++ b/core/relay/src/services/event_subscribe_service.rs @@ -11,6 +11,7 @@ use crate::db::Database; use crate::error::Error; use crate::relay_proto::{parse_address, LocationSegment}; use crate::services::helpers::update_event_subscription_status; +use crate::services::types::{Driver, Network}; // external modules use config; use serde; @@ -23,18 +24,6 @@ use tonic::transport::{Certificate, Channel, ClientTlsConfig}; pub struct EventSubscribeService { pub config_lock: RwLock, } -#[derive(Clone, PartialEq, serde::Serialize, serde::Deserialize, Debug)] -pub struct Driver { - port: String, - hostname: String, - tls: bool, - tlsca_cert_path: String, -} - -#[derive(Clone, PartialEq, serde::Serialize, serde::Deserialize, Debug)] -pub struct Network { - network: String, -} /// EventSubscribeService is the gRPC server implementation that handles the logic for /// communicating event subscription request between two relays and driver. diff --git a/core/relay/src/services/helpers.rs b/core/relay/src/services/helpers.rs index 8e02ead5f..31b67b0a8 100644 --- a/core/relay/src/services/helpers.rs +++ b/core/relay/src/services/helpers.rs @@ -1,5 +1,29 @@ +use crate::pb::common::query::Query; use crate::pb::common::events::{event_subscription_state, EventSubscriptionState}; +use crate::pb::common::events::{EventSubOperation, EventSubscription}; +use crate::pb::driver::driver::driver_communication_client::DriverCommunicationClient; + use crate::db::Database; +use crate::services::types::{Driver, Network}; +use crate::error::Error; + +use config; +use tokio::sync::RwLock; +use tonic::{Code, Request, Response, Status}; +use tonic::transport::{Certificate, Channel, ClientTlsConfig}; + +#[derive(Clone, PartialEq, serde::Serialize, serde::Deserialize, Debug)] +pub struct Driver { + pub port: String, + pub hostname: String, + pub tls: bool, + pub tlsca_cert_path: String, +} + +#[derive(Clone, PartialEq, serde::Serialize, serde::Deserialize, Debug)] +pub struct Network { + pub network: String, +} // Locally scoped function to update request status in db. This function is // called for the first time after an Ack is received from the remote relay. @@ -38,4 +62,78 @@ pub fn update_event_subscription_status( println!("EventSubscription Request not found. Error: {:?}", e); }, } +} + + +pub async fn driver_sign_subscription_helper( + event_subscription: EventSubscription, + request_id: String, + driver_id: String, + conf: config::Config, +) -> Result, Error> { + let networks_table = conf + .get_table("networks") + .map_err(|e| Error::Simple(format!("Unable to find networks table. Error: {:?}", e)))?; + let network_table = networks_table + .get::(&driver_id.to_string()) + .ok_or(Error::Simple(format!( + "Unable to find Network_id \"{}\" in config", + driver_id.to_string() + )))?; + let network_type = network_table + .clone() + .try_into::() + .expect("Error in config file networks table") + .clone(); + // get the driver host:port from the drivers map + let drivers_table = conf + .get_table("drivers") + .map_err(|e| Error::Simple(format!("Unable to find driver table. Error: {:?}", e)))?; + let driver_table = drivers_table + .get::(&network_type.network) + .ok_or(Error::Simple(format!( + "Unable to find driver port for network: {}", + driver_id.to_string() + )))?; + let driver_info = driver_table + .clone() + .try_into::() + .expect("Error in config file drivers table") + .clone(); + let port = driver_info.port.to_string(); + let hostname = driver_info.hostname.to_string(); + let use_tls = driver_info.tls; + let tlsca_cert_path = driver_info.tlsca_cert_path.to_string(); + + let driver_address = format!("http://{}:{}", hostname, port); + let client; + if use_tls { + let pem = tokio::fs::read(tlsca_cert_path).await?; + let ca = Certificate::from_pem(pem); + + let tls = ClientTlsConfig::new() + .ca_certificate(ca) + .domain_name(hostname); + + let channel = Channel::from_shared(driver_address).unwrap() + .tls_config(tls) + .connect() + .await + .unwrap(); + + client = DriverCommunicationClient::new(channel); + } else { + client = DriverCommunicationClient::connect(driver_address).await?; + } + println!("Sending Sign EventSubscription Request to driver: {:?}", event_subscription.clone()); + let signed_query = client + .clone() + .request_signed_event_subscription_query(event_subscription) + .await? + .into_inner(); + if signed_query.clone().request_id.to_string() == request_id.to_string() { + println!("Signed Query Response from driver={:?}\n", signed_query); + return Ok(tonic::Response::new(signed_query)) + } + Err(Error::Simple(format!("Error while requesting signature from driver: {:?}", signed_query))) } \ No newline at end of file diff --git a/core/relay/src/services/mod.rs b/core/relay/src/services/mod.rs index a28cabe03..343fa3dc7 100644 --- a/core/relay/src/services/mod.rs +++ b/core/relay/src/services/mod.rs @@ -2,3 +2,4 @@ pub mod data_transfer_service; pub mod network_service; pub mod event_subscribe_service; pub mod helpers; +pub mod types; diff --git a/core/relay/src/services/network_service.rs b/core/relay/src/services/network_service.rs index 912534a74..16eeac713 100644 --- a/core/relay/src/services/network_service.rs +++ b/core/relay/src/services/network_service.rs @@ -1,17 +1,20 @@ // Internal generated modules use crate::pb::common::ack::{ack, Ack}; use crate::pb::common::query::Query; -use crate::pb::common::events::EventSubscription; +use crate::pb::common::events::{EventSubOperation, EventSubscription}; use crate::pb::common::state::{request_state, RequestState}; use crate::pb::common::events::{event_subscription_state, EventSubscriptionState}; +use crate::pb::common::events::{event_publication, EventPublication}; use crate::pb::networks::networks::network_server::Network; -use crate::pb::networks::networks::{DbName, GetStateMessage, NetworkQuery, RelayDatabase, NetworkEventSubscription}; +use crate::pb::networks::networks::{DbName, GetStateMessage, NetworkQuery, RelayDatabase, NetworkEventSubscription, NetworkEventUnsubscription}; use crate::pb::relay::datatransfer::data_transfer_client::DataTransferClient; use crate::pb::relay::events::event_subscribe_client::EventSubscribeClient; use crate::relay_proto::{parse_address, LocationSegment}; -use crate::services::helpers::update_event_subscription_status; // Internal modules use crate::db::Database; +use crate::error::Error; +use crate::services::helpers::update_event_subscription_status; +use crate::services::helpers::driver_sign_subscription_helper; // External modules use config; @@ -193,6 +196,77 @@ impl Network for NetworkService { event_matcher: network_event_subscription.event_matcher.clone(), event_publication_spec: network_event_subscription.event_publication_spec.clone() }; + + // Create EventSubscription + let network_query = network_event_subscription.query.clone().expect("No query passed with NetworkEventSubscription request"); + let parsed_address = parse_address(network_query.address.to_string()); + let relay_name = conf.get_str("name").unwrap(); + let query: Query = Query { + policy: network_query.policy, + address: network_query.address, + requesting_relay: relay_name, + requesting_org: network_query.requesting_org, + requesting_network: network_query.requesting_network, + certificate: network_query.certificate, + requestor_signature: network_query.requestor_signature, + nonce: network_query.nonce, + request_id: request_id.to_string(), + confidential: network_query.confidential, + }; + mut event_subscription: EventSubscription = EventSubscription { + event_matcher: network_event_subscription.event_matcher, + query: Some(query), + operation: EventSubOperation::Subscribe as i32, + }; + + // Check if driver is subscribing + let event_publication_spec = network_event_subscription.event_publication_spec.clone().expect("No Event Publication Specification passed with NetworkEventSubscription request"); + match event_publication_spec.publication_target { + Some(data) => match data { + event_publication::PublicationTarget::Ctx(ctx) => { + let driver_id = ctx.clone().driver_id.to_string(); + let result = driver_sign_subscription_helper( + event_subscription, + request_id.to_string(), + driver_id, + conf.clone(), + ); + match result.await { + Ok(signed_query) => { + event_subscription = EventSubscription { + event_matcher: network_event_subscription.event_matcher, + query: Some(signed_query.into_inner()), + operation: EventSubOperation::Subscribe as i32, + }; + } + Err(e) => { + println!("Driver did not signed the subscription request"); + let reply = Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: {:?}", e), + }; + println!("Sending Ack back to network: {:?}\n", reply); + return Ok(Response::new(reply)) + } + } + } + event_publication::PublicationTarget::AppUrl(app_url) => { + println!("Registering for Client using App URL") + } + }, + None => { + println!("No Publication Target"); + let reply = Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("No Publication Target provided"), + }; + println!("Sending Ack back to network: {:?}\n", reply); + return Ok(Response::new(reply)) + } + }; + let message_insert = db.set(&request_id.to_string(), &target); // Kept this as a match as the error case returns an Ok. match message_insert { @@ -215,19 +289,16 @@ impl Network for NetworkService { return reply; } } - - let network_query = network_event_subscription.query.clone().expect("No query passed with NetworkEventSubscription request"); - let parsed_address = parse_address(network_query.address.to_string()); match parsed_address { Ok(address) => { // TODO: verify that host and port are valid // Spawns a child process to handle sending request spawn_send_event_subscription_request( conf, - network_event_subscription, + event_subscription, request_id.to_string(), address.location.hostname.to_string(), - address.location.port.to_string() + address.location.port.to_string(), ); // Send Ack back to network while request is happening in a thread let reply = Ack { @@ -275,6 +346,97 @@ impl Network for NetworkService { )), } } + // Unsubscribe Event Endpoints + async fn unsubscribe_event(&self, request: Request) -> Result, Status> { + println!( + "Got a Network Event Unubscription request from {:?} - {:?}", + request.remote_addr(), + request + ); + Err(tonic::Status::unimplemented("method not implemented")) + // let conf = self.config_lock.read().await.clone(); + // // Database access/storage + // let db = Database { + // db_path: conf.get_str("db_path").unwrap(), + // }; + // + // let net_event_sub = request.into_inner().clone(); + // let network_event_subscription = net_event_sub.request.clone().expect("No network event subscription passed"); + // let request_id = net_event_sub.request_id.to_string(); + // + // // Initial request state stored in DB. + // let target: EventSubscriptionState = EventSubscriptionState { + // status: event_subscription_state::Status::UnsubscribePending as i32, + // request_id: request_id.to_string(), + // message: "".to_string(), + // event_matcher: network_event_subscription.event_matcher.clone(), + // event_publication_spec: network_event_subscription.event_publication_spec.clone() + // }; + // let message_insert = db.set(&request_id.to_string(), &target); + // // Kept this as a match as the error case returns an Ok. + // match message_insert { + // Ok(_) => println!( + // "Successfully updated NetworkEventSubscription status as UNSUBSCRIBE_PENDING in db with request_id: {}", + // request_id.to_string() + // ), + // Err(e) => { + // // Internal failure of sled. Send Error response + // println!( + // "Error updating NetworkEventSubscription status as UNSUBSCRIBE_PENDING in db for request_id: {}", + // request_id.to_string() + // ); + // let reply = Ok(Response::new(Ack { + // status: ack::Status::Error as i32, + // request_id: request_id.to_string(), + // message: format!("{:?}", e), + // })); + // println!("Sending Ack back to network: {:?}\n", reply); + // return reply; + // } + // } + // + // let network_query = network_event_subscription.query.clone().expect("No query passed with NetworkEventSubscription request"); + // // let event_publication_spec = network_event_subscription.event_publication_spec.clone().expect("No Event Publication Specification passed with NetworkEventSubscription request"); + // // match event_publication_spec { + // // Some(data) => match data { + // // event_publication_spec + // // } + // // + // // } + // // let driver_id = event_publication_spec.publication_target. + // let parsed_address = parse_address(network_query.address.to_string()); + // match parsed_address { + // Ok(address) => { + // // TODO: verify that host and port are valid + // // Spawns a child process to handle sending request + // spawn_send_event_subscription_request( + // conf, + // network_event_subscription, + // request_id.to_string(), + // address.location.hostname.to_string(), + // address.location.port.to_string() + // ); + // // Send Ack back to network while request is happening in a thread + // let reply = Ack { + // status: ack::Status::Ok as i32, + // request_id: request_id.to_string(), + // message: "".to_string(), + // }; + // println!("Sending Ack back to network: {:?}\n", reply); + // Ok(Response::new(reply)) + // } + // Err(e) => { + // println!("Invalid Address"); + // let reply = Ack { + // status: ack::Status::Error as i32, + // request_id: request_id.to_string(), + // message: format!("Error: {:?}", e), + // }; + // println!("Sending Ack back to network: {:?}\n", reply); + // Ok(Response::new(reply)) + // } + // } + } } // Sends a request to the remote relay @@ -427,10 +589,11 @@ async fn data_transfer_call( Ok(response) } + // Sends a request to the remote relay fn spawn_send_event_subscription_request( conf: config::Config, - network_event_subscription: NetworkEventSubscription, + event_subscription: EventSubscription, request_id: String, relay_host: String, relay_port: String, @@ -454,10 +617,9 @@ fn spawn_send_event_subscription_request( } let result = suscribe_event_call( - conf.get_str("name").unwrap(), relay_host, relay_port, - network_event_subscription, + event_subscription, request_id.clone(), relay_tls, relay_tlsca_cert_path.to_string(), @@ -504,10 +666,9 @@ fn spawn_send_event_subscription_request( } // // Call to remote relay for the event subscription protocol. async fn suscribe_event_call( - relay_name: String, relay_host: String, relay_port: String, - network_event_subscription: NetworkEventSubscription, + event_subscription: EventSubscription, request_id: String, use_tls: bool, tlsca_cert_path: String, @@ -532,23 +693,7 @@ async fn suscribe_event_call( client = EventSubscribeClient::connect(client_addr).await?; } - let network_query = network_event_subscription.query.clone().expect("No query passed with NetworkEventSubscription request"); - let query: Query = Query { - policy: network_query.policy, - address: network_query.address, - requesting_relay: relay_name, - requesting_org: network_query.requesting_org, - requesting_network: network_query.requesting_network, - certificate: network_query.certificate, - requestor_signature: network_query.requestor_signature, - nonce: network_query.nonce, - request_id: request_id.to_string(), - confidential: network_query.confidential, - }; - let event_subscription_request = tonic::Request::new(EventSubscription { - event_matcher: network_event_subscription.event_matcher, - query: Some(query), - }); + let event_subscription_request = tonic::Request::new(event_subscription); println!("EventSubscription: {:?}", event_subscription_request); let response = client.subscribe_event(event_subscription_request).await?; Ok(response) diff --git a/core/relay/src/services/types.rs b/core/relay/src/services/types.rs new file mode 100644 index 000000000..c9b178021 --- /dev/null +++ b/core/relay/src/services/types.rs @@ -0,0 +1,14 @@ +use serde; + +#[derive(Clone, PartialEq, serde::Serialize, serde::Deserialize, Debug)] +pub struct Driver { + pub port: String, + pub hostname: String, + pub tls: bool, + pub tlsca_cert_path: String, +} + +#[derive(Clone, PartialEq, serde::Serialize, serde::Deserialize, Debug)] +pub struct Network { + pub network: String, +} \ No newline at end of file From 2249166d8174134be06dec38e3a7ca0ec69008d0 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Fri, 8 Jul 2022 23:55:15 +0530 Subject: [PATCH 028/150] modularize relay code Signed-off-by: sandeep.nishad1 --- core/relay/driver/driver.rs | 16 +++ .../src/services/data_transfer_service.rs | 97 ++++------------ .../src/services/event_subscribe_service.rs | 97 +++------------- core/relay/src/services/helpers.rs | 104 ++++++++++++++++++ core/relay/src/services/mod.rs | 1 + core/relay/src/services/network_service.rs | 13 ++- core/relay/src/services/types.rs | 14 +++ 7 files changed, 183 insertions(+), 159 deletions(-) create mode 100644 core/relay/src/services/types.rs diff --git a/core/relay/driver/driver.rs b/core/relay/driver/driver.rs index 1465ec1f2..060efad19 100644 --- a/core/relay/driver/driver.rs +++ b/core/relay/driver/driver.rs @@ -169,6 +169,22 @@ impl DriverCommunication for DriverCommunicationService { return Ok(Response::new(reply)); } + async fn request_signed_event_subscription_query(&self, request: Request) -> Result, Status> { + let received_query = request.into_inner().clone().query.expect("Err"); + let signed_query: Query = Query { + policy: received_query.policy, + address: received_query.address, + requesting_relay: received_query.requesting_relay, + requesting_org: received_query.requesting_org, + requesting_network: received_query.requesting_network, + certificate: "dummy-driver-certificate".to_string(), + requestor_signature: "dummy-driver-signature".to_string(), + nonce: received_query.nonce, + request_id: received_query.request_id, + confidential: received_query.confidential, + }; + return Ok(Response::new(signed_query)); + } } #[tokio::main] diff --git a/core/relay/src/services/data_transfer_service.rs b/core/relay/src/services/data_transfer_service.rs index 86db3af41..a1aab23d1 100644 --- a/core/relay/src/services/data_transfer_service.rs +++ b/core/relay/src/services/data_transfer_service.rs @@ -9,6 +9,8 @@ use crate::pb::relay::datatransfer::data_transfer_server::DataTransfer; use crate::db::Database; use crate::error::Error; use crate::relay_proto::{parse_address, LocationSegment}; +use crate::services::helpers::{get_driver, get_driver_client}; +use crate::services::types::{Driver, Network}; // external modules use config; use serde; @@ -21,18 +23,6 @@ use tonic::transport::{Certificate, Channel, ClientTlsConfig}; pub struct DataTransferService { pub config_lock: RwLock, } -#[derive(Clone, PartialEq, serde::Serialize, serde::Deserialize, Debug)] -pub struct Driver { - port: String, - hostname: String, - tls: bool, - tlsca_cert_path: String, -} - -#[derive(Clone, PartialEq, serde::Serialize, serde::Deserialize, Debug)] -pub struct Network { - network: String, -} /// DataTransferService is the gRPC server implementation that handles the logic for /// communication of the data transfer protocol between two relays. @@ -206,46 +196,19 @@ fn request_state_helper( .set(&request_id.to_string(), &query) .map_err(|e| Error::Simple(format!("DB Failure: {:?}", e)))?; let parsed_address = parse_address(query.address.to_string())?; - // get the driver type from the networks map - let networks_table = conf - .get_table("networks") - .map_err(|e| Error::Simple(format!("Unable to find networks table. Error: {:?}", e)))?; - let network_table = networks_table - .get::(&parsed_address.network_id.to_string()) - .ok_or(Error::Simple(format!( - "Unable to find Network_id \"{}\" in config", - parsed_address.network_id.to_string() - )))?; - let network_type = network_table - .clone() - .try_into::() - .expect("Error in config file networks table") - .clone(); - // get the driver host:port from the drivers map - let drivers_table = conf - .get_table("drivers") - .map_err(|e| Error::Simple(format!("Unable to find driver table. Error: {:?}", e)))?; - let driver_table = drivers_table - .get::(&network_type.network) - .ok_or(Error::Simple(format!( - "Unable to find driver port for network: {}", - parsed_address.network_id.to_string() - )))?; - let driver_info = driver_table - .clone() - .try_into::() - .expect("Error in config file drivers table") - .clone(); - let port = driver_info.port.to_string(); - let hostname = driver_info.hostname.to_string(); - let tls = driver_info.tls; - let tlsca_cert_path = driver_info.tlsca_cert_path.to_string(); - spawn_request_driver_state(query, hostname, port, tls, tlsca_cert_path, conf.clone()); - return Ok(Ack { - status: ack::Status::Ok as i32, - request_id, - message: "".to_string(), - }); + let result = get_driver(parsed_address.network_id.to_string(), conf.clone()); + match result { + Ok(driver_info) => { + spawn_request_driver_state(query, driver_info, conf.clone()); + return Ok(Ack { + status: ack::Status::Ok as i32, + request_id, + message: "".to_string(), + }); + }, + Err(e) => Err(e), + } + } /// send_driver_state is run on the remote relay. Runs when the driver sends the @@ -283,31 +246,9 @@ fn send_driver_state_helper( async fn spawn_request_driver_state_helper( query: Query, - hostname: String, - port: String, - use_tls: bool, - tlsca_cert_path: String, + driver_info: Driver, ) -> Result<(), Error> { - let driver_address = format!("http://{}:{}", hostname, port); - let client; - if use_tls { - let pem = tokio::fs::read(tlsca_cert_path).await?; - let ca = Certificate::from_pem(pem); - - let tls = ClientTlsConfig::new() - .ca_certificate(ca) - .domain_name(hostname); - - let channel = Channel::from_shared(driver_address).unwrap() - .tls_config(tls) - .connect() - .await - .unwrap(); - - client = DriverCommunicationClient::new(channel); - } else { - client = DriverCommunicationClient::connect(driver_address).await?; - } + let client = get_driver_client(driver_info).await?; println!("Sending request to driver with query {:?}", query.clone()); let ack = client .clone() @@ -327,9 +268,9 @@ async fn spawn_request_driver_state_helper( } // Function that starts a thread which sends the query information to the driver -fn spawn_request_driver_state(query: Query, hostname: String, port: String, use_tls: bool, tlsca_cert_path: String, conf: config::Config) { +fn spawn_request_driver_state(query: Query, driver_info: Driver, conf: config::Config) { tokio::spawn(async move { - let result = spawn_request_driver_state_helper(query.clone(), hostname, port, use_tls, tlsca_cert_path).await; + let result = spawn_request_driver_state_helper(query.clone(), driver_info).await; match result { Ok(_) => { // Do nothing diff --git a/core/relay/src/services/event_subscribe_service.rs b/core/relay/src/services/event_subscribe_service.rs index dadd16ece..2db1b7087 100644 --- a/core/relay/src/services/event_subscribe_service.rs +++ b/core/relay/src/services/event_subscribe_service.rs @@ -10,7 +10,8 @@ use crate::pb::common::events::{event_subscription_state, EventSubscriptionState use crate::db::Database; use crate::error::Error; use crate::relay_proto::{parse_address, LocationSegment}; -use crate::services::helpers::update_event_subscription_status; +use crate::services::helpers::{update_event_subscription_status, get_driver, get_driver_client}; +use crate::services::types::{Driver, Network}; // external modules use config; use serde; @@ -23,18 +24,6 @@ use tonic::transport::{Certificate, Channel, ClientTlsConfig}; pub struct EventSubscribeService { pub config_lock: RwLock, } -#[derive(Clone, PartialEq, serde::Serialize, serde::Deserialize, Debug)] -pub struct Driver { - port: String, - hostname: String, - tls: bool, - tlsca_cert_path: String, -} - -#[derive(Clone, PartialEq, serde::Serialize, serde::Deserialize, Debug)] -pub struct Network { - network: String, -} /// EventSubscribeService is the gRPC server implementation that handles the logic for /// communicating event subscription request between two relays and driver. @@ -152,52 +141,24 @@ fn subscribe_event_helper( .set(&request_id.to_string(), &query) .map_err(|e| Error::Simple(format!("DB Failure: {:?}", e)))?; let parsed_address = parse_address(query.address.to_string())?; - // get the driver type from the networks map - let networks_table = conf - .get_table("networks") - .map_err(|e| Error::Simple(format!("Unable to find networks table. Error: {:?}", e)))?; - let network_table = networks_table - .get::(&parsed_address.network_id.to_string()) - .ok_or(Error::Simple(format!( - "Unable to find Network_id \"{}\" in config", - parsed_address.network_id.to_string() - )))?; - let network_type = network_table - .clone() - .try_into::() - .expect("Error in config file networks table") - .clone(); - // get the driver host:port from the drivers map - let drivers_table = conf - .get_table("drivers") - .map_err(|e| Error::Simple(format!("Unable to find driver table. Error: {:?}", e)))?; - let driver_table = drivers_table - .get::(&network_type.network) - .ok_or(Error::Simple(format!( - "Unable to find driver port for network: {}", - parsed_address.network_id.to_string() - )))?; - let driver_info = driver_table - .clone() - .try_into::() - .expect("Error in config file drivers table") - .clone(); - let port = driver_info.port.to_string(); - let hostname = driver_info.hostname.to_string(); - let tls = driver_info.tls; - let tlsca_cert_path = driver_info.tlsca_cert_path.to_string(); - spawn_driver_subscribe_event(event_subscription, hostname, port, tls, tlsca_cert_path, conf.clone()); - return Ok(Ack { - status: ack::Status::Ok as i32, - request_id, - message: "".to_string(), - }); + let result = get_driver(parsed_address.network_id.to_string(), conf.clone()); + match result { + Ok(driver_info) => { + spawn_driver_subscribe_event(event_subscription, driver_info, conf.clone()); + return Ok(Ack { + status: ack::Status::Ok as i32, + request_id, + message: "".to_string(), + }); + }, + Err(e) => Err(e), + } } // Function that starts a thread which sends the event subscription request to the driver -fn spawn_driver_subscribe_event(event_subscription: EventSubscription, hostname: String, port: String, use_tls: bool, tlsca_cert_path: String, conf: config::Config) { +fn spawn_driver_subscribe_event(event_subscription: EventSubscription, driver_info: Driver, conf: config::Config) { tokio::spawn(async move { - let result = spawn_driver_subscribe_event_helper(event_subscription.clone(), hostname, port, use_tls, tlsca_cert_path).await; + let result = spawn_driver_subscribe_event_helper(event_subscription.clone(), driver_info).await; match result { Ok(_) => { // Do nothing @@ -238,31 +199,9 @@ fn spawn_driver_subscribe_event(event_subscription: EventSubscription, hostname: async fn spawn_driver_subscribe_event_helper( event_subscription: EventSubscription, - hostname: String, - port: String, - use_tls: bool, - tlsca_cert_path: String, + driver_info: Driver, ) -> Result<(), Error> { - let driver_address = format!("http://{}:{}", hostname, port); - let client; - if use_tls { - let pem = tokio::fs::read(tlsca_cert_path).await?; - let ca = Certificate::from_pem(pem); - - let tls = ClientTlsConfig::new() - .ca_certificate(ca) - .domain_name(hostname); - - let channel = Channel::from_shared(driver_address).unwrap() - .tls_config(tls) - .connect() - .await - .unwrap(); - - client = DriverCommunicationClient::new(channel); - } else { - client = DriverCommunicationClient::connect(driver_address).await?; - } + let client = get_driver_client(driver_info).await?; println!("Sending EventSubscription Request to driver: {:?}", event_subscription.clone()); let ack = client .clone() diff --git a/core/relay/src/services/helpers.rs b/core/relay/src/services/helpers.rs index 8e02ead5f..f8e858bbb 100644 --- a/core/relay/src/services/helpers.rs +++ b/core/relay/src/services/helpers.rs @@ -1,5 +1,16 @@ +use crate::pb::common::query::Query; use crate::pb::common::events::{event_subscription_state, EventSubscriptionState}; +use crate::pb::common::events::{EventSubOperation, EventSubscription}; +use crate::pb::driver::driver::driver_communication_client::DriverCommunicationClient; + use crate::db::Database; +use crate::services::types::{Driver, Network}; +use crate::error::Error; + +use config; +use tokio::sync::RwLock; +use tonic::{Code, Request, Response, Status}; +use tonic::transport::{Certificate, Channel, ClientTlsConfig}; // Locally scoped function to update request status in db. This function is // called for the first time after an Ack is received from the remote relay. @@ -38,4 +49,97 @@ pub fn update_event_subscription_status( println!("EventSubscription Request not found. Error: {:?}", e); }, } +} + +pub fn get_driver( + network_id: String, + conf: config::Config, +) -> Result { + // get the driver type from the networks map + let networks_table = conf + .get_table("networks") + .map_err(|e| Error::Simple(format!("Unable to find networks table. Error: {:?}", e)))?; + let network_table = networks_table + .get::(&network_id.to_string()) + .ok_or(Error::Simple(format!( + "Unable to find Network_id \"{}\" in config", + network_id.to_string() + )))?; + let network_type = network_table + .clone() + .try_into::() + .expect("Error in config file networks table") + .clone(); + // get the driver host:port from the drivers map + let drivers_table = conf + .get_table("drivers") + .map_err(|e| Error::Simple(format!("Unable to find driver table. Error: {:?}", e)))?; + let driver_table = drivers_table + .get::(&network_type.network) + .ok_or(Error::Simple(format!( + "Unable to find driver port for network: {}", + network_id.to_string() + )))?; + let driver_info = driver_table + .clone() + .try_into::() + .expect("Error in config file drivers table"); + return Ok(driver_info); +} + +pub async fn get_driver_client( + driver_info: Driver, +) -> Result, Error> { + let port = driver_info.port.to_string(); + let hostname = driver_info.hostname.to_string(); + let use_tls = driver_info.tls; + let tlsca_cert_path = driver_info.tlsca_cert_path.to_string(); + let driver_address = format!("http://{}:{}", hostname, port); + let client; + if use_tls { + let pem = tokio::fs::read(tlsca_cert_path).await?; + let ca = Certificate::from_pem(pem); + + let tls = ClientTlsConfig::new() + .ca_certificate(ca) + .domain_name(hostname); + + let channel = Channel::from_shared(driver_address).unwrap() + .tls_config(tls) + .connect() + .await + .unwrap(); + + client = DriverCommunicationClient::new(channel); + } else { + client = DriverCommunicationClient::connect(driver_address).await?; + } + return Ok(client) +} + + +pub async fn driver_sign_subscription_helper( + event_subscription: EventSubscription, + request_id: String, + driver_id: String, + conf: config::Config, +) -> Result, Error> { + let result = get_driver(driver_id.to_string(), conf.clone()); + match result { + Ok(driver_info) => { + let client = get_driver_client(driver_info).await?; + println!("Sending Sign EventSubscription Request to driver: {:?}", event_subscription.clone()); + let signed_query = client + .clone() + .request_signed_event_subscription_query(event_subscription) + .await? + .into_inner(); + if signed_query.clone().request_id.to_string() == request_id.to_string() { + println!("Signed Query Response from driver={:?}\n", signed_query); + return Ok(tonic::Response::new(signed_query)) + } + Err(Error::Simple(format!("Error while requesting signature from driver: {:?}", signed_query))) + }, + Err(e) => Err(e), + } } \ No newline at end of file diff --git a/core/relay/src/services/mod.rs b/core/relay/src/services/mod.rs index a28cabe03..04b170ac0 100644 --- a/core/relay/src/services/mod.rs +++ b/core/relay/src/services/mod.rs @@ -2,3 +2,4 @@ pub mod data_transfer_service; pub mod network_service; pub mod event_subscribe_service; pub mod helpers; +pub mod types; \ No newline at end of file diff --git a/core/relay/src/services/network_service.rs b/core/relay/src/services/network_service.rs index 912534a74..9f38f5aa9 100644 --- a/core/relay/src/services/network_service.rs +++ b/core/relay/src/services/network_service.rs @@ -3,9 +3,9 @@ use crate::pb::common::ack::{ack, Ack}; use crate::pb::common::query::Query; use crate::pb::common::events::EventSubscription; use crate::pb::common::state::{request_state, RequestState}; -use crate::pb::common::events::{event_subscription_state, EventSubscriptionState}; +use crate::pb::common::events::{event_subscription_state, EventSubscriptionState, EventSubOperation}; use crate::pb::networks::networks::network_server::Network; -use crate::pb::networks::networks::{DbName, GetStateMessage, NetworkQuery, RelayDatabase, NetworkEventSubscription}; +use crate::pb::networks::networks::{DbName, GetStateMessage, NetworkQuery, RelayDatabase, NetworkEventSubscription, NetworkEventUnsubscription}; use crate::pb::relay::datatransfer::data_transfer_client::DataTransferClient; use crate::pb::relay::events::event_subscribe_client::EventSubscribeClient; use crate::relay_proto::{parse_address, LocationSegment}; @@ -275,6 +275,14 @@ impl Network for NetworkService { )), } } + async fn unsubscribe_event(&self, request: Request) -> Result, Status> { + println!( + "Got a Network Event Unubscription request from {:?} - {:?}", + request.remote_addr(), + request + ); + Err(tonic::Status::unimplemented("method not implemented")) + } } // Sends a request to the remote relay @@ -548,6 +556,7 @@ async fn suscribe_event_call( let event_subscription_request = tonic::Request::new(EventSubscription { event_matcher: network_event_subscription.event_matcher, query: Some(query), + operation: EventSubOperation::Subscribe as i32, }); println!("EventSubscription: {:?}", event_subscription_request); let response = client.subscribe_event(event_subscription_request).await?; diff --git a/core/relay/src/services/types.rs b/core/relay/src/services/types.rs new file mode 100644 index 000000000..c9b178021 --- /dev/null +++ b/core/relay/src/services/types.rs @@ -0,0 +1,14 @@ +use serde; + +#[derive(Clone, PartialEq, serde::Serialize, serde::Deserialize, Debug)] +pub struct Driver { + pub port: String, + pub hostname: String, + pub tls: bool, + pub tlsca_cert_path: String, +} + +#[derive(Clone, PartialEq, serde::Serialize, serde::Deserialize, Debug)] +pub struct Network { + pub network: String, +} \ No newline at end of file From 7a3edc60e7e84a7683d492c9cf38ec5e0d06651a Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Sat, 9 Jul 2022 01:40:32 +0530 Subject: [PATCH 029/150] Added endpoints for unsubcription; for relay to fetch sign and cert from driver Signed-off-by: sandeep.nishad1 --- common/protos/common/events.proto | 17 +++++++++++++++-- common/protos/driver/driver.proto | 5 +++++ common/protos/networks/networks.proto | 11 ++++++++++- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/common/protos/common/events.proto b/common/protos/common/events.proto index f04d3bd19..1e6d30d20 100644 --- a/common/protos/common/events.proto +++ b/common/protos/common/events.proto @@ -20,10 +20,21 @@ message EventMatcher { string transaction_contract_id = 4; string transaction_func = 5; } + +enum EventSubOperation { + SUBSCRIBE = 0; + UNSUBSCRIBE = 1; + UPDATE = 2; +} + +// Below message is used to communicate between dest-relay and src-relay; +// and src-relay and src-driver. message EventSubscription { - EventMatcher event_matcher = 1; - common.query.Query query = 2; + EventMatcher event_matcher = 1; + common.query.Query query = 2; + EventSubOperation operation = 3; } + message EventSubscriptionState { enum STATUS { // pending ACK from remote relay @@ -32,6 +43,8 @@ message EventSubscriptionState { PENDING = 1; ERROR = 2; SUCCESS = 3; + UNSUBSCRIBE_PENDING = 4; + UNSUBSCRIBED = 5; }; string request_id = 1; STATUS status = 2; diff --git a/common/protos/driver/driver.proto b/common/protos/driver/driver.proto index 342d1ce87..94d83af59 100644 --- a/common/protos/driver/driver.proto +++ b/common/protos/driver/driver.proto @@ -18,4 +18,9 @@ service DriverCommunication { // Events Subscription // the src-relay uses this endpoint to forward the event subscription request from dest-relay to driver rpc SubscribeEvent(common.events.EventSubscription) returns (common.ack.Ack) {} + + // Recommended to have TLS mode on for this unsafe endpoint + // Relay uses this to get Query.requestor_signature and + // Query.certificate required for event subscription + rpc RequestSignedEventSubscriptionQuery(common.events.EventSubscription) returns (common.query.Query) {} } \ No newline at end of file diff --git a/common/protos/networks/networks.proto b/common/protos/networks/networks.proto index 4ea7ccdd3..7cd1590d4 100644 --- a/common/protos/networks/networks.proto +++ b/common/protos/networks/networks.proto @@ -24,7 +24,9 @@ service Network { // endpoint for a client to subscribe to event via local relay initiating subscription flow. rpc SubscribeEvent(NetworkEventSubscription) returns (common.ack.Ack) {} // This rpc endpoint is for polling the local relay for subscription state. - rpc GetEventSubscriptionState(GetStateMessage) returns(common.events.EventSubscriptionState) {} + rpc GetEventSubscriptionState(GetStateMessage) returns (common.events.EventSubscriptionState) {} + // endpoint for a client to subscribe to event via local relay initiating subscription flow. + rpc UnsubscribeEvent(NetworkEventUnsubscription) returns (common.ack.Ack) {} } message DbName { @@ -50,8 +52,15 @@ message NetworkQuery { string requesting_org = 8; bool confidential = 9; } + +// Below message is used for network/client to dest-relay communication message NetworkEventSubscription { common.events.EventMatcher event_matcher = 1; NetworkQuery query = 2; common.events.EventPublication event_publication_spec = 3; } + +message NetworkEventUnsubscription { + NetworkEventSubscription request = 1; + string request_id = 2; +} From 4deb4eaf51624aa8eeafa7b1ff3532777bf5de48 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Sat, 9 Jul 2022 01:43:12 +0530 Subject: [PATCH 030/150] fix fabric-cli subscription code: not fetch driver cert Signed-off-by: sandeep.nishad1 --- samples/fabric/fabric-cli/readme.md | 2 +- .../src/commands/event/suscribe-driver.ts | 30 ++----------------- 2 files changed, 4 insertions(+), 28 deletions(-) diff --git a/samples/fabric/fabric-cli/readme.md b/samples/fabric/fabric-cli/readme.md index 18047735e..c9a9a3e39 100644 --- a/samples/fabric/fabric-cli/readme.md +++ b/samples/fabric/fabric-cli/readme.md @@ -391,7 +391,7 @@ To suscribe for event, generate a JSON file like: [Sample Event Sub JSON](./src/ Then run following command: ``` -./bin/fabric-cli event subscribe --network=network1 --driver src/data/event_sub_sample.json +./bin/fabric-cli event subscribe --network=network1 src/data/event_sub_sample.json ``` ## NOTE diff --git a/samples/fabric/fabric-cli/src/commands/event/suscribe-driver.ts b/samples/fabric/fabric-cli/src/commands/event/suscribe-driver.ts index d3b55ab1a..47a1f5581 100644 --- a/samples/fabric/fabric-cli/src/commands/event/suscribe-driver.ts +++ b/samples/fabric/fabric-cli/src/commands/event/suscribe-driver.ts @@ -27,8 +27,8 @@ const command: GluegunCommand = { commandHelp( print, toolbox, - `fabric-cli event subscribe --network= --user=user1 --driver src/data/event_sub_sample.json`, - 'fabric-cli event subscribe --network= --user= --driver ', + `fabric-cli event subscribe --network= --user=user1 src/data/event_sub_sample.json`, + 'fabric-cli event subscribe --network= --user= ', [ { name: '--network', @@ -75,20 +75,6 @@ const command: GluegunCommand = { const filepath = path.resolve(array[0]) const data = JSON.parse(fs.readFileSync(filepath).toString()) - if (options['driver']) { - const walletPath = process.env.WALLET_PATH - ? process.env.WALLET_PATH - : path.join(__dirname, '../../', `wallet-${networkName}`) - const relayIdTargetPath = path.join(walletPath, 'relay.id') - if (!fs.existsSync(relayIdTargetPath)) { - const relayIdSrcPath = path.join(__dirname, '../../../../../../', 'core/drivers/fabric-driver/', `wallet-${networkName}`, 'relay.id') - fs.copyFile(relayIdSrcPath, relayIdTargetPath, (err) => { - if (err) throw err; - console.log('Relay id copied from fabric-driver directory'); - }); - } - } - const netConfig = getNetworkConfig(networkName) if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { throw new Error(`No valid config entry found for ${networkName}`) @@ -111,16 +97,6 @@ const command: GluegunCommand = { if (keyCertError) { throw new Error(`Error getting key and cert ${keyCertError}`) } - let cert = keyCert.cert - if (options['driver']) { - const [driverKeyCert, driverKeyCertError] = await handlePromise( - getKeyAndCertForRemoteRequestbyUserName(wallet, 'relay') - ) - if (driverKeyCertError) { - throw new Error(`Error getting key and cert ${driverKeyCertError}`) - } - cert = driverKeyCert.cert - } const eventMatcher = EventsManager.createEventMatcher(data.event_matcher) const eventPublicationSpec = EventsManager.createEventPublicationSpec(data.event_publication_spec) @@ -134,7 +110,7 @@ const command: GluegunCommand = { netConfig.mspId, netConfig.relayEndpoint, { address: data.view_address, Sign: true }, - { key: keyCert.key, cert: cert } + keyCert ) if (response.getStatus() == EventSubscriptionState.STATUS.SUCCESS) { From a743f4781b802f8ebb6973c465ec113775ade24d Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Sat, 9 Jul 2022 01:51:29 +0530 Subject: [PATCH 031/150] removed warnings from relay source code Signed-off-by: sandeep.nishad1 --- core/relay/src/client.rs | 8 ++++---- core/relay/src/relay_proto.rs | 3 +++ core/relay/src/services/data_transfer_service.rs | 5 +---- core/relay/src/services/event_subscribe_service.rs | 7 ++----- core/relay/src/services/helpers.rs | 4 +--- core/relay/src/services/network_service.rs | 4 ---- 6 files changed, 11 insertions(+), 20 deletions(-) diff --git a/core/relay/src/client.rs b/core/relay/src/client.rs index 228c698d6..e58dddc1f 100644 --- a/core/relay/src/client.rs +++ b/core/relay/src/client.rs @@ -3,7 +3,7 @@ mod relay_proto; use futures::future::{BoxFuture, FutureExt}; use pb::common::ack::ack; use pb::common::state::request_state; -use pb::common::events::{event_subscription_state, EventType, EventMatcher, EventPublication, event_publication}; +use pb::common::events::{event_subscription_state, EventMatcher, EventPublication, event_publication}; use pb::networks::networks::{network_client::NetworkClient, GetStateMessage, NetworkQuery, NetworkEventSubscription, NetworkEventUnsubscription}; use relay_proto::get_url; use std::env; @@ -73,7 +73,7 @@ fn poll_for_state( None => println!("No status returned from get state request"), }; } - Err(error) => println!("Error getting state response"), + Err(_error) => println!("Error getting state response"), } } .boxed() @@ -127,7 +127,7 @@ async fn event_suscribe() -> Result<(), Box> { }, None => println!("The returned Ack has no status"), } - event_unsuscribe(request_id.to_string()).await; + let _res = event_unsuscribe(request_id.to_string()).await; Ok(()) } @@ -209,7 +209,7 @@ fn poll_for_event_subscription( None => println!("No status returned from get state request"), }; } - Err(error) => println!("Error getting state response"), + Err(_error) => println!("Error getting state response"), } } .boxed() diff --git a/core/relay/src/relay_proto.rs b/core/relay/src/relay_proto.rs index d1311113c..4e72f6d0c 100644 --- a/core/relay/src/relay_proto.rs +++ b/core/relay/src/relay_proto.rs @@ -15,6 +15,7 @@ pub struct Address { pub network_id: String, } +#[allow(dead_code)] pub fn parse_address(address: String) -> Result { println!("Address to be parsed: {}", address); let v: Vec<&str> = address.split('/').collect(); @@ -31,6 +32,7 @@ pub fn parse_address(address: String) -> Result { }) } +#[allow(dead_code)] fn parse_location(location: String) -> Result { let v: Vec<&str> = location.split(":").collect(); if v.len() != 2 { @@ -47,6 +49,7 @@ fn parse_location(location: String) -> Result { }) } +#[allow(dead_code)] pub fn get_url(args: &[String]) -> String { let port = if args.len() >= 2 { args[1].clone() diff --git a/core/relay/src/services/data_transfer_service.rs b/core/relay/src/services/data_transfer_service.rs index a1aab23d1..5b65ccdf0 100644 --- a/core/relay/src/services/data_transfer_service.rs +++ b/core/relay/src/services/data_transfer_service.rs @@ -2,7 +2,6 @@ use crate::pb::common::ack::{ack, Ack}; use crate::pb::common::query::Query; use crate::pb::common::state::{request_state, view_payload, RequestState, ViewPayload}; -use crate::pb::driver::driver::driver_communication_client::DriverCommunicationClient; use crate::pb::relay::datatransfer::data_transfer_client::DataTransferClient; use crate::pb::relay::datatransfer::data_transfer_server::DataTransfer; // Internal modules @@ -10,13 +9,11 @@ use crate::db::Database; use crate::error::Error; use crate::relay_proto::{parse_address, LocationSegment}; use crate::services::helpers::{get_driver, get_driver_client}; -use crate::services::types::{Driver, Network}; +use crate::services::types::{Driver}; // external modules use config; -use serde; use tokio::sync::RwLock; use tonic::{Request, Response, Status}; -use base64::{encode, decode}; use tonic::transport::{Certificate, Channel, ClientTlsConfig}; diff --git a/core/relay/src/services/event_subscribe_service.rs b/core/relay/src/services/event_subscribe_service.rs index 2db1b7087..a49e2657e 100644 --- a/core/relay/src/services/event_subscribe_service.rs +++ b/core/relay/src/services/event_subscribe_service.rs @@ -2,22 +2,19 @@ use crate::pb::common::ack::{ack, Ack}; use crate::pb::common::query::Query; use crate::pb::common::events::EventSubscription; -use crate::pb::driver::driver::driver_communication_client::DriverCommunicationClient; use crate::pb::relay::events::event_subscribe_client::EventSubscribeClient; use crate::pb::relay::events::event_subscribe_server::EventSubscribe; -use crate::pb::common::events::{event_subscription_state, EventSubscriptionState}; +use crate::pb::common::events::{event_subscription_state}; // Internal modules use crate::db::Database; use crate::error::Error; use crate::relay_proto::{parse_address, LocationSegment}; use crate::services::helpers::{update_event_subscription_status, get_driver, get_driver_client}; -use crate::services::types::{Driver, Network}; +use crate::services::types::{Driver}; // external modules use config; -use serde; use tokio::sync::RwLock; use tonic::{Request, Response, Status}; -use base64::{encode, decode}; use tonic::transport::{Certificate, Channel, ClientTlsConfig}; diff --git a/core/relay/src/services/helpers.rs b/core/relay/src/services/helpers.rs index 129cd278c..98c66a0a2 100644 --- a/core/relay/src/services/helpers.rs +++ b/core/relay/src/services/helpers.rs @@ -1,6 +1,6 @@ use crate::pb::common::query::Query; use crate::pb::common::events::{event_subscription_state, EventSubscriptionState}; -use crate::pb::common::events::{EventSubOperation, EventSubscription}; +use crate::pb::common::events::{EventSubscription}; use crate::pb::driver::driver::driver_communication_client::DriverCommunicationClient; use crate::db::Database; @@ -8,8 +8,6 @@ use crate::services::types::{Driver, Network}; use crate::error::Error; use config; -use tokio::sync::RwLock; -use tonic::{Code, Request, Response, Status}; use tonic::transport::{Certificate, Channel, ClientTlsConfig}; // Locally scoped function to update request status in db. This function is diff --git a/core/relay/src/services/network_service.rs b/core/relay/src/services/network_service.rs index d1a3533a1..0ea5e9ab9 100644 --- a/core/relay/src/services/network_service.rs +++ b/core/relay/src/services/network_service.rs @@ -10,7 +10,6 @@ use crate::pb::relay::events::event_subscribe_client::EventSubscribeClient; use crate::relay_proto::{parse_address, LocationSegment}; // Internal modules use crate::db::Database; -use crate::error::Error; use crate::services::helpers::update_event_subscription_status; use crate::services::helpers::driver_sign_subscription_helper; @@ -20,7 +19,6 @@ use sled::open; use tokio::sync::RwLock; use tonic::{Code, Request, Response, Status}; use uuid::Uuid; -use base64::{encode, decode}; use tonic::transport::{Certificate, Channel, ClientTlsConfig}; @@ -611,7 +609,6 @@ fn spawn_send_event_subscription_request( relay_host, relay_port, event_subscription, - request_id.clone(), relay_tls, relay_tlsca_cert_path.to_string(), ) @@ -660,7 +657,6 @@ async fn suscribe_event_call( relay_host: String, relay_port: String, event_subscription: EventSubscription, - request_id: String, use_tls: bool, tlsca_cert_path: String, ) -> Result, Box> { From 5a49bd5daaea0799df0de304d18fe360760ac65b Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Sat, 9 Jul 2022 02:07:31 +0530 Subject: [PATCH 032/150] added unsubscribe api in weaver sdk and fabric-cli Signed-off-by: sandeep.nishad1 --- .../{suscribe-driver.ts => subscribe.ts} | 5 - .../src/commands/event/unsubscribe.ts | 137 ++++++++++++++++++ .../src/EventsManager.ts | 76 +++++++++- .../interoperation-node-sdk/src/Relay.ts | 115 ++++++++++++++- 4 files changed, 325 insertions(+), 8 deletions(-) rename samples/fabric/fabric-cli/src/commands/event/{suscribe-driver.ts => subscribe.ts} (96%) create mode 100644 samples/fabric/fabric-cli/src/commands/event/unsubscribe.ts diff --git a/samples/fabric/fabric-cli/src/commands/event/suscribe-driver.ts b/samples/fabric/fabric-cli/src/commands/event/subscribe.ts similarity index 96% rename from samples/fabric/fabric-cli/src/commands/event/suscribe-driver.ts rename to samples/fabric/fabric-cli/src/commands/event/subscribe.ts index 47a1f5581..366e83347 100644 --- a/samples/fabric/fabric-cli/src/commands/event/suscribe-driver.ts +++ b/samples/fabric/fabric-cli/src/commands/event/subscribe.ts @@ -40,11 +40,6 @@ const command: GluegunCommand = { description: 'User for subscription. Default: user1' }, - { - name: '--driver', - description: - 'Flag to indicate subscribing on behalf of driver' - }, { name: '--debug', description: diff --git a/samples/fabric/fabric-cli/src/commands/event/unsubscribe.ts b/samples/fabric/fabric-cli/src/commands/event/unsubscribe.ts new file mode 100644 index 000000000..d3d6fb504 --- /dev/null +++ b/samples/fabric/fabric-cli/src/commands/event/unsubscribe.ts @@ -0,0 +1,137 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import { GluegunCommand } from 'gluegun' +import { fabricHelper, getKeyAndCertForRemoteRequestbyUserName } from '../../helpers/fabric-functions' +import logger from '../../helpers/logger' +import { Utils, ICryptoKey } from 'fabric-common' +import { commandHelp, getNetworkConfig, handlePromise } from '../../helpers/helpers' +import { EventsManager } from '@hyperledger-labs/weaver-fabric-interop-sdk' +import { EventSubscriptionState, EventType } from "@hyperledger-labs/weaver-protos-js/common/events_pb"; +import * as fs from 'fs' +import * as path from 'path' + +const command: GluegunCommand = { + name: 'unsubscribe', + alias: ['-sd'], + description: 'Initiate event unsubscribe', + run: async toolbox => { + const { + print, + parameters: { options, array } + } = toolbox + if (options.help || options.h) { + commandHelp( + print, + toolbox, + `fabric-cli event unsubscribe --network= --user=user1 --request-id="abc123" src/data/event_sub_sample.json`, + 'fabric-cli event unsubscribe --network= --user= --request-id= ', + [ + { + name: '--network', + description: + 'Local network for command. ' + }, + { + name: '--user', + description: + 'User for subscription. Default: user1' + }, + { + name: '--request-id', + description: + 'Request ID received during subscription.' + }, + { + name: '--debug', + description: + 'Shows debug logs when running. Disabled by default. To enable --debug=true' + } + ], + command, + ['event', 'unsubscribe'] + ) + return + } + console.log("Event Subscription") + if (options.debug === 'true') { + logger.level = 'debug' + logger.debug('Debugging is enabled') + } + if (array.length != 1) { + print.error('Not enough arguments supplied') + return + } + if (!options['request-id']) + { + print.error('--request-id needs to be specified') + return + } + if (!options['user']) { + options['user'] = `user1` //Default user + } + + const networkName = options['network'] + const user = options['user'] + const requestId = options['request-id'] + + const filepath = path.resolve(array[0]) + const data = JSON.parse(fs.readFileSync(filepath).toString()) + + const netConfig = getNetworkConfig(networkName) + if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { + throw new Error(`No valid config entry found for ${networkName}`) + } + + const { gateway, wallet, contract } = await fabricHelper({ + channel: netConfig.channelName, + contractName: process.env.DEFAULT_CHAINCODE ? process.env.DEFAULT_CHAINCODE : 'interop', + connProfilePath: netConfig.connProfilePath, + networkName, + mspId: netConfig.mspId, + logger, + discoveryEnabled: true, + userString: user + }) + + const [keyCert, keyCertError] = await handlePromise( + getKeyAndCertForRemoteRequestbyUserName(wallet, user) + ) + if (keyCertError) { + throw new Error(`Error getting key and cert ${keyCertError}`) + } + + const eventMatcher = EventsManager.createEventMatcher(data.event_matcher) + const eventPublicationSpec = EventsManager.createEventPublicationSpec(data.event_publication_spec) + + try { + const response = await EventsManager.unsubscribeRemoteEvent( + contract, + eventMatcher, + eventPublicationSpec, + requestId, + networkName, + netConfig.mspId, + netConfig.relayEndpoint, + { address: data.view_address, Sign: true }, + keyCert + ) + + if (response.getStatus() == EventSubscriptionState.STATUS.UNSUBSCRIBED) { + console.log("Event Unsubscription Success for requestId:", response.getRequestId()) + } else { + console.log("Unknown error") + } + } catch(e) { + console.log("Error: ", e.toString()) + } + + process.exit() + } +} + + +module.exports = command diff --git a/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts b/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts index f5dd374ec..4e7fe18ea 100644 --- a/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts +++ b/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts @@ -124,7 +124,7 @@ const subscribeRemoteEvent = async ( event: ${eventMatcher} and publication spec: ${eventPublicationSpec}") const [relayResponse, relayResponseError] = await helpers.handlePromise( - relay.ProcessSuscribeEventRequest( + relay.ProcessSubscribeEventRequest( eventMatcher, eventPublicationSpec, computedAddress, @@ -147,9 +147,83 @@ const subscribeRemoteEvent = async ( return relayResponse } + +const unsubscribeRemoteEvent = async ( + interopContract: Contract, + eventMatcher: eventsPb.EventMatcher, + eventPublicationSpec: eventsPb.EventPublication, + requestID: string, + networkID: string, + org: string, + localRelayEndpoint: string, + interopJSON: InteropJSON, + keyCert: { key: ICryptoKey; cert: any }, + useTls: boolean = false, + tlsRootCACertPaths?: Array, + confidential: boolean = false, +): Promise => { + logger.debug("Remote Event Unsubscription") + const { + address, + ChaincodeFunc, + ChaincodeID, + ChannelID, + RemoteEndpoint, + NetworkID: RemoteNetworkID, + Sign, + ccArgs: args, + } = interopJSON; + // Step 1 + const computedAddress = + address || + createAddress( + { ccFunc: ChaincodeFunc, contractName: ChaincodeID, channel: ChannelID, ccArgs: args }, + RemoteNetworkID, + RemoteEndpoint, + ); + + const [policyCriteria, policyCriteriaError] = await helpers.handlePromise( + getPolicyCriteriaForAddress(interopContract, computedAddress), + ); + if (policyCriteriaError) { + throw new Error(`InteropFlow failed to get policy criteria: ${policyCriteriaError}`); + } + + const relay = useTls ? new Relay(localRelayEndpoint, Relay.defaultTimeout, true, tlsRootCACertPaths) : new Relay(localRelayEndpoint); + const uuidValue = uuidv4(); + + logger.debug("Making event unsubscription call to relay for \ + event: ${eventMatcher} and publication spec: ${eventPublicationSpec}") + + const [relayResponse, relayResponseError] = await helpers.handlePromise( + relay.ProcessUnsubscribeEventRequest( + eventMatcher, + eventPublicationSpec, + requestID, + computedAddress, + policyCriteria, + networkID, + keyCert.cert, + Sign ? signMessage(computedAddress + uuidValue, keyCert.key.toBytes()).toString("base64") : "", + uuidValue, + // Org is empty as the name is in the certs for + org, + confidential, + ), + ); + if (relayResponseError) { + throw new Error(`Event Unsubscription relay response error: ${relayResponseError}`); + } + + logger.debug(`Event Unsubscription Successfull: ${JSON.stringify(relayResponse)}`) + + return relayResponse +} + export { createEventMatcher, createEventPublicationSpec, subscribeRemoteEvent, + unsubscribeRemoteEvent, } diff --git a/sdks/fabric/interoperation-node-sdk/src/Relay.ts b/sdks/fabric/interoperation-node-sdk/src/Relay.ts index e2e0a2a4f..1e9e5d70f 100644 --- a/sdks/fabric/interoperation-node-sdk/src/Relay.ts +++ b/sdks/fabric/interoperation-node-sdk/src/Relay.ts @@ -314,7 +314,7 @@ class Relay { * Uses the timeout provided by the class. * @returns {string} The state returned by the remote request */ - async ProcessSuscribeEventRequest( + async ProcessSubscribeEventRequest( eventMatcher: eventsPb.EventMatcher, eventPublicationSpec: eventsPb.EventPublication, address: string, @@ -331,7 +331,7 @@ class Relay { this.SendEventSubscribeRequest(eventMatcher, eventPublicationSpec, address, policy, requestingNetwork, certificate, signature, nonce, org, confidential), ); if (error) { - throw new Error(`Request state error: ${error}`); + throw new Error(`Event subscription error: ${error}`); } // Adds timout time to current time. const dateObj = new Date(); @@ -354,6 +354,117 @@ class Relay { throw new Error(e); } } + /** + * SendEventUnsubscribeRequest to send a request to a remote network using gRPC and the relay. + * @returns {string} The ID of the request + */ + async SendEventUnsubscribeRequest( + eventMatcher: eventsPb.EventMatcher, + eventPublicationSpec: eventsPb.EventPublication, + requestId: string, + address: string, + policy, + requestingNetwork: string, + certificate: string, + signature: string, + nonce: string, + org: string, + confidential: boolean, + ): Promise { + try { + const networkClient = new networksGrpcPb.NetworkClient( + this.getEndpoint(), + this._useTls ? + (this._tlsRootCACerts.length == 0 ? grpcJs.credentials.createSsl() : grpcJs.credentials.createSsl(Buffer.from(this._tlsRootCACerts))) : + grpcJs.credentials.createInsecure() + ); + const { + unsubscribeEvent, + }: { + unsubscribeEvent: (eventUnsubscription: networksPb.NetworkEventUnsubscription) => Promise; + } = helpers.promisifyAll(networkClient); + + const query = new networksPb.NetworkQuery(); + query.setPolicyList(policy); + query.setAddress(address); + query.setCertificate(certificate); + query.setNonce(nonce); + query.setRequestorSignature(signature); + query.setRequestingRelay(""); + query.setRequestingNetwork(requestingNetwork); + query.setRequestingOrg(org || ""); + query.setConfidential(confidential || false); + + const eventSubscription = new networksPb.NetworkEventSubscription(); + eventSubscription.setEventMatcher(eventMatcher); + eventSubscription.setQuery(query); + eventSubscription.setEventPublicationSpec(eventPublicationSpec); + + const eventUnsubscription = new networksPb.NetworkEventUnsubscription(); + eventUnsubscription.setRequest(eventSubscription); + eventUnsubscription.setRequestId(requestId); + + if (typeof unsubscribeEvent === "function") { + const [resp, error] = await helpers.handlePromise(unsubscribeEvent(eventUnsubscription)); + if (error) { + throw new Error(`Event Unsubscription error: ${error}`); + } + if (resp.getStatus() === common_ack_pb.Ack.STATUS.ERROR) { + throw new Error(`Event Unsubscription request received negative Ack error: ${resp.getMessage()}`); + } + return resp.getRequestId(); + } + throw new Error("Error with event unsubscription in NetworkClient"); + } catch (e) { + throw new Error(`Error with Network Client: ${e}`); + } + } + /** + * ProcessEventUnsubscriptionRequest sends a event unsubscription request to a remote network using gRPC and the relay and polls for a response on the local network + * Uses the timeout provided by the class. + * @returns {string} The state returned by the remote request + */ + async ProcessUnsubscribeEventRequest( + eventMatcher: eventsPb.EventMatcher, + eventPublicationSpec: eventsPb.EventPublication, + requestId: string, + address: string, + policy, + requestingNetwork: string, + certificate: string, + signature: string, + nonce: string, + org: string, + confidential: boolean, + ): Promise { + try { + const [requestID, error] = await helpers.handlePromise( + this.SendEventUnsubscribeRequest(eventMatcher, eventPublicationSpec, requestId, address, policy, requestingNetwork, certificate, signature, nonce, org, confidential), + ); + if (error) { + throw new Error(`Event unsubscription error: ${error}`); + } + // Adds timout time to current time. + const dateObj = new Date(); + dateObj.setMilliseconds(dateObj.getMilliseconds() + this.timeoutTime); + //TODO: SLOW DOWN + const [finalState, stateError] = await helpers.handlePromise(this.recursiveEventSubscriptionState(requestID, dateObj)); + if (stateError) { + throw new Error(`Event unsubscription error: ${stateError}`); + } + if (finalState.getStatus() === eventsPb.EventSubscriptionState.STATUS.ERROR) { + if (finalState.getMessage()) { + throw new Error(`Error during event unsubscription : ${finalState.getMessage()}`); + } + else { + throw new Error(`Error during event unsubscription : UNKNOWN REASON}`); + } + } + return finalState; + } catch (e) { + throw new Error(e); + } + } } From 2d14341a66f2a8398188e54e9d0ed049ae5c94bb Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Sat, 9 Jul 2022 11:30:10 +0530 Subject: [PATCH 033/150] fix weaver sdk bug: not waiting for unsubscribe pending status Signed-off-by: sandeep.nishad1 --- .../fabric-cli/src/data/event_sub_sample.json | 22 +++++++++---------- .../interoperation-node-sdk/src/Relay.ts | 3 ++- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/samples/fabric/fabric-cli/src/data/event_sub_sample.json b/samples/fabric/fabric-cli/src/data/event_sub_sample.json index 4c1b2094f..bc7286f87 100644 --- a/samples/fabric/fabric-cli/src/data/event_sub_sample.json +++ b/samples/fabric/fabric-cli/src/data/event_sub_sample.json @@ -1,18 +1,18 @@ { "event_matcher": { - "event_type": 1, - "event_class_id": "", - "transaction_ledger_id": "mychannel", - "transaction_contract_id": "simplestate", - "transaction_func": "Create" + "eventType": 1, + "eventClassId": "", + "transactionLedgerId": "mychannel", + "transactionContractId": "simplestate", + "transactionFunc": "Create" }, "event_publication_spec": { - "args": [], - "contract_id": "simplestate", - "driver_id": "network1", - "func": "Create", - "ledger_id": "mychannel", - "replace_arg_index": "0" + "ccArgs": [], + "contractId": "simplestate", + "driverId": "network1", + "ccFunc": "Create", + "ledgerId": "mychannel", + "replaceArgIndex": "0" }, "view_address": "localhost:9083/network2/mychannel:simplestate:Read:a", "confidential": false diff --git a/sdks/fabric/interoperation-node-sdk/src/Relay.ts b/sdks/fabric/interoperation-node-sdk/src/Relay.ts index 1e9e5d70f..467f91d23 100644 --- a/sdks/fabric/interoperation-node-sdk/src/Relay.ts +++ b/sdks/fabric/interoperation-node-sdk/src/Relay.ts @@ -298,7 +298,8 @@ class Relay { } if ( state.getStatus() === eventsPb.EventSubscriptionState.STATUS.PENDING || - state.getStatus() === eventsPb.EventSubscriptionState.STATUS.PENDING_ACK + state.getStatus() === eventsPb.EventSubscriptionState.STATUS.PENDING_ACK || + state.getStatus() === eventsPb.EventSubscriptionState.STATUS.UNSUBSCRIBE_PENDING ) { if (dateObj.getTime() < Date.now()) { throw new Error("Timeout: State is still pending."); From f602fcc10441adc377e7f7c30ec2fd8d36b5a7f3 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Sun, 10 Jul 2022 14:41:45 +0530 Subject: [PATCH 034/150] 1. Added get subscription status api in weaver sdk and fabric-cli 2. Updated subscription status protos Signed-off-by: sandeep.nishad1 --- common/protos-go/common/events.pb.go | 190 +++++++++++----- common/protos-go/driver/driver.pb.go | 20 +- common/protos-go/driver/driver_grpc.pb.go | 42 ++++ common/protos-go/networks/networks.pb.go | 207 ++++++++++++------ common/protos-go/networks/networks_grpc.pb.go | 38 ++++ common/protos/common/events.proto | 9 +- core/relay/src/client.rs | 71 ++++-- .../src/services/event_subscribe_service.rs | 23 +- core/relay/src/services/helpers.rs | 87 +++++--- core/relay/src/services/network_service.rs | 22 +- samples/fabric/fabric-cli/readme.md | 20 +- .../commands/event/get-subscription-status.ts | 91 ++++++++ .../src/commands/event/subscribe.ts | 9 +- .../src/commands/event/unsubscribe.ts | 9 +- .../fabric-cli/src/data/event_sub_sample.json | 4 +- .../src/EventsManager.ts | 30 +++ .../interoperation-node-sdk/src/Relay.ts | 7 +- 17 files changed, 669 insertions(+), 210 deletions(-) create mode 100644 samples/fabric/fabric-cli/src/commands/event/get-subscription-status.ts diff --git a/common/protos-go/common/events.pb.go b/common/protos-go/common/events.pb.go index ab82338c3..080c9764c 100644 --- a/common/protos-go/common/events.pb.go +++ b/common/protos-go/common/events.pb.go @@ -69,30 +69,88 @@ func (EventType) EnumDescriptor() ([]byte, []int) { return file_common_events_proto_rawDescGZIP(), []int{0} } +type EventSubOperation int32 + +const ( + EventSubOperation_SUBSCRIBE EventSubOperation = 0 + EventSubOperation_UNSUBSCRIBE EventSubOperation = 1 + EventSubOperation_UPDATE EventSubOperation = 2 +) + +// Enum value maps for EventSubOperation. +var ( + EventSubOperation_name = map[int32]string{ + 0: "SUBSCRIBE", + 1: "UNSUBSCRIBE", + 2: "UPDATE", + } + EventSubOperation_value = map[string]int32{ + "SUBSCRIBE": 0, + "UNSUBSCRIBE": 1, + "UPDATE": 2, + } +) + +func (x EventSubOperation) Enum() *EventSubOperation { + p := new(EventSubOperation) + *p = x + return p +} + +func (x EventSubOperation) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (EventSubOperation) Descriptor() protoreflect.EnumDescriptor { + return file_common_events_proto_enumTypes[1].Descriptor() +} + +func (EventSubOperation) Type() protoreflect.EnumType { + return &file_common_events_proto_enumTypes[1] +} + +func (x EventSubOperation) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use EventSubOperation.Descriptor instead. +func (EventSubOperation) EnumDescriptor() ([]byte, []int) { + return file_common_events_proto_rawDescGZIP(), []int{1} +} + type EventSubscriptionState_STATUS int32 const ( // pending ACK from remote relay - EventSubscriptionState_PENDING_ACK EventSubscriptionState_STATUS = 0 + EventSubscriptionState_SUBSCRIBE_PENDING_ACK EventSubscriptionState_STATUS = 0 // Received ACK, waiting for event subscription confirmation from remote relay - EventSubscriptionState_PENDING EventSubscriptionState_STATUS = 1 - EventSubscriptionState_ERROR EventSubscriptionState_STATUS = 2 - EventSubscriptionState_SUCCESS EventSubscriptionState_STATUS = 3 + EventSubscriptionState_SUBSCRIBE_PENDING EventSubscriptionState_STATUS = 1 + EventSubscriptionState_SUBSCRIBED EventSubscriptionState_STATUS = 2 + EventSubscriptionState_UNSUBSCRIBE_PENDING_ACK EventSubscriptionState_STATUS = 3 + EventSubscriptionState_UNSUBSCRIBE_PENDING EventSubscriptionState_STATUS = 4 + EventSubscriptionState_UNSUBSCRIBED EventSubscriptionState_STATUS = 5 + EventSubscriptionState_ERROR EventSubscriptionState_STATUS = 6 ) // Enum value maps for EventSubscriptionState_STATUS. var ( EventSubscriptionState_STATUS_name = map[int32]string{ - 0: "PENDING_ACK", - 1: "PENDING", - 2: "ERROR", - 3: "SUCCESS", + 0: "SUBSCRIBE_PENDING_ACK", + 1: "SUBSCRIBE_PENDING", + 2: "SUBSCRIBED", + 3: "UNSUBSCRIBE_PENDING_ACK", + 4: "UNSUBSCRIBE_PENDING", + 5: "UNSUBSCRIBED", + 6: "ERROR", } EventSubscriptionState_STATUS_value = map[string]int32{ - "PENDING_ACK": 0, - "PENDING": 1, - "ERROR": 2, - "SUCCESS": 3, + "SUBSCRIBE_PENDING_ACK": 0, + "SUBSCRIBE_PENDING": 1, + "SUBSCRIBED": 2, + "UNSUBSCRIBE_PENDING_ACK": 3, + "UNSUBSCRIBE_PENDING": 4, + "UNSUBSCRIBED": 5, + "ERROR": 6, } ) @@ -107,11 +165,11 @@ func (x EventSubscriptionState_STATUS) String() string { } func (EventSubscriptionState_STATUS) Descriptor() protoreflect.EnumDescriptor { - return file_common_events_proto_enumTypes[1].Descriptor() + return file_common_events_proto_enumTypes[2].Descriptor() } func (EventSubscriptionState_STATUS) Type() protoreflect.EnumType { - return &file_common_events_proto_enumTypes[1] + return &file_common_events_proto_enumTypes[2] } func (x EventSubscriptionState_STATUS) Number() protoreflect.EnumNumber { @@ -202,13 +260,16 @@ func (x *EventMatcher) GetTransactionFunc() string { return "" } +// Below message is used to communicate between dest-relay and src-relay; +// and src-relay and src-driver. type EventSubscription struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - EventMatcher *EventMatcher `protobuf:"bytes,1,opt,name=event_matcher,json=eventMatcher,proto3" json:"event_matcher,omitempty"` - Query *Query `protobuf:"bytes,2,opt,name=query,proto3" json:"query,omitempty"` + EventMatcher *EventMatcher `protobuf:"bytes,1,opt,name=event_matcher,json=eventMatcher,proto3" json:"event_matcher,omitempty"` + Query *Query `protobuf:"bytes,2,opt,name=query,proto3" json:"query,omitempty"` + Operation EventSubOperation `protobuf:"varint,3,opt,name=operation,proto3,enum=common.events.EventSubOperation" json:"operation,omitempty"` } func (x *EventSubscription) Reset() { @@ -257,6 +318,13 @@ func (x *EventSubscription) GetQuery() *Query { return nil } +func (x *EventSubscription) GetOperation() EventSubOperation { + if x != nil { + return x.Operation + } + return EventSubOperation_SUBSCRIBE +} + type EventSubscriptionState struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -312,7 +380,7 @@ func (x *EventSubscriptionState) GetStatus() EventSubscriptionState_STATUS { if x != nil { return x.Status } - return EventSubscriptionState_PENDING_ACK + return EventSubscriptionState_SUBSCRIBE_PENDING_ACK } func (x *EventSubscriptionState) GetMessage() string { @@ -526,7 +594,7 @@ var file_common_events_proto_rawDesc = []byte{ 0x63, 0x74, 0x49, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x75, 0x6e, 0x63, 0x22, - 0x80, 0x01, 0x0a, 0x11, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0xc0, 0x01, 0x0a, 0x11, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, @@ -534,7 +602,11 @@ var file_common_events_proto_rawDesc = []byte{ 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x29, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x05, 0x71, 0x75, 0x65, - 0x72, 0x79, 0x22, 0xf0, 0x02, 0x0a, 0x16, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, + 0x72, 0x79, 0x12, 0x3e, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x4f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x22, 0xd0, 0x03, 0x0a, 0x16, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x44, 0x0a, 0x06, @@ -553,11 +625,17 @@ var file_common_events_proto_rawDesc = []byte{ 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x14, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x53, 0x70, 0x65, 0x63, 0x22, 0x3e, 0x0a, 0x06, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x12, - 0x0f, 0x0a, 0x0b, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x41, 0x43, 0x4b, 0x10, 0x00, - 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, - 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, - 0x45, 0x53, 0x53, 0x10, 0x03, 0x22, 0xc4, 0x01, 0x0a, 0x13, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, + 0x6e, 0x53, 0x70, 0x65, 0x63, 0x22, 0x9d, 0x01, 0x0a, 0x06, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, + 0x12, 0x19, 0x0a, 0x15, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x5f, 0x50, 0x45, + 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x41, 0x43, 0x4b, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x53, + 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, + 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x44, + 0x10, 0x02, 0x12, 0x1b, 0x0a, 0x17, 0x55, 0x4e, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, + 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x41, 0x43, 0x4b, 0x10, 0x03, 0x12, + 0x17, 0x0a, 0x13, 0x55, 0x4e, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x5f, 0x50, + 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x04, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x53, 0x55, + 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x44, 0x10, 0x05, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, + 0x52, 0x4f, 0x52, 0x10, 0x06, 0x22, 0xc4, 0x01, 0x0a, 0x13, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x65, @@ -581,15 +659,19 @@ var file_common_events_proto_rawDesc = []byte{ 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x4c, 0x45, 0x44, 0x47, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x53, 0x53, 0x45, 0x54, 0x5f, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x53, 0x53, 0x45, - 0x54, 0x5f, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x10, 0x02, 0x42, 0x72, 0x0a, 0x1f, 0x63, 0x6f, 0x6d, - 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x5a, 0x4f, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, - 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, - 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, - 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x54, 0x5f, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x10, 0x02, 0x2a, 0x3f, 0x0a, 0x11, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x53, 0x75, 0x62, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0d, + 0x0a, 0x09, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x10, 0x00, 0x12, 0x0f, 0x0a, + 0x0b, 0x55, 0x4e, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x10, 0x01, 0x12, 0x0a, + 0x0a, 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x02, 0x42, 0x72, 0x0a, 0x1f, 0x63, 0x6f, + 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x5a, 0x4f, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, + 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, + 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, + 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -604,31 +686,33 @@ func file_common_events_proto_rawDescGZIP() []byte { return file_common_events_proto_rawDescData } -var file_common_events_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_common_events_proto_enumTypes = make([]protoimpl.EnumInfo, 3) var file_common_events_proto_msgTypes = make([]protoimpl.MessageInfo, 5) var file_common_events_proto_goTypes = []interface{}{ (EventType)(0), // 0: common.events.EventType - (EventSubscriptionState_STATUS)(0), // 1: common.events.EventSubscriptionState.STATUS - (*EventMatcher)(nil), // 2: common.events.EventMatcher - (*EventSubscription)(nil), // 3: common.events.EventSubscription - (*EventSubscriptionState)(nil), // 4: common.events.EventSubscriptionState - (*ContractTransaction)(nil), // 5: common.events.ContractTransaction - (*EventPublication)(nil), // 6: common.events.EventPublication - (*Query)(nil), // 7: common.query.Query + (EventSubOperation)(0), // 1: common.events.EventSubOperation + (EventSubscriptionState_STATUS)(0), // 2: common.events.EventSubscriptionState.STATUS + (*EventMatcher)(nil), // 3: common.events.EventMatcher + (*EventSubscription)(nil), // 4: common.events.EventSubscription + (*EventSubscriptionState)(nil), // 5: common.events.EventSubscriptionState + (*ContractTransaction)(nil), // 6: common.events.ContractTransaction + (*EventPublication)(nil), // 7: common.events.EventPublication + (*Query)(nil), // 8: common.query.Query } var file_common_events_proto_depIdxs = []int32{ 0, // 0: common.events.EventMatcher.event_type:type_name -> common.events.EventType - 2, // 1: common.events.EventSubscription.event_matcher:type_name -> common.events.EventMatcher - 7, // 2: common.events.EventSubscription.query:type_name -> common.query.Query - 1, // 3: common.events.EventSubscriptionState.status:type_name -> common.events.EventSubscriptionState.STATUS - 2, // 4: common.events.EventSubscriptionState.event_matcher:type_name -> common.events.EventMatcher - 6, // 5: common.events.EventSubscriptionState.event_publication_spec:type_name -> common.events.EventPublication - 5, // 6: common.events.EventPublication.ctx:type_name -> common.events.ContractTransaction - 7, // [7:7] is the sub-list for method output_type - 7, // [7:7] is the sub-list for method input_type - 7, // [7:7] is the sub-list for extension type_name - 7, // [7:7] is the sub-list for extension extendee - 0, // [0:7] is the sub-list for field type_name + 3, // 1: common.events.EventSubscription.event_matcher:type_name -> common.events.EventMatcher + 8, // 2: common.events.EventSubscription.query:type_name -> common.query.Query + 1, // 3: common.events.EventSubscription.operation:type_name -> common.events.EventSubOperation + 2, // 4: common.events.EventSubscriptionState.status:type_name -> common.events.EventSubscriptionState.STATUS + 3, // 5: common.events.EventSubscriptionState.event_matcher:type_name -> common.events.EventMatcher + 7, // 6: common.events.EventSubscriptionState.event_publication_spec:type_name -> common.events.EventPublication + 6, // 7: common.events.EventPublication.ctx:type_name -> common.events.ContractTransaction + 8, // [8:8] is the sub-list for method output_type + 8, // [8:8] is the sub-list for method input_type + 8, // [8:8] is the sub-list for extension type_name + 8, // [8:8] is the sub-list for extension extendee + 0, // [0:8] is the sub-list for field type_name } func init() { file_common_events_proto_init() } @@ -708,7 +792,7 @@ func file_common_events_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_common_events_proto_rawDesc, - NumEnums: 2, + NumEnums: 3, NumMessages: 5, NumExtensions: 0, NumServices: 0, diff --git a/common/protos-go/driver/driver.pb.go b/common/protos-go/driver/driver.pb.go index b9a157733..3f324a774 100644 --- a/common/protos-go/driver/driver.pb.go +++ b/common/protos-go/driver/driver.pb.go @@ -29,7 +29,7 @@ var file_driver_driver_proto_rawDesc = []byte{ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x12, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x13, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, - 0x9a, 0x01, 0x0a, 0x13, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, + 0xfa, 0x01, 0x0a, 0x13, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x51, 0x75, 0x65, @@ -38,7 +38,13 @@ var file_driver_driver_proto_rawDesc = []byte{ 0x62, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, 0x72, 0x0a, 0x1f, + 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x5e, 0x0a, 0x23, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x12, 0x20, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x71, + 0x75, 0x65, 0x72, 0x79, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x22, 0x00, 0x42, 0x72, 0x0a, 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, @@ -57,10 +63,12 @@ var file_driver_driver_proto_goTypes = []interface{}{ var file_driver_driver_proto_depIdxs = []int32{ 0, // 0: driver.driver.DriverCommunication.RequestDriverState:input_type -> common.query.Query 1, // 1: driver.driver.DriverCommunication.SubscribeEvent:input_type -> common.events.EventSubscription - 2, // 2: driver.driver.DriverCommunication.RequestDriverState:output_type -> common.ack.Ack - 2, // 3: driver.driver.DriverCommunication.SubscribeEvent:output_type -> common.ack.Ack - 2, // [2:4] is the sub-list for method output_type - 0, // [0:2] is the sub-list for method input_type + 1, // 2: driver.driver.DriverCommunication.RequestSignedEventSubscriptionQuery:input_type -> common.events.EventSubscription + 2, // 3: driver.driver.DriverCommunication.RequestDriverState:output_type -> common.ack.Ack + 2, // 4: driver.driver.DriverCommunication.SubscribeEvent:output_type -> common.ack.Ack + 0, // 5: driver.driver.DriverCommunication.RequestSignedEventSubscriptionQuery:output_type -> common.query.Query + 3, // [3:6] is the sub-list for method output_type + 0, // [0:3] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name diff --git a/common/protos-go/driver/driver_grpc.pb.go b/common/protos-go/driver/driver_grpc.pb.go index ae7e067f2..0fa151bcc 100644 --- a/common/protos-go/driver/driver_grpc.pb.go +++ b/common/protos-go/driver/driver_grpc.pb.go @@ -26,6 +26,10 @@ type DriverCommunicationClient interface { // Events Subscription // the src-relay uses this endpoint to forward the event subscription request from dest-relay to driver SubscribeEvent(ctx context.Context, in *common.EventSubscription, opts ...grpc.CallOption) (*common.Ack, error) + // Recommended to have TLS mode on for this unsafe endpoint + // Relay uses this to get Query.requestor_signature and + // Query.certificate required for event subscription + RequestSignedEventSubscriptionQuery(ctx context.Context, in *common.EventSubscription, opts ...grpc.CallOption) (*common.Query, error) } type driverCommunicationClient struct { @@ -54,6 +58,15 @@ func (c *driverCommunicationClient) SubscribeEvent(ctx context.Context, in *comm return out, nil } +func (c *driverCommunicationClient) RequestSignedEventSubscriptionQuery(ctx context.Context, in *common.EventSubscription, opts ...grpc.CallOption) (*common.Query, error) { + out := new(common.Query) + err := c.cc.Invoke(ctx, "/driver.driver.DriverCommunication/RequestSignedEventSubscriptionQuery", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // DriverCommunicationServer is the server API for DriverCommunication service. // All implementations must embed UnimplementedDriverCommunicationServer // for forward compatibility @@ -65,6 +78,10 @@ type DriverCommunicationServer interface { // Events Subscription // the src-relay uses this endpoint to forward the event subscription request from dest-relay to driver SubscribeEvent(context.Context, *common.EventSubscription) (*common.Ack, error) + // Recommended to have TLS mode on for this unsafe endpoint + // Relay uses this to get Query.requestor_signature and + // Query.certificate required for event subscription + RequestSignedEventSubscriptionQuery(context.Context, *common.EventSubscription) (*common.Query, error) mustEmbedUnimplementedDriverCommunicationServer() } @@ -78,6 +95,9 @@ func (UnimplementedDriverCommunicationServer) RequestDriverState(context.Context func (UnimplementedDriverCommunicationServer) SubscribeEvent(context.Context, *common.EventSubscription) (*common.Ack, error) { return nil, status.Errorf(codes.Unimplemented, "method SubscribeEvent not implemented") } +func (UnimplementedDriverCommunicationServer) RequestSignedEventSubscriptionQuery(context.Context, *common.EventSubscription) (*common.Query, error) { + return nil, status.Errorf(codes.Unimplemented, "method RequestSignedEventSubscriptionQuery not implemented") +} func (UnimplementedDriverCommunicationServer) mustEmbedUnimplementedDriverCommunicationServer() {} // UnsafeDriverCommunicationServer may be embedded to opt out of forward compatibility for this service. @@ -127,6 +147,24 @@ func _DriverCommunication_SubscribeEvent_Handler(srv interface{}, ctx context.Co return interceptor(ctx, in, info, handler) } +func _DriverCommunication_RequestSignedEventSubscriptionQuery_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(common.EventSubscription) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DriverCommunicationServer).RequestSignedEventSubscriptionQuery(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/driver.driver.DriverCommunication/RequestSignedEventSubscriptionQuery", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DriverCommunicationServer).RequestSignedEventSubscriptionQuery(ctx, req.(*common.EventSubscription)) + } + return interceptor(ctx, in, info, handler) +} + // DriverCommunication_ServiceDesc is the grpc.ServiceDesc for DriverCommunication service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -142,6 +180,10 @@ var DriverCommunication_ServiceDesc = grpc.ServiceDesc{ MethodName: "SubscribeEvent", Handler: _DriverCommunication_SubscribeEvent_Handler, }, + { + MethodName: "RequestSignedEventSubscriptionQuery", + Handler: _DriverCommunication_RequestSignedEventSubscriptionQuery_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "driver/driver.proto", diff --git a/common/protos-go/networks/networks.pb.go b/common/protos-go/networks/networks.pb.go index 95f19ae3d..ec1b5e16e 100644 --- a/common/protos-go/networks/networks.pb.go +++ b/common/protos-go/networks/networks.pb.go @@ -273,6 +273,7 @@ func (x *NetworkQuery) GetConfidential() bool { return false } +// Below message is used for network/client to dest-relay communication type NetworkEventSubscription struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -336,6 +337,61 @@ func (x *NetworkEventSubscription) GetEventPublicationSpec() *common.EventPublic return nil } +type NetworkEventUnsubscription struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Request *NetworkEventSubscription `protobuf:"bytes,1,opt,name=request,proto3" json:"request,omitempty"` + RequestId string `protobuf:"bytes,2,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` +} + +func (x *NetworkEventUnsubscription) Reset() { + *x = NetworkEventUnsubscription{} + if protoimpl.UnsafeEnabled { + mi := &file_networks_networks_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NetworkEventUnsubscription) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetworkEventUnsubscription) ProtoMessage() {} + +func (x *NetworkEventUnsubscription) ProtoReflect() protoreflect.Message { + mi := &file_networks_networks_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NetworkEventUnsubscription.ProtoReflect.Descriptor instead. +func (*NetworkEventUnsubscription) Descriptor() ([]byte, []int) { + return file_networks_networks_proto_rawDescGZIP(), []int{5} +} + +func (x *NetworkEventUnsubscription) GetRequest() *NetworkEventSubscription { + if x != nil { + return x.Request + } + return nil +} + +func (x *NetworkEventUnsubscription) GetRequestId() string { + if x != nil { + return x.RequestId + } + return "" +} + var File_networks_networks_proto protoreflect.FileDescriptor var file_networks_networks_proto_rawDesc = []byte{ @@ -395,42 +451,55 @@ var file_networks_networks_proto_rawDesc = []byte{ 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x14, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x53, 0x70, 0x65, 0x63, 0x32, 0xa9, 0x03, 0x0a, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x12, 0x42, 0x0a, 0x0c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, - 0x12, 0x1f, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, - 0x63, 0x6b, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, - 0x12, 0x22, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, - 0x22, 0x00, 0x12, 0x50, 0x0a, 0x0f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, - 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x19, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, - 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x44, 0x62, 0x4e, 0x61, 0x6d, 0x65, - 0x1a, 0x20, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, - 0x73, 0x65, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x0e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, - 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2b, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, - 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x68, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x45, 0x76, 0x65, + 0x53, 0x70, 0x65, 0x63, 0x22, 0x82, 0x01, 0x0a, 0x1a, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x45, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x32, 0xff, 0x03, 0x0a, 0x07, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x42, 0x0a, 0x0c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, + 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x08, 0x47, 0x65, 0x74, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x22, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, + 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x0f, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x19, 0x2e, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x44, + 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x1a, 0x20, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, + 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x44, + 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x0e, 0x53, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2b, 0x2e, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, + 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x68, 0x0a, 0x19, 0x47, + 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x22, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x47, 0x65, 0x74, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x25, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x12, 0x22, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, - 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x25, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x00, - 0x42, 0x78, 0x0a, 0x23, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, - 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x5a, 0x51, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, - 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, - 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, - 0x6f, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x61, 0x74, 0x65, 0x22, 0x00, 0x12, 0x54, 0x0a, 0x10, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x62, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2d, 0x2e, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, 0x78, 0x0a, 0x23, 0x63, + 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, + 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x73, 0x5a, 0x51, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, + 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, + 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -445,40 +514,44 @@ func file_networks_networks_proto_rawDescGZIP() []byte { return file_networks_networks_proto_rawDescData } -var file_networks_networks_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_networks_networks_proto_msgTypes = make([]protoimpl.MessageInfo, 7) var file_networks_networks_proto_goTypes = []interface{}{ (*DbName)(nil), // 0: networks.networks.DbName (*RelayDatabase)(nil), // 1: networks.networks.RelayDatabase (*GetStateMessage)(nil), // 2: networks.networks.GetStateMessage (*NetworkQuery)(nil), // 3: networks.networks.NetworkQuery (*NetworkEventSubscription)(nil), // 4: networks.networks.NetworkEventSubscription - nil, // 5: networks.networks.RelayDatabase.PairsEntry - (*common.EventMatcher)(nil), // 6: common.events.EventMatcher - (*common.EventPublication)(nil), // 7: common.events.EventPublication - (*common.Ack)(nil), // 8: common.ack.Ack - (*common.RequestState)(nil), // 9: common.state.RequestState - (*common.EventSubscriptionState)(nil), // 10: common.events.EventSubscriptionState + (*NetworkEventUnsubscription)(nil), // 5: networks.networks.NetworkEventUnsubscription + nil, // 6: networks.networks.RelayDatabase.PairsEntry + (*common.EventMatcher)(nil), // 7: common.events.EventMatcher + (*common.EventPublication)(nil), // 8: common.events.EventPublication + (*common.Ack)(nil), // 9: common.ack.Ack + (*common.RequestState)(nil), // 10: common.state.RequestState + (*common.EventSubscriptionState)(nil), // 11: common.events.EventSubscriptionState } var file_networks_networks_proto_depIdxs = []int32{ - 5, // 0: networks.networks.RelayDatabase.pairs:type_name -> networks.networks.RelayDatabase.PairsEntry - 6, // 1: networks.networks.NetworkEventSubscription.event_matcher:type_name -> common.events.EventMatcher + 6, // 0: networks.networks.RelayDatabase.pairs:type_name -> networks.networks.RelayDatabase.PairsEntry + 7, // 1: networks.networks.NetworkEventSubscription.event_matcher:type_name -> common.events.EventMatcher 3, // 2: networks.networks.NetworkEventSubscription.query:type_name -> networks.networks.NetworkQuery - 7, // 3: networks.networks.NetworkEventSubscription.event_publication_spec:type_name -> common.events.EventPublication - 3, // 4: networks.networks.Network.RequestState:input_type -> networks.networks.NetworkQuery - 2, // 5: networks.networks.Network.GetState:input_type -> networks.networks.GetStateMessage - 0, // 6: networks.networks.Network.RequestDatabase:input_type -> networks.networks.DbName - 4, // 7: networks.networks.Network.SubscribeEvent:input_type -> networks.networks.NetworkEventSubscription - 2, // 8: networks.networks.Network.GetEventSubscriptionState:input_type -> networks.networks.GetStateMessage - 8, // 9: networks.networks.Network.RequestState:output_type -> common.ack.Ack - 9, // 10: networks.networks.Network.GetState:output_type -> common.state.RequestState - 1, // 11: networks.networks.Network.RequestDatabase:output_type -> networks.networks.RelayDatabase - 8, // 12: networks.networks.Network.SubscribeEvent:output_type -> common.ack.Ack - 10, // 13: networks.networks.Network.GetEventSubscriptionState:output_type -> common.events.EventSubscriptionState - 9, // [9:14] is the sub-list for method output_type - 4, // [4:9] is the sub-list for method input_type - 4, // [4:4] is the sub-list for extension type_name - 4, // [4:4] is the sub-list for extension extendee - 0, // [0:4] is the sub-list for field type_name + 8, // 3: networks.networks.NetworkEventSubscription.event_publication_spec:type_name -> common.events.EventPublication + 4, // 4: networks.networks.NetworkEventUnsubscription.request:type_name -> networks.networks.NetworkEventSubscription + 3, // 5: networks.networks.Network.RequestState:input_type -> networks.networks.NetworkQuery + 2, // 6: networks.networks.Network.GetState:input_type -> networks.networks.GetStateMessage + 0, // 7: networks.networks.Network.RequestDatabase:input_type -> networks.networks.DbName + 4, // 8: networks.networks.Network.SubscribeEvent:input_type -> networks.networks.NetworkEventSubscription + 2, // 9: networks.networks.Network.GetEventSubscriptionState:input_type -> networks.networks.GetStateMessage + 5, // 10: networks.networks.Network.UnsubscribeEvent:input_type -> networks.networks.NetworkEventUnsubscription + 9, // 11: networks.networks.Network.RequestState:output_type -> common.ack.Ack + 10, // 12: networks.networks.Network.GetState:output_type -> common.state.RequestState + 1, // 13: networks.networks.Network.RequestDatabase:output_type -> networks.networks.RelayDatabase + 9, // 14: networks.networks.Network.SubscribeEvent:output_type -> common.ack.Ack + 11, // 15: networks.networks.Network.GetEventSubscriptionState:output_type -> common.events.EventSubscriptionState + 9, // 16: networks.networks.Network.UnsubscribeEvent:output_type -> common.ack.Ack + 11, // [11:17] is the sub-list for method output_type + 5, // [5:11] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name } func init() { file_networks_networks_proto_init() } @@ -547,6 +620,18 @@ func file_networks_networks_proto_init() { return nil } } + file_networks_networks_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NetworkEventUnsubscription); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -554,7 +639,7 @@ func file_networks_networks_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_networks_networks_proto_rawDesc, NumEnums: 0, - NumMessages: 6, + NumMessages: 7, NumExtensions: 0, NumServices: 1, }, diff --git a/common/protos-go/networks/networks_grpc.pb.go b/common/protos-go/networks/networks_grpc.pb.go index 33f4a42c3..58191f113 100644 --- a/common/protos-go/networks/networks_grpc.pb.go +++ b/common/protos-go/networks/networks_grpc.pb.go @@ -31,6 +31,8 @@ type NetworkClient interface { SubscribeEvent(ctx context.Context, in *NetworkEventSubscription, opts ...grpc.CallOption) (*common.Ack, error) // This rpc endpoint is for polling the local relay for subscription state. GetEventSubscriptionState(ctx context.Context, in *GetStateMessage, opts ...grpc.CallOption) (*common.EventSubscriptionState, error) + // endpoint for a client to subscribe to event via local relay initiating subscription flow. + UnsubscribeEvent(ctx context.Context, in *NetworkEventUnsubscription, opts ...grpc.CallOption) (*common.Ack, error) } type networkClient struct { @@ -86,6 +88,15 @@ func (c *networkClient) GetEventSubscriptionState(ctx context.Context, in *GetSt return out, nil } +func (c *networkClient) UnsubscribeEvent(ctx context.Context, in *NetworkEventUnsubscription, opts ...grpc.CallOption) (*common.Ack, error) { + out := new(common.Ack) + err := c.cc.Invoke(ctx, "/networks.networks.Network/UnsubscribeEvent", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // NetworkServer is the server API for Network service. // All implementations must embed UnimplementedNetworkServer // for forward compatibility @@ -102,6 +113,8 @@ type NetworkServer interface { SubscribeEvent(context.Context, *NetworkEventSubscription) (*common.Ack, error) // This rpc endpoint is for polling the local relay for subscription state. GetEventSubscriptionState(context.Context, *GetStateMessage) (*common.EventSubscriptionState, error) + // endpoint for a client to subscribe to event via local relay initiating subscription flow. + UnsubscribeEvent(context.Context, *NetworkEventUnsubscription) (*common.Ack, error) mustEmbedUnimplementedNetworkServer() } @@ -124,6 +137,9 @@ func (UnimplementedNetworkServer) SubscribeEvent(context.Context, *NetworkEventS func (UnimplementedNetworkServer) GetEventSubscriptionState(context.Context, *GetStateMessage) (*common.EventSubscriptionState, error) { return nil, status.Errorf(codes.Unimplemented, "method GetEventSubscriptionState not implemented") } +func (UnimplementedNetworkServer) UnsubscribeEvent(context.Context, *NetworkEventUnsubscription) (*common.Ack, error) { + return nil, status.Errorf(codes.Unimplemented, "method UnsubscribeEvent not implemented") +} func (UnimplementedNetworkServer) mustEmbedUnimplementedNetworkServer() {} // UnsafeNetworkServer may be embedded to opt out of forward compatibility for this service. @@ -227,6 +243,24 @@ func _Network_GetEventSubscriptionState_Handler(srv interface{}, ctx context.Con return interceptor(ctx, in, info, handler) } +func _Network_UnsubscribeEvent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(NetworkEventUnsubscription) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NetworkServer).UnsubscribeEvent(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/networks.networks.Network/UnsubscribeEvent", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NetworkServer).UnsubscribeEvent(ctx, req.(*NetworkEventUnsubscription)) + } + return interceptor(ctx, in, info, handler) +} + // Network_ServiceDesc is the grpc.ServiceDesc for Network service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -254,6 +288,10 @@ var Network_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetEventSubscriptionState", Handler: _Network_GetEventSubscriptionState_Handler, }, + { + MethodName: "UnsubscribeEvent", + Handler: _Network_UnsubscribeEvent_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "networks/networks.proto", diff --git a/common/protos/common/events.proto b/common/protos/common/events.proto index 1e6d30d20..28d13b51f 100644 --- a/common/protos/common/events.proto +++ b/common/protos/common/events.proto @@ -38,13 +38,14 @@ message EventSubscription { message EventSubscriptionState { enum STATUS { // pending ACK from remote relay - PENDING_ACK = 0; + SUBSCRIBE_PENDING_ACK = 0; // Received ACK, waiting for event subscription confirmation from remote relay - PENDING = 1; - ERROR = 2; - SUCCESS = 3; + SUBSCRIBE_PENDING = 1; + SUBSCRIBED = 2; + UNSUBSCRIBE_PENDING_ACK = 3; UNSUBSCRIBE_PENDING = 4; UNSUBSCRIBED = 5; + ERROR = 6; }; string request_id = 1; STATUS status = 2; diff --git a/core/relay/src/client.rs b/core/relay/src/client.rs index e58dddc1f..2a8d4d942 100644 --- a/core/relay/src/client.rs +++ b/core/relay/src/client.rs @@ -44,9 +44,15 @@ async fn datasharing() -> Result<(), Box> { poll_for_state(request_id.to_string(), network_client).await; println!("Data Sharing: Success!"); } - ack::Status::Error => println!("An error occurred in request_state call"), + ack::Status::Error => { + println!("An error occurred in request_state call"); + std::process::exit(1); + } }, - None => println!("The returned Ack has no status"), + None => { + println!("The returned Ack has no status"); + std::process::exit(1); + } } Ok(()) } @@ -68,12 +74,21 @@ fn poll_for_state( Some(request_status) => { if request_status == request_state::Status::Pending { poll_for_state(request_id, network_client).await; + } else if request_status == request_state::Status::Error { + println!("Error"); + std::process::exit(1); } } - None => println!("No status returned from get state request"), + None => { + println!("No status returned from get state request"); + std::process::exit(1); + } }; } - Err(_error) => println!("Error getting state response"), + Err(_error) => { + println!("Error getting state response"); + std::process::exit(1); + } } } .boxed() @@ -121,14 +136,18 @@ async fn event_suscribe() -> Result<(), Box> { Some(ack_status) => match ack_status { ack::Status::Ok => { poll_for_event_subscription(request_id.clone().to_string(), network_client).await; - println!("Event Subscription: Success!"); } - ack::Status::Error => println!("An error occurred in subscribe_event call"), + ack::Status::Error => { + println!("An error occurred in subscribe_event call"); + std::process::exit(1); + } }, - None => println!("The returned Ack has no status"), + None => { + println!("The returned Ack has no status"); + std::process::exit(1); + } } - let _res = event_unsuscribe(request_id.to_string()).await; - Ok(()) + return event_unsuscribe(request_id.to_string()).await; } async fn event_unsuscribe(request_id: String) -> Result<(), Box> { @@ -176,11 +195,16 @@ async fn event_unsuscribe(request_id: String) -> Result<(), Box match ack_status { ack::Status::Ok => { poll_for_event_subscription(request_id.to_string(), network_client).await; - println!("Event Unsubscription: Success!"); } - ack::Status::Error => println!("An error occurred in unsubscribe_event call"), + ack::Status::Error => { + println!("An error occurred in unsubscribe_event call"); + std::process::exit(1); + } }, - None => println!("The returned Ack has no status"), + None => { + println!("The returned Ack has no status"); + std::process::exit(1); + } } Ok(()) } @@ -200,16 +224,31 @@ fn poll_for_event_subscription( println!("Get Event Subscription State response: {:?}", response); match event_subscription_state::Status::from_i32(response.get_ref().status) { Some(request_status) => { - if request_status == event_subscription_state::Status::Pending { + println!("Received status: {:?}", response); + if request_status == event_subscription_state::Status::SubscribePending || + request_status == event_subscription_state::Status::UnsubscribePending || + request_status == event_subscription_state::Status::SubscribePendingAck || + request_status == event_subscription_state::Status::SubscribePendingAck { poll_for_event_subscription(request_id, network_client).await; + } else if request_status == event_subscription_state::Status::Subscribed { + println!("Event Subscription: Success!"); + } else if request_status == event_subscription_state::Status::Unsubscribed { + println!("Event Unsubscription: Success!"); } else { - println!("Received status: {:?}", response); + println!("Error: {:?}", response.get_ref().message.to_string()); + std::process::exit(1); } } - None => println!("No status returned from get state request"), + None => { + println!("No status returned from get state request"); + std::process::exit(1); + } }; } - Err(_error) => println!("Error getting state response"), + Err(_error) => { + println!("Error getting state response"); + std::process::exit(1); + } } } .boxed() diff --git a/core/relay/src/services/event_subscribe_service.rs b/core/relay/src/services/event_subscribe_service.rs index a49e2657e..235daf6a3 100644 --- a/core/relay/src/services/event_subscribe_service.rs +++ b/core/relay/src/services/event_subscribe_service.rs @@ -4,7 +4,6 @@ use crate::pb::common::query::Query; use crate::pb::common::events::EventSubscription; use crate::pb::relay::events::event_subscribe_client::EventSubscribeClient; use crate::pb::relay::events::event_subscribe_server::EventSubscribe; -use crate::pb::common::events::{event_subscription_state}; // Internal modules use crate::db::Database; use crate::error::Error; @@ -26,6 +25,7 @@ pub struct EventSubscribeService { /// communicating event subscription request between two relays and driver. #[tonic::async_trait] impl EventSubscribe for EventSubscribeService { + // Dest-relay will call this endpoint of src-relay to request for event Subscription/Unsubscription async fn subscribe_event(&self, request: Request) -> Result, Status> { println!( "Got a Event Subscription request from {:?} - {:?}", @@ -60,7 +60,8 @@ impl EventSubscribe for EventSubscribeService { } } - /// send_driver_subscription_status is run on the remote relay. Run when the driver sends the ack back to the remote relay + // send_driver_subscription_status is run on the src relay. + // Run when the src driver sends the ack back to the src relay async fn send_driver_subscription_status( &self, request: Request, @@ -96,6 +97,8 @@ impl EventSubscribe for EventSubscribeService { } } } + + // Src-relay will call this endpoint of dest-relay to send Subscription/Unsubscription response. async fn send_subscription_status(&self, request: Request) -> Result, Status> { let request_ack = request.into_inner().clone(); println!( @@ -305,23 +308,15 @@ fn send_subscription_status_helper( db_path: String, ) -> Result<(), Error> { match ack::Status::from_i32(request_ack.status) { - Some(status) => match status { - ack::Status::Ok => update_event_subscription_status( - request_id.to_string(), - event_subscription_state::Status::Success, - db_path.to_string(), - "".to_string(), - ), - ack::Status::Error => update_event_subscription_status( + Some(status) => update_event_subscription_status( request_id.to_string(), - event_subscription_state::Status::Error, + status, db_path.to_string(), request_ack.message.to_string(), - ), - }, + ), None => update_event_subscription_status( request_id.to_string(), - event_subscription_state::Status::Error, + ack::Status::Error, db_path.to_string(), "Status is not supported or is invalid".to_string(), ), diff --git a/core/relay/src/services/helpers.rs b/core/relay/src/services/helpers.rs index 98c66a0a2..233e3af2f 100644 --- a/core/relay/src/services/helpers.rs +++ b/core/relay/src/services/helpers.rs @@ -1,3 +1,4 @@ +use crate::pb::common::ack::{ack}; use crate::pb::common::query::Query; use crate::pb::common::events::{event_subscription_state, EventSubscriptionState}; use crate::pb::common::events::{EventSubscription}; @@ -17,7 +18,7 @@ use tonic::transport::{Certificate, Channel, ClientTlsConfig}; // returned EventSubscriptionState with status SUCCESS or ERROR. pub fn update_event_subscription_status( curr_request_id: String, - new_status: event_subscription_state::Status, + new_status: ack::Status, curr_db_path: String, message: String, ) { @@ -27,38 +28,74 @@ pub fn update_event_subscription_status( let result = db.get::(curr_request_id.clone()); match result { Ok(fetched_event_sub_state) => { - let target: EventSubscriptionState; - match event_subscription_state::Status::from_i32(fetched_event_sub_state.status) { - Some(status) => match status { - event_subscription_state::Status::UnsubscribePending => { - target = EventSubscriptionState { - status: event_subscription_state::Status::Unsubscribed as i32, - request_id: curr_request_id.clone(), - message: message.to_string(), - event_matcher: fetched_event_sub_state.event_matcher, - event_publication_spec: fetched_event_sub_state.event_publication_spec - }; + if new_status == ack::Status::Ok { + match event_subscription_state::Status::from_i32(fetched_event_sub_state.status) { + Some(status) => match status { + event_subscription_state::Status::UnsubscribePendingAck => { + target = EventSubscriptionState { + status: event_subscription_state::Status::UnsubscribePending as i32, + request_id: curr_request_id.clone(), + message: message.to_string(), + event_matcher: fetched_event_sub_state.event_matcher, + event_publication_spec: fetched_event_sub_state.event_publication_spec + }; + }, + event_subscription_state::Status::UnsubscribePending => { + target = EventSubscriptionState { + status: event_subscription_state::Status::Unsubscribed as i32, + request_id: curr_request_id.clone(), + message: message.to_string(), + event_matcher: fetched_event_sub_state.event_matcher, + event_publication_spec: fetched_event_sub_state.event_publication_spec + }; + }, + event_subscription_state::Status::SubscribePendingAck => { + target = EventSubscriptionState { + status: event_subscription_state::Status::SubscribePending as i32, + request_id: curr_request_id.clone(), + message: message.to_string(), + event_matcher: fetched_event_sub_state.event_matcher.clone(), + event_publication_spec: fetched_event_sub_state.event_publication_spec.clone(), + }; + }, + event_subscription_state::Status::SubscribePending => { + target = EventSubscriptionState { + status: event_subscription_state::Status::Subscribed as i32, + request_id: curr_request_id.clone(), + message: message.to_string(), + event_matcher: fetched_event_sub_state.event_matcher.clone(), + event_publication_spec: fetched_event_sub_state.event_publication_spec.clone(), + }; + }, + _ => { + target = EventSubscriptionState { + status: event_subscription_state::Status::Error as i32, + request_id: curr_request_id.clone(), + message: "Status is not supported or is invalid".to_string(), + event_matcher: fetched_event_sub_state.event_matcher.clone(), + event_publication_spec: fetched_event_sub_state.event_publication_spec.clone(), + }; + }, }, - _ => { + None => { target = EventSubscriptionState { - status: new_status as i32, + status: event_subscription_state::Status::Error as i32, request_id: curr_request_id.clone(), - message: message.to_string(), + message: "No event subscription status set in database".to_string(), event_matcher: fetched_event_sub_state.event_matcher.clone(), event_publication_spec: fetched_event_sub_state.event_publication_spec.clone(), }; }, - }, - None => { - target = EventSubscriptionState { - status: new_status as i32, - request_id: curr_request_id.clone(), - message: message.to_string(), - event_matcher: fetched_event_sub_state.event_matcher.clone(), - event_publication_spec: fetched_event_sub_state.event_publication_spec.clone(), - }; - }, + } + } else { + target = EventSubscriptionState { + status: event_subscription_state::Status::Error as i32, + request_id: curr_request_id.clone(), + message: message.to_string(), + event_matcher: fetched_event_sub_state.event_matcher.clone(), + event_publication_spec: fetched_event_sub_state.event_publication_spec.clone(), + }; } // Panic if this fails, atm the panic is just logged by the tokio runtime diff --git a/core/relay/src/services/network_service.rs b/core/relay/src/services/network_service.rs index 0ea5e9ab9..31568da8b 100644 --- a/core/relay/src/services/network_service.rs +++ b/core/relay/src/services/network_service.rs @@ -186,7 +186,7 @@ impl Network for NetworkService { // Initial request state stored in DB. let target: EventSubscriptionState = EventSubscriptionState { - status: event_subscription_state::Status::PendingAck as i32, + status: event_subscription_state::Status::SubscribePendingAck as i32, request_id: request_id.to_string(), message: "".to_string(), event_matcher: network_event_subscription.event_matcher.clone(), @@ -279,7 +279,7 @@ impl Network for NetworkService { // Initial request state stored in DB. let target: EventSubscriptionState = EventSubscriptionState { - status: event_subscription_state::Status::UnsubscribePending as i32, + status: event_subscription_state::Status::UnsubscribePendingAck as i32, request_id: request_id.to_string(), message: "".to_string(), event_matcher: network_event_subscription.event_matcher.clone(), @@ -621,23 +621,15 @@ fn spawn_send_event_subscription_request( let ack_response_into_inner = ack_response.into_inner().clone(); // This match first checks if the status is valid. match ack::Status::from_i32(ack_response_into_inner.status) { - Some(status) => match status { - ack::Status::Ok => update_event_subscription_status( - request_id.to_string(), - event_subscription_state::Status::Pending, - db_path.to_string(), - "".to_string(), - ), - ack::Status::Error => update_event_subscription_status( + Some(status) => update_event_subscription_status( request_id.to_string(), - event_subscription_state::Status::Error, + status, db_path.to_string(), ack_response_into_inner.message.to_string(), - ), - }, + ), None => update_event_subscription_status( request_id.to_string(), - event_subscription_state::Status::Error, + ack::Status::Error, db_path.to_string(), "Status is not supported or is invalid".to_string(), ), @@ -645,7 +637,7 @@ fn spawn_send_event_subscription_request( } Err(result_error) => update_event_subscription_status( request_id.to_string(), - event_subscription_state::Status::Error, + ack::Status::Error, db_path.to_string(), format!("{:?}", result_error).to_string(), ), diff --git a/samples/fabric/fabric-cli/readme.md b/samples/fabric/fabric-cli/readme.md index c9a9a3e39..e85337534 100644 --- a/samples/fabric/fabric-cli/readme.md +++ b/samples/fabric/fabric-cli/readme.md @@ -385,14 +385,20 @@ Below are the steps to exercise asset transfers from `network1` to `network2` us ./scripts/getTokenBalance.sh network2 bob ``` -## Event Subscription +## Events -To suscribe for event, generate a JSON file like: [Sample Event Sub JSON](./src/data/event_sub_sample.json). Sample provided here assumes driver of `network1` is subscribing to an event of `network2`. - -Then run following command: -``` -./bin/fabric-cli event subscribe --network=network1 src/data/event_sub_sample.json -``` +* To suscribe for event, generate a JSON file like: [Sample Event Sub JSON](./src/data/event_sub_sample.json). Sample provided here assumes driver of `network1` is subscribing to an event of `network2`. Then run following command (and note the request id which will be used to unsubscribe or get status): + ``` + ./bin/fabric-cli event subscribe --network=network1 src/data/event_sub_sample.json + ``` +* To unsuscribe for event, use the same JSON file as in subscription like: [Sample Event Sub JSON](./src/data/event_sub_sample.json). Then run following command: + ``` + ./bin/fabric-cli event unsubscribe --network=network1 --request-id= src/data/event_sub_sample.json + ``` +* To get status for event subscription, run following command: + ``` + ./bin/fabric-cli event get-subscription-status --network=network1 --request-id= + ``` ## NOTE diff --git a/samples/fabric/fabric-cli/src/commands/event/get-subscription-status.ts b/samples/fabric/fabric-cli/src/commands/event/get-subscription-status.ts new file mode 100644 index 000000000..285b1fa56 --- /dev/null +++ b/samples/fabric/fabric-cli/src/commands/event/get-subscription-status.ts @@ -0,0 +1,91 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import { GluegunCommand } from 'gluegun' +import { fabricHelper, getKeyAndCertForRemoteRequestbyUserName } from '../../helpers/fabric-functions' +import logger from '../../helpers/logger' +import { Utils, ICryptoKey } from 'fabric-common' +import { commandHelp, getNetworkConfig, handlePromise } from '../../helpers/helpers' +import { EventsManager } from '@hyperledger-labs/weaver-fabric-interop-sdk' +import { EventSubscriptionState, EventType } from "@hyperledger-labs/weaver-protos-js/common/events_pb"; +import * as fs from 'fs' +import * as path from 'path' + +const command: GluegunCommand = { + name: 'get-subscription-status', + alias: ['-g'], + description: 'Get event subscription status', + run: async toolbox => { + const { + print, + parameters: { options, array } + } = toolbox + if (options.help || options.h) { + commandHelp( + print, + toolbox, + `fabric-cli event unsubscribe --network= --user=user1 --request-id="abc123"`, + 'fabric-cli event unsubscribe --network= --user= --request-id=', + [ + { + name: '--network', + description: + 'Local network for command. ' + }, + { + name: '--request-id', + description: + 'Request ID received during subscription.' + }, + { + name: '--debug', + description: + 'Shows debug logs when running. Disabled by default. To enable --debug=true' + } + ], + command, + ['event', 'get-subscription-status'] + ) + return + } + console.log("Get Event Subscription Status") + if (options.debug === 'true') { + logger.level = 'debug' + logger.debug('Debugging is enabled') + } + if (!options['network']) + { + print.error('--network needs to be specified') + return + } + if (!options['request-id']) + { + print.error('--request-id needs to be specified') + return + } + const networkName = options['network'] + const requestId = options['request-id'] + + const netConfig = getNetworkConfig(networkName) + if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { + throw new Error(`No valid config entry found for ${networkName}`) + } + try { + const response = await EventsManager.getSubscriptionStatus( + requestId, + netConfig.relayEndpoint + ) + console.log("Event subscription status:", JSON.stringify(response)) + } catch(e) { + console.log("Error: ", e.toString()) + } + + process.exit() + } +} + + +module.exports = command diff --git a/samples/fabric/fabric-cli/src/commands/event/subscribe.ts b/samples/fabric/fabric-cli/src/commands/event/subscribe.ts index 366e83347..bb7f711f9 100644 --- a/samples/fabric/fabric-cli/src/commands/event/subscribe.ts +++ b/samples/fabric/fabric-cli/src/commands/event/subscribe.ts @@ -16,7 +16,7 @@ import * as path from 'path' const command: GluegunCommand = { name: 'subscribe', - alias: ['-sd'], + alias: ['-s'], description: 'Initiate event subscribe', run: async toolbox => { const { @@ -60,6 +60,11 @@ const command: GluegunCommand = { print.error('Not enough arguments supplied') return } + if (!options['network']) + { + print.error('--network needs to be specified') + return + } if (!options['user']) { options['user'] = `user1` //Default user } @@ -108,7 +113,7 @@ const command: GluegunCommand = { keyCert ) - if (response.getStatus() == EventSubscriptionState.STATUS.SUCCESS) { + if (response.getStatus() == EventSubscriptionState.STATUS.SUBSCRIBED) { console.log("Event Subscription Status Success with requestId:", response.getRequestId()) } else { console.log("Unknown error") diff --git a/samples/fabric/fabric-cli/src/commands/event/unsubscribe.ts b/samples/fabric/fabric-cli/src/commands/event/unsubscribe.ts index d3d6fb504..a2e39268b 100644 --- a/samples/fabric/fabric-cli/src/commands/event/unsubscribe.ts +++ b/samples/fabric/fabric-cli/src/commands/event/unsubscribe.ts @@ -16,7 +16,7 @@ import * as path from 'path' const command: GluegunCommand = { name: 'unsubscribe', - alias: ['-sd'], + alias: ['-u'], description: 'Initiate event unsubscribe', run: async toolbox => { const { @@ -56,7 +56,7 @@ const command: GluegunCommand = { ) return } - console.log("Event Subscription") + console.log("Event Unsubscription") if (options.debug === 'true') { logger.level = 'debug' logger.debug('Debugging is enabled') @@ -65,6 +65,11 @@ const command: GluegunCommand = { print.error('Not enough arguments supplied') return } + if (!options['network']) + { + print.error('--network needs to be specified') + return + } if (!options['request-id']) { print.error('--request-id needs to be specified') diff --git a/samples/fabric/fabric-cli/src/data/event_sub_sample.json b/samples/fabric/fabric-cli/src/data/event_sub_sample.json index bc7286f87..350e382ce 100644 --- a/samples/fabric/fabric-cli/src/data/event_sub_sample.json +++ b/samples/fabric/fabric-cli/src/data/event_sub_sample.json @@ -8,10 +8,10 @@ }, "event_publication_spec": { "ccArgs": [], - "contractId": "simplestate", + "chaincodeId": "simplestate", "driverId": "network1", "ccFunc": "Create", - "ledgerId": "mychannel", + "channelId": "mychannel", "replaceArgIndex": "0" }, "view_address": "localhost:9083/network2/mychannel:simplestate:Read:a", diff --git a/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts b/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts index 4e7fe18ea..e978844d9 100644 --- a/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts +++ b/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts @@ -220,10 +220,40 @@ const unsubscribeRemoteEvent = async ( return relayResponse } +const getSubscriptionStatus = async ( + requestID: string, + localRelayEndpoint: string, + asJson: boolean = true, + useTls: boolean = false, + tlsRootCACertPaths?: Array, + confidential: boolean = false, +): Promise => { + logger.debug("Get Event Subscription Status") + + const relay = useTls ? new Relay(localRelayEndpoint, Relay.defaultTimeout, true, tlsRootCACertPaths) : new Relay(localRelayEndpoint); + + const [relayResponse, relayResponseError] = await helpers.handlePromise( + relay.GetEventSubscriptionState( + requestID, + asJson + ), + ); + if (relayResponseError) { + throw new Error(`Get event subscription relay response error: ${relayResponseError}`); + } + + logger.debug(`Get event subscription status response: ${JSON.stringify(relayResponse)}`) + + return relayResponse +} + + + export { createEventMatcher, createEventPublicationSpec, subscribeRemoteEvent, unsubscribeRemoteEvent, + getSubscriptionStatus, } diff --git a/sdks/fabric/interoperation-node-sdk/src/Relay.ts b/sdks/fabric/interoperation-node-sdk/src/Relay.ts index 467f91d23..7138f4015 100644 --- a/sdks/fabric/interoperation-node-sdk/src/Relay.ts +++ b/sdks/fabric/interoperation-node-sdk/src/Relay.ts @@ -297,9 +297,10 @@ class Relay { throw new Error(`Get event subscription state error: ${error}`); } if ( - state.getStatus() === eventsPb.EventSubscriptionState.STATUS.PENDING || - state.getStatus() === eventsPb.EventSubscriptionState.STATUS.PENDING_ACK || - state.getStatus() === eventsPb.EventSubscriptionState.STATUS.UNSUBSCRIBE_PENDING + state.getStatus() === eventsPb.EventSubscriptionState.STATUS.SUBSCRIBE_PENDING || + state.getStatus() === eventsPb.EventSubscriptionState.STATUS.SUBSCRIBE_PENDING_ACK || + state.getStatus() === eventsPb.EventSubscriptionState.STATUS.UNSUBSCRIBE_PENDING || + state.getStatus() === eventsPb.EventSubscriptionState.STATUS.UNSUBSCRIBE_PENDING_ACK ) { if (dateObj.getTime() < Date.now()) { throw new Error("Timeout: State is still pending."); From c15b7b3ed43dc2fc4e091a4eb736831f80e77d16 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Mon, 11 Jul 2022 20:14:49 +0530 Subject: [PATCH 035/150] changes for event unsubscription Signed-off-by: Krishnasuri Narayanam --- core/drivers/fabric-driver/.env.template | 1 + core/drivers/fabric-driver/.gitignore | 3 +- core/drivers/fabric-driver/makefile | 12 +- core/drivers/fabric-driver/package-local.json | 1 + core/drivers/fabric-driver/package.json | 6 +- .../fabric-driver/server/dbConnector.ts | 8 +- core/drivers/fabric-driver/server/events.ts | 102 +++++++++++++ core/drivers/fabric-driver/server/server.ts | 137 ++++++++++-------- core/drivers/fabric-driver/server/utils.ts | 116 ++++++++++++--- .../fabric-driver/server/walletSetup.ts | 23 ++- core/drivers/fabric-driver/tsconfig.json | 2 +- 11 files changed, 322 insertions(+), 89 deletions(-) create mode 100644 core/drivers/fabric-driver/server/events.ts diff --git a/core/drivers/fabric-driver/.env.template b/core/drivers/fabric-driver/.env.template index 181a20513..8a9dc47e1 100644 --- a/core/drivers/fabric-driver/.env.template +++ b/core/drivers/fabric-driver/.env.template @@ -11,3 +11,4 @@ DRIVER_CONFIG= INTEROP_CHAINCODE=interop MOCK=false DB_NAME=driverdb +DB_PATH=driverdbs diff --git a/core/drivers/fabric-driver/.gitignore b/core/drivers/fabric-driver/.gitignore index c5745fc45..94af7ad2c 100644 --- a/core/drivers/fabric-driver/.gitignore +++ b/core/drivers/fabric-driver/.gitignore @@ -5,4 +5,5 @@ .env /fabric-protos package-lock.json -.npmrc \ No newline at end of file +.npmrc +driverdbs diff --git a/core/drivers/fabric-driver/makefile b/core/drivers/fabric-driver/makefile index 0d757c5bd..29bc2341a 100644 --- a/core/drivers/fabric-driver/makefile +++ b/core/drivers/fabric-driver/makefile @@ -18,10 +18,11 @@ build-local: cp -r ../../../common/protos-js/peer ./protos-js/ && \ cp -r ../../../common/protos-js/relay ./protos-js/ && \ cp -r ../../../common/protos-js/package.json ./protos-js/ - cp package.json package-remote.json && \ + (cp package.json package-remote.json && \ cp package-local.json package.json && \ - npm install && \ - mv package-remote.json package.json + npm install) || \ + (mv package-remote.json package.json && exit 1) # Runs if failure + mv package-remote.json package.json # Runs if success npm run build npm run postinstall @@ -38,8 +39,9 @@ build-image-local: cp -r ../../../common/protos-js/package.json ./protos-js/ cp package.json package-remote.json cp package-local.json package.json - docker build --build-arg BUILD_TAG="local" --build-arg GIT_URL=$(GIT_URL) -t ${DOCKER_IMAGE_NAME}:$(DOCKER_TAG) -f fabricDriver.dockerfile.local . - mv package-remote.json package.json + (docker build --build-arg BUILD_TAG="local" --build-arg GIT_URL=$(GIT_URL) -t ${DOCKER_IMAGE_NAME}:$(DOCKER_TAG) -f fabricDriver.dockerfile.local . ) || \ + (mv package-remote.json package.json && exit 1) # Runs if failure + mv package-remote.json package.json # Runs if success rm -rf protos-js build-image: .npmrc diff --git a/core/drivers/fabric-driver/package-local.json b/core/drivers/fabric-driver/package-local.json index 20b13d840..f13e6d231 100644 --- a/core/drivers/fabric-driver/package-local.json +++ b/core/drivers/fabric-driver/package-local.json @@ -21,6 +21,7 @@ "license": "ISC", "dependencies": { "@hyperledger-labs/weaver-protos-js": "file:./protos-js", + "@hyperledger-labs/weaver-fabric-interop-sdk": "file:../../../sdks/fabric/interoperation-node-sdk", "@fidm/x509": "^1.2.1", "@grpc/grpc-js": "^1.1.1", "@typescript-eslint/eslint-plugin": "^3.5.0", diff --git a/core/drivers/fabric-driver/package.json b/core/drivers/fabric-driver/package.json index 0ad52fbd6..7edd0b807 100644 --- a/core/drivers/fabric-driver/package.json +++ b/core/drivers/fabric-driver/package.json @@ -20,7 +20,8 @@ "author": "", "license": "ISC", "dependencies": { - "@hyperledger-labs/weaver-protos-js": "^1.3.0", + "@hyperledger-labs/weaver-protos-js": "^1.4.0", + "@hyperledger-labs/weaver-fabric-interop-sdk": "^1.4.0", "@fidm/x509": "^1.2.1", "@grpc/grpc-js": "^1.1.1", "@typescript-eslint/eslint-plugin": "^3.5.0", @@ -29,7 +30,8 @@ "eslint-config-prettier": "^6.11.0", "eslint-plugin-prettier": "^3.1.4", "fabric-ca-client": "2.2.5", - "fabric-network": "2.2.5" + "fabric-network": "2.2.5", + "level": "^8.0.0" }, "devDependencies": { "patch-package": "^6.2.2", diff --git a/core/drivers/fabric-driver/server/dbConnector.ts b/core/drivers/fabric-driver/server/dbConnector.ts index 85a54e904..0389ca60b 100644 --- a/core/drivers/fabric-driver/server/dbConnector.ts +++ b/core/drivers/fabric-driver/server/dbConnector.ts @@ -4,7 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -const { Level } = require('level') +import { Level } from 'level'; +import * as path from 'path'; /* * Interfaces for all database connectors to be used for event subscriptions @@ -41,8 +42,11 @@ class LevelDBConnector implements DBConnector { constructor( dbName: string ) { + if (!dbName || dbName.length == 0) { + dbName = process.env.DB_NAME ? process.env.DB_NAME : "driverdb"; + } this.DB_NAME = dbName; - this.dbHandle = new Level(dbName, { valueEncoding: 'json' }); + this.dbHandle = new Level(path.join(process.env.DB_PATH ? process.env.DB_PATH : "./driverdbs", dbName), { valueEncoding: 'json' }); } async open( diff --git a/core/drivers/fabric-driver/server/events.ts b/core/drivers/fabric-driver/server/events.ts new file mode 100644 index 000000000..03cce6d26 --- /dev/null +++ b/core/drivers/fabric-driver/server/events.ts @@ -0,0 +1,102 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import ack_pb from '@hyperledger-labs/weaver-protos-js/common/ack_pb'; +import eventsPb from '@hyperledger-labs/weaver-protos-js/common/events_pb'; +import events_grpc_pb from '@hyperledger-labs/weaver-protos-js/relay/events_grpc_pb'; +import { addEventSubscription, deleteEventSubscription } from "./utils" + +function subscribeEventHelper( + call_request: eventsPb.EventSubscription, + client: events_grpc_pb.EventSubscribeClient +) { + const newRequestId = call_request.getQuery()!.getRequestId(); + addEventSubscription(call_request).then((requestId) => { + const ack_send = new ack_pb.Ack(); + if (newRequestId == requestId) { + // event being subscribed for the first time + ack_send.setMessage('Event subscription is successful!'); + ack_send.setStatus(ack_pb.Ack.STATUS.OK); + + // the event listener logic follows here + } else { + // event being subscribed already exists + ack_send.setMessage(`Event subscription already exists with requestId: ${requestId}`); + ack_send.setStatus(ack_pb.Ack.STATUS.ERROR); + } + ack_send.setRequestId(newRequestId); + + // gRPC response. + console.log(`Sending to the relay the eventSubscription Ack: ${JSON.stringify(ack_send.toObject())}`); + + if (!process.env.RELAY_ENDPOINT) { + throw new Error('RELAY_ENDPOINT is not set.'); + } + + // Sending the fabric state to the relay. + client.sendDriverSubscriptionStatus(ack_send, function (err: any, response: any) { + console.log(`Response: ${JSON.stringify(response.toObject())} Error: ${JSON.stringify(err)}`); + }); + }).catch((error) => { + const errorString: string = `error (thrown as part of async processing while storing to DB during subscribeEvent): ${JSON.stringify(error)}`; + console.error(errorString); + const ack_send_error = new ack_pb.Ack(); + ack_send_error.setRequestId(newRequestId); + ack_send_error.setMessage(errorString); + ack_send_error.setStatus(ack_pb.Ack.STATUS.ERROR); + // gRPC response. + console.log(`Sending to the relay the eventSubscription error Ack: ${JSON.stringify(ack_send_error.toObject())}`); + // Sending the fabric state to the relay. + client.sendDriverSubscriptionStatus(ack_send_error, function (err: any, response: any) { + console.log(`Response: ${JSON.stringify(response.toObject())} Error: ${JSON.stringify(err)}`); + }); + }); +} + +function unsubscribeEventHelper( + call_request: eventsPb.EventSubscription, + client: events_grpc_pb.EventSubscribeClient +) { + const newRequestId = call_request.getQuery()!.getRequestId(); + deleteEventSubscription(call_request.getEventMatcher()!, newRequestId).then((deletedSubscription: eventsPb.EventSubscription) => { + const ack_send = new ack_pb.Ack(); + + // event got unsubscribed + ack_send.setMessage(`Event ${JSON.stringify(deletedSubscription.toObject())} unsubscription is successful!`); + ack_send.setStatus(ack_pb.Ack.STATUS.OK); + ack_send.setRequestId(newRequestId); + + // gRPC response. + console.log(`Sending to the relay the eventSubscription Ack: ${JSON.stringify(ack_send.toObject())}`); + + if (!process.env.RELAY_ENDPOINT) { + throw new Error('RELAY_ENDPOINT is not set.'); + } + + // Sending the fabric state to the relay. + client.sendDriverSubscriptionStatus(ack_send, function (err: any, response: any) { + console.log(`Response: ${JSON.stringify(response.toObject())} Error: ${JSON.stringify(err)}`); + }); + }).catch((error) => { + const errorString: string = `error (thrown as part of async processing while deleting from DB during unsubscribeEvent): ${JSON.stringify(error)}`; + console.error(errorString); + const ack_send_error = new ack_pb.Ack(); + ack_send_error.setRequestId(newRequestId); + ack_send_error.setMessage(errorString); + ack_send_error.setStatus(ack_pb.Ack.STATUS.ERROR); + // gRPC response. + console.log(`Sending to the relay the eventSubscription error Ack: ${JSON.stringify(ack_send_error.toObject())}`); + // Sending the fabric state to the relay. + client.sendDriverSubscriptionStatus(ack_send_error, function (err: any, response: any) { + console.log(`Response: ${JSON.stringify(response.toObject())} Error: ${JSON.stringify(err)}`); + }); + }); +} + +export { + subscribeEventHelper, + unsubscribeEventHelper +} \ No newline at end of file diff --git a/core/drivers/fabric-driver/server/server.ts b/core/drivers/fabric-driver/server/server.ts index d2942cdc5..0fc53f180 100644 --- a/core/drivers/fabric-driver/server/server.ts +++ b/core/drivers/fabric-driver/server/server.ts @@ -17,10 +17,11 @@ import state_pb from '@hyperledger-labs/weaver-protos-js/common/state_pb'; import invoke from './fabric-code'; import 'dotenv/config'; import { walletSetup } from './walletSetup'; +import { subscribeEventHelper, unsubscribeEventHelper } from "./events" import { Certificate } from '@fidm/x509'; import * as path from 'path'; -import { addEventSubscription, dbConnectionTest, eventSubscriptionTest } from "./utils" +import { addEventSubscription, dbConnectionTest, eventSubscriptionTest, signEventSubscriptionQuery } from "./utils" const server = new Server(); console.log('driver def', JSON.stringify(driver_pb_grpc)); @@ -138,11 +139,35 @@ const fabricCommunication = async (query: query_pb.Query, networkName: string) = console.log('Sending state'); // Sending the fabric state to the relay. client.sendDriverState(viewPayload, function (err: any, response: any) { - console.log('Response:', response, 'Error: ', err); + console.log(`Response: ${JSON.stringify(response.toObject())} Error: ${JSON.stringify(err)}`); }); } }; +// If the events_grpc_pb.EventSubscribeClient() failes, then it throws an error which will be caught by the caller +async function getEventSubscriptionRelayClient( +): Promise { + let client; + + if (process.env.RELAY_TLS === 'true') { + if (!(process.env.RELAY_TLSCA_CERT_PATH && fs.existsSync(process.env.RELAY_TLSCA_CERT_PATH))) { + throw new Error("Missing or invalid RELAY_TLSCA_CERT_PATH: " + process.env.RELAY_TLSCA_CERT_PATH); + } + const rootCert = fs.readFileSync(process.env.RELAY_TLSCA_CERT_PATH); + client = new events_grpc_pb.EventSubscribeClient( + process.env.RELAY_ENDPOINT, + credentials.createSsl(rootCert) + ); + } else { + client = new events_grpc_pb.EventSubscribeClient( + process.env.RELAY_ENDPOINT, + credentials.createInsecure() + ); + } + + return client; +} + // Service for receiving communication from a relay. Will communicate with the network and respond with an ack to the relay while the fabric communication is being completed. //@ts-ignore server.addService(driver_pb_grpc.DriverCommunicationService, { @@ -171,66 +196,45 @@ server.addService(driver_pb_grpc.DriverCommunicationService, { } }, subscribeEvent: (call: { request: eventsPb.EventSubscription }, callback: (_: any, object: ack_pb.Ack) => void) => { - const ack_response = new ack_pb.Ack(); - var newRequestId: string = call.request.getQuery()!.getRequestId() + const newRequestId: string = call.request.getQuery()!.getRequestId() + const subscriptionOp: eventsPb.EventSubOperation = call.request.getOperation(); console.log(`newRequestId: ${newRequestId}`); try { if (process.env.MOCK === 'false') { - addEventSubscription(call.request).then((requestId) => { - if (newRequestId == requestId) { - // event being subscribed for the first time - ack_response.setMessage('Event subscription is successful!'); - ack_response.setStatus(ack_pb.Ack.STATUS.OK); - - // the event listener logic follows here - } else { - // event being subscribed already exists - ack_response.setMessage(`Event subscription already exists with requestId: ${requestId}`); - ack_response.setStatus(ack_pb.Ack.STATUS.ERROR); - } - ack_response.setRequestId(newRequestId); - - // gRPC response. - console.log(`Responding to the relay the eventSubscription Ack: ${JSON.stringify(ack_response.toObject())}`); - - if (!process.env.RELAY_ENDPOINT) { - throw new Error('RELAY_ENDPOINT is not set.'); - } - let client; - if (process.env.RELAY_TLS === 'true') { - if (!(process.env.RELAY_TLSCA_CERT_PATH && fs.existsSync(process.env.RELAY_TLSCA_CERT_PATH))) { - throw new Error("Missing or invalid RELAY_TLSCA_CERT_PATH: " + process.env.RELAY_TLSCA_CERT_PATH); - } - const rootCert = fs.readFileSync(process.env.RELAY_TLSCA_CERT_PATH); - client = new events_grpc_pb.EventSubscribeClient( - process.env.RELAY_ENDPOINT, - credentials.createSsl(rootCert) - ); + getEventSubscriptionRelayClient().then((client) => { + if (subscriptionOp == eventsPb.EventSubOperation.SUBSCRIBE) { + subscribeEventHelper(call.request, client); + } else if (subscriptionOp == eventsPb.EventSubOperation.UNSUBSCRIBE) { + unsubscribeEventHelper(call.request, client); } else { - client = new events_grpc_pb.EventSubscribeClient( - process.env.RELAY_ENDPOINT, - credentials.createInsecure() - ); + const errorString: string = `Error: subscribe operation ${subscriptionOp.toString()} not supported`; + console.error(errorString); + const ack_send_error = new ack_pb.Ack(); + ack_send_error.setRequestId(newRequestId); + ack_send_error.setMessage(errorString); + ack_send_error.setStatus(ack_pb.Ack.STATUS.ERROR); + // gRPC response. + console.log(`Sending to the relay the eventSubscription error Ack: ${JSON.stringify(ack_send_error.toObject())}`); + // Sending the fabric state to the relay. + client.sendDriverSubscriptionStatus(ack_send_error, function (err: any, response: any) { + console.log(`Response: ${JSON.stringify(response.toObject())} Error: ${JSON.stringify(err)}`); + }); } - - // Sending the fabric state to the relay. - //client.sendDriverSubscriptionStatus(ack_response, function (err: any, response: any) { - // console.log('Response:', response, 'Error: ', err); - //}); - + }).catch((error) => { + console.error(`failed to get the relay client (as part of async processing) with error: ${JSON.stringify(error)}`); }); - const ack_submitted = new ack_pb.Ack(); - ack_submitted.setMessage('Procesing addEventSubscription'); - ack_submitted.setRequestId(newRequestId); - ack_submitted.setStatus(ack_pb.Ack.STATUS.OK); + const ack_response = new ack_pb.Ack(); + ack_response.setRequestId(newRequestId); + ack_response.setMessage('Procesing addEventSubscription'); + ack_response.setStatus(ack_pb.Ack.STATUS.OK); // gRPC response. - console.log(`Responding to caller with Ack: ${JSON.stringify(ack_submitted.toObject())}`); - callback(null, ack_submitted); + console.log(`Responding to caller with Ack: ${JSON.stringify(ack_response.toObject())}`); + callback(null, ack_response); } else { dbConnectionTest().then((dbConnectTestStatus) => { if (dbConnectTestStatus == true) { - eventSubscriptionTest(call).then((eventSubscribeTestStatus) => { + eventSubscriptionTest(call.request).then((eventSubscribeTestStatus) => { if (eventSubscribeTestStatus == false) { console.error(`Failed eventSubscriptionTest()`); } @@ -242,15 +246,34 @@ server.addService(driver_pb_grpc.DriverCommunicationService, { }); } } catch (e) { - console.log(e); - ack_response.setMessage(newRequestId); - ack_response.setMessage(`Error: ${e}`); - ack_response.setStatus(ack_pb.Ack.STATUS.ERROR); + const errorString: string = `${JSON.stringify(e)}`; + console.log(`error: ${errorString}`); + const ack_error_response = new ack_pb.Ack(); + ack_error_response.setRequestId(newRequestId); + ack_error_response.setMessage(`Error: ${errorString}`); + ack_error_response.setStatus(ack_pb.Ack.STATUS.ERROR); // gRPC response. - console.error(`Responding to caller Ack: ${JSON.stringify(ack_response.toObject())}`); - callback(null, ack_response); + console.error(`Responding to caller with Ack: ${JSON.stringify(ack_error_response.toObject())}`); + callback(null, ack_error_response); } }, + requestSignedEventSubscriptionQuery: (call: { request: eventsPb.EventSubscription }, callback: (_: any, object: query_pb.Query) => void) => { + const ack_response = new ack_pb.Ack(); + + signEventSubscriptionQuery(call.request.getQuery()!).then((signedQuery) => { + // gRPC response. + console.log(`Responding to caller with signedQuery: ${JSON.stringify(signedQuery.toObject())}`); + callback(null, signedQuery); + }).catch((error) => { + const errorString: string = `${JSON.stringify(error)}`; + console.log(`error: ${errorString}`); + var emptyQuery: query_pb.Query = new query_pb.Query(); + emptyQuery.setRequestorSignature(errorString); + // gRPC response. + console.error(`Responding to caller with emptyQuery: ${JSON.stringify(emptyQuery.toObject())}`); + callback(null, emptyQuery); + }); + }, }); // Prepares required crypto material for communication with the fabric network diff --git a/core/drivers/fabric-driver/server/utils.ts b/core/drivers/fabric-driver/server/utils.ts index 773eb55a7..c8c8b6d48 100644 --- a/core/drivers/fabric-driver/server/utils.ts +++ b/core/drivers/fabric-driver/server/utils.ts @@ -6,17 +6,19 @@ import eventsPb from "@hyperledger-labs/weaver-protos-js/common/events_pb"; import queryPb from '@hyperledger-labs/weaver-protos-js/common/query_pb'; +import { getDriverKeyCert } from "./walletSetup" +import { InteroperableHelper } from '@hyperledger-labs/weaver-fabric-interop-sdk' import { LevelDBConnector } from "./dbConnector" -// Create connection to a database -var db: any = new LevelDBConnector(process.env.DB_NAME!); - // test the LevelDB basic operations async function dbConnectionTest( ): Promise { - console.log(`Start testing LevelDBConnector for ${db.DB_NAME}`) + console.log(`Start testing LevelDBConnector for ${process.env.DB_NAME!}`) try { + // Create connection to a database + const db: any = new LevelDBConnector(process.env.DB_NAME!); + const key: string = 'key'; var value: string = 'insert'; @@ -25,7 +27,7 @@ async function dbConnectionTest( // Fetch the value of the key value = await db.read(key); - console.log(`obtained : <${key}, ${value}>`) + console.log(`obtained : <${key}, ${value}>`); // Close the database connection await db.close(); @@ -50,27 +52,30 @@ async function dbConnectionTest( // Delete the key await db.delete(key); } catch (error) { - console.error(`Failed testing LevelDBConnector, with error: ${JSON.stringify(error)}`) + console.error(`Failed testing LevelDBConnector, with error: ${JSON.stringify(error)}`); return false; } - console.log(`End testing LevelDBConnector for ${db.DB_NAME}`) + console.log(`End testing LevelDBConnector for ${process.env.DB_NAME!}`); return true; } // test the event subscription operations: subscribeEvent, listEvents, deleteEvent async function eventSubscriptionTest( - call: any + eventSub: eventsPb.EventSubscription ): Promise { - console.debug(`Start eventSubscriptionTest()`) + console.debug(`Start eventSubscriptionTest()`); try { - var eventMatcher: eventsPb.EventMatcher = call.request.getEventmatcher()!; - await addEventSubscription(call.request); + // Create connection to a database + const db: any = new LevelDBConnector(process.env.DB_NAME!); + + var eventMatcher: eventsPb.EventMatcher = eventSub.getEventMatcher()!; + await addEventSubscription(eventSub); var subscriptions: Array = await lookupEventSubscriptions(eventMatcher) as Array; for (const subscription of subscriptions) { - if (subscription.getRequestId() == call.request.getQuery().getRequestId()) { + if (subscription.getRequestId() == eventSub.getQuery()!.getRequestId()) { await deleteEventSubscription(eventMatcher, subscription.getRequestId()); break; } @@ -80,7 +85,7 @@ async function eventSubscriptionTest( return false; } - console.debug(`End eventSubscriptionTest()`) + console.debug(`End eventSubscriptionTest()`); return true; } @@ -113,10 +118,14 @@ async function addEventSubscription( eventSub: eventsPb.EventSubscription ): Promise { console.log(`adding to driver, subscription of the eventSub: ${JSON.stringify(eventSub.toObject())}`); - + let db; try { + // Create connection to a database + db = new LevelDBConnector(process.env.DB_NAME!); + await db.open(); + // eventMatcher need to be non-null, hence apply the NaN assertion operator '!' - var eventMatcher: eventsPb.EventMatcher = eventSub.getEventmatcher()!; + var eventMatcher: eventsPb.EventMatcher = eventSub.getEventMatcher()!; // the serialized protobuf for eventMatcher below can be decoded to other formats like 'utf8' [.toString('utf8')] const key: string = Buffer.from(eventMatcher.serializeBinary()).toString('base64'); @@ -141,11 +150,11 @@ async function addEventSubscription( subscription.getRequestingRelay() == query.getRequestingRelay() && subscription.getRequestingNetwork() == query.getRequestingNetwork() && subscription.getCertificate() == query.getCertificate() && - subscription.getRequestorSignature() == query.getRequestorSignature() && subscription.getRequestingOrg() == query.getRequestingOrg() && subscription.getConfidential() == query.getConfidential()) { console.log(`found subscription for query with requestId: ${subscription.getRequestId()}`); + await db.close(); return subscription.getRequestId(); } } @@ -163,6 +172,7 @@ async function addEventSubscription( } else { // case of read failing due to some other issue console.error(`re-throwing error: ${errorString}`); + await db.close(); throw new Error(error); } } @@ -171,6 +181,7 @@ async function addEventSubscription( subscriptionsSerialized = JSON.stringify(subscriptions); // insert the value against key in the DB (it can be the scenario of a new key addition, or update to the value of an existing key) await db.insert(key, subscriptionsSerialized); + await db.close(); // TODO: register the event with fabric sdk console.log(`end addEventSubscription() .. requestId: ${query.getRequestId()}`); @@ -178,6 +189,7 @@ async function addEventSubscription( } catch(error: any) { console.error(`Error during addEventSubscription(): ${JSON.stringify(error)}`); + await db?.close(); throw new Error(error); } } @@ -189,8 +201,13 @@ const deleteEventSubscription = async ( console.log(`deleting from driver subscription of the eventMatcher: ${JSON.stringify(eventMatcher.toObject())} with requestId: ${requestId}`); var subscriptions: Array; var retVal: eventsPb.EventSubscription = new eventsPb.EventSubscription(); - retVal.setEventmatcher(eventMatcher); + retVal.setEventMatcher(eventMatcher); + let db; try { + // Create connection to a database + db = new LevelDBConnector(process.env.DB_NAME!); + await db.open(); + const key: string = Buffer.from(eventMatcher.serializeBinary()).toString('base64'); try { // fetch the current values in the DB against the given key @@ -198,18 +215,25 @@ const deleteEventSubscription = async ( subscriptions = JSON.parse(subscriptionsSerialized); console.debug(`subscriptions.length: ${subscriptions.length}`); + var foundEntry: boolean = false; for (var subscriptionSerialized of subscriptions) { var subscription: queryPb.Query = queryPb.Query.deserializeBinary(Buffer.from(subscriptionSerialized, 'base64')); if (subscription.getRequestId() == requestId) { console.debug(`deleting the subscription (with input requestId): ${JSON.stringify(subscription.toObject())}`); subscriptions.splice(subscriptions.indexOf(subscriptionSerialized), 1); retVal.setQuery(subscription); + foundEntry = true; break; } } + + if (!foundEntry) { + throw new Error(`event subscription with requestId: ${requestId} is not found!`); + } } catch (error: any) { // error could be either due to key not being present in the database or some other issue with database access console.error(`re-throwing error: ${JSON.stringify(error)}`); + await db.close(); throw new Error(error); } @@ -221,10 +245,12 @@ const deleteEventSubscription = async ( await db.insert(key, subscriptionsSerialized); } + await db.close(); console.log(`end deleteEventSubscription() .. retVal: ${JSON.stringify(retVal.toObject())}`); return retVal; } catch(error: any) { - console.error(`Error during lookup: ${JSON.stringify(error)}`); + console.error(`Error during delete: ${JSON.stringify(error)}`); + await db?.close(); throw new Error(error); } } @@ -235,8 +261,13 @@ async function lookupEventSubscriptions( console.info(`finding the subscriptions with eventMatcher: ${JSON.stringify(eventMatcher.toObject())}`); var subscriptions: Array; var returnSubscriptions: Array = new Array(); + let db; try { + // Create connection to a database + db = new LevelDBConnector(process.env.DB_NAME!); + await db.open(); + var eventMatcher: eventsPb.EventMatcher = eventMatcher; const key: string = Buffer.from(eventMatcher.serializeBinary()).toString('base64'); @@ -251,10 +282,12 @@ async function lookupEventSubscriptions( console.debug(`returnSubscriptions.length: ${returnSubscriptions.length}`); console.log(`end lookupEventSubscriptions()`); + await db.close(); return returnSubscriptions; } catch (error: any) { let errorString: string = `${JSON.stringify(error)}` + await db?.close(); if (errorString.includes('Error: NotFound:')) { // case of read failing due to key not found returnSubscriptions = new Array(); @@ -268,10 +301,55 @@ async function lookupEventSubscriptions( } } +async function signEventSubscriptionQuery( + inputQuery: queryPb.Query +): Promise { + console.log(`driver ready to provide sign on query: ${JSON.stringify(inputQuery.toObject())}`); + let signedQuery = new queryPb.Query(); + + try { + signedQuery.setPolicyList(inputQuery.getPolicyList()); + signedQuery.setAddress(inputQuery.getAddress()); + signedQuery.setRequestingRelay(inputQuery.getRequestingRelay()); + signedQuery.setRequestingOrg(inputQuery.getRequestingOrg()); + signedQuery.setRequestingNetwork(inputQuery.getRequestingNetwork()); + signedQuery.setNonce(inputQuery.getNonce()); + signedQuery.setRequestId(inputQuery.getRequestId()); + signedQuery.setConfidential(inputQuery.getConfidential()); + + const keyCert = await getDriverKeyCert() + signedQuery.setCertificate(keyCert.cert); + signedQuery.setRequestorSignature( + InteroperableHelper.signMessage( + inputQuery.getAddress() + inputQuery.getNonce(), + keyCert.key.toBytes() + ).toString("base64") + ); + return signedQuery; + } catch (error: any) { + const errorString: string = `${JSON.stringify(error)}`; + console.error(`signing query failed with error: ${errorString}`); + throw new Error(error); + } +} + +// A better way to handle errors for promises +function handlePromise(promise: Promise): Promise<[T?, Error?]> { + const result: Promise<[T?, Error?]> = promise + .then(data => { + const response: [T?, Error?] = [data, undefined] + return response + }) + .catch(error => Promise.resolve([undefined, error])) + return result +} + export { addEventSubscription, deleteEventSubscription, lookupEventSubscriptions, dbConnectionTest, - eventSubscriptionTest + eventSubscriptionTest, + signEventSubscriptionQuery, + handlePromise } \ No newline at end of file diff --git a/core/drivers/fabric-driver/server/walletSetup.ts b/core/drivers/fabric-driver/server/walletSetup.ts index adacb959a..72964e4e5 100644 --- a/core/drivers/fabric-driver/server/walletSetup.ts +++ b/core/drivers/fabric-driver/server/walletSetup.ts @@ -4,8 +4,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { Wallets, X509Identity } from 'fabric-network'; +import { Wallets } from 'fabric-network'; import FabricCAServices from 'fabric-ca-client'; +import { handlePromise } from './utils'; +import { InteroperableHelper } from '@hyperledger-labs/weaver-fabric-interop-sdk' import * as path from 'path'; import * as fs from 'fs'; @@ -108,4 +110,21 @@ const walletSetup = async (walletPath: string, conn_profile_path: string, networ throw new Error('Admin was not registered'); } }; -export { walletSetup, getConfig }; + +const getDriverKeyCert = async (): Promise => { + + const walletPath = path.join(process.cwd(), `wallet-${process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1'}`); + const config = getConfig(); + const wallet = await Wallets.newFileSystemWallet(walletPath); + console.log(`Wallet path: ${walletPath}`); + + const [keyCert, keyCertError] = await handlePromise( + InteroperableHelper.getKeyAndCertForRemoteRequestbyUserName(wallet, config.relay.name) + ) + if (keyCertError) { + throw new Error(`Error getting key and cert ${keyCertError}`) + } + return keyCert; +} + +export { walletSetup, getConfig, getDriverKeyCert }; diff --git a/core/drivers/fabric-driver/tsconfig.json b/core/drivers/fabric-driver/tsconfig.json index ed6e4533c..37e3f701e 100644 --- a/core/drivers/fabric-driver/tsconfig.json +++ b/core/drivers/fabric-driver/tsconfig.json @@ -25,7 +25,7 @@ // "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. */ + // "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. */ From 442b0c2b19a1961ecdd5f0b212f5fa1e5804a046 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Tue, 12 Jul 2022 11:27:44 +0530 Subject: [PATCH 036/150] driver build-local with weaver-fabric-interop-sdk Signed-off-by: Krishnasuri Narayanam --- .github/workflows/test_docker-build.yml | 6 +++- core/drivers/fabric-driver/.gitignore | 1 + core/drivers/fabric-driver/docker-compose.yml | 2 +- .../fabricDriver.dockerfile.local | 1 + core/drivers/fabric-driver/makefile | 32 +++++++++---------- core/drivers/fabric-driver/package-local.json | 4 +-- core/drivers/fabric-driver/package.json | 2 +- 7 files changed, 26 insertions(+), 22 deletions(-) diff --git a/.github/workflows/test_docker-build.yml b/.github/workflows/test_docker-build.yml index ef90df673..4280a9088 100644 --- a/.github/workflows/test_docker-build.yml +++ b/.github/workflows/test_docker-build.yml @@ -39,6 +39,10 @@ jobs: make build working-directory: common/protos-js + - name: Build Fabric Interop Node SDK (Local) + run: make build-local + working-directory: sdks/fabric/interoperation-node-sdk + - name: Build Image (Local) run: make build-image-local working-directory: core/drivers/fabric-driver @@ -114,4 +118,4 @@ jobs: - name: Build Image run: make image - working-directory: core/drivers/corda-driver \ No newline at end of file + working-directory: core/drivers/corda-driver diff --git a/core/drivers/fabric-driver/.gitignore b/core/drivers/fabric-driver/.gitignore index 94af7ad2c..0b29d7b40 100644 --- a/core/drivers/fabric-driver/.gitignore +++ b/core/drivers/fabric-driver/.gitignore @@ -7,3 +7,4 @@ package-lock.json .npmrc driverdbs +weaver-fabric-interop-sdk diff --git a/core/drivers/fabric-driver/docker-compose.yml b/core/drivers/fabric-driver/docker-compose.yml index 01d4c9f0a..481248f7a 100644 --- a/core/drivers/fabric-driver/docker-compose.yml +++ b/core/drivers/fabric-driver/docker-compose.yml @@ -29,7 +29,7 @@ services: - ../../relay/credentials:/fabric-driver/credentials ports: - "${DRIVER_PORT}:${DRIVER_PORT}" - command: sh -c "npm run dev" + command: sh -c "npm run start" # This networks section is required for when the peers have networks specified networks: default: diff --git a/core/drivers/fabric-driver/fabricDriver.dockerfile.local b/core/drivers/fabric-driver/fabricDriver.dockerfile.local index 5520a4471..d8f50968a 100644 --- a/core/drivers/fabric-driver/fabricDriver.dockerfile.local +++ b/core/drivers/fabric-driver/fabricDriver.dockerfile.local @@ -6,6 +6,7 @@ FROM node:14 AS builder-local WORKDIR /fabric-driver ADD protos-js /fabric-driver/protos-js +ADD weaver-fabric-interop-sdk /fabric-driver/weaver-fabric-interop-sdk # Remote build # FROM node:14 AS builder-remote diff --git a/core/drivers/fabric-driver/makefile b/core/drivers/fabric-driver/makefile index 29bc2341a..eab76e280 100644 --- a/core/drivers/fabric-driver/makefile +++ b/core/drivers/fabric-driver/makefile @@ -7,7 +7,7 @@ build: .npmrc npm run build npm run postinstall -build-local: +protos-js: mkdir -p protos-js && \ cp -r ../../../common/protos-js/common ./protos-js/ && \ cp -r ../../../common/protos-js/corda ./protos-js/ && \ @@ -18,30 +18,28 @@ build-local: cp -r ../../../common/protos-js/peer ./protos-js/ && \ cp -r ../../../common/protos-js/relay ./protos-js/ && \ cp -r ../../../common/protos-js/package.json ./protos-js/ + +weaver-fabric-interop-sdk: + mkdir -p weaver-fabric-interop-sdk && \ + cp -r ../../../sdks/fabric/interoperation-node-sdk/build ./weaver-fabric-interop-sdk/ && \ + cp -r ../../../sdks/fabric/interoperation-node-sdk/index.js ./weaver-fabric-interop-sdk/ && \ + cp -r ../../../sdks/fabric/interoperation-node-sdk/package.json ./weaver-fabric-interop-sdk/package.json + +build-local: protos-js weaver-fabric-interop-sdk (cp package.json package-remote.json && \ cp package-local.json package.json && \ npm install) || \ - (mv package-remote.json package.json && exit 1) # Runs if failure - mv package-remote.json package.json # Runs if success + (mv package-remote.json package.json && exit 1) # Only if fails + mv package-remote.json package.json # Only if success npm run build npm run postinstall -build-image-local: - mkdir -p protos-js && \ - cp -r ../../../common/protos-js/common ./protos-js/ && \ - cp -r ../../../common/protos-js/corda ./protos-js/ && \ - cp -r ../../../common/protos-js/driver ./protos-js/ && \ - cp -r ../../../common/protos-js/fabric ./protos-js/ && \ - cp -r ../../../common/protos-js/msp ./protos-js/ && \ - cp -r ../../../common/protos-js/networks ./protos-js/ && \ - cp -r ../../../common/protos-js/peer ./protos-js/ && \ - cp -r ../../../common/protos-js/relay ./protos-js/ && \ - cp -r ../../../common/protos-js/package.json ./protos-js/ +build-image-local: protos-js weaver-fabric-interop-sdk cp package.json package-remote.json cp package-local.json package.json (docker build --build-arg BUILD_TAG="local" --build-arg GIT_URL=$(GIT_URL) -t ${DOCKER_IMAGE_NAME}:$(DOCKER_TAG) -f fabricDriver.dockerfile.local . ) || \ - (mv package-remote.json package.json && exit 1) # Runs if failure - mv package-remote.json package.json # Runs if success + (mv package-remote.json package.json && exit 1) # Only if fails + mv package-remote.json package.json # Only if success rm -rf protos-js build-image: .npmrc @@ -63,4 +61,4 @@ clean: rm -rf node_modules package-lock.json out clean-local: - rm -rf node_modules package-lock.json out protos-js + rm -rf node_modules package-lock.json out protos-js weaver-fabric-interop-sdk diff --git a/core/drivers/fabric-driver/package-local.json b/core/drivers/fabric-driver/package-local.json index f13e6d231..e78ead61c 100644 --- a/core/drivers/fabric-driver/package-local.json +++ b/core/drivers/fabric-driver/package-local.json @@ -2,7 +2,7 @@ "name": "fabric-driver", "version": "1.3.0", "description": "", - "main": "index.js", + "main": "out/server.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "npm run tsc", @@ -21,7 +21,7 @@ "license": "ISC", "dependencies": { "@hyperledger-labs/weaver-protos-js": "file:./protos-js", - "@hyperledger-labs/weaver-fabric-interop-sdk": "file:../../../sdks/fabric/interoperation-node-sdk", + "@hyperledger-labs/weaver-fabric-interop-sdk": "file:./weaver-fabric-interop-sdk", "@fidm/x509": "^1.2.1", "@grpc/grpc-js": "^1.1.1", "@typescript-eslint/eslint-plugin": "^3.5.0", diff --git a/core/drivers/fabric-driver/package.json b/core/drivers/fabric-driver/package.json index 7edd0b807..c7ae08419 100644 --- a/core/drivers/fabric-driver/package.json +++ b/core/drivers/fabric-driver/package.json @@ -2,7 +2,7 @@ "name": "fabric-driver", "version": "1.3.0", "description": "", - "main": "index.js", + "main": "out/server.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "npm run tsc", From d22afe66535189cca46f75d6d132a669dc1176d2 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Tue, 12 Jul 2022 11:53:17 +0530 Subject: [PATCH 037/150] minor config related edits Signed-off-by: Krishnasuri Narayanam --- core/drivers/fabric-driver/.env.docker.template | 6 +++--- core/drivers/fabric-driver/docker-compose.yml | 2 ++ .../fabric-driver/fabricDriver.dockerfile | 1 - .../fabric-driver/fabricDriver.dockerfile.local | 1 - .../fabric-driver/makefile.variables.docker | 2 +- core/drivers/fabric-driver/package-local.json | 2 +- core/drivers/fabric-driver/package.json | 2 +- core/drivers/fabric-driver/readme.md | 4 ++++ .../server/data/mock-network-config.json | 1 - core/drivers/fabric-driver/temp.pem | 17 ----------------- core/relay/.env.template.2 | 2 +- 11 files changed, 13 insertions(+), 27 deletions(-) delete mode 100644 core/drivers/fabric-driver/server/data/mock-network-config.json delete mode 100644 core/drivers/fabric-driver/temp.pem diff --git a/core/drivers/fabric-driver/.env.docker.template b/core/drivers/fabric-driver/.env.docker.template index e456286d8..c63ab70eb 100644 --- a/core/drivers/fabric-driver/.env.docker.template +++ b/core/drivers/fabric-driver/.env.docker.template @@ -9,10 +9,10 @@ DRIVER_TLS=false DRIVER_TLS_CERT_PATH= DRIVER_TLS_KEY_PATH= INTEROP_CHAINCODE= +DB_NAME=driverdb +DB_PATH=driverdbs DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-fabric-driver -DOCKER_TAG=1.3.1 +DOCKER_TAG=1.4.0 EXTERNAL_NETWORK= COMPOSE_PROJECT_NAME= COMPOSE_PROJECT_NETWORK= -MOCK=false -DB_NAME=driverdb diff --git a/core/drivers/fabric-driver/docker-compose.yml b/core/drivers/fabric-driver/docker-compose.yml index 481248f7a..d4344d4d2 100644 --- a/core/drivers/fabric-driver/docker-compose.yml +++ b/core/drivers/fabric-driver/docker-compose.yml @@ -22,6 +22,8 @@ services: - DRIVER_TLS=${DRIVER_TLS} - DRIVER_TLS_CERT_PATH=${DRIVER_TLS_CERT_PATH} - DRIVER_TLS_KEY_PATH=${DRIVER_TLS_KEY_PATH} + - DB_NAME=${DB_NAME} + - DB_PATH=${DB_PATH} volumes: - ${CONNECTION_PROFILE}:/fabric-driver/ccp.json - ${DRIVER_CONFIG}:/fabric-driver/config.json diff --git a/core/drivers/fabric-driver/fabricDriver.dockerfile b/core/drivers/fabric-driver/fabricDriver.dockerfile index 759589cd2..ef82abea7 100644 --- a/core/drivers/fabric-driver/fabricDriver.dockerfile +++ b/core/drivers/fabric-driver/fabricDriver.dockerfile @@ -24,7 +24,6 @@ RUN npm install --unsafe-perm ADD patches /fabric-driver/patches ADD server /fabric-driver/server ADD config.json . -ADD temp.pem . ADD tsconfig.json . ADD .eslintrc . ADD .prettierrc . diff --git a/core/drivers/fabric-driver/fabricDriver.dockerfile.local b/core/drivers/fabric-driver/fabricDriver.dockerfile.local index d8f50968a..b582ca1c2 100644 --- a/core/drivers/fabric-driver/fabricDriver.dockerfile.local +++ b/core/drivers/fabric-driver/fabricDriver.dockerfile.local @@ -23,7 +23,6 @@ RUN npm install --unsafe-perm ADD patches /fabric-driver/patches ADD server /fabric-driver/server ADD config.json . -ADD temp.pem . ADD tsconfig.json . ADD .eslintrc . ADD .prettierrc . diff --git a/core/drivers/fabric-driver/makefile.variables.docker b/core/drivers/fabric-driver/makefile.variables.docker index 24b88a456..858a1f92c 100644 --- a/core/drivers/fabric-driver/makefile.variables.docker +++ b/core/drivers/fabric-driver/makefile.variables.docker @@ -1,4 +1,4 @@ DOCKER_IMAGE_NAME ?= weaver-fabric-driver -DOCKER_TAG ?= 1.3.1 +DOCKER_TAG ?= 1.4.0 DOCKER_REGISTRY ?= ghcr.io/hyperledger-labs GIT_URL = https://github.com/hyperledger-labs/weaver-dlt-interoperability/core/drivers/fabric-driver \ No newline at end of file diff --git a/core/drivers/fabric-driver/package-local.json b/core/drivers/fabric-driver/package-local.json index e78ead61c..9b546fc51 100644 --- a/core/drivers/fabric-driver/package-local.json +++ b/core/drivers/fabric-driver/package-local.json @@ -1,6 +1,6 @@ { "name": "fabric-driver", - "version": "1.3.0", + "version": "1.4.0", "description": "", "main": "out/server.js", "scripts": { diff --git a/core/drivers/fabric-driver/package.json b/core/drivers/fabric-driver/package.json index c7ae08419..59ef2e5b4 100644 --- a/core/drivers/fabric-driver/package.json +++ b/core/drivers/fabric-driver/package.json @@ -1,6 +1,6 @@ { "name": "fabric-driver", - "version": "1.3.0", + "version": "1.4.0", "description": "", "main": "out/server.js", "scripts": { diff --git a/core/drivers/fabric-driver/readme.md b/core/drivers/fabric-driver/readme.md index 014035468..f2713770d 100644 --- a/core/drivers/fabric-driver/readme.md +++ b/core/drivers/fabric-driver/readme.md @@ -93,6 +93,10 @@ Can pass in a config file for the driver to be run with: `DRIVER_CONFIG` (ex: DR `INTEROP_CHAINCODE` stores the name of the interop chaincode installed. +`DB_NAME` stores the name of the database used for storing the event subscription information. + +`DB_PATH` stores the path hosting the database files. + NOTE: When specifying ensure that they match the config that the relay is using. **For docker-compose:*** diff --git a/core/drivers/fabric-driver/server/data/mock-network-config.json b/core/drivers/fabric-driver/server/data/mock-network-config.json deleted file mode 100644 index 37a7df4a1..000000000 --- a/core/drivers/fabric-driver/server/data/mock-network-config.json +++ /dev/null @@ -1 +0,0 @@ -{"members":{"org1.network1.com":{"type":"ca","value":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNLakNDQWRHZ0F3SUJBZ0lVQkZUaTU2cm1qdW5KaVJFU3B5SlcwcTRzUkw0d0NnWUlLb1pJemowRUF3SXcKY2pFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1ROHdEUVlEVlFRSApFd1pFZFhKb1lXMHhHakFZQmdOVkJBb1RFVzl5WnpFdWJtVjBkMjl5YXpFdVkyOXRNUjB3R3dZRFZRUURFeFJqCllTNXZjbWN4TG01bGRIZHZjbXN4TG1OdmJUQWVGdzB5TURBM01qa3dORE0xTURCYUZ3MHpOVEEzTWpZd05ETTEKTURCYU1ISXhDekFKQmdOVkJBWVRBbFZUTVJjd0ZRWURWUVFJRXc1T2IzSjBhQ0JEWVhKdmJHbHVZVEVQTUEwRwpBMVVFQnhNR1JIVnlhR0Z0TVJvd0dBWURWUVFLRXhGdmNtY3hMbTVsZEhkdmNtc3hMbU52YlRFZE1Cc0dBMVVFCkF4TVVZMkV1YjNKbk1TNXVaWFIzYjNKck1TNWpiMjB3V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkMKQUFRT05zSU96NW8rSGhLZ1NkSU9wcUdyVGN2SjN0QURrRnN5TWcwdlYzTVNvNmd5QXE1VjIzYzFnck80WDV4VQpZNzFaVlRQUXVva3Y2L1dJUVlJYXVtakRvMFV3UXpBT0JnTlZIUThCQWY4RUJBTUNBUVl3RWdZRFZSMFRBUUgvCkJBZ3dCZ0VCL3dJQkFUQWRCZ05WSFE0RUZnUVUxZyt0UG5naDJ3OGc5OXoxbXdzVmJrS2pBS2t3Q2dZSUtvWkkKemowRUF3SURSd0F3UkFJZ0dkU015RXppbW9Td2pUeUYrTm1Pd09MbjR4cGVNT2hldjVpZFJXcHkrWnNDSUZLQQowSThjQ2Q1dHc3elR1a3lqV01KaTczN0srNHpQSzZRREtJZXFsK1IxCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"}}} \ No newline at end of file diff --git a/core/drivers/fabric-driver/temp.pem b/core/drivers/fabric-driver/temp.pem deleted file mode 100644 index 71278df8f..000000000 --- a/core/drivers/fabric-driver/temp.pem +++ /dev/null @@ -1,17 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICrTCCAlSgAwIBAgIUHCW/0mWLashHHoswLqUhi+QpDG8wCgYIKoZIzj0EAwIw -cjELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH -EwZEdXJoYW0xGjAYBgNVBAoTEW9yZzEubmV0d29yazEuY29tMR0wGwYDVQQDExRj -YS5vcmcxLm5ldHdvcmsxLmNvbTAeFw0yMDA3MjkwNDM2MDBaFw0yMTA3MjkwNDQx -MDBaMF0xCzAJBgNVBAYTAlVTMRcwFQYDVQQIEw5Ob3J0aCBDYXJvbGluYTEUMBIG -A1UEChMLSHlwZXJsZWRnZXIxDzANBgNVBAsTBmNsaWVudDEOMAwGA1UEAxMFdXNl -cjEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASuh/rVCf8ODuw0IhnrM2iif2a7 -sGT8BIV1PEDU3SnqClmh+RV/3JyKl/TythzN/ZVnKE/tv5d3gVWbNstc97+So4Hc -MIHZMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQx/hLY -CNG4ezCqvgTKC/WwuSVnmDAfBgNVHSMEGDAWgBTWD60+eCHbDyD33PWbCxVuQqMA -qTAfBgNVHREEGDAWghRvYzUxMDM3NDczODAuaWJtLmNvbTBYBggqAwQFBgcIAQRM -eyJhdHRycyI6eyJoZi5BZmZpbGlhdGlvbiI6IiIsImhmLkVucm9sbG1lbnRJRCI6 -InVzZXIxIiwiaGYuVHlwZSI6ImNsaWVudCJ9fTAKBggqhkjOPQQDAgNHADBEAiAF -nsL6UuxTmJK9nhdMMP5lV7xnyYl1WyDizEQsfwuOZwIgXcwnHOaUDWYjfXtFSI5y -zZ9mr6PEkR4DtTHIRFaMV18= ------END CERTIFICATE----- \ No newline at end of file diff --git a/core/relay/.env.template.2 b/core/relay/.env.template.2 index 13d1c0013..0ca531467 100644 --- a/core/relay/.env.template.2 +++ b/core/relay/.env.template.2 @@ -7,7 +7,7 @@ DRIVER_NAME= RELAY_NAME= RELAY_PORT= DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-relay-server -DOCKER_TAG=1.3.1 +DOCKER_TAG=1.4.0 EXTERNAL_NETWORK= COMPOSE_PROJECT_NAME= COMPOSE_PROJECT_NETWORK= From 0e1735c18a71b1d813a103d6d22ac09ae3980e66 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Tue, 12 Jul 2022 15:56:00 +0530 Subject: [PATCH 038/150] removing DB_NAME env variable Signed-off-by: Krishnasuri Narayanam --- common/protos/driver/driver.proto | 11 + .../fabric-driver/.env.docker.template | 1 - core/drivers/fabric-driver/.env.template | 1 - core/drivers/fabric-driver/docker-compose.yml | 1 - core/drivers/fabric-driver/readme.md | 4 +- .../fabric-driver/server/dbConnector.ts | 3 +- core/drivers/fabric-driver/server/events.ts | 249 +++++++++++++- core/drivers/fabric-driver/server/server.ts | 29 +- core/drivers/fabric-driver/server/tests.ts | 93 +++++ core/drivers/fabric-driver/server/utils.ts | 317 +----------------- core/relay/.env.template | 2 +- 11 files changed, 358 insertions(+), 353 deletions(-) create mode 100644 core/drivers/fabric-driver/server/tests.ts diff --git a/common/protos/driver/driver.proto b/common/protos/driver/driver.proto index 94d83af59..3a39f76d1 100644 --- a/common/protos/driver/driver.proto +++ b/common/protos/driver/driver.proto @@ -5,10 +5,17 @@ package driver.driver; import "common/ack.proto"; import "common/query.proto"; import "common/events.proto"; +import "common/state.proto"; option java_package = "com.weaver.protos.driver.driver"; option go_package = "github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go/driver"; +// Data for a View processing by dest-driver +message WriteExternalStateMessage { + common.state.ViewPayload view_payload = 1; + common.events.ContractTransaction ctx = 2; +} + service DriverCommunication { // Data Sharing // the remote relay sends a RequestDriverState request to its driver with a @@ -23,4 +30,8 @@ service DriverCommunication { // Relay uses this to get Query.requestor_signature and // Query.certificate required for event subscription rpc RequestSignedEventSubscriptionQuery(common.events.EventSubscription) returns (common.query.Query) {} + + // Events Publication + // the dest-relay calls the dest-driver on this end point to write the remote network state to the local ledger + rpc WriteExternalState(WriteExternalStateMessage) returns (common.ack.Ack) {} } \ No newline at end of file diff --git a/core/drivers/fabric-driver/.env.docker.template b/core/drivers/fabric-driver/.env.docker.template index c63ab70eb..ef09d3136 100644 --- a/core/drivers/fabric-driver/.env.docker.template +++ b/core/drivers/fabric-driver/.env.docker.template @@ -9,7 +9,6 @@ DRIVER_TLS=false DRIVER_TLS_CERT_PATH= DRIVER_TLS_KEY_PATH= INTEROP_CHAINCODE= -DB_NAME=driverdb DB_PATH=driverdbs DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-fabric-driver DOCKER_TAG=1.4.0 diff --git a/core/drivers/fabric-driver/.env.template b/core/drivers/fabric-driver/.env.template index 8a9dc47e1..bc57d9b42 100644 --- a/core/drivers/fabric-driver/.env.template +++ b/core/drivers/fabric-driver/.env.template @@ -10,5 +10,4 @@ NETWORK_NAME=network1 DRIVER_CONFIG= INTEROP_CHAINCODE=interop MOCK=false -DB_NAME=driverdb DB_PATH=driverdbs diff --git a/core/drivers/fabric-driver/docker-compose.yml b/core/drivers/fabric-driver/docker-compose.yml index d4344d4d2..dcb2a6c1d 100644 --- a/core/drivers/fabric-driver/docker-compose.yml +++ b/core/drivers/fabric-driver/docker-compose.yml @@ -22,7 +22,6 @@ services: - DRIVER_TLS=${DRIVER_TLS} - DRIVER_TLS_CERT_PATH=${DRIVER_TLS_CERT_PATH} - DRIVER_TLS_KEY_PATH=${DRIVER_TLS_KEY_PATH} - - DB_NAME=${DB_NAME} - DB_PATH=${DB_PATH} volumes: - ${CONNECTION_PROFILE}:/fabric-driver/ccp.json diff --git a/core/drivers/fabric-driver/readme.md b/core/drivers/fabric-driver/readme.md index f2713770d..190efac3a 100644 --- a/core/drivers/fabric-driver/readme.md +++ b/core/drivers/fabric-driver/readme.md @@ -93,9 +93,7 @@ Can pass in a config file for the driver to be run with: `DRIVER_CONFIG` (ex: DR `INTEROP_CHAINCODE` stores the name of the interop chaincode installed. -`DB_NAME` stores the name of the database used for storing the event subscription information. - -`DB_PATH` stores the path hosting the database files. +`DB_PATH` stores the path hosting the database files containing the event subscription information. NOTE: When specifying ensure that they match the config that the relay is using. diff --git a/core/drivers/fabric-driver/server/dbConnector.ts b/core/drivers/fabric-driver/server/dbConnector.ts index 0389ca60b..e02954994 100644 --- a/core/drivers/fabric-driver/server/dbConnector.ts +++ b/core/drivers/fabric-driver/server/dbConnector.ts @@ -43,7 +43,7 @@ class LevelDBConnector implements DBConnector { dbName: string ) { if (!dbName || dbName.length == 0) { - dbName = process.env.DB_NAME ? process.env.DB_NAME : "driverdb"; + dbName = "driverdb"; } this.DB_NAME = dbName; this.dbHandle = new Level(path.join(process.env.DB_PATH ? process.env.DB_PATH : "./driverdbs", dbName), { valueEncoding: 'json' }); @@ -133,5 +133,6 @@ class LevelDBConnector implements DBConnector { } export { + DBConnector, LevelDBConnector } \ No newline at end of file diff --git a/core/drivers/fabric-driver/server/events.ts b/core/drivers/fabric-driver/server/events.ts index 03cce6d26..3d735baaa 100644 --- a/core/drivers/fabric-driver/server/events.ts +++ b/core/drivers/fabric-driver/server/events.ts @@ -7,7 +7,13 @@ import ack_pb from '@hyperledger-labs/weaver-protos-js/common/ack_pb'; import eventsPb from '@hyperledger-labs/weaver-protos-js/common/events_pb'; import events_grpc_pb from '@hyperledger-labs/weaver-protos-js/relay/events_grpc_pb'; -import { addEventSubscription, deleteEventSubscription } from "./utils" +import queryPb from '@hyperledger-labs/weaver-protos-js/common/query_pb'; +import { InteroperableHelper } from '@hyperledger-labs/weaver-fabric-interop-sdk' +import { getDriverKeyCert } from "./walletSetup" +import { DBConnector, LevelDBConnector } from "./dbConnector" +import { checkIfArraysAreEqual, relayCallback } from "./utils" + +const DB_NAME: string = "driverdb"; function subscribeEventHelper( call_request: eventsPb.EventSubscription, @@ -37,9 +43,7 @@ function subscribeEventHelper( } // Sending the fabric state to the relay. - client.sendDriverSubscriptionStatus(ack_send, function (err: any, response: any) { - console.log(`Response: ${JSON.stringify(response.toObject())} Error: ${JSON.stringify(err)}`); - }); + client.sendDriverSubscriptionStatus(ack_send, relayCallback); }).catch((error) => { const errorString: string = `error (thrown as part of async processing while storing to DB during subscribeEvent): ${JSON.stringify(error)}`; console.error(errorString); @@ -50,9 +54,7 @@ function subscribeEventHelper( // gRPC response. console.log(`Sending to the relay the eventSubscription error Ack: ${JSON.stringify(ack_send_error.toObject())}`); // Sending the fabric state to the relay. - client.sendDriverSubscriptionStatus(ack_send_error, function (err: any, response: any) { - console.log(`Response: ${JSON.stringify(response.toObject())} Error: ${JSON.stringify(err)}`); - }); + client.sendDriverSubscriptionStatus(ack_send_error, relayCallback); }); } @@ -77,9 +79,7 @@ function unsubscribeEventHelper( } // Sending the fabric state to the relay. - client.sendDriverSubscriptionStatus(ack_send, function (err: any, response: any) { - console.log(`Response: ${JSON.stringify(response.toObject())} Error: ${JSON.stringify(err)}`); - }); + client.sendDriverSubscriptionStatus(ack_send, relayCallback); }).catch((error) => { const errorString: string = `error (thrown as part of async processing while deleting from DB during unsubscribeEvent): ${JSON.stringify(error)}`; console.error(errorString); @@ -90,13 +90,234 @@ function unsubscribeEventHelper( // gRPC response. console.log(`Sending to the relay the eventSubscription error Ack: ${JSON.stringify(ack_send_error.toObject())}`); // Sending the fabric state to the relay. - client.sendDriverSubscriptionStatus(ack_send_error, function (err: any, response: any) { - console.log(`Response: ${JSON.stringify(response.toObject())} Error: ${JSON.stringify(err)}`); - }); + client.sendDriverSubscriptionStatus(ack_send_error, relayCallback); }); } +async function addEventSubscription( + eventSub: eventsPb.EventSubscription +): Promise { + console.log(`adding to driver, subscription of the eventSub: ${JSON.stringify(eventSub.toObject())}`); + let db: DBConnector; + try { + // Create connection to a database + db = new LevelDBConnector(DB_NAME!); + await db.open(); + + // eventMatcher need to be non-null, hence apply the NaN assertion operator '!' + var eventMatcher: eventsPb.EventMatcher = eventSub.getEventMatcher()!; + // the serialized protobuf for eventMatcher below can be decoded to other formats like 'utf8' [.toString('utf8')] + const key: string = Buffer.from(eventMatcher.serializeBinary()).toString('base64'); + + // query need to be non-null, hence apply the NaN assertion operator '!' + var query: queryPb.Query = eventSub.getQuery()!; + // the serialized protobuf for query below can be decoded to other formats like 'utf8' [.toString('utf8')] + var querySerialized: string = Buffer.from(query.serializeBinary()).toString('base64'); + // serialized content of subscriptions is the value present in the key/value LevelDB corresponding to the key + var subscriptions: Array; + + try { + // fetch the current values in the DB against the given key + var subscriptionsSerialized: string = await db.read(key) as string; + subscriptions = JSON.parse(subscriptionsSerialized); + + console.debug(`subscriptions.length: ${subscriptions.length}`); + // check if the event to be subscribed is already present in the DB + for (const subscriptionSerialized of subscriptions) { + var subscription: queryPb.Query = queryPb.Query.deserializeBinary(Buffer.from(subscriptionSerialized, 'base64')); + if (checkIfArraysAreEqual(subscription.getPolicyList(), query.getPolicyList()) && + subscription.getAddress() == query.getAddress() && + subscription.getRequestingRelay() == query.getRequestingRelay() && + subscription.getRequestingNetwork() == query.getRequestingNetwork() && + subscription.getCertificate() == query.getCertificate() && + subscription.getRequestingOrg() == query.getRequestingOrg() && + subscription.getConfidential() == query.getConfidential()) { + + console.log(`found subscription for query with requestId: ${subscription.getRequestId()}`); + await db.close(); + return subscription.getRequestId(); + } + } + + // case of key being present in the list + console.debug(`eventMatcher: ${JSON.stringify(eventMatcher.toObject())} is already present in the database`); + subscriptions.push(querySerialized); + } catch (error: any) { + let errorString = `${JSON.stringify(error)}`; + if (errorString.includes('Error: NotFound:')) { + // case of read failing due to key not found + console.debug(`eventMatcher: ${JSON.stringify(eventMatcher.toObject())} is not present before in the database`); + subscriptions = new Array(); + subscriptions.push(querySerialized); + } else { + // case of read failing due to some other issue + console.error(`re-throwing error: ${errorString}`); + await db.close(); + throw new Error(error); + } + } + + console.debug(`subscriptions.length: ${subscriptions.length}`); + subscriptionsSerialized = JSON.stringify(subscriptions); + // insert the value against key in the DB (it can be the scenario of a new key addition, or update to the value of an existing key) + await db.insert(key, subscriptionsSerialized); + await db.close(); + + // TODO: register the event with fabric sdk + console.log(`end addEventSubscription() .. requestId: ${query.getRequestId()}`); + return query.getRequestId(); + + } catch(error: any) { + console.error(`Error during addEventSubscription(): ${JSON.stringify(error)}`); + await db?.close(); + throw new Error(error); + } +} + +const deleteEventSubscription = async ( + eventMatcher: eventsPb.EventMatcher, + requestId: string +): Promise => { + console.log(`deleting from driver subscription of the eventMatcher: ${JSON.stringify(eventMatcher.toObject())} with requestId: ${requestId}`); + var subscriptions: Array; + var retVal: eventsPb.EventSubscription = new eventsPb.EventSubscription(); + retVal.setEventMatcher(eventMatcher); + let db: DBConnector; + try { + // Create connection to a database + db = new LevelDBConnector(DB_NAME!); + await db.open(); + + const key: string = Buffer.from(eventMatcher.serializeBinary()).toString('base64'); + try { + // fetch the current values in the DB against the given key + var subscriptionsSerialized: string = await db.read(key) as string; + subscriptions = JSON.parse(subscriptionsSerialized); + + console.debug(`subscriptions.length: ${subscriptions.length}`); + var foundEntry: boolean = false; + for (var subscriptionSerialized of subscriptions) { + var subscription: queryPb.Query = queryPb.Query.deserializeBinary(Buffer.from(subscriptionSerialized, 'base64')); + if (subscription.getRequestId() == requestId) { + console.debug(`deleting the subscription (with input requestId): ${JSON.stringify(subscription.toObject())}`); + subscriptions.splice(subscriptions.indexOf(subscriptionSerialized), 1); + retVal.setQuery(subscription); + foundEntry = true; + break; + } + } + + if (!foundEntry) { + throw new Error(`event subscription with requestId: ${requestId} is not found!`); + } + } catch (error: any) { + // error could be either due to key not being present in the database or some other issue with database access + console.error(`re-throwing error: ${JSON.stringify(error)}`); + await db.close(); + throw new Error(error); + } + + console.debug(`subscriptions.length: ${subscriptions.length}`); + if (subscriptions.length == 0) { + await db.delete(key); + } else { + subscriptionsSerialized = JSON.stringify(subscriptions); + await db.insert(key, subscriptionsSerialized); + } + + await db.close(); + console.log(`end deleteEventSubscription() .. retVal: ${JSON.stringify(retVal.toObject())}`); + return retVal; + } catch(error: any) { + console.error(`Error during delete: ${JSON.stringify(error)}`); + await db?.close(); + throw new Error(error); + } +} + +async function lookupEventSubscriptions( + eventMatcher: eventsPb.EventMatcher +): Promise> { + console.info(`finding the subscriptions with eventMatcher: ${JSON.stringify(eventMatcher.toObject())}`); + var subscriptions: Array; + var returnSubscriptions: Array = new Array(); + let db: DBConnector; + + try { + // Create connection to a database + db = new LevelDBConnector(DB_NAME!); + await db.open(); + + var eventMatcher: eventsPb.EventMatcher = eventMatcher; + const key: string = Buffer.from(eventMatcher.serializeBinary()).toString('base64'); + + // fetch the current values in the DB against the given key + var subscriptionsSerialized: string = await db.read(key) as string; + subscriptions = JSON.parse(subscriptionsSerialized) + for (const subscriptionSerialized of subscriptions) { + var subscription: queryPb.Query = queryPb.Query.deserializeBinary(Buffer.from(subscriptionSerialized, 'base64')); + console.debug(`subscription: ${JSON.stringify(subscription.toObject())}`) + returnSubscriptions.push(subscription); + } + + console.debug(`returnSubscriptions.length: ${returnSubscriptions.length}`); + console.log(`end lookupEventSubscriptions()`); + await db.close(); + return returnSubscriptions; + + } catch (error: any) { + let errorString: string = `${JSON.stringify(error)}` + await db?.close(); + if (errorString.includes('Error: NotFound:')) { + // case of read failing due to key not found + returnSubscriptions = new Array(); + console.debug(`returnSubscriptions.length: ${returnSubscriptions.length}`); + return returnSubscriptions; + } else { + // case of read failing due to some other issue + console.error(`Error during lookup: ${JSON.stringify(error)}`); + throw new Error(error); + } + } +} + +async function signEventSubscriptionQuery( + inputQuery: queryPb.Query +): Promise { + console.log(`driver ready to provide sign on query: ${JSON.stringify(inputQuery.toObject())}`); + let signedQuery = new queryPb.Query(); + + try { + signedQuery.setPolicyList(inputQuery.getPolicyList()); + signedQuery.setAddress(inputQuery.getAddress()); + signedQuery.setRequestingRelay(inputQuery.getRequestingRelay()); + signedQuery.setRequestingOrg(inputQuery.getRequestingOrg()); + signedQuery.setRequestingNetwork(inputQuery.getRequestingNetwork()); + signedQuery.setNonce(inputQuery.getNonce()); + signedQuery.setRequestId(inputQuery.getRequestId()); + signedQuery.setConfidential(inputQuery.getConfidential()); + + const keyCert = await getDriverKeyCert() + signedQuery.setCertificate(keyCert.cert); + signedQuery.setRequestorSignature( + InteroperableHelper.signMessage( + inputQuery.getAddress() + inputQuery.getNonce(), + keyCert.key.toBytes() + ).toString("base64") + ); + return signedQuery; + } catch (error: any) { + const errorString: string = `${JSON.stringify(error)}`; + console.error(`signing query failed with error: ${errorString}`); + throw new Error(error); + } +} + export { subscribeEventHelper, - unsubscribeEventHelper + unsubscribeEventHelper, + addEventSubscription, + deleteEventSubscription, + lookupEventSubscriptions, + signEventSubscriptionQuery } \ No newline at end of file diff --git a/core/drivers/fabric-driver/server/server.ts b/core/drivers/fabric-driver/server/server.ts index 0fc53f180..1fd74e51e 100644 --- a/core/drivers/fabric-driver/server/server.ts +++ b/core/drivers/fabric-driver/server/server.ts @@ -17,11 +17,11 @@ import state_pb from '@hyperledger-labs/weaver-protos-js/common/state_pb'; import invoke from './fabric-code'; import 'dotenv/config'; import { walletSetup } from './walletSetup'; -import { subscribeEventHelper, unsubscribeEventHelper } from "./events" +import { subscribeEventHelper, unsubscribeEventHelper, signEventSubscriptionQuery } from "./events" import { Certificate } from '@fidm/x509'; import * as path from 'path'; - -import { addEventSubscription, dbConnectionTest, eventSubscriptionTest, signEventSubscriptionQuery } from "./utils" +import { handlePromise, relayCallback } from './utils'; +import { dbConnectionTest, eventSubscriptionTest } from "./tests" const server = new Server(); console.log('driver def', JSON.stringify(driver_pb_grpc)); @@ -57,23 +57,10 @@ function mockCommunication(query: query_pb.Query) { process.env.RELAY_ENDPOINT, credentials.createInsecure(), ); - client.sendDriverState(viewPayload, function (err: any, response: any) { - console.log('Response:', response); - }); + client.sendDriverState(viewPayload, relayCallback); }, 3000); } -// A better way to handle errors for promises -function handlePromise(promise: Promise): Promise<[T?, Error?]> { - const result: Promise<[T?, Error?]> = promise - .then((data) => { - const response: [T?, Error?] = [data, undefined]; - return response; - }) - .catch((error) => Promise.resolve([undefined, error])); - return result; -} - // Handles communication with fabric network and sends resulting data to the relay const fabricCommunication = async (query: query_pb.Query, networkName: string) => { // Query object from requestor @@ -117,9 +104,7 @@ const fabricCommunication = async (query: query_pb.Query, networkName: string) = errorViewPayload.setError(`Error: ${JSON.stringify(invokeError)}`); errorViewPayload.setRequestId(query.getRequestId()); // Send the error state to the relay - client.sendDriverState(errorViewPayload, function (err: any, response: any) { - console.log('Response:', response, 'Error: ', err); - }); + client.sendDriverState(errorViewPayload, relayCallback); } else { // Process response from invoke to send to relay console.log('Result of fabric invoke', result); @@ -138,9 +123,7 @@ const fabricCommunication = async (query: query_pb.Query, networkName: string) = console.log('Sending state'); // Sending the fabric state to the relay. - client.sendDriverState(viewPayload, function (err: any, response: any) { - console.log(`Response: ${JSON.stringify(response.toObject())} Error: ${JSON.stringify(err)}`); - }); + client.sendDriverState(viewPayload, relayCallback); } }; diff --git a/core/drivers/fabric-driver/server/tests.ts b/core/drivers/fabric-driver/server/tests.ts new file mode 100644 index 000000000..812d5fe7a --- /dev/null +++ b/core/drivers/fabric-driver/server/tests.ts @@ -0,0 +1,93 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import eventsPb from "@hyperledger-labs/weaver-protos-js/common/events_pb"; +import queryPb from '@hyperledger-labs/weaver-protos-js/common/query_pb'; +import { addEventSubscription, deleteEventSubscription, lookupEventSubscriptions } from "./events" +import { LevelDBConnector } from "./dbConnector" + +// test the LevelDB basic operations +async function dbConnectionTest( +): Promise { + console.log(`Start testing LevelDBConnector for ${process.env.DB_NAME!}`) + try { + // Create connection to a database + const db: any = new LevelDBConnector(process.env.DB_NAME!); + + const key: string = 'key'; + var value: string = 'insert'; + + // Add the entry to the database + await db.insert(key, value); + + // Fetch the value of the key + value = await db.read(key); + console.log(`obtained : <${key}, ${value}>`); + + // Close the database connection + await db.close(); + + // Try to update the key before opening the database connection + try { + value = 'update'; + await db.update(key, value); + } catch (error: any) { + const errorString: string = `${JSON.stringify(error)}`; + if (errorString.includes(`is not open`)) { + // open the database connection + await db.open(); + // try to update again the key + await db.update(key, value); + } else { + console.error(`re-throwing the error: ${errorString}`); + throw new Error(error); + } + } + + // Delete the key + await db.delete(key); + } catch (error) { + console.error(`Failed testing LevelDBConnector, with error: ${JSON.stringify(error)}`); + return false; + } + + console.log(`End testing LevelDBConnector for ${process.env.DB_NAME!}`); + return true; +} + +// test the event subscription operations: subscribeEvent, listEvents, deleteEvent +async function eventSubscriptionTest( + eventSub: eventsPb.EventSubscription +): Promise { + console.debug(`Start eventSubscriptionTest()`); + + try { + // Create connection to a database + const db: any = new LevelDBConnector(process.env.DB_NAME!); + + var eventMatcher: eventsPb.EventMatcher = eventSub.getEventMatcher()!; + await addEventSubscription(eventSub); + var subscriptions: Array = await lookupEventSubscriptions(eventMatcher) as Array; + + for (const subscription of subscriptions) { + if (subscription.getRequestId() == eventSub.getQuery()!.getRequestId()) { + await deleteEventSubscription(eventMatcher, subscription.getRequestId()); + break; + } + } + } catch (error) { + console.error(`Failed testing event subscription operations, with error: ${JSON.stringify(error)}`); + return false; + } + + console.debug(`End eventSubscriptionTest()`); + return true; +} + +export { + dbConnectionTest, + eventSubscriptionTest +} \ No newline at end of file diff --git a/core/drivers/fabric-driver/server/utils.ts b/core/drivers/fabric-driver/server/utils.ts index c8c8b6d48..f8e626b26 100644 --- a/core/drivers/fabric-driver/server/utils.ts +++ b/core/drivers/fabric-driver/server/utils.ts @@ -4,91 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -import eventsPb from "@hyperledger-labs/weaver-protos-js/common/events_pb"; -import queryPb from '@hyperledger-labs/weaver-protos-js/common/query_pb'; -import { getDriverKeyCert } from "./walletSetup" -import { InteroperableHelper } from '@hyperledger-labs/weaver-fabric-interop-sdk' - -import { LevelDBConnector } from "./dbConnector" - -// test the LevelDB basic operations -async function dbConnectionTest( -): Promise { - console.log(`Start testing LevelDBConnector for ${process.env.DB_NAME!}`) - try { - // Create connection to a database - const db: any = new LevelDBConnector(process.env.DB_NAME!); - - const key: string = 'key'; - var value: string = 'insert'; - - // Add the entry to the database - await db.insert(key, value); - - // Fetch the value of the key - value = await db.read(key); - console.log(`obtained : <${key}, ${value}>`); - - // Close the database connection - await db.close(); - - // Try to update the key before opening the database connection - try { - value = 'update'; - await db.update(key, value); - } catch (error: any) { - const errorString: string = `${JSON.stringify(error)}`; - if (errorString.includes(`is not open`)) { - // open the database connection - await db.open(); - // try to update again the key - await db.update(key, value); - } else { - console.error(`re-throwing the error: ${errorString}`); - throw new Error(error); - } - } - - // Delete the key - await db.delete(key); - } catch (error) { - console.error(`Failed testing LevelDBConnector, with error: ${JSON.stringify(error)}`); - return false; - } - - console.log(`End testing LevelDBConnector for ${process.env.DB_NAME!}`); - return true; -} - -// test the event subscription operations: subscribeEvent, listEvents, deleteEvent -async function eventSubscriptionTest( - eventSub: eventsPb.EventSubscription -): Promise { - console.debug(`Start eventSubscriptionTest()`); - - try { - // Create connection to a database - const db: any = new LevelDBConnector(process.env.DB_NAME!); - - var eventMatcher: eventsPb.EventMatcher = eventSub.getEventMatcher()!; - await addEventSubscription(eventSub); - var subscriptions: Array = await lookupEventSubscriptions(eventMatcher) as Array; - - for (const subscription of subscriptions) { - if (subscription.getRequestId() == eventSub.getQuery()!.getRequestId()) { - await deleteEventSubscription(eventMatcher, subscription.getRequestId()); - break; - } - } - } catch (error) { - console.error(`Failed testing event subscription operations, with error: ${JSON.stringify(error)}`); - return false; - } - - console.debug(`End eventSubscriptionTest()`); - return true; -} - function checkIfArraysAreEqual(x: Array, y: Array): boolean { if (x == y) { return true; @@ -114,222 +29,12 @@ function checkIfArraysAreEqual(x: Array, y: Array): boolean { return true; } -async function addEventSubscription( - eventSub: eventsPb.EventSubscription -): Promise { - console.log(`adding to driver, subscription of the eventSub: ${JSON.stringify(eventSub.toObject())}`); - let db; - try { - // Create connection to a database - db = new LevelDBConnector(process.env.DB_NAME!); - await db.open(); - - // eventMatcher need to be non-null, hence apply the NaN assertion operator '!' - var eventMatcher: eventsPb.EventMatcher = eventSub.getEventMatcher()!; - // the serialized protobuf for eventMatcher below can be decoded to other formats like 'utf8' [.toString('utf8')] - const key: string = Buffer.from(eventMatcher.serializeBinary()).toString('base64'); - - // query need to be non-null, hence apply the NaN assertion operator '!' - var query: queryPb.Query = eventSub.getQuery()!; - // the serialized protobuf for query below can be decoded to other formats like 'utf8' [.toString('utf8')] - var querySerialized: string = Buffer.from(query.serializeBinary()).toString('base64'); - // serialized content of subscriptions is the value present in the key/value LevelDB corresponding to the key - var subscriptions: Array; - - try { - // fetch the current values in the DB against the given key - var subscriptionsSerialized: string = await db.read(key) as string; - subscriptions = JSON.parse(subscriptionsSerialized); - - console.debug(`subscriptions.length: ${subscriptions.length}`); - // check if the event to be subscribed is already present in the DB - for (const subscriptionSerialized of subscriptions) { - var subscription: queryPb.Query = queryPb.Query.deserializeBinary(Buffer.from(subscriptionSerialized, 'base64')); - if (checkIfArraysAreEqual(subscription.getPolicyList(), query.getPolicyList()) && - subscription.getAddress() == query.getAddress() && - subscription.getRequestingRelay() == query.getRequestingRelay() && - subscription.getRequestingNetwork() == query.getRequestingNetwork() && - subscription.getCertificate() == query.getCertificate() && - subscription.getRequestingOrg() == query.getRequestingOrg() && - subscription.getConfidential() == query.getConfidential()) { - - console.log(`found subscription for query with requestId: ${subscription.getRequestId()}`); - await db.close(); - return subscription.getRequestId(); - } - } - - // case of key being present in the list - console.debug(`eventMatcher: ${JSON.stringify(eventMatcher.toObject())} is already present in the database`); - subscriptions.push(querySerialized); - } catch (error: any) { - let errorString = `${JSON.stringify(error)}`; - if (errorString.includes('Error: NotFound:')) { - // case of read failing due to key not found - console.debug(`eventMatcher: ${JSON.stringify(eventMatcher.toObject())} is not present before in the database`); - subscriptions = new Array(); - subscriptions.push(querySerialized); - } else { - // case of read failing due to some other issue - console.error(`re-throwing error: ${errorString}`); - await db.close(); - throw new Error(error); - } - } - - console.debug(`subscriptions.length: ${subscriptions.length}`); - subscriptionsSerialized = JSON.stringify(subscriptions); - // insert the value against key in the DB (it can be the scenario of a new key addition, or update to the value of an existing key) - await db.insert(key, subscriptionsSerialized); - await db.close(); - - // TODO: register the event with fabric sdk - console.log(`end addEventSubscription() .. requestId: ${query.getRequestId()}`); - return query.getRequestId(); - - } catch(error: any) { - console.error(`Error during addEventSubscription(): ${JSON.stringify(error)}`); - await db?.close(); - throw new Error(error); - } -} - -const deleteEventSubscription = async ( - eventMatcher: eventsPb.EventMatcher, - requestId: string -): Promise => { - console.log(`deleting from driver subscription of the eventMatcher: ${JSON.stringify(eventMatcher.toObject())} with requestId: ${requestId}`); - var subscriptions: Array; - var retVal: eventsPb.EventSubscription = new eventsPb.EventSubscription(); - retVal.setEventMatcher(eventMatcher); - let db; - try { - // Create connection to a database - db = new LevelDBConnector(process.env.DB_NAME!); - await db.open(); - - const key: string = Buffer.from(eventMatcher.serializeBinary()).toString('base64'); - try { - // fetch the current values in the DB against the given key - var subscriptionsSerialized: string = await db.read(key) as string; - subscriptions = JSON.parse(subscriptionsSerialized); - - console.debug(`subscriptions.length: ${subscriptions.length}`); - var foundEntry: boolean = false; - for (var subscriptionSerialized of subscriptions) { - var subscription: queryPb.Query = queryPb.Query.deserializeBinary(Buffer.from(subscriptionSerialized, 'base64')); - if (subscription.getRequestId() == requestId) { - console.debug(`deleting the subscription (with input requestId): ${JSON.stringify(subscription.toObject())}`); - subscriptions.splice(subscriptions.indexOf(subscriptionSerialized), 1); - retVal.setQuery(subscription); - foundEntry = true; - break; - } - } - - if (!foundEntry) { - throw new Error(`event subscription with requestId: ${requestId} is not found!`); - } - } catch (error: any) { - // error could be either due to key not being present in the database or some other issue with database access - console.error(`re-throwing error: ${JSON.stringify(error)}`); - await db.close(); - throw new Error(error); - } - - console.debug(`subscriptions.length: ${subscriptions.length}`); - if (subscriptions.length == 0) { - await db.delete(key); - } else { - subscriptionsSerialized = JSON.stringify(subscriptions); - await db.insert(key, subscriptionsSerialized); - } - - await db.close(); - console.log(`end deleteEventSubscription() .. retVal: ${JSON.stringify(retVal.toObject())}`); - return retVal; - } catch(error: any) { - console.error(`Error during delete: ${JSON.stringify(error)}`); - await db?.close(); - throw new Error(error); - } -} - -async function lookupEventSubscriptions( - eventMatcher: eventsPb.EventMatcher -): Promise> { - console.info(`finding the subscriptions with eventMatcher: ${JSON.stringify(eventMatcher.toObject())}`); - var subscriptions: Array; - var returnSubscriptions: Array = new Array(); - let db; - - try { - // Create connection to a database - db = new LevelDBConnector(process.env.DB_NAME!); - await db.open(); - - var eventMatcher: eventsPb.EventMatcher = eventMatcher; - const key: string = Buffer.from(eventMatcher.serializeBinary()).toString('base64'); - - // fetch the current values in the DB against the given key - var subscriptionsSerialized: string = await db.read(key) as string; - subscriptions = JSON.parse(subscriptionsSerialized) - for (const subscriptionSerialized of subscriptions) { - var subscription: queryPb.Query = queryPb.Query.deserializeBinary(Buffer.from(subscriptionSerialized, 'base64')); - console.debug(`subscription: ${JSON.stringify(subscription.toObject())}`) - returnSubscriptions.push(subscription); - } - - console.debug(`returnSubscriptions.length: ${returnSubscriptions.length}`); - console.log(`end lookupEventSubscriptions()`); - await db.close(); - return returnSubscriptions; - - } catch (error: any) { - let errorString: string = `${JSON.stringify(error)}` - await db?.close(); - if (errorString.includes('Error: NotFound:')) { - // case of read failing due to key not found - returnSubscriptions = new Array(); - console.debug(`returnSubscriptions.length: ${returnSubscriptions.length}`); - return returnSubscriptions; - } else { - // case of read failing due to some other issue - console.error(`Error during lookup: ${JSON.stringify(error)}`); - throw new Error(error); - } - } -} - -async function signEventSubscriptionQuery( - inputQuery: queryPb.Query -): Promise { - console.log(`driver ready to provide sign on query: ${JSON.stringify(inputQuery.toObject())}`); - let signedQuery = new queryPb.Query(); - - try { - signedQuery.setPolicyList(inputQuery.getPolicyList()); - signedQuery.setAddress(inputQuery.getAddress()); - signedQuery.setRequestingRelay(inputQuery.getRequestingRelay()); - signedQuery.setRequestingOrg(inputQuery.getRequestingOrg()); - signedQuery.setRequestingNetwork(inputQuery.getRequestingNetwork()); - signedQuery.setNonce(inputQuery.getNonce()); - signedQuery.setRequestId(inputQuery.getRequestId()); - signedQuery.setConfidential(inputQuery.getConfidential()); - - const keyCert = await getDriverKeyCert() - signedQuery.setCertificate(keyCert.cert); - signedQuery.setRequestorSignature( - InteroperableHelper.signMessage( - inputQuery.getAddress() + inputQuery.getNonce(), - keyCert.key.toBytes() - ).toString("base64") - ); - return signedQuery; - } catch (error: any) { - const errorString: string = `${JSON.stringify(error)}`; - console.error(`signing query failed with error: ${errorString}`); - throw new Error(error); +// handle callback +function relayCallback(err: any, response: any) { + if (response) { + console.log(`Response: ${JSON.stringify(response.toObject())}`); + } else if (err) { + console.log(`Error: ${JSON.stringify(err)}`); } } @@ -345,11 +50,7 @@ function handlePromise(promise: Promise): Promise<[T?, Error?]> { } export { - addEventSubscription, - deleteEventSubscription, - lookupEventSubscriptions, - dbConnectionTest, - eventSubscriptionTest, - signEventSubscriptionQuery, - handlePromise + checkIfArraysAreEqual, + handlePromise, + relayCallback } \ No newline at end of file diff --git a/core/relay/.env.template b/core/relay/.env.template index 8cd7655be..df958629f 100644 --- a/core/relay/.env.template +++ b/core/relay/.env.template @@ -2,7 +2,7 @@ PATH_TO_CONFIG= RELAY_NAME=<"name" in config toml file> RELAY_PORT= DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-relay-server -DOCKER_TAG=1.3.1 +DOCKER_TAG=1.4.0 EXTERNAL_NETWORK= COMPOSE_PROJECT_NAME= COMPOSE_PROJECT_NETWORK= \ No newline at end of file From 7137b70dfe752d2f11f1250333cf5b24c4063f31 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Tue, 12 Jul 2022 16:10:31 +0530 Subject: [PATCH 039/150] version change to 1.4.1 Signed-off-by: Krishnasuri Narayanam --- common/protos-java-kt/gradle.properties | 2 +- common/protos-js/package.json | 2 +- core/drivers/corda-driver/build.gradle | 2 +- core/drivers/fabric-driver/server/server.ts | 4 +--- core/network/corda-interop-app/constants.properties | 2 +- samples/corda/corda-simple-application/constants.properties | 2 +- sdks/corda/build.gradle | 2 +- tests/network-setups/corda/scripts/get-cordapps.sh | 2 +- tests/network-setups/corda/scripts/start-nodes.sh | 2 +- 9 files changed, 9 insertions(+), 11 deletions(-) diff --git a/common/protos-java-kt/gradle.properties b/common/protos-java-kt/gradle.properties index c21b590dd..fc8963ef9 100644 --- a/common/protos-java-kt/gradle.properties +++ b/common/protos-java-kt/gradle.properties @@ -1,4 +1,4 @@ name=Interop Protos group=com.weaver -version=1.4.0 +version=1.4.1 kotlin.incremental=false diff --git a/common/protos-js/package.json b/common/protos-js/package.json index 177626667..a60a209e0 100644 --- a/common/protos-js/package.json +++ b/common/protos-js/package.json @@ -1,6 +1,6 @@ { "name": "@hyperledger-labs/weaver-protos-js", - "version": "1.4.0", + "version": "1.4.1", "description": "Interop protos for Node JS (Weaver)", "main": "index.js", "exports": { diff --git a/core/drivers/corda-driver/build.gradle b/core/drivers/corda-driver/build.gradle index 89f90f9a1..1627bff37 100644 --- a/core/drivers/corda-driver/build.gradle +++ b/core/drivers/corda-driver/build.gradle @@ -10,7 +10,7 @@ buildscript { ext.corda_version = "4.8.4" ext.corda_core_version = "4.8.4" ext.arrow_version = "0.10.4" - ext.weaver_protos_version = "1.4.0" + ext.weaver_protos_version = "1.4.1" ext.weaver_corda_version = "1.2.9" repositories { diff --git a/core/drivers/fabric-driver/server/server.ts b/core/drivers/fabric-driver/server/server.ts index 1fd74e51e..b3286f449 100644 --- a/core/drivers/fabric-driver/server/server.ts +++ b/core/drivers/fabric-driver/server/server.ts @@ -199,9 +199,7 @@ server.addService(driver_pb_grpc.DriverCommunicationService, { // gRPC response. console.log(`Sending to the relay the eventSubscription error Ack: ${JSON.stringify(ack_send_error.toObject())}`); // Sending the fabric state to the relay. - client.sendDriverSubscriptionStatus(ack_send_error, function (err: any, response: any) { - console.log(`Response: ${JSON.stringify(response.toObject())} Error: ${JSON.stringify(err)}`); - }); + client.sendDriverSubscriptionStatus(ack_send_error, relayCallback); } }).catch((error) => { console.error(`failed to get the relay client (as part of async processing) with error: ${JSON.stringify(error)}`); diff --git a/core/network/corda-interop-app/constants.properties b/core/network/corda-interop-app/constants.properties index d8993c173..3b4ec5bf3 100644 --- a/core/network/corda-interop-app/constants.properties +++ b/core/network/corda-interop-app/constants.properties @@ -11,4 +11,4 @@ slf4jVersion=1.7.25 nettyVersion=4.1.22.Final arrowVersion=0.10.4 -weaverVersion=1.4.0 +weaverVersion=1.4.1 diff --git a/samples/corda/corda-simple-application/constants.properties b/samples/corda/corda-simple-application/constants.properties index 2e55ff254..d67b889de 100644 --- a/samples/corda/corda-simple-application/constants.properties +++ b/samples/corda/corda-simple-application/constants.properties @@ -9,5 +9,5 @@ log4jVersion =2.16.0 platformVersion=10 slf4jVersion=1.7.25 nettyVersion=4.1.22.Final -weaverProtosVersion=1.4.0 +weaverProtosVersion=1.4.1 weaverCordaVersion=1.2.9 diff --git a/sdks/corda/build.gradle b/sdks/corda/build.gradle index 43a87b4b2..d17dbb9fb 100644 --- a/sdks/corda/build.gradle +++ b/sdks/corda/build.gradle @@ -13,7 +13,7 @@ buildscript { ext.corda_gradle_plugins_version = "5.0.12" ext.log4j_version = "2.16.0" ext.slf4j_version = "1.7.25" - ext.weaver_protos_version = "1.4.0" + ext.weaver_protos_version = "1.4.1" ext.weaver_corda_version = "1.2.9" dependencies { diff --git a/tests/network-setups/corda/scripts/get-cordapps.sh b/tests/network-setups/corda/scripts/get-cordapps.sh index 97863fe28..964c7cbad 100755 --- a/tests/network-setups/corda/scripts/get-cordapps.sh +++ b/tests/network-setups/corda/scripts/get-cordapps.sh @@ -4,7 +4,7 @@ directory=$(dirname $0) app=${1:-simple} local=$2 weaverCordaVersion="1.2.9" -weaverProtosVersion="1.4.0" +weaverProtosVersion="1.4.1" if [ "simple" = "$app" ]; then cordappPath=$directory/../../../../samples/corda/corda-simple-application diff --git a/tests/network-setups/corda/scripts/start-nodes.sh b/tests/network-setups/corda/scripts/start-nodes.sh index 96e85fa4f..b7814e051 100755 --- a/tests/network-setups/corda/scripts/start-nodes.sh +++ b/tests/network-setups/corda/scripts/start-nodes.sh @@ -10,7 +10,7 @@ houseTokenAppVersion="1.0" tokenVersion="1.2" weaverCordaVersion="1.2.9" -weaverProtosVersion="1.4.0" +weaverProtosVersion="1.4.1" parties="Notary PartyA PartyB PartyC" From 885f8c0402769b1b185dc34aa60da08ca6312720 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Tue, 12 Jul 2022 16:34:03 +0530 Subject: [PATCH 040/150] relay event publish stub service Signed-off-by: Krishnasuri Narayanam --- common/protos/relay/events.proto | 8 ++++ core/relay/driver/driver.rs | 4 ++ core/relay/src/main.rs | 7 ++++ .../src/services/event_publish_service.rs | 38 +++++++++++++++++++ core/relay/src/services/mod.rs | 1 + 5 files changed, 58 insertions(+) create mode 100644 core/relay/src/services/event_publish_service.rs diff --git a/common/protos/relay/events.proto b/common/protos/relay/events.proto index 8216e4655..af3ee11a1 100644 --- a/common/protos/relay/events.proto +++ b/common/protos/relay/events.proto @@ -4,6 +4,7 @@ package relay.events; import "common/ack.proto"; import "common/events.proto"; +import "common/state.proto"; option java_package = "com.weaver.protos.relay.events"; option go_package = "github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go/relay"; @@ -18,3 +19,10 @@ service EventSubscribe { // to the src-relay by calling a new endpoint in src-relay rpc SendDriverSubscriptionStatus(common.ack.Ack) returns (common.ack.Ack) {} } + +service EventPublish { + // src-driver forwards the state as part of event subscription to src-relay + rpc SendDriverState(common.state.ViewPayload) returns (common.ack.Ack) {} + // src-relay will forward the state as part of event subscription to dest-relay + rpc SendState(common.state.ViewPayload) returns (common.ack.Ack) {} +} \ No newline at end of file diff --git a/core/relay/driver/driver.rs b/core/relay/driver/driver.rs index 060efad19..6b85943bb 100644 --- a/core/relay/driver/driver.rs +++ b/core/relay/driver/driver.rs @@ -6,6 +6,7 @@ use common::query::Query; use common::events::EventSubscription; use common::state::{view_payload, Meta, meta, ViewPayload, View}; use driver::driver::driver_communication_server::{DriverCommunication, DriverCommunicationServer}; +use driver::driver::WriteExternalStateMessage; // External modules use config; @@ -185,6 +186,9 @@ impl DriverCommunication for DriverCommunicationService { }; return Ok(Response::new(signed_query)); } + async fn write_external_state(&self, request: Request) -> Result, Status> { + Err(tonic::Status::unimplemented("method not implemented")) + } } #[tokio::main] diff --git a/core/relay/src/main.rs b/core/relay/src/main.rs index d13a79de9..4a90984e2 100644 --- a/core/relay/src/main.rs +++ b/core/relay/src/main.rs @@ -2,10 +2,12 @@ use pb::networks::networks::network_server::NetworkServer; use pb::relay::datatransfer::data_transfer_server::DataTransferServer; use pb::relay::events::event_subscribe_server::EventSubscribeServer; +use pb::relay::events::event_publish_server::EventPublishServer; // Internal modules use services::data_transfer_service::DataTransferService; use services::event_subscribe_service::EventSubscribeService; +use services::event_publish_service::EventPublishService; use services::network_service::NetworkService; // External modules @@ -56,6 +58,9 @@ async fn main() -> Result<(), Box> { let event_subscribe = EventSubscribeService { config_lock: RwLock::new(settings.clone()), }; + let event_publish = EventPublishService { + config_lock: RwLock::new(settings.clone()), + }; let network = NetworkService { config_lock: RwLock::new(settings.clone()), }; @@ -70,6 +75,7 @@ async fn main() -> Result<(), Box> { .tls_config(ServerTlsConfig::new().identity(identity)) .add_service(DataTransferServer::new(relay)) .add_service(EventSubscribeServer::new(event_subscribe)) + .add_service(EventPublishServer::new(event_publish)) .add_service(NetworkServer::new(network)); server.serve(addr).await?; } else { @@ -77,6 +83,7 @@ async fn main() -> Result<(), Box> { let server = Server::builder() .add_service(DataTransferServer::new(relay)) .add_service(EventSubscribeServer::new(event_subscribe)) + .add_service(EventPublishServer::new(event_publish)) .add_service(NetworkServer::new(network)); server.serve(addr).await?; } diff --git a/core/relay/src/services/event_publish_service.rs b/core/relay/src/services/event_publish_service.rs new file mode 100644 index 000000000..231ae0a39 --- /dev/null +++ b/core/relay/src/services/event_publish_service.rs @@ -0,0 +1,38 @@ +// Internal generated modules +use crate::pb::common::ack::{ack, Ack}; +use crate::pb::common::query::Query; +use crate::pb::common::state::{request_state, view_payload, RequestState, ViewPayload}; +use crate::pb::relay::events::event_publish_client::EventPublishClient; +use crate::pb::relay::events::event_publish_server::EventPublish; +// Internal modules +use crate::db::Database; +use crate::error::Error; +use crate::relay_proto::{parse_address, LocationSegment}; +// external modules +use config; +use tokio::sync::RwLock; +use tonic::{Request, Response, Status}; + +use tonic::transport::{Certificate, Channel, ClientTlsConfig}; + +pub struct EventPublishService { + pub config_lock: RwLock, +} + +/// EventPublishService is the gRPC server implementation that handles the logic for +/// communicating event published from driver to the remote relay. +#[tonic::async_trait] +impl EventPublish for EventPublishService { + // src-driver forwards the state as part of event subscription to src-relay + async fn send_driver_state( + &self, + request: Request, + ) -> Result, Status> { + Err(tonic::Status::unimplemented("method not implemented")) + } + // src-relay will forward the state as part of event subscription to dest-relay + async fn send_state(&self, request: Request) -> Result, Status> { + Err(tonic::Status::unimplemented("method not implemented")) + } + +} \ No newline at end of file diff --git a/core/relay/src/services/mod.rs b/core/relay/src/services/mod.rs index 343fa3dc7..dde7ea28b 100644 --- a/core/relay/src/services/mod.rs +++ b/core/relay/src/services/mod.rs @@ -1,5 +1,6 @@ pub mod data_transfer_service; pub mod network_service; pub mod event_subscribe_service; +pub mod event_publish_service; pub mod helpers; pub mod types; From 69550ec425fbb55e4b2910710be1d3ae8e12b553 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Wed, 13 Jul 2022 14:25:02 +0530 Subject: [PATCH 041/150] updated lookupEventSubscriptions() to allow filtering based on partial key components Signed-off-by: Krishnasuri Narayanam --- .../fabric-driver/server/dbConnector.ts | 6 +++++ core/drivers/fabric-driver/server/events.ts | 23 +++++++++++-------- core/drivers/fabric-driver/server/tests.ts | 9 +++----- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/core/drivers/fabric-driver/server/dbConnector.ts b/core/drivers/fabric-driver/server/dbConnector.ts index e02954994..7e076172e 100644 --- a/core/drivers/fabric-driver/server/dbConnector.ts +++ b/core/drivers/fabric-driver/server/dbConnector.ts @@ -130,6 +130,12 @@ class LevelDBConnector implements DBConnector { return Promise.resolve(true); } + + async readKeys( + ):Promise { + const keys = await this.dbHandle.keys().all(); + return keys; + } } export { diff --git a/core/drivers/fabric-driver/server/events.ts b/core/drivers/fabric-driver/server/events.ts index 3d735baaa..e46332107 100644 --- a/core/drivers/fabric-driver/server/events.ts +++ b/core/drivers/fabric-driver/server/events.ts @@ -248,16 +248,21 @@ async function lookupEventSubscriptions( db = new LevelDBConnector(DB_NAME!); await db.open(); - var eventMatcher: eventsPb.EventMatcher = eventMatcher; - const key: string = Buffer.from(eventMatcher.serializeBinary()).toString('base64'); + for await (const [keySerialized, subscriptionsSerialized] of db.dbHandle.iterator()) { + var item: eventsPb.EventMatcher = eventsPb.EventMatcher.deserializeBinary(Buffer.from(keySerialized, 'base64')); + if ((eventMatcher.getEventClassId() == '*' || eventMatcher.getEventClassId() == item.getEventClassId()) && + (eventMatcher.getTransactionContractId() == '*' || eventMatcher.getTransactionContractId() == item.getTransactionContractId()) && + (eventMatcher.getTransactionLedgerId() == '*' || eventMatcher.getTransactionLedgerId() == item.getTransactionLedgerId()) && + (eventMatcher.getTransactionFunc() == '*' || eventMatcher.getTransactionFunc() == item.getTransactionFunc())) { + + subscriptions = JSON.parse(subscriptionsSerialized) + for (const subscriptionSerialized of subscriptions) { + var subscription: queryPb.Query = queryPb.Query.deserializeBinary(Buffer.from(subscriptionSerialized, 'base64')); + console.debug(`subscription: ${JSON.stringify(subscription.toObject())}`) + returnSubscriptions.push(subscription); + } + } - // fetch the current values in the DB against the given key - var subscriptionsSerialized: string = await db.read(key) as string; - subscriptions = JSON.parse(subscriptionsSerialized) - for (const subscriptionSerialized of subscriptions) { - var subscription: queryPb.Query = queryPb.Query.deserializeBinary(Buffer.from(subscriptionSerialized, 'base64')); - console.debug(`subscription: ${JSON.stringify(subscription.toObject())}`) - returnSubscriptions.push(subscription); } console.debug(`returnSubscriptions.length: ${returnSubscriptions.length}`); diff --git a/core/drivers/fabric-driver/server/tests.ts b/core/drivers/fabric-driver/server/tests.ts index 812d5fe7a..2bf67fee0 100644 --- a/core/drivers/fabric-driver/server/tests.ts +++ b/core/drivers/fabric-driver/server/tests.ts @@ -12,10 +12,10 @@ import { LevelDBConnector } from "./dbConnector" // test the LevelDB basic operations async function dbConnectionTest( ): Promise { - console.log(`Start testing LevelDBConnector for ${process.env.DB_NAME!}`) + console.log(`Start testing LevelDBConnector()`) try { // Create connection to a database - const db: any = new LevelDBConnector(process.env.DB_NAME!); + const db: any = new LevelDBConnector(""); const key: string = 'key'; var value: string = 'insert'; @@ -54,7 +54,7 @@ async function dbConnectionTest( return false; } - console.log(`End testing LevelDBConnector for ${process.env.DB_NAME!}`); + console.log(`End testing LevelDBConnector()`); return true; } @@ -65,9 +65,6 @@ async function eventSubscriptionTest( console.debug(`Start eventSubscriptionTest()`); try { - // Create connection to a database - const db: any = new LevelDBConnector(process.env.DB_NAME!); - var eventMatcher: eventsPb.EventMatcher = eventSub.getEventMatcher()!; await addEventSubscription(eventSub); var subscriptions: Array = await lookupEventSubscriptions(eventMatcher) as Array; From fdd23e82f0645fb250711a4dce62015822d87585 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Wed, 13 Jul 2022 14:31:54 +0530 Subject: [PATCH 042/150] adding identity protos to makefile Signed-off-by: Krishnasuri Narayanam --- core/drivers/fabric-driver/makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/core/drivers/fabric-driver/makefile b/core/drivers/fabric-driver/makefile index eab76e280..917caf128 100644 --- a/core/drivers/fabric-driver/makefile +++ b/core/drivers/fabric-driver/makefile @@ -13,6 +13,7 @@ protos-js: cp -r ../../../common/protos-js/corda ./protos-js/ && \ cp -r ../../../common/protos-js/driver ./protos-js/ && \ cp -r ../../../common/protos-js/fabric ./protos-js/ && \ + cp -r ../../../common/protos-js/identity ./protos-js/ && \ cp -r ../../../common/protos-js/msp ./protos-js/ && \ cp -r ../../../common/protos-js/networks ./protos-js/ && \ cp -r ../../../common/protos-js/peer ./protos-js/ && \ From aaa833adb42b946fa19c10a19966467ca6184636 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Thu, 14 Jul 2022 09:34:35 +0000 Subject: [PATCH 043/150] Updated Fabric CLI README file Signed-off-by: VRamakrishna --- samples/fabric/fabric-cli/readme.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/samples/fabric/fabric-cli/readme.md b/samples/fabric/fabric-cli/readme.md index e85337534..4c2be1e96 100644 --- a/samples/fabric/fabric-cli/readme.md +++ b/samples/fabric/fabric-cli/readme.md @@ -86,19 +86,19 @@ Then run `docker-compose up -d` to start fabric-cli container. Then run `docker exec -it fabric-cli bash`, to open interactive shell for fabric-cli, where regular fabric-cli calls can be made. Setting env is not required inside docker, as env variables are already declared, so next steps would be: -* `fabric-cli config set-file $CONFG_PATH` -* `fabric-cli configure all network1 network2`. +* `./bin/fabric-cli config set-file $CONFG_PATH` +* `./bin/fabric-cli configure all network1 network2`. ## Example Invoke To record a key `test` with the value `teststate` via the `simplestate` contract deployed on the `mychannel` channel in `network1`, run: ``` -$ fabric-cli chaincode invoke mychannel simplestate create '["test", "teststate"]'` --local-network=network1 +$ ./bin/fabric-cli chaincode invoke mychannel simplestate create '["test", "teststate"]' --local-network=network1 ``` To now query the value of the the `test` key, run: ``` -$ fabric-cli chaincode query mychannel simplestate read '["test"]' --local-network=network1 +$ ./bin/fabric-cli chaincode query mychannel simplestate read '["test"]' --local-network=network1 ``` NOTE: Use the `--help` flag with any command to view examples and usage. @@ -387,7 +387,7 @@ Below are the steps to exercise asset transfers from `network1` to `network2` us ## Events -* To suscribe for event, generate a JSON file like: [Sample Event Sub JSON](./src/data/event_sub_sample.json). Sample provided here assumes driver of `network1` is subscribing to an event of `network2`. Then run following command (and note the request id which will be used to unsubscribe or get status): +* To subscribe for an event, generate a JSON file like: [Sample Event Sub JSON](./src/data/event_sub_sample.json). Sample provided here assumes driver of `network1` is subscribing to an event of `network2`. Then run following command (and note the request id which will be used to unsubscribe or get status): ``` ./bin/fabric-cli event subscribe --network=network1 src/data/event_sub_sample.json ``` From 41c204294a17beab9bd69daa6526aeba580095ca Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Thu, 14 Jul 2022 15:19:26 +0530 Subject: [PATCH 044/150] convert the sync functions for event subscribe/unsubscribe to async Signed-off-by: Krishnasuri Narayanam --- core/drivers/fabric-driver/server/events.ts | 61 +++++++++++---------- core/drivers/fabric-driver/server/tests.ts | 8 ++- 2 files changed, 39 insertions(+), 30 deletions(-) diff --git a/core/drivers/fabric-driver/server/events.ts b/core/drivers/fabric-driver/server/events.ts index e46332107..037c6e908 100644 --- a/core/drivers/fabric-driver/server/events.ts +++ b/core/drivers/fabric-driver/server/events.ts @@ -11,23 +11,37 @@ import queryPb from '@hyperledger-labs/weaver-protos-js/common/query_pb'; import { InteroperableHelper } from '@hyperledger-labs/weaver-fabric-interop-sdk' import { getDriverKeyCert } from "./walletSetup" import { DBConnector, LevelDBConnector } from "./dbConnector" -import { checkIfArraysAreEqual, relayCallback } from "./utils" +import { checkIfArraysAreEqual, handlePromise, relayCallback } from "./utils" const DB_NAME: string = "driverdb"; -function subscribeEventHelper( +async function subscribeEventHelper( call_request: eventsPb.EventSubscription, client: events_grpc_pb.EventSubscribeClient ) { const newRequestId = call_request.getQuery()!.getRequestId(); - addEventSubscription(call_request).then((requestId) => { + const [requestId, error] = await handlePromise(addEventSubscription(call_request)); + if (error) { + const errorString: string = `error (thrown as part of async processing while storing to DB during subscribeEvent): ${JSON.stringify(error)}`; + console.error(errorString); + const ack_send_error = new ack_pb.Ack(); + ack_send_error.setRequestId(newRequestId); + ack_send_error.setMessage(errorString); + ack_send_error.setStatus(ack_pb.Ack.STATUS.ERROR); + // gRPC response. + console.log(`Sending to the relay the eventSubscription error Ack: ${JSON.stringify(ack_send_error.toObject())}`); + // Sending the fabric state to the relay. + client.sendDriverSubscriptionStatus(ack_send_error, relayCallback); + } else { const ack_send = new ack_pb.Ack(); if (newRequestId == requestId) { // event being subscribed for the first time + + // the event listener logic follows here + // set the following ack_send message below, only if the event listener logic is successful; else set to an error message + ack_send.setMessage('Event subscription is successful!'); ack_send.setStatus(ack_pb.Ack.STATUS.OK); - - // the event listener logic follows here } else { // event being subscribed already exists ack_send.setMessage(`Event subscription already exists with requestId: ${requestId}`); @@ -44,8 +58,18 @@ function subscribeEventHelper( // Sending the fabric state to the relay. client.sendDriverSubscriptionStatus(ack_send, relayCallback); - }).catch((error) => { - const errorString: string = `error (thrown as part of async processing while storing to DB during subscribeEvent): ${JSON.stringify(error)}`; + } +} + +async function unsubscribeEventHelper( + call_request: eventsPb.EventSubscription, + client: events_grpc_pb.EventSubscribeClient +) { + const newRequestId = call_request.getQuery()!.getRequestId(); + const [deletedSubscription, error] = + await handlePromise(deleteEventSubscription(call_request.getEventMatcher()!, newRequestId)); + if (error) { + const errorString: string = `error (thrown as part of async processing while deleting from DB during unsubscribeEvent): ${JSON.stringify(error)}`; console.error(errorString); const ack_send_error = new ack_pb.Ack(); ack_send_error.setRequestId(newRequestId); @@ -55,15 +79,7 @@ function subscribeEventHelper( console.log(`Sending to the relay the eventSubscription error Ack: ${JSON.stringify(ack_send_error.toObject())}`); // Sending the fabric state to the relay. client.sendDriverSubscriptionStatus(ack_send_error, relayCallback); - }); -} - -function unsubscribeEventHelper( - call_request: eventsPb.EventSubscription, - client: events_grpc_pb.EventSubscribeClient -) { - const newRequestId = call_request.getQuery()!.getRequestId(); - deleteEventSubscription(call_request.getEventMatcher()!, newRequestId).then((deletedSubscription: eventsPb.EventSubscription) => { + } else { const ack_send = new ack_pb.Ack(); // event got unsubscribed @@ -80,18 +96,7 @@ function unsubscribeEventHelper( // Sending the fabric state to the relay. client.sendDriverSubscriptionStatus(ack_send, relayCallback); - }).catch((error) => { - const errorString: string = `error (thrown as part of async processing while deleting from DB during unsubscribeEvent): ${JSON.stringify(error)}`; - console.error(errorString); - const ack_send_error = new ack_pb.Ack(); - ack_send_error.setRequestId(newRequestId); - ack_send_error.setMessage(errorString); - ack_send_error.setStatus(ack_pb.Ack.STATUS.ERROR); - // gRPC response. - console.log(`Sending to the relay the eventSubscription error Ack: ${JSON.stringify(ack_send_error.toObject())}`); - // Sending the fabric state to the relay. - client.sendDriverSubscriptionStatus(ack_send_error, relayCallback); - }); + } } async function addEventSubscription( diff --git a/core/drivers/fabric-driver/server/tests.ts b/core/drivers/fabric-driver/server/tests.ts index 2bf67fee0..10e7de299 100644 --- a/core/drivers/fabric-driver/server/tests.ts +++ b/core/drivers/fabric-driver/server/tests.ts @@ -7,15 +7,16 @@ import eventsPb from "@hyperledger-labs/weaver-protos-js/common/events_pb"; import queryPb from '@hyperledger-labs/weaver-protos-js/common/query_pb'; import { addEventSubscription, deleteEventSubscription, lookupEventSubscriptions } from "./events" -import { LevelDBConnector } from "./dbConnector" +import { LevelDBConnector, DBConnector } from "./dbConnector" // test the LevelDB basic operations async function dbConnectionTest( ): Promise { console.log(`Start testing LevelDBConnector()`) + let db: DBConnector; try { // Create connection to a database - const db: any = new LevelDBConnector(""); + db = new LevelDBConnector(""); const key: string = 'key'; var value: string = 'insert'; @@ -43,14 +44,17 @@ async function dbConnectionTest( await db.update(key, value); } else { console.error(`re-throwing the error: ${errorString}`); + db.close(); throw new Error(error); } } // Delete the key await db.delete(key); + await db.close(); } catch (error) { console.error(`Failed testing LevelDBConnector, with error: ${JSON.stringify(error)}`); + db.close(); return false; } From bf79b2f77973ea366bb4ce40b444ef06f12b07e1 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Thu, 14 Jul 2022 19:17:12 +0000 Subject: [PATCH 045/150] Added basic listener support in Fabric driver Added logic to start either a block or a contract listener depending on the content of an event subscription. Upgraded Fabric package dependencies in Fabric driver. Added event emission from 'simplestate' chaincode to test. Made minor fixes in Fabric interop SDK and Fabric CLI config files. Signed-off-by: VRamakrishna --- core/drivers/fabric-driver/package-local.json | 4 +- core/drivers/fabric-driver/package.json | 4 +- .../patches/fabric-network+2.2.0.patch | 105 ------------ .../patches/fabric-network+2.2.13.patch | 45 +++++ .../fabric-driver/server/dbConnector.ts | 4 +- core/drivers/fabric-driver/server/events.ts | 26 +-- .../fabric-driver/server/fabric-code.ts | 47 ++++-- core/drivers/fabric-driver/server/listener.ts | 156 ++++++++++++++++++ core/drivers/fabric-driver/server/server.ts | 10 +- .../fabric-cli/src/data/event_sub_sample.json | 2 +- samples/fabric/simplestate/simplestate.go | 11 +- sdks/fabric/interoperation-node-sdk/makefile | 1 + 12 files changed, 269 insertions(+), 146 deletions(-) delete mode 100644 core/drivers/fabric-driver/patches/fabric-network+2.2.0.patch create mode 100644 core/drivers/fabric-driver/patches/fabric-network+2.2.13.patch create mode 100644 core/drivers/fabric-driver/server/listener.ts diff --git a/core/drivers/fabric-driver/package-local.json b/core/drivers/fabric-driver/package-local.json index 9b546fc51..4f451da47 100644 --- a/core/drivers/fabric-driver/package-local.json +++ b/core/drivers/fabric-driver/package-local.json @@ -29,8 +29,8 @@ "dotenv": "^8.2.0", "eslint-config-prettier": "^6.11.0", "eslint-plugin-prettier": "^3.1.4", - "fabric-ca-client": "2.2.5", - "fabric-network": "2.2.5", + "fabric-ca-client": "^2.2.8", + "fabric-network": "^2.2.8", "level": "^8.0.0" }, "devDependencies": { diff --git a/core/drivers/fabric-driver/package.json b/core/drivers/fabric-driver/package.json index 59ef2e5b4..72d81c918 100644 --- a/core/drivers/fabric-driver/package.json +++ b/core/drivers/fabric-driver/package.json @@ -29,8 +29,8 @@ "dotenv": "^8.2.0", "eslint-config-prettier": "^6.11.0", "eslint-plugin-prettier": "^3.1.4", - "fabric-ca-client": "2.2.5", - "fabric-network": "2.2.5", + "fabric-ca-client": "^2.2.8", + "fabric-network": "^2.2.8", "level": "^8.0.0" }, "devDependencies": { diff --git a/core/drivers/fabric-driver/patches/fabric-network+2.2.0.patch b/core/drivers/fabric-driver/patches/fabric-network+2.2.0.patch deleted file mode 100644 index d471cf43d..000000000 --- a/core/drivers/fabric-driver/patches/fabric-network+2.2.0.patch +++ /dev/null @@ -1,105 +0,0 @@ -diff --git a/node_modules/fabric-network/lib/transaction.d.ts b/node_modules/fabric-network/lib/transaction.d.ts -index 1255f26..9344f1d 100644 ---- a/node_modules/fabric-network/lib/transaction.d.ts -+++ b/node_modules/fabric-network/lib/transaction.d.ts -@@ -84,7 +84,7 @@ export declare class Transaction { - * @throws {module:fabric-network.TimeoutError} If the transaction was successfully submitted to the orderer but - * timed out before a commit event was received from peers. - */ -- submit(...args: string[]): Promise; -+ submit(...args: string[]): Promise; - /** - * Evaluate a transaction function and return its results. - * The transaction function will be evaluated on the endorsing peers but -diff --git a/node_modules/fabric-network/lib/transaction.js b/node_modules/fabric-network/lib/transaction.js -index b8a1bdc..8177482 100644 ---- a/node_modules/fabric-network/lib/transaction.js -+++ b/node_modules/fabric-network/lib/transaction.js -@@ -172,7 +172,7 @@ class Transaction { - logger.debug('%s - build and send the endorsement', method); - // build the outbound request along with getting a new transactionId - // from the identity context -- endorsement.build(this.identityContext, proposalBuildRequest); -+ const proposal = endorsement.build(this.identityContext, proposalBuildRequest); - endorsement.sign(this.identityContext); - // ------- S E N D P R O P O S A L - // This is where the request gets sent to the peers -@@ -209,42 +209,42 @@ class Transaction { - const proposalResponse = await endorsement.send(proposalSendRequest); - try { - const result = getResponsePayload(proposalResponse); -- // ------- E V E N T M O N I T O R -- const eventHandler = this.eventHandlerStrategyFactory(endorsement.getTransactionId(), this.contract.network); -- await eventHandler.startListening(); -- const commit = endorsement.newCommit(); -- commit.build(this.identityContext); -- commit.sign(this.identityContext); -- // ----- C O M M I T E N D O R S E M E N T -- // this is where the endorsement results are sent to the orderer -- const commitSendRequest = {}; -- if (isInteger(transactionOptions.commitTimeout)) { -- commitSendRequest.requestTimeout = transactionOptions.commitTimeout * 1000; // in ms; -- } -- if (proposalSendRequest.handler) { -- logger.debug('%s - use discovery to commit', method); -- commitSendRequest.handler = proposalSendRequest.handler; -- } -- else { -- logger.debug('%s - use the orderers assigned to the channel', method); -- commitSendRequest.targets = channel.getCommitters(); -- } -- // by now we should have a discovery handler or use the target orderers -- // that have been assigned from the channel to perform the commit -- const commitResponse = await commit.send(commitSendRequest); -- logger.debug('%s - commit response %j', method, commitResponse); -- if (commitResponse.status !== 'SUCCESS') { -- const msg = `Failed to commit transaction %${endorsement.getTransactionId()}, orderer response status: ${commitResponse.status}`; -- logger.error('%s - %s', method, msg); -- eventHandler.cancelListening(); -- throw new Error(msg); -- } -- else { -- logger.debug('%s - successful commit', method); -- } -- logger.debug('%s - wait for the transaction to be committed on the peer', method); -- await eventHandler.waitForEvents(); -- return result; -+ // // ------- E V E N T M O N I T O R -+ // const eventHandler = this.eventHandlerStrategyFactory(endorsement.getTransactionId(), this.contract.network); -+ // await eventHandler.startListening(); -+ // const commit = endorsement.newCommit(); -+ // commit.build(this.identityContext); -+ // commit.sign(this.identityContext); -+ // // ----- C O M M I T E N D O R S E M E N T -+ // // this is where the endorsement results are sent to the orderer -+ // const commitSendRequest = {}; -+ // if (isInteger(transactionOptions.commitTimeout)) { -+ // commitSendRequest.requestTimeout = transactionOptions.commitTimeout * 1000; // in ms; -+ // } -+ // if (proposalSendRequest.handler) { -+ // logger.debug('%s - use discovery to commit', method); -+ // commitSendRequest.handler = proposalSendRequest.handler; -+ // } -+ // else { -+ // logger.debug('%s - use the orderers assigned to the channel', method); -+ // commitSendRequest.targets = channel.getCommitters(); -+ // } -+ // // by now we should have a discovery handler or use the target orderers -+ // // that have been assigned from the channel to perform the commit -+ // const commitResponse = await commit.send(commitSendRequest); -+ // logger.debug('%s - commit response %j', method, commitResponse); -+ // if (commitResponse.status !== 'SUCCESS') { -+ // const msg = `Failed to commit transaction %${endorsement.getTransactionId()}, orderer response status: ${commitResponse.status}`; -+ // logger.error('%s - %s', method, msg); -+ // eventHandler.cancelListening(); -+ // throw new Error(msg); -+ // } -+ // else { -+ // logger.debug('%s - successful commit', method); -+ // } -+ // logger.debug('%s - wait for the transaction to be committed on the peer', method); -+ // await eventHandler.waitForEvents(); -+ return {result, proposalResponse: proposalResponse.responses, proposal: proposal} ; - } - catch (err) { - err.responses = proposalResponse.responses; diff --git a/core/drivers/fabric-driver/patches/fabric-network+2.2.13.patch b/core/drivers/fabric-driver/patches/fabric-network+2.2.13.patch new file mode 100644 index 000000000..a9d6f0a57 --- /dev/null +++ b/core/drivers/fabric-driver/patches/fabric-network+2.2.13.patch @@ -0,0 +1,45 @@ +diff --git a/node_modules/fabric-network/lib/transaction.d.ts b/node_modules/fabric-network/lib/transaction.d.ts +index 47ce1d1..3c65e83 100644 +--- a/node_modules/fabric-network/lib/transaction.d.ts ++++ b/node_modules/fabric-network/lib/transaction.d.ts +@@ -100,7 +100,7 @@ export declare class Transaction { + * @throws {module:fabric-network.TransactionError} If the transaction committed with an unsuccessful transaction + * validation code, and so did not update the ledger. + */ +- submit(...args: string[]): Promise; ++ submit(...args: string[]): Promise; + /** + * Evaluate a transaction function and return its results. + * The transaction function will be evaluated on the endorsing peers but +diff --git a/node_modules/fabric-network/lib/transaction.js b/node_modules/fabric-network/lib/transaction.js +index 24e66f2..12dbb43 100644 +--- a/node_modules/fabric-network/lib/transaction.js ++++ b/node_modules/fabric-network/lib/transaction.js +@@ -216,7 +216,7 @@ class Transaction { + logger.debug('%s - build and send the endorsement', method); + // build the outbound request along with getting a new transactionId + // from the identity context +- endorsement.build(this.identityContext, proposalBuildRequest); ++ const proposal = endorsement.build(this.identityContext, proposalBuildRequest); + endorsement.sign(this.identityContext); + // ------- S E N D P R O P O S A L + // This is where the request gets sent to the peers +@@ -253,7 +253,7 @@ class Transaction { + const proposalResponse = await endorsement.send(proposalSendRequest); + try { + const result = getResponsePayload(proposalResponse); +- // ------- E V E N T M O N I T O R ++ /* // ------- E V E N T M O N I T O R + const eventHandler = this.eventHandlerStrategyFactory(endorsement.getTransactionId(), this.contract.network); + await eventHandler.startListening(); + const commit = endorsement.newCommit(); +@@ -288,7 +288,8 @@ class Transaction { + } + logger.debug('%s - wait for the transaction to be committed on the peer', method); + await eventHandler.waitForEvents(); +- return result; ++ return result;*/ ++ return {result, proposalResponse: proposalResponse.responses, proposal: proposal} ; + } + catch (err) { + err.responses = proposalResponse.responses; diff --git a/core/drivers/fabric-driver/server/dbConnector.ts b/core/drivers/fabric-driver/server/dbConnector.ts index 7e076172e..313f1f0af 100644 --- a/core/drivers/fabric-driver/server/dbConnector.ts +++ b/core/drivers/fabric-driver/server/dbConnector.ts @@ -84,7 +84,7 @@ class LevelDBConnector implements DBConnector { console.debug(`read() got value: ${JSON.stringify(value)}`) } catch (error: any) { console.error(`failed to read key ${JSON.stringify(key)} with error: ${JSON.stringify(error)}`); - throw new Error(error); + throw error; } return value; @@ -141,4 +141,4 @@ class LevelDBConnector implements DBConnector { export { DBConnector, LevelDBConnector -} \ No newline at end of file +} diff --git a/core/drivers/fabric-driver/server/events.ts b/core/drivers/fabric-driver/server/events.ts index 037c6e908..a286669b4 100644 --- a/core/drivers/fabric-driver/server/events.ts +++ b/core/drivers/fabric-driver/server/events.ts @@ -8,16 +8,18 @@ import ack_pb from '@hyperledger-labs/weaver-protos-js/common/ack_pb'; import eventsPb from '@hyperledger-labs/weaver-protos-js/common/events_pb'; import events_grpc_pb from '@hyperledger-labs/weaver-protos-js/relay/events_grpc_pb'; import queryPb from '@hyperledger-labs/weaver-protos-js/common/query_pb'; -import { InteroperableHelper } from '@hyperledger-labs/weaver-fabric-interop-sdk' -import { getDriverKeyCert } from "./walletSetup" -import { DBConnector, LevelDBConnector } from "./dbConnector" -import { checkIfArraysAreEqual, handlePromise, relayCallback } from "./utils" +import { InteroperableHelper } from '@hyperledger-labs/weaver-fabric-interop-sdk'; +import { getDriverKeyCert } from "./walletSetup"; +import { DBConnector, LevelDBConnector } from "./dbConnector"; +import { checkIfArraysAreEqual, handlePromise, relayCallback } from "./utils"; +import { registerListenerForEventSubscription } from "./listener"; const DB_NAME: string = "driverdb"; async function subscribeEventHelper( call_request: eventsPb.EventSubscription, - client: events_grpc_pb.EventSubscribeClient + client: events_grpc_pb.EventSubscribeClient, + network_name: string, ) { const newRequestId = call_request.getQuery()!.getRequestId(); const [requestId, error] = await handlePromise(addEventSubscription(call_request)); @@ -38,6 +40,7 @@ async function subscribeEventHelper( // event being subscribed for the first time // the event listener logic follows here + await registerListenerForEventSubscription(call_request, network_name); // set the following ack_send message below, only if the event listener logic is successful; else set to an error message ack_send.setMessage('Event subscription is successful!'); @@ -63,7 +66,8 @@ async function subscribeEventHelper( async function unsubscribeEventHelper( call_request: eventsPb.EventSubscription, - client: events_grpc_pb.EventSubscribeClient + client: events_grpc_pb.EventSubscribeClient, + network_name: string, ) { const newRequestId = call_request.getQuery()!.getRequestId(); const [deletedSubscription, error] = @@ -148,8 +152,8 @@ async function addEventSubscription( console.debug(`eventMatcher: ${JSON.stringify(eventMatcher.toObject())} is already present in the database`); subscriptions.push(querySerialized); } catch (error: any) { - let errorString = `${JSON.stringify(error)}`; - if (errorString.includes('Error: NotFound:')) { + let errorString = error.toString(); + if (errorString.includes('Error: NotFound:') || errorString.includes('LEVEL_NOT_FOUND')) { // case of read failing due to key not found console.debug(`eventMatcher: ${JSON.stringify(eventMatcher.toObject())} is not present before in the database`); subscriptions = new Array(); @@ -276,9 +280,9 @@ async function lookupEventSubscriptions( return returnSubscriptions; } catch (error: any) { - let errorString: string = `${JSON.stringify(error)}` + let errorString: string = error.toString(); await db?.close(); - if (errorString.includes('Error: NotFound:')) { + if (errorString.includes('Error: NotFound:') || errorString.includes('LEVEL_NOT_FOUND')) { // case of read failing due to key not found returnSubscriptions = new Array(); console.debug(`returnSubscriptions.length: ${returnSubscriptions.length}`); @@ -330,4 +334,4 @@ export { deleteEventSubscription, lookupEventSubscriptions, signEventSubscriptionQuery -} \ No newline at end of file +} diff --git a/core/drivers/fabric-driver/server/fabric-code.ts b/core/drivers/fabric-driver/server/fabric-code.ts index a3ed64029..a0246f56b 100644 --- a/core/drivers/fabric-driver/server/fabric-code.ts +++ b/core/drivers/fabric-driver/server/fabric-code.ts @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { Gateway, Wallets } from 'fabric-network'; +import { Gateway, Wallets, Network } from 'fabric-network'; import { Endorser } from 'fabric-common'; import * as path from 'path'; import * as fs from 'fs'; @@ -21,22 +21,13 @@ const parseAddress = (address: string) => { const fabricArgs = addressList[2].split(':'); return { channel: fabricArgs[0], contract: fabricArgs[1], ccFunc: fabricArgs[2], args: fabricArgs.slice(3) }; }; + const getWallet = (walletPath: string) => { return Wallets.newFileSystemWallet(walletPath); }; -// Main invoke function wtih logic to handle policy and turn response from chaincode into a view. -// 1. Prepare credentials/gateway for communicating with fabric network -// 2. prepare info required for invoke (address/policy) -// 3. Set the endorser list for the transaction, this enforces that the list provided will endorse the proposed transaction -// 4. Prepare the view and return. -async function invoke( - query: query_pb.Query, - networkName: string, - requestingNetwork: string, - requestingOrg: string, -): Promise { - console.log('Running invoke on fabric network'); +// Get a handle to a network gateway using existing wallet credentials +const getNetworkGateway = async (networkName: string): Promise => { try { // load the network configuration const ccpPath = process.env.CONNECTION_PROFILE @@ -51,8 +42,8 @@ async function invoke( } const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8')); const config = getConfig(); - // 1. Prepare credentials/gateway for communicating with fabric network - // Create a new file system based wallet for managing identities. + + // Create a new file system-based wallet for managing identities. const walletPath = path.join(process.cwd(), `wallet-${networkName}`); const userName = config.relay.name; const wallet = await getWallet(walletPath); @@ -70,8 +61,30 @@ async function invoke( identity: `${userName}`, discovery: { enabled: true, asLocalhost: process.env.local === 'false' ? false : true }, }); - // 2. prepare info required for invoke (address/policy) + return gateway; + } catch (error) { + console.error(`Failed to instantiate network (channel): ${error}`); + throw error; + } +} + +// Main invoke function wtih logic to handle policy and turn response from chaincode into a view. +// 1. Prepare credentials/gateway for communicating with fabric network +// 2. Prepare info required for invoke (address/policy) +// 3. Set the endorser list for the transaction, this enforces that the list provided will endorse the proposed transaction +// 4. Prepare the view and return. +async function invoke( + query: query_pb.Query, + networkName: string, + requestingNetwork: string, + requestingOrg: string, +): Promise { + console.log('Running invoke on fabric network'); + try { + // 1. Prepare credentials/gateway for communicating with fabric network + const gateway = await getNetworkGateway(networkName); + // 2. Prepare info required for invoke (address/policy) const parsedAddress = parseAddress(query.getAddress()); // Get the network (channel) our contract is deployed to. console.log(parsedAddress.channel); @@ -150,4 +163,4 @@ async function invoke( } } -export default invoke; +export { getNetworkGateway, invoke }; diff --git a/core/drivers/fabric-driver/server/listener.ts b/core/drivers/fabric-driver/server/listener.ts new file mode 100644 index 000000000..e267ffec7 --- /dev/null +++ b/core/drivers/fabric-driver/server/listener.ts @@ -0,0 +1,156 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as $protobuf from "protobufjs"; +import ByteBuffer from 'bytebuffer'; +import * as fabproto6 from 'fabric-protos'; +import { Gateway, Wallets, Network, Contract, BlockListener, ContractListener } from 'fabric-network'; +import query_pb from '@hyperledger-labs/weaver-protos-js/common/query_pb'; +import events_pb from '@hyperledger-labs/weaver-protos-js/common/events_pb'; +import { lookupEventSubscriptions } from './events'; +import { getNetworkGateway } from './fabric-code'; + +let channelBlockListenerMap = new Map(); +let channelContractListenerMap = new Map(); + +function getChannelContractKey(channelId: string, contractId: string) { + return channelId + ':' + contractId; +} + +/** + * Register a block listener with a callback + **/ +const initBlockEventListenerForChannel = async ( + network: Network, + channelId: string, +): Promise => { + const listener: BlockListener = async (event) => { + // Parse the block data; typically there is only one element in this array but we will interate over it just to be safe + const blockData = ((event.blockData as fabproto6.common.Block).data as fabproto6.common.BlockData).data; + blockData.forEach((item) => { + const payload = Object.values(item)[Object.keys(item).indexOf('payload')]; + const payloadData = Object.values(payload)[Object.keys(payload).indexOf('data')]; + const transactions = payloadData.actions; + // Iterate through the transaction list + transactions.forEach(async (transaction: any) => { + // Get transaction chaincode ID + const chaincodeId = transaction.payload.chaincode_proposal_payload.input.chaincode_spec.chaincode_id.name; + if (transaction.payload.chaincode_proposal_payload.input.chaincode_spec.input.args.length > 0) { + // Get transaction function name: first argument according to convention + const chaincodeFunc = transaction.payload.chaincode_proposal_payload.input.chaincode_spec.input.args[0].toString(); + console.log('Trying to find match for channel', channelId, 'chaincode', chaincodeId, 'function', chaincodeFunc); + // Find all matching event subscriptions stored in the database + let eventMatcher = new events_pb.EventMatcher(); + eventMatcher.setEventType(events_pb.EventType.LEDGER_STATE); + eventMatcher.setEventClassId('*'); + eventMatcher.setTransactionLedgerId(channelId); + eventMatcher.setTransactionContractId(chaincodeId); + eventMatcher.setTransactionFunc(chaincodeFunc); + const eventSubscriptionQueries = await lookupEventSubscriptions(eventMatcher); + // Iterate through the view requests in the matching event subscriptions + eventSubscriptionQueries.forEach((eventSubscriptionQuery: query_pb.Query) => { + // Trigger proof collection + // Package view and send to relay + console.log('Generating view and collecting proof for event subscription'); + }) + } + }) + }) + }; + await network.addBlockListener(listener); + channelBlockListenerMap.set(channelId, listener); + console.log('Added block listener for channel', channelId); +} + +/** + * Register a block listener with a callback + **/ +const initContractEventListener = ( + contract: Contract, + channelId: string, + chaincodeId: string, +): void => { + const listener: ContractListener = async (event) => { + console.log('Received event:', event.eventName); + if (event.eventName === 'CreateSimpleState') { + if (event.payload) + console.log('Event payload:', event.payload.toString()); + } + console.log('Trying to find match for channel', channelId, 'chaincode', chaincodeId, 'event name', event.eventName); + // Find all matching event subscriptions stored in the database + let eventMatcher = new events_pb.EventMatcher(); + eventMatcher.setEventType(events_pb.EventType.LEDGER_STATE); + eventMatcher.setEventClassId(event.eventName); + eventMatcher.setTransactionLedgerId(channelId); + eventMatcher.setTransactionContractId(chaincodeId); + eventMatcher.setTransactionFunc('*'); + const eventSubscriptionQueries = await lookupEventSubscriptions(eventMatcher); + // Iterate through the view requests in the matching event subscriptions + eventSubscriptionQueries.forEach((eventSubscriptionQuery: query_pb.Query) => { + // Trigger proof collection + // Package view and send to relay + console.log('Generating view and collecting proof for event subscription'); + }) + }; + contract.addContractListener(listener); + channelContractListenerMap.set(getChannelContractKey(channelId, chaincodeId), listener); + console.log('Added contract listener for channel', channelId, 'and contract', chaincodeId); +} + +/** + * Record event subscription in the driver database. + * Start an appropriate listener if there is currently none for the channel this event subscription refers to. + **/ +const registerListenerForEventSubscription = async ( + eventSubscription: events_pb.EventSubscription, + networkName: string, +): Promise => { + // Lookup the event suscription from the database. + const eventMatcher = eventSubscription.getEventMatcher(); + if (!eventMatcher) { + throw new Error('No event matcher in event subscription'); + } + + /*const queries: Array = await lookupEventSubscriptions(eventMatcher); + if (!queries || queries.length === 0) { + // If it doesn't exist, record it. + const requestId: string = await addEventSubscription(eventSubscription); + if (!requestId) { + throw new Error('Unable to record event subscription in storage'); + } + }*/ + + const channelId = eventMatcher.getTransactionLedgerId(); + const gateway = await getNetworkGateway(networkName); + const network = await gateway.getNetwork(channelId); + // Check if the event_class_id is specified in the event matcher field. + if (eventMatcher.getEventClassId().length === 0) { + // Check if there is an active block listener for the channel specified in this event subscription. + if (!channelBlockListenerMap.has(channelId)) { + // Start a block listener. + await initBlockEventListenerForChannel(network, channelId); + } + } else { + // Check if there is an active contract listener for the contract function specified in this event subscription. + const contractId = eventMatcher.getTransactionContractId(); + const contract = network.getContract(contractId); + if (!channelContractListenerMap.has(getChannelContractKey(channelId, contractId))) { + // Start a contract listener. + initContractEventListener(contract, channelId, contractId); + } + } +} + +/** + * Load event subscriptions from the driver database. + * Start a listener for each channel from which one of the subscribed events originate. + **/ +const loadEventSubscriptionsFromStorage = ( +): void => { + // TODO +} + +export { registerListenerForEventSubscription, loadEventSubscriptionsFromStorage }; diff --git a/core/drivers/fabric-driver/server/server.ts b/core/drivers/fabric-driver/server/server.ts index b3286f449..37bd76039 100644 --- a/core/drivers/fabric-driver/server/server.ts +++ b/core/drivers/fabric-driver/server/server.ts @@ -14,7 +14,7 @@ import driver_pb_grpc from '@hyperledger-labs/weaver-protos-js/driver/driver_grp import datatransfer_grpc_pb from '@hyperledger-labs/weaver-protos-js/relay/datatransfer_grpc_pb'; import events_grpc_pb from '@hyperledger-labs/weaver-protos-js/relay/events_grpc_pb'; import state_pb from '@hyperledger-labs/weaver-protos-js/common/state_pb'; -import invoke from './fabric-code'; +import { invoke, getNetworkGateway } from './fabric-code'; import 'dotenv/config'; import { walletSetup } from './walletSetup'; import { subscribeEventHelper, unsubscribeEventHelper, signEventSubscriptionQuery } from "./events" @@ -183,12 +183,12 @@ server.addService(driver_pb_grpc.DriverCommunicationService, { const subscriptionOp: eventsPb.EventSubOperation = call.request.getOperation(); console.log(`newRequestId: ${newRequestId}`); try { - if (process.env.MOCK === 'false') { + if (process.env.MOCK !== 'true') { getEventSubscriptionRelayClient().then((client) => { if (subscriptionOp == eventsPb.EventSubOperation.SUBSCRIBE) { - subscribeEventHelper(call.request, client); + subscribeEventHelper(call.request, client, process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1'); } else if (subscriptionOp == eventsPb.EventSubOperation.UNSUBSCRIBE) { - unsubscribeEventHelper(call.request, client); + unsubscribeEventHelper(call.request, client, process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1'); } else { const errorString: string = `Error: subscribe operation ${subscriptionOp.toString()} not supported`; console.error(errorString); @@ -296,4 +296,4 @@ if (process.env.DRIVER_TLS === 'true') { server.start(); }); }); -} \ No newline at end of file +} diff --git a/samples/fabric/fabric-cli/src/data/event_sub_sample.json b/samples/fabric/fabric-cli/src/data/event_sub_sample.json index 350e382ce..b6bfc8cb1 100644 --- a/samples/fabric/fabric-cli/src/data/event_sub_sample.json +++ b/samples/fabric/fabric-cli/src/data/event_sub_sample.json @@ -4,7 +4,7 @@ "eventClassId": "", "transactionLedgerId": "mychannel", "transactionContractId": "simplestate", - "transactionFunc": "Create" + "transactionFunc": "create" }, "event_publication_spec": { "ccArgs": [], diff --git a/samples/fabric/simplestate/simplestate.go b/samples/fabric/simplestate/simplestate.go index d744654f6..18f6c06c7 100755 --- a/samples/fabric/simplestate/simplestate.go +++ b/samples/fabric/simplestate/simplestate.go @@ -37,7 +37,16 @@ func (s *SmartContract) Create(ctx contractapi.TransactionContextInterface, key bytes := []byte(value) fmt.Printf("Create called. Key: %s Value: %s\n", key, value) - return ctx.GetStub().PutState(key, bytes) + err := ctx.GetStub().PutState(key, bytes) + if err != nil { + return err + } else { + err = ctx.GetStub().SetEvent("CreateSimpleState", []byte(key + ":" + value)) + if err != nil { + fmt.Printf("Unable to set 'CreateSimpleState' event: %+v\n", err) + } + } + return nil } // Read returns the value of the entry with the specified key diff --git a/sdks/fabric/interoperation-node-sdk/makefile b/sdks/fabric/interoperation-node-sdk/makefile index ea214c6a0..a7b635e82 100644 --- a/sdks/fabric/interoperation-node-sdk/makefile +++ b/sdks/fabric/interoperation-node-sdk/makefile @@ -14,6 +14,7 @@ build-local: cp -r ../../../common/protos-js/networks ./protos-js/ && \ cp -r ../../../common/protos-js/peer ./protos-js/ && \ cp -r ../../../common/protos-js/relay ./protos-js/ && \ + cp -r ../../../common/protos-js/identity ./protos-js/ && \ cp -r ../../../common/protos-js/package.json ./protos-js/ (cp package.json package-remote.json && \ cp package-local.json package.json && \ From 4afbfc45c4100afb24ee260ce697518ed4367689 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Thu, 14 Jul 2022 20:24:37 +0000 Subject: [PATCH 046/150] Added proof collection logic to Fabric driver event listeners Signed-off-by: VRamakrishna --- .../fabric-driver/server/fabric-code.ts | 8 +-- core/drivers/fabric-driver/server/listener.ts | 56 ++++++++------- core/drivers/fabric-driver/server/server.ts | 69 +++++++++++-------- 3 files changed, 76 insertions(+), 57 deletions(-) diff --git a/core/drivers/fabric-driver/server/fabric-code.ts b/core/drivers/fabric-driver/server/fabric-code.ts index a0246f56b..3a070dbdf 100644 --- a/core/drivers/fabric-driver/server/fabric-code.ts +++ b/core/drivers/fabric-driver/server/fabric-code.ts @@ -76,8 +76,6 @@ const getNetworkGateway = async (networkName: string): Promise => { async function invoke( query: query_pb.Query, networkName: string, - requestingNetwork: string, - requestingOrg: string, ): Promise { console.log('Running invoke on fabric network'); try { @@ -100,12 +98,14 @@ async function invoke( const identities = query.getPolicyList(); console.log('Message: ', query.getAddress() + query.getNonce(), identities); + const cert = Certificate.fromPEM(Buffer.from(query.getCertificate())); + const orgName = cert.issuer.organizationName; console.log( 'CC ARGS', parsedAddress.ccFunc, ...parsedAddress.args, - requestingNetwork, - requestingOrg, + query.getRequestingNetwork(), + query.getRequestingOrg() ? query.getRequestingOrg() : orgName, query.getCertificate(), query.getRequestorSignature(), query.getAddress() + query.getNonce(), diff --git a/core/drivers/fabric-driver/server/listener.ts b/core/drivers/fabric-driver/server/listener.ts index e267ffec7..562b24de5 100644 --- a/core/drivers/fabric-driver/server/listener.ts +++ b/core/drivers/fabric-driver/server/listener.ts @@ -11,7 +11,9 @@ import { Gateway, Wallets, Network, Contract, BlockListener, ContractListener } import query_pb from '@hyperledger-labs/weaver-protos-js/common/query_pb'; import events_pb from '@hyperledger-labs/weaver-protos-js/common/events_pb'; import { lookupEventSubscriptions } from './events'; -import { getNetworkGateway } from './fabric-code'; +import { invoke, getNetworkGateway } from './fabric-code'; +import { getRelayClient, packageViewAndSendToRelay } from './server'; +import { handlePromise } from './utils'; let channelBlockListenerMap = new Map(); let channelContractListenerMap = new Map(); @@ -25,6 +27,7 @@ function getChannelContractKey(channelId: string, contractId: string) { **/ const initBlockEventListenerForChannel = async ( network: Network, + networkName: string, channelId: string, ): Promise => { const listener: BlockListener = async (event) => { @@ -51,10 +54,19 @@ const initBlockEventListenerForChannel = async ( eventMatcher.setTransactionFunc(chaincodeFunc); const eventSubscriptionQueries = await lookupEventSubscriptions(eventMatcher); // Iterate through the view requests in the matching event subscriptions - eventSubscriptionQueries.forEach((eventSubscriptionQuery: query_pb.Query) => { + eventSubscriptionQueries.forEach(async (eventSubscriptionQuery: query_pb.Query) => { + console.log('Generating view and collecting proof for channel', channelId, 'chaincode', chaincodeId); // Trigger proof collection - // Package view and send to relay - console.log('Generating view and collecting proof for event subscription'); + const [result, invokeError] = await handlePromise( + invoke( + eventSubscriptionQuery, + networkName, + ), + ); + if (!invokeError) { + // Package view and send to relay + packageViewAndSendToRelay(eventSubscriptionQuery, result, getRelayClient()); + } }) } }) @@ -70,16 +82,12 @@ const initBlockEventListenerForChannel = async ( **/ const initContractEventListener = ( contract: Contract, + networkName: string, channelId: string, chaincodeId: string, ): void => { const listener: ContractListener = async (event) => { - console.log('Received event:', event.eventName); - if (event.eventName === 'CreateSimpleState') { - if (event.payload) - console.log('Event payload:', event.payload.toString()); - } - console.log('Trying to find match for channel', channelId, 'chaincode', chaincodeId, 'event name', event.eventName); + console.log('Trying to find match for channel', channelId, 'chaincode', chaincodeId, 'event class', event.eventName); // Find all matching event subscriptions stored in the database let eventMatcher = new events_pb.EventMatcher(); eventMatcher.setEventType(events_pb.EventType.LEDGER_STATE); @@ -89,10 +97,21 @@ const initContractEventListener = ( eventMatcher.setTransactionFunc('*'); const eventSubscriptionQueries = await lookupEventSubscriptions(eventMatcher); // Iterate through the view requests in the matching event subscriptions - eventSubscriptionQueries.forEach((eventSubscriptionQuery: query_pb.Query) => { + eventSubscriptionQueries.forEach(async (eventSubscriptionQuery: query_pb.Query) => { // Trigger proof collection // Package view and send to relay - console.log('Generating view and collecting proof for event subscription'); + console.log('Generating view and collecting proof for event class', event.eventName, 'channel', channelId, 'chaincode', chaincodeId); + // Trigger proof collection + const [result, invokeError] = await handlePromise( + invoke( + eventSubscriptionQuery, + networkName, + ), + ); + if (!invokeError) { + // Package view and send to relay + packageViewAndSendToRelay(eventSubscriptionQuery, result, getRelayClient()); + } }) }; contract.addContractListener(listener); @@ -114,15 +133,6 @@ const registerListenerForEventSubscription = async ( throw new Error('No event matcher in event subscription'); } - /*const queries: Array = await lookupEventSubscriptions(eventMatcher); - if (!queries || queries.length === 0) { - // If it doesn't exist, record it. - const requestId: string = await addEventSubscription(eventSubscription); - if (!requestId) { - throw new Error('Unable to record event subscription in storage'); - } - }*/ - const channelId = eventMatcher.getTransactionLedgerId(); const gateway = await getNetworkGateway(networkName); const network = await gateway.getNetwork(channelId); @@ -131,7 +141,7 @@ const registerListenerForEventSubscription = async ( // Check if there is an active block listener for the channel specified in this event subscription. if (!channelBlockListenerMap.has(channelId)) { // Start a block listener. - await initBlockEventListenerForChannel(network, channelId); + await initBlockEventListenerForChannel(network, networkName, channelId); } } else { // Check if there is an active contract listener for the contract function specified in this event subscription. @@ -139,7 +149,7 @@ const registerListenerForEventSubscription = async ( const contract = network.getContract(contractId); if (!channelContractListenerMap.has(getChannelContractKey(channelId, contractId))) { // Start a contract listener. - initContractEventListener(contract, channelId, contractId); + initContractEventListener(contract, networkName, channelId, contractId); } } } diff --git a/core/drivers/fabric-driver/server/server.ts b/core/drivers/fabric-driver/server/server.ts index 37bd76039..50ce31e62 100644 --- a/core/drivers/fabric-driver/server/server.ts +++ b/core/drivers/fabric-driver/server/server.ts @@ -7,8 +7,8 @@ import fs from 'fs'; import { Server, ServerCredentials, credentials } from '@grpc/grpc-js'; import ack_pb from '@hyperledger-labs/weaver-protos-js/common/ack_pb'; -import fabricView from '@hyperledger-labs/weaver-protos-js/fabric/view_data_pb'; import query_pb from '@hyperledger-labs/weaver-protos-js/common/query_pb'; +import fabricView from '@hyperledger-labs/weaver-protos-js/fabric/view_data_pb'; import eventsPb, { EventMatcher } from '@hyperledger-labs/weaver-protos-js/common/events_pb'; import driver_pb_grpc from '@hyperledger-labs/weaver-protos-js/driver/driver_grpc_pb'; import datatransfer_grpc_pb from '@hyperledger-labs/weaver-protos-js/relay/datatransfer_grpc_pb'; @@ -18,7 +18,6 @@ import { invoke, getNetworkGateway } from './fabric-code'; import 'dotenv/config'; import { walletSetup } from './walletSetup'; import { subscribeEventHelper, unsubscribeEventHelper, signEventSubscriptionQuery } from "./events" -import { Certificate } from '@fidm/x509'; import * as path from 'path'; import { handlePromise, relayCallback } from './utils'; import { dbConnectionTest, eventSubscriptionTest } from "./tests" @@ -61,16 +60,30 @@ function mockCommunication(query: query_pb.Query) { }, 3000); } -// Handles communication with fabric network and sends resulting data to the relay -const fabricCommunication = async (query: query_pb.Query, networkName: string) => { - // Query object from requestor - console.log('query', query.getRequestId()); +// Package view and send to relay +export function packageViewAndSendToRelay( + query: query_pb.Query, + viewData: fabricView.FabricView, + client: datatransfer_grpc_pb.DataTransferClient, +) { + const meta = new state_pb.Meta(); + meta.setTimestamp(new Date().toISOString()); + meta.setProofType('Notarization'); + meta.setSerializationFormat('STRING'); + meta.setProtocol(state_pb.Meta.Protocol.FABRIC); + const view = new state_pb.View(); + view.setMeta(meta); + view.setData(viewData ? viewData.serializeBinary() : Buffer.from('')); + const viewPayload = new state_pb.ViewPayload(); + viewPayload.setView(view); + viewPayload.setRequestId(query.getRequestId()); - // Client created using the relay_endpoint in the env. - // TODO: need credentials here to ensure the local relay is only communicating with local drivers - if (!process.env.RELAY_ENDPOINT) { - throw new Error('RELAY_ENDPOINT is not set.'); - } + console.log('Sending state'); + // Sending the fabric state to the relay. + client.sendDriverState(viewPayload, relayCallback); +} + +export function getRelayClient() { let client; if (process.env.RELAY_TLS === 'true') { if (!(process.env.RELAY_TLSCA_CERT_PATH && fs.existsSync(process.env.RELAY_TLSCA_CERT_PATH))) { @@ -87,15 +100,25 @@ const fabricCommunication = async (query: query_pb.Query, networkName: string) = credentials.createInsecure() ); } - const cert = Certificate.fromPEM(Buffer.from(query.getCertificate())); - const orgName = cert.issuer.organizationName; + return client; +} + +// Handles communication with fabric network and sends resulting data to the relay +const fabricCommunication = async (query: query_pb.Query, networkName: string) => { + // Query object from requestor + console.log('query', query.getRequestId()); + + // Client created using the relay_endpoint in the env. + // TODO: need credentials here to ensure the local relay is only communicating with local drivers + if (!process.env.RELAY_ENDPOINT) { + throw new Error('RELAY_ENDPOINT is not set.'); + } + const client = getRelayClient(); // Invokes the fabric network const [result, invokeError] = await handlePromise( invoke( query, networkName, - query.getRequestingNetwork(), - query.getRequestingOrg() ? query.getRequestingOrg() : orgName, ), ); if (invokeError) { @@ -109,21 +132,7 @@ const fabricCommunication = async (query: query_pb.Query, networkName: string) = // Process response from invoke to send to relay console.log('Result of fabric invoke', result); console.log('Sending state'); - const meta = new state_pb.Meta(); - meta.setTimestamp(new Date().toISOString()); - meta.setProofType('Notarization'); - meta.setSerializationFormat('STRING'); - meta.setProtocol(state_pb.Meta.Protocol.FABRIC); - const view = new state_pb.View(); - view.setMeta(meta); - view.setData(result ? result.serializeBinary() : Buffer.from('')); - const viewPayload = new state_pb.ViewPayload(); - viewPayload.setView(view); - viewPayload.setRequestId(query.getRequestId()); - - console.log('Sending state'); - // Sending the fabric state to the relay. - client.sendDriverState(viewPayload, relayCallback); + packageViewAndSendToRelay(query, result, client); } }; From d803b4073a7ad9eb3f8c7d9d72b5b06b87719183 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Mon, 18 Jul 2022 20:54:30 +0000 Subject: [PATCH 047/150] Fixed event listening and CLI triggering logic Channelling events from Fabric driver to the right relay endpoint. Fixed error handling logic in promise-based functions. Managing database access contention in Fabric driver using retry and backoff logic. Updated event subsciption Fabric CLI logic to take multiple subscriptions as input. Added missing text in a tutorial doc. Signed-off-by: VRamakrishna --- .../fabric-driver/server/dbConnector.ts | 12 ++-- core/drivers/fabric-driver/server/events.ts | 2 +- core/drivers/fabric-driver/server/listener.ts | 52 +++++++++++++---- core/drivers/fabric-driver/server/server.ts | 38 ++++++++++--- .../external/user-stories/global-trade.md | 1 + samples/fabric/fabric-cli/readme.md | 6 +- .../src/commands/event/subscribe.ts | 46 ++++++++------- .../src/commands/event/unsubscribe.ts | 48 ++++++++-------- .../fabric-cli/src/data/event_sub_sample.json | 57 +++++++++++++------ 9 files changed, 170 insertions(+), 92 deletions(-) diff --git a/core/drivers/fabric-driver/server/dbConnector.ts b/core/drivers/fabric-driver/server/dbConnector.ts index 313f1f0af..7b7bbe237 100644 --- a/core/drivers/fabric-driver/server/dbConnector.ts +++ b/core/drivers/fabric-driver/server/dbConnector.ts @@ -55,7 +55,7 @@ class LevelDBConnector implements DBConnector { await this.dbHandle.open(); } catch (error: any) { console.error(`failed to open database connection with error: ${JSON.stringify(error)}`); - throw new Error(error); + return Promise.reject(JSON.stringify(error)); } return Promise.resolve(true); @@ -69,7 +69,7 @@ class LevelDBConnector implements DBConnector { await this.dbHandle.put(key, value); } catch (error: any) { console.error(`failed to insert key ${JSON.stringify(key)} with error: ${JSON.stringify(error)}`); - throw new Error(error); + return Promise.reject(JSON.stringify(error)); } return Promise.resolve(true); @@ -84,7 +84,7 @@ class LevelDBConnector implements DBConnector { console.debug(`read() got value: ${JSON.stringify(value)}`) } catch (error: any) { console.error(`failed to read key ${JSON.stringify(key)} with error: ${JSON.stringify(error)}`); - throw error; + return Promise.reject(JSON.stringify(error)); } return value; @@ -98,7 +98,7 @@ class LevelDBConnector implements DBConnector { await this.dbHandle.put(key, value); } catch (error: any) { console.error(`failed to update key ${JSON.stringify(key)} with error: ${JSON.stringify(error)}`); - throw new Error(error); + return Promise.reject(JSON.stringify(error)); } return true; @@ -113,7 +113,7 @@ class LevelDBConnector implements DBConnector { await this.dbHandle.del(key); } catch (error: any) { console.error(`failed to delete key ${JSON.stringify(key)} with error: ${JSON.stringify(error)}`); - throw new Error(error); + return Promise.reject(JSON.stringify(error)); } return value; @@ -125,7 +125,7 @@ class LevelDBConnector implements DBConnector { await this.dbHandle.close(); } catch (error: any) { console.error(`failed to close database connection with error: ${JSON.stringify(error)}`); - throw new Error(error); + return Promise.reject(JSON.stringify(error)); } return Promise.resolve(true); diff --git a/core/drivers/fabric-driver/server/events.ts b/core/drivers/fabric-driver/server/events.ts index a286669b4..976292b49 100644 --- a/core/drivers/fabric-driver/server/events.ts +++ b/core/drivers/fabric-driver/server/events.ts @@ -289,7 +289,7 @@ async function lookupEventSubscriptions( return returnSubscriptions; } else { // case of read failing due to some other issue - console.error(`Error during lookup: ${JSON.stringify(error)}`); + console.error(`Error during lookup: ${errorString}`); throw new Error(error); } } diff --git a/core/drivers/fabric-driver/server/listener.ts b/core/drivers/fabric-driver/server/listener.ts index 562b24de5..a26c68f0b 100644 --- a/core/drivers/fabric-driver/server/listener.ts +++ b/core/drivers/fabric-driver/server/listener.ts @@ -12,8 +12,8 @@ import query_pb from '@hyperledger-labs/weaver-protos-js/common/query_pb'; import events_pb from '@hyperledger-labs/weaver-protos-js/common/events_pb'; import { lookupEventSubscriptions } from './events'; import { invoke, getNetworkGateway } from './fabric-code'; -import { getRelayClient, packageViewAndSendToRelay } from './server'; -import { handlePromise } from './utils'; +import { getRelayClientForEventPublish, packageView } from './server'; +import { handlePromise, relayCallback } from './utils'; let channelBlockListenerMap = new Map(); let channelContractListenerMap = new Map(); @@ -48,11 +48,23 @@ const initBlockEventListenerForChannel = async ( // Find all matching event subscriptions stored in the database let eventMatcher = new events_pb.EventMatcher(); eventMatcher.setEventType(events_pb.EventType.LEDGER_STATE); - eventMatcher.setEventClassId('*'); + eventMatcher.setEventClassId(''); // Only match subscriptions where class ID is not specified eventMatcher.setTransactionLedgerId(channelId); eventMatcher.setTransactionContractId(chaincodeId); eventMatcher.setTransactionFunc(chaincodeFunc); - const eventSubscriptionQueries = await lookupEventSubscriptions(eventMatcher); + let eventSubscriptionQueries; + for (let i = 0 ; i < 10 ; i++) { + try{ + eventSubscriptionQueries = await lookupEventSubscriptions(eventMatcher); + break; + } catch(error) { + let errorString: string = error.toString(); + if (!errorString.includes('LEVEL_LOCKED')) { // Check if contention was preventing DB access + throw(error); + } + await new Promise(f => setTimeout(f, 2000)); // Sleep 2 seconds + } + } // Iterate through the view requests in the matching event subscriptions eventSubscriptionQueries.forEach(async (eventSubscriptionQuery: query_pb.Query) => { console.log('Generating view and collecting proof for channel', channelId, 'chaincode', chaincodeId); @@ -65,7 +77,12 @@ const initBlockEventListenerForChannel = async ( ); if (!invokeError) { // Package view and send to relay - packageViewAndSendToRelay(eventSubscriptionQuery, result, getRelayClient()); + const client = getRelayClientForEventPublish(); + const viewPayload = packageView(eventSubscriptionQuery, result); + + console.log('Sending block event'); + // Sending the Fabric event to the relay. + client.sendDriverState(viewPayload, relayCallback); } }) } @@ -78,7 +95,7 @@ const initBlockEventListenerForChannel = async ( } /** - * Register a block listener with a callback + * Register a chaincode event listener with a callback **/ const initContractEventListener = ( contract: Contract, @@ -95,11 +112,21 @@ const initContractEventListener = ( eventMatcher.setTransactionLedgerId(channelId); eventMatcher.setTransactionContractId(chaincodeId); eventMatcher.setTransactionFunc('*'); - const eventSubscriptionQueries = await lookupEventSubscriptions(eventMatcher); + let eventSubscriptionQueries; + for (let i = 0 ; i < 10 ; i++) { + try{ + eventSubscriptionQueries = await lookupEventSubscriptions(eventMatcher); + break; + } catch(error) { + let errorString: string = error.toString(); + if (!errorString.includes('LEVEL_LOCKED')) { // Check if contention was preventing DB access + throw(error); + } + await new Promise(f => setTimeout(f, 2000)); // Sleep 2 seconds + } + } // Iterate through the view requests in the matching event subscriptions eventSubscriptionQueries.forEach(async (eventSubscriptionQuery: query_pb.Query) => { - // Trigger proof collection - // Package view and send to relay console.log('Generating view and collecting proof for event class', event.eventName, 'channel', channelId, 'chaincode', chaincodeId); // Trigger proof collection const [result, invokeError] = await handlePromise( @@ -110,7 +137,12 @@ const initContractEventListener = ( ); if (!invokeError) { // Package view and send to relay - packageViewAndSendToRelay(eventSubscriptionQuery, result, getRelayClient()); + const client = getRelayClientForEventPublish(); + const viewPayload = packageView(eventSubscriptionQuery, result); + + console.log('Sending contract event'); + // Sending the Fabric event to the relay. + client.sendDriverState(viewPayload, relayCallback); } }) }; diff --git a/core/drivers/fabric-driver/server/server.ts b/core/drivers/fabric-driver/server/server.ts index 50ce31e62..8803325be 100644 --- a/core/drivers/fabric-driver/server/server.ts +++ b/core/drivers/fabric-driver/server/server.ts @@ -61,10 +61,9 @@ function mockCommunication(query: query_pb.Query) { } // Package view and send to relay -export function packageViewAndSendToRelay( +export function packageView( query: query_pb.Query, viewData: fabricView.FabricView, - client: datatransfer_grpc_pb.DataTransferClient, ) { const meta = new state_pb.Meta(); meta.setTimestamp(new Date().toISOString()); @@ -77,13 +76,10 @@ export function packageViewAndSendToRelay( const viewPayload = new state_pb.ViewPayload(); viewPayload.setView(view); viewPayload.setRequestId(query.getRequestId()); - - console.log('Sending state'); - // Sending the fabric state to the relay. - client.sendDriverState(viewPayload, relayCallback); + return viewPayload; } -export function getRelayClient() { +export function getRelayClientForQueryResponse() { let client; if (process.env.RELAY_TLS === 'true') { if (!(process.env.RELAY_TLSCA_CERT_PATH && fs.existsSync(process.env.RELAY_TLSCA_CERT_PATH))) { @@ -103,6 +99,26 @@ export function getRelayClient() { return client; } +export function getRelayClientForEventPublish() { + let client; + if (process.env.RELAY_TLS === 'true') { + if (!(process.env.RELAY_TLSCA_CERT_PATH && fs.existsSync(process.env.RELAY_TLSCA_CERT_PATH))) { + throw new Error("Missing or invalid RELAY_TLSCA_CERT_PATH: " + process.env.RELAY_TLSCA_CERT_PATH); + } + const rootCert = fs.readFileSync(process.env.RELAY_TLSCA_CERT_PATH); + client = new events_grpc_pb.EventPublishClient( + process.env.RELAY_ENDPOINT, + credentials.createSsl(rootCert) + ); + } else { + client = new events_grpc_pb.EventPublishClient( + process.env.RELAY_ENDPOINT, + credentials.createInsecure() + ); + } + return client; +} + // Handles communication with fabric network and sends resulting data to the relay const fabricCommunication = async (query: query_pb.Query, networkName: string) => { // Query object from requestor @@ -113,7 +129,6 @@ const fabricCommunication = async (query: query_pb.Query, networkName: string) = if (!process.env.RELAY_ENDPOINT) { throw new Error('RELAY_ENDPOINT is not set.'); } - const client = getRelayClient(); // Invokes the fabric network const [result, invokeError] = await handlePromise( invoke( @@ -121,6 +136,7 @@ const fabricCommunication = async (query: query_pb.Query, networkName: string) = networkName, ), ); + const client = getRelayClientForQueryResponse(); if (invokeError) { console.log('Invoke Error'); const errorViewPayload = new state_pb.ViewPayload(); @@ -132,7 +148,11 @@ const fabricCommunication = async (query: query_pb.Query, networkName: string) = // Process response from invoke to send to relay console.log('Result of fabric invoke', result); console.log('Sending state'); - packageViewAndSendToRelay(query, result, client); + const viewPayload: state_pb.ViewPayload = packageView(query, result); + + console.log('Sending state'); + // Sending the fabric state to the relay. + client.sendDriverState(viewPayload, relayCallback); } }; diff --git a/docs/docs/external/user-stories/global-trade.md b/docs/docs/external/user-stories/global-trade.md index f7fa58384..2e2cb9d4d 100644 --- a/docs/docs/external/user-stories/global-trade.md +++ b/docs/docs/external/user-stories/global-trade.md @@ -103,5 +103,6 @@ The data-sharing interoperation steps are as follows: - _Step 11_: The trade logistics network fetches tracking information indicating delivery of goods to the warehouse before permitting a consignment to be created. - _Step 16_: The trade finance network fetches a B/L from the trade logistics network before permitting the seller's bank to register a payment request. - _Step 18_: This is a recurring step, in each instance of which the food tracking network fetches location and condition information for a given consignment from the trade logistics network, and does not permit the confirmation of consignment delivery and the integrity of the goods within until the shipment reaches its destination and its condition meets the required standard. +- _Step 19_: The trade finance network gets confirmation of payment (from buyer's account to seller's account) from the payments network. To summarize, internationally traded goods can be tracked from a farm in one country to a retailer in another, the goods can be exported and shipped with all regulations complied with, financial guarantees can be put in place to safeguard the trading parties, and cross-border payments can be processed seamlessly and in a trustworthy manner. But this requires a combination of private blockchain networks willing to share data with each other and also have the ability to verify the authenticity of received data. We hope this scenario makes the motivation for data-sharing interoperation mechanisms perfectly clear. diff --git a/samples/fabric/fabric-cli/readme.md b/samples/fabric/fabric-cli/readme.md index 4c2be1e96..82bf805b0 100644 --- a/samples/fabric/fabric-cli/readme.md +++ b/samples/fabric/fabric-cli/readme.md @@ -387,15 +387,15 @@ Below are the steps to exercise asset transfers from `network1` to `network2` us ## Events -* To subscribe for an event, generate a JSON file like: [Sample Event Sub JSON](./src/data/event_sub_sample.json). Sample provided here assumes driver of `network1` is subscribing to an event of `network2`. Then run following command (and note the request id which will be used to unsubscribe or get status): +* To subscribe for one or more events, generate a JSON file like: [Sample Event Sub JSON](./src/data/event_sub_sample.json), which contains an array of event subscription specifications. The samples provided here assume that the driver of `network1` is subscribing to an event of `network2`. Then run the following command (and note the request id which will be used to unsubscribe or get status): ``` ./bin/fabric-cli event subscribe --network=network1 src/data/event_sub_sample.json ``` -* To unsuscribe for event, use the same JSON file as in subscription like: [Sample Event Sub JSON](./src/data/event_sub_sample.json). Then run following command: +* To unsuscribe for one or more events, use the same JSON file as in subscription like: [Sample Event Sub JSON](./src/data/event_sub_sample.json). Then run the following command: ``` ./bin/fabric-cli event unsubscribe --network=network1 --request-id= src/data/event_sub_sample.json ``` -* To get status for event subscription, run following command: +* To get the status of an event subscription, run the following command: ``` ./bin/fabric-cli event get-subscription-status --network=network1 --request-id= ``` diff --git a/samples/fabric/fabric-cli/src/commands/event/subscribe.ts b/samples/fabric/fabric-cli/src/commands/event/subscribe.ts index bb7f711f9..8da2e7ff3 100644 --- a/samples/fabric/fabric-cli/src/commands/event/subscribe.ts +++ b/samples/fabric/fabric-cli/src/commands/event/subscribe.ts @@ -73,7 +73,6 @@ const command: GluegunCommand = { const user = options['user'] const filepath = path.resolve(array[0]) - const data = JSON.parse(fs.readFileSync(filepath).toString()) const netConfig = getNetworkConfig(networkName) if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { @@ -98,28 +97,31 @@ const command: GluegunCommand = { throw new Error(`Error getting key and cert ${keyCertError}`) } - const eventMatcher = EventsManager.createEventMatcher(data.event_matcher) - const eventPublicationSpec = EventsManager.createEventPublicationSpec(data.event_publication_spec) - - try { - const response = await EventsManager.subscribeRemoteEvent( - contract, - eventMatcher, - eventPublicationSpec, - networkName, - netConfig.mspId, - netConfig.relayEndpoint, - { address: data.view_address, Sign: true }, - keyCert - ) - - if (response.getStatus() == EventSubscriptionState.STATUS.SUBSCRIBED) { - console.log("Event Subscription Status Success with requestId:", response.getRequestId()) - } else { - console.log("Unknown error") + const data = JSON.parse(fs.readFileSync(filepath).toString()) + for (let i = 0 ; i < data.length ; i++) { + const eventMatcher = EventsManager.createEventMatcher(data[i].event_matcher) + const eventPublicationSpec = EventsManager.createEventPublicationSpec(data[i].event_publication_spec) + + try { + const response = await EventsManager.subscribeRemoteEvent( + contract, + eventMatcher, + eventPublicationSpec, + networkName, + netConfig.mspId, + netConfig.relayEndpoint, + { address: data[i].view_address, Sign: true }, + keyCert + ) + + if (response.getStatus() == EventSubscriptionState.STATUS.SUBSCRIBED) { + console.log("Event Subscription Status Success with requestId:", response.getRequestId()) + } else { + console.log("Unknown error") + } + } catch(e) { + console.log("Error: ", e.toString()) } - } catch(e) { - console.log("Error: ", e.toString()) } process.exit() diff --git a/samples/fabric/fabric-cli/src/commands/event/unsubscribe.ts b/samples/fabric/fabric-cli/src/commands/event/unsubscribe.ts index a2e39268b..351ec29da 100644 --- a/samples/fabric/fabric-cli/src/commands/event/unsubscribe.ts +++ b/samples/fabric/fabric-cli/src/commands/event/unsubscribe.ts @@ -84,7 +84,6 @@ const command: GluegunCommand = { const requestId = options['request-id'] const filepath = path.resolve(array[0]) - const data = JSON.parse(fs.readFileSync(filepath).toString()) const netConfig = getNetworkConfig(networkName) if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { @@ -109,29 +108,32 @@ const command: GluegunCommand = { throw new Error(`Error getting key and cert ${keyCertError}`) } - const eventMatcher = EventsManager.createEventMatcher(data.event_matcher) - const eventPublicationSpec = EventsManager.createEventPublicationSpec(data.event_publication_spec) - - try { - const response = await EventsManager.unsubscribeRemoteEvent( - contract, - eventMatcher, - eventPublicationSpec, - requestId, - networkName, - netConfig.mspId, - netConfig.relayEndpoint, - { address: data.view_address, Sign: true }, - keyCert - ) - - if (response.getStatus() == EventSubscriptionState.STATUS.UNSUBSCRIBED) { - console.log("Event Unsubscription Success for requestId:", response.getRequestId()) - } else { - console.log("Unknown error") + const data = JSON.parse(fs.readFileSync(filepath).toString()) + for (let i = 0 ; i < data.length ; i++) { + const eventMatcher = EventsManager.createEventMatcher(data[i].event_matcher) + const eventPublicationSpec = EventsManager.createEventPublicationSpec(data[i].event_publication_spec) + + try { + const response = await EventsManager.unsubscribeRemoteEvent( + contract, + eventMatcher, + eventPublicationSpec, + requestId, + networkName, + netConfig.mspId, + netConfig.relayEndpoint, + { address: data[i].view_address, Sign: true }, + keyCert + ) + + if (response.getStatus() == EventSubscriptionState.STATUS.UNSUBSCRIBED) { + console.log("Event Unsubscription Success for requestId:", response.getRequestId()) + } else { + console.log("Unknown error") + } + } catch(e) { + console.log("Error: ", e.toString()) } - } catch(e) { - console.log("Error: ", e.toString()) } process.exit() diff --git a/samples/fabric/fabric-cli/src/data/event_sub_sample.json b/samples/fabric/fabric-cli/src/data/event_sub_sample.json index b6bfc8cb1..7addd80cc 100644 --- a/samples/fabric/fabric-cli/src/data/event_sub_sample.json +++ b/samples/fabric/fabric-cli/src/data/event_sub_sample.json @@ -1,19 +1,40 @@ -{ - "event_matcher": { - "eventType": 1, - "eventClassId": "", - "transactionLedgerId": "mychannel", - "transactionContractId": "simplestate", - "transactionFunc": "create" +[ + { + "event_matcher": { + "eventType": 1, + "eventClassId": "", + "transactionLedgerId": "mychannel", + "transactionContractId": "simplestate", + "transactionFunc": "create" + }, + "event_publication_spec": { + "ccArgs": [], + "chaincodeId": "simplestate", + "driverId": "network1", + "ccFunc": "Create", + "channelId": "mychannel", + "replaceArgIndex": "0" + }, + "view_address": "localhost:9083/network2/mychannel:simplestate:Read:a", + "confidential": false }, - "event_publication_spec": { - "ccArgs": [], - "chaincodeId": "simplestate", - "driverId": "network1", - "ccFunc": "Create", - "channelId": "mychannel", - "replaceArgIndex": "0" - }, - "view_address": "localhost:9083/network2/mychannel:simplestate:Read:a", - "confidential": false -} + { + "event_matcher": { + "eventType": 1, + "eventClassId": "CreateSimpleState", + "transactionLedgerId": "mychannel", + "transactionContractId": "simplestate", + "transactionFunc": "create" + }, + "event_publication_spec": { + "ccArgs": [], + "chaincodeId": "simplestate", + "driverId": "network1", + "ccFunc": "Create", + "channelId": "mychannel", + "replaceArgIndex": "0" + }, + "view_address": "localhost:9083/network2/mychannel:simplestate:Read:a", + "confidential": false + } +] From 334162055935291121b72b96b91a2ac7d9c3cb0c Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Tue, 19 Jul 2022 20:09:48 +0000 Subject: [PATCH 048/150] Fabric driver event code error management and refactoring Also added counters for active listeners for tracking. Signed-off-by: VRamakrishna --- core/drivers/fabric-driver/server/events.ts | 19 +++--- .../fabric-driver/server/fabric-code.ts | 22 ++++++- core/drivers/fabric-driver/server/listener.ts | 38 +++++++---- core/drivers/fabric-driver/server/server.ts | 65 +------------------ core/drivers/fabric-driver/server/utils.ts | 51 ++++++++++++++- 5 files changed, 108 insertions(+), 87 deletions(-) diff --git a/core/drivers/fabric-driver/server/events.ts b/core/drivers/fabric-driver/server/events.ts index 976292b49..ea25f2e42 100644 --- a/core/drivers/fabric-driver/server/events.ts +++ b/core/drivers/fabric-driver/server/events.ts @@ -36,15 +36,16 @@ async function subscribeEventHelper( client.sendDriverSubscriptionStatus(ack_send_error, relayCallback); } else { const ack_send = new ack_pb.Ack(); - if (newRequestId == requestId) { - // event being subscribed for the first time - - // the event listener logic follows here - await registerListenerForEventSubscription(call_request, network_name); - // set the following ack_send message below, only if the event listener logic is successful; else set to an error message - - ack_send.setMessage('Event subscription is successful!'); - ack_send.setStatus(ack_pb.Ack.STATUS.OK); + if (newRequestId == requestId) { // event being subscribed for the first time + // Start an appropriate type of event listener for this event subscription if one is not already active + const [listenerHandle, error] = await handlePromise(registerListenerForEventSubscription(call_request, network_name)); + if (error) { + ack_send.setMessage('Event subscription succeeded but listener registration failed'); + ack_send.setStatus(ack_pb.Ack.STATUS.ERROR); + } else { + ack_send.setMessage('Event subscription is successful!'); + ack_send.setStatus(ack_pb.Ack.STATUS.OK); + } } else { // event being subscribed already exists ack_send.setMessage(`Event subscription already exists with requestId: ${requestId}`); diff --git a/core/drivers/fabric-driver/server/fabric-code.ts b/core/drivers/fabric-driver/server/fabric-code.ts index 3a070dbdf..d443d3726 100644 --- a/core/drivers/fabric-driver/server/fabric-code.ts +++ b/core/drivers/fabric-driver/server/fabric-code.ts @@ -13,6 +13,7 @@ import query_pb from '@hyperledger-labs/weaver-protos-js/common/query_pb'; import view_data from '@hyperledger-labs/weaver-protos-js/fabric/view_data_pb'; import proposalResponse from '@hyperledger-labs/weaver-protos-js/peer/proposal_response_pb'; import interopPayload from '@hyperledger-labs/weaver-protos-js/common/interop_payload_pb'; +import state_pb from '@hyperledger-labs/weaver-protos-js/common/state_pb'; import { Certificate } from '@fidm/x509'; import { getConfig } from './walletSetup'; @@ -163,4 +164,23 @@ async function invoke( } } -export { getNetworkGateway, invoke }; +// Package view and send to relay +function packageFabricView( + query: query_pb.Query, + viewData: view_data.FabricView, +) { + const meta = new state_pb.Meta(); + meta.setTimestamp(new Date().toISOString()); + meta.setProofType('Notarization'); + meta.setSerializationFormat('STRING'); + meta.setProtocol(state_pb.Meta.Protocol.FABRIC); + const view = new state_pb.View(); + view.setMeta(meta); + view.setData(viewData ? viewData.serializeBinary() : Buffer.from('')); + const viewPayload = new state_pb.ViewPayload(); + viewPayload.setView(view); + viewPayload.setRequestId(query.getRequestId()); + return viewPayload; +} + +export { getNetworkGateway, invoke, packageFabricView }; diff --git a/core/drivers/fabric-driver/server/listener.ts b/core/drivers/fabric-driver/server/listener.ts index a26c68f0b..9313d571f 100644 --- a/core/drivers/fabric-driver/server/listener.ts +++ b/core/drivers/fabric-driver/server/listener.ts @@ -11,12 +11,13 @@ import { Gateway, Wallets, Network, Contract, BlockListener, ContractListener } import query_pb from '@hyperledger-labs/weaver-protos-js/common/query_pb'; import events_pb from '@hyperledger-labs/weaver-protos-js/common/events_pb'; import { lookupEventSubscriptions } from './events'; -import { invoke, getNetworkGateway } from './fabric-code'; -import { getRelayClientForEventPublish, packageView } from './server'; -import { handlePromise, relayCallback } from './utils'; +import { invoke, getNetworkGateway, packageFabricView } from './fabric-code'; +import { handlePromise, relayCallback, getRelayClientForEventPublish } from './utils'; let channelBlockListenerMap = new Map(); +let channelBlockListenerCount = new Map(); let channelContractListenerMap = new Map(); +let channelContractListenerCount = new Map(); function getChannelContractKey(channelId: string, contractId: string) { return channelId + ':' + contractId; @@ -29,7 +30,7 @@ const initBlockEventListenerForChannel = async ( network: Network, networkName: string, channelId: string, -): Promise => { +): Promise => { const listener: BlockListener = async (event) => { // Parse the block data; typically there is only one element in this array but we will interate over it just to be safe const blockData = ((event.blockData as fabproto6.common.Block).data as fabproto6.common.BlockData).data; @@ -67,7 +68,7 @@ const initBlockEventListenerForChannel = async ( } // Iterate through the view requests in the matching event subscriptions eventSubscriptionQueries.forEach(async (eventSubscriptionQuery: query_pb.Query) => { - console.log('Generating view and collecting proof for channel', channelId, 'chaincode', chaincodeId); + console.log('Generating view and collecting proof for channel', channelId, 'chaincode', chaincodeId, 'function', chaincodeFunc); // Trigger proof collection const [result, invokeError] = await handlePromise( invoke( @@ -78,7 +79,7 @@ const initBlockEventListenerForChannel = async ( if (!invokeError) { // Package view and send to relay const client = getRelayClientForEventPublish(); - const viewPayload = packageView(eventSubscriptionQuery, result); + const viewPayload = packageFabricView(eventSubscriptionQuery, result); console.log('Sending block event'); // Sending the Fabric event to the relay. @@ -92,6 +93,7 @@ const initBlockEventListenerForChannel = async ( await network.addBlockListener(listener); channelBlockListenerMap.set(channelId, listener); console.log('Added block listener for channel', channelId); + return listener; } /** @@ -102,7 +104,7 @@ const initContractEventListener = ( networkName: string, channelId: string, chaincodeId: string, -): void => { +): any => { const listener: ContractListener = async (event) => { console.log('Trying to find match for channel', channelId, 'chaincode', chaincodeId, 'event class', event.eventName); // Find all matching event subscriptions stored in the database @@ -138,7 +140,7 @@ const initContractEventListener = ( if (!invokeError) { // Package view and send to relay const client = getRelayClientForEventPublish(); - const viewPayload = packageView(eventSubscriptionQuery, result); + const viewPayload = packageFabricView(eventSubscriptionQuery, result); console.log('Sending contract event'); // Sending the Fabric event to the relay. @@ -149,6 +151,7 @@ const initContractEventListener = ( contract.addContractListener(listener); channelContractListenerMap.set(getChannelContractKey(channelId, chaincodeId), listener); console.log('Added contract listener for channel', channelId, 'and contract', chaincodeId); + return listener; } /** @@ -158,7 +161,7 @@ const initContractEventListener = ( const registerListenerForEventSubscription = async ( eventSubscription: events_pb.EventSubscription, networkName: string, -): Promise => { +): Promise => { // Lookup the event suscription from the database. const eventMatcher = eventSubscription.getEventMatcher(); if (!eventMatcher) { @@ -171,19 +174,28 @@ const registerListenerForEventSubscription = async ( // Check if the event_class_id is specified in the event matcher field. if (eventMatcher.getEventClassId().length === 0) { // Check if there is an active block listener for the channel specified in this event subscription. - if (!channelBlockListenerMap.has(channelId)) { + if (channelBlockListenerMap.has(channelId)) { + channelBlockListenerCount.set(channelId, channelBlockListenerCount.get(channelId) + 1); + } else { // Start a block listener. - await initBlockEventListenerForChannel(network, networkName, channelId); + const listener = await initBlockEventListenerForChannel(network, networkName, channelId); + channelBlockListenerCount.set(channelId, 0); + return listener; } } else { // Check if there is an active contract listener for the contract function specified in this event subscription. const contractId = eventMatcher.getTransactionContractId(); const contract = network.getContract(contractId); - if (!channelContractListenerMap.has(getChannelContractKey(channelId, contractId))) { + const channelContractKey = getChannelContractKey(channelId, contractId); + if (channelContractListenerMap.has(channelContractKey)) { + channelContractListenerCount.set(channelContractKey, channelContractListenerCount.get(channelContractKey) + 1); + } else { // Start a contract listener. - initContractEventListener(contract, networkName, channelId, contractId); + const listener = initContractEventListener(contract, networkName, channelId, contractId); + channelContractListenerCount.set(channelContractKey, 0); } } + return null; // Listener was already running. Nothing to do. } /** diff --git a/core/drivers/fabric-driver/server/server.ts b/core/drivers/fabric-driver/server/server.ts index 8803325be..63f016481 100644 --- a/core/drivers/fabric-driver/server/server.ts +++ b/core/drivers/fabric-driver/server/server.ts @@ -14,12 +14,12 @@ import driver_pb_grpc from '@hyperledger-labs/weaver-protos-js/driver/driver_grp import datatransfer_grpc_pb from '@hyperledger-labs/weaver-protos-js/relay/datatransfer_grpc_pb'; import events_grpc_pb from '@hyperledger-labs/weaver-protos-js/relay/events_grpc_pb'; import state_pb from '@hyperledger-labs/weaver-protos-js/common/state_pb'; -import { invoke, getNetworkGateway } from './fabric-code'; +import { invoke, getNetworkGateway, packageFabricView } from './fabric-code'; import 'dotenv/config'; import { walletSetup } from './walletSetup'; import { subscribeEventHelper, unsubscribeEventHelper, signEventSubscriptionQuery } from "./events" import * as path from 'path'; -import { handlePromise, relayCallback } from './utils'; +import { handlePromise, relayCallback, getRelayClientForQueryResponse } from './utils'; import { dbConnectionTest, eventSubscriptionTest } from "./tests" const server = new Server(); @@ -60,65 +60,6 @@ function mockCommunication(query: query_pb.Query) { }, 3000); } -// Package view and send to relay -export function packageView( - query: query_pb.Query, - viewData: fabricView.FabricView, -) { - const meta = new state_pb.Meta(); - meta.setTimestamp(new Date().toISOString()); - meta.setProofType('Notarization'); - meta.setSerializationFormat('STRING'); - meta.setProtocol(state_pb.Meta.Protocol.FABRIC); - const view = new state_pb.View(); - view.setMeta(meta); - view.setData(viewData ? viewData.serializeBinary() : Buffer.from('')); - const viewPayload = new state_pb.ViewPayload(); - viewPayload.setView(view); - viewPayload.setRequestId(query.getRequestId()); - return viewPayload; -} - -export function getRelayClientForQueryResponse() { - let client; - if (process.env.RELAY_TLS === 'true') { - if (!(process.env.RELAY_TLSCA_CERT_PATH && fs.existsSync(process.env.RELAY_TLSCA_CERT_PATH))) { - throw new Error("Missing or invalid RELAY_TLSCA_CERT_PATH: " + process.env.RELAY_TLSCA_CERT_PATH); - } - const rootCert = fs.readFileSync(process.env.RELAY_TLSCA_CERT_PATH); - client = new datatransfer_grpc_pb.DataTransferClient( - process.env.RELAY_ENDPOINT, - credentials.createSsl(rootCert) - ); - } else { - client = new datatransfer_grpc_pb.DataTransferClient( - process.env.RELAY_ENDPOINT, - credentials.createInsecure() - ); - } - return client; -} - -export function getRelayClientForEventPublish() { - let client; - if (process.env.RELAY_TLS === 'true') { - if (!(process.env.RELAY_TLSCA_CERT_PATH && fs.existsSync(process.env.RELAY_TLSCA_CERT_PATH))) { - throw new Error("Missing or invalid RELAY_TLSCA_CERT_PATH: " + process.env.RELAY_TLSCA_CERT_PATH); - } - const rootCert = fs.readFileSync(process.env.RELAY_TLSCA_CERT_PATH); - client = new events_grpc_pb.EventPublishClient( - process.env.RELAY_ENDPOINT, - credentials.createSsl(rootCert) - ); - } else { - client = new events_grpc_pb.EventPublishClient( - process.env.RELAY_ENDPOINT, - credentials.createInsecure() - ); - } - return client; -} - // Handles communication with fabric network and sends resulting data to the relay const fabricCommunication = async (query: query_pb.Query, networkName: string) => { // Query object from requestor @@ -148,7 +89,7 @@ const fabricCommunication = async (query: query_pb.Query, networkName: string) = // Process response from invoke to send to relay console.log('Result of fabric invoke', result); console.log('Sending state'); - const viewPayload: state_pb.ViewPayload = packageView(query, result); + const viewPayload: state_pb.ViewPayload = packageFabricView(query, result); console.log('Sending state'); // Sending the fabric state to the relay. diff --git a/core/drivers/fabric-driver/server/utils.ts b/core/drivers/fabric-driver/server/utils.ts index f8e626b26..e347c7a18 100644 --- a/core/drivers/fabric-driver/server/utils.ts +++ b/core/drivers/fabric-driver/server/utils.ts @@ -4,6 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ +import fs from 'fs'; +import { credentials } from '@grpc/grpc-js'; +import datatransfer_grpc_pb from '@hyperledger-labs/weaver-protos-js/relay/datatransfer_grpc_pb'; +import events_grpc_pb from '@hyperledger-labs/weaver-protos-js/relay/events_grpc_pb'; + function checkIfArraysAreEqual(x: Array, y: Array): boolean { if (x == y) { return true; @@ -49,8 +54,50 @@ function handlePromise(promise: Promise): Promise<[T?, Error?]> { return result } +function getRelayClientForQueryResponse() { + let client; + if (process.env.RELAY_TLS === 'true') { + if (!(process.env.RELAY_TLSCA_CERT_PATH && fs.existsSync(process.env.RELAY_TLSCA_CERT_PATH))) { + throw new Error("Missing or invalid RELAY_TLSCA_CERT_PATH: " + process.env.RELAY_TLSCA_CERT_PATH); + } + const rootCert = fs.readFileSync(process.env.RELAY_TLSCA_CERT_PATH); + client = new datatransfer_grpc_pb.DataTransferClient( + process.env.RELAY_ENDPOINT, + credentials.createSsl(rootCert) + ); + } else { + client = new datatransfer_grpc_pb.DataTransferClient( + process.env.RELAY_ENDPOINT, + credentials.createInsecure() + ); + } + return client; +} + +function getRelayClientForEventPublish() { + let client; + if (process.env.RELAY_TLS === 'true') { + if (!(process.env.RELAY_TLSCA_CERT_PATH && fs.existsSync(process.env.RELAY_TLSCA_CERT_PATH))) { + throw new Error("Missing or invalid RELAY_TLSCA_CERT_PATH: " + process.env.RELAY_TLSCA_CERT_PATH); + } + const rootCert = fs.readFileSync(process.env.RELAY_TLSCA_CERT_PATH); + client = new events_grpc_pb.EventPublishClient( + process.env.RELAY_ENDPOINT, + credentials.createSsl(rootCert) + ); + } else { + client = new events_grpc_pb.EventPublishClient( + process.env.RELAY_ENDPOINT, + credentials.createInsecure() + ); + } + return client; +} + export { checkIfArraysAreEqual, handlePromise, - relayCallback -} \ No newline at end of file + relayCallback, + getRelayClientForQueryResponse, + getRelayClientForEventPublish +} From 50fc8c1cd15a627c5683c8a38e9f90a3f9bc70be Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Wed, 20 Jul 2022 12:54:47 +0000 Subject: [PATCH 049/150] Added event listener removal logic from Fabric Driver Updated the Fabric CLI to match driver changes. Signed-off-by: VRamakrishna --- core/drivers/fabric-driver/server/events.ts | 11 ++- core/drivers/fabric-driver/server/listener.ts | 98 +++++++++++++++++-- samples/fabric/fabric-cli/readme.md | 2 +- .../src/commands/event/subscribe.ts | 2 +- .../src/commands/event/unsubscribe.ts | 30 ++++-- 5 files changed, 122 insertions(+), 21 deletions(-) diff --git a/core/drivers/fabric-driver/server/events.ts b/core/drivers/fabric-driver/server/events.ts index ea25f2e42..fda55cb62 100644 --- a/core/drivers/fabric-driver/server/events.ts +++ b/core/drivers/fabric-driver/server/events.ts @@ -12,7 +12,7 @@ import { InteroperableHelper } from '@hyperledger-labs/weaver-fabric-interop-sdk import { getDriverKeyCert } from "./walletSetup"; import { DBConnector, LevelDBConnector } from "./dbConnector"; import { checkIfArraysAreEqual, handlePromise, relayCallback } from "./utils"; -import { registerListenerForEventSubscription } from "./listener"; +import { registerListenerForEventSubscription, unregisterListenerForEventSubscription } from "./listener"; const DB_NAME: string = "driverdb"; @@ -70,6 +70,15 @@ async function unsubscribeEventHelper( client: events_grpc_pb.EventSubscribeClient, network_name: string, ) { + const [unregister, err] = + await handlePromise(unregisterListenerForEventSubscription(call_request.getEventMatcher()!, network_name)); + if (!unregister) { // Just log a warning. This is not critical. + console.warn('No listener running for the given subscription or unable to stop listener'); + } + if (err) { // Just log the error. This is not critical. + const errorString: string = `${JSON.stringify(err)}`; + console.error(errorString); + } const newRequestId = call_request.getQuery()!.getRequestId(); const [deletedSubscription, error] = await handlePromise(deleteEventSubscription(call_request.getEventMatcher()!, newRequestId)); diff --git a/core/drivers/fabric-driver/server/listener.ts b/core/drivers/fabric-driver/server/listener.ts index 9313d571f..dadab3d5f 100644 --- a/core/drivers/fabric-driver/server/listener.ts +++ b/core/drivers/fabric-driver/server/listener.ts @@ -14,6 +14,9 @@ import { lookupEventSubscriptions } from './events'; import { invoke, getNetworkGateway, packageFabricView } from './fabric-code'; import { handlePromise, relayCallback, getRelayClientForEventPublish } from './utils'; +let networkGatewayMap = new Map(); +let networkChannelMap = new Map(); +let networkChannelContractMap = new Map(); let channelBlockListenerMap = new Map(); let channelBlockListenerCount = new Map(); let channelContractListenerMap = new Map(); @@ -155,8 +158,7 @@ const initContractEventListener = ( } /** - * Record event subscription in the driver database. - * Start an appropriate listener if there is currently none for the channel this event subscription refers to. + * Start an appropriate listener if there is currently none for the channel (or chaincode) this event subscription refers to. **/ const registerListenerForEventSubscription = async ( eventSubscription: events_pb.EventSubscription, @@ -169,8 +171,19 @@ const registerListenerForEventSubscription = async ( } const channelId = eventMatcher.getTransactionLedgerId(); - const gateway = await getNetworkGateway(networkName); - const network = await gateway.getNetwork(channelId); + let gateway: Gateway, network: Network; + if (networkGatewayMap.has(networkName)) { + gateway = networkGatewayMap.get(networkName); + network = networkChannelMap.get(channelId); + if (!network) { + throw new Error('No network/channel handle found for existing gateway and channel ID: ' + channelId); + } + } else { + gateway = await getNetworkGateway(networkName); + networkGatewayMap.set(networkName, gateway); + network = await gateway.getNetwork(channelId); + networkChannelMap.set(channelId, network); + } // Check if the event_class_id is specified in the event matcher field. if (eventMatcher.getEventClassId().length === 0) { // Check if there is an active block listener for the channel specified in this event subscription. @@ -179,25 +192,94 @@ const registerListenerForEventSubscription = async ( } else { // Start a block listener. const listener = await initBlockEventListenerForChannel(network, networkName, channelId); - channelBlockListenerCount.set(channelId, 0); + channelBlockListenerCount.set(channelId, 1); return listener; } } else { // Check if there is an active contract listener for the contract function specified in this event subscription. const contractId = eventMatcher.getTransactionContractId(); - const contract = network.getContract(contractId); const channelContractKey = getChannelContractKey(channelId, contractId); + let contract: Contract; + if (networkChannelContractMap.has(channelContractKey)) { + contract = networkChannelContractMap.get(channelContractKey); + } else { + contract = network.getContract(contractId); + networkChannelContractMap.set(channelContractKey, contract); + } if (channelContractListenerMap.has(channelContractKey)) { channelContractListenerCount.set(channelContractKey, channelContractListenerCount.get(channelContractKey) + 1); } else { // Start a contract listener. const listener = initContractEventListener(contract, networkName, channelId, contractId); - channelContractListenerCount.set(channelContractKey, 0); + channelContractListenerCount.set(channelContractKey, 1); + return listener; } } return null; // Listener was already running. Nothing to do. } +/** + * Decrement subscription count against an active listener. Stop the listener if the count is 0. + **/ +const unregisterListenerForEventSubscription = async ( + eventMatcher: events_pb.EventMatcher, + networkName: string, +): Promise => { + if (!eventMatcher) { + throw new Error('No event matcher in event subscription'); + } + + const channelId = eventMatcher.getTransactionLedgerId(); + let gateway: Gateway, network: Network; + if (networkGatewayMap.has(networkName)) { + gateway = networkGatewayMap.get(networkName); + network = networkChannelMap.get(channelId); + if (!network) { + throw new Error('No network/channel handle found for existing gateway and channel ID: ' + channelId); + } + } else { + gateway = await getNetworkGateway(networkName); + networkGatewayMap.set(networkName, gateway); + network = await gateway.getNetwork(channelId); + networkChannelMap.set(channelId, network); + } + // Check if the event_class_id is specified in the event matcher field. + if (eventMatcher.getEventClassId().length === 0) { + if (!channelBlockListenerMap.has(channelId)) { + return false; + } + channelBlockListenerCount.set(channelId, channelBlockListenerCount.get(channelId) - 1); + if (channelBlockListenerCount.get(channelId) === 0) { // Remove listener and counter + network.removeBlockListener(channelBlockListenerMap.get(channelId)); + channelBlockListenerCount.delete(channelId); + return channelBlockListenerMap.delete(channelId); + } else { + return true; + } + } else { + const contractId = eventMatcher.getTransactionContractId(); + const channelContractKey = getChannelContractKey(channelId, contractId); + let contract: Contract; + if (networkChannelContractMap.has(channelContractKey)) { + contract = networkChannelContractMap.get(channelContractKey); + } else { + contract = network.getContract(contractId); + networkChannelContractMap.set(channelContractKey, contract); + } + if (!channelContractListenerMap.has(channelContractKey)) { + return false; + } + channelContractListenerCount.set(channelContractKey, channelContractListenerCount.get(channelContractKey) - 1); + if (channelContractListenerCount.get(channelContractKey) === 0) { // Remove listener and counter + contract.removeContractListener(channelContractListenerMap.get(channelContractKey)); + channelContractListenerCount.delete(channelContractKey); + return channelContractListenerMap.delete(channelContractKey); + } else { + return true; + } + } +} + /** * Load event subscriptions from the driver database. * Start a listener for each channel from which one of the subscribed events originate. @@ -207,4 +289,4 @@ const loadEventSubscriptionsFromStorage = ( // TODO } -export { registerListenerForEventSubscription, loadEventSubscriptionsFromStorage }; +export { registerListenerForEventSubscription, unregisterListenerForEventSubscription, loadEventSubscriptionsFromStorage }; diff --git a/samples/fabric/fabric-cli/readme.md b/samples/fabric/fabric-cli/readme.md index 82bf805b0..f95cb0a3f 100644 --- a/samples/fabric/fabric-cli/readme.md +++ b/samples/fabric/fabric-cli/readme.md @@ -393,7 +393,7 @@ Below are the steps to exercise asset transfers from `network1` to `network2` us ``` * To unsuscribe for one or more events, use the same JSON file as in subscription like: [Sample Event Sub JSON](./src/data/event_sub_sample.json). Then run the following command: ``` - ./bin/fabric-cli event unsubscribe --network=network1 --request-id= src/data/event_sub_sample.json + ./bin/fabric-cli event unsubscribe --network=network1 --request-ids= src/data/event_sub_sample.json ``` * To get the status of an event subscription, run the following command: ``` diff --git a/samples/fabric/fabric-cli/src/commands/event/subscribe.ts b/samples/fabric/fabric-cli/src/commands/event/subscribe.ts index 8da2e7ff3..55a1f5349 100644 --- a/samples/fabric/fabric-cli/src/commands/event/subscribe.ts +++ b/samples/fabric/fabric-cli/src/commands/event/subscribe.ts @@ -115,7 +115,7 @@ const command: GluegunCommand = { ) if (response.getStatus() == EventSubscriptionState.STATUS.SUBSCRIBED) { - console.log("Event Subscription Status Success with requestId:", response.getRequestId()) + console.log("Event Subscription Status Success with requestId:", response.getRequestId(), 'and event matcher:', eventMatcher) } else { console.log("Unknown error") } diff --git a/samples/fabric/fabric-cli/src/commands/event/unsubscribe.ts b/samples/fabric/fabric-cli/src/commands/event/unsubscribe.ts index 351ec29da..9372c1119 100644 --- a/samples/fabric/fabric-cli/src/commands/event/unsubscribe.ts +++ b/samples/fabric/fabric-cli/src/commands/event/unsubscribe.ts @@ -27,8 +27,8 @@ const command: GluegunCommand = { commandHelp( print, toolbox, - `fabric-cli event unsubscribe --network= --user=user1 --request-id="abc123" src/data/event_sub_sample.json`, - 'fabric-cli event unsubscribe --network= --user= --request-id= ', + `fabric-cli event unsubscribe --network= --user=user1 --request-ids="abc123:efg456" src/data/event_sub_sample.json`, + 'fabric-cli event unsubscribe --network= --user= --request-ids= ', [ { name: '--network', @@ -41,9 +41,9 @@ const command: GluegunCommand = { 'User for subscription. Default: user1' }, { - name: '--request-id', + name: '--request-ids', description: - 'Request ID received during subscription.' + 'Colon-separated list of request IDs received during subscriptions. A request ID can be left blank, indicating that the corresponding JSON (i.e., at the same index) in the file should not be unsubscribed' }, { name: '--debug', @@ -70,9 +70,9 @@ const command: GluegunCommand = { print.error('--network needs to be specified') return } - if (!options['request-id']) + if (!options['request-ids']) { - print.error('--request-id needs to be specified') + print.error('--request-ids needs to be specified') return } if (!options['user']) { @@ -81,7 +81,7 @@ const command: GluegunCommand = { const networkName = options['network'] const user = options['user'] - const requestId = options['request-id'] + const requestIds = options['request-ids'] const filepath = path.resolve(array[0]) @@ -107,9 +107,19 @@ const command: GluegunCommand = { if (keyCertError) { throw new Error(`Error getting key and cert ${keyCertError}`) } - + + const requestIdList = requestIds.split(':') const data = JSON.parse(fs.readFileSync(filepath).toString()) + if (requestIdList.length !== data.length) { + throw new Error(`Mismatching request ID list and subscription JSON counts. #Request IDs = ${requestIdList.length}, #JSON items = ${data.length}.`) + } for (let i = 0 ; i < data.length ; i++) { + if (requestIdList[i] === '') { + // Don't unsubscribe + continue; + } + + // Unsubscribe const eventMatcher = EventsManager.createEventMatcher(data[i].event_matcher) const eventPublicationSpec = EventsManager.createEventPublicationSpec(data[i].event_publication_spec) @@ -118,7 +128,7 @@ const command: GluegunCommand = { contract, eventMatcher, eventPublicationSpec, - requestId, + requestIdList[i], networkName, netConfig.mspId, netConfig.relayEndpoint, @@ -127,7 +137,7 @@ const command: GluegunCommand = { ) if (response.getStatus() == EventSubscriptionState.STATUS.UNSUBSCRIBED) { - console.log("Event Unsubscription Success for requestId:", response.getRequestId()) + console.log("Event Unsubscription Success for requestId:", response.getRequestId(), 'and event matcher:', eventMatcher) } else { console.log("Unknown error") } From a5828be002de1d89906775781ff5df501310bdf7 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Wed, 20 Jul 2022 13:03:26 +0000 Subject: [PATCH 050/150] Deleting event susbcription upon listener registration failure in Fabric Driver Signed-off-by: VRamakrishna --- core/drivers/fabric-driver/server/events.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/drivers/fabric-driver/server/events.ts b/core/drivers/fabric-driver/server/events.ts index fda55cb62..66c126714 100644 --- a/core/drivers/fabric-driver/server/events.ts +++ b/core/drivers/fabric-driver/server/events.ts @@ -40,6 +40,13 @@ async function subscribeEventHelper( // Start an appropriate type of event listener for this event subscription if one is not already active const [listenerHandle, error] = await handlePromise(registerListenerForEventSubscription(call_request, network_name)); if (error) { + // Need to delete subscription in database too, for consistency + const [deletedSubscription, err] = + await handlePromise(deleteEventSubscription(call_request.getEventMatcher()!, newRequestId)); + if (err) { + const errorString: string = `${JSON.stringify(err)}`; + console.error(errorString); + } ack_send.setMessage('Event subscription succeeded but listener registration failed'); ack_send.setStatus(ack_pb.Ack.STATUS.ERROR); } else { From c9bd492b063406398597730190d1707d2f867950 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Wed, 20 Jul 2022 14:16:59 +0000 Subject: [PATCH 051/150] Fixed error message in Fabric Driver Signed-off-by: VRamakrishna --- core/drivers/fabric-driver/server/events.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/drivers/fabric-driver/server/events.ts b/core/drivers/fabric-driver/server/events.ts index 66c126714..6176eb82e 100644 --- a/core/drivers/fabric-driver/server/events.ts +++ b/core/drivers/fabric-driver/server/events.ts @@ -47,7 +47,7 @@ async function subscribeEventHelper( const errorString: string = `${JSON.stringify(err)}`; console.error(errorString); } - ack_send.setMessage('Event subscription succeeded but listener registration failed'); + ack_send.setMessage('Event subscription error: listener registration failed'); ack_send.setStatus(ack_pb.Ack.STATUS.ERROR); } else { ack_send.setMessage('Event subscription is successful!'); From ba9175e596feb3d0115b78c70328d0f7ff25ba12 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Wed, 20 Jul 2022 20:12:13 +0530 Subject: [PATCH 052/150] event publication support added in relay Signed-off-by: sandeep.nishad1 --- core/relay/Cargo.lock | 974 +++++++++++++----- core/relay/Cargo.toml | 1 + core/relay/driver/driver.rs | 7 +- core/relay/src/db.rs | 5 + core/relay/src/error.rs | 7 + .../src/services/event_publish_service.rs | 345 ++++++- .../src/services/event_subscribe_service.rs | 84 +- core/relay/src/services/helpers.rs | 100 +- core/relay/src/services/network_service.rs | 78 +- 9 files changed, 1302 insertions(+), 299 deletions(-) diff --git a/core/relay/Cargo.lock b/core/relay/Cargo.lock index 8a017fe6b..9414e8ade 100644 --- a/core/relay/Cargo.lock +++ b/core/relay/Cargo.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "aho-corasick" -version = "0.7.10" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ "memchr", ] [[package]] name = "anyhow" -version = "1.0.31" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f" +checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" [[package]] name = "arrayvec" @@ -46,9 +46,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.31" +version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c4f3195085c36ea8d24d32b2f828d23296a9370a28aa39d111f6f16bef9f3b" +checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716" dependencies = [ "proc-macro2", "quote", @@ -57,9 +57,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "base64" @@ -75,43 +75,48 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "bincode" -version = "1.2.1" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" dependencies = [ - "byteorder", - "serde 1.0.110", + "serde 1.0.139", ] [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bumpalo" -version = "3.4.0" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" +checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" [[package]] name = "byteorder" -version = "1.3.4" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" [[package]] name = "bytes" -version = "0.5.4" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1" +checksum = "f0b3de4a0c5e67e16066a0715723abd91edc2f9001d09c46e1dca929351e130e" [[package]] name = "cc" -version = "1.0.54" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" [[package]] name = "cfg-if" @@ -143,20 +148,36 @@ dependencies = [ "lazy_static", "nom", "rust-ini", - "serde 1.0.110", + "serde 1.0.139", "serde-hjson", "serde_json", "toml", "yaml-rust", ] +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + [[package]] name = "crc32fast" -version = "1.2.0" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", ] [[package]] @@ -187,9 +208,27 @@ dependencies = [ [[package]] name = "either" -version = "1.5.3" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" +checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" + +[[package]] +name = "encoding_rs" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] [[package]] name = "fixedbitset" @@ -203,6 +242,31 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + [[package]] name = "fs2" version = "0.4.3" @@ -210,7 +274,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" dependencies = [ "libc", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] @@ -231,9 +295,9 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "futures" -version = "0.3.5" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e05b85ec287aac0dc34db7d4a569323df697f9c55b99b15d6b4ef8cde49f613" +checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" dependencies = [ "futures-channel", "futures-core", @@ -246,9 +310,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.5" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" dependencies = [ "futures-core", "futures-sink", @@ -256,15 +320,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.5" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" [[package]] name = "futures-executor" -version = "0.3.5" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10d6bb888be1153d3abeb9006b11b02cf5e9b209fda28693c31ae1e4e012e314" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" dependencies = [ "futures-core", "futures-task", @@ -273,17 +337,16 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.5" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" [[package]] name = "futures-macro" -version = "0.3.5" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" dependencies = [ - "proc-macro-hack", "proc-macro2", "quote", "syn", @@ -291,9 +354,9 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.5" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" [[package]] name = "futures-task" @@ -303,9 +366,9 @@ checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" [[package]] name = "futures-util" -version = "0.3.5" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" dependencies = [ "futures-channel", "futures-core", @@ -314,10 +377,8 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project", + "pin-project-lite 0.2.9", "pin-utils", - "proc-macro-hack", - "proc-macro-nested", "slab", ] @@ -332,52 +393,70 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.14" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "libc", - "wasi", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] name = "h2" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79b7246d7e4b979c03fa093da39cfb3617a96bbeee6310af63991668d7e843ff" +checksum = "5e4728fd124914ad25e99e3d15a9361a879f6620f63cb56bbb08f95abb97a535" dependencies = [ - "bytes", + "bytes 0.5.6", "fnv", "futures-core", "futures-sink", "futures-util", "http", "indexmap", - "log", "slab", "tokio", "tokio-util", + "tracing", + "tracing-futures", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "heck" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" dependencies = [ "unicode-segmentation", ] [[package]] name = "http" -version = "0.2.1" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d569972648b2c512421b5f2a405ad6ac9666547189d0c5477a3f200f3e02f9" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ - "bytes", + "bytes 1.2.0", "fnv", - "itoa", + "itoa 1.0.2", ] [[package]] @@ -386,23 +465,29 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b" dependencies = [ - "bytes", + "bytes 0.5.6", "http", ] [[package]] name = "httparse" -version = "1.3.4" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" +checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" + +[[package]] +name = "httpdate" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" [[package]] name = "hyper" -version = "0.13.5" +version = "0.13.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96816e1d921eca64d208a85aab4f7798455a8e34229ee5a88c935bdee1b78b14" +checksum = "8a6f157065790a3ed2f88679250419b5cdd96e714a0d65f7797fd337186e96bb" dependencies = [ - "bytes", + "bytes 0.5.6", "futures-channel", "futures-core", "futures-util", @@ -410,23 +495,57 @@ dependencies = [ "http", "http-body", "httparse", - "itoa", - "log", - "net2", - "pin-project", - "time", + "httpdate", + "itoa 0.4.8", + "pin-project 1.0.11", + "socket2", "tokio", "tower-service", + "tracing", "want", ] +[[package]] +name = "hyper-tls" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d979acc56dcb5b8dddba3917601745e877576475aa046df3226eabdecef78eed" +dependencies = [ + "bytes 0.5.6", + "hyper", + "native-tls", + "tokio", + "tokio-tls", +] + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "indexmap" -version = "1.3.2" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if 1.0.0", ] [[package]] @@ -438,6 +557,12 @@ dependencies = [ "libc", ] +[[package]] +name = "ipnet" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" + [[package]] name = "itertools" version = "0.8.2" @@ -449,15 +574,21 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.5" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" [[package]] name = "js-sys" -version = "0.3.39" +version = "0.3.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa5a448de267e7358beaf4a5d849518fe9a0c13fce7afd44b06e68550e5562a7" +checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" dependencies = [ "wasm-bindgen", ] @@ -493,9 +624,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.70" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" [[package]] name = "linked-hash-map" @@ -509,19 +640,19 @@ dependencies = [ [[package]] name = "linked-hash-map" -version = "0.5.3" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "listenfd" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "492158e732f2e2de81c592f0a2427e57e12cd3d59877378fe7af624b6bbe0ca1" +checksum = "809e514e2cb8a9624701346ea3e694c1766d76778e343e537d873c1c366e79a7" dependencies = [ "libc", - "uuid 0.6.5", - "winapi 0.3.8", + "uuid", + "winapi 0.3.9", ] [[package]] @@ -535,13 +666,19 @@ dependencies = [ [[package]] name = "log" -version = "0.4.8" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", ] +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + [[package]] name = "maybe-uninit" version = "2.0.0" @@ -550,24 +687,40 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] name = "memchr" -version = "2.3.3" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8" +checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" dependencies = [ "autocfg", ] +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "mio" -version = "0.6.22" +version = "0.6.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" +checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" dependencies = [ "cfg-if 0.1.10", "fuchsia-zircon", @@ -596,9 +749,27 @@ dependencies = [ [[package]] name = "multimap" -version = "0.8.1" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + +[[package]] +name = "native-tls" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8883adfde9756c1d30b0f519c9b8c502a94b41ac62f696453c37c7fc0a958ce" +checksum = "fd7e2f3618557f980e0b17e8856252eee3c97fa12c54dff0ca290fb6266ca4a9" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] [[package]] name = "net2" @@ -608,7 +779,7 @@ checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" dependencies = [ "cfg-if 0.1.10", "libc", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] @@ -628,23 +799,68 @@ version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" dependencies = [ - "num-traits 0.2.11", + "num-traits 0.2.15", ] [[package]] name = "num-traits" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", ] [[package]] name = "once_cell" -version = "1.4.0" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + +[[package]] +name = "openssl" +version = "0.10.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" +checksum = "618febf65336490dfcf20b73f885f5651a0c89c64c2d4a8c3662585a70bf5bd0" +dependencies = [ + "bitflags", + "cfg-if 1.0.0", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5f9bd0c2710541a3cda73d6f9ac4f1b240de4ae261065d309dbe73d9dceb42f" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] [[package]] name = "parking_lot" @@ -665,9 +881,9 @@ dependencies = [ "cfg-if 0.1.10", "cloudabi", "libc", - "redox_syscall", + "redox_syscall 0.1.57", "smallvec", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] @@ -688,18 +904,38 @@ dependencies = [ [[package]] name = "pin-project" -version = "0.4.17" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ef0f924a5ee7ea9cbcea77529dba45f8a9ba9f622419fe3386ca581a3ae9d5a" +dependencies = [ + "pin-project-internal 0.4.30", +] + +[[package]] +name = "pin-project" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc93aeee735e60ecb40cf740eb319ff23eab1c5748abfdb5c180e4ce49f7791" +checksum = "78203e83c48cffbe01e4a2d35d566ca4de445d79a85372fc64e378bfc812a260" dependencies = [ - "pin-project-internal", + "pin-project-internal 1.0.11", ] [[package]] name = "pin-project-internal" -version = "0.4.17" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "851c8d0ce9bebe43790dedfc86614c23494ac9f423dd618d3a61fc693eafe61e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e58db2081ba5b4c93bd6be09c40fd36cb9193a8336c384f3b40012e531aa7e40" +checksum = "710faf75e1b33345361201d36d04e98ac1ed8909151a017ed384700836104c74" dependencies = [ "proc-macro2", "quote", @@ -708,41 +944,41 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.1.5" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7505eeebd78492e0f6108f7171c4948dbb120ee8119d9d77d0afa5469bef67f" +checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" [[package]] -name = "pin-utils" -version = "0.1.0" +name = "pin-project-lite" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" [[package]] -name = "ppv-lite86" -version = "0.2.8" +name = "pin-utils" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] -name = "proc-macro-hack" -version = "0.5.16" +name = "pkg-config" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" [[package]] -name = "proc-macro-nested" -version = "0.1.6" +name = "ppv-lite86" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "proc-macro2" -version = "1.0.17" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1502d12e458c49a4c9cbff560d0fe0060c252bc29799ed94ca2ed4bb665a0101" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] @@ -751,7 +987,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce49aefe0a6144a45de32927c77bd2859a5f7677b55f220ae5b744e87389c212" dependencies = [ - "bytes", + "bytes 0.5.6", "prost-derive", ] @@ -761,7 +997,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02b10678c913ecbd69350e8535c3aef91a8676c0773fc1d7b95cdd196d7f2f26" dependencies = [ - "bytes", + "bytes 0.5.6", "heck", "itertools", "log", @@ -792,15 +1028,15 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1834f67c0697c001304b75be76f67add9c89742eda3a085ad8ee0bb38c3417aa" dependencies = [ - "bytes", + "bytes 0.5.6", "prost", ] [[package]] name = "quote" -version = "1.0.6" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" dependencies = [ "proc-macro2", ] @@ -811,7 +1047,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom", + "getrandom 0.1.16", "libc", "rand_chacha", "rand_core", @@ -835,7 +1071,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom", + "getrandom 0.1.16", ] [[package]] @@ -858,27 +1094,35 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.1.56" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + +[[package]] +name = "redox_syscall" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] [[package]] name = "regex" -version = "1.3.9" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ "aho-corasick", "memchr", "regex-syntax", - "thread_local", ] [[package]] name = "regex-syntax" -version = "0.6.18" +version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" [[package]] name = "relay" @@ -890,28 +1134,65 @@ dependencies = [ "futures", "listenfd", "prost", - "serde 1.0.110", + "reqwest", + "serde 1.0.139", "sled", "tokio", "tonic", "tonic-build", - "uuid 0.8.1", + "uuid", ] [[package]] name = "remove_dir_all" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ - "winapi 0.3.8", + "winapi 0.3.9", +] + +[[package]] +name = "reqwest" +version = "0.10.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0718f81a8e14c4dbb3b34cf23dc6aaf9ab8a0dfec160c534b3dbca1aaa21f47c" +dependencies = [ + "base64 0.13.0", + "bytes 0.5.6", + "encoding_rs", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "lazy_static", + "log", + "mime", + "mime_guess", + "native-tls", + "percent-encoding", + "pin-project-lite 0.2.9", + "serde 1.0.139", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-tls", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", ] [[package]] name = "ring" -version = "0.16.14" +version = "0.16.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06b3fefa4f12272808f809a0af618501fdaba41a58963c5fb72238ab0be09603" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" dependencies = [ "cc", "libc", @@ -919,7 +1200,7 @@ dependencies = [ "spin", "untrusted", "web-sys", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] @@ -943,9 +1224,19 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.5" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "schannel" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +dependencies = [ + "lazy_static", + "windows-sys", +] [[package]] name = "scopeguard" @@ -955,14 +1246,37 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "sct" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3042af939fca8c3453b7af0f1c66e533a15a86169e39de2657310ade8f98d3c" +checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" dependencies = [ "ring", "untrusted", ] +[[package]] +name = "security-framework" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "serde" version = "0.8.23" @@ -971,9 +1285,9 @@ checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" [[package]] name = "serde" -version = "1.0.110" +version = "1.0.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e7b308464d16b56eba9964e4972a3eee817760ab60d88c3f86e1fecb08204c" +checksum = "0171ebb889e45aa68b44aee0859b3eede84c6f5f5c228e6f140c0b2a0a46cad6" dependencies = [ "serde_derive", ] @@ -993,9 +1307,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.110" +version = "1.0.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "818fbf6bfa9a42d3bfcaca148547aa00c7b915bec71d1757aa2d44ca68771984" +checksum = "dc1d3230c1de7932af58ad8ffbe1d784bd55efd5a9d84ac24f69c72d83543dfb" dependencies = [ "proc-macro2", "quote", @@ -1004,13 +1318,13 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.53" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "993948e75b189211a9b31a7528f950c6adc21f9720b6438ff80a7fa2f864cea2" +checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" dependencies = [ - "itoa", + "itoa 1.0.2", "ryu", - "serde 1.0.110", + "serde 1.0.139", ] [[package]] @@ -1022,11 +1336,26 @@ dependencies = [ "serde 0.8.23", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa 1.0.2", + "ryu", + "serde 1.0.139", +] + [[package]] name = "slab" -version = "0.4.2" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] [[package]] name = "sled" @@ -1046,9 +1375,20 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" + +[[package]] +name = "socket2" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "winapi 0.3.9", +] [[package]] name = "spin" @@ -1064,71 +1404,67 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "syn" -version = "1.0.24" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f87bc5b2815ebb664de0392fdf1b95b6d10e160f86d9f64ff65e5679841ca06a" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] name = "tempfile" -version = "3.1.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", + "fastrand", "libc", - "rand", - "redox_syscall", + "redox_syscall 0.2.13", "remove_dir_all", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] -name = "thread_local" -version = "1.0.1" +name = "tinyvec" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ - "lazy_static", + "tinyvec_macros", ] [[package]] -name = "time" -version = "0.1.43" +name = "tinyvec_macros" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" -dependencies = [ - "libc", - "winapi 0.3.8", -] +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "0.2.21" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d099fa27b9702bed751524694adbe393e18b36b204da91eb1cbbbbb4a5ee2d58" +checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092" dependencies = [ - "bytes", + "bytes 0.5.6", "fnv", "futures-core", "iovec", "lazy_static", "memchr", "mio", - "pin-project-lite", + "pin-project-lite 0.1.12", "slab", "tokio-macros", ] [[package]] name = "tokio-macros" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389" +checksum = "e44da00bfc73a25f814cd8d7e57a68a5c31b74b3152a0a1d1f590c97ed06265a" dependencies = [ "proc-macro2", "quote", @@ -1147,27 +1483,37 @@ dependencies = [ "webpki", ] +[[package]] +name = "tokio-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a70f4fcd7b3b24fb194f837560168208f669ca8cb70d0c4b862944452396343" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-util" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" dependencies = [ - "bytes", + "bytes 0.5.6", "futures-core", "futures-sink", "log", - "pin-project-lite", + "pin-project-lite 0.1.12", "tokio", ] [[package]] name = "toml" -version = "0.5.6" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" dependencies = [ - "serde 1.0.110", + "serde 1.0.139", ] [[package]] @@ -1179,14 +1525,14 @@ dependencies = [ "async-stream", "async-trait", "base64 0.11.0", - "bytes", + "bytes 0.5.6", "futures-core", "futures-util", "http", "http-body", "hyper", "percent-encoding", - "pin-project", + "pin-project 0.4.30", "prost", "prost-derive", "tokio", @@ -1240,7 +1586,7 @@ dependencies = [ "futures-core", "futures-util", "indexmap", - "pin-project", + "pin-project 0.4.30", "rand", "slab", "tokio", @@ -1260,7 +1606,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4887dc2a65d464c8b9b66e0e4d51c2fd6cf5b3373afc72805b0a60bce00446a" dependencies = [ "futures-core", - "pin-project", + "pin-project 0.4.30", "tokio", "tower-layer", "tower-service", @@ -1274,15 +1620,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f6b5000c3c54d269cc695dff28136bb33d08cbf1df2c48129e143ab65bf3c2a" dependencies = [ "futures-core", - "pin-project", + "pin-project 0.4.30", "tower-service", ] [[package]] name = "tower-layer" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35d656f2638b288b33495d1053ea74c40dc05ec0b92084dd71ca5566c4ed1dc" +checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" [[package]] name = "tower-limit" @@ -1291,7 +1637,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92c3040c5dbed68abffaa0d4517ac1a454cd741044f33ab0eefab6b8d1361404" dependencies = [ "futures-core", - "pin-project", + "pin-project 0.4.30", "tokio", "tower-layer", "tower-load", @@ -1306,7 +1652,7 @@ checksum = "8cc79fc3afd07492b7966d7efa7c6c50f8ed58d768a6075dd7ae6591c5d2017b" dependencies = [ "futures-core", "log", - "pin-project", + "pin-project 0.4.30", "tokio", "tower-discover", "tower-service", @@ -1319,7 +1665,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f021e23900173dc315feb4b6922510dae3e79c689b74c089112066c11f0ae4e" dependencies = [ "futures-core", - "pin-project", + "pin-project 0.4.30", "tower-layer", "tower-service", ] @@ -1355,7 +1701,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6727956aaa2f8957d4d9232b308fe8e4e65d99db30f42b225646e86c9b6a952" dependencies = [ "futures-core", - "pin-project", + "pin-project 0.4.30", "tokio", "tower-layer", "tower-service", @@ -1363,9 +1709,9 @@ dependencies = [ [[package]] name = "tower-service" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e987b6bf443f4b5b3b6f38704195592cca41c5bb7aedd3c3693c7081f8289860" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tower-timeout" @@ -1373,7 +1719,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "127b8924b357be938823eaaec0608c482d40add25609481027b96198b2e4b31e" dependencies = [ - "pin-project", + "pin-project 0.4.30", "tokio", "tower-layer", "tower-service", @@ -1387,27 +1733,28 @@ checksum = "d1093c19826d33807c72511e68f73b4a0469a3f22c2bd5f7d5212178b4b89674" dependencies = [ "futures-core", "futures-util", - "pin-project", + "pin-project 0.4.30", "tower-service", ] [[package]] name = "tracing" -version = "0.1.14" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7c6b59d116d218cb2d990eb06b77b64043e0268ef7323aae63d8b30ae462923" +checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "log", + "pin-project-lite 0.2.9", "tracing-attributes", "tracing-core", ] [[package]] name = "tracing-attributes" -version = "0.1.8" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99bbad0de3fd923c9c3232ead88510b783e5a4d16a6154adffa3d53308de984c" +checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" dependencies = [ "proc-macro2", "quote", @@ -1416,40 +1763,64 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.10" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa83a9a47081cd522c09c81b31aec2c9273424976f922ad61c053b58350b715" +checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" dependencies = [ - "lazy_static", + "once_cell", ] [[package]] name = "tracing-futures" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab7bb6f14721aa00656086e9335d363c5c8747bae02ebe32ea2c7dece5689b4c" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" dependencies = [ - "pin-project", + "pin-project 1.0.11", "tracing", ] [[package]] name = "try-lock" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] -name = "unicode-segmentation" -version = "1.6.0" +name = "unicase" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] [[package]] -name = "unicode-xid" -version = "0.2.0" +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" + +[[package]] +name = "unicode-normalization" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" [[package]] name = "untrusted" @@ -1458,28 +1829,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] -name = "uuid" -version = "0.6.5" +name = "url" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1436e58182935dcd9ce0add9ea0b558e8a87befe01c1a301e6020aeb0876363" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" dependencies = [ - "cfg-if 0.1.10", + "form_urlencoded", + "idna", + "matches", + "percent-encoding", ] [[package]] name = "uuid" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "rand", + "getrandom 0.2.7", ] +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "want" @@ -1497,21 +1877,29 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "wasm-bindgen" -version = "0.2.62" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c7d40d09cdbf0f4895ae58cf57d92e1e57a9dd8ed2e8390514b54a47cc5551" +checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", + "serde 1.0.139", + "serde_json", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.62" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3972e137ebf830900db522d6c8fd74d1900dcfc733462e9a12e942b00b4ac94" +checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" dependencies = [ "bumpalo", "lazy_static", @@ -1522,11 +1910,23 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de9a9cec1733468a8c657e57fa2413d2ae2c0129b95e87c5b72b8ace4d13f31f" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" -version = "0.2.62" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cd85aa2c579e8892442954685f0d801f9129de24fa2136b2c6a539c76b65776" +checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1534,9 +1934,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.62" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eb197bd3a47553334907ffd2f16507b4f4f01bbec3ac921a7719e0decdfe72a" +checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" dependencies = [ "proc-macro2", "quote", @@ -1547,15 +1947,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.62" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a91c2916119c17a8e316507afaaa2dd94b47646048014bbdf6bef098c1bb58ad" +checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" [[package]] name = "web-sys" -version = "0.3.39" +version = "0.3.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bc359e5dd3b46cb9687a051d50a2fdd228e4ba7cf6fcf861a5365c3d671a642" +checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90" dependencies = [ "js-sys", "wasm-bindgen", @@ -1563,9 +1963,9 @@ dependencies = [ [[package]] name = "webpki" -version = "0.21.3" +version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab146130f5f790d45f82aeeb09e55a256573373ec64409fc19a6fb82fb1032ae" +checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" dependencies = [ "ring", "untrusted", @@ -1588,9 +1988,9 @@ checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" [[package]] name = "winapi" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", @@ -1614,6 +2014,58 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "winreg" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "ws2_32-sys" version = "0.2.1" @@ -1626,9 +2078,9 @@ dependencies = [ [[package]] name = "yaml-rust" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" dependencies = [ - "linked-hash-map 0.5.3", + "linked-hash-map 0.5.6", ] diff --git a/core/relay/Cargo.toml b/core/relay/Cargo.toml index 3ed05c5e3..1a5b78d93 100644 --- a/core/relay/Cargo.toml +++ b/core/relay/Cargo.toml @@ -33,6 +33,7 @@ config = "0.10.1" listenfd = "0.3" futures = { version = "0.3.5" } base64 = "0.13.0" +reqwest = { version = "0.10.10", features = ["json"] } [build-dependencies] diff --git a/core/relay/driver/driver.rs b/core/relay/driver/driver.rs index 6b85943bb..7c269312d 100644 --- a/core/relay/driver/driver.rs +++ b/core/relay/driver/driver.rs @@ -187,7 +187,12 @@ impl DriverCommunication for DriverCommunicationService { return Ok(Response::new(signed_query)); } async fn write_external_state(&self, request: Request) -> Result, Status> { - Err(tonic::Status::unimplemented("method not implemented")) + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request.into_inner().view_payload.expect("Error").request_id.to_string(), + message: "Successfully written".to_string(), + }; + return Ok(Response::new(reply)); } } diff --git a/core/relay/src/db.rs b/core/relay/src/db.rs index c9f4b56f7..5d035d2d0 100644 --- a/core/relay/src/db.rs +++ b/core/relay/src/db.rs @@ -33,4 +33,9 @@ impl Database { req_db.remove(format!("b{}", key))?; decoded_result } + pub fn has_key(&self, key: String) -> Result { + let req_db = open(&self.db_path).unwrap(); + let result = req_db.contains_key(format!("b{}", key))?; + Ok(result) + } } diff --git a/core/relay/src/error.rs b/core/relay/src/error.rs index 5182953d8..1a91966f4 100644 --- a/core/relay/src/error.rs +++ b/core/relay/src/error.rs @@ -11,6 +11,7 @@ pub enum Error { StatusError(tonic::Status), SledError(sled::Error), ConfigError(config::ConfigError), + ReqwestError(reqwest::Error), } impl From for Error { @@ -46,3 +47,9 @@ impl From for Error { Error::StatusError(e) } } + +impl From for Error { + fn from(e: reqwest::Error) -> Self { + Error::ReqwestError(e) + } +} diff --git a/core/relay/src/services/event_publish_service.rs b/core/relay/src/services/event_publish_service.rs index 231ae0a39..4be1bf410 100644 --- a/core/relay/src/services/event_publish_service.rs +++ b/core/relay/src/services/event_publish_service.rs @@ -2,18 +2,24 @@ use crate::pb::common::ack::{ack, Ack}; use crate::pb::common::query::Query; use crate::pb::common::state::{request_state, view_payload, RequestState, ViewPayload}; +use crate::pb::common::events::{EventSubscription, EventSubscriptionState, event_publication, EventPublication, EventState, EventStates}; use crate::pb::relay::events::event_publish_client::EventPublishClient; use crate::pb::relay::events::event_publish_server::EventPublish; +use crate::pb::driver::driver::WriteExternalStateMessage; + // Internal modules use crate::db::Database; use crate::error::Error; -use crate::relay_proto::{parse_address, LocationSegment}; +use crate::relay_proto::LocationSegment; +use crate::services::helpers::{get_driver, get_driver_client, get_event_subscription_key, get_event_publication_key, update_event_state}; + // external modules use config; use tokio::sync::RwLock; use tonic::{Request, Response, Status}; - +use uuid::Uuid; use tonic::transport::{Certificate, Channel, ClientTlsConfig}; +use reqwest; pub struct EventPublishService { pub config_lock: RwLock, @@ -28,11 +34,342 @@ impl EventPublish for EventPublishService { &self, request: Request, ) -> Result, Status> { - Err(tonic::Status::unimplemented("method not implemented")) + let state = request.into_inner().clone(); + let state_clone = state.clone(); + println!("Received State from driver: {:?}", state_clone.request_id); + match state_clone.state.as_ref().unwrap() { + view_payload::State::View(v) => println!("View Meta: {:?}, View Data: {:?}", v.meta, base64::encode(&v.data)), + view_payload::State::Error(e) => println!("Error: {:?}", e), + } + let request_id = state.request_id.to_string(); + let conf = self.config_lock.read().await; + // Database access/storage + let remote_db = Database { + db_path: conf.get_str("remote_db_path").unwrap(), + }; + + let result = + send_driver_state_helper(request_id.to_string(), remote_db, conf.clone(), state); + match result { + Ok(resp) => { + let reply = Ok(resp); + println!("Sending back Ack to driver: {:?}\n", reply); + return reply; + } + Err(e) => { + // NOTE: No way to send another state to Relay, if it reaches this error the next will also error. + let reply = Ok(Response::new(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: {:?}", e), + })); + println!("Sending back Ack to driver: {:?}\n", reply); + return reply; + } + } } // src-relay will forward the state as part of event subscription to dest-relay async fn send_state(&self, request: Request) -> Result, Status> { - Err(tonic::Status::unimplemented("method not implemented")) + let request_view_payload = request.into_inner().clone(); + println!( + "Event: Received state from remote relay: Request ID = {:?}", + request_view_payload.request_id + ); + match request_view_payload.state.as_ref().unwrap() { + view_payload::State::View(v) => println!("View Meta: {:?}, View Data: {:?}", v.meta, base64::encode(&v.data)), + view_payload::State::Error(e) => println!("Error: {:?}", e), + } + let request_id = &request_view_payload.request_id.to_string(); + let conf = self.config_lock.read().await.clone(); + // Database access/storage + let db = Database { + db_path: conf.get_str("db_path").unwrap(), + }; + let result = send_state_helper(request_view_payload, request_id.to_string(), db, conf); + + match result { + Ok(_) => { + let reply = Ok(Response::new(Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "".to_string(), + })); + println!("Event: Sending back Ack to remote relay: {:?}", reply); + reply + }, + Err(e) => { + let reply = Ok(Response::new(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("{:?}", e), + })); + println!("Event: Sending back Ack to remote relay: {:?}", reply); + reply + } + } } +} + + +/// send_driver_state is run on the remote relay. Runs when the driver sends the +/// state back to the remote relay or if there was an error making the +/// request_driver_state gRPC call. +fn send_driver_state_helper( + request_id: String, + remote_db: Database, + conf: config::Config, + state: ViewPayload, +) -> Result, Error> { + let event_sub_key = get_event_subscription_key(request_id.to_string()); + let event_sub: EventSubscription = remote_db + .get::(event_sub_key.to_string()) + .map_err(|e| Error::GetQuery(format!("Failed to get event subscription from db. Error: {:?}", e)))?; + let query: &Query = &event_sub.clone().query.expect("Unexpected Error: Query not found in event subscription"); + let relays_table = conf.get_table("relays")?; + let relay_uri = relays_table + .get(&query.requesting_relay.to_string()) + .ok_or(Error::Simple("Relay name not found".to_string()))?; + let uri = relay_uri.clone().try_into::()?; + spawn_send_state( + state, + uri.hostname.to_string(), + uri.port.to_string(), + uri.tls, + uri.tlsca_cert_path.to_string(), + ); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id, + message: "".to_string(), + }; + + return Ok(Response::new(reply)); +} + +// spawn_send_state sends data from the remote relay back to the requesting relay +// When it errors it currently logs to console. Needs improving +fn spawn_send_state(state: ViewPayload, requestor_host: String, requester_port: String, use_tls: bool, tlsca_cert_path: String) { + tokio::spawn(async move { + println!("Event Publish: Sending state back to requesting relay: Request ID = {:?}", state.request_id); + match state.state.as_ref().unwrap() { + view_payload::State::View(v) => println!("View Meta: {:?}, View Data: {:?}", v.meta, base64::encode(&v.data)), + view_payload::State::Error(e) => println!("Error: {:?}", e), + } + let client_addr = format!("http://{}:{}", requestor_host, requester_port); + if use_tls { + let pem = tokio::fs::read(tlsca_cert_path).await.unwrap(); + let ca = Certificate::from_pem(pem); + + let tls = ClientTlsConfig::new() + .ca_certificate(ca) + .domain_name(requestor_host); + + let channel = Channel::from_shared(client_addr).unwrap() + .tls_config(tls) + .connect() + .await + .unwrap(); + + let mut client_result = EventPublishClient::new(channel); + let response = client_result.send_state(state).await; + println!("Event Publish: Response ACK from requesting relay={:?}\n", response); + } else { + let client_result = EventPublishClient::connect(client_addr).await; + match client_result { + Ok(client) => { + let response = client.clone().send_state(state).await; + println!("Event Publish: Response ACK from requesting relay={:?}\n", response); + // Not returning anything here + } + Err(e) => { + // TODO: Add better error handling (Attempt a few times?) + println!( + "Event Publish: Failed to connect to client: ${:?}. Error: {}\n", + requester_port, + e.to_string() + ); + // TODO: Handle this error thorugh join handle after thread completes. + // Not actually returning anything here yet + } + } + } + }); +} + +/// send_state is run on the requesting relay when a remote relay sends a result back to the requesting relay +fn send_state_helper( + state: ViewPayload, + request_id: String, + db: Database, + conf: config::Config +) -> Result<(), Error> { + let event_sub_key = get_event_subscription_key(request_id.to_string()); + let event_sub_state: EventSubscriptionState = db.get::(event_sub_key.to_string()) + .map_err(|err| Error::GetQuery(format!("Failed to get event subscription state from db. Error: {:?}", err)))?; + + let event_publish_key = get_event_publication_key(request_id.to_string()); + let event_id = Uuid::new_v4(); + let target; + match state.clone().state { + Some(data) => match data { + view_payload::State::View(payload) => { + let request_state = RequestState { + status: request_state::Status::EventReceived as i32, + request_id: request_id.to_string(), + state: Some(request_state::State::View(payload)), + }; + target = EventState { + state: Some(request_state), + event_id: event_id.to_string(), + message: "Successfully received state for event subscribed".to_string(), + }; + } + view_payload::State::Error(error) => { + let request_state = RequestState { + status: request_state::Status::Error as i32, + request_id: request_id.to_string(), + state: Some(request_state::State::Error(error)), + }; + target = EventState { + state: Some(request_state), + event_id: event_id.to_string(), + message: "Received error for the event subscribed".to_string(), + }; + } + }, + None => { + let request_state = RequestState { + status: request_state::Status::Error as i32, + request_id: request_id.to_string(), + state: Some(request_state::State::Error("Missing state".to_string())), + }; + target = EventState { + state: Some(request_state), + event_id: event_id.to_string(), + message: "No state received for the event subscribed".to_string(), + }; + } + }; + let mut event_states_list: Vec = Vec::new(); + event_states_list.push(target.clone()); + if db.has_key(event_publish_key.to_string())? { + let mut curr_event_states: EventStates = db.get::(event_publish_key.to_string()).expect("SendState: Unexpected DB Error"); + event_states_list.append(&mut curr_event_states.states); + } + + let event_states: EventStates = EventStates { + states: event_states_list, + }; + + db.set(&event_publish_key, &event_states) + .expect("Failed to insert into DB"); + + spawn_handle_event( + state, + event_sub_state.event_publication_spec.expect("No Publication Spec stored in event subscription state"), + request_id, + event_id.to_string(), + conf + ); + + return Ok(()); +} + +fn spawn_handle_event(state: ViewPayload, publication_spec: EventPublication, request_id: String, event_id: String, conf: config::Config) { + tokio::spawn(async move { + println!("Event Publish: Sending state to subscriber: Request ID = {:?}", request_id.to_string()); + match state.state.as_ref().unwrap() { + view_payload::State::View(v) => println!("View Meta: {:?}, View Data: {:?}", v.meta, base64::encode(&v.data)), + view_payload::State::Error(e) => println!("Error: {:?}", e), + } + let result = handle_event(state, publication_spec, conf.clone()).await; + match result { + Ok(message) => { + if message.contains("written") { + // Update published event status to written to request_id, event_id in db + update_event_state( + request_id, + event_id, + request_state::Status::EventWritten, + conf.get_str("db_path").unwrap(), + message.to_string(), + ) + } else { + update_event_state( + request_id, + event_id, + request_state::Status::Completed, + conf.get_str("db_path").unwrap(), + message.to_string(), + ) + } + println!("Success: {}", message.to_string()); + } + Err(e) => { + // Update published event status to error and error message to request_id, event_id in db + println!("Write Error: {:?}", e); + update_event_state( + request_id, + event_id, + request_state::Status::EventWriteError, + conf.get_str("db_path").unwrap(), + format!("Write Error: {:?}", e), + ) + } + }; + }); +} + +async fn handle_event( + state: ViewPayload, + publication_spec: EventPublication, + conf: config::Config +) -> Result { + return match publication_spec.publication_target { + Some(data) => match data { + event_publication::PublicationTarget::Ctx(ctx) => { + let driver_id = ctx.clone().driver_id.to_string(); + let result = get_driver(driver_id.to_string(), conf.clone()); + match result { + Ok(driver_info) => { + let client = get_driver_client(driver_info).await?; + println!("Sending Received Event to driver: {:?}", state.clone()); + let write_external_state_message: WriteExternalStateMessage = WriteExternalStateMessage { + view_payload: Some(state), + ctx: Some(ctx), + }; + let ack = client + .clone() + .write_external_state(write_external_state_message) + .await? + .into_inner(); + println!("Response ACK from driver={:?}\n", ack); + let status = ack::Status::from_i32(ack.status) + .ok_or(Error::Simple("Status from Driver error".to_string()))?; + match status { + ack::Status::Ok => Ok(format!("Successfully written to ledger based on ContractTransaction")), + ack::Status::Error => Err(Error::Simple(format!("Error from driver: {}", ack.message))), + } + }, + Err(e) => Err(e), + } + } + event_publication::PublicationTarget::AppUrl(app_url) => { + let app_url_clone = app_url.clone(); + tokio::spawn(async move { + let client = reqwest::Client::new(); + let res = client.post(&app_url_clone) + .json(&state) + .send() + .await; + println!("Result from app: {:?}", res); + }); + Ok(format!("Published to app url: {}", app_url.to_string())) + } + }, + None => { + Ok(format!("Cannot publish event received: No publication target found.")) + } + }; } \ No newline at end of file diff --git a/core/relay/src/services/event_subscribe_service.rs b/core/relay/src/services/event_subscribe_service.rs index 235daf6a3..957adb665 100644 --- a/core/relay/src/services/event_subscribe_service.rs +++ b/core/relay/src/services/event_subscribe_service.rs @@ -1,14 +1,14 @@ // Internal generated modules use crate::pb::common::ack::{ack, Ack}; use crate::pb::common::query::Query; -use crate::pb::common::events::EventSubscription; +use crate::pb::common::events::{EventSubOperation, EventSubscription}; use crate::pb::relay::events::event_subscribe_client::EventSubscribeClient; use crate::pb::relay::events::event_subscribe_server::EventSubscribe; // Internal modules use crate::db::Database; use crate::error::Error; -use crate::relay_proto::{parse_address, LocationSegment}; -use crate::services::helpers::{update_event_subscription_status, get_driver, get_driver_client}; +use crate::relay_proto::{parse_address, LocationSegment} ; +use crate::services::helpers::{update_event_subscription_status, get_driver, get_driver_client, get_event_subscription_key}; use crate::services::types::{Driver}; // external modules use config; @@ -41,7 +41,7 @@ impl EventSubscribe for EventSubscribeService { let remote_db = Database { db_path: conf.get_str("remote_db_path").unwrap(), }; - match subscribe_event_helper(remote_db, request_id.to_string(), event_subscription, query, conf.clone()) { + match subscribe_event_helper(remote_db, request_id.to_string(), event_subscription, conf.clone()) { Ok(ack) => { let reply = Ok(Response::new(ack)); println!("Sending back Ack: {:?}\n", reply); @@ -134,12 +134,14 @@ fn subscribe_event_helper( remote_db: Database, request_id: String, event_subscription: EventSubscription, - query: Query, conf: config::Config, ) -> Result { - let _set_query = remote_db - .set(&request_id.to_string(), &query) + let event_sub_key = get_event_subscription_key(request_id.to_string()); + let _set_event_sub = remote_db + .set(&event_sub_key.to_string(), &event_subscription) .map_err(|e| Error::Simple(format!("DB Failure: {:?}", e)))?; + + let query = event_subscription.query.clone().expect("No query passed with EventSubscription request"); let parsed_address = parse_address(query.address.to_string())?; let result = get_driver(parsed_address.network_id.to_string(), conf.clone()); match result { @@ -230,9 +232,14 @@ fn send_driver_subscription_status_helper( conf: config::Config, ack: Ack, ) -> Result, Error> { - let query: Query = remote_db - .get::(request_id.to_string()) - .map_err(|err| Error::GetQuery(format!("Failed to get query from db. Error: {:?}", err)))?; + let event_sub_key = get_event_subscription_key(request_id.to_string()); + let event_sub: EventSubscription = remote_db + .get::(event_sub_key.to_string()) + .map_err(|err| Error::GetQuery(format!("Failed to get event subscription from db. Error: {:?}", err)))?; + let query: Query = event_sub.query.clone().expect("Unexpected Error: Query not found in event subscription"); + let operation = EventSubOperation::from_i32(event_sub.operation) + .ok_or(Error::Simple("Error: No Event Subscription operation defined".to_string()))?; + let unsubscribe = operation == EventSubOperation::Unsubscribe; let relays_table = conf.get_table("relays")?; let relay_uri = relays_table .get(&query.requesting_relay.to_string()) @@ -244,6 +251,8 @@ fn send_driver_subscription_status_helper( uri.port.to_string(), uri.tls, uri.tlsca_cert_path.to_string(), + unsubscribe, + remote_db ); let reply = Ack { status: ack::Status::Ok as i32, @@ -258,10 +267,20 @@ fn send_driver_subscription_status_helper( // spawn_send_subscription_status sends event subscription status from the remote relay back // to the requesting relay. // When it errors it currently logs to console. Needs improving -fn spawn_send_subscription_status(ack: Ack, requestor_host: String, requester_port: String, use_tls: bool, tlsca_cert_path: String) { +fn spawn_send_subscription_status( + ack: Ack, + requestor_host: String, + requester_port: String, + use_tls: bool, + tlsca_cert_path: String, + unsubscribe: bool, + remote_db: Database, +) { tokio::spawn(async move { - println!("Sending Subscription Status back to requesting relay: Request ID = {:?}", ack.request_id); + let request_id = ack.clone().request_id; + println!("Sending Subscription Status back to requesting relay: Request ID = {:?}", request_id); let client_addr = format!("http://{}:{}", requestor_host, requester_port); + let mut response: Result, tonic::Status> = Err(tonic::Status::unimplemented("uninitialized")); if use_tls { let pem = tokio::fs::read(tlsca_cert_path).await.unwrap(); let ca = Certificate::from_pem(pem); @@ -270,20 +289,20 @@ fn spawn_send_subscription_status(ack: Ack, requestor_host: String, requester_po .ca_certificate(ca) .domain_name(requestor_host); - let channel = Channel::from_shared(client_addr).unwrap() + let channel = Channel::from_shared(client_addr.clone()).unwrap() .tls_config(tls) .connect() .await .unwrap(); let mut client_result = EventSubscribeClient::new(channel); - let response = client_result.send_subscription_status(ack).await; + response = client_result.send_subscription_status(ack.clone()).await; println!("Response ACK from requesting relay={:?}\n", response); } else { - let client_result = EventSubscribeClient::connect(client_addr).await; + let client_result = EventSubscribeClient::connect(client_addr.clone()).await; match client_result { Ok(client) => { - let response = client.clone().send_subscription_status(ack).await; + response = client.clone().send_subscription_status(ack.clone()).await; println!("Response ACK from requesting relay={:?}\n", response); // Not returning anything here } @@ -299,6 +318,39 @@ fn spawn_send_subscription_status(ack: Ack, requestor_host: String, requester_po } } } + if unsubscribe { + println!("\nUnsubscribe Operation, deleting entry from remote_db\n"); + match response { + Ok(response_ack) => { + println!("Response ACK from relay={:?}\n", ack); + match ack::Status::from_i32(response_ack.into_inner().status) { + Some(status) => match status { + ack::Status::Ok => { + let event_sub_key = get_event_subscription_key(request_id.to_string()); + let db_result = remote_db.unset::(event_sub_key); + match db_result { + Ok(old_state) => { + println!("Removed EventSubscription from database: {:?}", old_state); + }, + Err(e) => { + println!("EventSubscription Request not found. Error: {:?}", e); + } + } + }, + ack::Status::Error => { + println!("Error from relay: {}", ack.message) + } + } + None => { + println!("Error: No Ack Status from relay") + } + } + } + Err(_e) => { + println!("Error: error connecting to relay at {}", client_addr); + } + } + } }); } diff --git a/core/relay/src/services/helpers.rs b/core/relay/src/services/helpers.rs index 233e3af2f..5026d9179 100644 --- a/core/relay/src/services/helpers.rs +++ b/core/relay/src/services/helpers.rs @@ -1,7 +1,8 @@ use crate::pb::common::ack::{ack}; use crate::pb::common::query::Query; +use crate::pb::common::state::{request_state, RequestState}; use crate::pb::common::events::{event_subscription_state, EventSubscriptionState}; -use crate::pb::common::events::{EventSubscription}; +use crate::pb::common::events::{EventSubscription, EventStates, EventState}; use crate::pb::driver::driver::driver_communication_client::DriverCommunicationClient; use crate::db::Database; @@ -25,7 +26,8 @@ pub fn update_event_subscription_status( let db = Database { db_path: curr_db_path, }; - let result = db.get::(curr_request_id.clone()); + let event_sub_key = get_event_subscription_key(curr_request_id.clone()); + let result = db.get::(event_sub_key.to_string()); match result { Ok(fetched_event_sub_state) => { let target: EventSubscriptionState; @@ -99,10 +101,10 @@ pub fn update_event_subscription_status( } // Panic if this fails, atm the panic is just logged by the tokio runtime - db.set(&curr_request_id, &target) + db.set(&event_sub_key.to_string(), &target) .expect("Failed to insert into DB"); println!("Successfully written EventSubscriptionState to database"); - println!("{:?}\n", db.get::(curr_request_id).unwrap()) + println!("{:?}\n", db.get::(event_sub_key.to_string()).unwrap()) }, Err(e) => { @@ -202,4 +204,94 @@ pub async fn driver_sign_subscription_helper( }, Err(e) => Err(e), } +} + +pub fn update_event_state( + request_id: String, + event_id: String, + new_status: request_state::Status, + curr_db_path: String, + message: String, +) { + let db = Database { + db_path: curr_db_path, + }; + let event_publish_key = get_event_publication_key(request_id.to_string()); + let result = db.get::(event_publish_key.to_string()); + match result { + Ok(fetched_event_states) => { + let mut updated_event_states: Vec = Vec::new(); + for fetched_event_state in fetched_event_states.states { + if fetched_event_state.event_id.to_string() == event_id.to_string() { + let new_request_state: RequestState = RequestState { + status: new_status as i32, + request_id: request_id.to_string(), + state: fetched_event_state.state.expect("No State found").state, + }; + let new_event_state: EventState = EventState { + state: Some(new_request_state), + event_id: event_id.to_string(), + message: message.to_string(), + }; + updated_event_states.push(new_event_state); + } + else { + updated_event_states.push(fetched_event_state); + } + } + // Panic if this fails, atm the panic is just logged by the tokio runtime + db.set(&event_publish_key.to_string(), &updated_event_states) + .expect("Failed to insert into DB"); + println!("Successfully updated EventStates in database"); + println!("{:?}\n", updated_event_states); + }, + Err(e) => { + println!("EventStates not found. Error: {:?}", e); + }, + } +} + +pub fn try_mark_request_state_deleted(state: RequestState, request_id: String, db: Database) { + let state_status = request_state::Status::from_i32(state.clone().status).expect("No Status"); + if state_status == request_state::Status::Error || + state_status == request_state::Status::Completed { + let deleted_request_state = RequestState { + status: request_state::Status::Deleted as i32, + request_id: request_id.to_string(), + state: state.state, + }; + db.set(&request_id, &deleted_request_state) + .expect("RequestState Delete: Failed to insert into DB"); + } +} + +pub fn mark_event_states_deleted(fetched_event_states: EventStates, request_id: String, db: Database) { + let mut updated_event_states: Vec = Vec::new(); + for fetched_event_state in fetched_event_states.states { + let state_status = request_state::Status::from_i32(fetched_event_state.clone().state.expect("No State").status).expect("No Status"); + if state_status == request_state::Status::Error || + state_status == request_state::Status::Completed || + state_status == request_state::Status::EventWritten { + let deleted_request_state = RequestState { + status: request_state::Status::Deleted as i32, + request_id: request_id.to_string(), + state: fetched_event_state.state.expect("No State found").state, + }; + let deleted_event_state = EventState { + state: Some(deleted_request_state), + event_id: fetched_event_state.event_id, + message: fetched_event_state.message.to_string(), + }; + updated_event_states.push(deleted_event_state); + } + } + + db.set(&get_event_publication_key(request_id.to_string()), &updated_event_states) + .expect("EventState Delete: Failed to insert into DB"); +} +pub fn get_event_subscription_key(request_id: String) -> String { + return format!("event_sub_{}", request_id); +} +pub fn get_event_publication_key(request_id: String) -> String { + return format!("event_pub_{}", request_id); } \ No newline at end of file diff --git a/core/relay/src/services/network_service.rs b/core/relay/src/services/network_service.rs index 31568da8b..b93969c98 100644 --- a/core/relay/src/services/network_service.rs +++ b/core/relay/src/services/network_service.rs @@ -2,7 +2,7 @@ use crate::pb::common::ack::{ack, Ack}; use crate::pb::common::query::Query; use crate::pb::common::state::{request_state, RequestState}; -use crate::pb::common::events::{EventSubscription, event_subscription_state, EventSubscriptionState, EventSubOperation, event_publication, EventPublication}; +use crate::pb::common::events::{EventSubscription, event_subscription_state, EventSubscriptionState, EventSubOperation, event_publication, EventPublication, EventStates}; use crate::pb::networks::networks::network_server::Network; use crate::pb::networks::networks::{DbName, GetStateMessage, NetworkQuery, RelayDatabase, NetworkEventSubscription, NetworkEventUnsubscription}; use crate::pb::relay::datatransfer::data_transfer_client::DataTransferClient; @@ -10,8 +10,7 @@ use crate::pb::relay::events::event_subscribe_client::EventSubscribeClient; use crate::relay_proto::{parse_address, LocationSegment}; // Internal modules use crate::db::Database; -use crate::services::helpers::update_event_subscription_status; -use crate::services::helpers::driver_sign_subscription_helper; +use crate::services::helpers::{update_event_subscription_status, driver_sign_subscription_helper, try_mark_request_state_deleted, mark_event_states_deleted, get_event_publication_key, get_event_subscription_key}; // External modules use config; @@ -39,7 +38,8 @@ impl Network for NetworkService { let db = Database { db_path: conf.get_str("db_path").unwrap(), }; - let result = db.get::(request.into_inner().request_id); + let request_id = request.into_inner().request_id; + let result = db.get::(request_id.to_string()); match result { Ok(request_state) => { println!("Sending back RequestState to network: Request ID = {:?}, Status = {:?}", @@ -48,6 +48,7 @@ impl Network for NetworkService { ); match request_state.state.as_ref() { Some(state) => { + try_mark_request_state_deleted(request_state.clone(), request_id.to_string(), db); match state { request_state::State::View(v) => println!("View Meta: {:?}, View Data: {:?}", v.meta, base64::encode(&v.data)), request_state::State::Error(e) => println!("Error: {:?}", e), @@ -75,14 +76,34 @@ impl Network for NetworkService { let mut curr_key = req_db.get_gt("").unwrap(); while let Some(key) = curr_key { - let decoded_result: Result = - bincode::deserialize(&key.1[..]); // println!("{:?}", key); let decoded_key = std::str::from_utf8(&key.0[..]).unwrap(); - requests.insert( - format!("{:?}", decoded_key), - format!("{:?}", decoded_result), - ); + + if decoded_key.to_string().contains(&"event_sub".to_string()) { + let decoded_result: Result = + bincode::deserialize(&key.1[..]); + requests.insert( + format!("{:?}", decoded_key), + format!("{:?}", decoded_result), + ); + println!("Event Sub {:?} => {:?}", decoded_key, decoded_result); + } else if decoded_key.to_string().contains(&"event_pub".to_string()) { + let decoded_result: Result = + bincode::deserialize(&key.1[..]); + requests.insert( + format!("{:?}", decoded_key), + format!("{:?}", decoded_result), + ); + println!("Event Pub {:?} => {:?}", decoded_key, decoded_result); + } else { + let decoded_result: Result = + bincode::deserialize(&key.1[..]); + requests.insert( + format!("{:?}", decoded_key), + format!("{:?}", decoded_result), + ); + println!("RequestState {:?} => {:?}", decoded_key, decoded_result); + } curr_key = req_db.get_gt(key.0).unwrap(); } return Ok(Response::new(RelayDatabase { pairs: requests })); @@ -227,13 +248,14 @@ impl Network for NetworkService { let db = Database { db_path: conf.get_str("db_path").unwrap(), }; - let result = db.get::(request.into_inner().request_id); + let event_sub_key = get_event_subscription_key(request.into_inner().request_id); + let result = db.get::(event_sub_key.to_string()); match result { Ok(fetched_event_sub_state) => { match event_subscription_state::Status::from_i32(fetched_event_sub_state.status) { Some(status) => match status { event_subscription_state::Status::Unsubscribed => { - let result = db.unset::(fetched_event_sub_state.clone().request_id); + let result = db.unset::(event_sub_key.to_string()); match result { Ok(old_state) => { println!("Removed EventSubscription from database: {:?}", old_state); @@ -310,6 +332,35 @@ impl Network for NetworkService { return event_subscription_helper(event_subscription, event_publication_spec, target, request_id.to_string(), db, conf).await; } + + // Fetch EventStates for given subscription request identified by request_id. + async fn get_event_states( + &self, + request: Request, + ) -> Result, Status> { + println!("\nReceived GetEventStates request from network: {:?}", request); + let conf = self.config_lock.read().await.clone(); + let db = Database { + db_path: conf.get_str("db_path").unwrap(), + }; + let request_id = request.into_inner().request_id; + let event_publish_key = get_event_publication_key(request_id.to_string()); + let result = db.get::(event_publish_key.to_string()); + match result { + Ok(fetched_event_states) => { + mark_event_states_deleted(fetched_event_states.clone(), request_id.to_string(), db); + println!("Sending back EventStates to network: Request ID = {:?}: {:?}", + request_id.to_string(), + fetched_event_states.clone() + ); + return Ok(Response::new(fetched_event_states)); + }, + Err(e) => Err(Status::new( + Code::NotFound, + format!("EventStates not found for request_id: {}. Error: {:?}", request_id.to_string(), e), + )), + } + } } async fn event_subscription_helper( @@ -371,7 +422,8 @@ async fn event_subscription_helper( } }; - let message_insert = db.set(&request_id.to_string(), &target_status); + let event_sub_key = get_event_subscription_key(request_id.to_string()); + let message_insert = db.set(&event_sub_key.to_string(), &target_status); // Kept this as a match as the error case returns an Ok. match message_insert { Ok(_) => println!( From dc2a4cd7076bfc738507002f21c85591ffdb9f90 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Wed, 20 Jul 2022 20:17:00 +0530 Subject: [PATCH 053/150] updated protos required for event publish, and protos version to 1.4.2 Signed-off-by: sandeep.nishad1 --- common/protos-go/common/events.pb.go | 375 +++++++++++++----- common/protos-go/common/state.pb.go | 60 ++- common/protos-go/driver/driver.pb.go | 188 +++++++-- common/protos-go/driver/driver_grpc.pb.go | 40 ++ common/protos-go/networks/networks.pb.go | 45 ++- common/protos-go/networks/networks_grpc.pb.go | 40 ++ common/protos-go/relay/events.pb.go | 65 +-- common/protos-go/relay/events_grpc.pb.go | 126 ++++++ common/protos-java-kt/gradle.properties | 2 +- common/protos-js/package.json | 2 +- common/protos/common/events.proto | 15 +- common/protos/common/state.proto | 8 +- common/protos/networks/networks.proto | 3 + core/drivers/corda-driver/build.gradle | 2 +- .../corda-interop-app/constants.properties | 2 +- .../constants.properties | 2 +- sdks/corda/build.gradle | 2 +- .../corda/scripts/get-cordapps.sh | 2 +- .../corda/scripts/start-nodes.sh | 2 +- 19 files changed, 755 insertions(+), 226 deletions(-) diff --git a/common/protos-go/common/events.pb.go b/common/protos-go/common/events.pb.go index 080c9764c..76160920d 100644 --- a/common/protos-go/common/events.pb.go +++ b/common/protos-go/common/events.pb.go @@ -571,107 +571,232 @@ func (*EventPublication_Ctx) isEventPublication_PublicationTarget() {} func (*EventPublication_AppUrl) isEventPublication_PublicationTarget() {} +type EventStates struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + States []*EventState `protobuf:"bytes,1,rep,name=states,proto3" json:"states,omitempty"` +} + +func (x *EventStates) Reset() { + *x = EventStates{} + if protoimpl.UnsafeEnabled { + mi := &file_common_events_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EventStates) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EventStates) ProtoMessage() {} + +func (x *EventStates) ProtoReflect() protoreflect.Message { + mi := &file_common_events_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EventStates.ProtoReflect.Descriptor instead. +func (*EventStates) Descriptor() ([]byte, []int) { + return file_common_events_proto_rawDescGZIP(), []int{5} +} + +func (x *EventStates) GetStates() []*EventState { + if x != nil { + return x.States + } + return nil +} + +// the payload that is used for the communication between the requesting relay +// and its network +type EventState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + State *RequestState `protobuf:"bytes,1,opt,name=state,proto3" json:"state,omitempty"` + EventId string `protobuf:"bytes,2,opt,name=event_id,json=eventId,proto3" json:"event_id,omitempty"` + Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *EventState) Reset() { + *x = EventState{} + if protoimpl.UnsafeEnabled { + mi := &file_common_events_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EventState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EventState) ProtoMessage() {} + +func (x *EventState) ProtoReflect() protoreflect.Message { + mi := &file_common_events_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EventState.ProtoReflect.Descriptor instead. +func (*EventState) Descriptor() ([]byte, []int) { + return file_common_events_proto_rawDescGZIP(), []int{6} +} + +func (x *EventState) GetState() *RequestState { + if x != nil { + return x.State + } + return nil +} + +func (x *EventState) GetEventId() string { + if x != nil { + return x.EventId + } + return "" +} + +func (x *EventState) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + var File_common_events_proto protoreflect.FileDescriptor var file_common_events_proto_rawDesc = []byte{ 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0x12, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x71, 0x75, 0x65, - 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x84, 0x02, 0x0a, 0x0c, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x37, 0x0a, 0x0a, 0x65, 0x76, 0x65, - 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6c, 0x61, 0x73, - 0x73, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x15, 0x74, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x5f, 0x69, - 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x49, 0x64, 0x12, 0x36, 0x0a, 0x17, - 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x74, - 0x72, 0x61, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, - 0x63, 0x74, 0x49, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, - 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x75, 0x6e, 0x63, 0x22, - 0xc0, 0x01, 0x0a, 0x11, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, - 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x52, 0x0c, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x29, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, - 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x05, 0x71, 0x75, 0x65, - 0x72, 0x79, 0x12, 0x3e, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, - 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x4f, 0x70, - 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x22, 0xd0, 0x03, 0x0a, 0x16, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1d, 0x0a, - 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x44, 0x0a, 0x06, - 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x2e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x40, 0x0a, 0x0d, - 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, - 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, - 0x52, 0x0c, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x55, - 0x0a, 0x16, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, - 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x14, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x53, 0x70, 0x65, 0x63, 0x22, 0x9d, 0x01, 0x0a, 0x06, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, - 0x12, 0x19, 0x0a, 0x15, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x5f, 0x50, 0x45, - 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x41, 0x43, 0x4b, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x53, - 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, - 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x44, - 0x10, 0x02, 0x12, 0x1b, 0x0a, 0x17, 0x55, 0x4e, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, - 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x41, 0x43, 0x4b, 0x10, 0x03, 0x12, - 0x17, 0x0a, 0x13, 0x55, 0x4e, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x5f, 0x50, - 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x04, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x53, 0x55, - 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x44, 0x10, 0x05, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, - 0x52, 0x4f, 0x52, 0x10, 0x06, 0x22, 0xc4, 0x01, 0x0a, 0x13, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, - 0x63, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, - 0x09, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x65, - 0x64, 0x67, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, - 0x65, 0x64, 0x67, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x72, - 0x61, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x75, 0x6e, 0x63, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x75, 0x6e, 0x63, 0x12, 0x12, 0x0a, 0x04, - 0x61, 0x72, 0x67, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x04, 0x61, 0x72, 0x67, 0x73, - 0x12, 0x2a, 0x0a, 0x11, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x5f, 0x61, 0x72, 0x67, 0x5f, - 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x72, 0x65, 0x70, - 0x6c, 0x61, 0x63, 0x65, 0x41, 0x72, 0x67, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x7b, 0x0a, 0x10, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x36, 0x0a, 0x03, 0x63, 0x74, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, + 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x12, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x84, 0x02, 0x0a, + 0x0c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x37, 0x0a, + 0x0a, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x18, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x09, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, + 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x15, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x65, 0x64, 0x67, + 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x49, 0x64, + 0x12, 0x36, 0x0a, 0x17, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x15, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, + 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x49, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x46, + 0x75, 0x6e, 0x63, 0x22, 0xc0, 0x01, 0x0a, 0x11, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x0d, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, + 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x52, 0x0c, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x29, 0x0a, 0x05, 0x71, + 0x75, 0x65, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, + 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x3e, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, + 0x75, 0x62, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x6f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xd0, 0x03, 0x0a, 0x16, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, + 0x12, 0x44, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x2c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, + 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x52, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x40, 0x0a, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, + 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, + 0x63, 0x68, 0x65, 0x72, 0x52, 0x0c, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, + 0x65, 0x72, 0x12, 0x55, 0x0a, 0x16, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x14, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x22, 0x9d, 0x01, 0x0a, 0x06, 0x53, 0x54, + 0x41, 0x54, 0x55, 0x53, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, + 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x41, 0x43, 0x4b, 0x10, 0x00, 0x12, + 0x15, 0x0a, 0x11, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x5f, 0x50, 0x45, 0x4e, + 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, + 0x49, 0x42, 0x45, 0x44, 0x10, 0x02, 0x12, 0x1b, 0x0a, 0x17, 0x55, 0x4e, 0x53, 0x55, 0x42, 0x53, + 0x43, 0x52, 0x49, 0x42, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x41, 0x43, + 0x4b, 0x10, 0x03, 0x12, 0x17, 0x0a, 0x13, 0x55, 0x4e, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, + 0x42, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x04, 0x12, 0x10, 0x0a, 0x0c, + 0x55, 0x4e, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x44, 0x10, 0x05, 0x12, 0x09, + 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x06, 0x22, 0xc4, 0x01, 0x0a, 0x13, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x48, 0x00, 0x52, 0x03, 0x63, 0x74, 0x78, 0x12, 0x19, 0x0a, 0x07, 0x61, 0x70, 0x70, 0x5f, - 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x61, 0x70, 0x70, - 0x55, 0x72, 0x6c, 0x42, 0x14, 0x0a, 0x12, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2a, 0x3e, 0x0a, 0x09, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x4c, 0x45, 0x44, 0x47, 0x45, 0x52, - 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x53, 0x53, 0x45, - 0x54, 0x5f, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x53, 0x53, 0x45, - 0x54, 0x5f, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x10, 0x02, 0x2a, 0x3f, 0x0a, 0x11, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x53, 0x75, 0x62, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0d, - 0x0a, 0x09, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x10, 0x00, 0x12, 0x0f, 0x0a, - 0x0b, 0x55, 0x4e, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x10, 0x01, 0x12, 0x0a, - 0x0a, 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x02, 0x42, 0x72, 0x0a, 0x1f, 0x63, 0x6f, - 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x5a, 0x4f, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, - 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, - 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, - 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1b, + 0x0a, 0x09, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, + 0x66, 0x75, 0x6e, 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x75, 0x6e, 0x63, + 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x67, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x04, + 0x61, 0x72, 0x67, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x5f, + 0x61, 0x72, 0x67, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x41, 0x72, 0x67, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x22, 0x7b, 0x0a, 0x10, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x03, 0x63, 0x74, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x03, 0x63, 0x74, 0x78, 0x12, 0x19, 0x0a, 0x07, + 0x61, 0x70, 0x70, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, + 0x06, 0x61, 0x70, 0x70, 0x55, 0x72, 0x6c, 0x42, 0x14, 0x0a, 0x12, 0x70, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0x40, 0x0a, + 0x0b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x12, 0x31, 0x0a, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x65, 0x73, 0x22, + 0x73, 0x0a, 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x30, 0x0a, + 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, + 0x19, 0x0a, 0x08, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x2a, 0x3e, 0x0a, 0x09, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x4c, 0x45, 0x44, 0x47, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, + 0x45, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x53, 0x53, 0x45, 0x54, 0x5f, 0x4c, 0x4f, 0x43, + 0x4b, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x53, 0x53, 0x45, 0x54, 0x5f, 0x43, 0x4c, 0x41, + 0x49, 0x4d, 0x10, 0x02, 0x2a, 0x3f, 0x0a, 0x11, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, + 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x55, 0x42, + 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x55, + 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x50, 0x44, + 0x41, 0x54, 0x45, 0x10, 0x02, 0x42, 0x72, 0x0a, 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, + 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, + 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, + 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, + 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, + 0x67, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( @@ -687,7 +812,7 @@ func file_common_events_proto_rawDescGZIP() []byte { } var file_common_events_proto_enumTypes = make([]protoimpl.EnumInfo, 3) -var file_common_events_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_common_events_proto_msgTypes = make([]protoimpl.MessageInfo, 7) var file_common_events_proto_goTypes = []interface{}{ (EventType)(0), // 0: common.events.EventType (EventSubOperation)(0), // 1: common.events.EventSubOperation @@ -697,22 +822,27 @@ var file_common_events_proto_goTypes = []interface{}{ (*EventSubscriptionState)(nil), // 5: common.events.EventSubscriptionState (*ContractTransaction)(nil), // 6: common.events.ContractTransaction (*EventPublication)(nil), // 7: common.events.EventPublication - (*Query)(nil), // 8: common.query.Query + (*EventStates)(nil), // 8: common.events.EventStates + (*EventState)(nil), // 9: common.events.EventState + (*Query)(nil), // 10: common.query.Query + (*RequestState)(nil), // 11: common.state.RequestState } var file_common_events_proto_depIdxs = []int32{ - 0, // 0: common.events.EventMatcher.event_type:type_name -> common.events.EventType - 3, // 1: common.events.EventSubscription.event_matcher:type_name -> common.events.EventMatcher - 8, // 2: common.events.EventSubscription.query:type_name -> common.query.Query - 1, // 3: common.events.EventSubscription.operation:type_name -> common.events.EventSubOperation - 2, // 4: common.events.EventSubscriptionState.status:type_name -> common.events.EventSubscriptionState.STATUS - 3, // 5: common.events.EventSubscriptionState.event_matcher:type_name -> common.events.EventMatcher - 7, // 6: common.events.EventSubscriptionState.event_publication_spec:type_name -> common.events.EventPublication - 6, // 7: common.events.EventPublication.ctx:type_name -> common.events.ContractTransaction - 8, // [8:8] is the sub-list for method output_type - 8, // [8:8] is the sub-list for method input_type - 8, // [8:8] is the sub-list for extension type_name - 8, // [8:8] is the sub-list for extension extendee - 0, // [0:8] is the sub-list for field type_name + 0, // 0: common.events.EventMatcher.event_type:type_name -> common.events.EventType + 3, // 1: common.events.EventSubscription.event_matcher:type_name -> common.events.EventMatcher + 10, // 2: common.events.EventSubscription.query:type_name -> common.query.Query + 1, // 3: common.events.EventSubscription.operation:type_name -> common.events.EventSubOperation + 2, // 4: common.events.EventSubscriptionState.status:type_name -> common.events.EventSubscriptionState.STATUS + 3, // 5: common.events.EventSubscriptionState.event_matcher:type_name -> common.events.EventMatcher + 7, // 6: common.events.EventSubscriptionState.event_publication_spec:type_name -> common.events.EventPublication + 6, // 7: common.events.EventPublication.ctx:type_name -> common.events.ContractTransaction + 9, // 8: common.events.EventStates.states:type_name -> common.events.EventState + 11, // 9: common.events.EventState.state:type_name -> common.state.RequestState + 10, // [10:10] is the sub-list for method output_type + 10, // [10:10] is the sub-list for method input_type + 10, // [10:10] is the sub-list for extension type_name + 10, // [10:10] is the sub-list for extension extendee + 0, // [0:10] is the sub-list for field type_name } func init() { file_common_events_proto_init() } @@ -721,6 +851,7 @@ func file_common_events_proto_init() { return } file_common_query_proto_init() + file_common_state_proto_init() if !protoimpl.UnsafeEnabled { file_common_events_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*EventMatcher); i { @@ -782,6 +913,30 @@ func file_common_events_proto_init() { return nil } } + file_common_events_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EventStates); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_common_events_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EventState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_common_events_proto_msgTypes[4].OneofWrappers = []interface{}{ (*EventPublication_Ctx)(nil), @@ -793,7 +948,7 @@ func file_common_events_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_common_events_proto_rawDesc, NumEnums: 3, - NumMessages: 5, + NumMessages: 7, NumExtensions: 0, NumServices: 0, }, diff --git a/common/protos-go/common/state.pb.go b/common/protos-go/common/state.pb.go index b69e94b65..3f22d0359 100644 --- a/common/protos-go/common/state.pb.go +++ b/common/protos-go/common/state.pb.go @@ -78,9 +78,13 @@ const ( // pending ACK from remote relay RequestState_PENDING_ACK RequestState_STATUS = 0 // Received ACK, waiting for data to be sent from remote relay - RequestState_PENDING RequestState_STATUS = 1 - RequestState_ERROR RequestState_STATUS = 2 - RequestState_COMPLETED RequestState_STATUS = 3 + RequestState_PENDING RequestState_STATUS = 1 + RequestState_ERROR RequestState_STATUS = 2 // View is not there, received error from remote relay + RequestState_COMPLETED RequestState_STATUS = 3 // Data Sharing completed Successfully + RequestState_EVENT_RECEIVED RequestState_STATUS = 4 // View is there and event is received from remote relay + RequestState_EVENT_WRITTEN RequestState_STATUS = 5 // Driver Successfully wrote the view to ledger, hence view is not stored anymore. + RequestState_EVENT_WRITE_ERROR RequestState_STATUS = 6 // View is there but driver failed to write + RequestState_DELETED RequestState_STATUS = 7 // Once network fetches this request state, mark it delete for cleanup later on. ) // Enum value maps for RequestState_STATUS. @@ -90,12 +94,20 @@ var ( 1: "PENDING", 2: "ERROR", 3: "COMPLETED", + 4: "EVENT_RECEIVED", + 5: "EVENT_WRITTEN", + 6: "EVENT_WRITE_ERROR", + 7: "DELETED", } RequestState_STATUS_value = map[string]int32{ - "PENDING_ACK": 0, - "PENDING": 1, - "ERROR": 2, - "COMPLETED": 3, + "PENDING_ACK": 0, + "PENDING": 1, + "ERROR": 2, + "COMPLETED": 3, + "EVENT_RECEIVED": 4, + "EVENT_WRITTEN": 5, + "EVENT_WRITE_ERROR": 6, + "DELETED": 7, } ) @@ -481,7 +493,7 @@ var file_common_state_proto_rawDesc = []byte{ 0x65, 0x2e, 0x56, 0x69, 0x65, 0x77, 0x48, 0x00, 0x52, 0x04, 0x76, 0x69, 0x65, 0x77, 0x12, 0x16, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, 0x07, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, - 0xf5, 0x01, 0x0a, 0x0c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, + 0xc1, 0x02, 0x0a, 0x0c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x39, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, @@ -491,20 +503,24 @@ var file_common_state_proto_rawDesc = []byte{ 0x65, 0x77, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x56, 0x69, 0x65, 0x77, 0x48, 0x00, 0x52, 0x04, 0x76, 0x69, 0x65, 0x77, 0x12, 0x16, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x40, 0x0a, 0x06, - 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, - 0x47, 0x5f, 0x41, 0x43, 0x4b, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x45, 0x4e, 0x44, 0x49, - 0x4e, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, - 0x0d, 0x0a, 0x09, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x03, 0x42, 0x07, - 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x42, 0x71, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x77, - 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, - 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, - 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, - 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, - 0x2d, 0x67, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x8b, 0x01, 0x0a, + 0x06, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x45, 0x4e, 0x44, 0x49, + 0x4e, 0x47, 0x5f, 0x41, 0x43, 0x4b, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x45, 0x4e, 0x44, + 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, + 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x03, 0x12, + 0x12, 0x0a, 0x0e, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x43, 0x45, 0x49, 0x56, 0x45, + 0x44, 0x10, 0x04, 0x12, 0x11, 0x0a, 0x0d, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x57, 0x52, 0x49, + 0x54, 0x54, 0x45, 0x4e, 0x10, 0x05, 0x12, 0x15, 0x0a, 0x11, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, + 0x57, 0x52, 0x49, 0x54, 0x45, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x06, 0x12, 0x0b, 0x0a, + 0x07, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x07, 0x42, 0x07, 0x0a, 0x05, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x42, 0x71, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, + 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, + 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/common/protos-go/driver/driver.pb.go b/common/protos-go/driver/driver.pb.go index 3f324a774..a0d669699 100644 --- a/common/protos-go/driver/driver.pb.go +++ b/common/protos-go/driver/driver.pb.go @@ -11,6 +11,7 @@ import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" + sync "sync" ) const ( @@ -20,6 +21,62 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// Data for a View processing by dest-driver +type WriteExternalStateMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ViewPayload *common.ViewPayload `protobuf:"bytes,1,opt,name=view_payload,json=viewPayload,proto3" json:"view_payload,omitempty"` + Ctx *common.ContractTransaction `protobuf:"bytes,2,opt,name=ctx,proto3" json:"ctx,omitempty"` +} + +func (x *WriteExternalStateMessage) Reset() { + *x = WriteExternalStateMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_driver_driver_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WriteExternalStateMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WriteExternalStateMessage) ProtoMessage() {} + +func (x *WriteExternalStateMessage) ProtoReflect() protoreflect.Message { + mi := &file_driver_driver_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WriteExternalStateMessage.ProtoReflect.Descriptor instead. +func (*WriteExternalStateMessage) Descriptor() ([]byte, []int) { + return file_driver_driver_proto_rawDescGZIP(), []int{0} +} + +func (x *WriteExternalStateMessage) GetViewPayload() *common.ViewPayload { + if x != nil { + return x.ViewPayload + } + return nil +} + +func (x *WriteExternalStateMessage) GetCtx() *common.ContractTransaction { + if x != nil { + return x.Ctx + } + return nil +} + var File_driver_driver_proto protoreflect.FileDescriptor var file_driver_driver_proto_rawDesc = []byte{ @@ -28,50 +85,86 @@ var file_driver_driver_proto_rawDesc = []byte{ 0x69, 0x76, 0x65, 0x72, 0x1a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x61, 0x63, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x12, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x13, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, - 0xfa, 0x01, 0x0a, 0x13, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x13, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x51, 0x75, 0x65, - 0x72, 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, - 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x45, 0x0a, 0x0e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x62, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x5e, 0x0a, 0x23, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x51, 0x75, - 0x65, 0x72, 0x79, 0x12, 0x20, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, - 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x71, - 0x75, 0x65, 0x72, 0x79, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x22, 0x00, 0x42, 0x72, 0x0a, 0x1f, - 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x73, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x5a, - 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, - 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, - 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, - 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x6e, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, + 0x12, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x22, 0x8f, 0x01, 0x0a, 0x19, 0x57, 0x72, 0x69, 0x74, 0x65, 0x45, 0x78, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x3c, 0x0a, 0x0c, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x56, 0x69, 0x65, 0x77, 0x50, 0x61, 0x79, 0x6c, 0x6f, + 0x61, 0x64, 0x52, 0x0b, 0x76, 0x69, 0x65, 0x77, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, + 0x34, 0x0a, 0x03, 0x63, 0x74, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, + 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x03, 0x63, 0x74, 0x78, 0x32, 0xcd, 0x02, 0x0a, 0x13, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, + 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, + 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x71, 0x75, 0x65, + 0x72, 0x79, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x45, 0x0a, 0x0e, 0x53, + 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, + 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, + 0x22, 0x00, 0x12, 0x5e, 0x0a, 0x23, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x69, 0x67, + 0x6e, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x20, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, + 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x13, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x22, 0x00, 0x12, 0x51, 0x0a, 0x12, 0x57, 0x72, 0x69, 0x74, 0x65, 0x45, 0x78, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x28, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, + 0x72, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x45, 0x78, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, + 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, 0x72, 0x0a, 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, + 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, + 0x72, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, + 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, + 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, + 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, + 0x67, 0x6f, 0x2f, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, +} + +var ( + file_driver_driver_proto_rawDescOnce sync.Once + file_driver_driver_proto_rawDescData = file_driver_driver_proto_rawDesc +) + +func file_driver_driver_proto_rawDescGZIP() []byte { + file_driver_driver_proto_rawDescOnce.Do(func() { + file_driver_driver_proto_rawDescData = protoimpl.X.CompressGZIP(file_driver_driver_proto_rawDescData) + }) + return file_driver_driver_proto_rawDescData } +var file_driver_driver_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_driver_driver_proto_goTypes = []interface{}{ - (*common.Query)(nil), // 0: common.query.Query - (*common.EventSubscription)(nil), // 1: common.events.EventSubscription - (*common.Ack)(nil), // 2: common.ack.Ack + (*WriteExternalStateMessage)(nil), // 0: driver.driver.WriteExternalStateMessage + (*common.ViewPayload)(nil), // 1: common.state.ViewPayload + (*common.ContractTransaction)(nil), // 2: common.events.ContractTransaction + (*common.Query)(nil), // 3: common.query.Query + (*common.EventSubscription)(nil), // 4: common.events.EventSubscription + (*common.Ack)(nil), // 5: common.ack.Ack } var file_driver_driver_proto_depIdxs = []int32{ - 0, // 0: driver.driver.DriverCommunication.RequestDriverState:input_type -> common.query.Query - 1, // 1: driver.driver.DriverCommunication.SubscribeEvent:input_type -> common.events.EventSubscription - 1, // 2: driver.driver.DriverCommunication.RequestSignedEventSubscriptionQuery:input_type -> common.events.EventSubscription - 2, // 3: driver.driver.DriverCommunication.RequestDriverState:output_type -> common.ack.Ack - 2, // 4: driver.driver.DriverCommunication.SubscribeEvent:output_type -> common.ack.Ack - 0, // 5: driver.driver.DriverCommunication.RequestSignedEventSubscriptionQuery:output_type -> common.query.Query - 3, // [3:6] is the sub-list for method output_type - 0, // [0:3] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name + 1, // 0: driver.driver.WriteExternalStateMessage.view_payload:type_name -> common.state.ViewPayload + 2, // 1: driver.driver.WriteExternalStateMessage.ctx:type_name -> common.events.ContractTransaction + 3, // 2: driver.driver.DriverCommunication.RequestDriverState:input_type -> common.query.Query + 4, // 3: driver.driver.DriverCommunication.SubscribeEvent:input_type -> common.events.EventSubscription + 4, // 4: driver.driver.DriverCommunication.RequestSignedEventSubscriptionQuery:input_type -> common.events.EventSubscription + 0, // 5: driver.driver.DriverCommunication.WriteExternalState:input_type -> driver.driver.WriteExternalStateMessage + 5, // 6: driver.driver.DriverCommunication.RequestDriverState:output_type -> common.ack.Ack + 5, // 7: driver.driver.DriverCommunication.SubscribeEvent:output_type -> common.ack.Ack + 3, // 8: driver.driver.DriverCommunication.RequestSignedEventSubscriptionQuery:output_type -> common.query.Query + 5, // 9: driver.driver.DriverCommunication.WriteExternalState:output_type -> common.ack.Ack + 6, // [6:10] is the sub-list for method output_type + 2, // [2:6] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name } func init() { file_driver_driver_proto_init() } @@ -79,18 +172,33 @@ func file_driver_driver_proto_init() { if File_driver_driver_proto != nil { return } + if !protoimpl.UnsafeEnabled { + file_driver_driver_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WriteExternalStateMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_driver_driver_proto_rawDesc, NumEnums: 0, - NumMessages: 0, + NumMessages: 1, NumExtensions: 0, NumServices: 1, }, GoTypes: file_driver_driver_proto_goTypes, DependencyIndexes: file_driver_driver_proto_depIdxs, + MessageInfos: file_driver_driver_proto_msgTypes, }.Build() File_driver_driver_proto = out.File file_driver_driver_proto_rawDesc = nil diff --git a/common/protos-go/driver/driver_grpc.pb.go b/common/protos-go/driver/driver_grpc.pb.go index 0fa151bcc..b129a6e94 100644 --- a/common/protos-go/driver/driver_grpc.pb.go +++ b/common/protos-go/driver/driver_grpc.pb.go @@ -30,6 +30,9 @@ type DriverCommunicationClient interface { // Relay uses this to get Query.requestor_signature and // Query.certificate required for event subscription RequestSignedEventSubscriptionQuery(ctx context.Context, in *common.EventSubscription, opts ...grpc.CallOption) (*common.Query, error) + // Events Publication + // the dest-relay calls the dest-driver on this end point to write the remote network state to the local ledger + WriteExternalState(ctx context.Context, in *WriteExternalStateMessage, opts ...grpc.CallOption) (*common.Ack, error) } type driverCommunicationClient struct { @@ -67,6 +70,15 @@ func (c *driverCommunicationClient) RequestSignedEventSubscriptionQuery(ctx cont return out, nil } +func (c *driverCommunicationClient) WriteExternalState(ctx context.Context, in *WriteExternalStateMessage, opts ...grpc.CallOption) (*common.Ack, error) { + out := new(common.Ack) + err := c.cc.Invoke(ctx, "/driver.driver.DriverCommunication/WriteExternalState", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // DriverCommunicationServer is the server API for DriverCommunication service. // All implementations must embed UnimplementedDriverCommunicationServer // for forward compatibility @@ -82,6 +94,9 @@ type DriverCommunicationServer interface { // Relay uses this to get Query.requestor_signature and // Query.certificate required for event subscription RequestSignedEventSubscriptionQuery(context.Context, *common.EventSubscription) (*common.Query, error) + // Events Publication + // the dest-relay calls the dest-driver on this end point to write the remote network state to the local ledger + WriteExternalState(context.Context, *WriteExternalStateMessage) (*common.Ack, error) mustEmbedUnimplementedDriverCommunicationServer() } @@ -98,6 +113,9 @@ func (UnimplementedDriverCommunicationServer) SubscribeEvent(context.Context, *c func (UnimplementedDriverCommunicationServer) RequestSignedEventSubscriptionQuery(context.Context, *common.EventSubscription) (*common.Query, error) { return nil, status.Errorf(codes.Unimplemented, "method RequestSignedEventSubscriptionQuery not implemented") } +func (UnimplementedDriverCommunicationServer) WriteExternalState(context.Context, *WriteExternalStateMessage) (*common.Ack, error) { + return nil, status.Errorf(codes.Unimplemented, "method WriteExternalState not implemented") +} func (UnimplementedDriverCommunicationServer) mustEmbedUnimplementedDriverCommunicationServer() {} // UnsafeDriverCommunicationServer may be embedded to opt out of forward compatibility for this service. @@ -165,6 +183,24 @@ func _DriverCommunication_RequestSignedEventSubscriptionQuery_Handler(srv interf return interceptor(ctx, in, info, handler) } +func _DriverCommunication_WriteExternalState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(WriteExternalStateMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DriverCommunicationServer).WriteExternalState(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/driver.driver.DriverCommunication/WriteExternalState", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DriverCommunicationServer).WriteExternalState(ctx, req.(*WriteExternalStateMessage)) + } + return interceptor(ctx, in, info, handler) +} + // DriverCommunication_ServiceDesc is the grpc.ServiceDesc for DriverCommunication service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -184,6 +220,10 @@ var DriverCommunication_ServiceDesc = grpc.ServiceDesc{ MethodName: "RequestSignedEventSubscriptionQuery", Handler: _DriverCommunication_RequestSignedEventSubscriptionQuery_Handler, }, + { + MethodName: "WriteExternalState", + Handler: _DriverCommunication_WriteExternalState_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "driver/driver.proto", diff --git a/common/protos-go/networks/networks.pb.go b/common/protos-go/networks/networks.pb.go index ec1b5e16e..23519b4a1 100644 --- a/common/protos-go/networks/networks.pb.go +++ b/common/protos-go/networks/networks.pb.go @@ -459,7 +459,7 @@ var file_networks_networks_proto_rawDesc = []byte{ 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x32, 0xff, 0x03, 0x0a, 0x07, 0x4e, 0x65, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x32, 0xd3, 0x04, 0x0a, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x42, 0x0a, 0x0c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, @@ -491,15 +491,21 @@ var file_networks_networks_proto_rawDesc = []byte{ 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, 0x78, 0x0a, 0x23, 0x63, - 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, - 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x73, 0x5a, 0x51, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, - 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, - 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x6e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x0e, 0x47, + 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x12, 0x22, 0x2e, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x73, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x1a, 0x1a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x22, 0x00, 0x42, + 0x78, 0x0a, 0x23, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x5a, 0x51, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, + 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, + 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( @@ -528,6 +534,7 @@ var file_networks_networks_proto_goTypes = []interface{}{ (*common.Ack)(nil), // 9: common.ack.Ack (*common.RequestState)(nil), // 10: common.state.RequestState (*common.EventSubscriptionState)(nil), // 11: common.events.EventSubscriptionState + (*common.EventStates)(nil), // 12: common.events.EventStates } var file_networks_networks_proto_depIdxs = []int32{ 6, // 0: networks.networks.RelayDatabase.pairs:type_name -> networks.networks.RelayDatabase.PairsEntry @@ -541,14 +548,16 @@ var file_networks_networks_proto_depIdxs = []int32{ 4, // 8: networks.networks.Network.SubscribeEvent:input_type -> networks.networks.NetworkEventSubscription 2, // 9: networks.networks.Network.GetEventSubscriptionState:input_type -> networks.networks.GetStateMessage 5, // 10: networks.networks.Network.UnsubscribeEvent:input_type -> networks.networks.NetworkEventUnsubscription - 9, // 11: networks.networks.Network.RequestState:output_type -> common.ack.Ack - 10, // 12: networks.networks.Network.GetState:output_type -> common.state.RequestState - 1, // 13: networks.networks.Network.RequestDatabase:output_type -> networks.networks.RelayDatabase - 9, // 14: networks.networks.Network.SubscribeEvent:output_type -> common.ack.Ack - 11, // 15: networks.networks.Network.GetEventSubscriptionState:output_type -> common.events.EventSubscriptionState - 9, // 16: networks.networks.Network.UnsubscribeEvent:output_type -> common.ack.Ack - 11, // [11:17] is the sub-list for method output_type - 5, // [5:11] is the sub-list for method input_type + 2, // 11: networks.networks.Network.GetEventStates:input_type -> networks.networks.GetStateMessage + 9, // 12: networks.networks.Network.RequestState:output_type -> common.ack.Ack + 10, // 13: networks.networks.Network.GetState:output_type -> common.state.RequestState + 1, // 14: networks.networks.Network.RequestDatabase:output_type -> networks.networks.RelayDatabase + 9, // 15: networks.networks.Network.SubscribeEvent:output_type -> common.ack.Ack + 11, // 16: networks.networks.Network.GetEventSubscriptionState:output_type -> common.events.EventSubscriptionState + 9, // 17: networks.networks.Network.UnsubscribeEvent:output_type -> common.ack.Ack + 12, // 18: networks.networks.Network.GetEventStates:output_type -> common.events.EventStates + 12, // [12:19] is the sub-list for method output_type + 5, // [5:12] is the sub-list for method input_type 5, // [5:5] is the sub-list for extension type_name 5, // [5:5] is the sub-list for extension extendee 0, // [0:5] is the sub-list for field type_name diff --git a/common/protos-go/networks/networks_grpc.pb.go b/common/protos-go/networks/networks_grpc.pb.go index 58191f113..73e621b9c 100644 --- a/common/protos-go/networks/networks_grpc.pb.go +++ b/common/protos-go/networks/networks_grpc.pb.go @@ -33,6 +33,9 @@ type NetworkClient interface { GetEventSubscriptionState(ctx context.Context, in *GetStateMessage, opts ...grpc.CallOption) (*common.EventSubscriptionState, error) // endpoint for a client to subscribe to event via local relay initiating subscription flow. UnsubscribeEvent(ctx context.Context, in *NetworkEventUnsubscription, opts ...grpc.CallOption) (*common.Ack, error) + // endpoint for a client to fetch received events. + // Note: events are marked as deleted from relay database as soon as client fetches them. + GetEventStates(ctx context.Context, in *GetStateMessage, opts ...grpc.CallOption) (*common.EventStates, error) } type networkClient struct { @@ -97,6 +100,15 @@ func (c *networkClient) UnsubscribeEvent(ctx context.Context, in *NetworkEventUn return out, nil } +func (c *networkClient) GetEventStates(ctx context.Context, in *GetStateMessage, opts ...grpc.CallOption) (*common.EventStates, error) { + out := new(common.EventStates) + err := c.cc.Invoke(ctx, "/networks.networks.Network/GetEventStates", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // NetworkServer is the server API for Network service. // All implementations must embed UnimplementedNetworkServer // for forward compatibility @@ -115,6 +127,9 @@ type NetworkServer interface { GetEventSubscriptionState(context.Context, *GetStateMessage) (*common.EventSubscriptionState, error) // endpoint for a client to subscribe to event via local relay initiating subscription flow. UnsubscribeEvent(context.Context, *NetworkEventUnsubscription) (*common.Ack, error) + // endpoint for a client to fetch received events. + // Note: events are marked as deleted from relay database as soon as client fetches them. + GetEventStates(context.Context, *GetStateMessage) (*common.EventStates, error) mustEmbedUnimplementedNetworkServer() } @@ -140,6 +155,9 @@ func (UnimplementedNetworkServer) GetEventSubscriptionState(context.Context, *Ge func (UnimplementedNetworkServer) UnsubscribeEvent(context.Context, *NetworkEventUnsubscription) (*common.Ack, error) { return nil, status.Errorf(codes.Unimplemented, "method UnsubscribeEvent not implemented") } +func (UnimplementedNetworkServer) GetEventStates(context.Context, *GetStateMessage) (*common.EventStates, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetEventStates not implemented") +} func (UnimplementedNetworkServer) mustEmbedUnimplementedNetworkServer() {} // UnsafeNetworkServer may be embedded to opt out of forward compatibility for this service. @@ -261,6 +279,24 @@ func _Network_UnsubscribeEvent_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _Network_GetEventStates_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetStateMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NetworkServer).GetEventStates(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/networks.networks.Network/GetEventStates", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NetworkServer).GetEventStates(ctx, req.(*GetStateMessage)) + } + return interceptor(ctx, in, info, handler) +} + // Network_ServiceDesc is the grpc.ServiceDesc for Network service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -292,6 +328,10 @@ var Network_ServiceDesc = grpc.ServiceDesc{ MethodName: "UnsubscribeEvent", Handler: _Network_UnsubscribeEvent_Handler, }, + { + MethodName: "GetEventStates", + Handler: _Network_GetEventStates_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "networks/networks.proto", diff --git a/common/protos-go/relay/events.pb.go b/common/protos-go/relay/events.pb.go index 4c39dc72f..8a99a3502 100644 --- a/common/protos-go/relay/events.pb.go +++ b/common/protos-go/relay/events.pb.go @@ -27,43 +27,58 @@ var file_relay_events_proto_rawDesc = []byte{ 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x61, 0x63, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x13, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x65, 0x76, 0x65, - 0x6e, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xd9, 0x01, 0x0a, 0x0e, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x45, 0x0a, 0x0e, - 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x20, - 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, - 0x6b, 0x22, 0x00, 0x12, 0x3c, 0x0a, 0x16, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x75, 0x62, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0f, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x1a, 0x0f, - 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, - 0x00, 0x12, 0x42, 0x0a, 0x1c, 0x53, 0x65, 0x6e, 0x64, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x53, + 0x6e, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x12, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xd9, 0x01, + 0x0a, 0x0e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, + 0x12, 0x45, 0x0a, 0x0e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x12, 0x20, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, + 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x3c, 0x0a, 0x16, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, - 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, 0x70, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, - 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x79, - 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x5a, 0x4e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, - 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, - 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, - 0x6f, 0x2f, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x1c, 0x53, 0x65, 0x6e, 0x64, 0x44, 0x72, 0x69, + 0x76, 0x65, 0x72, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, + 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x32, 0x8a, 0x01, 0x0a, 0x0c, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x12, 0x3f, 0x0a, 0x0f, 0x53, 0x65, + 0x6e, 0x64, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x19, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x56, 0x69, 0x65, + 0x77, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x09, 0x53, + 0x65, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x19, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x56, 0x69, 0x65, 0x77, 0x50, 0x61, 0x79, 0x6c, + 0x6f, 0x61, 0x64, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, + 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, 0x70, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, + 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x6c, 0x61, + 0x79, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x5a, 0x4e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, + 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, + 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, + 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, + 0x67, 0x6f, 0x2f, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var file_relay_events_proto_goTypes = []interface{}{ (*common.EventSubscription)(nil), // 0: common.events.EventSubscription (*common.Ack)(nil), // 1: common.ack.Ack + (*common.ViewPayload)(nil), // 2: common.state.ViewPayload } var file_relay_events_proto_depIdxs = []int32{ 0, // 0: relay.events.EventSubscribe.SubscribeEvent:input_type -> common.events.EventSubscription 1, // 1: relay.events.EventSubscribe.SendSubscriptionStatus:input_type -> common.ack.Ack 1, // 2: relay.events.EventSubscribe.SendDriverSubscriptionStatus:input_type -> common.ack.Ack - 1, // 3: relay.events.EventSubscribe.SubscribeEvent:output_type -> common.ack.Ack - 1, // 4: relay.events.EventSubscribe.SendSubscriptionStatus:output_type -> common.ack.Ack - 1, // 5: relay.events.EventSubscribe.SendDriverSubscriptionStatus:output_type -> common.ack.Ack - 3, // [3:6] is the sub-list for method output_type - 0, // [0:3] is the sub-list for method input_type + 2, // 3: relay.events.EventPublish.SendDriverState:input_type -> common.state.ViewPayload + 2, // 4: relay.events.EventPublish.SendState:input_type -> common.state.ViewPayload + 1, // 5: relay.events.EventSubscribe.SubscribeEvent:output_type -> common.ack.Ack + 1, // 6: relay.events.EventSubscribe.SendSubscriptionStatus:output_type -> common.ack.Ack + 1, // 7: relay.events.EventSubscribe.SendDriverSubscriptionStatus:output_type -> common.ack.Ack + 1, // 8: relay.events.EventPublish.SendDriverState:output_type -> common.ack.Ack + 1, // 9: relay.events.EventPublish.SendState:output_type -> common.ack.Ack + 5, // [5:10] is the sub-list for method output_type + 0, // [0:5] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name @@ -82,7 +97,7 @@ func file_relay_events_proto_init() { NumEnums: 0, NumMessages: 0, NumExtensions: 0, - NumServices: 1, + NumServices: 2, }, GoTypes: file_relay_events_proto_goTypes, DependencyIndexes: file_relay_events_proto_depIdxs, diff --git a/common/protos-go/relay/events_grpc.pb.go b/common/protos-go/relay/events_grpc.pb.go index 7f5c9404c..fc5931666 100644 --- a/common/protos-go/relay/events_grpc.pb.go +++ b/common/protos-go/relay/events_grpc.pb.go @@ -182,3 +182,129 @@ var EventSubscribe_ServiceDesc = grpc.ServiceDesc{ Streams: []grpc.StreamDesc{}, Metadata: "relay/events.proto", } + +// EventPublishClient is the client API for EventPublish service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type EventPublishClient interface { + // src-driver forwards the state as part of event subscription to src-relay + SendDriverState(ctx context.Context, in *common.ViewPayload, opts ...grpc.CallOption) (*common.Ack, error) + // src-relay will forward the state as part of event subscription to dest-relay + SendState(ctx context.Context, in *common.ViewPayload, opts ...grpc.CallOption) (*common.Ack, error) +} + +type eventPublishClient struct { + cc grpc.ClientConnInterface +} + +func NewEventPublishClient(cc grpc.ClientConnInterface) EventPublishClient { + return &eventPublishClient{cc} +} + +func (c *eventPublishClient) SendDriverState(ctx context.Context, in *common.ViewPayload, opts ...grpc.CallOption) (*common.Ack, error) { + out := new(common.Ack) + err := c.cc.Invoke(ctx, "/relay.events.EventPublish/SendDriverState", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *eventPublishClient) SendState(ctx context.Context, in *common.ViewPayload, opts ...grpc.CallOption) (*common.Ack, error) { + out := new(common.Ack) + err := c.cc.Invoke(ctx, "/relay.events.EventPublish/SendState", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// EventPublishServer is the server API for EventPublish service. +// All implementations must embed UnimplementedEventPublishServer +// for forward compatibility +type EventPublishServer interface { + // src-driver forwards the state as part of event subscription to src-relay + SendDriverState(context.Context, *common.ViewPayload) (*common.Ack, error) + // src-relay will forward the state as part of event subscription to dest-relay + SendState(context.Context, *common.ViewPayload) (*common.Ack, error) + mustEmbedUnimplementedEventPublishServer() +} + +// UnimplementedEventPublishServer must be embedded to have forward compatible implementations. +type UnimplementedEventPublishServer struct { +} + +func (UnimplementedEventPublishServer) SendDriverState(context.Context, *common.ViewPayload) (*common.Ack, error) { + return nil, status.Errorf(codes.Unimplemented, "method SendDriverState not implemented") +} +func (UnimplementedEventPublishServer) SendState(context.Context, *common.ViewPayload) (*common.Ack, error) { + return nil, status.Errorf(codes.Unimplemented, "method SendState not implemented") +} +func (UnimplementedEventPublishServer) mustEmbedUnimplementedEventPublishServer() {} + +// UnsafeEventPublishServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to EventPublishServer will +// result in compilation errors. +type UnsafeEventPublishServer interface { + mustEmbedUnimplementedEventPublishServer() +} + +func RegisterEventPublishServer(s grpc.ServiceRegistrar, srv EventPublishServer) { + s.RegisterService(&EventPublish_ServiceDesc, srv) +} + +func _EventPublish_SendDriverState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(common.ViewPayload) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EventPublishServer).SendDriverState(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/relay.events.EventPublish/SendDriverState", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EventPublishServer).SendDriverState(ctx, req.(*common.ViewPayload)) + } + return interceptor(ctx, in, info, handler) +} + +func _EventPublish_SendState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(common.ViewPayload) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EventPublishServer).SendState(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/relay.events.EventPublish/SendState", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EventPublishServer).SendState(ctx, req.(*common.ViewPayload)) + } + return interceptor(ctx, in, info, handler) +} + +// EventPublish_ServiceDesc is the grpc.ServiceDesc for EventPublish service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var EventPublish_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "relay.events.EventPublish", + HandlerType: (*EventPublishServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SendDriverState", + Handler: _EventPublish_SendDriverState_Handler, + }, + { + MethodName: "SendState", + Handler: _EventPublish_SendState_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "relay/events.proto", +} diff --git a/common/protos-java-kt/gradle.properties b/common/protos-java-kt/gradle.properties index fc8963ef9..2b6638d90 100644 --- a/common/protos-java-kt/gradle.properties +++ b/common/protos-java-kt/gradle.properties @@ -1,4 +1,4 @@ name=Interop Protos group=com.weaver -version=1.4.1 +version=1.4.2 kotlin.incremental=false diff --git a/common/protos-js/package.json b/common/protos-js/package.json index a60a209e0..749577aa8 100644 --- a/common/protos-js/package.json +++ b/common/protos-js/package.json @@ -1,6 +1,6 @@ { "name": "@hyperledger-labs/weaver-protos-js", - "version": "1.4.1", + "version": "1.4.2", "description": "Interop protos for Node JS (Weaver)", "main": "index.js", "exports": { diff --git a/common/protos/common/events.proto b/common/protos/common/events.proto index 28d13b51f..416247532 100644 --- a/common/protos/common/events.proto +++ b/common/protos/common/events.proto @@ -3,6 +3,7 @@ syntax = "proto3"; package common.events; import "common/query.proto"; +import "common/state.proto"; option java_package = "com.weaver.protos.common.events"; option go_package = "github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go/common"; @@ -68,4 +69,16 @@ message EventPublication { ContractTransaction ctx = 1; string app_url = 2; } -} \ No newline at end of file +} + +message EventStates { + repeated EventState states = 1; +} + +// the payload that is used for the communication between the requesting relay +// and its network +message EventState { + common.state.RequestState state = 1; + string event_id = 2; + string message = 3; +} diff --git a/common/protos/common/state.proto b/common/protos/common/state.proto index c25697128..e65227586 100644 --- a/common/protos/common/state.proto +++ b/common/protos/common/state.proto @@ -49,8 +49,12 @@ message RequestState { PENDING_ACK = 0; // Received ACK, waiting for data to be sent from remote relay PENDING = 1; - ERROR = 2; - COMPLETED = 3; + ERROR = 2; // View is not there, received error from remote relay + COMPLETED = 3; // Data Sharing completed Successfully + EVENT_RECEIVED = 4; // View is there and event is received from remote relay + EVENT_WRITTEN = 5; // Driver Successfully wrote the view to ledger, hence view is not stored anymore. + EVENT_WRITE_ERROR = 6; // View is there but driver failed to write + DELETED = 7; // Once network fetches this request state, mark it delete for cleanup later on. }; string request_id = 1; STATUS status = 2; diff --git a/common/protos/networks/networks.proto b/common/protos/networks/networks.proto index 7cd1590d4..a6da84508 100644 --- a/common/protos/networks/networks.proto +++ b/common/protos/networks/networks.proto @@ -27,6 +27,9 @@ service Network { rpc GetEventSubscriptionState(GetStateMessage) returns (common.events.EventSubscriptionState) {} // endpoint for a client to subscribe to event via local relay initiating subscription flow. rpc UnsubscribeEvent(NetworkEventUnsubscription) returns (common.ack.Ack) {} + // endpoint for a client to fetch received events. + // Note: events are marked as deleted from relay database as soon as client fetches them. + rpc GetEventStates(GetStateMessage) returns(common.events.EventStates) {} } message DbName { diff --git a/core/drivers/corda-driver/build.gradle b/core/drivers/corda-driver/build.gradle index 1627bff37..220aac829 100644 --- a/core/drivers/corda-driver/build.gradle +++ b/core/drivers/corda-driver/build.gradle @@ -10,7 +10,7 @@ buildscript { ext.corda_version = "4.8.4" ext.corda_core_version = "4.8.4" ext.arrow_version = "0.10.4" - ext.weaver_protos_version = "1.4.1" + ext.weaver_protos_version = "1.4.2" ext.weaver_corda_version = "1.2.9" repositories { diff --git a/core/network/corda-interop-app/constants.properties b/core/network/corda-interop-app/constants.properties index 3b4ec5bf3..0e6ae6940 100644 --- a/core/network/corda-interop-app/constants.properties +++ b/core/network/corda-interop-app/constants.properties @@ -11,4 +11,4 @@ slf4jVersion=1.7.25 nettyVersion=4.1.22.Final arrowVersion=0.10.4 -weaverVersion=1.4.1 +weaverVersion=1.4.2 diff --git a/samples/corda/corda-simple-application/constants.properties b/samples/corda/corda-simple-application/constants.properties index d67b889de..0b23f87e3 100644 --- a/samples/corda/corda-simple-application/constants.properties +++ b/samples/corda/corda-simple-application/constants.properties @@ -9,5 +9,5 @@ log4jVersion =2.16.0 platformVersion=10 slf4jVersion=1.7.25 nettyVersion=4.1.22.Final -weaverProtosVersion=1.4.1 +weaverProtosVersion=1.4.2 weaverCordaVersion=1.2.9 diff --git a/sdks/corda/build.gradle b/sdks/corda/build.gradle index d17dbb9fb..87e32cbec 100644 --- a/sdks/corda/build.gradle +++ b/sdks/corda/build.gradle @@ -13,7 +13,7 @@ buildscript { ext.corda_gradle_plugins_version = "5.0.12" ext.log4j_version = "2.16.0" ext.slf4j_version = "1.7.25" - ext.weaver_protos_version = "1.4.1" + ext.weaver_protos_version = "1.4.2" ext.weaver_corda_version = "1.2.9" dependencies { diff --git a/tests/network-setups/corda/scripts/get-cordapps.sh b/tests/network-setups/corda/scripts/get-cordapps.sh index 964c7cbad..274c2fe0a 100755 --- a/tests/network-setups/corda/scripts/get-cordapps.sh +++ b/tests/network-setups/corda/scripts/get-cordapps.sh @@ -4,7 +4,7 @@ directory=$(dirname $0) app=${1:-simple} local=$2 weaverCordaVersion="1.2.9" -weaverProtosVersion="1.4.1" +weaverProtosVersion="1.4.2" if [ "simple" = "$app" ]; then cordappPath=$directory/../../../../samples/corda/corda-simple-application diff --git a/tests/network-setups/corda/scripts/start-nodes.sh b/tests/network-setups/corda/scripts/start-nodes.sh index b7814e051..f2caa8826 100755 --- a/tests/network-setups/corda/scripts/start-nodes.sh +++ b/tests/network-setups/corda/scripts/start-nodes.sh @@ -10,7 +10,7 @@ houseTokenAppVersion="1.0" tokenVersion="1.2" weaverCordaVersion="1.2.9" -weaverProtosVersion="1.4.1" +weaverProtosVersion="1.4.2" parties="Notary PartyA PartyB PartyC" From 407b80277cacce7a794d4a95bd0ef9de61965925 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Wed, 20 Jul 2022 22:04:33 +0530 Subject: [PATCH 054/150] not to change status in case of app_url Signed-off-by: sandeep.nishad1 --- .../src/services/event_publish_service.rs | 8 -- core/relay/src/services/helpers.rs | 2 +- samples/fabric/fabric-cli/package-local.json | 3 + samples/fabric/fabric-cli/package.json | 7 +- .../fabric-cli/src/commands/event/receive.ts | 89 +++++++++++++++++++ 5 files changed, 98 insertions(+), 11 deletions(-) create mode 100644 samples/fabric/fabric-cli/src/commands/event/receive.ts diff --git a/core/relay/src/services/event_publish_service.rs b/core/relay/src/services/event_publish_service.rs index 4be1bf410..6a7d1d45b 100644 --- a/core/relay/src/services/event_publish_service.rs +++ b/core/relay/src/services/event_publish_service.rs @@ -295,14 +295,6 @@ fn spawn_handle_event(state: ViewPayload, publication_spec: EventPublication, re conf.get_str("db_path").unwrap(), message.to_string(), ) - } else { - update_event_state( - request_id, - event_id, - request_state::Status::Completed, - conf.get_str("db_path").unwrap(), - message.to_string(), - ) } println!("Success: {}", message.to_string()); } diff --git a/core/relay/src/services/helpers.rs b/core/relay/src/services/helpers.rs index 5026d9179..8798b41a9 100644 --- a/core/relay/src/services/helpers.rs +++ b/core/relay/src/services/helpers.rs @@ -270,7 +270,7 @@ pub fn mark_event_states_deleted(fetched_event_states: EventStates, request_id: for fetched_event_state in fetched_event_states.states { let state_status = request_state::Status::from_i32(fetched_event_state.clone().state.expect("No State").status).expect("No Status"); if state_status == request_state::Status::Error || - state_status == request_state::Status::Completed || + state_status == request_state::Status::EventReceived || state_status == request_state::Status::EventWritten { let deleted_request_state = RequestState { status: request_state::Status::Deleted as i32, diff --git a/samples/fabric/fabric-cli/package-local.json b/samples/fabric/fabric-cli/package-local.json index 6d9b5087e..36de88fe7 100644 --- a/samples/fabric/fabric-cli/package-local.json +++ b/samples/fabric/fabric-cli/package-local.json @@ -40,6 +40,8 @@ "elliptic": "^6.5.4", "fabric-ca-client": "^2.2.8", "fabric-network": "^2.2.8", + "express": "^4.18.1", + "body-parser": "^1.20.0", "gluegun": "latest", "grpc-tools": "1.9.1", "ini": "^1.3.6", @@ -51,6 +53,7 @@ "devDependencies": { "@grpc/grpc-js": "^1.1.1", "@grpc/proto-loader": "^0.5.4", + "@types/express": "^4.17.13", "@types/jest": "^24.0.18", "@types/node": "^12.12.54", "@typescript-eslint/eslint-plugin": "^3.5.0", diff --git a/samples/fabric/fabric-cli/package.json b/samples/fabric/fabric-cli/package.json index 108176b75..0f84e085f 100644 --- a/samples/fabric/fabric-cli/package.json +++ b/samples/fabric/fabric-cli/package.json @@ -32,12 +32,14 @@ ], "license": "MIT", "dependencies": { - "@hyperledger-labs/weaver-protos-js": "latest", - "@hyperledger-labs/weaver-fabric-interop-sdk": "latest", "@fidm/x509": "^1.2.1", + "@hyperledger-labs/weaver-fabric-interop-sdk": "latest", + "@hyperledger-labs/weaver-protos-js": "latest", + "body-parser": "^1.20.0", "crypto": "^1.0.1", "dotenv": "^8.2.0", "elliptic": "^6.5.4", + "express": "^4.18.1", "fabric-ca-client": "^2.2.8", "fabric-network": "^2.2.8", "gluegun": "latest", @@ -51,6 +53,7 @@ "devDependencies": { "@grpc/grpc-js": "^1.1.1", "@grpc/proto-loader": "^0.5.4", + "@types/express": "^4.17.13", "@types/jest": "^24.0.18", "@types/node": "^12.12.54", "@typescript-eslint/eslint-plugin": "^3.5.0", diff --git a/samples/fabric/fabric-cli/src/commands/event/receive.ts b/samples/fabric/fabric-cli/src/commands/event/receive.ts new file mode 100644 index 000000000..cecb65d4b --- /dev/null +++ b/samples/fabric/fabric-cli/src/commands/event/receive.ts @@ -0,0 +1,89 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import { GluegunCommand } from 'gluegun' +import { fabricHelper, getKeyAndCertForRemoteRequestbyUserName } from '../../helpers/fabric-functions' +import logger from '../../helpers/logger' +import { Utils, ICryptoKey } from 'fabric-common' +import { commandHelp, getNetworkConfig, handlePromise } from '../../helpers/helpers' +import { EventsManager } from '@hyperledger-labs/weaver-fabric-interop-sdk' +import { EventSubscriptionState, EventType } from "@hyperledger-labs/weaver-protos-js/common/events_pb"; +import * as fs from 'fs' +import * as path from 'path' +import * as express from 'express'; +import * as bodyParser from 'body-parser'; + +const command: GluegunCommand = { + name: 'receive', + alias: ['-r'], + description: 'Start simple http server to receive event', + run: async toolbox => { + const { + print, + parameters: { options, array } + } = toolbox + if (options.help || options.h) { + commandHelp( + print, + toolbox, + `fabric-cli event receive --port=8080"`, + 'fabric-cli event receive --port=', + [ + { + name: '--network', + description: + 'Local network for command. ' + }, + { + name: '--port', + description: + 'Port at which to start http server (Optional). Default: 8080' + }, + { + name: '--debug', + description: + 'Shows debug logs when running. Disabled by default. To enable --debug=true' + } + ], + command, + ['event', 'receive'] + ) + return + } + console.log("Start HTTP Server for handling events from remote network") + if (options.debug === 'true') { + logger.level = 'debug' + logger.debug('Debugging is enabled') + } + var port = 8080 + if (options.port) { + port = options.port + } + + const app = express(); + app.use(bodyParser.json()); + app.use(bodyParser.urlencoded({ + extended: false + })); + + app.post('/simple-event-callback', (req, res) => { + console.log("Received Event State: ", req.body.state) + if (req.body.state) { + const data = Buffer.from(req.body.state.View.data).toString('utf8'); + console.log("Received Event Data:", data); + } else { + console.log("Received Error Event:", req.body.error); + } + res.status(200).send('Ok'); + }); + console.log(`Server is running at https://localhost:${port}`); + console.log(`Use endpoint '/simple-event-callback' for event publishing`); + await app.listen(port); + } +} + + +module.exports = command From e415416770522c8e96e8a636fdaa8654057e04d9 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Wed, 20 Jul 2022 22:23:16 +0530 Subject: [PATCH 055/150] bug fix in get event states relay endpoint; added sdk function to get event states; added fabric cli command for that Signed-off-by: sandeep.nishad1 --- core/relay/src/services/helpers.rs | 6 +- core/relay/src/services/network_service.rs | 2 +- .../fabric-cli/src/commands/event/get-all.ts | 91 +++++++++++++++++++ .../commands/event/get-subscription-status.ts | 4 +- .../src/EventsManager.ts | 27 +++++- .../interoperation-node-sdk/src/Relay.ts | 25 +++++ 6 files changed, 149 insertions(+), 6 deletions(-) create mode 100644 samples/fabric/fabric-cli/src/commands/event/get-all.ts diff --git a/core/relay/src/services/helpers.rs b/core/relay/src/services/helpers.rs index 8798b41a9..189469cb9 100644 --- a/core/relay/src/services/helpers.rs +++ b/core/relay/src/services/helpers.rs @@ -265,7 +265,7 @@ pub fn try_mark_request_state_deleted(state: RequestState, request_id: String, d } } -pub fn mark_event_states_deleted(fetched_event_states: EventStates, request_id: String, db: Database) { +pub fn mark_event_states_deleted(fetched_event_states: EventStates, request_id: String, event_publish_key: String, db: Database) { let mut updated_event_states: Vec = Vec::new(); for fetched_event_state in fetched_event_states.states { let state_status = request_state::Status::from_i32(fetched_event_state.clone().state.expect("No State").status).expect("No Status"); @@ -283,10 +283,12 @@ pub fn mark_event_states_deleted(fetched_event_states: EventStates, request_id: message: fetched_event_state.message.to_string(), }; updated_event_states.push(deleted_event_state); + } else { + updated_event_states.push(fetched_event_state); } } - db.set(&get_event_publication_key(request_id.to_string()), &updated_event_states) + db.set(&event_publish_key.to_string(), &updated_event_states) .expect("EventState Delete: Failed to insert into DB"); } pub fn get_event_subscription_key(request_id: String) -> String { diff --git a/core/relay/src/services/network_service.rs b/core/relay/src/services/network_service.rs index b93969c98..ac6187f2b 100644 --- a/core/relay/src/services/network_service.rs +++ b/core/relay/src/services/network_service.rs @@ -348,7 +348,7 @@ impl Network for NetworkService { let result = db.get::(event_publish_key.to_string()); match result { Ok(fetched_event_states) => { - mark_event_states_deleted(fetched_event_states.clone(), request_id.to_string(), db); + mark_event_states_deleted(fetched_event_states.clone(), request_id.to_string(), event_publish_key.to_string(), db); println!("Sending back EventStates to network: Request ID = {:?}: {:?}", request_id.to_string(), fetched_event_states.clone() diff --git a/samples/fabric/fabric-cli/src/commands/event/get-all.ts b/samples/fabric/fabric-cli/src/commands/event/get-all.ts new file mode 100644 index 000000000..7a6fb5924 --- /dev/null +++ b/samples/fabric/fabric-cli/src/commands/event/get-all.ts @@ -0,0 +1,91 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import { GluegunCommand } from 'gluegun' +import { fabricHelper, getKeyAndCertForRemoteRequestbyUserName } from '../../helpers/fabric-functions' +import logger from '../../helpers/logger' +import { Utils, ICryptoKey } from 'fabric-common' +import { commandHelp, getNetworkConfig, handlePromise } from '../../helpers/helpers' +import { EventsManager } from '@hyperledger-labs/weaver-fabric-interop-sdk' +import { EventSubscriptionState, EventType } from "@hyperledger-labs/weaver-protos-js/common/events_pb"; +import * as fs from 'fs' +import * as path from 'path' + +const command: GluegunCommand = { + name: 'get-all', + alias: ['-gall'], + description: 'Get all received event states', + run: async toolbox => { + const { + print, + parameters: { options, array } + } = toolbox + if (options.help || options.h) { + commandHelp( + print, + toolbox, + `fabric-cli event get-all --network= --request-id="abc123"`, + 'fabric-cli event get-all --network= --request-id=', + [ + { + name: '--network', + description: + 'Local network for command. ' + }, + { + name: '--request-id', + description: + 'Request ID received during subscription.' + }, + { + name: '--debug', + description: + 'Shows debug logs when running. Disabled by default. To enable --debug=true' + } + ], + command, + ['event', 'get-all'] + ) + return + } + console.log("Get All Received Event States") + if (options.debug === 'true') { + logger.level = 'debug' + logger.debug('Debugging is enabled') + } + if (!options['network']) + { + print.error('--network needs to be specified') + return + } + if (!options['request-id']) + { + print.error('--request-id needs to be specified') + return + } + const networkName = options['network'] + const requestId = options['request-id'] + + const netConfig = getNetworkConfig(networkName) + if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { + throw new Error(`No valid config entry found for ${networkName}`) + } + try { + const response = await EventsManager.getAllReceivedEvents( + requestId, + netConfig.relayEndpoint + ) + console.log("Event States:", JSON.stringify(response, null, 4)) + } catch(e) { + console.log("Error: ", e.toString()) + } + + process.exit() + } +} + + +module.exports = command diff --git a/samples/fabric/fabric-cli/src/commands/event/get-subscription-status.ts b/samples/fabric/fabric-cli/src/commands/event/get-subscription-status.ts index 285b1fa56..cebbe91c2 100644 --- a/samples/fabric/fabric-cli/src/commands/event/get-subscription-status.ts +++ b/samples/fabric/fabric-cli/src/commands/event/get-subscription-status.ts @@ -27,8 +27,8 @@ const command: GluegunCommand = { commandHelp( print, toolbox, - `fabric-cli event unsubscribe --network= --user=user1 --request-id="abc123"`, - 'fabric-cli event unsubscribe --network= --user= --request-id=', + `fabric-cli event unsubscribe --network= --request-id="abc123"`, + 'fabric-cli event unsubscribe --network= --request-id=', [ { name: '--network', diff --git a/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts b/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts index e978844d9..9669e1c83 100644 --- a/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts +++ b/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts @@ -226,7 +226,6 @@ const getSubscriptionStatus = async ( asJson: boolean = true, useTls: boolean = false, tlsRootCACertPaths?: Array, - confidential: boolean = false, ): Promise => { logger.debug("Get Event Subscription Status") @@ -247,6 +246,31 @@ const getSubscriptionStatus = async ( return relayResponse } +const getAllReceivedEvents = async ( + requestID: string, + localRelayEndpoint: string, + asJson: boolean = true, + useTls: boolean = false, + tlsRootCACertPaths?: Array, +): Promise => { + logger.debug("Get all received event states") + + const relay = useTls ? new Relay(localRelayEndpoint, Relay.defaultTimeout, true, tlsRootCACertPaths) : new Relay(localRelayEndpoint); + + const [relayResponse, relayResponseError] = await helpers.handlePromise( + relay.GetEventStates( + requestID, + asJson + ), + ); + if (relayResponseError) { + throw new Error(`Get event states relay response error: ${relayResponseError}`); + } + + logger.debug(`Get event states response: ${JSON.stringify(relayResponse)}`) + + return relayResponse +} export { @@ -255,5 +279,6 @@ export { subscribeRemoteEvent, unsubscribeRemoteEvent, getSubscriptionStatus, + getAllReceivedEvents, } diff --git a/sdks/fabric/interoperation-node-sdk/src/Relay.ts b/sdks/fabric/interoperation-node-sdk/src/Relay.ts index 7138f4015..2c5842176 100644 --- a/sdks/fabric/interoperation-node-sdk/src/Relay.ts +++ b/sdks/fabric/interoperation-node-sdk/src/Relay.ts @@ -467,6 +467,31 @@ class Relay { throw new Error(e); } } + /** + * GetSubscriptionStatus is used to get the request from the local network + * @returns {object} The request object from the relay + */ + async GetEventStates(requestId: string, asJson = true): Promise { + const networkClient = new networksGrpcPb.NetworkClient( + this.getEndpoint(), + this._useTls ? + (this._tlsRootCACerts.length == 0 ? grpcJs.credentials.createSsl() : grpcJs.credentials.createSsl(Buffer.from(this._tlsRootCACerts))) : + grpcJs.credentials.createInsecure() + ); + const { + getEventStates, + }: { getEventStates: (message: networksPb.GetStateMessage) => Promise } = helpers.promisifyAll( + networkClient, + ); + const getStateMessage = new networksPb.GetStateMessage(); + getStateMessage.setRequestId(requestId); + const [state, error] = await helpers.handlePromise(getEventStates(getStateMessage)); + if (error) { + throw new Error(`Error: ${error}`); + } + + return asJson ? state.toObject() : state; + } } From 9dae8f0997347cdf58c07fb0c80e89a82bd92706 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Wed, 20 Jul 2022 22:27:10 +0530 Subject: [PATCH 056/150] relay version upgraded to v1.4.2; sdk to v1.4.2 Signed-off-by: sandeep.nishad1 --- core/relay/Cargo.toml | 2 +- core/relay/Makefile.variables.docker | 2 +- sdks/fabric/interoperation-node-sdk/package-local.json | 2 +- sdks/fabric/interoperation-node-sdk/package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/relay/Cargo.toml b/core/relay/Cargo.toml index 1a5b78d93..92216e62d 100644 --- a/core/relay/Cargo.toml +++ b/core/relay/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "relay" -version = "1.4.0" +version = "1.4.2" authors = ["Antony Targett ", "Nick Waywood ", "Sandeep Nishad Date: Wed, 20 Jul 2022 22:35:52 +0530 Subject: [PATCH 057/150] added new subscription for app_url target Signed-off-by: sandeep.nishad1 --- .../fabric-cli/src/data/event_sub_sample.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/samples/fabric/fabric-cli/src/data/event_sub_sample.json b/samples/fabric/fabric-cli/src/data/event_sub_sample.json index 7addd80cc..c72cc7c6e 100644 --- a/samples/fabric/fabric-cli/src/data/event_sub_sample.json +++ b/samples/fabric/fabric-cli/src/data/event_sub_sample.json @@ -36,5 +36,19 @@ }, "view_address": "localhost:9083/network2/mychannel:simplestate:Read:a", "confidential": false + }, + { + "event_matcher": { + "eventType": 1, + "eventClassId": "CreateSimpleState", + "transactionLedgerId": "mychannel", + "transactionContractId": "simplestate", + "transactionFunc": "create" + }, + "event_publication_spec": { + "appUrl": "http://localhost:8080/simple-event-callback" + }, + "view_address": "localhost:9083/network2/mychannel:simplestate:Read:a", + "confidential": false } ] From 7dd2b45889cd9c67a8671cfcadd065b3c7dab18e Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Thu, 21 Jul 2022 12:38:48 +0530 Subject: [PATCH 058/150] added unit test for event publish in relay; delete all event states once fetched by client Signed-off-by: sandeep.nishad1 --- core/relay/Cargo.lock | 3 +- core/relay/Cargo.toml | 1 + core/relay/driver/driver.rs | 33 ++++- core/relay/src/client.rs | 190 +++++++++++++++++++++++++++-- core/relay/src/services/helpers.rs | 29 ++--- 5 files changed, 224 insertions(+), 32 deletions(-) diff --git a/core/relay/Cargo.lock b/core/relay/Cargo.lock index 9414e8ade..344042653 100644 --- a/core/relay/Cargo.lock +++ b/core/relay/Cargo.lock @@ -1126,7 +1126,7 @@ checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" [[package]] name = "relay" -version = "1.4.0" +version = "1.4.2" dependencies = [ "base64 0.13.0", "bincode", @@ -1136,6 +1136,7 @@ dependencies = [ "prost", "reqwest", "serde 1.0.139", + "serde_json", "sled", "tokio", "tonic", diff --git a/core/relay/Cargo.toml b/core/relay/Cargo.toml index 92216e62d..c759b2e04 100644 --- a/core/relay/Cargo.toml +++ b/core/relay/Cargo.toml @@ -34,6 +34,7 @@ listenfd = "0.3" futures = { version = "0.3.5" } base64 = "0.13.0" reqwest = { version = "0.10.10", features = ["json"] } +serde_json = "1.0.1" [build-dependencies] diff --git a/core/relay/driver/driver.rs b/core/relay/driver/driver.rs index 7c269312d..5232c27d2 100644 --- a/core/relay/driver/driver.rs +++ b/core/relay/driver/driver.rs @@ -187,12 +187,35 @@ impl DriverCommunication for DriverCommunicationService { return Ok(Response::new(signed_query)); } async fn write_external_state(&self, request: Request) -> Result, Status> { - let reply = Ack { - status: ack::Status::Ok as i32, - request_id: request.into_inner().view_payload.expect("Error").request_id.to_string(), - message: "Successfully written".to_string(), + let view_payload = request.into_inner().view_payload.expect("Error"); + let request_id = view_payload.clone().request_id.to_string(); + match view_payload.state { + Some(state) => match state { + view_payload::State::Error(error) => { + let reply = Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error received: {:?}", error).to_string(), + }; + return Ok(Response::new(reply)); + } + view_payload::State::View(_view) => { + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Successfully written".to_string(), + }; + return Ok(Response::new(reply)); + } + } + None => {} + } + let reply_error = Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error".to_string(), }; - return Ok(Response::new(reply)); + return Ok(Response::new(reply_error)); } } diff --git a/core/relay/src/client.rs b/core/relay/src/client.rs index 2a8d4d942..6d4599d64 100644 --- a/core/relay/src/client.rs +++ b/core/relay/src/client.rs @@ -2,18 +2,24 @@ mod pb; mod relay_proto; use futures::future::{BoxFuture, FutureExt}; use pb::common::ack::ack; -use pb::common::state::request_state; -use pb::common::events::{event_subscription_state, EventMatcher, EventPublication, event_publication}; +use pb::common::state::{request_state, view_payload, ViewPayload, View, Meta, meta}; +use pb::common::events::{event_subscription_state, EventMatcher, EventPublication, event_publication, ContractTransaction}; +use pb::relay::events::{event_publish_client::EventPublishClient}; use pb::networks::networks::{network_client::NetworkClient, GetStateMessage, NetworkQuery, NetworkEventSubscription, NetworkEventUnsubscription}; use relay_proto::get_url; use std::env; use std::thread::sleep; use std::time; +use serde_json; #[tokio::main] async fn main() -> Result<(), Box> { + println!("\nData Sharing Test"); datasharing().await?; - event_suscribe().await?; + println!("\nEvent: Driver Subscription Test"); + event_suscribe(true).await?; + println!("\nEvent: Client Subscription Test"); + event_suscribe(false).await?; Ok(()) } @@ -95,7 +101,7 @@ fn poll_for_state( } -async fn event_suscribe() -> Result<(), Box> { +async fn event_suscribe(driver: bool) -> Result<(), Box> { let args: Vec = env::args().collect(); let net_addr = format!("http://{}", get_url(&args)); let mut network_client = NetworkClient::connect(net_addr).await?; @@ -120,7 +126,20 @@ async fn event_suscribe() -> Result<(), Box> { transaction_contract_id: "test".to_string(), transaction_func: "test".to_string(), }; - let tmp = event_publication::PublicationTarget::AppUrl("abc".to_string()); + let tmp; + if driver { + let ctx = ContractTransaction { + driver_id: "Dummy_Network".to_string(), + ledger_id: "abc".to_string(), + contract_id: "abc".to_string(), + func: "abc".to_string(), + args: vec![], + replace_arg_index: 0, + }; + tmp = event_publication::PublicationTarget::Ctx(ctx); + } else { + tmp = event_publication::PublicationTarget::AppUrl("abc".to_string()); + } let event_publication_spec = EventPublication { publication_target: std::option::Option::Some(tmp), }; @@ -147,10 +166,22 @@ async fn event_suscribe() -> Result<(), Box> { std::process::exit(1); } } - return event_unsuscribe(request_id.to_string()).await; + println!("\n"); + let result = event_publish_test(request_id.to_string(), driver).await; + match result { + Ok(()) => { + println!("Publish test: Successful"); + }, + Err(error) => { + println!("Error during Publish Test: {:?}", error); + std::process::exit(1); + } + } + println!("\n"); + return event_unsuscribe(request_id.to_string(), driver).await; } -async fn event_unsuscribe(request_id: String) -> Result<(), Box> { +async fn event_unsuscribe(request_id: String, driver: bool) -> Result<(), Box> { let args: Vec = env::args().collect(); let net_addr = format!("http://{}", get_url(&args)); let mut network_client = NetworkClient::connect(net_addr).await?; @@ -175,7 +206,20 @@ async fn event_unsuscribe(request_id: String) -> Result<(), Box Result<(), Box> { + let args: Vec = env::args().collect(); + let net_addr = format!("http://{}", get_url(&args)); + let mut client = EventPublishClient::connect(net_addr.to_string()).await?; + // localhost:9081/Corda_Network/test + // {locationsegment}/{Network_id}/{query} + // localhost:9081/Corda_Network/mychannel:simplestate:read:TestState + let meta = Meta { + proof_type: "abc".to_string(), + protocol: meta::Protocol::Fabric as i32, + serialization_format: "abc".to_string(), + timestamp: "abc".to_string(), + }; + let data: Vec = vec![104, 101, 108, 108, 111]; + let view = View { + meta: Some(meta), + data: data, + }; + let view_payload = ViewPayload { + request_id: request_id.to_string(), + state: Some(view_payload::State::View(view)), + }; + let view_payload_err = ViewPayload { + request_id: request_id.to_string(), + state: Some(view_payload::State::Error("mock error".to_string())), + }; + + let response = client.send_driver_state(view_payload.clone()).await?; + if ack::Status::from_i32(response.get_ref().status).expect("No Valid Status") != ack::Status::Ok { + println!("An error occurred in send driver state call {:?}", response.get_ref().message); + std::process::exit(1); + } + + sleep(time::Duration::from_millis(2000)); + + let response_err = client.send_driver_state(view_payload_err.clone()).await?; + if ack::Status::from_i32(response_err.get_ref().status).expect("No Valid Status") != ack::Status::Ok { + println!("An error occurred in send driver state call {:?}", response.get_ref().message); + std::process::exit(1); + } + + sleep(time::Duration::from_millis(2000)); + + let mut network_client = NetworkClient::connect(net_addr.to_string()).await?; + let request = tonic::Request::new(GetStateMessage { + request_id: request_id.to_string(), + }); + + // Check if states status are correct. + let event_states_res = network_client.get_event_states(request).await; + match event_states_res { + Ok(response) => { + let mut event_states = response.into_inner().states; + println!("Received States: {:?}", event_states); + let event_state = event_states.pop().expect("No State"); + let event_state_status = event_state.clone().state.expect("No RequestState").status; + if driver { + if request_state::Status::from_i32(event_state_status).expect("No Valid Status") != request_state::Status::EventWritten { + println!("Error: event not got written to ledger: {:?}", event_state.message.to_string()); + std::process::exit(1); + } + } else { + if request_state::Status::from_i32(event_state_status).expect("No Valid Status") != request_state::Status::EventReceived { + println!("Error: event status not correct: expected 4, received {:?}", event_state_status); + std::process::exit(1); + } + } + let event_state_json = serde_json::to_string(&event_state.clone().state.expect("No RequestState").state); + let view_payload_json = serde_json::to_string(&view_payload.clone().state); + if event_state_json.expect("stringify error") != view_payload_json.expect("stringify error") { + println!("Error: event state different than what is send: \nExpected: {:?}, \nReceived: {:?}", event_state.state, view_payload.state); + std::process::exit(1); + } + let event_state_err = event_states.pop().expect("No State"); + let event_state_err_status = event_state_err.clone().state.expect("No RequestState").status; + if driver { + if request_state::Status::from_i32(event_state_err_status.clone()).expect("No Valid Status") != request_state::Status::EventWriteError { + println!("Error: event status not correct: expected 6, received {:?}", event_state_err_status); + std::process::exit(1); + } + } else { + if request_state::Status::from_i32(event_state_err_status.clone()).expect("No Valid Status") != request_state::Status::Error { + println!("Error: event status not correct: expected 2, received {:?}", event_state_err_status); + std::process::exit(1); + } + } + let event_state_err_json = serde_json::to_string(&event_state_err.clone().state.expect("No RequestState").state); + let view_payload_err_json = serde_json::to_string(&view_payload_err.clone().state); + if event_state_err_json.expect("stringify error") != view_payload_err_json.expect("stringify error") { + println!("Error: event state different than what is send: \nExpected: {:?}, \nReceived: {:?}", event_state_err.state, view_payload_err.state); + std::process::exit(1); + } + }, + Err(error) => { + println!("An error occurred while getting event states: {:?}.", error); + std::process::exit(1); + } + } + + let request_2 = tonic::Request::new(GetStateMessage { + request_id: request_id.to_string(), + }); + // Check if states are deleted after first fetch. + let event_states_res = network_client.get_event_states(request_2).await; + match event_states_res { + Ok(response) => { + let mut event_states = response.into_inner().states; + println!("Received States 2nd: {:?}", event_states); + let event_state = event_states.pop().expect("No State"); + let event_state_status = event_state.state.expect("No RequestState").status; + if request_state::Status::from_i32(event_state_status.clone()).expect("No Valid Status") != request_state::Status::Deleted { + println!("Error: event status not correct: expected 7, received {:?}", event_state_status); + std::process::exit(1); + } + let event_state_err = event_states.pop().expect("No State"); + let event_state_err_status = event_state_err.state.expect("No RequestState").status; + if request_state::Status::from_i32(event_state_err_status.clone()).expect("No Valid Status") != request_state::Status::Deleted { + println!("Error: event status not correct: expected 7, received {:?}", event_state_err_status); + std::process::exit(1); + } + }, + Err(error) => { + println!("An error occurred while getting event states: {:?}.", error); + std::process::exit(1); + } + } + + Ok(()) +} + diff --git a/core/relay/src/services/helpers.rs b/core/relay/src/services/helpers.rs index 189469cb9..873d7c7f2 100644 --- a/core/relay/src/services/helpers.rs +++ b/core/relay/src/services/helpers.rs @@ -268,24 +268,17 @@ pub fn try_mark_request_state_deleted(state: RequestState, request_id: String, d pub fn mark_event_states_deleted(fetched_event_states: EventStates, request_id: String, event_publish_key: String, db: Database) { let mut updated_event_states: Vec = Vec::new(); for fetched_event_state in fetched_event_states.states { - let state_status = request_state::Status::from_i32(fetched_event_state.clone().state.expect("No State").status).expect("No Status"); - if state_status == request_state::Status::Error || - state_status == request_state::Status::EventReceived || - state_status == request_state::Status::EventWritten { - let deleted_request_state = RequestState { - status: request_state::Status::Deleted as i32, - request_id: request_id.to_string(), - state: fetched_event_state.state.expect("No State found").state, - }; - let deleted_event_state = EventState { - state: Some(deleted_request_state), - event_id: fetched_event_state.event_id, - message: fetched_event_state.message.to_string(), - }; - updated_event_states.push(deleted_event_state); - } else { - updated_event_states.push(fetched_event_state); - } + let deleted_request_state = RequestState { + status: request_state::Status::Deleted as i32, + request_id: request_id.to_string(), + state: fetched_event_state.state.expect("No State found").state, + }; + let deleted_event_state = EventState { + state: Some(deleted_request_state), + event_id: fetched_event_state.event_id, + message: fetched_event_state.message.to_string(), + }; + updated_event_states.push(deleted_event_state); } db.set(&event_publish_key.to_string(), &updated_event_states) From 7418a7a305cb9b68ec0fbd13bedf4ec4d665ac37 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Thu, 21 Jul 2022 16:32:26 +0530 Subject: [PATCH 059/150] Krishna comments addressed; Dockerfile for relay updated Signed-off-by: sandeep.nishad1 --- core/relay/Dockerfile | 26 ++++++++++++++++--- core/relay/Dockerfile.client | 26 ++++++++++++++++--- core/relay/Dockerfile.driver | 26 ++++++++++++++++--- core/relay/Dockerfile.server | 26 +++++++++++++++---- .../src/services/event_publish_service.rs | 5 ++-- .../src/services/event_subscribe_service.rs | 2 +- core/relay/src/services/network_service.rs | 1 + 7 files changed, 92 insertions(+), 20 deletions(-) diff --git a/core/relay/Dockerfile b/core/relay/Dockerfile index 9b87f69c1..ae1e01cb4 100644 --- a/core/relay/Dockerfile +++ b/core/relay/Dockerfile @@ -1,8 +1,8 @@ -FROM rust:1.45.2-slim-stretch AS builder +FROM rust:1.62.1-slim-bullseye AS builder RUN apt-get update -RUN apt-get install musl-tools -y +RUN apt-get install curl musl-tools perl build-essential -y # adding the musl library target so that we can build # the components for busybox/alpine environments @@ -13,11 +13,29 @@ RUN rustup target add x86_64-unknown-linux-musl # toolchain than the target we are building, but given that we are building # on linux (debian), we can use the toolchain mentioned below also because # custom toolchains are not supported. -# -RUN rustup component add rustfmt --toolchain 1.45.2-x86_64-unknown-linux-gnu +# +RUN rustup component add rustfmt --toolchain 1.62.1-x86_64-unknown-linux-gnu RUN mkdir -p /opt/relay COPY . /opt/relay +# Build OpenSSL + +ENV SSL_VERSION=1.1.1f + +RUN ln -s /usr/include/x86_64-linux-gnu/asm /usr/include/x86_64-linux-musl/asm && \ + ln -s /usr/include/asm-generic /usr/include/x86_64-linux-musl/asm-generic && \ + ln -s /usr/include/linux /usr/include/x86_64-linux-musl/linux +RUN mkdir /musl && \ + curl https://www.openssl.org/source/openssl-$SSL_VERSION.tar.gz -O && \ + tar zxvf openssl-$SSL_VERSION.tar.gz && \ + cd openssl-$SSL_VERSION/ && \ + CC="musl-gcc -fPIE -pie" ./Configure no-shared no-async --prefix=/musl --openssldir=/musl/ssl linux-x86_64 && \ + make depend && make -j$(nproc) && make install + +ENV PKG_CONFIG_ALLOW_CROSS=1 \ + OPENSSL_STATIC=true \ + OPENSSL_DIR=/musl + # We install missing dependencies within the # the same layer where we do the compilation # to then remove it from the image in the diff --git a/core/relay/Dockerfile.client b/core/relay/Dockerfile.client index dc4a128e1..616f4f2ab 100644 --- a/core/relay/Dockerfile.client +++ b/core/relay/Dockerfile.client @@ -1,8 +1,8 @@ -FROM rust:1.45.2-slim-stretch AS builder +FROM rust:1.62.1-slim-bullseye AS builder RUN apt-get update -RUN apt-get install musl-tools -y +RUN apt-get install curl musl-tools perl build-essential -y # adding the musl library target so that we can build # the components for busybox/alpine environments @@ -13,11 +13,29 @@ RUN rustup target add x86_64-unknown-linux-musl # toolchain than the target we are building, but given that we are building # on linux (debian), we can use the toolchain mentioned below also because # custom toolchains are not supported. -# -RUN rustup component add rustfmt --toolchain 1.45.2-x86_64-unknown-linux-gnu +# +RUN rustup component add rustfmt --toolchain 1.62.1-x86_64-unknown-linux-gnu RUN mkdir -p /opt/relay COPY . /opt/relay +# Build OpenSSL + +ENV SSL_VERSION=1.1.1f + +RUN ln -s /usr/include/x86_64-linux-gnu/asm /usr/include/x86_64-linux-musl/asm && \ + ln -s /usr/include/asm-generic /usr/include/x86_64-linux-musl/asm-generic && \ + ln -s /usr/include/linux /usr/include/x86_64-linux-musl/linux +RUN mkdir /musl && \ + curl https://www.openssl.org/source/openssl-$SSL_VERSION.tar.gz -O && \ + tar zxvf openssl-$SSL_VERSION.tar.gz && \ + cd openssl-$SSL_VERSION/ && \ + CC="musl-gcc -fPIE -pie" ./Configure no-shared no-async --prefix=/musl --openssldir=/musl/ssl linux-x86_64 && \ + make depend && make -j$(nproc) && make install + +ENV PKG_CONFIG_ALLOW_CROSS=1 \ + OPENSSL_STATIC=true \ + OPENSSL_DIR=/musl + # We install missing dependencies within the # the same layer where we do the compilation # to then remove it from the image in the diff --git a/core/relay/Dockerfile.driver b/core/relay/Dockerfile.driver index 88d77ea35..623bb0f96 100644 --- a/core/relay/Dockerfile.driver +++ b/core/relay/Dockerfile.driver @@ -1,8 +1,8 @@ -FROM rust:1.45.2-slim-stretch AS builder +FROM rust:1.62.1-slim-bullseye AS builder RUN apt-get update -RUN apt-get install musl-tools -y +RUN apt-get install curl musl-tools perl build-essential -y # adding the musl library target so that we can build # the components for busybox/alpine environments @@ -13,11 +13,29 @@ RUN rustup target add x86_64-unknown-linux-musl # toolchain than the target we are building, but given that we are building # on linux (debian), we can use the toolchain mentioned below also because # custom toolchains are not supported. -# -RUN rustup component add rustfmt --toolchain 1.45.2-x86_64-unknown-linux-gnu +# +RUN rustup component add rustfmt --toolchain 1.62.1-x86_64-unknown-linux-gnu RUN mkdir -p /opt/relay COPY . /opt/relay +# Build OpenSSL + +ENV SSL_VERSION=1.1.1f + +RUN ln -s /usr/include/x86_64-linux-gnu/asm /usr/include/x86_64-linux-musl/asm && \ + ln -s /usr/include/asm-generic /usr/include/x86_64-linux-musl/asm-generic && \ + ln -s /usr/include/linux /usr/include/x86_64-linux-musl/linux +RUN mkdir /musl && \ + curl https://www.openssl.org/source/openssl-$SSL_VERSION.tar.gz -O && \ + tar zxvf openssl-$SSL_VERSION.tar.gz && \ + cd openssl-$SSL_VERSION/ && \ + CC="musl-gcc -fPIE -pie" ./Configure no-shared no-async --prefix=/musl --openssldir=/musl/ssl linux-x86_64 && \ + make depend && make -j$(nproc) && make install + +ENV PKG_CONFIG_ALLOW_CROSS=1 \ + OPENSSL_STATIC=true \ + OPENSSL_DIR=/musl + # We install missing dependencies within the # the same layer where we do the compilation # to then remove it from the image in the diff --git a/core/relay/Dockerfile.server b/core/relay/Dockerfile.server index c288fd100..e5bcbac3f 100644 --- a/core/relay/Dockerfile.server +++ b/core/relay/Dockerfile.server @@ -1,8 +1,8 @@ -FROM rust:1.45.2-slim-stretch AS builder +FROM rust:1.62.1-slim-bullseye AS builder RUN apt-get update -RUN apt-get install musl-tools -y +RUN apt-get install curl musl-tools perl build-essential -y # adding the musl library target so that we can build # the components for busybox/alpine environments @@ -14,18 +14,34 @@ RUN rustup target add x86_64-unknown-linux-musl # on linux (debian), we can use the toolchain mentioned below also because # custom toolchains are not supported. # -RUN rustup component add rustfmt --toolchain 1.45.2-x86_64-unknown-linux-gnu +RUN rustup component add rustfmt --toolchain 1.62.1-x86_64-unknown-linux-gnu RUN mkdir -p /opt/relay COPY . /opt/relay +# Build OpenSSL + +ENV SSL_VERSION=1.1.1f + +RUN ln -s /usr/include/x86_64-linux-gnu/asm /usr/include/x86_64-linux-musl/asm && \ + ln -s /usr/include/asm-generic /usr/include/x86_64-linux-musl/asm-generic && \ + ln -s /usr/include/linux /usr/include/x86_64-linux-musl/linux +RUN mkdir /musl && \ + curl https://www.openssl.org/source/openssl-$SSL_VERSION.tar.gz -O && \ + tar zxvf openssl-$SSL_VERSION.tar.gz && \ + cd openssl-$SSL_VERSION/ && \ + CC="musl-gcc -fPIE -pie" ./Configure no-shared no-async --prefix=/musl --openssldir=/musl/ssl linux-x86_64 && \ + make depend && make -j$(nproc) && make install + +ENV PKG_CONFIG_ALLOW_CROSS=1 \ + OPENSSL_STATIC=true \ + OPENSSL_DIR=/musl + # We install missing dependencies within the # the same layer where we do the compilation # to then remove it from the image in the # same docker command. RUN cd /opt/relay && RUSTFLAGS=-Clinker=musl-gcc cargo build --release --target x86_64-unknown-linux-musl - - FROM busybox AS server LABEL COMPONENT=i"relay server" diff --git a/core/relay/src/services/event_publish_service.rs b/core/relay/src/services/event_publish_service.rs index 6a7d1d45b..a5f27f46f 100644 --- a/core/relay/src/services/event_publish_service.rs +++ b/core/relay/src/services/event_publish_service.rs @@ -113,8 +113,7 @@ impl EventPublish for EventPublishService { /// send_driver_state is run on the remote relay. Runs when the driver sends the -/// state back to the remote relay or if there was an error making the -/// request_driver_state gRPC call. +/// state or error back to the remote relay. fn send_driver_state_helper( request_id: String, remote_db: Database, @@ -276,6 +275,7 @@ fn send_state_helper( return Ok(()); } +// Calls handle_event and updates status of event_state depending upon the success or failure. fn spawn_handle_event(state: ViewPayload, publication_spec: EventPublication, request_id: String, event_id: String, conf: config::Config) { tokio::spawn(async move { println!("Event Publish: Sending state to subscriber: Request ID = {:?}", request_id.to_string()); @@ -313,6 +313,7 @@ fn spawn_handle_event(state: ViewPayload, publication_spec: EventPublication, re }); } +// Sends event payload to either driver or app_url depending upon publication spec during subscription async fn handle_event( state: ViewPayload, publication_spec: EventPublication, diff --git a/core/relay/src/services/event_subscribe_service.rs b/core/relay/src/services/event_subscribe_service.rs index 957adb665..fd9e803b7 100644 --- a/core/relay/src/services/event_subscribe_service.rs +++ b/core/relay/src/services/event_subscribe_service.rs @@ -7,7 +7,7 @@ use crate::pb::relay::events::event_subscribe_server::EventSubscribe; // Internal modules use crate::db::Database; use crate::error::Error; -use crate::relay_proto::{parse_address, LocationSegment} ; +use crate::relay_proto::{parse_address, LocationSegment}; use crate::services::helpers::{update_event_subscription_status, get_driver, get_driver_client, get_event_subscription_key}; use crate::services::types::{Driver}; // external modules diff --git a/core/relay/src/services/network_service.rs b/core/relay/src/services/network_service.rs index ac6187f2b..d631b87f3 100644 --- a/core/relay/src/services/network_service.rs +++ b/core/relay/src/services/network_service.rs @@ -48,6 +48,7 @@ impl Network for NetworkService { ); match request_state.state.as_ref() { Some(state) => { + // Because already state is passed to client, deleting the state if status is completed or error try_mark_request_state_deleted(request_state.clone(), request_id.to_string(), db); match state { request_state::State::View(v) => println!("View Meta: {:?}, View Data: {:?}", v.meta, base64::encode(&v.data)), From abd3c3069e0dc579437b19d4c9e22120b27472c9 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Thu, 21 Jul 2022 16:51:30 +0530 Subject: [PATCH 060/150] updated RFC for RequestState proto Signed-off-by: sandeep.nishad1 --- common/protos/common/state.proto | 4 ++-- rfcs/formats/views/request.md | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/common/protos/common/state.proto b/common/protos/common/state.proto index e65227586..9dd153cad 100644 --- a/common/protos/common/state.proto +++ b/common/protos/common/state.proto @@ -52,9 +52,9 @@ message RequestState { ERROR = 2; // View is not there, received error from remote relay COMPLETED = 3; // Data Sharing completed Successfully EVENT_RECEIVED = 4; // View is there and event is received from remote relay - EVENT_WRITTEN = 5; // Driver Successfully wrote the view to ledger, hence view is not stored anymore. + EVENT_WRITTEN = 5; // Driver Successfully wrote the view to ledger EVENT_WRITE_ERROR = 6; // View is there but driver failed to write - DELETED = 7; // Once network fetches this request state, mark it delete for cleanup later on. + DELETED = 7; // Once network fetches this request state, mark it delete for cleanup later on }; string request_id = 1; STATUS status = 2; diff --git a/rfcs/formats/views/request.md b/rfcs/formats/views/request.md index 18bb7fed8..80cb0dc8a 100644 --- a/rfcs/formats/views/request.md +++ b/rfcs/formats/views/request.md @@ -59,8 +59,12 @@ message RequestState { PENDING_ACK = 0; // Received ACK, waiting for data to be sent from remote relay PENDING = 1; - ERROR = 2; - COMPLETED = 3; + ERROR = 2; // View is not there, received error from remote relay + COMPLETED = 3; // Data Sharing completed Successfully + EVENT_RECEIVED = 4; // View is there and event is received from remote relay + EVENT_WRITTEN = 5; // Driver Successfully wrote the view to ledger + EVENT_WRITE_ERROR = 6; // View is there but driver failed to write + DELETED = 7; // Once network fetches this request state, mark it delete for cleanup later on }; string request_id = 1; STATUS status = 2; From d5ca9e07dab812c8e1ec557cba396122357cf553 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Thu, 21 Jul 2022 19:07:30 +0530 Subject: [PATCH 061/150] bug fix in fabric driver wallet Setup Signed-off-by: sandeep.nishad1 --- core/drivers/fabric-driver/server/walletSetup.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/drivers/fabric-driver/server/walletSetup.ts b/core/drivers/fabric-driver/server/walletSetup.ts index 72964e4e5..e57ef2092 100644 --- a/core/drivers/fabric-driver/server/walletSetup.ts +++ b/core/drivers/fabric-driver/server/walletSetup.ts @@ -37,10 +37,10 @@ const walletSetup = async (walletPath: string, conn_profile_path: string, networ const config = getConfig(); // Create a new CA client for interacting with the CA. const org = ccp.client["organization"]; - console.log('Org ', org); + console.log('Org', org); const caName = ccp.organizations[org]["certificateAuthorities"][0]; - console.log('CA Name ', caName); - const caURL = ccp.certificateAuthorities[config.caUrl ? config.caUrl : caName].url; + console.log('CA Name', caName); + const caURL = config.caUrl ? config.caUrl : ccp.certificateAuthorities[caName].url; console.log('CA URL', caURL); const ca = new FabricCAServices(caURL); const ident = ca.newIdentityService(); From 17b78e0919789156309cd4e6dbcaf5b782f92ca2 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Thu, 21 Jul 2022 22:56:36 +0530 Subject: [PATCH 062/150] destination driver endpoint for writing external ledger state Signed-off-by: Krishnasuri Narayanam --- core/drivers/fabric-driver/server/server.ts | 89 ++++++++++++++++++- core/drivers/fabric-driver/server/utils.ts | 4 +- .../src/InteroperableHelper.ts | 7 +- 3 files changed, 91 insertions(+), 9 deletions(-) diff --git a/core/drivers/fabric-driver/server/server.ts b/core/drivers/fabric-driver/server/server.ts index 63f016481..99785d9b3 100644 --- a/core/drivers/fabric-driver/server/server.ts +++ b/core/drivers/fabric-driver/server/server.ts @@ -8,19 +8,23 @@ import fs from 'fs'; import { Server, ServerCredentials, credentials } from '@grpc/grpc-js'; import ack_pb from '@hyperledger-labs/weaver-protos-js/common/ack_pb'; import query_pb from '@hyperledger-labs/weaver-protos-js/common/query_pb'; -import fabricView from '@hyperledger-labs/weaver-protos-js/fabric/view_data_pb'; +import fabricViewPb from '@hyperledger-labs/weaver-protos-js/fabric/view_data_pb'; import eventsPb, { EventMatcher } from '@hyperledger-labs/weaver-protos-js/common/events_pb'; import driver_pb_grpc from '@hyperledger-labs/weaver-protos-js/driver/driver_grpc_pb'; import datatransfer_grpc_pb from '@hyperledger-labs/weaver-protos-js/relay/datatransfer_grpc_pb'; import events_grpc_pb from '@hyperledger-labs/weaver-protos-js/relay/events_grpc_pb'; import state_pb from '@hyperledger-labs/weaver-protos-js/common/state_pb'; -import { invoke, getNetworkGateway, packageFabricView } from './fabric-code'; +import { invoke, packageFabricView } from './fabric-code'; import 'dotenv/config'; import { walletSetup } from './walletSetup'; import { subscribeEventHelper, unsubscribeEventHelper, signEventSubscriptionQuery } from "./events" import * as path from 'path'; import { handlePromise, relayCallback, getRelayClientForQueryResponse } from './utils'; import { dbConnectionTest, eventSubscriptionTest } from "./tests" +import driverPb from '@hyperledger-labs/weaver-protos-js/driver/driver_pb'; +import { getDriverKeyCert } from "./walletSetup"; +import { getResponseDataFromView, submitTransactionWithRemoteViews } from '@hyperledger-labs/weaver-fabric-interop-sdk'; +import { getNetworkGateway } from "./fabric-code"; const server = new Server(); console.log('driver def', JSON.stringify(driver_pb_grpc)); @@ -43,7 +47,7 @@ function mockCommunication(query: query_pb.Query) { const view = new state_pb.View(); view.setMeta(meta); //@ts-ignore - const viewDataBinary = fabricView.FabricView.deserializeBinary(mockedB64Data).serializeBinary(); + const viewDataBinary = fabricViewPb.FabricView.deserializeBinary(mockedB64Data).serializeBinary(); console.log('viewData', viewDataBinary); view.setData(viewDataBinary); const viewPayload = new state_pb.ViewPayload(); @@ -100,7 +104,7 @@ const fabricCommunication = async (query: query_pb.Query, networkName: string) = // If the events_grpc_pb.EventSubscribeClient() failes, then it throws an error which will be caught by the caller async function getEventSubscriptionRelayClient( ): Promise { - let client; + let client: events_grpc_pb.EventSubscribeClient; if (process.env.RELAY_TLS === 'true') { if (!(process.env.RELAY_TLSCA_CERT_PATH && fs.existsSync(process.env.RELAY_TLSCA_CERT_PATH))) { @@ -225,8 +229,85 @@ server.addService(driver_pb_grpc.DriverCommunicationService, { callback(null, emptyQuery); }); }, + writeExternalState: (call: { request: driverPb.WriteExternalStateMessage }, callback: (_: any, object: ack_pb.Ack) => void) => { + const viewPayload: state_pb.ViewPayload = call.request.getViewPayload(); + const requestId: string = viewPayload.getRequestId(); + + writeExternalStateHelper(call.request, process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1').then(() => { + const ack_response = new ack_pb.Ack(); + ack_response.setRequestId(requestId); + ack_response.setMessage('Successfully written to the ledger'); + ack_response.setStatus(ack_pb.Ack.STATUS.OK); + // gRPC response. + console.log(`Responding to caller with Ack: ${JSON.stringify(ack_response.toObject())}`); + callback(null, ack_response); + }).catch((error) => { + const ack_err_response = new ack_pb.Ack(); + ack_err_response.setRequestId(requestId); + ack_err_response.setMessage(JSON.stringify(error)); + ack_err_response.setStatus(ack_pb.Ack.STATUS.ERROR); + // gRPC response. + console.log(`Responding to caller with error Ack: ${JSON.stringify(ack_err_response.toObject())}`); + callback(null, ack_err_response); + }); + }, }); +async function writeExternalStateHelper( + writeExternalStateMessage: driverPb.WriteExternalStateMessage, + networkName: string +) : Promise { + const viewPayload: state_pb.ViewPayload = writeExternalStateMessage.getViewPayload(); + const ctx: eventsPb.ContractTransaction = writeExternalStateMessage.getCtx(); + const keyCert = await getDriverKeyCert(); + + const requestId: string = viewPayload.getRequestId(); + if (!viewPayload.getError()) { + + let interopArgIndices = [], viewsSerializedBase64 = [], addresses = [], viewContentsBase64 = []; + const view: state_pb.View = viewPayload.getView(); + + const result = getResponseDataFromView(view, keyCert.key.toBytes()); + if (result.interopPayload.getConfidential()) { + viewContentsBase64.push(result.contents.toString("base64")); + } else { + viewContentsBase64.push(""); + } + + interopArgIndices.push(ctx.getReplaceArgIndex()); + addresses.push(result.interopPayload.getAddress()); + viewsSerializedBase64.push(Buffer.from(viewPayload.getView().serializeBinary()).toString("base64")); + + const invokeObject = { + channel: ctx.getLedgerId(), + ccFunc: ctx.getFunc(), + ccArgs: ctx.getArgsList(), + contractName: ctx.getContractId() + } + + const gateway = await getNetworkGateway(networkName); + const network = await gateway.getNetwork(ctx.getLedgerId()); + const interopContract = network.getContract(process.env.INTEROP_CHAINCODE ? process.env.INTEROP_CHAINCODE : 'interop'); + + const [ response, responseError ] = await handlePromise(submitTransactionWithRemoteViews( + interopContract, + invokeObject, + interopArgIndices, + addresses, + viewsSerializedBase64, + viewContentsBase64 + )); + if (responseError) { + console.log(`Failed writing to the ledger with error: ${responseError}`); + throw responseError; + } + } else { + const errorString: string = 'erroneous viewPayload identified in WriteExternalState processing'; + console.log(`error viewPayload.getError(): ${JSON.stringify(viewPayload.getError())}`); + throw new Error(errorString); + } +} + // Prepares required crypto material for communication with the fabric network const configSetup = async () => { // uses the network name to create a unique wallet path diff --git a/core/drivers/fabric-driver/server/utils.ts b/core/drivers/fabric-driver/server/utils.ts index e347c7a18..1d7282ac3 100644 --- a/core/drivers/fabric-driver/server/utils.ts +++ b/core/drivers/fabric-driver/server/utils.ts @@ -55,7 +55,7 @@ function handlePromise(promise: Promise): Promise<[T?, Error?]> { } function getRelayClientForQueryResponse() { - let client; + let client: datatransfer_grpc_pb.DataTransferClient; if (process.env.RELAY_TLS === 'true') { if (!(process.env.RELAY_TLSCA_CERT_PATH && fs.existsSync(process.env.RELAY_TLSCA_CERT_PATH))) { throw new Error("Missing or invalid RELAY_TLSCA_CERT_PATH: " + process.env.RELAY_TLSCA_CERT_PATH); @@ -75,7 +75,7 @@ function getRelayClientForQueryResponse() { } function getRelayClientForEventPublish() { - let client; + let client: events_grpc_pb.EventPublishClient; if (process.env.RELAY_TLS === 'true') { if (!(process.env.RELAY_TLSCA_CERT_PATH && fs.existsSync(process.env.RELAY_TLSCA_CERT_PATH))) { throw new Error("Missing or invalid RELAY_TLSCA_CERT_PATH: " + process.env.RELAY_TLSCA_CERT_PATH); diff --git a/sdks/fabric/interoperation-node-sdk/src/InteroperableHelper.ts b/sdks/fabric/interoperation-node-sdk/src/InteroperableHelper.ts index 2e5dbc67d..6c1e8e39c 100644 --- a/sdks/fabric/interoperation-node-sdk/src/InteroperableHelper.ts +++ b/sdks/fabric/interoperation-node-sdk/src/InteroperableHelper.ts @@ -174,14 +174,14 @@ const getResponseDataFromView = (view, privKeyPEM = null) => { const confidentialPayload = interopPayloadPb.ConfidentialPayload.deserializeBinary(Uint8Array.from(Buffer.from(interopPayload.getPayload()))); const decryptedPayload = decryptData(Buffer.from(confidentialPayload.getEncryptedPayload()), privKeyPEM); const decryptedPayloadContents = interopPayloadPb.ConfidentialPayloadContents.deserializeBinary(Uint8Array.from(Buffer.from(decryptedPayload))); - return { data: Buffer.from(decryptedPayloadContents.getPayload()).toString(), contents: decryptedPayload }; + return { interopPayload: interopPayload, data: Buffer.from(decryptedPayloadContents.getPayload()).toString(), contents: decryptedPayload }; } else { - return { data: Buffer.from(interopPayload.getPayload()).toString() }; + return { interopPayload: interopPayload, data: Buffer.from(interopPayload.getPayload()).toString() }; } } else if (view.getMeta().getProtocol() == statePb.Meta.Protocol.CORDA) { const cordaView = cordaViewPb.ViewData.deserializeBinary(view.getData()); const interopPayload = interopPayloadPb.InteropPayload.deserializeBinary(Uint8Array.from(Buffer.from(cordaView.getPayload()))); - return { data: Buffer.from(interopPayload.getPayload()).toString() }; + return { interopPayload: interopPayload, data: Buffer.from(interopPayload.getPayload()).toString() }; } else { const protocolType = view.getMeta().getProtocol(); throw new Error(`Unsupported DLT type: ${protocolType}`); @@ -670,4 +670,5 @@ export { getRemoteView, createFlowAddress, createAddress, + decryptData }; From 2aebb28d522f336c1f7eb9e9582e1c35bb79af10 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Fri, 22 Jul 2022 12:08:13 +0530 Subject: [PATCH 063/150] add latest tag to docker images; use latest tag in testnet; not push tag (except latest) if already exists Signed-off-by: sandeep.nishad1 --- .../corda-driver/docker-testnet-envs/.env.corda | 2 +- .../corda-driver/docker-testnet-envs/.env.corda.tls | 2 +- .../corda-driver/docker-testnet-envs/.env.corda2 | 2 +- .../docker-testnet-envs/.env.corda2.tls | 2 +- core/drivers/corda-driver/makefile | 11 ++++++++++- .../fabric-driver/docker-testnet-envs/.env.n1 | 2 +- .../fabric-driver/docker-testnet-envs/.env.n1.tls | 2 +- .../fabric-driver/docker-testnet-envs/.env.n2 | 2 +- .../fabric-driver/docker-testnet-envs/.env.n2.tls | 2 +- core/drivers/fabric-driver/makefile | 9 ++++++++- core/relay/.env.template | 2 +- core/relay/.env.template.2 | 2 +- core/relay/Makefile | 13 ++++++++++++- core/relay/docker/testnet-envs/.env.corda | 2 +- core/relay/docker/testnet-envs/.env.corda.tls | 2 +- core/relay/docker/testnet-envs/.env.corda2 | 2 +- core/relay/docker/testnet-envs/.env.corda2.tls | 2 +- core/relay/docker/testnet-envs/.env.n1 | 2 +- core/relay/docker/testnet-envs/.env.n1.tls | 2 +- core/relay/docker/testnet-envs/.env.n2 | 2 +- core/relay/docker/testnet-envs/.env.n2.tls | 2 +- 21 files changed, 48 insertions(+), 21 deletions(-) diff --git a/core/drivers/corda-driver/docker-testnet-envs/.env.corda b/core/drivers/corda-driver/docker-testnet-envs/.env.corda index 72b72d6b5..e85be8ee5 100644 --- a/core/drivers/corda-driver/docker-testnet-envs/.env.corda +++ b/core/drivers/corda-driver/docker-testnet-envs/.env.corda @@ -3,7 +3,7 @@ DRIVER_PORT=9099 DRIVER_RPC_USERNAME=driverUser1 DRIVER_RPC_PASSWORD=test DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-corda-driver -DOCKER_TAG=1.2.9 +DOCKER_TAG=latest EXTERNAL_NETWORK=corda_default COMPOSE_PROJECT_NAME=corda COMPOSE_PROJECT_NETWORK=default diff --git a/core/drivers/corda-driver/docker-testnet-envs/.env.corda.tls b/core/drivers/corda-driver/docker-testnet-envs/.env.corda.tls index 399e7d645..70ef05b67 100644 --- a/core/drivers/corda-driver/docker-testnet-envs/.env.corda.tls +++ b/core/drivers/corda-driver/docker-testnet-envs/.env.corda.tls @@ -3,7 +3,7 @@ DRIVER_PORT=9099 DRIVER_RPC_USERNAME=driverUser1 DRIVER_RPC_PASSWORD=test DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-corda-driver -DOCKER_TAG=1.2.9 +DOCKER_TAG=latest EXTERNAL_NETWORK=corda_default COMPOSE_PROJECT_NAME=corda COMPOSE_PROJECT_NETWORK=default diff --git a/core/drivers/corda-driver/docker-testnet-envs/.env.corda2 b/core/drivers/corda-driver/docker-testnet-envs/.env.corda2 index daa6e2a4f..7df9207a0 100644 --- a/core/drivers/corda-driver/docker-testnet-envs/.env.corda2 +++ b/core/drivers/corda-driver/docker-testnet-envs/.env.corda2 @@ -3,7 +3,7 @@ DRIVER_PORT=9098 DRIVER_RPC_USERNAME=driverUser1 DRIVER_RPC_PASSWORD=test DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-corda-driver -DOCKER_TAG=1.2.9 +DOCKER_TAG=latest EXTERNAL_NETWORK=corda_network2_default COMPOSE_PROJECT_NAME=corda_network2 COMPOSE_PROJECT_NETWORK=default diff --git a/core/drivers/corda-driver/docker-testnet-envs/.env.corda2.tls b/core/drivers/corda-driver/docker-testnet-envs/.env.corda2.tls index 70fa382da..021ff29d0 100644 --- a/core/drivers/corda-driver/docker-testnet-envs/.env.corda2.tls +++ b/core/drivers/corda-driver/docker-testnet-envs/.env.corda2.tls @@ -3,7 +3,7 @@ DRIVER_PORT=9098 DRIVER_RPC_USERNAME=driverUser1 DRIVER_RPC_PASSWORD=test DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-corda-driver -DOCKER_TAG=1.2.9 +DOCKER_TAG=latest EXTERNAL_NETWORK=corda_network2_default COMPOSE_PROJECT_NAME=corda_network2 COMPOSE_PROJECT_NETWORK=default diff --git a/core/drivers/corda-driver/makefile b/core/drivers/corda-driver/makefile index 946db1beb..61778c35d 100644 --- a/core/drivers/corda-driver/makefile +++ b/core/drivers/corda-driver/makefile @@ -28,10 +28,19 @@ image-local: build-local image: github.properties docker build --build-arg GIT_URL=$(GIT_URL) -f Dockerfile.remote -t $(DOCKER_IMAGE_NAME):$(DOCKER_TAG) . +.PHONY: check-if-tag-exists +check-if-tag-exists: + !(DOCKER_CLI_EXPERIMENTAL=enabled docker manifest inspect $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_NAME):$(DOCKER_TAG) > /dev/null) + .PHONY: push-image -push-image: image +push-image: check-if-tag-exists image docker tag $(DOCKER_IMAGE_NAME):$(DOCKER_TAG) $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_NAME):$(DOCKER_TAG) docker push $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_NAME):$(DOCKER_TAG) + +.PHONY: push-image-latest +push-image-latest: + docker tag $(DOCKER_IMAGE_NAME):$(DOCKER_TAG) $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_NAME):latest + docker push $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_NAME):latest .PHONY: run run: diff --git a/core/drivers/fabric-driver/docker-testnet-envs/.env.n1 b/core/drivers/fabric-driver/docker-testnet-envs/.env.n1 index f6b96b952..479d6416f 100644 --- a/core/drivers/fabric-driver/docker-testnet-envs/.env.n1 +++ b/core/drivers/fabric-driver/docker-testnet-envs/.env.n1 @@ -5,7 +5,7 @@ NETWORK_NAME=network1 DRIVER_PORT=9090 INTEROP_CHAINCODE=interop DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-fabric-driver -DOCKER_TAG=1.3.1 +DOCKER_TAG=latest EXTERNAL_NETWORK=network1_net COMPOSE_PROJECT_NAME=network1 COMPOSE_PROJECT_NETWORK=net diff --git a/core/drivers/fabric-driver/docker-testnet-envs/.env.n1.tls b/core/drivers/fabric-driver/docker-testnet-envs/.env.n1.tls index 539fad0f3..6adc02c40 100644 --- a/core/drivers/fabric-driver/docker-testnet-envs/.env.n1.tls +++ b/core/drivers/fabric-driver/docker-testnet-envs/.env.n1.tls @@ -5,7 +5,7 @@ NETWORK_NAME=network1 DRIVER_PORT=9090 INTEROP_CHAINCODE=interop DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-fabric-driver -DOCKER_TAG=1.3.1 +DOCKER_TAG=latest EXTERNAL_NETWORK=network1_net COMPOSE_PROJECT_NAME=network1 COMPOSE_PROJECT_NETWORK=net diff --git a/core/drivers/fabric-driver/docker-testnet-envs/.env.n2 b/core/drivers/fabric-driver/docker-testnet-envs/.env.n2 index 68cb7bbd0..f313ff278 100644 --- a/core/drivers/fabric-driver/docker-testnet-envs/.env.n2 +++ b/core/drivers/fabric-driver/docker-testnet-envs/.env.n2 @@ -5,7 +5,7 @@ NETWORK_NAME=network2 DRIVER_PORT=9095 INTEROP_CHAINCODE=interop DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-fabric-driver -DOCKER_TAG=1.3.1 +DOCKER_TAG=latest EXTERNAL_NETWORK=network2_net COMPOSE_PROJECT_NAME=network2 COMPOSE_PROJECT_NETWORK=net diff --git a/core/drivers/fabric-driver/docker-testnet-envs/.env.n2.tls b/core/drivers/fabric-driver/docker-testnet-envs/.env.n2.tls index bd40f8a3e..eea66e556 100644 --- a/core/drivers/fabric-driver/docker-testnet-envs/.env.n2.tls +++ b/core/drivers/fabric-driver/docker-testnet-envs/.env.n2.tls @@ -5,7 +5,7 @@ NETWORK_NAME=network2 DRIVER_PORT=9095 INTEROP_CHAINCODE=interop DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-fabric-driver -DOCKER_TAG=1.3.1 +DOCKER_TAG=latest EXTERNAL_NETWORK=network2_net COMPOSE_PROJECT_NAME=network2 COMPOSE_PROJECT_NETWORK=net diff --git a/core/drivers/fabric-driver/makefile b/core/drivers/fabric-driver/makefile index 917caf128..5441f0557 100644 --- a/core/drivers/fabric-driver/makefile +++ b/core/drivers/fabric-driver/makefile @@ -45,11 +45,18 @@ build-image-local: protos-js weaver-fabric-interop-sdk build-image: .npmrc docker build --build-arg BUILD_TAG="remote" --build-arg GIT_URL=$(GIT_URL) -t ${DOCKER_IMAGE_NAME}:$(DOCKER_TAG) -f fabricDriver.dockerfile . + +check-if-tag-exists: + !(DOCKER_CLI_EXPERIMENTAL=enabled docker manifest inspect $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_NAME):$(DOCKER_TAG) > /dev/null) -push-image: build-image +push-image: check-if-tag-exists build-image docker tag ${DOCKER_IMAGE_NAME}:$(DOCKER_TAG) $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_NAME):$(DOCKER_TAG) docker push $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_NAME):$(DOCKER_TAG) +push-image-latest: + docker tag ${DOCKER_IMAGE_NAME}:$(DOCKER_TAG) $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_NAME):latest + docker push $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_NAME):latest + deploy: docker-compose $(COMPOSE_ARG) up -d diff --git a/core/relay/.env.template b/core/relay/.env.template index df958629f..cb1da1cf9 100644 --- a/core/relay/.env.template +++ b/core/relay/.env.template @@ -2,7 +2,7 @@ PATH_TO_CONFIG= RELAY_NAME=<"name" in config toml file> RELAY_PORT= DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-relay-server -DOCKER_TAG=1.4.0 +DOCKER_TAG=1.4.2 EXTERNAL_NETWORK= COMPOSE_PROJECT_NAME= COMPOSE_PROJECT_NETWORK= \ No newline at end of file diff --git a/core/relay/.env.template.2 b/core/relay/.env.template.2 index 0ca531467..dbc0291cd 100644 --- a/core/relay/.env.template.2 +++ b/core/relay/.env.template.2 @@ -7,7 +7,7 @@ DRIVER_NAME= RELAY_NAME= RELAY_PORT= DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-relay-server -DOCKER_TAG=1.4.0 +DOCKER_TAG=1.4.2 EXTERNAL_NETWORK= COMPOSE_PROJECT_NAME= COMPOSE_PROJECT_NETWORK= diff --git a/core/relay/Makefile b/core/relay/Makefile index 2bc91d2e8..c02b537a3 100644 --- a/core/relay/Makefile +++ b/core/relay/Makefile @@ -4,6 +4,7 @@ PROTOS_TAG ?= v0.7 DOCKER_IMAGE_ALL = $(DOCKER_IMAGE_NAME):$(DOCKER_TAG) DOCKER_IMAGE_SERVER = $(DOCKER_IMAGE_NAME)-server:$(DOCKER_TAG) +DOCKER_IMAGE_SERVER_LATEST = $(DOCKER_IMAGE_NAME)-server:latest DOCKER_IMAGE_CLIENT = $(DOCKER_IMAGE_NAME)-client:$(DOCKER_TAG) DOCKER_IMAGE_DRIVER = $(DOCKER_IMAGE_NAME)-driver:$(DOCKER_TAG) @@ -105,11 +106,21 @@ build-allinone-local: protos-local fingerprint.json .PHONY: build-images-local build-images-local: build-allinone-local build-driver-local build-server-local build-client-local +.PHONY: check-if-tag-exists +check-if-tag-exists: + !(DOCKER_CLI_EXPERIMENTAL=enabled docker manifest inspect $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_SERVER) > /dev/null) + .PHONY: push-server -push-server: build-server-local +push-server: check-if-tag-exists build-server-local @echo -e "\033[1mPUSH\033[0m - Pushing Docker image (relay server)..." docker tag $(DOCKER_IMAGE_SERVER) $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_SERVER) docker push $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_SERVER) + +.PHONY: push-server +push-server-latest: + @echo -e "\033[1mPUSH\033[0m - Pushing Docker image Latest tag (relay server)..." + docker tag $(DOCKER_IMAGE_SERVER) $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_SERVER_LATEST) + docker push $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_SERVER_LATEST) .PHONY: push-client push-client: build-client diff --git a/core/relay/docker/testnet-envs/.env.corda b/core/relay/docker/testnet-envs/.env.corda index 6ba6d3342..ddba41ec2 100644 --- a/core/relay/docker/testnet-envs/.env.corda +++ b/core/relay/docker/testnet-envs/.env.corda @@ -7,7 +7,7 @@ DRIVER_NAME=corda-driver-Corda_Network RELAY_NAME=relay-corda RELAY_PORT=9081 DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-relay-server -DOCKER_TAG=1.3.1 +DOCKER_TAG=latest EXTERNAL_NETWORK=corda_default COMPOSE_PROJECT_NAME=corda COMPOSE_PROJECT_NETWORK=default diff --git a/core/relay/docker/testnet-envs/.env.corda.tls b/core/relay/docker/testnet-envs/.env.corda.tls index 494eb7c6c..df5e570de 100644 --- a/core/relay/docker/testnet-envs/.env.corda.tls +++ b/core/relay/docker/testnet-envs/.env.corda.tls @@ -7,7 +7,7 @@ DRIVER_NAME=corda-driver-Corda_Network RELAY_NAME=relay-corda RELAY_PORT=9081 DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-relay-server -DOCKER_TAG=1.3.1 +DOCKER_TAG=latest EXTERNAL_NETWORK=corda_default COMPOSE_PROJECT_NAME=corda COMPOSE_PROJECT_NETWORK=default diff --git a/core/relay/docker/testnet-envs/.env.corda2 b/core/relay/docker/testnet-envs/.env.corda2 index 4f958487b..436b5e5e2 100644 --- a/core/relay/docker/testnet-envs/.env.corda2 +++ b/core/relay/docker/testnet-envs/.env.corda2 @@ -7,7 +7,7 @@ DRIVER_NAME=corda-driver-Corda_Network2 RELAY_NAME=relay-corda2 RELAY_PORT=9082 DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-relay-server -DOCKER_TAG=1.3.1 +DOCKER_TAG=latest EXTERNAL_NETWORK=corda_network2_default COMPOSE_PROJECT_NAME=corda_network2 COMPOSE_PROJECT_NETWORK=default diff --git a/core/relay/docker/testnet-envs/.env.corda2.tls b/core/relay/docker/testnet-envs/.env.corda2.tls index 1f11398d1..0c8183111 100644 --- a/core/relay/docker/testnet-envs/.env.corda2.tls +++ b/core/relay/docker/testnet-envs/.env.corda2.tls @@ -7,7 +7,7 @@ DRIVER_NAME=corda-driver-Corda_Network2 RELAY_NAME=relay-corda2 RELAY_PORT=9082 DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-relay-server -DOCKER_TAG=1.3.1 +DOCKER_TAG=latest EXTERNAL_NETWORK=corda_network2_default COMPOSE_PROJECT_NAME=corda_network2 COMPOSE_PROJECT_NETWORK=default diff --git a/core/relay/docker/testnet-envs/.env.n1 b/core/relay/docker/testnet-envs/.env.n1 index 147dadc64..94f418953 100644 --- a/core/relay/docker/testnet-envs/.env.n1 +++ b/core/relay/docker/testnet-envs/.env.n1 @@ -7,7 +7,7 @@ DRIVER_NAME=fabric-driver-network1 RELAY_NAME=relay-network1 RELAY_PORT=9080 DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-relay-server -DOCKER_TAG=1.3.1 +DOCKER_TAG=latest EXTERNAL_NETWORK=network1_net COMPOSE_PROJECT_NAME=network1 COMPOSE_PROJECT_NETWORK=net diff --git a/core/relay/docker/testnet-envs/.env.n1.tls b/core/relay/docker/testnet-envs/.env.n1.tls index bb3fb4cc7..e7d63b13f 100644 --- a/core/relay/docker/testnet-envs/.env.n1.tls +++ b/core/relay/docker/testnet-envs/.env.n1.tls @@ -7,7 +7,7 @@ DRIVER_NAME=fabric-driver-network1 RELAY_NAME=relay-network1 RELAY_PORT=9080 DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-relay-server -DOCKER_TAG=1.3.1 +DOCKER_TAG=latest EXTERNAL_NETWORK=network1_net COMPOSE_PROJECT_NAME=network1 COMPOSE_PROJECT_NETWORK=net diff --git a/core/relay/docker/testnet-envs/.env.n2 b/core/relay/docker/testnet-envs/.env.n2 index e63771fbf..bbe7c89ec 100644 --- a/core/relay/docker/testnet-envs/.env.n2 +++ b/core/relay/docker/testnet-envs/.env.n2 @@ -7,7 +7,7 @@ DRIVER_NAME=fabric-driver-network2 RELAY_NAME=relay-network2 RELAY_PORT=9083 DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-relay-server -DOCKER_TAG=1.3.1 +DOCKER_TAG=latest EXTERNAL_NETWORK=network2_net COMPOSE_PROJECT_NAME=network2 COMPOSE_PROJECT_NETWORK=net diff --git a/core/relay/docker/testnet-envs/.env.n2.tls b/core/relay/docker/testnet-envs/.env.n2.tls index 15705dd1e..9c08d2671 100644 --- a/core/relay/docker/testnet-envs/.env.n2.tls +++ b/core/relay/docker/testnet-envs/.env.n2.tls @@ -7,7 +7,7 @@ DRIVER_NAME=fabric-driver-network2 RELAY_NAME=relay-network2 RELAY_PORT=9083 DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-relay-server -DOCKER_TAG=1.3.1 +DOCKER_TAG=latest EXTERNAL_NETWORK=network2_net COMPOSE_PROJECT_NAME=network2 COMPOSE_PROJECT_NETWORK=net From 2adfeb31f74a475acc4518894867a79227cb459a Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Fri, 22 Jul 2022 12:08:40 +0530 Subject: [PATCH 064/150] added push latest tag for docker images in workflows Signed-off-by: sandeep.nishad1 --- .github/workflows/deploy_corda-pkgs.yml | 4 ++++ .github/workflows/deploy_fabric-pkgs.yml | 4 ++++ .github/workflows/deploy_relay-server.yml | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/.github/workflows/deploy_corda-pkgs.yml b/.github/workflows/deploy_corda-pkgs.yml index 1f5420b14..9bd6a4f74 100644 --- a/.github/workflows/deploy_corda-pkgs.yml +++ b/.github/workflows/deploy_corda-pkgs.yml @@ -129,3 +129,7 @@ jobs: - name: Build and Push run: make push-image working-directory: core/drivers/corda-driver + + - name: Push latest tag + run: make push-image-latest + working-directory: core/drivers/corda-driver diff --git a/.github/workflows/deploy_fabric-pkgs.yml b/.github/workflows/deploy_fabric-pkgs.yml index 2b3d27b1f..253a94b05 100644 --- a/.github/workflows/deploy_fabric-pkgs.yml +++ b/.github/workflows/deploy_fabric-pkgs.yml @@ -100,3 +100,7 @@ jobs: - name: Build and Push run: make push-image working-directory: core/drivers/fabric-driver + + - name: Push latest tag + run: make push-image-latest + working-directory: core/drivers/fabric-driver diff --git a/.github/workflows/deploy_relay-server.yml b/.github/workflows/deploy_relay-server.yml index 18bfe0504..3e4bcc27e 100644 --- a/.github/workflows/deploy_relay-server.yml +++ b/.github/workflows/deploy_relay-server.yml @@ -27,4 +27,8 @@ jobs: - name: Build and Push run: make push-server + working-directory: core/relay + + - name: Push latest tag + run: make push-server-latest working-directory: core/relay \ No newline at end of file From 630abe2d1c8f21ac4bbbe7857d9b2e2e3fcbef5a Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Fri, 22 Jul 2022 17:37:53 +0530 Subject: [PATCH 065/150] code restructuring Signed-off-by: Krishnasuri Narayanam --- core/drivers/fabric-driver/server/events.ts | 61 +++++++++++++++++++- core/drivers/fabric-driver/server/server.ts | 64 +-------------------- 2 files changed, 63 insertions(+), 62 deletions(-) diff --git a/core/drivers/fabric-driver/server/events.ts b/core/drivers/fabric-driver/server/events.ts index 6176eb82e..923a9d45e 100644 --- a/core/drivers/fabric-driver/server/events.ts +++ b/core/drivers/fabric-driver/server/events.ts @@ -13,6 +13,9 @@ import { getDriverKeyCert } from "./walletSetup"; import { DBConnector, LevelDBConnector } from "./dbConnector"; import { checkIfArraysAreEqual, handlePromise, relayCallback } from "./utils"; import { registerListenerForEventSubscription, unregisterListenerForEventSubscription } from "./listener"; +import { getNetworkGateway } from "./fabric-code"; +import state_pb from '@hyperledger-labs/weaver-protos-js/common/state_pb'; +import driverPb from '@hyperledger-labs/weaver-protos-js/driver/driver_pb'; const DB_NAME: string = "driverdb"; @@ -344,11 +347,67 @@ async function signEventSubscriptionQuery( } } +async function writeExternalStateHelper( + writeExternalStateMessage: driverPb.WriteExternalStateMessage, + networkName: string +) : Promise { + const viewPayload: state_pb.ViewPayload = writeExternalStateMessage.getViewPayload(); + const ctx: eventsPb.ContractTransaction = writeExternalStateMessage.getCtx(); + const keyCert = await getDriverKeyCert(); + + const requestId: string = viewPayload.getRequestId(); + if (!viewPayload.getError()) { + + let interopArgIndices = [], viewsSerializedBase64 = [], addresses = [], viewContentsBase64 = []; + const view: state_pb.View = viewPayload.getView(); + + const result = InteroperableHelper.getResponseDataFromView(view, keyCert.key.toBytes()); + if (result.interopPayload.getConfidential()) { + viewContentsBase64.push(result.contents.toString("base64")); + } else { + viewContentsBase64.push(""); + } + + interopArgIndices.push(ctx.getReplaceArgIndex()); + addresses.push(result.interopPayload.getAddress()); + viewsSerializedBase64.push(Buffer.from(viewPayload.getView().serializeBinary()).toString("base64")); + + const invokeObject = { + channel: ctx.getLedgerId(), + ccFunc: ctx.getFunc(), + ccArgs: ctx.getArgsList(), + contractName: ctx.getContractId() + } + + const gateway = await getNetworkGateway(networkName); + const network = await gateway.getNetwork(ctx.getLedgerId()); + const interopContract = network.getContract(process.env.INTEROP_CHAINCODE ? process.env.INTEROP_CHAINCODE : 'interop'); + + const [ response, responseError ] = await handlePromise(InteroperableHelper.submitTransactionWithRemoteViews( + interopContract, + invokeObject, + interopArgIndices, + addresses, + viewsSerializedBase64, + viewContentsBase64 + )); + if (responseError) { + console.log(`Failed writing to the ledger with error: ${responseError}`); + throw responseError; + } + } else { + const errorString: string = `erroneous viewPayload identified in WriteExternalState processing`; + console.log(`error viewPayload.getError(): ${JSON.stringify(viewPayload.getError())}`); + throw new Error(errorString); + } +} + export { subscribeEventHelper, unsubscribeEventHelper, addEventSubscription, deleteEventSubscription, lookupEventSubscriptions, - signEventSubscriptionQuery + signEventSubscriptionQuery, + writeExternalStateHelper } diff --git a/core/drivers/fabric-driver/server/server.ts b/core/drivers/fabric-driver/server/server.ts index 99785d9b3..a7e33780a 100644 --- a/core/drivers/fabric-driver/server/server.ts +++ b/core/drivers/fabric-driver/server/server.ts @@ -9,7 +9,7 @@ import { Server, ServerCredentials, credentials } from '@grpc/grpc-js'; import ack_pb from '@hyperledger-labs/weaver-protos-js/common/ack_pb'; import query_pb from '@hyperledger-labs/weaver-protos-js/common/query_pb'; import fabricViewPb from '@hyperledger-labs/weaver-protos-js/fabric/view_data_pb'; -import eventsPb, { EventMatcher } from '@hyperledger-labs/weaver-protos-js/common/events_pb'; +import eventsPb from '@hyperledger-labs/weaver-protos-js/common/events_pb'; import driver_pb_grpc from '@hyperledger-labs/weaver-protos-js/driver/driver_grpc_pb'; import datatransfer_grpc_pb from '@hyperledger-labs/weaver-protos-js/relay/datatransfer_grpc_pb'; import events_grpc_pb from '@hyperledger-labs/weaver-protos-js/relay/events_grpc_pb'; @@ -17,14 +17,11 @@ import state_pb from '@hyperledger-labs/weaver-protos-js/common/state_pb'; import { invoke, packageFabricView } from './fabric-code'; import 'dotenv/config'; import { walletSetup } from './walletSetup'; -import { subscribeEventHelper, unsubscribeEventHelper, signEventSubscriptionQuery } from "./events" +import { subscribeEventHelper, unsubscribeEventHelper, signEventSubscriptionQuery, writeExternalStateHelper } from "./events" import * as path from 'path'; import { handlePromise, relayCallback, getRelayClientForQueryResponse } from './utils'; import { dbConnectionTest, eventSubscriptionTest } from "./tests" import driverPb from '@hyperledger-labs/weaver-protos-js/driver/driver_pb'; -import { getDriverKeyCert } from "./walletSetup"; -import { getResponseDataFromView, submitTransactionWithRemoteViews } from '@hyperledger-labs/weaver-fabric-interop-sdk'; -import { getNetworkGateway } from "./fabric-code"; const server = new Server(); console.log('driver def', JSON.stringify(driver_pb_grpc)); @@ -244,7 +241,7 @@ server.addService(driver_pb_grpc.DriverCommunicationService, { }).catch((error) => { const ack_err_response = new ack_pb.Ack(); ack_err_response.setRequestId(requestId); - ack_err_response.setMessage(JSON.stringify(error)); + ack_err_response.setMessage(error.toString()); ack_err_response.setStatus(ack_pb.Ack.STATUS.ERROR); // gRPC response. console.log(`Responding to caller with error Ack: ${JSON.stringify(ack_err_response.toObject())}`); @@ -253,61 +250,6 @@ server.addService(driver_pb_grpc.DriverCommunicationService, { }, }); -async function writeExternalStateHelper( - writeExternalStateMessage: driverPb.WriteExternalStateMessage, - networkName: string -) : Promise { - const viewPayload: state_pb.ViewPayload = writeExternalStateMessage.getViewPayload(); - const ctx: eventsPb.ContractTransaction = writeExternalStateMessage.getCtx(); - const keyCert = await getDriverKeyCert(); - - const requestId: string = viewPayload.getRequestId(); - if (!viewPayload.getError()) { - - let interopArgIndices = [], viewsSerializedBase64 = [], addresses = [], viewContentsBase64 = []; - const view: state_pb.View = viewPayload.getView(); - - const result = getResponseDataFromView(view, keyCert.key.toBytes()); - if (result.interopPayload.getConfidential()) { - viewContentsBase64.push(result.contents.toString("base64")); - } else { - viewContentsBase64.push(""); - } - - interopArgIndices.push(ctx.getReplaceArgIndex()); - addresses.push(result.interopPayload.getAddress()); - viewsSerializedBase64.push(Buffer.from(viewPayload.getView().serializeBinary()).toString("base64")); - - const invokeObject = { - channel: ctx.getLedgerId(), - ccFunc: ctx.getFunc(), - ccArgs: ctx.getArgsList(), - contractName: ctx.getContractId() - } - - const gateway = await getNetworkGateway(networkName); - const network = await gateway.getNetwork(ctx.getLedgerId()); - const interopContract = network.getContract(process.env.INTEROP_CHAINCODE ? process.env.INTEROP_CHAINCODE : 'interop'); - - const [ response, responseError ] = await handlePromise(submitTransactionWithRemoteViews( - interopContract, - invokeObject, - interopArgIndices, - addresses, - viewsSerializedBase64, - viewContentsBase64 - )); - if (responseError) { - console.log(`Failed writing to the ledger with error: ${responseError}`); - throw responseError; - } - } else { - const errorString: string = 'erroneous viewPayload identified in WriteExternalState processing'; - console.log(`error viewPayload.getError(): ${JSON.stringify(viewPayload.getError())}`); - throw new Error(errorString); - } -} - // Prepares required crypto material for communication with the fabric network const configSetup = async () => { // uses the network name to create a unique wallet path From 1755e966ccaefdfd89ceeab0885136803b637ab4 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Tue, 26 Jul 2022 03:02:06 +0000 Subject: [PATCH 066/150] doc changes and minor edits Signed-off-by: Krishnasuri Narayanam --- core/drivers/fabric-driver/server/events.ts | 8 +++++++- samples/fabric/fabric-cli/readme.md | 8 ++++++++ .../src/data/credentials/network1/access-control.json | 2 +- .../data/credentials/network1/verification-policy.json | 2 +- sdks/fabric/interoperation-node-sdk/src/EventsManager.ts | 9 ++++++++- 5 files changed, 25 insertions(+), 4 deletions(-) diff --git a/core/drivers/fabric-driver/server/events.ts b/core/drivers/fabric-driver/server/events.ts index 923a9d45e..92d321ae6 100644 --- a/core/drivers/fabric-driver/server/events.ts +++ b/core/drivers/fabric-driver/server/events.ts @@ -372,12 +372,18 @@ async function writeExternalStateHelper( addresses.push(result.interopPayload.getAddress()); viewsSerializedBase64.push(Buffer.from(viewPayload.getView().serializeBinary()).toString("base64")); + let ccArgsB64 = ctx.getArgsList_asB64(); + let ccArgsStr = []; + for (const ccArgB64 of ccArgsB64) { + ccArgsStr.push(Buffer.from(ccArgB64, 'base64').toString('utf8')); + } const invokeObject = { channel: ctx.getLedgerId(), ccFunc: ctx.getFunc(), - ccArgs: ctx.getArgsList(), + ccArgs: ccArgsStr, contractName: ctx.getContractId() } + console.debug(`invokeObject.ccArgs: ${invokeObject.ccArgs}`) const gateway = await getNetworkGateway(networkName); const network = await gateway.getNetwork(ctx.getLedgerId()); diff --git a/samples/fabric/fabric-cli/readme.md b/samples/fabric/fabric-cli/readme.md index f95cb0a3f..ba84a7ab9 100644 --- a/samples/fabric/fabric-cli/readme.md +++ b/samples/fabric/fabric-cli/readme.md @@ -399,6 +399,14 @@ Below are the steps to exercise asset transfers from `network1` to `network2` us ``` ./bin/fabric-cli event get-subscription-status --network=network1 --request-id= ``` +* To start the HTTP server to listen to the published events by the destination/importing relay (fetched from the source/exporting network), run the following command: + ``` + ./bin/fabric-cli event receive + ``` + By default, it will start the below endpoint: + ``` + http://localhost:8080/simple-event-callback + ``` ## NOTE diff --git a/samples/fabric/fabric-cli/src/data/credentials/network1/access-control.json b/samples/fabric/fabric-cli/src/data/credentials/network1/access-control.json index 9146b7417..42d5e2c55 100644 --- a/samples/fabric/fabric-cli/src/data/credentials/network1/access-control.json +++ b/samples/fabric/fabric-cli/src/data/credentials/network1/access-control.json @@ -1 +1 @@ -{"securityDomain":"network1","rules":[{"principal":"Org1MSP","principalType":"ca","resource":"mychannel:simplestate:Read:*","read":true}]} +{"securityDomain":"network1","rules":[{"principal":"Org1MSP","principalType":"ca","resource":"mychannel:simplestate:Read:*","read":true}]} \ No newline at end of file diff --git a/samples/fabric/fabric-cli/src/data/credentials/network1/verification-policy.json b/samples/fabric/fabric-cli/src/data/credentials/network1/verification-policy.json index 1e8556e3b..8f6aaa053 100644 --- a/samples/fabric/fabric-cli/src/data/credentials/network1/verification-policy.json +++ b/samples/fabric/fabric-cli/src/data/credentials/network1/verification-policy.json @@ -1 +1 @@ -{"securityDomain":"network1","identifiers":[{"pattern":"mychannel:simplestate:Read:*","policy":{"type":"Signature","criteria":["Org1MSP"]}}]} +{"securityDomain":"network1","identifiers":[{"pattern":"mychannel:simplestate:Read:*","policy":{"type":"Signature","criteria":["Org1MSP"]}}]} \ No newline at end of file diff --git a/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts b/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts index 9669e1c83..2b7abfd87 100644 --- a/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts +++ b/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts @@ -65,12 +65,19 @@ function createEventPublicationSpec ({ if (appUrl) { eventPublicationSpec.setAppUrl(appUrl) } else { + + let ccArgsB64 = []; + for (const ccArg of ccArgs) { + ccArgsB64.push(Buffer.from(ccArg).toString('base64')); + } + console.log(`ccArgs: ${ccArgs} ccArgsB64: ${ccArgsB64}`) + const ctx = new eventsPb.ContractTransaction() ctx.setDriverId(driverId) ctx.setLedgerId(channelId) ctx.setContractId(chaincodeId) ctx.setFunc(ccFunc) - ctx.setArgsList(ccArgs) + ctx.setArgsList(ccArgsB64) ctx.setReplaceArgIndex(replaceArgIndex) eventPublicationSpec.setCtx(ctx) } From 0736f3aa3203987613b8c2d5ba030f8d4e349a5c Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Tue, 26 Jul 2022 14:44:16 +0530 Subject: [PATCH 067/150] weaver-cc image for external service added Signed-off-by: sandeep.nishad1 --- core/network/fabric-interop-cc/.env.template | 10 ++++++++ core/network/fabric-interop-cc/.gitignore | 3 ++- core/network/fabric-interop-cc/Dockerfile | 3 +++ .../fabric-interop-cc/docker-compose.yml | 23 +++++++++++++++++++ .../external-service/connection.json | 9 ++++++++ .../external-service/metadata.json | 5 ++++ core/network/fabric-interop-cc/makefile | 19 ++++++++++++++- .../makefile.variables.docker | 4 ++++ 8 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 core/network/fabric-interop-cc/.env.template create mode 100644 core/network/fabric-interop-cc/docker-compose.yml create mode 100644 core/network/fabric-interop-cc/external-service/connection.json create mode 100644 core/network/fabric-interop-cc/external-service/metadata.json create mode 100644 core/network/fabric-interop-cc/makefile.variables.docker diff --git a/core/network/fabric-interop-cc/.env.template b/core/network/fabric-interop-cc/.env.template new file mode 100644 index 000000000..d0902ceb2 --- /dev/null +++ b/core/network/fabric-interop-cc/.env.template @@ -0,0 +1,10 @@ +CCID= +CHANNEL= +PEER= +ORG= +NETWORK= +DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-fabric-cc +DOCKER_TAG=1.4.0 +EXTERNAL_NETWORK= +COMPOSE_PROJECT_NAME= +COMPOSE_PROJECT_NETWORK= \ No newline at end of file diff --git a/core/network/fabric-interop-cc/.gitignore b/core/network/fabric-interop-cc/.gitignore index 97f005b91..a3b4dbb4e 100644 --- a/core/network/fabric-interop-cc/.gitignore +++ b/core/network/fabric-interop-cc/.gitignore @@ -15,4 +15,5 @@ # vendor/ protos fabric-protos -bin \ No newline at end of file +bin +.env diff --git a/core/network/fabric-interop-cc/Dockerfile b/core/network/fabric-interop-cc/Dockerfile index 92386d1bb..a413d3171 100644 --- a/core/network/fabric-interop-cc/Dockerfile +++ b/core/network/fabric-interop-cc/Dockerfile @@ -19,3 +19,6 @@ USER 1000 WORKDIR /app CMD ./interop + +ARG GIT_URL +LABEL org.opencontainers.image.source ${GIT_URL} \ No newline at end of file diff --git a/core/network/fabric-interop-cc/docker-compose.yml b/core/network/fabric-interop-cc/docker-compose.yml new file mode 100644 index 000000000..0cb7d0bae --- /dev/null +++ b/core/network/fabric-interop-cc/docker-compose.yml @@ -0,0 +1,23 @@ +# +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +version: '2' +services: + fabric-driver: + image: ${DOCKER_IMAGE_NAME}:${DOCKER_TAG} + container_name: weaver-faric-${CHANNEL}-${PEER}-${ORG}-${NETWORK} + environment: + - CC_NAME=interop + - EXTERNAL_SERVICE=true + - CHAINCODE_ADDRESS=0.0.0.0:7052 + - CHAINCODE_CCID=${CCID} + ports: + - 7052:7052 +# This networks section is required for when the peers have networks specified +networks: + default: + external: + name: ${EXTERNAL_NETWORK} diff --git a/core/network/fabric-interop-cc/external-service/connection.json b/core/network/fabric-interop-cc/external-service/connection.json new file mode 100644 index 000000000..b8bb7272a --- /dev/null +++ b/core/network/fabric-interop-cc/external-service/connection.json @@ -0,0 +1,9 @@ +{ + "address": "weaver-fabric-mychannel-peer0-org1-network1:7052", + "dial_timeout": "10s", + "tls_required": "false", + "client_auth_required": "false", + "client_key": "-----BEGIN EC PRIVATE KEY----- ... -----END EC PRIVATE KEY-----", + "client_cert": "-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----", + "root_cert": "-----BEGIN CERTIFICATE---- ... -----END CERTIFICATE-----" +} \ No newline at end of file diff --git a/core/network/fabric-interop-cc/external-service/metadata.json b/core/network/fabric-interop-cc/external-service/metadata.json new file mode 100644 index 000000000..d70d6317c --- /dev/null +++ b/core/network/fabric-interop-cc/external-service/metadata.json @@ -0,0 +1,5 @@ +{ + "path":"", + "type":"external", + "label":"weavercc" +} \ No newline at end of file diff --git a/core/network/fabric-interop-cc/makefile b/core/network/fabric-interop-cc/makefile index 6bfda1f81..5eb946d79 100644 --- a/core/network/fabric-interop-cc/makefile +++ b/core/network/fabric-interop-cc/makefile @@ -1,4 +1,6 @@ -.PHONY: build protos all clean +include makefile.variables.docker + +.PHONY: build protos all clean image push-image check-if-tag-exists all: build @@ -6,5 +8,20 @@ build: echo "Building chaincode binary" ./scripts/build.sh +image: + (cd contracts/interop && make run-vendor) + docker build --build-arg GIT_URL=$(GIT_URL) -t ${DOCKER_IMAGE_NAME}:$(DOCKER_TAG) . + +check-if-tag-exists: + !(DOCKER_CLI_EXPERIMENTAL=enabled docker manifest inspect $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_NAME):$(DOCKER_TAG) > /dev/null) + +push-image: check-if-tag-exists image + docker tag ${DOCKER_IMAGE_NAME}:$(DOCKER_TAG) $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_NAME):$(DOCKER_TAG) + docker push $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_NAME):$(DOCKER_TAG) + +push-image-latest: + docker tag ${DOCKER_IMAGE_NAME}:$(DOCKER_TAG) $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_NAME):latest + docker push $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_NAME):latest + clean: rm -rf ./bin diff --git a/core/network/fabric-interop-cc/makefile.variables.docker b/core/network/fabric-interop-cc/makefile.variables.docker new file mode 100644 index 000000000..75d2b1855 --- /dev/null +++ b/core/network/fabric-interop-cc/makefile.variables.docker @@ -0,0 +1,4 @@ +DOCKER_IMAGE_NAME ?= weaver-fabric-cc +DOCKER_TAG ?= 1.4.0 +DOCKER_REGISTRY ?= ghcr.io/hyperledger-labs +GIT_URL = https://github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc \ No newline at end of file From a76866c4c4d62333041bc83d87fd841013c46b57 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Tue, 26 Jul 2022 14:48:40 +0530 Subject: [PATCH 068/150] workflow to deploy weaver chaincode docker image Signed-off-by: sandeep.nishad1 --- .github/workflows/deploy_weaver-fabric-cc.yml | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/workflows/deploy_weaver-fabric-cc.yml diff --git a/.github/workflows/deploy_weaver-fabric-cc.yml b/.github/workflows/deploy_weaver-fabric-cc.yml new file mode 100644 index 000000000..c66ff9fe0 --- /dev/null +++ b/.github/workflows/deploy_weaver-fabric-cc.yml @@ -0,0 +1,34 @@ +name: Deploy Weaver Fabric CC Docker Image + +on: + push: + branches: + - main + paths: + - 'core/network/fabric-interop-cc/Makefile.variables.docker' + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + relay-image: + if: github.repository_owner == 'hyperledger-labs' + runs-on: ubuntu-latest + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and Push + run: make push-image + working-directory: core/network/fabric-interop-cc + + - name: Push latest tag + run: make push-image-latest + working-directory: core/network/fabric-interop-cc \ No newline at end of file From 2fcf5fd41f421ee5054f1c932763643230328d20 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Tue, 26 Jul 2022 15:10:19 +0530 Subject: [PATCH 069/150] changed Args to string array Signed-off-by: Krishnasuri Narayanam --- common/protos/common/events.proto | 2 +- core/drivers/fabric-driver/server/events.ts | 7 +------ sdks/fabric/interoperation-node-sdk/src/EventsManager.ts | 8 +------- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/common/protos/common/events.proto b/common/protos/common/events.proto index 416247532..d8377bd39 100644 --- a/common/protos/common/events.proto +++ b/common/protos/common/events.proto @@ -60,7 +60,7 @@ message ContractTransaction { string ledger_id = 2; string contract_id = 3; string func = 4; - repeated bytes args = 5; + repeated string args = 5; uint64 replace_arg_index = 6; } diff --git a/core/drivers/fabric-driver/server/events.ts b/core/drivers/fabric-driver/server/events.ts index 92d321ae6..c9cdde7c3 100644 --- a/core/drivers/fabric-driver/server/events.ts +++ b/core/drivers/fabric-driver/server/events.ts @@ -372,15 +372,10 @@ async function writeExternalStateHelper( addresses.push(result.interopPayload.getAddress()); viewsSerializedBase64.push(Buffer.from(viewPayload.getView().serializeBinary()).toString("base64")); - let ccArgsB64 = ctx.getArgsList_asB64(); - let ccArgsStr = []; - for (const ccArgB64 of ccArgsB64) { - ccArgsStr.push(Buffer.from(ccArgB64, 'base64').toString('utf8')); - } const invokeObject = { channel: ctx.getLedgerId(), ccFunc: ctx.getFunc(), - ccArgs: ccArgsStr, + ccArgs: ctx.getArgsList(), contractName: ctx.getContractId() } console.debug(`invokeObject.ccArgs: ${invokeObject.ccArgs}`) diff --git a/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts b/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts index 2b7abfd87..1670143d4 100644 --- a/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts +++ b/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts @@ -66,18 +66,12 @@ function createEventPublicationSpec ({ eventPublicationSpec.setAppUrl(appUrl) } else { - let ccArgsB64 = []; - for (const ccArg of ccArgs) { - ccArgsB64.push(Buffer.from(ccArg).toString('base64')); - } - console.log(`ccArgs: ${ccArgs} ccArgsB64: ${ccArgsB64}`) - const ctx = new eventsPb.ContractTransaction() ctx.setDriverId(driverId) ctx.setLedgerId(channelId) ctx.setContractId(chaincodeId) ctx.setFunc(ccFunc) - ctx.setArgsList(ccArgsB64) + ctx.setArgsList(ccArgs) ctx.setReplaceArgIndex(replaceArgIndex) eventPublicationSpec.setCtx(ctx) } From 5a446daef9d140717f9c02a85c020de0d97653cc Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Wed, 27 Jul 2022 03:38:54 +0000 Subject: [PATCH 070/150] disconnect gateway at the end Signed-off-by: Krishnasuri Narayanam --- core/drivers/fabric-driver/server/events.ts | 10 +++++++--- .../fabric/fabric-cli/src/helpers/fabric-functions.ts | 6 +++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/core/drivers/fabric-driver/server/events.ts b/core/drivers/fabric-driver/server/events.ts index c9cdde7c3..7baea85fb 100644 --- a/core/drivers/fabric-driver/server/events.ts +++ b/core/drivers/fabric-driver/server/events.ts @@ -14,6 +14,7 @@ import { DBConnector, LevelDBConnector } from "./dbConnector"; import { checkIfArraysAreEqual, handlePromise, relayCallback } from "./utils"; import { registerListenerForEventSubscription, unregisterListenerForEventSubscription } from "./listener"; import { getNetworkGateway } from "./fabric-code"; +import { Gateway, Network, Contract } from "fabric-network"; import state_pb from '@hyperledger-labs/weaver-protos-js/common/state_pb'; import driverPb from '@hyperledger-labs/weaver-protos-js/driver/driver_pb'; @@ -354,6 +355,7 @@ async function writeExternalStateHelper( const viewPayload: state_pb.ViewPayload = writeExternalStateMessage.getViewPayload(); const ctx: eventsPb.ContractTransaction = writeExternalStateMessage.getCtx(); const keyCert = await getDriverKeyCert(); + let gateway: Gateway; const requestId: string = viewPayload.getRequestId(); if (!viewPayload.getError()) { @@ -380,9 +382,9 @@ async function writeExternalStateHelper( } console.debug(`invokeObject.ccArgs: ${invokeObject.ccArgs}`) - const gateway = await getNetworkGateway(networkName); - const network = await gateway.getNetwork(ctx.getLedgerId()); - const interopContract = network.getContract(process.env.INTEROP_CHAINCODE ? process.env.INTEROP_CHAINCODE : 'interop'); + gateway = await getNetworkGateway(networkName); + const network: Network = await gateway.getNetwork(ctx.getLedgerId()); + const interopContract: Contract = network.getContract(process.env.INTEROP_CHAINCODE ? process.env.INTEROP_CHAINCODE : 'interop'); const [ response, responseError ] = await handlePromise(InteroperableHelper.submitTransactionWithRemoteViews( interopContract, @@ -396,9 +398,11 @@ async function writeExternalStateHelper( console.log(`Failed writing to the ledger with error: ${responseError}`); throw responseError; } + gateway.disconnect(); } else { const errorString: string = `erroneous viewPayload identified in WriteExternalState processing`; console.log(`error viewPayload.getError(): ${JSON.stringify(viewPayload.getError())}`); + gateway.disconnect(); throw new Error(errorString); } } diff --git a/samples/fabric/fabric-cli/src/helpers/fabric-functions.ts b/samples/fabric/fabric-cli/src/helpers/fabric-functions.ts index 7cf68917f..72f756829 100644 --- a/samples/fabric/fabric-cli/src/helpers/fabric-functions.ts +++ b/samples/fabric/fabric-cli/src/helpers/fabric-functions.ts @@ -58,7 +58,7 @@ const walletSetup = async ( : path.join(__dirname, '../', `wallet-${networkName}`) const wallet = await Wallets.newFileSystemWallet(walletPath) - logger.info(`Wallet Setup: wallet path: ${walletPath}`) + logger.debug(`Wallet Setup: wallet path: ${walletPath}`) // build a user object for authenticating with the CA // Check to see if we've already enrolled the admin user. let adminIdentity = await wallet.get('admin') @@ -87,7 +87,7 @@ const walletSetup = async ( const provider = wallet.getProviderRegistry().getProvider(adminIdentity.type) const adminUser = await provider.getUserContext(adminIdentity, 'admin') const identity = await wallet.get(userName) - logger.info(`user ${userName}`) + logger.debug(`user ${userName}`) if (!identity) { // Register the user, enroll the user, and import the new identity into the wallet. if (!register) { @@ -156,7 +156,7 @@ const walletSetup = async ( await wallet.put(userName, x509Identity) } else { - logger.info(`Identity ${userName} already exists.\n`) + logger.debug(`Identity ${userName} already exists.\n`) } return wallet From 7be1d895d36d2731153af608acb1132437a5e7c8 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Wed, 27 Jul 2022 10:24:24 +0000 Subject: [PATCH 071/150] workaround fix with patch Signed-off-by: Krishnasuri Narayanam --- .../fabric-driver/patches/fabric-network+2.2.13.patch | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/core/drivers/fabric-driver/patches/fabric-network+2.2.13.patch b/core/drivers/fabric-driver/patches/fabric-network+2.2.13.patch index a9d6f0a57..c72ef8d0f 100644 --- a/core/drivers/fabric-driver/patches/fabric-network+2.2.13.patch +++ b/core/drivers/fabric-driver/patches/fabric-network+2.2.13.patch @@ -24,21 +24,12 @@ index 24e66f2..12dbb43 100644 endorsement.sign(this.identityContext); // ------- S E N D P R O P O S A L // This is where the request gets sent to the peers -@@ -253,7 +253,7 @@ class Transaction { - const proposalResponse = await endorsement.send(proposalSendRequest); - try { - const result = getResponsePayload(proposalResponse); -- // ------- E V E N T M O N I T O R -+ /* // ------- E V E N T M O N I T O R - const eventHandler = this.eventHandlerStrategyFactory(endorsement.getTransactionId(), this.contract.network); - await eventHandler.startListening(); - const commit = endorsement.newCommit(); @@ -288,7 +288,8 @@ class Transaction { } logger.debug('%s - wait for the transaction to be committed on the peer', method); await eventHandler.waitForEvents(); - return result; -+ return result;*/ ++ // need this dummy comment line for the patch to work + return {result, proposalResponse: proposalResponse.responses, proposal: proposal} ; } catch (err) { From 2edc6d2a78345ffbfaa7e4bba7b00995b08b2ee3 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Wed, 27 Jul 2022 13:12:07 +0000 Subject: [PATCH 072/150] fabric driver doing a query instead of invoke to the ledger Signed-off-by: Krishnasuri Narayanam --- core/drivers/fabric-driver/makefile | 2 - core/drivers/fabric-driver/package-local.json | 1 - core/drivers/fabric-driver/package.json | 1 - .../patches/fabric-network+2.2.13.patch | 36 --------------- .../fabric-driver/server/fabric-code.ts | 44 +++++++++++++------ 5 files changed, 31 insertions(+), 53 deletions(-) delete mode 100644 core/drivers/fabric-driver/patches/fabric-network+2.2.13.patch diff --git a/core/drivers/fabric-driver/makefile b/core/drivers/fabric-driver/makefile index 917caf128..eb4ecbe0e 100644 --- a/core/drivers/fabric-driver/makefile +++ b/core/drivers/fabric-driver/makefile @@ -5,7 +5,6 @@ COMPOSE_ARG ?= build: .npmrc npm install npm run build - npm run postinstall protos-js: mkdir -p protos-js && \ @@ -33,7 +32,6 @@ build-local: protos-js weaver-fabric-interop-sdk (mv package-remote.json package.json && exit 1) # Only if fails mv package-remote.json package.json # Only if success npm run build - npm run postinstall build-image-local: protos-js weaver-fabric-interop-sdk cp package.json package-remote.json diff --git a/core/drivers/fabric-driver/package-local.json b/core/drivers/fabric-driver/package-local.json index 4f451da47..6b2df0b27 100644 --- a/core/drivers/fabric-driver/package-local.json +++ b/core/drivers/fabric-driver/package-local.json @@ -6,7 +6,6 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "npm run tsc", - "postinstall": "patch-package", "tsc": "tsc", "start": "node out/server.js", "watch": "tsc --watch", diff --git a/core/drivers/fabric-driver/package.json b/core/drivers/fabric-driver/package.json index 72d81c918..acd652ea5 100644 --- a/core/drivers/fabric-driver/package.json +++ b/core/drivers/fabric-driver/package.json @@ -6,7 +6,6 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "npm run tsc", - "postinstall": "patch-package", "tsc": "tsc", "start": "node out/server.js", "watch": "tsc --watch", diff --git a/core/drivers/fabric-driver/patches/fabric-network+2.2.13.patch b/core/drivers/fabric-driver/patches/fabric-network+2.2.13.patch deleted file mode 100644 index c72ef8d0f..000000000 --- a/core/drivers/fabric-driver/patches/fabric-network+2.2.13.patch +++ /dev/null @@ -1,36 +0,0 @@ -diff --git a/node_modules/fabric-network/lib/transaction.d.ts b/node_modules/fabric-network/lib/transaction.d.ts -index 47ce1d1..3c65e83 100644 ---- a/node_modules/fabric-network/lib/transaction.d.ts -+++ b/node_modules/fabric-network/lib/transaction.d.ts -@@ -100,7 +100,7 @@ export declare class Transaction { - * @throws {module:fabric-network.TransactionError} If the transaction committed with an unsuccessful transaction - * validation code, and so did not update the ledger. - */ -- submit(...args: string[]): Promise; -+ submit(...args: string[]): Promise; - /** - * Evaluate a transaction function and return its results. - * The transaction function will be evaluated on the endorsing peers but -diff --git a/node_modules/fabric-network/lib/transaction.js b/node_modules/fabric-network/lib/transaction.js -index 24e66f2..12dbb43 100644 ---- a/node_modules/fabric-network/lib/transaction.js -+++ b/node_modules/fabric-network/lib/transaction.js -@@ -216,7 +216,7 @@ class Transaction { - logger.debug('%s - build and send the endorsement', method); - // build the outbound request along with getting a new transactionId - // from the identity context -- endorsement.build(this.identityContext, proposalBuildRequest); -+ const proposal = endorsement.build(this.identityContext, proposalBuildRequest); - endorsement.sign(this.identityContext); - // ------- S E N D P R O P O S A L - // This is where the request gets sent to the peers -@@ -288,7 +288,8 @@ class Transaction { - } - logger.debug('%s - wait for the transaction to be committed on the peer', method); - await eventHandler.waitForEvents(); -- return result; -+ // need this dummy comment line for the patch to work -+ return {result, proposalResponse: proposalResponse.responses, proposal: proposal} ; - } - catch (err) { - err.responses = proposalResponse.responses; diff --git a/core/drivers/fabric-driver/server/fabric-code.ts b/core/drivers/fabric-driver/server/fabric-code.ts index d443d3726..e20e02011 100644 --- a/core/drivers/fabric-driver/server/fabric-code.ts +++ b/core/drivers/fabric-driver/server/fabric-code.ts @@ -78,12 +78,12 @@ async function invoke( query: query_pb.Query, networkName: string, ): Promise { - console.log('Running invoke on fabric network'); + console.log('Running query on fabric network'); try { // 1. Prepare credentials/gateway for communicating with fabric network const gateway = await getNetworkGateway(networkName); - // 2. Prepare info required for invoke (address/policy) + // 2. Prepare info required for query (address/policy) const parsedAddress = parseAddress(query.getAddress()); // Get the network (channel) our contract is deployed to. console.log(parsedAddress.channel); @@ -93,7 +93,7 @@ async function invoke( console.log(endorsers); // Get the contract from the network. console.log('policy', query.getPolicyList()); - const contract = network.getContract(process.env.INTEROP_CHAINCODE ? process.env.INTEROP_CHAINCODE : 'interop'); + const chaincodeId = process.env.INTEROP_CHAINCODE ? process.env.INTEROP_CHAINCODE : 'interop'; // LOGIC for getting identities from the provided policy. If none can be found it will default to all. const identities = query.getPolicyList(); @@ -111,8 +111,19 @@ async function invoke( query.getRequestorSignature(), query.getAddress() + query.getNonce(), ); + const b64QueryBytes = Buffer.from(query.serializeBinary()).toString('base64'); + + const idx = gateway.identityContext.calculateTransactionId(); + const queryProposal = currentChannel.newQuery(chaincodeId); + const request = { + fcn: 'HandleExternalRequest', + args: [b64QueryBytes], + generateTransactionId: false + }; + queryProposal.build(idx, request); + queryProposal.sign(idx); // 3. Set the endorser list for the transaction, this enforces that the list provided will endorse the proposed transaction - const transaction = contract.createTransaction('HandleExternalRequest'); + let proposalRequest; if (identities.length > 0) { const endorserList = endorsers.filter((endorser: Endorser) => { //@ts-ignore @@ -120,23 +131,30 @@ async function invoke( const orgName = cert.issuer.organizationName; return identities.includes(endorser.mspid) || identities.includes(orgName); }); - console.log('Endorsers', endorserList); - transaction.setEndorsingPeers(endorserList); - console.log('Set endorsers'); + console.log('Set endorserList', endorserList); + proposalRequest = { + targets: endorserList, + requestTimeout: 30000 + }; } else { // When no identities provided it will default to all peers - transaction.setEndorsingPeers(endorsers); + console.log('Set endorsers', endorsers); + proposalRequest = { + targets: endorsers, + requestTimeout: 30000 + }; } - const b64QueryBytes = Buffer.from(query.serializeBinary()).toString('base64'); - // submit transaction and get result from chaincode - const read = await transaction.submit(b64QueryBytes); - console.log('Submittransactionresponse', read); + + // submit query transaction and get result from chaincode + const proposalResponseResult = await queryProposal.send(proposalRequest); + console.log(JSON.stringify(proposalResponse, null, 2)) + // 4. Prepare the view and return. const viewPayload = new view_data.FabricView(); const endorsements: proposalResponse.Endorsement[] = []; //TODO Fix ts error //@ts-ignore - read.proposalResponse.forEach((response) => { + proposalResponseResult.responses.forEach((response) => { console.log('Response', response); viewPayload.setProposalResponsePayload( proposalResponse.ProposalResponsePayload.deserializeBinary(response.payload), From 6856e7ce1fb91f7bc686af251b0a92c1fde14886 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Thu, 28 Jul 2022 11:24:04 +0000 Subject: [PATCH 073/150] get the utf8 object in query event subscription Signed-off-by: Krishnasuri Narayanam --- common/protos/common/events.proto | 2 +- core/drivers/fabric-driver/server/events.ts | 8 +++++- core/relay/Dockerfile | 2 +- core/relay/Dockerfile.client | 2 +- core/relay/Dockerfile.driver | 2 +- core/relay/Dockerfile.server | 4 +-- core/relay/Makefile | 2 +- .../src/EventsManager.ts | 27 ++++++++++++++----- 8 files changed, 35 insertions(+), 14 deletions(-) diff --git a/common/protos/common/events.proto b/common/protos/common/events.proto index d8377bd39..416247532 100644 --- a/common/protos/common/events.proto +++ b/common/protos/common/events.proto @@ -60,7 +60,7 @@ message ContractTransaction { string ledger_id = 2; string contract_id = 3; string func = 4; - repeated string args = 5; + repeated bytes args = 5; uint64 replace_arg_index = 6; } diff --git a/core/drivers/fabric-driver/server/events.ts b/core/drivers/fabric-driver/server/events.ts index 7baea85fb..cafff03f4 100644 --- a/core/drivers/fabric-driver/server/events.ts +++ b/core/drivers/fabric-driver/server/events.ts @@ -374,10 +374,16 @@ async function writeExternalStateHelper( addresses.push(result.interopPayload.getAddress()); viewsSerializedBase64.push(Buffer.from(viewPayload.getView().serializeBinary()).toString("base64")); + let ccArgsB64 = ctx.getArgsList_asB64(); + let ccArgsStr = []; + for (const ccArgB64 of ccArgsB64) { + ccArgsStr.push(Buffer.from(ccArgB64, 'base64').toString('utf8')); + } + const invokeObject = { channel: ctx.getLedgerId(), ccFunc: ctx.getFunc(), - ccArgs: ctx.getArgsList(), + ccArgs: ccArgsStr, contractName: ctx.getContractId() } console.debug(`invokeObject.ccArgs: ${invokeObject.ccArgs}`) diff --git a/core/relay/Dockerfile b/core/relay/Dockerfile index ae1e01cb4..dd9710592 100644 --- a/core/relay/Dockerfile +++ b/core/relay/Dockerfile @@ -40,7 +40,7 @@ ENV PKG_CONFIG_ALLOW_CROSS=1 \ # the same layer where we do the compilation # to then remove it from the image in the # same docker command. -RUN cd /opt/relay && RUSTFLAGS=-Clinker=musl-gcc cargo build --release --target x86_64-unknown-linux-musl +RUN cd /opt/relay && RUSTFLAGS=-Clinker="-Clinker=musl-gcc -Crelocation-model=static" cargo build --release --target x86_64-unknown-linux-musl diff --git a/core/relay/Dockerfile.client b/core/relay/Dockerfile.client index 616f4f2ab..82145d970 100644 --- a/core/relay/Dockerfile.client +++ b/core/relay/Dockerfile.client @@ -40,7 +40,7 @@ ENV PKG_CONFIG_ALLOW_CROSS=1 \ # the same layer where we do the compilation # to then remove it from the image in the # same docker command. -RUN cd /opt/relay && RUSTFLAGS=-Clinker=musl-gcc cargo build --release --target x86_64-unknown-linux-musl +RUN cd /opt/relay && RUSTFLAGS=-Clinker="-Clinker=musl-gcc -Crelocation-model=static" cargo build --release --target x86_64-unknown-linux-musl diff --git a/core/relay/Dockerfile.driver b/core/relay/Dockerfile.driver index 623bb0f96..398409ed9 100644 --- a/core/relay/Dockerfile.driver +++ b/core/relay/Dockerfile.driver @@ -40,7 +40,7 @@ ENV PKG_CONFIG_ALLOW_CROSS=1 \ # the same layer where we do the compilation # to then remove it from the image in the # same docker command. -RUN cd /opt/relay && RUSTFLAGS=-Clinker=musl-gcc cargo build --release --target x86_64-unknown-linux-musl +RUN cd /opt/relay && RUSTFLAGS="-Clinker=musl-gcc -Crelocation-model=static" cargo build --release --target x86_64-unknown-linux-musl diff --git a/core/relay/Dockerfile.server b/core/relay/Dockerfile.server index e5bcbac3f..d21b42219 100644 --- a/core/relay/Dockerfile.server +++ b/core/relay/Dockerfile.server @@ -40,7 +40,7 @@ ENV PKG_CONFIG_ALLOW_CROSS=1 \ # the same layer where we do the compilation # to then remove it from the image in the # same docker command. -RUN cd /opt/relay && RUSTFLAGS=-Clinker=musl-gcc cargo build --release --target x86_64-unknown-linux-musl +RUN cd /opt/relay && RUSTFLAGS="-Clinker=musl-gcc -Crelocation-model=static" cargo build --release --target x86_64-unknown-linux-musl FROM busybox AS server @@ -80,4 +80,4 @@ ARG VERSION ARG PROTOS_VERSION ARG GIT_URL LABEL COMMIT=${COMMIT} BRANCH=${BRANCH} VERSION=${VERSION} ROTOS_VERSION=${PROTOS_VERSION} -LABEL org.opencontainers.image.source ${GIT_URL} \ No newline at end of file +LABEL org.opencontainers.image.source ${GIT_URL} diff --git a/core/relay/Makefile b/core/relay/Makefile index 2bc91d2e8..874c22b51 100644 --- a/core/relay/Makefile +++ b/core/relay/Makefile @@ -1,6 +1,6 @@ include Makefile.variables.docker -PROTOS_TAG ?= v0.7 +PROTOS_TAG ?= v1.4.2 DOCKER_IMAGE_ALL = $(DOCKER_IMAGE_NAME):$(DOCKER_TAG) DOCKER_IMAGE_SERVER = $(DOCKER_IMAGE_NAME)-server:$(DOCKER_TAG) diff --git a/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts b/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts index 1670143d4..6dbdd9c42 100644 --- a/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts +++ b/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts @@ -66,12 +66,18 @@ function createEventPublicationSpec ({ eventPublicationSpec.setAppUrl(appUrl) } else { + let ccArgsB64 = []; + for (const ccArg of ccArgs) { + ccArgsB64.push(Buffer.from(ccArg).toString('base64')); + } + console.log(`ccArgs: ${ccArgs} ccArgsB64: ${ccArgsB64}`) + const ctx = new eventsPb.ContractTransaction() ctx.setDriverId(driverId) ctx.setLedgerId(channelId) ctx.setContractId(chaincodeId) ctx.setFunc(ccFunc) - ctx.setArgsList(ccArgs) + ctx.setArgsList(ccArgsB64) ctx.setReplaceArgIndex(replaceArgIndex) eventPublicationSpec.setCtx(ctx) } @@ -231,20 +237,29 @@ const getSubscriptionStatus = async ( logger.debug("Get Event Subscription Status") const relay = useTls ? new Relay(localRelayEndpoint, Relay.defaultTimeout, true, tlsRootCACertPaths) : new Relay(localRelayEndpoint); - + const [relayResponse, relayResponseError] = await helpers.handlePromise( relay.GetEventSubscriptionState( requestID, - asJson + false ), ); if (relayResponseError) { throw new Error(`Get event subscription relay response error: ${relayResponseError}`); } - + + let eventSubscriptionState: eventsPb.EventSubscriptionState = relayResponse; + let ccArgsB64 = eventSubscriptionState.getEventPublicationSpec().getCtx().getArgsList_asB64(); + let ccArgsStr = []; + for (const ccArgB64 of ccArgsB64) { + ccArgsStr.push(Buffer.from(ccArgB64, 'base64').toString('utf8')); + } + + eventSubscriptionState.getEventPublicationSpec().getCtx().setArgsList(ccArgsStr); + logger.debug(`Get event subscription status response: ${JSON.stringify(relayResponse)}`) - - return relayResponse + + return asJson? eventSubscriptionState.toObject() : relayResponse; } const getAllReceivedEvents = async ( From d9affbb8d2225c859126deb7ee013a8fd74c4dc8 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Thu, 28 Jul 2022 12:11:24 +0000 Subject: [PATCH 074/150] version changes Signed-off-by: Krishnasuri Narayanam --- core/drivers/fabric-driver/fabricDriver.dockerfile | 2 -- core/drivers/fabric-driver/fabricDriver.dockerfile.local | 2 -- core/drivers/fabric-driver/makefile.variables.docker | 4 ++-- core/drivers/fabric-driver/package-local.json | 2 +- core/drivers/fabric-driver/package.json | 6 +++--- core/drivers/fabric-driver/server/events.ts | 4 ++-- samples/fabric/fabric-cli/src/commands/event/subscribe.ts | 2 +- samples/fabric/fabric-cli/src/commands/event/unsubscribe.ts | 2 +- sdks/fabric/interoperation-node-sdk/src/EventsManager.ts | 6 +++--- 9 files changed, 13 insertions(+), 17 deletions(-) diff --git a/core/drivers/fabric-driver/fabricDriver.dockerfile b/core/drivers/fabric-driver/fabricDriver.dockerfile index ef82abea7..064785036 100644 --- a/core/drivers/fabric-driver/fabricDriver.dockerfile +++ b/core/drivers/fabric-driver/fabricDriver.dockerfile @@ -21,7 +21,6 @@ ADD package.json . RUN npm install --unsafe-perm -ADD patches /fabric-driver/patches ADD server /fabric-driver/server ADD config.json . ADD tsconfig.json . @@ -29,7 +28,6 @@ ADD .eslintrc . ADD .prettierrc . RUN npm run build -RUN npm run postinstall RUN rm /fabric-driver/.npmrc ARG GIT_URL diff --git a/core/drivers/fabric-driver/fabricDriver.dockerfile.local b/core/drivers/fabric-driver/fabricDriver.dockerfile.local index b582ca1c2..7bab4220c 100644 --- a/core/drivers/fabric-driver/fabricDriver.dockerfile.local +++ b/core/drivers/fabric-driver/fabricDriver.dockerfile.local @@ -20,7 +20,6 @@ ADD package.json . RUN npm install --unsafe-perm -ADD patches /fabric-driver/patches ADD server /fabric-driver/server ADD config.json . ADD tsconfig.json . @@ -28,7 +27,6 @@ ADD .eslintrc . ADD .prettierrc . RUN npm run build -RUN npm run postinstall ARG GIT_URL LABEL org.opencontainers.image.source ${GIT_URL} diff --git a/core/drivers/fabric-driver/makefile.variables.docker b/core/drivers/fabric-driver/makefile.variables.docker index 858a1f92c..aa0cc0c7c 100644 --- a/core/drivers/fabric-driver/makefile.variables.docker +++ b/core/drivers/fabric-driver/makefile.variables.docker @@ -1,4 +1,4 @@ DOCKER_IMAGE_NAME ?= weaver-fabric-driver -DOCKER_TAG ?= 1.4.0 +DOCKER_TAG ?= 1.4.2 DOCKER_REGISTRY ?= ghcr.io/hyperledger-labs -GIT_URL = https://github.com/hyperledger-labs/weaver-dlt-interoperability/core/drivers/fabric-driver \ No newline at end of file +GIT_URL = https://github.com/hyperledger-labs/weaver-dlt-interoperability/core/drivers/fabric-driver diff --git a/core/drivers/fabric-driver/package-local.json b/core/drivers/fabric-driver/package-local.json index 6b2df0b27..b584df8d9 100644 --- a/core/drivers/fabric-driver/package-local.json +++ b/core/drivers/fabric-driver/package-local.json @@ -1,6 +1,6 @@ { "name": "fabric-driver", - "version": "1.4.0", + "version": "1.4.2", "description": "", "main": "out/server.js", "scripts": { diff --git a/core/drivers/fabric-driver/package.json b/core/drivers/fabric-driver/package.json index acd652ea5..d0ab44a03 100644 --- a/core/drivers/fabric-driver/package.json +++ b/core/drivers/fabric-driver/package.json @@ -1,6 +1,6 @@ { "name": "fabric-driver", - "version": "1.4.0", + "version": "1.4.2", "description": "", "main": "out/server.js", "scripts": { @@ -19,8 +19,8 @@ "author": "", "license": "ISC", "dependencies": { - "@hyperledger-labs/weaver-protos-js": "^1.4.0", - "@hyperledger-labs/weaver-fabric-interop-sdk": "^1.4.0", + "@hyperledger-labs/weaver-protos-js": "^1.4.2", + "@hyperledger-labs/weaver-fabric-interop-sdk": "^1.4.2", "@fidm/x509": "^1.2.1", "@grpc/grpc-js": "^1.1.1", "@typescript-eslint/eslint-plugin": "^3.5.0", diff --git a/core/drivers/fabric-driver/server/events.ts b/core/drivers/fabric-driver/server/events.ts index cafff03f4..c098178ea 100644 --- a/core/drivers/fabric-driver/server/events.ts +++ b/core/drivers/fabric-driver/server/events.ts @@ -374,10 +374,10 @@ async function writeExternalStateHelper( addresses.push(result.interopPayload.getAddress()); viewsSerializedBase64.push(Buffer.from(viewPayload.getView().serializeBinary()).toString("base64")); - let ccArgsB64 = ctx.getArgsList_asB64(); + let ccArgsB64 = ctx.getArgsList(); let ccArgsStr = []; for (const ccArgB64 of ccArgsB64) { - ccArgsStr.push(Buffer.from(ccArgB64, 'base64').toString('utf8')); + ccArgsStr.push(Buffer.from(ccArgB64).toString('utf8')); } const invokeObject = { diff --git a/samples/fabric/fabric-cli/src/commands/event/subscribe.ts b/samples/fabric/fabric-cli/src/commands/event/subscribe.ts index 55a1f5349..a219fa3ef 100644 --- a/samples/fabric/fabric-cli/src/commands/event/subscribe.ts +++ b/samples/fabric/fabric-cli/src/commands/event/subscribe.ts @@ -115,7 +115,7 @@ const command: GluegunCommand = { ) if (response.getStatus() == EventSubscriptionState.STATUS.SUBSCRIBED) { - console.log("Event Subscription Status Success with requestId:", response.getRequestId(), 'and event matcher:', eventMatcher) + console.log("Event Subscription Status Success with requestId:", response.getRequestId(), 'and event matcher:', JSON.stringify(eventMatcher.toObject())) } else { console.log("Unknown error") } diff --git a/samples/fabric/fabric-cli/src/commands/event/unsubscribe.ts b/samples/fabric/fabric-cli/src/commands/event/unsubscribe.ts index 9372c1119..770725160 100644 --- a/samples/fabric/fabric-cli/src/commands/event/unsubscribe.ts +++ b/samples/fabric/fabric-cli/src/commands/event/unsubscribe.ts @@ -137,7 +137,7 @@ const command: GluegunCommand = { ) if (response.getStatus() == EventSubscriptionState.STATUS.UNSUBSCRIBED) { - console.log("Event Unsubscription Success for requestId:", response.getRequestId(), 'and event matcher:', eventMatcher) + console.log("Event Unsubscription Success for requestId:", response.getRequestId(), 'and event matcher:', JSON.stringify(eventMatcher.toObject())) } else { console.log("Unknown error") } diff --git a/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts b/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts index 6dbdd9c42..a1e6a92f0 100644 --- a/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts +++ b/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts @@ -68,7 +68,7 @@ function createEventPublicationSpec ({ let ccArgsB64 = []; for (const ccArg of ccArgs) { - ccArgsB64.push(Buffer.from(ccArg).toString('base64')); + ccArgsB64.push(Buffer.from(ccArg)); } console.log(`ccArgs: ${ccArgs} ccArgsB64: ${ccArgsB64}`) @@ -249,10 +249,10 @@ const getSubscriptionStatus = async ( } let eventSubscriptionState: eventsPb.EventSubscriptionState = relayResponse; - let ccArgsB64 = eventSubscriptionState.getEventPublicationSpec().getCtx().getArgsList_asB64(); + let ccArgsB64 = eventSubscriptionState.getEventPublicationSpec().getCtx().getArgsList(); let ccArgsStr = []; for (const ccArgB64 of ccArgsB64) { - ccArgsStr.push(Buffer.from(ccArgB64, 'base64').toString('utf8')); + ccArgsStr.push(Buffer.from(ccArgB64).toString('utf8')); } eventSubscriptionState.getEventPublicationSpec().getCtx().setArgsList(ccArgsStr); From eae0b10b4a0d821f8f6d7c46f72fbdb115faec2d Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Thu, 28 Jul 2022 12:15:57 +0000 Subject: [PATCH 075/150] minor edit for version dependency Signed-off-by: Krishnasuri Narayanam --- core/drivers/fabric-driver/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/drivers/fabric-driver/package.json b/core/drivers/fabric-driver/package.json index d0ab44a03..69199c63d 100644 --- a/core/drivers/fabric-driver/package.json +++ b/core/drivers/fabric-driver/package.json @@ -20,7 +20,7 @@ "license": "ISC", "dependencies": { "@hyperledger-labs/weaver-protos-js": "^1.4.2", - "@hyperledger-labs/weaver-fabric-interop-sdk": "^1.4.2", + "@hyperledger-labs/weaver-fabric-interop-sdk": "^1.4.0", "@fidm/x509": "^1.2.1", "@grpc/grpc-js": "^1.1.1", "@typescript-eslint/eslint-plugin": "^3.5.0", From 93c58b965ee3516e9832c922d28816fc5d97592d Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Fri, 29 Jul 2022 18:27:46 +0530 Subject: [PATCH 076/150] error handling in the DB layer Signed-off-by: Krishnasuri Narayanam --- .../fabric-driver/server/dbConnector.ts | 102 ++++++++++++++++-- core/drivers/fabric-driver/server/events.ts | 39 ++++--- core/drivers/fabric-driver/server/listener.ts | 9 +- core/drivers/fabric-driver/server/tests.ts | 34 +++++- 4 files changed, 150 insertions(+), 34 deletions(-) diff --git a/core/drivers/fabric-driver/server/dbConnector.ts b/core/drivers/fabric-driver/server/dbConnector.ts index 7b7bbe237..41850ec5d 100644 --- a/core/drivers/fabric-driver/server/dbConnector.ts +++ b/core/drivers/fabric-driver/server/dbConnector.ts @@ -28,6 +28,8 @@ interface DBConnector { update(key: any, value: any): Promise; // interface to delete a key from the database delete(key: any): Promise; + // get iterator + filteredRead(keyFilterCallback : (key: any, targetKey: any) => boolean, targetKey: any): Promise>; // close the database connection close(): Promise; } @@ -55,10 +57,14 @@ class LevelDBConnector implements DBConnector { await this.dbHandle.open(); } catch (error: any) { console.error(`failed to open database connection with error: ${JSON.stringify(error)}`); - return Promise.reject(JSON.stringify(error)); + if (error.code == 'LEVEL_DATABASE_NOT_OPEN' && error.cause && error.cause.code == 'LEVEL_LOCKED') { + throw new DBLockedError(error.toString()); + } else { + throw new DBNotOpenError(error.toString()); + } } - return Promise.resolve(true); + return true; } async insert( @@ -69,10 +75,14 @@ class LevelDBConnector implements DBConnector { await this.dbHandle.put(key, value); } catch (error: any) { console.error(`failed to insert key ${JSON.stringify(key)} with error: ${JSON.stringify(error)}`); - return Promise.reject(JSON.stringify(error)); + if (error.code == 'LEVEL_DATABASE_NOT_OPEN') { + throw new DBNotOpenError(error.toString()); + } else { + throw new DBError(error.toString()); + } } - return Promise.resolve(true); + return true; } async read( @@ -84,7 +94,13 @@ class LevelDBConnector implements DBConnector { console.debug(`read() got value: ${JSON.stringify(value)}`) } catch (error: any) { console.error(`failed to read key ${JSON.stringify(key)} with error: ${JSON.stringify(error)}`); - return Promise.reject(JSON.stringify(error)); + if (error.code == 'LEVEL_NOT_FOUND') { + throw new DBKeyNotFoundError(error.toString()); + } else if (error.code == 'LEVEL_DATABASE_NOT_OPEN') { + throw new DBNotOpenError(error.toString()); + } else { + throw new DBError(error.toString()); + } } return value; @@ -98,7 +114,11 @@ class LevelDBConnector implements DBConnector { await this.dbHandle.put(key, value); } catch (error: any) { console.error(`failed to update key ${JSON.stringify(key)} with error: ${JSON.stringify(error)}`); - return Promise.reject(JSON.stringify(error)); + if (error.code == 'LEVEL_DATABASE_NOT_OPEN') { + throw new DBNotOpenError(error.toString()); + } else { + throw new DBError(error.toString()); + } } return true; @@ -113,22 +133,52 @@ class LevelDBConnector implements DBConnector { await this.dbHandle.del(key); } catch (error: any) { console.error(`failed to delete key ${JSON.stringify(key)} with error: ${JSON.stringify(error)}`); - return Promise.reject(JSON.stringify(error)); + if (error.code == 'LEVEL_NOT_FOUND') { + throw new DBKeyNotFoundError(error.toString()); + } else if (error.code == 'LEVEL_DATABASE_NOT_OPEN') { + throw new DBNotOpenError(error.toString()); + } else { + throw new DBError(error.toString()); + } } return value; } + async filteredRead(keyFilterCallback : (key: any, targetKey: any) => boolean, targetKey: any): Promise> { + try { + let retVal = new Array(); + for await (const [key1, value1] of this.dbHandle.iterator()) { + if (keyFilterCallback(key1, targetKey)) { + retVal.push(value1); + } + } + + return retVal; + } catch (error: any) { + console.error(`filteredRead error: ${JSON.stringify(error)}`); + if (error.code == 'LEVEL_DATABASE_NOT_OPEN') { + throw new DBNotOpenError(error.toString()); + } else { + throw new DBError(error.toString()); + } + } + } + async close( ): Promise { try { await this.dbHandle.close(); } catch (error: any) { console.error(`failed to close database connection with error: ${JSON.stringify(error)}`); - return Promise.reject(JSON.stringify(error)); + if (error.code == 'LEVEL_DATABASE_NOT_OPEN') { + throw new DBNotOpenError(error.toString()); + } else { + throw new DBError(error.toString()); + } } - return Promise.resolve(true); + return true; } async readKeys( @@ -138,7 +188,39 @@ class LevelDBConnector implements DBConnector { } } +class DBKeyNotFoundError extends Error { + constructor(msg: string) { + super(`key not found in database: ${msg}`); + Object.setPrototypeOf(this, DBKeyNotFoundError.prototype); + } +} + +class DBNotOpenError extends Error { + constructor(msg: string) { + super(`database is not open: ${msg}`); + Object.setPrototypeOf(this, DBNotOpenError.prototype); + } +} + +class DBLockedError extends Error { + constructor(msg: string) { + super(`database already in use: ${msg}`); + Object.setPrototypeOf(this, DBLockedError.prototype); + } +} + +class DBError extends Error { + constructor(msg: string) { + super(`database error: ${msg}`); + Object.setPrototypeOf(this, DBError.prototype); + } +} + export { DBConnector, - LevelDBConnector + LevelDBConnector, + DBLockedError, + DBKeyNotFoundError, + DBNotOpenError, + DBError } diff --git a/core/drivers/fabric-driver/server/events.ts b/core/drivers/fabric-driver/server/events.ts index c098178ea..b84e94e46 100644 --- a/core/drivers/fabric-driver/server/events.ts +++ b/core/drivers/fabric-driver/server/events.ts @@ -10,7 +10,7 @@ import events_grpc_pb from '@hyperledger-labs/weaver-protos-js/relay/events_grpc import queryPb from '@hyperledger-labs/weaver-protos-js/common/query_pb'; import { InteroperableHelper } from '@hyperledger-labs/weaver-fabric-interop-sdk'; import { getDriverKeyCert } from "./walletSetup"; -import { DBConnector, LevelDBConnector } from "./dbConnector"; +import { DBConnector, DBKeyNotFoundError, LevelDBConnector } from "./dbConnector"; import { checkIfArraysAreEqual, handlePromise, relayCallback } from "./utils"; import { registerListenerForEventSubscription, unregisterListenerForEventSubscription } from "./listener"; import { getNetworkGateway } from "./fabric-code"; @@ -174,7 +174,7 @@ async function addEventSubscription( subscriptions.push(querySerialized); } catch (error: any) { let errorString = error.toString(); - if (errorString.includes('Error: NotFound:') || errorString.includes('LEVEL_NOT_FOUND')) { + if (error instanceof DBKeyNotFoundError) { // case of read failing due to key not found console.debug(`eventMatcher: ${JSON.stringify(eventMatcher.toObject())} is not present before in the database`); subscriptions = new Array(); @@ -265,6 +265,19 @@ const deleteEventSubscription = async ( } } +function filterEventMatcher(keySerialized: string, eventMatcher: eventsPb.EventMatcher) : boolean { + var item: eventsPb.EventMatcher = eventsPb.EventMatcher.deserializeBinary(Buffer.from(keySerialized, 'base64')); + if ((eventMatcher.getEventClassId() == '*' || eventMatcher.getEventClassId() == item.getEventClassId()) && + (eventMatcher.getTransactionContractId() == '*' || eventMatcher.getTransactionContractId() == item.getTransactionContractId()) && + (eventMatcher.getTransactionLedgerId() == '*' || eventMatcher.getTransactionLedgerId() == item.getTransactionLedgerId()) && + (eventMatcher.getTransactionFunc() == '*' || eventMatcher.getTransactionFunc() == item.getTransactionFunc())) { + + return true; + } else { + return false; + } +} + async function lookupEventSubscriptions( eventMatcher: eventsPb.EventMatcher ): Promise> { @@ -278,21 +291,13 @@ async function lookupEventSubscriptions( db = new LevelDBConnector(DB_NAME!); await db.open(); - for await (const [keySerialized, subscriptionsSerialized] of db.dbHandle.iterator()) { - var item: eventsPb.EventMatcher = eventsPb.EventMatcher.deserializeBinary(Buffer.from(keySerialized, 'base64')); - if ((eventMatcher.getEventClassId() == '*' || eventMatcher.getEventClassId() == item.getEventClassId()) && - (eventMatcher.getTransactionContractId() == '*' || eventMatcher.getTransactionContractId() == item.getTransactionContractId()) && - (eventMatcher.getTransactionLedgerId() == '*' || eventMatcher.getTransactionLedgerId() == item.getTransactionLedgerId()) && - (eventMatcher.getTransactionFunc() == '*' || eventMatcher.getTransactionFunc() == item.getTransactionFunc())) { - - subscriptions = JSON.parse(subscriptionsSerialized) - for (const subscriptionSerialized of subscriptions) { - var subscription: queryPb.Query = queryPb.Query.deserializeBinary(Buffer.from(subscriptionSerialized, 'base64')); - console.debug(`subscription: ${JSON.stringify(subscription.toObject())}`) - returnSubscriptions.push(subscription); - } + for (const subscriptionsSerialized of await db.filteredRead(filterEventMatcher, eventMatcher)) { + subscriptions = JSON.parse(subscriptionsSerialized) + for (const subscriptionSerialized of subscriptions) { + var subscription: queryPb.Query = queryPb.Query.deserializeBinary(Buffer.from(subscriptionSerialized, 'base64')); + console.debug(`subscription: ${JSON.stringify(subscription.toObject())}`) + returnSubscriptions.push(subscription); } - } console.debug(`returnSubscriptions.length: ${returnSubscriptions.length}`); @@ -303,7 +308,7 @@ async function lookupEventSubscriptions( } catch (error: any) { let errorString: string = error.toString(); await db?.close(); - if (errorString.includes('Error: NotFound:') || errorString.includes('LEVEL_NOT_FOUND')) { + if (error instanceof DBKeyNotFoundError) { // case of read failing due to key not found returnSubscriptions = new Array(); console.debug(`returnSubscriptions.length: ${returnSubscriptions.length}`); diff --git a/core/drivers/fabric-driver/server/listener.ts b/core/drivers/fabric-driver/server/listener.ts index dadab3d5f..fb043b6a6 100644 --- a/core/drivers/fabric-driver/server/listener.ts +++ b/core/drivers/fabric-driver/server/listener.ts @@ -4,15 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as $protobuf from "protobufjs"; -import ByteBuffer from 'bytebuffer'; import * as fabproto6 from 'fabric-protos'; -import { Gateway, Wallets, Network, Contract, BlockListener, ContractListener } from 'fabric-network'; +import { Gateway, Network, Contract, BlockListener, ContractListener } from 'fabric-network'; import query_pb from '@hyperledger-labs/weaver-protos-js/common/query_pb'; import events_pb from '@hyperledger-labs/weaver-protos-js/common/events_pb'; import { lookupEventSubscriptions } from './events'; import { invoke, getNetworkGateway, packageFabricView } from './fabric-code'; import { handlePromise, relayCallback, getRelayClientForEventPublish } from './utils'; +import { DBLockedError } from './dbConnector'; let networkGatewayMap = new Map(); let networkChannelMap = new Map(); @@ -63,7 +62,7 @@ const initBlockEventListenerForChannel = async ( break; } catch(error) { let errorString: string = error.toString(); - if (!errorString.includes('LEVEL_LOCKED')) { // Check if contention was preventing DB access + if (!(error instanceof DBLockedError)) { // Check if contention was preventing DB access throw(error); } await new Promise(f => setTimeout(f, 2000)); // Sleep 2 seconds @@ -124,7 +123,7 @@ const initContractEventListener = ( break; } catch(error) { let errorString: string = error.toString(); - if (!errorString.includes('LEVEL_LOCKED')) { // Check if contention was preventing DB access + if (!(error instanceof DBLockedError)) { // Check if contention was preventing DB access throw(error); } await new Promise(f => setTimeout(f, 2000)); // Sleep 2 seconds diff --git a/core/drivers/fabric-driver/server/tests.ts b/core/drivers/fabric-driver/server/tests.ts index 10e7de299..2722067a3 100644 --- a/core/drivers/fabric-driver/server/tests.ts +++ b/core/drivers/fabric-driver/server/tests.ts @@ -7,7 +7,7 @@ import eventsPb from "@hyperledger-labs/weaver-protos-js/common/events_pb"; import queryPb from '@hyperledger-labs/weaver-protos-js/common/query_pb'; import { addEventSubscription, deleteEventSubscription, lookupEventSubscriptions } from "./events" -import { LevelDBConnector, DBConnector } from "./dbConnector" +import { LevelDBConnector, DBConnector, DBNotOpenError, DBKeyNotFoundError, DBLockedError } from "./dbConnector" // test the LevelDB basic operations async function dbConnectionTest( @@ -37,7 +37,8 @@ async function dbConnectionTest( await db.update(key, value); } catch (error: any) { const errorString: string = `${JSON.stringify(error)}`; - if (errorString.includes(`is not open`)) { + if (error instanceof DBNotOpenError) { + console.log(`test success for DBNotOpenError`); // open the database connection await db.open(); // try to update again the key @@ -51,6 +52,35 @@ async function dbConnectionTest( // Delete the key await db.delete(key); + + // Try to read key that is already deleted + try { + await db.read(key); + } catch (error: any) { + const errorString: string = `${JSON.stringify(error)}`; + if (error instanceof DBKeyNotFoundError) { + console.log(`test success for DBKeyNotFoundError`); + } else { + console.error(`re-throwing the error: ${errorString}`); + db.close(); + throw new Error(error); + } + } + + // Try to open another connection which should fail + try { + let db2 = new LevelDBConnector(""); + await db2.open(); + } catch (error: any) { + const errorString: string = `${JSON.stringify(error)}`; + if (error instanceof DBLockedError) { + console.log(`test success for DBLockedError`); + } else { + console.error(`re-throwing the error: ${errorString}`); + throw new Error(error); + } + } + await db.close(); } catch (error) { console.error(`Failed testing LevelDBConnector, with error: ${JSON.stringify(error)}`); From 0fedf1eb24af01a30a62f10f2486e0d2e5e3e972 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Fri, 29 Jul 2022 18:39:45 +0530 Subject: [PATCH 077/150] addressing code review comments Signed-off-by: Krishnasuri Narayanam --- core/drivers/fabric-driver/server/events.ts | 7 +++---- samples/fabric/fabric-cli/readme.md | 4 ++++ .../interoperation-node-sdk/src/EventsManager.ts | 14 +++++++------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/core/drivers/fabric-driver/server/events.ts b/core/drivers/fabric-driver/server/events.ts index b84e94e46..a79172a2a 100644 --- a/core/drivers/fabric-driver/server/events.ts +++ b/core/drivers/fabric-driver/server/events.ts @@ -360,7 +360,6 @@ async function writeExternalStateHelper( const viewPayload: state_pb.ViewPayload = writeExternalStateMessage.getViewPayload(); const ctx: eventsPb.ContractTransaction = writeExternalStateMessage.getCtx(); const keyCert = await getDriverKeyCert(); - let gateway: Gateway; const requestId: string = viewPayload.getRequestId(); if (!viewPayload.getError()) { @@ -393,7 +392,7 @@ async function writeExternalStateHelper( } console.debug(`invokeObject.ccArgs: ${invokeObject.ccArgs}`) - gateway = await getNetworkGateway(networkName); + let gateway: Gateway = await getNetworkGateway(networkName); const network: Network = await gateway.getNetwork(ctx.getLedgerId()); const interopContract: Contract = network.getContract(process.env.INTEROP_CHAINCODE ? process.env.INTEROP_CHAINCODE : 'interop'); @@ -407,13 +406,13 @@ async function writeExternalStateHelper( )); if (responseError) { console.log(`Failed writing to the ledger with error: ${responseError}`); + gateway.disconnect(); throw responseError; } - gateway.disconnect(); + gateway.disconnect(); } else { const errorString: string = `erroneous viewPayload identified in WriteExternalState processing`; console.log(`error viewPayload.getError(): ${JSON.stringify(viewPayload.getError())}`); - gateway.disconnect(); throw new Error(errorString); } } diff --git a/samples/fabric/fabric-cli/readme.md b/samples/fabric/fabric-cli/readme.md index ba84a7ab9..d515a812d 100644 --- a/samples/fabric/fabric-cli/readme.md +++ b/samples/fabric/fabric-cli/readme.md @@ -407,6 +407,10 @@ Below are the steps to exercise asset transfers from `network1` to `network2` us ``` http://localhost:8080/simple-event-callback ``` +* To fetch the statuses of all the events received, run the following command: + ``` + ./bin/fabric-cli event get-all --network=network1 --request-id= + ``` ## NOTE diff --git a/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts b/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts index a1e6a92f0..31d26e0b4 100644 --- a/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts +++ b/sdks/fabric/interoperation-node-sdk/src/EventsManager.ts @@ -66,18 +66,18 @@ function createEventPublicationSpec ({ eventPublicationSpec.setAppUrl(appUrl) } else { - let ccArgsB64 = []; + let ccArgsBytes = []; for (const ccArg of ccArgs) { - ccArgsB64.push(Buffer.from(ccArg)); + ccArgsBytes.push(Buffer.from(ccArg)); } - console.log(`ccArgs: ${ccArgs} ccArgsB64: ${ccArgsB64}`) + console.log(`ccArgs: ${ccArgs} ccArgsBytes: ${ccArgsBytes}`) const ctx = new eventsPb.ContractTransaction() ctx.setDriverId(driverId) ctx.setLedgerId(channelId) ctx.setContractId(chaincodeId) ctx.setFunc(ccFunc) - ctx.setArgsList(ccArgsB64) + ctx.setArgsList(ccArgsBytes) ctx.setReplaceArgIndex(replaceArgIndex) eventPublicationSpec.setCtx(ctx) } @@ -249,10 +249,10 @@ const getSubscriptionStatus = async ( } let eventSubscriptionState: eventsPb.EventSubscriptionState = relayResponse; - let ccArgsB64 = eventSubscriptionState.getEventPublicationSpec().getCtx().getArgsList(); + let ccArgsBytes = eventSubscriptionState.getEventPublicationSpec().getCtx().getArgsList(); let ccArgsStr = []; - for (const ccArgB64 of ccArgsB64) { - ccArgsStr.push(Buffer.from(ccArgB64).toString('utf8')); + for (const ccArgBytes of ccArgsBytes) { + ccArgsStr.push(Buffer.from(ccArgBytes).toString('utf8')); } eventSubscriptionState.getEventPublicationSpec().getCtx().setArgsList(ccArgsStr); From 0db0c66c375cf1802b35c48bcb7c7e5d1fca08c1 Mon Sep 17 00:00:00 2001 From: sannish Date: Thu, 4 Aug 2022 07:20:30 +0000 Subject: [PATCH 078/150] update expired fabric-certs Signed-off-by: sannish --- .../fabric-driver/wallet-network1/admin.id | 2 +- .../fabric-driver/wallet-network1/relay.id | 2 +- .../fabric-driver/wallet-network2/admin.id | 2 +- .../fabric-driver/wallet-network2/relay.id | 2 +- .../credentials/network1/access-control.json | 4 +- .../credentials/network1/membership.json | 11 +- .../credentials/network2/access-control.json | 4 +- .../credentials/network2/membership.json | 11 +- .../network1/access-control.json | 4 +- .../network1/membership.json | 11 +- .../network2/access-control.json | 4 +- .../network2/membership.json | 11 +- .../data/credentials/network1/membership.json | 2 +- .../credentials/network2/access-control.json | 2 +- .../data/credentials/network2/membership.json | 2 +- .../network1/membership.json | 2 +- .../network2/access-control.json | 2 +- .../network2/membership.json | 2 +- .../fabric-cli/src/wallet-network1/user1.id | 2 +- .../fabric-cli/src/wallet-network2/user1.id | 2 +- tests/network-setups/fabric/dev/Makefile | 44 ++ .../channel-artifacts/Org1MSPanchors.tx | Bin 313 -> 313 bytes .../channel-artifacts/mychannel.block | Bin 17138 -> 17129 bytes .../network1/channel-artifacts/mychannel.tx | Bin 421 -> 421 bytes .../fabric-ca/ordererOrg/IssuerPublicKey | Bin 843 -> 843 bytes .../ordererOrg/IssuerRevocationPublicKey | 6 +- .../network1/fabric-ca/ordererOrg/ca-cert.pem | 14 +- .../fabric-ca/ordererOrg/fabric-ca-server.db | Bin 61440 -> 61440 bytes ...7c9b9083b64b4b46e327d36f94e16f8ad46f204_sk | 5 + ...e4ff06c983cc896e5552c9e0c0f766aa5476755_sk | 5 + ...f83ae4cd3c985349a51610e6f9a35e930ea11eb_sk | 5 - .../msp/keystore/IssuerRevocationPrivateKey | 8 +- .../ordererOrg/msp/keystore/IssuerSecretKey | 2 +- ...d4ae87f718c65ca2ca3832c72423a3802b68c66_sk | 5 - .../fabric-ca/ordererOrg/tls-cert.pem | 20 +- .../network1/fabric-ca/org1/IssuerPublicKey | Bin 843 -> 843 bytes .../fabric-ca/org1/IssuerRevocationPublicKey | 6 +- .../network1/fabric-ca/org1/ca-cert.pem | 14 +- .../fabric-ca/org1/fabric-ca-server.db | Bin 65536 -> 65536 bytes ...8a53afd1a529b416f42db95e8592bb820633e3e_sk | 5 - ...4c4c1ebb56d3fa0b0ac8a34e2943beeff243edd_sk | 5 + .../msp/keystore/IssuerRevocationPrivateKey | 8 +- .../org1/msp/keystore/IssuerSecretKey | Bin 32 -> 32 bytes ...0220190470e56a5318f27e6052850765098f1df_sk | 5 - ...76abf24fa24ec232b8f7844cf8f19730b3504ac_sk | 5 + .../network1/fabric-ca/org1/tls-cert.pem | 20 +- .../network1/ordererOrg/IssuerPublicKey | Bin 0 -> 843 bytes .../ordererOrg/IssuerRevocationPublicKey | 5 + .../network1/ordererOrg/ca-cert.pem | 14 + .../ordererOrg/fabric-ca-server-config.yaml | 504 ++++++++++++++++++ .../network1/ordererOrg/fabric-ca-server.db | Bin 0 -> 61440 bytes ...7c9b9083b64b4b46e327d36f94e16f8ad46f204_sk | 5 + ...e4ff06c983cc896e5552c9e0c0f766aa5476755_sk | 5 + .../msp/keystore/IssuerRevocationPrivateKey | 6 + .../ordererOrg/msp/keystore/IssuerSecretKey | 1 + .../network1/ordererOrg/tls-cert.pem | 16 + .../network1.com/msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 +- ...localhost-9054-ca-orderer-network1-com.pem | 14 +- ...ca4b8ac3d20a66f2f899f3bd8eef1a06dfca4d9_sk | 5 + ...55a872b6eca64b4de3bb7c41625d223c055b40b_sk | 5 - .../network1.com/msp/signcerts/cert.pem | 16 +- .../tlscacerts/tlsca.network1.com-cert.pem | 14 +- .../orderer.network1.com/msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 +- ...localhost-9054-ca-orderer-network1-com.pem | 14 +- ...cc884be1a3bf58080c2fa71095838351616ed69_sk | 5 - ...1a8f7755eccfbd8d2f9e0597320fe1eaa47c16e_sk | 5 + .../msp/signcerts/cert.pem | 16 +- .../tlscacerts/tlsca.network1.com-cert.pem | 14 +- .../orderer.network1.com/tls/IssuerPublicKey | Bin 843 -> 843 bytes .../tls/IssuerRevocationPublicKey | 6 +- .../orderers/orderer.network1.com/tls/ca.crt | 14 +- ...d8815192305afa9716ad6d6377520659afda105_sk | 5 - ...809cd1c2ec4b9dbb9d0083146c8a6afd50f7223_sk | 5 + .../orderer.network1.com/tls/server.crt | 18 +- .../orderer.network1.com/tls/server.key | 6 +- .../tls/signcerts/cert.pem | 18 +- ...localhost-9054-ca-orderer-network1-com.pem | 14 +- .../Admin@network1.com/msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 +- ...localhost-9054-ca-orderer-network1-com.pem | 14 +- ...fab34bc73a5921da7a80691393b105e7fcb3226_sk | 5 + ...dde304d16d6b4733b290981ec9b52baaf9f5e5c_sk | 5 - .../Admin@network1.com/msp/signcerts/cert.pem | 18 +- .../network1/org1/IssuerPublicKey | Bin 0 -> 843 bytes .../network1/org1/IssuerRevocationPublicKey | 5 + .../network1/org1/ca-cert.pem | 14 + .../org1/fabric-ca-server-config.yaml | 504 ++++++++++++++++++ .../network1/org1/fabric-ca-server.db | Bin 0 -> 61440 bytes ...4c4c1ebb56d3fa0b0ac8a34e2943beeff243edd_sk | 5 + .../msp/keystore/IssuerRevocationPrivateKey | 6 + .../org1/msp/keystore/IssuerSecretKey | Bin 0 -> 32 bytes ...76abf24fa24ec232b8f7844cf8f19730b3504ac_sk | 5 + .../network1/org1/tls-cert.pem | 16 + .../ca/ca.org1.network1.com-cert.pem | 14 +- .../connection-org1.docker.json | 4 +- .../org1.network1.com/connection-org1.json | 4 +- .../org1.network1.com/connection-org1.yaml | 98 ++-- .../org1.network1.com/msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 +- .../localhost-7054-ca-org1-network1-com.pem | 14 +- ...fa4330bc2d45b0e12c2e5c42e4f7eadfe36164c_sk | 5 - ...fd0ec68bb71d49cde36019cc47bc66e0ab07334_sk | 5 + .../org1.network1.com/msp/signcerts/cert.pem | 16 +- .../org1.network1.com/msp/tlscacerts/ca.crt | 14 +- .../msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 +- .../localhost-7054-ca-org1-network1-com.pem | 14 +- ...df4fd0e38469608ecb0f9c4f235e543c303d127_sk | 5 - ...6e96ebc18782d275d3eae560dccb2667848adfe_sk | 5 + .../msp/signcerts/cert.pem | 18 +- .../tls/IssuerPublicKey | Bin 843 -> 843 bytes .../tls/IssuerRevocationPublicKey | 6 +- .../peers/peer0.org1.network1.com/tls/ca.crt | 14 +- ...536fe4325325082313dce4d076625c185f0140e_sk | 5 + ...a90ce16937ec46dece2734ed9349d491a59e24d_sk | 5 - .../peer0.org1.network1.com/tls/server.crt | 18 +- .../peer0.org1.network1.com/tls/server.key | 6 +- .../tls/signcerts/cert.pem | 18 +- ...ls-localhost-7054-ca-org1-network1-com.pem | 14 +- .../tlsca/tlsca.org1.network1.com-cert.pem | 14 +- .../msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 +- .../localhost-7054-ca-org1-network1-com.pem | 14 +- ...27cc9960303200526435bc864bd96b3e82e819f_sk | 5 - ...e4da28fa3e3cd86b6d3a34c91c9bc163c57492e_sk | 5 + .../msp/signcerts/cert.pem | 18 +- .../msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 +- .../localhost-7054-ca-org1-network1-com.pem | 14 +- ...6132512d9552ace941a60701c810771291b03ec_sk | 5 - ...fc89055cdf55db0fb2057032401956f9873d30a_sk | 5 + .../msp/signcerts/cert.pem | 16 +- .../system-genesis-block/genesis.block | Bin 13407 -> 13399 bytes .../channel-artifacts/Org1MSPanchors.tx | Bin 313 -> 313 bytes .../channel-artifacts/mychannel.block | Bin 17129 -> 17142 bytes .../network2/channel-artifacts/mychannel.tx | Bin 421 -> 421 bytes .../fabric-ca/ordererOrg/IssuerPublicKey | Bin 843 -> 843 bytes .../ordererOrg/IssuerRevocationPublicKey | 6 +- .../network2/fabric-ca/ordererOrg/ca-cert.pem | 14 +- .../fabric-ca/ordererOrg/fabric-ca-server.db | Bin 61440 -> 61440 bytes ...0950584b74dce5a32ffd6ab7b438b0d86ed3f5e_sk | 5 + ...3d23c2aad6410f31007d63835fadb159cbcb3d9_sk | 5 + ...beb757a7fdea932edc5ba3672d1fd1c0b087b13_sk | 5 - .../msp/keystore/IssuerRevocationPrivateKey | 8 +- .../ordererOrg/msp/keystore/IssuerSecretKey | 2 +- ...233e6d0c2cdca9bd2a8e7f76f8365e9a96e52f8_sk | 5 - .../fabric-ca/ordererOrg/tls-cert.pem | 20 +- .../network2/fabric-ca/org1/IssuerPublicKey | Bin 843 -> 843 bytes .../fabric-ca/org1/IssuerRevocationPublicKey | 6 +- .../network2/fabric-ca/org1/ca-cert.pem | 14 +- .../fabric-ca/org1/fabric-ca-server.db | Bin 65536 -> 65536 bytes ...7f518f7f2d789dc81156f6b38c9a432b5b6083d_sk | 5 + ...8ec7de7a6c9070ae57f5cf423bfc2472f0d13b0_sk | 5 + ...781ff8a6a75f6fd974f25e9f674873feebd9ea1_sk | 5 - .../msp/keystore/IssuerRevocationPrivateKey | 8 +- .../org1/msp/keystore/IssuerSecretKey | 2 +- ...733e49c3aa42209717522d2307fcf37d7cecaed_sk | 5 - .../network2/fabric-ca/org1/tls-cert.pem | 20 +- .../network2.com/msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 +- ...localhost-8054-ca-orderer-network2-com.pem | 14 +- ...b83ca7f217cd794857d1347dd27ad47f601cbe7_sk | 5 - ...5bb100e2b26f93b0fabcc0f04a0a7f48b071c87_sk | 5 + .../network2.com/msp/signcerts/cert.pem | 16 +- .../tlscacerts/tlsca.network2.com-cert.pem | 14 +- .../orderer.network2.com/msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 +- ...localhost-8054-ca-orderer-network2-com.pem | 14 +- ...e47a76862fdad6f576f4ecce02468af34289e78_sk | 5 + ...d6e23bb09ed8f3165c7b9957c8761bd9695297f_sk | 5 - .../msp/signcerts/cert.pem | 16 +- .../tlscacerts/tlsca.network2.com-cert.pem | 14 +- .../orderer.network2.com/tls/IssuerPublicKey | Bin 843 -> 843 bytes .../tls/IssuerRevocationPublicKey | 6 +- .../orderers/orderer.network2.com/tls/ca.crt | 14 +- ...aed451ba70639e08a135901d916089703b38eda_sk | 5 + ...cdfa32801c8ae5fc26211ea4faff9ae6672bd35_sk | 5 - .../orderer.network2.com/tls/server.crt | 18 +- .../orderer.network2.com/tls/server.key | 6 +- .../tls/signcerts/cert.pem | 18 +- ...localhost-8054-ca-orderer-network2-com.pem | 14 +- .../Admin@network2.com/msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 +- ...localhost-8054-ca-orderer-network2-com.pem | 14 +- ...2a005780753ee8529259598d515f6e14024fe8a_sk | 5 - ...a559d0ac39b35270df2fce0d798db6b1b11b2b0_sk | 5 + .../Admin@network2.com/msp/signcerts/cert.pem | 18 +- .../ca/ca.org1.network2.com-cert.pem | 14 +- .../connection-org1.docker.json | 4 +- .../org1.network2.com/connection-org1.json | 4 +- .../org1.network2.com/connection-org1.yaml | 86 +-- .../org1.network2.com/msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 +- .../localhost-5054-ca-org1-network2-com.pem | 14 +- ...6c33dd1edcbed4a5e599a116854e71eaf427e96_sk | 5 - ...be9c9f4e32539e9b85a692086de0fb364dbea54_sk | 5 + .../org1.network2.com/msp/signcerts/cert.pem | 16 +- .../org1.network2.com/msp/tlscacerts/ca.crt | 14 +- .../msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 +- .../localhost-5054-ca-org1-network2-com.pem | 14 +- ...10ac4979b258a864c5778180cc43dda00ef02ad_sk | 5 - ...77543cad709ec379f6e3070e992e67b4ed03a29_sk | 5 + .../msp/signcerts/cert.pem | 18 +- .../tls/IssuerPublicKey | Bin 843 -> 843 bytes .../tls/IssuerRevocationPublicKey | 6 +- .../peers/peer0.org1.network2.com/tls/ca.crt | 14 +- ...06ad859de7854abfd5d485a9da4ebf322b9a566_sk | 5 + ...fb0dc92a4099335a1b737e7380d5bbd5cbb57e6_sk | 5 - .../peer0.org1.network2.com/tls/server.crt | 18 +- .../peer0.org1.network2.com/tls/server.key | 6 +- .../tls/signcerts/cert.pem | 18 +- ...ls-localhost-5054-ca-org1-network2-com.pem | 14 +- .../tlsca/tlsca.org1.network2.com-cert.pem | 14 +- .../msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 +- .../localhost-5054-ca-org1-network2-com.pem | 14 +- ...08949aeb68fd089dec6d386f21ff361eccc2072_sk | 5 - ...a0473efb852a4a17e2fd2cb419efe78852a887f_sk | 5 + .../msp/signcerts/cert.pem | 18 +- .../msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 +- .../localhost-5054-ca-org1-network2-com.pem | 14 +- ...682540ecb8ff59924b569c0dca624b478025f3d_sk | 5 - ...ca6f9ed2559e7812c0d756e1f2f43942d8e786b_sk | 5 + .../msp/signcerts/cert.pem | 16 +- .../system-genesis-block/genesis.block | Bin 13399 -> 13407 bytes 229 files changed, 1949 insertions(+), 908 deletions(-) create mode 100644 tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/397c85579ed7ffcec218676697c9b9083b64b4b46e327d36f94e16f8ad46f204_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/6d26b02a002fb3081c443b1f8e4ff06c983cc896e5552c9e0c0f766aa5476755_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/94255e346295ca5a0e3bb32e7f83ae4cd3c985349a51610e6f9a35e930ea11eb_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/d43d8da7496c8f02d534cd58cd4ae87f718c65ca2ca3832c72423a3802b68c66_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/5dfbce629e275090ced3e2e678a53afd1a529b416f42db95e8592bb820633e3e_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/82bb24244d4f7bcbffb96a71c4c4c1ebb56d3fa0b0ac8a34e2943beeff243edd_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/cd392f2c72a2673ecdd5400bf0220190470e56a5318f27e6052850765098f1df_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/e509e7d66bdbd1e7e777acd4c76abf24fa24ec232b8f7844cf8f19730b3504ac_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrg/IssuerPublicKey create mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrg/IssuerRevocationPublicKey create mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrg/ca-cert.pem create mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrg/fabric-ca-server-config.yaml create mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrg/fabric-ca-server.db create mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/397c85579ed7ffcec218676697c9b9083b64b4b46e327d36f94e16f8ad46f204_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/6d26b02a002fb3081c443b1f8e4ff06c983cc896e5552c9e0c0f766aa5476755_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/IssuerRevocationPrivateKey create mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/IssuerSecretKey create mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrg/tls-cert.pem create mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/keystore/2b1bb41ced0015f0c3b2ee752ca4b8ac3d20a66f2f899f3bd8eef1a06dfca4d9_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/keystore/ae13856d0a06478551748e67a55a872b6eca64b4de3bb7c41625d223c055b40b_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/keystore/e77cc1ca55809c7a48c804fe7cc884be1a3bf58080c2fa71095838351616ed69_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/keystore/f949ca1e0e7d7e6d996176d4b1a8f7755eccfbd8d2f9e0597320fe1eaa47c16e_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/keystore/39f5127d7653c2b2fceef7ed6d8815192305afa9716ad6d6377520659afda105_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/keystore/75f5e9c82d2e8d17470e65e5a809cd1c2ec4b9dbb9d0083146c8a6afd50f7223_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/keystore/3e3a32bdfc3ef9a6639c212e3fab34bc73a5921da7a80691393b105e7fcb3226_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/keystore/d7ac31a822ab05c8800fd03bddde304d16d6b4733b290981ec9b52baaf9f5e5c_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/org1/IssuerPublicKey create mode 100644 tests/network-setups/fabric/network-artifacts/network1/org1/IssuerRevocationPublicKey create mode 100644 tests/network-setups/fabric/network-artifacts/network1/org1/ca-cert.pem create mode 100644 tests/network-setups/fabric/network-artifacts/network1/org1/fabric-ca-server-config.yaml create mode 100644 tests/network-setups/fabric/network-artifacts/network1/org1/fabric-ca-server.db create mode 100644 tests/network-setups/fabric/network-artifacts/network1/org1/msp/keystore/82bb24244d4f7bcbffb96a71c4c4c1ebb56d3fa0b0ac8a34e2943beeff243edd_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/org1/msp/keystore/IssuerRevocationPrivateKey create mode 100644 tests/network-setups/fabric/network-artifacts/network1/org1/msp/keystore/IssuerSecretKey create mode 100644 tests/network-setups/fabric/network-artifacts/network1/org1/msp/keystore/e509e7d66bdbd1e7e777acd4c76abf24fa24ec232b8f7844cf8f19730b3504ac_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/org1/tls-cert.pem delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/keystore/198a5af9008e2b0127f3120a5fa4330bc2d45b0e12c2e5c42e4f7eadfe36164c_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/keystore/2d9968bdb307fb3b5f163356cfd0ec68bb71d49cde36019cc47bc66e0ab07334_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/keystore/085360b244a3d2dbf494a2390df4fd0e38469608ecb0f9c4f235e543c303d127_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/keystore/5bee0474d81dd757d01966e5b6e96ebc18782d275d3eae560dccb2667848adfe_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/keystore/2c73ce9f512e2c8d611a66199536fe4325325082313dce4d076625c185f0140e_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/keystore/5ef7cb27d6b4866bc9d704c91a90ce16937ec46dece2734ed9349d491a59e24d_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/keystore/7a2bc768da5d5ecf5ba6e206e27cc9960303200526435bc864bd96b3e82e819f_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/keystore/b5ff454e5ceb3f2ce336a9080e4da28fa3e3cd86b6d3a34c91c9bc163c57492e_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/keystore/43e1a75012fe2626d853745be6132512d9552ace941a60701c810771291b03ec_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/keystore/d397d85065544e3fb772bf88afc89055cdf55db0fb2057032401956f9873d30a_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/117fbb29176584efb8df9c8370950584b74dce5a32ffd6ab7b438b0d86ed3f5e_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/3db8e1f785d24ba97583a0d2a3d23c2aad6410f31007d63835fadb159cbcb3d9_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/4d66bd3a677d620e418fdb85cbeb757a7fdea932edc5ba3672d1fd1c0b087b13_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/e29c727a5c3adda2daa247431233e6d0c2cdca9bd2a8e7f76f8365e9a96e52f8_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/2ab00f3ef573479ef8514bd647f518f7f2d789dc81156f6b38c9a432b5b6083d_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/2ab49b69a5e965d0baf9acc108ec7de7a6c9070ae57f5cf423bfc2472f0d13b0_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/7d3e97c4644391d43429e1b9e781ff8a6a75f6fd974f25e9f674873feebd9ea1_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/ff63d3aee2f2cb882477e67de733e49c3aa42209717522d2307fcf37d7cecaed_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/keystore/25ad3edad97423cb9ceba6b06b83ca7f217cd794857d1347dd27ad47f601cbe7_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/keystore/64aa0b911f0d7d9a5bd9d0d275bb100e2b26f93b0fabcc0f04a0a7f48b071c87_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/keystore/0d73dff17d0b0d8641206ae38e47a76862fdad6f576f4ecce02468af34289e78_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/keystore/d30db3151430ff2c370f8f40cd6e23bb09ed8f3165c7b9957c8761bd9695297f_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/keystore/9fa526f760e0e861f3118d68faed451ba70639e08a135901d916089703b38eda_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/keystore/cc2fe89245d366799edfc39e8cdfa32801c8ae5fc26211ea4faff9ae6672bd35_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/keystore/8163fd4f80204f53f3149c20b2a005780753ee8529259598d515f6e14024fe8a_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/keystore/d602b7fae48619fb0dd47e941a559d0ac39b35270df2fce0d798db6b1b11b2b0_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/msp/keystore/3fec22439cf4be3c4f4a960276c33dd1edcbed4a5e599a116854e71eaf427e96_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/msp/keystore/50239d57381580b71992a618abe9c9f4e32539e9b85a692086de0fb364dbea54_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/keystore/03bc2a06ccd3c6456e6aac3a010ac4979b258a864c5778180cc43dda00ef02ad_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/keystore/0a43a8644bf07831479fe95ed77543cad709ec379f6e3070e992e67b4ed03a29_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/keystore/b6733ab74dc103dc93f71621606ad859de7854abfd5d485a9da4ebf322b9a566_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/keystore/b921b2940a4a7cdb8dd8a4509fb0dc92a4099335a1b737e7380d5bbd5cbb57e6_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/keystore/05e000f93c5285fb535f2d8d208949aeb68fd089dec6d386f21ff361eccc2072_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/keystore/99e69faef39205dde6522521da0473efb852a4a17e2fd2cb419efe78852a887f_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/keystore/0e6057bbf43121b51abad6a86682540ecb8ff59924b569c0dca624b478025f3d_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/keystore/9691d2d62a2d71ff121ee3a07ca6f9ed2559e7812c0d756e1f2f43942d8e786b_sk diff --git a/core/drivers/fabric-driver/wallet-network1/admin.id b/core/drivers/fabric-driver/wallet-network1/admin.id index 2c855f307..6d9f764cb 100644 --- a/core/drivers/fabric-driver/wallet-network1/admin.id +++ b/core/drivers/fabric-driver/wallet-network1/admin.id @@ -1 +1 @@ -{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIIB6jCCAZGgAwIBAgIUHxlIrtjJD5bVRoClhhsPiYUF2ckwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDczMDA1NDkwMFoXDTIyMDczMDA1NTQwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwVhZG1pbjBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABN4PSXdYzB+NQ3W0zlhPDGIiBUZ/BvPx9sn8C08u8q7y0HuYyfbLqfQP\nqpitQT55vto8gILg6BEXYEshDcXrjMCjYDBeMA4GA1UdDwEB/wQEAwIHgDAMBgNV\nHRMBAf8EAjAAMB0GA1UdDgQWBBQFGbBZ2bD8FLQfye8wKFoWL88iejAfBgNVHSME\nGDAWgBRyhvWC+jgvOsuRSF6arXu2zl0g/DAKBggqhkjOPQQDAgNHADBEAiBOUsm9\nIi/CZ7AJaTMTNc+UMwi7UhGp4MQcDYAOcm/PWQIgUUwYAhp0i5CDCJrDsYXGnxqh\nT58Uxd1Vr6dCxym+wN4=\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgb+llbCAwEAv3rtot\r\n/BmEPJVD0E+C/njeut9+Yz7dUimhRANCAATeD0l3WMwfjUN1tM5YTwxiIgVGfwbz\r\n8fbJ/AtPLvKu8tB7mMn2y6n0D6qYrUE+eb7aPICC4OgRF2BLIQ3F64zA\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file +{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIIB6jCCAZGgAwIBAgIUeRXp2NTeDriWFAW2Qylu/SBvq/MwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NDYwMFoXDTIzMDgwNDA2NTEwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwVhZG1pbjBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABBuGP+kB2T3nuPz4n+A5Rmi/mAObXwaTFtn+6KZCmj5ih1Z5w9dWgO14\nFf1SQZBE/FeWHb34/ktya1NxnD0cFwOjYDBeMA4GA1UdDwEB/wQEAwIHgDAMBgNV\nHRMBAf8EAjAAMB0GA1UdDgQWBBS6ZDoiZpG2AkRVHHxTUAnb83+UGDAfBgNVHSME\nGDAWgBQqEdSZb30F3rAKZ4lFrXItXF4jjDAKBggqhkjOPQQDAgNHADBEAiBxLKGe\naHAclQI5z0GFw0KAhzqte7pEpN22bWM0gteXHAIgY1qkaNrkx/mUTzVKY8TeS17g\nxxyVYIO4BCaIoEdyOJM=\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgb551as8oT5MWF83M\r\nzdPrpubdS20Rg7k9db6I33wdYzKhRANCAAQbhj/pAdk957j8+J/gOUZov5gDm18G\r\nkxbZ/uimQpo+YodWecPXVoDteBX9UkGQRPxXlh29+P5LcmtTcZw9HBcD\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file diff --git a/core/drivers/fabric-driver/wallet-network1/relay.id b/core/drivers/fabric-driver/wallet-network1/relay.id index dd2c77e24..0961605af 100644 --- a/core/drivers/fabric-driver/wallet-network1/relay.id +++ b/core/drivers/fabric-driver/wallet-network1/relay.id @@ -1 +1 @@ -{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIIChzCCAi2gAwIBAgIUWKNRifU+CDCSgJFDPuF8BBzf8KMwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDczMDA1NDkwMFoXDTIyMDczMDA1NTQwMFowQjEwMA0G\nA1UECxMGY2xpZW50MAsGA1UECxMEb3JnMTASBgNVBAsTC2RlcGFydG1lbnQxMQ4w\nDAYDVQQDEwVyZWxheTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCozF3M1L2iI\nIR7RaYaPNvVcftGltoKegO9MBPdMhxByiBqSiqInwr5eUO83qNwUaXvwMVmS8v/4\nbg/0febq8eyjgdowgdcwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYD\nVR0OBBYEFKfkp8twqOO0jw+v9H7e/yFZaNhCMB8GA1UdIwQYMBaAFHKG9YL6OC86\ny5FIXpqte7bOXSD8MHcGCCoDBAUGBwgBBGt7ImF0dHJzIjp7ImhmLkFmZmlsaWF0\naW9uIjoib3JnMS5kZXBhcnRtZW50MSIsImhmLkVucm9sbG1lbnRJRCI6InJlbGF5\nIiwiaGYuVHlwZSI6ImNsaWVudCIsInJlbGF5IjoidHJ1ZSJ9fTAKBggqhkjOPQQD\nAgNIADBFAiEA2ph3/nFY9qy2hr+0V2AGt9jEhDx/d6lYV+OrNOZcz4ACIAPeoFLG\nxbx3IAAD6OllR0BMXjLr3ptCsq1ZSUGlhK0p\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgyIRERhw6D+tCF1b0\r\n/WZCMHZONI7lxUAbiOwulotp/12hRANCAAQqMxdzNS9oiCEe0WmGjzb1XH7RpbaC\r\nnoDvTAT3TIcQcogakoqiJ8K+XlDvN6jcFGl78DFZkvL/+G4P9H3m6vHs\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file +{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIIChzCCAi2gAwIBAgIUatGEIkHJrXkasjI9aTBotPvrma0wCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NDYwMFoXDTIzMDgwNDA2NTEwMFowQjEwMA0G\nA1UECxMGY2xpZW50MAsGA1UECxMEb3JnMTASBgNVBAsTC2RlcGFydG1lbnQxMQ4w\nDAYDVQQDEwVyZWxheTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJ3Du7v+kssR\nzMU2Odc/vKStlt9HIcbyPqkeID6xxEXvFfZAEDTupbTahwEa2LvBDF7iCvXv09QC\nHbO1SzBd9+mjgdowgdcwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYD\nVR0OBBYEFBYqy2oOduP3fuO3lYMnI230Bg2OMB8GA1UdIwQYMBaAFCoR1JlvfQXe\nsApniUWtci1cXiOMMHcGCCoDBAUGBwgBBGt7ImF0dHJzIjp7ImhmLkFmZmlsaWF0\naW9uIjoib3JnMS5kZXBhcnRtZW50MSIsImhmLkVucm9sbG1lbnRJRCI6InJlbGF5\nIiwiaGYuVHlwZSI6ImNsaWVudCIsInJlbGF5IjoidHJ1ZSJ9fTAKBggqhkjOPQQD\nAgNIADBFAiEA+VDjQJLHxaFWFcY7Os6B+csLeUh7UyY/lIsOIBRGGqsCIDjTHPCf\n/2L7uKO02Yb/ROCOCKF/aLf06AoVHLMqURAh\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg/d6t/S1/x2Y1xAS5\r\nqQMpXIYTvVr7MMJIyFQkuRKJap6hRANCAASdw7u7/pLLEczFNjnXP7ykrZbfRyHG\r\n8j6pHiA+scRF7xX2QBA07qW02ocBGti7wQxe4gr179PUAh2ztUswXffp\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file diff --git a/core/drivers/fabric-driver/wallet-network2/admin.id b/core/drivers/fabric-driver/wallet-network2/admin.id index 1ae55c288..41578fcdb 100644 --- a/core/drivers/fabric-driver/wallet-network2/admin.id +++ b/core/drivers/fabric-driver/wallet-network2/admin.id @@ -1 +1 @@ -{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIIB6jCCAZGgAwIBAgIUcl74d4kQXUuE0PaBDSNOGhp1HrIwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDczMDA1NDkwMFoXDTIyMDczMDA1NTQwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwVhZG1pbjBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABJqfyV6xeUd4yeoeUuNboMPKRTCBTxaVLeqdMTK4sL7JCDzVecgq5udA\n6ueaDUT/DxHOjHiA4/Yq/Cxv+A5BL3ijYDBeMA4GA1UdDwEB/wQEAwIHgDAMBgNV\nHRMBAf8EAjAAMB0GA1UdDgQWBBRoxyJ6nA70Z2zlkFI398/cZIpGqjAfBgNVHSME\nGDAWgBS5xG0DXfVWPnA5kg786sSNHCiZ8TAKBggqhkjOPQQDAgNHADBEAiA+0Nd5\nZcw3DW6tgblWI1B9La9lXXKFxGJA3fc6nvOVowIgXQGS/PRgkKxMO+O3aqCNpKKM\nMSO4IrSs9fmeEjvIS+s=\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgFP8ZIMZ33nWmBO+Y\r\nJqubeP3ysmWtrCsF8AlDeafQd1ehRANCAASan8lesXlHeMnqHlLjW6DDykUwgU8W\r\nlS3qnTEyuLC+yQg81XnIKubnQOrnmg1E/w8Rzox4gOP2Kvwsb/gOQS94\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file +{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIIB6jCCAZGgAwIBAgIULg8U7R0NWK/th8hCEUxY1JZIZc0wCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NDcwMFoXDTIzMDgwNDA2NTIwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwVhZG1pbjBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABBHbYAOMQndXD1C+yPyaprYtjw5rdu+PMI1UVXD+ctQmMU/PiOu3uhzu\nb+iCn8haZWV40igvRIZGHPY73INbVTKjYDBeMA4GA1UdDwEB/wQEAwIHgDAMBgNV\nHRMBAf8EAjAAMB0GA1UdDgQWBBTRZ/2DmXyEAoOgVjE6FWMxut14NjAfBgNVHSME\nGDAWgBT8HtS6zbiN91ZvhHYDvxP4yYoVNTAKBggqhkjOPQQDAgNHADBEAiAxc7Qs\nUE1xp87yN1U54BDOiA2sWqrqMVGdFgoN67ZpLwIgFYBrLZhN59bn7wH2DdKpln1N\nmJX5B5poUz5o/1JUWRs=\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgxr2t90O+Bnn7GxYV\r\nL7cFuAxLBnd6h/OWOzPlj5JC+QChRANCAAQR22ADjEJ3Vw9Qvsj8mqa2LY8Oa3bv\r\njzCNVFVw/nLUJjFPz4jrt7oc7m/ogp/IWmVleNIoL0SGRhz2O9yDW1Uy\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file diff --git a/core/drivers/fabric-driver/wallet-network2/relay.id b/core/drivers/fabric-driver/wallet-network2/relay.id index ae51e9f45..a46730cb4 100644 --- a/core/drivers/fabric-driver/wallet-network2/relay.id +++ b/core/drivers/fabric-driver/wallet-network2/relay.id @@ -1 +1 @@ -{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIIChjCCAi2gAwIBAgIULxdG78xMwWqGDVvfxN5bfhcI9nEwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDczMDA1NDkwMFoXDTIyMDczMDA1NTQwMFowQjEwMA0G\nA1UECxMGY2xpZW50MAsGA1UECxMEb3JnMTASBgNVBAsTC2RlcGFydG1lbnQxMQ4w\nDAYDVQQDEwVyZWxheTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCM8ed3/O+6r\n+irE7f3LJwhmNEM/WSiuo0RahLKiqOUPAnZwrs9RTyg8Usj8WU+vZSMGtVHGFD+Y\ncZIljuSkeySjgdowgdcwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYD\nVR0OBBYEFElmORX12RRa5jzLrHmar+uMXYyiMB8GA1UdIwQYMBaAFLnEbQNd9VY+\ncDmSDvzqxI0cKJnxMHcGCCoDBAUGBwgBBGt7ImF0dHJzIjp7ImhmLkFmZmlsaWF0\naW9uIjoib3JnMS5kZXBhcnRtZW50MSIsImhmLkVucm9sbG1lbnRJRCI6InJlbGF5\nIiwiaGYuVHlwZSI6ImNsaWVudCIsInJlbGF5IjoidHJ1ZSJ9fTAKBggqhkjOPQQD\nAgNHADBEAiAFrzIP8+i2b8IHOV/istJPKl/7ApDO3fJ31uGE57D9aAIgdGaUrPFS\njpaEwj5+c2VfXHTlTTUlZIGT9C6vTvquFTk=\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgqbTBgiFPy+vUYOx+\r\nuIlucpEKPFuNECBauv8V3I56nWehRANCAAQjPHnd/zvuq/oqxO39yycIZjRDP1ko\r\nrqNEWoSyoqjlDwJ2cK7PUU8oPFLI/FlPr2UjBrVRxhQ/mHGSJY7kpHsk\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file +{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIIChjCCAi2gAwIBAgIUYrS6rylTI2wTWRNgTJIdbve47GswCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NDcwMFoXDTIzMDgwNDA2NTIwMFowQjEwMA0G\nA1UECxMGY2xpZW50MAsGA1UECxMEb3JnMTASBgNVBAsTC2RlcGFydG1lbnQxMQ4w\nDAYDVQQDEwVyZWxheTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLUOEH7UaUgO\nbX7XZowasZfKSEVJ3DrUbBRnfVAcRKPOhaMVTpqm8itrlvI7OLrGuy+fjEdDwI96\nQ8o5mxmfdwGjgdowgdcwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYD\nVR0OBBYEFC3nU1Y4kYAI4LjYB0KykOZohQ3qMB8GA1UdIwQYMBaAFPwe1LrNuI33\nVm+EdgO/E/jJihU1MHcGCCoDBAUGBwgBBGt7ImF0dHJzIjp7ImhmLkFmZmlsaWF0\naW9uIjoib3JnMS5kZXBhcnRtZW50MSIsImhmLkVucm9sbG1lbnRJRCI6InJlbGF5\nIiwiaGYuVHlwZSI6ImNsaWVudCIsInJlbGF5IjoidHJ1ZSJ9fTAKBggqhkjOPQQD\nAgNHADBEAiAiSTLTgj0fSLmNCCJTr8hoZHSLSPiFZgT3oeymy9ocdAIgSF8R15R8\nUPxQQkbNI/LFmEEsPrJjRimgKwzWRcXPzYc=\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgei8TtJsEZjUhuPge\r\nmOEGuE7wR8f01Swvty0OSPpMWCahRANCAAS1DhB+1GlIDm1+12aMGrGXykhFSdw6\r\n1GwUZ31QHESjzoWjFU6apvIra5byOzi6xrsvn4xHQ8CPekPKOZsZn3cB\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file diff --git a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network1/access-control.json b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network1/access-control.json index fe24a8181..d2cbd4215 100644 --- a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network1/access-control.json +++ b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network1/access-control.json @@ -2,13 +2,13 @@ "securityDomain": "network1", "rules": [ { - "principal": "-----BEGIN CERTIFICATE-----\nMIICRjCCAe2gAwIBAgIUBMI+vcDI6Z/4bMZN2Cjp6vAXDtgwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDkwNzA5MTQwMFoXDTIyMDkwNzA5MTkwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABFoZaE1MsLtrLRYFzJRyj5uelfL/Fa5pLN2kiO+M5tnxf0+wAotEeC8z\nLCS1KHVIQ7UJD/AOL1OFkbJCHKSdFJGjgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFPzrPjhbfwF/wxP8iFKy4NspQw0uMB8GA1Ud\nIwQYMBaAFHKG9YL6OC86y5FIXpqte7bOXSD8MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0cAMEQCIDP8WLlE4btz\niw6tI/EFdLY/CSOW1P8bOFquaz5YwjYhAiBxEKH6+udDehvHU+wmRaC/Kp1VJNJZ\ndbjNTs65n8zfbQ==\n-----END CERTIFICATE-----\n", + "principal": "-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUNtt5srTRKRumyRD/O2FFoOImcjkwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABJ+cH+YyJCTeAyOXaIdNMFUYwKqUjClxSlEcHObedbmofV+WluvdkCsf\nWyv72JliZEm0HngxkkumIOxir0VBW4KjgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFN6zn3QTE1IuXKG2rnGCUuhkP2rIMB8GA1Ud\nIwQYMBaAFCoR1JlvfQXesApniUWtci1cXiOMMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQCpVjfnmEM7\nFHK9UX2j1+a25IFD5/p62CljJRQgnLUWXwIgBOKluTSOICeQ3FWx8+5+ZWrYL2wn\nPL3qORlNthH+Vrc=\n-----END CERTIFICATE-----\n", "principalType": "ca", "resource": "localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:*", "read": true }, { - "principal": "-----BEGIN CERTIFICATE-----\nMIICRjCCAe2gAwIBAgIUBMI+vcDI6Z/4bMZN2Cjp6vAXDtgwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDkwNzA5MTQwMFoXDTIyMDkwNzA5MTkwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABFoZaE1MsLtrLRYFzJRyj5uelfL/Fa5pLN2kiO+M5tnxf0+wAotEeC8z\nLCS1KHVIQ7UJD/AOL1OFkbJCHKSdFJGjgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFPzrPjhbfwF/wxP8iFKy4NspQw0uMB8GA1Ud\nIwQYMBaAFHKG9YL6OC86y5FIXpqte7bOXSD8MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0cAMEQCIDP8WLlE4btz\niw6tI/EFdLY/CSOW1P8bOFquaz5YwjYhAiBxEKH6+udDehvHU+wmRaC/Kp1VJNJZ\ndbjNTs65n8zfbQ==\n-----END CERTIFICATE-----\n", + "principal": "-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUNtt5srTRKRumyRD/O2FFoOImcjkwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABJ+cH+YyJCTeAyOXaIdNMFUYwKqUjClxSlEcHObedbmofV+WluvdkCsf\nWyv72JliZEm0HngxkkumIOxir0VBW4KjgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFN6zn3QTE1IuXKG2rnGCUuhkP2rIMB8GA1Ud\nIwQYMBaAFCoR1JlvfQXesApniUWtci1cXiOMMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQCpVjfnmEM7\nFHK9UX2j1+a25IFD5/p62CljJRQgnLUWXwIgBOKluTSOICeQ3FWx8+5+ZWrYL2wn\nPL3qORlNthH+Vrc=\n-----END CERTIFICATE-----\n", "principalType": "ca", "resource": "localhost:30006#com.cordaSimpleApplication.flow.GetStateByKey:*", "read": true diff --git a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network1/membership.json b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network1/membership.json index 485cb4895..7280e1a65 100644 --- a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network1/membership.json +++ b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network1/membership.json @@ -1,10 +1 @@ -{ - "securityDomain": "network1", - "members": { - "Org1MSP": { - "type": "ca", - "value": "-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUYyc2soSqUtWVHTOtud7D1FbCHp0wCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTM2MDcyNjA1NDYwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEM/GelSlifY6+rMOE3G95SXF+\ndTHpG8j5cYK82EVCaLCSvNlCKgpupuQnbkLy+V6dgf9tKSnEsZgiHeB6AyJK/6NF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFHKG9YL6OC86y5FIXpqte7bOXSD8MAoGCCqGSM49BAMCA0cAMEQCIA9iMqQ/aJiC\na++ft4tN7io83jB17/fzG3BRC9soRR3bAiALgWNYk5118DKTkhFdJVQ0VIoopEtq\nGzi+/j4j7fu/wQ==\n-----END CERTIFICATE-----\n", - "chain": [] - } - } -} +{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR\nynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq\nm2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd\nzQkhznMIF4SBF4k=\n-----END CERTIFICATE-----\n"}},"securityDomain":"network1"} \ No newline at end of file diff --git a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network2/access-control.json b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network2/access-control.json index 9e6790d6b..3ac2b0b08 100644 --- a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network2/access-control.json +++ b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network2/access-control.json @@ -2,13 +2,13 @@ "securityDomain": "network2", "rules": [ { - "principal": "-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUGvDSMG39o7baaCZKihlM/Udlx5YwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDkwNzA5MTcwMFoXDTIyMDkwNzA5MjIwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABFZDosCNi+A6D4b4dDrt5aGw0PB7fRT0p4hgTnqk1UWf52U8jOIXgk+t\nWFzICJ0Ltc6iZWEKdeIu6UzK/Q2etE6jgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFC2PFn4siCLGXl//tdAGTIJeUeJ1MB8GA1Ud\nIwQYMBaAFLnEbQNd9VY+cDmSDvzqxI0cKJnxMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQCDa9yllzfE\nGko3C/H8ZxSJwe1e6IgWLnsUIN9Ecx3+pQIgPIu/E0vlwcjguL5xjb6iAJFsqe1V\nR99IpF9SoUQ5CjM=\n-----END CERTIFICATE-----\n", + "principal": "-----BEGIN CERTIFICATE-----\nMIICRjCCAe2gAwIBAgIURRRCdbZ63i59M3w68P5I25rz2LAwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABNOgoRbrgtfXxqa/mbBQNmyx1PIXLAuaMWpqAIu1Lw1LM28tJthOJqXU\nz6EwHLGeLlbvSET6xmoXrgIvBB1ZwG6jgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFMsXP7BjMsmfUuKfueUsrY74pX0GMB8GA1Ud\nIwQYMBaAFPwe1LrNuI33Vm+EdgO/E/jJihU1MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0cAMEQCIBB/681WfBR+\nQWIGfiYKOk3HuRtO8JFwbTiEjnAgCRvnAiBa69wWYaZ25ZR+Gay69eV+vDZkPMHS\ngdRjAItcKGstFg==\n-----END CERTIFICATE-----\n", "principalType": "ca", "resource": "localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:*", "read": true }, { - "principal": "-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUGvDSMG39o7baaCZKihlM/Udlx5YwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDkwNzA5MTcwMFoXDTIyMDkwNzA5MjIwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABFZDosCNi+A6D4b4dDrt5aGw0PB7fRT0p4hgTnqk1UWf52U8jOIXgk+t\nWFzICJ0Ltc6iZWEKdeIu6UzK/Q2etE6jgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFC2PFn4siCLGXl//tdAGTIJeUeJ1MB8GA1Ud\nIwQYMBaAFLnEbQNd9VY+cDmSDvzqxI0cKJnxMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQCDa9yllzfE\nGko3C/H8ZxSJwe1e6IgWLnsUIN9Ecx3+pQIgPIu/E0vlwcjguL5xjb6iAJFsqe1V\nR99IpF9SoUQ5CjM=\n-----END CERTIFICATE-----\n", + "principal": "-----BEGIN CERTIFICATE-----\nMIICRjCCAe2gAwIBAgIURRRCdbZ63i59M3w68P5I25rz2LAwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABNOgoRbrgtfXxqa/mbBQNmyx1PIXLAuaMWpqAIu1Lw1LM28tJthOJqXU\nz6EwHLGeLlbvSET6xmoXrgIvBB1ZwG6jgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFMsXP7BjMsmfUuKfueUsrY74pX0GMB8GA1Ud\nIwQYMBaAFPwe1LrNuI33Vm+EdgO/E/jJihU1MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0cAMEQCIBB/681WfBR+\nQWIGfiYKOk3HuRtO8JFwbTiEjnAgCRvnAiBa69wWYaZ25ZR+Gay69eV+vDZkPMHS\ngdRjAItcKGstFg==\n-----END CERTIFICATE-----\n", "principalType": "ca", "resource": "localhost:30006#com.cordaSimpleApplication.flow.GetStateByKey:*", "read": true diff --git a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network2/membership.json b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network2/membership.json index 8a6953069..912758323 100644 --- a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network2/membership.json +++ b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network2/membership.json @@ -1,10 +1 @@ -{ - "securityDomain": "network2", - "members": { - "Org1MSP": { - "type": "ca", - "value": "-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUar7AQ9tuF+EnYEV5NzojPETw1B0wCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTM2MDcyNjA1NDgwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHX4bYZ98sCjpCzBsmiW6j42Q\nQkB+dpDkS5IhblsJT8wesFf4EpkkFdR0utBgdL27UmbmmoTHh6P2AWwAtg6UTqNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFLnEbQNd9VY+cDmSDvzqxI0cKJnxMAoGCCqGSM49BAMCA0cAMEQCICqeGasMewgQ\nbm3A30b/VARhu853QV7MeWbVi5J0lYE7AiAIGm0t947c/hKmiqG+JiU8hlsZzA73\nBbhDFXqROY1Q+g==\n-----END CERTIFICATE-----\n", - "chain": [] - } - } -} +{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUaRllBApd/UVhTSw9k4cCNqGfyWEwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTM3MDczMTA2MDQwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEr6IYnwH5QCqxy9F3i1x77rLD\nWG3EjMsD16528Q5N8BVStH5A89XeXLrALrAFxvgF5zlFriMRtQMrCxy0pZzJPaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFPwe1LrNuI33Vm+EdgO/E/jJihU1MAoGCCqGSM49BAMCA0gAMEUCIQDPHTMu/Hx1\nqm/G090dqV0215wZQ0Dl7al5TlSrrhftfgIge5QZxYKUsUkptToiOnRJY5pD/Oc+\nF9RBKXnii85zCnI=\n-----END CERTIFICATE-----\n"}},"securityDomain":"network2"} \ No newline at end of file diff --git a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network1/access-control.json b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network1/access-control.json index e2c08ff7a..347d25a22 100644 --- a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network1/access-control.json +++ b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network1/access-control.json @@ -2,13 +2,13 @@ "securityDomain": "network1", "rules": [ { - "principal": "-----BEGIN CERTIFICATE-----\nMIICRjCCAe2gAwIBAgIUBMI+vcDI6Z/4bMZN2Cjp6vAXDtgwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDkwNzA5MTQwMFoXDTIyMDkwNzA5MTkwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABFoZaE1MsLtrLRYFzJRyj5uelfL/Fa5pLN2kiO+M5tnxf0+wAotEeC8z\nLCS1KHVIQ7UJD/AOL1OFkbJCHKSdFJGjgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFPzrPjhbfwF/wxP8iFKy4NspQw0uMB8GA1Ud\nIwQYMBaAFHKG9YL6OC86y5FIXpqte7bOXSD8MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0cAMEQCIDP8WLlE4btz\niw6tI/EFdLY/CSOW1P8bOFquaz5YwjYhAiBxEKH6+udDehvHU+wmRaC/Kp1VJNJZ\ndbjNTs65n8zfbQ==\n-----END CERTIFICATE-----\n", + "principal": "-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUNtt5srTRKRumyRD/O2FFoOImcjkwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABJ+cH+YyJCTeAyOXaIdNMFUYwKqUjClxSlEcHObedbmofV+WluvdkCsf\nWyv72JliZEm0HngxkkumIOxir0VBW4KjgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFN6zn3QTE1IuXKG2rnGCUuhkP2rIMB8GA1Ud\nIwQYMBaAFCoR1JlvfQXesApniUWtci1cXiOMMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQCpVjfnmEM7\nFHK9UX2j1+a25IFD5/p62CljJRQgnLUWXwIgBOKluTSOICeQ3FWx8+5+ZWrYL2wn\nPL3qORlNthH+Vrc=\n-----END CERTIFICATE-----\n", "principalType": "ca", "resource": "corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:*", "read": true }, { - "principal": "-----BEGIN CERTIFICATE-----\nMIICRjCCAe2gAwIBAgIUBMI+vcDI6Z/4bMZN2Cjp6vAXDtgwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDkwNzA5MTQwMFoXDTIyMDkwNzA5MTkwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABFoZaE1MsLtrLRYFzJRyj5uelfL/Fa5pLN2kiO+M5tnxf0+wAotEeC8z\nLCS1KHVIQ7UJD/AOL1OFkbJCHKSdFJGjgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFPzrPjhbfwF/wxP8iFKy4NspQw0uMB8GA1Ud\nIwQYMBaAFHKG9YL6OC86y5FIXpqte7bOXSD8MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0cAMEQCIDP8WLlE4btz\niw6tI/EFdLY/CSOW1P8bOFquaz5YwjYhAiBxEKH6+udDehvHU+wmRaC/Kp1VJNJZ\ndbjNTs65n8zfbQ==\n-----END CERTIFICATE-----\n", + "principal": "-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUNtt5srTRKRumyRD/O2FFoOImcjkwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABJ+cH+YyJCTeAyOXaIdNMFUYwKqUjClxSlEcHObedbmofV+WluvdkCsf\nWyv72JliZEm0HngxkkumIOxir0VBW4KjgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFN6zn3QTE1IuXKG2rnGCUuhkP2rIMB8GA1Ud\nIwQYMBaAFCoR1JlvfQXesApniUWtci1cXiOMMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQCpVjfnmEM7\nFHK9UX2j1+a25IFD5/p62CljJRQgnLUWXwIgBOKluTSOICeQ3FWx8+5+ZWrYL2wn\nPL3qORlNthH+Vrc=\n-----END CERTIFICATE-----\n", "principalType": "ca", "resource": "corda_network2_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:*", "read": true diff --git a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network1/membership.json b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network1/membership.json index 485cb4895..7280e1a65 100644 --- a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network1/membership.json +++ b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network1/membership.json @@ -1,10 +1 @@ -{ - "securityDomain": "network1", - "members": { - "Org1MSP": { - "type": "ca", - "value": "-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUYyc2soSqUtWVHTOtud7D1FbCHp0wCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTM2MDcyNjA1NDYwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEM/GelSlifY6+rMOE3G95SXF+\ndTHpG8j5cYK82EVCaLCSvNlCKgpupuQnbkLy+V6dgf9tKSnEsZgiHeB6AyJK/6NF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFHKG9YL6OC86y5FIXpqte7bOXSD8MAoGCCqGSM49BAMCA0cAMEQCIA9iMqQ/aJiC\na++ft4tN7io83jB17/fzG3BRC9soRR3bAiALgWNYk5118DKTkhFdJVQ0VIoopEtq\nGzi+/j4j7fu/wQ==\n-----END CERTIFICATE-----\n", - "chain": [] - } - } -} +{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR\nynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq\nm2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd\nzQkhznMIF4SBF4k=\n-----END CERTIFICATE-----\n"}},"securityDomain":"network1"} \ No newline at end of file diff --git a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network2/access-control.json b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network2/access-control.json index 7e3a89511..6d82fd892 100644 --- a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network2/access-control.json +++ b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network2/access-control.json @@ -2,13 +2,13 @@ "securityDomain": "network2", "rules": [ { - "principal": "-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUGvDSMG39o7baaCZKihlM/Udlx5YwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDkwNzA5MTcwMFoXDTIyMDkwNzA5MjIwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABFZDosCNi+A6D4b4dDrt5aGw0PB7fRT0p4hgTnqk1UWf52U8jOIXgk+t\nWFzICJ0Ltc6iZWEKdeIu6UzK/Q2etE6jgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFC2PFn4siCLGXl//tdAGTIJeUeJ1MB8GA1Ud\nIwQYMBaAFLnEbQNd9VY+cDmSDvzqxI0cKJnxMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQCDa9yllzfE\nGko3C/H8ZxSJwe1e6IgWLnsUIN9Ecx3+pQIgPIu/E0vlwcjguL5xjb6iAJFsqe1V\nR99IpF9SoUQ5CjM=\n-----END CERTIFICATE-----\n", + "principal": "-----BEGIN CERTIFICATE-----\nMIICRjCCAe2gAwIBAgIURRRCdbZ63i59M3w68P5I25rz2LAwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABNOgoRbrgtfXxqa/mbBQNmyx1PIXLAuaMWpqAIu1Lw1LM28tJthOJqXU\nz6EwHLGeLlbvSET6xmoXrgIvBB1ZwG6jgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFMsXP7BjMsmfUuKfueUsrY74pX0GMB8GA1Ud\nIwQYMBaAFPwe1LrNuI33Vm+EdgO/E/jJihU1MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0cAMEQCIBB/681WfBR+\nQWIGfiYKOk3HuRtO8JFwbTiEjnAgCRvnAiBa69wWYaZ25ZR+Gay69eV+vDZkPMHS\ngdRjAItcKGstFg==\n-----END CERTIFICATE-----\n", "principalType": "ca", "resource": "corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:*", "read": true }, { - "principal": "-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUGvDSMG39o7baaCZKihlM/Udlx5YwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDkwNzA5MTcwMFoXDTIyMDkwNzA5MjIwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABFZDosCNi+A6D4b4dDrt5aGw0PB7fRT0p4hgTnqk1UWf52U8jOIXgk+t\nWFzICJ0Ltc6iZWEKdeIu6UzK/Q2etE6jgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFC2PFn4siCLGXl//tdAGTIJeUeJ1MB8GA1Ud\nIwQYMBaAFLnEbQNd9VY+cDmSDvzqxI0cKJnxMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQCDa9yllzfE\nGko3C/H8ZxSJwe1e6IgWLnsUIN9Ecx3+pQIgPIu/E0vlwcjguL5xjb6iAJFsqe1V\nR99IpF9SoUQ5CjM=\n-----END CERTIFICATE-----\n", + "principal": "-----BEGIN CERTIFICATE-----\nMIICRjCCAe2gAwIBAgIURRRCdbZ63i59M3w68P5I25rz2LAwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABNOgoRbrgtfXxqa/mbBQNmyx1PIXLAuaMWpqAIu1Lw1LM28tJthOJqXU\nz6EwHLGeLlbvSET6xmoXrgIvBB1ZwG6jgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFMsXP7BjMsmfUuKfueUsrY74pX0GMB8GA1Ud\nIwQYMBaAFPwe1LrNuI33Vm+EdgO/E/jJihU1MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0cAMEQCIBB/681WfBR+\nQWIGfiYKOk3HuRtO8JFwbTiEjnAgCRvnAiBa69wWYaZ25ZR+Gay69eV+vDZkPMHS\ngdRjAItcKGstFg==\n-----END CERTIFICATE-----\n", "principalType": "ca", "resource": "corda_network2_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:*", "read": true diff --git a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network2/membership.json b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network2/membership.json index 8a6953069..912758323 100644 --- a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network2/membership.json +++ b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network2/membership.json @@ -1,10 +1 @@ -{ - "securityDomain": "network2", - "members": { - "Org1MSP": { - "type": "ca", - "value": "-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUar7AQ9tuF+EnYEV5NzojPETw1B0wCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTM2MDcyNjA1NDgwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHX4bYZ98sCjpCzBsmiW6j42Q\nQkB+dpDkS5IhblsJT8wesFf4EpkkFdR0utBgdL27UmbmmoTHh6P2AWwAtg6UTqNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFLnEbQNd9VY+cDmSDvzqxI0cKJnxMAoGCCqGSM49BAMCA0cAMEQCICqeGasMewgQ\nbm3A30b/VARhu853QV7MeWbVi5J0lYE7AiAIGm0t947c/hKmiqG+JiU8hlsZzA73\nBbhDFXqROY1Q+g==\n-----END CERTIFICATE-----\n", - "chain": [] - } - } -} +{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUaRllBApd/UVhTSw9k4cCNqGfyWEwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTM3MDczMTA2MDQwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEr6IYnwH5QCqxy9F3i1x77rLD\nWG3EjMsD16528Q5N8BVStH5A89XeXLrALrAFxvgF5zlFriMRtQMrCxy0pZzJPaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFPwe1LrNuI33Vm+EdgO/E/jJihU1MAoGCCqGSM49BAMCA0gAMEUCIQDPHTMu/Hx1\nqm/G090dqV0215wZQ0Dl7al5TlSrrhftfgIge5QZxYKUsUkptToiOnRJY5pD/Oc+\nF9RBKXnii85zCnI=\n-----END CERTIFICATE-----\n"}},"securityDomain":"network2"} \ No newline at end of file diff --git a/samples/fabric/fabric-cli/src/data/credentials/network1/membership.json b/samples/fabric/fabric-cli/src/data/credentials/network1/membership.json index 8fe5f465f..7280e1a65 100644 --- a/samples/fabric/fabric-cli/src/data/credentials/network1/membership.json +++ b/samples/fabric/fabric-cli/src/data/credentials/network1/membership.json @@ -1 +1 @@ -{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUYyc2soSqUtWVHTOtud7D1FbCHp0wCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTM2MDcyNjA1NDYwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEM/GelSlifY6+rMOE3G95SXF+\ndTHpG8j5cYK82EVCaLCSvNlCKgpupuQnbkLy+V6dgf9tKSnEsZgiHeB6AyJK/6NF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFHKG9YL6OC86y5FIXpqte7bOXSD8MAoGCCqGSM49BAMCA0cAMEQCIA9iMqQ/aJiC\na++ft4tN7io83jB17/fzG3BRC9soRR3bAiALgWNYk5118DKTkhFdJVQ0VIoopEtq\nGzi+/j4j7fu/wQ==\n-----END CERTIFICATE-----\n"}},"securityDomain":"network1"} \ No newline at end of file +{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR\nynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq\nm2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd\nzQkhznMIF4SBF4k=\n-----END CERTIFICATE-----\n"}},"securityDomain":"network1"} \ No newline at end of file diff --git a/samples/fabric/fabric-cli/src/data/credentials/network2/access-control.json b/samples/fabric/fabric-cli/src/data/credentials/network2/access-control.json index d2711ab18..95d4a4f62 100644 --- a/samples/fabric/fabric-cli/src/data/credentials/network2/access-control.json +++ b/samples/fabric/fabric-cli/src/data/credentials/network2/access-control.json @@ -1 +1 @@ -{"securityDomain":"network2","rules":[{"principal":"-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUGvDSMG39o7baaCZKihlM/Udlx5YwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDkwNzA5MTcwMFoXDTIyMDkwNzA5MjIwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABFZDosCNi+A6D4b4dDrt5aGw0PB7fRT0p4hgTnqk1UWf52U8jOIXgk+t\nWFzICJ0Ltc6iZWEKdeIu6UzK/Q2etE6jgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFC2PFn4siCLGXl//tdAGTIJeUeJ1MB8GA1Ud\nIwQYMBaAFLnEbQNd9VY+cDmSDvzqxI0cKJnxMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQCDa9yllzfE\nGko3C/H8ZxSJwe1e6IgWLnsUIN9Ecx3+pQIgPIu/E0vlwcjguL5xjb6iAJFsqe1V\nR99IpF9SoUQ5CjM=\n-----END CERTIFICATE-----\n","principalType":"certificate","resource":"mychannel:simplestate:Read:*","read":true}]} \ No newline at end of file +{"securityDomain":"network2","rules":[{"principal":"-----BEGIN CERTIFICATE-----\nMIICRjCCAe2gAwIBAgIURRRCdbZ63i59M3w68P5I25rz2LAwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABNOgoRbrgtfXxqa/mbBQNmyx1PIXLAuaMWpqAIu1Lw1LM28tJthOJqXU\nz6EwHLGeLlbvSET6xmoXrgIvBB1ZwG6jgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFMsXP7BjMsmfUuKfueUsrY74pX0GMB8GA1Ud\nIwQYMBaAFPwe1LrNuI33Vm+EdgO/E/jJihU1MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0cAMEQCIBB/681WfBR+\nQWIGfiYKOk3HuRtO8JFwbTiEjnAgCRvnAiBa69wWYaZ25ZR+Gay69eV+vDZkPMHS\ngdRjAItcKGstFg==\n-----END CERTIFICATE-----\n","principalType":"certificate","resource":"mychannel:simplestate:Read:*","read":true}]} \ No newline at end of file diff --git a/samples/fabric/fabric-cli/src/data/credentials/network2/membership.json b/samples/fabric/fabric-cli/src/data/credentials/network2/membership.json index fd7d03ede..912758323 100644 --- a/samples/fabric/fabric-cli/src/data/credentials/network2/membership.json +++ b/samples/fabric/fabric-cli/src/data/credentials/network2/membership.json @@ -1 +1 @@ -{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUar7AQ9tuF+EnYEV5NzojPETw1B0wCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTM2MDcyNjA1NDgwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHX4bYZ98sCjpCzBsmiW6j42Q\nQkB+dpDkS5IhblsJT8wesFf4EpkkFdR0utBgdL27UmbmmoTHh6P2AWwAtg6UTqNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFLnEbQNd9VY+cDmSDvzqxI0cKJnxMAoGCCqGSM49BAMCA0cAMEQCICqeGasMewgQ\nbm3A30b/VARhu853QV7MeWbVi5J0lYE7AiAIGm0t947c/hKmiqG+JiU8hlsZzA73\nBbhDFXqROY1Q+g==\n-----END CERTIFICATE-----\n"}},"securityDomain":"network2"} \ No newline at end of file +{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUaRllBApd/UVhTSw9k4cCNqGfyWEwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTM3MDczMTA2MDQwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEr6IYnwH5QCqxy9F3i1x77rLD\nWG3EjMsD16528Q5N8BVStH5A89XeXLrALrAFxvgF5zlFriMRtQMrCxy0pZzJPaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFPwe1LrNuI33Vm+EdgO/E/jJihU1MAoGCCqGSM49BAMCA0gAMEUCIQDPHTMu/Hx1\nqm/G090dqV0215wZQ0Dl7al5TlSrrhftfgIge5QZxYKUsUkptToiOnRJY5pD/Oc+\nF9RBKXnii85zCnI=\n-----END CERTIFICATE-----\n"}},"securityDomain":"network2"} \ No newline at end of file diff --git a/samples/fabric/fabric-cli/src/data/credentials_docker/network1/membership.json b/samples/fabric/fabric-cli/src/data/credentials_docker/network1/membership.json index 8fe5f465f..7280e1a65 100644 --- a/samples/fabric/fabric-cli/src/data/credentials_docker/network1/membership.json +++ b/samples/fabric/fabric-cli/src/data/credentials_docker/network1/membership.json @@ -1 +1 @@ -{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUYyc2soSqUtWVHTOtud7D1FbCHp0wCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTM2MDcyNjA1NDYwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEM/GelSlifY6+rMOE3G95SXF+\ndTHpG8j5cYK82EVCaLCSvNlCKgpupuQnbkLy+V6dgf9tKSnEsZgiHeB6AyJK/6NF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFHKG9YL6OC86y5FIXpqte7bOXSD8MAoGCCqGSM49BAMCA0cAMEQCIA9iMqQ/aJiC\na++ft4tN7io83jB17/fzG3BRC9soRR3bAiALgWNYk5118DKTkhFdJVQ0VIoopEtq\nGzi+/j4j7fu/wQ==\n-----END CERTIFICATE-----\n"}},"securityDomain":"network1"} \ No newline at end of file +{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR\nynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq\nm2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd\nzQkhznMIF4SBF4k=\n-----END CERTIFICATE-----\n"}},"securityDomain":"network1"} \ No newline at end of file diff --git a/samples/fabric/fabric-cli/src/data/credentials_docker/network2/access-control.json b/samples/fabric/fabric-cli/src/data/credentials_docker/network2/access-control.json index bc28c761e..a654e3720 100644 --- a/samples/fabric/fabric-cli/src/data/credentials_docker/network2/access-control.json +++ b/samples/fabric/fabric-cli/src/data/credentials_docker/network2/access-control.json @@ -1 +1 @@ -{"securityDomain":"network2","rules":[{"principal":"-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUGvDSMG39o7baaCZKihlM/Udlx5YwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDkwNzA5MTcwMFoXDTIyMDkwNzA5MjIwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABFZDosCNi+A6D4b4dDrt5aGw0PB7fRT0p4hgTnqk1UWf52U8jOIXgk+t\nWFzICJ0Ltc6iZWEKdeIu6UzK/Q2etE6jgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFC2PFn4siCLGXl//tdAGTIJeUeJ1MB8GA1Ud\nIwQYMBaAFLnEbQNd9VY+cDmSDvzqxI0cKJnxMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQCDa9yllzfE\nGko3C/H8ZxSJwe1e6IgWLnsUIN9Ecx3+pQIgPIu/E0vlwcjguL5xjb6iAJFsqe1V\nR99IpF9SoUQ5CjM=\n-----END CERTIFICATE-----\n","principalType":"certificate","resource":"mychannel:simplestate:Read:*","read":true},{"principal":"-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUGvDSMG39o7baaCZKihlM/Udlx5YwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDkwNzA5MTcwMFoXDTIyMDkwNzA5MjIwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABFZDosCNi+A6D4b4dDrt5aGw0PB7fRT0p4hgTnqk1UWf52U8jOIXgk+t\nWFzICJ0Ltc6iZWEKdeIu6UzK/Q2etE6jgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFC2PFn4siCLGXl//tdAGTIJeUeJ1MB8GA1Ud\nIwQYMBaAFLnEbQNd9VY+cDmSDvzqxI0cKJnxMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQCDa9yllzfE\nGko3C/H8ZxSJwe1e6IgWLnsUIN9Ecx3+pQIgPIu/E0vlwcjguL5xjb6iAJFsqe1V\nR99IpF9SoUQ5CjM=\n-----END CERTIFICATE-----\n","principalType":"certificate","resource":"mychannel:simplestatewithacl:Read:*","read":true}]} \ No newline at end of file +{"securityDomain":"network2","rules":[{"principal":"-----BEGIN CERTIFICATE-----\nMIICRjCCAe2gAwIBAgIURRRCdbZ63i59M3w68P5I25rz2LAwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABNOgoRbrgtfXxqa/mbBQNmyx1PIXLAuaMWpqAIu1Lw1LM28tJthOJqXU\nz6EwHLGeLlbvSET6xmoXrgIvBB1ZwG6jgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFMsXP7BjMsmfUuKfueUsrY74pX0GMB8GA1Ud\nIwQYMBaAFPwe1LrNuI33Vm+EdgO/E/jJihU1MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0cAMEQCIBB/681WfBR+\nQWIGfiYKOk3HuRtO8JFwbTiEjnAgCRvnAiBa69wWYaZ25ZR+Gay69eV+vDZkPMHS\ngdRjAItcKGstFg==\n-----END CERTIFICATE-----\n","principalType":"certificate","resource":"mychannel:simplestate:Read:*","read":true},{"principal":"----BEGIN CERTIFICATE-----\nMIICRjCCAe2gAwIBAgIURRRCdbZ63i59M3w68P5I25rz2LAwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABNOgoRbrgtfXxqa/mbBQNmyx1PIXLAuaMWpqAIu1Lw1LM28tJthOJqXU\nz6EwHLGeLlbvSET6xmoXrgIvBB1ZwG6jgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFMsXP7BjMsmfUuKfueUsrY74pX0GMB8GA1Ud\nIwQYMBaAFPwe1LrNuI33Vm+EdgO/E/jJihU1MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0cAMEQCIBB/681WfBR+\nQWIGfiYKOk3HuRtO8JFwbTiEjnAgCRvnAiBa69wWYaZ25ZR+Gay69eV+vDZkPMHS\ngdRjAItcKGstFg==\n-----END CERTIFICATE-----\n","principalType":"certificate","resource":"mychannel:simplestatewithacl:Read:*","read":true}]} diff --git a/samples/fabric/fabric-cli/src/data/credentials_docker/network2/membership.json b/samples/fabric/fabric-cli/src/data/credentials_docker/network2/membership.json index fd7d03ede..912758323 100644 --- a/samples/fabric/fabric-cli/src/data/credentials_docker/network2/membership.json +++ b/samples/fabric/fabric-cli/src/data/credentials_docker/network2/membership.json @@ -1 +1 @@ -{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUar7AQ9tuF+EnYEV5NzojPETw1B0wCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTM2MDcyNjA1NDgwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHX4bYZ98sCjpCzBsmiW6j42Q\nQkB+dpDkS5IhblsJT8wesFf4EpkkFdR0utBgdL27UmbmmoTHh6P2AWwAtg6UTqNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFLnEbQNd9VY+cDmSDvzqxI0cKJnxMAoGCCqGSM49BAMCA0cAMEQCICqeGasMewgQ\nbm3A30b/VARhu853QV7MeWbVi5J0lYE7AiAIGm0t947c/hKmiqG+JiU8hlsZzA73\nBbhDFXqROY1Q+g==\n-----END CERTIFICATE-----\n"}},"securityDomain":"network2"} \ No newline at end of file +{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUaRllBApd/UVhTSw9k4cCNqGfyWEwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTM3MDczMTA2MDQwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEr6IYnwH5QCqxy9F3i1x77rLD\nWG3EjMsD16528Q5N8BVStH5A89XeXLrALrAFxvgF5zlFriMRtQMrCxy0pZzJPaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFPwe1LrNuI33Vm+EdgO/E/jJihU1MAoGCCqGSM49BAMCA0gAMEUCIQDPHTMu/Hx1\nqm/G090dqV0215wZQ0Dl7al5TlSrrhftfgIge5QZxYKUsUkptToiOnRJY5pD/Oc+\nF9RBKXnii85zCnI=\n-----END CERTIFICATE-----\n"}},"securityDomain":"network2"} \ No newline at end of file diff --git a/samples/fabric/fabric-cli/src/wallet-network1/user1.id b/samples/fabric/fabric-cli/src/wallet-network1/user1.id index 6107739f7..924c4007b 100644 --- a/samples/fabric/fabric-cli/src/wallet-network1/user1.id +++ b/samples/fabric/fabric-cli/src/wallet-network1/user1.id @@ -1 +1 @@ -{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIICRjCCAe2gAwIBAgIUBMI+vcDI6Z/4bMZN2Cjp6vAXDtgwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDkwNzA5MTQwMFoXDTIyMDkwNzA5MTkwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABFoZaE1MsLtrLRYFzJRyj5uelfL/Fa5pLN2kiO+M5tnxf0+wAotEeC8z\nLCS1KHVIQ7UJD/AOL1OFkbJCHKSdFJGjgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFPzrPjhbfwF/wxP8iFKy4NspQw0uMB8GA1Ud\nIwQYMBaAFHKG9YL6OC86y5FIXpqte7bOXSD8MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0cAMEQCIDP8WLlE4btz\niw6tI/EFdLY/CSOW1P8bOFquaz5YwjYhAiBxEKH6+udDehvHU+wmRaC/Kp1VJNJZ\ndbjNTs65n8zfbQ==\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgdSo5uIgF2yX79LXZ\r\nmP1USII6QeIYwfNCUQvo0rtKkZyhRANCAARaGWhNTLC7ay0WBcyUco+bnpXy/xWu\r\naSzdpIjvjObZ8X9PsAKLRHgvMywktSh1SEO1CQ/wDi9ThZGyQhyknRSR\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file +{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUNtt5srTRKRumyRD/O2FFoOImcjkwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABJ+cH+YyJCTeAyOXaIdNMFUYwKqUjClxSlEcHObedbmofV+WluvdkCsf\nWyv72JliZEm0HngxkkumIOxir0VBW4KjgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFN6zn3QTE1IuXKG2rnGCUuhkP2rIMB8GA1Ud\nIwQYMBaAFCoR1JlvfQXesApniUWtci1cXiOMMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQCpVjfnmEM7\nFHK9UX2j1+a25IFD5/p62CljJRQgnLUWXwIgBOKluTSOICeQ3FWx8+5+ZWrYL2wn\nPL3qORlNthH+Vrc=\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg3o4KcLGfi9C/XYd8\r\nE0sc/oKd2/jf+qhHQ1a62mHq+EyhRANCAASfnB/mMiQk3gMjl2iHTTBVGMCqlIwp\r\ncUpRHBzm3nW5qH1flpbr3ZArH1sr+9iZYmRJtB54MZJLpiDsYq9FQVuC\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file diff --git a/samples/fabric/fabric-cli/src/wallet-network2/user1.id b/samples/fabric/fabric-cli/src/wallet-network2/user1.id index 618cde0c8..7b1f6c586 100644 --- a/samples/fabric/fabric-cli/src/wallet-network2/user1.id +++ b/samples/fabric/fabric-cli/src/wallet-network2/user1.id @@ -1 +1 @@ -{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUGvDSMG39o7baaCZKihlM/Udlx5YwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDkwNzA5MTcwMFoXDTIyMDkwNzA5MjIwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABFZDosCNi+A6D4b4dDrt5aGw0PB7fRT0p4hgTnqk1UWf52U8jOIXgk+t\nWFzICJ0Ltc6iZWEKdeIu6UzK/Q2etE6jgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFC2PFn4siCLGXl//tdAGTIJeUeJ1MB8GA1Ud\nIwQYMBaAFLnEbQNd9VY+cDmSDvzqxI0cKJnxMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQCDa9yllzfE\nGko3C/H8ZxSJwe1e6IgWLnsUIN9Ecx3+pQIgPIu/E0vlwcjguL5xjb6iAJFsqe1V\nR99IpF9SoUQ5CjM=\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgr8a9bNfLU9/NK3fN\r\npXmjyqQeLr6S7sdEX/wLpski4P6hRANCAARWQ6LAjYvgOg+G+HQ67eWhsNDwe30U\r\n9KeIYE56pNVFn+dlPIziF4JPrVhcyAidC7XOomVhCnXiLulMyv0NnrRO\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file +{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIICRjCCAe2gAwIBAgIURRRCdbZ63i59M3w68P5I25rz2LAwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABNOgoRbrgtfXxqa/mbBQNmyx1PIXLAuaMWpqAIu1Lw1LM28tJthOJqXU\nz6EwHLGeLlbvSET6xmoXrgIvBB1ZwG6jgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFMsXP7BjMsmfUuKfueUsrY74pX0GMB8GA1Ud\nIwQYMBaAFPwe1LrNuI33Vm+EdgO/E/jJihU1MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0cAMEQCIBB/681WfBR+\nQWIGfiYKOk3HuRtO8JFwbTiEjnAgCRvnAiBa69wWYaZ25ZR+Gay69eV+vDZkPMHS\ngdRjAItcKGstFg==\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgY++YAA3V0++Z3IFs\r\n+khIphLS3JI5hf+N1VhJTcw3Pk6hRANCAATToKEW64LX18amv5mwUDZssdTyFywL\r\nmjFqagCLtS8NSzNvLSbYTial1M+hMByxni5W70hE+sZqF64CLwQdWcBu\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file diff --git a/tests/network-setups/fabric/dev/Makefile b/tests/network-setups/fabric/dev/Makefile index ceeedbc5f..058f8524a 100644 --- a/tests/network-setups/fabric/dev/Makefile +++ b/tests/network-setups/fabric/dev/Makefile @@ -134,3 +134,47 @@ clean: remove +rm .fabric-setup || true +chmod -R 755 ../shared/chaincode/interop +rm -rf ../shared/chaincode/* + +chmod-artifacts: + sudo chmod 644 ../shared/network1/fabric-ca/ordererOrg/msp/keystore/* + sudo chmod 644 ../shared/network1/fabric-ca/org1/msp/keystore/* + sudo chmod 644 ../shared/network2/fabric-ca/ordererOrg/msp/keystore/* + sudo chmod 644 ../shared/network2/fabric-ca/org1/msp/keystore/* + +docker-ccp: + (cd ../shared/network1/peerOrganizations/org1.network1.com && \ + cp connection-org1.json connection-org1.docker.json && \ + sed -i'.bkp' -e 27' s/localhost/peer0.org1.network1.com/' connection-org1.docker.json && \ + sed -i'.bkp' -e 39' s/localhost/ca.org1.network1.com/' connection-org1.docker.json && \ + rm -rf connection-org1.docker.json.bkp) + (cd ../shared/network2/peerOrganizations/org1.network2.com && \ + cp connection-org1.json connection-org1.docker.json && \ + sed -i'.bkp' -e 27' s/localhost/peer0.org1.network2.com/' connection-org1.docker.json && \ + sed -i'.bkp' -e 39' s/localhost/ca.org1.network2.com/' connection-org1.docker.json && \ + rm -rf connection-org1.docker.json.bkp) + + +backup-network1: + cp -r ../shared/network1/ordererOrganizations ../network-artifacts/network1/ + cp -r ../shared/network1/peerOrganizations ../network-artifacts/network1/ + cp ../shared/network1/system-genesis-block/genesis.block ../network-artifacts/network1/system-genesis-block/ + cp -r ../shared/network1/channel-artifacts ../network-artifacts/network1/ + cp -r ../shared/network1/fabric-ca/ordererOrg ../network-artifacts/network1/fabric-ca + cp -r ../shared/network1/fabric-ca/org1 ../network-artifacts/network1/fabric-ca + rm ../network-artifacts/network1/fabric-ca/ordererOrg/fabric-ca-server-config.yaml ../network-artifacts/network1/fabric-ca/org1/fabric-ca-server-config.yaml + +backup-network2: + cp -r ../shared/network2/ordererOrganizations ../network-artifacts/network2/ + cp -r ../shared/network2/peerOrganizations ../network-artifacts/network2/ + cp ../shared/network2/system-genesis-block/genesis.block ../network-artifacts/network2/system-genesis-block/ + cp -r ../shared/network2/channel-artifacts ../network-artifacts/network2/ + cp -r ../shared/network2/fabric-ca/ordererOrg ../network-artifacts/network2/fabric-ca + cp -r ../shared/network2/fabric-ca/org1 ../network-artifacts/network2/fabric-ca + rm ../network-artifacts/network2/fabric-ca/ordererOrg/fabric-ca-server-config.yaml ../network-artifacts/network2/fabric-ca/org1/fabric-ca-server-config.yaml + +backup: backup-network1 backup-network2 + +delete-artifacts: + (cd ../network-artifacts/network1 && rm -rf ordererOrganizations peerOrganizations system-genesis-block/* channel-artifacts fabric-ca/ordererOrg fabric-ca/org1) + (cd ../network-artifacts/network2 && rm -rf ordererOrganizations peerOrganizations system-genesis-block/* channel-artifacts fabric-ca/ordererOrg fabric-ca/org1) + diff --git a/tests/network-setups/fabric/network-artifacts/network1/channel-artifacts/Org1MSPanchors.tx b/tests/network-setups/fabric/network-artifacts/network1/channel-artifacts/Org1MSPanchors.tx index b8f16d23f0fe41772913c9bced5060693340d33e..769324a78098c6fe1bd63b5a3bf8415d1c319d6d 100644 GIT binary patch delta 34 qcmdnVw3A7IYa0`nIF~2~lN1}r!Xs;^PZaQ+%)zKRF_U*<|0)2MQwih% delta 34 qcmdnVw3A7IYa0`nIF~2~lN1}rhh=>o69qgc7RgR#XOx`SzX|}EX9@2B diff --git a/tests/network-setups/fabric/network-artifacts/network1/channel-artifacts/mychannel.block b/tests/network-setups/fabric/network-artifacts/network1/channel-artifacts/mychannel.block index ca59ff50101257990a2b35838e79f5c837662d93..55d2bc4a86a16c4bfc0cfbb720e5fde56c9ba39a 100644 GIT binary patch literal 17129 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 Lhn4}@GkO0ne;)Rt literal 17138 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 KWdIIL?*9ueMARYx diff --git a/tests/network-setups/fabric/network-artifacts/network1/channel-artifacts/mychannel.tx b/tests/network-setups/fabric/network-artifacts/network1/channel-artifacts/mychannel.tx index 1fa91628001e24f2d07e6f4cfbd73fc4c76b72ac..4b40f322cb5233d80b67d780ca2c641ee3676486 100644 GIT binary patch delta 35 rcmZ3=yp&mhYY{V-IF~2~lN1}r!Xs;^PZXFlIg(Lf;)=DCD;aeFqX7z( delta 34 qcmZ3=yp&mhYY{V-IF~2~lN1}rhh=>o69wi>ys&cO3YE!~j5+|K77Ggi diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/IssuerPublicKey index b35c28f7ef8348f469f1d0dbd110f08e11d44a32..15c01b255288251fd71275c0fe0d801c04e38886 100644 GIT binary patch delta 810 zcmV+_1J(S?2FnJJE`PZSMQQxLs9~ALH~f`2Cbx#&Tc>OB28FBX(5b3dLa!1awS4iw zJ>U}PwvbB(U40%=&8^DGznF|)nfpZdA=s|F8bk^p1oj=?CB>ynbSYk$Z^{YyZ{m!b zh$5z!8hUEO1h<8M5+L!HQQJXY{EwmO(XO#kl&ZiYu+xNrXMd?aMejMWH0N9*L<%4+ zCVO{dXAhv08!qT+*~u0nY=2dB+qt=(j)Np@s@s1OAg0nzO1Dac!7-_lbEwd(6I~t= z?D~!uJdv;cMbH(0Dk4M*ASr>+HybgC@8}G2X2W2n;66_o}1f=muqv^b#Oz z@B9O!tHMiZb$@!hBcEi$k40@kHO+T9f6tq0>LpP*B18%xiHR;rXUUIsl+{%}_fsXP zdbzD=H;1@yrt5IkKn+gw5+HIU)$woB;We^_9Ntuzm5Rm(B?U*uELLl#3hwLZPxK;0 z3LxKa%#c;}4hKOtZvc08spM>bg29y0oH-N`ow!H`rGNYqAVTCCxwUy8d@H5m?c{&> z(!@H8*bPW2)+9(vKnh{Eq$-F33LwArz~Q`GgOD6oFZirJPGY0I7}dP&>vj+8X)W3=(k^@D7gxI`$v1j z(-Osj)PE|xU=I1WJP$3WBF0K0AZ=nxL0ui^%Vs4mlG>C+InfEA&9p)^7C}Y;(0F12 zeKJG}Ag9=T>{lZG;{l4mv4YjUpC-;WK8<-}y@0hF3vaPgY!V=e2J%)w+LhkK&4xZx zX}_~d^-^z3r%PU{jZK6%T@4R9L<%6g4^+T-rhf}!{GAYe?@bYP(J-QbQ9GokBDk-s zT-BN>5+Hw#g|X?o3*_zxeZ?0rdH4EWby1jKWZl1I3xCLn6K+Bvz|i~d3Z`{}F9fZQ zedh++9Xz~!tFM+CL>S%K1l#8uN+8p~eWxQc>8;1UPHo0Ag4og{LX(TDp$VIG2OoeX oZzG3NAhN%`ZvQjvip%SovAxQbviV2P-J<$}}l4W!b6vH$=8 delta 810 zcmV+_1J(S?2FnJJE`R%2C;{FBqxeDP=;!II;tIY=BbNb7vUuk>wj}~`qG}Q#-_vQk z+bg2A^_MDAQN96i#bBjIxm{@f~6E7;zFpL zqV6wtkG&~^*QAx#J0e61Aiq0G{Y%Q>-(9*v3m;h2%B~6N`;QlwdnTN{=KwSP7KexnesbSEDd%|2YG|15nQg>XhvB18%xUY|dRREVMOzWY+#GN8;o z>%Brd(v!AxTH+jRQ)28*$JedL9n$BiHESyc#Vx9?G7K1!Pqq-+#*zAjzZVNR;!G-D371#6SQB znK+%U=hUg2Js}4YE`6`G33LwIUba9A!hL|10mV10)71SZYdq+u${R950^pF;s zqd^iNNYk0gVVL9tol_+JQ5UTQNwbXAKKTWK<>dp*dIF?>8X)5!w6)>l!>l?W7$OST z>FAHj*?*m*&V>hT2^X~f(?NA2APR!Ca7c!@8&&-h+ExIdENb$B-Ct=I-h@3ItN4=- zWHLkwAnAgb9)+Hi3yBUJVvdB`do?uxLZ~EGJxVPpKmGs+rV=2ay=h~r&@rgD(jEMv zCP`leYL<%4deP7xY;(xDV1p#sOw}=RCG$Qlp^k}UnRAALA zzEG9P5+H_3aK`%m2k*14w{TcQM?@uIOk1`^MXvIJ_@3NEWTQeLuzcX*Z77~qFs5Dx z7Z9&=H1Z4NjxR4ZTW_^MXZjZIN+1oY-~Aoa-Imv_RASrw-Uyvjs*#+%$OigsJRp>%R0fk&AR0g!X_01)xr9h^0mH+?% diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/IssuerRevocationPublicKey index dc4c6f6fb..7ef9db090 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/IssuerRevocationPublicKey +++ b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/IssuerRevocationPublicKey @@ -1,5 +1,5 @@ -----BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEKJ7KBEAeS+e6lPUS3eCgZiImNpXJ2R0c -rVb28F2tYtczCf1dg7MFLDFaL4AieRATNZxAtHXOoo4smc+DCGHeFOB8IIEL8sHG -fUrGj43x0eFV16Our2mt1DzRhScQ/bCV +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEkglrbl6Llw5yDS3ARDs0tli8HpKvfaB3 +UESim8WHqjt/y67VHVtzvLE2uNI0/+5gFys0Qwwbz688O1qazwzCIOg05vtl0AnR +f3UvZhMWhBllNwb14aWJl5Am89Zcm+Bb -----END PUBLIC KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/ca-cert.pem b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/ca-cert.pem index 6d1103342..44fad8ac2 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/ca-cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/ca-cert.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFjCCAb2gAwIBAgIURwEWXKViiCnfztwadQU0Xv3sV/MwCgYIKoZIzj0EAwIw +MIICFzCCAb2gAwIBAgIUMSokEmwIGLStVW15f5Vk/pmJ8bEwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTM2MDcyNjA1NDYwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEENQJSbn/q+iNKSDsVp0kx9bR -AAd9slqL8odhUGAL5/UOwhTqTI3YKVyUJLyx7PE6G0qZjdHWffa28xCSdN0GpqNF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIW3OjyOU3HkXNUKfcRXwIxEd +NCaVdaZikxSsAXtWK4755DpN+DlJwMmFj6CkdOyh6+L0BLH0gybH0TM2xAw/eaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FD6tYQP/qhHd7hPK0db/ZnRDP4Y0MAoGCCqGSM49BAMCA0cAMEQCIAIPEZGutxkq -HnTrmpt16WEyl+R0cFnxVWHoP/mN2zxiAiBU7WwaDXCAQf9jiXGk3rCqF4KBjiXI -G/SqmgUTqBvo0g== +FGwHRYYRsEzEMSWQLUR/FRW4Q9M1MAoGCCqGSM49BAMCA0gAMEUCIQDlwQ5K7yM+ +bbYz10jGDbwuXuD2azQPphoZ32Lg1uA9fgIgf2XzZtvLHY2bB/PEJPbHCpLq+bst +X6bmPz2oSrn1tRc= -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/fabric-ca-server.db b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/fabric-ca-server.db index 42e44281c83d28968dda5e52b1ce80d47c59e444..60c4084b91214e58c5232e1a3f0605d7de74d894 100644 GIT binary patch literal 61440 zcmeI4OKjsvdVnR%k2c%gnwd<)Gnk8}XB%j*y4xg0y#`oxNQsgtiIPaY6*LTrq)1An zD3g>ZX|V}BGr>-Po!wv$dkS*NB|#7%#~gwj76@|7B?vG9atM%14ndCDAURBmvTRFk zySIDL-oYA0+fuP!too|zub)-*yUG_m>F2`_ArH!L6OI?|*&|z4KG= z=ei7_KO_JNKmw4!ts-#8@C*A-pZdQr9igksqHH-@PZI@4wvS9*x_rNt;%Tx*hiW8M zq(cuc2R{rw)}&B_3>ic= zMo&VPJTV8dbOdJC72lC;T+T+9C*VO$sYYjMK9r_2WW87mp-(~;o?%J89V*c6$7{8^ zz8(h$C+`J!_8&d+pC}8!La(Rkn&4>W&|Y=lUjw@u5_&uo4EY=?hT_D*Il)l9#Bg=` zNoZurfZ%$pC!uSqa&YG#d>?zQegfElR$qOb*Xlwq{@(U};gR2`4JCPMAL~FhIRb5E zF7A)knjKrc+uZvzAL9*>=UdzR)u*qO0eIliS|(l*wtskcXaD1m{U_w2gd@uwd0kVs zFI;!9f_=-hck#b(J_R z#1VG-efOk#XJ`NUbN^@2Md7`{0)znQrCzfyhp09L+Ua!xyK7avHd^ShJTgV~YI*Lw`QRYBv%SxJa$V0@AppkZ1*bdr z|JL`FC(6DM7ky-P+^@RV=ZMviD}b)a(aYd2y57sP!)KLu7jpI26eh6VxGU4!+bqoL zly+mSedAMA{GC?`{k2H~TfOt%O;3e>;8j9@HHjzUkJd8rd^S&}_jmU9_x+!j7d>nY zdWXIE*jQ`Eh1V7B=YR=*80yX(S$Gn1W~0l(ex(HKf)`BSj$>)vF;II#HM&(hRWVj1 zQpgadNAl1zb=?3;ioGJMu2UDZp=er`EILOc!M0t~@^lYJHbxhzFSLt;d-uNb1@8Xb zcmKzCf4=wCtq?(!6UV^L9a+HD{(o;m_*r!n0@j;_;l(%vKdky6k{#L`S)16%*9HejKfr zgk=`L_rr(YlHS8lAF91)^!YmllYaQ*;bM≱>1pT(N&!%rP+EdS`qYRVdT!FjV3 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 literal 61440 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 J!@;@&_J1a>X14$U diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/397c85579ed7ffcec218676697c9b9083b64b4b46e327d36f94e16f8ad46f204_sk b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/397c85579ed7ffcec218676697c9b9083b64b4b46e327d36f94e16f8ad46f204_sk new file mode 100644 index 000000000..295d2fdc8 --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/397c85579ed7ffcec218676697c9b9083b64b4b46e327d36f94e16f8ad46f204_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg2PZimGmj5xw/Ql4A ++qv5cIt4biXy6zcZ6vHo0R4kIimhRANCAAQuDLeYJhoKkNqhAWWJao6XMB+JyiJg +9E0q0IjrCmvOTVheNu/6nyZGGGNrI+2b3X+cbdoVKeXJtlPeL5jLrWd/ +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/6d26b02a002fb3081c443b1f8e4ff06c983cc896e5552c9e0c0f766aa5476755_sk b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/6d26b02a002fb3081c443b1f8e4ff06c983cc896e5552c9e0c0f766aa5476755_sk new file mode 100644 index 000000000..71d9e07b3 --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/6d26b02a002fb3081c443b1f8e4ff06c983cc896e5552c9e0c0f766aa5476755_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgDoD9mbCn3exf2LUv +Qm+vXm2Wwl11i2Wjpc6HxJaWsjyhRANCAAQhbc6PI5TceRc1Qp9xFfAjER00JpV1 +pmKTFKwBe1YrjvnkOk34OUnAyYWPoKR07KHr4vQEsfSDJsfRMzbEDD95 +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/94255e346295ca5a0e3bb32e7f83ae4cd3c985349a51610e6f9a35e930ea11eb_sk b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/94255e346295ca5a0e3bb32e7f83ae4cd3c985349a51610e6f9a35e930ea11eb_sk deleted file mode 100644 index a3201eced..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/94255e346295ca5a0e3bb32e7f83ae4cd3c985349a51610e6f9a35e930ea11eb_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgHZ/Dyhppx5rHx499 -4V8fFFTaoXnb1kiOW8zhF7a4g6ehRANCAARzCbbWKbFe+lv9NgJwg0ugs/BlRiRD -NU5jPcrp3O0gy2uDrGXI4VWRlO/SYtLlWTYKnPGru6ryOVMWVJfxwKMl ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/IssuerRevocationPrivateKey b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/IssuerRevocationPrivateKey index 0a6eb603c..e64f0f991 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/IssuerRevocationPrivateKey +++ b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/IssuerRevocationPrivateKey @@ -1,6 +1,6 @@ -----BEGIN PRIVATE KEY----- -MIGkAgEBBDBltYeYkxoPTO+z+pAYOyRAWb05XjiF9PoOOzlCISHyCY0dvjd8hspQ -ESqtHYwDEUOgBwYFK4EEACKhZANiAAQonsoEQB5L57qU9RLd4KBmIiY2lcnZHRyt -VvbwXa1i1zMJ/V2DswUsMVovgCJ5EBM1nEC0dc6ijiyZz4MIYd4U4HwggQvywcZ9 -SsaPjfHR4VXXo66vaa3UPNGFJxD9sJU= +MIGkAgEBBDBhu3eNtA6ZI0yd4VCnuUhcbCDs6ScjhZIUPQy0D9YDYkVq5mg8FKGq +vOb4ll8vEJ2gBwYFK4EEACKhZANiAASSCWtuXouXDnINLcBEOzS2WLwekq99oHdQ +RKKbxYeqO3/LrtUdW3O8sTa40jT/7mAXKzRDDBvPrzw7WprPDMIg6DTm+2XQCdF/ +dS9mExaEGWU3BvXhpYmXkCbz1lyb4Fs= -----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/IssuerSecretKey b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/IssuerSecretKey index c5c72fc1c..4995ae62c 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/IssuerSecretKey +++ b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/IssuerSecretKey @@ -1 +1 @@ - š;›H#—SuFê=5’`z+Ñ!dÆÙ —gíÇNâEç& \ No newline at end of file +~ÇÃÓûýß‹ÖÐÖ¥`‘Oø`"ÅòÜó'  Ò‚ò0ñC \ No newline at end of file diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/d43d8da7496c8f02d534cd58cd4ae87f718c65ca2ca3832c72423a3802b68c66_sk b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/d43d8da7496c8f02d534cd58cd4ae87f718c65ca2ca3832c72423a3802b68c66_sk deleted file mode 100644 index da16c2437..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/d43d8da7496c8f02d534cd58cd4ae87f718c65ca2ca3832c72423a3802b68c66_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg3TVdc2rHUCPnlQZk -V1KAmi+t6SZY6GP8KDlp2JGC1ZahRANCAAQQ1AlJuf+r6I0pIOxWnSTH1tEAB32y -Wovyh2FQYAvn9Q7CFOpMjdgpXJQkvLHs8TobSpmN0dZ99rbzEJJ03Qam ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/tls-cert.pem b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/tls-cert.pem index f5a8d9605..71ba6e4bd 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/tls-cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/tls-cert.pem @@ -1,16 +1,16 @@ -----BEGIN CERTIFICATE----- -MIICczCCAhmgAwIBAgIUJIE7EnBqOt7qnfjQQHIiWHu1ng4wCgYIKoZIzj0EAwIw +MIICcjCCAhmgAwIBAgIUOpnMv5vB6JvnOhXdQ4blHsBNyuIwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTIyMDczMDA1NDYwMFowZDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTIzMDgwNDA2MDIwMFowZDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl -cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRUwEwYDVQQDEwxmNTg2ZjdiY2JhNTQw -WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARzCbbWKbFe+lv9NgJwg0ugs/BlRiRD -NU5jPcrp3O0gy2uDrGXI4VWRlO/SYtLlWTYKnPGru6ryOVMWVJfxwKMlo4GkMIGh +cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRUwEwYDVQQDEww2ZGYwMjY1NWZmZDEw +WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQuDLeYJhoKkNqhAWWJao6XMB+JyiJg +9E0q0IjrCmvOTVheNu/6nyZGGGNrI+2b3X+cbdoVKeXJtlPeL5jLrWd/o4GkMIGh MA4GA1UdDwEB/wQEAwIDqDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw -DAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUHjIHH1YdUklBfock8aDBw4F4ilYwHwYD -VR0jBBgwFoAUPq1hA/+qEd3uE8rR1v9mdEM/hjQwIgYDVR0RBBswGYIMZjU4NmY3 -YmNiYTU0gglsb2NhbGhvc3QwCgYIKoZIzj0EAwIDSAAwRQIhALC6HyJ1GV8Lzj4A -0AwCWUfbtUAL2ymf20KbqTaleWHxAiBRpWMUE4kynCuGiqMbHER6yypD+6U/jC4H -nN25HMjQTQ== +DAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUPgcKZtxWmeKy1jUZyUX7tFm7E/swHwYD +VR0jBBgwFoAUbAdFhhGwTMQxJZAtRH8VFbhD0zUwIgYDVR0RBBswGYIMZjU4NmY3 +YmNiYTU0gglsb2NhbGhvc3QwCgYIKoZIzj0EAwIDRwAwRAIgRM8T2DATd/oa9IMn +vC314JYP3L2HPyY2puszol2b/TQCIAgrBqwQX1agPuT7XA7izuplvDRazOn2z6Ls +EcSE5SG2 -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/IssuerPublicKey index 2acebf637bbdfb644bec49d966c99ce34ebb12b4..e4e39a4683359596c3c6a9ef67aed4995c58c786 100644 GIT binary patch delta 810 zcmV+_1J(S?2FnJJE`Q!2;V{_*FQmi?(B>(|!m*0`grhGnnM*iBF}5Q1n7I-lT%rbj zqM!wLuOz{!YRK-)(;uAb%9h2jlsjm-eTq^w8bk^pE7ObR5+D_=KO@xEb{8E*gdKb8MooJ1MM(%-e}B(MD38sIZ1=VzL<%74 z;X+1Q^4M(D0+zGL7J&pGs(N7MA1{SHdKpIdNsf~eApD>`?Ax}u^fxQdUCQ-@v9WV+ z^^!a5NW)>|;=X1pa3VwsAoVY>xeHcgsr;1#mn_2Zi(P&xeB&!x5zE6=hH#aP^b#O| z1G5OGhJ0yNL4S@-LUf79)-0`}_B&|~xOO|6bzr=HB18%x1sF-66GQaHW+t;7yq?Ib zO+UfOxP#6w(DOvfF`49$5+In1y8$FQUSbM$Qsj2W`iA-&T02aIB2^_8X+|K2^B*Ea z3Lvz7BttU%w}vMLj#39++f?~eAZN^_Q?nFwMB~8W$A2XfATJIGK^hR8EBx8jd^|e2 z+_GFq&`%hC1$vI+$U8~tFDi%u3Lqom7zLoYM0n0&8m~n7&1kP!uomSC*1DQM(Dt;D z<>V3|B6~&9tPJt_v8|xO{-2|=YKRRel0Teekckw+TC78H8X)8ut|-s&uYX8att8IQ zD>dY|CVygZl9c{Ky{^|)!zD)|AiSVZxGLs5d_X8B7|4*weDPwUtMT666P`IB7~rDQ z%rZm@AZg*}P;zV9CAoV$;r{_!`u7a&FRp>8#s3EaAOFi*EfOHYCeDDtdDD6hKc4nFL<%6`a0J^OJ%7Qld0NS~87i9&rq6^*PXBx<6_|iLu7s%8bk^p1k137>DDvPwJg`wMt<}qKqL0E zcV~lionsJ@xtE>O5+J*0*Pf(iIVp>H&MZ<4@*tEyG5EDb=zlI!T>%`u_5F1sL<%6a zwdqONiEy6MOhn5OVW-UE@{$R~^NUniM#+a}tUQtuAS&Dz^;PGtziNmiJ9OS#r!X`Q zqlvMZGWK=Gch7~sw@Q82k8@yomXI+xpdbjB18%xh|M?sVfn3+_kB*76geQY z-e?!!SH0IIXNr=DQ%RnM5+J)xgt~EZjV*_O6O)i8gvXv7Mh&-ndckMTxv$$#;8-F= z3LsBG8jju{-36YDMkTZ28@J1)$Y;WGw#f{;f7QoBZGYDiAh!w~aapHSs0zTHCmv45 zSMLA5wOm3j>@;QASZP*5J}QU-3Lsa|YQ_LS)r!9Yz+j^u(RT;l^Lu<#;|z8Cjw;RV zt$7k4v<9g|lzHN{P=H0>n{Su&-@JbcnS)p+-KrvLx| diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/IssuerRevocationPublicKey index 985bbf417..4d36cad18 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/IssuerRevocationPublicKey +++ b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/IssuerRevocationPublicKey @@ -1,5 +1,5 @@ -----BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEdtoEVkZA2hvW7Mv6qT4KPgvn1PY8Y6bg -9crbesbtreIp4GlpXch//H+MazEww9pX02fGEhWOrlbFvlYYK4GqVPjS1lTYwTWI -5/irOyTNdRvkPr6C3CWsbyX3rNnzWSkY +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEfDgje7iiTZQ/7ZljIoyOf+AiYXuvHZUG +CohejruX2TTz0uBIRQeSAh55zvv9628DMOcll0DXUrykdccjUqZBA9uSuYFRaANm +IhqLp7VFNB2gMIFcMLJ5SwexnZoJKdK7 -----END PUBLIC KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/ca-cert.pem b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/ca-cert.pem index 6047e9ae5..3d82333d8 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/ca-cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/ca-cert.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFjCCAb2gAwIBAgIUYyc2soSqUtWVHTOtud7D1FbCHp0wCgYIKoZIzj0EAwIw +MIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTM2MDcyNjA1NDYwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEM/GelSlifY6+rMOE3G95SXF+ -dTHpG8j5cYK82EVCaLCSvNlCKgpupuQnbkLy+V6dgf9tKSnEsZgiHeB6AyJK/6NF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR +ynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FHKG9YL6OC86y5FIXpqte7bOXSD8MAoGCCqGSM49BAMCA0cAMEQCIA9iMqQ/aJiC -a++ft4tN7io83jB17/fzG3BRC9soRR3bAiALgWNYk5118DKTkhFdJVQ0VIoopEtq -Gzi+/j4j7fu/wQ== +FCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq +m2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd +zQkhznMIF4SBF4k= -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/fabric-ca-server.db b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/fabric-ca-server.db index 1663a1734a4a563d0c7f7dad9153610a1a714abc..3a4b5f21c43fe05bbbeffef8f866ef861e4ed8f2 100644 GIT binary patch literal 65536 zcmeI4ON`@4nwT>y>y_-P&Ytl!YUVWRo@uyiRaN3!VgrLR-=ZW+qF$6_7Yclf5-Ca| zB}!TtM)iz$+wjhK_u`8UUyOylFbwQ*4~7p57{1#uFgAQJ;ENB&UJUFSSQz7=@|~4c zUDH$DJ>46uOeGnN=NA$G|108;YHKw=adK|72#q91?7g?QzrXi)a=E>|z3lfr@Oygw zEpT)5^a1?czi|Jm+uYuhr~mc--Ei;TonP*~)4dlU|KRY?k=EgRhd)2Mb?2Aw{`5Y2 z_ZQi}S7iXhApuAL5`YB0RRr#a`^JOEkN1BTC59O|ma|BF*SCzsiJwP-ef9Yk-xAr5 znCq}yP0W3G_4S9jk9|AWV_STgZGDVW)Wb))*je~S@O-)qO=poagUHO)8=YLeTdO_F z8Ovl8E&OEjeBx}L`?fR9ihnttWjqfI(+PIzL7s_`EaR)0EgU0`ra6C_JjyxinZMZN z5OJFa)$$dOELgx%BhT`PI zGlIEpUD3MYqugxa0D_leJ<7eJDG%@d$Gs1-UVj1DfL^~?T-NJ`Tm0_r2i1@E_x!2t ztmAnAOq1uJucF=a^Gn^1U3|KE?_cgI*#vod>-K~8<2T9x6!`p7CRr73|L!|?9(?e@ z{tI?j!`UL5Wkb`6&+qPCLUtaW`}pMk9LMoUTp7Xg93)QBV02#W)6--R9}@R&Kaf9o zRqfA$+JSQ(7#MMK9QNFwKA%O=*?fHEn7#~PSIEPM zpMLN5od-Yq(f&_Qq}#&TNf;xDt@GPEmui0D#Wlk0Lc31td_|yT$*&5OFHLy8(O7t? z$`2n>cWysWe)Ou5ae)Asm*<@BzWeX?ex8Z4pIN&xa&g{YyuYj?F21=2=p{LN72NsI zds#bt+WgK=u6|Bs4lZ}@1@-neD|1n$eQCY@rK_sqd#@Avmy`r{@#zT2`(vSh@H(M? zF-a!kpI^!(3%U7X{qCIy4<79Qw6PmuOE5a(-N%hf-M9<7rvDP4;HNorlQ_nsT(X&6 z74{cua9QvI1)d}e-&_K-C)W}ConsT@f<(%N#`?K4T|_|;0wX29Agf+wF8EU`S}YtZ zc|J4ZIE@yW?U6X)>^$|kb@A{%(44mp*L&~&9`a}R|LC1R0k`mi1Rw!O01|)%AOT1K z68I7beEO4H_a3~s`GdzleR_Dfe|O;o#^%Sk@na1AablBx!DR73tyjx2KPEP{n$_@x z;bPh!@O)FK#ntkY)iR#iy+9&+{zB3lR^S8sFj{!n6Wf^?izG7_vA_GfA7-mKAAa)T zu7D38eYjhU0ME%{>43-G%G-yZWKVzp(OKk?`$RmmIThhTveRr{nXUuO-wW}NtM$5q z*z=XC3+b*l9Zg45M1xcG^U3Mzea{-|RAYlUARVcBNvkYxyqo*TsLcrvK^&n0&Dxc(>0;TL@~s*meJTO54=+o+ zmgD(xvM?4;*t0L?7oz{pmFO2nuj*w}{PXi|MS&Avh

3^BM?F;CNs&;Ybo03`6$6Zp&q;{VyR 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 diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/5dfbce629e275090ced3e2e678a53afd1a529b416f42db95e8592bb820633e3e_sk b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/5dfbce629e275090ced3e2e678a53afd1a529b416f42db95e8592bb820633e3e_sk deleted file mode 100644 index c1219bd06..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/5dfbce629e275090ced3e2e678a53afd1a529b416f42db95e8592bb820633e3e_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgYubxseYFdkIAtpQE -nDaomhAGt+Qke3sjCIMKwZG8PvmhRANCAAR2rpGI0ewWeP+c9fE0ThyrYieh1Jbi -1UkMx55h9wK+UDU1JpojwT9yehUB0lH/AkIpOyXEg8FMNIlGMa//zswG ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/82bb24244d4f7bcbffb96a71c4c4c1ebb56d3fa0b0ac8a34e2943beeff243edd_sk b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/82bb24244d4f7bcbffb96a71c4c4c1ebb56d3fa0b0ac8a34e2943beeff243edd_sk new file mode 100644 index 000000000..7f3a7aedc --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/82bb24244d4f7bcbffb96a71c4c4c1ebb56d3fa0b0ac8a34e2943beeff243edd_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgTtGRAknCc308yJ4X +MLwSJpMkGwN0AsvM6Rq25r9rjyGhRANCAASmf1fHM5MTdAPQbqrmL10SdtHKdPpf +lhoVUTACx2BDKVgrsxuaaWRLZkcE/hCLmSt/5nDP3JTrNgA+oRkJ6YsV +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/IssuerRevocationPrivateKey b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/IssuerRevocationPrivateKey index d39577e51..d30106489 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/IssuerRevocationPrivateKey +++ b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/IssuerRevocationPrivateKey @@ -1,6 +1,6 @@ -----BEGIN PRIVATE KEY----- -MIGkAgEBBDA26NPpOGmZlL7ShRPXGHeLYkXZ1TzCN8WDE2BZmb3kVKengVU0yhr9 -lCKBLlMXURegBwYFK4EEACKhZANiAAR22gRWRkDaG9bsy/qpPgo+C+fU9jxjpuD1 -ytt6xu2t4ingaWldyH/8f4xrMTDD2lfTZ8YSFY6uVsW+VhgrgapU+NLWVNjBNYjn -+Ks7JM11G+Q+voLcJaxvJfes2fNZKRg= +MIGkAgEBBDD0TtyscuOlTFjRAlZ+vPyeXMvJX0Sl+/2x2j7tq1qwBLttNb/zsuRb +EmV1t9iJGKagBwYFK4EEACKhZANiAAR8OCN7uKJNlD/tmWMijI5/4CJhe68dlQYK +iF6Ou5fZNPPS4EhFB5ICHnnO+/3rbwMw5yWXQNdSvKR1xyNSpkED25K5gVFoA2Yi +GountUU0HaAwgVwwsnlLB7Gdmgkp0rs= -----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/IssuerSecretKey b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/IssuerSecretKey index 39e9cfc97dce560bd19d63b10c93ed17352d8034..8ab58d269f487ae87f82c0a649c8b0303a9bb72f 100644 GIT binary patch literal 32 qcmV+*0N?+uX1lH3Nl3*fvB0m}SB2ENIrhxLZUBC{^l;6wSMInu`V)Kr literal 32 ocmdO3I?_?3{aDtRm7{LC>+Hu5;>6{CMjaH@<4j+3n+a diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/cd392f2c72a2673ecdd5400bf0220190470e56a5318f27e6052850765098f1df_sk b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/cd392f2c72a2673ecdd5400bf0220190470e56a5318f27e6052850765098f1df_sk deleted file mode 100644 index 1319b3a4a..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/cd392f2c72a2673ecdd5400bf0220190470e56a5318f27e6052850765098f1df_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgV+HxMS8DCSEyBUIa -ICvAwY+bU2dBxlP2503TH1K+xwahRANCAAQz8Z6VKWJ9jr6sw4Tcb3lJcX51Mekb -yPlxgrzYRUJosJK82UIqCm6m5CduQvL5Xp2B/20pKcSxmCId4HoDIkr/ ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/e509e7d66bdbd1e7e777acd4c76abf24fa24ec232b8f7844cf8f19730b3504ac_sk b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/e509e7d66bdbd1e7e777acd4c76abf24fa24ec232b8f7844cf8f19730b3504ac_sk new file mode 100644 index 000000000..cd5f9c248 --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/e509e7d66bdbd1e7e777acd4c76abf24fa24ec232b8f7844cf8f19730b3504ac_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg+cQoONl+UyLmTx/z +E/Vw/ZwEYAAUZodYAzdquhGJX6OhRANCAASl3OGXJE472oTSDUEpls9May1/NjEj +tR7UKsksDkwIzC4zQfuMBbICh7y7IObEZOf6Jocln3evQxiwcal6qKfi +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/tls-cert.pem b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/tls-cert.pem index 919dedd51..754c923d2 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/tls-cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/tls-cert.pem @@ -1,16 +1,16 @@ -----BEGIN CERTIFICATE----- -MIICczCCAhmgAwIBAgIUDyxQWKbSONMWISOkWvyo5wMOZJAwCgYIKoZIzj0EAwIw +MIICcjCCAhmgAwIBAgIUIXKV63PP4GV4E+tR28AckDctJG0wCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTIyMDczMDA1NDYwMFowZDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTIzMDgwNDA2MDIwMFowZDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl -cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRUwEwYDVQQDEww2YmJkODk0MzAxNjYw -WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR2rpGI0ewWeP+c9fE0ThyrYieh1Jbi -1UkMx55h9wK+UDU1JpojwT9yehUB0lH/AkIpOyXEg8FMNIlGMa//zswGo4GkMIGh +cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRUwEwYDVQQDEwxhODdiOTg4MmY1Yjgw +WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASl3OGXJE472oTSDUEpls9May1/NjEj +tR7UKsksDkwIzC4zQfuMBbICh7y7IObEZOf6Jocln3evQxiwcal6qKfio4GkMIGh MA4GA1UdDwEB/wQEAwIDqDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw -DAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUS4zjtD/PRYNAHRhU6Th1QhdfXc8wHwYD -VR0jBBgwFoAUcob1gvo4LzrLkUhemq17ts5dIPwwIgYDVR0RBBswGYIMNmJiZDg5 -NDMwMTY2gglsb2NhbGhvc3QwCgYIKoZIzj0EAwIDSAAwRQIhAMN1Bw6fdATd3diB -F1gaj/T7keJUpZYpyMHwwVN0JnvZAiAtS4V7JyhtLwFYMw28XfwleaBJ70RaUP/K -wIz363DCfQ== +DAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU2y2f5N75dHoLvtoHyEgqd3FnCQAwHwYD +VR0jBBgwFoAUKhHUmW99Bd6wCmeJRa1yLVxeI4wwIgYDVR0RBBswGYIMNmJiZDg5 +NDMwMTY2gglsb2NhbGhvc3QwCgYIKoZIzj0EAwIDRwAwRAIgHJt1FU/iOZOvEFK8 +uQy2DfbNLBvaR4XgZGfyjuH6AEwCIFULB108BivuJPuvci5NUxpTtJLNsGzCKW/Q ++7XeDsWx -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/IssuerPublicKey new file mode 100644 index 0000000000000000000000000000000000000000..15c01b255288251fd71275c0fe0d801c04e38886 GIT binary patch literal 843 zcmV-R1GM}K0#8*61X6EoWeN;MZgOvIY;9$3bV)=C5K?7!Z)0I}X>V>wVQyq>WfDXR zAh`-fY5cyZVVTA^{FOK+w}#zYr)%*Bg{$e%sj62(uM!}&eDT0N;1cMzkV^(#eI8NG zt;)&2n2cYU`$YF4*si-8L<%4T_8s0O#idJhDPEax$_e;y;*6V!BBqxbdTPT2w}pQa zAn}(`+d*FZkD=+&uCY;+s=y+!(}aO%sXj&TIk7b7Tp~mYAT1_)cVlM{ppzRe=xN!> z79wnaRdn0Axt@-LBy6hNe-a?3(oRaZN`%2NsgiT3(5n+&9ue&Nju$+Uul+^P6@Mxs zL<%4&fzUS_F^KQz4035-cr`T8_;&~lCd>D#qvGfWWsmd{AZzdZ1EZ_LOKEj_yCa`u z!;eL6K{d^HIe*WaYU(9XIU+;~Ac=`CNoUEAb(GarKKD~4sCv1rXg7zrZ>H;T)j$nS z^AaF(B-Qb6)8RF;g&f{gn3amg2PFkZ#w=EArV8%s=uh+_L<%6^Z_JQY^$rI?Hg5oT zcB$lSe}ci3(VRIH5uLb52c`THAVTCCxwUy8d@H5m?c{&>(!@H8*bPW2)+9(vKnh{E zq$-F33LwArz~Q`GgOD6oFZirJPGY0I7}dP&>vj+8X)W3=(k^@D7gxI`$v1j(-Osj)GEAS4*9n{4=tx6 z#!4a}ZDLD7T^;AkW+g6?+LS~&(Fvfr`UY#S0eu70gAw} zg4MpCCeAiKjd^3efVCS7Z?RKs5+I2N@>W3FmEOe7hCWkizq3m9Qg2JAOJ1stO@udH z4G%g*3Lv`=RKR$q3u6485Pk1W5p~fpqJU95q^Badud7_unkf<>e~pE)>AMT$?gxFv z7chDE`d)QWm|tYwzhw)5$cPheLLk7<`|b*+b%HMht&V-?2HG7wynU;$mKsDD-Pr`& z=Nn2O)4+YFBQxo($G%Q&#xjD~(j!8Xi>sjtn{)>sfF*B-QXsOwy>9:@:/ + # 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: + - f586f7bcba54 + - localhost + 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/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/fabric-ca-server.db b/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/fabric-ca-server.db new file mode 100644 index 0000000000000000000000000000000000000000..60c4084b91214e58c5232e1a3f0605d7de74d894 GIT binary patch literal 61440 zcmeI4OKjsvdVnR%k2c%gnwd<)Gnk8}XB%j*y4xg0y#`oxNQsgtiIPaY6*LTrq)1An zD3g>ZX|V}BGr>-Po!wv$dkS*NB|#7%#~gwj76@|7B?vG9atM%14ndCDAURBmvTRFk zySIDL-oYA0+fuP!too|zub)-*yUG_m>F2`_ArH!L6OI?|*&|z4KG= z=ei7_KO_JNKmw4!ts-#8@C*A-pZdQr9igksqHH-@PZI@4wvS9*x_rNt;%Tx*hiW8M zq(cuc2R{rw)}&B_3>ic= zMo&VPJTV8dbOdJC72lC;T+T+9C*VO$sYYjMK9r_2WW87mp-(~;o?%J89V*c6$7{8^ zz8(h$C+`J!_8&d+pC}8!La(Rkn&4>W&|Y=lUjw@u5_&uo4EY=?hT_D*Il)l9#Bg=` zNoZurfZ%$pC!uSqa&YG#d>?zQegfElR$qOb*Xlwq{@(U};gR2`4JCPMAL~FhIRb5E zF7A)knjKrc+uZvzAL9*>=UdzR)u*qO0eIliS|(l*wtskcXaD1m{U_w2gd@uwd0kVs zFI;!9f_=-hck#b(J_R z#1VG-efOk#XJ`NUbN^@2Md7`{0)znQrCzfyhp09L+Ua!xyK7avHd^ShJTgV~YI*Lw`QRYBv%SxJa$V0@AppkZ1*bdr z|JL`FC(6DM7ky-P+^@RV=ZMviD}b)a(aYd2y57sP!)KLu7jpI26eh6VxGU4!+bqoL zly+mSedAMA{GC?`{k2H~TfOt%O;3e>;8j9@HHjzUkJd8rd^S&}_jmU9_x+!j7d>nY zdWXIE*jQ`Eh1V7B=YR=*80yX(S$Gn1W~0l(ex(HKf)`BSj$>)vF;II#HM&(hRWVj1 zQpgadNAl1zb=?3;ioGJMu2UDZp=er`EILOc!M0t~@^lYJHbxhzFSLt;d-uNb1@8Xb zcmKzCf4=wCtq?(!6UV^L9a+HD{(o;m_*r!n0@j;_;l(%vKdky6k{#L`S)16%*9HejKfr zgk=`L_rr(YlHS8lAF91)^!YmllYaQ*;bM≱>1pT(N&!%rP+EdS`qYRVdT!FjV3 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 literal 0 HcmV?d00001 diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/397c85579ed7ffcec218676697c9b9083b64b4b46e327d36f94e16f8ad46f204_sk b/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/397c85579ed7ffcec218676697c9b9083b64b4b46e327d36f94e16f8ad46f204_sk new file mode 100644 index 000000000..295d2fdc8 --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/397c85579ed7ffcec218676697c9b9083b64b4b46e327d36f94e16f8ad46f204_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg2PZimGmj5xw/Ql4A ++qv5cIt4biXy6zcZ6vHo0R4kIimhRANCAAQuDLeYJhoKkNqhAWWJao6XMB+JyiJg +9E0q0IjrCmvOTVheNu/6nyZGGGNrI+2b3X+cbdoVKeXJtlPeL5jLrWd/ +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/6d26b02a002fb3081c443b1f8e4ff06c983cc896e5552c9e0c0f766aa5476755_sk b/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/6d26b02a002fb3081c443b1f8e4ff06c983cc896e5552c9e0c0f766aa5476755_sk new file mode 100644 index 000000000..71d9e07b3 --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/6d26b02a002fb3081c443b1f8e4ff06c983cc896e5552c9e0c0f766aa5476755_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgDoD9mbCn3exf2LUv +Qm+vXm2Wwl11i2Wjpc6HxJaWsjyhRANCAAQhbc6PI5TceRc1Qp9xFfAjER00JpV1 +pmKTFKwBe1YrjvnkOk34OUnAyYWPoKR07KHr4vQEsfSDJsfRMzbEDD95 +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/IssuerRevocationPrivateKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/IssuerRevocationPrivateKey new file mode 100644 index 000000000..e64f0f991 --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/IssuerRevocationPrivateKey @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIGkAgEBBDBhu3eNtA6ZI0yd4VCnuUhcbCDs6ScjhZIUPQy0D9YDYkVq5mg8FKGq +vOb4ll8vEJ2gBwYFK4EEACKhZANiAASSCWtuXouXDnINLcBEOzS2WLwekq99oHdQ +RKKbxYeqO3/LrtUdW3O8sTa40jT/7mAXKzRDDBvPrzw7WprPDMIg6DTm+2XQCdF/ +dS9mExaEGWU3BvXhpYmXkCbz1lyb4Fs= +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/IssuerSecretKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/IssuerSecretKey new file mode 100644 index 000000000..4995ae62c --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/IssuerSecretKey @@ -0,0 +1 @@ +~ÇÃÓûýß‹ÖÐÖ¥`‘Oø`"ÅòÜó'  Ò‚ò0ñC \ No newline at end of file diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/tls-cert.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/tls-cert.pem new file mode 100644 index 000000000..71ba6e4bd --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/tls-cert.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIICcjCCAhmgAwIBAgIUOpnMv5vB6JvnOhXdQ4blHsBNyuIwCgYIKoZIzj0EAwIw +aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK +EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTIzMDgwNDA2MDIwMFowZDELMAkG +A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl +cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRUwEwYDVQQDEww2ZGYwMjY1NWZmZDEw +WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQuDLeYJhoKkNqhAWWJao6XMB+JyiJg +9E0q0IjrCmvOTVheNu/6nyZGGGNrI+2b3X+cbdoVKeXJtlPeL5jLrWd/o4GkMIGh +MA4GA1UdDwEB/wQEAwIDqDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw +DAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUPgcKZtxWmeKy1jUZyUX7tFm7E/swHwYD +VR0jBBgwFoAUbAdFhhGwTMQxJZAtRH8VFbhD0zUwIgYDVR0RBBswGYIMZjU4NmY3 +YmNiYTU0gglsb2NhbGhvc3QwCgYIKoZIzj0EAwIDRwAwRAIgRM8T2DATd/oa9IMn +vC314JYP3L2HPyY2puszol2b/TQCIAgrBqwQX1agPuT7XA7izuplvDRazOn2z6Ls +EcSE5SG2 +-----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/IssuerPublicKey index b35c28f7ef8348f469f1d0dbd110f08e11d44a32..15c01b255288251fd71275c0fe0d801c04e38886 100644 GIT binary patch delta 810 zcmV+_1J(S?2FnJJE`PZSMQQxLs9~ALH~f`2Cbx#&Tc>OB28FBX(5b3dLa!1awS4iw zJ>U}PwvbB(U40%=&8^DGznF|)nfpZdA=s|F8bk^p1oj=?CB>ynbSYk$Z^{YyZ{m!b zh$5z!8hUEO1h<8M5+L!HQQJXY{EwmO(XO#kl&ZiYu+xNrXMd?aMejMWH0N9*L<%4+ zCVO{dXAhv08!qT+*~u0nY=2dB+qt=(j)Np@s@s1OAg0nzO1Dac!7-_lbEwd(6I~t= z?D~!uJdv;cMbH(0Dk4M*ASr>+HybgC@8}G2X2W2n;66_o}1f=muqv^b#Oz z@B9O!tHMiZb$@!hBcEi$k40@kHO+T9f6tq0>LpP*B18%xiHR;rXUUIsl+{%}_fsXP zdbzD=H;1@yrt5IkKn+gw5+HIU)$woB;We^_9Ntuzm5Rm(B?U*uELLl#3hwLZPxK;0 z3LxKa%#c;}4hKOtZvc08spM>bg29y0oH-N`ow!H`rGNYqAVTCCxwUy8d@H5m?c{&> z(!@H8*bPW2)+9(vKnh{Eq$-F33LwArz~Q`GgOD6oFZirJPGY0I7}dP&>vj+8X)W3=(k^@D7gxI`$v1j z(-Osj)PE|xU=I1WJP$3WBF0K0AZ=nxL0ui^%Vs4mlG>C+InfEA&9p)^7C}Y;(0F12 zeKJG}Ag9=T>{lZG;{l4mv4YjUpC-;WK8<-}y@0hF3vaPgY!V=e2J%)w+LhkK&4xZx zX}_~d^-^z3r%PU{jZK6%T@4R9L<%6g4^+T-rhf}!{GAYe?@bYP(J-QbQ9GokBDk-s zT-BN>5+Hw#g|X?o3*_zxeZ?0rdH4EWby1jKWZl1I3xCLn6K+Bvz|i~d3Z`{}F9fZQ zedh++9Xz~!tFM+CL>S%K1l#8uN+8p~eWxQc>8;1UPHo0Ag4og{LX(TDp$VIG2OoeX oZzG3NAhN%`ZvQjvip%SovAxQbviV2P-J<$}}l4W!b6vH$=8 delta 810 zcmV+_1J(S?2FnJJE`R%2C;{FBqxeDP=;!II;tIY=BbNb7vUuk>wj}~`qG}Q#-_vQk z+bg2A^_MDAQN96i#bBjIxm{@f~6E7;zFpL zqV6wtkG&~^*QAx#J0e61Aiq0G{Y%Q>-(9*v3m;h2%B~6N`;QlwdnTN{=KwSP7KexnesbSEDd%|2YG|15nQg>XhvB18%xUY|dRREVMOzWY+#GN8;o z>%Brd(v!AxTH+jRQ)28*$JedL9n$BiHESyc#Vx9?G7K1!Pqq-+#*zAjzZVNR;!G-D371#6SQB znK+%U=hUg2Js}4YE`6`G33LwIUba9A!hL|10mV10)71SZYdq+u${R950^pF;s zqd^iNNYk0gVVL9tol_+JQ5UTQNwbXAKKTWK<>dp*dIF?>8X)5!w6)>l!>l?W7$OST z>FAHj*?*m*&V>hT2^X~f(?NA2APR!Ca7c!@8&&-h+ExIdENb$B-Ct=I-h@3ItN4=- zWHLkwAnAgb9)+Hi3yBUJVvdB`do?uxLZ~EGJxVPpKmGs+rV=2ay=h~r&@rgD(jEMv zCP`leYL<%4deP7xY;(xDV1p#sOw}=RCG$Qlp^k}UnRAALA zzEG9P5+H_3aK`%m2k*14w{TcQM?@uIOk1`^MXvIJ_@3NEWTQeLuzcX*Z77~qFs5Dx z7Z9&=H1Z4NjxR4ZTW_^MXZjZIN+1oY-~Aoa-Imv_RASrw-Uyvjs*#+%$OigsJRp>%R0fk&AR0g!X_01)xr9h^0mH+?% diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/IssuerRevocationPublicKey index dc4c6f6fb..7ef9db090 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/IssuerRevocationPublicKey +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/IssuerRevocationPublicKey @@ -1,5 +1,5 @@ -----BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEKJ7KBEAeS+e6lPUS3eCgZiImNpXJ2R0c -rVb28F2tYtczCf1dg7MFLDFaL4AieRATNZxAtHXOoo4smc+DCGHeFOB8IIEL8sHG -fUrGj43x0eFV16Our2mt1DzRhScQ/bCV +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEkglrbl6Llw5yDS3ARDs0tli8HpKvfaB3 +UESim8WHqjt/y67VHVtzvLE2uNI0/+5gFys0Qwwbz688O1qazwzCIOg05vtl0AnR +f3UvZhMWhBllNwb14aWJl5Am89Zcm+Bb -----END PUBLIC KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem index 6d1103342..44fad8ac2 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFjCCAb2gAwIBAgIURwEWXKViiCnfztwadQU0Xv3sV/MwCgYIKoZIzj0EAwIw +MIICFzCCAb2gAwIBAgIUMSokEmwIGLStVW15f5Vk/pmJ8bEwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTM2MDcyNjA1NDYwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEENQJSbn/q+iNKSDsVp0kx9bR -AAd9slqL8odhUGAL5/UOwhTqTI3YKVyUJLyx7PE6G0qZjdHWffa28xCSdN0GpqNF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIW3OjyOU3HkXNUKfcRXwIxEd +NCaVdaZikxSsAXtWK4755DpN+DlJwMmFj6CkdOyh6+L0BLH0gybH0TM2xAw/eaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FD6tYQP/qhHd7hPK0db/ZnRDP4Y0MAoGCCqGSM49BAMCA0cAMEQCIAIPEZGutxkq -HnTrmpt16WEyl+R0cFnxVWHoP/mN2zxiAiBU7WwaDXCAQf9jiXGk3rCqF4KBjiXI -G/SqmgUTqBvo0g== +FGwHRYYRsEzEMSWQLUR/FRW4Q9M1MAoGCCqGSM49BAMCA0gAMEUCIQDlwQ5K7yM+ +bbYz10jGDbwuXuD2azQPphoZ32Lg1uA9fgIgf2XzZtvLHY2bB/PEJPbHCpLq+bst +X6bmPz2oSrn1tRc= -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/keystore/2b1bb41ced0015f0c3b2ee752ca4b8ac3d20a66f2f899f3bd8eef1a06dfca4d9_sk b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/keystore/2b1bb41ced0015f0c3b2ee752ca4b8ac3d20a66f2f899f3bd8eef1a06dfca4d9_sk new file mode 100644 index 000000000..bcf40aa9a --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/keystore/2b1bb41ced0015f0c3b2ee752ca4b8ac3d20a66f2f899f3bd8eef1a06dfca4d9_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgAgpj8lDen5ANKXZx +kmGQeHbis+BIMjPDdFjssI4pcHahRANCAATyEchXgQkX7FzEAaf7Aj7dS8aqXJfN +QfbKIJfnm2jMbOIdZYa6y5UobBTxAt1ds3I7LpET/wQVx6IjptqYOulO +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/keystore/ae13856d0a06478551748e67a55a872b6eca64b4de3bb7c41625d223c055b40b_sk b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/keystore/ae13856d0a06478551748e67a55a872b6eca64b4de3bb7c41625d223c055b40b_sk deleted file mode 100644 index 04933b79a..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/keystore/ae13856d0a06478551748e67a55a872b6eca64b4de3bb7c41625d223c055b40b_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgwFOAEpZ9xnaSpB+t -BJvyTxorPFiNA0DuQcUEUPSX1tKhRANCAAQNGYH2wRu1pYFhACJYxMd2QN2QOLlZ -Y3hDQX5ZiozLAI4aD7fHBqZeg/WeUKlN6cgCbI8Svl5ud0rSRSGquxpG ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/signcerts/cert.pem index 99f8c78ce..9e0fe4fc6 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/signcerts/cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/signcerts/cert.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICPDCCAeKgAwIBAgIUVCTlEdsJKLq5h3sUu4RI5P64EfcwCgYIKoZIzj0EAwIw +MIICPDCCAeKgAwIBAgIUThuWZsnNciPhfgUMijrzpW0Z9yQwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDcwMFoXDTIyMDczMDA1NTIwMFowXTELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTIzMDgwNDA2MDcwMFowXTELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGY2xpZW50MQ4wDAYDVQQDEwVhZG1pbjBZMBMGByqG -SM49AgEGCCqGSM49AwEHA0IABA0ZgfbBG7WlgWEAIljEx3ZA3ZA4uVljeENBflmK -jMsAjhoPt8cGpl6D9Z5QqU3pyAJsjxK+Xm53StJFIaq7GkajdTBzMA4GA1UdDwEB -/wQEAwIHgDAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRqOqSUdGPZWNNHw24AWmQI -I8fBDzAfBgNVHSMEGDAWgBQ+rWED/6oR3e4TytHW/2Z0Qz+GNDATBgNVHREEDDAK -gghzYW5uaXNoMTAKBggqhkjOPQQDAgNIADBFAiEArgEnWyhzAw6Ok7RGBnvBuZUf -/SwHfGsCuzW4/B3XkBUCIHORnjey2GWdVfuaylVUbxcV6mkiyAlCFvx8CWiUwzbb +SM49AgEGCCqGSM49AwEHA0IABPIRyFeBCRfsXMQBp/sCPt1Lxqpcl81B9sogl+eb +aMxs4h1lhrrLlShsFPEC3V2zcjsukRP/BBXHoiOm2pg66U6jdTBzMA4GA1UdDwEB +/wQEAwIHgDAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSOFgewRUQfwWCegvsR9KMu +zhD3dDAfBgNVHSMEGDAWgBRsB0WGEbBMxDElkC1EfxUVuEPTNTATBgNVHREEDDAK +gghzYW5uaXNoMTAKBggqhkjOPQQDAgNIADBFAiEAox/vVl7xZNCaWziwygW/eC2A +lWzWc4A6PwldteEgwdsCIGnWipmT609hsoiRngvT+JMa7ywnnhGBiIFSUIhUkRpt -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem index 6d1103342..44fad8ac2 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFjCCAb2gAwIBAgIURwEWXKViiCnfztwadQU0Xv3sV/MwCgYIKoZIzj0EAwIw +MIICFzCCAb2gAwIBAgIUMSokEmwIGLStVW15f5Vk/pmJ8bEwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTM2MDcyNjA1NDYwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEENQJSbn/q+iNKSDsVp0kx9bR -AAd9slqL8odhUGAL5/UOwhTqTI3YKVyUJLyx7PE6G0qZjdHWffa28xCSdN0GpqNF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIW3OjyOU3HkXNUKfcRXwIxEd +NCaVdaZikxSsAXtWK4755DpN+DlJwMmFj6CkdOyh6+L0BLH0gybH0TM2xAw/eaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FD6tYQP/qhHd7hPK0db/ZnRDP4Y0MAoGCCqGSM49BAMCA0cAMEQCIAIPEZGutxkq -HnTrmpt16WEyl+R0cFnxVWHoP/mN2zxiAiBU7WwaDXCAQf9jiXGk3rCqF4KBjiXI -G/SqmgUTqBvo0g== +FGwHRYYRsEzEMSWQLUR/FRW4Q9M1MAoGCCqGSM49BAMCA0gAMEUCIQDlwQ5K7yM+ +bbYz10jGDbwuXuD2azQPphoZ32Lg1uA9fgIgf2XzZtvLHY2bB/PEJPbHCpLq+bst +X6bmPz2oSrn1tRc= -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/IssuerPublicKey index b35c28f7ef8348f469f1d0dbd110f08e11d44a32..15c01b255288251fd71275c0fe0d801c04e38886 100644 GIT binary patch delta 810 zcmV+_1J(S?2FnJJE`PZSMQQxLs9~ALH~f`2Cbx#&Tc>OB28FBX(5b3dLa!1awS4iw zJ>U}PwvbB(U40%=&8^DGznF|)nfpZdA=s|F8bk^p1oj=?CB>ynbSYk$Z^{YyZ{m!b zh$5z!8hUEO1h<8M5+L!HQQJXY{EwmO(XO#kl&ZiYu+xNrXMd?aMejMWH0N9*L<%4+ zCVO{dXAhv08!qT+*~u0nY=2dB+qt=(j)Np@s@s1OAg0nzO1Dac!7-_lbEwd(6I~t= z?D~!uJdv;cMbH(0Dk4M*ASr>+HybgC@8}G2X2W2n;66_o}1f=muqv^b#Oz z@B9O!tHMiZb$@!hBcEi$k40@kHO+T9f6tq0>LpP*B18%xiHR;rXUUIsl+{%}_fsXP zdbzD=H;1@yrt5IkKn+gw5+HIU)$woB;We^_9Ntuzm5Rm(B?U*uELLl#3hwLZPxK;0 z3LxKa%#c;}4hKOtZvc08spM>bg29y0oH-N`ow!H`rGNYqAVTCCxwUy8d@H5m?c{&> z(!@H8*bPW2)+9(vKnh{Eq$-F33LwArz~Q`GgOD6oFZirJPGY0I7}dP&>vj+8X)W3=(k^@D7gxI`$v1j z(-Osj)PE|xU=I1WJP$3WBF0K0AZ=nxL0ui^%Vs4mlG>C+InfEA&9p)^7C}Y;(0F12 zeKJG}Ag9=T>{lZG;{l4mv4YjUpC-;WK8<-}y@0hF3vaPgY!V=e2J%)w+LhkK&4xZx zX}_~d^-^z3r%PU{jZK6%T@4R9L<%6g4^+T-rhf}!{GAYe?@bYP(J-QbQ9GokBDk-s zT-BN>5+Hw#g|X?o3*_zxeZ?0rdH4EWby1jKWZl1I3xCLn6K+Bvz|i~d3Z`{}F9fZQ zedh++9Xz~!tFM+CL>S%K1l#8uN+8p~eWxQc>8;1UPHo0Ag4og{LX(TDp$VIG2OoeX oZzG3NAhN%`ZvQjvip%SovAxQbviV2P-J<$}}l4W!b6vH$=8 delta 810 zcmV+_1J(S?2FnJJE`R%2C;{FBqxeDP=;!II;tIY=BbNb7vUuk>wj}~`qG}Q#-_vQk z+bg2A^_MDAQN96i#bBjIxm{@f~6E7;zFpL zqV6wtkG&~^*QAx#J0e61Aiq0G{Y%Q>-(9*v3m;h2%B~6N`;QlwdnTN{=KwSP7KexnesbSEDd%|2YG|15nQg>XhvB18%xUY|dRREVMOzWY+#GN8;o z>%Brd(v!AxTH+jRQ)28*$JedL9n$BiHESyc#Vx9?G7K1!Pqq-+#*zAjzZVNR;!G-D371#6SQB znK+%U=hUg2Js}4YE`6`G33LwIUba9A!hL|10mV10)71SZYdq+u${R950^pF;s zqd^iNNYk0gVVL9tol_+JQ5UTQNwbXAKKTWK<>dp*dIF?>8X)5!w6)>l!>l?W7$OST z>FAHj*?*m*&V>hT2^X~f(?NA2APR!Ca7c!@8&&-h+ExIdENb$B-Ct=I-h@3ItN4=- zWHLkwAnAgb9)+Hi3yBUJVvdB`do?uxLZ~EGJxVPpKmGs+rV=2ay=h~r&@rgD(jEMv zCP`leYL<%4deP7xY;(xDV1p#sOw}=RCG$Qlp^k}UnRAALA zzEG9P5+H_3aK`%m2k*14w{TcQM?@uIOk1`^MXvIJ_@3NEWTQeLuzcX*Z77~qFs5Dx z7Z9&=H1Z4NjxR4ZTW_^MXZjZIN+1oY-~Aoa-Imv_RASrw-Uyvjs*#+%$OigsJRp>%R0fk&AR0g!X_01)xr9h^0mH+?% diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/IssuerRevocationPublicKey index dc4c6f6fb..7ef9db090 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/IssuerRevocationPublicKey +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/IssuerRevocationPublicKey @@ -1,5 +1,5 @@ -----BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEKJ7KBEAeS+e6lPUS3eCgZiImNpXJ2R0c -rVb28F2tYtczCf1dg7MFLDFaL4AieRATNZxAtHXOoo4smc+DCGHeFOB8IIEL8sHG -fUrGj43x0eFV16Our2mt1DzRhScQ/bCV +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEkglrbl6Llw5yDS3ARDs0tli8HpKvfaB3 +UESim8WHqjt/y67VHVtzvLE2uNI0/+5gFys0Qwwbz688O1qazwzCIOg05vtl0AnR +f3UvZhMWhBllNwb14aWJl5Am89Zcm+Bb -----END PUBLIC KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem index 6d1103342..44fad8ac2 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFjCCAb2gAwIBAgIURwEWXKViiCnfztwadQU0Xv3sV/MwCgYIKoZIzj0EAwIw +MIICFzCCAb2gAwIBAgIUMSokEmwIGLStVW15f5Vk/pmJ8bEwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTM2MDcyNjA1NDYwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEENQJSbn/q+iNKSDsVp0kx9bR -AAd9slqL8odhUGAL5/UOwhTqTI3YKVyUJLyx7PE6G0qZjdHWffa28xCSdN0GpqNF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIW3OjyOU3HkXNUKfcRXwIxEd +NCaVdaZikxSsAXtWK4755DpN+DlJwMmFj6CkdOyh6+L0BLH0gybH0TM2xAw/eaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FD6tYQP/qhHd7hPK0db/ZnRDP4Y0MAoGCCqGSM49BAMCA0cAMEQCIAIPEZGutxkq -HnTrmpt16WEyl+R0cFnxVWHoP/mN2zxiAiBU7WwaDXCAQf9jiXGk3rCqF4KBjiXI -G/SqmgUTqBvo0g== +FGwHRYYRsEzEMSWQLUR/FRW4Q9M1MAoGCCqGSM49BAMCA0gAMEUCIQDlwQ5K7yM+ +bbYz10jGDbwuXuD2azQPphoZ32Lg1uA9fgIgf2XzZtvLHY2bB/PEJPbHCpLq+bst +X6bmPz2oSrn1tRc= -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/keystore/e77cc1ca55809c7a48c804fe7cc884be1a3bf58080c2fa71095838351616ed69_sk b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/keystore/e77cc1ca55809c7a48c804fe7cc884be1a3bf58080c2fa71095838351616ed69_sk deleted file mode 100644 index 38f7162d5..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/keystore/e77cc1ca55809c7a48c804fe7cc884be1a3bf58080c2fa71095838351616ed69_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQguiVzYcBdp1LN1vLh -NSePcZ+kuMxaOoJasuqXvozfH8mhRANCAATFqNp5NXhlSV+Kwxc/BjWln87T6rbz -6UzSFxJyP98flse/kPjGRgfuKFHCVifbpenVopBwDuTjtjRUdxeFH1wP ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/keystore/f949ca1e0e7d7e6d996176d4b1a8f7755eccfbd8d2f9e0597320fe1eaa47c16e_sk b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/keystore/f949ca1e0e7d7e6d996176d4b1a8f7755eccfbd8d2f9e0597320fe1eaa47c16e_sk new file mode 100644 index 000000000..2998f8e56 --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/keystore/f949ca1e0e7d7e6d996176d4b1a8f7755eccfbd8d2f9e0597320fe1eaa47c16e_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQglmRvQ1l2rttkcSLE +R/o8a0xX9roaSIkl4ivUO3rV1sKhRANCAAQGU+KBsKjDpYcrVIPPkRJqIfO3iTbh +aPJKgD3gV/yVCQ8nvWsDkpk6xG0va61++j4rvq1/q27FpAWiYQi2QPEu +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/signcerts/cert.pem index 9bc948e7c..d9312d929 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/signcerts/cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/signcerts/cert.pem @@ -1,17 +1,17 @@ -----BEGIN CERTIFICATE----- -MIICtDCCAlugAwIBAgIUTB+NUu/uarOcF3YIpgcxaRj8974wCgYIKoZIzj0EAwIw +MIICtDCCAlugAwIBAgIUHQJpkm8eQdl6WtX1DXJsOBgDVGUwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDcwMFoXDTIyMDczMDA1NTIwMFowYDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTIzMDgwNDA2MDcwMFowYDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEQMA4GA1UECxMHb3JkZXJlcjEQMA4GA1UEAxMHb3JkZXJlcjBZMBMG -ByqGSM49AgEGCCqGSM49AwEHA0IABMWo2nk1eGVJX4rDFz8GNaWfztPqtvPpTNIX -EnI/3x+Wx7+Q+MZGB+4oUcJWJ9ul6dWikHAO5OO2NFR3F4UfXA+jgeowgecwDgYD -VR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFKsy/SyaOgce851T -ORtCe7fzZKDDMB8GA1UdIwQYMBaAFD6tYQP/qhHd7hPK0db/ZnRDP4Y0MCoGA1Ud +ByqGSM49AgEGCCqGSM49AwEHA0IABAZT4oGwqMOlhytUg8+REmoh87eJNuFo8kqA +PeBX/JUJDye9awOSmTrEbS9rrX76Piu+rX+rbsWkBaJhCLZA8S6jgeowgecwDgYD +VR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFFjlk9VI+mRs2hvq +VLq3ejWAkGFRMB8GA1UdIwQYMBaAFGwHRYYRsEzEMSWQLUR/FRW4Q9M1MCoGA1Ud EQQjMCGCFG9yZGVyZXIubmV0d29yazEuY29tgglsb2NhbGhvc3QwWwYIKgMEBQYH CAEET3siYXR0cnMiOnsiaGYuQWZmaWxpYXRpb24iOiIiLCJoZi5FbnJvbGxtZW50 SUQiOiJvcmRlcmVyIiwiaGYuVHlwZSI6Im9yZGVyZXIifX0wCgYIKoZIzj0EAwID -RwAwRAIge2m09M3veb+jez0HYcUcqdis8OlAhfF0mYIe9xOXvksCIDUQ+9Wh8H54 -2XtKXcf3Vzoz7pr98l2TC8P2XJcjx2da +RwAwRAIhAIYSkttY4h+5+pQLQ6fFIVBYXBj7LPwPdayQow2hip9cAh8zod7cgB78 +NL2Nne4k5+iY7A6huV8MIeYG76Hjz86e -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem index 6d1103342..44fad8ac2 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFjCCAb2gAwIBAgIURwEWXKViiCnfztwadQU0Xv3sV/MwCgYIKoZIzj0EAwIw +MIICFzCCAb2gAwIBAgIUMSokEmwIGLStVW15f5Vk/pmJ8bEwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTM2MDcyNjA1NDYwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEENQJSbn/q+iNKSDsVp0kx9bR -AAd9slqL8odhUGAL5/UOwhTqTI3YKVyUJLyx7PE6G0qZjdHWffa28xCSdN0GpqNF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIW3OjyOU3HkXNUKfcRXwIxEd +NCaVdaZikxSsAXtWK4755DpN+DlJwMmFj6CkdOyh6+L0BLH0gybH0TM2xAw/eaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FD6tYQP/qhHd7hPK0db/ZnRDP4Y0MAoGCCqGSM49BAMCA0cAMEQCIAIPEZGutxkq -HnTrmpt16WEyl+R0cFnxVWHoP/mN2zxiAiBU7WwaDXCAQf9jiXGk3rCqF4KBjiXI -G/SqmgUTqBvo0g== +FGwHRYYRsEzEMSWQLUR/FRW4Q9M1MAoGCCqGSM49BAMCA0gAMEUCIQDlwQ5K7yM+ +bbYz10jGDbwuXuD2azQPphoZ32Lg1uA9fgIgf2XzZtvLHY2bB/PEJPbHCpLq+bst +X6bmPz2oSrn1tRc= -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/IssuerPublicKey index b35c28f7ef8348f469f1d0dbd110f08e11d44a32..15c01b255288251fd71275c0fe0d801c04e38886 100644 GIT binary patch delta 810 zcmV+_1J(S?2FnJJE`PZSMQQxLs9~ALH~f`2Cbx#&Tc>OB28FBX(5b3dLa!1awS4iw zJ>U}PwvbB(U40%=&8^DGznF|)nfpZdA=s|F8bk^p1oj=?CB>ynbSYk$Z^{YyZ{m!b zh$5z!8hUEO1h<8M5+L!HQQJXY{EwmO(XO#kl&ZiYu+xNrXMd?aMejMWH0N9*L<%4+ zCVO{dXAhv08!qT+*~u0nY=2dB+qt=(j)Np@s@s1OAg0nzO1Dac!7-_lbEwd(6I~t= z?D~!uJdv;cMbH(0Dk4M*ASr>+HybgC@8}G2X2W2n;66_o}1f=muqv^b#Oz z@B9O!tHMiZb$@!hBcEi$k40@kHO+T9f6tq0>LpP*B18%xiHR;rXUUIsl+{%}_fsXP zdbzD=H;1@yrt5IkKn+gw5+HIU)$woB;We^_9Ntuzm5Rm(B?U*uELLl#3hwLZPxK;0 z3LxKa%#c;}4hKOtZvc08spM>bg29y0oH-N`ow!H`rGNYqAVTCCxwUy8d@H5m?c{&> z(!@H8*bPW2)+9(vKnh{Eq$-F33LwArz~Q`GgOD6oFZirJPGY0I7}dP&>vj+8X)W3=(k^@D7gxI`$v1j z(-Osj)PE|xU=I1WJP$3WBF0K0AZ=nxL0ui^%Vs4mlG>C+InfEA&9p)^7C}Y;(0F12 zeKJG}Ag9=T>{lZG;{l4mv4YjUpC-;WK8<-}y@0hF3vaPgY!V=e2J%)w+LhkK&4xZx zX}_~d^-^z3r%PU{jZK6%T@4R9L<%6g4^+T-rhf}!{GAYe?@bYP(J-QbQ9GokBDk-s zT-BN>5+Hw#g|X?o3*_zxeZ?0rdH4EWby1jKWZl1I3xCLn6K+Bvz|i~d3Z`{}F9fZQ zedh++9Xz~!tFM+CL>S%K1l#8uN+8p~eWxQc>8;1UPHo0Ag4og{LX(TDp$VIG2OoeX oZzG3NAhN%`ZvQjvip%SovAxQbviV2P-J<$}}l4W!b6vH$=8 delta 810 zcmV+_1J(S?2FnJJE`R%2C;{FBqxeDP=;!II;tIY=BbNb7vUuk>wj}~`qG}Q#-_vQk z+bg2A^_MDAQN96i#bBjIxm{@f~6E7;zFpL zqV6wtkG&~^*QAx#J0e61Aiq0G{Y%Q>-(9*v3m;h2%B~6N`;QlwdnTN{=KwSP7KexnesbSEDd%|2YG|15nQg>XhvB18%xUY|dRREVMOzWY+#GN8;o z>%Brd(v!AxTH+jRQ)28*$JedL9n$BiHESyc#Vx9?G7K1!Pqq-+#*zAjzZVNR;!G-D371#6SQB znK+%U=hUg2Js}4YE`6`G33LwIUba9A!hL|10mV10)71SZYdq+u${R950^pF;s zqd^iNNYk0gVVL9tol_+JQ5UTQNwbXAKKTWK<>dp*dIF?>8X)5!w6)>l!>l?W7$OST z>FAHj*?*m*&V>hT2^X~f(?NA2APR!Ca7c!@8&&-h+ExIdENb$B-Ct=I-h@3ItN4=- zWHLkwAnAgb9)+Hi3yBUJVvdB`do?uxLZ~EGJxVPpKmGs+rV=2ay=h~r&@rgD(jEMv zCP`leYL<%4deP7xY;(xDV1p#sOw}=RCG$Qlp^k}UnRAALA zzEG9P5+H_3aK`%m2k*14w{TcQM?@uIOk1`^MXvIJ_@3NEWTQeLuzcX*Z77~qFs5Dx z7Z9&=H1Z4NjxR4ZTW_^MXZjZIN+1oY-~Aoa-Imv_RASrw-Uyvjs*#+%$OigsJRp>%R0fk&AR0g!X_01)xr9h^0mH+?% diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/IssuerRevocationPublicKey index dc4c6f6fb..7ef9db090 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/IssuerRevocationPublicKey +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/IssuerRevocationPublicKey @@ -1,5 +1,5 @@ -----BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEKJ7KBEAeS+e6lPUS3eCgZiImNpXJ2R0c -rVb28F2tYtczCf1dg7MFLDFaL4AieRATNZxAtHXOoo4smc+DCGHeFOB8IIEL8sHG -fUrGj43x0eFV16Our2mt1DzRhScQ/bCV +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEkglrbl6Llw5yDS3ARDs0tli8HpKvfaB3 +UESim8WHqjt/y67VHVtzvLE2uNI0/+5gFys0Qwwbz688O1qazwzCIOg05vtl0AnR +f3UvZhMWhBllNwb14aWJl5Am89Zcm+Bb -----END PUBLIC KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/ca.crt b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/ca.crt index 6d1103342..44fad8ac2 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/ca.crt +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/ca.crt @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFjCCAb2gAwIBAgIURwEWXKViiCnfztwadQU0Xv3sV/MwCgYIKoZIzj0EAwIw +MIICFzCCAb2gAwIBAgIUMSokEmwIGLStVW15f5Vk/pmJ8bEwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTM2MDcyNjA1NDYwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEENQJSbn/q+iNKSDsVp0kx9bR -AAd9slqL8odhUGAL5/UOwhTqTI3YKVyUJLyx7PE6G0qZjdHWffa28xCSdN0GpqNF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIW3OjyOU3HkXNUKfcRXwIxEd +NCaVdaZikxSsAXtWK4755DpN+DlJwMmFj6CkdOyh6+L0BLH0gybH0TM2xAw/eaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FD6tYQP/qhHd7hPK0db/ZnRDP4Y0MAoGCCqGSM49BAMCA0cAMEQCIAIPEZGutxkq -HnTrmpt16WEyl+R0cFnxVWHoP/mN2zxiAiBU7WwaDXCAQf9jiXGk3rCqF4KBjiXI -G/SqmgUTqBvo0g== +FGwHRYYRsEzEMSWQLUR/FRW4Q9M1MAoGCCqGSM49BAMCA0gAMEUCIQDlwQ5K7yM+ +bbYz10jGDbwuXuD2azQPphoZ32Lg1uA9fgIgf2XzZtvLHY2bB/PEJPbHCpLq+bst +X6bmPz2oSrn1tRc= -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/keystore/39f5127d7653c2b2fceef7ed6d8815192305afa9716ad6d6377520659afda105_sk b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/keystore/39f5127d7653c2b2fceef7ed6d8815192305afa9716ad6d6377520659afda105_sk deleted file mode 100644 index 5f7cd0d8e..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/keystore/39f5127d7653c2b2fceef7ed6d8815192305afa9716ad6d6377520659afda105_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg7y0PBJNvUDOJGAoY -pquNCLpsbcAf0dk1B+oBaKs1IOahRANCAATuJbR3uHAA6tSLa3u3Exkk5tXLdalz -xVBR4W7A8omTGcfoTz4v8omjO2hzHx/eE/1qLEmCBEE39V9c8gf9Ofvn ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/keystore/75f5e9c82d2e8d17470e65e5a809cd1c2ec4b9dbb9d0083146c8a6afd50f7223_sk b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/keystore/75f5e9c82d2e8d17470e65e5a809cd1c2ec4b9dbb9d0083146c8a6afd50f7223_sk new file mode 100644 index 000000000..a42779be0 --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/keystore/75f5e9c82d2e8d17470e65e5a809cd1c2ec4b9dbb9d0083146c8a6afd50f7223_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgNjzTcFJxWtRYdrRC +YEXzNAKIBcYA/bImBs5q6xrgbaChRANCAASggl5d89FgqSzdB2033rYnlejo5bXX +fGC5oC1GyIfO2n2zq5lILMaYUa/jwS1SByqlb6CSh6L0AOzCkFfcRH5P +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.crt b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.crt index c8be1d280..bb19964dc 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.crt +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.crt @@ -1,18 +1,18 @@ -----BEGIN CERTIFICATE----- -MIIC1jCCAnygAwIBAgIUUFUPOt2Iq4BAbu4izr4jPvgTf+IwCgYIKoZIzj0EAwIw +MIIC1TCCAnygAwIBAgIUfBcNYTEE8L0Bdmk65WqhkQO+kHkwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDcwMFoXDTIyMDczMDA1NTIwMFowYDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTIzMDgwNDA2MDcwMFowYDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEQMA4GA1UECxMHb3JkZXJlcjEQMA4GA1UEAxMHb3JkZXJlcjBZMBMG -ByqGSM49AgEGCCqGSM49AwEHA0IABO4ltHe4cADq1Itre7cTGSTm1ct1qXPFUFHh -bsDyiZMZx+hPPi/yiaM7aHMfH94T/WosSYIEQTf1X1zyB/05++ejggEKMIIBBjAO +ByqGSM49AgEGCCqGSM49AwEHA0IABKCCXl3z0WCpLN0HbTfetieV6Ojltdd8YLmg +LUbIh87afbOrmUgsxphRr+PBLVIHKqVvoJKHovQA7MKQV9xEfk+jggEKMIIBBjAO BgNVHQ8BAf8EBAMCA6gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwG -A1UdEwEB/wQCMAAwHQYDVR0OBBYEFAlEgmrPvzu5v0ZOBkyV8XITILkhMB8GA1Ud -IwQYMBaAFD6tYQP/qhHd7hPK0db/ZnRDP4Y0MCoGA1UdEQQjMCGCFG9yZGVyZXIu +A1UdEwEB/wQCMAAwHQYDVR0OBBYEFIlygLHp/jwTR9CNn5g51jm6q7JVMB8GA1Ud +IwQYMBaAFGwHRYYRsEzEMSWQLUR/FRW4Q9M1MCoGA1UdEQQjMCGCFG9yZGVyZXIu bmV0d29yazEuY29tgglsb2NhbGhvc3QwWwYIKgMEBQYHCAEET3siYXR0cnMiOnsi aGYuQWZmaWxpYXRpb24iOiIiLCJoZi5FbnJvbGxtZW50SUQiOiJvcmRlcmVyIiwi -aGYuVHlwZSI6Im9yZGVyZXIifX0wCgYIKoZIzj0EAwIDSAAwRQIhAMEMcNxYCENx -1CSSs8SYB+5CDSWXEK/ApKMAbqZ6Zo6/AiA/B9akIzDRqMSc7Xsl+nAVDzOOjFo1 -tGhAGDPrKszsGw== +aGYuVHlwZSI6Im9yZGVyZXIifX0wCgYIKoZIzj0EAwIDRwAwRAIgLwh2fOXcSPND +W0qgcx7FvRvrcUzA+IUeyTKc6WuqBHYCIB9v7cfw1A1RQV94FgUvc+OhvIMVXKb3 +0vidYlqPTrlS -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.key b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.key index 5f7cd0d8e..a42779be0 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.key +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.key @@ -1,5 +1,5 @@ -----BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg7y0PBJNvUDOJGAoY -pquNCLpsbcAf0dk1B+oBaKs1IOahRANCAATuJbR3uHAA6tSLa3u3Exkk5tXLdalz -xVBR4W7A8omTGcfoTz4v8omjO2hzHx/eE/1qLEmCBEE39V9c8gf9Ofvn +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgNjzTcFJxWtRYdrRC +YEXzNAKIBcYA/bImBs5q6xrgbaChRANCAASggl5d89FgqSzdB2033rYnlejo5bXX +fGC5oC1GyIfO2n2zq5lILMaYUa/jwS1SByqlb6CSh6L0AOzCkFfcRH5P -----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/signcerts/cert.pem index c8be1d280..bb19964dc 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/signcerts/cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/signcerts/cert.pem @@ -1,18 +1,18 @@ -----BEGIN CERTIFICATE----- -MIIC1jCCAnygAwIBAgIUUFUPOt2Iq4BAbu4izr4jPvgTf+IwCgYIKoZIzj0EAwIw +MIIC1TCCAnygAwIBAgIUfBcNYTEE8L0Bdmk65WqhkQO+kHkwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDcwMFoXDTIyMDczMDA1NTIwMFowYDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTIzMDgwNDA2MDcwMFowYDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEQMA4GA1UECxMHb3JkZXJlcjEQMA4GA1UEAxMHb3JkZXJlcjBZMBMG -ByqGSM49AgEGCCqGSM49AwEHA0IABO4ltHe4cADq1Itre7cTGSTm1ct1qXPFUFHh -bsDyiZMZx+hPPi/yiaM7aHMfH94T/WosSYIEQTf1X1zyB/05++ejggEKMIIBBjAO +ByqGSM49AgEGCCqGSM49AwEHA0IABKCCXl3z0WCpLN0HbTfetieV6Ojltdd8YLmg +LUbIh87afbOrmUgsxphRr+PBLVIHKqVvoJKHovQA7MKQV9xEfk+jggEKMIIBBjAO BgNVHQ8BAf8EBAMCA6gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwG -A1UdEwEB/wQCMAAwHQYDVR0OBBYEFAlEgmrPvzu5v0ZOBkyV8XITILkhMB8GA1Ud -IwQYMBaAFD6tYQP/qhHd7hPK0db/ZnRDP4Y0MCoGA1UdEQQjMCGCFG9yZGVyZXIu +A1UdEwEB/wQCMAAwHQYDVR0OBBYEFIlygLHp/jwTR9CNn5g51jm6q7JVMB8GA1Ud +IwQYMBaAFGwHRYYRsEzEMSWQLUR/FRW4Q9M1MCoGA1UdEQQjMCGCFG9yZGVyZXIu bmV0d29yazEuY29tgglsb2NhbGhvc3QwWwYIKgMEBQYHCAEET3siYXR0cnMiOnsi aGYuQWZmaWxpYXRpb24iOiIiLCJoZi5FbnJvbGxtZW50SUQiOiJvcmRlcmVyIiwi -aGYuVHlwZSI6Im9yZGVyZXIifX0wCgYIKoZIzj0EAwIDSAAwRQIhAMEMcNxYCENx -1CSSs8SYB+5CDSWXEK/ApKMAbqZ6Zo6/AiA/B9akIzDRqMSc7Xsl+nAVDzOOjFo1 -tGhAGDPrKszsGw== +aGYuVHlwZSI6Im9yZGVyZXIifX0wCgYIKoZIzj0EAwIDRwAwRAIgLwh2fOXcSPND +W0qgcx7FvRvrcUzA+IUeyTKc6WuqBHYCIB9v7cfw1A1RQV94FgUvc+OhvIMVXKb3 +0vidYlqPTrlS -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/tlscacerts/tls-localhost-9054-ca-orderer-network1-com.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/tlscacerts/tls-localhost-9054-ca-orderer-network1-com.pem index 6d1103342..44fad8ac2 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/tlscacerts/tls-localhost-9054-ca-orderer-network1-com.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/tlscacerts/tls-localhost-9054-ca-orderer-network1-com.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFjCCAb2gAwIBAgIURwEWXKViiCnfztwadQU0Xv3sV/MwCgYIKoZIzj0EAwIw +MIICFzCCAb2gAwIBAgIUMSokEmwIGLStVW15f5Vk/pmJ8bEwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTM2MDcyNjA1NDYwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEENQJSbn/q+iNKSDsVp0kx9bR -AAd9slqL8odhUGAL5/UOwhTqTI3YKVyUJLyx7PE6G0qZjdHWffa28xCSdN0GpqNF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIW3OjyOU3HkXNUKfcRXwIxEd +NCaVdaZikxSsAXtWK4755DpN+DlJwMmFj6CkdOyh6+L0BLH0gybH0TM2xAw/eaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FD6tYQP/qhHd7hPK0db/ZnRDP4Y0MAoGCCqGSM49BAMCA0cAMEQCIAIPEZGutxkq -HnTrmpt16WEyl+R0cFnxVWHoP/mN2zxiAiBU7WwaDXCAQf9jiXGk3rCqF4KBjiXI -G/SqmgUTqBvo0g== +FGwHRYYRsEzEMSWQLUR/FRW4Q9M1MAoGCCqGSM49BAMCA0gAMEUCIQDlwQ5K7yM+ +bbYz10jGDbwuXuD2azQPphoZ32Lg1uA9fgIgf2XzZtvLHY2bB/PEJPbHCpLq+bst +X6bmPz2oSrn1tRc= -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/IssuerPublicKey index b35c28f7ef8348f469f1d0dbd110f08e11d44a32..15c01b255288251fd71275c0fe0d801c04e38886 100644 GIT binary patch delta 810 zcmV+_1J(S?2FnJJE`PZSMQQxLs9~ALH~f`2Cbx#&Tc>OB28FBX(5b3dLa!1awS4iw zJ>U}PwvbB(U40%=&8^DGznF|)nfpZdA=s|F8bk^p1oj=?CB>ynbSYk$Z^{YyZ{m!b zh$5z!8hUEO1h<8M5+L!HQQJXY{EwmO(XO#kl&ZiYu+xNrXMd?aMejMWH0N9*L<%4+ zCVO{dXAhv08!qT+*~u0nY=2dB+qt=(j)Np@s@s1OAg0nzO1Dac!7-_lbEwd(6I~t= z?D~!uJdv;cMbH(0Dk4M*ASr>+HybgC@8}G2X2W2n;66_o}1f=muqv^b#Oz z@B9O!tHMiZb$@!hBcEi$k40@kHO+T9f6tq0>LpP*B18%xiHR;rXUUIsl+{%}_fsXP zdbzD=H;1@yrt5IkKn+gw5+HIU)$woB;We^_9Ntuzm5Rm(B?U*uELLl#3hwLZPxK;0 z3LxKa%#c;}4hKOtZvc08spM>bg29y0oH-N`ow!H`rGNYqAVTCCxwUy8d@H5m?c{&> z(!@H8*bPW2)+9(vKnh{Eq$-F33LwArz~Q`GgOD6oFZirJPGY0I7}dP&>vj+8X)W3=(k^@D7gxI`$v1j z(-Osj)PE|xU=I1WJP$3WBF0K0AZ=nxL0ui^%Vs4mlG>C+InfEA&9p)^7C}Y;(0F12 zeKJG}Ag9=T>{lZG;{l4mv4YjUpC-;WK8<-}y@0hF3vaPgY!V=e2J%)w+LhkK&4xZx zX}_~d^-^z3r%PU{jZK6%T@4R9L<%6g4^+T-rhf}!{GAYe?@bYP(J-QbQ9GokBDk-s zT-BN>5+Hw#g|X?o3*_zxeZ?0rdH4EWby1jKWZl1I3xCLn6K+Bvz|i~d3Z`{}F9fZQ zedh++9Xz~!tFM+CL>S%K1l#8uN+8p~eWxQc>8;1UPHo0Ag4og{LX(TDp$VIG2OoeX oZzG3NAhN%`ZvQjvip%SovAxQbviV2P-J<$}}l4W!b6vH$=8 delta 810 zcmV+_1J(S?2FnJJE`R%2C;{FBqxeDP=;!II;tIY=BbNb7vUuk>wj}~`qG}Q#-_vQk z+bg2A^_MDAQN96i#bBjIxm{@f~6E7;zFpL zqV6wtkG&~^*QAx#J0e61Aiq0G{Y%Q>-(9*v3m;h2%B~6N`;QlwdnTN{=KwSP7KexnesbSEDd%|2YG|15nQg>XhvB18%xUY|dRREVMOzWY+#GN8;o z>%Brd(v!AxTH+jRQ)28*$JedL9n$BiHESyc#Vx9?G7K1!Pqq-+#*zAjzZVNR;!G-D371#6SQB znK+%U=hUg2Js}4YE`6`G33LwIUba9A!hL|10mV10)71SZYdq+u${R950^pF;s zqd^iNNYk0gVVL9tol_+JQ5UTQNwbXAKKTWK<>dp*dIF?>8X)5!w6)>l!>l?W7$OST z>FAHj*?*m*&V>hT2^X~f(?NA2APR!Ca7c!@8&&-h+ExIdENb$B-Ct=I-h@3ItN4=- zWHLkwAnAgb9)+Hi3yBUJVvdB`do?uxLZ~EGJxVPpKmGs+rV=2ay=h~r&@rgD(jEMv zCP`leYL<%4deP7xY;(xDV1p#sOw}=RCG$Qlp^k}UnRAALA zzEG9P5+H_3aK`%m2k*14w{TcQM?@uIOk1`^MXvIJ_@3NEWTQeLuzcX*Z77~qFs5Dx z7Z9&=H1Z4NjxR4ZTW_^MXZjZIN+1oY-~Aoa-Imv_RASrw-Uyvjs*#+%$OigsJRp>%R0fk&AR0g!X_01)xr9h^0mH+?% diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/IssuerRevocationPublicKey index dc4c6f6fb..7ef9db090 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/IssuerRevocationPublicKey +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/IssuerRevocationPublicKey @@ -1,5 +1,5 @@ -----BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEKJ7KBEAeS+e6lPUS3eCgZiImNpXJ2R0c -rVb28F2tYtczCf1dg7MFLDFaL4AieRATNZxAtHXOoo4smc+DCGHeFOB8IIEL8sHG -fUrGj43x0eFV16Our2mt1DzRhScQ/bCV +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEkglrbl6Llw5yDS3ARDs0tli8HpKvfaB3 +UESim8WHqjt/y67VHVtzvLE2uNI0/+5gFys0Qwwbz688O1qazwzCIOg05vtl0AnR +f3UvZhMWhBllNwb14aWJl5Am89Zcm+Bb -----END PUBLIC KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem index 6d1103342..44fad8ac2 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFjCCAb2gAwIBAgIURwEWXKViiCnfztwadQU0Xv3sV/MwCgYIKoZIzj0EAwIw +MIICFzCCAb2gAwIBAgIUMSokEmwIGLStVW15f5Vk/pmJ8bEwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTM2MDcyNjA1NDYwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEENQJSbn/q+iNKSDsVp0kx9bR -AAd9slqL8odhUGAL5/UOwhTqTI3YKVyUJLyx7PE6G0qZjdHWffa28xCSdN0GpqNF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIW3OjyOU3HkXNUKfcRXwIxEd +NCaVdaZikxSsAXtWK4755DpN+DlJwMmFj6CkdOyh6+L0BLH0gybH0TM2xAw/eaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FD6tYQP/qhHd7hPK0db/ZnRDP4Y0MAoGCCqGSM49BAMCA0cAMEQCIAIPEZGutxkq -HnTrmpt16WEyl+R0cFnxVWHoP/mN2zxiAiBU7WwaDXCAQf9jiXGk3rCqF4KBjiXI -G/SqmgUTqBvo0g== +FGwHRYYRsEzEMSWQLUR/FRW4Q9M1MAoGCCqGSM49BAMCA0gAMEUCIQDlwQ5K7yM+ +bbYz10jGDbwuXuD2azQPphoZ32Lg1uA9fgIgf2XzZtvLHY2bB/PEJPbHCpLq+bst +X6bmPz2oSrn1tRc= -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/keystore/3e3a32bdfc3ef9a6639c212e3fab34bc73a5921da7a80691393b105e7fcb3226_sk b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/keystore/3e3a32bdfc3ef9a6639c212e3fab34bc73a5921da7a80691393b105e7fcb3226_sk new file mode 100644 index 000000000..a556cc5ab --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/keystore/3e3a32bdfc3ef9a6639c212e3fab34bc73a5921da7a80691393b105e7fcb3226_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgfsNQt1f2GORjzVSj +FGzokdjbKqJrWgECnFhz0VWxMZ2hRANCAARF7xZVR9HxuJ+fzlx47ydkOHMa7yIJ +TAMVAQcOqQjN8VNfp68Ghb2zLKw+tikrkTQLurt3A9iOBL+EnIUjwnwe +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/keystore/d7ac31a822ab05c8800fd03bddde304d16d6b4733b290981ec9b52baaf9f5e5c_sk b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/keystore/d7ac31a822ab05c8800fd03bddde304d16d6b4733b290981ec9b52baaf9f5e5c_sk deleted file mode 100644 index 71d3bcfbb..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/keystore/d7ac31a822ab05c8800fd03bddde304d16d6b4733b290981ec9b52baaf9f5e5c_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgZbiLfV458Jghw4r8 -QPW9CdyjqsIa7vCJ1vWrsQimdlOhRANCAAS2+UQWA+HryYEOqE+BuVN4Xw9z158x -izHsb2EQEih2AsMrDPrkY5pDgpBkEpGdpNnaLFu9XEvs6wkNLRAZDJjj ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/signcerts/cert.pem index fd8441fc2..9b3739549 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/signcerts/cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/signcerts/cert.pem @@ -1,17 +1,17 @@ -----BEGIN CERTIFICATE----- -MIICpDCCAkqgAwIBAgIUPbbUVj06uRAmtK8YPKV9RWO2KX4wCgYIKoZIzj0EAwIw +MIICozCCAkqgAwIBAgIUGqI5zOxQZFNH+9rIXUgOrkidzjEwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDcwMFoXDTIyMDczMDA1NTIwMFowYzELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTIzMDgwNDA2MDcwMFowYzELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEOMAwGA1UECxMFYWRtaW4xFTATBgNVBAMTDG9yZGVyZXJBZG1pbjBZ -MBMGByqGSM49AgEGCCqGSM49AwEHA0IABLb5RBYD4evJgQ6oT4G5U3hfD3PXnzGL -MexvYRASKHYCwysM+uRjmkOCkGQSkZ2k2dosW71cS+zrCQ0tEBkMmOOjgdYwgdMw -DgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFGjMAddeIzz0 -EfVKyDlgmE6kz6rNMB8GA1UdIwQYMBaAFD6tYQP/qhHd7hPK0db/ZnRDP4Y0MBMG +MBMGByqGSM49AgEGCCqGSM49AwEHA0IABEXvFlVH0fG4n5/OXHjvJ2Q4cxrvIglM +AxUBBw6pCM3xU1+nrwaFvbMsrD62KSuRNAu6u3cD2I4Ev4SchSPCfB6jgdYwgdMw +DgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFMoWeRBl6V8Z +5ykpm7i+3sPnWJzsMB8GA1UdIwQYMBaAFGwHRYYRsEzEMSWQLUR/FRW4Q9M1MBMG A1UdEQQMMAqCCHNhbm5pc2gxMF4GCCoDBAUGBwgBBFJ7ImF0dHJzIjp7ImhmLkFm ZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoib3JkZXJlckFkbWluIiwi -aGYuVHlwZSI6ImFkbWluIn19MAoGCCqGSM49BAMCA0gAMEUCIQCvd9esiH0QAd/M -aOlp/Y65W9HAa3r3A6aGXjajwEtPwwIgDw9Z+1xjHHWDfbvN+F/dtW0FivaywldW -SNVhZ8DDePM= +aGYuVHlwZSI6ImFkbWluIn19MAoGCCqGSM49BAMCA0cAMEQCIB4+S7UcTRKxyVME +QWjkDTo1HK7wTC7sqoQ4zeUdZd6nAiAUAH+j8aarEWjGgI12yL5w6hvPkWiS/TMj +GgHZChvt5g== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/org1/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/org1/IssuerPublicKey new file mode 100644 index 0000000000000000000000000000000000000000..e4e39a4683359596c3c6a9ef67aed4995c58c786 GIT binary patch literal 843 zcmV-R1GM}K0#8*61X6EoWeN;MZgOvIY;9$3bV)=C5K?7!Z)0I}X>V>wVQyq>WfDXR zAl@M1Fxdnzq{Io(<|)R)v5NbIqc1O+OE^O@wj%bJxe_2;q6U4UpaplYB*Ca^$nMP3 zADrsSmc_7?J7~Fmic&QiL<%4)(~J{AnyP)TuVP!u@1V?V7!tsk;ekpw8D_RlD!&HWFm5lTfAb$t4%+_$+&~gFVOQu$}ySb zkP;x6i@O0NIbLE4byDPZ$NGl)8(KR|g(6iY7HLKxhw~pIL<%6ZeI!FN{I`ZD1&&e& zUfWdpQy^!|rBkyMbVTF8;m0KsATJIGK^hR8EBx8jd^|e2+_GFq&`%hC1$vI+$U8~t zFDi%u3Lqom7zLoYM0n0&8m~n7&1kP!uomSC*1DQM(Dt;D<>V3|B6~&9tPJt_v8|xO z{-2|=YKRRel0Teekckw+TC78H8X)8ut|-s&uYX8att8IQD>dY|CSq`sl>S4#uGdw= zB}XD4yr59HD&{+UKqw{{$dJf<@nWK@@!sAOo;e^G;G)yaGDHd>Y2oKka%~LLl3*W>W+J&=Y|DF*$zPD0(6R#;OUA@;nNf+5B&V zCuT|@^$Ac=@8(JGl?1L^s!>3&w;@T1eJ+#m?D<6UaTon!QXmZTcm6a0LHHY{l_y?$ V?ZzKCmy?8$yQ%PR-BJ6fBAiaMh&uoP literal 0 HcmV?d00001 diff --git a/tests/network-setups/fabric/network-artifacts/network1/org1/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/org1/IssuerRevocationPublicKey new file mode 100644 index 000000000..4d36cad18 --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/org1/IssuerRevocationPublicKey @@ -0,0 +1,5 @@ +-----BEGIN PUBLIC KEY----- +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEfDgje7iiTZQ/7ZljIoyOf+AiYXuvHZUG +CohejruX2TTz0uBIRQeSAh55zvv9628DMOcll0DXUrykdccjUqZBA9uSuYFRaANm +IhqLp7VFNB2gMIFcMLJ5SwexnZoJKdK7 +-----END PUBLIC KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/org1/ca-cert.pem b/tests/network-setups/fabric/network-artifacts/network1/org1/ca-cert.pem new file mode 100644 index 000000000..3d82333d8 --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/org1/ca-cert.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw +aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK +EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG +A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl +cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR +ynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF +MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE +FCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq +m2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd +zQkhznMIF4SBF4k= +-----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/org1/fabric-ca-server-config.yaml b/tests/network-setups/fabric/network-artifacts/network1/org1/fabric-ca-server-config.yaml new file mode 100644 index 000000000..b7198b94a --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/org1/fabric-ca-server-config.yaml @@ -0,0 +1,504 @@ +############################################################################# +# 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.4.7 + +# Server's listening port (default: 7054) +port: 7054 + +# 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: false + # 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: + # 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: admin + pass: adminpw + 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: + - 6bbd89430166 + - localhost + 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/tests/network-setups/fabric/network-artifacts/network1/org1/fabric-ca-server.db b/tests/network-setups/fabric/network-artifacts/network1/org1/fabric-ca-server.db new file mode 100644 index 0000000000000000000000000000000000000000..1a2a216f63ada40a1655d26ae648caa0992095ad GIT binary patch literal 61440 zcmeI4ON`q{ddFMc?QS>6ZOv}h=$+GQJZr?gZM#W|dJV8}_!cEm67`mnL4z+*l=zTD zN|dw+0(&>u39yfxl0$-A_L4;qV2^tUa#$e9Jwbp?kXtS}1VK*O0KsBXRKKKlx5qoN zcXo`T?QXJIRjm3|)t?`$zH(J6n7$tCx?@}RWATl5HzJXZ--*RGHZ~5xzbN>3e*6|V z**?DjzauN>H=Q1AJbC)h`?u|lJG(#Mc&C2HLjGXyXGmr5-M#NeZ|(m4?zi{R+dl~Z z+>`+fhXf!2NB|Oes|eh-Bl5xH$C2;2zN}cfs*ioMYpSxZdnc}?UA?|VS6H&f#%d&0 zU}N{M-o77uXlk(rS)sFJ3m zhmT@oed-Q$?F77CS3-xneKi|PpMnPo#Tv`Al^DZvWW7*}p^swaiXf7eb}Y}fAFkEv z=6W0+KKpWX_u#>U$TMRJSnhUB%anc7b-dN{yK7)q@5CNDvaMf0#Za6$ydW5>7X_)# zK8g*;Iv}_n>rw26svO?_`;GU*R(}TAfL339T-fSzH}&P6gZzWYhUsYf%o|z2G&uon zqYWV(AWv`Y98@2_QU>6GCu^C6McDb)JG%$(zaM!fYtqoi${a;jxEj=a)E6d*W2KCYK=bL=yDQ)iym(c6b=Svva_|e^co%A9aFVp6@@~ z-`hQS@4d*g$+F0f>!`YS`V(0z>S3cU- z;gz}9z1;-d7fAnJ{&AS1VAqhoBeEvnhvl|Z@RI!R>d2m#UAQISM8k- zuSYRQpZO;}+0iWhGSHGe|1|8xbWVn@dodnw?9=N2mJc~ReEyZ4-GdK4hmP2f_z8^^6q)U|e2u zx_$R=HohN9*>}`sA6XsutLN+Qh}ApS0A173tKcrX-ivRC=jAUgb@fvUv$fv1E3dcL zS(w#V+8b-_H~y+hz56oJUwcVlt5@N->8a>%y-f61lY|m~vX)60vi)p!clY4nAoA_f zvWHDT@9>sCHrJYQ8FWqi`QQcb#FV+O%a3CIe0WvtS4yxhyx;}y`(sm?0JA4nV_UUT z6Jte@VzxXx(VektSvD|IycMmw$y_iU)g6y@)jt`^o)@^|(Dv|kdw7}p(z-a@-~ZE% zZRDpLcfX7L^v;jo`SDw2Wx~op0+0YC00}?>kN_kA3A{A~o;jO$4xVk_+kZ|*B9Yre zT_2-g$K|hM=+{L)Dd%clrqJ#)a;N8bfvFvrGP&b|D%(LT;r(9s343953(WmT_m`76;Lh?v;CeY_dH+LyJkfvu(Q3LHu>Y^b ze_3?$a$;^J)s++~YHOgf zlVa^js#hZAei_9Vz2Rs+qkHX+Tc~P!HC`Ad$)?wuFEe z2Q?pUg-!k5{&P00dH5BEoz;5Kn?KRIe%3NG7!y~Y^zANIF172&c7{#xO`(};xM|LC zkI~koU6G6-AE#;6GQp?Rt5kdWsFzjYN@Jhq{IUeET4yj$|Ld%Khjo6-yZ0xX&!>^o zHvUd2tnX^iZVUsXxtQ}Z-$JWscZyGOSI}LPife4q>oleuST~@O=D35F%r0ly^I4a_ zrj2>sp(_Q@IOjtdyT3kiE4pEN{#YJAAuqnlSE7I8O7xYc6pisp#GCW2xR&m%#Jrm2 zWeFJF(haa0^64qU)rFTmU2uGTZ0j1B{MTu6<>8>1AAPcU3-q)|^nb(m!p`Zh@Dv`9 z03`5v5cpUFFT0OE+P`=E>C+$n_TEzXF$L=qU4oD`MZpLSOUDy&C60G-Sy$s&GJ~dM zEtyJyYYfwfOeWb)X=p;z6%>_|sdR=&$XW`=wS=0`@pxJ_Tvx+UJpLF>KSqfdn*0z= zeTbq*C<=ap1ADyu8(Usq+;|)w6w3?67|m8{0w>U5Np=~Eh=M@7eVQf*wm}90MH)h# zpJmFGJf7l;JX24J)BGfu$&&7OuyjBhZ6WV=ghd}^LHq!b8MYvj1D?d{EY%a~Mnjx& z3$j5O#RkZ&#tafu)v34wTkNSeFyWeso>-9r)@U;gNy;N^;0t<-vQ&F!b$HEE`)pYx z(Pf78Oynyzcum+=U#tuQE?6dF*coNFo4L8%6n&(Pv%ZQq=9=A@ixkmfYQkJ(jG)Mn zxX1{B$hl$I;xbGP!-D4GwB*QVE&6%Mk(HtsMbbMjI;--HusS7?43=T!Oyo|($e>vx zYm}jmdV_umDN6!H8OHLWEQu5q6ls!_=3Tjzu2dvjNF@{4P|pZTl~=Mx#-I6QuAG+^ z!*N_iyA;xH=GjiS%J*urZn(CZ%+_j0Tw-S8>_l#8S|>R|hj?p-YdOv(vYIGlWsxMp zQfW-UQpj;2h3%O&7*Y(IE?W^PvYTefJ_!Prt)Vf7)TF4YSi`4Yq1>=X%|gK>6;AMT_&!IEYFZlgOWz9R_!Qpl#7qae21{OaZB)99MSJHqpOPL&$f3>lGu!~t*uDOK|NJlE5*mAN_>k_fnPJ7$9F z*qx!mTRn}priv*f1yk?@yJr^$jY-%86&|w`r;@AC;GRQSot6*?W?&*R-<~wGR?w+l z+%UT>^lG1HDghZ(NWthx2{~>ra-E|^x11T55Vc(bT`f~i^k-tPq86xf+2D<1CGWIp zfgZ<4dd~1>ts~Y1YzDbFKWnN-9f|WiJJS~x5*cGHrF)bYkmcZHi_D7y_PcHH`E({T z-~ZCy(%vHQWE|5qG@j5jRMRzCNyJm>q^w|?ilGY7mW&eDGVx#M0%{zaCVR_zVQ%$h>B@!7D`OrWAf1PpnmkU^u@;jy98 zr#d1f^3;69BUO>ekOs@s^oU=c2W*x^1(M2(`mB*I&un?%9hGK`W|hq8#2HN-Gf~O# zni}+H&U}HC5=}=B>`8OP83{Ut&zYGcN&{+KBZJWqKds2ae!Dzwb8^j?lZM1-ldt-(E)no?9Y^Y}}%P?dfF^t}#-Aqj6R?!t}Wd2fi zC5AML0?AMuX|m*q&{3f|bLD0e=SzLJ-pR33%AyfL&5b0s-l+!!H6*6(0iLD>o+_mE z^bzo>QS+lBpUk0yWlcd&uf|KeH;B z5kqRHhC!X>`eYppx-n(293`m?DFKTzXj7C_&n_*>rG!<`8YyLuDN+c?^TZOta)wmL z=U_w>Qwc5W7N)+NowLSBi*pVwkwF%)K^hgb56r26bIE$Xm#y2)Ooq~u0d4EKij2(* zjhQYGK_G-CXa%iMlo#-AK`h!iv%?q(q{xVYSZm{kVR;H(>?wS2s>Y?OZ>0-EAe-|s zu6}HmI;APg<hYpx3&=Qb7%jT8+Sj6{?*+dN9+5)yj%S|zI)&^ zApuAL5`Y9C0Z0H6fCL}`NB|Om1l}Nl`u0a3MF;}NFiZ~@i4x$*=qOld!iXf1i6@h& zoB%6LYF9;xSDh2uIm-I9&*S)^BbxPnhPp5Cz zKx^&2?isv&(7m>{{&?e^f86~A_yrG00225d3BdJ#xc=W~;rf5L*ap}C;rjmzZboqZ z|Fd~WUFT-Bwm1ma|6l561lRvx&65zW|NrWqgmC>IuKx?huY3JJ^bSOp-~XF`w(-vI z?QVi!@PGt_529}tRwU#K# z>0`%0WtQnDnt8$=8-4fKMbic~tm+go&5ruhX5Y}nz|hEm0bXID3t9Qp|19(h)yXpt zevJjb^1!K$7D?c1CN15^N)***Il4zr=0no!w0nKv28SqIMx7mVEZ0gFMJl~?v=;)Y zEmAVc(QXCHS<|l6(mitMnDwTwnwZ)$OJeA&8#?79tR#sdIil$-@ISK?LlrjwLJ#=v zx(r3uc`7g{ip``1n?tp1ZXxuC;5_tl=j@Jcd5GNPP`R0z2z}QK-P=R&_DVA`SMZsq zG#e9*wb<~U63;nelN%^aYjPeh^nyp0Zt(Wm4F}7Jq60g#4mx&#MEkHEFa7Qx10n z7Lr6&P8}^0w5gV=tpbu_jBj4=0k?bue%!ou;R^r5{k`R$Pl9;8s~2xZVyp%5lkF!j zB}Nz#-ci=(9cwNn8r4z0Xqg;IJB)hO>F|pzF`t_&JQnT`5^JyG3NIR7CZk(TYJ`@J zL0T_sMAjz<9D1DQ3jN9;ht?{nC?dQn7qv!-sT+hn9Mn^uUM-a5xy*KQ{!#x(PUKp% zj&8Q&VzH8BZ6GgXV5sO)UP5(2ekFM+DJ72+%4H6nq`1xk&kRk(XE;AI0=~PSL0&?2 z0iL>7<;A!nFS8rvB~%w6F`q6kTB{iDfies9a(7NW-0Bs|PB>|Sgu51mYo$d6(jw6U zb2Q`o(hQUQUNxakbe#8yv_?1jiA+X0Y9V#e@kZ6oVy3bV*iUp^&3i<1%y2=-cW1)eq%6Prd-*gXmtnwe8$&L1Yb}>9)@BOEO{%Hn zXr@-sX1Ow~9x1H_iR5WdYI8iFDfP%?ZanKQfXBXyqGp!?tvjvNJ!8S~7&%_d43`in zI^0(!N!KY$$vxk@my@KXNJ(IPgYAh@oudM<%W%~Tzkj*!54nEhU!_bpQ@)cU!GB8U zHl2ZSJQv+0E;|I#U*GqKe9Fc@|9nSIu1^lG+xLg8ZTxEsIfc*k+h8}25-*~_kh~&O zq2;q~1tI5V(5qTOXWKF_WC}UgspSnbm+8K^S11ei3b8Ei;Qcall<%-P zA4Td8-Nu;WBt6e2%8hidqcNIm2!_^PH1%GUDb6Q~755uf*W0{?mVWKmw2eBmfCO0+0YC00}?>kN_kA2|xmnz*|fp-2V^1|KH*U zhE;{XY`@#Rm8b4@dwKfCL}`NB|Om1Rw!O z01|)%AOT1K5_r1^>_%>F>}~FC{X6vkf4dqM)&>%Q1Rw!O01|)%AOT1K5`Y9C0Z0H6 zxQ+ny|G$n341)w90Z0H6fCL}`NB|Om1Rw!O01|)%-Yx>+`u|S!4>zL!5&fs=-$ws3 z`X}H59*_Ve00}?>kN_kA2|xmn03-kjKmw2eB=GtPM0d76h&ryL>Q5|vs$1B*x3(Tc z$ExXc-LsIdY;Qe|s$*T#9p99#v(S56TgOpVANyw4RAv7>`MpgLEO)!6Wy-$kI%l!J z9N9XIn#&yg`Dqv)uK({uzqb+ndGu$|zmEQA^n1}ifBhANIYI)E03-kjKmw2eBmfCO z0+0YC00}?>kia>C=++03m05tDcefryRwn^&eP!!$kN_kA2|xmn03`5h zCGgc-+mG+v&*I=Kslzz(|!m*0`grhGnnM*iBF}5Q1n7I-lT%rbj zqM!wLuOz{!YRK-)(;uAb%9h2jlsjm-eTq^w8bk^pE7ObR5+D_=KO@xEb{8E*gdKb8MooJ1MM(%-e}B(MD38sIZ1=VzL<%74 z;X+1Q^4M(D0+zGL7J&pGs(N7MA1{SHdKpIdNsf~eApD>`?Ax}u^fxQdUCQ-@v9WV+ z^^!a5NW)>|;=X1pa3VwsAoVY>xeHcgsr;1#mn_2Zi(P&xeB&!x5zE6=hH#aP^b#O| z1G5OGhJ0yNL4S@-LUf79)-0`}_B&|~xOO|6bzr=HB18%x1sF-66GQaHW+t;7yq?Ib zO+UfOxP#6w(DOvfF`49$5+In1y8$FQUSbM$Qsj2W`iA-&T02aIB2^_8X+|K2^B*Ea z3Lvz7BttU%w}vMLj#39++f?~eAZN^_Q?nFwMB~8W$A2XfATJIGK^hR8EBx8jd^|e2 z+_GFq&`%hC1$vI+$U8~tFDi%u3Lqom7zLoYM0n0&8m~n7&1kP!uomSC*1DQM(Dt;D z<>V3|B6~&9tPJt_v8|xO{-2|=YKRRel0Teekckw+TC78H8X)8ut|-s&uYX8att8IQ zD>dY|CVygZl9c{Ky{^|)!zD)|AiSVZxGLs5d_X8B7|4*weDPwUtMT666P`IB7~rDQ z%rZm@AZg*}P;zV9CAoV$;r{_!`u7a&FRp>8#s3EaAOFi*EfOHYCeDDtdDD6hKc4nFL<%6`a0J^OJ%7Qld0NS~87i9&rq6^*PXBx<6_|iLu7s%8bk^p1k137>DDvPwJg`wMt<}qKqL0E zcV~lionsJ@xtE>O5+J*0*Pf(iIVp>H&MZ<4@*tEyG5EDb=zlI!T>%`u_5F1sL<%6a zwdqONiEy6MOhn5OVW-UE@{$R~^NUniM#+a}tUQtuAS&Dz^;PGtziNmiJ9OS#r!X`Q zqlvMZGWK=Gch7~sw@Q82k8@yomXI+xpdbjB18%xh|M?sVfn3+_kB*76geQY z-e?!!SH0IIXNr=DQ%RnM5+J)xgt~EZjV*_O6O)i8gvXv7Mh&-ndckMTxv$$#;8-F= z3LsBG8jju{-36YDMkTZ28@J1)$Y;WGw#f{;f7QoBZGYDiAh!w~aapHSs0zTHCmv45 zSMLA5wOm3j>@;QASZP*5J}QU-3Lsa|YQ_LS)r!9Yz+j^u(RT;l^Lu<#;|z8Cjw;RV zt$7k4v<9g|lzHN{P=H0>n{Su&-@JbcnS)p+-KrvLx| diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/IssuerRevocationPublicKey index 985bbf417..4d36cad18 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/IssuerRevocationPublicKey +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/IssuerRevocationPublicKey @@ -1,5 +1,5 @@ -----BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEdtoEVkZA2hvW7Mv6qT4KPgvn1PY8Y6bg -9crbesbtreIp4GlpXch//H+MazEww9pX02fGEhWOrlbFvlYYK4GqVPjS1lTYwTWI -5/irOyTNdRvkPr6C3CWsbyX3rNnzWSkY +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEfDgje7iiTZQ/7ZljIoyOf+AiYXuvHZUG +CohejruX2TTz0uBIRQeSAh55zvv9628DMOcll0DXUrykdccjUqZBA9uSuYFRaANm +IhqLp7VFNB2gMIFcMLJ5SwexnZoJKdK7 -----END PUBLIC KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem index 6047e9ae5..3d82333d8 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFjCCAb2gAwIBAgIUYyc2soSqUtWVHTOtud7D1FbCHp0wCgYIKoZIzj0EAwIw +MIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTM2MDcyNjA1NDYwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEM/GelSlifY6+rMOE3G95SXF+ -dTHpG8j5cYK82EVCaLCSvNlCKgpupuQnbkLy+V6dgf9tKSnEsZgiHeB6AyJK/6NF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR +ynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FHKG9YL6OC86y5FIXpqte7bOXSD8MAoGCCqGSM49BAMCA0cAMEQCIA9iMqQ/aJiC -a++ft4tN7io83jB17/fzG3BRC9soRR3bAiALgWNYk5118DKTkhFdJVQ0VIoopEtq -Gzi+/j4j7fu/wQ== +FCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq +m2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd +zQkhznMIF4SBF4k= -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/keystore/198a5af9008e2b0127f3120a5fa4330bc2d45b0e12c2e5c42e4f7eadfe36164c_sk b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/keystore/198a5af9008e2b0127f3120a5fa4330bc2d45b0e12c2e5c42e4f7eadfe36164c_sk deleted file mode 100644 index 0f6412972..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/keystore/198a5af9008e2b0127f3120a5fa4330bc2d45b0e12c2e5c42e4f7eadfe36164c_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgQlcrAY3FzkoVNDry -JXmZlklG85S9ing69LjKdBbGHdWhRANCAAQMeHLxz5qHVdDv2MySGh2A9T3ecotb -QzBo081M1Y6DXM8/iukYfGFvMU1nSMDkM0WQNBZhbS2xoSvvIAmcG2u5 ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/keystore/2d9968bdb307fb3b5f163356cfd0ec68bb71d49cde36019cc47bc66e0ab07334_sk b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/keystore/2d9968bdb307fb3b5f163356cfd0ec68bb71d49cde36019cc47bc66e0ab07334_sk new file mode 100644 index 000000000..acd48b161 --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/keystore/2d9968bdb307fb3b5f163356cfd0ec68bb71d49cde36019cc47bc66e0ab07334_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgBpFRooCgfaUyuGxv +CvHiJSyR4TWRZbvzV1bshc0NiFChRANCAASjHsVfD8ZmpLPjsQ3ZTor7p6rp4uUf +RnXMI8Z8szuVp3sJrlqhYOQu9sg8ZzEJAa0wMKvhr0WqY2D62BWk4LiQ +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/signcerts/cert.pem index 3c8b73fbd..5dcf256ed 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/signcerts/cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/signcerts/cert.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICPDCCAeKgAwIBAgIUduy0pkjS5yHnwECV0MXCTN9mGLMwCgYIKoZIzj0EAwIw +MIICPDCCAeKgAwIBAgIUQmMe0DXdDe2rU3hqsdwQsR2bPZowCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDcwMFoXDTIyMDczMDA1NTIwMFowXTELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTIzMDgwNDA2MDcwMFowXTELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGY2xpZW50MQ4wDAYDVQQDEwVhZG1pbjBZMBMGByqG -SM49AgEGCCqGSM49AwEHA0IABAx4cvHPmodV0O/YzJIaHYD1Pd5yi1tDMGjTzUzV -joNczz+K6Rh8YW8xTWdIwOQzRZA0FmFtLbGhK+8gCZwba7mjdTBzMA4GA1UdDwEB -/wQEAwIHgDAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRQUEsxidtjPaZG3pJneFyW -yxlzEjAfBgNVHSMEGDAWgBRyhvWC+jgvOsuRSF6arXu2zl0g/DATBgNVHREEDDAK -gghzYW5uaXNoMTAKBggqhkjOPQQDAgNIADBFAiEAqKp6LIfQBOAAt2q3HgWhaOcf -ukEqqJWlOoBD7wqd3NwCICWadcAzY5miwVtWbdb87ZPNP35Vlk4lcUvBL/771p4l +SM49AgEGCCqGSM49AwEHA0IABKMexV8Pxmaks+OxDdlOivunquni5R9Gdcwjxnyz +O5WnewmuWqFg5C72yDxnMQkBrTAwq+GvRapjYPrYFaTguJCjdTBzMA4GA1UdDwEB +/wQEAwIHgDAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBS0kfusY9DIDNzzmuiWVY0L +rhrbCDAfBgNVHSMEGDAWgBQqEdSZb30F3rAKZ4lFrXItXF4jjDATBgNVHREEDDAK +gghzYW5uaXNoMTAKBggqhkjOPQQDAgNIADBFAiEAq4e0IWxoaWW2GOjoUZJEvBlC +IcJqQEUZUw4Bp4vYk28CIGBL8e8+rekcKqNG6J0kWKKu1xV4XYfEIR2DpHCbVM8V -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/tlscacerts/ca.crt b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/tlscacerts/ca.crt index 6047e9ae5..3d82333d8 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/tlscacerts/ca.crt +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/tlscacerts/ca.crt @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFjCCAb2gAwIBAgIUYyc2soSqUtWVHTOtud7D1FbCHp0wCgYIKoZIzj0EAwIw +MIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTM2MDcyNjA1NDYwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEM/GelSlifY6+rMOE3G95SXF+ -dTHpG8j5cYK82EVCaLCSvNlCKgpupuQnbkLy+V6dgf9tKSnEsZgiHeB6AyJK/6NF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR +ynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FHKG9YL6OC86y5FIXpqte7bOXSD8MAoGCCqGSM49BAMCA0cAMEQCIA9iMqQ/aJiC -a++ft4tN7io83jB17/fzG3BRC9soRR3bAiALgWNYk5118DKTkhFdJVQ0VIoopEtq -Gzi+/j4j7fu/wQ== +FCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq +m2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd +zQkhznMIF4SBF4k= -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/IssuerPublicKey index 2acebf637bbdfb644bec49d966c99ce34ebb12b4..e4e39a4683359596c3c6a9ef67aed4995c58c786 100644 GIT binary patch delta 810 zcmV+_1J(S?2FnJJE`Q!2;V{_*FQmi?(B>(|!m*0`grhGnnM*iBF}5Q1n7I-lT%rbj zqM!wLuOz{!YRK-)(;uAb%9h2jlsjm-eTq^w8bk^pE7ObR5+D_=KO@xEb{8E*gdKb8MooJ1MM(%-e}B(MD38sIZ1=VzL<%74 z;X+1Q^4M(D0+zGL7J&pGs(N7MA1{SHdKpIdNsf~eApD>`?Ax}u^fxQdUCQ-@v9WV+ z^^!a5NW)>|;=X1pa3VwsAoVY>xeHcgsr;1#mn_2Zi(P&xeB&!x5zE6=hH#aP^b#O| z1G5OGhJ0yNL4S@-LUf79)-0`}_B&|~xOO|6bzr=HB18%x1sF-66GQaHW+t;7yq?Ib zO+UfOxP#6w(DOvfF`49$5+In1y8$FQUSbM$Qsj2W`iA-&T02aIB2^_8X+|K2^B*Ea z3Lvz7BttU%w}vMLj#39++f?~eAZN^_Q?nFwMB~8W$A2XfATJIGK^hR8EBx8jd^|e2 z+_GFq&`%hC1$vI+$U8~tFDi%u3Lqom7zLoYM0n0&8m~n7&1kP!uomSC*1DQM(Dt;D z<>V3|B6~&9tPJt_v8|xO{-2|=YKRRel0Teekckw+TC78H8X)8ut|-s&uYX8att8IQ zD>dY|CVygZl9c{Ky{^|)!zD)|AiSVZxGLs5d_X8B7|4*weDPwUtMT666P`IB7~rDQ z%rZm@AZg*}P;zV9CAoV$;r{_!`u7a&FRp>8#s3EaAOFi*EfOHYCeDDtdDD6hKc4nFL<%6`a0J^OJ%7Qld0NS~87i9&rq6^*PXBx<6_|iLu7s%8bk^p1k137>DDvPwJg`wMt<}qKqL0E zcV~lionsJ@xtE>O5+J*0*Pf(iIVp>H&MZ<4@*tEyG5EDb=zlI!T>%`u_5F1sL<%6a zwdqONiEy6MOhn5OVW-UE@{$R~^NUniM#+a}tUQtuAS&Dz^;PGtziNmiJ9OS#r!X`Q zqlvMZGWK=Gch7~sw@Q82k8@yomXI+xpdbjB18%xh|M?sVfn3+_kB*76geQY z-e?!!SH0IIXNr=DQ%RnM5+J)xgt~EZjV*_O6O)i8gvXv7Mh&-ndckMTxv$$#;8-F= z3LsBG8jju{-36YDMkTZ28@J1)$Y;WGw#f{;f7QoBZGYDiAh!w~aapHSs0zTHCmv45 zSMLA5wOm3j>@;QASZP*5J}QU-3Lsa|YQ_LS)r!9Yz+j^u(RT;l^Lu<#;|z8Cjw;RV zt$7k4v<9g|lzHN{P=H0>n{Su&-@JbcnS)p+-KrvLx| diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/IssuerRevocationPublicKey index 985bbf417..4d36cad18 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/IssuerRevocationPublicKey +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/IssuerRevocationPublicKey @@ -1,5 +1,5 @@ -----BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEdtoEVkZA2hvW7Mv6qT4KPgvn1PY8Y6bg -9crbesbtreIp4GlpXch//H+MazEww9pX02fGEhWOrlbFvlYYK4GqVPjS1lTYwTWI -5/irOyTNdRvkPr6C3CWsbyX3rNnzWSkY +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEfDgje7iiTZQ/7ZljIoyOf+AiYXuvHZUG +CohejruX2TTz0uBIRQeSAh55zvv9628DMOcll0DXUrykdccjUqZBA9uSuYFRaANm +IhqLp7VFNB2gMIFcMLJ5SwexnZoJKdK7 -----END PUBLIC KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem index 6047e9ae5..3d82333d8 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFjCCAb2gAwIBAgIUYyc2soSqUtWVHTOtud7D1FbCHp0wCgYIKoZIzj0EAwIw +MIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTM2MDcyNjA1NDYwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEM/GelSlifY6+rMOE3G95SXF+ -dTHpG8j5cYK82EVCaLCSvNlCKgpupuQnbkLy+V6dgf9tKSnEsZgiHeB6AyJK/6NF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR +ynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FHKG9YL6OC86y5FIXpqte7bOXSD8MAoGCCqGSM49BAMCA0cAMEQCIA9iMqQ/aJiC -a++ft4tN7io83jB17/fzG3BRC9soRR3bAiALgWNYk5118DKTkhFdJVQ0VIoopEtq -Gzi+/j4j7fu/wQ== +FCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq +m2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd +zQkhznMIF4SBF4k= -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/keystore/085360b244a3d2dbf494a2390df4fd0e38469608ecb0f9c4f235e543c303d127_sk b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/keystore/085360b244a3d2dbf494a2390df4fd0e38469608ecb0f9c4f235e543c303d127_sk deleted file mode 100644 index 70742b623..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/keystore/085360b244a3d2dbf494a2390df4fd0e38469608ecb0f9c4f235e543c303d127_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQggNbFvWKX5tF1uNd3 -BUCLCt3Nu/mmFpqbwb0oHrYtjUShRANCAATZMnSXQo+0qhqMnrblQ94lhLluoAyL -l1D5+bONDfEvQOHUOG+/W/Jj9Eu3U0L+Me4swW53vFbbG4kV/6XC1Y2Q ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/keystore/5bee0474d81dd757d01966e5b6e96ebc18782d275d3eae560dccb2667848adfe_sk b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/keystore/5bee0474d81dd757d01966e5b6e96ebc18782d275d3eae560dccb2667848adfe_sk new file mode 100644 index 000000000..d7cf7c11f --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/keystore/5bee0474d81dd757d01966e5b6e96ebc18782d275d3eae560dccb2667848adfe_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgV+nkFEhw/PERweWL +nT4Nazo1OA5/A7HQnVyrqnzUX62hRANCAAQyfaO8RRQmI7651pe9IbSGbHg9txtA +JPKQzpr3c0fBYWKEZfSGhTaegomc6HTT+F5xi2EuaVddZ6q0p2Xx2dJF +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/signcerts/cert.pem index 072eecfb3..bfd7eb01b 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/signcerts/cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/signcerts/cert.pem @@ -1,17 +1,17 @@ -----BEGIN CERTIFICATE----- -MIICojCCAkmgAwIBAgIUMcxcQMXCTq8iViBdU+DSbu5c3dswCgYIKoZIzj0EAwIw +MIICojCCAkmgAwIBAgIUGx9PRK27FNGDU7MvKuwxaQetZ18wCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDcwMFoXDTIyMDczMDA1NTIwMFowWzELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTIzMDgwNDA2MDcwMFowWzELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjENMAsGA1UECxMEcGVlcjEOMAwGA1UEAxMFcGVlcjAwWTATBgcqhkjO -PQIBBggqhkjOPQMBBwNCAATZMnSXQo+0qhqMnrblQ94lhLluoAyLl1D5+bONDfEv -QOHUOG+/W/Jj9Eu3U0L+Me4swW53vFbbG4kV/6XC1Y2Qo4HdMIHaMA4GA1UdDwEB -/wQEAwIHgDAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRezv+w23QwiaXpeXIHATj/ -bQJ0rjAfBgNVHSMEGDAWgBRyhvWC+jgvOsuRSF6arXu2zl0g/DAiBgNVHREEGzAZ +PQIBBggqhkjOPQMBBwNCAAQyfaO8RRQmI7651pe9IbSGbHg9txtAJPKQzpr3c0fB +YWKEZfSGhTaegomc6HTT+F5xi2EuaVddZ6q0p2Xx2dJFo4HdMIHaMA4GA1UdDwEB +/wQEAwIHgDAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSMT2vsLPVmqWLLlApmZfHb +JqDjiDAfBgNVHSMEGDAWgBQqEdSZb30F3rAKZ4lFrXItXF4jjDAiBgNVHREEGzAZ ghdwZWVyMC5vcmcxLm5ldHdvcmsxLmNvbTBWBggqAwQFBgcIAQRKeyJhdHRycyI6 eyJoZi5BZmZpbGlhdGlvbiI6IiIsImhmLkVucm9sbG1lbnRJRCI6InBlZXIwIiwi -aGYuVHlwZSI6InBlZXIifX0wCgYIKoZIzj0EAwIDRwAwRAIgOrVfonbB8xvEO3b7 -nMN8wL+ua5UvFehJyGKDHHStaDYCIG5DVtN6Zm7CBttmqBRzukyS0igjzpOM1sqO -Se/xA/xx +aGYuVHlwZSI6InBlZXIifX0wCgYIKoZIzj0EAwIDRwAwRAIgZQ5a3mzJZ+zfP9rO +cYOoXD9P5jxMhRcLBPPgGg/bKnYCICr3qeJgsxX+EiAWgkJ3GxWc+ZQFssm9jMbA +r1Xbf+KI -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/IssuerPublicKey index 2acebf637bbdfb644bec49d966c99ce34ebb12b4..e4e39a4683359596c3c6a9ef67aed4995c58c786 100644 GIT binary patch delta 810 zcmV+_1J(S?2FnJJE`Q!2;V{_*FQmi?(B>(|!m*0`grhGnnM*iBF}5Q1n7I-lT%rbj zqM!wLuOz{!YRK-)(;uAb%9h2jlsjm-eTq^w8bk^pE7ObR5+D_=KO@xEb{8E*gdKb8MooJ1MM(%-e}B(MD38sIZ1=VzL<%74 z;X+1Q^4M(D0+zGL7J&pGs(N7MA1{SHdKpIdNsf~eApD>`?Ax}u^fxQdUCQ-@v9WV+ z^^!a5NW)>|;=X1pa3VwsAoVY>xeHcgsr;1#mn_2Zi(P&xeB&!x5zE6=hH#aP^b#O| z1G5OGhJ0yNL4S@-LUf79)-0`}_B&|~xOO|6bzr=HB18%x1sF-66GQaHW+t;7yq?Ib zO+UfOxP#6w(DOvfF`49$5+In1y8$FQUSbM$Qsj2W`iA-&T02aIB2^_8X+|K2^B*Ea z3Lvz7BttU%w}vMLj#39++f?~eAZN^_Q?nFwMB~8W$A2XfATJIGK^hR8EBx8jd^|e2 z+_GFq&`%hC1$vI+$U8~tFDi%u3Lqom7zLoYM0n0&8m~n7&1kP!uomSC*1DQM(Dt;D z<>V3|B6~&9tPJt_v8|xO{-2|=YKRRel0Teekckw+TC78H8X)8ut|-s&uYX8att8IQ zD>dY|CVygZl9c{Ky{^|)!zD)|AiSVZxGLs5d_X8B7|4*weDPwUtMT666P`IB7~rDQ z%rZm@AZg*}P;zV9CAoV$;r{_!`u7a&FRp>8#s3EaAOFi*EfOHYCeDDtdDD6hKc4nFL<%6`a0J^OJ%7Qld0NS~87i9&rq6^*PXBx<6_|iLu7s%8bk^p1k137>DDvPwJg`wMt<}qKqL0E zcV~lionsJ@xtE>O5+J*0*Pf(iIVp>H&MZ<4@*tEyG5EDb=zlI!T>%`u_5F1sL<%6a zwdqONiEy6MOhn5OVW-UE@{$R~^NUniM#+a}tUQtuAS&Dz^;PGtziNmiJ9OS#r!X`Q zqlvMZGWK=Gch7~sw@Q82k8@yomXI+xpdbjB18%xh|M?sVfn3+_kB*76geQY z-e?!!SH0IIXNr=DQ%RnM5+J)xgt~EZjV*_O6O)i8gvXv7Mh&-ndckMTxv$$#;8-F= z3LsBG8jju{-36YDMkTZ28@J1)$Y;WGw#f{;f7QoBZGYDiAh!w~aapHSs0zTHCmv45 zSMLA5wOm3j>@;QASZP*5J}QU-3Lsa|YQ_LS)r!9Yz+j^u(RT;l^Lu<#;|z8Cjw;RV zt$7k4v<9g|lzHN{P=H0>n{Su&-@JbcnS)p+-KrvLx| diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/IssuerRevocationPublicKey index 985bbf417..4d36cad18 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/IssuerRevocationPublicKey +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/IssuerRevocationPublicKey @@ -1,5 +1,5 @@ -----BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEdtoEVkZA2hvW7Mv6qT4KPgvn1PY8Y6bg -9crbesbtreIp4GlpXch//H+MazEww9pX02fGEhWOrlbFvlYYK4GqVPjS1lTYwTWI -5/irOyTNdRvkPr6C3CWsbyX3rNnzWSkY +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEfDgje7iiTZQ/7ZljIoyOf+AiYXuvHZUG +CohejruX2TTz0uBIRQeSAh55zvv9628DMOcll0DXUrykdccjUqZBA9uSuYFRaANm +IhqLp7VFNB2gMIFcMLJ5SwexnZoJKdK7 -----END PUBLIC KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/ca.crt b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/ca.crt index 6047e9ae5..3d82333d8 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/ca.crt +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/ca.crt @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFjCCAb2gAwIBAgIUYyc2soSqUtWVHTOtud7D1FbCHp0wCgYIKoZIzj0EAwIw +MIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTM2MDcyNjA1NDYwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEM/GelSlifY6+rMOE3G95SXF+ -dTHpG8j5cYK82EVCaLCSvNlCKgpupuQnbkLy+V6dgf9tKSnEsZgiHeB6AyJK/6NF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR +ynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FHKG9YL6OC86y5FIXpqte7bOXSD8MAoGCCqGSM49BAMCA0cAMEQCIA9iMqQ/aJiC -a++ft4tN7io83jB17/fzG3BRC9soRR3bAiALgWNYk5118DKTkhFdJVQ0VIoopEtq -Gzi+/j4j7fu/wQ== +FCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq +m2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd +zQkhznMIF4SBF4k= -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/keystore/2c73ce9f512e2c8d611a66199536fe4325325082313dce4d076625c185f0140e_sk b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/keystore/2c73ce9f512e2c8d611a66199536fe4325325082313dce4d076625c185f0140e_sk new file mode 100644 index 000000000..37c1a906c --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/keystore/2c73ce9f512e2c8d611a66199536fe4325325082313dce4d076625c185f0140e_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgJdkerHx85MCgRVir +QpEPRVneKQ4quSYLbVQXkWwn5cihRANCAAQd4J9DHA0gaLfTXoCNTxb1FuS76qxc +R0WPRpS+bXzAKCsQYFGG9OhA6Jrxfzl3Oc00ifDzjCvTUsgzFG1Arzxg +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/keystore/5ef7cb27d6b4866bc9d704c91a90ce16937ec46dece2734ed9349d491a59e24d_sk b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/keystore/5ef7cb27d6b4866bc9d704c91a90ce16937ec46dece2734ed9349d491a59e24d_sk deleted file mode 100644 index 6a52eefe7..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/keystore/5ef7cb27d6b4866bc9d704c91a90ce16937ec46dece2734ed9349d491a59e24d_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgWR2NFSPzYdY1RVNH -BZiLLCHG6vN2zcHaVMZ5blVW/W6hRANCAAQ49ZM9Y1fVHlzYp8LZTdbW4JROYNfI -rUdRZH/UsltlPN4S2eOeTB2nPKPt64r66TEzMYyNIx/n2bix105qq4Jv ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/server.crt b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/server.crt index 69e8de007..a7f62ff29 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/server.crt +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/server.crt @@ -1,18 +1,18 @@ -----BEGIN CERTIFICATE----- -MIICzjCCAnWgAwIBAgIUb5it42SbEl1OK6uZ6752qdVsSBcwCgYIKoZIzj0EAwIw +MIICzjCCAnWgAwIBAgIUJ+YiGvU7Dp31vYSQHeWWsPEGfxIwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDcwMFoXDTIyMDczMDA1NTIwMFowWzELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTIzMDgwNDA2MDcwMFowWzELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjENMAsGA1UECxMEcGVlcjEOMAwGA1UEAxMFcGVlcjAwWTATBgcqhkjO -PQIBBggqhkjOPQMBBwNCAAQ49ZM9Y1fVHlzYp8LZTdbW4JROYNfIrUdRZH/Usltl -PN4S2eOeTB2nPKPt64r66TEzMYyNIx/n2bix105qq4Jvo4IBCDCCAQQwDgYDVR0P +PQIBBggqhkjOPQMBBwNCAAQd4J9DHA0gaLfTXoCNTxb1FuS76qxcR0WPRpS+bXzA +KCsQYFGG9OhA6Jrxfzl3Oc00ifDzjCvTUsgzFG1Arzxgo4IBCDCCAQQwDgYDVR0P AQH/BAQDAgOoMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMB -Af8EAjAAMB0GA1UdDgQWBBQlEZldu7ZOFwpXlcbwCzuLxQRigzAfBgNVHSMEGDAW -gBRyhvWC+jgvOsuRSF6arXu2zl0g/DAtBgNVHREEJjAkghdwZWVyMC5vcmcxLm5l +Af8EAjAAMB0GA1UdDgQWBBRPCW7tnJAattoWnkg/yMo62an44jAfBgNVHSMEGDAW +gBQqEdSZb30F3rAKZ4lFrXItXF4jjDAtBgNVHREEJjAkghdwZWVyMC5vcmcxLm5l dHdvcmsxLmNvbYIJbG9jYWxob3N0MFYGCCoDBAUGBwgBBEp7ImF0dHJzIjp7Imhm LkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoicGVlcjAiLCJoZi5U -eXBlIjoicGVlciJ9fTAKBggqhkjOPQQDAgNHADBEAiB+vYGMBqkXA+jSaYemxr6v -YSH4dGl87tAPxpLMd4CwvwIgYdzixsbScvcY7BkzhsoJCO3J2VKejybIL/4TSEIN -yWo= +eXBlIjoicGVlciJ9fTAKBggqhkjOPQQDAgNHADBEAiBcC+dc32qMz2jPD+KZEJt0 +UnCY1DNu8yH5PV8hZdDdogIgdYzWehSDNyubl3tVlfsGHr4ahCKekvc7xPvTpN+J +rJg= -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/server.key b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/server.key index 6a52eefe7..37c1a906c 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/server.key +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/server.key @@ -1,5 +1,5 @@ -----BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgWR2NFSPzYdY1RVNH -BZiLLCHG6vN2zcHaVMZ5blVW/W6hRANCAAQ49ZM9Y1fVHlzYp8LZTdbW4JROYNfI -rUdRZH/UsltlPN4S2eOeTB2nPKPt64r66TEzMYyNIx/n2bix105qq4Jv +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgJdkerHx85MCgRVir +QpEPRVneKQ4quSYLbVQXkWwn5cihRANCAAQd4J9DHA0gaLfTXoCNTxb1FuS76qxc +R0WPRpS+bXzAKCsQYFGG9OhA6Jrxfzl3Oc00ifDzjCvTUsgzFG1Arzxg -----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/signcerts/cert.pem index 69e8de007..a7f62ff29 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/signcerts/cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/signcerts/cert.pem @@ -1,18 +1,18 @@ -----BEGIN CERTIFICATE----- -MIICzjCCAnWgAwIBAgIUb5it42SbEl1OK6uZ6752qdVsSBcwCgYIKoZIzj0EAwIw +MIICzjCCAnWgAwIBAgIUJ+YiGvU7Dp31vYSQHeWWsPEGfxIwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDcwMFoXDTIyMDczMDA1NTIwMFowWzELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTIzMDgwNDA2MDcwMFowWzELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjENMAsGA1UECxMEcGVlcjEOMAwGA1UEAxMFcGVlcjAwWTATBgcqhkjO -PQIBBggqhkjOPQMBBwNCAAQ49ZM9Y1fVHlzYp8LZTdbW4JROYNfIrUdRZH/Usltl -PN4S2eOeTB2nPKPt64r66TEzMYyNIx/n2bix105qq4Jvo4IBCDCCAQQwDgYDVR0P +PQIBBggqhkjOPQMBBwNCAAQd4J9DHA0gaLfTXoCNTxb1FuS76qxcR0WPRpS+bXzA +KCsQYFGG9OhA6Jrxfzl3Oc00ifDzjCvTUsgzFG1Arzxgo4IBCDCCAQQwDgYDVR0P AQH/BAQDAgOoMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMB -Af8EAjAAMB0GA1UdDgQWBBQlEZldu7ZOFwpXlcbwCzuLxQRigzAfBgNVHSMEGDAW -gBRyhvWC+jgvOsuRSF6arXu2zl0g/DAtBgNVHREEJjAkghdwZWVyMC5vcmcxLm5l +Af8EAjAAMB0GA1UdDgQWBBRPCW7tnJAattoWnkg/yMo62an44jAfBgNVHSMEGDAW +gBQqEdSZb30F3rAKZ4lFrXItXF4jjDAtBgNVHREEJjAkghdwZWVyMC5vcmcxLm5l dHdvcmsxLmNvbYIJbG9jYWxob3N0MFYGCCoDBAUGBwgBBEp7ImF0dHJzIjp7Imhm LkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoicGVlcjAiLCJoZi5U -eXBlIjoicGVlciJ9fTAKBggqhkjOPQQDAgNHADBEAiB+vYGMBqkXA+jSaYemxr6v -YSH4dGl87tAPxpLMd4CwvwIgYdzixsbScvcY7BkzhsoJCO3J2VKejybIL/4TSEIN -yWo= +eXBlIjoicGVlciJ9fTAKBggqhkjOPQQDAgNHADBEAiBcC+dc32qMz2jPD+KZEJt0 +UnCY1DNu8yH5PV8hZdDdogIgdYzWehSDNyubl3tVlfsGHr4ahCKekvc7xPvTpN+J +rJg= -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/tlscacerts/tls-localhost-7054-ca-org1-network1-com.pem b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/tlscacerts/tls-localhost-7054-ca-org1-network1-com.pem index 6047e9ae5..3d82333d8 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/tlscacerts/tls-localhost-7054-ca-org1-network1-com.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/tlscacerts/tls-localhost-7054-ca-org1-network1-com.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFjCCAb2gAwIBAgIUYyc2soSqUtWVHTOtud7D1FbCHp0wCgYIKoZIzj0EAwIw +MIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTM2MDcyNjA1NDYwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEM/GelSlifY6+rMOE3G95SXF+ -dTHpG8j5cYK82EVCaLCSvNlCKgpupuQnbkLy+V6dgf9tKSnEsZgiHeB6AyJK/6NF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR +ynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FHKG9YL6OC86y5FIXpqte7bOXSD8MAoGCCqGSM49BAMCA0cAMEQCIA9iMqQ/aJiC -a++ft4tN7io83jB17/fzG3BRC9soRR3bAiALgWNYk5118DKTkhFdJVQ0VIoopEtq -Gzi+/j4j7fu/wQ== +FCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq +m2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd +zQkhznMIF4SBF4k= -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/tlsca/tlsca.org1.network1.com-cert.pem b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/tlsca/tlsca.org1.network1.com-cert.pem index 6047e9ae5..3d82333d8 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/tlsca/tlsca.org1.network1.com-cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/tlsca/tlsca.org1.network1.com-cert.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFjCCAb2gAwIBAgIUYyc2soSqUtWVHTOtud7D1FbCHp0wCgYIKoZIzj0EAwIw +MIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTM2MDcyNjA1NDYwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEM/GelSlifY6+rMOE3G95SXF+ -dTHpG8j5cYK82EVCaLCSvNlCKgpupuQnbkLy+V6dgf9tKSnEsZgiHeB6AyJK/6NF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR +ynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FHKG9YL6OC86y5FIXpqte7bOXSD8MAoGCCqGSM49BAMCA0cAMEQCIA9iMqQ/aJiC -a++ft4tN7io83jB17/fzG3BRC9soRR3bAiALgWNYk5118DKTkhFdJVQ0VIoopEtq -Gzi+/j4j7fu/wQ== +FCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq +m2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd +zQkhznMIF4SBF4k= -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/IssuerPublicKey index 2acebf637bbdfb644bec49d966c99ce34ebb12b4..e4e39a4683359596c3c6a9ef67aed4995c58c786 100644 GIT binary patch delta 810 zcmV+_1J(S?2FnJJE`Q!2;V{_*FQmi?(B>(|!m*0`grhGnnM*iBF}5Q1n7I-lT%rbj zqM!wLuOz{!YRK-)(;uAb%9h2jlsjm-eTq^w8bk^pE7ObR5+D_=KO@xEb{8E*gdKb8MooJ1MM(%-e}B(MD38sIZ1=VzL<%74 z;X+1Q^4M(D0+zGL7J&pGs(N7MA1{SHdKpIdNsf~eApD>`?Ax}u^fxQdUCQ-@v9WV+ z^^!a5NW)>|;=X1pa3VwsAoVY>xeHcgsr;1#mn_2Zi(P&xeB&!x5zE6=hH#aP^b#O| z1G5OGhJ0yNL4S@-LUf79)-0`}_B&|~xOO|6bzr=HB18%x1sF-66GQaHW+t;7yq?Ib zO+UfOxP#6w(DOvfF`49$5+In1y8$FQUSbM$Qsj2W`iA-&T02aIB2^_8X+|K2^B*Ea z3Lvz7BttU%w}vMLj#39++f?~eAZN^_Q?nFwMB~8W$A2XfATJIGK^hR8EBx8jd^|e2 z+_GFq&`%hC1$vI+$U8~tFDi%u3Lqom7zLoYM0n0&8m~n7&1kP!uomSC*1DQM(Dt;D z<>V3|B6~&9tPJt_v8|xO{-2|=YKRRel0Teekckw+TC78H8X)8ut|-s&uYX8att8IQ zD>dY|CVygZl9c{Ky{^|)!zD)|AiSVZxGLs5d_X8B7|4*weDPwUtMT666P`IB7~rDQ z%rZm@AZg*}P;zV9CAoV$;r{_!`u7a&FRp>8#s3EaAOFi*EfOHYCeDDtdDD6hKc4nFL<%6`a0J^OJ%7Qld0NS~87i9&rq6^*PXBx<6_|iLu7s%8bk^p1k137>DDvPwJg`wMt<}qKqL0E zcV~lionsJ@xtE>O5+J*0*Pf(iIVp>H&MZ<4@*tEyG5EDb=zlI!T>%`u_5F1sL<%6a zwdqONiEy6MOhn5OVW-UE@{$R~^NUniM#+a}tUQtuAS&Dz^;PGtziNmiJ9OS#r!X`Q zqlvMZGWK=Gch7~sw@Q82k8@yomXI+xpdbjB18%xh|M?sVfn3+_kB*76geQY z-e?!!SH0IIXNr=DQ%RnM5+J)xgt~EZjV*_O6O)i8gvXv7Mh&-ndckMTxv$$#;8-F= z3LsBG8jju{-36YDMkTZ28@J1)$Y;WGw#f{;f7QoBZGYDiAh!w~aapHSs0zTHCmv45 zSMLA5wOm3j>@;QASZP*5J}QU-3Lsa|YQ_LS)r!9Yz+j^u(RT;l^Lu<#;|z8Cjw;RV zt$7k4v<9g|lzHN{P=H0>n{Su&-@JbcnS)p+-KrvLx| diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/IssuerRevocationPublicKey index 985bbf417..4d36cad18 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/IssuerRevocationPublicKey +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/IssuerRevocationPublicKey @@ -1,5 +1,5 @@ -----BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEdtoEVkZA2hvW7Mv6qT4KPgvn1PY8Y6bg -9crbesbtreIp4GlpXch//H+MazEww9pX02fGEhWOrlbFvlYYK4GqVPjS1lTYwTWI -5/irOyTNdRvkPr6C3CWsbyX3rNnzWSkY +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEfDgje7iiTZQ/7ZljIoyOf+AiYXuvHZUG +CohejruX2TTz0uBIRQeSAh55zvv9628DMOcll0DXUrykdccjUqZBA9uSuYFRaANm +IhqLp7VFNB2gMIFcMLJ5SwexnZoJKdK7 -----END PUBLIC KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem index 6047e9ae5..3d82333d8 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFjCCAb2gAwIBAgIUYyc2soSqUtWVHTOtud7D1FbCHp0wCgYIKoZIzj0EAwIw +MIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTM2MDcyNjA1NDYwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEM/GelSlifY6+rMOE3G95SXF+ -dTHpG8j5cYK82EVCaLCSvNlCKgpupuQnbkLy+V6dgf9tKSnEsZgiHeB6AyJK/6NF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR +ynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FHKG9YL6OC86y5FIXpqte7bOXSD8MAoGCCqGSM49BAMCA0cAMEQCIA9iMqQ/aJiC -a++ft4tN7io83jB17/fzG3BRC9soRR3bAiALgWNYk5118DKTkhFdJVQ0VIoopEtq -Gzi+/j4j7fu/wQ== +FCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq +m2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd +zQkhznMIF4SBF4k= -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/keystore/7a2bc768da5d5ecf5ba6e206e27cc9960303200526435bc864bd96b3e82e819f_sk b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/keystore/7a2bc768da5d5ecf5ba6e206e27cc9960303200526435bc864bd96b3e82e819f_sk deleted file mode 100644 index 5d366c60f..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/keystore/7a2bc768da5d5ecf5ba6e206e27cc9960303200526435bc864bd96b3e82e819f_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg9OVkGkiCVJdhddeQ -y5+83KLJ2RuJ219WWzQ/TuahODGhRANCAARfhtM9Yw4Bmcm6a/zcnSQBSPthHH1I -sXmQCYMRNrrKVU5Aa5nClGmBFGUtl4WOI0YNFLYkfHFl+tJa1QQouHEM ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/keystore/b5ff454e5ceb3f2ce336a9080e4da28fa3e3cd86b6d3a34c91c9bc163c57492e_sk b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/keystore/b5ff454e5ceb3f2ce336a9080e4da28fa3e3cd86b6d3a34c91c9bc163c57492e_sk new file mode 100644 index 000000000..89072feda --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/keystore/b5ff454e5ceb3f2ce336a9080e4da28fa3e3cd86b6d3a34c91c9bc163c57492e_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgKuP4ikGiaB8+K5gA +RlRcSlZJpfhjT7sB+O5Ppxn6ek6hRANCAARtxjT+3TcVOir+Rtl+hMJMwCdc+3Ux +bC5/wly/1t1ldebgE1zDGvP54NGhA4+ViuJq4I6P6NPIAaUngeLx6o71 +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/signcerts/cert.pem index 718c8e455..6d1724d51 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/signcerts/cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/signcerts/cert.pem @@ -1,17 +1,17 @@ -----BEGIN CERTIFICATE----- -MIICnTCCAkSgAwIBAgIUVt3GEZHXqj+2R+3UObDpQKHBxYYwCgYIKoZIzj0EAwIw +MIICnjCCAkSgAwIBAgIURCER5FrVVVngStFGSTZgpbMs/AQwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDcwMFoXDTIyMDczMDA1NTIwMFowYDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTIzMDgwNDA2MDcwMFowYDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEOMAwGA1UECxMFYWRtaW4xEjAQBgNVBAMTCW9yZzFhZG1pbjBZMBMG -ByqGSM49AgEGCCqGSM49AwEHA0IABF+G0z1jDgGZybpr/NydJAFI+2EcfUixeZAJ -gxE2uspVTkBrmcKUaYEUZS2XhY4jRg0UtiR8cWX60lrVBCi4cQyjgdMwgdAwDgYD -VR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFAVW9c1Bkf/R+78z -boG/kxNNiT8MMB8GA1UdIwQYMBaAFHKG9YL6OC86y5FIXpqte7bOXSD8MBMGA1Ud +ByqGSM49AgEGCCqGSM49AwEHA0IABG3GNP7dNxU6Kv5G2X6EwkzAJ1z7dTFsLn/C +XL/W3WV15uATXMMa8/ng0aEDj5WK4mrgjo/o08gBpSeB4vHqjvWjgdMwgdAwDgYD +VR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFChCuypAsZYhjMIG +bF9cx/FEFX6NMB8GA1UdIwQYMBaAFCoR1JlvfQXesApniUWtci1cXiOMMBMGA1Ud EQQMMAqCCHNhbm5pc2gxMFsGCCoDBAUGBwgBBE97ImF0dHJzIjp7ImhmLkFmZmls aWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoib3JnMWFkbWluIiwiaGYuVHlw -ZSI6ImFkbWluIn19MAoGCCqGSM49BAMCA0cAMEQCIBdi4blZ0T/TqKioQtc5s+tS -FTMZczqTU5Tn4YVp/ORNAiBda7Ay1CqgV0kuEh9jJ/NvZl2P+sXK5Pre4sYj60N8 -QQ== +ZSI6ImFkbWluIn19MAoGCCqGSM49BAMCA0gAMEUCIQDsuD0DKbeoidHXbfhRqpml +sHpDMGQqRDMa4dKl2B4DMwIga84gIKzPmySksXuVY4iaZVvFL64Sa7+z5CicOSXL +7Dg= -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/IssuerPublicKey index 2acebf637bbdfb644bec49d966c99ce34ebb12b4..e4e39a4683359596c3c6a9ef67aed4995c58c786 100644 GIT binary patch delta 810 zcmV+_1J(S?2FnJJE`Q!2;V{_*FQmi?(B>(|!m*0`grhGnnM*iBF}5Q1n7I-lT%rbj zqM!wLuOz{!YRK-)(;uAb%9h2jlsjm-eTq^w8bk^pE7ObR5+D_=KO@xEb{8E*gdKb8MooJ1MM(%-e}B(MD38sIZ1=VzL<%74 z;X+1Q^4M(D0+zGL7J&pGs(N7MA1{SHdKpIdNsf~eApD>`?Ax}u^fxQdUCQ-@v9WV+ z^^!a5NW)>|;=X1pa3VwsAoVY>xeHcgsr;1#mn_2Zi(P&xeB&!x5zE6=hH#aP^b#O| z1G5OGhJ0yNL4S@-LUf79)-0`}_B&|~xOO|6bzr=HB18%x1sF-66GQaHW+t;7yq?Ib zO+UfOxP#6w(DOvfF`49$5+In1y8$FQUSbM$Qsj2W`iA-&T02aIB2^_8X+|K2^B*Ea z3Lvz7BttU%w}vMLj#39++f?~eAZN^_Q?nFwMB~8W$A2XfATJIGK^hR8EBx8jd^|e2 z+_GFq&`%hC1$vI+$U8~tFDi%u3Lqom7zLoYM0n0&8m~n7&1kP!uomSC*1DQM(Dt;D z<>V3|B6~&9tPJt_v8|xO{-2|=YKRRel0Teekckw+TC78H8X)8ut|-s&uYX8att8IQ zD>dY|CVygZl9c{Ky{^|)!zD)|AiSVZxGLs5d_X8B7|4*weDPwUtMT666P`IB7~rDQ z%rZm@AZg*}P;zV9CAoV$;r{_!`u7a&FRp>8#s3EaAOFi*EfOHYCeDDtdDD6hKc4nFL<%6`a0J^OJ%7Qld0NS~87i9&rq6^*PXBx<6_|iLu7s%8bk^p1k137>DDvPwJg`wMt<}qKqL0E zcV~lionsJ@xtE>O5+J*0*Pf(iIVp>H&MZ<4@*tEyG5EDb=zlI!T>%`u_5F1sL<%6a zwdqONiEy6MOhn5OVW-UE@{$R~^NUniM#+a}tUQtuAS&Dz^;PGtziNmiJ9OS#r!X`Q zqlvMZGWK=Gch7~sw@Q82k8@yomXI+xpdbjB18%xh|M?sVfn3+_kB*76geQY z-e?!!SH0IIXNr=DQ%RnM5+J)xgt~EZjV*_O6O)i8gvXv7Mh&-ndckMTxv$$#;8-F= z3LsBG8jju{-36YDMkTZ28@J1)$Y;WGw#f{;f7QoBZGYDiAh!w~aapHSs0zTHCmv45 zSMLA5wOm3j>@;QASZP*5J}QU-3Lsa|YQ_LS)r!9Yz+j^u(RT;l^Lu<#;|z8Cjw;RV zt$7k4v<9g|lzHN{P=H0>n{Su&-@JbcnS)p+-KrvLx| diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/IssuerRevocationPublicKey index 985bbf417..4d36cad18 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/IssuerRevocationPublicKey +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/IssuerRevocationPublicKey @@ -1,5 +1,5 @@ -----BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEdtoEVkZA2hvW7Mv6qT4KPgvn1PY8Y6bg -9crbesbtreIp4GlpXch//H+MazEww9pX02fGEhWOrlbFvlYYK4GqVPjS1lTYwTWI -5/irOyTNdRvkPr6C3CWsbyX3rNnzWSkY +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEfDgje7iiTZQ/7ZljIoyOf+AiYXuvHZUG +CohejruX2TTz0uBIRQeSAh55zvv9628DMOcll0DXUrykdccjUqZBA9uSuYFRaANm +IhqLp7VFNB2gMIFcMLJ5SwexnZoJKdK7 -----END PUBLIC KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem index 6047e9ae5..3d82333d8 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFjCCAb2gAwIBAgIUYyc2soSqUtWVHTOtud7D1FbCHp0wCgYIKoZIzj0EAwIw +MIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTM2MDcyNjA1NDYwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEM/GelSlifY6+rMOE3G95SXF+ -dTHpG8j5cYK82EVCaLCSvNlCKgpupuQnbkLy+V6dgf9tKSnEsZgiHeB6AyJK/6NF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR +ynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FHKG9YL6OC86y5FIXpqte7bOXSD8MAoGCCqGSM49BAMCA0cAMEQCIA9iMqQ/aJiC -a++ft4tN7io83jB17/fzG3BRC9soRR3bAiALgWNYk5118DKTkhFdJVQ0VIoopEtq -Gzi+/j4j7fu/wQ== +FCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq +m2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd +zQkhznMIF4SBF4k= -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/keystore/43e1a75012fe2626d853745be6132512d9552ace941a60701c810771291b03ec_sk b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/keystore/43e1a75012fe2626d853745be6132512d9552ace941a60701c810771291b03ec_sk deleted file mode 100644 index cbe6b9ae1..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/keystore/43e1a75012fe2626d853745be6132512d9552ace941a60701c810771291b03ec_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgyUPe33zqIlEdM4aq -35fqlqcaVkH7uWBj/gz8WtTYVaGhRANCAASpFEGiH56bBpwHurdhLBPJF+zBGByB -y6gu70gNM6FNJk0aReIbK953WtxV5mGBGun5xIoepmYFPBaL0cD28WSw ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/keystore/d397d85065544e3fb772bf88afc89055cdf55db0fb2057032401956f9873d30a_sk b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/keystore/d397d85065544e3fb772bf88afc89055cdf55db0fb2057032401956f9873d30a_sk new file mode 100644 index 000000000..7671108a4 --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/keystore/d397d85065544e3fb772bf88afc89055cdf55db0fb2057032401956f9873d30a_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgyZonzG15+m//Lm3z +bfUyZFsW6+0g45r6Mi52+UYfu6ShRANCAATILPfXpVgatD4JPHj3eB7QJBdP/BS4 +0ZCdE0dDDBnGjXVTg1IOJqZFO7HkizmsmhGSbfo/muSV8WXomNzDUehJ +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/signcerts/cert.pem index 891bc00f6..a6192a592 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/signcerts/cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/signcerts/cert.pem @@ -1,16 +1,16 @@ -----BEGIN CERTIFICATE----- -MIICmDCCAj6gAwIBAgIUZ/a0pQQfq5dLvxaJyzBmM4CyPLswCgYIKoZIzj0EAwIw +MIIClzCCAj6gAwIBAgIURIq4s+HmGnlyQ5VSqKNliFACnDcwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDcwMFoXDTIyMDczMDA1NTIwMFowXTELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTIzMDgwNDA2MDcwMFowXTELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqG -SM49AgEGCCqGSM49AwEHA0IABKkUQaIfnpsGnAe6t2EsE8kX7MEYHIHLqC7vSA0z -oU0mTRpF4hsr3nda3FXmYYEa6fnEih6mZgU8FovRwPbxZLCjgdAwgc0wDgYDVR0P -AQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFNt706kSKQClODp2Q2bU -OiwmqCPWMB8GA1UdIwQYMBaAFHKG9YL6OC86y5FIXpqte7bOXSD8MBMGA1UdEQQM +SM49AgEGCCqGSM49AwEHA0IABMgs99elWBq0Pgk8ePd4HtAkF0/8FLjRkJ0TR0MM +GcaNdVODUg4mpkU7seSLOayaEZJt+j+a5JXxZeiY3MNR6EmjgdAwgc0wDgYDVR0P +AQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFObOsFIPPF0u7FZz29pi +tDFt9qs9MB8GA1UdIwQYMBaAFCoR1JlvfQXesApniUWtci1cXiOMMBMGA1UdEQQM MAqCCHNhbm5pc2gxMFgGCCoDBAUGBwgBBEx7ImF0dHJzIjp7ImhmLkFmZmlsaWF0 aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEiLCJoZi5UeXBlIjoiY2xp -ZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQDs4Xyxoo9Mx45wY6coA4A0cG621tcP -IODxsjNkTKr+KwIgWZcLirV48YhcmCFmoAh3+WdaBAzDr2/APncLRv7QmX0= +ZW50In19MAoGCCqGSM49BAMCA0cAMEQCID+xGjQx1QthS5cue2Gs48dCVj599b+X +UMnsqSZzxcEnAiB/SKs4WrDFw7gv1Dk3bnqU3YcwuQYCub/ghGtFJHAEYQ== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/system-genesis-block/genesis.block b/tests/network-setups/fabric/network-artifacts/network1/system-genesis-block/genesis.block index a6a7cef46ef85428c2ab547cecaffd9fcd2d6519..c47b2e26c310a7d12c9c520281dbe18d5074cbf4 100644 GIT binary patch literal 13399 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 diff --git a/tests/network-setups/fabric/network-artifacts/network2/channel-artifacts/Org1MSPanchors.tx b/tests/network-setups/fabric/network-artifacts/network2/channel-artifacts/Org1MSPanchors.tx index b1909234d0b13cb523328cd711810682a249dec6..c2c176b4e6b2158953f21b821a86105bdfaa5d29 100644 GIT binary patch delta 34 qcmdnVw3A7IYa0`nIF~2~lN1|A@6ol>Ckl8@7Gac~m?}B3e-!|gLkZac delta 34 qcmdnVw3A7IYa0`nIF~2~lN1}rk>!0I69qgcW~ojVW)z&*zX|}Bs|m;e diff --git a/tests/network-setups/fabric/network-artifacts/network2/channel-artifacts/mychannel.block b/tests/network-setups/fabric/network-artifacts/network2/channel-artifacts/mychannel.block index 23e879c325e9d9742455a940c55f9ce11d382b1b..980bbbe4ba6c821f6f61aa1d052fb42d85d18192 100644 GIT binary patch literal 17142 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 L=X?O{8$bUKN<{Eu diff --git a/tests/network-setups/fabric/network-artifacts/network2/channel-artifacts/mychannel.tx b/tests/network-setups/fabric/network-artifacts/network2/channel-artifacts/mychannel.tx index a994e68dedf1c1afda6ddac0a7bc520fa7fd1ffe..0c2496d978ef4794698cac5424480c51480c8284 100644 GIT binary patch delta 34 qcmZ3=yp&mhYY{V-IF~2~lN1|A@6ol>Cko7*cy`Ui6)KY}8Fc`k@(S_* delta 35 rcmZ3=yp&mhYY{V-IF~2~lN1}rk>!0I69r~Y4r5fFxMJ<(N=6+3ppOb^ diff --git a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/IssuerPublicKey index cf4837d09e16d220a2e6c8e9e951b94ea75ae0fe..15c8a4ad0ceebc274ce70ae967a680ff4811f24a 100644 GIT binary patch delta 810 zcmV+_1J(S?2FnJJE`ROR1&!K}?uia_x8QOc<977(X2n;yZg>>Zyw(NUeC-k-k%Tvp z2ZJCL+|*gO8(CtSY$~e~AQ-L?=qXqihGosfwD1YW5gfbY zfz&PBKC0PYV1fQ9kRn71An3t0!~H9GT7kgvL}618zN+=%BdrrKmNuL$Atc@#!XU4cgtbE8#p}o18M$@>+7t$g` z3Luod`Ne^AqO-#F(iBkTSb~L{e!T1cSS$(j=uv!Wr+V~}S z`Rm4HZhmbLVZ->rfr{Ns8Y+kZ3Luhmm(W8 z&m6b$jsF2$_L<%70T{!5a>wif>hJ9(zm$z`@e4vtSQwB`a=?Hb| zf8hwG5+KBKAqsvhrQXG(d*N0?86yU2f#m|tzScf_(Ril8bk^pxI-=N~KB#mSRT3Z= z$%`UKg$a=F1%Gj*FxgJ7s0)XLkZ0fLgsRlS;cawaB18%xnSP?ckkN%se-mT$6IB?x zQ~Dw-;80xk^*Zf@LWWk#5+Lg}V%8bfPq7DK4VeQ3hCF!B9jj}ZNot6Y>7bhrx0ND9 z3Lr{;p}Y$$WMm`_o6ZW;8D%&y1C_q(Tw0i_FHAcc3w=?cY9Nhlr6k(Gx`GubZrFf5mdf@UccXV!iM zB{D<`Ac<&;H6)bDi93)=B&Qit-TfZ%~6R2!4e?Rh+FRBkGB2iA_Rso z6quk=P3>^ub^uJLCPr_n%5cIuL<%6S$lIpBw11U4bjN*w-#H=WiiriGL4x-6jc*_- zKe58a5+Fu~b&?=q9=@5A$lU=dsIN+5rfY%f9j*(XUgVi0No*l|W*%>Cjc+Zyh#YM?MT oxFh9KAh1G2n0giyqQHz6akL0mbT=3K9`zl3`@{&C4QTLhnJqDQS^xk5 diff --git a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/IssuerRevocationPublicKey index 611fab391..9b62f7ae4 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/IssuerRevocationPublicKey +++ b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/IssuerRevocationPublicKey @@ -1,5 +1,5 @@ -----BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEgJ8xIRqgf3y/NEW4a0sB149n0xIyMILm -cu/fPRD0T+rRCW4PmNtzJtIwF/dOvZ0o3sF2viN5od5prlozeBdY2T0Ba328PSHv -n2pCvE0oV7UmR8hL1kD/E1yZnc1J/arJ +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEEl7jcAeURcDE2Miyc0fyYPmUT1/7hnPw +NcvnpTjyVabK9nTbqXTUhXi5wapWBtm1ArwhFJ7EYX9zV3inzfiFyCeKUToDlc9a +UfbSsI0ahJYhe47SsjOUfVDN9oU8ChpY -----END PUBLIC KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/ca-cert.pem b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/ca-cert.pem index 7bc4e17b0..263498d74 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/ca-cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/ca-cert.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFzCCAb2gAwIBAgIUcD3XTdKlKhRXdbBDR6f0TJeiPnowCgYIKoZIzj0EAwIw +MIICFjCCAb2gAwIBAgIUE1YC4hF0zZ1tbaqoonCjZSAze40wCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTM2MDcyNjA1NDgwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTM3MDczMTA2MDQwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdUmrRFbY2jFmawWYLpEgdcH0 -2j428D/3gk+1Vm7DlGjd9QudiaJKEEwQkThAAW2ZVxyJTeDJ9Ar0/O9K4+jSB6NF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEi4mzLXiztQ2XsIvmMNaXQC25 +UGUBq8ZWt2jmfIjfQkh7+tht/wg5tosanXa/9SCvAJhnQsCQd9SulCnK6r3t3qNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FP/qccGjA9pznt57d7IH+6x7tkaXMAoGCCqGSM49BAMCA0gAMEUCIQDES/I1hE8k -CbdiFv5GMSPI5ez9yoduP/kFGHUMW3XMVwIgBbMVw2r62VwuaN5peauo2iyC/bgY -HwkoUVYqbWHakNc= +FN4QeBfxtxhbd7JLY5NrbCSOyZuVMAoGCCqGSM49BAMCA0cAMEQCICB+TzsiJu79 +XiFtDi1WvEUIDusQE4B06oPPZXaXgbxiAiAJyzHCy683xZy8yI2DM6QAbJwTDx+C +3A8PnkEulaO4UA== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/fabric-ca-server.db b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/fabric-ca-server.db index 5bfdebf20106ecf6b2c3dff658dfb3060e5d2cbf..24aa685f67379ecaebaeac907f06a36836fb2e89 100644 GIT binary patch delta 4662 zcmeH~Pt4n99mmVwZLFc|RtZjJtb%nF3w>ih{y$MF|BW5TapE{}oT=OF$N!x;d1E_v za(Q=TyD(&l0~~e(P16KbIdI~_kx5)Qa6qCG;siI&2+~(-xlGzyR*6fWgAb3apDcf$ z@ALhB-n)PF-uh8Je*+uF6ag(aXp$V_P-JFkj+uHP>w<>F~Xi zk=%_DpLe`voHc*H+HSu7%1{315BS~p{gJe*WlagBnvZtwU=Ns4r_?udo863)5vgF~ z9AZk36A)QdM=}I`a|ai(pA~O4pS)@`FTMIw^N(-+_TIlekR~DOW1j2dC=c5Qkqf~&p6iO2= zMY#ZXNsPfrmxKVPeaJ8_Lxii92M~bWMCh9cehnetM3^@bq>VJ5b*o*NJkKu5kgXJs z4V8&$Phw1QIh@(1;*MPCiz=1^pj1n``ONyowVft})j(i@CX6agTFnGg+5dMhZLVGa z)EbQEUA5OI6Fg64a|%sp?MaS+9IS$+G#yNZZi}kc>M&MPb-3P0`C?SBC(5voroC7M z-EE=tAzdWsEKCHvpHIMAliST}uiuvWm|M$S(SasaOjWU!uFz4*Mf>G^>1iC@WzmVJ zR3lsC99A0OBcBWEqK;gT>h*16uyOgZzMGfR=9AYy^T#Y(86zcPRa&vcv5{Fg=#HQ! zw1=o6*x5Qr<@E?N4sUd5Turx-7uc9vI7~l7_OI<4f7!v*v0j%w+t0f`0VfkF9}i41w0^0kurcemd|V-K9nY59a{FcUP9=F_KmIWInQ;RX)K4Tp#tcu{gTb{JQ(c?#OCGW z*QR5V$t_AAck`a8=@G^CNLO{bo@o*6yx-E+D|}b;y<*l&G2f^+l%e!7R3_C@KtnRk zENZV@NC#|)?&{#IT>P5RtlY-2JIYHa%BsxsevRM z7go}WonR4%OPwy(l?p6RizEd_-czXFl9)8NI_g`)9Ow47k}!E^QEID}gS2-pkCM7)u@oFB4T3}>4^0jLDJfpY~eCYsosz&roK&{Fv^zNFhy$}NA5ZyE1PZp z+PU$<<&Q7_`||ju$-OJ@vX@UM&)&K76@tJp0?;T4AcdhQgFuoFP=a<4%6EO5#!!z8 zaPQpWKX*12^JtO)kZ=hvKm!kTe40cZlmUmkp2h)&Aue@_qSWE?I9~=ldp7ooCd=s| zT8_@fKIyCN8T0UGFMg4&e(<=ydhx=A3r9!Ug|GeLtN%R8?*91QrvdylfS(5N(*Qn4 zVSXCG|Nj8iUq2c=fB)WDs7_86vacPpkvYfyj)~u^E3OlEUCm= zfEJEs>z2`pS>|N3>_EN%Y%zK)a{BiC?y1dcqQ)!IFzeR%0@g{s8RSXJftZ`*WWDzD z9v#HOL@Q!L^vP*Q%pM%W-D%+9Y|##5+bb|Xob66W`Shm znOSSs1=?_7=@q3^!)T%xK5k)UvIq)4rE}WsC;Cn=D0Ul6`!l?!NM>{N_EOdn#;gt~ z?qD5%7_DdINkPU@qSByxsDJBR==__vf8U&TF5VeJ)!~hily7FO(x0EK&>+C-Skz7| z!_~Vcirf9zFL#cf=LaZjBPJKLXHsEx*lMUVTc(}@X_gz_gtS{b1#Df&4f%RQ`v+{k K_qTVhe)u17y|UW? delta 4674 zcmeHL&+pr2883Xhv1ME7q;cxDRHIB?*AL?y(DBjSig+R^SZZQbaBLmx}_tM~BewLj1E zd_Et)eedY)dq*FCbdCVwn8}0~UL`}a3wq;lhj;6;E_BU2)eF) zOYgYvHh+EXH_f}RUc8E6Q+=~@W>uCPbE};#0UEXkt9?mUvg?e4z+P`wWF~=_>J4ga zkg3Pf(hZigwE4$5sCnhJUw-Wa{QgJ9GGUJKtz-qY}^Ys^+f4%<0JO4hvK6+0(ee%xFj$S-> z>{;{nci0Fb~7a4(8NmqL8R z#Q+w#6vl)>NO=_Hp@51!*QY#>#7TyVvn)UXie3TK6%1Se#8m>j3IGI}z`6z%0?)IH zGG;58V`JG2O^45fZXzLmOqZs-#0_&mnuT_CX`a)c(?aUSodH-n7 zP@7jT{??K(rB8YJ#i zxuysE0xqQ7sZ%5xAw;<|U~i)9bY?XdE?t*|TyTbzyI#n=Avt-gc2IAQ5@mu;O_ifN zEMf+7HFQ+YW!oCO_We%6GOIc*2r8gt2_kn?F?a3egG+Z^y<#h!m1AQp<~7Bd(L_{5 zqPI+kE)g*#6Oc5@cpefRunYbdM4Ouy2Wj`g z43$SCAiXFMT-@ZDc&Z+Qt)_SzW@CXEk5c%lQLn~w%^~8+6>C_Wip9G z6mSD=MD#n5y{v+DtKO>ZRa?tP{iQg>?QPrbqQtP^k+m1H-JD&dHjcvGS{cd?)>WGK z-@GRAj*+hCk+7Ip?e>|nmrV^J`n(Gr(7-Hd` zgUd}wO*)IZc>_B3WLDtX>`Y{rV=+rgh&EDekC{6=fTB$>A33f0phio*E-Ik9BOg|b z5zEVL*_HE2&B(nrs~J#7oH$_a@7Tk$KhHse&!#~i4a;gpG{1x1Ji()oMDgel0l+aL z^t>Pld_W>Tc39#Rh$sprQ9q<;h9fKdrQI2S}jeV9h*~QCGh&TdG~lOm4Se>oBpbX#1%tx9Fo*CT`}qb0V=6-gw|LG z3CG1%J7Y~4TJ0)V70`4LVrhYG;)u$n64h6Ja}8GBQcX(WVp>ue+uo~mtEBq&#D`Qz zj)53+rr4m0<&^#Vbd3^#|lIOR}nEWkaN>009!DM4($E5Uf! z{0+YR+_%j$qcb0#`Q*;aKV{FHn5S>t_y&cOi0k_l=|;?9)Oz$`*1$Cq3G}X&k=n^Iz6hKmMwH_0p+Rr;d*DQ!o7CTmL-DZ@(8DJtg0#bgG)#Hv-j@2eD+Vzp1hMi^Ww#ajtPF~nArO!?@6=q=h>zQBKsgwFF0u5XPsW{2>5Qb*^QlUTDr6o4|n@eZxtJZp-Uon zVQ{T=<$j2L;Q}w}hTN8U)({`;wN8Exoqpt*Zy^sWfWp6AG<_A#^m*Wa=9v-WPyy-w zvkDmSFvC*a3g`C=Dsi>aZ-;p&_eT$u_+xqIvET}WUa!w}H=8nIYp3>2a}h803muUL z#FE-NY^x*|<-D+@5=+n!GKQ1DwNS?zlH0i}FQ&nCG8meHDuadVw727A0X3i8SZaMS z)gdXRSug9vgJ7qo)j@05Ry0B%;@^54%dGO*1AE-fiHe857#0^9U43=^g Vwsc9Q2TMZT1|o9j?>Eog`VYZJ%6)Ry#{@rif%k%LcsG~4 z%ydcl{*&m@(hhUAnj%CBAj4BtxSaX^qQL7TKh>a^t^GE+@DC8Iu04%Axl-qEh!P-J zc`~EwAaxfkI)DCU4XYx9EUmZou09nq!X;dUg?z*HB18%xuQf1-?CG&pq#!&03}=Xw z`1K$u9+Gicg)Lq4_|B8h5+MHAVq-%FN(nb=?68`C=zL;&#sQT)yu3u&aB?xKL6ssz z3LswjVN>d{E9uR48)9iG8X!#Bu*C+an_g%Zy(dZl z#L9*u9Di%OtjXVh-&e2runlk`AWlnm`*=dk?4MQrZi^qc>lpo*7I9DPe0WwKtn!l+ za56*+Ad6oMUt>IcgL<%5ta%8=qet(iQ(7Absl5^)j68%> zNz+;wC2e^5Tt z(mj4ko>>Yw>SCW;@>J9TbE`yQPK`(BG+xc6mge{pAlntT;*hsMUz_5^x^TiIdlNx#CJEA2I-iB zF$whLl?eFJ?H6~0QhWtW5+D&Llmnp^ZWfc~Hep@H0r<(||6i9Pov7%H>i<40(P$z> z3LuuTcByQgs$+|G-u0h0*DgS)<_|e)-or6=;u02}k$=t-AOzG0`(4)9;!Q6YK;k{i zUlyO){$j_Ss1^u+W24_W-zta!3Lu;U1=FqPF)Qg(`&RG@{w;xlbuHy^ooth(tY1{F z^*|CJ)1^qlZSH_n%~G1q`+*#bWAt~|DwrDtip{Vfx>M>&8XygithW;k_GAe_1eADn z#^yt&see8WWB7kj9!G#z-dFk}ATEF?zLiced?eOMry1=0eNh|+R$)!Kmv?mw^bu-4 z>@q|OAatp(kCA&gjcC7jL1edXnUbS|PiSe$)Ca#;4KN~mfD$0NnOxgeWs|8?GEw97 z;tg@ub*MuHv$sX>Lm(Mc2iSNzL<%5@8;L%jQ-5;g?9QG1g3d&gZ)YpB#-g_EYxE+H z8{YZ95+I4U3f3m4GVZ%i(mp1m^lJh+#R;n|F*SQ-K7N}WEyhA1HaU7$bl;(>LF!y>y_-P&Ytl!YUVWR?rEUQsw(jYZmW$TaSCockBp>%?R~JfzrXjl3WdGBz5M5c?C13O z8`;Ut(~Ioy{)O}FP78Zap8nVSccZ;~cYd+=UiV%I{k_9KhqS{F4u5uZ>&`FU|M7kJ z?$7i8t}6hf0|I~mAOHxwQv~it`^JOEkN1BPCx#h1mNQQRH?WMvSv-$J`|9;AP7|1p zQ0OphLnwTF_4dbw&jP#9V>GVHXrG}3@$gY$;miXgd_Gx5rZX>?VQdzZW~ZQZ8;wT= zW10BzJV-Xr$Ij+?U^|oi^)KhMjOU?YI^pj5tjxqnmW!)}%^hPAPYS^#c~o%L(_p?S zBthh4nWO2W!rWQKW5<4;S=S4xQzyDwOz5n#7fDJ-5CyHk3l*l@=oH{bg_b7Cj5aLP zh2dwHT6KLp9zJ~W-J?4XKK*q6g|`E2xNZ;zMiRu6#l`dYFM+*yr|{Xth@3O12#n$n z&j=Q}illahM}_I!$p~J~^{8-7Qy$*^k9!~Gz5XI&llA(=*X6x#xaIHOeo+5(e=nHW z&U!HmGuPyK)>rZF`uU}9M=oC7y!S8mq+CFr-n#vu{rHUv$X@vTQXzR2ZvVl1cOHE7 z(f$i&SHtN%p5{Z-S)8BUyM*jKz3|z|`8kf`k+?F#uwxgYT~uo3ZFUC*z!-s>rr9itdr-yF|kAEJTWvD$#L5AVDfw#$7k|*?U=p{VE2-T z55N50?K=-X`DFjcC)#c9>@Fmmk#T`QCYR@&?!N!;_I{SDvY%MHF>+DvFP>kv5f|^g0_Y_@dKKLH z(0kcBeA)WWPOtuo${bwo+zaOIZC2)@N&Cin`x`e^4Xf761HFA$iKp7wh-$Jb3V6|HsYU2wP^OW3l^n<5D;7l3vk&NoL?D1#^=)#-l>A znO;@)7iw@>@n!}*N#=pM%-o(rM;LUDU5pDFsSp|K=gwpvhhdaCDT@ob>N2mk_r z03ZMed;29v<%Bojaki`4MXT2!VeTZO2iE=4Tc?6%|ihEZuoI zZCbra3x3k*YpsE=Rz^=IEsE*ZrCtZAr1FNe!XWbxy5sI@#rJ=I!Ip^Q*u6=q$7EJ`v7*PKm$p*l97>KG(_I-wXMV ztM$4UG3PT=7oNM?kSirTyYXUjBj@+w{V$pQ{r$UB$C<+?{Ai1l6?3d&+LRr#c1__7 z6LvOy)D#DjPnTe^;~3=7qukNf^-V)*KUt!A0q3-?2e5n5mD*eacLhM6|8?14-TW(0 zJiGDB8!ytE_kQ@|=7alR)(^7==YR}53MMCw#yc#z>I$=l?nIWmk{w~=^Gjx^h+9*o zx{EQ7w>vXwJh$nopN$V;NKERx0^X$6XK%YwvDdYHSNQAlzgg3Nc_Wj)zsN=9{+B}D z^870dIcfFSq}H@D9rB|RO=^o;$XA(`V;}@>FV@ZVdfu{{wK0zMG>;!OyC$39Gwygy zzDcupuXDEd`QZLC-9K*hPnvn7FAnUMZV~H# zXwU3ESGDZzddQCFPdtt2);xdH?G3h(m^gSNrPY$cj09sWiNPznSehixJaX)865QdK zjQFW0L_WT(`9x>JX^q!p&>SyVBy(f_ggN_qzmWZJUMcUwFqget7hLz^^K!K~bQTwK zUM=!GC+~!gm$m3uKasCOTzUJmgJ0gbl}Xo)qrb{6+y_U0eSDH%fCCT!1b%x2zVb7* z|LocQ5AQyG`j1M7J2!(QX@Vwjn4oPGFVjSsuq+I5X_KIE48>`SvM9oFNY_Ff8#fKh zHYv(>%LGZf6kaA_%ybdVr7W7tOd>{jacrY7iamy@$1q-i$a~LkdaP~VpkjJ}! zh28bpjmP=H3ZkSGI6>=36^YB1Vt1*KEJ<9vc}yy?j3;&VX}_mdCT)%AAzQvm zBtv!6wnoxmIZQckDAi+K+Kyl$%b!99FEnIkEHX$}V11eE_2hMB%k)@J>1CyL_%X4v zCR!{Bif={q!srvetf{Hs4f&p`)*&HHBxk^eR8oTkjAyEJAkSB}$|wBKPmtY^*q@u&&4REcFh zZ+FpBWtL49j$t}&lw#Uu#dG8Sc#UVD3Y$@JEiG7WHm_98sB5?8#WucRe1ZO9?>}mJE1r7UNZ0ma2x#;CZcVJ{4G~l&X1uRz04P z^RBCEGRwG>z>JtIVb>cr@2P#3?X+eMdO@}OHYw@Jc(S!{DXBx1WW<>~)uc^s%|M|MedSk&{A%68H^aE6beQ1yMS>u186EO`JJtJH7joHviL7-aB0{@r zXXlGeBT`mohwbN#m{hG~;3P)X>dvO-+f{92Z6p%PE@C|(SUu9GrWpFR7_Q7fBBelD zNRb~k#=T`e0!SwB^Vk;gspeT0bb#Z|tNk7p{ zWm_EAsjJw3pHuBUpRfMpd=dFDh*rafO5k*PUib(xh#b~6*9wv5w^ zCx{$36L;sSP-S3=VYzXQ3^a~x&3ntPQJ1jUtfP-dG_6$1Y|K$=V-QZ)Z3td9C}$`p zC5bEPgSLY9olRv~UCrHgHR4$xw(D&6nbu}zs6;NBBfG z+1sGa4pdwZYxefnQZ<>X&2^d}@H|t8JkQ?_`^3^1D6!mO>gTFgG*ZB{neBGd!L@j_Rk+5x+rX8Wejx;9K#5krV$rIP0T?Nj=viszVk3r{lpJ?tKP&V5kGf?x~XvL2&L;t9c78zC_hHJ4gNIFXhuQlZUB3+5q%sQ<$CS1~tSy}O_Vx~IGB~z>_ z%G@t9%Rz6;`J|79m>Q9tdW?%>SrUEdqP(AY7W|B7>|^JkD^x~IHxs%!>j@QBwRlF& zyvlUQvTC=w^D1{LOoKa&S}n1RlrpCetGH0{)NUP{!A_6S@qulR6s)r*dR5<6);)wu zs~H=pr@^DlrAjL?(=D;(?s9?RBiHVmxP~%is#BDsdZp7%rQ8kGV2x!LsW_Bmy<-Q% zNL@p+s0Yf{Lp?8Cn5g2LqQ9~*_3Ds4cLtgx0T#mn=f>2U^m-7!U?X*=lV+l|Gk2*h zBc&N^pf>5cTBckQmYt5g3MJEiyrT6epcyP|bq7+rSf<&|Sb^luutVS#3Qk|)3}oLm zw{K^^ZXH0`Z|L5i>>YLQ|KIo9_y6Vle|qn)kN)+&Ke?~I|I6Rr*AI9TAOHve0)PM@ z00;mAfB+x>2mk^n1iCk$J=@0#1jo@bVUlITc2K8mV_4b33>S7CoU%>Ya50-Q;WwSX zfOe%~n28evOgb>^nnbqXl0~-IHb%fG0#hcE&4s!cMdIk2mU_4=l|;>KJ;rcRn!r$u zv=EG-k!*q$w`dfxNyjallw*^Cj-&aPC1wqTba4T^RRjJ7b!HeiZ`i86(hvmXjJNVtrc)SH%i`?#*Afnqp~ z;E0R6WxEU`2$IbxBesDUCXM4+R~aC#mO*2vl{MRe zZP+d2mSNyofd3n=h~3;uM9N;>;GRbO6paiMwb=`!TSGeLyf@t|C>b< zg7yDjKbjD%|AY1aEEw>&yZ(P3!MpqZzwuA^-upXuZe)MJ0SNrA5ctZzeeZ{-A@M&v zJllizwkIsVnXvfDC=ZKopT(+*7LOS5glt+(C6Zxa$-qom}-{)A>;WrV; zb`}DkMf6vOeJwHi_*xh-Y90~BGIEFO(;IzTxfHJo#V3JjC+lyLt$&7{*GTlVg z2v%@b9C@~!dNz~tS!7rqM%FrxLCYgU9p)sG-xji%`7E%Fle19ps=5myYqIQ6sMO)1 z7|$1$4LeTXMSF>Yv(zr&UP{%W%oqSMu_L?Q3G^z!D z7s=yw^Wc0)P*quGW*k?|V$dRDYN1|+aFNCD#yrb(MK<+VR-nsLRDtbkZ7YqY*?AuA zUWxQ5TtG&@0vmmLDUISF4|C6>+_gTjG12wH?Dv+o5DNJ{6RS<+er0U-!{uqdJQ^O_ zg~LZDHzo)zGx1sUaMpDk1AB}tbU8`oSY(@$Ev8ndFrBHn*)D|5pavPEn(8}rbrh@u z#zh-WxNtd7@>dy#`N9&>cPN|r0EgT-n z_X)|JHwlLq=jCnGRt79x9=h_X?o7EFHKy@dHxZ@QY|yUtN(s|~Vq|LyBF!$h&BTPY zj@d)&USD+F6gJzlQd5#c7!AS-=Y?gX=Va=INj(eRsh3>4K);rH5k^MGvTPNu*Q#_D zM!Kw%5U&VEdps$B9rcoHmn>TMs(SIRsF(G%>Lu4MnTq+<>ct)?`Ch1?!R>bGbn`7= zx!TDmE}(qpg7kXTf)+KFipunQD%F(Ya5)T+cxud?{-Ej1p;<2+@m;(&Lq};tmAr~= zPo!cUZ`T^tdQ(zT6)SS(pjb9AF{~EFOz{eM&u?WB#;?;X|KOvWXPV_7e{{U3?`^MO zelwb7n>#O){+VWx{dQ*~2Q_t5Qt0Wi-tX4 z^_&g7LYKW5msl=0CaU@>&C-ld_wdzJwJ)=3Cg0gMMYUUD(`>il#Yp_o`TjrX)f)iY z=wv_%_IOrSQO~67%Vfl^ZOm&_v&}V^_Wwb@Vgq1ux+|wPV#cr9{|8;#063Itrbv&5 z{dH_&3YeO`yph@) ze^_x5ayf$VJ~gcOm2%(@w9-O}iI5Z3Ohr|fQqOTsvJc}mJ=-zhPt~$nYzpJGHYhLq zwGeI&vW+q|NaXR?>8Sks|I+{E|99o<57Yw?00aO5KmZT`1ONd*01yBK00BS%5C8<; z8i9QOKluKCYdAqcfB+x>2mk_r03ZMe00MvjAOHve0)W8pB!PVWfB)!z?`8kM0SEvB zfB+x>2mk_r03ZMe00MvjAOHve0`C@qJNvix4sRSD{7(@7|88|GXbm6$2mk_r03ZMe z00MvjAOHve0)PM@@G1fz{{K}}KpG$b2mk_r03ZMe00MvjAOHve0)PM@@NN;v*Z*%H z{r$b8|8?|Vj{g18zdHIS*#$TN0YCr{00aO5KmZT`1ONd*01yBK00BVY?GreJa~L$%^lmBB!Lm0q<(mCP&%@lc@nsRWhAGM ze|RHHHe5Fd10xCI$w}_-?jJln3U(zVo8vSzU;n>-^hbL~zc~8yqknVs7e{||^v~XY z13`&^03ZMe00MvjAOHve0)PM@00;mAfB+zHO5o_=ll=>`0JlFl_;ml`B*3lj9X#H@ zItOs`!-LZPOH%*`dFo3u05`sK@bK{R1VFz2f9vR^eAQo3!C#Hf6%Dg*Y~D8kTKRl$4k=^Me&cNhxrG){!a_$8>~UDkMu1r;Rv{ zaZry*C6@7|uBK_6ZR#Wz5VVY?B-J7$l$dYP29t8$P^!nev>m}hmOq6IUTDb7SY(i{ z!1^-R>&ffNmg%vc(#uNg@MB_SO|)1N6yJ*Ih0!N`SyNNN8}dC>twTbZNX~!_t!N$U zq8(Zzp(Qi$u0U=ri&|6(tSB7G+BmJGyN7sT%|^q1ZDaK11RA13Vxhf_9rZRcix2pY zw2^r)Rd@zfI#McE;yi78o@V7~snj`s5tLUwf71|MPxU?l%POAo%*mV59+DR>cUWC! zWs%*?#I}snj3psZeELiD8wd7i;F+OWeVFW|Sh6Rh4M7Mq1LK!7L5AKbxq{qSFY?Ra@wg>nI+~J!!?Vh@Oh%$TJtIXL>20L(||E zqgG2Sqw@3LAEQu~tV2E%%D zj8&If(xhsY)a(SpXu^1$wwf>jYmju>9~wGJ=vq-UHYDxziYs0px8!OY@@#FyNQqS! z7fHqY;tOaeB7(xdEH*z456^`CAC?adI|?QkX5s_^lMW2KCPC7KV>z~s5ip9tl!?Hk z>tYm%qu;8qvt%ypx_Bn+a#`!KOQx0dLuZ@72;*}NK`d?kvGo6=u=~1*OwG}o2z#U5 zkE2p0Xi}?9km7LBY;)rY-+;NR?E2&f_27W{hWW6}6kA^(!$PB)dOa54v zr}kM^olM!WhPS06C&c}^PD!=?8d){GX?e@I`NP$=EI=a9^gXsiRg*TkH3Nl4^p#&7 z@~d?V-wflP(qZbX=gs`_sM%6;HKSA+o)t0)A{OinhpMGuQlDUW#qOzFTDM0rvQATv z7;3gOEn{(@&Kvzy^7L8IP#fDK+=)0^S2jz$qNwu?4Ea;IqAs>pziTHFSEt}!_jTg- z)ziCY;`Z}rhjS;)WEV9vi)pwhO<*WSS_nqa2u8xVMWcvKI&Rsd9E&u6193yoOz79P zt$r?U!MSZ6&fDaC6Lust?esOp>(nIMTse4IT>RdN8^5!oS8VIf-lpnENOL3pvTbD+ zr4?iyXM z37LcPK#x;np}Y0A(5qqmylb-B#O*PbR&OWasU)rNyz~?k#f%&D_z~Y8oez z(xeueVugTCEqJdQrg}TO5h~B?rykxK&9@Q;tu+p!W5})!pp}QU;HC@sz_+8Qy_-P&Ytl!YUVWAJ=55(RaJ@aM=u6Fe2JnYN}@!)Xcr26ixMeH z)Ps^1hEYA^aU0&5U0>{j7rrbO_QEjW;~oqj7BGDC#V{}id@$gP4~Bi)HLx(oLFGH^ zF*Uu_(=+X0Wh%)a8INB?{J&7d7uD8l;lexilQgy#$Hd-yd;9x)KRiC(+uQp9{JsZ% z&yK$ZPHvuEfWP~f&R=!v-r-*$t;6>Ye|mK5&d=Zd z(S7vp&+>n-iU5W~0+0YC0114p2;7bLtp|@E@BcViSa#$&Ub+bV(6JWY{8T_3+X0+)G0%dNx_cwwE5;QDPt08^&?H zQ>#5Xww8-wl7@@Tv$3~%7P{UfPyWT{9P3$R*U5z9+uYu)mhZ{B`T z{b+wLoVeb4K8wK6AfMj4{hHcTbF7tV30U`ieXVy&imsl z+w@fcyF?y7{Ont|?>zY4_x68us&1*bQy43nI~S*SuH^jEjhBeorE;C-`I?~RuU{9G zFHOAOs4cvZ<%bWcJGURG-+NWdxI_T-%L`6--~G3HKh34=$Ih;eT<-Um&#&5u%XeM^ z^oovN2Y1o*UbGIMHNUab)nAgCgR7N$$-KSI%v?5UUs`Q{>86T#?{%Vo#YkY6ua1D; zpNRg!>qP(ZE4jo!yAnwra`XB6-8&B+JlOwHW7oo#pmof5A2+U4<1XkW^|t^9esXMY z7M}I!c(IvY7yC;&xGKEBfG-wlXfMIA=h%?@#>o)lk|G_)*7}(@Ns}mw!60RRNvmEp zTnHyllBS-scs8}>^DIg8vB$!Trx$Nuj4mGDzyDA7Zr|ni-u(&k=lA~Poj*HVg9~^- z0+0YC00}?>kN_m`Is%`Ox9|Pl^PAs!{G-Fe!~MG*Fm}Rzn4|&rWa2Hr=wpmOagzA^ zxb=Mu{eG1&dhKniGmpDobxDu((IOC*Tv~KXsGtVbMyPh42%~8hq`qCN_h->Ujh!e2 zL!Vugt~a&PMLrV3{`T*Gm`_lA_{oPu|A~A)LQ!PSw@Wdcr2V=V_=}m9OYdFJ?X?)5-uUbXx9&aIVf!@4mU@x3IfdkKgT@9& zTO8)r1vTP>h@gE>Y_r{IS)9fzK^%09nP%dO+NIF2DTR7v^UEOZ61bGXyyVw1b%nz# zh@M6BmGgT(xsmgG|NdwE{{H^mspqBWDL-!{Q1j+^z@ihmvfA=vqR;di!&FvfKC5ZA zRw)h)ZPHswL)WTJrhcVU2es~{Z_=c83B3;7wFZaMh$Y zx}$Ryv1-!02;QXB=c!%G*p()8t>nANU-$f*6&;j(cChOz_dk>KlIP#Tu+vhbc(UxK zXwQ1mC_mYzm)j(Y%1PFY}H=#z(qOu z^GSwFkAuQIJ^00qTcD-gIQq-n!oPR)*C!|W1w0@DNZ{8`;ByxkyQfd@zkm1BPyg_D z4tK&&S`5kB7Uz*1N8q-NV;Jy6i1Vsxd3O>PsJ>LBs@2<~pJkAe6R@C~j zD7Or?q>5lkb{C3hswyTUQRK&Qz-Ow!2WqE1Y1d|6+tkwekYuMpPg+v0-g3EZmWjbY zttO_r9id=Mre=sG$u*51D?HYbg`p;PyV|<6<-0;q?}FG2X-uu0Nh?w1`p}8Fxz(eF zT1(I5U?6pMy^6@$LiPGWEwm=5Bym0XD#*MohO(6S{p{_N_*=iDx)ukZQN=Y8JIS(_mJS^*NPjZfY(X5~4 z9J!SBy2j7XvMxJHH!n^@F5+AWdBrgdo^mG<8i7vbxCg zx-qCr=CEUd_2|_kt#b2*Y}upEINPlKK-R2kwXU|?Qon?hYm%N8Nv~0knDR#JQL9dm z8)h4+BbIx#vPtSrO-c1p6jsHAEW4Uowltp1bLC2zEFi^9&+D@sNW7L;UAd(RywA$~ zhz9|?+Hj>n?+JpzcZzxeox4$~Iw?C1YTWG*I$}*@dOG6$-OFuFRwTX`2yJSupiu(8V3wZ&)fB~7@DlXhbIZiva;n(BpAAx*#lK5f(8>i>sm}jZrKIr^Gz+TuWUo; z<&5}DF9C2WueYk+rZRNPt&Ou$X#`v(W=IKUY))+@8oElfvO|?tLv^mk!?-r?F7p;> zD_CStT9uXv?oEWq?5mj?W+7rJgJriIWoG;QM(Fp^>up|YWqj7+)u5v}ZaJ!_anM~Z z1=B}(O706yPmtkDcv9?U@L}!+rOjM=uYGV#6TXR8eakDq5&~mAlO#A*|Z7%|) zx7ApL%9iKDl)ENT;|PuUJfcqoN) zzD?mSYk|Wh80)K*nWh9}#;cyojN#V_TeJ9i#@QQ#ELHtQ8?Vl0D3M%8{@W}wed9}z znJWr8z}Hi=N1>WdW)gp@kXd(VD%jK>38p4!im;g}NLwR0K9ChroGH8WOfK`N$_vdA ziPn~imNd$2gYT>w?Ou0SnsmhpXpdl0qr&x#pgcxQ3mcnZ$?q37X&DR3LqibtR(GP4 zj)C`0vhAV_#nJt4Sfn^E9=V3F{em*n4)p<^sY6a?xfRPS%uR0_L%E`qm;WwqMr;o5d(aplPxEc?l;mRL;Y+Au45S+X+w`)3~=dW>zm80yEt2wm)b|OG#5ootN!oL4lJsyFKqoDf zv|0L#cX5(EA2593k%VJ_E3VIuR$B_Ht{Z;2 z%8Hd*t;muUEdpIU={IC~U~b#f%pf-CmLtbb0T0AJ@AX<^F!1XMk~~C5n`J!H&`LWJ zm!hpDq%zi2Wr$qv@28^*X(sXR$-tl^mqvUCbh=asrGZ_0b8bnXe!&;pg_7ax6M_YWZgrW+EyAE+pQzc1gsVhv$&Db7+qLz zHL<)dlwEuv_+x%RR6AaQD%3R07%O67J}-}HN$GINxaOMWh4zCN!~%S;xqTaa+&VzO zCvxvk_wN1myMK0HfA<$hoqKPMqSEweFx-} zvKbF!P}Zjz>`n7}cNZ%IGU~Go!*Uo(xnQ1#bWxvXG1SEg(!(swVkpeB@i&e2&PlAK zZ=)XPlQxOEDCvWUE#Gx$(x!diLUGK-9onVeIM&-IvD%geYKJ8(iuEndK?xGI2#aQM z+M`+41v5`Hj`{4H=JnPISH|^F7jtRLq8K}0=mIlWB<|7_D8B1qEJd=GL-=nR>&;!P zZ+m_1;3U?!Je_{S0KMSwZO`D{2jX&Y@JD;^{HHsA1^&PT5`YB0LIQC8AFlt8WVrsH zFSfz;f4Khtf}0Us|NmkhQZI8ey0SP3*Z*JZW(3#&-^h~?uK)k)o`i7yAFluZde{Fi zJa>2B|8M-Wy?6f3og3f}JRpJJ6at^Sx9@%T%oYB-hv$3Hn72G(`Q^C7PjV-=ar@j) z)osoj6Li6&aC<%eB>bEYLBniOh;Bhi0mqU}k?a3S2Ds z);#e)%e_K9{?votm4UB3aB34Zp3lnq&V8&Q2m`q!EmvuOMip9Jg4s3$gdJ+rLciNy zj|yW=V0Vu8YNih~!QxA`iEQh2m+KA+juf}0)poX4QKwp&taD%8+$kTCbzRf=nJAWl z|5;2;9XtRC=fHP2kp#Y@2w5NqGRLTK33bc4Q|uI+=U(om*o>n&V)aU>)#H}xC<$}- z_T0O@)uT2xz6MRVyL9D9&hOboWuo;;W4jkE&z{S@;E|mhe0+Lif^iz3oO=#~suOwC z;WZgJze>6lrqgYqV@{-qmLrnPIzC%QGOCELQdeu$do$6h_lQ!s;zORPwR&T>JnsZu zsn?t0)#i2_TKp0etlZ>Df|zMbyVz*<5IOk4iym+n7Vz^P*ol26Gxra7dp?=Byn6BF zNKCW^5;LODCB~x@HI}A>!ZefgY9kI}DjAtUPxXVZlf-;wuJB<06xdi|yooD(Evc1e zTA|oYXY)!5TwB9stC_S6LR}i&fi^KI#&i}+%v@lb7`?l* zHb+UEFy-Q=SZg=yqA6O8jY-A6{#s@EhacQLSC&8e;AAf!{+3rTzZ_-R=E^eZohwU) zBkSefEb_K}e0&9A!wpS|=ET}oN5u$J z-Asx3D8tF1C?K`oC{)5}HKO!NEoDkwBBlL#-7$2dQK`rx+1~i2kf@k7J4{Gb5c7Ri zy8bd{X(VTR_bR&H(*zy#Z?HX4@05fL>@vLUg+IF3_lLZE<6lb_Y01Dw)NEyMX9*(_ zSU4LkMsn`Ne`Vhv@=G@UEzWl2R7U*xW&8e+D;xg?YQx&-#?=v5cN!(c)#z0I;; zELpYCZuTZazr%y!Qa>otJuXWWd#hI3y_U32{kXz}W)y9P*jRKeVOXaS!=~jI{QoaT zKl%6nEC0*?Z_2knm=8z*5`Y9C0Z0H6fCL}`NB|Om1Rw!O01|j>1oHj=@caK;!wDmT z1Rw!O01|)%AOT1K5`Y9C0Z0H6fCPRc3FPbl`$vDZ2Y%oI2|xmn03-kjKmw2eBmfCO z0+0YC00}?>UoQf8_HXSS-Z(t?AJG5*>s7I^G>`x!00}?>kN_kA2|xmn03-kjKmw4! z%LqXK|CdpLVUPeM00}?>kN_kA2|xmn03-kjKmw4!*NZ^D{(t-E@9!P`&!hi*^zV-T z<;Jcp{$TIu=SP2W^skTp*U=vw{qfr`AdC?bfCL}`NB|Om z1Rw!O01|)%AOT1K5`YBG2pk=JZ~xLP!0q=AKH9%L32^IM2aor!&jH+g|Dd@4!W6(k z9{R!zz>RMlJUqNQ0g$i%-#Yr|dq;nH^k2aYz@LLtct8S>03-kjKmw2eBmfCO0+0YC z00}?>kif5%z_)MReEj}lk_Pw_*PB}DA_mLkN_kA2|xmn03-kj zKmw4!S4<#x0k}RNaO>{D`@6uKr+2T+1RT615W8{bU^lOTNzsh$Ff8u)C{6kf zK@up-xhPJPuICUK?GZG}F*fIrw2Kmy>r)g>cnnH#9FBUv<5>>Lx|oBr9Oq*}lDIgE z@XNV=qHH{xD zJl2tgp(b{_+PbvmyFyU!g4hgcOs$+rD^cb8(22RZ)uV=5OV8wBAa!-UipbeQ_4-2O z#OugZ+{hWpO^ru)5sGU~X~m_`iKCI$8fT?!_mU*9g?P}bY^*b=r>k=P$JfiVgUS?O$WTBYpqQ>)CS>HX_5QKqTlA}Tk>om)4FKFv)ugp}* zXxg&GZpqLDb_dZ_Gku^57GJ7OWLvMhTz61#q_{1uwzIX0I@QW#t(6l{=0pD#2pZI4S5s|ue)4>G ziR7)z-c?Jh(h^l#jk;U2uda24+n8HmbGM(iJP5Z}3$i2xi0asL|AONOhH$gc2XhJegQaYqKOZraoR3%CV#gLWFTT!qzCu zn6eHxR!Ul{#bB*KRF%G%vO&pMCvw=;l}2pZYjI$10-JL!Wtg@LT;ebyt<;Oiu20H! z>BWBflj!i?gHyfvN6ew+#^D4bC<3QEl(86`pedZ9aE!)X2dE6gSuEkxxaGMR{gtYV zK#zdBn98}j$e0$9<>{s#Rk~`g=47a61;xRPX$`(k>Y^GaGWMdn=wv4Gr#hB(ho*u} z?a|AHA=d?jKNE)XHtbSVx1vP&WW{tWlwJ2HX{pByjHokM1jeMNm`=0A^VN3Wb!UZ2 z&00w)QrhUm`^?&K4|L59X4kTX7bq^`G zG=cY7nIG{WWGBt86zDxc(CK2oUH3-LxPn&nT4OUX2dE}aR)Rm`{ru%}Tayt*;(LM6 zrq&87_5E(IIpL{sz_9eZT`!BF$-daz%AmK&e8>+MOu<1GI<2eo*sU8an)S4`I8ua# zlyXg+>1<+`66YgL*44lzYKsCn2o{xjxmzzax>U{bDOW>=7DMS&v&n0jP+Ul zO?UhJ)4S*0?PpI9Q!lbMxQ{U;4Q#SQIu1r#ERDL9?fMQd<&@2M7=yAt&0v3n?na*5 z>@RH0hk17k@$>FhTe}LwuC=T;Q>5<7U)L$yA37>Gk$>yDn>2ojG1qs-Tpzs+V-C6| za;a}_%-(wFy~1c;vDu==dM;6H6zCKwgsIHuiB2$dSSv*h>#p^oC1d!cuGg2ArL{7si$dmWeDc!}3p*6l=VR$GQB7;CFr^JcDQRLOab zsfg0H>p8)UTDm+!FFi}@7)5DaZj8zyPlDl5QCzPIJSEhKzmdUiCF@Ovp70E6;@fCk zQVEVN0>POov$tfh3uxV?5Yx#BsYfpYJL;*Jz||}+>i4UqwNl{;-=Qa~MmNdSpsy?K pVzU*Dt81-MXb{#+tWT>|4bj>SQcc@)&W}BLv{KuJ`Rlsd{{xt8_JaTb diff --git a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/2ab00f3ef573479ef8514bd647f518f7f2d789dc81156f6b38c9a432b5b6083d_sk b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/2ab00f3ef573479ef8514bd647f518f7f2d789dc81156f6b38c9a432b5b6083d_sk new file mode 100644 index 000000000..8e43e7c04 --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/2ab00f3ef573479ef8514bd647f518f7f2d789dc81156f6b38c9a432b5b6083d_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgqxY6GRcIuI3TUVEB +t4JOZ7r6IWcIEJoOikcHqbv1S2qhRANCAASvohifAflAKrHL0XeLXHvussNYbcSM +ywPXrnbxDk3wFVK0fkDz1d5cusAusAXG+AXnOUWuIxG1AysLHLSlnMk9 +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/2ab49b69a5e965d0baf9acc108ec7de7a6c9070ae57f5cf423bfc2472f0d13b0_sk b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/2ab49b69a5e965d0baf9acc108ec7de7a6c9070ae57f5cf423bfc2472f0d13b0_sk new file mode 100644 index 000000000..456964430 --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/2ab49b69a5e965d0baf9acc108ec7de7a6c9070ae57f5cf423bfc2472f0d13b0_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgFSdba14DZbynhmfJ +Jl0LvQWl1SycE1P3KH3pNmE2A1ChRANCAAQoYbRJDZZRnbv38eSGABZYlxGLXtTu +4JLMWswvGHpnsvyb0/Raq7NgHG9AgbuA+HNNrh+AuXVzCh6h3l3Qm6TK +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/7d3e97c4644391d43429e1b9e781ff8a6a75f6fd974f25e9f674873feebd9ea1_sk b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/7d3e97c4644391d43429e1b9e781ff8a6a75f6fd974f25e9f674873feebd9ea1_sk deleted file mode 100644 index 4ae9bbdc3..000000000 --- a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/7d3e97c4644391d43429e1b9e781ff8a6a75f6fd974f25e9f674873feebd9ea1_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgNQry0UG5iTzM/38l -thuR+zFjky2o12A+3IM53IvmbMyhRANCAAQdfhthn3ywKOkLMGyaJbqPjZBCQH52 -kORLkiFuWwlPzB6wV/gSmSQV1HS60GB0vbtSZuaahMeHo/YBbAC2DpRO ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/IssuerRevocationPrivateKey b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/IssuerRevocationPrivateKey index e0591fd05..47aeeb2b5 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/IssuerRevocationPrivateKey +++ b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/IssuerRevocationPrivateKey @@ -1,6 +1,6 @@ -----BEGIN PRIVATE KEY----- -MIGkAgEBBDCuVGe3RY/K6lDjMjebR3OQLNUNokeTNZafBA8rMo7Np0+rwaWu4fC4 -0VQVdVz4k/qgBwYFK4EEACKhZANiAAS7G7pxx6LDcFoMyD98dsjeslo56/siRp5J -k8h+xqQdgstbrdVuFQyvm8deLk+B4Y5Q5v3CM2k3tuQ3qKcOCq6eq1gcmU2u28AX -2OTs23ubzl1n9cOgjyl+fJngmZq+T/I= +MIGkAgEBBDAxGjerv1VROhu+wUc0BXln5+JLlOVDUYpXAKRlIfn78awUVY0dpdaF +3vsySTlyVDKgBwYFK4EEACKhZANiAATcZV9BLHVZwh6KHqzU8YaA9h8bGBNrfZC0 +zqcInnBH32KdZk8eDKVtsJnWaFdmE0yqF7LJM04+sDYI55eEf7Vdf+lCcfq+x0HY +08KeL4xJvkyWxrlb+s25p4+8XvFX3xU= -----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/IssuerSecretKey b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/IssuerSecretKey index 2c540381e..e2ebb15b4 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/IssuerSecretKey +++ b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/IssuerSecretKey @@ -1 +1 @@ --ÉFÕ^ [2Þª;Å0$"½·/—ŽÑ>YÑÙÅZk9¨ \ No newline at end of file +×ù¾˜‹)Ÿ§xÕFTèrB?1g¶s-¥[ÁS·÷ \ No newline at end of file diff --git a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/ff63d3aee2f2cb882477e67de733e49c3aa42209717522d2307fcf37d7cecaed_sk b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/ff63d3aee2f2cb882477e67de733e49c3aa42209717522d2307fcf37d7cecaed_sk deleted file mode 100644 index 22d735884..000000000 --- a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/ff63d3aee2f2cb882477e67de733e49c3aa42209717522d2307fcf37d7cecaed_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgW/mqGmpm8BSDVoCA -iLj08yCfWPoUK7qu/M90/hCdOX2hRANCAAQDDoVeSbLLuBIQQTfHK8CJLL/84JMl -ZaoXOEEYZzSpwT3y0z94kc+2gCXAeWRkzj0WBDEh0jyumqM0JSlCuCbM ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/tls-cert.pem b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/tls-cert.pem index b5d46dbc0..6543000b4 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/tls-cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/tls-cert.pem @@ -1,16 +1,16 @@ -----BEGIN CERTIFICATE----- -MIICcTCCAhmgAwIBAgIUd3SkX/D/PkKYFEbstE4tdZSgS4YwCgYIKoZIzj0EAwIw +MIICczCCAhmgAwIBAgIUNdmR8ys6KgaaNdKNQy7xCr+sGZ4wCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTIyMDczMDA1NDgwMFowZDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTIzMDgwNDA2MDQwMFowZDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl -cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRUwEwYDVQQDEwxlN2JiZDEwZmI3ODYw -WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQDDoVeSbLLuBIQQTfHK8CJLL/84JMl -ZaoXOEEYZzSpwT3y0z94kc+2gCXAeWRkzj0WBDEh0jyumqM0JSlCuCbMo4GkMIGh +cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRUwEwYDVQQDEwxmMjBkMzczMmVhNDMw +WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQoYbRJDZZRnbv38eSGABZYlxGLXtTu +4JLMWswvGHpnsvyb0/Raq7NgHG9AgbuA+HNNrh+AuXVzCh6h3l3Qm6TKo4GkMIGh MA4GA1UdDwEB/wQEAwIDqDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw -DAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUlK+bqtU61AjaOTTy7Fg40w41s0UwHwYD -VR0jBBgwFoAUucRtA131Vj5wOZIO/OrEjRwomfEwIgYDVR0RBBswGYIMZTdiYmQx -MGZiNzg2gglsb2NhbGhvc3QwCgYIKoZIzj0EAwIDRgAwQwIgJzqY+4dqdS9JcoxW -PMzDYTzzcCqB1LmhwmOw616+xzMCHx+Hd2YBfkAY3KUe+5+LM1TkGC+ssHk6DGU9 -kLdZHtM= +DAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUK3q0eVAZ4XddjN3Tx5VHhdNxV18wHwYD +VR0jBBgwFoAU/B7Uus24jfdWb4R2A78T+MmKFTUwIgYDVR0RBBswGYIMZTdiYmQx +MGZiNzg2gglsb2NhbGhvc3QwCgYIKoZIzj0EAwIDSAAwRQIhAOjE0GlXCfo8x6gV +4sBmQqZ6btRSs8S7M1/q0a2d6ffRAiAtBBpjgF8M9hov9Zmi9A3lPUXIS+79BTkN +MTYT54F80w== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/IssuerPublicKey index cf4837d09e16d220a2e6c8e9e951b94ea75ae0fe..15c8a4ad0ceebc274ce70ae967a680ff4811f24a 100644 GIT binary patch delta 810 zcmV+_1J(S?2FnJJE`ROR1&!K}?uia_x8QOc<977(X2n;yZg>>Zyw(NUeC-k-k%Tvp z2ZJCL+|*gO8(CtSY$~e~AQ-L?=qXqihGosfwD1YW5gfbY zfz&PBKC0PYV1fQ9kRn71An3t0!~H9GT7kgvL}618zN+=%BdrrKmNuL$Atc@#!XU4cgtbE8#p}o18M$@>+7t$g` z3Luod`Ne^AqO-#F(iBkTSb~L{e!T1cSS$(j=uv!Wr+V~}S z`Rm4HZhmbLVZ->rfr{Ns8Y+kZ3Luhmm(W8 z&m6b$jsF2$_L<%70T{!5a>wif>hJ9(zm$z`@e4vtSQwB`a=?Hb| zf8hwG5+KBKAqsvhrQXG(d*N0?86yU2f#m|tzScf_(Ril8bk^pxI-=N~KB#mSRT3Z= z$%`UKg$a=F1%Gj*FxgJ7s0)XLkZ0fLgsRlS;cawaB18%xnSP?ckkN%se-mT$6IB?x zQ~Dw-;80xk^*Zf@LWWk#5+Lg}V%8bfPq7DK4VeQ3hCF!B9jj}ZNot6Y>7bhrx0ND9 z3Lr{;p}Y$$WMm`_o6ZW;8D%&y1C_q(Tw0i_FHAcc3w=?cY9Nhlr6k(Gx`GubZrFf5mdf@UccXV!iM zB{D<`Ac<&;H6)bDi93)=B&Qit-TfZ%~6R2!4e?Rh+FRBkGB2iA_Rso z6quk=P3>^ub^uJLCPr_n%5cIuL<%6S$lIpBw11U4bjN*w-#H=WiiriGL4x-6jc*_- zKe58a5+Fu~b&?=q9=@5A$lU=dsIN+5rfY%f9j*(XUgVi0No*l|W*%>Cjc+Zyh#YM?MT oxFh9KAh1G2n0giyqQHz6akL0mbT=3K9`zl3`@{&C4QTLhnJqDQS^xk5 diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/IssuerRevocationPublicKey index 611fab391..9b62f7ae4 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/IssuerRevocationPublicKey +++ b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/IssuerRevocationPublicKey @@ -1,5 +1,5 @@ -----BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEgJ8xIRqgf3y/NEW4a0sB149n0xIyMILm -cu/fPRD0T+rRCW4PmNtzJtIwF/dOvZ0o3sF2viN5od5prlozeBdY2T0Ba328PSHv -n2pCvE0oV7UmR8hL1kD/E1yZnc1J/arJ +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEEl7jcAeURcDE2Miyc0fyYPmUT1/7hnPw +NcvnpTjyVabK9nTbqXTUhXi5wapWBtm1ArwhFJ7EYX9zV3inzfiFyCeKUToDlc9a +UfbSsI0ahJYhe47SsjOUfVDN9oU8ChpY -----END PUBLIC KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem index 7bc4e17b0..263498d74 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem +++ b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFzCCAb2gAwIBAgIUcD3XTdKlKhRXdbBDR6f0TJeiPnowCgYIKoZIzj0EAwIw +MIICFjCCAb2gAwIBAgIUE1YC4hF0zZ1tbaqoonCjZSAze40wCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTM2MDcyNjA1NDgwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTM3MDczMTA2MDQwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdUmrRFbY2jFmawWYLpEgdcH0 -2j428D/3gk+1Vm7DlGjd9QudiaJKEEwQkThAAW2ZVxyJTeDJ9Ar0/O9K4+jSB6NF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEi4mzLXiztQ2XsIvmMNaXQC25 +UGUBq8ZWt2jmfIjfQkh7+tht/wg5tosanXa/9SCvAJhnQsCQd9SulCnK6r3t3qNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FP/qccGjA9pznt57d7IH+6x7tkaXMAoGCCqGSM49BAMCA0gAMEUCIQDES/I1hE8k -CbdiFv5GMSPI5ez9yoduP/kFGHUMW3XMVwIgBbMVw2r62VwuaN5peauo2iyC/bgY -HwkoUVYqbWHakNc= +FN4QeBfxtxhbd7JLY5NrbCSOyZuVMAoGCCqGSM49BAMCA0cAMEQCICB+TzsiJu79 +XiFtDi1WvEUIDusQE4B06oPPZXaXgbxiAiAJyzHCy683xZy8yI2DM6QAbJwTDx+C +3A8PnkEulaO4UA== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/keystore/25ad3edad97423cb9ceba6b06b83ca7f217cd794857d1347dd27ad47f601cbe7_sk b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/keystore/25ad3edad97423cb9ceba6b06b83ca7f217cd794857d1347dd27ad47f601cbe7_sk deleted file mode 100644 index 0fc57376d..000000000 --- a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/keystore/25ad3edad97423cb9ceba6b06b83ca7f217cd794857d1347dd27ad47f601cbe7_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgtqwq+wuBtwD0ve8B -sTmIkwBCuEurl40ffoBPHaGdg02hRANCAAQnxvmbowKl3Dcej4vqK5o2XxNtATj0 -uTRvl5sHas7zBaRT60jZhEOF7xWiduULQtam3gCawJZ1+NvycykCGNyS ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/keystore/64aa0b911f0d7d9a5bd9d0d275bb100e2b26f93b0fabcc0f04a0a7f48b071c87_sk b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/keystore/64aa0b911f0d7d9a5bd9d0d275bb100e2b26f93b0fabcc0f04a0a7f48b071c87_sk new file mode 100644 index 000000000..fa7d4a69b --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/keystore/64aa0b911f0d7d9a5bd9d0d275bb100e2b26f93b0fabcc0f04a0a7f48b071c87_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgOEXW+R621BW7Wp3G +U8Y1f3ubCCeK3HhbKAOaFD+8+nKhRANCAATWET9jPydirpEy5FRvQ59loP593aDF +eePe3pJ3uDZVbq54xR9/sGvNZIZEdwPcUVlsY2yvzBtuICsFmY5YA7s6 +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/signcerts/cert.pem index c4fb3917d..76e803a30 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/signcerts/cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/signcerts/cert.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICPDCCAeKgAwIBAgIUVGktrA2AiBj4KFpflp1oKbsf3n0wCgYIKoZIzj0EAwIw +MIICOzCCAeKgAwIBAgIUZDtctp6016RIyZ4mHezAToPDXH4wCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTIyMDczMDA1NTMwMFowXTELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTIzMDgwNDA2MDkwMFowXTELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGY2xpZW50MQ4wDAYDVQQDEwVhZG1pbjBZMBMGByqG -SM49AgEGCCqGSM49AwEHA0IABCfG+ZujAqXcNx6Pi+ormjZfE20BOPS5NG+Xmwdq -zvMFpFPrSNmEQ4XvFaJ25QtC1qbeAJrAlnX42/JzKQIY3JKjdTBzMA4GA1UdDwEB -/wQEAwIHgDAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRCYTnqkfDlZWFFv88Wb7u/ -9OKOEjAfBgNVHSMEGDAWgBT/6nHBowPac57ee3eyB/use7ZGlzATBgNVHREEDDAK -gghzYW5uaXNoMTAKBggqhkjOPQQDAgNIADBFAiEAmVEoju+8Tn3y3UxXd+fsdkSY -kOz2uRztw0MaSc/KTSACIAuJIrZz9ILFAPT+GEZY0kcxAEZYNkr0j4ihdN2euwp5 +SM49AgEGCCqGSM49AwEHA0IABNYRP2M/J2KukTLkVG9Dn2Wg/n3doMV5497ekne4 +NlVurnjFH3+wa81khkR3A9xRWWxjbK/MG24gKwWZjlgDuzqjdTBzMA4GA1UdDwEB +/wQEAwIHgDAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRabNtCH1axnuzGT+57D7bt +CNQLATAfBgNVHSMEGDAWgBTeEHgX8bcYW3eyS2OTa2wkjsmblTATBgNVHREEDDAK +gghzYW5uaXNoMTAKBggqhkjOPQQDAgNHADBEAiBvNQpNn9xz4YfNs2a01kNz3kc6 +LRhUP0kG6HTBhYRJegIgIeI3GmM82d4B20CGoWFd9FWte6sQYaosU3D4OQJMSEQ= -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/tlscacerts/tlsca.network2.com-cert.pem b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/tlscacerts/tlsca.network2.com-cert.pem index 7bc4e17b0..263498d74 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/tlscacerts/tlsca.network2.com-cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/tlscacerts/tlsca.network2.com-cert.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFzCCAb2gAwIBAgIUcD3XTdKlKhRXdbBDR6f0TJeiPnowCgYIKoZIzj0EAwIw +MIICFjCCAb2gAwIBAgIUE1YC4hF0zZ1tbaqoonCjZSAze40wCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTM2MDcyNjA1NDgwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTM3MDczMTA2MDQwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdUmrRFbY2jFmawWYLpEgdcH0 -2j428D/3gk+1Vm7DlGjd9QudiaJKEEwQkThAAW2ZVxyJTeDJ9Ar0/O9K4+jSB6NF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEi4mzLXiztQ2XsIvmMNaXQC25 +UGUBq8ZWt2jmfIjfQkh7+tht/wg5tosanXa/9SCvAJhnQsCQd9SulCnK6r3t3qNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FP/qccGjA9pznt57d7IH+6x7tkaXMAoGCCqGSM49BAMCA0gAMEUCIQDES/I1hE8k -CbdiFv5GMSPI5ez9yoduP/kFGHUMW3XMVwIgBbMVw2r62VwuaN5peauo2iyC/bgY -HwkoUVYqbWHakNc= +FN4QeBfxtxhbd7JLY5NrbCSOyZuVMAoGCCqGSM49BAMCA0cAMEQCICB+TzsiJu79 +XiFtDi1WvEUIDusQE4B06oPPZXaXgbxiAiAJyzHCy683xZy8yI2DM6QAbJwTDx+C +3A8PnkEulaO4UA== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/IssuerPublicKey index cf4837d09e16d220a2e6c8e9e951b94ea75ae0fe..15c8a4ad0ceebc274ce70ae967a680ff4811f24a 100644 GIT binary patch delta 810 zcmV+_1J(S?2FnJJE`ROR1&!K}?uia_x8QOc<977(X2n;yZg>>Zyw(NUeC-k-k%Tvp z2ZJCL+|*gO8(CtSY$~e~AQ-L?=qXqihGosfwD1YW5gfbY zfz&PBKC0PYV1fQ9kRn71An3t0!~H9GT7kgvL}618zN+=%BdrrKmNuL$Atc@#!XU4cgtbE8#p}o18M$@>+7t$g` z3Luod`Ne^AqO-#F(iBkTSb~L{e!T1cSS$(j=uv!Wr+V~}S z`Rm4HZhmbLVZ->rfr{Ns8Y+kZ3Luhmm(W8 z&m6b$jsF2$_L<%70T{!5a>wif>hJ9(zm$z`@e4vtSQwB`a=?Hb| zf8hwG5+KBKAqsvhrQXG(d*N0?86yU2f#m|tzScf_(Ril8bk^pxI-=N~KB#mSRT3Z= z$%`UKg$a=F1%Gj*FxgJ7s0)XLkZ0fLgsRlS;cawaB18%xnSP?ckkN%se-mT$6IB?x zQ~Dw-;80xk^*Zf@LWWk#5+Lg}V%8bfPq7DK4VeQ3hCF!B9jj}ZNot6Y>7bhrx0ND9 z3Lr{;p}Y$$WMm`_o6ZW;8D%&y1C_q(Tw0i_FHAcc3w=?cY9Nhlr6k(Gx`GubZrFf5mdf@UccXV!iM zB{D<`Ac<&;H6)bDi93)=B&Qit-TfZ%~6R2!4e?Rh+FRBkGB2iA_Rso z6quk=P3>^ub^uJLCPr_n%5cIuL<%6S$lIpBw11U4bjN*w-#H=WiiriGL4x-6jc*_- zKe58a5+Fu~b&?=q9=@5A$lU=dsIN+5rfY%f9j*(XUgVi0No*l|W*%>Cjc+Zyh#YM?MT oxFh9KAh1G2n0giyqQHz6akL0mbT=3K9`zl3`@{&C4QTLhnJqDQS^xk5 diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/IssuerRevocationPublicKey index 611fab391..9b62f7ae4 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/IssuerRevocationPublicKey +++ b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/IssuerRevocationPublicKey @@ -1,5 +1,5 @@ -----BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEgJ8xIRqgf3y/NEW4a0sB149n0xIyMILm -cu/fPRD0T+rRCW4PmNtzJtIwF/dOvZ0o3sF2viN5od5prlozeBdY2T0Ba328PSHv -n2pCvE0oV7UmR8hL1kD/E1yZnc1J/arJ +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEEl7jcAeURcDE2Miyc0fyYPmUT1/7hnPw +NcvnpTjyVabK9nTbqXTUhXi5wapWBtm1ArwhFJ7EYX9zV3inzfiFyCeKUToDlc9a +UfbSsI0ahJYhe47SsjOUfVDN9oU8ChpY -----END PUBLIC KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem index 7bc4e17b0..263498d74 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem +++ b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFzCCAb2gAwIBAgIUcD3XTdKlKhRXdbBDR6f0TJeiPnowCgYIKoZIzj0EAwIw +MIICFjCCAb2gAwIBAgIUE1YC4hF0zZ1tbaqoonCjZSAze40wCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTM2MDcyNjA1NDgwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTM3MDczMTA2MDQwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdUmrRFbY2jFmawWYLpEgdcH0 -2j428D/3gk+1Vm7DlGjd9QudiaJKEEwQkThAAW2ZVxyJTeDJ9Ar0/O9K4+jSB6NF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEi4mzLXiztQ2XsIvmMNaXQC25 +UGUBq8ZWt2jmfIjfQkh7+tht/wg5tosanXa/9SCvAJhnQsCQd9SulCnK6r3t3qNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FP/qccGjA9pznt57d7IH+6x7tkaXMAoGCCqGSM49BAMCA0gAMEUCIQDES/I1hE8k -CbdiFv5GMSPI5ez9yoduP/kFGHUMW3XMVwIgBbMVw2r62VwuaN5peauo2iyC/bgY -HwkoUVYqbWHakNc= +FN4QeBfxtxhbd7JLY5NrbCSOyZuVMAoGCCqGSM49BAMCA0cAMEQCICB+TzsiJu79 +XiFtDi1WvEUIDusQE4B06oPPZXaXgbxiAiAJyzHCy683xZy8yI2DM6QAbJwTDx+C +3A8PnkEulaO4UA== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/keystore/0d73dff17d0b0d8641206ae38e47a76862fdad6f576f4ecce02468af34289e78_sk b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/keystore/0d73dff17d0b0d8641206ae38e47a76862fdad6f576f4ecce02468af34289e78_sk new file mode 100644 index 000000000..93ce458c6 --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/keystore/0d73dff17d0b0d8641206ae38e47a76862fdad6f576f4ecce02468af34289e78_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgAhZzrAOJK5Rl3MSI +LrXnMFokcTzGsYJ/F3spdTuG0NGhRANCAATUmRiiS+o+LJB01XE3Fs+geXAXMH5h +VTVQxu8KSj4iJCj6axbJUMaVCDy9ZCYhNhr7SC3PLY9V4Iw+C7FNqTB/ +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/keystore/d30db3151430ff2c370f8f40cd6e23bb09ed8f3165c7b9957c8761bd9695297f_sk b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/keystore/d30db3151430ff2c370f8f40cd6e23bb09ed8f3165c7b9957c8761bd9695297f_sk deleted file mode 100644 index 7a032fdb2..000000000 --- a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/keystore/d30db3151430ff2c370f8f40cd6e23bb09ed8f3165c7b9957c8761bd9695297f_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgGdEn3r1vd/S0cVwQ -GowrNFFF1MoA4eqHWrRbYAQqJAehRANCAAR9yje267F14rfm3+tKvtraRfQrzZKO -ePkau0AtL//z7I9PsNp1Zy4DjWJpD0Xcrf7R62M59X0tebsU/22UUfKF ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/signcerts/cert.pem index ee27f5a4d..e6281de73 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/signcerts/cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/signcerts/cert.pem @@ -1,17 +1,17 @@ -----BEGIN CERTIFICATE----- -MIICtDCCAlugAwIBAgIUeUYCoDJjH1cg8uUIm4TUmwBgvUswCgYIKoZIzj0EAwIw +MIICtTCCAlugAwIBAgIUTYUi3IbB49vkEy6lOlwiFf2Iwm8wCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTIyMDczMDA1NTMwMFowYDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTIzMDgwNDA2MDkwMFowYDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEQMA4GA1UECxMHb3JkZXJlcjEQMA4GA1UEAxMHb3JkZXJlcjBZMBMG -ByqGSM49AgEGCCqGSM49AwEHA0IABH3KN7brsXXit+bf60q+2tpF9CvNko54+Rq7 -QC0v//Psj0+w2nVnLgONYmkPRdyt/tHrYzn1fS15uxT/bZRR8oWjgeowgecwDgYD -VR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFDrDYQ7aqlICTHYr -zY2bk25uj2hUMB8GA1UdIwQYMBaAFP/qccGjA9pznt57d7IH+6x7tkaXMCoGA1Ud +ByqGSM49AgEGCCqGSM49AwEHA0IABNSZGKJL6j4skHTVcTcWz6B5cBcwfmFVNVDG +7wpKPiIkKPprFslQxpUIPL1kJiE2GvtILc8tj1XgjD4LsU2pMH+jgeowgecwDgYD +VR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFCiBpHBt/cT7tVKE +ko1QuBhzmZmdMB8GA1UdIwQYMBaAFN4QeBfxtxhbd7JLY5NrbCSOyZuVMCoGA1Ud EQQjMCGCFG9yZGVyZXIubmV0d29yazIuY29tgglsb2NhbGhvc3QwWwYIKgMEBQYH CAEET3siYXR0cnMiOnsiaGYuQWZmaWxpYXRpb24iOiIiLCJoZi5FbnJvbGxtZW50 SUQiOiJvcmRlcmVyIiwiaGYuVHlwZSI6Im9yZGVyZXIifX0wCgYIKoZIzj0EAwID -RwAwRAIgTVErz7AUfZEME5Fyn37dDwlD1/5rgVKys1ut77eduKwCIHlQi7nWyslu -pD4HlUtfvmWjxwEfLhXANv2CPZKIN6PD +SAAwRQIhAK8IWESRnW42GQcMD+P1RDYnpfkHpQ3RIhA/84KkvcCDAiBma8HUHkVa +imb0Rul9c+VSFnct/wl5qDgbuXp6IJRxJA== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/tlscacerts/tlsca.network2.com-cert.pem b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/tlscacerts/tlsca.network2.com-cert.pem index 7bc4e17b0..263498d74 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/tlscacerts/tlsca.network2.com-cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/tlscacerts/tlsca.network2.com-cert.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFzCCAb2gAwIBAgIUcD3XTdKlKhRXdbBDR6f0TJeiPnowCgYIKoZIzj0EAwIw +MIICFjCCAb2gAwIBAgIUE1YC4hF0zZ1tbaqoonCjZSAze40wCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTM2MDcyNjA1NDgwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTM3MDczMTA2MDQwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdUmrRFbY2jFmawWYLpEgdcH0 -2j428D/3gk+1Vm7DlGjd9QudiaJKEEwQkThAAW2ZVxyJTeDJ9Ar0/O9K4+jSB6NF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEi4mzLXiztQ2XsIvmMNaXQC25 +UGUBq8ZWt2jmfIjfQkh7+tht/wg5tosanXa/9SCvAJhnQsCQd9SulCnK6r3t3qNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FP/qccGjA9pznt57d7IH+6x7tkaXMAoGCCqGSM49BAMCA0gAMEUCIQDES/I1hE8k -CbdiFv5GMSPI5ez9yoduP/kFGHUMW3XMVwIgBbMVw2r62VwuaN5peauo2iyC/bgY -HwkoUVYqbWHakNc= +FN4QeBfxtxhbd7JLY5NrbCSOyZuVMAoGCCqGSM49BAMCA0cAMEQCICB+TzsiJu79 +XiFtDi1WvEUIDusQE4B06oPPZXaXgbxiAiAJyzHCy683xZy8yI2DM6QAbJwTDx+C +3A8PnkEulaO4UA== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/IssuerPublicKey index cf4837d09e16d220a2e6c8e9e951b94ea75ae0fe..15c8a4ad0ceebc274ce70ae967a680ff4811f24a 100644 GIT binary patch delta 810 zcmV+_1J(S?2FnJJE`ROR1&!K}?uia_x8QOc<977(X2n;yZg>>Zyw(NUeC-k-k%Tvp z2ZJCL+|*gO8(CtSY$~e~AQ-L?=qXqihGosfwD1YW5gfbY zfz&PBKC0PYV1fQ9kRn71An3t0!~H9GT7kgvL}618zN+=%BdrrKmNuL$Atc@#!XU4cgtbE8#p}o18M$@>+7t$g` z3Luod`Ne^AqO-#F(iBkTSb~L{e!T1cSS$(j=uv!Wr+V~}S z`Rm4HZhmbLVZ->rfr{Ns8Y+kZ3Luhmm(W8 z&m6b$jsF2$_L<%70T{!5a>wif>hJ9(zm$z`@e4vtSQwB`a=?Hb| zf8hwG5+KBKAqsvhrQXG(d*N0?86yU2f#m|tzScf_(Ril8bk^pxI-=N~KB#mSRT3Z= z$%`UKg$a=F1%Gj*FxgJ7s0)XLkZ0fLgsRlS;cawaB18%xnSP?ckkN%se-mT$6IB?x zQ~Dw-;80xk^*Zf@LWWk#5+Lg}V%8bfPq7DK4VeQ3hCF!B9jj}ZNot6Y>7bhrx0ND9 z3Lr{;p}Y$$WMm`_o6ZW;8D%&y1C_q(Tw0i_FHAcc3w=?cY9Nhlr6k(Gx`GubZrFf5mdf@UccXV!iM zB{D<`Ac<&;H6)bDi93)=B&Qit-TfZ%~6R2!4e?Rh+FRBkGB2iA_Rso z6quk=P3>^ub^uJLCPr_n%5cIuL<%6S$lIpBw11U4bjN*w-#H=WiiriGL4x-6jc*_- zKe58a5+Fu~b&?=q9=@5A$lU=dsIN+5rfY%f9j*(XUgVi0No*l|W*%>Cjc+Zyh#YM?MT oxFh9KAh1G2n0giyqQHz6akL0mbT=3K9`zl3`@{&C4QTLhnJqDQS^xk5 diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/IssuerRevocationPublicKey index 611fab391..9b62f7ae4 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/IssuerRevocationPublicKey +++ b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/IssuerRevocationPublicKey @@ -1,5 +1,5 @@ -----BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEgJ8xIRqgf3y/NEW4a0sB149n0xIyMILm -cu/fPRD0T+rRCW4PmNtzJtIwF/dOvZ0o3sF2viN5od5prlozeBdY2T0Ba328PSHv -n2pCvE0oV7UmR8hL1kD/E1yZnc1J/arJ +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEEl7jcAeURcDE2Miyc0fyYPmUT1/7hnPw +NcvnpTjyVabK9nTbqXTUhXi5wapWBtm1ArwhFJ7EYX9zV3inzfiFyCeKUToDlc9a +UfbSsI0ahJYhe47SsjOUfVDN9oU8ChpY -----END PUBLIC KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/ca.crt b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/ca.crt index 7bc4e17b0..263498d74 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/ca.crt +++ b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/ca.crt @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFzCCAb2gAwIBAgIUcD3XTdKlKhRXdbBDR6f0TJeiPnowCgYIKoZIzj0EAwIw +MIICFjCCAb2gAwIBAgIUE1YC4hF0zZ1tbaqoonCjZSAze40wCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTM2MDcyNjA1NDgwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTM3MDczMTA2MDQwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdUmrRFbY2jFmawWYLpEgdcH0 -2j428D/3gk+1Vm7DlGjd9QudiaJKEEwQkThAAW2ZVxyJTeDJ9Ar0/O9K4+jSB6NF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEi4mzLXiztQ2XsIvmMNaXQC25 +UGUBq8ZWt2jmfIjfQkh7+tht/wg5tosanXa/9SCvAJhnQsCQd9SulCnK6r3t3qNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FP/qccGjA9pznt57d7IH+6x7tkaXMAoGCCqGSM49BAMCA0gAMEUCIQDES/I1hE8k -CbdiFv5GMSPI5ez9yoduP/kFGHUMW3XMVwIgBbMVw2r62VwuaN5peauo2iyC/bgY -HwkoUVYqbWHakNc= +FN4QeBfxtxhbd7JLY5NrbCSOyZuVMAoGCCqGSM49BAMCA0cAMEQCICB+TzsiJu79 +XiFtDi1WvEUIDusQE4B06oPPZXaXgbxiAiAJyzHCy683xZy8yI2DM6QAbJwTDx+C +3A8PnkEulaO4UA== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/keystore/9fa526f760e0e861f3118d68faed451ba70639e08a135901d916089703b38eda_sk b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/keystore/9fa526f760e0e861f3118d68faed451ba70639e08a135901d916089703b38eda_sk new file mode 100644 index 000000000..7693127d3 --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/keystore/9fa526f760e0e861f3118d68faed451ba70639e08a135901d916089703b38eda_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgIU7MQen79ghi3Fkk +i6Dhsn5pId/XMTh2c2QOiGrBtGuhRANCAATcFdzKg16Ab54VD84ORPDkdcOGwZ1t +o63U58htjD5VjsOyMD4VDrXuFt7o5X7XpPLPEy4zsjrewL31S1+CSBUw +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/keystore/cc2fe89245d366799edfc39e8cdfa32801c8ae5fc26211ea4faff9ae6672bd35_sk b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/keystore/cc2fe89245d366799edfc39e8cdfa32801c8ae5fc26211ea4faff9ae6672bd35_sk deleted file mode 100644 index 2759c2c7a..000000000 --- a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/keystore/cc2fe89245d366799edfc39e8cdfa32801c8ae5fc26211ea4faff9ae6672bd35_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgUDXGmLy3ZJAggFb6 -dGVgigCf0fnGt5fabS7DBYQD5VihRANCAAQ2gziyzQSbLLnwM2M3FFJYJcpUdRzu -Zu72ALuZbpLVh7t49nvk0GXWltmFkOr5GiJYXYWTkFHTCNJWmBb1Y5fg ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/server.crt b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/server.crt index 22cc7360c..e399c6e4c 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/server.crt +++ b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/server.crt @@ -1,18 +1,18 @@ -----BEGIN CERTIFICATE----- -MIIC1TCCAnygAwIBAgIUdOC/9A7Jw4Cyl7jaPucFerGrcSIwCgYIKoZIzj0EAwIw +MIIC1jCCAnygAwIBAgIUPYZSxbXfH9GuhhoZLxuEIzC3EXEwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTIyMDczMDA1NTMwMFowYDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTIzMDgwNDA2MDkwMFowYDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEQMA4GA1UECxMHb3JkZXJlcjEQMA4GA1UEAxMHb3JkZXJlcjBZMBMG -ByqGSM49AgEGCCqGSM49AwEHA0IABDaDOLLNBJssufAzYzcUUlglylR1HO5m7vYA -u5luktWHu3j2e+TQZdaW2YWQ6vkaIlhdhZOQUdMI0laYFvVjl+CjggEKMIIBBjAO +ByqGSM49AgEGCCqGSM49AwEHA0IABNwV3MqDXoBvnhUPzg5E8OR1w4bBnW2jrdTn +yG2MPlWOw7IwPhUOte4W3ujlftek8s8TLjOyOt7AvfVLX4JIFTCjggEKMIIBBjAO BgNVHQ8BAf8EBAMCA6gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwG -A1UdEwEB/wQCMAAwHQYDVR0OBBYEFNEnR+Hn8AboGgOdxMnw1jzzWfS2MB8GA1Ud -IwQYMBaAFP/qccGjA9pznt57d7IH+6x7tkaXMCoGA1UdEQQjMCGCFG9yZGVyZXIu +A1UdEwEB/wQCMAAwHQYDVR0OBBYEFO09TwcWza3/ePhpX6qt6ihjK82wMB8GA1Ud +IwQYMBaAFN4QeBfxtxhbd7JLY5NrbCSOyZuVMCoGA1UdEQQjMCGCFG9yZGVyZXIu bmV0d29yazIuY29tgglsb2NhbGhvc3QwWwYIKgMEBQYHCAEET3siYXR0cnMiOnsi aGYuQWZmaWxpYXRpb24iOiIiLCJoZi5FbnJvbGxtZW50SUQiOiJvcmRlcmVyIiwi -aGYuVHlwZSI6Im9yZGVyZXIifX0wCgYIKoZIzj0EAwIDRwAwRAIgFEbMfwIBO7F1 -jKGUXeWggFUVsAjtWU5RKPvSyxq+05oCIGZACKgoBpzlCM4diQlEdfBOE+0OmIwe -RHM8Om5MvdE1 +aGYuVHlwZSI6Im9yZGVyZXIifX0wCgYIKoZIzj0EAwIDSAAwRQIhAPcKaCRQFsrX +ueZqo1ff3xiEMqWRbOGT14YLieuyaOssAiB+0TBf+XFtW/AwPO9v9xV2FXsRdU6Y +yI2vbcBPCxr8eA== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/server.key b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/server.key index 2759c2c7a..7693127d3 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/server.key +++ b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/server.key @@ -1,5 +1,5 @@ -----BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgUDXGmLy3ZJAggFb6 -dGVgigCf0fnGt5fabS7DBYQD5VihRANCAAQ2gziyzQSbLLnwM2M3FFJYJcpUdRzu -Zu72ALuZbpLVh7t49nvk0GXWltmFkOr5GiJYXYWTkFHTCNJWmBb1Y5fg +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgIU7MQen79ghi3Fkk +i6Dhsn5pId/XMTh2c2QOiGrBtGuhRANCAATcFdzKg16Ab54VD84ORPDkdcOGwZ1t +o63U58htjD5VjsOyMD4VDrXuFt7o5X7XpPLPEy4zsjrewL31S1+CSBUw -----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/signcerts/cert.pem index 22cc7360c..e399c6e4c 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/signcerts/cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/signcerts/cert.pem @@ -1,18 +1,18 @@ -----BEGIN CERTIFICATE----- -MIIC1TCCAnygAwIBAgIUdOC/9A7Jw4Cyl7jaPucFerGrcSIwCgYIKoZIzj0EAwIw +MIIC1jCCAnygAwIBAgIUPYZSxbXfH9GuhhoZLxuEIzC3EXEwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTIyMDczMDA1NTMwMFowYDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTIzMDgwNDA2MDkwMFowYDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEQMA4GA1UECxMHb3JkZXJlcjEQMA4GA1UEAxMHb3JkZXJlcjBZMBMG -ByqGSM49AgEGCCqGSM49AwEHA0IABDaDOLLNBJssufAzYzcUUlglylR1HO5m7vYA -u5luktWHu3j2e+TQZdaW2YWQ6vkaIlhdhZOQUdMI0laYFvVjl+CjggEKMIIBBjAO +ByqGSM49AgEGCCqGSM49AwEHA0IABNwV3MqDXoBvnhUPzg5E8OR1w4bBnW2jrdTn +yG2MPlWOw7IwPhUOte4W3ujlftek8s8TLjOyOt7AvfVLX4JIFTCjggEKMIIBBjAO BgNVHQ8BAf8EBAMCA6gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwG -A1UdEwEB/wQCMAAwHQYDVR0OBBYEFNEnR+Hn8AboGgOdxMnw1jzzWfS2MB8GA1Ud -IwQYMBaAFP/qccGjA9pznt57d7IH+6x7tkaXMCoGA1UdEQQjMCGCFG9yZGVyZXIu +A1UdEwEB/wQCMAAwHQYDVR0OBBYEFO09TwcWza3/ePhpX6qt6ihjK82wMB8GA1Ud +IwQYMBaAFN4QeBfxtxhbd7JLY5NrbCSOyZuVMCoGA1UdEQQjMCGCFG9yZGVyZXIu bmV0d29yazIuY29tgglsb2NhbGhvc3QwWwYIKgMEBQYHCAEET3siYXR0cnMiOnsi aGYuQWZmaWxpYXRpb24iOiIiLCJoZi5FbnJvbGxtZW50SUQiOiJvcmRlcmVyIiwi -aGYuVHlwZSI6Im9yZGVyZXIifX0wCgYIKoZIzj0EAwIDRwAwRAIgFEbMfwIBO7F1 -jKGUXeWggFUVsAjtWU5RKPvSyxq+05oCIGZACKgoBpzlCM4diQlEdfBOE+0OmIwe -RHM8Om5MvdE1 +aGYuVHlwZSI6Im9yZGVyZXIifX0wCgYIKoZIzj0EAwIDSAAwRQIhAPcKaCRQFsrX +ueZqo1ff3xiEMqWRbOGT14YLieuyaOssAiB+0TBf+XFtW/AwPO9v9xV2FXsRdU6Y +yI2vbcBPCxr8eA== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/tlscacerts/tls-localhost-8054-ca-orderer-network2-com.pem b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/tlscacerts/tls-localhost-8054-ca-orderer-network2-com.pem index 7bc4e17b0..263498d74 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/tlscacerts/tls-localhost-8054-ca-orderer-network2-com.pem +++ b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/tlscacerts/tls-localhost-8054-ca-orderer-network2-com.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFzCCAb2gAwIBAgIUcD3XTdKlKhRXdbBDR6f0TJeiPnowCgYIKoZIzj0EAwIw +MIICFjCCAb2gAwIBAgIUE1YC4hF0zZ1tbaqoonCjZSAze40wCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTM2MDcyNjA1NDgwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTM3MDczMTA2MDQwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdUmrRFbY2jFmawWYLpEgdcH0 -2j428D/3gk+1Vm7DlGjd9QudiaJKEEwQkThAAW2ZVxyJTeDJ9Ar0/O9K4+jSB6NF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEi4mzLXiztQ2XsIvmMNaXQC25 +UGUBq8ZWt2jmfIjfQkh7+tht/wg5tosanXa/9SCvAJhnQsCQd9SulCnK6r3t3qNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FP/qccGjA9pznt57d7IH+6x7tkaXMAoGCCqGSM49BAMCA0gAMEUCIQDES/I1hE8k -CbdiFv5GMSPI5ez9yoduP/kFGHUMW3XMVwIgBbMVw2r62VwuaN5peauo2iyC/bgY -HwkoUVYqbWHakNc= +FN4QeBfxtxhbd7JLY5NrbCSOyZuVMAoGCCqGSM49BAMCA0cAMEQCICB+TzsiJu79 +XiFtDi1WvEUIDusQE4B06oPPZXaXgbxiAiAJyzHCy683xZy8yI2DM6QAbJwTDx+C +3A8PnkEulaO4UA== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/IssuerPublicKey index cf4837d09e16d220a2e6c8e9e951b94ea75ae0fe..15c8a4ad0ceebc274ce70ae967a680ff4811f24a 100644 GIT binary patch delta 810 zcmV+_1J(S?2FnJJE`ROR1&!K}?uia_x8QOc<977(X2n;yZg>>Zyw(NUeC-k-k%Tvp z2ZJCL+|*gO8(CtSY$~e~AQ-L?=qXqihGosfwD1YW5gfbY zfz&PBKC0PYV1fQ9kRn71An3t0!~H9GT7kgvL}618zN+=%BdrrKmNuL$Atc@#!XU4cgtbE8#p}o18M$@>+7t$g` z3Luod`Ne^AqO-#F(iBkTSb~L{e!T1cSS$(j=uv!Wr+V~}S z`Rm4HZhmbLVZ->rfr{Ns8Y+kZ3Luhmm(W8 z&m6b$jsF2$_L<%70T{!5a>wif>hJ9(zm$z`@e4vtSQwB`a=?Hb| zf8hwG5+KBKAqsvhrQXG(d*N0?86yU2f#m|tzScf_(Ril8bk^pxI-=N~KB#mSRT3Z= z$%`UKg$a=F1%Gj*FxgJ7s0)XLkZ0fLgsRlS;cawaB18%xnSP?ckkN%se-mT$6IB?x zQ~Dw-;80xk^*Zf@LWWk#5+Lg}V%8bfPq7DK4VeQ3hCF!B9jj}ZNot6Y>7bhrx0ND9 z3Lr{;p}Y$$WMm`_o6ZW;8D%&y1C_q(Tw0i_FHAcc3w=?cY9Nhlr6k(Gx`GubZrFf5mdf@UccXV!iM zB{D<`Ac<&;H6)bDi93)=B&Qit-TfZ%~6R2!4e?Rh+FRBkGB2iA_Rso z6quk=P3>^ub^uJLCPr_n%5cIuL<%6S$lIpBw11U4bjN*w-#H=WiiriGL4x-6jc*_- zKe58a5+Fu~b&?=q9=@5A$lU=dsIN+5rfY%f9j*(XUgVi0No*l|W*%>Cjc+Zyh#YM?MT oxFh9KAh1G2n0giyqQHz6akL0mbT=3K9`zl3`@{&C4QTLhnJqDQS^xk5 diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/IssuerRevocationPublicKey index 611fab391..9b62f7ae4 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/IssuerRevocationPublicKey +++ b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/IssuerRevocationPublicKey @@ -1,5 +1,5 @@ -----BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEgJ8xIRqgf3y/NEW4a0sB149n0xIyMILm -cu/fPRD0T+rRCW4PmNtzJtIwF/dOvZ0o3sF2viN5od5prlozeBdY2T0Ba328PSHv -n2pCvE0oV7UmR8hL1kD/E1yZnc1J/arJ +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEEl7jcAeURcDE2Miyc0fyYPmUT1/7hnPw +NcvnpTjyVabK9nTbqXTUhXi5wapWBtm1ArwhFJ7EYX9zV3inzfiFyCeKUToDlc9a +UfbSsI0ahJYhe47SsjOUfVDN9oU8ChpY -----END PUBLIC KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem index 7bc4e17b0..263498d74 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem +++ b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/cacerts/localhost-8054-ca-orderer-network2-com.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFzCCAb2gAwIBAgIUcD3XTdKlKhRXdbBDR6f0TJeiPnowCgYIKoZIzj0EAwIw +MIICFjCCAb2gAwIBAgIUE1YC4hF0zZ1tbaqoonCjZSAze40wCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTM2MDcyNjA1NDgwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTM3MDczMTA2MDQwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdUmrRFbY2jFmawWYLpEgdcH0 -2j428D/3gk+1Vm7DlGjd9QudiaJKEEwQkThAAW2ZVxyJTeDJ9Ar0/O9K4+jSB6NF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEi4mzLXiztQ2XsIvmMNaXQC25 +UGUBq8ZWt2jmfIjfQkh7+tht/wg5tosanXa/9SCvAJhnQsCQd9SulCnK6r3t3qNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FP/qccGjA9pznt57d7IH+6x7tkaXMAoGCCqGSM49BAMCA0gAMEUCIQDES/I1hE8k -CbdiFv5GMSPI5ez9yoduP/kFGHUMW3XMVwIgBbMVw2r62VwuaN5peauo2iyC/bgY -HwkoUVYqbWHakNc= +FN4QeBfxtxhbd7JLY5NrbCSOyZuVMAoGCCqGSM49BAMCA0cAMEQCICB+TzsiJu79 +XiFtDi1WvEUIDusQE4B06oPPZXaXgbxiAiAJyzHCy683xZy8yI2DM6QAbJwTDx+C +3A8PnkEulaO4UA== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/keystore/8163fd4f80204f53f3149c20b2a005780753ee8529259598d515f6e14024fe8a_sk b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/keystore/8163fd4f80204f53f3149c20b2a005780753ee8529259598d515f6e14024fe8a_sk deleted file mode 100644 index 8d064442b..000000000 --- a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/keystore/8163fd4f80204f53f3149c20b2a005780753ee8529259598d515f6e14024fe8a_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg7AtwLFfiPRqolVyi -26xp95pPllmipeYDF+HH5oxZraKhRANCAARSsdxQQTd+MTd2Wvlek0pv+ejE182f -WbitsP5wZILR1M6dw/8whHwRClnBhNTwUY64baQL6VtokqszhIoAaGbY ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/keystore/d602b7fae48619fb0dd47e941a559d0ac39b35270df2fce0d798db6b1b11b2b0_sk b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/keystore/d602b7fae48619fb0dd47e941a559d0ac39b35270df2fce0d798db6b1b11b2b0_sk new file mode 100644 index 000000000..625945cb4 --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/keystore/d602b7fae48619fb0dd47e941a559d0ac39b35270df2fce0d798db6b1b11b2b0_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgPmiVWYa+cvihxTpk +ELbiAEsx3LtAPxm4mgXUREHqS2qhRANCAATp7XzomEOopm8NRGL51/IPdUaLbowY +o2NjnQubiusnF5M8ycEbHyhDLoIIcQA0Qy3aMDFDFyCHdFdv1vC7LpZ7 +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/signcerts/cert.pem index 561208d3b..778be5565 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/signcerts/cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/signcerts/cert.pem @@ -1,17 +1,17 @@ -----BEGIN CERTIFICATE----- -MIICpDCCAkqgAwIBAgIUdGGsx2r5tkuMe45vHb0t/orrky0wCgYIKoZIzj0EAwIw +MIICojCCAkqgAwIBAgIUVTNSgWLHMRkMaPFYoH6+iDHW9N4wCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTIyMDczMDA1NTMwMFowYzELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTIzMDgwNDA2MDkwMFowYzELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEOMAwGA1UECxMFYWRtaW4xFTATBgNVBAMTDG9yZGVyZXJBZG1pbjBZ -MBMGByqGSM49AgEGCCqGSM49AwEHA0IABFKx3FBBN34xN3Za+V6TSm/56MTXzZ9Z -uK2w/nBkgtHUzp3D/zCEfBEKWcGE1PBRjrhtpAvpW2iSqzOEigBoZtijgdYwgdMw -DgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFMpYhmiKaAIE -X6b9KgDBLrBg9Ct1MB8GA1UdIwQYMBaAFP/qccGjA9pznt57d7IH+6x7tkaXMBMG +MBMGByqGSM49AgEGCCqGSM49AwEHA0IABOntfOiYQ6imbw1EYvnX8g91RotujBij +Y2OdC5uK6ycXkzzJwRsfKEMugghxADRDLdowMUMXIId0V2/W8LsulnujgdYwgdMw +DgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFFK5pDcW41np +R/iA9qrm/cCt2AtQMB8GA1UdIwQYMBaAFN4QeBfxtxhbd7JLY5NrbCSOyZuVMBMG A1UdEQQMMAqCCHNhbm5pc2gxMF4GCCoDBAUGBwgBBFJ7ImF0dHJzIjp7ImhmLkFm ZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoib3JkZXJlckFkbWluIiwi -aGYuVHlwZSI6ImFkbWluIn19MAoGCCqGSM49BAMCA0gAMEUCIQCHr2XNXOVp/fEf -mZ2sH9gtE2KqoUfm/eMh5YXgP9NEPgIgU4tB+yNAYLzYD4xpsxVYJnua8YgQxyeR -tsT98u5ra/0= +aGYuVHlwZSI6ImFkbWluIn19MAoGCCqGSM49BAMCA0YAMEMCIFPnGx4lcxjsrNsj +ac3bjs6xpesJ8fiDUMtiRMCfw0d5Ah8TRxnMMVWMQrDWxqShyXTgLDw/EznDBmE5 +vHs+M1sH -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/ca/ca.org1.network2.com-cert.pem b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/ca/ca.org1.network2.com-cert.pem index f30b4366a..524585f8d 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/ca/ca.org1.network2.com-cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/ca/ca.org1.network2.com-cert.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFjCCAb2gAwIBAgIUar7AQ9tuF+EnYEV5NzojPETw1B0wCgYIKoZIzj0EAwIw +MIICFzCCAb2gAwIBAgIUaRllBApd/UVhTSw9k4cCNqGfyWEwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTM2MDcyNjA1NDgwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTM3MDczMTA2MDQwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHX4bYZ98sCjpCzBsmiW6j42Q -QkB+dpDkS5IhblsJT8wesFf4EpkkFdR0utBgdL27UmbmmoTHh6P2AWwAtg6UTqNF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEr6IYnwH5QCqxy9F3i1x77rLD +WG3EjMsD16528Q5N8BVStH5A89XeXLrALrAFxvgF5zlFriMRtQMrCxy0pZzJPaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FLnEbQNd9VY+cDmSDvzqxI0cKJnxMAoGCCqGSM49BAMCA0cAMEQCICqeGasMewgQ -bm3A30b/VARhu853QV7MeWbVi5J0lYE7AiAIGm0t947c/hKmiqG+JiU8hlsZzA73 -BbhDFXqROY1Q+g== +FPwe1LrNuI33Vm+EdgO/E/jJihU1MAoGCCqGSM49BAMCA0gAMEUCIQDPHTMu/Hx1 +qm/G090dqV0215wZQ0Dl7al5TlSrrhftfgIge5QZxYKUsUkptToiOnRJY5pD/Oc+ +F9RBKXnii85zCnI= -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/connection-org1.docker.json b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/connection-org1.docker.json index f6d082d9e..edce8e12f 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/connection-org1.docker.json +++ b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/connection-org1.docker.json @@ -26,7 +26,7 @@ "peer0.org1.network2.com": { "url": "grpcs://peer0.org1.network2.com:9051", "tlsCACerts": { - "pem": "-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUar7AQ9tuF+EnYEV5NzojPETw1B0wCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTM2MDcyNjA1NDgwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHX4bYZ98sCjpCzBsmiW6j42Q\nQkB+dpDkS5IhblsJT8wesFf4EpkkFdR0utBgdL27UmbmmoTHh6P2AWwAtg6UTqNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFLnEbQNd9VY+cDmSDvzqxI0cKJnxMAoGCCqGSM49BAMCA0cAMEQCICqeGasMewgQ\nbm3A30b/VARhu853QV7MeWbVi5J0lYE7AiAIGm0t947c/hKmiqG+JiU8hlsZzA73\nBbhDFXqROY1Q+g==\n-----END CERTIFICATE-----\n" + "pem": "-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUaRllBApd/UVhTSw9k4cCNqGfyWEwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTM3MDczMTA2MDQwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEr6IYnwH5QCqxy9F3i1x77rLD\nWG3EjMsD16528Q5N8BVStH5A89XeXLrALrAFxvgF5zlFriMRtQMrCxy0pZzJPaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFPwe1LrNuI33Vm+EdgO/E/jJihU1MAoGCCqGSM49BAMCA0gAMEUCIQDPHTMu/Hx1\nqm/G090dqV0215wZQ0Dl7al5TlSrrhftfgIge5QZxYKUsUkptToiOnRJY5pD/Oc+\nF9RBKXnii85zCnI=\n-----END CERTIFICATE-----\n" }, "grpcOptions": { "ssl-target-name-override": "peer0.org1.network2.com", @@ -39,7 +39,7 @@ "url": "https://ca.org1.network2.com:5054", "caName": "ca-org1", "tlsCACerts": { - "pem": "-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUar7AQ9tuF+EnYEV5NzojPETw1B0wCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTM2MDcyNjA1NDgwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHX4bYZ98sCjpCzBsmiW6j42Q\nQkB+dpDkS5IhblsJT8wesFf4EpkkFdR0utBgdL27UmbmmoTHh6P2AWwAtg6UTqNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFLnEbQNd9VY+cDmSDvzqxI0cKJnxMAoGCCqGSM49BAMCA0cAMEQCICqeGasMewgQ\nbm3A30b/VARhu853QV7MeWbVi5J0lYE7AiAIGm0t947c/hKmiqG+JiU8hlsZzA73\nBbhDFXqROY1Q+g==\n-----END CERTIFICATE-----\n" + "pem": "-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUaRllBApd/UVhTSw9k4cCNqGfyWEwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTM3MDczMTA2MDQwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEr6IYnwH5QCqxy9F3i1x77rLD\nWG3EjMsD16528Q5N8BVStH5A89XeXLrALrAFxvgF5zlFriMRtQMrCxy0pZzJPaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFPwe1LrNuI33Vm+EdgO/E/jJihU1MAoGCCqGSM49BAMCA0gAMEUCIQDPHTMu/Hx1\nqm/G090dqV0215wZQ0Dl7al5TlSrrhftfgIge5QZxYKUsUkptToiOnRJY5pD/Oc+\nF9RBKXnii85zCnI=\n-----END CERTIFICATE-----\n" }, "httpOptions": { "verify": false diff --git a/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/connection-org1.json b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/connection-org1.json index 5eb2bbaab..b3821e499 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/connection-org1.json +++ b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/connection-org1.json @@ -26,7 +26,7 @@ "peer0.org1.network2.com": { "url": "grpcs://localhost:9051", "tlsCACerts": { - "pem": "-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUar7AQ9tuF+EnYEV5NzojPETw1B0wCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTM2MDcyNjA1NDgwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHX4bYZ98sCjpCzBsmiW6j42Q\nQkB+dpDkS5IhblsJT8wesFf4EpkkFdR0utBgdL27UmbmmoTHh6P2AWwAtg6UTqNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFLnEbQNd9VY+cDmSDvzqxI0cKJnxMAoGCCqGSM49BAMCA0cAMEQCICqeGasMewgQ\nbm3A30b/VARhu853QV7MeWbVi5J0lYE7AiAIGm0t947c/hKmiqG+JiU8hlsZzA73\nBbhDFXqROY1Q+g==\n-----END CERTIFICATE-----\n" + "pem": "-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUaRllBApd/UVhTSw9k4cCNqGfyWEwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTM3MDczMTA2MDQwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEr6IYnwH5QCqxy9F3i1x77rLD\nWG3EjMsD16528Q5N8BVStH5A89XeXLrALrAFxvgF5zlFriMRtQMrCxy0pZzJPaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFPwe1LrNuI33Vm+EdgO/E/jJihU1MAoGCCqGSM49BAMCA0gAMEUCIQDPHTMu/Hx1\nqm/G090dqV0215wZQ0Dl7al5TlSrrhftfgIge5QZxYKUsUkptToiOnRJY5pD/Oc+\nF9RBKXnii85zCnI=\n-----END CERTIFICATE-----\n" }, "grpcOptions": { "ssl-target-name-override": "peer0.org1.network2.com", @@ -39,7 +39,7 @@ "url": "https://localhost:5054", "caName": "ca-org1", "tlsCACerts": { - "pem": "-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUar7AQ9tuF+EnYEV5NzojPETw1B0wCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTM2MDcyNjA1NDgwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHX4bYZ98sCjpCzBsmiW6j42Q\nQkB+dpDkS5IhblsJT8wesFf4EpkkFdR0utBgdL27UmbmmoTHh6P2AWwAtg6UTqNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFLnEbQNd9VY+cDmSDvzqxI0cKJnxMAoGCCqGSM49BAMCA0cAMEQCICqeGasMewgQ\nbm3A30b/VARhu853QV7MeWbVi5J0lYE7AiAIGm0t947c/hKmiqG+JiU8hlsZzA73\nBbhDFXqROY1Q+g==\n-----END CERTIFICATE-----\n" + "pem": "-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUaRllBApd/UVhTSw9k4cCNqGfyWEwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTM3MDczMTA2MDQwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEr6IYnwH5QCqxy9F3i1x77rLD\nWG3EjMsD16528Q5N8BVStH5A89XeXLrALrAFxvgF5zlFriMRtQMrCxy0pZzJPaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFPwe1LrNuI33Vm+EdgO/E/jJihU1MAoGCCqGSM49BAMCA0gAMEUCIQDPHTMu/Hx1\nqm/G090dqV0215wZQ0Dl7al5TlSrrhftfgIge5QZxYKUsUkptToiOnRJY5pD/Oc+\nF9RBKXnii85zCnI=\n-----END CERTIFICATE-----\n" }, "httpOptions": { "verify": false diff --git a/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/connection-org1.yaml b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/connection-org1.yaml index e552943ba..eef344a39 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/connection-org1.yaml +++ b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/connection-org1.yaml @@ -13,45 +13,9 @@ client: timeout: peer: endorser: '300' -channels: - mychannel: - orderers: - - orderer.network2.com - peers: - peer0.org1.network2.com: - endorsingPeer: true - chaincodeQuery: true - ledgerQuery: true - eventSource: true - -orderers: - orderer.network2.com: - url: grpcs://localhost:9050 - tlsCACerts: - pem: | - -----BEGIN CERTIFICATE----- - MIICFjCCAb2gAwIBAgIUar7AQ9tuF+EnYEV5NzojPETw1B0wCgYIKoZIzj0EAwIw - aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK - EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt - Y2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTM2MDcyNjA1NDgwMFowaDELMAkG - A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl - cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy - dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHX4bYZ98sCjpCzBsmiW6j42Q - QkB+dpDkS5IhblsJT8wesFf4EpkkFdR0utBgdL27UmbmmoTHh6P2AWwAtg6UTqNF - MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE - FLnEbQNd9VY+cDmSDvzqxI0cKJnxMAoGCCqGSM49BAMCA0cAMEQCICqeGasMewgQ - bm3A30b/VARhu853QV7MeWbVi5J0lYE7AiAIGm0t947c/hKmiqG+JiU8hlsZzA73 - BbhDFXqROY1Q+g== - -----END CERTIFICATE----- - - grpcOptions: - ssl-target-name-override: orderer.network2.com - hostnameOverride: orderer.network2.com - organizations: Org1: mspid: Org1MSP - cryptoPath: users/{username}@org1.network2.com/msp peers: - peer0.org1.network2.com certificateAuthorities: @@ -62,18 +26,18 @@ peers: tlsCACerts: pem: | -----BEGIN CERTIFICATE----- - MIICFjCCAb2gAwIBAgIUar7AQ9tuF+EnYEV5NzojPETw1B0wCgYIKoZIzj0EAwIw + MIICFzCCAb2gAwIBAgIUaRllBApd/UVhTSw9k4cCNqGfyWEwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt - Y2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTM2MDcyNjA1NDgwMFowaDELMAkG + Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTM3MDczMTA2MDQwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy - dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHX4bYZ98sCjpCzBsmiW6j42Q - QkB+dpDkS5IhblsJT8wesFf4EpkkFdR0utBgdL27UmbmmoTHh6P2AWwAtg6UTqNF + dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEr6IYnwH5QCqxy9F3i1x77rLD + WG3EjMsD16528Q5N8BVStH5A89XeXLrALrAFxvgF5zlFriMRtQMrCxy0pZzJPaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE - FLnEbQNd9VY+cDmSDvzqxI0cKJnxMAoGCCqGSM49BAMCA0cAMEQCICqeGasMewgQ - bm3A30b/VARhu853QV7MeWbVi5J0lYE7AiAIGm0t947c/hKmiqG+JiU8hlsZzA73 - BbhDFXqROY1Q+g== + FPwe1LrNuI33Vm+EdgO/E/jJihU1MAoGCCqGSM49BAMCA0gAMEUCIQDPHTMu/Hx1 + qm/G090dqV0215wZQ0Dl7al5TlSrrhftfgIge5QZxYKUsUkptToiOnRJY5pD/Oc+ + F9RBKXnii85zCnI= -----END CERTIFICATE----- grpcOptions: @@ -82,27 +46,23 @@ peers: certificateAuthorities: ca.org1.network2.com: url: https://localhost:5054 - caName: ca.org1.network2.com - registrar: - enrollId: admin - enrollSecret: adminpw + caName: ca-org1 tlsCACerts: - pem: - - | - -----BEGIN CERTIFICATE----- - MIICFjCCAb2gAwIBAgIUar7AQ9tuF+EnYEV5NzojPETw1B0wCgYIKoZIzj0EAwIw - aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK - EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt - Y2Etc2VydmVyMB4XDTIxMDczMDA1NDgwMFoXDTM2MDcyNjA1NDgwMFowaDELMAkG - A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl - cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy - dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHX4bYZ98sCjpCzBsmiW6j42Q - QkB+dpDkS5IhblsJT8wesFf4EpkkFdR0utBgdL27UmbmmoTHh6P2AWwAtg6UTqNF - MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE - FLnEbQNd9VY+cDmSDvzqxI0cKJnxMAoGCCqGSM49BAMCA0cAMEQCICqeGasMewgQ - bm3A30b/VARhu853QV7MeWbVi5J0lYE7AiAIGm0t947c/hKmiqG+JiU8hlsZzA73 - BbhDFXqROY1Q+g== - -----END CERTIFICATE----- + pem: | + -----BEGIN CERTIFICATE----- + MIICFzCCAb2gAwIBAgIUaRllBApd/UVhTSw9k4cCNqGfyWEwCgYIKoZIzj0EAwIw + aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK + EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt + Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTM3MDczMTA2MDQwMFowaDELMAkG + A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl + cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy + dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEr6IYnwH5QCqxy9F3i1x77rLD + WG3EjMsD16528Q5N8BVStH5A89XeXLrALrAFxvgF5zlFriMRtQMrCxy0pZzJPaNF + MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE + FPwe1LrNuI33Vm+EdgO/E/jJihU1MAoGCCqGSM49BAMCA0gAMEUCIQDPHTMu/Hx1 + qm/G090dqV0215wZQ0Dl7al5TlSrrhftfgIge5QZxYKUsUkptToiOnRJY5pD/Oc+ + F9RBKXnii85zCnI= + -----END CERTIFICATE----- httpOptions: verify: false diff --git a/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/msp/IssuerPublicKey index 06ed0f36c2143db352e229c330135625e60c1426..d1b268697b562f4ffa0c3225185168fcf16d995c 100644 GIT binary patch delta 810 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 literal 13399 zcmeI3Ta4pY8OQh5+4Sso8V)Vp4N#VW>25dOjpN)~RqgRL&Ww|B?#=_nw>VDhI1@YL zBp@*$9(bzMB0v<1cmg5bk)Q$pLyz)&%cCq-+W>7M)vQa-4n0<ieLjJ!sf>mv+i5J- zmXmQs%Hi#{oJ}h@rexDvLd#~dIW?WhCDQFgT24q>R!b&vxs9dLDNTkEcwzm|KYHr? z-+uVHCw}_cU%&Q)fBpL_kHtUz@i%|{A^3G2d{u{E*5QlKfU~8cstvUv{K7NvjmrQm zHcLYt{^WAxkDK5$U)h1b-Gsl~gumEa_0Jk#Ub{AX5H!mbFOhV)$}t>?s`R`S@Ek`n zQ<6k7t|N~lkj~W}s&UgyWm6x9j6SocS(QoYok(l6T_UF;}U&XF3a4qp~LS{JFhAZ!8Jb2+U^ zn2I$vTdZm-U3!N{*nB{8%(G>SF%-+}^5ve#c=IHR9ut<>C`_aV?*b90T?MaCRI5JW ziDZ+ia$}xSraXn>MN0R0#`fEI+;5u{yQ?;DIdgEYQ(w*;-0RerGY9jjGd+*?#Qb7) zNhGXRnnHp?2|A+Hnl&slvWRyXOY$1x_JGz^C658To5ZtJETQ+J@w%0vOt!1$gpq1U zg)N%)gkH6SPy=t($CE-;qY61R#A2n~Rx;YH5a}WVc$)X9*;i7=c94*d5lEnrPP070 z&Athh_GlvJ2^^0^0=2XL>}W49%;QT0A<}@^iR~&1+eNv-wC|=eYKF^4)8mZWlbSrT zS(4mkD||9XAf7~+j(EC8asowHVqCmKXM2E@RfE|}vHmg3rL<{oVymN_SdU@zHNKH( z@^z2X3E6+chiSa-jih2~ph+VeHzs6E)BNcP;6b{t z4s4_EI&c$y7+hRLT<>eHXAgV$b;Y)x&S5ERnX{1ui)?rmUh;p*d<2Hzn*V+(bRrUl z>qjBkjPV_O(nbQDEo+hw+Z=cWKJJG{j-;)_^GDN;CN+kJdsj(Um;3fH@ImqbD3&$H z9U6*j*nJ0vmZL{L3C@$!K#~p9a1G6Yk3axI;7lEV0fQ%2QD6K3c!=~9wZ1cQs*`~R z-wMOOgh5Di6?G`JU3eo5eijCg{I``0-(VsyhvvZK4xlhz^+92OvI2!_iHzk?rr;&X ziJ9q2J0peBhU`$OaPM7E$W2!8u*%QQPCj!yK%Dm#6bd{_E*WQDP852rW?{xYSM6xb zA899AJi)Vom>f{F8Jb%XHRREGgmH+VB&xK%T_g&QGisx$I8|yjQ#U7OIi4@2tjwN> zz$j&odTt{>N_258S`}KV)WF4tklyP_oY_%3t&&hvc@8rrk=d(v%_!N`b$ZL^#01er zB{1W6RlXuh9Cvd!uxbIC-kKZ69?Tbw${`dy3W+< z4(hs%TB^LYvsamnccWO!CONi+$SvI_22+#dld2(@wAv<0bQCLDoTq_up3j!76u+m^ z@jHOhjo_p(XFtJ7Avh@nCxwM)2qAbNg<+Nx1{Y3Vdf>|b{{CUHvH>0>BvarYxK+$e<18yS_{Njq z+^p2HhpsWQ9QflW;agWgxFT5tQ#74&DF)ILRl4RZ@N3?FlDRIAKz-zD!xrCkQ}+Iv691Uo-X*s zQvxM0IaWvI&M2Eo2=xrFHRQUHDqyBaXOMw7*23IeGNZ&gTb8lQMhiwQ+cBNi6lD^C zkUJF9+%1>HxDeH!z27!%Ad-8!4ddOvmmv_z{SnFC*tCH-0&)D`H~PGnt{``5(+2to z^zr`E$KBYpfjR^_1Na=ytc*NX2 zHjzU^I1SGE*0ViyG|Ru=?|EQ~x49$nbG0fl zkK>u^nE#AFotZi7w;TB#I@C{qa9(mcMqfv!Zu@?D$AWOS00%eWFIO&d4P2a~T}pDL xMMA|Ljudw^)coUVE%dhkcz7A^)8dt5zaqEyKzH8>bzXg`{{IKSDR5%>{147gLsI|% From 6c46d542cb2c3644cffc3da7e7b3d47d749cc58a Mon Sep 17 00:00:00 2001 From: sannish Date: Thu, 4 Aug 2022 07:27:09 +0000 Subject: [PATCH 079/150] update fabric/shared/README as per latest instructions Signed-off-by: sannish --- tests/network-setups/fabric/shared/README.md | 35 +++++++++----------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/tests/network-setups/fabric/shared/README.md b/tests/network-setups/fabric/shared/README.md index 7191590c7..8e69521cf 100644 --- a/tests/network-setups/fabric/shared/README.md +++ b/tests/network-setups/fabric/shared/README.md @@ -7,26 +7,20 @@ If these get expired they can be generated again. First stop all testnet deploye ## Steps to generate -All paths in following steps are relative to this folder (`tests/network-setups/fabric/shared`). +All paths in following steps are relative to this folder (`tests/network-setups/fabric/dev`). 1. Run following to delete existing crypto materials and artifacts: ``` - cd network1 - rm -rf ordererOrganizations/ peerOrganizations/ system-genesis-block/ channel-artifacts/ fabric-ca/ordererOrg/ fabric-ca/org1/ - cd ../network2 - rm -rf ordererOrganizations/ peerOrganizations/ system-genesis-block/ channel-artifacts/ fabric-ca/ordererOrg/ fabric-ca/org1/ + make delete-artifacts + ``` +2. Run `make start-interop`. This will re-generate all crypto materials and artifacts. +3. To generate ccp file for docker, run: + ``` + make docker-ccp ``` -2. Go to `../dev`, and run `make start-interop`. This will re-generate all crypto materials and artifacts. -3. Go to `network1/peerOrganizations/org1.network1.com`, create a copy of `connection-org1.json`, named `connection-org1.docker.json`. Edit the `connection-org1.docker.json`: - - Line 27 change url, replace `localhost` to `peer0.org1.network1.com`. - - Line 39 change url, replace `localhost` to `ca.org1.network1.com`. -4. Repeat above step 3, for `network2` as well, by replacing `network1` with `network2` in step 3. 5. Run following to allow these crypto materials to be checked in github: ``` - sudo chmod 644 network1/fabric-ca/ordererOrg/msp/keystore/* - sudo chmod 644 network1/fabric-ca/org1/msp/keystore/* - sudo chmod 644 network2/fabric-ca/ordererOrg/msp/keystore/* - sudo chmod 644 network2/fabric-ca/org1/msp/keystore/* + make chmod-artifacts ``` ## Steps to update wallets and credentials in other components: @@ -36,9 +30,8 @@ All paths in following steps are relative to this folder (`tests/network-setups/ - Delete contents of `src/wallet-network1` and `src/wallet-network2`. - Delete contents of `src/data/credentials/network1` and `src/data/credentials/network2`. - Delete contents of `src/data/credentials_docker/network1` and `src/data/credentials_docker/network2`. -3. Now follow the steps to run testnet demo provided [here](https://labs.hyperledger.org/weaver-dlt-interoperability/docs/external/getting-started), to: - - Build and run `fabric-driver` for both networks. This will re-generate wallets for fabric-driver. - - Build `fabric-cli`. Set up `.env` and `config.json` as per the steps there. (Don't run anything else in fabric-cli from the steps there). +3. Now follow the steps to run testnet demo provided [here](https://labs.hyperledger.org/weaver-dlt-interoperability/docs/external/getting-started/test-network/setup-local#fabric-driver), to build and run `fabric-driver` for both networks. This will re-generate wallets for fabric-driver. +4. Build `fabric-cli`. Set up `.env` and `config.json` as per the steps in docs. (Don't run anything else in fabric-cli from the steps there). 4. Go to `samples/fabric/fabric-cli`, and run following commands to create credentials for fabric networks: ``` ./bin/fabric-cli configure create all --local-network=network1 @@ -49,8 +42,12 @@ All paths in following steps are relative to this folder (`tests/network-setups/ - Go to `samples/fabric/fabric-cli` and copy `src/data/credentials/network1` and `src/data/credentials/network2` to `src/data/credentials_docker` directory. - Go to `samples/corda/corda-simple-application/clients/src/main/resources/config` and then follow these steps: 1. With reference from `samples/fabric/fabric-cli/src/data/credentials/network1/access-control.json`, update the `rules.principal` key in `network1/access-control.json`. - 2. With reference from `samples/fabric/fabric-cli/src/data/credentials/network1/membership.json`, update the `members.Org1MSP.value` key in `network1/membership.json`. - 3. Repeat steps `a` and `b` for `network1-docker` as well with same reference. + 2. Copy `samples/fabric/fabric-cli/src/data/credentials/network1/membership.json` to `credentials/network1/membership.json`. + 3. Repeat steps `a` and `b` for `network1-docker`. 4. Repeat steps `a` and `b` for `network2` by replacing `network1` with `network2`. +6. Go to `tests/network-setups/fabric/dev` folder, and finally run, to create backup of artifacts: + ``` + make backup + ``` --- From 7b57658f95ea7f7a6222ed43dc5332493e1fae0d Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Thu, 4 Aug 2022 16:29:57 +0530 Subject: [PATCH 080/150] update unit tests and added that to readme Signed-off-by: sandeep.nishad1 --- .../corda/app/interop/WriteExternalStateTest.kt | 4 ++-- .../contracts/interop/write_external_state_test.go | 14 +++++++------- tests/network-setups/fabric/shared/README.md | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/network/corda-interop-app/interop-workflows/src/test/kotlin/com/weaver/corda/app/interop/WriteExternalStateTest.kt b/core/network/corda-interop-app/interop-workflows/src/test/kotlin/com/weaver/corda/app/interop/WriteExternalStateTest.kt index a099ce494..a2b0f73f7 100644 --- a/core/network/corda-interop-app/interop-workflows/src/test/kotlin/com/weaver/corda/app/interop/WriteExternalStateTest.kt +++ b/core/network/corda-interop-app/interop-workflows/src/test/kotlin/com/weaver/corda/app/interop/WriteExternalStateTest.kt @@ -47,9 +47,9 @@ class WriteExternalStateTest { val fabricRelayEndpoint = "relay-network1:9080" val fabricViewAddress = "mychannel:simplestate:Read:a" - val b64FabricView = "CjIIAxIYMjAyMS0wOC0wOVQxMToxOToxNC41OTJaGgxOb3Rhcml6YXRpb24iBlNUUklORxKBDApKCMgBGkUKCEFyY3R1cnVzEjlyZWxheS1uZXR3b3JrMTo5MDgwL25ldHdvcmsxL215Y2hhbm5lbDpzaW1wbGVzdGF0ZTpSZWFkOmEaigMKIFDt2MRSUeTYAeOVPLZH7N+xPQ+ayZ2KwTWB2AlSLsXsEuUCCogCEmYKCl9saWZlY3ljbGUSWAooCiJuYW1lc3BhY2VzL2ZpZWxkcy9pbnRlcm9wL1NlcXVlbmNlEgIIBgosCiZuYW1lc3BhY2VzL2ZpZWxkcy9zaW1wbGVzdGF0ZS9TZXF1ZW5jZRICCAMSagoHaW50ZXJvcBJfCiMKHQBhY2Nlc3NDb250cm9sAENvcmRhX05ldHdvcmsAEgIICwogChoAbWVtYmVyc2hpcABDb3JkYV9OZXR3b3JrABICCA0KFgoQAPSPv79pbml0aWFsaXplZBICCAcSMgoLc2ltcGxlc3RhdGUSIwoWChAA9I+/v2luaXRpYWxpemVkEgIIBAoJCgFhEgQICRABGkoIyAEaRQoIQXJjdHVydXMSOXJlbGF5LW5ldHdvcmsxOjkwODAvbmV0d29yazEvbXljaGFubmVsOnNpbXBsZXN0YXRlOlJlYWQ6YSIMEgdpbnRlcm9wGgExIqUICtkHCgdPcmcxTVNQEs0HLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNvakNDQWttZ0F3SUJBZ0lVTWN4Y1FNWENUcThpVmlCZFUrRFNidTVjM2Rzd0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEl4TURjek1EQTFORGN3TUZvWERUSXlNRGN6TURBMU5USXdNRm93V3pFTE1Ba0cKQTFVRUJoTUNWVk14RnpBVkJnTlZCQWdURGs1dmNuUm9JRU5oY205c2FXNWhNUlF3RWdZRFZRUUtFd3RJZVhCbApjbXhsWkdkbGNqRU5NQXNHQTFVRUN4TUVjR1ZsY2pFT01Bd0dBMVVFQXhNRmNHVmxjakF3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFUWk1uU1hRbyswcWhxTW5yYmxROTRsaExsdW9BeUxsMUQ1K2JPTkRmRXYKUU9IVU9HKy9XL0pqOUV1M1UwTCtNZTRzd1c1M3ZGYmJHNGtWLzZYQzFZMlFvNEhkTUlIYU1BNEdBMVVkRHdFQgovd1FFQXdJSGdEQU1CZ05WSFJNQkFmOEVBakFBTUIwR0ExVWREZ1FXQkJSZXp2K3cyM1F3aWFYcGVYSUhBVGovCmJRSjByakFmQmdOVkhTTUVHREFXZ0JSeWh2V0Mramd2T3N1UlNGNmFyWHUyemwwZy9EQWlCZ05WSFJFRUd6QVoKZ2hkd1pXVnlNQzV2Y21jeExtNWxkSGR2Y21zeExtTnZiVEJXQmdncUF3UUZCZ2NJQVFSS2V5SmhkSFJ5Y3lJNgpleUpvWmk1QlptWnBiR2xoZEdsdmJpSTZJaUlzSW1obUxrVnVjbTlzYkcxbGJuUkpSQ0k2SW5CbFpYSXdJaXdpCmFHWXVWSGx3WlNJNkluQmxaWElpZlgwd0NnWUlLb1pJemowRUF3SURSd0F3UkFJZ09yVmZvbmJCOHh2RU8zYjcKbk1OOHdMK3VhNVV2RmVoSnlHS0RISFN0YURZQ0lHNURWdE42Wm03Q0J0dG1xQlJ6dWt5UzBpZ2p6cE9NMXNxTwpTZS94QS94eAotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tChJHMEUCIQCwTtxvaQhZmLWuBXJFtI0RUaBOxBB5O2ItCjekFUyMUwIgTrOPxQ/PSKDsj+mJTLfEcrK5+f80sqQoQFJr+qBLy2k=" + val b64FabricView = "CjIIAxIYMjAyMi0wOC0wNFQxMDoyNDo0Ny42MDVaGgxOb3Rhcml6YXRpb24iBlNUUklORxKLGgrFBwjIARq/BwoGMTcuNjcxEjlyZWxheS1uZXR3b3JrMTo5MDgwL25ldHdvcmsxL215Y2hhbm5lbDpzaW1wbGVzdGF0ZTpSZWFkOmEi0wYtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ1JqQ0NBZTJnQXdJQkFnSVVSUlJDZGJaNjNpNTlNM3c2OFA1STI1cnoyTEF3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRBMk5USXdNRm9YRFRJek1EZ3dOREEyTlRjd01Gb3dJVEVQTUEwRwpBMVVFQ3hNR1kyeHBaVzUwTVE0d0RBWURWUVFERXdWMWMyVnlNVEJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5CkF3RUhBMElBQk5PZ29SYnJndGZYeHFhL21iQlFObXl4MVBJWExBdWFNV3BxQUl1MUx3MUxNMjh0SnRoT0pxWFUKejZFd0hMR2VMbGJ2U0VUNnhtb1hyZ0l2QkIxWndHNmpnYnN3Z2Jnd0RnWURWUjBQQVFIL0JBUURBZ2VBTUF3RwpBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRk1zWFA3QmpNc21mVXVLZnVlVXNyWTc0cFgwR01COEdBMVVkCkl3UVlNQmFBRlB3ZTFMck51STMzVm0rRWRnTy9FL2pKaWhVMU1GZ0dDQ29EQkFVR0J3Z0JCRXg3SW1GMGRISnoKSWpwN0ltaG1Ma0ZtWm1sc2FXRjBhVzl1SWpvaUlpd2lhR1l1Ulc1eWIyeHNiV1Z1ZEVsRUlqb2lkWE5sY2pFaQpMQ0pvWmk1VWVYQmxJam9pWTJ4cFpXNTBJbjE5TUFvR0NDcUdTTTQ5QkFNQ0EwY0FNRVFDSUJCLzY4MVdmQlIrClFXSUdmaVlLT2szSHVSdE84SkZ3YlRpRWpuQWdDUnZuQWlCYTY5d1dZYVoyNVpSK0dheTY5ZVYrdkRaa1BNSFMKZ2RSakFJdGNLR3N0Rmc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCiokZWE3OWU2NjQtYTJmMi00YzlmLTg2NDMtZTYwNjAwODhmYzlhGpgKCiBVNNh9oMmGr6mjpkClfw32G8jILQMdz9o0hFOMbTk7vRLzCQqaAhJmCgpfbGlmZWN5Y2xlElgKKAoibmFtZXNwYWNlcy9maWVsZHMvaW50ZXJvcC9TZXF1ZW5jZRICCAYKLAombmFtZXNwYWNlcy9maWVsZHMvc2ltcGxlc3RhdGUvU2VxdWVuY2USAggDEn4KB2ludGVyb3AScwoeChgAYWNjZXNzQ29udHJvbABuZXR3b3JrMgASAggUChsKFQBtZW1iZXJzaGlwAG5ldHdvcmsyABICCBYKFgoQAPSPv79pbml0aWFsaXplZBICCAcKHAoWZTJlQ29uZmlkZW50aWFsaXR5RmxhZxICCAcSMAoLc2ltcGxlc3RhdGUSIQoWChAA9I+/v2luaXRpYWxpemVkEgIIBAoHCgFhEgIIGhrFBwjIARq/BwoGMTcuNjcxEjlyZWxheS1uZXR3b3JrMTo5MDgwL25ldHdvcmsxL215Y2hhbm5lbDpzaW1wbGVzdGF0ZTpSZWFkOmEi0wYtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ1JqQ0NBZTJnQXdJQkFnSVVSUlJDZGJaNjNpNTlNM3c2OFA1STI1cnoyTEF3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRBMk5USXdNRm9YRFRJek1EZ3dOREEyTlRjd01Gb3dJVEVQTUEwRwpBMVVFQ3hNR1kyeHBaVzUwTVE0d0RBWURWUVFERXdWMWMyVnlNVEJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5CkF3RUhBMElBQk5PZ29SYnJndGZYeHFhL21iQlFObXl4MVBJWExBdWFNV3BxQUl1MUx3MUxNMjh0SnRoT0pxWFUKejZFd0hMR2VMbGJ2U0VUNnhtb1hyZ0l2QkIxWndHNmpnYnN3Z2Jnd0RnWURWUjBQQVFIL0JBUURBZ2VBTUF3RwpBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRk1zWFA3QmpNc21mVXVLZnVlVXNyWTc0cFgwR01COEdBMVVkCkl3UVlNQmFBRlB3ZTFMck51STMzVm0rRWRnTy9FL2pKaWhVMU1GZ0dDQ29EQkFVR0J3Z0JCRXg3SW1GMGRISnoKSWpwN0ltaG1Ma0ZtWm1sc2FXRjBhVzl1SWpvaUlpd2lhR1l1Ulc1eWIyeHNiV1Z1ZEVsRUlqb2lkWE5sY2pFaQpMQ0pvWmk1VWVYQmxJam9pWTJ4cFpXNTBJbjE5TUFvR0NDcUdTTTQ5QkFNQ0EwY0FNRVFDSUJCLzY4MVdmQlIrClFXSUdmaVlLT2szSHVSdE84SkZ3YlRpRWpuQWdDUnZuQWlCYTY5d1dZYVoyNVpSK0dheTY5ZVYrdkRaa1BNSFMKZ2RSakFJdGNLR3N0Rmc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCiokZWE3OWU2NjQtYTJmMi00YzlmLTg2NDMtZTYwNjAwODhmYzlhIgwSB2ludGVyb3AaATEipQgK2QcKB09yZzFNU1ASzQctLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ29qQ0NBa21nQXdJQkFnSVVHeDlQUksyN0ZOR0RVN012S3V3eGFRZXRaMTh3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRBMk1ESXdNRm9YRFRJek1EZ3dOREEyTURjd01Gb3dXekVMTUFrRwpBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRS0V3dEllWEJsCmNteGxaR2RsY2pFTk1Bc0dBMVVFQ3hNRWNHVmxjakVPTUF3R0ExVUVBeE1GY0dWbGNqQXdXVEFUQmdjcWhrak8KUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVF5ZmFPOFJSUW1JNzY1MXBlOUliU0diSGc5dHh0QUpQS1F6cHIzYzBmQgpZV0tFWmZTR2hUYWVnb21jNkhUVCtGNXhpMkV1YVZkZFo2cTBwMlh4MmRKRm80SGRNSUhhTUE0R0ExVWREd0VCCi93UUVBd0lIZ0RBTUJnTlZIUk1CQWY4RUFqQUFNQjBHQTFVZERnUVdCQlNNVDJ2c0xQVm1xV0xMbEFwbVpmSGIKSnFEamlEQWZCZ05WSFNNRUdEQVdnQlFxRWRTWmIzMEYzckFLWjRsRnJYSXRYRjRqakRBaUJnTlZIUkVFR3pBWgpnaGR3WldWeU1DNXZjbWN4TG01bGRIZHZjbXN4TG1OdmJUQldCZ2dxQXdRRkJnY0lBUVJLZXlKaGRIUnljeUk2CmV5Sm9aaTVCWm1acGJHbGhkR2x2YmlJNklpSXNJbWhtTGtWdWNtOXNiRzFsYm5SSlJDSTZJbkJsWlhJd0lpd2kKYUdZdVZIbHdaU0k2SW5CbFpYSWlmWDB3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnWlE1YTNtekpaK3pmUDlyTwpjWU9vWEQ5UDVqeE1oUmNMQlBQZ0dnL2JLbllDSUNyM3FlSmdzeFgrRWlBV2drSjNHeFdjK1pRRnNzbTlqTWJBCnIxWGJmK0tJCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KEkcwRQIhAM1Gyv7e+SYniXLgB8iBuRqS4C/A9D36SLl4Zj/AkxrpAiByAoaBFpRIMEJsmGasggaQ4AUST+M2n8ctBZCHjDwRxQ==" - val fabricCert = "-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUYyc2soSqUtWVHTOtud7D1FbCHp0wCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTM2MDcyNjA1NDYwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEM/GelSlifY6+rMOE3G95SXF+\ndTHpG8j5cYK82EVCaLCSvNlCKgpupuQnbkLy+V6dgf9tKSnEsZgiHeB6AyJK/6NF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFHKG9YL6OC86y5FIXpqte7bOXSD8MAoGCCqGSM49BAMCA0cAMEQCIA9iMqQ/aJiC\na++ft4tN7io83jB17/fzG3BRC9soRR3bAiALgWNYk5118DKTkhFdJVQ0VIoopEtq\nGzi+/j4j7fu/wQ==\n-----END CERTIFICATE-----\n" + val fabricCert = "-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR\nynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq\nm2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd\nzQkhznMIF4SBF4k=\n-----END CERTIFICATE-----\n" val fabricVerificationPolicy = VerificationPolicyState( securityDomain = fabricNetwork, diff --git a/core/network/fabric-interop-cc/contracts/interop/write_external_state_test.go b/core/network/fabric-interop-cc/contracts/interop/write_external_state_test.go index a8d0472d2..935fdd400 100644 --- a/core/network/fabric-interop-cc/contracts/interop/write_external_state_test.go +++ b/core/network/fabric-interop-cc/contracts/interop/write_external_state_test.go @@ -47,24 +47,24 @@ var fabricRelayEndpoint = "relay-network1:9080" var fabricPattern = "mychannel:simplestate:Read:a" var fabricViewAddress = fabricRelayEndpoint + "/" + fabricNetwork + "/" + fabricPattern -var b64View = "CjIIAxIYMjAyMS0wOC0wOVQxMToxOToxNC41OTJaGgxOb3Rhcml6YXRpb24iBlNUUklORxKBDApKCMgBGkUKCEFyY3R1cnVzEjlyZWxheS1uZXR3b3JrMTo5MDgwL25ldHdvcmsxL215Y2hhbm5lbDpzaW1wbGVzdGF0ZTpSZWFkOmEaigMKIFDt2MRSUeTYAeOVPLZH7N+xPQ+ayZ2KwTWB2AlSLsXsEuUCCogCEmYKCl9saWZlY3ljbGUSWAooCiJuYW1lc3BhY2VzL2ZpZWxkcy9pbnRlcm9wL1NlcXVlbmNlEgIIBgosCiZuYW1lc3BhY2VzL2ZpZWxkcy9zaW1wbGVzdGF0ZS9TZXF1ZW5jZRICCAMSagoHaW50ZXJvcBJfCiMKHQBhY2Nlc3NDb250cm9sAENvcmRhX05ldHdvcmsAEgIICwogChoAbWVtYmVyc2hpcABDb3JkYV9OZXR3b3JrABICCA0KFgoQAPSPv79pbml0aWFsaXplZBICCAcSMgoLc2ltcGxlc3RhdGUSIwoWChAA9I+/v2luaXRpYWxpemVkEgIIBAoJCgFhEgQICRABGkoIyAEaRQoIQXJjdHVydXMSOXJlbGF5LW5ldHdvcmsxOjkwODAvbmV0d29yazEvbXljaGFubmVsOnNpbXBsZXN0YXRlOlJlYWQ6YSIMEgdpbnRlcm9wGgExIqUICtkHCgdPcmcxTVNQEs0HLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNvakNDQWttZ0F3SUJBZ0lVTWN4Y1FNWENUcThpVmlCZFUrRFNidTVjM2Rzd0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEl4TURjek1EQTFORGN3TUZvWERUSXlNRGN6TURBMU5USXdNRm93V3pFTE1Ba0cKQTFVRUJoTUNWVk14RnpBVkJnTlZCQWdURGs1dmNuUm9JRU5oY205c2FXNWhNUlF3RWdZRFZRUUtFd3RJZVhCbApjbXhsWkdkbGNqRU5NQXNHQTFVRUN4TUVjR1ZsY2pFT01Bd0dBMVVFQXhNRmNHVmxjakF3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFUWk1uU1hRbyswcWhxTW5yYmxROTRsaExsdW9BeUxsMUQ1K2JPTkRmRXYKUU9IVU9HKy9XL0pqOUV1M1UwTCtNZTRzd1c1M3ZGYmJHNGtWLzZYQzFZMlFvNEhkTUlIYU1BNEdBMVVkRHdFQgovd1FFQXdJSGdEQU1CZ05WSFJNQkFmOEVBakFBTUIwR0ExVWREZ1FXQkJSZXp2K3cyM1F3aWFYcGVYSUhBVGovCmJRSjByakFmQmdOVkhTTUVHREFXZ0JSeWh2V0Mramd2T3N1UlNGNmFyWHUyemwwZy9EQWlCZ05WSFJFRUd6QVoKZ2hkd1pXVnlNQzV2Y21jeExtNWxkSGR2Y21zeExtTnZiVEJXQmdncUF3UUZCZ2NJQVFSS2V5SmhkSFJ5Y3lJNgpleUpvWmk1QlptWnBiR2xoZEdsdmJpSTZJaUlzSW1obUxrVnVjbTlzYkcxbGJuUkpSQ0k2SW5CbFpYSXdJaXdpCmFHWXVWSGx3WlNJNkluQmxaWElpZlgwd0NnWUlLb1pJemowRUF3SURSd0F3UkFJZ09yVmZvbmJCOHh2RU8zYjcKbk1OOHdMK3VhNVV2RmVoSnlHS0RISFN0YURZQ0lHNURWdE42Wm03Q0J0dG1xQlJ6dWt5UzBpZ2p6cE9NMXNxTwpTZS94QS94eAotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tChJHMEUCIQCwTtxvaQhZmLWuBXJFtI0RUaBOxBB5O2ItCjekFUyMUwIgTrOPxQ/PSKDsj+mJTLfEcrK5+f80sqQoQFJr+qBLy2k=" +var b64View = "CjIIAxIYMjAyMi0wOC0wNFQxMDoyNDo0Ny42MDVaGgxOb3Rhcml6YXRpb24iBlNUUklORxKLGgrFBwjIARq/BwoGMTcuNjcxEjlyZWxheS1uZXR3b3JrMTo5MDgwL25ldHdvcmsxL215Y2hhbm5lbDpzaW1wbGVzdGF0ZTpSZWFkOmEi0wYtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ1JqQ0NBZTJnQXdJQkFnSVVSUlJDZGJaNjNpNTlNM3c2OFA1STI1cnoyTEF3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRBMk5USXdNRm9YRFRJek1EZ3dOREEyTlRjd01Gb3dJVEVQTUEwRwpBMVVFQ3hNR1kyeHBaVzUwTVE0d0RBWURWUVFERXdWMWMyVnlNVEJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5CkF3RUhBMElBQk5PZ29SYnJndGZYeHFhL21iQlFObXl4MVBJWExBdWFNV3BxQUl1MUx3MUxNMjh0SnRoT0pxWFUKejZFd0hMR2VMbGJ2U0VUNnhtb1hyZ0l2QkIxWndHNmpnYnN3Z2Jnd0RnWURWUjBQQVFIL0JBUURBZ2VBTUF3RwpBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRk1zWFA3QmpNc21mVXVLZnVlVXNyWTc0cFgwR01COEdBMVVkCkl3UVlNQmFBRlB3ZTFMck51STMzVm0rRWRnTy9FL2pKaWhVMU1GZ0dDQ29EQkFVR0J3Z0JCRXg3SW1GMGRISnoKSWpwN0ltaG1Ma0ZtWm1sc2FXRjBhVzl1SWpvaUlpd2lhR1l1Ulc1eWIyeHNiV1Z1ZEVsRUlqb2lkWE5sY2pFaQpMQ0pvWmk1VWVYQmxJam9pWTJ4cFpXNTBJbjE5TUFvR0NDcUdTTTQ5QkFNQ0EwY0FNRVFDSUJCLzY4MVdmQlIrClFXSUdmaVlLT2szSHVSdE84SkZ3YlRpRWpuQWdDUnZuQWlCYTY5d1dZYVoyNVpSK0dheTY5ZVYrdkRaa1BNSFMKZ2RSakFJdGNLR3N0Rmc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCiokZWE3OWU2NjQtYTJmMi00YzlmLTg2NDMtZTYwNjAwODhmYzlhGpgKCiBVNNh9oMmGr6mjpkClfw32G8jILQMdz9o0hFOMbTk7vRLzCQqaAhJmCgpfbGlmZWN5Y2xlElgKKAoibmFtZXNwYWNlcy9maWVsZHMvaW50ZXJvcC9TZXF1ZW5jZRICCAYKLAombmFtZXNwYWNlcy9maWVsZHMvc2ltcGxlc3RhdGUvU2VxdWVuY2USAggDEn4KB2ludGVyb3AScwoeChgAYWNjZXNzQ29udHJvbABuZXR3b3JrMgASAggUChsKFQBtZW1iZXJzaGlwAG5ldHdvcmsyABICCBYKFgoQAPSPv79pbml0aWFsaXplZBICCAcKHAoWZTJlQ29uZmlkZW50aWFsaXR5RmxhZxICCAcSMAoLc2ltcGxlc3RhdGUSIQoWChAA9I+/v2luaXRpYWxpemVkEgIIBAoHCgFhEgIIGhrFBwjIARq/BwoGMTcuNjcxEjlyZWxheS1uZXR3b3JrMTo5MDgwL25ldHdvcmsxL215Y2hhbm5lbDpzaW1wbGVzdGF0ZTpSZWFkOmEi0wYtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ1JqQ0NBZTJnQXdJQkFnSVVSUlJDZGJaNjNpNTlNM3c2OFA1STI1cnoyTEF3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRBMk5USXdNRm9YRFRJek1EZ3dOREEyTlRjd01Gb3dJVEVQTUEwRwpBMVVFQ3hNR1kyeHBaVzUwTVE0d0RBWURWUVFERXdWMWMyVnlNVEJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5CkF3RUhBMElBQk5PZ29SYnJndGZYeHFhL21iQlFObXl4MVBJWExBdWFNV3BxQUl1MUx3MUxNMjh0SnRoT0pxWFUKejZFd0hMR2VMbGJ2U0VUNnhtb1hyZ0l2QkIxWndHNmpnYnN3Z2Jnd0RnWURWUjBQQVFIL0JBUURBZ2VBTUF3RwpBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRk1zWFA3QmpNc21mVXVLZnVlVXNyWTc0cFgwR01COEdBMVVkCkl3UVlNQmFBRlB3ZTFMck51STMzVm0rRWRnTy9FL2pKaWhVMU1GZ0dDQ29EQkFVR0J3Z0JCRXg3SW1GMGRISnoKSWpwN0ltaG1Ma0ZtWm1sc2FXRjBhVzl1SWpvaUlpd2lhR1l1Ulc1eWIyeHNiV1Z1ZEVsRUlqb2lkWE5sY2pFaQpMQ0pvWmk1VWVYQmxJam9pWTJ4cFpXNTBJbjE5TUFvR0NDcUdTTTQ5QkFNQ0EwY0FNRVFDSUJCLzY4MVdmQlIrClFXSUdmaVlLT2szSHVSdE84SkZ3YlRpRWpuQWdDUnZuQWlCYTY5d1dZYVoyNVpSK0dheTY5ZVYrdkRaa1BNSFMKZ2RSakFJdGNLR3N0Rmc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCiokZWE3OWU2NjQtYTJmMi00YzlmLTg2NDMtZTYwNjAwODhmYzlhIgwSB2ludGVyb3AaATEipQgK2QcKB09yZzFNU1ASzQctLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ29qQ0NBa21nQXdJQkFnSVVHeDlQUksyN0ZOR0RVN012S3V3eGFRZXRaMTh3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRBMk1ESXdNRm9YRFRJek1EZ3dOREEyTURjd01Gb3dXekVMTUFrRwpBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRS0V3dEllWEJsCmNteGxaR2RsY2pFTk1Bc0dBMVVFQ3hNRWNHVmxjakVPTUF3R0ExVUVBeE1GY0dWbGNqQXdXVEFUQmdjcWhrak8KUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVF5ZmFPOFJSUW1JNzY1MXBlOUliU0diSGc5dHh0QUpQS1F6cHIzYzBmQgpZV0tFWmZTR2hUYWVnb21jNkhUVCtGNXhpMkV1YVZkZFo2cTBwMlh4MmRKRm80SGRNSUhhTUE0R0ExVWREd0VCCi93UUVBd0lIZ0RBTUJnTlZIUk1CQWY4RUFqQUFNQjBHQTFVZERnUVdCQlNNVDJ2c0xQVm1xV0xMbEFwbVpmSGIKSnFEamlEQWZCZ05WSFNNRUdEQVdnQlFxRWRTWmIzMEYzckFLWjRsRnJYSXRYRjRqakRBaUJnTlZIUkVFR3pBWgpnaGR3WldWeU1DNXZjbWN4TG01bGRIZHZjbXN4TG1OdmJUQldCZ2dxQXdRRkJnY0lBUVJLZXlKaGRIUnljeUk2CmV5Sm9aaTVCWm1acGJHbGhkR2x2YmlJNklpSXNJbWhtTGtWdWNtOXNiRzFsYm5SSlJDSTZJbkJsWlhJd0lpd2kKYUdZdVZIbHdaU0k2SW5CbFpYSWlmWDB3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnWlE1YTNtekpaK3pmUDlyTwpjWU9vWEQ5UDVqeE1oUmNMQlBQZ0dnL2JLbllDSUNyM3FlSmdzeFgrRWlBV2drSjNHeFdjK1pRRnNzbTlqTWJBCnIxWGJmK0tJCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KEkcwRQIhAM1Gyv7e+SYniXLgB8iBuRqS4C/A9D36SLl4Zj/AkxrpAiByAoaBFpRIMEJsmGasggaQ4AUST+M2n8ctBZCHjDwRxQ==" -var b64ViewConfidential = "CjIIAxIYMjAyMi0wNC0yOVQxODo0Njo1OC45NzJaGgxOb3Rhcml6YXRpb24iBlNUUklORxLpHAr0CAjIARruCAqyAQqNAQTmm12BRo0TmKw6iwCuxSIgm7ZwEGib20B8e/z2pOkkkzBLPQHUqDYV9Fi4o9SJRhWG+6xWJ5Ohb9QeFjad9p4fnz6GfE3Y4nniiOPMQoDiMbzu0WMorzaPtdCrQAXTXlbPGvE89TDi7FimFpkW/Uq+GDUShvcVv4FiUe55YrgX1XUZzQPYHQipulpiiRogAeXsECkdXiDOcqaoeuUhyX02kmYMDnPRIBhWY6mlnIYSOXJlbGF5LW5ldHdvcmsxOjkwODAvbmV0d29yazEvbXljaGFubmVsOnNpbXBsZXN0YXRlOlJlYWQ6YRgBItMGLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNSekNDQWUyZ0F3SUJBZ0lVR3ZEU01HMzlvN2JhYUNaS2lobE0vVWRseDVZd0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEl4TURrd056QTVNVGN3TUZvWERUSXlNRGt3TnpBNU1qSXdNRm93SVRFUE1BMEcKQTFVRUN4TUdZMnhwWlc1ME1RNHdEQVlEVlFRREV3VjFjMlZ5TVRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OQpBd0VIQTBJQUJGWkRvc0NOaStBNkQ0YjRkRHJ0NWFHdzBQQjdmUlQwcDRoZ1RucWsxVVdmNTJVOGpPSVhnayt0CldGeklDSjBMdGM2aVpXRUtkZUl1NlV6Sy9RMmV0RTZqZ2Jzd2diZ3dEZ1lEVlIwUEFRSC9CQVFEQWdlQU1Bd0cKQTFVZEV3RUIvd1FDTUFBd0hRWURWUjBPQkJZRUZDMlBGbjRzaUNMR1hsLy90ZEFHVElKZVVlSjFNQjhHQTFVZApJd1FZTUJhQUZMbkViUU5kOVZZK2NEbVNEdnpxeEkwY0tKbnhNRmdHQ0NvREJBVUdCd2dCQkV4N0ltRjBkSEp6CklqcDdJbWhtTGtGbVptbHNhV0YwYVc5dUlqb2lJaXdpYUdZdVJXNXliMnhzYldWdWRFbEVJam9pZFhObGNqRWkKTENKb1ppNVVlWEJsSWpvaVkyeHBaVzUwSW4xOU1Bb0dDQ3FHU000OUJBTUNBMGdBTUVVQ0lRQ0RhOXlsbHpmRQpHa28zQy9IOFp4U0p3ZTFlNklnV0xuc1VJTjlFY3gzK3BRSWdQSXUvRTB2bHdjamd1TDV4amI2aUFKRnNxZTFWClI5OUlwRjlTb1VRNUNqTT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoqJDU3NTRiOTQ4LWM4MGYtNDUwYS1hNzA1LWY1NmM3NTA2MjMxNhrHCwogFcRWeu2pvbBCYfrDN0psmIG56fC7F8Ju5dCMIIjGDH8SogsKmgISZgoKX2xpZmVjeWNsZRJYCigKIm5hbWVzcGFjZXMvZmllbGRzL2ludGVyb3AvU2VxdWVuY2USAggGCiwKJm5hbWVzcGFjZXMvZmllbGRzL3NpbXBsZXN0YXRlL1NlcXVlbmNlEgIIAxJ+CgdpbnRlcm9wEnMKHgoYAGFjY2Vzc0NvbnRyb2wAbmV0d29yazIAEgIIDgobChUAbWVtYmVyc2hpcABuZXR3b3JrMgASAggQChYKEAD0j7+/aW5pdGlhbGl6ZWQSAggHChwKFmUyZUNvbmZpZGVudGlhbGl0eUZsYWcSAggHEjAKC3NpbXBsZXN0YXRlEiEKFgoQAPSPv79pbml0aWFsaXplZBICCAQKBwoBYRICCAga9AgIyAEa7ggKsgEKjQEE5ptdgUaNE5isOosArsUiIJu2cBBom9tAfHv89qTpJJMwSz0B1Kg2FfRYuKPUiUYVhvusVieToW/UHhY2nfaeH58+hnxN2OJ54ojjzEKA4jG87tFjKK82j7XQq0AF015WzxrxPPUw4uxYphaZFv1Kvhg1Eob3Fb+BYlHueWK4F9V1Gc0D2B0IqbpaYokaIAHl7BApHV4gznKmqHrlIcl9NpJmDA5z0SAYVmOppZyGEjlyZWxheS1uZXR3b3JrMTo5MDgwL25ldHdvcmsxL215Y2hhbm5lbDpzaW1wbGVzdGF0ZTpSZWFkOmEYASLTBi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlDUnpDQ0FlMmdBd0lCQWdJVUd2RFNNRzM5bzdiYWFDWktpaGxNL1VkbHg1WXdDZ1lJS29aSXpqMEVBd0l3CmFERUxNQWtHQTFVRUJoTUNWVk14RnpBVkJnTlZCQWdURGs1dmNuUm9JRU5oY205c2FXNWhNUlF3RWdZRFZRUUsKRXd0SWVYQmxjbXhsWkdkbGNqRVBNQTBHQTFVRUN4TUdSbUZpY21sak1Sa3dGd1lEVlFRREV4Qm1ZV0p5YVdNdApZMkV0YzJWeWRtVnlNQjRYRFRJeE1Ea3dOekE1TVRjd01Gb1hEVEl5TURrd056QTVNakl3TUZvd0lURVBNQTBHCkExVUVDeE1HWTJ4cFpXNTBNUTR3REFZRFZRUURFd1YxYzJWeU1UQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDkKQXdFSEEwSUFCRlpEb3NDTmkrQTZENGI0ZERydDVhR3cwUEI3ZlJUMHA0aGdUbnFrMVVXZjUyVThqT0lYZ2srdApXRnpJQ0owTHRjNmlaV0VLZGVJdTZVeksvUTJldEU2amdic3dnYmd3RGdZRFZSMFBBUUgvQkFRREFnZUFNQXdHCkExVWRFd0VCL3dRQ01BQXdIUVlEVlIwT0JCWUVGQzJQRm40c2lDTEdYbC8vdGRBR1RJSmVVZUoxTUI4R0ExVWQKSXdRWU1CYUFGTG5FYlFOZDlWWStjRG1TRHZ6cXhJMGNLSm54TUZnR0NDb0RCQVVHQndnQkJFeDdJbUYwZEhKegpJanA3SW1obUxrRm1abWxzYVdGMGFXOXVJam9pSWl3aWFHWXVSVzV5YjJ4c2JXVnVkRWxFSWpvaWRYTmxjakVpCkxDSm9aaTVVZVhCbElqb2lZMnhwWlc1MEluMTlNQW9HQ0NxR1NNNDlCQU1DQTBnQU1FVUNJUUNEYTl5bGx6ZkUKR2tvM0MvSDhaeFNKd2UxZTZJZ1dMbnNVSU45RWN4MytwUUlnUEl1L0Uwdmx3Y2pndUw1eGpiNmlBSkZzcWUxVgpSOTlJcEY5U29VUTVDak09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KKiQ1NzU0Yjk0OC1jODBmLTQ1MGEtYTcwNS1mNTZjNzUwNjIzMTYiDBIHaW50ZXJvcBoBMSKlCArZBwoHT3JnMU1TUBLNBy0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlDb2pDQ0FrbWdBd0lCQWdJVU1jeGNRTVhDVHE4aVZpQmRVK0RTYnU1YzNkc3dDZ1lJS29aSXpqMEVBd0l3CmFERUxNQWtHQTFVRUJoTUNWVk14RnpBVkJnTlZCQWdURGs1dmNuUm9JRU5oY205c2FXNWhNUlF3RWdZRFZRUUsKRXd0SWVYQmxjbXhsWkdkbGNqRVBNQTBHQTFVRUN4TUdSbUZpY21sak1Sa3dGd1lEVlFRREV4Qm1ZV0p5YVdNdApZMkV0YzJWeWRtVnlNQjRYRFRJeE1EY3pNREExTkRjd01Gb1hEVEl5TURjek1EQTFOVEl3TUZvd1d6RUxNQWtHCkExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLRXd0SWVYQmwKY214bFpHZGxjakVOTUFzR0ExVUVDeE1FY0dWbGNqRU9NQXdHQTFVRUF4TUZjR1ZsY2pBd1dUQVRCZ2NxaGtqTwpQUUlCQmdncWhrak9QUU1CQndOQ0FBVFpNblNYUW8rMHFocU1ucmJsUTk0bGhMbHVvQXlMbDFENStiT05EZkV2ClFPSFVPRysvVy9KajlFdTNVMEwrTWU0c3dXNTN2RmJiRzRrVi82WEMxWTJRbzRIZE1JSGFNQTRHQTFVZER3RUIKL3dRRUF3SUhnREFNQmdOVkhSTUJBZjhFQWpBQU1CMEdBMVVkRGdRV0JCUmV6dit3MjNRd2lhWHBlWElIQVRqLwpiUUowcmpBZkJnTlZIU01FR0RBV2dCUnlodldDK2pndk9zdVJTRjZhclh1MnpsMGcvREFpQmdOVkhSRUVHekFaCmdoZHdaV1Z5TUM1dmNtY3hMbTVsZEhkdmNtc3hMbU52YlRCV0JnZ3FBd1FGQmdjSUFRUktleUpoZEhSeWN5STYKZXlKb1ppNUJabVpwYkdsaGRHbHZiaUk2SWlJc0ltaG1Ma1Z1Y205c2JHMWxiblJKUkNJNkluQmxaWEl3SWl3aQphR1l1Vkhsd1pTSTZJbkJsWlhJaWZYMHdDZ1lJS29aSXpqMEVBd0lEUndBd1JBSWdPclZmb25iQjh4dkVPM2I3Cm5NTjh3TCt1YTVVdkZlaEp5R0tESEhTdGFEWUNJRzVEVnRONlptN0NCdHRtcUJSenVreVMwaWdqenBPTTFzcU8KU2UveEEveHgKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoSRzBFAiEApQJHQ6Cn36u44EtWW713lnDj2y8xQUTGRczi/FGucKwCIH3zsuTHrS5w6mEALO8fgY6tVI9TLtDiz6Abnm8GiIUe" +var b64ViewConfidential = "CjIIAxIYMjAyMi0wOC0wNFQxMDozMjoyMC4zMTlaGgxOb3Rhcml6YXRpb24iBlNUUklORxLrHAr0CAjIARruCAqyAQqNAQRdCc5yPbVtY77Ow/6sH6V8AOwbumdSxFq5T62tOT8LIThrPue3yCQBp7P5/6NoKRZR9grAbP9mVHiZ5814qf/DnXULpdh5O5EbVKSZX5BtmXCqTwpmZaqrQzAGgNXVzB8L6QSEVz48fp9X9SuA3r74mzNM5Ip6WbsNXnENpfifEbUfHcDUK28KHN9U+xogYzlOibmMtRdSuUyam+LQmZ5Y4/9X7AyhqEGNe0INblsSOXJlbGF5LW5ldHdvcmsxOjkwODAvbmV0d29yazEvbXljaGFubmVsOnNpbXBsZXN0YXRlOlJlYWQ6YRgBItMGLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNSakNDQWUyZ0F3SUJBZ0lVUlJSQ2RiWjYzaTU5TTN3NjhQNUkyNXJ6MkxBd0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEl5TURnd05EQTJOVEl3TUZvWERUSXpNRGd3TkRBMk5UY3dNRm93SVRFUE1BMEcKQTFVRUN4TUdZMnhwWlc1ME1RNHdEQVlEVlFRREV3VjFjMlZ5TVRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OQpBd0VIQTBJQUJOT2dvUmJyZ3RmWHhxYS9tYkJRTm15eDFQSVhMQXVhTVdwcUFJdTFMdzFMTTI4dEp0aE9KcVhVCno2RXdITEdlTGxidlNFVDZ4bW9YcmdJdkJCMVp3RzZqZ2Jzd2diZ3dEZ1lEVlIwUEFRSC9CQVFEQWdlQU1Bd0cKQTFVZEV3RUIvd1FDTUFBd0hRWURWUjBPQkJZRUZNc1hQN0JqTXNtZlV1S2Z1ZVVzclk3NHBYMEdNQjhHQTFVZApJd1FZTUJhQUZQd2UxTHJOdUkzM1ZtK0VkZ08vRS9qSmloVTFNRmdHQ0NvREJBVUdCd2dCQkV4N0ltRjBkSEp6CklqcDdJbWhtTGtGbVptbHNhV0YwYVc5dUlqb2lJaXdpYUdZdVJXNXliMnhzYldWdWRFbEVJam9pZFhObGNqRWkKTENKb1ppNVVlWEJsSWpvaVkyeHBaVzUwSW4xOU1Bb0dDQ3FHU000OUJBTUNBMGNBTUVRQ0lCQi82ODFXZkJSKwpRV0lHZmlZS09rM0h1UnRPOEpGd2JUaUVqbkFnQ1J2bkFpQmE2OXdXWWFaMjVaUitHYXk2OWVWK3ZEWmtQTUhTCmdkUmpBSXRjS0dzdEZnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoqJDQwZTFjMGUxLWJkZDctNDQ2MC04YzhhLWRlMTZhOWQyOGYwYRrJCwogZOyCYqcgmQJccj0IkSL3t+oNKIzv0PmJqnzbH2jfIV8SpAsKnAISZgoKX2xpZmVjeWNsZRJYCigKIm5hbWVzcGFjZXMvZmllbGRzL2ludGVyb3AvU2VxdWVuY2USAggGCiwKJm5hbWVzcGFjZXMvZmllbGRzL3NpbXBsZXN0YXRlL1NlcXVlbmNlEgIIAxJ+CgdpbnRlcm9wEnMKHgoYAGFjY2Vzc0NvbnRyb2wAbmV0d29yazIAEgIIJwobChUAbWVtYmVyc2hpcABuZXR3b3JrMgASAggpChYKEAD0j7+/aW5pdGlhbGl6ZWQSAggHChwKFmUyZUNvbmZpZGVudGlhbGl0eUZsYWcSAggHEjIKC3NpbXBsZXN0YXRlEiMKFgoQAPSPv79pbml0aWFsaXplZBICCAQKCQoBYRIECBsQARr0CAjIARruCAqyAQqNAQRdCc5yPbVtY77Ow/6sH6V8AOwbumdSxFq5T62tOT8LIThrPue3yCQBp7P5/6NoKRZR9grAbP9mVHiZ5814qf/DnXULpdh5O5EbVKSZX5BtmXCqTwpmZaqrQzAGgNXVzB8L6QSEVz48fp9X9SuA3r74mzNM5Ip6WbsNXnENpfifEbUfHcDUK28KHN9U+xogYzlOibmMtRdSuUyam+LQmZ5Y4/9X7AyhqEGNe0INblsSOXJlbGF5LW5ldHdvcmsxOjkwODAvbmV0d29yazEvbXljaGFubmVsOnNpbXBsZXN0YXRlOlJlYWQ6YRgBItMGLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNSakNDQWUyZ0F3SUJBZ0lVUlJSQ2RiWjYzaTU5TTN3NjhQNUkyNXJ6MkxBd0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEl5TURnd05EQTJOVEl3TUZvWERUSXpNRGd3TkRBMk5UY3dNRm93SVRFUE1BMEcKQTFVRUN4TUdZMnhwWlc1ME1RNHdEQVlEVlFRREV3VjFjMlZ5TVRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OQpBd0VIQTBJQUJOT2dvUmJyZ3RmWHhxYS9tYkJRTm15eDFQSVhMQXVhTVdwcUFJdTFMdzFMTTI4dEp0aE9KcVhVCno2RXdITEdlTGxidlNFVDZ4bW9YcmdJdkJCMVp3RzZqZ2Jzd2diZ3dEZ1lEVlIwUEFRSC9CQVFEQWdlQU1Bd0cKQTFVZEV3RUIvd1FDTUFBd0hRWURWUjBPQkJZRUZNc1hQN0JqTXNtZlV1S2Z1ZVVzclk3NHBYMEdNQjhHQTFVZApJd1FZTUJhQUZQd2UxTHJOdUkzM1ZtK0VkZ08vRS9qSmloVTFNRmdHQ0NvREJBVUdCd2dCQkV4N0ltRjBkSEp6CklqcDdJbWhtTGtGbVptbHNhV0YwYVc5dUlqb2lJaXdpYUdZdVJXNXliMnhzYldWdWRFbEVJam9pZFhObGNqRWkKTENKb1ppNVVlWEJsSWpvaVkyeHBaVzUwSW4xOU1Bb0dDQ3FHU000OUJBTUNBMGNBTUVRQ0lCQi82ODFXZkJSKwpRV0lHZmlZS09rM0h1UnRPOEpGd2JUaUVqbkFnQ1J2bkFpQmE2OXdXWWFaMjVaUitHYXk2OWVWK3ZEWmtQTUhTCmdkUmpBSXRjS0dzdEZnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoqJDQwZTFjMGUxLWJkZDctNDQ2MC04YzhhLWRlMTZhOWQyOGYwYSIMEgdpbnRlcm9wGgExIqUICtkHCgdPcmcxTVNQEs0HLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNvakNDQWttZ0F3SUJBZ0lVR3g5UFJLMjdGTkdEVTdNdkt1d3hhUWV0WjE4d0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEl5TURnd05EQTJNREl3TUZvWERUSXpNRGd3TkRBMk1EY3dNRm93V3pFTE1Ba0cKQTFVRUJoTUNWVk14RnpBVkJnTlZCQWdURGs1dmNuUm9JRU5oY205c2FXNWhNUlF3RWdZRFZRUUtFd3RJZVhCbApjbXhsWkdkbGNqRU5NQXNHQTFVRUN4TUVjR1ZsY2pFT01Bd0dBMVVFQXhNRmNHVmxjakF3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFReWZhTzhSUlFtSTc2NTFwZTlJYlNHYkhnOXR4dEFKUEtRenByM2MwZkIKWVdLRVpmU0doVGFlZ29tYzZIVFQrRjV4aTJFdWFWZGRaNnEwcDJYeDJkSkZvNEhkTUlIYU1BNEdBMVVkRHdFQgovd1FFQXdJSGdEQU1CZ05WSFJNQkFmOEVBakFBTUIwR0ExVWREZ1FXQkJTTVQydnNMUFZtcVdMTGxBcG1aZkhiCkpxRGppREFmQmdOVkhTTUVHREFXZ0JRcUVkU1piMzBGM3JBS1o0bEZyWEl0WEY0ampEQWlCZ05WSFJFRUd6QVoKZ2hkd1pXVnlNQzV2Y21jeExtNWxkSGR2Y21zeExtTnZiVEJXQmdncUF3UUZCZ2NJQVFSS2V5SmhkSFJ5Y3lJNgpleUpvWmk1QlptWnBiR2xoZEdsdmJpSTZJaUlzSW1obUxrVnVjbTlzYkcxbGJuUkpSQ0k2SW5CbFpYSXdJaXdpCmFHWXVWSGx3WlNJNkluQmxaWElpZlgwd0NnWUlLb1pJemowRUF3SURSd0F3UkFJZ1pRNWEzbXpKWit6ZlA5ck8KY1lPb1hEOVA1anhNaFJjTEJQUGdHZy9iS25ZQ0lDcjNxZUpnc3hYK0VpQVdna0ozR3hXYytaUUZzc205ak1iQQpyMVhiZitLSQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tChJHMEUCIQC4MR1TNTeK+FHqEStQkXTM+9kgF4v3SldTn8G3T8Wb1wIgWnDGTnmhr4gL/UmYdB+uQrYaF3IvGtlKZ4r0rDhczxg=" -var b64ViewContents = "CghBcmN0dXJ1cxIQev6XmXObPZZ3lyo7WO9gmw==" +var b64ViewContents = "CghBcmN0dXJ1cxIQTZKuC0jTLZxn3JowK/x2Xg==" -var fabricCert = "-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUYyc2soSqUtWVHTOtud7D1FbCHp0wCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTM2MDcyNjA1NDYwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEM/GelSlifY6+rMOE3G95SXF+\ndTHpG8j5cYK82EVCaLCSvNlCKgpupuQnbkLy+V6dgf9tKSnEsZgiHeB6AyJK/6NF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFHKG9YL6OC86y5FIXpqte7bOXSD8MAoGCCqGSM49BAMCA0cAMEQCIA9iMqQ/aJiC\na++ft4tN7io83jB17/fzG3BRC9soRR3bAiALgWNYk5118DKTkhFdJVQ0VIoopEtq\nGzi+/j4j7fu/wQ==\n-----END CERTIFICATE-----\n" +var fabricCaCertNetwork1 = "-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR\nynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq\nm2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd\nzQkhznMIF4SBF4k=\n-----END CERTIFICATE-----\n" -var network2Member = common.Member{ - Value: fabricCert, +var network1Member = common.Member{ + Value: fabricCaCertNetwork1, Type: "ca", Chain: []string{}, } var network1Membership = common.Membership{ SecurityDomain: fabricNetwork, - Members: map[string]*common.Member{"Org1MSP": &network2Member}, + Members: map[string]*common.Member{"Org1MSP": &network1Member}, } var network1VerificationPolicy = common.VerificationPolicy{ diff --git a/tests/network-setups/fabric/shared/README.md b/tests/network-setups/fabric/shared/README.md index 8e69521cf..a7ac018f1 100644 --- a/tests/network-setups/fabric/shared/README.md +++ b/tests/network-setups/fabric/shared/README.md @@ -49,5 +49,5 @@ All paths in following steps are relative to this folder (`tests/network-setups/ ``` make backup ``` - +Note: Do Update the certs in `fabric-interop-cc` and `corda-interop-app` unit tests for `WriteExternalState`. --- From 03ad0a25e9723c54c7a4d14a0442371ba7ec91f5 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Thu, 4 Aug 2022 16:31:46 +0530 Subject: [PATCH 081/150] remove unncecessary files from fabric/shared (previous commit bug) Signed-off-by: sandeep.nishad1 --- .../network1/ordererOrg/IssuerPublicKey | Bin 843 -> 0 bytes .../ordererOrg/IssuerRevocationPublicKey | 5 - .../network1/ordererOrg/ca-cert.pem | 14 - .../ordererOrg/fabric-ca-server-config.yaml | 504 ------------------ .../network1/ordererOrg/fabric-ca-server.db | Bin 61440 -> 0 bytes ...7c9b9083b64b4b46e327d36f94e16f8ad46f204_sk | 5 - ...e4ff06c983cc896e5552c9e0c0f766aa5476755_sk | 5 - .../msp/keystore/IssuerRevocationPrivateKey | 6 - .../ordererOrg/msp/keystore/IssuerSecretKey | 1 - .../network1/ordererOrg/tls-cert.pem | 16 - .../network1/org1/IssuerPublicKey | Bin 843 -> 0 bytes .../network1/org1/IssuerRevocationPublicKey | 5 - .../network1/org1/ca-cert.pem | 14 - .../org1/fabric-ca-server-config.yaml | 504 ------------------ .../network1/org1/fabric-ca-server.db | Bin 61440 -> 0 bytes ...4c4c1ebb56d3fa0b0ac8a34e2943beeff243edd_sk | 5 - .../msp/keystore/IssuerRevocationPrivateKey | 6 - .../org1/msp/keystore/IssuerSecretKey | Bin 32 -> 0 bytes ...76abf24fa24ec232b8f7844cf8f19730b3504ac_sk | 5 - .../network1/org1/tls-cert.pem | 16 - 20 files changed, 1111 deletions(-) delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrg/IssuerPublicKey delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrg/IssuerRevocationPublicKey delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrg/ca-cert.pem delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrg/fabric-ca-server-config.yaml delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrg/fabric-ca-server.db delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/397c85579ed7ffcec218676697c9b9083b64b4b46e327d36f94e16f8ad46f204_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/6d26b02a002fb3081c443b1f8e4ff06c983cc896e5552c9e0c0f766aa5476755_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/IssuerRevocationPrivateKey delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/IssuerSecretKey delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrg/tls-cert.pem delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/org1/IssuerPublicKey delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/org1/IssuerRevocationPublicKey delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/org1/ca-cert.pem delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/org1/fabric-ca-server-config.yaml delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/org1/fabric-ca-server.db delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/org1/msp/keystore/82bb24244d4f7bcbffb96a71c4c4c1ebb56d3fa0b0ac8a34e2943beeff243edd_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/org1/msp/keystore/IssuerRevocationPrivateKey delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/org1/msp/keystore/IssuerSecretKey delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/org1/msp/keystore/e509e7d66bdbd1e7e777acd4c76abf24fa24ec232b8f7844cf8f19730b3504ac_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/org1/tls-cert.pem diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/IssuerPublicKey deleted file mode 100644 index 15c01b255288251fd71275c0fe0d801c04e38886..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 843 zcmV-R1GM}K0#8*61X6EoWeN;MZgOvIY;9$3bV)=C5K?7!Z)0I}X>V>wVQyq>WfDXR zAh`-fY5cyZVVTA^{FOK+w}#zYr)%*Bg{$e%sj62(uM!}&eDT0N;1cMzkV^(#eI8NG zt;)&2n2cYU`$YF4*si-8L<%4T_8s0O#idJhDPEax$_e;y;*6V!BBqxbdTPT2w}pQa zAn}(`+d*FZkD=+&uCY;+s=y+!(}aO%sXj&TIk7b7Tp~mYAT1_)cVlM{ppzRe=xN!> z79wnaRdn0Axt@-LBy6hNe-a?3(oRaZN`%2NsgiT3(5n+&9ue&Nju$+Uul+^P6@Mxs zL<%4&fzUS_F^KQz4035-cr`T8_;&~lCd>D#qvGfWWsmd{AZzdZ1EZ_LOKEj_yCa`u z!;eL6K{d^HIe*WaYU(9XIU+;~Ac=`CNoUEAb(GarKKD~4sCv1rXg7zrZ>H;T)j$nS z^AaF(B-Qb6)8RF;g&f{gn3amg2PFkZ#w=EArV8%s=uh+_L<%6^Z_JQY^$rI?Hg5oT zcB$lSe}ci3(VRIH5uLb52c`THAVTCCxwUy8d@H5m?c{&>(!@H8*bPW2)+9(vKnh{E zq$-F33LwArz~Q`GgOD6oFZirJPGY0I7}dP&>vj+8X)W3=(k^@D7gxI`$v1j(-Osj)GEAS4*9n{4=tx6 z#!4a}ZDLD7T^;AkW+g6?+LS~&(Fvfr`UY#S0eu70gAw} zg4MpCCeAiKjd^3efVCS7Z?RKs5+I2N@>W3FmEOe7hCWkizq3m9Qg2JAOJ1stO@udH z4G%g*3Lv`=RKR$q3u6485Pk1W5p~fpqJU95q^Badud7_unkf<>e~pE)>AMT$?gxFv z7chDE`d)QWm|tYwzhw)5$cPheLLk7<`|b*+b%HMht&V-?2HG7wynU;$mKsDD-Pr`& z=Nn2O)4+YFBQxo($G%Q&#xjD~(j!8Xi>sjtn{)>sfF*B-QXsOwy>9:@:/ - # 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: - - f586f7bcba54 - - localhost - 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/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/fabric-ca-server.db b/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/fabric-ca-server.db deleted file mode 100644 index 60c4084b91214e58c5232e1a3f0605d7de74d894..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61440 zcmeI4OKjsvdVnR%k2c%gnwd<)Gnk8}XB%j*y4xg0y#`oxNQsgtiIPaY6*LTrq)1An zD3g>ZX|V}BGr>-Po!wv$dkS*NB|#7%#~gwj76@|7B?vG9atM%14ndCDAURBmvTRFk zySIDL-oYA0+fuP!too|zub)-*yUG_m>F2`_ArH!L6OI?|*&|z4KG= z=ei7_KO_JNKmw4!ts-#8@C*A-pZdQr9igksqHH-@PZI@4wvS9*x_rNt;%Tx*hiW8M zq(cuc2R{rw)}&B_3>ic= zMo&VPJTV8dbOdJC72lC;T+T+9C*VO$sYYjMK9r_2WW87mp-(~;o?%J89V*c6$7{8^ zz8(h$C+`J!_8&d+pC}8!La(Rkn&4>W&|Y=lUjw@u5_&uo4EY=?hT_D*Il)l9#Bg=` zNoZurfZ%$pC!uSqa&YG#d>?zQegfElR$qOb*Xlwq{@(U};gR2`4JCPMAL~FhIRb5E zF7A)knjKrc+uZvzAL9*>=UdzR)u*qO0eIliS|(l*wtskcXaD1m{U_w2gd@uwd0kVs zFI;!9f_=-hck#b(J_R z#1VG-efOk#XJ`NUbN^@2Md7`{0)znQrCzfyhp09L+Ua!xyK7avHd^ShJTgV~YI*Lw`QRYBv%SxJa$V0@AppkZ1*bdr z|JL`FC(6DM7ky-P+^@RV=ZMviD}b)a(aYd2y57sP!)KLu7jpI26eh6VxGU4!+bqoL zly+mSedAMA{GC?`{k2H~TfOt%O;3e>;8j9@HHjzUkJd8rd^S&}_jmU9_x+!j7d>nY zdWXIE*jQ`Eh1V7B=YR=*80yX(S$Gn1W~0l(ex(HKf)`BSj$>)vF;II#HM&(hRWVj1 zQpgadNAl1zb=?3;ioGJMu2UDZp=er`EILOc!M0t~@^lYJHbxhzFSLt;d-uNb1@8Xb zcmKzCf4=wCtq?(!6UV^L9a+HD{(o;m_*r!n0@j;_;l(%vKdky6k{#L`S)16%*9HejKfr zgk=`L_rr(YlHS8lAF91)^!YmllYaQ*;bM≱>1pT(N&!%rP+EdS`qYRVdT!FjV3 ztNYdyh^w_wRki?Os%!lniaStiPE`w~~Zh$#xji>cowTZ4$F* zdYy8xWXo+;4|Nhx868bBS{B15N5v955(F=UH>myMftQN+Dg=xCUlsrL0DQ9ndguQx zn|`JKx4-GX+4yYY-`hXg{P5lvWv}K7qRV>MN^>lm6V!>)QW=$%szkRUlr5q?qN)l; z4_al7ugPw@JXDDMI5N&LG0hNl4ZJR|wK+3%WXq5xunI1x$d!(WJzVeLS$UY^i?4{l z%Zg?@mS8<2&tKnHqJRHVek-ldD%MKG%MZTDmp66UUWs`*%Zr$4S(g=1qhFuG+lILG z^cUZ3Y=J)K5B{Gg7q?HpJSV&$0Z8EH2z>ebfxVAjytwz^&hzI#Ywj**T}(ppSTc#n zdYDXLQZgiID`BKqFBi7LAE$oQNi37}iAzQ6wT59!;XSL=f>F7R937 z1QC%Uk*H#t5{}}Lr)c6SN`%nZr)d0B6b+*&_yiaBbnzQn+@A+L^)8CeGNn+8=4(ub zNrA1`g)hP~Ov*{8QlvgsNSC2Vg{kMb{Age#WKPm!O{ayWTY0-oDd|SG?xvJBQ!qQs zypPf#zKaNHy2z4)EQ!@=N@Y`x20P8n$p)pA8X&h?dJvt6L*8WQk}4WWTWCgAmgihr zX{Q?;S3qdjVdNI2i^f#%WF=kf(-oFP7a69eY?e1NnrP^KmLIqocabPfPbs6_%+G`- z>mY5Mc0{}}lZ?iUrHEF##?08X;+E1R&ZZfc&6u9w{K8N4{6JQxB}cw((a%bbtQ4JN zN#d;Nxo#vs=(O@)mCpUiDZAoNby$kcBGl|STV;tPsnFR}YUy_A9Ema{MRsb0nRSoZ zvaZgYx{?UmZHRbG*Ago&V)HVZsSQuQFObD zm(*@norn?6ZMvX0DlAQL?HrOKX}T7%wRVd~#UZPehqfkU+heZTF@)xH1pG%`oY2Y| zqZLzmv!g{b-C=&x%}$+8Gm0YBItK#t6Vc#7Z*0sM&0S>B$mwpU%ETDsykuIhg(3K08CeWkx|Du-Apf|%vA4ezKwrJPyU@1? z8S5rvv6z??fxy8dG8UK7C@Lm|h|r4&(U^oKdvTojZpBZ<6F+j{T>RA3akFC&OQKd$ zdrF&9#8Th z*NUDB!_P7@mEwDLi{+@%p`EHYSaEth67>W|C2dpD!*Ul9*r`pZn66q@QLn0Yrb4G8 z4SX*4?eT!G98y#(XKG~wA1Sd|J=T|M)O;x@r8JN*2oN#ebdpojBs-%mretMe^T`4`M&@cdBBjaRB5{?avuU!aP`pi{%`Dxe z*lC*92Pus1P3w&@U8$97WbO1pG@VY91w>KQdAk`M3$2pL*2n^-D97rcU#@VTKrAt2 zn#zzGO`6lgNkflMJEfG+oNMk(X&%ZcoJ92IyeSf7tm5jDBh!j2*(oMFY-%H;7DJP& zZEE~bnbg90R*28s;ZV&|8k4Ek8MQv(N6st8_LtxH?>$EFMxgA4%p>?>Oo6s=UhWLeYRCnn!<;ZpMPPXl`{Wewt za~~*$i!>MgU0il)hPvq9EJeAc6iIU9bWv{SRkJWC9jj!snHS7hi>1Q(nU+_OB#j=U zOy5cwlX9)0%BAsPYzQXmY_?=EVZ0k@g~hI9HVSep@8}h|80{CWrgUf$*#XOBRb+L% zFNb^jI892YBeqUw`eYrH%AyoHLvdo7X?Nm)+T=Fb2N6;CC zt5+1U&~c_sLoUp)e!VlRx8hF5h|`C*n*(e-9j6Z}?q*D~-X*1ss%G69%T4ng(&2N7 zMy9K#(RtlvJk^v(d5W^#Y@1;_{W?)H+7YB}l(crOj$T$nE-A(7r5>R0Y@&vz$r_*_ zBpG&yOi~ey$hRwzBA%=yIczsl*+gkZ;^3rJ|5|lG%w7{ zLwp`9+6XOH>1Z{JUo9-a>&;dG@jmZYefO*PzX|?juzvq9ZtkrI<_rly0+0YC00}?> zkN_kA2|xmn03>j$2-G)Uyzpa!fJeYulPpHj7!i$tt*Ndgh>55~Bv4t9i9`}u`9-kT zU1{1{u*mgo zFQ;$R0N35Oy@GcSbiF`e;=B7#JHG;7@PY&&fg2|P_y6Jk|Jpu3IJ&U1&ky(i;r>6| z|9|<^f_MA~?*D(glT%k6KU&)yg!}(+{~zxEe6||7U*V`~TkQK*W3h-`M^) z-(4PjzzY(91Rw!O01~(*1im!4&JV->?C{LeW?|v^wznv5#@xo7gTt_c4w4((-$Vf3)v%JnCCoFl}kHDMH;MaXF#oSKb|Qfy>e z$HGI)6*7}9Yg_3UUZ{@w5;=~IBVrn72zo+PMYUQ<^(bI+Beh*cVqL_uxp`xg8`f;f zJf+7Pi4GE-4Ms*>3rFnAu$iCRZ)9@gnH(*QdpM3|$>UTi2TW>==t#sBfRO+uNM@QM z>siWGC@PbWGe!oLa``#a9|5;&6bBgt=@>dN=E|T#GdX7ZCNQcwwU*(V(ODOt+TCVj zEYUjcg`FEh4KjmnQy+VA5zjW~!n9@?FvOB9X`UNFfhJ6ms7SIjI3P*Jje}hm9V*qllSK~d~a`UzmQ6`^vE1-rocZoKy%$%PX_;+ zv=J-!bw`pC?V_O|#d?aD z>;NxGt5+KWo}K?Mx+>l)x5R3tlt!B9u_8|6nF&9!#QK~JGj(}ZD~Pe?_?XJIfp|+! z;$qLmNQ?*VNMw}yL=2bJ3Bxv8g>D2vCz{mOk1I7xuf9TBdGG(=pZ>!O5`Y9C0Z0H6 zfCL}`NB|Om1Rw!O01|)%ZZQGR{vW>o-{J;_Rf7Z|0Z0H6fCL}`NB|Om1Rw!O01|)% z00D3R-yi&y5B$Ol5`Y9C0Z0H6fCL}`NB|Om1Rw!O01|)%ZWnj?0@cjSn zYFJnsNB|Om1Rw!O01|)%AOT1K5`Y9C0Z8B~0`UC*RaBrKBmfCO0+0YC00}?>kN_kA z2|xmn03>j`2zdMd+rdBd1^+Yn&%wV7{(0~h;09ih03-kjKmw2eBmfCO0+0YC00}?> zkN_m`_6Y>H1D^zk=1`QM>GDL@v3IrtkAjw{4SVL&=l#vV)1YX{l00-YL0|el2m}s; zqHH-@PZI^_Ect^C;4Soenyv|sW)7FJ-}46!g4!YnXLjm`d;9;}!JqhoUk85~{Hx%9 z1%DF!leb?%m?I4oLA8c(teXwg<3jR!zM}p-TVEZ5Q?(b}FKDf6C z`5>^2gRR8DK^*LZjVnUD)Yu*WGBxJy|8E8V+86wv;J*j|G5Ghu2`@+h5`Y9C0Z0H6 yfCL}`NB|Om1Rw!O0226)33x{UF0Th{-3dHccy2C3*H!`oS9oF@JAuWz0`~uE1Xij5 diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/397c85579ed7ffcec218676697c9b9083b64b4b46e327d36f94e16f8ad46f204_sk b/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/397c85579ed7ffcec218676697c9b9083b64b4b46e327d36f94e16f8ad46f204_sk deleted file mode 100644 index 295d2fdc8..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/397c85579ed7ffcec218676697c9b9083b64b4b46e327d36f94e16f8ad46f204_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg2PZimGmj5xw/Ql4A -+qv5cIt4biXy6zcZ6vHo0R4kIimhRANCAAQuDLeYJhoKkNqhAWWJao6XMB+JyiJg -9E0q0IjrCmvOTVheNu/6nyZGGGNrI+2b3X+cbdoVKeXJtlPeL5jLrWd/ ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/6d26b02a002fb3081c443b1f8e4ff06c983cc896e5552c9e0c0f766aa5476755_sk b/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/6d26b02a002fb3081c443b1f8e4ff06c983cc896e5552c9e0c0f766aa5476755_sk deleted file mode 100644 index 71d9e07b3..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/6d26b02a002fb3081c443b1f8e4ff06c983cc896e5552c9e0c0f766aa5476755_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgDoD9mbCn3exf2LUv -Qm+vXm2Wwl11i2Wjpc6HxJaWsjyhRANCAAQhbc6PI5TceRc1Qp9xFfAjER00JpV1 -pmKTFKwBe1YrjvnkOk34OUnAyYWPoKR07KHr4vQEsfSDJsfRMzbEDD95 ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/IssuerRevocationPrivateKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/IssuerRevocationPrivateKey deleted file mode 100644 index e64f0f991..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/IssuerRevocationPrivateKey +++ /dev/null @@ -1,6 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGkAgEBBDBhu3eNtA6ZI0yd4VCnuUhcbCDs6ScjhZIUPQy0D9YDYkVq5mg8FKGq -vOb4ll8vEJ2gBwYFK4EEACKhZANiAASSCWtuXouXDnINLcBEOzS2WLwekq99oHdQ -RKKbxYeqO3/LrtUdW3O8sTa40jT/7mAXKzRDDBvPrzw7WprPDMIg6DTm+2XQCdF/ -dS9mExaEGWU3BvXhpYmXkCbz1lyb4Fs= ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/IssuerSecretKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/IssuerSecretKey deleted file mode 100644 index 4995ae62c..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/msp/keystore/IssuerSecretKey +++ /dev/null @@ -1 +0,0 @@ -~ÇÃÓûýß‹ÖÐÖ¥`‘Oø`"ÅòÜó'  Ò‚ò0ñC \ No newline at end of file diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/tls-cert.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/tls-cert.pem deleted file mode 100644 index 71ba6e4bd..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrg/tls-cert.pem +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICcjCCAhmgAwIBAgIUOpnMv5vB6JvnOhXdQ4blHsBNyuIwCgYIKoZIzj0EAwIw -aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK -EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTIzMDgwNDA2MDIwMFowZDELMAkG -A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl -cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRUwEwYDVQQDEww2ZGYwMjY1NWZmZDEw -WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQuDLeYJhoKkNqhAWWJao6XMB+JyiJg -9E0q0IjrCmvOTVheNu/6nyZGGGNrI+2b3X+cbdoVKeXJtlPeL5jLrWd/o4GkMIGh -MA4GA1UdDwEB/wQEAwIDqDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw -DAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUPgcKZtxWmeKy1jUZyUX7tFm7E/swHwYD -VR0jBBgwFoAUbAdFhhGwTMQxJZAtRH8VFbhD0zUwIgYDVR0RBBswGYIMZjU4NmY3 -YmNiYTU0gglsb2NhbGhvc3QwCgYIKoZIzj0EAwIDRwAwRAIgRM8T2DATd/oa9IMn -vC314JYP3L2HPyY2puszol2b/TQCIAgrBqwQX1agPuT7XA7izuplvDRazOn2z6Ls -EcSE5SG2 ------END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/org1/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/org1/IssuerPublicKey deleted file mode 100644 index e4e39a4683359596c3c6a9ef67aed4995c58c786..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 843 zcmV-R1GM}K0#8*61X6EoWeN;MZgOvIY;9$3bV)=C5K?7!Z)0I}X>V>wVQyq>WfDXR zAl@M1Fxdnzq{Io(<|)R)v5NbIqc1O+OE^O@wj%bJxe_2;q6U4UpaplYB*Ca^$nMP3 zADrsSmc_7?J7~Fmic&QiL<%4)(~J{AnyP)TuVP!u@1V?V7!tsk;ekpw8D_RlD!&HWFm5lTfAb$t4%+_$+&~gFVOQu$}ySb zkP;x6i@O0NIbLE4byDPZ$NGl)8(KR|g(6iY7HLKxhw~pIL<%6ZeI!FN{I`ZD1&&e& zUfWdpQy^!|rBkyMbVTF8;m0KsATJIGK^hR8EBx8jd^|e2+_GFq&`%hC1$vI+$U8~t zFDi%u3Lqom7zLoYM0n0&8m~n7&1kP!uomSC*1DQM(Dt;D<>V3|B6~&9tPJt_v8|xO z{-2|=YKRRel0Teekckw+TC78H8X)8ut|-s&uYX8att8IQD>dY|CSq`sl>S4#uGdw= zB}XD4yr59HD&{+UKqw{{$dJf<@nWK@@!sAOo;e^G;G)yaGDHd>Y2oKka%~LLl3*W>W+J&=Y|DF*$zPD0(6R#;OUA@;nNf+5B&V zCuT|@^$Ac=@8(JGl?1L^s!>3&w;@T1eJ+#m?D<6UaTon!QXmZTcm6a0LHHY{l_y?$ V?ZzKCmy?8$yQ%PR-BJ6fBAiaMh&uoP diff --git a/tests/network-setups/fabric/network-artifacts/network1/org1/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/org1/IssuerRevocationPublicKey deleted file mode 100644 index 4d36cad18..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/org1/IssuerRevocationPublicKey +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEfDgje7iiTZQ/7ZljIoyOf+AiYXuvHZUG -CohejruX2TTz0uBIRQeSAh55zvv9628DMOcll0DXUrykdccjUqZBA9uSuYFRaANm -IhqLp7VFNB2gMIFcMLJ5SwexnZoJKdK7 ------END PUBLIC KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/org1/ca-cert.pem b/tests/network-setups/fabric/network-artifacts/network1/org1/ca-cert.pem deleted file mode 100644 index 3d82333d8..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/org1/ca-cert.pem +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw -aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK -EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG -A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl -cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR -ynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF -MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq -m2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd -zQkhznMIF4SBF4k= ------END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/org1/fabric-ca-server-config.yaml b/tests/network-setups/fabric/network-artifacts/network1/org1/fabric-ca-server-config.yaml deleted file mode 100644 index b7198b94a..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/org1/fabric-ca-server-config.yaml +++ /dev/null @@ -1,504 +0,0 @@ -############################################################################# -# 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.4.7 - -# Server's listening port (default: 7054) -port: 7054 - -# 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: false - # 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: - # 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: admin - pass: adminpw - 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: - - 6bbd89430166 - - localhost - 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/tests/network-setups/fabric/network-artifacts/network1/org1/fabric-ca-server.db b/tests/network-setups/fabric/network-artifacts/network1/org1/fabric-ca-server.db deleted file mode 100644 index 1a2a216f63ada40a1655d26ae648caa0992095ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61440 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 Date: Thu, 4 Aug 2022 17:14:57 +0530 Subject: [PATCH 082/150] use 10 years as expiry for certs in testnet Signed-off-by: sandeep.nishad1 --- .../fabric-ca/ordererOrg/fabric-ca-server-config.yaml | 6 +++--- .../network1/fabric-ca/org1/fabric-ca-server-config.yaml | 6 +++--- .../fabric-ca/ordererOrg/fabric-ca-server-config.yaml | 6 +++--- .../network2/fabric-ca/org1/fabric-ca-server-config.yaml | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/network-setups/fabric/shared/network1/fabric-ca/ordererOrg/fabric-ca-server-config.yaml b/tests/network-setups/fabric/shared/network1/fabric-ca/ordererOrg/fabric-ca-server-config.yaml index e433bbeba..64fe7009e 100644 --- a/tests/network-setups/fabric/shared/network1/fabric-ca/ordererOrg/fabric-ca-server-config.yaml +++ b/tests/network-setups/fabric/shared/network1/fabric-ca/ordererOrg/fabric-ca-server-config.yaml @@ -269,13 +269,13 @@ signing: default: usage: - digital signature - expiry: 8760h + expiry: 87660h profiles: ca: usage: - cert sign - crl sign - expiry: 43800h + expiry: 87660h caconstraint: isca: true maxpathlen: 0 @@ -286,7 +286,7 @@ signing: - server auth - client auth - key agreement - expiry: 8760h + expiry: 87660h ########################################################################### # Certificate Signing Request (CSR) section. diff --git a/tests/network-setups/fabric/shared/network1/fabric-ca/org1/fabric-ca-server-config.yaml b/tests/network-setups/fabric/shared/network1/fabric-ca/org1/fabric-ca-server-config.yaml index b7198b94a..b696bcce8 100644 --- a/tests/network-setups/fabric/shared/network1/fabric-ca/org1/fabric-ca-server-config.yaml +++ b/tests/network-setups/fabric/shared/network1/fabric-ca/org1/fabric-ca-server-config.yaml @@ -269,13 +269,13 @@ signing: default: usage: - digital signature - expiry: 8760h + expiry: 87660h profiles: ca: usage: - cert sign - crl sign - expiry: 43800h + expiry: 87660h caconstraint: isca: true maxpathlen: 0 @@ -286,7 +286,7 @@ signing: - server auth - client auth - key agreement - expiry: 8760h + expiry: 87660h ########################################################################### # Certificate Signing Request (CSR) section. diff --git a/tests/network-setups/fabric/shared/network2/fabric-ca/ordererOrg/fabric-ca-server-config.yaml b/tests/network-setups/fabric/shared/network2/fabric-ca/ordererOrg/fabric-ca-server-config.yaml index 825c3678b..2ddde3d30 100644 --- a/tests/network-setups/fabric/shared/network2/fabric-ca/ordererOrg/fabric-ca-server-config.yaml +++ b/tests/network-setups/fabric/shared/network2/fabric-ca/ordererOrg/fabric-ca-server-config.yaml @@ -269,13 +269,13 @@ signing: default: usage: - digital signature - expiry: 8760h + expiry: 87660h profiles: ca: usage: - cert sign - crl sign - expiry: 43800h + expiry: 87660h caconstraint: isca: true maxpathlen: 0 @@ -286,7 +286,7 @@ signing: - server auth - client auth - key agreement - expiry: 8760h + expiry: 87660h ########################################################################### # Certificate Signing Request (CSR) section. diff --git a/tests/network-setups/fabric/shared/network2/fabric-ca/org1/fabric-ca-server-config.yaml b/tests/network-setups/fabric/shared/network2/fabric-ca/org1/fabric-ca-server-config.yaml index 9f14c57a7..4612d5447 100644 --- a/tests/network-setups/fabric/shared/network2/fabric-ca/org1/fabric-ca-server-config.yaml +++ b/tests/network-setups/fabric/shared/network2/fabric-ca/org1/fabric-ca-server-config.yaml @@ -269,13 +269,13 @@ signing: default: usage: - digital signature - expiry: 8760h + expiry: 87660h profiles: ca: usage: - cert sign - crl sign - expiry: 43800h + expiry: 87660h caconstraint: isca: true maxpathlen: 0 @@ -286,7 +286,7 @@ signing: - server auth - client auth - key agreement - expiry: 8760h + expiry: 87660h ########################################################################### # Certificate Signing Request (CSR) section. From 69ada631e33087d089249ec40b9cbc640de1cfdd Mon Sep 17 00:00:00 2001 From: sannish Date: Thu, 4 Aug 2022 18:43:39 +0000 Subject: [PATCH 083/150] renew fabric certs for 10 years Signed-off-by: sannish --- .../fabric-driver/wallet-network1/admin.id | 2 +- .../fabric-driver/wallet-network1/relay.id | 2 +- .../fabric-driver/wallet-network2/admin.id | 2 +- .../fabric-driver/wallet-network2/relay.id | 2 +- .../credentials/network1/access-control.json | 4 +-- .../credentials/network1/membership.json | 2 +- .../credentials/network2/access-control.json | 4 +-- .../credentials/network2/membership.json | 2 +- .../network1/access-control.json | 4 +-- .../network1/membership.json | 2 +- .../network2/access-control.json | 4 +-- .../network2/membership.json | 2 +- .../data/credentials/network1/membership.json | 2 +- .../credentials/network2/access-control.json | 2 +- .../data/credentials/network2/membership.json | 2 +- .../network1/membership.json | 2 +- .../network2/access-control.json | 2 +- .../network2/membership.json | 2 +- .../src/wallet-Dummy_Network/admin.id | 1 + .../src/wallet-Dummy_Network/alice.id | 1 + .../src/wallet-Dummy_Network/bob.id | 1 + .../src/wallet-Dummy_Network/user1.id | 1 + .../fabric-cli/src/wallet-network1/user1.id | 2 +- .../fabric-cli/src/wallet-network2/user1.id | 2 +- .../channel-artifacts/Org1MSPanchors.tx | Bin 313 -> 313 bytes .../channel-artifacts/mychannel.block | Bin 17129 -> 17139 bytes .../network1/channel-artifacts/mychannel.tx | Bin 421 -> 421 bytes .../fabric-ca/ordererOrg/IssuerPublicKey | Bin 843 -> 843 bytes .../ordererOrg/IssuerRevocationPublicKey | 6 ++-- .../network1/fabric-ca/ordererOrg/ca-cert.pem | 14 ++++----- .../fabric-ca/ordererOrg/fabric-ca-server.db | Bin 61440 -> 61440 bytes ...7c9b9083b64b4b46e327d36f94e16f8ad46f204_sk | 5 ---- ...6f69ac46a1a5cfea98922d30ad7fb901eab1869_sk | 5 ++++ ...3a075518b1646a76c1675abf0acafcc06e158c1_sk | 5 ++++ ...e4ff06c983cc896e5552c9e0c0f766aa5476755_sk | 5 ---- .../msp/keystore/IssuerRevocationPrivateKey | 8 ++--- .../ordererOrg/msp/keystore/IssuerSecretKey | 2 +- .../fabric-ca/ordererOrg/tls-cert.pem | 20 ++++++------- .../network1/fabric-ca/org1/IssuerPublicKey | Bin 843 -> 843 bytes .../fabric-ca/org1/IssuerRevocationPublicKey | 6 ++-- .../network1/fabric-ca/org1/ca-cert.pem | 14 ++++----- .../fabric-ca/org1/fabric-ca-server.db | Bin 65536 -> 65536 bytes ...2e879866997c87c1cca786a9263be68d6f021d6_sk | 5 ++++ ...4c4c1ebb56d3fa0b0ac8a34e2943beeff243edd_sk | 5 ---- ...1dbfd38547df4a3b43a764321ed14beb191f382_sk | 5 ++++ .../msp/keystore/IssuerRevocationPrivateKey | 8 ++--- .../org1/msp/keystore/IssuerSecretKey | Bin 32 -> 32 bytes ...76abf24fa24ec232b8f7844cf8f19730b3504ac_sk | 5 ---- .../network1/fabric-ca/org1/tls-cert.pem | 20 ++++++------- .../network1.com/msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 ++-- ...localhost-9054-ca-orderer-network1-com.pem | 14 ++++----- ...ca4b8ac3d20a66f2f899f3bd8eef1a06dfca4d9_sk | 5 ---- ...46793178da020db97c77840c7f7cf91fa0fdcef_sk | 5 ++++ .../network1.com/msp/signcerts/cert.pem | 16 +++++----- .../tlscacerts/tlsca.network1.com-cert.pem | 14 ++++----- .../orderer.network1.com/msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 ++-- ...localhost-9054-ca-orderer-network1-com.pem | 14 ++++----- ...32db70a58e01fec07cb84204b6a69176b73ed5e_sk | 5 ++++ ...1a8f7755eccfbd8d2f9e0597320fe1eaa47c16e_sk | 5 ---- .../msp/signcerts/cert.pem | 16 +++++----- .../tlscacerts/tlsca.network1.com-cert.pem | 14 ++++----- .../orderer.network1.com/tls/IssuerPublicKey | Bin 843 -> 843 bytes .../tls/IssuerRevocationPublicKey | 6 ++-- .../orderers/orderer.network1.com/tls/ca.crt | 14 ++++----- ...9026d8e11a5a776e83cd39609407f402517a38c_sk | 5 ++++ ...809cd1c2ec4b9dbb9d0083146c8a6afd50f7223_sk | 5 ---- .../orderer.network1.com/tls/server.crt | 18 +++++------ .../orderer.network1.com/tls/server.key | 6 ++-- .../tls/signcerts/cert.pem | 18 +++++------ ...localhost-9054-ca-orderer-network1-com.pem | 14 ++++----- .../Admin@network1.com/msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 ++-- ...localhost-9054-ca-orderer-network1-com.pem | 14 ++++----- ...6360b0c2a170273c894946f30d3662ad3429fe3_sk | 5 ++++ ...fab34bc73a5921da7a80691393b105e7fcb3226_sk | 5 ---- .../Admin@network1.com/msp/signcerts/cert.pem | 18 +++++------ .../ca/ca.org1.network1.com-cert.pem | 14 ++++----- .../connection-org1.docker.json | 4 +-- .../org1.network1.com/connection-org1.json | 4 +-- .../org1.network1.com/connection-org1.yaml | 28 +++++++++--------- .../org1.network1.com/msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 ++-- .../localhost-7054-ca-org1-network1-com.pem | 14 ++++----- ...fd0ec68bb71d49cde36019cc47bc66e0ab07334_sk | 5 ---- ...59984e1ef4340b087ceee17078dc76daecba926_sk | 5 ++++ .../org1.network1.com/msp/signcerts/cert.pem | 16 +++++----- .../org1.network1.com/msp/tlscacerts/ca.crt | 14 ++++----- .../msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 ++-- .../localhost-7054-ca-org1-network1-com.pem | 14 ++++----- ...6e96ebc18782d275d3eae560dccb2667848adfe_sk | 5 ---- ...634d639ab4af83d576149caaaf04d84c41c3032_sk | 5 ++++ .../msp/signcerts/cert.pem | 18 +++++------ .../tls/IssuerPublicKey | Bin 843 -> 843 bytes .../tls/IssuerRevocationPublicKey | 6 ++-- .../peers/peer0.org1.network1.com/tls/ca.crt | 14 ++++----- ...536fe4325325082313dce4d076625c185f0140e_sk | 5 ---- ...c632f1aff7534f91cdc5f0e1cd6ad2cc65512aa_sk | 5 ++++ .../peer0.org1.network1.com/tls/server.crt | 18 +++++------ .../peer0.org1.network1.com/tls/server.key | 6 ++-- .../tls/signcerts/cert.pem | 18 +++++------ ...ls-localhost-7054-ca-org1-network1-com.pem | 14 ++++----- .../tlsca/tlsca.org1.network1.com-cert.pem | 14 ++++----- .../msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 ++-- .../localhost-7054-ca-org1-network1-com.pem | 14 ++++----- ...e4da28fa3e3cd86b6d3a34c91c9bc163c57492e_sk | 5 ---- ...c99c104873c5b33613fbad99e0e167e0a4b3f27_sk | 5 ++++ .../msp/signcerts/cert.pem | 18 +++++------ .../msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 ++-- .../localhost-7054-ca-org1-network1-com.pem | 14 ++++----- ...e079f9eddae2842adfeca1da831ac4de259156a_sk | 5 ++++ ...fc89055cdf55db0fb2057032401956f9873d30a_sk | 5 ---- .../msp/signcerts/cert.pem | 16 +++++----- .../system-genesis-block/genesis.block | Bin 13399 -> 13407 bytes .../channel-artifacts/Org1MSPanchors.tx | Bin 313 -> 313 bytes .../channel-artifacts/mychannel.block | Bin 17142 -> 17143 bytes .../network2/channel-artifacts/mychannel.tx | Bin 421 -> 421 bytes .../fabric-ca/ordererOrg/IssuerPublicKey | Bin 843 -> 843 bytes .../ordererOrg/IssuerRevocationPublicKey | 6 ++-- .../network2/fabric-ca/ordererOrg/ca-cert.pem | 14 ++++----- .../fabric-ca/ordererOrg/fabric-ca-server.db | Bin 61440 -> 61440 bytes ...0950584b74dce5a32ffd6ab7b438b0d86ed3f5e_sk | 5 ---- ...3d23c2aad6410f31007d63835fadb159cbcb3d9_sk | 5 ---- .../msp/keystore/IssuerRevocationPrivateKey | 8 ++--- .../ordererOrg/msp/keystore/IssuerSecretKey | 2 +- ...7e0ec1fce62dc8991c442652758229b6e3dedce_sk | 5 ++++ ...6ef683613c0c10b38390fe6bbd055ae4bad202c_sk | 5 ++++ .../fabric-ca/ordererOrg/tls-cert.pem | 20 ++++++------- .../network2/fabric-ca/org1/IssuerPublicKey | Bin 843 -> 843 bytes .../fabric-ca/org1/IssuerRevocationPublicKey | 6 ++-- .../network2/fabric-ca/org1/ca-cert.pem | 14 ++++----- .../fabric-ca/org1/fabric-ca-server.db | Bin 65536 -> 65536 bytes ...7f518f7f2d789dc81156f6b38c9a432b5b6083d_sk | 5 ---- ...8ec7de7a6c9070ae57f5cf423bfc2472f0d13b0_sk | 5 ---- ...75b33ac433247effae20bb8268ed30b5522673e_sk | 5 ++++ .../msp/keystore/IssuerRevocationPrivateKey | 8 ++--- .../org1/msp/keystore/IssuerSecretKey | 2 +- ...60ca7c1974b16bdc51356c7808614c73b4f0c40_sk | 5 ++++ .../network2/fabric-ca/org1/tls-cert.pem | 20 ++++++------- .../network2.com/msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 ++-- ...localhost-8054-ca-orderer-network2-com.pem | 14 ++++----- ...8cd80113ee3eae2d5acad8561f60bc6d27464be_sk | 5 ++++ ...5bb100e2b26f93b0fabcc0f04a0a7f48b071c87_sk | 5 ---- .../network2.com/msp/signcerts/cert.pem | 16 +++++----- .../tlscacerts/tlsca.network2.com-cert.pem | 14 ++++----- .../orderer.network2.com/msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 ++-- ...localhost-8054-ca-orderer-network2-com.pem | 14 ++++----- ...e47a76862fdad6f576f4ecce02468af34289e78_sk | 5 ---- ...3c6ffb193ba73157b71f3b8718164c95fc54b25_sk | 5 ++++ .../msp/signcerts/cert.pem | 16 +++++----- .../tlscacerts/tlsca.network2.com-cert.pem | 14 ++++----- .../orderer.network2.com/tls/IssuerPublicKey | Bin 843 -> 843 bytes .../tls/IssuerRevocationPublicKey | 6 ++-- .../orderers/orderer.network2.com/tls/ca.crt | 14 ++++----- ...001920f12327aa7346e101aa6172650f310501f_sk | 5 ++++ ...aed451ba70639e08a135901d916089703b38eda_sk | 5 ---- .../orderer.network2.com/tls/server.crt | 18 +++++------ .../orderer.network2.com/tls/server.key | 6 ++-- .../tls/signcerts/cert.pem | 18 +++++------ ...localhost-8054-ca-orderer-network2-com.pem | 14 ++++----- .../Admin@network2.com/msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 ++-- ...localhost-8054-ca-orderer-network2-com.pem | 14 ++++----- ...2d6ab14dce0cfadde971c6f46df0efe03998925_sk | 5 ++++ ...a559d0ac39b35270df2fce0d798db6b1b11b2b0_sk | 5 ---- .../Admin@network2.com/msp/signcerts/cert.pem | 18 +++++------ .../ca/ca.org1.network2.com-cert.pem | 14 ++++----- .../connection-org1.docker.json | 4 +-- .../org1.network2.com/connection-org1.json | 4 +-- .../org1.network2.com/connection-org1.yaml | 28 +++++++++--------- .../org1.network2.com/msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 ++-- .../localhost-5054-ca-org1-network2-com.pem | 14 ++++----- ...f8cc9948e6c3490ebb6146c88063a36415a9064_sk | 5 ++++ ...be9c9f4e32539e9b85a692086de0fb364dbea54_sk | 5 ---- .../org1.network2.com/msp/signcerts/cert.pem | 16 +++++----- .../org1.network2.com/msp/tlscacerts/ca.crt | 14 ++++----- .../msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 ++-- .../localhost-5054-ca-org1-network2-com.pem | 14 ++++----- ...77543cad709ec379f6e3070e992e67b4ed03a29_sk | 5 ---- ...998e65374d1f2baf88d02e7af88befe74798c8a_sk | 5 ++++ .../msp/signcerts/cert.pem | 18 +++++------ .../tls/IssuerPublicKey | Bin 843 -> 843 bytes .../tls/IssuerRevocationPublicKey | 6 ++-- .../peers/peer0.org1.network2.com/tls/ca.crt | 14 ++++----- ...b57cb25e58b2c22500c2dcf0358acfc81c0e8c4_sk | 5 ++++ ...06ad859de7854abfd5d485a9da4ebf322b9a566_sk | 5 ---- .../peer0.org1.network2.com/tls/server.crt | 18 +++++------ .../peer0.org1.network2.com/tls/server.key | 6 ++-- .../tls/signcerts/cert.pem | 18 +++++------ ...ls-localhost-5054-ca-org1-network2-com.pem | 14 ++++----- .../tlsca/tlsca.org1.network2.com-cert.pem | 14 ++++----- .../msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 ++-- .../localhost-5054-ca-org1-network2-com.pem | 14 ++++----- ...001a6923fa134462a5f5cb3507eb3b2bc330d10_sk | 5 ++++ ...a0473efb852a4a17e2fd2cb419efe78852a887f_sk | 5 ---- .../msp/signcerts/cert.pem | 18 +++++------ .../msp/IssuerPublicKey | Bin 843 -> 843 bytes .../msp/IssuerRevocationPublicKey | 6 ++-- .../localhost-5054-ca-org1-network2-com.pem | 14 ++++----- ...ef6b993686b4bdbbe689a6368003a303752511a_sk | 5 ++++ ...ca6f9ed2559e7812c0d756e1f2f43942d8e786b_sk | 5 ---- .../msp/signcerts/cert.pem | 16 +++++----- .../system-genesis-block/genesis.block | Bin 13407 -> 13407 bytes 212 files changed, 773 insertions(+), 769 deletions(-) create mode 100644 samples/fabric/fabric-cli/src/wallet-Dummy_Network/admin.id create mode 100644 samples/fabric/fabric-cli/src/wallet-Dummy_Network/alice.id create mode 100644 samples/fabric/fabric-cli/src/wallet-Dummy_Network/bob.id create mode 100644 samples/fabric/fabric-cli/src/wallet-Dummy_Network/user1.id delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/397c85579ed7ffcec218676697c9b9083b64b4b46e327d36f94e16f8ad46f204_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/3ac44c3fc37d9844f62a7025a6f69ac46a1a5cfea98922d30ad7fb901eab1869_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/44602e251c95b69ca3833d9ec3a075518b1646a76c1675abf0acafcc06e158c1_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/msp/keystore/6d26b02a002fb3081c443b1f8e4ff06c983cc896e5552c9e0c0f766aa5476755_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/6f6237ceb26ff0976337f15602e879866997c87c1cca786a9263be68d6f021d6_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/82bb24244d4f7bcbffb96a71c4c4c1ebb56d3fa0b0ac8a34e2943beeff243edd_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/91f44bfbbf9a6b8ae2055fa311dbfd38547df4a3b43a764321ed14beb191f382_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/e509e7d66bdbd1e7e777acd4c76abf24fa24ec232b8f7844cf8f19730b3504ac_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/keystore/2b1bb41ced0015f0c3b2ee752ca4b8ac3d20a66f2f899f3bd8eef1a06dfca4d9_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/keystore/58dca995909dfa76173499b1046793178da020db97c77840c7f7cf91fa0fdcef_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/keystore/b693c9143aa4020e1865f5e6232db70a58e01fec07cb84204b6a69176b73ed5e_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/keystore/f949ca1e0e7d7e6d996176d4b1a8f7755eccfbd8d2f9e0597320fe1eaa47c16e_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/keystore/426c3a6d0556e0020c276da919026d8e11a5a776e83cd39609407f402517a38c_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/keystore/75f5e9c82d2e8d17470e65e5a809cd1c2ec4b9dbb9d0083146c8a6afd50f7223_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/keystore/0f8b9ac723af2ec1426c2407e6360b0c2a170273c894946f30d3662ad3429fe3_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/keystore/3e3a32bdfc3ef9a6639c212e3fab34bc73a5921da7a80691393b105e7fcb3226_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/keystore/2d9968bdb307fb3b5f163356cfd0ec68bb71d49cde36019cc47bc66e0ab07334_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/keystore/c1c4b353508ec6783a48de0b559984e1ef4340b087ceee17078dc76daecba926_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/keystore/5bee0474d81dd757d01966e5b6e96ebc18782d275d3eae560dccb2667848adfe_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/keystore/eeafea5d436bd8876f9f74206634d639ab4af83d576149caaaf04d84c41c3032_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/keystore/2c73ce9f512e2c8d611a66199536fe4325325082313dce4d076625c185f0140e_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/tls/keystore/64e6843f927cfde4f395cdc29c632f1aff7534f91cdc5f0e1cd6ad2cc65512aa_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/keystore/b5ff454e5ceb3f2ce336a9080e4da28fa3e3cd86b6d3a34c91c9bc163c57492e_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/Admin@org1.network1.com/msp/keystore/f61df36f24b9dcdb70044843dc99c104873c5b33613fbad99e0e167e0a4b3f27_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/keystore/61348d574115ae16f64e30953e079f9eddae2842adfeca1da831ac4de259156a_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/users/User1@org1.network1.com/msp/keystore/d397d85065544e3fb772bf88afc89055cdf55db0fb2057032401956f9873d30a_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/117fbb29176584efb8df9c8370950584b74dce5a32ffd6ab7b438b0d86ed3f5e_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/3db8e1f785d24ba97583a0d2a3d23c2aad6410f31007d63835fadb159cbcb3d9_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/c8e7c3ec740c26225a50644bd7e0ec1fce62dc8991c442652758229b6e3dedce_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/f55d5b0330bca287938b240a76ef683613c0c10b38390fe6bbd055ae4bad202c_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/2ab00f3ef573479ef8514bd647f518f7f2d789dc81156f6b38c9a432b5b6083d_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/2ab49b69a5e965d0baf9acc108ec7de7a6c9070ae57f5cf423bfc2472f0d13b0_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/74f4f59913d646a10a22dba3975b33ac433247effae20bb8268ed30b5522673e_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/msp/keystore/a6b930f2b348edf7e5c710f8a60ca7c1974b16bdc51356c7808614c73b4f0c40_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/keystore/012e804cf869407db87e4d7868cd80113ee3eae2d5acad8561f60bc6d27464be_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/msp/keystore/64aa0b911f0d7d9a5bd9d0d275bb100e2b26f93b0fabcc0f04a0a7f48b071c87_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/keystore/0d73dff17d0b0d8641206ae38e47a76862fdad6f576f4ecce02468af34289e78_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/msp/keystore/4c21369668c86e0bf3b63d3243c6ffb193ba73157b71f3b8718164c95fc54b25_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/keystore/3fe44a7452d166ae9043780b6001920f12327aa7346e101aa6172650f310501f_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/orderers/orderer.network2.com/tls/keystore/9fa526f760e0e861f3118d68faed451ba70639e08a135901d916089703b38eda_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/keystore/a9ed543c015ace8f956ce32962d6ab14dce0cfadde971c6f46df0efe03998925_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/ordererOrganizations/network2.com/users/Admin@network2.com/msp/keystore/d602b7fae48619fb0dd47e941a559d0ac39b35270df2fce0d798db6b1b11b2b0_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/msp/keystore/1826f80031dea43ee2308ddc5f8cc9948e6c3490ebb6146c88063a36415a9064_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/msp/keystore/50239d57381580b71992a618abe9c9f4e32539e9b85a692086de0fb364dbea54_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/keystore/0a43a8644bf07831479fe95ed77543cad709ec379f6e3070e992e67b4ed03a29_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/msp/keystore/f1d0e29c4e887ab38554c60a4998e65374d1f2baf88d02e7af88befe74798c8a_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/keystore/1eff54fc76366bfda301db060b57cb25e58b2c22500c2dcf0358acfc81c0e8c4_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/peers/peer0.org1.network2.com/tls/keystore/b6733ab74dc103dc93f71621606ad859de7854abfd5d485a9da4ebf322b9a566_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/keystore/80861e9c031f090c4bc6f9375001a6923fa134462a5f5cb3507eb3b2bc330d10_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/Admin@org1.network2.com/msp/keystore/99e69faef39205dde6522521da0473efb852a4a17e2fd2cb419efe78852a887f_sk create mode 100644 tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/keystore/0f87dbe410da9703883f1fd2bef6b993686b4bdbbe689a6368003a303752511a_sk delete mode 100644 tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/users/User1@org1.network2.com/msp/keystore/9691d2d62a2d71ff121ee3a07ca6f9ed2559e7812c0d756e1f2f43942d8e786b_sk diff --git a/core/drivers/fabric-driver/wallet-network1/admin.id b/core/drivers/fabric-driver/wallet-network1/admin.id index 6d9f764cb..e5b4ba884 100644 --- a/core/drivers/fabric-driver/wallet-network1/admin.id +++ b/core/drivers/fabric-driver/wallet-network1/admin.id @@ -1 +1 @@ -{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIIB6jCCAZGgAwIBAgIUeRXp2NTeDriWFAW2Qylu/SBvq/MwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NDYwMFoXDTIzMDgwNDA2NTEwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwVhZG1pbjBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABBuGP+kB2T3nuPz4n+A5Rmi/mAObXwaTFtn+6KZCmj5ih1Z5w9dWgO14\nFf1SQZBE/FeWHb34/ktya1NxnD0cFwOjYDBeMA4GA1UdDwEB/wQEAwIHgDAMBgNV\nHRMBAf8EAjAAMB0GA1UdDgQWBBS6ZDoiZpG2AkRVHHxTUAnb83+UGDAfBgNVHSME\nGDAWgBQqEdSZb30F3rAKZ4lFrXItXF4jjDAKBggqhkjOPQQDAgNHADBEAiBxLKGe\naHAclQI5z0GFw0KAhzqte7pEpN22bWM0gteXHAIgY1qkaNrkx/mUTzVKY8TeS17g\nxxyVYIO4BCaIoEdyOJM=\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgb551as8oT5MWF83M\r\nzdPrpubdS20Rg7k9db6I33wdYzKhRANCAAQbhj/pAdk957j8+J/gOUZov5gDm18G\r\nkxbZ/uimQpo+YodWecPXVoDteBX9UkGQRPxXlh29+P5LcmtTcZw9HBcD\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file +{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIIB6jCCAZGgAwIBAgIUGR1th6phPuxVYid5izC/cAd/YHYwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjcwMFoXDTMyMDgwNDA2MzIwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwVhZG1pbjBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABNLu/ESWWs8vOXBseLjpk52L7eS8fRJ1xHbY8pHRyKfaMFxkVo9nKSOe\nIxfkzZ+ga49ltyo5CEVrpo+9/VvMdeyjYDBeMA4GA1UdDwEB/wQEAwIHgDAMBgNV\nHRMBAf8EAjAAMB0GA1UdDgQWBBRf+RvqFtLHN/dP7tPVtTSA3TQDijAfBgNVHSME\nGDAWgBTOxwzHoYh5fG/dkEjDeENRQeyVPzAKBggqhkjOPQQDAgNHADBEAiAnbRjJ\nfonA7DLk7JDfN4EtAwObH4ed3LXb9+mj1pUrggIgTvXNJFo4+5K6v4J4sgb98Ns1\nyXff+jf0DYoXfg3dwyg=\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgvVKn/bCUoTc998sj\r\n9SQqy+EkkM8jSr/JUkF1/IHkeIehRANCAATS7vxEllrPLzlwbHi46ZOdi+3kvH0S\r\ndcR22PKR0cin2jBcZFaPZykjniMX5M2foGuPZbcqOQhFa6aPvf1bzHXs\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file diff --git a/core/drivers/fabric-driver/wallet-network1/relay.id b/core/drivers/fabric-driver/wallet-network1/relay.id index 0961605af..d4ec38260 100644 --- a/core/drivers/fabric-driver/wallet-network1/relay.id +++ b/core/drivers/fabric-driver/wallet-network1/relay.id @@ -1 +1 @@ -{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIIChzCCAi2gAwIBAgIUatGEIkHJrXkasjI9aTBotPvrma0wCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NDYwMFoXDTIzMDgwNDA2NTEwMFowQjEwMA0G\nA1UECxMGY2xpZW50MAsGA1UECxMEb3JnMTASBgNVBAsTC2RlcGFydG1lbnQxMQ4w\nDAYDVQQDEwVyZWxheTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJ3Du7v+kssR\nzMU2Odc/vKStlt9HIcbyPqkeID6xxEXvFfZAEDTupbTahwEa2LvBDF7iCvXv09QC\nHbO1SzBd9+mjgdowgdcwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYD\nVR0OBBYEFBYqy2oOduP3fuO3lYMnI230Bg2OMB8GA1UdIwQYMBaAFCoR1JlvfQXe\nsApniUWtci1cXiOMMHcGCCoDBAUGBwgBBGt7ImF0dHJzIjp7ImhmLkFmZmlsaWF0\naW9uIjoib3JnMS5kZXBhcnRtZW50MSIsImhmLkVucm9sbG1lbnRJRCI6InJlbGF5\nIiwiaGYuVHlwZSI6ImNsaWVudCIsInJlbGF5IjoidHJ1ZSJ9fTAKBggqhkjOPQQD\nAgNIADBFAiEA+VDjQJLHxaFWFcY7Os6B+csLeUh7UyY/lIsOIBRGGqsCIDjTHPCf\n/2L7uKO02Yb/ROCOCKF/aLf06AoVHLMqURAh\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg/d6t/S1/x2Y1xAS5\r\nqQMpXIYTvVr7MMJIyFQkuRKJap6hRANCAASdw7u7/pLLEczFNjnXP7ykrZbfRyHG\r\n8j6pHiA+scRF7xX2QBA07qW02ocBGti7wQxe4gr179PUAh2ztUswXffp\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file +{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIIChzCCAi2gAwIBAgIUEb3YJ1WxG38rYB98nInUjKwjqH0wCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjcwMFoXDTMyMDgwNDA2MzIwMFowQjEwMA0G\nA1UECxMGY2xpZW50MAsGA1UECxMEb3JnMTASBgNVBAsTC2RlcGFydG1lbnQxMQ4w\nDAYDVQQDEwVyZWxheTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAqMFWah1Esy\n3NOd6Z5voukbtKiE7tCmzParS6ttNG3mzCf73cZpReSbKldXdttZWe+/k5ZJiPwU\n6+bOrn7I7LujgdowgdcwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYD\nVR0OBBYEFH8m6m2tQSaHFsGliBbhfe01ACehMB8GA1UdIwQYMBaAFM7HDMehiHl8\nb92QSMN4Q1FB7JU/MHcGCCoDBAUGBwgBBGt7ImF0dHJzIjp7ImhmLkFmZmlsaWF0\naW9uIjoib3JnMS5kZXBhcnRtZW50MSIsImhmLkVucm9sbG1lbnRJRCI6InJlbGF5\nIiwiaGYuVHlwZSI6ImNsaWVudCIsInJlbGF5IjoidHJ1ZSJ9fTAKBggqhkjOPQQD\nAgNIADBFAiEA+2U+oxFetp7yRz79u+nVQtltcDqpNDk0RwpI5UhxEvoCICRpw9pV\nI9H3lkEJCsIO7R3qEBCbK2+cAlSn3/6tJSlU\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgdFQhvrT/5VxwN3gt\r\nokqSCkVARLc4PBJRRsFD8xKZbtyhRANCAAQKjBVmodRLMtzTnemeb6LpG7SohO7Q\r\npsz2q0urbTRt5swn+93GaUXkmypXV3bbWVnvv5OWSYj8FOvmzq5+yOy7\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file diff --git a/core/drivers/fabric-driver/wallet-network2/admin.id b/core/drivers/fabric-driver/wallet-network2/admin.id index 41578fcdb..ecac419f8 100644 --- a/core/drivers/fabric-driver/wallet-network2/admin.id +++ b/core/drivers/fabric-driver/wallet-network2/admin.id @@ -1 +1 @@ -{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIIB6jCCAZGgAwIBAgIULg8U7R0NWK/th8hCEUxY1JZIZc0wCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NDcwMFoXDTIzMDgwNDA2NTIwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwVhZG1pbjBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABBHbYAOMQndXD1C+yPyaprYtjw5rdu+PMI1UVXD+ctQmMU/PiOu3uhzu\nb+iCn8haZWV40igvRIZGHPY73INbVTKjYDBeMA4GA1UdDwEB/wQEAwIHgDAMBgNV\nHRMBAf8EAjAAMB0GA1UdDgQWBBTRZ/2DmXyEAoOgVjE6FWMxut14NjAfBgNVHSME\nGDAWgBT8HtS6zbiN91ZvhHYDvxP4yYoVNTAKBggqhkjOPQQDAgNHADBEAiAxc7Qs\nUE1xp87yN1U54BDOiA2sWqrqMVGdFgoN67ZpLwIgFYBrLZhN59bn7wH2DdKpln1N\nmJX5B5poUz5o/1JUWRs=\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgxr2t90O+Bnn7GxYV\r\nL7cFuAxLBnd6h/OWOzPlj5JC+QChRANCAAQR22ADjEJ3Vw9Qvsj8mqa2LY8Oa3bv\r\njzCNVFVw/nLUJjFPz4jrt7oc7m/ogp/IWmVleNIoL0SGRhz2O9yDW1Uy\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file +{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIIB6zCCAZGgAwIBAgIUIUnz6BX3PnvH2NSkRwhdDk9A09gwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjcwMFoXDTMyMDgwNDA2MzIwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwVhZG1pbjBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABDhughEJgo7liburjUMmJCcgCzzy46Fp+NSEAWnt0kiz7+IqGBDaWAtv\n9vkxSBGVvSwmW4svbZ5374+DeglJRE+jYDBeMA4GA1UdDwEB/wQEAwIHgDAMBgNV\nHRMBAf8EAjAAMB0GA1UdDgQWBBQIZQ7gFqXffKBpceoM9MDa4aozFzAfBgNVHSME\nGDAWgBThONcBHwYB3/nH40M2shP0PKZtmzAKBggqhkjOPQQDAgNIADBFAiEAn3vD\nS2slTCrwbbXoIxHKScy3+X+wfTwEIRsWJ8pvK0kCIEoxPaep7QSb9ATTbZT1ZenN\nIXImeItGxE3tdw2eq0j2\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgA1dbdty5wlVhvaHz\r\nk3tMqxiaobJ4WtTVHlAQCfCMSGKhRANCAAQ4boIRCYKO5Ym7q41DJiQnIAs88uOh\r\nafjUhAFp7dJIs+/iKhgQ2lgLb/b5MUgRlb0sJluLL22ed++Pg3oJSURP\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file diff --git a/core/drivers/fabric-driver/wallet-network2/relay.id b/core/drivers/fabric-driver/wallet-network2/relay.id index a46730cb4..b14a5fbfb 100644 --- a/core/drivers/fabric-driver/wallet-network2/relay.id +++ b/core/drivers/fabric-driver/wallet-network2/relay.id @@ -1 +1 @@ -{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIIChjCCAi2gAwIBAgIUYrS6rylTI2wTWRNgTJIdbve47GswCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NDcwMFoXDTIzMDgwNDA2NTIwMFowQjEwMA0G\nA1UECxMGY2xpZW50MAsGA1UECxMEb3JnMTASBgNVBAsTC2RlcGFydG1lbnQxMQ4w\nDAYDVQQDEwVyZWxheTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLUOEH7UaUgO\nbX7XZowasZfKSEVJ3DrUbBRnfVAcRKPOhaMVTpqm8itrlvI7OLrGuy+fjEdDwI96\nQ8o5mxmfdwGjgdowgdcwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYD\nVR0OBBYEFC3nU1Y4kYAI4LjYB0KykOZohQ3qMB8GA1UdIwQYMBaAFPwe1LrNuI33\nVm+EdgO/E/jJihU1MHcGCCoDBAUGBwgBBGt7ImF0dHJzIjp7ImhmLkFmZmlsaWF0\naW9uIjoib3JnMS5kZXBhcnRtZW50MSIsImhmLkVucm9sbG1lbnRJRCI6InJlbGF5\nIiwiaGYuVHlwZSI6ImNsaWVudCIsInJlbGF5IjoidHJ1ZSJ9fTAKBggqhkjOPQQD\nAgNHADBEAiAiSTLTgj0fSLmNCCJTr8hoZHSLSPiFZgT3oeymy9ocdAIgSF8R15R8\nUPxQQkbNI/LFmEEsPrJjRimgKwzWRcXPzYc=\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgei8TtJsEZjUhuPge\r\nmOEGuE7wR8f01Swvty0OSPpMWCahRANCAAS1DhB+1GlIDm1+12aMGrGXykhFSdw6\r\n1GwUZ31QHESjzoWjFU6apvIra5byOzi6xrsvn4xHQ8CPekPKOZsZn3cB\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file +{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIIChzCCAi2gAwIBAgIUcFecSeiNvsORvf1CCzeOArYngFEwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjcwMFoXDTMyMDgwNDA2MzIwMFowQjEwMA0G\nA1UECxMGY2xpZW50MAsGA1UECxMEb3JnMTASBgNVBAsTC2RlcGFydG1lbnQxMQ4w\nDAYDVQQDEwVyZWxheTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABDAs7e4rYWM8\n5mhGGbWGVK8VruU5iJsHLN5Y0i05oFnXHdqJip5xh5j+pER73/5BXiuh1A8IbZ8x\nJJkQlyuDq4GjgdowgdcwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYD\nVR0OBBYEFMedxIDZUSmoP6BmnYzZK8GvgdrbMB8GA1UdIwQYMBaAFOE41wEfBgHf\n+cfjQzayE/Q8pm2bMHcGCCoDBAUGBwgBBGt7ImF0dHJzIjp7ImhmLkFmZmlsaWF0\naW9uIjoib3JnMS5kZXBhcnRtZW50MSIsImhmLkVucm9sbG1lbnRJRCI6InJlbGF5\nIiwiaGYuVHlwZSI6ImNsaWVudCIsInJlbGF5IjoidHJ1ZSJ9fTAKBggqhkjOPQQD\nAgNIADBFAiEAydPSud2FJEj1SMkhGWytrj+54KQbTakZnnTvDRq3TfQCIFG52z1R\n0xDEj7GtDbtuYduaeb2NwEM3bv2dBI12nsAq\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgT2sdHg76GIlJg7tl\r\nH7eaUDHcPjxJI9yUF9+hucRo6dahRANCAAQwLO3uK2FjPOZoRhm1hlSvFa7lOYib\r\nByzeWNItOaBZ1x3aiYqecYeY/qREe9/+QV4rodQPCG2fMSSZEJcrg6uB\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file diff --git a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network1/access-control.json b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network1/access-control.json index d2cbd4215..d28f0d6d2 100644 --- a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network1/access-control.json +++ b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network1/access-control.json @@ -2,13 +2,13 @@ "securityDomain": "network1", "rules": [ { - "principal": "-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUNtt5srTRKRumyRD/O2FFoOImcjkwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABJ+cH+YyJCTeAyOXaIdNMFUYwKqUjClxSlEcHObedbmofV+WluvdkCsf\nWyv72JliZEm0HngxkkumIOxir0VBW4KjgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFN6zn3QTE1IuXKG2rnGCUuhkP2rIMB8GA1Ud\nIwQYMBaAFCoR1JlvfQXesApniUWtci1cXiOMMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQCpVjfnmEM7\nFHK9UX2j1+a25IFD5/p62CljJRQgnLUWXwIgBOKluTSOICeQ3FWx8+5+ZWrYL2wn\nPL3qORlNthH+Vrc=\n-----END CERTIFICATE-----\n", + "principal": "-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUf+IGiJyyyaGWwjRnjpnO0D7uzngwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjgwMFoXDTMyMDgwNDA2MzMwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABNoLyPx0DGMc4ilZlCtQw+vu2r1ZeHJukaaEk6U57gMXlpi6mU80E0xi\n7bIjQQDVdhH//zyFREjp/R5QyCRW66mjgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFAwA6h6ex1yPFlxuw5MP5UFdy0SkMB8GA1Ud\nIwQYMBaAFM7HDMehiHl8b92QSMN4Q1FB7JU/MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQDhDvnTZ0/+\n623lX153M/EESY5wCeSIu8V6BUfAn/VC6gIgJLkdVHwWNfqtI7+9pHD4uTE86QoP\nTyegatE7P10qwNc=\n-----END CERTIFICATE-----\n", "principalType": "ca", "resource": "localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:*", "read": true }, { - "principal": "-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUNtt5srTRKRumyRD/O2FFoOImcjkwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABJ+cH+YyJCTeAyOXaIdNMFUYwKqUjClxSlEcHObedbmofV+WluvdkCsf\nWyv72JliZEm0HngxkkumIOxir0VBW4KjgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFN6zn3QTE1IuXKG2rnGCUuhkP2rIMB8GA1Ud\nIwQYMBaAFCoR1JlvfQXesApniUWtci1cXiOMMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQCpVjfnmEM7\nFHK9UX2j1+a25IFD5/p62CljJRQgnLUWXwIgBOKluTSOICeQ3FWx8+5+ZWrYL2wn\nPL3qORlNthH+Vrc=\n-----END CERTIFICATE-----\n", + "principal": "-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUf+IGiJyyyaGWwjRnjpnO0D7uzngwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjgwMFoXDTMyMDgwNDA2MzMwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABNoLyPx0DGMc4ilZlCtQw+vu2r1ZeHJukaaEk6U57gMXlpi6mU80E0xi\n7bIjQQDVdhH//zyFREjp/R5QyCRW66mjgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFAwA6h6ex1yPFlxuw5MP5UFdy0SkMB8GA1Ud\nIwQYMBaAFM7HDMehiHl8b92QSMN4Q1FB7JU/MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQDhDvnTZ0/+\n623lX153M/EESY5wCeSIu8V6BUfAn/VC6gIgJLkdVHwWNfqtI7+9pHD4uTE86QoP\nTyegatE7P10qwNc=\n-----END CERTIFICATE-----\n", "principalType": "ca", "resource": "localhost:30006#com.cordaSimpleApplication.flow.GetStateByKey:*", "read": true diff --git a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network1/membership.json b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network1/membership.json index 7280e1a65..1c1fd61b6 100644 --- a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network1/membership.json +++ b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network1/membership.json @@ -1 +1 @@ -{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR\nynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq\nm2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd\nzQkhznMIF4SBF4k=\n-----END CERTIFICATE-----\n"}},"securityDomain":"network1"} \ No newline at end of file +{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUYxHjCF1HdZexrgAM73ec4jdHy8owCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE76ubZH/VHJszsYLHVKaUwKBR\nUZv8P+Jq6Op5PeBf02JUKPM15DSF9n56RJq+7mrM9zBzPvBsUySFd+rr/BrsW6NF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFM7HDMehiHl8b92QSMN4Q1FB7JU/MAoGCCqGSM49BAMCA0cAMEQCIH4UJq+qY2OP\n7DzBAwY7woYuy4zoT2kxyiexlix38aY4AiAo+8OKE1wFM+XKLUqI4zzgq2bpg1qb\nU5aIsTpdz3N2tg==\n-----END CERTIFICATE-----\n"}},"securityDomain":"network1"} \ No newline at end of file diff --git a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network2/access-control.json b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network2/access-control.json index 3ac2b0b08..6d6ca3f03 100644 --- a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network2/access-control.json +++ b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network2/access-control.json @@ -2,13 +2,13 @@ "securityDomain": "network2", "rules": [ { - "principal": "-----BEGIN CERTIFICATE-----\nMIICRjCCAe2gAwIBAgIURRRCdbZ63i59M3w68P5I25rz2LAwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABNOgoRbrgtfXxqa/mbBQNmyx1PIXLAuaMWpqAIu1Lw1LM28tJthOJqXU\nz6EwHLGeLlbvSET6xmoXrgIvBB1ZwG6jgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFMsXP7BjMsmfUuKfueUsrY74pX0GMB8GA1Ud\nIwQYMBaAFPwe1LrNuI33Vm+EdgO/E/jJihU1MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0cAMEQCIBB/681WfBR+\nQWIGfiYKOk3HuRtO8JFwbTiEjnAgCRvnAiBa69wWYaZ25ZR+Gay69eV+vDZkPMHS\ngdRjAItcKGstFg==\n-----END CERTIFICATE-----\n", + "principal": "-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUJjZQPlP6RXYv+XfLI66gBJ4dxmIwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjgwMFoXDTMyMDgwNDA2MzMwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABEOUMDwPOOLjs2UGvIhWiMLuwC+GoDNV2nz6st9Gzua2h01M8o95Iio6\nmzdln9L4pZm/2HzMnBoyPKrrjYRmciajgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFCCYZMhh/FIOW6zkBBBINwBobdpDMB8GA1Ud\nIwQYMBaAFOE41wEfBgHf+cfjQzayE/Q8pm2bMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQDyUvNXt6nM\nl0/7G/oJjeBywsQeL4IU2QDBSmi7Zk1oOQIgIkQtsg+duHOWCX60zUEThXeZsg9U\ndQHFXVncLBWQhLk=\n-----END CERTIFICATE-----\n", "principalType": "ca", "resource": "localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:*", "read": true }, { - "principal": "-----BEGIN CERTIFICATE-----\nMIICRjCCAe2gAwIBAgIURRRCdbZ63i59M3w68P5I25rz2LAwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABNOgoRbrgtfXxqa/mbBQNmyx1PIXLAuaMWpqAIu1Lw1LM28tJthOJqXU\nz6EwHLGeLlbvSET6xmoXrgIvBB1ZwG6jgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFMsXP7BjMsmfUuKfueUsrY74pX0GMB8GA1Ud\nIwQYMBaAFPwe1LrNuI33Vm+EdgO/E/jJihU1MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0cAMEQCIBB/681WfBR+\nQWIGfiYKOk3HuRtO8JFwbTiEjnAgCRvnAiBa69wWYaZ25ZR+Gay69eV+vDZkPMHS\ngdRjAItcKGstFg==\n-----END CERTIFICATE-----\n", + "principal": "-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUJjZQPlP6RXYv+XfLI66gBJ4dxmIwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjgwMFoXDTMyMDgwNDA2MzMwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABEOUMDwPOOLjs2UGvIhWiMLuwC+GoDNV2nz6st9Gzua2h01M8o95Iio6\nmzdln9L4pZm/2HzMnBoyPKrrjYRmciajgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFCCYZMhh/FIOW6zkBBBINwBobdpDMB8GA1Ud\nIwQYMBaAFOE41wEfBgHf+cfjQzayE/Q8pm2bMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQDyUvNXt6nM\nl0/7G/oJjeBywsQeL4IU2QDBSmi7Zk1oOQIgIkQtsg+duHOWCX60zUEThXeZsg9U\ndQHFXVncLBWQhLk=\n-----END CERTIFICATE-----\n", "principalType": "ca", "resource": "localhost:30006#com.cordaSimpleApplication.flow.GetStateByKey:*", "read": true diff --git a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network2/membership.json b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network2/membership.json index 912758323..12f3d4d0d 100644 --- a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network2/membership.json +++ b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials/network2/membership.json @@ -1 +1 @@ -{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUaRllBApd/UVhTSw9k4cCNqGfyWEwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTM3MDczMTA2MDQwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEr6IYnwH5QCqxy9F3i1x77rLD\nWG3EjMsD16528Q5N8BVStH5A89XeXLrALrAFxvgF5zlFriMRtQMrCxy0pZzJPaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFPwe1LrNuI33Vm+EdgO/E/jJihU1MAoGCCqGSM49BAMCA0gAMEUCIQDPHTMu/Hx1\nqm/G090dqV0215wZQ0Dl7al5TlSrrhftfgIge5QZxYKUsUkptToiOnRJY5pD/Oc+\nF9RBKXnii85zCnI=\n-----END CERTIFICATE-----\n"}},"securityDomain":"network2"} \ No newline at end of file +{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUajWU/EzwkVocqYksNXUdm04WvCswCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjQwMFoXDTM3MDczMTE4MjQwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5is5AaAg+nbhzGDEQG+liqNH\nhl876WuMbeT8k6dRNAsBpIwpxRWlg9iNrnvlkkhCBjb9AUyczQ7+BY1+NfUYlKNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFOE41wEfBgHf+cfjQzayE/Q8pm2bMAoGCCqGSM49BAMCA0gAMEUCIQCDmJzZfO1n\nVX5eMdDkDDtDz+eAXhPsu7upJW0ukhxkTAIgJceBfxJYwM1Tof1ADInIY+M+U8y+\nTL2JfaeZkJJz42E=\n-----END CERTIFICATE-----\n"}},"securityDomain":"network2"} \ No newline at end of file diff --git a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network1/access-control.json b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network1/access-control.json index 347d25a22..55af6a9fd 100644 --- a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network1/access-control.json +++ b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network1/access-control.json @@ -2,13 +2,13 @@ "securityDomain": "network1", "rules": [ { - "principal": "-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUNtt5srTRKRumyRD/O2FFoOImcjkwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABJ+cH+YyJCTeAyOXaIdNMFUYwKqUjClxSlEcHObedbmofV+WluvdkCsf\nWyv72JliZEm0HngxkkumIOxir0VBW4KjgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFN6zn3QTE1IuXKG2rnGCUuhkP2rIMB8GA1Ud\nIwQYMBaAFCoR1JlvfQXesApniUWtci1cXiOMMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQCpVjfnmEM7\nFHK9UX2j1+a25IFD5/p62CljJRQgnLUWXwIgBOKluTSOICeQ3FWx8+5+ZWrYL2wn\nPL3qORlNthH+Vrc=\n-----END CERTIFICATE-----\n", + "principal": "-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUf+IGiJyyyaGWwjRnjpnO0D7uzngwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjgwMFoXDTMyMDgwNDA2MzMwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABNoLyPx0DGMc4ilZlCtQw+vu2r1ZeHJukaaEk6U57gMXlpi6mU80E0xi\n7bIjQQDVdhH//zyFREjp/R5QyCRW66mjgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFAwA6h6ex1yPFlxuw5MP5UFdy0SkMB8GA1Ud\nIwQYMBaAFM7HDMehiHl8b92QSMN4Q1FB7JU/MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQDhDvnTZ0/+\n623lX153M/EESY5wCeSIu8V6BUfAn/VC6gIgJLkdVHwWNfqtI7+9pHD4uTE86QoP\nTyegatE7P10qwNc=\n-----END CERTIFICATE-----\n", "principalType": "ca", "resource": "corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:*", "read": true }, { - "principal": "-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUNtt5srTRKRumyRD/O2FFoOImcjkwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABJ+cH+YyJCTeAyOXaIdNMFUYwKqUjClxSlEcHObedbmofV+WluvdkCsf\nWyv72JliZEm0HngxkkumIOxir0VBW4KjgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFN6zn3QTE1IuXKG2rnGCUuhkP2rIMB8GA1Ud\nIwQYMBaAFCoR1JlvfQXesApniUWtci1cXiOMMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQCpVjfnmEM7\nFHK9UX2j1+a25IFD5/p62CljJRQgnLUWXwIgBOKluTSOICeQ3FWx8+5+ZWrYL2wn\nPL3qORlNthH+Vrc=\n-----END CERTIFICATE-----\n", + "principal": "-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUf+IGiJyyyaGWwjRnjpnO0D7uzngwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjgwMFoXDTMyMDgwNDA2MzMwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABNoLyPx0DGMc4ilZlCtQw+vu2r1ZeHJukaaEk6U57gMXlpi6mU80E0xi\n7bIjQQDVdhH//zyFREjp/R5QyCRW66mjgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFAwA6h6ex1yPFlxuw5MP5UFdy0SkMB8GA1Ud\nIwQYMBaAFM7HDMehiHl8b92QSMN4Q1FB7JU/MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQDhDvnTZ0/+\n623lX153M/EESY5wCeSIu8V6BUfAn/VC6gIgJLkdVHwWNfqtI7+9pHD4uTE86QoP\nTyegatE7P10qwNc=\n-----END CERTIFICATE-----\n", "principalType": "ca", "resource": "corda_network2_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:*", "read": true diff --git a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network1/membership.json b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network1/membership.json index 7280e1a65..1c1fd61b6 100644 --- a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network1/membership.json +++ b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network1/membership.json @@ -1 +1 @@ -{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR\nynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq\nm2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd\nzQkhznMIF4SBF4k=\n-----END CERTIFICATE-----\n"}},"securityDomain":"network1"} \ No newline at end of file +{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUYxHjCF1HdZexrgAM73ec4jdHy8owCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE76ubZH/VHJszsYLHVKaUwKBR\nUZv8P+Jq6Op5PeBf02JUKPM15DSF9n56RJq+7mrM9zBzPvBsUySFd+rr/BrsW6NF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFM7HDMehiHl8b92QSMN4Q1FB7JU/MAoGCCqGSM49BAMCA0cAMEQCIH4UJq+qY2OP\n7DzBAwY7woYuy4zoT2kxyiexlix38aY4AiAo+8OKE1wFM+XKLUqI4zzgq2bpg1qb\nU5aIsTpdz3N2tg==\n-----END CERTIFICATE-----\n"}},"securityDomain":"network1"} \ No newline at end of file diff --git a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network2/access-control.json b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network2/access-control.json index 6d82fd892..7b0290676 100644 --- a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network2/access-control.json +++ b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network2/access-control.json @@ -2,13 +2,13 @@ "securityDomain": "network2", "rules": [ { - "principal": "-----BEGIN CERTIFICATE-----\nMIICRjCCAe2gAwIBAgIURRRCdbZ63i59M3w68P5I25rz2LAwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABNOgoRbrgtfXxqa/mbBQNmyx1PIXLAuaMWpqAIu1Lw1LM28tJthOJqXU\nz6EwHLGeLlbvSET6xmoXrgIvBB1ZwG6jgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFMsXP7BjMsmfUuKfueUsrY74pX0GMB8GA1Ud\nIwQYMBaAFPwe1LrNuI33Vm+EdgO/E/jJihU1MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0cAMEQCIBB/681WfBR+\nQWIGfiYKOk3HuRtO8JFwbTiEjnAgCRvnAiBa69wWYaZ25ZR+Gay69eV+vDZkPMHS\ngdRjAItcKGstFg==\n-----END CERTIFICATE-----\n", + "principal": "-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUJjZQPlP6RXYv+XfLI66gBJ4dxmIwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjgwMFoXDTMyMDgwNDA2MzMwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABEOUMDwPOOLjs2UGvIhWiMLuwC+GoDNV2nz6st9Gzua2h01M8o95Iio6\nmzdln9L4pZm/2HzMnBoyPKrrjYRmciajgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFCCYZMhh/FIOW6zkBBBINwBobdpDMB8GA1Ud\nIwQYMBaAFOE41wEfBgHf+cfjQzayE/Q8pm2bMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQDyUvNXt6nM\nl0/7G/oJjeBywsQeL4IU2QDBSmi7Zk1oOQIgIkQtsg+duHOWCX60zUEThXeZsg9U\ndQHFXVncLBWQhLk=\n-----END CERTIFICATE-----\n", "principalType": "ca", "resource": "corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:*", "read": true }, { - "principal": "-----BEGIN CERTIFICATE-----\nMIICRjCCAe2gAwIBAgIURRRCdbZ63i59M3w68P5I25rz2LAwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABNOgoRbrgtfXxqa/mbBQNmyx1PIXLAuaMWpqAIu1Lw1LM28tJthOJqXU\nz6EwHLGeLlbvSET6xmoXrgIvBB1ZwG6jgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFMsXP7BjMsmfUuKfueUsrY74pX0GMB8GA1Ud\nIwQYMBaAFPwe1LrNuI33Vm+EdgO/E/jJihU1MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0cAMEQCIBB/681WfBR+\nQWIGfiYKOk3HuRtO8JFwbTiEjnAgCRvnAiBa69wWYaZ25ZR+Gay69eV+vDZkPMHS\ngdRjAItcKGstFg==\n-----END CERTIFICATE-----\n", + "principal": "-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUJjZQPlP6RXYv+XfLI66gBJ4dxmIwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjgwMFoXDTMyMDgwNDA2MzMwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABEOUMDwPOOLjs2UGvIhWiMLuwC+GoDNV2nz6st9Gzua2h01M8o95Iio6\nmzdln9L4pZm/2HzMnBoyPKrrjYRmciajgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFCCYZMhh/FIOW6zkBBBINwBobdpDMB8GA1Ud\nIwQYMBaAFOE41wEfBgHf+cfjQzayE/Q8pm2bMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQDyUvNXt6nM\nl0/7G/oJjeBywsQeL4IU2QDBSmi7Zk1oOQIgIkQtsg+duHOWCX60zUEThXeZsg9U\ndQHFXVncLBWQhLk=\n-----END CERTIFICATE-----\n", "principalType": "ca", "resource": "corda_network2_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:*", "read": true diff --git a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network2/membership.json b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network2/membership.json index 912758323..12f3d4d0d 100644 --- a/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network2/membership.json +++ b/samples/corda/corda-simple-application/clients/src/main/resources/config/credentials_docker/network2/membership.json @@ -1 +1 @@ -{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUaRllBApd/UVhTSw9k4cCNqGfyWEwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTM3MDczMTA2MDQwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEr6IYnwH5QCqxy9F3i1x77rLD\nWG3EjMsD16528Q5N8BVStH5A89XeXLrALrAFxvgF5zlFriMRtQMrCxy0pZzJPaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFPwe1LrNuI33Vm+EdgO/E/jJihU1MAoGCCqGSM49BAMCA0gAMEUCIQDPHTMu/Hx1\nqm/G090dqV0215wZQ0Dl7al5TlSrrhftfgIge5QZxYKUsUkptToiOnRJY5pD/Oc+\nF9RBKXnii85zCnI=\n-----END CERTIFICATE-----\n"}},"securityDomain":"network2"} \ No newline at end of file +{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUajWU/EzwkVocqYksNXUdm04WvCswCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjQwMFoXDTM3MDczMTE4MjQwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5is5AaAg+nbhzGDEQG+liqNH\nhl876WuMbeT8k6dRNAsBpIwpxRWlg9iNrnvlkkhCBjb9AUyczQ7+BY1+NfUYlKNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFOE41wEfBgHf+cfjQzayE/Q8pm2bMAoGCCqGSM49BAMCA0gAMEUCIQCDmJzZfO1n\nVX5eMdDkDDtDz+eAXhPsu7upJW0ukhxkTAIgJceBfxJYwM1Tof1ADInIY+M+U8y+\nTL2JfaeZkJJz42E=\n-----END CERTIFICATE-----\n"}},"securityDomain":"network2"} \ No newline at end of file diff --git a/samples/fabric/fabric-cli/src/data/credentials/network1/membership.json b/samples/fabric/fabric-cli/src/data/credentials/network1/membership.json index 7280e1a65..1c1fd61b6 100644 --- a/samples/fabric/fabric-cli/src/data/credentials/network1/membership.json +++ b/samples/fabric/fabric-cli/src/data/credentials/network1/membership.json @@ -1 +1 @@ -{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR\nynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq\nm2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd\nzQkhznMIF4SBF4k=\n-----END CERTIFICATE-----\n"}},"securityDomain":"network1"} \ No newline at end of file +{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUYxHjCF1HdZexrgAM73ec4jdHy8owCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE76ubZH/VHJszsYLHVKaUwKBR\nUZv8P+Jq6Op5PeBf02JUKPM15DSF9n56RJq+7mrM9zBzPvBsUySFd+rr/BrsW6NF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFM7HDMehiHl8b92QSMN4Q1FB7JU/MAoGCCqGSM49BAMCA0cAMEQCIH4UJq+qY2OP\n7DzBAwY7woYuy4zoT2kxyiexlix38aY4AiAo+8OKE1wFM+XKLUqI4zzgq2bpg1qb\nU5aIsTpdz3N2tg==\n-----END CERTIFICATE-----\n"}},"securityDomain":"network1"} \ No newline at end of file diff --git a/samples/fabric/fabric-cli/src/data/credentials/network2/access-control.json b/samples/fabric/fabric-cli/src/data/credentials/network2/access-control.json index 95d4a4f62..c5fd1f434 100644 --- a/samples/fabric/fabric-cli/src/data/credentials/network2/access-control.json +++ b/samples/fabric/fabric-cli/src/data/credentials/network2/access-control.json @@ -1 +1 @@ -{"securityDomain":"network2","rules":[{"principal":"-----BEGIN CERTIFICATE-----\nMIICRjCCAe2gAwIBAgIURRRCdbZ63i59M3w68P5I25rz2LAwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABNOgoRbrgtfXxqa/mbBQNmyx1PIXLAuaMWpqAIu1Lw1LM28tJthOJqXU\nz6EwHLGeLlbvSET6xmoXrgIvBB1ZwG6jgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFMsXP7BjMsmfUuKfueUsrY74pX0GMB8GA1Ud\nIwQYMBaAFPwe1LrNuI33Vm+EdgO/E/jJihU1MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0cAMEQCIBB/681WfBR+\nQWIGfiYKOk3HuRtO8JFwbTiEjnAgCRvnAiBa69wWYaZ25ZR+Gay69eV+vDZkPMHS\ngdRjAItcKGstFg==\n-----END CERTIFICATE-----\n","principalType":"certificate","resource":"mychannel:simplestate:Read:*","read":true}]} \ No newline at end of file +{"securityDomain":"network2","rules":[{"principal":"-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUJjZQPlP6RXYv+XfLI66gBJ4dxmIwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjgwMFoXDTMyMDgwNDA2MzMwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABEOUMDwPOOLjs2UGvIhWiMLuwC+GoDNV2nz6st9Gzua2h01M8o95Iio6\nmzdln9L4pZm/2HzMnBoyPKrrjYRmciajgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFCCYZMhh/FIOW6zkBBBINwBobdpDMB8GA1Ud\nIwQYMBaAFOE41wEfBgHf+cfjQzayE/Q8pm2bMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQDyUvNXt6nM\nl0/7G/oJjeBywsQeL4IU2QDBSmi7Zk1oOQIgIkQtsg+duHOWCX60zUEThXeZsg9U\ndQHFXVncLBWQhLk=\n-----END CERTIFICATE-----\n","principalType":"certificate","resource":"mychannel:simplestate:Read:*","read":true}]} \ No newline at end of file diff --git a/samples/fabric/fabric-cli/src/data/credentials/network2/membership.json b/samples/fabric/fabric-cli/src/data/credentials/network2/membership.json index 912758323..12f3d4d0d 100644 --- a/samples/fabric/fabric-cli/src/data/credentials/network2/membership.json +++ b/samples/fabric/fabric-cli/src/data/credentials/network2/membership.json @@ -1 +1 @@ -{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUaRllBApd/UVhTSw9k4cCNqGfyWEwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTM3MDczMTA2MDQwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEr6IYnwH5QCqxy9F3i1x77rLD\nWG3EjMsD16528Q5N8BVStH5A89XeXLrALrAFxvgF5zlFriMRtQMrCxy0pZzJPaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFPwe1LrNuI33Vm+EdgO/E/jJihU1MAoGCCqGSM49BAMCA0gAMEUCIQDPHTMu/Hx1\nqm/G090dqV0215wZQ0Dl7al5TlSrrhftfgIge5QZxYKUsUkptToiOnRJY5pD/Oc+\nF9RBKXnii85zCnI=\n-----END CERTIFICATE-----\n"}},"securityDomain":"network2"} \ No newline at end of file +{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUajWU/EzwkVocqYksNXUdm04WvCswCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjQwMFoXDTM3MDczMTE4MjQwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5is5AaAg+nbhzGDEQG+liqNH\nhl876WuMbeT8k6dRNAsBpIwpxRWlg9iNrnvlkkhCBjb9AUyczQ7+BY1+NfUYlKNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFOE41wEfBgHf+cfjQzayE/Q8pm2bMAoGCCqGSM49BAMCA0gAMEUCIQCDmJzZfO1n\nVX5eMdDkDDtDz+eAXhPsu7upJW0ukhxkTAIgJceBfxJYwM1Tof1ADInIY+M+U8y+\nTL2JfaeZkJJz42E=\n-----END CERTIFICATE-----\n"}},"securityDomain":"network2"} \ No newline at end of file diff --git a/samples/fabric/fabric-cli/src/data/credentials_docker/network1/membership.json b/samples/fabric/fabric-cli/src/data/credentials_docker/network1/membership.json index 7280e1a65..1c1fd61b6 100644 --- a/samples/fabric/fabric-cli/src/data/credentials_docker/network1/membership.json +++ b/samples/fabric/fabric-cli/src/data/credentials_docker/network1/membership.json @@ -1 +1 @@ -{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR\nynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq\nm2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd\nzQkhznMIF4SBF4k=\n-----END CERTIFICATE-----\n"}},"securityDomain":"network1"} \ No newline at end of file +{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUYxHjCF1HdZexrgAM73ec4jdHy8owCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE76ubZH/VHJszsYLHVKaUwKBR\nUZv8P+Jq6Op5PeBf02JUKPM15DSF9n56RJq+7mrM9zBzPvBsUySFd+rr/BrsW6NF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFM7HDMehiHl8b92QSMN4Q1FB7JU/MAoGCCqGSM49BAMCA0cAMEQCIH4UJq+qY2OP\n7DzBAwY7woYuy4zoT2kxyiexlix38aY4AiAo+8OKE1wFM+XKLUqI4zzgq2bpg1qb\nU5aIsTpdz3N2tg==\n-----END CERTIFICATE-----\n"}},"securityDomain":"network1"} \ No newline at end of file diff --git a/samples/fabric/fabric-cli/src/data/credentials_docker/network2/access-control.json b/samples/fabric/fabric-cli/src/data/credentials_docker/network2/access-control.json index a654e3720..8b69549c8 100644 --- a/samples/fabric/fabric-cli/src/data/credentials_docker/network2/access-control.json +++ b/samples/fabric/fabric-cli/src/data/credentials_docker/network2/access-control.json @@ -1 +1 @@ -{"securityDomain":"network2","rules":[{"principal":"-----BEGIN CERTIFICATE-----\nMIICRjCCAe2gAwIBAgIURRRCdbZ63i59M3w68P5I25rz2LAwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABNOgoRbrgtfXxqa/mbBQNmyx1PIXLAuaMWpqAIu1Lw1LM28tJthOJqXU\nz6EwHLGeLlbvSET6xmoXrgIvBB1ZwG6jgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFMsXP7BjMsmfUuKfueUsrY74pX0GMB8GA1Ud\nIwQYMBaAFPwe1LrNuI33Vm+EdgO/E/jJihU1MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0cAMEQCIBB/681WfBR+\nQWIGfiYKOk3HuRtO8JFwbTiEjnAgCRvnAiBa69wWYaZ25ZR+Gay69eV+vDZkPMHS\ngdRjAItcKGstFg==\n-----END CERTIFICATE-----\n","principalType":"certificate","resource":"mychannel:simplestate:Read:*","read":true},{"principal":"----BEGIN CERTIFICATE-----\nMIICRjCCAe2gAwIBAgIURRRCdbZ63i59M3w68P5I25rz2LAwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABNOgoRbrgtfXxqa/mbBQNmyx1PIXLAuaMWpqAIu1Lw1LM28tJthOJqXU\nz6EwHLGeLlbvSET6xmoXrgIvBB1ZwG6jgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFMsXP7BjMsmfUuKfueUsrY74pX0GMB8GA1Ud\nIwQYMBaAFPwe1LrNuI33Vm+EdgO/E/jJihU1MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0cAMEQCIBB/681WfBR+\nQWIGfiYKOk3HuRtO8JFwbTiEjnAgCRvnAiBa69wWYaZ25ZR+Gay69eV+vDZkPMHS\ngdRjAItcKGstFg==\n-----END CERTIFICATE-----\n","principalType":"certificate","resource":"mychannel:simplestatewithacl:Read:*","read":true}]} +{"securityDomain":"network2","rules":[{"principal":"-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUJjZQPlP6RXYv+XfLI66gBJ4dxmIwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjgwMFoXDTMyMDgwNDA2MzMwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABEOUMDwPOOLjs2UGvIhWiMLuwC+GoDNV2nz6st9Gzua2h01M8o95Iio6\nmzdln9L4pZm/2HzMnBoyPKrrjYRmciajgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFCCYZMhh/FIOW6zkBBBINwBobdpDMB8GA1Ud\nIwQYMBaAFOE41wEfBgHf+cfjQzayE/Q8pm2bMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQDyUvNXt6nM\nl0/7G/oJjeBywsQeL4IU2QDBSmi7Zk1oOQIgIkQtsg+duHOWCX60zUEThXeZsg9U\ndQHFXVncLBWQhLk=\n-----END CERTIFICATE-----\n","principalType":"certificate","resource":"mychannel:simplestate:Read:*","read":true},{"principal":"-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUJjZQPlP6RXYv+XfLI66gBJ4dxmIwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjgwMFoXDTMyMDgwNDA2MzMwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABEOUMDwPOOLjs2UGvIhWiMLuwC+GoDNV2nz6st9Gzua2h01M8o95Iio6\nmzdln9L4pZm/2HzMnBoyPKrrjYRmciajgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFCCYZMhh/FIOW6zkBBBINwBobdpDMB8GA1Ud\nIwQYMBaAFOE41wEfBgHf+cfjQzayE/Q8pm2bMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQDyUvNXt6nM\nl0/7G/oJjeBywsQeL4IU2QDBSmi7Zk1oOQIgIkQtsg+duHOWCX60zUEThXeZsg9U\ndQHFXVncLBWQhLk=\n-----END CERTIFICATE-----\n","principalType":"certificate","resource":"mychannel:simplestatewithacl:Read:*","read":true}]} diff --git a/samples/fabric/fabric-cli/src/data/credentials_docker/network2/membership.json b/samples/fabric/fabric-cli/src/data/credentials_docker/network2/membership.json index 912758323..12f3d4d0d 100644 --- a/samples/fabric/fabric-cli/src/data/credentials_docker/network2/membership.json +++ b/samples/fabric/fabric-cli/src/data/credentials_docker/network2/membership.json @@ -1 +1 @@ -{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUaRllBApd/UVhTSw9k4cCNqGfyWEwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTM3MDczMTA2MDQwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEr6IYnwH5QCqxy9F3i1x77rLD\nWG3EjMsD16528Q5N8BVStH5A89XeXLrALrAFxvgF5zlFriMRtQMrCxy0pZzJPaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFPwe1LrNuI33Vm+EdgO/E/jJihU1MAoGCCqGSM49BAMCA0gAMEUCIQDPHTMu/Hx1\nqm/G090dqV0215wZQ0Dl7al5TlSrrhftfgIge5QZxYKUsUkptToiOnRJY5pD/Oc+\nF9RBKXnii85zCnI=\n-----END CERTIFICATE-----\n"}},"securityDomain":"network2"} \ No newline at end of file +{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUajWU/EzwkVocqYksNXUdm04WvCswCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjQwMFoXDTM3MDczMTE4MjQwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5is5AaAg+nbhzGDEQG+liqNH\nhl876WuMbeT8k6dRNAsBpIwpxRWlg9iNrnvlkkhCBjb9AUyczQ7+BY1+NfUYlKNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFOE41wEfBgHf+cfjQzayE/Q8pm2bMAoGCCqGSM49BAMCA0gAMEUCIQCDmJzZfO1n\nVX5eMdDkDDtDz+eAXhPsu7upJW0ukhxkTAIgJceBfxJYwM1Tof1ADInIY+M+U8y+\nTL2JfaeZkJJz42E=\n-----END CERTIFICATE-----\n"}},"securityDomain":"network2"} \ No newline at end of file diff --git a/samples/fabric/fabric-cli/src/wallet-Dummy_Network/admin.id b/samples/fabric/fabric-cli/src/wallet-Dummy_Network/admin.id new file mode 100644 index 000000000..5728d610d --- /dev/null +++ b/samples/fabric/fabric-cli/src/wallet-Dummy_Network/admin.id @@ -0,0 +1 @@ +{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIIB6zCCAZGgAwIBAgIUGdKilZLHRbBMNKIJkfJW/txCmycwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMTIyMjEyNDcwMFoXDTIyMTIyMjEyNTIwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwVhZG1pbjBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABAgC75qKkepz3qmN2mXtOvZcBTY+jpPj7JfZulgbtHRNGM+IuLNY1Ba6\nXtCq+aE2L0hCrixdeU57Pv2kfe304fKjYDBeMA4GA1UdDwEB/wQEAwIHgDAMBgNV\nHRMBAf8EAjAAMB0GA1UdDgQWBBS82LliVtb0bSkNlAUSopxdVOTiHDAfBgNVHSME\nGDAWgBRyhvWC+jgvOsuRSF6arXu2zl0g/DAKBggqhkjOPQQDAgNIADBFAiEAvVwm\nR5bED0bGKh0a5I0SgFhbWWJqsB3TdTkDH6VG2uYCIDTQxhdKFEYjt/zD8hfo7Viv\nJcSUDK4i6VBl0kNc7fiw\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg5/h+UW63+O946lp+\r\n69A03VKnE5IB/FyAJt6/vDc+sGKhRANCAAQIAu+aipHqc96pjdpl7Tr2XAU2Po6T\r\n4+yX2bpYG7R0TRjPiLizWNQWul7QqvmhNi9IQq4sXXlOez79pH3t9OHy\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file diff --git a/samples/fabric/fabric-cli/src/wallet-Dummy_Network/alice.id b/samples/fabric/fabric-cli/src/wallet-Dummy_Network/alice.id new file mode 100644 index 000000000..29b71059c --- /dev/null +++ b/samples/fabric/fabric-cli/src/wallet-Dummy_Network/alice.id @@ -0,0 +1 @@ +{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIICdzCCAh6gAwIBAgIURDTyar4rqQHsdS+e3SNfXWPA4MgwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMTIyMjEyNDcwMFoXDTIyMTIyMjEyNTIwMFowQjEwMA0G\nA1UECxMGY2xpZW50MAsGA1UECxMEb3JnMTASBgNVBAsTC2RlcGFydG1lbnQxMQ4w\nDAYDVQQDEwVhbGljZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABN81GZdxlkqc\nCmjrFFFoRTu52bH8W8aZ1jlNm63WEHdTkhBokpYhz3CKOLtfcvXEo5gRMFEwiebw\nnBMCXY4X4cmjgcswgcgwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYD\nVR0OBBYEFG0ENsxu+zkEC3WEtr5LjvjXroH3MB8GA1UdIwQYMBaAFHKG9YL6OC86\ny5FIXpqte7bOXSD8MGgGCCoDBAUGBwgBBFx7ImF0dHJzIjp7ImhmLkFmZmlsaWF0\naW9uIjoib3JnMS5kZXBhcnRtZW50MSIsImhmLkVucm9sbG1lbnRJRCI6ImFsaWNl\nIiwiaGYuVHlwZSI6ImNsaWVudCJ9fTAKBggqhkjOPQQDAgNHADBEAiBLH04OFthd\nlKJstFwzia4E7/7j4dm/0QSS2TDdzatJbAIgIKcEmZEHg5fyygrUBXdB204mVVuD\nBQrjKcyqDb3j1OM=\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQggiIMoz/H/In441zW\r\nhkWBymQqawT3iOBIkLM/87xIx+OhRANCAATfNRmXcZZKnApo6xRRaEU7udmx/FvG\r\nmdY5TZut1hB3U5IQaJKWIc9wiji7X3L1xKOYETBRMInm8JwTAl2OF+HJ\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file diff --git a/samples/fabric/fabric-cli/src/wallet-Dummy_Network/bob.id b/samples/fabric/fabric-cli/src/wallet-Dummy_Network/bob.id new file mode 100644 index 000000000..607805e97 --- /dev/null +++ b/samples/fabric/fabric-cli/src/wallet-Dummy_Network/bob.id @@ -0,0 +1 @@ +{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIICdDCCAhqgAwIBAgIUQt/AkTbCRgPAQf8WzYTr75bGaj0wCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMTIyMjEyNDgwMFoXDTIyMTIyMjEyNTMwMFowQDEwMA0G\nA1UECxMGY2xpZW50MAsGA1UECxMEb3JnMTASBgNVBAsTC2RlcGFydG1lbnQxMQww\nCgYDVQQDEwNib2IwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAT05/C4elB82Jgf\nJmK5GecjY/xNELBdsR4g441WB8ocZ/5JEYy5mM0aMZJfOi0vVn+OVzQMJ5sOz0k5\nHdxvkPc/o4HJMIHGMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMB0GA1Ud\nDgQWBBR1+ssr8ZO4lLO+IkgYhChfHz6yETAfBgNVHSMEGDAWgBRyhvWC+jgvOsuR\nSF6arXu2zl0g/DBmBggqAwQFBgcIAQRaeyJhdHRycyI6eyJoZi5BZmZpbGlhdGlv\nbiI6Im9yZzEuZGVwYXJ0bWVudDEiLCJoZi5FbnJvbGxtZW50SUQiOiJib2IiLCJo\nZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQCNIwE4oXMQqgXK\n1cpsPU7PWhAr0oy7P4TpsR1SN64GmwIgVmPNb7O77M63U756XPdLW0HCTQSdZSHK\n1EoNob1WC5o=\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgsj1o70bbnyEugrQa\r\nTehiIXbHnzCKK0xaQuuI7lIUeVahRANCAAT05/C4elB82JgfJmK5GecjY/xNELBd\r\nsR4g441WB8ocZ/5JEYy5mM0aMZJfOi0vVn+OVzQMJ5sOz0k5HdxvkPc/\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file diff --git a/samples/fabric/fabric-cli/src/wallet-Dummy_Network/user1.id b/samples/fabric/fabric-cli/src/wallet-Dummy_Network/user1.id new file mode 100644 index 000000000..6107739f7 --- /dev/null +++ b/samples/fabric/fabric-cli/src/wallet-Dummy_Network/user1.id @@ -0,0 +1 @@ +{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIICRjCCAe2gAwIBAgIUBMI+vcDI6Z/4bMZN2Cjp6vAXDtgwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDkwNzA5MTQwMFoXDTIyMDkwNzA5MTkwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABFoZaE1MsLtrLRYFzJRyj5uelfL/Fa5pLN2kiO+M5tnxf0+wAotEeC8z\nLCS1KHVIQ7UJD/AOL1OFkbJCHKSdFJGjgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFPzrPjhbfwF/wxP8iFKy4NspQw0uMB8GA1Ud\nIwQYMBaAFHKG9YL6OC86y5FIXpqte7bOXSD8MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0cAMEQCIDP8WLlE4btz\niw6tI/EFdLY/CSOW1P8bOFquaz5YwjYhAiBxEKH6+udDehvHU+wmRaC/Kp1VJNJZ\ndbjNTs65n8zfbQ==\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgdSo5uIgF2yX79LXZ\r\nmP1USII6QeIYwfNCUQvo0rtKkZyhRANCAARaGWhNTLC7ay0WBcyUco+bnpXy/xWu\r\naSzdpIjvjObZ8X9PsAKLRHgvMywktSh1SEO1CQ/wDi9ThZGyQhyknRSR\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file diff --git a/samples/fabric/fabric-cli/src/wallet-network1/user1.id b/samples/fabric/fabric-cli/src/wallet-network1/user1.id index 924c4007b..6e9517319 100644 --- a/samples/fabric/fabric-cli/src/wallet-network1/user1.id +++ b/samples/fabric/fabric-cli/src/wallet-network1/user1.id @@ -1 +1 @@ -{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUNtt5srTRKRumyRD/O2FFoOImcjkwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABJ+cH+YyJCTeAyOXaIdNMFUYwKqUjClxSlEcHObedbmofV+WluvdkCsf\nWyv72JliZEm0HngxkkumIOxir0VBW4KjgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFN6zn3QTE1IuXKG2rnGCUuhkP2rIMB8GA1Ud\nIwQYMBaAFCoR1JlvfQXesApniUWtci1cXiOMMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQCpVjfnmEM7\nFHK9UX2j1+a25IFD5/p62CljJRQgnLUWXwIgBOKluTSOICeQ3FWx8+5+ZWrYL2wn\nPL3qORlNthH+Vrc=\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg3o4KcLGfi9C/XYd8\r\nE0sc/oKd2/jf+qhHQ1a62mHq+EyhRANCAASfnB/mMiQk3gMjl2iHTTBVGMCqlIwp\r\ncUpRHBzm3nW5qH1flpbr3ZArH1sr+9iZYmRJtB54MZJLpiDsYq9FQVuC\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file +{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUf+IGiJyyyaGWwjRnjpnO0D7uzngwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjgwMFoXDTMyMDgwNDA2MzMwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABNoLyPx0DGMc4ilZlCtQw+vu2r1ZeHJukaaEk6U57gMXlpi6mU80E0xi\n7bIjQQDVdhH//zyFREjp/R5QyCRW66mjgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFAwA6h6ex1yPFlxuw5MP5UFdy0SkMB8GA1Ud\nIwQYMBaAFM7HDMehiHl8b92QSMN4Q1FB7JU/MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQDhDvnTZ0/+\n623lX153M/EESY5wCeSIu8V6BUfAn/VC6gIgJLkdVHwWNfqtI7+9pHD4uTE86QoP\nTyegatE7P10qwNc=\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg2uMP8qtgRmGFz1hg\r\nM/uqEoKd6QFbPO41toS9q1i4Kg6hRANCAATaC8j8dAxjHOIpWZQrUMPr7tq9WXhy\r\nbpGmhJOlOe4DF5aYuplPNBNMYu2yI0EA1XYR//88hURI6f0eUMgkVuup\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file diff --git a/samples/fabric/fabric-cli/src/wallet-network2/user1.id b/samples/fabric/fabric-cli/src/wallet-network2/user1.id index 7b1f6c586..4b2a8fdd3 100644 --- a/samples/fabric/fabric-cli/src/wallet-network2/user1.id +++ b/samples/fabric/fabric-cli/src/wallet-network2/user1.id @@ -1 +1 @@ -{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIICRjCCAe2gAwIBAgIURRRCdbZ63i59M3w68P5I25rz2LAwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2NTIwMFoXDTIzMDgwNDA2NTcwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABNOgoRbrgtfXxqa/mbBQNmyx1PIXLAuaMWpqAIu1Lw1LM28tJthOJqXU\nz6EwHLGeLlbvSET6xmoXrgIvBB1ZwG6jgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFMsXP7BjMsmfUuKfueUsrY74pX0GMB8GA1Ud\nIwQYMBaAFPwe1LrNuI33Vm+EdgO/E/jJihU1MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0cAMEQCIBB/681WfBR+\nQWIGfiYKOk3HuRtO8JFwbTiEjnAgCRvnAiBa69wWYaZ25ZR+Gay69eV+vDZkPMHS\ngdRjAItcKGstFg==\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgY++YAA3V0++Z3IFs\r\n+khIphLS3JI5hf+N1VhJTcw3Pk6hRANCAATToKEW64LX18amv5mwUDZssdTyFywL\r\nmjFqagCLtS8NSzNvLSbYTial1M+hMByxni5W70hE+sZqF64CLwQdWcBu\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file +{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUJjZQPlP6RXYv+XfLI66gBJ4dxmIwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjgwMFoXDTMyMDgwNDA2MzMwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABEOUMDwPOOLjs2UGvIhWiMLuwC+GoDNV2nz6st9Gzua2h01M8o95Iio6\nmzdln9L4pZm/2HzMnBoyPKrrjYRmciajgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFCCYZMhh/FIOW6zkBBBINwBobdpDMB8GA1Ud\nIwQYMBaAFOE41wEfBgHf+cfjQzayE/Q8pm2bMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQDyUvNXt6nM\nl0/7G/oJjeBywsQeL4IU2QDBSmi7Zk1oOQIgIkQtsg+duHOWCX60zUEThXeZsg9U\ndQHFXVncLBWQhLk=\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgJ3VTKbfrMI3dm+iI\r\nTGcMCwgmi+8JhUVYZIZfjl9okWChRANCAARDlDA8Dzji47NlBryIVojC7sAvhqAz\r\nVdp8+rLfRs7mtodNTPKPeSIqOps3ZZ/S+KWZv9h8zJwaMjyq642EZnIm\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file diff --git a/tests/network-setups/fabric/network-artifacts/network1/channel-artifacts/Org1MSPanchors.tx b/tests/network-setups/fabric/network-artifacts/network1/channel-artifacts/Org1MSPanchors.tx index 769324a78098c6fe1bd63b5a3bf8415d1c319d6d..eb998981fc77a49efb49e7d50618e85a1f1ccd8c 100644 GIT binary patch delta 24 gcmdnVw3CUSYa0`nIF~2~lN1}rocS9z@@p{y07SqAkN^Mx delta 24 gcmdnVw3CUSYa0`nIF~2~lN1}r!Xs-p@@p{y07bF|w*UYD diff --git a/tests/network-setups/fabric/network-artifacts/network1/channel-artifacts/mychannel.block b/tests/network-setups/fabric/network-artifacts/network1/channel-artifacts/mychannel.block index 55d2bc4a86a16c4bfc0cfbb720e5fde56c9ba39a..425d4b7e03bc194b7acdf0496d11acdda55202f8 100644 GIT binary patch literal 17139 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 literal 17129 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 Lhn4}@GkO0ne;)Rt diff --git a/tests/network-setups/fabric/network-artifacts/network1/channel-artifacts/mychannel.tx b/tests/network-setups/fabric/network-artifacts/network1/channel-artifacts/mychannel.tx index 4b40f322cb5233d80b67d780ca2c641ee3676486..5516cacd5a637620fa53334a61bfdbb2afe42c49 100644 GIT binary patch delta 24 gcmZ3=yp)-rYY{V-IF~2~lN1}rocS9z@=s#~06^6R!vFvP delta 24 gcmZ3=yp)-rYY{V-IF~2~lN1}r!Xs-p@=s#~071tE>Hq)$ diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/IssuerPublicKey index 15c01b255288251fd71275c0fe0d801c04e38886..b5f24d41140e7a1f88d91f2ed87c37203802883b 100644 GIT binary patch delta 810 zcmV+_1J(S?2FnJJE`RaI>QHn^pIZS~ALpP=05D&jsV2b0K(ZX!*WDN%-X0Pll^@F$ z#gLC8pcOfc^Zg*{A) zQ8`mw&~0Jl$fu#A5+G6gJn0`tkfYI1z&nK8B-iI5yRuVgr+*5i!M>dWiuhw9L<%6; z$)CsZs*qWsZId%f+;Y14IB*47G4VPsEAAe+cDqf_B+t3B18%xa|_j?G6<`d1$ zeKPzB-`(gqV7r;|2ywI75+G9wqk&!B(3t;WhYX-u!)L2x7G@;k0W;n?w;@6zHR&Qm z3Lt`m%}%#f)Wh!e#SOVl%(=4hm~H9(i)ruh=Dbr>m49>+AV(0+auJ|1M{MLnN&qBQ z97B+`&v)O^KiBR3A%+~u94d$b3LwN{GE5|IJ$u!G#awEJBBE;DA9iSlb9AF_3-8k= zyD<_VJq2*~zDcHRHqd>wT+#1H}n1BlfgnD`aFUS_*OB28FBX(5b3dLa!1awS4iw zJ>U}PwvbB(U40%=&8^DGznF|)nfpZdA=s|F8bk^p1oj=?CB>ynbSYk$Z^{YyZ{m!b zh$5z!8hUEO1h<8M5+L!HQQJXY{EwmO(XO#kl&ZiYu+xNrXMd?aMejMWH0N9*L<%4+ zCVO{dXAhv08!qT+*~u0nY=2dB+qt=(j)Np@s@s1OAg0nzO1Dac!7-_lbEwd(6I~t= z?D~!uJdv;cMbH(0Dk4M*ASr>+HybgC@8}G2X2W2n;66_o}1f=muqv^b#Oz z@B9O!tHMiZb$@!hBcEi$k40@kHO+T9f6tq0>LpP*B18%xiHR;rXUUIsl+{%}_fsXP zdbzD=H;1@yrt5IkKn+gw5+HIU)$woB;We^_9Ntuzm5Rm(B?U*uELLl#3hwLZPxK;0 z3LxKa%#c;}4hKOtZvc08spM>bg29y0oH-N`ow!H`rGNYqAVTCCxwUy8d@H5m?c{&> z(!@H8*bPW2)+9(vKnh{Eq$-F33LwArz~Q`GgOD6oFZirJPGY0I7}dP&>vj+8X)W3=(k^@D7gxI`$v1j z(-Osj)PE|xU=I1WJP$3WBF0K0AZ=nxL0ui^%Vs4mlG>C+InfEA&9p)^7C}Y;(0F12 zeKJG}Ag9=T>{lZG;{l4mv4YjUpC-;WK8<-}y@0hF3vaPgY!V=e2J%)w+LhkK&4xZx zX}_~d^-^z3r%PU{jZK6%T@4R9L<%6g4^+T-rhf}!{GAYe?@bYP(J-QbQ9GokBDk-s zT-BN>5+Hw#g|X?o3*_zxeZ?0rdH4EWby1jKWZl1I3xCLn6K+Bvz|i~d3Z`{}F9fZQ zedh++9Xz~!tFM+CL>S%K1l#8uN+8p~eWxQc>8;1UPHo0Ag4og{LX(TDp$VIG2OoeX oZzG3NAhN%`ZvQjvip%SovAxQbviV2P-J<$}}l4W!b6vH$=8 diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/IssuerRevocationPublicKey index 7ef9db090..0446428da 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/IssuerRevocationPublicKey +++ b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/IssuerRevocationPublicKey @@ -1,5 +1,5 @@ -----BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEkglrbl6Llw5yDS3ARDs0tli8HpKvfaB3 -UESim8WHqjt/y67VHVtzvLE2uNI0/+5gFys0Qwwbz688O1qazwzCIOg05vtl0AnR -f3UvZhMWhBllNwb14aWJl5Am89Zcm+Bb +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEd39gnT70tFBHKV7uqQD+YHZ3XLF/2OjS +zMwotj+tL3Cp5FKl9ZyA4Gfx3aBUyY/1htC5R8C3LfhEW/sn1KxVfzRO87+e/nts +7hW2/pSe2BoUfafI094kjoBxXwtti08X -----END PUBLIC KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/ca-cert.pem b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/ca-cert.pem index 44fad8ac2..2ab432eef 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/ca-cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/ca-cert.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFzCCAb2gAwIBAgIUMSokEmwIGLStVW15f5Vk/pmJ8bEwCgYIKoZIzj0EAwIw +MIICFjCCAb2gAwIBAgIUM6cOj4I4iM/mzV1zDRWHdggGlW0wCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIW3OjyOU3HkXNUKfcRXwIxEd -NCaVdaZikxSsAXtWK4755DpN+DlJwMmFj6CkdOyh6+L0BLH0gybH0TM2xAw/eaNF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdJBRx8CYboiYFTl5R0XQq14+ +E4ekzCf6EHG2Srqh8u4oIFD+QeyR+4wwSJbJf9PWS3ngrnuoFYGwzOp0P4trUaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FGwHRYYRsEzEMSWQLUR/FRW4Q9M1MAoGCCqGSM49BAMCA0gAMEUCIQDlwQ5K7yM+ -bbYz10jGDbwuXuD2azQPphoZ32Lg1uA9fgIgf2XzZtvLHY2bB/PEJPbHCpLq+bst -X6bmPz2oSrn1tRc= +FPwe+lWvofc06dG7IQQ32tIduAHkMAoGCCqGSM49BAMCA0cAMEQCIBykgEh65XUl +yNUvDx2rMKwiyPL1A6rr7hoiFJX7KRN4AiBQpctKYeXqe/qDWFB+KaiC1YHalCrb +FQNkBAC+kBjBjQ== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/fabric-ca-server.db b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/ordererOrg/fabric-ca-server.db index 60c4084b91214e58c5232e1a3f0605d7de74d894..6217b4024cb0e79ade0372f09d5aae678af7c69b 100644 GIT binary patch delta 4471 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 delta 810 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 literal 65536 zcmeI4ON`@4nwT>y>y_-P&Ytl!YUVWRo@uyiRaN3!VgrLR-=ZW+qF$6_7Yclf5-Ca| zB}!TtM)iz$+wjhK_u`8UUyOylFbwQ*4~7p57{1#uFgAQJ;ENB&UJUFSSQz7=@|~4c zUDH$DJ>46uOeGnN=NA$G|108;YHKw=adK|72#q91?7g?QzrXi)a=E>|z3lfr@Oygw zEpT)5^a1?czi|Jm+uYuhr~mc--Ei;TonP*~)4dlU|KRY?k=EgRhd)2Mb?2Aw{`5Y2 z_ZQi}S7iXhApuAL5`YB0RRr#a`^JOEkN1BTC59O|ma|BF*SCzsiJwP-ef9Yk-xAr5 znCq}yP0W3G_4S9jk9|AWV_STgZGDVW)Wb))*je~S@O-)qO=poagUHO)8=YLeTdO_F z8Ovl8E&OEjeBx}L`?fR9ihnttWjqfI(+PIzL7s_`EaR)0EgU0`ra6C_JjyxinZMZN z5OJFa)$$dOELgx%BhT`PI zGlIEpUD3MYqugxa0D_leJ<7eJDG%@d$Gs1-UVj1DfL^~?T-NJ`Tm0_r2i1@E_x!2t ztmAnAOq1uJucF=a^Gn^1U3|KE?_cgI*#vod>-K~8<2T9x6!`p7CRr73|L!|?9(?e@ z{tI?j!`UL5Wkb`6&+qPCLUtaW`}pMk9LMoUTp7Xg93)QBV02#W)6--R9}@R&Kaf9o zRqfA$+JSQ(7#MMK9QNFwKA%O=*?fHEn7#~PSIEPM zpMLN5od-Yq(f&_Qq}#&TNf;xDt@GPEmui0D#Wlk0Lc31td_|yT$*&5OFHLy8(O7t? z$`2n>cWysWe)Ou5ae)Asm*<@BzWeX?ex8Z4pIN&xa&g{YyuYj?F21=2=p{LN72NsI zds#bt+WgK=u6|Bs4lZ}@1@-neD|1n$eQCY@rK_sqd#@Avmy`r{@#zT2`(vSh@H(M? zF-a!kpI^!(3%U7X{qCIy4<79Qw6PmuOE5a(-N%hf-M9<7rvDP4;HNorlQ_nsT(X&6 z74{cua9QvI1)d}e-&_K-C)W}ConsT@f<(%N#`?K4T|_|;0wX29Agf+wF8EU`S}YtZ zc|J4ZIE@yW?U6X)>^$|kb@A{%(44mp*L&~&9`a}R|LC1R0k`mi1Rw!O01|)%AOT1K z68I7beEO4H_a3~s`GdzleR_Dfe|O;o#^%Sk@na1AablBx!DR73tyjx2KPEP{n$_@x z;bPh!@O)FK#ntkY)iR#iy+9&+{zB3lR^S8sFj{!n6Wf^?izG7_vA_GfA7-mKAAa)T zu7D38eYjhU0ME%{>43-G%G-yZWKVzp(OKk?`$RmmIThhTveRr{nXUuO-wW}NtM$5q z*z=XC3+b*l9Zg45M1xcG^U3Mzea{-|RAYlUARVcBNvkYxyqo*TsLcrvK^&n0&Dxc(>0;TL@~s*meJTO54=+o+ zmgD(xvM?4;*t0L?7oz{pmFO2nuj*w}{PXi|MS&Avh

3^BM?F;CNs&;Ybo03`6$6Zp&q;{VyR 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 literal 32 qcmV+*0N?+uX1lH3Nl3*fvB0m}SB2ENIrhxLZUBC{^l;6wSMInu`V)Kr diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/e509e7d66bdbd1e7e777acd4c76abf24fa24ec232b8f7844cf8f19730b3504ac_sk b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/e509e7d66bdbd1e7e777acd4c76abf24fa24ec232b8f7844cf8f19730b3504ac_sk deleted file mode 100644 index cd5f9c248..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/msp/keystore/e509e7d66bdbd1e7e777acd4c76abf24fa24ec232b8f7844cf8f19730b3504ac_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg+cQoONl+UyLmTx/z -E/Vw/ZwEYAAUZodYAzdquhGJX6OhRANCAASl3OGXJE472oTSDUEpls9May1/NjEj -tR7UKsksDkwIzC4zQfuMBbICh7y7IObEZOf6Jocln3evQxiwcal6qKfi ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/tls-cert.pem b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/tls-cert.pem index 754c923d2..85bf6f288 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/tls-cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/fabric-ca/org1/tls-cert.pem @@ -1,16 +1,16 @@ -----BEGIN CERTIFICATE----- -MIICcjCCAhmgAwIBAgIUIXKV63PP4GV4E+tR28AckDctJG0wCgYIKoZIzj0EAwIw +MIICczCCAhmgAwIBAgIUYLuArOIRKq7WUs6dSE577nZyHYIwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTIzMDgwNDA2MDIwMFowZDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTMyMDgwNDA2MjIwMFowZDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl -cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRUwEwYDVQQDEwxhODdiOTg4MmY1Yjgw -WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASl3OGXJE472oTSDUEpls9May1/NjEj -tR7UKsksDkwIzC4zQfuMBbICh7y7IObEZOf6Jocln3evQxiwcal6qKfio4GkMIGh +cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRUwEwYDVQQDEww4NTAyYzA1YWM0OGYw +WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARi/49Za+kHWHwM0CZAGN2SqCvoTRQZ +4558ABC0X0zOW8H4f5F9hy4bJqmyvw3IIff1g/zrZ0gJKwG5Tqq0IMW2o4GkMIGh MA4GA1UdDwEB/wQEAwIDqDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw -DAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU2y2f5N75dHoLvtoHyEgqd3FnCQAwHwYD -VR0jBBgwFoAUKhHUmW99Bd6wCmeJRa1yLVxeI4wwIgYDVR0RBBswGYIMNmJiZDg5 -NDMwMTY2gglsb2NhbGhvc3QwCgYIKoZIzj0EAwIDRwAwRAIgHJt1FU/iOZOvEFK8 -uQy2DfbNLBvaR4XgZGfyjuH6AEwCIFULB108BivuJPuvci5NUxpTtJLNsGzCKW/Q -+7XeDsWx +DAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUG9snwjivUgjDLL3IjB/IkD6JXkIwHwYD +VR0jBBgwFoAUzscMx6GIeXxv3ZBIw3hDUUHslT8wIgYDVR0RBBswGYIMNmJiZDg5 +NDMwMTY2gglsb2NhbGhvc3QwCgYIKoZIzj0EAwIDSAAwRQIhANS2OL8/6u+onCx2 +HKJHuoZbmvMWRPBAf9hDmZxLxWv0AiANxoAEN5VQIND0MsObabfpt/walvjxQvao +3JA54Yj5pg== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/IssuerPublicKey index 15c01b255288251fd71275c0fe0d801c04e38886..b5f24d41140e7a1f88d91f2ed87c37203802883b 100644 GIT binary patch delta 810 zcmV+_1J(S?2FnJJE`RaI>QHn^pIZS~ALpP=05D&jsV2b0K(ZX!*WDN%-X0Pll^@F$ z#gLC8pcOfc^Zg*{A) zQ8`mw&~0Jl$fu#A5+G6gJn0`tkfYI1z&nK8B-iI5yRuVgr+*5i!M>dWiuhw9L<%6; z$)CsZs*qWsZId%f+;Y14IB*47G4VPsEAAe+cDqf_B+t3B18%xa|_j?G6<`d1$ zeKPzB-`(gqV7r;|2ywI75+G9wqk&!B(3t;WhYX-u!)L2x7G@;k0W;n?w;@6zHR&Qm z3Lt`m%}%#f)Wh!e#SOVl%(=4hm~H9(i)ruh=Dbr>m49>+AV(0+auJ|1M{MLnN&qBQ z97B+`&v)O^KiBR3A%+~u94d$b3LwN{GE5|IJ$u!G#awEJBBE;DA9iSlb9AF_3-8k= zyD<_VJq2*~zDcHRHqd>wT+#1H}n1BlfgnD`aFUS_*OB28FBX(5b3dLa!1awS4iw zJ>U}PwvbB(U40%=&8^DGznF|)nfpZdA=s|F8bk^p1oj=?CB>ynbSYk$Z^{YyZ{m!b zh$5z!8hUEO1h<8M5+L!HQQJXY{EwmO(XO#kl&ZiYu+xNrXMd?aMejMWH0N9*L<%4+ zCVO{dXAhv08!qT+*~u0nY=2dB+qt=(j)Np@s@s1OAg0nzO1Dac!7-_lbEwd(6I~t= z?D~!uJdv;cMbH(0Dk4M*ASr>+HybgC@8}G2X2W2n;66_o}1f=muqv^b#Oz z@B9O!tHMiZb$@!hBcEi$k40@kHO+T9f6tq0>LpP*B18%xiHR;rXUUIsl+{%}_fsXP zdbzD=H;1@yrt5IkKn+gw5+HIU)$woB;We^_9Ntuzm5Rm(B?U*uELLl#3hwLZPxK;0 z3LxKa%#c;}4hKOtZvc08spM>bg29y0oH-N`ow!H`rGNYqAVTCCxwUy8d@H5m?c{&> z(!@H8*bPW2)+9(vKnh{Eq$-F33LwArz~Q`GgOD6oFZirJPGY0I7}dP&>vj+8X)W3=(k^@D7gxI`$v1j z(-Osj)PE|xU=I1WJP$3WBF0K0AZ=nxL0ui^%Vs4mlG>C+InfEA&9p)^7C}Y;(0F12 zeKJG}Ag9=T>{lZG;{l4mv4YjUpC-;WK8<-}y@0hF3vaPgY!V=e2J%)w+LhkK&4xZx zX}_~d^-^z3r%PU{jZK6%T@4R9L<%6g4^+T-rhf}!{GAYe?@bYP(J-QbQ9GokBDk-s zT-BN>5+Hw#g|X?o3*_zxeZ?0rdH4EWby1jKWZl1I3xCLn6K+Bvz|i~d3Z`{}F9fZQ zedh++9Xz~!tFM+CL>S%K1l#8uN+8p~eWxQc>8;1UPHo0Ag4og{LX(TDp$VIG2OoeX oZzG3NAhN%`ZvQjvip%SovAxQbviV2P-J<$}}l4W!b6vH$=8 diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/IssuerRevocationPublicKey index 7ef9db090..0446428da 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/IssuerRevocationPublicKey +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/IssuerRevocationPublicKey @@ -1,5 +1,5 @@ -----BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEkglrbl6Llw5yDS3ARDs0tli8HpKvfaB3 -UESim8WHqjt/y67VHVtzvLE2uNI0/+5gFys0Qwwbz688O1qazwzCIOg05vtl0AnR -f3UvZhMWhBllNwb14aWJl5Am89Zcm+Bb +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEd39gnT70tFBHKV7uqQD+YHZ3XLF/2OjS +zMwotj+tL3Cp5FKl9ZyA4Gfx3aBUyY/1htC5R8C3LfhEW/sn1KxVfzRO87+e/nts +7hW2/pSe2BoUfafI094kjoBxXwtti08X -----END PUBLIC KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem index 44fad8ac2..2ab432eef 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFzCCAb2gAwIBAgIUMSokEmwIGLStVW15f5Vk/pmJ8bEwCgYIKoZIzj0EAwIw +MIICFjCCAb2gAwIBAgIUM6cOj4I4iM/mzV1zDRWHdggGlW0wCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIW3OjyOU3HkXNUKfcRXwIxEd -NCaVdaZikxSsAXtWK4755DpN+DlJwMmFj6CkdOyh6+L0BLH0gybH0TM2xAw/eaNF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdJBRx8CYboiYFTl5R0XQq14+ +E4ekzCf6EHG2Srqh8u4oIFD+QeyR+4wwSJbJf9PWS3ngrnuoFYGwzOp0P4trUaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FGwHRYYRsEzEMSWQLUR/FRW4Q9M1MAoGCCqGSM49BAMCA0gAMEUCIQDlwQ5K7yM+ -bbYz10jGDbwuXuD2azQPphoZ32Lg1uA9fgIgf2XzZtvLHY2bB/PEJPbHCpLq+bst -X6bmPz2oSrn1tRc= +FPwe+lWvofc06dG7IQQ32tIduAHkMAoGCCqGSM49BAMCA0cAMEQCIBykgEh65XUl +yNUvDx2rMKwiyPL1A6rr7hoiFJX7KRN4AiBQpctKYeXqe/qDWFB+KaiC1YHalCrb +FQNkBAC+kBjBjQ== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/keystore/2b1bb41ced0015f0c3b2ee752ca4b8ac3d20a66f2f899f3bd8eef1a06dfca4d9_sk b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/keystore/2b1bb41ced0015f0c3b2ee752ca4b8ac3d20a66f2f899f3bd8eef1a06dfca4d9_sk deleted file mode 100644 index bcf40aa9a..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/keystore/2b1bb41ced0015f0c3b2ee752ca4b8ac3d20a66f2f899f3bd8eef1a06dfca4d9_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgAgpj8lDen5ANKXZx -kmGQeHbis+BIMjPDdFjssI4pcHahRANCAATyEchXgQkX7FzEAaf7Aj7dS8aqXJfN -QfbKIJfnm2jMbOIdZYa6y5UobBTxAt1ds3I7LpET/wQVx6IjptqYOulO ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/keystore/58dca995909dfa76173499b1046793178da020db97c77840c7f7cf91fa0fdcef_sk b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/keystore/58dca995909dfa76173499b1046793178da020db97c77840c7f7cf91fa0fdcef_sk new file mode 100644 index 000000000..2be231c57 --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/keystore/58dca995909dfa76173499b1046793178da020db97c77840c7f7cf91fa0fdcef_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg0tGanPJdJJojJklV +7Lcpr4LtX5+z55xrYzagByDScVmhRANCAARcw9r4mfm/p7VnriQzGJ1onrdOYaqK +NmzQ15Jn2D4xFGj+2xu0BU3Sq/D3dePU5GEjiMiVxrCZ0Vs/95IJXUgh +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/signcerts/cert.pem index 9e0fe4fc6..b0e041937 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/signcerts/cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/signcerts/cert.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICPDCCAeKgAwIBAgIUThuWZsnNciPhfgUMijrzpW0Z9yQwCgYIKoZIzj0EAwIw +MIICPDCCAeKgAwIBAgIUEZQYTbxUDnTSAiMZtONa2bhx3aAwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTIzMDgwNDA2MDcwMFowXTELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTMyMDgwNDA2MjcwMFowXTELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGY2xpZW50MQ4wDAYDVQQDEwVhZG1pbjBZMBMGByqG -SM49AgEGCCqGSM49AwEHA0IABPIRyFeBCRfsXMQBp/sCPt1Lxqpcl81B9sogl+eb -aMxs4h1lhrrLlShsFPEC3V2zcjsukRP/BBXHoiOm2pg66U6jdTBzMA4GA1UdDwEB -/wQEAwIHgDAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSOFgewRUQfwWCegvsR9KMu -zhD3dDAfBgNVHSMEGDAWgBRsB0WGEbBMxDElkC1EfxUVuEPTNTATBgNVHREEDDAK -gghzYW5uaXNoMTAKBggqhkjOPQQDAgNIADBFAiEAox/vVl7xZNCaWziwygW/eC2A -lWzWc4A6PwldteEgwdsCIGnWipmT609hsoiRngvT+JMa7ywnnhGBiIFSUIhUkRpt +SM49AgEGCCqGSM49AwEHA0IABFzD2viZ+b+ntWeuJDMYnWiet05hqoo2bNDXkmfY +PjEUaP7bG7QFTdKr8Pd149TkYSOIyJXGsJnRWz/3kgldSCGjdTBzMA4GA1UdDwEB +/wQEAwIHgDAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSlgNmAXk6+uaAI5jPMd+ZI +MeGBKDAfBgNVHSMEGDAWgBT8HvpVr6H3NOnRuyEEN9rSHbgB5DATBgNVHREEDDAK +gghzYW5uaXNoMTAKBggqhkjOPQQDAgNIADBFAiEA4r0W5vVYanq2ptg2ioT2Yrey +wdypYA7+m5ZlDdUsh4wCIC2T2KuVIl/L+mbSGDmPItT3IuwX/jQYeYydigxZUmEH -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem index 44fad8ac2..2ab432eef 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFzCCAb2gAwIBAgIUMSokEmwIGLStVW15f5Vk/pmJ8bEwCgYIKoZIzj0EAwIw +MIICFjCCAb2gAwIBAgIUM6cOj4I4iM/mzV1zDRWHdggGlW0wCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIW3OjyOU3HkXNUKfcRXwIxEd -NCaVdaZikxSsAXtWK4755DpN+DlJwMmFj6CkdOyh6+L0BLH0gybH0TM2xAw/eaNF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdJBRx8CYboiYFTl5R0XQq14+ +E4ekzCf6EHG2Srqh8u4oIFD+QeyR+4wwSJbJf9PWS3ngrnuoFYGwzOp0P4trUaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FGwHRYYRsEzEMSWQLUR/FRW4Q9M1MAoGCCqGSM49BAMCA0gAMEUCIQDlwQ5K7yM+ -bbYz10jGDbwuXuD2azQPphoZ32Lg1uA9fgIgf2XzZtvLHY2bB/PEJPbHCpLq+bst -X6bmPz2oSrn1tRc= +FPwe+lWvofc06dG7IQQ32tIduAHkMAoGCCqGSM49BAMCA0cAMEQCIBykgEh65XUl +yNUvDx2rMKwiyPL1A6rr7hoiFJX7KRN4AiBQpctKYeXqe/qDWFB+KaiC1YHalCrb +FQNkBAC+kBjBjQ== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/IssuerPublicKey index 15c01b255288251fd71275c0fe0d801c04e38886..b5f24d41140e7a1f88d91f2ed87c37203802883b 100644 GIT binary patch delta 810 zcmV+_1J(S?2FnJJE`RaI>QHn^pIZS~ALpP=05D&jsV2b0K(ZX!*WDN%-X0Pll^@F$ z#gLC8pcOfc^Zg*{A) zQ8`mw&~0Jl$fu#A5+G6gJn0`tkfYI1z&nK8B-iI5yRuVgr+*5i!M>dWiuhw9L<%6; z$)CsZs*qWsZId%f+;Y14IB*47G4VPsEAAe+cDqf_B+t3B18%xa|_j?G6<`d1$ zeKPzB-`(gqV7r;|2ywI75+G9wqk&!B(3t;WhYX-u!)L2x7G@;k0W;n?w;@6zHR&Qm z3Lt`m%}%#f)Wh!e#SOVl%(=4hm~H9(i)ruh=Dbr>m49>+AV(0+auJ|1M{MLnN&qBQ z97B+`&v)O^KiBR3A%+~u94d$b3LwN{GE5|IJ$u!G#awEJBBE;DA9iSlb9AF_3-8k= zyD<_VJq2*~zDcHRHqd>wT+#1H}n1BlfgnD`aFUS_*OB28FBX(5b3dLa!1awS4iw zJ>U}PwvbB(U40%=&8^DGznF|)nfpZdA=s|F8bk^p1oj=?CB>ynbSYk$Z^{YyZ{m!b zh$5z!8hUEO1h<8M5+L!HQQJXY{EwmO(XO#kl&ZiYu+xNrXMd?aMejMWH0N9*L<%4+ zCVO{dXAhv08!qT+*~u0nY=2dB+qt=(j)Np@s@s1OAg0nzO1Dac!7-_lbEwd(6I~t= z?D~!uJdv;cMbH(0Dk4M*ASr>+HybgC@8}G2X2W2n;66_o}1f=muqv^b#Oz z@B9O!tHMiZb$@!hBcEi$k40@kHO+T9f6tq0>LpP*B18%xiHR;rXUUIsl+{%}_fsXP zdbzD=H;1@yrt5IkKn+gw5+HIU)$woB;We^_9Ntuzm5Rm(B?U*uELLl#3hwLZPxK;0 z3LxKa%#c;}4hKOtZvc08spM>bg29y0oH-N`ow!H`rGNYqAVTCCxwUy8d@H5m?c{&> z(!@H8*bPW2)+9(vKnh{Eq$-F33LwArz~Q`GgOD6oFZirJPGY0I7}dP&>vj+8X)W3=(k^@D7gxI`$v1j z(-Osj)PE|xU=I1WJP$3WBF0K0AZ=nxL0ui^%Vs4mlG>C+InfEA&9p)^7C}Y;(0F12 zeKJG}Ag9=T>{lZG;{l4mv4YjUpC-;WK8<-}y@0hF3vaPgY!V=e2J%)w+LhkK&4xZx zX}_~d^-^z3r%PU{jZK6%T@4R9L<%6g4^+T-rhf}!{GAYe?@bYP(J-QbQ9GokBDk-s zT-BN>5+Hw#g|X?o3*_zxeZ?0rdH4EWby1jKWZl1I3xCLn6K+Bvz|i~d3Z`{}F9fZQ zedh++9Xz~!tFM+CL>S%K1l#8uN+8p~eWxQc>8;1UPHo0Ag4og{LX(TDp$VIG2OoeX oZzG3NAhN%`ZvQjvip%SovAxQbviV2P-J<$}}l4W!b6vH$=8 diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/IssuerRevocationPublicKey index 7ef9db090..0446428da 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/IssuerRevocationPublicKey +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/IssuerRevocationPublicKey @@ -1,5 +1,5 @@ -----BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEkglrbl6Llw5yDS3ARDs0tli8HpKvfaB3 -UESim8WHqjt/y67VHVtzvLE2uNI0/+5gFys0Qwwbz688O1qazwzCIOg05vtl0AnR -f3UvZhMWhBllNwb14aWJl5Am89Zcm+Bb +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEd39gnT70tFBHKV7uqQD+YHZ3XLF/2OjS +zMwotj+tL3Cp5FKl9ZyA4Gfx3aBUyY/1htC5R8C3LfhEW/sn1KxVfzRO87+e/nts +7hW2/pSe2BoUfafI094kjoBxXwtti08X -----END PUBLIC KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem index 44fad8ac2..2ab432eef 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFzCCAb2gAwIBAgIUMSokEmwIGLStVW15f5Vk/pmJ8bEwCgYIKoZIzj0EAwIw +MIICFjCCAb2gAwIBAgIUM6cOj4I4iM/mzV1zDRWHdggGlW0wCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIW3OjyOU3HkXNUKfcRXwIxEd -NCaVdaZikxSsAXtWK4755DpN+DlJwMmFj6CkdOyh6+L0BLH0gybH0TM2xAw/eaNF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdJBRx8CYboiYFTl5R0XQq14+ +E4ekzCf6EHG2Srqh8u4oIFD+QeyR+4wwSJbJf9PWS3ngrnuoFYGwzOp0P4trUaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FGwHRYYRsEzEMSWQLUR/FRW4Q9M1MAoGCCqGSM49BAMCA0gAMEUCIQDlwQ5K7yM+ -bbYz10jGDbwuXuD2azQPphoZ32Lg1uA9fgIgf2XzZtvLHY2bB/PEJPbHCpLq+bst -X6bmPz2oSrn1tRc= +FPwe+lWvofc06dG7IQQ32tIduAHkMAoGCCqGSM49BAMCA0cAMEQCIBykgEh65XUl +yNUvDx2rMKwiyPL1A6rr7hoiFJX7KRN4AiBQpctKYeXqe/qDWFB+KaiC1YHalCrb +FQNkBAC+kBjBjQ== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/keystore/b693c9143aa4020e1865f5e6232db70a58e01fec07cb84204b6a69176b73ed5e_sk b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/keystore/b693c9143aa4020e1865f5e6232db70a58e01fec07cb84204b6a69176b73ed5e_sk new file mode 100644 index 000000000..12b427c79 --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/keystore/b693c9143aa4020e1865f5e6232db70a58e01fec07cb84204b6a69176b73ed5e_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgv27/23sMY7TqBWIu +jYvUzS+xHHvMD1g7cdGQXBhtf/ShRANCAAQW6SRaERdVSbaV9mse6WR2xxIICEuv +VNIjyOrSlS3YQ54cReOQw3SDnnjyOWoND+5xL3p90nrDFUKMnJQIpTzE +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/keystore/f949ca1e0e7d7e6d996176d4b1a8f7755eccfbd8d2f9e0597320fe1eaa47c16e_sk b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/keystore/f949ca1e0e7d7e6d996176d4b1a8f7755eccfbd8d2f9e0597320fe1eaa47c16e_sk deleted file mode 100644 index 2998f8e56..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/keystore/f949ca1e0e7d7e6d996176d4b1a8f7755eccfbd8d2f9e0597320fe1eaa47c16e_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQglmRvQ1l2rttkcSLE -R/o8a0xX9roaSIkl4ivUO3rV1sKhRANCAAQGU+KBsKjDpYcrVIPPkRJqIfO3iTbh -aPJKgD3gV/yVCQ8nvWsDkpk6xG0va61++j4rvq1/q27FpAWiYQi2QPEu ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/signcerts/cert.pem index d9312d929..c766e4ef6 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/signcerts/cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/signcerts/cert.pem @@ -1,17 +1,17 @@ -----BEGIN CERTIFICATE----- -MIICtDCCAlugAwIBAgIUHQJpkm8eQdl6WtX1DXJsOBgDVGUwCgYIKoZIzj0EAwIw +MIICtDCCAlugAwIBAgIUDqp7YaO3em9Mq5sptpC8jlYp3i4wCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTIzMDgwNDA2MDcwMFowYDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDE4MjMwMFoXDTMyMDgwNDA2MjgwMFowYDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEQMA4GA1UECxMHb3JkZXJlcjEQMA4GA1UEAxMHb3JkZXJlcjBZMBMG -ByqGSM49AgEGCCqGSM49AwEHA0IABAZT4oGwqMOlhytUg8+REmoh87eJNuFo8kqA -PeBX/JUJDye9awOSmTrEbS9rrX76Piu+rX+rbsWkBaJhCLZA8S6jgeowgecwDgYD -VR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFFjlk9VI+mRs2hvq -VLq3ejWAkGFRMB8GA1UdIwQYMBaAFGwHRYYRsEzEMSWQLUR/FRW4Q9M1MCoGA1Ud +ByqGSM49AgEGCCqGSM49AwEHA0IABBbpJFoRF1VJtpX2ax7pZHbHEggIS69U0iPI +6tKVLdhDnhxF45DDdIOeePI5ag0P7nEven3SesMVQoyclAilPMSjgeowgecwDgYD +VR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFFHMJfL+IJNmS7q4 +55l3ON+BzxZ5MB8GA1UdIwQYMBaAFPwe+lWvofc06dG7IQQ32tIduAHkMCoGA1Ud EQQjMCGCFG9yZGVyZXIubmV0d29yazEuY29tgglsb2NhbGhvc3QwWwYIKgMEBQYH CAEET3siYXR0cnMiOnsiaGYuQWZmaWxpYXRpb24iOiIiLCJoZi5FbnJvbGxtZW50 SUQiOiJvcmRlcmVyIiwiaGYuVHlwZSI6Im9yZGVyZXIifX0wCgYIKoZIzj0EAwID -RwAwRAIhAIYSkttY4h+5+pQLQ6fFIVBYXBj7LPwPdayQow2hip9cAh8zod7cgB78 -NL2Nne4k5+iY7A6huV8MIeYG76Hjz86e +RwAwRAIgTBN59cdC/ZDvGJOlnsZqA+GRWlBnJoCSFUJHUl09xDQCIEVGQVIfxLn7 +v/93ifVMjITI9j+Ae7vptjzzFI3a6L+o -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem index 44fad8ac2..2ab432eef 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/msp/tlscacerts/tlsca.network1.com-cert.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFzCCAb2gAwIBAgIUMSokEmwIGLStVW15f5Vk/pmJ8bEwCgYIKoZIzj0EAwIw +MIICFjCCAb2gAwIBAgIUM6cOj4I4iM/mzV1zDRWHdggGlW0wCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIW3OjyOU3HkXNUKfcRXwIxEd -NCaVdaZikxSsAXtWK4755DpN+DlJwMmFj6CkdOyh6+L0BLH0gybH0TM2xAw/eaNF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdJBRx8CYboiYFTl5R0XQq14+ +E4ekzCf6EHG2Srqh8u4oIFD+QeyR+4wwSJbJf9PWS3ngrnuoFYGwzOp0P4trUaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FGwHRYYRsEzEMSWQLUR/FRW4Q9M1MAoGCCqGSM49BAMCA0gAMEUCIQDlwQ5K7yM+ -bbYz10jGDbwuXuD2azQPphoZ32Lg1uA9fgIgf2XzZtvLHY2bB/PEJPbHCpLq+bst -X6bmPz2oSrn1tRc= +FPwe+lWvofc06dG7IQQ32tIduAHkMAoGCCqGSM49BAMCA0cAMEQCIBykgEh65XUl +yNUvDx2rMKwiyPL1A6rr7hoiFJX7KRN4AiBQpctKYeXqe/qDWFB+KaiC1YHalCrb +FQNkBAC+kBjBjQ== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/IssuerPublicKey index 15c01b255288251fd71275c0fe0d801c04e38886..b5f24d41140e7a1f88d91f2ed87c37203802883b 100644 GIT binary patch delta 810 zcmV+_1J(S?2FnJJE`RaI>QHn^pIZS~ALpP=05D&jsV2b0K(ZX!*WDN%-X0Pll^@F$ z#gLC8pcOfc^Zg*{A) zQ8`mw&~0Jl$fu#A5+G6gJn0`tkfYI1z&nK8B-iI5yRuVgr+*5i!M>dWiuhw9L<%6; z$)CsZs*qWsZId%f+;Y14IB*47G4VPsEAAe+cDqf_B+t3B18%xa|_j?G6<`d1$ zeKPzB-`(gqV7r;|2ywI75+G9wqk&!B(3t;WhYX-u!)L2x7G@;k0W;n?w;@6zHR&Qm z3Lt`m%}%#f)Wh!e#SOVl%(=4hm~H9(i)ruh=Dbr>m49>+AV(0+auJ|1M{MLnN&qBQ z97B+`&v)O^KiBR3A%+~u94d$b3LwN{GE5|IJ$u!G#awEJBBE;DA9iSlb9AF_3-8k= zyD<_VJq2*~zDcHRHqd>wT+#1H}n1BlfgnD`aFUS_*OB28FBX(5b3dLa!1awS4iw zJ>U}PwvbB(U40%=&8^DGznF|)nfpZdA=s|F8bk^p1oj=?CB>ynbSYk$Z^{YyZ{m!b zh$5z!8hUEO1h<8M5+L!HQQJXY{EwmO(XO#kl&ZiYu+xNrXMd?aMejMWH0N9*L<%4+ zCVO{dXAhv08!qT+*~u0nY=2dB+qt=(j)Np@s@s1OAg0nzO1Dac!7-_lbEwd(6I~t= z?D~!uJdv;cMbH(0Dk4M*ASr>+HybgC@8}G2X2W2n;66_o}1f=muqv^b#Oz z@B9O!tHMiZb$@!hBcEi$k40@kHO+T9f6tq0>LpP*B18%xiHR;rXUUIsl+{%}_fsXP zdbzD=H;1@yrt5IkKn+gw5+HIU)$woB;We^_9Ntuzm5Rm(B?U*uELLl#3hwLZPxK;0 z3LxKa%#c;}4hKOtZvc08spM>bg29y0oH-N`ow!H`rGNYqAVTCCxwUy8d@H5m?c{&> z(!@H8*bPW2)+9(vKnh{Eq$-F33LwArz~Q`GgOD6oFZirJPGY0I7}dP&>vj+8X)W3=(k^@D7gxI`$v1j z(-Osj)PE|xU=I1WJP$3WBF0K0AZ=nxL0ui^%Vs4mlG>C+InfEA&9p)^7C}Y;(0F12 zeKJG}Ag9=T>{lZG;{l4mv4YjUpC-;WK8<-}y@0hF3vaPgY!V=e2J%)w+LhkK&4xZx zX}_~d^-^z3r%PU{jZK6%T@4R9L<%6g4^+T-rhf}!{GAYe?@bYP(J-QbQ9GokBDk-s zT-BN>5+Hw#g|X?o3*_zxeZ?0rdH4EWby1jKWZl1I3xCLn6K+Bvz|i~d3Z`{}F9fZQ zedh++9Xz~!tFM+CL>S%K1l#8uN+8p~eWxQc>8;1UPHo0Ag4og{LX(TDp$VIG2OoeX oZzG3NAhN%`ZvQjvip%SovAxQbviV2P-J<$}}l4W!b6vH$=8 diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/IssuerRevocationPublicKey index 7ef9db090..0446428da 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/IssuerRevocationPublicKey +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/IssuerRevocationPublicKey @@ -1,5 +1,5 @@ -----BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEkglrbl6Llw5yDS3ARDs0tli8HpKvfaB3 -UESim8WHqjt/y67VHVtzvLE2uNI0/+5gFys0Qwwbz688O1qazwzCIOg05vtl0AnR -f3UvZhMWhBllNwb14aWJl5Am89Zcm+Bb +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEd39gnT70tFBHKV7uqQD+YHZ3XLF/2OjS +zMwotj+tL3Cp5FKl9ZyA4Gfx3aBUyY/1htC5R8C3LfhEW/sn1KxVfzRO87+e/nts +7hW2/pSe2BoUfafI094kjoBxXwtti08X -----END PUBLIC KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/ca.crt b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/ca.crt index 44fad8ac2..2ab432eef 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/ca.crt +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/ca.crt @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFzCCAb2gAwIBAgIUMSokEmwIGLStVW15f5Vk/pmJ8bEwCgYIKoZIzj0EAwIw +MIICFjCCAb2gAwIBAgIUM6cOj4I4iM/mzV1zDRWHdggGlW0wCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIW3OjyOU3HkXNUKfcRXwIxEd -NCaVdaZikxSsAXtWK4755DpN+DlJwMmFj6CkdOyh6+L0BLH0gybH0TM2xAw/eaNF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdJBRx8CYboiYFTl5R0XQq14+ +E4ekzCf6EHG2Srqh8u4oIFD+QeyR+4wwSJbJf9PWS3ngrnuoFYGwzOp0P4trUaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FGwHRYYRsEzEMSWQLUR/FRW4Q9M1MAoGCCqGSM49BAMCA0gAMEUCIQDlwQ5K7yM+ -bbYz10jGDbwuXuD2azQPphoZ32Lg1uA9fgIgf2XzZtvLHY2bB/PEJPbHCpLq+bst -X6bmPz2oSrn1tRc= +FPwe+lWvofc06dG7IQQ32tIduAHkMAoGCCqGSM49BAMCA0cAMEQCIBykgEh65XUl +yNUvDx2rMKwiyPL1A6rr7hoiFJX7KRN4AiBQpctKYeXqe/qDWFB+KaiC1YHalCrb +FQNkBAC+kBjBjQ== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/keystore/426c3a6d0556e0020c276da919026d8e11a5a776e83cd39609407f402517a38c_sk b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/keystore/426c3a6d0556e0020c276da919026d8e11a5a776e83cd39609407f402517a38c_sk new file mode 100644 index 000000000..7f81fa8e7 --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/keystore/426c3a6d0556e0020c276da919026d8e11a5a776e83cd39609407f402517a38c_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgV6AZrtJ74dNEmrV0 +8ST6RLcbTTHBC87yCmu2BqaHr2uhRANCAAScOU8CMx4TC69oAxLL6+8oAG6ACopn +6NKxPQ6WoKmivglaJFSC5R1W5kK6DifBfuLPWqVxoTt4kgXCchXpr3eo +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/keystore/75f5e9c82d2e8d17470e65e5a809cd1c2ec4b9dbb9d0083146c8a6afd50f7223_sk b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/keystore/75f5e9c82d2e8d17470e65e5a809cd1c2ec4b9dbb9d0083146c8a6afd50f7223_sk deleted file mode 100644 index a42779be0..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/keystore/75f5e9c82d2e8d17470e65e5a809cd1c2ec4b9dbb9d0083146c8a6afd50f7223_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgNjzTcFJxWtRYdrRC -YEXzNAKIBcYA/bImBs5q6xrgbaChRANCAASggl5d89FgqSzdB2033rYnlejo5bXX -fGC5oC1GyIfO2n2zq5lILMaYUa/jwS1SByqlb6CSh6L0AOzCkFfcRH5P ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.crt b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.crt index bb19964dc..a4004f141 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.crt +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.crt @@ -1,18 +1,18 @@ -----BEGIN CERTIFICATE----- -MIIC1TCCAnygAwIBAgIUfBcNYTEE8L0Bdmk65WqhkQO+kHkwCgYIKoZIzj0EAwIw +MIIC1jCCAnygAwIBAgIUMQgnjBA3ZvQj6vAIJ1IMsVmupgowCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTIzMDgwNDA2MDcwMFowYDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDE4MjMwMFoXDTMyMDgwNDA2MjgwMFowYDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEQMA4GA1UECxMHb3JkZXJlcjEQMA4GA1UEAxMHb3JkZXJlcjBZMBMG -ByqGSM49AgEGCCqGSM49AwEHA0IABKCCXl3z0WCpLN0HbTfetieV6Ojltdd8YLmg -LUbIh87afbOrmUgsxphRr+PBLVIHKqVvoJKHovQA7MKQV9xEfk+jggEKMIIBBjAO +ByqGSM49AgEGCCqGSM49AwEHA0IABJw5TwIzHhMLr2gDEsvr7ygAboAKimfo0rE9 +DpagqaK+CVokVILlHVbmQroOJ8F+4s9apXGhO3iSBcJyFemvd6ijggEKMIIBBjAO BgNVHQ8BAf8EBAMCA6gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwG -A1UdEwEB/wQCMAAwHQYDVR0OBBYEFIlygLHp/jwTR9CNn5g51jm6q7JVMB8GA1Ud -IwQYMBaAFGwHRYYRsEzEMSWQLUR/FRW4Q9M1MCoGA1UdEQQjMCGCFG9yZGVyZXIu +A1UdEwEB/wQCMAAwHQYDVR0OBBYEFCaJQnyaCBBf9OH7tRm5zD4GwYw9MB8GA1Ud +IwQYMBaAFPwe+lWvofc06dG7IQQ32tIduAHkMCoGA1UdEQQjMCGCFG9yZGVyZXIu bmV0d29yazEuY29tgglsb2NhbGhvc3QwWwYIKgMEBQYHCAEET3siYXR0cnMiOnsi aGYuQWZmaWxpYXRpb24iOiIiLCJoZi5FbnJvbGxtZW50SUQiOiJvcmRlcmVyIiwi -aGYuVHlwZSI6Im9yZGVyZXIifX0wCgYIKoZIzj0EAwIDRwAwRAIgLwh2fOXcSPND -W0qgcx7FvRvrcUzA+IUeyTKc6WuqBHYCIB9v7cfw1A1RQV94FgUvc+OhvIMVXKb3 -0vidYlqPTrlS +aGYuVHlwZSI6Im9yZGVyZXIifX0wCgYIKoZIzj0EAwIDSAAwRQIhAM5OXPDym1il +E/zJlyOEyl1kx5sKzodppv7SyIYzZ/uEAiBKlI7PZhj4grqR0chbvJt0JI8OuDpw +mz+8SJNMjiUwPw== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.key b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.key index a42779be0..7f81fa8e7 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.key +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/server.key @@ -1,5 +1,5 @@ -----BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgNjzTcFJxWtRYdrRC -YEXzNAKIBcYA/bImBs5q6xrgbaChRANCAASggl5d89FgqSzdB2033rYnlejo5bXX -fGC5oC1GyIfO2n2zq5lILMaYUa/jwS1SByqlb6CSh6L0AOzCkFfcRH5P +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgV6AZrtJ74dNEmrV0 +8ST6RLcbTTHBC87yCmu2BqaHr2uhRANCAAScOU8CMx4TC69oAxLL6+8oAG6ACopn +6NKxPQ6WoKmivglaJFSC5R1W5kK6DifBfuLPWqVxoTt4kgXCchXpr3eo -----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/signcerts/cert.pem index bb19964dc..a4004f141 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/signcerts/cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/signcerts/cert.pem @@ -1,18 +1,18 @@ -----BEGIN CERTIFICATE----- -MIIC1TCCAnygAwIBAgIUfBcNYTEE8L0Bdmk65WqhkQO+kHkwCgYIKoZIzj0EAwIw +MIIC1jCCAnygAwIBAgIUMQgnjBA3ZvQj6vAIJ1IMsVmupgowCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTIzMDgwNDA2MDcwMFowYDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDE4MjMwMFoXDTMyMDgwNDA2MjgwMFowYDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEQMA4GA1UECxMHb3JkZXJlcjEQMA4GA1UEAxMHb3JkZXJlcjBZMBMG -ByqGSM49AgEGCCqGSM49AwEHA0IABKCCXl3z0WCpLN0HbTfetieV6Ojltdd8YLmg -LUbIh87afbOrmUgsxphRr+PBLVIHKqVvoJKHovQA7MKQV9xEfk+jggEKMIIBBjAO +ByqGSM49AgEGCCqGSM49AwEHA0IABJw5TwIzHhMLr2gDEsvr7ygAboAKimfo0rE9 +DpagqaK+CVokVILlHVbmQroOJ8F+4s9apXGhO3iSBcJyFemvd6ijggEKMIIBBjAO BgNVHQ8BAf8EBAMCA6gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwG -A1UdEwEB/wQCMAAwHQYDVR0OBBYEFIlygLHp/jwTR9CNn5g51jm6q7JVMB8GA1Ud -IwQYMBaAFGwHRYYRsEzEMSWQLUR/FRW4Q9M1MCoGA1UdEQQjMCGCFG9yZGVyZXIu +A1UdEwEB/wQCMAAwHQYDVR0OBBYEFCaJQnyaCBBf9OH7tRm5zD4GwYw9MB8GA1Ud +IwQYMBaAFPwe+lWvofc06dG7IQQ32tIduAHkMCoGA1UdEQQjMCGCFG9yZGVyZXIu bmV0d29yazEuY29tgglsb2NhbGhvc3QwWwYIKgMEBQYHCAEET3siYXR0cnMiOnsi aGYuQWZmaWxpYXRpb24iOiIiLCJoZi5FbnJvbGxtZW50SUQiOiJvcmRlcmVyIiwi -aGYuVHlwZSI6Im9yZGVyZXIifX0wCgYIKoZIzj0EAwIDRwAwRAIgLwh2fOXcSPND -W0qgcx7FvRvrcUzA+IUeyTKc6WuqBHYCIB9v7cfw1A1RQV94FgUvc+OhvIMVXKb3 -0vidYlqPTrlS +aGYuVHlwZSI6Im9yZGVyZXIifX0wCgYIKoZIzj0EAwIDSAAwRQIhAM5OXPDym1il +E/zJlyOEyl1kx5sKzodppv7SyIYzZ/uEAiBKlI7PZhj4grqR0chbvJt0JI8OuDpw +mz+8SJNMjiUwPw== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/tlscacerts/tls-localhost-9054-ca-orderer-network1-com.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/tlscacerts/tls-localhost-9054-ca-orderer-network1-com.pem index 44fad8ac2..2ab432eef 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/tlscacerts/tls-localhost-9054-ca-orderer-network1-com.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/orderers/orderer.network1.com/tls/tlscacerts/tls-localhost-9054-ca-orderer-network1-com.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFzCCAb2gAwIBAgIUMSokEmwIGLStVW15f5Vk/pmJ8bEwCgYIKoZIzj0EAwIw +MIICFjCCAb2gAwIBAgIUM6cOj4I4iM/mzV1zDRWHdggGlW0wCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIW3OjyOU3HkXNUKfcRXwIxEd -NCaVdaZikxSsAXtWK4755DpN+DlJwMmFj6CkdOyh6+L0BLH0gybH0TM2xAw/eaNF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdJBRx8CYboiYFTl5R0XQq14+ +E4ekzCf6EHG2Srqh8u4oIFD+QeyR+4wwSJbJf9PWS3ngrnuoFYGwzOp0P4trUaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FGwHRYYRsEzEMSWQLUR/FRW4Q9M1MAoGCCqGSM49BAMCA0gAMEUCIQDlwQ5K7yM+ -bbYz10jGDbwuXuD2azQPphoZ32Lg1uA9fgIgf2XzZtvLHY2bB/PEJPbHCpLq+bst -X6bmPz2oSrn1tRc= +FPwe+lWvofc06dG7IQQ32tIduAHkMAoGCCqGSM49BAMCA0cAMEQCIBykgEh65XUl +yNUvDx2rMKwiyPL1A6rr7hoiFJX7KRN4AiBQpctKYeXqe/qDWFB+KaiC1YHalCrb +FQNkBAC+kBjBjQ== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/IssuerPublicKey index 15c01b255288251fd71275c0fe0d801c04e38886..b5f24d41140e7a1f88d91f2ed87c37203802883b 100644 GIT binary patch delta 810 zcmV+_1J(S?2FnJJE`RaI>QHn^pIZS~ALpP=05D&jsV2b0K(ZX!*WDN%-X0Pll^@F$ z#gLC8pcOfc^Zg*{A) zQ8`mw&~0Jl$fu#A5+G6gJn0`tkfYI1z&nK8B-iI5yRuVgr+*5i!M>dWiuhw9L<%6; z$)CsZs*qWsZId%f+;Y14IB*47G4VPsEAAe+cDqf_B+t3B18%xa|_j?G6<`d1$ zeKPzB-`(gqV7r;|2ywI75+G9wqk&!B(3t;WhYX-u!)L2x7G@;k0W;n?w;@6zHR&Qm z3Lt`m%}%#f)Wh!e#SOVl%(=4hm~H9(i)ruh=Dbr>m49>+AV(0+auJ|1M{MLnN&qBQ z97B+`&v)O^KiBR3A%+~u94d$b3LwN{GE5|IJ$u!G#awEJBBE;DA9iSlb9AF_3-8k= zyD<_VJq2*~zDcHRHqd>wT+#1H}n1BlfgnD`aFUS_*OB28FBX(5b3dLa!1awS4iw zJ>U}PwvbB(U40%=&8^DGznF|)nfpZdA=s|F8bk^p1oj=?CB>ynbSYk$Z^{YyZ{m!b zh$5z!8hUEO1h<8M5+L!HQQJXY{EwmO(XO#kl&ZiYu+xNrXMd?aMejMWH0N9*L<%4+ zCVO{dXAhv08!qT+*~u0nY=2dB+qt=(j)Np@s@s1OAg0nzO1Dac!7-_lbEwd(6I~t= z?D~!uJdv;cMbH(0Dk4M*ASr>+HybgC@8}G2X2W2n;66_o}1f=muqv^b#Oz z@B9O!tHMiZb$@!hBcEi$k40@kHO+T9f6tq0>LpP*B18%xiHR;rXUUIsl+{%}_fsXP zdbzD=H;1@yrt5IkKn+gw5+HIU)$woB;We^_9Ntuzm5Rm(B?U*uELLl#3hwLZPxK;0 z3LxKa%#c;}4hKOtZvc08spM>bg29y0oH-N`ow!H`rGNYqAVTCCxwUy8d@H5m?c{&> z(!@H8*bPW2)+9(vKnh{Eq$-F33LwArz~Q`GgOD6oFZirJPGY0I7}dP&>vj+8X)W3=(k^@D7gxI`$v1j z(-Osj)PE|xU=I1WJP$3WBF0K0AZ=nxL0ui^%Vs4mlG>C+InfEA&9p)^7C}Y;(0F12 zeKJG}Ag9=T>{lZG;{l4mv4YjUpC-;WK8<-}y@0hF3vaPgY!V=e2J%)w+LhkK&4xZx zX}_~d^-^z3r%PU{jZK6%T@4R9L<%6g4^+T-rhf}!{GAYe?@bYP(J-QbQ9GokBDk-s zT-BN>5+Hw#g|X?o3*_zxeZ?0rdH4EWby1jKWZl1I3xCLn6K+Bvz|i~d3Z`{}F9fZQ zedh++9Xz~!tFM+CL>S%K1l#8uN+8p~eWxQc>8;1UPHo0Ag4og{LX(TDp$VIG2OoeX oZzG3NAhN%`ZvQjvip%SovAxQbviV2P-J<$}}l4W!b6vH$=8 diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/IssuerRevocationPublicKey b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/IssuerRevocationPublicKey index 7ef9db090..0446428da 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/IssuerRevocationPublicKey +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/IssuerRevocationPublicKey @@ -1,5 +1,5 @@ -----BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEkglrbl6Llw5yDS3ARDs0tli8HpKvfaB3 -UESim8WHqjt/y67VHVtzvLE2uNI0/+5gFys0Qwwbz688O1qazwzCIOg05vtl0AnR -f3UvZhMWhBllNwb14aWJl5Am89Zcm+Bb +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEd39gnT70tFBHKV7uqQD+YHZ3XLF/2OjS +zMwotj+tL3Cp5FKl9ZyA4Gfx3aBUyY/1htC5R8C3LfhEW/sn1KxVfzRO87+e/nts +7hW2/pSe2BoUfafI094kjoBxXwtti08X -----END PUBLIC KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem index 44fad8ac2..2ab432eef 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/cacerts/localhost-9054-ca-orderer-network1-com.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFzCCAb2gAwIBAgIUMSokEmwIGLStVW15f5Vk/pmJ8bEwCgYIKoZIzj0EAwIw +MIICFjCCAb2gAwIBAgIUM6cOj4I4iM/mzV1zDRWHdggGlW0wCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIW3OjyOU3HkXNUKfcRXwIxEd -NCaVdaZikxSsAXtWK4755DpN+DlJwMmFj6CkdOyh6+L0BLH0gybH0TM2xAw/eaNF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdJBRx8CYboiYFTl5R0XQq14+ +E4ekzCf6EHG2Srqh8u4oIFD+QeyR+4wwSJbJf9PWS3ngrnuoFYGwzOp0P4trUaNF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FGwHRYYRsEzEMSWQLUR/FRW4Q9M1MAoGCCqGSM49BAMCA0gAMEUCIQDlwQ5K7yM+ -bbYz10jGDbwuXuD2azQPphoZ32Lg1uA9fgIgf2XzZtvLHY2bB/PEJPbHCpLq+bst -X6bmPz2oSrn1tRc= +FPwe+lWvofc06dG7IQQ32tIduAHkMAoGCCqGSM49BAMCA0cAMEQCIBykgEh65XUl +yNUvDx2rMKwiyPL1A6rr7hoiFJX7KRN4AiBQpctKYeXqe/qDWFB+KaiC1YHalCrb +FQNkBAC+kBjBjQ== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/keystore/0f8b9ac723af2ec1426c2407e6360b0c2a170273c894946f30d3662ad3429fe3_sk b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/keystore/0f8b9ac723af2ec1426c2407e6360b0c2a170273c894946f30d3662ad3429fe3_sk new file mode 100644 index 000000000..8a5b66800 --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/keystore/0f8b9ac723af2ec1426c2407e6360b0c2a170273c894946f30d3662ad3429fe3_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg6im84O3yj4FrfbTu +v9Q8UBt17KsIfwRGhFhw1oLbzoihRANCAAT1aix7Vlh0W/4/TmU9/qWXVT7zzDk6 +avbbxbROz14hbP4J0nFCg121XkUOHBFcMDWHgyQR8zGNomPW4Rxlh3cO +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/keystore/3e3a32bdfc3ef9a6639c212e3fab34bc73a5921da7a80691393b105e7fcb3226_sk b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/keystore/3e3a32bdfc3ef9a6639c212e3fab34bc73a5921da7a80691393b105e7fcb3226_sk deleted file mode 100644 index a556cc5ab..000000000 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/keystore/3e3a32bdfc3ef9a6639c212e3fab34bc73a5921da7a80691393b105e7fcb3226_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgfsNQt1f2GORjzVSj -FGzokdjbKqJrWgECnFhz0VWxMZ2hRANCAARF7xZVR9HxuJ+fzlx47ydkOHMa7yIJ -TAMVAQcOqQjN8VNfp68Ghb2zLKw+tikrkTQLurt3A9iOBL+EnIUjwnwe ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/signcerts/cert.pem b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/signcerts/cert.pem index 9b3739549..bb95ed32a 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/signcerts/cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/ordererOrganizations/network1.com/users/Admin@network1.com/msp/signcerts/cert.pem @@ -1,17 +1,17 @@ -----BEGIN CERTIFICATE----- -MIICozCCAkqgAwIBAgIUGqI5zOxQZFNH+9rIXUgOrkidzjEwCgYIKoZIzj0EAwIw +MIICozCCAkqgAwIBAgIUce98OV7kP9dKmv/NATtR83/TOa8wCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTIzMDgwNDA2MDcwMFowYzELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDE4MjMwMFoXDTMyMDgwNDA2MjgwMFowYzELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEOMAwGA1UECxMFYWRtaW4xFTATBgNVBAMTDG9yZGVyZXJBZG1pbjBZ -MBMGByqGSM49AgEGCCqGSM49AwEHA0IABEXvFlVH0fG4n5/OXHjvJ2Q4cxrvIglM -AxUBBw6pCM3xU1+nrwaFvbMsrD62KSuRNAu6u3cD2I4Ev4SchSPCfB6jgdYwgdMw -DgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFMoWeRBl6V8Z -5ykpm7i+3sPnWJzsMB8GA1UdIwQYMBaAFGwHRYYRsEzEMSWQLUR/FRW4Q9M1MBMG +MBMGByqGSM49AgEGCCqGSM49AwEHA0IABPVqLHtWWHRb/j9OZT3+pZdVPvPMOTpq +9tvFtE7PXiFs/gnScUKDXbVeRQ4cEVwwNYeDJBHzMY2iY9bhHGWHdw6jgdYwgdMw +DgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFJWi6/LF3OOp +/HQPjjuxGYvUMHg4MB8GA1UdIwQYMBaAFPwe+lWvofc06dG7IQQ32tIduAHkMBMG A1UdEQQMMAqCCHNhbm5pc2gxMF4GCCoDBAUGBwgBBFJ7ImF0dHJzIjp7ImhmLkFm ZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoib3JkZXJlckFkbWluIiwi -aGYuVHlwZSI6ImFkbWluIn19MAoGCCqGSM49BAMCA0cAMEQCIB4+S7UcTRKxyVME -QWjkDTo1HK7wTC7sqoQ4zeUdZd6nAiAUAH+j8aarEWjGgI12yL5w6hvPkWiS/TMj -GgHZChvt5g== +aGYuVHlwZSI6ImFkbWluIn19MAoGCCqGSM49BAMCA0cAMEQCIEKAs43gBjPaTJd+ +g//Hhj6nv2FcpvHX+ISlqmIEWv4ZAiBRmdC7/x90NhQ85qmOFIvgIKl5sB6IdRBf +DbbnXDua0Q== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/ca/ca.org1.network1.com-cert.pem b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/ca/ca.org1.network1.com-cert.pem index 3d82333d8..cf1d2d465 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/ca/ca.org1.network1.com-cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/ca/ca.org1.network1.com-cert.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw +MIICFjCCAb2gAwIBAgIUYxHjCF1HdZexrgAM73ec4jdHy8owCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy -dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR -ynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE76ubZH/VHJszsYLHVKaUwKBR +UZv8P+Jq6Op5PeBf02JUKPM15DSF9n56RJq+7mrM9zBzPvBsUySFd+rr/BrsW6NF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE -FCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq -m2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd -zQkhznMIF4SBF4k= +FM7HDMehiHl8b92QSMN4Q1FB7JU/MAoGCCqGSM49BAMCA0cAMEQCIH4UJq+qY2OP +7DzBAwY7woYuy4zoT2kxyiexlix38aY4AiAo+8OKE1wFM+XKLUqI4zzgq2bpg1qb +U5aIsTpdz3N2tg== -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.docker.json b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.docker.json index 2d56d1f51..34ef0938b 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.docker.json +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.docker.json @@ -26,7 +26,7 @@ "peer0.org1.network1.com": { "url": "grpcs://peer0.org1.network1.com:7051", "tlsCACerts": { - "pem": "-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR\nynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq\nm2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd\nzQkhznMIF4SBF4k=\n-----END CERTIFICATE-----\n" + "pem": "-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUYxHjCF1HdZexrgAM73ec4jdHy8owCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE76ubZH/VHJszsYLHVKaUwKBR\nUZv8P+Jq6Op5PeBf02JUKPM15DSF9n56RJq+7mrM9zBzPvBsUySFd+rr/BrsW6NF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFM7HDMehiHl8b92QSMN4Q1FB7JU/MAoGCCqGSM49BAMCA0cAMEQCIH4UJq+qY2OP\n7DzBAwY7woYuy4zoT2kxyiexlix38aY4AiAo+8OKE1wFM+XKLUqI4zzgq2bpg1qb\nU5aIsTpdz3N2tg==\n-----END CERTIFICATE-----\n" }, "grpcOptions": { "ssl-target-name-override": "peer0.org1.network1.com", @@ -39,7 +39,7 @@ "url": "https://ca.org1.network1.com:7054", "caName": "ca-org1", "tlsCACerts": { - "pem": "-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR\nynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq\nm2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd\nzQkhznMIF4SBF4k=\n-----END CERTIFICATE-----\n" + "pem": "-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUYxHjCF1HdZexrgAM73ec4jdHy8owCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE76ubZH/VHJszsYLHVKaUwKBR\nUZv8P+Jq6Op5PeBf02JUKPM15DSF9n56RJq+7mrM9zBzPvBsUySFd+rr/BrsW6NF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFM7HDMehiHl8b92QSMN4Q1FB7JU/MAoGCCqGSM49BAMCA0cAMEQCIH4UJq+qY2OP\n7DzBAwY7woYuy4zoT2kxyiexlix38aY4AiAo+8OKE1wFM+XKLUqI4zzgq2bpg1qb\nU5aIsTpdz3N2tg==\n-----END CERTIFICATE-----\n" }, "httpOptions": { "verify": false diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.json b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.json index 181ebe9c8..13611b542 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.json +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.json @@ -26,7 +26,7 @@ "peer0.org1.network1.com": { "url": "grpcs://localhost:7051", "tlsCACerts": { - "pem": "-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR\nynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq\nm2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd\nzQkhznMIF4SBF4k=\n-----END CERTIFICATE-----\n" + "pem": "-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUYxHjCF1HdZexrgAM73ec4jdHy8owCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE76ubZH/VHJszsYLHVKaUwKBR\nUZv8P+Jq6Op5PeBf02JUKPM15DSF9n56RJq+7mrM9zBzPvBsUySFd+rr/BrsW6NF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFM7HDMehiHl8b92QSMN4Q1FB7JU/MAoGCCqGSM49BAMCA0cAMEQCIH4UJq+qY2OP\n7DzBAwY7woYuy4zoT2kxyiexlix38aY4AiAo+8OKE1wFM+XKLUqI4zzgq2bpg1qb\nU5aIsTpdz3N2tg==\n-----END CERTIFICATE-----\n" }, "grpcOptions": { "ssl-target-name-override": "peer0.org1.network1.com", @@ -39,7 +39,7 @@ "url": "https://localhost:7054", "caName": "ca-org1", "tlsCACerts": { - "pem": "-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR\nynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq\nm2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd\nzQkhznMIF4SBF4k=\n-----END CERTIFICATE-----\n" + "pem": "-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUYxHjCF1HdZexrgAM73ec4jdHy8owCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE76ubZH/VHJszsYLHVKaUwKBR\nUZv8P+Jq6Op5PeBf02JUKPM15DSF9n56RJq+7mrM9zBzPvBsUySFd+rr/BrsW6NF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFM7HDMehiHl8b92QSMN4Q1FB7JU/MAoGCCqGSM49BAMCA0cAMEQCIH4UJq+qY2OP\n7DzBAwY7woYuy4zoT2kxyiexlix38aY4AiAo+8OKE1wFM+XKLUqI4zzgq2bpg1qb\nU5aIsTpdz3N2tg==\n-----END CERTIFICATE-----\n" }, "httpOptions": { "verify": false diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.yaml b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.yaml index c19192374..ba9fa56e6 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.yaml +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.yaml @@ -26,18 +26,18 @@ peers: tlsCACerts: pem: | -----BEGIN CERTIFICATE----- - MIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw + MIICFjCCAb2gAwIBAgIUYxHjCF1HdZexrgAM73ec4jdHy8owCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt - Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG + Y2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy - dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR - ynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF + dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE76ubZH/VHJszsYLHVKaUwKBR + UZv8P+Jq6Op5PeBf02JUKPM15DSF9n56RJq+7mrM9zBzPvBsUySFd+rr/BrsW6NF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE - FCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq - m2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd - zQkhznMIF4SBF4k= + FM7HDMehiHl8b92QSMN4Q1FB7JU/MAoGCCqGSM49BAMCA0cAMEQCIH4UJq+qY2OP + 7DzBAwY7woYuy4zoT2kxyiexlix38aY4AiAo+8OKE1wFM+XKLUqI4zzgq2bpg1qb + U5aIsTpdz3N2tg== -----END CERTIFICATE----- grpcOptions: @@ -50,18 +50,18 @@ certificateAuthorities: tlsCACerts: pem: | -----BEGIN CERTIFICATE----- - MIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw + MIICFjCCAb2gAwIBAgIUYxHjCF1HdZexrgAM73ec4jdHy8owCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt - Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG + Y2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy - dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR - ynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF + dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE76ubZH/VHJszsYLHVKaUwKBR + UZv8P+Jq6Op5PeBf02JUKPM15DSF9n56RJq+7mrM9zBzPvBsUySFd+rr/BrsW6NF MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE - FCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq - m2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd - zQkhznMIF4SBF4k= + FM7HDMehiHl8b92QSMN4Q1FB7JU/MAoGCCqGSM49BAMCA0cAMEQCIH4UJq+qY2OP + 7DzBAwY7woYuy4zoT2kxyiexlix38aY4AiAo+8OKE1wFM+XKLUqI4zzgq2bpg1qb + U5aIsTpdz3N2tg== -----END CERTIFICATE----- httpOptions: diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/msp/IssuerPublicKey index e4e39a4683359596c3c6a9ef67aed4995c58c786..4b818bdff2316786cf76dfc740d03a8f011f6363 100644 GIT binary patch delta 810 zcmV+_1J(S?2FnJJE`LZ_J#hJc&X7gIGdp*3JoJsJTiImLbTX?&)Vdnfi$)S4t1BW* z{EEtO9d-cS8#Y=c8BNa%#_O?9H!+1@hWx6#8bk^p635SHg6)9*VuK}L{NraW`fKM# zCajKXHlzJ3LAH015+J~{2Rc-aJ*t&}Jz^RW*1&7f?iKu%<$op18f8Wa2Ul_;L<%54 z1m2B&f`7xo^bWb;>gFOW5b)B0jTc`0{|BK^TjPonAk-#HXu4V-OIcy4!UY=Xqc#Oz zv0aM+kYzdEnO%03VdXppMRfX%Wpttl+uaW z(zZu`bF~+mOnxml^0Q0r5+I_p5_(9@We=vvU_dz(%b3%^mYv z3Lx0#B0Z_5vXs5L0k$J3jLJ=g<*v3+5hxofzE={WRDTH)AXiIl-4X_u&BdpwWObNT zIOD(Ad~ko4lQY4X{j;%72P%jG3Lri^=0axLFv>gx%a1TH3aGhM#7_v*UOlWA)YCIUPnAjSJcrA+~z6sjsCp6r$ok71%d{d$A_8X!_3YG{<| zJTgQIARuwIA~1G9N4Asrvwl-<%=rHK;}8>qfqrYJ9HHpY5E3A{47lQ7Qm3O}JSaZ* z)z3|GDHcD)_*2bdgS%x5YNl#BL<%4b48Ux|m4BeIb6`(Q{+X^=%kti76)boE{SMf` z?OkB65+HPqD}@3~`n{q}T;pa>k)fNt%H1W<^cceON!Y%OAT>fDT$uiP60e5&!J^*D zU6rztq_R{wMnH79G(EZ(vv+s{N+4qiHAzB-+x`#rTWZmC2tNwG0ecdn@Z7C%qU)NA oFC$D+AYsaXP3-9-i<@EMsF8v6BrcHcy6d9WM+|ldQ7xmt>F29~d;kCd delta 810 zcmV+_1J(S?2FnJJE`Q!2;V{_*FQmi?(B>(|!m*0`grhGnnM*iBF}5Q1n7I-lT%rbj zqM!wLuOz{!YRK-)(;uAb%9h2jlsjm-eTq^w8bk^pE7ObR5+D_=KO@xEb{8E*gdKb8MooJ1MM(%-e}B(MD38sIZ1=VzL<%74 z;X+1Q^4M(D0+zGL7J&pGs(N7MA1{SHdKpIdNsf~eApD>`?Ax}u^fxQdUCQ-@v9WV+ z^^!a5NW)>|;=X1pa3VwsAoVY>xeHcgsr;1#mn_2Zi(P&xeB&!x5zE6=hH#aP^b#O| z1G5OGhJ0yNL4S@-LUf79)-0`}_B&|~xOO|6bzr=HB18%x1sF-66GQaHW+t;7yq?Ib zO+UfOxP#6w(DOvfF`49$5+In1y8$FQUSbM$Qsj2W`iA-&T02aIB2^_8X+|K2^B*Ea z3Lvz7BttU%w}vMLj#39++f?~eAZN^_Q?nFwMB~8W$A2XfATJIGK^hR8EBx8jd^|e2 z+_GFq&`%hC1$vI+$U8~tFDi%u3Lqom7zLoYM0n0&8m~n7&1kP!uomSC*1DQM(Dt;D z<>V3|B6~&9tPJt_v8|xO{-2|=YKRRel0Teekckw+TC78H8X)8ut|-s&uYX8att8IQ zD>dY|CVygZl9c{Ky{^|)!zD)|AiSVZxGLs5d_X8B7|4*weDPwUtMT666P`IB7~rDQ z%rZm@AZg*}P;zV9CAoV$;r{_!`u7a&FRp>8#s3EaAOFi*EfOHYCeDDtdDD6hKc4nFL<%6`a0J^OJ%7Qld0NS~87i9&rq6^gFOW5b)B0jTc`0{|BK^TjPonAk-#HXu4V-OIcy4!UY=Xqc#Oz zv0aM+kYzdEnO%03VdXppMRfX%Wpttl+uaW z(zZu`bF~+mOnxml^0Q0r5+I_p5_(9@We=vvU_dz(%b3%^mYv z3Lx0#B0Z_5vXs5L0k$J3jLJ=g<*v3+5hxofzE={WRDTH)AXiIl-4X_u&BdpwWObNT zIOD(Ad~ko4lQY4X{j;%72P%jG3Lri^=0axLFv>gx%a1TH3aGhM#7_v*UOlWA)YCIUPnAjSJcrA+~z6sjsCp6r$ok71%d{d$A_8X!_3YG{<| zJTgQIARuwIA~1G9N4Asrvwl-<%=rHK;}8>qfqrYJ9HHpY5E3A{47lQ7Qm3O}JSaZ* z)z3|GDHcD)_*2bdgS%x5YNl#BL<%4b48Ux|m4BeIb6`(Q{+X^=%kti76)boE{SMf` z?OkB65+HPqD}@3~`n{q}T;pa>k)fNt%H1W<^cceON!Y%OAT>fDT$uiP60e5&!J^*D zU6rztq_R{wMnH79G(EZ(vv+s{N+4qiHAzB-+x`#rTWZmC2tNwG0ecdn@Z7C%qU)NA oFC$D+AYsaXP3-9-i<@EMsF8v6BrcHcy6d9WM+|ldQ7xmt>F29~d;kCd delta 810 zcmV+_1J(S?2FnJJE`Q!2;V{_*FQmi?(B>(|!m*0`grhGnnM*iBF}5Q1n7I-lT%rbj zqM!wLuOz{!YRK-)(;uAb%9h2jlsjm-eTq^w8bk^pE7ObR5+D_=KO@xEb{8E*gdKb8MooJ1MM(%-e}B(MD38sIZ1=VzL<%74 z;X+1Q^4M(D0+zGL7J&pGs(N7MA1{SHdKpIdNsf~eApD>`?Ax}u^fxQdUCQ-@v9WV+ z^^!a5NW)>|;=X1pa3VwsAoVY>xeHcgsr;1#mn_2Zi(P&xeB&!x5zE6=hH#aP^b#O| z1G5OGhJ0yNL4S@-LUf79)-0`}_B&|~xOO|6bzr=HB18%x1sF-66GQaHW+t;7yq?Ib zO+UfOxP#6w(DOvfF`49$5+In1y8$FQUSbM$Qsj2W`iA-&T02aIB2^_8X+|K2^B*Ea z3Lvz7BttU%w}vMLj#39++f?~eAZN^_Q?nFwMB~8W$A2XfATJIGK^hR8EBx8jd^|e2 z+_GFq&`%hC1$vI+$U8~tFDi%u3Lqom7zLoYM0n0&8m~n7&1kP!uomSC*1DQM(Dt;D z<>V3|B6~&9tPJt_v8|xO{-2|=YKRRel0Teekckw+TC78H8X)8ut|-s&uYX8att8IQ zD>dY|CVygZl9c{Ky{^|)!zD)|AiSVZxGLs5d_X8B7|4*weDPwUtMT666P`IB7~rDQ z%rZm@AZg*}P;zV9CAoV$;r{_!`u7a&FRp>8#s3EaAOFi*EfOHYCeDDtdDD6hKc4nFL<%6`a0J^OJ%7Qld0NS~87i9&rq6^gFOW5b)B0jTc`0{|BK^TjPonAk-#HXu4V-OIcy4!UY=Xqc#Oz zv0aM+kYzdEnO%03VdXppMRfX%Wpttl+uaW z(zZu`bF~+mOnxml^0Q0r5+I_p5_(9@We=vvU_dz(%b3%^mYv z3Lx0#B0Z_5vXs5L0k$J3jLJ=g<*v3+5hxofzE={WRDTH)AXiIl-4X_u&BdpwWObNT zIOD(Ad~ko4lQY4X{j;%72P%jG3Lri^=0axLFv>gx%a1TH3aGhM#7_v*UOlWA)YCIUPnAjSJcrA+~z6sjsCp6r$ok71%d{d$A_8X!_3YG{<| zJTgQIARuwIA~1G9N4Asrvwl-<%=rHK;}8>qfqrYJ9HHpY5E3A{47lQ7Qm3O}JSaZ* z)z3|GDHcD)_*2bdgS%x5YNl#BL<%4b48Ux|m4BeIb6`(Q{+X^=%kti76)boE{SMf` z?OkB65+HPqD}@3~`n{q}T;pa>k)fNt%H1W<^cceON!Y%OAT>fDT$uiP60e5&!J^*D zU6rztq_R{wMnH79G(EZ(vv+s{N+4qiHAzB-+x`#rTWZmC2tNwG0ecdn@Z7C%qU)NA oFC$D+AYsaXP3-9-i<@EMsF8v6BrcHcy6d9WM+|ldQ7xmt>F29~d;kCd delta 810 zcmV+_1J(S?2FnJJE`Q!2;V{_*FQmi?(B>(|!m*0`grhGnnM*iBF}5Q1n7I-lT%rbj zqM!wLuOz{!YRK-)(;uAb%9h2jlsjm-eTq^w8bk^pE7ObR5+D_=KO@xEb{8E*gdKb8MooJ1MM(%-e}B(MD38sIZ1=VzL<%74 z;X+1Q^4M(D0+zGL7J&pGs(N7MA1{SHdKpIdNsf~eApD>`?Ax}u^fxQdUCQ-@v9WV+ z^^!a5NW)>|;=X1pa3VwsAoVY>xeHcgsr;1#mn_2Zi(P&xeB&!x5zE6=hH#aP^b#O| z1G5OGhJ0yNL4S@-LUf79)-0`}_B&|~xOO|6bzr=HB18%x1sF-66GQaHW+t;7yq?Ib zO+UfOxP#6w(DOvfF`49$5+In1y8$FQUSbM$Qsj2W`iA-&T02aIB2^_8X+|K2^B*Ea z3Lvz7BttU%w}vMLj#39++f?~eAZN^_Q?nFwMB~8W$A2XfATJIGK^hR8EBx8jd^|e2 z+_GFq&`%hC1$vI+$U8~tFDi%u3Lqom7zLoYM0n0&8m~n7&1kP!uomSC*1DQM(Dt;D z<>V3|B6~&9tPJt_v8|xO{-2|=YKRRel0Teekckw+TC78H8X)8ut|-s&uYX8att8IQ zD>dY|CVygZl9c{Ky{^|)!zD)|AiSVZxGLs5d_X8B7|4*weDPwUtMT666P`IB7~rDQ z%rZm@AZg*}P;zV9CAoV$;r{_!`u7a&FRp>8#s3EaAOFi*EfOHYCeDDtdDD6hKc4nFL<%6`a0J^OJ%7Qld0NS~87i9&rq6^gFOW5b)B0jTc`0{|BK^TjPonAk-#HXu4V-OIcy4!UY=Xqc#Oz zv0aM+kYzdEnO%03VdXppMRfX%Wpttl+uaW z(zZu`bF~+mOnxml^0Q0r5+I_p5_(9@We=vvU_dz(%b3%^mYv z3Lx0#B0Z_5vXs5L0k$J3jLJ=g<*v3+5hxofzE={WRDTH)AXiIl-4X_u&BdpwWObNT zIOD(Ad~ko4lQY4X{j;%72P%jG3Lri^=0axLFv>gx%a1TH3aGhM#7_v*UOlWA)YCIUPnAjSJcrA+~z6sjsCp6r$ok71%d{d$A_8X!_3YG{<| zJTgQIARuwIA~1G9N4Asrvwl-<%=rHK;}8>qfqrYJ9HHpY5E3A{47lQ7Qm3O}JSaZ* z)z3|GDHcD)_*2bdgS%x5YNl#BL<%4b48Ux|m4BeIb6`(Q{+X^=%kti76)boE{SMf` z?OkB65+HPqD}@3~`n{q}T;pa>k)fNt%H1W<^cceON!Y%OAT>fDT$uiP60e5&!J^*D zU6rztq_R{wMnH79G(EZ(vv+s{N+4qiHAzB-+x`#rTWZmC2tNwG0ecdn@Z7C%qU)NA oFC$D+AYsaXP3-9-i<@EMsF8v6BrcHcy6d9WM+|ldQ7xmt>F29~d;kCd delta 810 zcmV+_1J(S?2FnJJE`Q!2;V{_*FQmi?(B>(|!m*0`grhGnnM*iBF}5Q1n7I-lT%rbj zqM!wLuOz{!YRK-)(;uAb%9h2jlsjm-eTq^w8bk^pE7ObR5+D_=KO@xEb{8E*gdKb8MooJ1MM(%-e}B(MD38sIZ1=VzL<%74 z;X+1Q^4M(D0+zGL7J&pGs(N7MA1{SHdKpIdNsf~eApD>`?Ax}u^fxQdUCQ-@v9WV+ z^^!a5NW)>|;=X1pa3VwsAoVY>xeHcgsr;1#mn_2Zi(P&xeB&!x5zE6=hH#aP^b#O| z1G5OGhJ0yNL4S@-LUf79)-0`}_B&|~xOO|6bzr=HB18%x1sF-66GQaHW+t;7yq?Ib zO+UfOxP#6w(DOvfF`49$5+In1y8$FQUSbM$Qsj2W`iA-&T02aIB2^_8X+|K2^B*Ea z3Lvz7BttU%w}vMLj#39++f?~eAZN^_Q?nFwMB~8W$A2XfATJIGK^hR8EBx8jd^|e2 z+_GFq&`%hC1$vI+$U8~tFDi%u3Lqom7zLoYM0n0&8m~n7&1kP!uomSC*1DQM(Dt;D z<>V3|B6~&9tPJt_v8|xO{-2|=YKRRel0Teekckw+TC78H8X)8ut|-s&uYX8att8IQ zD>dY|CVygZl9c{Ky{^|)!zD)|AiSVZxGLs5d_X8B7|4*weDPwUtMT666P`IB7~rDQ z%rZm@AZg*}P;zV9CAoV$;r{_!`u7a&FRp>8#s3EaAOFi*EfOHYCeDDtdDD6hKc4nFL<%6`a0J^OJ%7Qld0NS~87i9&rq6^gFOW5b)B0jTc`0{|BK^TjPonAk-#HXu4V-OIcy4!UY=Xqc#Oz zv0aM+kYzdEnO%03VdXppMRfX%Wpttl+uaW z(zZu`bF~+mOnxml^0Q0r5+I_p5_(9@We=vvU_dz(%b3%^mYv z3Lx0#B0Z_5vXs5L0k$J3jLJ=g<*v3+5hxofzE={WRDTH)AXiIl-4X_u&BdpwWObNT zIOD(Ad~ko4lQY4X{j;%72P%jG3Lri^=0axLFv>gx%a1TH3aGhM#7_v*UOlWA)YCIUPnAjSJcrA+~z6sjsCp6r$ok71%d{d$A_8X!_3YG{<| zJTgQIARuwIA~1G9N4Asrvwl-<%=rHK;}8>qfqrYJ9HHpY5E3A{47lQ7Qm3O}JSaZ* z)z3|GDHcD)_*2bdgS%x5YNl#BL<%4b48Ux|m4BeIb6`(Q{+X^=%kti76)boE{SMf` z?OkB65+HPqD}@3~`n{q}T;pa>k)fNt%H1W<^cceON!Y%OAT>fDT$uiP60e5&!J^*D zU6rztq_R{wMnH79G(EZ(vv+s{N+4qiHAzB-+x`#rTWZmC2tNwG0ecdn@Z7C%qU)NA oFC$D+AYsaXP3-9-i<@EMsF8v6BrcHcy6d9WM+|ldQ7xmt>F29~d;kCd delta 810 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 literal 13399 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 literal 17142 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 delta 810 zcmV+_1J(S?2FnJJE`ROR1&!K}?uia_x8QOc<977(X2n;yZg>>Zyw(NUeC-k-k%Tvp z2ZJCL+|*gO8(CtSY$~e~AQ-L?=qXqihGosfwD1YW5gfbY zfz&PBKC0PYV1fQ9kRn71An3t0!~H9GT7kgvL}618zN+=%BdrrKmNuL$Atc@#!XU4cgtbE8#p}o18M$@>+7t$g` z3Luod`Ne^AqO-#F(iBkTSb~L{e!T1cSS$(j=uv!Wr+V~}S z`Rm4HZhmbLVZ->rfr{Ns8Y+kZ3Luhmm(W8 z&m6b$jsF2$_L<%70T{!5a>wif>hJ9(zm$z`@e4vtSQwB`a=?Hb| zf8hwG5+KBKAqsv5v_9Wx~buvKB136k5!*`4D8@z(Q&o zCF!_0*U?DUo8_%1zFmIl;}@=YwM~1GwRDk%v3ODkW__v(sn!nr1uqC$ZBrxspszt1 zAekQ3i&8SsygF8>P_I=Kl7%V` z*^HzG)=W&-=Dmtdw~dQ$@8kSs&=|HQ!)iKrr}|bX*ga! z^~`f(+a?4K36pL?c2=W)MMv0yxwN>9XhbqY3N)m-Qr;cPj78TQtdq;Dxn|gCHWCVN zG0CmLtl2Q_Zuy;Oer2|Tfv2jqh9+b}qK##S9k-JfSDh`=rKLk zbF4j#l3^vybXr8TNe@=@+>a;ZW|XwYJ)b1kL$nwqt#0}2PeBf51Bb#%+;%(*r?!G% zxJNiBWm~@OSsuV~42FHn{jh@l;M1oLjJz;Li%nuVtI(dU8)=p$s9^S6IJmoDuYKlw zMkkq313d~?3Ys+6Jk}AC#Hh0>M^ZAuBmru6Z_Lj2*C4~?x#)bj7@_ZFLq`k35s8Oxj4Ct70Bbs(dq+jd8 zVkPbB=1NzRK}1YZs)~(sDUha{4N?qk+$ySYD_+})A}DQd%)?@L-s~`oiG>iTE?}m7 zwQ}k9#kaYqSiYx9b%~`_{?1(G<%>rixp4jZiL-|fKlj{ME*!&b406!z$|!~77U@y0 zjX1VPA~xki5CvezwqYB1#J1lsf<%GsJ0C)1^a=n~0JisXWKdOS!m{)z3g}#7=s?n} z7aaX@`Mja3N^8^# zg_?+_w2q87byq{-RFvk4?-7+~Sp*@h$XQD-XgHHo9yB|ZB}sCt6xX;> zPpgMQlNXeXl=~}fyDt*&28iXW*tRj@HLampNQ2tMkXsuC539@3fS*%05%{T;M*`tz!>S{DC)sD1mQkPxxVfAhZcIzU)0{;%YLNp zap;2GJ7quWf7}D=b`OrdZ&O|UfL(QBXJ==3cd>K)mk<4Eck#w6?(Tg{y>F@ioq_IK z>U~SSZ>j$`OYJ=U;9EP#+Yi2V^Yp2oKX~}^?C2vGu5I~hi&tN*9g7#Px9}G9?NIg+ zTkLye9_mW@qQP9;Y@uqJ{0pj>W|xBsLDA?*l}1*X9tuP>Gmy)nD7eKYssk~~2CeowJUd(^ zQcfrPSXYMYu0L&mp#1X*^NmA?miaC# zvF+}Mw@Oy0??cMBQ?016HQG|dE?`F4x~@t~%3BVEG;Sg(0;BT*HK-uW zaBNR_bEV~Ztu5=RGLJo?h%w%8L0NZ#P*Sjt0@C6}EIY3TZoPQ*`A})B2D!kx;%Z!g z!1!oVF<$eGeAu2w-^C)33lN4X{@ zb#K1&!o~TKU)((T=GXT>23>Z&xwTkD+k*@^UIfr%d*$zLJ$`(5@9c?fJ8#Dil;67b z_`#8XjN!_b$Bypb*xCQ>{!jOB?EiWHoh??swqM@(!$Y6_k77s9>|Q!@yTZS%0PQ`z Wd-l%c?)HH*#~yfS_w4Oe;J*RyhP(g( delta 4593 zcmeHLU8vjU89wPr(#C0Wl96;RX_La*rqn&h(x?AY*6GKxWLuUk%a-LXU8GNcmTcL_ zk}TO5OK%2cu$EO&*v%LW2BXlW&F%*qyWMutU9Hf-*wrpJ*kFS(HlJ)O8}uh#dzs7k zlk|Qc-^24h&!d-b@4kF{_vVi-5dqhl&F#!?3tnJu_+dQ+rmu+{%5OgU*tnJPQFuhu)F2^Rj z?1w#4#`+1w%od!Djl}!m1vIkGA`K6#xqCZ=mv`p969fq3TLrm2k*I@SENN?J5;l65}l>Z z_to_{8-aK_V!r$?GvbliUrf&%44%!jJHJ{G;%Sjxfwe zdikyW>t*E`&ght07bvwRXl0S!j)o0Jh=JkPV$7KCz-x*4MrQQ%&!{>CjF8L$chNgkJ>poC*3*=Fl%wGU=JtJQ-jD zuJ)Qrzuqfa0Z%?NX~Vo7Oo8$%_sl?kX%MzKLHW*RnL84ezIYu2LP)R1-DEMGea zB|Po3b1v1VT|OfRT?|Tcs?tNRn!sGjO`$T>kdWj2T%5B5EZ}gl*1#HKiX~ARMj%a^ zGS!?BgOaUr<&CeM8g~<%+n935B(-U#%qtdBUE4%R^Bcbp43%G*WN*?6QZY{hcETdH zda*!|sIUerIP)W_*=5q9Ym$eIyrPy&T3Jj2dl8bkx#jC4<=<+jAMEe!y?OSBXa8}w zzc;vb{yKa1#^Ct1YsUxz!w5j5B!Co#q6`8_+CvH2LMYdEX&OTv(!-s*M*PH`u9!oU z1b~E1I3DUbsO8cmYM~6+PHq|p7>3x?4HTue!{Y8H`tdt$KUbZ&u@#ElJ8eJjQFfoc zz1dTr#HBBPS~8v4+1c6MjdxD}^8P>V#&3W7`aSWyC!QZ?cO_zXrt=B*>DAFYLp4r4bz=6&t@qE-y19x+w9la0 zJk3IG5>`y0Iy{lJ$Tb{An@uy<60cQPGT#phR?vjDGtZTQGLmHn8G@QYx07rdmv5L~ zk;E3U5TJph@uH&DCMsD2k| zG#_Hhp)i_rt9Tm=Ha=0ORSnH?n~Mz)E*(9ttQ$b-P7O7uPB=z z>+Miot0~2&TsR*Oz+i+`PHMbiqM&w~iPJ*ySgZw|hRqiT`{`jSL z$6eU6c&#TU%TXnB$A@#&^RQx4R}Kx$RvS8so9&64tt~Z4wrRAA=$uy_iK$Uz^RCLQ zm|_UTQKC5m(yXjyu(Bc7<%=cl9;MNDuAf;P`{}K-zxvKz`MdYOaQgW1i)Xg9^ufcs z<@erygt+hc{>7sjJ#gHGwM=K*e-Y?W{lKw*zlm11&g#V8&7Hl!?)`S}7kfY7ySa79 s-`y*3{^9;Fg8%;P!~?q*j~(?szI}G#^6rJ*{iE`KTHkm7?!Wf?CwSAExc~qF diff --git a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/117fbb29176584efb8df9c8370950584b74dce5a32ffd6ab7b438b0d86ed3f5e_sk b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/117fbb29176584efb8df9c8370950584b74dce5a32ffd6ab7b438b0d86ed3f5e_sk deleted file mode 100644 index 9936475d6..000000000 --- a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/117fbb29176584efb8df9c8370950584b74dce5a32ffd6ab7b438b0d86ed3f5e_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgQ2QHBuM0PvN++zpH -VYiYU20yiV3Q31QtIJrJ4IkiulihRANCAASLibMteLO1DZewi+Yw1pdALblQZQGr -xla3aOZ8iN9CSHv62G3/CDm2ixqddr/1IK8AmGdCwJB31K6UKcrqve3e ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/3db8e1f785d24ba97583a0d2a3d23c2aad6410f31007d63835fadb159cbcb3d9_sk b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/3db8e1f785d24ba97583a0d2a3d23c2aad6410f31007d63835fadb159cbcb3d9_sk deleted file mode 100644 index de2a10153..000000000 --- a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/3db8e1f785d24ba97583a0d2a3d23c2aad6410f31007d63835fadb159cbcb3d9_sk +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgoEVc3zfLTlzULb3J -rV/Dnuq0A07c2erKzBv94eSSUCqhRANCAAS69sW7HSGsJEMOh7BJ6bKaGdTW5AZL -Mpo4yxCJtXJk3eRxr7RIL31H6KuD1g6knW7pmR3ZvWd4nP/apEJR0ynJ ------END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/IssuerRevocationPrivateKey b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/IssuerRevocationPrivateKey index 68510547f..2b193341f 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/IssuerRevocationPrivateKey +++ b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/IssuerRevocationPrivateKey @@ -1,6 +1,6 @@ -----BEGIN PRIVATE KEY----- -MIGkAgEBBDAlx91bX713QWrjTlqRRV1xF9y3EhGC+TI8hNI9NShEuxeWKyMcxQSD -6ckxyc4z0nagBwYFK4EEACKhZANiAAQSXuNwB5RFwMTYyLJzR/Jg+ZRPX/uGc/A1 -y+elOPJVpsr2dNupdNSFeLnBqlYG2bUCvCEUnsRhf3NXeKfN+IXIJ4pROgOVz1pR -9tKwjRqEliF7jtKyM5R9UM32hTwKGlg= +MIGkAgEBBDBtnYgK61JzblNKAiAWzjWkJLjRiKqwnPMQcf7bjxwm1LnACLvR2bf9 +faaWp20ALragBwYFK4EEACKhZANiAAT1LI5Ks1qfR2nXnulXnjjgM4Dr/SF+kttd +rHdUnAPjoXklMZL7LAHSVrfUzizTk0JJKFbYzrlDBzaKh5lBYtOY4GRC3InXLNyu +4JdIIsmMfCd1Ij2NOZ0CsuZkip4kgPE= -----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/IssuerSecretKey b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/IssuerSecretKey index abf3c82cf..78edf5cd6 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/IssuerSecretKey +++ b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/IssuerSecretKey @@ -1 +1 @@ -Ì8Ä Š8×]¹E•ó0û6]\Ÿ¸n/Wr öm-6º \ No newline at end of file +Ï÷Ó >ÍÇÅLLjÍPÑR Á¿Sº«bäC÷@ \ No newline at end of file diff --git a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/c8e7c3ec740c26225a50644bd7e0ec1fce62dc8991c442652758229b6e3dedce_sk b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/c8e7c3ec740c26225a50644bd7e0ec1fce62dc8991c442652758229b6e3dedce_sk new file mode 100644 index 000000000..ccd08eb44 --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/c8e7c3ec740c26225a50644bd7e0ec1fce62dc8991c442652758229b6e3dedce_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgX4ILc8gdngRW7yLI +XzJQ0yoo8U1zoV2ckbVXFl5AtNehRANCAATTPLhLlG/H4uAV3izFdU42uHIpqfe7 +msygl2PMvLPZ0NJoV1WJeEUtaoV6fpac6EvqmHdPiMCAH4KIbK0A2LWs +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/f55d5b0330bca287938b240a76ef683613c0c10b38390fe6bbd055ae4bad202c_sk b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/f55d5b0330bca287938b240a76ef683613c0c10b38390fe6bbd055ae4bad202c_sk new file mode 100644 index 000000000..70ac69761 --- /dev/null +++ b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/msp/keystore/f55d5b0330bca287938b240a76ef683613c0c10b38390fe6bbd055ae4bad202c_sk @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg2qMqTm1Dx+uiQq+b +2HSqPLCMKzHRqfrcKfN8f8z+AvGhRANCAARhjTKG7fy8CdilJoQG38H6VSdej4UV +y1lhPZFPQf3+Sp5S/xNuyuRL2xdRbUAJ0VWeCqbHrsJa8rXb0dHcKhvB +-----END PRIVATE KEY----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/tls-cert.pem b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/tls-cert.pem index ff6495f2e..a0e0fccde 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/tls-cert.pem +++ b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/ordererOrg/tls-cert.pem @@ -1,16 +1,16 @@ -----BEGIN CERTIFICATE----- -MIICczCCAhmgAwIBAgIUKclI/O8Zwt2lXD6MuSu3df5Kfi4wCgYIKoZIzj0EAwIw +MIICcjCCAhmgAwIBAgIUao6ds8voO58RkCy7Kw5waVeEC/wwCgYIKoZIzj0EAwIw aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt -Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDQwMFoXDTIzMDgwNDA2MDQwMFowZDELMAkG +Y2Etc2VydmVyMB4XDTIyMDgwNDE4MjQwMFoXDTMyMDgwNDA2MjQwMFowZDELMAkG A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl -cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRUwEwYDVQQDEwxmODFiNzBjNWY5N2Ew -WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS69sW7HSGsJEMOh7BJ6bKaGdTW5AZL -Mpo4yxCJtXJk3eRxr7RIL31H6KuD1g6knW7pmR3ZvWd4nP/apEJR0ynJo4GkMIGh +cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRUwEwYDVQQDEww1YjUxYzRjODM0OTYw +WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATTPLhLlG/H4uAV3izFdU42uHIpqfe7 +msygl2PMvLPZ0NJoV1WJeEUtaoV6fpac6EvqmHdPiMCAH4KIbK0A2LWso4GkMIGh MA4GA1UdDwEB/wQEAwIDqDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw -DAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU4tSAoBtTlPCu6UP3cHItO8Vf+scwHwYD -VR0jBBgwFoAU3hB4F/G3GFt3sktjk2tsJI7Jm5UwIgYDVR0RBBswGYIMNGZlNjI0 -ZmZmZmQwgglsb2NhbGhvc3QwCgYIKoZIzj0EAwIDSAAwRQIhAPs4BzYIj9s/luMo -a0+yb5j8CzgS2WOCvY6QiKhtFwthAiA0/Exp00kxaUvcmgk7JP9tVeY6q9Iv7r9t -pihbpj6wYA== +DAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUrl4VnFx60w4bSykmhUOsafb6ZXgwHwYD +VR0jBBgwFoAUkJzAy2lRZvi+EbJ6uPBpecolltAwIgYDVR0RBBswGYIMNGZlNjI0 +ZmZmZmQwgglsb2NhbGhvc3QwCgYIKoZIzj0EAwIDRwAwRAIgbPoDBY7hYnMuE0KO +s88Dtu6UDhRUFlGKEGPv8MStUeECIEdg3afT5bce2xAU4vlA0/jWMLzP6l+shXEn +Fofub0hX -----END CERTIFICATE----- diff --git a/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/IssuerPublicKey b/tests/network-setups/fabric/network-artifacts/network2/fabric-ca/org1/IssuerPublicKey index d1b268697b562f4ffa0c3225185168fcf16d995c..ae08bee1de47ab4d4d4c2ad21a71ca2018fe94a8 100644 GIT binary patch delta 810 zcmV+_1J(S?2FnJJE`RIY*UGQp1a-KEY7nZ`lJ2Sf=fW7|Io4e7ewrU@D z-dSx6RWOhCzz03o5+Ls$!u`zG;gOOZ<7N@r;)8?Gbw`T;4}UpTm;lxgHB+u4L<%5Z zrLAzwOY@5))TJKdh$y%^A3V5RgU0dr1_6fkO8Q|EAgZ8(c{xu4?o|iB$WcjpWV{oL_<<7s?@J zeee<>yd{n%_j8V$oy;l+3i6q9c)24yiddgkIjq(8Qu&DS8X$7q9EC?0kVr3`j}4g& z4#dE49e;<$cZa>ujKhYv|E^XdAVMkSa#Z+a-*IK*SZafmA~jY)Sy4`rXjY~vKNxx$ zBr-$_AU%tdQG2MfLV_h<+@oAkiLd&*R3;&neUZ^6A-A=7eG(uBI9&vEu^+x`PL=W+ zLfPI;p5WS1wcg}?9#J9nvc8u(L<%50{9?x4Tz}2Brsu$o!j!@Z+;B)Ls_xHT6yB^w z1OK(<5+L%s>z9C}V`=w(UjtgnoTY2u?;`W5u`wI3^cK>0?ae|U8na60R-lr>MH|p( zCzC3#o0(w=Kmg<$OLup84ZeCtN+1fl{F@jbg|nr2DlUhEWv@pw9<{e=^4dplRDhh; o*CT0CAd?7;st6~Wwt^jMcA>w%utg+{mMp5j*U}cIH>R(Rm6dLQ$^ZZW delta 810 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 i9vFr-G>D-a*DI literal 65536 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 delta 810 zcmV+_1J(S?2FnJJE`ROR1&!K}?uia_x8QOc<977(X2n;yZg>>Zyw(NUeC-k-k%Tvp z2ZJCL+|*gO8(CtSY$~e~AQ-L?=qXqihGosfwD1YW5gfbY zfz&PBKC0PYV1fQ9kRn71An3t0!~H9GT7kgvL}618zN+=%BdrrKmNuL$Atc@#!XU4cgtbE8#p}o18M$@>+7t$g` z3Luod`Ne^AqO-#F(iBkTSb~L{e!T1cSS$(j=uv!Wr+V~}S z`Rm4HZhmbLVZ->rfr{Ns8Y+kZ3Luhmm(W8 z&m6b$jsF2$_L<%70T{!5a>wif>hJ9(zm$z`@e4vtSQwB`a=?Hb| zf8hwG5+KBKAqsvXZ>Ul|yl;>MgiFDz+&|D~mdbN<+;2yyn08bk^p;L%%y3+otEr`_rhj0>F`>owaTX^cL<%6^ zDLty#ZrYL#3Ff2>oghs;baXE-cxGXriLy}A=j!YdAaPS|)0<)J2fMa*oExwg;Oar& zvewL1hoEgK4p-6VGa^I^Adbio4<3>HQOlx2VJh-TGmmVz+m5;Rb3>;L`@=ltUlJg+ z1WLZR?FDb(PJj4~`a7Wll9lo+mY@Ap{9Lcu!I|>cB18%xzlV&j(5keQkF#Nsz)(g` zV!EZX?BE1%4qrv!3F9{}5+J@pMli&G9hG1~N4HpGB^ezkQ)as4+4>(}MwaF%UebYO@Fu&Anv5(^ZTSw{TW$e*b!OA zw2l;nihBU60ua}zcpKutd@6_m3LptXJMvsA-p+OlHr83*b4=iT-=^C?CI6A^942l% ztXUEu9X2A*&y_w(Tz39NJpz!CR<~~PYzoLCDU8^;t+H{s8Xz_k5)HLE39h&s(?pPZ z`p3gYy?;XR##v(^0NPx%FIy@iAVv{pCY_e%KmTa8hmQ*-BKM#rm&&+0c-q^M@kn(( z;4(xCAQW}wcd^JO;@c9pD0gBDvBHH!x_dcwCqtre7?DT-6cQjt%6xaBc8>s*E)>qc zc`BM#u#PdP6#=?#3>ftIyfjKWL<%6hi&YbYZGVE;I~*;8>Iz*#nyO}AF8a3y%BwNiu_!_(sZ;$5=q81?7HkX o9V7fwAP$us{94i*7oBY0GUrRI9d$Zuj;iA87{AKW8!e{lmqX`z(EtDd delta 810 zcmV+_1J(S?2FnJJE`ROR1&!K}?uia_x8QOc<977(X2n;yZg>>Zyw(NUeC-k-k%Tvp z2ZJCL+|*gO8(CtSY$~e~AQ-L?=qXqihGosfwD1YW5gfbY zfz&PBKC0PYV1fQ9kRn71An3t0!~H9GT7kgvL}618zN+=%BdrrKmNuL$Atc@#!XU4cgtbE8#p}o18M$@>+7t$g` z3Luod`Ne^AqO-#F(iBkTSb~L{e!T1cSS$(j=uv!Wr+V~}S z`Rm4HZhmbLVZ->rfr{Ns8Y+kZ3Luhmm(W8 z&m6b$jsF2$_L<%70T{!5a>wif>hJ9(zm$z`@e4vtSQwB`a=?Hb| zf8hwG5+KBKAqsvXZ>Ul|yl;>MgiFDz+&|D~mdbN<+;2yyn08bk^p;L%%y3+otEr`_rhj0>F`>owaTX^cL<%6^ zDLty#ZrYL#3Ff2>oghs;baXE-cxGXriLy}A=j!YdAaPS|)0<)J2fMa*oExwg;Oar& zvewL1hoEgK4p-6VGa^I^Adbio4<3>HQOlx2VJh-TGmmVz+m5;Rb3>;L`@=ltUlJg+ z1WLZR?FDb(PJj4~`a7Wll9lo+mY@Ap{9Lcu!I|>cB18%xzlV&j(5keQkF#Nsz)(g` zV!EZX?BE1%4qrv!3F9{}5+J@pMli&G9hG1~N4HpGB^ezkQ)as4+4>(}MwaF%UebYO@Fu&Anv5(^ZTSw{TW$e*b!OA zw2l;nihBU60ua}zcpKutd@6_m3LptXJMvsA-p+OlHr83*b4=iT-=^C?CI6A^942l% ztXUEu9X2A*&y_w(Tz39NJpz!CR<~~PYzoLCDU8^;t+H{s8Xz_k5)HLE39h&s(?pPZ z`p3gYy?;XR##v(^0NPx%FIy@iAVv{pCY_e%KmTa8hmQ*-BKM#rm&&+0c-q^M@kn(( z;4(xCAQW}wcd^JO;@c9pD0gBDvBHH!x_dcwCqtre7?DT-6cQjt%6xaBc8>s*E)>qc zc`BM#u#PdP6#=?#3>ftIyfjKWL<%6hi&YbYZGVE;I~*;8>Iz*#nyO}AF8a3y%BwNiu_!_(sZ;$5=q81?7HkX o9V7fwAP$us{94i*7oBY0GUrRI9d$Zuj;iA87{AKW8!e{lmqX`z(EtDd delta 810 zcmV+_1J(S?2FnJJE`ROR1&!K}?uia_x8QOc<977(X2n;yZg>>Zyw(NUeC-k-k%Tvp z2ZJCL+|*gO8(CtSY$~e~AQ-L?=qXqihGosfwD1YW5gfbY zfz&PBKC0PYV1fQ9kRn71An3t0!~H9GT7kgvL}618zN+=%BdrrKmNuL$Atc@#!XU4cgtbE8#p}o18M$@>+7t$g` z3Luod`Ne^AqO-#F(iBkTSb~L{e!T1cSS$(j=uv!Wr+V~}S z`Rm4HZhmbLVZ->rfr{Ns8Y+kZ3Luhmm(W8 z&m6b$jsF2$_L<%70T{!5a>wif>hJ9(zm$z`@e4vtSQwB`a=?Hb| zf8hwG5+KBKAqsvXZ>Ul|yl;>MgiFDz+&|D~mdbN<+;2yyn08bk^p;L%%y3+otEr`_rhj0>F`>owaTX^cL<%6^ zDLty#ZrYL#3Ff2>oghs;baXE-cxGXriLy}A=j!YdAaPS|)0<)J2fMa*oExwg;Oar& zvewL1hoEgK4p-6VGa^I^Adbio4<3>HQOlx2VJh-TGmmVz+m5;Rb3>;L`@=ltUlJg+ z1WLZR?FDb(PJj4~`a7Wll9lo+mY@Ap{9Lcu!I|>cB18%xzlV&j(5keQkF#Nsz)(g` zV!EZX?BE1%4qrv!3F9{}5+J@pMli&G9hG1~N4HpGB^ezkQ)as4+4>(}MwaF%UebYO@Fu&Anv5(^ZTSw{TW$e*b!OA zw2l;nihBU60ua}zcpKutd@6_m3LptXJMvsA-p+OlHr83*b4=iT-=^C?CI6A^942l% ztXUEu9X2A*&y_w(Tz39NJpz!CR<~~PYzoLCDU8^;t+H{s8Xz_k5)HLE39h&s(?pPZ z`p3gYy?;XR##v(^0NPx%FIy@iAVv{pCY_e%KmTa8hmQ*-BKM#rm&&+0c-q^M@kn(( z;4(xCAQW}wcd^JO;@c9pD0gBDvBHH!x_dcwCqtre7?DT-6cQjt%6xaBc8>s*E)>qc zc`BM#u#PdP6#=?#3>ftIyfjKWL<%6hi&YbYZGVE;I~*;8>Iz*#nyO}AF8a3y%BwNiu_!_(sZ;$5=q81?7HkX o9V7fwAP$us{94i*7oBY0GUrRI9d$Zuj;iA87{AKW8!e{lmqX`z(EtDd delta 810 zcmV+_1J(S?2FnJJE`ROR1&!K}?uia_x8QOc<977(X2n;yZg>>Zyw(NUeC-k-k%Tvp z2ZJCL+|*gO8(CtSY$~e~AQ-L?=qXqihGosfwD1YW5gfbY zfz&PBKC0PYV1fQ9kRn71An3t0!~H9GT7kgvL}618zN+=%BdrrKmNuL$Atc@#!XU4cgtbE8#p}o18M$@>+7t$g` z3Luod`Ne^AqO-#F(iBkTSb~L{e!T1cSS$(j=uv!Wr+V~}S z`Rm4HZhmbLVZ->rfr{Ns8Y+kZ3Luhmm(W8 z&m6b$jsF2$_L<%70T{!5a>wif>hJ9(zm$z`@e4vtSQwB`a=?Hb| zf8hwG5+KBKAqsve7ewrU@D z-dSx6RWOhCzz03o5+Ls$!u`zG;gOOZ<7N@r;)8?Gbw`T;4}UpTm;lxgHB+u4L<%5Z zrLAzwOY@5))TJKdh$y%^A3V5RgU0dr1_6fkO8Q|EAgZ8(c{xu4?o|iB$WcjpWV{oL_<<7s?@J zeee<>yd{n%_j8V$oy;l+3i6q9c)24yiddgkIjq(8Qu&DS8X$7q9EC?0kVr3`j}4g& z4#dE49e;<$cZa>ujKhYv|E^XdAVMkSa#Z+a-*IK*SZafmA~jY)Sy4`rXjY~vKNxx$ zBr-$_AU%tdQG2MfLV_h<+@oAkiLd&*R3;&neUZ^6A-A=7eG(uBI9&vEu^+x`PL=W+ zLfPI;p5WS1wcg}?9#J9nvc8u(L<%50{9?x4Tz}2Brsu$o!j!@Z+;B)Ls_xHT6yB^w z1OK(<5+L%s>z9C}V`=w(UjtgnoTY2u?;`W5u`wI3^cK>0?ae|U8na60R-lr>MH|p( zCzC3#o0(w=Kmg<$OLup84ZeCtN+1fl{F@jbg|nr2DlUhEWv@pw9<{e=^4dplRDhh; o*CT0CAd?7;st6~Wwt^jMcA>w%utg+{mMp5j*U}cIH>R(Rm6dLQ$^ZZW delta 810 zcmV+_1J(S?2FnJJE`N#a;&)_mGXg@wj6;)Ry#{@rif%k%LcsG~4 z%ydcl{*&m@(hhUAnj%CBAj4BtxSaX^qQL7TKh>a^t^GE+@DC8Iu04%Axl-qEh!P-J zc`~EwAaxfkI)DCU4XYx9EUmZou09nq!X;dUg?z*HB18%xuQf1-?CG&pq#!&03}=Xw z`1K$u9+Gicg)Lq4_|B8h5+MHAVq-%FN(nb=?68`C=zL;&#sQT)yu3u&aB?xKL6ssz z3LswjVN>d{E9uR48)9iG8X!#Bu*C+an_g%Zy(dZl z#L9*u9Di%OtjXVh-&e2runlk`AWlnm`*=dk?4MQrZi^qc>lpo*7I9DPe0WwKtn!l+ za56*+Ad6oMUt>IcgL<%5ta%8=qet(iQ(7Ae7ewrU@D z-dSx6RWOhCzz03o5+Ls$!u`zG;gOOZ<7N@r;)8?Gbw`T;4}UpTm;lxgHB+u4L<%5Z zrLAzwOY@5))TJKdh$y%^A3V5RgU0dr1_6fkO8Q|EAgZ8(c{xu4?o|iB$WcjpWV{oL_<<7s?@J zeee<>yd{n%_j8V$oy;l+3i6q9c)24yiddgkIjq(8Qu&DS8X$7q9EC?0kVr3`j}4g& z4#dE49e;<$cZa>ujKhYv|E^XdAVMkSa#Z+a-*IK*SZafmA~jY)Sy4`rXjY~vKNxx$ zBr-$_AU%tdQG2MfLV_h<+@oAkiLd&*R3;&neUZ^6A-A=7eG(uBI9&vEu^+x`PL=W+ zLfPI;p5WS1wcg}?9#J9nvc8u(L<%50{9?x4Tz}2Brsu$o!j!@Z+;B)Ls_xHT6yB^w z1OK(<5+L%s>z9C}V`=w(UjtgnoTY2u?;`W5u`wI3^cK>0?ae|U8na60R-lr>MH|p( zCzC3#o0(w=Kmg<$OLup84ZeCtN+1fl{F@jbg|nr2DlUhEWv@pw9<{e=^4dplRDhh; o*CT0CAd?7;st6~Wwt^jMcA>w%utg+{mMp5j*U}cIH>R(Rm6dLQ$^ZZW delta 810 zcmV+_1J(S?2FnJJE`N#a;&)_mGXg@wj6;)Ry#{@rif%k%LcsG~4 z%ydcl{*&m@(hhUAnj%CBAj4BtxSaX^qQL7TKh>a^t^GE+@DC8Iu04%Axl-qEh!P-J zc`~EwAaxfkI)DCU4XYx9EUmZou09nq!X;dUg?z*HB18%xuQf1-?CG&pq#!&03}=Xw z`1K$u9+Gicg)Lq4_|B8h5+MHAVq-%FN(nb=?68`C=zL;&#sQT)yu3u&aB?xKL6ssz z3LswjVN>d{E9uR48)9iG8X!#Bu*C+an_g%Zy(dZl z#L9*u9Di%OtjXVh-&e2runlk`AWlnm`*=dk?4MQrZi^qc>lpo*7I9DPe0WwKtn!l+ za56*+Ad6oMUt>IcgL<%5ta%8=qet(iQ(7Ae7ewrU@D z-dSx6RWOhCzz03o5+Ls$!u`zG;gOOZ<7N@r;)8?Gbw`T;4}UpTm;lxgHB+u4L<%5Z zrLAzwOY@5))TJKdh$y%^A3V5RgU0dr1_6fkO8Q|EAgZ8(c{xu4?o|iB$WcjpWV{oL_<<7s?@J zeee<>yd{n%_j8V$oy;l+3i6q9c)24yiddgkIjq(8Qu&DS8X$7q9EC?0kVr3`j}4g& z4#dE49e;<$cZa>ujKhYv|E^XdAVMkSa#Z+a-*IK*SZafmA~jY)Sy4`rXjY~vKNxx$ zBr-$_AU%tdQG2MfLV_h<+@oAkiLd&*R3;&neUZ^6A-A=7eG(uBI9&vEu^+x`PL=W+ zLfPI;p5WS1wcg}?9#J9nvc8u(L<%50{9?x4Tz}2Brsu$o!j!@Z+;B)Ls_xHT6yB^w z1OK(<5+L%s>z9C}V`=w(UjtgnoTY2u?;`W5u`wI3^cK>0?ae|U8na60R-lr>MH|p( zCzC3#o0(w=Kmg<$OLup84ZeCtN+1fl{F@jbg|nr2DlUhEWv@pw9<{e=^4dplRDhh; o*CT0CAd?7;st6~Wwt^jMcA>w%utg+{mMp5j*U}cIH>R(Rm6dLQ$^ZZW delta 810 zcmV+_1J(S?2FnJJE`N#a;&)_mGXg@wj6;)Ry#{@rif%k%LcsG~4 z%ydcl{*&m@(hhUAnj%CBAj4BtxSaX^qQL7TKh>a^t^GE+@DC8Iu04%Axl-qEh!P-J zc`~EwAaxfkI)DCU4XYx9EUmZou09nq!X;dUg?z*HB18%xuQf1-?CG&pq#!&03}=Xw z`1K$u9+Gicg)Lq4_|B8h5+MHAVq-%FN(nb=?68`C=zL;&#sQT)yu3u&aB?xKL6ssz z3LswjVN>d{E9uR48)9iG8X!#Bu*C+an_g%Zy(dZl z#L9*u9Di%OtjXVh-&e2runlk`AWlnm`*=dk?4MQrZi^qc>lpo*7I9DPe0WwKtn!l+ za56*+Ad6oMUt>IcgL<%5ta%8=qet(iQ(7Ae7ewrU@D z-dSx6RWOhCzz03o5+Ls$!u`zG;gOOZ<7N@r;)8?Gbw`T;4}UpTm;lxgHB+u4L<%5Z zrLAzwOY@5))TJKdh$y%^A3V5RgU0dr1_6fkO8Q|EAgZ8(c{xu4?o|iB$WcjpWV{oL_<<7s?@J zeee<>yd{n%_j8V$oy;l+3i6q9c)24yiddgkIjq(8Qu&DS8X$7q9EC?0kVr3`j}4g& z4#dE49e;<$cZa>ujKhYv|E^XdAVMkSa#Z+a-*IK*SZafmA~jY)Sy4`rXjY~vKNxx$ zBr-$_AU%tdQG2MfLV_h<+@oAkiLd&*R3;&neUZ^6A-A=7eG(uBI9&vEu^+x`PL=W+ zLfPI;p5WS1wcg}?9#J9nvc8u(L<%50{9?x4Tz}2Brsu$o!j!@Z+;B)Ls_xHT6yB^w z1OK(<5+L%s>z9C}V`=w(UjtgnoTY2u?;`W5u`wI3^cK>0?ae|U8na60R-lr>MH|p( zCzC3#o0(w=Kmg<$OLup84ZeCtN+1fl{F@jbg|nr2DlUhEWv@pw9<{e=^4dplRDhh; o*CT0CAd?7;st6~Wwt^jMcA>w%utg+{mMp5j*U}cIH>R(Rm6dLQ$^ZZW delta 810 zcmV+_1J(S?2FnJJE`N#a;&)_mGXg@wj6;)Ry#{@rif%k%LcsG~4 z%ydcl{*&m@(hhUAnj%CBAj4BtxSaX^qQL7TKh>a^t^GE+@DC8Iu04%Axl-qEh!P-J zc`~EwAaxfkI)DCU4XYx9EUmZou09nq!X;dUg?z*HB18%xuQf1-?CG&pq#!&03}=Xw z`1K$u9+Gicg)Lq4_|B8h5+MHAVq-%FN(nb=?68`C=zL;&#sQT)yu3u&aB?xKL6ssz z3LswjVN>d{E9uR48)9iG8X!#Bu*C+an_g%Zy(dZl z#L9*u9Di%OtjXVh-&e2runlk`AWlnm`*=dk?4MQrZi^qc>lpo*7I9DPe0WwKtn!l+ za56*+Ad6oMUt>IcgL<%5ta%8=qet(iQ(7Ae7ewrU@D z-dSx6RWOhCzz03o5+Ls$!u`zG;gOOZ<7N@r;)8?Gbw`T;4}UpTm;lxgHB+u4L<%5Z zrLAzwOY@5))TJKdh$y%^A3V5RgU0dr1_6fkO8Q|EAgZ8(c{xu4?o|iB$WcjpWV{oL_<<7s?@J zeee<>yd{n%_j8V$oy;l+3i6q9c)24yiddgkIjq(8Qu&DS8X$7q9EC?0kVr3`j}4g& z4#dE49e;<$cZa>ujKhYv|E^XdAVMkSa#Z+a-*IK*SZafmA~jY)Sy4`rXjY~vKNxx$ zBr-$_AU%tdQG2MfLV_h<+@oAkiLd&*R3;&neUZ^6A-A=7eG(uBI9&vEu^+x`PL=W+ zLfPI;p5WS1wcg}?9#J9nvc8u(L<%50{9?x4Tz}2Brsu$o!j!@Z+;B)Ls_xHT6yB^w z1OK(<5+L%s>z9C}V`=w(UjtgnoTY2u?;`W5u`wI3^cK>0?ae|U8na60R-lr>MH|p( zCzC3#o0(w=Kmg<$OLup84ZeCtN+1fl{F@jbg|nr2DlUhEWv@pw9<{e=^4dplRDhh; o*CT0CAd?7;st6~Wwt^jMcA>w%utg+{mMp5j*U}cIH>R(Rm6dLQ$^ZZW delta 810 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 From 6a0552e26b411b6879c8187a8b68adf837fe1787 Mon Sep 17 00:00:00 2001 From: sannish Date: Thu, 4 Aug 2022 19:03:43 +0000 Subject: [PATCH 084/150] update unit tests; added fabric-cli debug log to help updating unit tests viewb64 in core contracts Signed-off-by: sannish --- .../weaver/corda/app/interop/WriteExternalStateTest.kt | 6 +++--- .../contracts/interop/write_external_state_test.go | 8 ++++---- samples/fabric/fabric-cli/src/helpers/helpers.ts | 4 ++++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/core/network/corda-interop-app/interop-workflows/src/test/kotlin/com/weaver/corda/app/interop/WriteExternalStateTest.kt b/core/network/corda-interop-app/interop-workflows/src/test/kotlin/com/weaver/corda/app/interop/WriteExternalStateTest.kt index a2b0f73f7..20d3bff4f 100644 --- a/core/network/corda-interop-app/interop-workflows/src/test/kotlin/com/weaver/corda/app/interop/WriteExternalStateTest.kt +++ b/core/network/corda-interop-app/interop-workflows/src/test/kotlin/com/weaver/corda/app/interop/WriteExternalStateTest.kt @@ -47,9 +47,9 @@ class WriteExternalStateTest { val fabricRelayEndpoint = "relay-network1:9080" val fabricViewAddress = "mychannel:simplestate:Read:a" - val b64FabricView = "CjIIAxIYMjAyMi0wOC0wNFQxMDoyNDo0Ny42MDVaGgxOb3Rhcml6YXRpb24iBlNUUklORxKLGgrFBwjIARq/BwoGMTcuNjcxEjlyZWxheS1uZXR3b3JrMTo5MDgwL25ldHdvcmsxL215Y2hhbm5lbDpzaW1wbGVzdGF0ZTpSZWFkOmEi0wYtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ1JqQ0NBZTJnQXdJQkFnSVVSUlJDZGJaNjNpNTlNM3c2OFA1STI1cnoyTEF3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRBMk5USXdNRm9YRFRJek1EZ3dOREEyTlRjd01Gb3dJVEVQTUEwRwpBMVVFQ3hNR1kyeHBaVzUwTVE0d0RBWURWUVFERXdWMWMyVnlNVEJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5CkF3RUhBMElBQk5PZ29SYnJndGZYeHFhL21iQlFObXl4MVBJWExBdWFNV3BxQUl1MUx3MUxNMjh0SnRoT0pxWFUKejZFd0hMR2VMbGJ2U0VUNnhtb1hyZ0l2QkIxWndHNmpnYnN3Z2Jnd0RnWURWUjBQQVFIL0JBUURBZ2VBTUF3RwpBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRk1zWFA3QmpNc21mVXVLZnVlVXNyWTc0cFgwR01COEdBMVVkCkl3UVlNQmFBRlB3ZTFMck51STMzVm0rRWRnTy9FL2pKaWhVMU1GZ0dDQ29EQkFVR0J3Z0JCRXg3SW1GMGRISnoKSWpwN0ltaG1Ma0ZtWm1sc2FXRjBhVzl1SWpvaUlpd2lhR1l1Ulc1eWIyeHNiV1Z1ZEVsRUlqb2lkWE5sY2pFaQpMQ0pvWmk1VWVYQmxJam9pWTJ4cFpXNTBJbjE5TUFvR0NDcUdTTTQ5QkFNQ0EwY0FNRVFDSUJCLzY4MVdmQlIrClFXSUdmaVlLT2szSHVSdE84SkZ3YlRpRWpuQWdDUnZuQWlCYTY5d1dZYVoyNVpSK0dheTY5ZVYrdkRaa1BNSFMKZ2RSakFJdGNLR3N0Rmc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCiokZWE3OWU2NjQtYTJmMi00YzlmLTg2NDMtZTYwNjAwODhmYzlhGpgKCiBVNNh9oMmGr6mjpkClfw32G8jILQMdz9o0hFOMbTk7vRLzCQqaAhJmCgpfbGlmZWN5Y2xlElgKKAoibmFtZXNwYWNlcy9maWVsZHMvaW50ZXJvcC9TZXF1ZW5jZRICCAYKLAombmFtZXNwYWNlcy9maWVsZHMvc2ltcGxlc3RhdGUvU2VxdWVuY2USAggDEn4KB2ludGVyb3AScwoeChgAYWNjZXNzQ29udHJvbABuZXR3b3JrMgASAggUChsKFQBtZW1iZXJzaGlwAG5ldHdvcmsyABICCBYKFgoQAPSPv79pbml0aWFsaXplZBICCAcKHAoWZTJlQ29uZmlkZW50aWFsaXR5RmxhZxICCAcSMAoLc2ltcGxlc3RhdGUSIQoWChAA9I+/v2luaXRpYWxpemVkEgIIBAoHCgFhEgIIGhrFBwjIARq/BwoGMTcuNjcxEjlyZWxheS1uZXR3b3JrMTo5MDgwL25ldHdvcmsxL215Y2hhbm5lbDpzaW1wbGVzdGF0ZTpSZWFkOmEi0wYtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ1JqQ0NBZTJnQXdJQkFnSVVSUlJDZGJaNjNpNTlNM3c2OFA1STI1cnoyTEF3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRBMk5USXdNRm9YRFRJek1EZ3dOREEyTlRjd01Gb3dJVEVQTUEwRwpBMVVFQ3hNR1kyeHBaVzUwTVE0d0RBWURWUVFERXdWMWMyVnlNVEJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5CkF3RUhBMElBQk5PZ29SYnJndGZYeHFhL21iQlFObXl4MVBJWExBdWFNV3BxQUl1MUx3MUxNMjh0SnRoT0pxWFUKejZFd0hMR2VMbGJ2U0VUNnhtb1hyZ0l2QkIxWndHNmpnYnN3Z2Jnd0RnWURWUjBQQVFIL0JBUURBZ2VBTUF3RwpBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRk1zWFA3QmpNc21mVXVLZnVlVXNyWTc0cFgwR01COEdBMVVkCkl3UVlNQmFBRlB3ZTFMck51STMzVm0rRWRnTy9FL2pKaWhVMU1GZ0dDQ29EQkFVR0J3Z0JCRXg3SW1GMGRISnoKSWpwN0ltaG1Ma0ZtWm1sc2FXRjBhVzl1SWpvaUlpd2lhR1l1Ulc1eWIyeHNiV1Z1ZEVsRUlqb2lkWE5sY2pFaQpMQ0pvWmk1VWVYQmxJam9pWTJ4cFpXNTBJbjE5TUFvR0NDcUdTTTQ5QkFNQ0EwY0FNRVFDSUJCLzY4MVdmQlIrClFXSUdmaVlLT2szSHVSdE84SkZ3YlRpRWpuQWdDUnZuQWlCYTY5d1dZYVoyNVpSK0dheTY5ZVYrdkRaa1BNSFMKZ2RSakFJdGNLR3N0Rmc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCiokZWE3OWU2NjQtYTJmMi00YzlmLTg2NDMtZTYwNjAwODhmYzlhIgwSB2ludGVyb3AaATEipQgK2QcKB09yZzFNU1ASzQctLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ29qQ0NBa21nQXdJQkFnSVVHeDlQUksyN0ZOR0RVN012S3V3eGFRZXRaMTh3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRBMk1ESXdNRm9YRFRJek1EZ3dOREEyTURjd01Gb3dXekVMTUFrRwpBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRS0V3dEllWEJsCmNteGxaR2RsY2pFTk1Bc0dBMVVFQ3hNRWNHVmxjakVPTUF3R0ExVUVBeE1GY0dWbGNqQXdXVEFUQmdjcWhrak8KUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVF5ZmFPOFJSUW1JNzY1MXBlOUliU0diSGc5dHh0QUpQS1F6cHIzYzBmQgpZV0tFWmZTR2hUYWVnb21jNkhUVCtGNXhpMkV1YVZkZFo2cTBwMlh4MmRKRm80SGRNSUhhTUE0R0ExVWREd0VCCi93UUVBd0lIZ0RBTUJnTlZIUk1CQWY4RUFqQUFNQjBHQTFVZERnUVdCQlNNVDJ2c0xQVm1xV0xMbEFwbVpmSGIKSnFEamlEQWZCZ05WSFNNRUdEQVdnQlFxRWRTWmIzMEYzckFLWjRsRnJYSXRYRjRqakRBaUJnTlZIUkVFR3pBWgpnaGR3WldWeU1DNXZjbWN4TG01bGRIZHZjbXN4TG1OdmJUQldCZ2dxQXdRRkJnY0lBUVJLZXlKaGRIUnljeUk2CmV5Sm9aaTVCWm1acGJHbGhkR2x2YmlJNklpSXNJbWhtTGtWdWNtOXNiRzFsYm5SSlJDSTZJbkJsWlhJd0lpd2kKYUdZdVZIbHdaU0k2SW5CbFpYSWlmWDB3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnWlE1YTNtekpaK3pmUDlyTwpjWU9vWEQ5UDVqeE1oUmNMQlBQZ0dnL2JLbllDSUNyM3FlSmdzeFgrRWlBV2drSjNHeFdjK1pRRnNzbTlqTWJBCnIxWGJmK0tJCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KEkcwRQIhAM1Gyv7e+SYniXLgB8iBuRqS4C/A9D36SLl4Zj/AkxrpAiByAoaBFpRIMEJsmGasggaQ4AUST+M2n8ctBZCHjDwRxQ==" + val b64FabricView = "CjIIAxIYMjAyMi0wOC0wNFQxODo1ODo1MS40MTNaGgxOb3Rhcml6YXRpb24iBlNUUklORxKVGgrHBwjIARrBBwoIQXJjdHVydXMSOXJlbGF5LW5ldHdvcmsxOjkwODAvbmV0d29yazEvbXljaGFubmVsOnNpbXBsZXN0YXRlOlJlYWQ6YSLTBi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlDUnpDQ0FlMmdBd0lCQWdJVUpqWlFQbFA2UlhZditYZkxJNjZnQko0ZHhtSXdDZ1lJS29aSXpqMEVBd0l3CmFERUxNQWtHQTFVRUJoTUNWVk14RnpBVkJnTlZCQWdURGs1dmNuUm9JRU5oY205c2FXNWhNUlF3RWdZRFZRUUsKRXd0SWVYQmxjbXhsWkdkbGNqRVBNQTBHQTFVRUN4TUdSbUZpY21sak1Sa3dGd1lEVlFRREV4Qm1ZV0p5YVdNdApZMkV0YzJWeWRtVnlNQjRYRFRJeU1EZ3dOREU0TWpnd01Gb1hEVE15TURnd05EQTJNek13TUZvd0lURVBNQTBHCkExVUVDeE1HWTJ4cFpXNTBNUTR3REFZRFZRUURFd1YxYzJWeU1UQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDkKQXdFSEEwSUFCRU9VTUR3UE9PTGpzMlVHdkloV2lNTHV3QytHb0ROVjJuejZzdDlHenVhMmgwMU04bzk1SWlvNgptemRsbjlMNHBabS8ySHpNbkJveVBLcnJqWVJtY2lhamdic3dnYmd3RGdZRFZSMFBBUUgvQkFRREFnZUFNQXdHCkExVWRFd0VCL3dRQ01BQXdIUVlEVlIwT0JCWUVGQ0NZWk1oaC9GSU9XNnprQkJCSU53Qm9iZHBETUI4R0ExVWQKSXdRWU1CYUFGT0U0MXdFZkJnSGYrY2ZqUXpheUUvUThwbTJiTUZnR0NDb0RCQVVHQndnQkJFeDdJbUYwZEhKegpJanA3SW1obUxrRm1abWxzYVdGMGFXOXVJam9pSWl3aWFHWXVSVzV5YjJ4c2JXVnVkRWxFSWpvaWRYTmxjakVpCkxDSm9aaTVVZVhCbElqb2lZMnhwWlc1MEluMTlNQW9HQ0NxR1NNNDlCQU1DQTBnQU1FVUNJUUR5VXZOWHQ2bk0KbDAvN0cvb0pqZUJ5d3NRZUw0SVUyUURCU21pN1prMW9PUUlnSWtRdHNnK2R1SE9XQ1g2MHpVRVRoWGVac2c5VQpkUUhGWFZuY0xCV1FoTGs9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KKiQwMDVkMDg2Yy1iYjc0LTRkZDctOWM1My0wYjkyYTAzNmMxNTAanAoKIMJ+2a8Uja1yb9fSYl8ChORWohrjHGeEbcqPvbbeTteBEvcJCpwCEmYKCl9saWZlY3ljbGUSWAooCiJuYW1lc3BhY2VzL2ZpZWxkcy9pbnRlcm9wL1NlcXVlbmNlEgIIBgosCiZuYW1lc3BhY2VzL2ZpZWxkcy9zaW1wbGVzdGF0ZS9TZXF1ZW5jZRICCAMSfgoHaW50ZXJvcBJzCh4KGABhY2Nlc3NDb250cm9sAG5ldHdvcmsyABICCBcKGwoVAG1lbWJlcnNoaXAAbmV0d29yazIAEgIIGQoWChAA9I+/v2luaXRpYWxpemVkEgIIBwocChZlMmVDb25maWRlbnRpYWxpdHlGbGFnEgIIBxIyCgtzaW1wbGVzdGF0ZRIjChYKEAD0j7+/aW5pdGlhbGl6ZWQSAggECgkKAWESBAgJEAYaxwcIyAEawQcKCEFyY3R1cnVzEjlyZWxheS1uZXR3b3JrMTo5MDgwL25ldHdvcmsxL215Y2hhbm5lbDpzaW1wbGVzdGF0ZTpSZWFkOmEi0wYtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ1J6Q0NBZTJnQXdJQkFnSVVKalpRUGxQNlJYWXYrWGZMSTY2Z0JKNGR4bUl3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRFNE1qZ3dNRm9YRFRNeU1EZ3dOREEyTXpNd01Gb3dJVEVQTUEwRwpBMVVFQ3hNR1kyeHBaVzUwTVE0d0RBWURWUVFERXdWMWMyVnlNVEJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5CkF3RUhBMElBQkVPVU1Ed1BPT0xqczJVR3ZJaFdpTUx1d0MrR29ETlYybno2c3Q5R3p1YTJoMDFNOG85NUlpbzYKbXpkbG45TDRwWm0vMkh6TW5Cb3lQS3JyallSbWNpYWpnYnN3Z2Jnd0RnWURWUjBQQVFIL0JBUURBZ2VBTUF3RwpBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRkNDWVpNaGgvRklPVzZ6a0JCQklOd0JvYmRwRE1COEdBMVVkCkl3UVlNQmFBRk9FNDF3RWZCZ0hmK2NmalF6YXlFL1E4cG0yYk1GZ0dDQ29EQkFVR0J3Z0JCRXg3SW1GMGRISnoKSWpwN0ltaG1Ma0ZtWm1sc2FXRjBhVzl1SWpvaUlpd2lhR1l1Ulc1eWIyeHNiV1Z1ZEVsRUlqb2lkWE5sY2pFaQpMQ0pvWmk1VWVYQmxJam9pWTJ4cFpXNTBJbjE5TUFvR0NDcUdTTTQ5QkFNQ0EwZ0FNRVVDSVFEeVV2Tlh0Nm5NCmwwLzdHL29KamVCeXdzUWVMNElVMlFEQlNtaTdaazFvT1FJZ0lrUXRzZytkdUhPV0NYNjB6VUVUaFhlWnNnOVUKZFFIRlhWbmNMQldRaExrPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCiokMDA1ZDA4NmMtYmI3NC00ZGQ3LTljNTMtMGI5MmEwMzZjMTUwIgwSB2ludGVyb3AaATEiqQgK3QcKB09yZzFNU1AS0QctLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ296Q0NBa21nQXdJQkFnSVVFQ2QzSnNnWHBVRTJ3TWc1NVAxdi9EWnpvaXd3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRFNE1qSXdNRm9YRFRNeU1EZ3dOREEyTWpjd01Gb3dXekVMTUFrRwpBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRS0V3dEllWEJsCmNteGxaR2RsY2pFTk1Bc0dBMVVFQ3hNRWNHVmxjakVPTUF3R0ExVUVBeE1GY0dWbGNqQXdXVEFUQmdjcWhrak8KUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVJpTlc0YXhVUWw4WS81NjFoYVU3eFkzUTk2OTM0QkgwMnAyOE9RZFM0awprUmdOb1JwMWIrS0d6MGNJSXZnRFROaENJcmswTFF6bmFYZkhZaTErK01HZG80SGRNSUhhTUE0R0ExVWREd0VCCi93UUVBd0lIZ0RBTUJnTlZIUk1CQWY4RUFqQUFNQjBHQTFVZERnUVdCQlJkQ2hKRnhEVHFSVG5TTm1tamJWbm8KUnBkcVR6QWZCZ05WSFNNRUdEQVdnQlRPeHd6SG9ZaDVmRy9ka0VqRGVFTlJRZXlWUHpBaUJnTlZIUkVFR3pBWgpnaGR3WldWeU1DNXZjbWN4TG01bGRIZHZjbXN4TG1OdmJUQldCZ2dxQXdRRkJnY0lBUVJLZXlKaGRIUnljeUk2CmV5Sm9aaTVCWm1acGJHbGhkR2x2YmlJNklpSXNJbWhtTGtWdWNtOXNiRzFsYm5SSlJDSTZJbkJsWlhJd0lpd2kKYUdZdVZIbHdaU0k2SW5CbFpYSWlmWDB3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQU9ra0tUMFpoYm9oMTZONQpOcjFpU2hYa085RkZrRmF3U3VCLzA2cUZzSXhLQWlCZ3d0YWhwTTliNjJqbFIrbnFsaHg2eTJDQnUrUzFYRkpuCkwwTzZoVVVMQ3c9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tChJHMEUCIQD7ubwSdS/lUNt1m+0P7HgsdVsinZJkZXzAkNzQm/jMVQIgA3QCOcbkotaKtY/t+ntyYS3jaX/1X71Bwv9xxtRoj6I=" - val fabricCert = "-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR\nynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq\nm2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd\nzQkhznMIF4SBF4k=\n-----END CERTIFICATE-----\n" + val fabricCert = "-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUYxHjCF1HdZexrgAM73ec4jdHy8owCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE76ubZH/VHJszsYLHVKaUwKBR\nUZv8P+Jq6Op5PeBf02JUKPM15DSF9n56RJq+7mrM9zBzPvBsUySFd+rr/BrsW6NF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFM7HDMehiHl8b92QSMN4Q1FB7JU/MAoGCCqGSM49BAMCA0cAMEQCIH4UJq+qY2OP\n7DzBAwY7woYuy4zoT2kxyiexlix38aY4AiAo+8OKE1wFM+XKLUqI4zzgq2bpg1qb\nU5aIsTpdz3N2tg==\n-----END CERTIFICATE-----\n" val fabricVerificationPolicy = VerificationPolicyState( securityDomain = fabricNetwork, @@ -150,4 +150,4 @@ class WriteExternalStateTest { } -} \ No newline at end of file +} diff --git a/core/network/fabric-interop-cc/contracts/interop/write_external_state_test.go b/core/network/fabric-interop-cc/contracts/interop/write_external_state_test.go index 935fdd400..eef75829a 100644 --- a/core/network/fabric-interop-cc/contracts/interop/write_external_state_test.go +++ b/core/network/fabric-interop-cc/contracts/interop/write_external_state_test.go @@ -47,13 +47,13 @@ var fabricRelayEndpoint = "relay-network1:9080" var fabricPattern = "mychannel:simplestate:Read:a" var fabricViewAddress = fabricRelayEndpoint + "/" + fabricNetwork + "/" + fabricPattern -var b64View = "CjIIAxIYMjAyMi0wOC0wNFQxMDoyNDo0Ny42MDVaGgxOb3Rhcml6YXRpb24iBlNUUklORxKLGgrFBwjIARq/BwoGMTcuNjcxEjlyZWxheS1uZXR3b3JrMTo5MDgwL25ldHdvcmsxL215Y2hhbm5lbDpzaW1wbGVzdGF0ZTpSZWFkOmEi0wYtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ1JqQ0NBZTJnQXdJQkFnSVVSUlJDZGJaNjNpNTlNM3c2OFA1STI1cnoyTEF3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRBMk5USXdNRm9YRFRJek1EZ3dOREEyTlRjd01Gb3dJVEVQTUEwRwpBMVVFQ3hNR1kyeHBaVzUwTVE0d0RBWURWUVFERXdWMWMyVnlNVEJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5CkF3RUhBMElBQk5PZ29SYnJndGZYeHFhL21iQlFObXl4MVBJWExBdWFNV3BxQUl1MUx3MUxNMjh0SnRoT0pxWFUKejZFd0hMR2VMbGJ2U0VUNnhtb1hyZ0l2QkIxWndHNmpnYnN3Z2Jnd0RnWURWUjBQQVFIL0JBUURBZ2VBTUF3RwpBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRk1zWFA3QmpNc21mVXVLZnVlVXNyWTc0cFgwR01COEdBMVVkCkl3UVlNQmFBRlB3ZTFMck51STMzVm0rRWRnTy9FL2pKaWhVMU1GZ0dDQ29EQkFVR0J3Z0JCRXg3SW1GMGRISnoKSWpwN0ltaG1Ma0ZtWm1sc2FXRjBhVzl1SWpvaUlpd2lhR1l1Ulc1eWIyeHNiV1Z1ZEVsRUlqb2lkWE5sY2pFaQpMQ0pvWmk1VWVYQmxJam9pWTJ4cFpXNTBJbjE5TUFvR0NDcUdTTTQ5QkFNQ0EwY0FNRVFDSUJCLzY4MVdmQlIrClFXSUdmaVlLT2szSHVSdE84SkZ3YlRpRWpuQWdDUnZuQWlCYTY5d1dZYVoyNVpSK0dheTY5ZVYrdkRaa1BNSFMKZ2RSakFJdGNLR3N0Rmc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCiokZWE3OWU2NjQtYTJmMi00YzlmLTg2NDMtZTYwNjAwODhmYzlhGpgKCiBVNNh9oMmGr6mjpkClfw32G8jILQMdz9o0hFOMbTk7vRLzCQqaAhJmCgpfbGlmZWN5Y2xlElgKKAoibmFtZXNwYWNlcy9maWVsZHMvaW50ZXJvcC9TZXF1ZW5jZRICCAYKLAombmFtZXNwYWNlcy9maWVsZHMvc2ltcGxlc3RhdGUvU2VxdWVuY2USAggDEn4KB2ludGVyb3AScwoeChgAYWNjZXNzQ29udHJvbABuZXR3b3JrMgASAggUChsKFQBtZW1iZXJzaGlwAG5ldHdvcmsyABICCBYKFgoQAPSPv79pbml0aWFsaXplZBICCAcKHAoWZTJlQ29uZmlkZW50aWFsaXR5RmxhZxICCAcSMAoLc2ltcGxlc3RhdGUSIQoWChAA9I+/v2luaXRpYWxpemVkEgIIBAoHCgFhEgIIGhrFBwjIARq/BwoGMTcuNjcxEjlyZWxheS1uZXR3b3JrMTo5MDgwL25ldHdvcmsxL215Y2hhbm5lbDpzaW1wbGVzdGF0ZTpSZWFkOmEi0wYtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ1JqQ0NBZTJnQXdJQkFnSVVSUlJDZGJaNjNpNTlNM3c2OFA1STI1cnoyTEF3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRBMk5USXdNRm9YRFRJek1EZ3dOREEyTlRjd01Gb3dJVEVQTUEwRwpBMVVFQ3hNR1kyeHBaVzUwTVE0d0RBWURWUVFERXdWMWMyVnlNVEJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5CkF3RUhBMElBQk5PZ29SYnJndGZYeHFhL21iQlFObXl4MVBJWExBdWFNV3BxQUl1MUx3MUxNMjh0SnRoT0pxWFUKejZFd0hMR2VMbGJ2U0VUNnhtb1hyZ0l2QkIxWndHNmpnYnN3Z2Jnd0RnWURWUjBQQVFIL0JBUURBZ2VBTUF3RwpBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRk1zWFA3QmpNc21mVXVLZnVlVXNyWTc0cFgwR01COEdBMVVkCkl3UVlNQmFBRlB3ZTFMck51STMzVm0rRWRnTy9FL2pKaWhVMU1GZ0dDQ29EQkFVR0J3Z0JCRXg3SW1GMGRISnoKSWpwN0ltaG1Ma0ZtWm1sc2FXRjBhVzl1SWpvaUlpd2lhR1l1Ulc1eWIyeHNiV1Z1ZEVsRUlqb2lkWE5sY2pFaQpMQ0pvWmk1VWVYQmxJam9pWTJ4cFpXNTBJbjE5TUFvR0NDcUdTTTQ5QkFNQ0EwY0FNRVFDSUJCLzY4MVdmQlIrClFXSUdmaVlLT2szSHVSdE84SkZ3YlRpRWpuQWdDUnZuQWlCYTY5d1dZYVoyNVpSK0dheTY5ZVYrdkRaa1BNSFMKZ2RSakFJdGNLR3N0Rmc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCiokZWE3OWU2NjQtYTJmMi00YzlmLTg2NDMtZTYwNjAwODhmYzlhIgwSB2ludGVyb3AaATEipQgK2QcKB09yZzFNU1ASzQctLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ29qQ0NBa21nQXdJQkFnSVVHeDlQUksyN0ZOR0RVN012S3V3eGFRZXRaMTh3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRBMk1ESXdNRm9YRFRJek1EZ3dOREEyTURjd01Gb3dXekVMTUFrRwpBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRS0V3dEllWEJsCmNteGxaR2RsY2pFTk1Bc0dBMVVFQ3hNRWNHVmxjakVPTUF3R0ExVUVBeE1GY0dWbGNqQXdXVEFUQmdjcWhrak8KUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVF5ZmFPOFJSUW1JNzY1MXBlOUliU0diSGc5dHh0QUpQS1F6cHIzYzBmQgpZV0tFWmZTR2hUYWVnb21jNkhUVCtGNXhpMkV1YVZkZFo2cTBwMlh4MmRKRm80SGRNSUhhTUE0R0ExVWREd0VCCi93UUVBd0lIZ0RBTUJnTlZIUk1CQWY4RUFqQUFNQjBHQTFVZERnUVdCQlNNVDJ2c0xQVm1xV0xMbEFwbVpmSGIKSnFEamlEQWZCZ05WSFNNRUdEQVdnQlFxRWRTWmIzMEYzckFLWjRsRnJYSXRYRjRqakRBaUJnTlZIUkVFR3pBWgpnaGR3WldWeU1DNXZjbWN4TG01bGRIZHZjbXN4TG1OdmJUQldCZ2dxQXdRRkJnY0lBUVJLZXlKaGRIUnljeUk2CmV5Sm9aaTVCWm1acGJHbGhkR2x2YmlJNklpSXNJbWhtTGtWdWNtOXNiRzFsYm5SSlJDSTZJbkJsWlhJd0lpd2kKYUdZdVZIbHdaU0k2SW5CbFpYSWlmWDB3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnWlE1YTNtekpaK3pmUDlyTwpjWU9vWEQ5UDVqeE1oUmNMQlBQZ0dnL2JLbllDSUNyM3FlSmdzeFgrRWlBV2drSjNHeFdjK1pRRnNzbTlqTWJBCnIxWGJmK0tJCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KEkcwRQIhAM1Gyv7e+SYniXLgB8iBuRqS4C/A9D36SLl4Zj/AkxrpAiByAoaBFpRIMEJsmGasggaQ4AUST+M2n8ctBZCHjDwRxQ==" +var b64View = "CjIIAxIYMjAyMi0wOC0wNFQxODo1ODo1MS40MTNaGgxOb3Rhcml6YXRpb24iBlNUUklORxKVGgrHBwjIARrBBwoIQXJjdHVydXMSOXJlbGF5LW5ldHdvcmsxOjkwODAvbmV0d29yazEvbXljaGFubmVsOnNpbXBsZXN0YXRlOlJlYWQ6YSLTBi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlDUnpDQ0FlMmdBd0lCQWdJVUpqWlFQbFA2UlhZditYZkxJNjZnQko0ZHhtSXdDZ1lJS29aSXpqMEVBd0l3CmFERUxNQWtHQTFVRUJoTUNWVk14RnpBVkJnTlZCQWdURGs1dmNuUm9JRU5oY205c2FXNWhNUlF3RWdZRFZRUUsKRXd0SWVYQmxjbXhsWkdkbGNqRVBNQTBHQTFVRUN4TUdSbUZpY21sak1Sa3dGd1lEVlFRREV4Qm1ZV0p5YVdNdApZMkV0YzJWeWRtVnlNQjRYRFRJeU1EZ3dOREU0TWpnd01Gb1hEVE15TURnd05EQTJNek13TUZvd0lURVBNQTBHCkExVUVDeE1HWTJ4cFpXNTBNUTR3REFZRFZRUURFd1YxYzJWeU1UQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDkKQXdFSEEwSUFCRU9VTUR3UE9PTGpzMlVHdkloV2lNTHV3QytHb0ROVjJuejZzdDlHenVhMmgwMU04bzk1SWlvNgptemRsbjlMNHBabS8ySHpNbkJveVBLcnJqWVJtY2lhamdic3dnYmd3RGdZRFZSMFBBUUgvQkFRREFnZUFNQXdHCkExVWRFd0VCL3dRQ01BQXdIUVlEVlIwT0JCWUVGQ0NZWk1oaC9GSU9XNnprQkJCSU53Qm9iZHBETUI4R0ExVWQKSXdRWU1CYUFGT0U0MXdFZkJnSGYrY2ZqUXpheUUvUThwbTJiTUZnR0NDb0RCQVVHQndnQkJFeDdJbUYwZEhKegpJanA3SW1obUxrRm1abWxzYVdGMGFXOXVJam9pSWl3aWFHWXVSVzV5YjJ4c2JXVnVkRWxFSWpvaWRYTmxjakVpCkxDSm9aaTVVZVhCbElqb2lZMnhwWlc1MEluMTlNQW9HQ0NxR1NNNDlCQU1DQTBnQU1FVUNJUUR5VXZOWHQ2bk0KbDAvN0cvb0pqZUJ5d3NRZUw0SVUyUURCU21pN1prMW9PUUlnSWtRdHNnK2R1SE9XQ1g2MHpVRVRoWGVac2c5VQpkUUhGWFZuY0xCV1FoTGs9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KKiQwMDVkMDg2Yy1iYjc0LTRkZDctOWM1My0wYjkyYTAzNmMxNTAanAoKIMJ+2a8Uja1yb9fSYl8ChORWohrjHGeEbcqPvbbeTteBEvcJCpwCEmYKCl9saWZlY3ljbGUSWAooCiJuYW1lc3BhY2VzL2ZpZWxkcy9pbnRlcm9wL1NlcXVlbmNlEgIIBgosCiZuYW1lc3BhY2VzL2ZpZWxkcy9zaW1wbGVzdGF0ZS9TZXF1ZW5jZRICCAMSfgoHaW50ZXJvcBJzCh4KGABhY2Nlc3NDb250cm9sAG5ldHdvcmsyABICCBcKGwoVAG1lbWJlcnNoaXAAbmV0d29yazIAEgIIGQoWChAA9I+/v2luaXRpYWxpemVkEgIIBwocChZlMmVDb25maWRlbnRpYWxpdHlGbGFnEgIIBxIyCgtzaW1wbGVzdGF0ZRIjChYKEAD0j7+/aW5pdGlhbGl6ZWQSAggECgkKAWESBAgJEAYaxwcIyAEawQcKCEFyY3R1cnVzEjlyZWxheS1uZXR3b3JrMTo5MDgwL25ldHdvcmsxL215Y2hhbm5lbDpzaW1wbGVzdGF0ZTpSZWFkOmEi0wYtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ1J6Q0NBZTJnQXdJQkFnSVVKalpRUGxQNlJYWXYrWGZMSTY2Z0JKNGR4bUl3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRFNE1qZ3dNRm9YRFRNeU1EZ3dOREEyTXpNd01Gb3dJVEVQTUEwRwpBMVVFQ3hNR1kyeHBaVzUwTVE0d0RBWURWUVFERXdWMWMyVnlNVEJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5CkF3RUhBMElBQkVPVU1Ed1BPT0xqczJVR3ZJaFdpTUx1d0MrR29ETlYybno2c3Q5R3p1YTJoMDFNOG85NUlpbzYKbXpkbG45TDRwWm0vMkh6TW5Cb3lQS3JyallSbWNpYWpnYnN3Z2Jnd0RnWURWUjBQQVFIL0JBUURBZ2VBTUF3RwpBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRkNDWVpNaGgvRklPVzZ6a0JCQklOd0JvYmRwRE1COEdBMVVkCkl3UVlNQmFBRk9FNDF3RWZCZ0hmK2NmalF6YXlFL1E4cG0yYk1GZ0dDQ29EQkFVR0J3Z0JCRXg3SW1GMGRISnoKSWpwN0ltaG1Ma0ZtWm1sc2FXRjBhVzl1SWpvaUlpd2lhR1l1Ulc1eWIyeHNiV1Z1ZEVsRUlqb2lkWE5sY2pFaQpMQ0pvWmk1VWVYQmxJam9pWTJ4cFpXNTBJbjE5TUFvR0NDcUdTTTQ5QkFNQ0EwZ0FNRVVDSVFEeVV2Tlh0Nm5NCmwwLzdHL29KamVCeXdzUWVMNElVMlFEQlNtaTdaazFvT1FJZ0lrUXRzZytkdUhPV0NYNjB6VUVUaFhlWnNnOVUKZFFIRlhWbmNMQldRaExrPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCiokMDA1ZDA4NmMtYmI3NC00ZGQ3LTljNTMtMGI5MmEwMzZjMTUwIgwSB2ludGVyb3AaATEiqQgK3QcKB09yZzFNU1AS0QctLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ296Q0NBa21nQXdJQkFnSVVFQ2QzSnNnWHBVRTJ3TWc1NVAxdi9EWnpvaXd3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRFNE1qSXdNRm9YRFRNeU1EZ3dOREEyTWpjd01Gb3dXekVMTUFrRwpBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRS0V3dEllWEJsCmNteGxaR2RsY2pFTk1Bc0dBMVVFQ3hNRWNHVmxjakVPTUF3R0ExVUVBeE1GY0dWbGNqQXdXVEFUQmdjcWhrak8KUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVJpTlc0YXhVUWw4WS81NjFoYVU3eFkzUTk2OTM0QkgwMnAyOE9RZFM0awprUmdOb1JwMWIrS0d6MGNJSXZnRFROaENJcmswTFF6bmFYZkhZaTErK01HZG80SGRNSUhhTUE0R0ExVWREd0VCCi93UUVBd0lIZ0RBTUJnTlZIUk1CQWY4RUFqQUFNQjBHQTFVZERnUVdCQlJkQ2hKRnhEVHFSVG5TTm1tamJWbm8KUnBkcVR6QWZCZ05WSFNNRUdEQVdnQlRPeHd6SG9ZaDVmRy9ka0VqRGVFTlJRZXlWUHpBaUJnTlZIUkVFR3pBWgpnaGR3WldWeU1DNXZjbWN4TG01bGRIZHZjbXN4TG1OdmJUQldCZ2dxQXdRRkJnY0lBUVJLZXlKaGRIUnljeUk2CmV5Sm9aaTVCWm1acGJHbGhkR2x2YmlJNklpSXNJbWhtTGtWdWNtOXNiRzFsYm5SSlJDSTZJbkJsWlhJd0lpd2kKYUdZdVZIbHdaU0k2SW5CbFpYSWlmWDB3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQU9ra0tUMFpoYm9oMTZONQpOcjFpU2hYa085RkZrRmF3U3VCLzA2cUZzSXhLQWlCZ3d0YWhwTTliNjJqbFIrbnFsaHg2eTJDQnUrUzFYRkpuCkwwTzZoVVVMQ3c9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tChJHMEUCIQD7ubwSdS/lUNt1m+0P7HgsdVsinZJkZXzAkNzQm/jMVQIgA3QCOcbkotaKtY/t+ntyYS3jaX/1X71Bwv9xxtRoj6I=" -var b64ViewConfidential = "CjIIAxIYMjAyMi0wOC0wNFQxMDozMjoyMC4zMTlaGgxOb3Rhcml6YXRpb24iBlNUUklORxLrHAr0CAjIARruCAqyAQqNAQRdCc5yPbVtY77Ow/6sH6V8AOwbumdSxFq5T62tOT8LIThrPue3yCQBp7P5/6NoKRZR9grAbP9mVHiZ5814qf/DnXULpdh5O5EbVKSZX5BtmXCqTwpmZaqrQzAGgNXVzB8L6QSEVz48fp9X9SuA3r74mzNM5Ip6WbsNXnENpfifEbUfHcDUK28KHN9U+xogYzlOibmMtRdSuUyam+LQmZ5Y4/9X7AyhqEGNe0INblsSOXJlbGF5LW5ldHdvcmsxOjkwODAvbmV0d29yazEvbXljaGFubmVsOnNpbXBsZXN0YXRlOlJlYWQ6YRgBItMGLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNSakNDQWUyZ0F3SUJBZ0lVUlJSQ2RiWjYzaTU5TTN3NjhQNUkyNXJ6MkxBd0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEl5TURnd05EQTJOVEl3TUZvWERUSXpNRGd3TkRBMk5UY3dNRm93SVRFUE1BMEcKQTFVRUN4TUdZMnhwWlc1ME1RNHdEQVlEVlFRREV3VjFjMlZ5TVRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OQpBd0VIQTBJQUJOT2dvUmJyZ3RmWHhxYS9tYkJRTm15eDFQSVhMQXVhTVdwcUFJdTFMdzFMTTI4dEp0aE9KcVhVCno2RXdITEdlTGxidlNFVDZ4bW9YcmdJdkJCMVp3RzZqZ2Jzd2diZ3dEZ1lEVlIwUEFRSC9CQVFEQWdlQU1Bd0cKQTFVZEV3RUIvd1FDTUFBd0hRWURWUjBPQkJZRUZNc1hQN0JqTXNtZlV1S2Z1ZVVzclk3NHBYMEdNQjhHQTFVZApJd1FZTUJhQUZQd2UxTHJOdUkzM1ZtK0VkZ08vRS9qSmloVTFNRmdHQ0NvREJBVUdCd2dCQkV4N0ltRjBkSEp6CklqcDdJbWhtTGtGbVptbHNhV0YwYVc5dUlqb2lJaXdpYUdZdVJXNXliMnhzYldWdWRFbEVJam9pZFhObGNqRWkKTENKb1ppNVVlWEJsSWpvaVkyeHBaVzUwSW4xOU1Bb0dDQ3FHU000OUJBTUNBMGNBTUVRQ0lCQi82ODFXZkJSKwpRV0lHZmlZS09rM0h1UnRPOEpGd2JUaUVqbkFnQ1J2bkFpQmE2OXdXWWFaMjVaUitHYXk2OWVWK3ZEWmtQTUhTCmdkUmpBSXRjS0dzdEZnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoqJDQwZTFjMGUxLWJkZDctNDQ2MC04YzhhLWRlMTZhOWQyOGYwYRrJCwogZOyCYqcgmQJccj0IkSL3t+oNKIzv0PmJqnzbH2jfIV8SpAsKnAISZgoKX2xpZmVjeWNsZRJYCigKIm5hbWVzcGFjZXMvZmllbGRzL2ludGVyb3AvU2VxdWVuY2USAggGCiwKJm5hbWVzcGFjZXMvZmllbGRzL3NpbXBsZXN0YXRlL1NlcXVlbmNlEgIIAxJ+CgdpbnRlcm9wEnMKHgoYAGFjY2Vzc0NvbnRyb2wAbmV0d29yazIAEgIIJwobChUAbWVtYmVyc2hpcABuZXR3b3JrMgASAggpChYKEAD0j7+/aW5pdGlhbGl6ZWQSAggHChwKFmUyZUNvbmZpZGVudGlhbGl0eUZsYWcSAggHEjIKC3NpbXBsZXN0YXRlEiMKFgoQAPSPv79pbml0aWFsaXplZBICCAQKCQoBYRIECBsQARr0CAjIARruCAqyAQqNAQRdCc5yPbVtY77Ow/6sH6V8AOwbumdSxFq5T62tOT8LIThrPue3yCQBp7P5/6NoKRZR9grAbP9mVHiZ5814qf/DnXULpdh5O5EbVKSZX5BtmXCqTwpmZaqrQzAGgNXVzB8L6QSEVz48fp9X9SuA3r74mzNM5Ip6WbsNXnENpfifEbUfHcDUK28KHN9U+xogYzlOibmMtRdSuUyam+LQmZ5Y4/9X7AyhqEGNe0INblsSOXJlbGF5LW5ldHdvcmsxOjkwODAvbmV0d29yazEvbXljaGFubmVsOnNpbXBsZXN0YXRlOlJlYWQ6YRgBItMGLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNSakNDQWUyZ0F3SUJBZ0lVUlJSQ2RiWjYzaTU5TTN3NjhQNUkyNXJ6MkxBd0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEl5TURnd05EQTJOVEl3TUZvWERUSXpNRGd3TkRBMk5UY3dNRm93SVRFUE1BMEcKQTFVRUN4TUdZMnhwWlc1ME1RNHdEQVlEVlFRREV3VjFjMlZ5TVRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OQpBd0VIQTBJQUJOT2dvUmJyZ3RmWHhxYS9tYkJRTm15eDFQSVhMQXVhTVdwcUFJdTFMdzFMTTI4dEp0aE9KcVhVCno2RXdITEdlTGxidlNFVDZ4bW9YcmdJdkJCMVp3RzZqZ2Jzd2diZ3dEZ1lEVlIwUEFRSC9CQVFEQWdlQU1Bd0cKQTFVZEV3RUIvd1FDTUFBd0hRWURWUjBPQkJZRUZNc1hQN0JqTXNtZlV1S2Z1ZVVzclk3NHBYMEdNQjhHQTFVZApJd1FZTUJhQUZQd2UxTHJOdUkzM1ZtK0VkZ08vRS9qSmloVTFNRmdHQ0NvREJBVUdCd2dCQkV4N0ltRjBkSEp6CklqcDdJbWhtTGtGbVptbHNhV0YwYVc5dUlqb2lJaXdpYUdZdVJXNXliMnhzYldWdWRFbEVJam9pZFhObGNqRWkKTENKb1ppNVVlWEJsSWpvaVkyeHBaVzUwSW4xOU1Bb0dDQ3FHU000OUJBTUNBMGNBTUVRQ0lCQi82ODFXZkJSKwpRV0lHZmlZS09rM0h1UnRPOEpGd2JUaUVqbkFnQ1J2bkFpQmE2OXdXWWFaMjVaUitHYXk2OWVWK3ZEWmtQTUhTCmdkUmpBSXRjS0dzdEZnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoqJDQwZTFjMGUxLWJkZDctNDQ2MC04YzhhLWRlMTZhOWQyOGYwYSIMEgdpbnRlcm9wGgExIqUICtkHCgdPcmcxTVNQEs0HLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNvakNDQWttZ0F3SUJBZ0lVR3g5UFJLMjdGTkdEVTdNdkt1d3hhUWV0WjE4d0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEl5TURnd05EQTJNREl3TUZvWERUSXpNRGd3TkRBMk1EY3dNRm93V3pFTE1Ba0cKQTFVRUJoTUNWVk14RnpBVkJnTlZCQWdURGs1dmNuUm9JRU5oY205c2FXNWhNUlF3RWdZRFZRUUtFd3RJZVhCbApjbXhsWkdkbGNqRU5NQXNHQTFVRUN4TUVjR1ZsY2pFT01Bd0dBMVVFQXhNRmNHVmxjakF3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFReWZhTzhSUlFtSTc2NTFwZTlJYlNHYkhnOXR4dEFKUEtRenByM2MwZkIKWVdLRVpmU0doVGFlZ29tYzZIVFQrRjV4aTJFdWFWZGRaNnEwcDJYeDJkSkZvNEhkTUlIYU1BNEdBMVVkRHdFQgovd1FFQXdJSGdEQU1CZ05WSFJNQkFmOEVBakFBTUIwR0ExVWREZ1FXQkJTTVQydnNMUFZtcVdMTGxBcG1aZkhiCkpxRGppREFmQmdOVkhTTUVHREFXZ0JRcUVkU1piMzBGM3JBS1o0bEZyWEl0WEY0ampEQWlCZ05WSFJFRUd6QVoKZ2hkd1pXVnlNQzV2Y21jeExtNWxkSGR2Y21zeExtTnZiVEJXQmdncUF3UUZCZ2NJQVFSS2V5SmhkSFJ5Y3lJNgpleUpvWmk1QlptWnBiR2xoZEdsdmJpSTZJaUlzSW1obUxrVnVjbTlzYkcxbGJuUkpSQ0k2SW5CbFpYSXdJaXdpCmFHWXVWSGx3WlNJNkluQmxaWElpZlgwd0NnWUlLb1pJemowRUF3SURSd0F3UkFJZ1pRNWEzbXpKWit6ZlA5ck8KY1lPb1hEOVA1anhNaFJjTEJQUGdHZy9iS25ZQ0lDcjNxZUpnc3hYK0VpQVdna0ozR3hXYytaUUZzc205ak1iQQpyMVhiZitLSQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tChJHMEUCIQC4MR1TNTeK+FHqEStQkXTM+9kgF4v3SldTn8G3T8Wb1wIgWnDGTnmhr4gL/UmYdB+uQrYaF3IvGtlKZ4r0rDhczxg=" +var b64ViewConfidential = "CjIIAxIYMjAyMi0wOC0wNFQxODo1NzowNy44NTZaGgxOb3Rhcml6YXRpb24iBlNUUklORxLvHAr0CAjIARruCAqyAQqNAQQ/gq3dNCo0ZsXWbYd3aXjzOxl0xwzWgyLVEvQ8rHhD7tQyGPURFd3iAf4QVq16cqgJbMzNYLmfeZj82WF4txrhaKQQgjeyFuKulyO2J68yU/EjHwzvwSw4nTvQmFndWDOw/gDPJX4USGImlMka3zRZOyZDaRFsKGgvUDDhIfNsdde4FQefboLekvL+4xogKpBWaZBrQgTRjozQxmniu32oD/54hxpgRcQVkYRd3NESOXJlbGF5LW5ldHdvcmsxOjkwODAvbmV0d29yazEvbXljaGFubmVsOnNpbXBsZXN0YXRlOlJlYWQ6YRgBItMGLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNSekNDQWUyZ0F3SUJBZ0lVSmpaUVBsUDZSWFl2K1hmTEk2NmdCSjRkeG1Jd0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEl5TURnd05ERTRNamd3TUZvWERUTXlNRGd3TkRBMk16TXdNRm93SVRFUE1BMEcKQTFVRUN4TUdZMnhwWlc1ME1RNHdEQVlEVlFRREV3VjFjMlZ5TVRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OQpBd0VIQTBJQUJFT1VNRHdQT09ManMyVUd2SWhXaU1MdXdDK0dvRE5WMm56NnN0OUd6dWEyaDAxTThvOTVJaW82Cm16ZGxuOUw0cFptLzJIek1uQm95UEtycmpZUm1jaWFqZ2Jzd2diZ3dEZ1lEVlIwUEFRSC9CQVFEQWdlQU1Bd0cKQTFVZEV3RUIvd1FDTUFBd0hRWURWUjBPQkJZRUZDQ1laTWhoL0ZJT1c2emtCQkJJTndCb2JkcERNQjhHQTFVZApJd1FZTUJhQUZPRTQxd0VmQmdIZitjZmpRemF5RS9ROHBtMmJNRmdHQ0NvREJBVUdCd2dCQkV4N0ltRjBkSEp6CklqcDdJbWhtTGtGbVptbHNhV0YwYVc5dUlqb2lJaXdpYUdZdVJXNXliMnhzYldWdWRFbEVJam9pZFhObGNqRWkKTENKb1ppNVVlWEJsSWpvaVkyeHBaVzUwSW4xOU1Bb0dDQ3FHU000OUJBTUNBMGdBTUVVQ0lRRHlVdk5YdDZuTQpsMC83Ry9vSmplQnl3c1FlTDRJVTJRREJTbWk3Wmsxb09RSWdJa1F0c2crZHVIT1dDWDYwelVFVGhYZVpzZzlVCmRRSEZYVm5jTEJXUWhMaz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoqJGRiNTAyZDQ0LTE1YmYtNGZjOC05ZTM0LWYzNDkzZWZmMTI4YRrJCwogGoFqJ55W3XeaUnS8uU10C2jSTsPxCJz2tceWBBp0lRMSpAsKnAISZgoKX2xpZmVjeWNsZRJYCigKIm5hbWVzcGFjZXMvZmllbGRzL2ludGVyb3AvU2VxdWVuY2USAggGCiwKJm5hbWVzcGFjZXMvZmllbGRzL3NpbXBsZXN0YXRlL1NlcXVlbmNlEgIIAxJ+CgdpbnRlcm9wEnMKHgoYAGFjY2Vzc0NvbnRyb2wAbmV0d29yazIAEgIIFwobChUAbWVtYmVyc2hpcABuZXR3b3JrMgASAggZChYKEAD0j7+/aW5pdGlhbGl6ZWQSAggHChwKFmUyZUNvbmZpZGVudGlhbGl0eUZsYWcSAggHEjIKC3NpbXBsZXN0YXRlEiMKFgoQAPSPv79pbml0aWFsaXplZBICCAQKCQoBYRIECAkQBhr0CAjIARruCAqyAQqNAQQ/gq3dNCo0ZsXWbYd3aXjzOxl0xwzWgyLVEvQ8rHhD7tQyGPURFd3iAf4QVq16cqgJbMzNYLmfeZj82WF4txrhaKQQgjeyFuKulyO2J68yU/EjHwzvwSw4nTvQmFndWDOw/gDPJX4USGImlMka3zRZOyZDaRFsKGgvUDDhIfNsdde4FQefboLekvL+4xogKpBWaZBrQgTRjozQxmniu32oD/54hxpgRcQVkYRd3NESOXJlbGF5LW5ldHdvcmsxOjkwODAvbmV0d29yazEvbXljaGFubmVsOnNpbXBsZXN0YXRlOlJlYWQ6YRgBItMGLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNSekNDQWUyZ0F3SUJBZ0lVSmpaUVBsUDZSWFl2K1hmTEk2NmdCSjRkeG1Jd0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEl5TURnd05ERTRNamd3TUZvWERUTXlNRGd3TkRBMk16TXdNRm93SVRFUE1BMEcKQTFVRUN4TUdZMnhwWlc1ME1RNHdEQVlEVlFRREV3VjFjMlZ5TVRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OQpBd0VIQTBJQUJFT1VNRHdQT09ManMyVUd2SWhXaU1MdXdDK0dvRE5WMm56NnN0OUd6dWEyaDAxTThvOTVJaW82Cm16ZGxuOUw0cFptLzJIek1uQm95UEtycmpZUm1jaWFqZ2Jzd2diZ3dEZ1lEVlIwUEFRSC9CQVFEQWdlQU1Bd0cKQTFVZEV3RUIvd1FDTUFBd0hRWURWUjBPQkJZRUZDQ1laTWhoL0ZJT1c2emtCQkJJTndCb2JkcERNQjhHQTFVZApJd1FZTUJhQUZPRTQxd0VmQmdIZitjZmpRemF5RS9ROHBtMmJNRmdHQ0NvREJBVUdCd2dCQkV4N0ltRjBkSEp6CklqcDdJbWhtTGtGbVptbHNhV0YwYVc5dUlqb2lJaXdpYUdZdVJXNXliMnhzYldWdWRFbEVJam9pZFhObGNqRWkKTENKb1ppNVVlWEJsSWpvaVkyeHBaVzUwSW4xOU1Bb0dDQ3FHU000OUJBTUNBMGdBTUVVQ0lRRHlVdk5YdDZuTQpsMC83Ry9vSmplQnl3c1FlTDRJVTJRREJTbWk3Wmsxb09RSWdJa1F0c2crZHVIT1dDWDYwelVFVGhYZVpzZzlVCmRRSEZYVm5jTEJXUWhMaz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoqJGRiNTAyZDQ0LTE1YmYtNGZjOC05ZTM0LWYzNDkzZWZmMTI4YSIMEgdpbnRlcm9wGgExIqkICt0HCgdPcmcxTVNQEtEHLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNvekNDQWttZ0F3SUJBZ0lVRUNkM0pzZ1hwVUUyd01nNTVQMXYvRFp6b2l3d0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEl5TURnd05ERTRNakl3TUZvWERUTXlNRGd3TkRBMk1qY3dNRm93V3pFTE1Ba0cKQTFVRUJoTUNWVk14RnpBVkJnTlZCQWdURGs1dmNuUm9JRU5oY205c2FXNWhNUlF3RWdZRFZRUUtFd3RJZVhCbApjbXhsWkdkbGNqRU5NQXNHQTFVRUN4TUVjR1ZsY2pFT01Bd0dBMVVFQXhNRmNHVmxjakF3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFSaU5XNGF4VVFsOFkvNTYxaGFVN3hZM1E5NjkzNEJIMDJwMjhPUWRTNGsKa1JnTm9ScDFiK0tHejBjSUl2Z0RUTmhDSXJrMExRem5hWGZIWWkxKytNR2RvNEhkTUlIYU1BNEdBMVVkRHdFQgovd1FFQXdJSGdEQU1CZ05WSFJNQkFmOEVBakFBTUIwR0ExVWREZ1FXQkJSZENoSkZ4RFRxUlRuU05tbWpiVm5vClJwZHFUekFmQmdOVkhTTUVHREFXZ0JUT3h3ekhvWWg1ZkcvZGtFakRlRU5SUWV5VlB6QWlCZ05WSFJFRUd6QVoKZ2hkd1pXVnlNQzV2Y21jeExtNWxkSGR2Y21zeExtTnZiVEJXQmdncUF3UUZCZ2NJQVFSS2V5SmhkSFJ5Y3lJNgpleUpvWmk1QlptWnBiR2xoZEdsdmJpSTZJaUlzSW1obUxrVnVjbTlzYkcxbGJuUkpSQ0k2SW5CbFpYSXdJaXdpCmFHWXVWSGx3WlNJNkluQmxaWElpZlgwd0NnWUlLb1pJemowRUF3SURTQUF3UlFJaEFPa2tLVDBaaGJvaDE2TjUKTnIxaVNoWGtPOUZGa0Zhd1N1Qi8wNnFGc0l4S0FpQmd3dGFocE05YjYyamxSK25xbGh4NnkyQ0J1K1MxWEZKbgpMME82aFVVTEN3PT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoSRzBFAiEAghlxfQj7OlrS4YKmDPgvrHhkxipXkjJtqdLyUXOAwmMCIHEdJUF3cSEIqSphe6Iz9veTddMcJU3BUTq4QFN9ZiCf" -var b64ViewContents = "CghBcmN0dXJ1cxIQTZKuC0jTLZxn3JowK/x2Xg==" +var b64ViewContents = "CghBcmN0dXJ1cxIQARfOa/iwhY2JU95UJWdq1w==" -var fabricCaCertNetwork1 = "-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR\nynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq\nm2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd\nzQkhznMIF4SBF4k=\n-----END CERTIFICATE-----\n" +var fabricCaCertNetwork1 = "-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUYxHjCF1HdZexrgAM73ec4jdHy8owCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE76ubZH/VHJszsYLHVKaUwKBR\nUZv8P+Jq6Op5PeBf02JUKPM15DSF9n56RJq+7mrM9zBzPvBsUySFd+rr/BrsW6NF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFM7HDMehiHl8b92QSMN4Q1FB7JU/MAoGCCqGSM49BAMCA0cAMEQCIH4UJq+qY2OP\n7DzBAwY7woYuy4zoT2kxyiexlix38aY4AiAo+8OKE1wFM+XKLUqI4zzgq2bpg1qb\nU5aIsTpdz3N2tg==\n-----END CERTIFICATE-----\n" var network1Member = common.Member{ diff --git a/samples/fabric/fabric-cli/src/helpers/helpers.ts b/samples/fabric/fabric-cli/src/helpers/helpers.ts index 4131e35f8..b8c61c606 100644 --- a/samples/fabric/fabric-cli/src/helpers/helpers.ts +++ b/samples/fabric/fabric-cli/src/helpers/helpers.ts @@ -840,10 +840,14 @@ const interopHelper = async ( interopFlowResponse.views[0].toObject() )}. Interop Flow result: ${interopFlowResponse.result || 'successful'}` ) + logger.debug(`ViewB64: ${Buffer.from(interopFlowResponse.views[0].serializeBinary()).toString('base64')}`) const remoteValue = (options['e2e-confidentiality'] === 'true' ? InteroperableHelper.getResponseDataFromView(interopFlowResponse.views[0], keyCert.key.toBytes()) : InteroperableHelper.getResponseDataFromView(interopFlowResponse.views[0]) ) + if (remoteValue.contents) { + logger.debug(`ViewB64Contents: ${Buffer.from(remoteValue.contents).toString('base64')}`) + } spinner.succeed( `Called Function ${applicationFunction}. With Args: ${invokeObject.ccArgs} ${remoteValue.data}` ) From 0ed1f37ecac7939554176f7dc81cad85843554d3 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Mon, 8 Aug 2022 19:07:30 +0530 Subject: [PATCH 085/150] read test data from files for both fabric and corda interop unit tests Signed-off-by: sandeep.nishad1 --- .../interop-workflows/build.gradle | 1 + .../app/interop/WriteExternalStateTest.kt | 41 +++-- .../test_data/corda_cacert_doorman.pem | 15 ++ .../resources/test_data/corda_cacert_node.pem | 16 ++ .../resources/test_data/corda_cacert_root.pem | 13 ++ .../resources/test_data/corda_viewdata.json | 7 + .../resources/test_data/fabric_cacert.pem | 14 ++ .../resources/test_data/fabric_viewdata.json | 7 + core/network/fabric-interop-cc/.env.template | 2 +- .../test_data/corda_cacert_doorman.pem | 15 ++ .../interop/test_data/corda_cacert_node.pem | 16 ++ .../interop/test_data/corda_cacert_root.pem | 13 ++ .../interop/test_data/corda_viewdata.json | 7 + .../interop/test_data/fabric_cacert.pem | 14 ++ .../interop/test_data/fabric_viewdata.json | 7 + .../interop/write_external_state_test.go | 142 ++++++++++-------- 16 files changed, 250 insertions(+), 80 deletions(-) create mode 100644 core/network/corda-interop-app/interop-workflows/src/test/resources/test_data/corda_cacert_doorman.pem create mode 100644 core/network/corda-interop-app/interop-workflows/src/test/resources/test_data/corda_cacert_node.pem create mode 100644 core/network/corda-interop-app/interop-workflows/src/test/resources/test_data/corda_cacert_root.pem create mode 100644 core/network/corda-interop-app/interop-workflows/src/test/resources/test_data/corda_viewdata.json create mode 100644 core/network/corda-interop-app/interop-workflows/src/test/resources/test_data/fabric_cacert.pem create mode 100644 core/network/corda-interop-app/interop-workflows/src/test/resources/test_data/fabric_viewdata.json create mode 100644 core/network/fabric-interop-cc/contracts/interop/test_data/corda_cacert_doorman.pem create mode 100644 core/network/fabric-interop-cc/contracts/interop/test_data/corda_cacert_node.pem create mode 100644 core/network/fabric-interop-cc/contracts/interop/test_data/corda_cacert_root.pem create mode 100644 core/network/fabric-interop-cc/contracts/interop/test_data/corda_viewdata.json create mode 100644 core/network/fabric-interop-cc/contracts/interop/test_data/fabric_cacert.pem create mode 100644 core/network/fabric-interop-cc/contracts/interop/test_data/fabric_viewdata.json diff --git a/core/network/corda-interop-app/interop-workflows/build.gradle b/core/network/corda-interop-app/interop-workflows/build.gradle index 01e8f91b4..fa6011c3a 100644 --- a/core/network/corda-interop-app/interop-workflows/build.gradle +++ b/core/network/corda-interop-app/interop-workflows/build.gradle @@ -63,6 +63,7 @@ configurations { dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" + implementation 'com.google.code.gson:gson:2.9.1' testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" testCompile "junit:junit:$junit_version" diff --git a/core/network/corda-interop-app/interop-workflows/src/test/kotlin/com/weaver/corda/app/interop/WriteExternalStateTest.kt b/core/network/corda-interop-app/interop-workflows/src/test/kotlin/com/weaver/corda/app/interop/WriteExternalStateTest.kt index a2b0f73f7..df2f63656 100644 --- a/core/network/corda-interop-app/interop-workflows/src/test/kotlin/com/weaver/corda/app/interop/WriteExternalStateTest.kt +++ b/core/network/corda-interop-app/interop-workflows/src/test/kotlin/com/weaver/corda/app/interop/WriteExternalStateTest.kt @@ -18,6 +18,8 @@ import org.junit.BeforeClass import org.junit.Test import kotlin.test.assertEquals import kotlin.test.assertTrue +import com.google.gson.Gson +import com.google.gson.annotations.SerializedName class WriteExternalStateTest { companion object { @@ -46,10 +48,16 @@ class WriteExternalStateTest { val fabricNetwork = "network1" val fabricRelayEndpoint = "relay-network1:9080" val fabricViewAddress = "mychannel:simplestate:Read:a" - - val b64FabricView = "CjIIAxIYMjAyMi0wOC0wNFQxMDoyNDo0Ny42MDVaGgxOb3Rhcml6YXRpb24iBlNUUklORxKLGgrFBwjIARq/BwoGMTcuNjcxEjlyZWxheS1uZXR3b3JrMTo5MDgwL25ldHdvcmsxL215Y2hhbm5lbDpzaW1wbGVzdGF0ZTpSZWFkOmEi0wYtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ1JqQ0NBZTJnQXdJQkFnSVVSUlJDZGJaNjNpNTlNM3c2OFA1STI1cnoyTEF3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRBMk5USXdNRm9YRFRJek1EZ3dOREEyTlRjd01Gb3dJVEVQTUEwRwpBMVVFQ3hNR1kyeHBaVzUwTVE0d0RBWURWUVFERXdWMWMyVnlNVEJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5CkF3RUhBMElBQk5PZ29SYnJndGZYeHFhL21iQlFObXl4MVBJWExBdWFNV3BxQUl1MUx3MUxNMjh0SnRoT0pxWFUKejZFd0hMR2VMbGJ2U0VUNnhtb1hyZ0l2QkIxWndHNmpnYnN3Z2Jnd0RnWURWUjBQQVFIL0JBUURBZ2VBTUF3RwpBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRk1zWFA3QmpNc21mVXVLZnVlVXNyWTc0cFgwR01COEdBMVVkCkl3UVlNQmFBRlB3ZTFMck51STMzVm0rRWRnTy9FL2pKaWhVMU1GZ0dDQ29EQkFVR0J3Z0JCRXg3SW1GMGRISnoKSWpwN0ltaG1Ma0ZtWm1sc2FXRjBhVzl1SWpvaUlpd2lhR1l1Ulc1eWIyeHNiV1Z1ZEVsRUlqb2lkWE5sY2pFaQpMQ0pvWmk1VWVYQmxJam9pWTJ4cFpXNTBJbjE5TUFvR0NDcUdTTTQ5QkFNQ0EwY0FNRVFDSUJCLzY4MVdmQlIrClFXSUdmaVlLT2szSHVSdE84SkZ3YlRpRWpuQWdDUnZuQWlCYTY5d1dZYVoyNVpSK0dheTY5ZVYrdkRaa1BNSFMKZ2RSakFJdGNLR3N0Rmc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCiokZWE3OWU2NjQtYTJmMi00YzlmLTg2NDMtZTYwNjAwODhmYzlhGpgKCiBVNNh9oMmGr6mjpkClfw32G8jILQMdz9o0hFOMbTk7vRLzCQqaAhJmCgpfbGlmZWN5Y2xlElgKKAoibmFtZXNwYWNlcy9maWVsZHMvaW50ZXJvcC9TZXF1ZW5jZRICCAYKLAombmFtZXNwYWNlcy9maWVsZHMvc2ltcGxlc3RhdGUvU2VxdWVuY2USAggDEn4KB2ludGVyb3AScwoeChgAYWNjZXNzQ29udHJvbABuZXR3b3JrMgASAggUChsKFQBtZW1iZXJzaGlwAG5ldHdvcmsyABICCBYKFgoQAPSPv79pbml0aWFsaXplZBICCAcKHAoWZTJlQ29uZmlkZW50aWFsaXR5RmxhZxICCAcSMAoLc2ltcGxlc3RhdGUSIQoWChAA9I+/v2luaXRpYWxpemVkEgIIBAoHCgFhEgIIGhrFBwjIARq/BwoGMTcuNjcxEjlyZWxheS1uZXR3b3JrMTo5MDgwL25ldHdvcmsxL215Y2hhbm5lbDpzaW1wbGVzdGF0ZTpSZWFkOmEi0wYtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ1JqQ0NBZTJnQXdJQkFnSVVSUlJDZGJaNjNpNTlNM3c2OFA1STI1cnoyTEF3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRBMk5USXdNRm9YRFRJek1EZ3dOREEyTlRjd01Gb3dJVEVQTUEwRwpBMVVFQ3hNR1kyeHBaVzUwTVE0d0RBWURWUVFERXdWMWMyVnlNVEJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5CkF3RUhBMElBQk5PZ29SYnJndGZYeHFhL21iQlFObXl4MVBJWExBdWFNV3BxQUl1MUx3MUxNMjh0SnRoT0pxWFUKejZFd0hMR2VMbGJ2U0VUNnhtb1hyZ0l2QkIxWndHNmpnYnN3Z2Jnd0RnWURWUjBQQVFIL0JBUURBZ2VBTUF3RwpBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRk1zWFA3QmpNc21mVXVLZnVlVXNyWTc0cFgwR01COEdBMVVkCkl3UVlNQmFBRlB3ZTFMck51STMzVm0rRWRnTy9FL2pKaWhVMU1GZ0dDQ29EQkFVR0J3Z0JCRXg3SW1GMGRISnoKSWpwN0ltaG1Ma0ZtWm1sc2FXRjBhVzl1SWpvaUlpd2lhR1l1Ulc1eWIyeHNiV1Z1ZEVsRUlqb2lkWE5sY2pFaQpMQ0pvWmk1VWVYQmxJam9pWTJ4cFpXNTBJbjE5TUFvR0NDcUdTTTQ5QkFNQ0EwY0FNRVFDSUJCLzY4MVdmQlIrClFXSUdmaVlLT2szSHVSdE84SkZ3YlRpRWpuQWdDUnZuQWlCYTY5d1dZYVoyNVpSK0dheTY5ZVYrdkRaa1BNSFMKZ2RSakFJdGNLR3N0Rmc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCiokZWE3OWU2NjQtYTJmMi00YzlmLTg2NDMtZTYwNjAwODhmYzlhIgwSB2ludGVyb3AaATEipQgK2QcKB09yZzFNU1ASzQctLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ29qQ0NBa21nQXdJQkFnSVVHeDlQUksyN0ZOR0RVN012S3V3eGFRZXRaMTh3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRBMk1ESXdNRm9YRFRJek1EZ3dOREEyTURjd01Gb3dXekVMTUFrRwpBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRS0V3dEllWEJsCmNteGxaR2RsY2pFTk1Bc0dBMVVFQ3hNRWNHVmxjakVPTUF3R0ExVUVBeE1GY0dWbGNqQXdXVEFUQmdjcWhrak8KUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVF5ZmFPOFJSUW1JNzY1MXBlOUliU0diSGc5dHh0QUpQS1F6cHIzYzBmQgpZV0tFWmZTR2hUYWVnb21jNkhUVCtGNXhpMkV1YVZkZFo2cTBwMlh4MmRKRm80SGRNSUhhTUE0R0ExVWREd0VCCi93UUVBd0lIZ0RBTUJnTlZIUk1CQWY4RUFqQUFNQjBHQTFVZERnUVdCQlNNVDJ2c0xQVm1xV0xMbEFwbVpmSGIKSnFEamlEQWZCZ05WSFNNRUdEQVdnQlFxRWRTWmIzMEYzckFLWjRsRnJYSXRYRjRqakRBaUJnTlZIUkVFR3pBWgpnaGR3WldWeU1DNXZjbWN4TG01bGRIZHZjbXN4TG1OdmJUQldCZ2dxQXdRRkJnY0lBUVJLZXlKaGRIUnljeUk2CmV5Sm9aaTVCWm1acGJHbGhkR2x2YmlJNklpSXNJbWhtTGtWdWNtOXNiRzFsYm5SSlJDSTZJbkJsWlhJd0lpd2kKYUdZdVZIbHdaU0k2SW5CbFpYSWlmWDB3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnWlE1YTNtekpaK3pmUDlyTwpjWU9vWEQ5UDVqeE1oUmNMQlBQZ0dnL2JLbllDSUNyM3FlSmdzeFgrRWlBV2drSjNHeFdjK1pRRnNzbTlqTWJBCnIxWGJmK0tJCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KEkcwRQIhAM1Gyv7e+SYniXLgB8iBuRqS4C/A9D36SLl4Zj/AkxrpAiByAoaBFpRIMEJsmGasggaQ4AUST+M2n8ctBZCHjDwRxQ==" - - val fabricCert = "-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR\nynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq\nm2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd\nzQkhznMIF4SBF4k=\n-----END CERTIFICATE-----\n" + + data class TestData( + @SerializedName("view64") val B64View: String, + @SerializedName("confidential_view64") val B64ViewConfidential: String, + @SerializedName("confidential_view_content64") val B64ViewContents: String + ) + val fabricTestDataJSON = javaClass.getResource("/test_data/fabric_viewdata.json").readText(Charsets.UTF_8) + val fabricTestData = Gson().fromJson(fabricTestDataJSON, TestData::class.java) + + val fabricCert = javaClass.getResource("/test_data/fabric_cacert.pem").readText(Charsets.UTF_8) val fabricVerificationPolicy = VerificationPolicyState( securityDomain = fabricNetwork, @@ -67,8 +75,9 @@ class WriteExternalStateTest { chain = listOf("") )) ) - - val cordaB64View = "CjQIBBIcVHVlIE5vdiAxNyAwMDoxMzo0NiBHTVQgMjAyMBoMTm90YXJpemF0aW9uIgRKU09OEtYHCoQGClhhMjZHVW9WYythenlIMENUYjN2K2pTdmp3Y255M0hFd3AyMlJrdDkvZC9GcXN4WVVvYXhVWTdUOWNKRk9TVTZiVW42UFIwNmFVckxxdjZLbzZ1NG5CUT09Ep8FLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJ3akNDQVYrZ0F3SUJBZ0lJVUprUXZtS20zNVl3RkFZSUtvWkl6ajBFQXdJR0NDcUdTTTQ5QXdFSE1DOHgKQ3pBSkJnTlZCQVlUQWtkQ01ROHdEUVlEVlFRSERBWk1iMjVrYjI0eER6QU5CZ05WQkFvTUJsQmhjblI1UVRBZQpGdzB5TURBM01qUXdNREF3TURCYUZ3MHlOekExTWpBd01EQXdNREJhTUM4eEN6QUpCZ05WQkFZVEFrZENNUTh3CkRRWURWUVFIREFaTWIyNWtiMjR4RHpBTkJnTlZCQW9NQmxCaGNuUjVRVEFxTUFVR0F5dGxjQU1oQU1NS2FSRUsKaGNUZ1NCTU16Szgxb1BVU1BvVm1HL2ZKTUxYcS91alNtc2U5bzRHSk1JR0dNQjBHQTFVZERnUVdCQlJNWHREcwpLRlp6VUxkUTNjMkRDVUV4M1QxQ1VEQVBCZ05WSFJNQkFmOEVCVEFEQVFIL01Bc0dBMVVkRHdRRUF3SUNoREFUCkJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREFqQWZCZ05WSFNNRUdEQVdnQlI0aHdMdUxnZklaTUVXekc0bjNBeHcKZmdQYmV6QVJCZ29yQmdFRUFZT0tZZ0VCQkFNQ0FRWXdGQVlJS29aSXpqMEVBd0lHQ0NxR1NNNDlBd0VIQTBjQQpNRVFDSUM3SjQ2U3hERHozTGpETnJFUGpqd1AycHJnTUVNaDdyL2dKcG91UUhCaytBaUErS3pYRDBkNW1pSTg2CkQybVlLNEMzdFJsaTNYM1ZnbkNlOENPcWZZeXVRZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0aBlBhcnR5QRLMAQpsW1NpbXBsZVN0YXRlKGtleT1ILCB2YWx1ZT0xLCBvd25lcj1PPVBhcnR5QSwgTD1Mb25kb24sIEM9R0IsIGxpbmVhcklkPTIzMTRkNmI3LTFlY2EtNDg5Mi04OGY4LTc2ZDg1YjhhODVjZCldElxsb2NhbGhvc3Q6OTA4MC9Db3JkYV9OZXR3b3JrL2xvY2FsaG9zdDoxMDAwNiNjb20uY29yZGFTaW1wbGVBcHBsaWNhdGlvbi5mbG93LkdldFN0YXRlQnlLZXk6SA==" + + val cordaTestDataJSON = javaClass.getResource("/test_data/corda_viewdata.json").readText(Charsets.UTF_8) + val cordaTestData = Gson().fromJson(cordaTestDataJSON, TestData::class.java) val cordaVerificationPolicy = VerificationPolicyState( securityDomain = "Corda_Network", @@ -77,12 +86,17 @@ class WriteExternalStateTest { Policy("signature", listOf("PartyA")) )) ) - + + val rootCACert = javaClass.getResource("/test_data/corda_cacert_root.pem").readText(Charsets.UTF_8) + val doormanCACert = javaClass.getResource("/test_data/corda_cacert_doorman.pem").readText(Charsets.UTF_8) + val nodeCACert = javaClass.getResource("/test_data/corda_cacert_node.pem").readText(Charsets.UTF_8) val certChain = listOf( - "-----BEGIN CERTIFICATE-----\nMIICCTCCAbCgAwIBAgIIcFe0qctqSucwCgYIKoZIzj0EAwIwWDEbMBkGA1UEAwwS\nQ29yZGEgTm9kZSBSb290IENBMQswCQYDVQQKDAJSMzEOMAwGA1UECwwFY29yZGEx\nDzANBgNVBAcMBkxvbmRvbjELMAkGA1UEBhMCVUswHhcNMTcwNTIyMDAwMDAwWhcN\nMjcwNTIwMDAwMDAwWjBYMRswGQYDVQQDDBJDb3JkYSBOb2RlIFJvb3QgQ0ExCzAJ\nBgNVBAoMAlIzMQ4wDAYDVQQLDAVjb3JkYTEPMA0GA1UEBwwGTG9uZG9uMQswCQYD\nVQQGEwJVSzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGlm6LFHrVkzfuUHin36\nJrm1aUMarX/NUZXw8n8gSiJmsZPlUEplJ+f/lzZMky5EZPTtCciG34pnOP0eiMd/\nJTCjZDBiMB0GA1UdDgQWBBR8rqnfuUgBKxOJC5rmRYUcORcHczALBgNVHQ8EBAMC\nAYYwIwYDVR0lBBwwGgYIKwYBBQUHAwEGCCsGAQUFBwMCBgRVHSUAMA8GA1UdEwEB\n/wQFMAMBAf8wCgYIKoZIzj0EAwIDRwAwRAIgDaL4SguKsNeTT7SeUkFdoCBACeG8\nGqO4M1KlfimphQwCICiq00hDanT5W8bTLqE7GIGuplf/O8AABlpWrUg6uiUB\n-----END CERTIFICATE-----", - "-----BEGIN CERTIFICATE-----\nMIICXjCCAfugAwIBAgIIHVb6wd3RHhIwFAYIKoZIzj0EAwIGCCqGSM49AwEHMFgx\nGzAZBgNVBAMMEkNvcmRhIE5vZGUgUm9vdCBDQTELMAkGA1UECgwCUjMxDjAMBgNV\nBAsMBWNvcmRhMQ8wDQYDVQQHDAZMb25kb24xCzAJBgNVBAYTAlVLMB4XDTE4MDcx\nMDAwMDAwMFoXDTI3MDUyMDAwMDAwMFowYzELMAkGA1UEBhMCVVMxETAPBgNVBAcT\nCE5ldyBZb3JrMQ4wDAYDVQQLEwVDb3JkYTEWMBQGA1UEChMNUjMgSG9sZENvIExM\nQzEZMBcGA1UEAxMQQ29yZGEgRG9vcm1hbiBDQTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABAPL3qAm4WZms5ciBVoxMQXfK7uTmHRVvWfWQ+QVYP3bMHSguHZRzB3v\n7EOE8RZpGDan+w007Xj7XR0+xG9SxmCjgZkwgZYwHQYDVR0OBBYEFOvuLjAVKUCu\nGZge2G/jfX8HosITMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgGGMCMGA1Ud\nJQQcMBoGCCsGAQUFBwMBBggrBgEFBQcDAgYEVR0lADAfBgNVHSMEGDAWgBR8rqnf\nuUgBKxOJC5rmRYUcORcHczARBgorBgEEAYOKYgEBBAMCAQEwFAYIKoZIzj0EAwIG\nCCqGSM49AwEHA0cAMEQCIBmzQXpnCo9eAxkhwMt0bBr1Q0APJXF0KuBRsFBWAa6S\nAiBgx6G8G9Ij7B8+y65ItLKVcs7Kh6Rdnr5/1zB/yPwfrg==\n-----END CERTIFICATE-----", - "-----BEGIN CERTIFICATE-----\nMIICbTCCAgmgAwIBAgIIYRljUiZaGSkwFAYIKoZIzj0EAwIGCCqGSM49AwEHMGMx\nCzAJBgNVBAYTAlVTMREwDwYDVQQHEwhOZXcgWW9yazEOMAwGA1UECxMFQ29yZGEx\nFjAUBgNVBAoTDVIzIEhvbGRDbyBMTEMxGTAXBgNVBAMTEENvcmRhIERvb3JtYW4g\nQ0EwHhcNMjAwNzI0MDAwMDAwWhcNMjcwNTIwMDAwMDAwWjAvMQswCQYDVQQGEwJH\nQjEPMA0GA1UEBwwGTG9uZG9uMQ8wDQYDVQQKDAZQYXJ0eUEwWTATBgcqhkjOPQIB\nBggqhkjOPQMBBwNCAASFze6k3tINqGLsKTi0a50RpOUCysno1/1lwIfEqaboauuj\no6Ecfu8X1WnW92VrEZGKslIJzR8R0deOEJvBs0rzo4HQMIHNMB0GA1UdDgQWBBR4\nhwLuLgfIZMEWzG4n3AxwfgPbezAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB\nhjATBgNVHSUEDDAKBggrBgEFBQcDAjAfBgNVHSMEGDAWgBTr7i4wFSlArhmYHthv\n431/B6LCEzARBgorBgEEAYOKYgEBBAMCAQQwRQYDVR0eAQH/BDswOaA1MDOkMTAv\nMQswCQYDVQQGEwJHQjEPMA0GA1UEBwwGTG9uZG9uMQ8wDQYDVQQKDAZQYXJ0eUGh\nADAUBggqhkjOPQQDAgYIKoZIzj0DAQcDSAAwRQIhANXBVAebUsY9AMfjZedNYN14\nWy76Ru5vMSta3Av1d08lAiAi2GZWk5XwJoEYuhQHXsHQLZbXphAVk+Q5tVgMgywj\ntQ==\n-----END CERTIFICATE-----") + rootCACert, + doormanCACert, + nodeCACert) + /* val cordaCert = javaClass.getResource("/test_data/corda_cacert.pem").readText(Charsets.UTF_8) */ + val cordaMembership = MembershipState( securityDomain = "Corda_Network", members = mapOf("PartyA" to Member( @@ -96,6 +110,7 @@ class WriteExternalStateTest { fun `WriteExternalState tests`() { // Corda happy case // Create corda membership and verificationPolicy in vault + println(fabricCert) val future = partyA.startFlow(CreateVerificationPolicyState(cordaVerificationPolicy)) network.runNetwork() val linearId = future.getOrThrow() @@ -106,7 +121,7 @@ class WriteExternalStateTest { val linearId2 = future2.getOrThrow() assert(linearId2.isRight()) { "CreateMembershipState should return a Right(UniqueIdentifier)" } - val happyFuture = partyA.startFlow(WriteExternalStateInitiator(cordaB64View, "localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H")) + val happyFuture = partyA.startFlow(WriteExternalStateInitiator(cordaTestData.B64View, "localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H")) network.runNetwork() val happyLinearId = happyFuture.getOrThrow() assertTrue(happyLinearId.isRight()) @@ -123,7 +138,7 @@ class WriteExternalStateTest { val linearId4 = future4.getOrThrow() assert(linearId4.isRight()) { "CreateMembershipState should return a Right(UniqueIdentifier)" } - val happyFuture2 = partyA.startFlow(WriteExternalStateInitiator(b64FabricView, "${fabricRelayEndpoint}/${fabricNetwork}/${fabricViewAddress}")) + val happyFuture2 = partyA.startFlow(WriteExternalStateInitiator(fabricTestData.B64View, "${fabricRelayEndpoint}/${fabricNetwork}/${fabricViewAddress}")) network.runNetwork() val happyLinearId2 = happyFuture2.getOrThrow() assertTrue(happyLinearId2.isRight()) @@ -139,7 +154,7 @@ class WriteExternalStateTest { val linearId5 = future5.getOrThrow() assert(linearId5.isRight()) { "UpdateMembershipState should return a Right(UniqueIdentifier)" } - val unhappyFuture = partyA.startFlow(WriteExternalStateInitiator(cordaB64View, "localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H")) + val unhappyFuture = partyA.startFlow(WriteExternalStateInitiator(cordaTestData.B64View, "localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H")) network.runNetwork() val unhappyLinearId = unhappyFuture.getOrThrow() assertTrue(unhappyLinearId.isLeft()) diff --git a/core/network/corda-interop-app/interop-workflows/src/test/resources/test_data/corda_cacert_doorman.pem b/core/network/corda-interop-app/interop-workflows/src/test/resources/test_data/corda_cacert_doorman.pem new file mode 100644 index 000000000..4ca4d78eb --- /dev/null +++ b/core/network/corda-interop-app/interop-workflows/src/test/resources/test_data/corda_cacert_doorman.pem @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICXjCCAfugAwIBAgIIHVb6wd3RHhIwFAYIKoZIzj0EAwIGCCqGSM49AwEHMFgx +GzAZBgNVBAMMEkNvcmRhIE5vZGUgUm9vdCBDQTELMAkGA1UECgwCUjMxDjAMBgNV +BAsMBWNvcmRhMQ8wDQYDVQQHDAZMb25kb24xCzAJBgNVBAYTAlVLMB4XDTE4MDcx +MDAwMDAwMFoXDTI3MDUyMDAwMDAwMFowYzELMAkGA1UEBhMCVVMxETAPBgNVBAcT +CE5ldyBZb3JrMQ4wDAYDVQQLEwVDb3JkYTEWMBQGA1UEChMNUjMgSG9sZENvIExM +QzEZMBcGA1UEAxMQQ29yZGEgRG9vcm1hbiBDQTBZMBMGByqGSM49AgEGCCqGSM49 +AwEHA0IABAPL3qAm4WZms5ciBVoxMQXfK7uTmHRVvWfWQ+QVYP3bMHSguHZRzB3v +7EOE8RZpGDan+w007Xj7XR0+xG9SxmCjgZkwgZYwHQYDVR0OBBYEFOvuLjAVKUCu +GZge2G/jfX8HosITMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgGGMCMGA1Ud +JQQcMBoGCCsGAQUFBwMBBggrBgEFBQcDAgYEVR0lADAfBgNVHSMEGDAWgBR8rqnf +uUgBKxOJC5rmRYUcORcHczARBgorBgEEAYOKYgEBBAMCAQEwFAYIKoZIzj0EAwIG +CCqGSM49AwEHA0cAMEQCIBmzQXpnCo9eAxkhwMt0bBr1Q0APJXF0KuBRsFBWAa6S +AiBgx6G8G9Ij7B8+y65ItLKVcs7Kh6Rdnr5/1zB/yPwfrg== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/core/network/corda-interop-app/interop-workflows/src/test/resources/test_data/corda_cacert_node.pem b/core/network/corda-interop-app/interop-workflows/src/test/resources/test_data/corda_cacert_node.pem new file mode 100644 index 000000000..6dfb29cb0 --- /dev/null +++ b/core/network/corda-interop-app/interop-workflows/src/test/resources/test_data/corda_cacert_node.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIICbTCCAgmgAwIBAgIIYRljUiZaGSkwFAYIKoZIzj0EAwIGCCqGSM49AwEHMGMx +CzAJBgNVBAYTAlVTMREwDwYDVQQHEwhOZXcgWW9yazEOMAwGA1UECxMFQ29yZGEx +FjAUBgNVBAoTDVIzIEhvbGRDbyBMTEMxGTAXBgNVBAMTEENvcmRhIERvb3JtYW4g +Q0EwHhcNMjAwNzI0MDAwMDAwWhcNMjcwNTIwMDAwMDAwWjAvMQswCQYDVQQGEwJH +QjEPMA0GA1UEBwwGTG9uZG9uMQ8wDQYDVQQKDAZQYXJ0eUEwWTATBgcqhkjOPQIB +BggqhkjOPQMBBwNCAASFze6k3tINqGLsKTi0a50RpOUCysno1/1lwIfEqaboauuj +o6Ecfu8X1WnW92VrEZGKslIJzR8R0deOEJvBs0rzo4HQMIHNMB0GA1UdDgQWBBR4 +hwLuLgfIZMEWzG4n3AxwfgPbezAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB +hjATBgNVHSUEDDAKBggrBgEFBQcDAjAfBgNVHSMEGDAWgBTr7i4wFSlArhmYHthv +431/B6LCEzARBgorBgEEAYOKYgEBBAMCAQQwRQYDVR0eAQH/BDswOaA1MDOkMTAv +MQswCQYDVQQGEwJHQjEPMA0GA1UEBwwGTG9uZG9uMQ8wDQYDVQQKDAZQYXJ0eUGh +ADAUBggqhkjOPQQDAgYIKoZIzj0DAQcDSAAwRQIhANXBVAebUsY9AMfjZedNYN14 +Wy76Ru5vMSta3Av1d08lAiAi2GZWk5XwJoEYuhQHXsHQLZbXphAVk+Q5tVgMgywj +tQ== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/core/network/corda-interop-app/interop-workflows/src/test/resources/test_data/corda_cacert_root.pem b/core/network/corda-interop-app/interop-workflows/src/test/resources/test_data/corda_cacert_root.pem new file mode 100644 index 000000000..3409b3d56 --- /dev/null +++ b/core/network/corda-interop-app/interop-workflows/src/test/resources/test_data/corda_cacert_root.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIICCTCCAbCgAwIBAgIIcFe0qctqSucwCgYIKoZIzj0EAwIwWDEbMBkGA1UEAwwS +Q29yZGEgTm9kZSBSb290IENBMQswCQYDVQQKDAJSMzEOMAwGA1UECwwFY29yZGEx +DzANBgNVBAcMBkxvbmRvbjELMAkGA1UEBhMCVUswHhcNMTcwNTIyMDAwMDAwWhcN +MjcwNTIwMDAwMDAwWjBYMRswGQYDVQQDDBJDb3JkYSBOb2RlIFJvb3QgQ0ExCzAJ +BgNVBAoMAlIzMQ4wDAYDVQQLDAVjb3JkYTEPMA0GA1UEBwwGTG9uZG9uMQswCQYD +VQQGEwJVSzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGlm6LFHrVkzfuUHin36 +Jrm1aUMarX/NUZXw8n8gSiJmsZPlUEplJ+f/lzZMky5EZPTtCciG34pnOP0eiMd/ +JTCjZDBiMB0GA1UdDgQWBBR8rqnfuUgBKxOJC5rmRYUcORcHczALBgNVHQ8EBAMC +AYYwIwYDVR0lBBwwGgYIKwYBBQUHAwEGCCsGAQUFBwMCBgRVHSUAMA8GA1UdEwEB +/wQFMAMBAf8wCgYIKoZIzj0EAwIDRwAwRAIgDaL4SguKsNeTT7SeUkFdoCBACeG8 +GqO4M1KlfimphQwCICiq00hDanT5W8bTLqE7GIGuplf/O8AABlpWrUg6uiUB +-----END CERTIFICATE----- \ No newline at end of file diff --git a/core/network/corda-interop-app/interop-workflows/src/test/resources/test_data/corda_viewdata.json b/core/network/corda-interop-app/interop-workflows/src/test/resources/test_data/corda_viewdata.json new file mode 100644 index 000000000..6061c5a61 --- /dev/null +++ b/core/network/corda-interop-app/interop-workflows/src/test/resources/test_data/corda_viewdata.json @@ -0,0 +1,7 @@ +{ + "view64": "CjQIBBIcVHVlIE5vdiAxNyAwMDoxMzo0NiBHTVQgMjAyMBoMTm90YXJpemF0aW9uIgRKU09OEtYHCoQGClhhMjZHVW9WYythenlIMENUYjN2K2pTdmp3Y255M0hFd3AyMlJrdDkvZC9GcXN4WVVvYXhVWTdUOWNKRk9TVTZiVW42UFIwNmFVckxxdjZLbzZ1NG5CUT09Ep8FLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJ3akNDQVYrZ0F3SUJBZ0lJVUprUXZtS20zNVl3RkFZSUtvWkl6ajBFQXdJR0NDcUdTTTQ5QXdFSE1DOHgKQ3pBSkJnTlZCQVlUQWtkQ01ROHdEUVlEVlFRSERBWk1iMjVrYjI0eER6QU5CZ05WQkFvTUJsQmhjblI1UVRBZQpGdzB5TURBM01qUXdNREF3TURCYUZ3MHlOekExTWpBd01EQXdNREJhTUM4eEN6QUpCZ05WQkFZVEFrZENNUTh3CkRRWURWUVFIREFaTWIyNWtiMjR4RHpBTkJnTlZCQW9NQmxCaGNuUjVRVEFxTUFVR0F5dGxjQU1oQU1NS2FSRUsKaGNUZ1NCTU16Szgxb1BVU1BvVm1HL2ZKTUxYcS91alNtc2U5bzRHSk1JR0dNQjBHQTFVZERnUVdCQlJNWHREcwpLRlp6VUxkUTNjMkRDVUV4M1QxQ1VEQVBCZ05WSFJNQkFmOEVCVEFEQVFIL01Bc0dBMVVkRHdRRUF3SUNoREFUCkJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREFqQWZCZ05WSFNNRUdEQVdnQlI0aHdMdUxnZklaTUVXekc0bjNBeHcKZmdQYmV6QVJCZ29yQmdFRUFZT0tZZ0VCQkFNQ0FRWXdGQVlJS29aSXpqMEVBd0lHQ0NxR1NNNDlBd0VIQTBjQQpNRVFDSUM3SjQ2U3hERHozTGpETnJFUGpqd1AycHJnTUVNaDdyL2dKcG91UUhCaytBaUErS3pYRDBkNW1pSTg2CkQybVlLNEMzdFJsaTNYM1ZnbkNlOENPcWZZeXVRZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0aBlBhcnR5QRLMAQpsW1NpbXBsZVN0YXRlKGtleT1ILCB2YWx1ZT0xLCBvd25lcj1PPVBhcnR5QSwgTD1Mb25kb24sIEM9R0IsIGxpbmVhcklkPTIzMTRkNmI3LTFlY2EtNDg5Mi04OGY4LTc2ZDg1YjhhODVjZCldElxsb2NhbGhvc3Q6OTA4MC9Db3JkYV9OZXR3b3JrL2xvY2FsaG9zdDoxMDAwNiNjb20uY29yZGFTaW1wbGVBcHBsaWNhdGlvbi5mbG93LkdldFN0YXRlQnlLZXk6SA==", + + "confidential_view64": "", + + "confidential_view_content64": "" +} \ No newline at end of file diff --git a/core/network/corda-interop-app/interop-workflows/src/test/resources/test_data/fabric_cacert.pem b/core/network/corda-interop-app/interop-workflows/src/test/resources/test_data/fabric_cacert.pem new file mode 100644 index 000000000..3d82333d8 --- /dev/null +++ b/core/network/corda-interop-app/interop-workflows/src/test/resources/test_data/fabric_cacert.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw +aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK +EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG +A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl +cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR +ynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF +MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE +FCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq +m2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd +zQkhznMIF4SBF4k= +-----END CERTIFICATE----- diff --git a/core/network/corda-interop-app/interop-workflows/src/test/resources/test_data/fabric_viewdata.json b/core/network/corda-interop-app/interop-workflows/src/test/resources/test_data/fabric_viewdata.json new file mode 100644 index 000000000..3d2672272 --- /dev/null +++ b/core/network/corda-interop-app/interop-workflows/src/test/resources/test_data/fabric_viewdata.json @@ -0,0 +1,7 @@ +{ + "view64": "CjIIAxIYMjAyMi0wOC0wNFQxMDoyNDo0Ny42MDVaGgxOb3Rhcml6YXRpb24iBlNUUklORxKLGgrFBwjIARq/BwoGMTcuNjcxEjlyZWxheS1uZXR3b3JrMTo5MDgwL25ldHdvcmsxL215Y2hhbm5lbDpzaW1wbGVzdGF0ZTpSZWFkOmEi0wYtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ1JqQ0NBZTJnQXdJQkFnSVVSUlJDZGJaNjNpNTlNM3c2OFA1STI1cnoyTEF3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRBMk5USXdNRm9YRFRJek1EZ3dOREEyTlRjd01Gb3dJVEVQTUEwRwpBMVVFQ3hNR1kyeHBaVzUwTVE0d0RBWURWUVFERXdWMWMyVnlNVEJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5CkF3RUhBMElBQk5PZ29SYnJndGZYeHFhL21iQlFObXl4MVBJWExBdWFNV3BxQUl1MUx3MUxNMjh0SnRoT0pxWFUKejZFd0hMR2VMbGJ2U0VUNnhtb1hyZ0l2QkIxWndHNmpnYnN3Z2Jnd0RnWURWUjBQQVFIL0JBUURBZ2VBTUF3RwpBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRk1zWFA3QmpNc21mVXVLZnVlVXNyWTc0cFgwR01COEdBMVVkCkl3UVlNQmFBRlB3ZTFMck51STMzVm0rRWRnTy9FL2pKaWhVMU1GZ0dDQ29EQkFVR0J3Z0JCRXg3SW1GMGRISnoKSWpwN0ltaG1Ma0ZtWm1sc2FXRjBhVzl1SWpvaUlpd2lhR1l1Ulc1eWIyeHNiV1Z1ZEVsRUlqb2lkWE5sY2pFaQpMQ0pvWmk1VWVYQmxJam9pWTJ4cFpXNTBJbjE5TUFvR0NDcUdTTTQ5QkFNQ0EwY0FNRVFDSUJCLzY4MVdmQlIrClFXSUdmaVlLT2szSHVSdE84SkZ3YlRpRWpuQWdDUnZuQWlCYTY5d1dZYVoyNVpSK0dheTY5ZVYrdkRaa1BNSFMKZ2RSakFJdGNLR3N0Rmc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCiokZWE3OWU2NjQtYTJmMi00YzlmLTg2NDMtZTYwNjAwODhmYzlhGpgKCiBVNNh9oMmGr6mjpkClfw32G8jILQMdz9o0hFOMbTk7vRLzCQqaAhJmCgpfbGlmZWN5Y2xlElgKKAoibmFtZXNwYWNlcy9maWVsZHMvaW50ZXJvcC9TZXF1ZW5jZRICCAYKLAombmFtZXNwYWNlcy9maWVsZHMvc2ltcGxlc3RhdGUvU2VxdWVuY2USAggDEn4KB2ludGVyb3AScwoeChgAYWNjZXNzQ29udHJvbABuZXR3b3JrMgASAggUChsKFQBtZW1iZXJzaGlwAG5ldHdvcmsyABICCBYKFgoQAPSPv79pbml0aWFsaXplZBICCAcKHAoWZTJlQ29uZmlkZW50aWFsaXR5RmxhZxICCAcSMAoLc2ltcGxlc3RhdGUSIQoWChAA9I+/v2luaXRpYWxpemVkEgIIBAoHCgFhEgIIGhrFBwjIARq/BwoGMTcuNjcxEjlyZWxheS1uZXR3b3JrMTo5MDgwL25ldHdvcmsxL215Y2hhbm5lbDpzaW1wbGVzdGF0ZTpSZWFkOmEi0wYtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ1JqQ0NBZTJnQXdJQkFnSVVSUlJDZGJaNjNpNTlNM3c2OFA1STI1cnoyTEF3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRBMk5USXdNRm9YRFRJek1EZ3dOREEyTlRjd01Gb3dJVEVQTUEwRwpBMVVFQ3hNR1kyeHBaVzUwTVE0d0RBWURWUVFERXdWMWMyVnlNVEJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5CkF3RUhBMElBQk5PZ29SYnJndGZYeHFhL21iQlFObXl4MVBJWExBdWFNV3BxQUl1MUx3MUxNMjh0SnRoT0pxWFUKejZFd0hMR2VMbGJ2U0VUNnhtb1hyZ0l2QkIxWndHNmpnYnN3Z2Jnd0RnWURWUjBQQVFIL0JBUURBZ2VBTUF3RwpBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRk1zWFA3QmpNc21mVXVLZnVlVXNyWTc0cFgwR01COEdBMVVkCkl3UVlNQmFBRlB3ZTFMck51STMzVm0rRWRnTy9FL2pKaWhVMU1GZ0dDQ29EQkFVR0J3Z0JCRXg3SW1GMGRISnoKSWpwN0ltaG1Ma0ZtWm1sc2FXRjBhVzl1SWpvaUlpd2lhR1l1Ulc1eWIyeHNiV1Z1ZEVsRUlqb2lkWE5sY2pFaQpMQ0pvWmk1VWVYQmxJam9pWTJ4cFpXNTBJbjE5TUFvR0NDcUdTTTQ5QkFNQ0EwY0FNRVFDSUJCLzY4MVdmQlIrClFXSUdmaVlLT2szSHVSdE84SkZ3YlRpRWpuQWdDUnZuQWlCYTY5d1dZYVoyNVpSK0dheTY5ZVYrdkRaa1BNSFMKZ2RSakFJdGNLR3N0Rmc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCiokZWE3OWU2NjQtYTJmMi00YzlmLTg2NDMtZTYwNjAwODhmYzlhIgwSB2ludGVyb3AaATEipQgK2QcKB09yZzFNU1ASzQctLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ29qQ0NBa21nQXdJQkFnSVVHeDlQUksyN0ZOR0RVN012S3V3eGFRZXRaMTh3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRBMk1ESXdNRm9YRFRJek1EZ3dOREEyTURjd01Gb3dXekVMTUFrRwpBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRS0V3dEllWEJsCmNteGxaR2RsY2pFTk1Bc0dBMVVFQ3hNRWNHVmxjakVPTUF3R0ExVUVBeE1GY0dWbGNqQXdXVEFUQmdjcWhrak8KUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVF5ZmFPOFJSUW1JNzY1MXBlOUliU0diSGc5dHh0QUpQS1F6cHIzYzBmQgpZV0tFWmZTR2hUYWVnb21jNkhUVCtGNXhpMkV1YVZkZFo2cTBwMlh4MmRKRm80SGRNSUhhTUE0R0ExVWREd0VCCi93UUVBd0lIZ0RBTUJnTlZIUk1CQWY4RUFqQUFNQjBHQTFVZERnUVdCQlNNVDJ2c0xQVm1xV0xMbEFwbVpmSGIKSnFEamlEQWZCZ05WSFNNRUdEQVdnQlFxRWRTWmIzMEYzckFLWjRsRnJYSXRYRjRqakRBaUJnTlZIUkVFR3pBWgpnaGR3WldWeU1DNXZjbWN4TG01bGRIZHZjbXN4TG1OdmJUQldCZ2dxQXdRRkJnY0lBUVJLZXlKaGRIUnljeUk2CmV5Sm9aaTVCWm1acGJHbGhkR2x2YmlJNklpSXNJbWhtTGtWdWNtOXNiRzFsYm5SSlJDSTZJbkJsWlhJd0lpd2kKYUdZdVZIbHdaU0k2SW5CbFpYSWlmWDB3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnWlE1YTNtekpaK3pmUDlyTwpjWU9vWEQ5UDVqeE1oUmNMQlBQZ0dnL2JLbllDSUNyM3FlSmdzeFgrRWlBV2drSjNHeFdjK1pRRnNzbTlqTWJBCnIxWGJmK0tJCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KEkcwRQIhAM1Gyv7e+SYniXLgB8iBuRqS4C/A9D36SLl4Zj/AkxrpAiByAoaBFpRIMEJsmGasggaQ4AUST+M2n8ctBZCHjDwRxQ==", + + "confidential_view64": "CjIIAxIYMjAyMi0wOC0wNFQxMDozMjoyMC4zMTlaGgxOb3Rhcml6YXRpb24iBlNUUklORxLrHAr0CAjIARruCAqyAQqNAQRdCc5yPbVtY77Ow/6sH6V8AOwbumdSxFq5T62tOT8LIThrPue3yCQBp7P5/6NoKRZR9grAbP9mVHiZ5814qf/DnXULpdh5O5EbVKSZX5BtmXCqTwpmZaqrQzAGgNXVzB8L6QSEVz48fp9X9SuA3r74mzNM5Ip6WbsNXnENpfifEbUfHcDUK28KHN9U+xogYzlOibmMtRdSuUyam+LQmZ5Y4/9X7AyhqEGNe0INblsSOXJlbGF5LW5ldHdvcmsxOjkwODAvbmV0d29yazEvbXljaGFubmVsOnNpbXBsZXN0YXRlOlJlYWQ6YRgBItMGLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNSakNDQWUyZ0F3SUJBZ0lVUlJSQ2RiWjYzaTU5TTN3NjhQNUkyNXJ6MkxBd0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEl5TURnd05EQTJOVEl3TUZvWERUSXpNRGd3TkRBMk5UY3dNRm93SVRFUE1BMEcKQTFVRUN4TUdZMnhwWlc1ME1RNHdEQVlEVlFRREV3VjFjMlZ5TVRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OQpBd0VIQTBJQUJOT2dvUmJyZ3RmWHhxYS9tYkJRTm15eDFQSVhMQXVhTVdwcUFJdTFMdzFMTTI4dEp0aE9KcVhVCno2RXdITEdlTGxidlNFVDZ4bW9YcmdJdkJCMVp3RzZqZ2Jzd2diZ3dEZ1lEVlIwUEFRSC9CQVFEQWdlQU1Bd0cKQTFVZEV3RUIvd1FDTUFBd0hRWURWUjBPQkJZRUZNc1hQN0JqTXNtZlV1S2Z1ZVVzclk3NHBYMEdNQjhHQTFVZApJd1FZTUJhQUZQd2UxTHJOdUkzM1ZtK0VkZ08vRS9qSmloVTFNRmdHQ0NvREJBVUdCd2dCQkV4N0ltRjBkSEp6CklqcDdJbWhtTGtGbVptbHNhV0YwYVc5dUlqb2lJaXdpYUdZdVJXNXliMnhzYldWdWRFbEVJam9pZFhObGNqRWkKTENKb1ppNVVlWEJsSWpvaVkyeHBaVzUwSW4xOU1Bb0dDQ3FHU000OUJBTUNBMGNBTUVRQ0lCQi82ODFXZkJSKwpRV0lHZmlZS09rM0h1UnRPOEpGd2JUaUVqbkFnQ1J2bkFpQmE2OXdXWWFaMjVaUitHYXk2OWVWK3ZEWmtQTUhTCmdkUmpBSXRjS0dzdEZnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoqJDQwZTFjMGUxLWJkZDctNDQ2MC04YzhhLWRlMTZhOWQyOGYwYRrJCwogZOyCYqcgmQJccj0IkSL3t+oNKIzv0PmJqnzbH2jfIV8SpAsKnAISZgoKX2xpZmVjeWNsZRJYCigKIm5hbWVzcGFjZXMvZmllbGRzL2ludGVyb3AvU2VxdWVuY2USAggGCiwKJm5hbWVzcGFjZXMvZmllbGRzL3NpbXBsZXN0YXRlL1NlcXVlbmNlEgIIAxJ+CgdpbnRlcm9wEnMKHgoYAGFjY2Vzc0NvbnRyb2wAbmV0d29yazIAEgIIJwobChUAbWVtYmVyc2hpcABuZXR3b3JrMgASAggpChYKEAD0j7+/aW5pdGlhbGl6ZWQSAggHChwKFmUyZUNvbmZpZGVudGlhbGl0eUZsYWcSAggHEjIKC3NpbXBsZXN0YXRlEiMKFgoQAPSPv79pbml0aWFsaXplZBICCAQKCQoBYRIECBsQARr0CAjIARruCAqyAQqNAQRdCc5yPbVtY77Ow/6sH6V8AOwbumdSxFq5T62tOT8LIThrPue3yCQBp7P5/6NoKRZR9grAbP9mVHiZ5814qf/DnXULpdh5O5EbVKSZX5BtmXCqTwpmZaqrQzAGgNXVzB8L6QSEVz48fp9X9SuA3r74mzNM5Ip6WbsNXnENpfifEbUfHcDUK28KHN9U+xogYzlOibmMtRdSuUyam+LQmZ5Y4/9X7AyhqEGNe0INblsSOXJlbGF5LW5ldHdvcmsxOjkwODAvbmV0d29yazEvbXljaGFubmVsOnNpbXBsZXN0YXRlOlJlYWQ6YRgBItMGLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNSakNDQWUyZ0F3SUJBZ0lVUlJSQ2RiWjYzaTU5TTN3NjhQNUkyNXJ6MkxBd0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEl5TURnd05EQTJOVEl3TUZvWERUSXpNRGd3TkRBMk5UY3dNRm93SVRFUE1BMEcKQTFVRUN4TUdZMnhwWlc1ME1RNHdEQVlEVlFRREV3VjFjMlZ5TVRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OQpBd0VIQTBJQUJOT2dvUmJyZ3RmWHhxYS9tYkJRTm15eDFQSVhMQXVhTVdwcUFJdTFMdzFMTTI4dEp0aE9KcVhVCno2RXdITEdlTGxidlNFVDZ4bW9YcmdJdkJCMVp3RzZqZ2Jzd2diZ3dEZ1lEVlIwUEFRSC9CQVFEQWdlQU1Bd0cKQTFVZEV3RUIvd1FDTUFBd0hRWURWUjBPQkJZRUZNc1hQN0JqTXNtZlV1S2Z1ZVVzclk3NHBYMEdNQjhHQTFVZApJd1FZTUJhQUZQd2UxTHJOdUkzM1ZtK0VkZ08vRS9qSmloVTFNRmdHQ0NvREJBVUdCd2dCQkV4N0ltRjBkSEp6CklqcDdJbWhtTGtGbVptbHNhV0YwYVc5dUlqb2lJaXdpYUdZdVJXNXliMnhzYldWdWRFbEVJam9pZFhObGNqRWkKTENKb1ppNVVlWEJsSWpvaVkyeHBaVzUwSW4xOU1Bb0dDQ3FHU000OUJBTUNBMGNBTUVRQ0lCQi82ODFXZkJSKwpRV0lHZmlZS09rM0h1UnRPOEpGd2JUaUVqbkFnQ1J2bkFpQmE2OXdXWWFaMjVaUitHYXk2OWVWK3ZEWmtQTUhTCmdkUmpBSXRjS0dzdEZnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoqJDQwZTFjMGUxLWJkZDctNDQ2MC04YzhhLWRlMTZhOWQyOGYwYSIMEgdpbnRlcm9wGgExIqUICtkHCgdPcmcxTVNQEs0HLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNvakNDQWttZ0F3SUJBZ0lVR3g5UFJLMjdGTkdEVTdNdkt1d3hhUWV0WjE4d0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEl5TURnd05EQTJNREl3TUZvWERUSXpNRGd3TkRBMk1EY3dNRm93V3pFTE1Ba0cKQTFVRUJoTUNWVk14RnpBVkJnTlZCQWdURGs1dmNuUm9JRU5oY205c2FXNWhNUlF3RWdZRFZRUUtFd3RJZVhCbApjbXhsWkdkbGNqRU5NQXNHQTFVRUN4TUVjR1ZsY2pFT01Bd0dBMVVFQXhNRmNHVmxjakF3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFReWZhTzhSUlFtSTc2NTFwZTlJYlNHYkhnOXR4dEFKUEtRenByM2MwZkIKWVdLRVpmU0doVGFlZ29tYzZIVFQrRjV4aTJFdWFWZGRaNnEwcDJYeDJkSkZvNEhkTUlIYU1BNEdBMVVkRHdFQgovd1FFQXdJSGdEQU1CZ05WSFJNQkFmOEVBakFBTUIwR0ExVWREZ1FXQkJTTVQydnNMUFZtcVdMTGxBcG1aZkhiCkpxRGppREFmQmdOVkhTTUVHREFXZ0JRcUVkU1piMzBGM3JBS1o0bEZyWEl0WEY0ampEQWlCZ05WSFJFRUd6QVoKZ2hkd1pXVnlNQzV2Y21jeExtNWxkSGR2Y21zeExtTnZiVEJXQmdncUF3UUZCZ2NJQVFSS2V5SmhkSFJ5Y3lJNgpleUpvWmk1QlptWnBiR2xoZEdsdmJpSTZJaUlzSW1obUxrVnVjbTlzYkcxbGJuUkpSQ0k2SW5CbFpYSXdJaXdpCmFHWXVWSGx3WlNJNkluQmxaWElpZlgwd0NnWUlLb1pJemowRUF3SURSd0F3UkFJZ1pRNWEzbXpKWit6ZlA5ck8KY1lPb1hEOVA1anhNaFJjTEJQUGdHZy9iS25ZQ0lDcjNxZUpnc3hYK0VpQVdna0ozR3hXYytaUUZzc205ak1iQQpyMVhiZitLSQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tChJHMEUCIQC4MR1TNTeK+FHqEStQkXTM+9kgF4v3SldTn8G3T8Wb1wIgWnDGTnmhr4gL/UmYdB+uQrYaF3IvGtlKZ4r0rDhczxg=", + + "confidential_view_content64": "CghBcmN0dXJ1cxIQTZKuC0jTLZxn3JowK/x2Xg==" +} \ No newline at end of file diff --git a/core/network/fabric-interop-cc/.env.template b/core/network/fabric-interop-cc/.env.template index d0902ceb2..67f81144c 100644 --- a/core/network/fabric-interop-cc/.env.template +++ b/core/network/fabric-interop-cc/.env.template @@ -1,4 +1,4 @@ -CCID= +CCID= CHANNEL= PEER= ORG= diff --git a/core/network/fabric-interop-cc/contracts/interop/test_data/corda_cacert_doorman.pem b/core/network/fabric-interop-cc/contracts/interop/test_data/corda_cacert_doorman.pem new file mode 100644 index 000000000..4ca4d78eb --- /dev/null +++ b/core/network/fabric-interop-cc/contracts/interop/test_data/corda_cacert_doorman.pem @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICXjCCAfugAwIBAgIIHVb6wd3RHhIwFAYIKoZIzj0EAwIGCCqGSM49AwEHMFgx +GzAZBgNVBAMMEkNvcmRhIE5vZGUgUm9vdCBDQTELMAkGA1UECgwCUjMxDjAMBgNV +BAsMBWNvcmRhMQ8wDQYDVQQHDAZMb25kb24xCzAJBgNVBAYTAlVLMB4XDTE4MDcx +MDAwMDAwMFoXDTI3MDUyMDAwMDAwMFowYzELMAkGA1UEBhMCVVMxETAPBgNVBAcT +CE5ldyBZb3JrMQ4wDAYDVQQLEwVDb3JkYTEWMBQGA1UEChMNUjMgSG9sZENvIExM +QzEZMBcGA1UEAxMQQ29yZGEgRG9vcm1hbiBDQTBZMBMGByqGSM49AgEGCCqGSM49 +AwEHA0IABAPL3qAm4WZms5ciBVoxMQXfK7uTmHRVvWfWQ+QVYP3bMHSguHZRzB3v +7EOE8RZpGDan+w007Xj7XR0+xG9SxmCjgZkwgZYwHQYDVR0OBBYEFOvuLjAVKUCu +GZge2G/jfX8HosITMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgGGMCMGA1Ud +JQQcMBoGCCsGAQUFBwMBBggrBgEFBQcDAgYEVR0lADAfBgNVHSMEGDAWgBR8rqnf +uUgBKxOJC5rmRYUcORcHczARBgorBgEEAYOKYgEBBAMCAQEwFAYIKoZIzj0EAwIG +CCqGSM49AwEHA0cAMEQCIBmzQXpnCo9eAxkhwMt0bBr1Q0APJXF0KuBRsFBWAa6S +AiBgx6G8G9Ij7B8+y65ItLKVcs7Kh6Rdnr5/1zB/yPwfrg== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/core/network/fabric-interop-cc/contracts/interop/test_data/corda_cacert_node.pem b/core/network/fabric-interop-cc/contracts/interop/test_data/corda_cacert_node.pem new file mode 100644 index 000000000..6dfb29cb0 --- /dev/null +++ b/core/network/fabric-interop-cc/contracts/interop/test_data/corda_cacert_node.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIICbTCCAgmgAwIBAgIIYRljUiZaGSkwFAYIKoZIzj0EAwIGCCqGSM49AwEHMGMx +CzAJBgNVBAYTAlVTMREwDwYDVQQHEwhOZXcgWW9yazEOMAwGA1UECxMFQ29yZGEx +FjAUBgNVBAoTDVIzIEhvbGRDbyBMTEMxGTAXBgNVBAMTEENvcmRhIERvb3JtYW4g +Q0EwHhcNMjAwNzI0MDAwMDAwWhcNMjcwNTIwMDAwMDAwWjAvMQswCQYDVQQGEwJH +QjEPMA0GA1UEBwwGTG9uZG9uMQ8wDQYDVQQKDAZQYXJ0eUEwWTATBgcqhkjOPQIB +BggqhkjOPQMBBwNCAASFze6k3tINqGLsKTi0a50RpOUCysno1/1lwIfEqaboauuj +o6Ecfu8X1WnW92VrEZGKslIJzR8R0deOEJvBs0rzo4HQMIHNMB0GA1UdDgQWBBR4 +hwLuLgfIZMEWzG4n3AxwfgPbezAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB +hjATBgNVHSUEDDAKBggrBgEFBQcDAjAfBgNVHSMEGDAWgBTr7i4wFSlArhmYHthv +431/B6LCEzARBgorBgEEAYOKYgEBBAMCAQQwRQYDVR0eAQH/BDswOaA1MDOkMTAv +MQswCQYDVQQGEwJHQjEPMA0GA1UEBwwGTG9uZG9uMQ8wDQYDVQQKDAZQYXJ0eUGh +ADAUBggqhkjOPQQDAgYIKoZIzj0DAQcDSAAwRQIhANXBVAebUsY9AMfjZedNYN14 +Wy76Ru5vMSta3Av1d08lAiAi2GZWk5XwJoEYuhQHXsHQLZbXphAVk+Q5tVgMgywj +tQ== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/core/network/fabric-interop-cc/contracts/interop/test_data/corda_cacert_root.pem b/core/network/fabric-interop-cc/contracts/interop/test_data/corda_cacert_root.pem new file mode 100644 index 000000000..3409b3d56 --- /dev/null +++ b/core/network/fabric-interop-cc/contracts/interop/test_data/corda_cacert_root.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIICCTCCAbCgAwIBAgIIcFe0qctqSucwCgYIKoZIzj0EAwIwWDEbMBkGA1UEAwwS +Q29yZGEgTm9kZSBSb290IENBMQswCQYDVQQKDAJSMzEOMAwGA1UECwwFY29yZGEx +DzANBgNVBAcMBkxvbmRvbjELMAkGA1UEBhMCVUswHhcNMTcwNTIyMDAwMDAwWhcN +MjcwNTIwMDAwMDAwWjBYMRswGQYDVQQDDBJDb3JkYSBOb2RlIFJvb3QgQ0ExCzAJ +BgNVBAoMAlIzMQ4wDAYDVQQLDAVjb3JkYTEPMA0GA1UEBwwGTG9uZG9uMQswCQYD +VQQGEwJVSzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGlm6LFHrVkzfuUHin36 +Jrm1aUMarX/NUZXw8n8gSiJmsZPlUEplJ+f/lzZMky5EZPTtCciG34pnOP0eiMd/ +JTCjZDBiMB0GA1UdDgQWBBR8rqnfuUgBKxOJC5rmRYUcORcHczALBgNVHQ8EBAMC +AYYwIwYDVR0lBBwwGgYIKwYBBQUHAwEGCCsGAQUFBwMCBgRVHSUAMA8GA1UdEwEB +/wQFMAMBAf8wCgYIKoZIzj0EAwIDRwAwRAIgDaL4SguKsNeTT7SeUkFdoCBACeG8 +GqO4M1KlfimphQwCICiq00hDanT5W8bTLqE7GIGuplf/O8AABlpWrUg6uiUB +-----END CERTIFICATE----- \ No newline at end of file diff --git a/core/network/fabric-interop-cc/contracts/interop/test_data/corda_viewdata.json b/core/network/fabric-interop-cc/contracts/interop/test_data/corda_viewdata.json new file mode 100644 index 000000000..6061c5a61 --- /dev/null +++ b/core/network/fabric-interop-cc/contracts/interop/test_data/corda_viewdata.json @@ -0,0 +1,7 @@ +{ + "view64": "CjQIBBIcVHVlIE5vdiAxNyAwMDoxMzo0NiBHTVQgMjAyMBoMTm90YXJpemF0aW9uIgRKU09OEtYHCoQGClhhMjZHVW9WYythenlIMENUYjN2K2pTdmp3Y255M0hFd3AyMlJrdDkvZC9GcXN4WVVvYXhVWTdUOWNKRk9TVTZiVW42UFIwNmFVckxxdjZLbzZ1NG5CUT09Ep8FLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJ3akNDQVYrZ0F3SUJBZ0lJVUprUXZtS20zNVl3RkFZSUtvWkl6ajBFQXdJR0NDcUdTTTQ5QXdFSE1DOHgKQ3pBSkJnTlZCQVlUQWtkQ01ROHdEUVlEVlFRSERBWk1iMjVrYjI0eER6QU5CZ05WQkFvTUJsQmhjblI1UVRBZQpGdzB5TURBM01qUXdNREF3TURCYUZ3MHlOekExTWpBd01EQXdNREJhTUM4eEN6QUpCZ05WQkFZVEFrZENNUTh3CkRRWURWUVFIREFaTWIyNWtiMjR4RHpBTkJnTlZCQW9NQmxCaGNuUjVRVEFxTUFVR0F5dGxjQU1oQU1NS2FSRUsKaGNUZ1NCTU16Szgxb1BVU1BvVm1HL2ZKTUxYcS91alNtc2U5bzRHSk1JR0dNQjBHQTFVZERnUVdCQlJNWHREcwpLRlp6VUxkUTNjMkRDVUV4M1QxQ1VEQVBCZ05WSFJNQkFmOEVCVEFEQVFIL01Bc0dBMVVkRHdRRUF3SUNoREFUCkJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREFqQWZCZ05WSFNNRUdEQVdnQlI0aHdMdUxnZklaTUVXekc0bjNBeHcKZmdQYmV6QVJCZ29yQmdFRUFZT0tZZ0VCQkFNQ0FRWXdGQVlJS29aSXpqMEVBd0lHQ0NxR1NNNDlBd0VIQTBjQQpNRVFDSUM3SjQ2U3hERHozTGpETnJFUGpqd1AycHJnTUVNaDdyL2dKcG91UUhCaytBaUErS3pYRDBkNW1pSTg2CkQybVlLNEMzdFJsaTNYM1ZnbkNlOENPcWZZeXVRZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0aBlBhcnR5QRLMAQpsW1NpbXBsZVN0YXRlKGtleT1ILCB2YWx1ZT0xLCBvd25lcj1PPVBhcnR5QSwgTD1Mb25kb24sIEM9R0IsIGxpbmVhcklkPTIzMTRkNmI3LTFlY2EtNDg5Mi04OGY4LTc2ZDg1YjhhODVjZCldElxsb2NhbGhvc3Q6OTA4MC9Db3JkYV9OZXR3b3JrL2xvY2FsaG9zdDoxMDAwNiNjb20uY29yZGFTaW1wbGVBcHBsaWNhdGlvbi5mbG93LkdldFN0YXRlQnlLZXk6SA==", + + "confidential_view64": "", + + "confidential_view_content64": "" +} \ No newline at end of file diff --git a/core/network/fabric-interop-cc/contracts/interop/test_data/fabric_cacert.pem b/core/network/fabric-interop-cc/contracts/interop/test_data/fabric_cacert.pem new file mode 100644 index 000000000..cd84e020a --- /dev/null +++ b/core/network/fabric-interop-cc/contracts/interop/test_data/fabric_cacert.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw +aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK +EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt +Y2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG +A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl +cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy +dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR +ynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF +MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE +FCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq +m2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd +zQkhznMIF4SBF4k= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/core/network/fabric-interop-cc/contracts/interop/test_data/fabric_viewdata.json b/core/network/fabric-interop-cc/contracts/interop/test_data/fabric_viewdata.json new file mode 100644 index 000000000..3d2672272 --- /dev/null +++ b/core/network/fabric-interop-cc/contracts/interop/test_data/fabric_viewdata.json @@ -0,0 +1,7 @@ +{ + "view64": "CjIIAxIYMjAyMi0wOC0wNFQxMDoyNDo0Ny42MDVaGgxOb3Rhcml6YXRpb24iBlNUUklORxKLGgrFBwjIARq/BwoGMTcuNjcxEjlyZWxheS1uZXR3b3JrMTo5MDgwL25ldHdvcmsxL215Y2hhbm5lbDpzaW1wbGVzdGF0ZTpSZWFkOmEi0wYtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ1JqQ0NBZTJnQXdJQkFnSVVSUlJDZGJaNjNpNTlNM3c2OFA1STI1cnoyTEF3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRBMk5USXdNRm9YRFRJek1EZ3dOREEyTlRjd01Gb3dJVEVQTUEwRwpBMVVFQ3hNR1kyeHBaVzUwTVE0d0RBWURWUVFERXdWMWMyVnlNVEJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5CkF3RUhBMElBQk5PZ29SYnJndGZYeHFhL21iQlFObXl4MVBJWExBdWFNV3BxQUl1MUx3MUxNMjh0SnRoT0pxWFUKejZFd0hMR2VMbGJ2U0VUNnhtb1hyZ0l2QkIxWndHNmpnYnN3Z2Jnd0RnWURWUjBQQVFIL0JBUURBZ2VBTUF3RwpBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRk1zWFA3QmpNc21mVXVLZnVlVXNyWTc0cFgwR01COEdBMVVkCkl3UVlNQmFBRlB3ZTFMck51STMzVm0rRWRnTy9FL2pKaWhVMU1GZ0dDQ29EQkFVR0J3Z0JCRXg3SW1GMGRISnoKSWpwN0ltaG1Ma0ZtWm1sc2FXRjBhVzl1SWpvaUlpd2lhR1l1Ulc1eWIyeHNiV1Z1ZEVsRUlqb2lkWE5sY2pFaQpMQ0pvWmk1VWVYQmxJam9pWTJ4cFpXNTBJbjE5TUFvR0NDcUdTTTQ5QkFNQ0EwY0FNRVFDSUJCLzY4MVdmQlIrClFXSUdmaVlLT2szSHVSdE84SkZ3YlRpRWpuQWdDUnZuQWlCYTY5d1dZYVoyNVpSK0dheTY5ZVYrdkRaa1BNSFMKZ2RSakFJdGNLR3N0Rmc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCiokZWE3OWU2NjQtYTJmMi00YzlmLTg2NDMtZTYwNjAwODhmYzlhGpgKCiBVNNh9oMmGr6mjpkClfw32G8jILQMdz9o0hFOMbTk7vRLzCQqaAhJmCgpfbGlmZWN5Y2xlElgKKAoibmFtZXNwYWNlcy9maWVsZHMvaW50ZXJvcC9TZXF1ZW5jZRICCAYKLAombmFtZXNwYWNlcy9maWVsZHMvc2ltcGxlc3RhdGUvU2VxdWVuY2USAggDEn4KB2ludGVyb3AScwoeChgAYWNjZXNzQ29udHJvbABuZXR3b3JrMgASAggUChsKFQBtZW1iZXJzaGlwAG5ldHdvcmsyABICCBYKFgoQAPSPv79pbml0aWFsaXplZBICCAcKHAoWZTJlQ29uZmlkZW50aWFsaXR5RmxhZxICCAcSMAoLc2ltcGxlc3RhdGUSIQoWChAA9I+/v2luaXRpYWxpemVkEgIIBAoHCgFhEgIIGhrFBwjIARq/BwoGMTcuNjcxEjlyZWxheS1uZXR3b3JrMTo5MDgwL25ldHdvcmsxL215Y2hhbm5lbDpzaW1wbGVzdGF0ZTpSZWFkOmEi0wYtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ1JqQ0NBZTJnQXdJQkFnSVVSUlJDZGJaNjNpNTlNM3c2OFA1STI1cnoyTEF3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRBMk5USXdNRm9YRFRJek1EZ3dOREEyTlRjd01Gb3dJVEVQTUEwRwpBMVVFQ3hNR1kyeHBaVzUwTVE0d0RBWURWUVFERXdWMWMyVnlNVEJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5CkF3RUhBMElBQk5PZ29SYnJndGZYeHFhL21iQlFObXl4MVBJWExBdWFNV3BxQUl1MUx3MUxNMjh0SnRoT0pxWFUKejZFd0hMR2VMbGJ2U0VUNnhtb1hyZ0l2QkIxWndHNmpnYnN3Z2Jnd0RnWURWUjBQQVFIL0JBUURBZ2VBTUF3RwpBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRk1zWFA3QmpNc21mVXVLZnVlVXNyWTc0cFgwR01COEdBMVVkCkl3UVlNQmFBRlB3ZTFMck51STMzVm0rRWRnTy9FL2pKaWhVMU1GZ0dDQ29EQkFVR0J3Z0JCRXg3SW1GMGRISnoKSWpwN0ltaG1Ma0ZtWm1sc2FXRjBhVzl1SWpvaUlpd2lhR1l1Ulc1eWIyeHNiV1Z1ZEVsRUlqb2lkWE5sY2pFaQpMQ0pvWmk1VWVYQmxJam9pWTJ4cFpXNTBJbjE5TUFvR0NDcUdTTTQ5QkFNQ0EwY0FNRVFDSUJCLzY4MVdmQlIrClFXSUdmaVlLT2szSHVSdE84SkZ3YlRpRWpuQWdDUnZuQWlCYTY5d1dZYVoyNVpSK0dheTY5ZVYrdkRaa1BNSFMKZ2RSakFJdGNLR3N0Rmc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCiokZWE3OWU2NjQtYTJmMi00YzlmLTg2NDMtZTYwNjAwODhmYzlhIgwSB2ludGVyb3AaATEipQgK2QcKB09yZzFNU1ASzQctLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ29qQ0NBa21nQXdJQkFnSVVHeDlQUksyN0ZOR0RVN012S3V3eGFRZXRaMTh3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRBMk1ESXdNRm9YRFRJek1EZ3dOREEyTURjd01Gb3dXekVMTUFrRwpBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRS0V3dEllWEJsCmNteGxaR2RsY2pFTk1Bc0dBMVVFQ3hNRWNHVmxjakVPTUF3R0ExVUVBeE1GY0dWbGNqQXdXVEFUQmdjcWhrak8KUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVF5ZmFPOFJSUW1JNzY1MXBlOUliU0diSGc5dHh0QUpQS1F6cHIzYzBmQgpZV0tFWmZTR2hUYWVnb21jNkhUVCtGNXhpMkV1YVZkZFo2cTBwMlh4MmRKRm80SGRNSUhhTUE0R0ExVWREd0VCCi93UUVBd0lIZ0RBTUJnTlZIUk1CQWY4RUFqQUFNQjBHQTFVZERnUVdCQlNNVDJ2c0xQVm1xV0xMbEFwbVpmSGIKSnFEamlEQWZCZ05WSFNNRUdEQVdnQlFxRWRTWmIzMEYzckFLWjRsRnJYSXRYRjRqakRBaUJnTlZIUkVFR3pBWgpnaGR3WldWeU1DNXZjbWN4TG01bGRIZHZjbXN4TG1OdmJUQldCZ2dxQXdRRkJnY0lBUVJLZXlKaGRIUnljeUk2CmV5Sm9aaTVCWm1acGJHbGhkR2x2YmlJNklpSXNJbWhtTGtWdWNtOXNiRzFsYm5SSlJDSTZJbkJsWlhJd0lpd2kKYUdZdVZIbHdaU0k2SW5CbFpYSWlmWDB3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnWlE1YTNtekpaK3pmUDlyTwpjWU9vWEQ5UDVqeE1oUmNMQlBQZ0dnL2JLbllDSUNyM3FlSmdzeFgrRWlBV2drSjNHeFdjK1pRRnNzbTlqTWJBCnIxWGJmK0tJCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KEkcwRQIhAM1Gyv7e+SYniXLgB8iBuRqS4C/A9D36SLl4Zj/AkxrpAiByAoaBFpRIMEJsmGasggaQ4AUST+M2n8ctBZCHjDwRxQ==", + + "confidential_view64": "CjIIAxIYMjAyMi0wOC0wNFQxMDozMjoyMC4zMTlaGgxOb3Rhcml6YXRpb24iBlNUUklORxLrHAr0CAjIARruCAqyAQqNAQRdCc5yPbVtY77Ow/6sH6V8AOwbumdSxFq5T62tOT8LIThrPue3yCQBp7P5/6NoKRZR9grAbP9mVHiZ5814qf/DnXULpdh5O5EbVKSZX5BtmXCqTwpmZaqrQzAGgNXVzB8L6QSEVz48fp9X9SuA3r74mzNM5Ip6WbsNXnENpfifEbUfHcDUK28KHN9U+xogYzlOibmMtRdSuUyam+LQmZ5Y4/9X7AyhqEGNe0INblsSOXJlbGF5LW5ldHdvcmsxOjkwODAvbmV0d29yazEvbXljaGFubmVsOnNpbXBsZXN0YXRlOlJlYWQ6YRgBItMGLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNSakNDQWUyZ0F3SUJBZ0lVUlJSQ2RiWjYzaTU5TTN3NjhQNUkyNXJ6MkxBd0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEl5TURnd05EQTJOVEl3TUZvWERUSXpNRGd3TkRBMk5UY3dNRm93SVRFUE1BMEcKQTFVRUN4TUdZMnhwWlc1ME1RNHdEQVlEVlFRREV3VjFjMlZ5TVRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OQpBd0VIQTBJQUJOT2dvUmJyZ3RmWHhxYS9tYkJRTm15eDFQSVhMQXVhTVdwcUFJdTFMdzFMTTI4dEp0aE9KcVhVCno2RXdITEdlTGxidlNFVDZ4bW9YcmdJdkJCMVp3RzZqZ2Jzd2diZ3dEZ1lEVlIwUEFRSC9CQVFEQWdlQU1Bd0cKQTFVZEV3RUIvd1FDTUFBd0hRWURWUjBPQkJZRUZNc1hQN0JqTXNtZlV1S2Z1ZVVzclk3NHBYMEdNQjhHQTFVZApJd1FZTUJhQUZQd2UxTHJOdUkzM1ZtK0VkZ08vRS9qSmloVTFNRmdHQ0NvREJBVUdCd2dCQkV4N0ltRjBkSEp6CklqcDdJbWhtTGtGbVptbHNhV0YwYVc5dUlqb2lJaXdpYUdZdVJXNXliMnhzYldWdWRFbEVJam9pZFhObGNqRWkKTENKb1ppNVVlWEJsSWpvaVkyeHBaVzUwSW4xOU1Bb0dDQ3FHU000OUJBTUNBMGNBTUVRQ0lCQi82ODFXZkJSKwpRV0lHZmlZS09rM0h1UnRPOEpGd2JUaUVqbkFnQ1J2bkFpQmE2OXdXWWFaMjVaUitHYXk2OWVWK3ZEWmtQTUhTCmdkUmpBSXRjS0dzdEZnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoqJDQwZTFjMGUxLWJkZDctNDQ2MC04YzhhLWRlMTZhOWQyOGYwYRrJCwogZOyCYqcgmQJccj0IkSL3t+oNKIzv0PmJqnzbH2jfIV8SpAsKnAISZgoKX2xpZmVjeWNsZRJYCigKIm5hbWVzcGFjZXMvZmllbGRzL2ludGVyb3AvU2VxdWVuY2USAggGCiwKJm5hbWVzcGFjZXMvZmllbGRzL3NpbXBsZXN0YXRlL1NlcXVlbmNlEgIIAxJ+CgdpbnRlcm9wEnMKHgoYAGFjY2Vzc0NvbnRyb2wAbmV0d29yazIAEgIIJwobChUAbWVtYmVyc2hpcABuZXR3b3JrMgASAggpChYKEAD0j7+/aW5pdGlhbGl6ZWQSAggHChwKFmUyZUNvbmZpZGVudGlhbGl0eUZsYWcSAggHEjIKC3NpbXBsZXN0YXRlEiMKFgoQAPSPv79pbml0aWFsaXplZBICCAQKCQoBYRIECBsQARr0CAjIARruCAqyAQqNAQRdCc5yPbVtY77Ow/6sH6V8AOwbumdSxFq5T62tOT8LIThrPue3yCQBp7P5/6NoKRZR9grAbP9mVHiZ5814qf/DnXULpdh5O5EbVKSZX5BtmXCqTwpmZaqrQzAGgNXVzB8L6QSEVz48fp9X9SuA3r74mzNM5Ip6WbsNXnENpfifEbUfHcDUK28KHN9U+xogYzlOibmMtRdSuUyam+LQmZ5Y4/9X7AyhqEGNe0INblsSOXJlbGF5LW5ldHdvcmsxOjkwODAvbmV0d29yazEvbXljaGFubmVsOnNpbXBsZXN0YXRlOlJlYWQ6YRgBItMGLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNSakNDQWUyZ0F3SUJBZ0lVUlJSQ2RiWjYzaTU5TTN3NjhQNUkyNXJ6MkxBd0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEl5TURnd05EQTJOVEl3TUZvWERUSXpNRGd3TkRBMk5UY3dNRm93SVRFUE1BMEcKQTFVRUN4TUdZMnhwWlc1ME1RNHdEQVlEVlFRREV3VjFjMlZ5TVRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OQpBd0VIQTBJQUJOT2dvUmJyZ3RmWHhxYS9tYkJRTm15eDFQSVhMQXVhTVdwcUFJdTFMdzFMTTI4dEp0aE9KcVhVCno2RXdITEdlTGxidlNFVDZ4bW9YcmdJdkJCMVp3RzZqZ2Jzd2diZ3dEZ1lEVlIwUEFRSC9CQVFEQWdlQU1Bd0cKQTFVZEV3RUIvd1FDTUFBd0hRWURWUjBPQkJZRUZNc1hQN0JqTXNtZlV1S2Z1ZVVzclk3NHBYMEdNQjhHQTFVZApJd1FZTUJhQUZQd2UxTHJOdUkzM1ZtK0VkZ08vRS9qSmloVTFNRmdHQ0NvREJBVUdCd2dCQkV4N0ltRjBkSEp6CklqcDdJbWhtTGtGbVptbHNhV0YwYVc5dUlqb2lJaXdpYUdZdVJXNXliMnhzYldWdWRFbEVJam9pZFhObGNqRWkKTENKb1ppNVVlWEJsSWpvaVkyeHBaVzUwSW4xOU1Bb0dDQ3FHU000OUJBTUNBMGNBTUVRQ0lCQi82ODFXZkJSKwpRV0lHZmlZS09rM0h1UnRPOEpGd2JUaUVqbkFnQ1J2bkFpQmE2OXdXWWFaMjVaUitHYXk2OWVWK3ZEWmtQTUhTCmdkUmpBSXRjS0dzdEZnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoqJDQwZTFjMGUxLWJkZDctNDQ2MC04YzhhLWRlMTZhOWQyOGYwYSIMEgdpbnRlcm9wGgExIqUICtkHCgdPcmcxTVNQEs0HLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNvakNDQWttZ0F3SUJBZ0lVR3g5UFJLMjdGTkdEVTdNdkt1d3hhUWV0WjE4d0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEl5TURnd05EQTJNREl3TUZvWERUSXpNRGd3TkRBMk1EY3dNRm93V3pFTE1Ba0cKQTFVRUJoTUNWVk14RnpBVkJnTlZCQWdURGs1dmNuUm9JRU5oY205c2FXNWhNUlF3RWdZRFZRUUtFd3RJZVhCbApjbXhsWkdkbGNqRU5NQXNHQTFVRUN4TUVjR1ZsY2pFT01Bd0dBMVVFQXhNRmNHVmxjakF3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFReWZhTzhSUlFtSTc2NTFwZTlJYlNHYkhnOXR4dEFKUEtRenByM2MwZkIKWVdLRVpmU0doVGFlZ29tYzZIVFQrRjV4aTJFdWFWZGRaNnEwcDJYeDJkSkZvNEhkTUlIYU1BNEdBMVVkRHdFQgovd1FFQXdJSGdEQU1CZ05WSFJNQkFmOEVBakFBTUIwR0ExVWREZ1FXQkJTTVQydnNMUFZtcVdMTGxBcG1aZkhiCkpxRGppREFmQmdOVkhTTUVHREFXZ0JRcUVkU1piMzBGM3JBS1o0bEZyWEl0WEY0ampEQWlCZ05WSFJFRUd6QVoKZ2hkd1pXVnlNQzV2Y21jeExtNWxkSGR2Y21zeExtTnZiVEJXQmdncUF3UUZCZ2NJQVFSS2V5SmhkSFJ5Y3lJNgpleUpvWmk1QlptWnBiR2xoZEdsdmJpSTZJaUlzSW1obUxrVnVjbTlzYkcxbGJuUkpSQ0k2SW5CbFpYSXdJaXdpCmFHWXVWSGx3WlNJNkluQmxaWElpZlgwd0NnWUlLb1pJemowRUF3SURSd0F3UkFJZ1pRNWEzbXpKWit6ZlA5ck8KY1lPb1hEOVA1anhNaFJjTEJQUGdHZy9iS25ZQ0lDcjNxZUpnc3hYK0VpQVdna0ozR3hXYytaUUZzc205ak1iQQpyMVhiZitLSQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tChJHMEUCIQC4MR1TNTeK+FHqEStQkXTM+9kgF4v3SldTn8G3T8Wb1wIgWnDGTnmhr4gL/UmYdB+uQrYaF3IvGtlKZ4r0rDhczxg=", + + "confidential_view_content64": "CghBcmN0dXJ1cxIQTZKuC0jTLZxn3JowK/x2Xg==" +} \ No newline at end of file diff --git a/core/network/fabric-interop-cc/contracts/interop/write_external_state_test.go b/core/network/fabric-interop-cc/contracts/interop/write_external_state_test.go index 935fdd400..449e39cdb 100644 --- a/core/network/fabric-interop-cc/contracts/interop/write_external_state_test.go +++ b/core/network/fabric-interop-cc/contracts/interop/write_external_state_test.go @@ -11,6 +11,7 @@ package main import ( "encoding/json" "testing" + "io/ioutil" "github.com/hyperledger/fabric-protos-go/peer" "github.com/stretchr/testify/require" @@ -18,67 +19,76 @@ import ( wtest "github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/testutils" ) -var cordaB64View = `CjQIBBIcVHVlIE5vdiAxNyAwMDoxMzo0NiBHTVQgMjAyMBoMTm90YXJpemF0aW9uIgRKU09OEtYHCoQGClhhMjZHVW9WYythenlIMENUYjN2K2pTdmp3Y255M0hFd3AyMlJrdDkvZC9GcXN4WVVvYXhVWTdUOWNKRk9TVTZiVW42UFIwNmFVckxxdjZLbzZ1NG5CUT09Ep8FLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJ3akNDQVYrZ0F3SUJBZ0lJVUprUXZtS20zNVl3RkFZSUtvWkl6ajBFQXdJR0NDcUdTTTQ5QXdFSE1DOHgKQ3pBSkJnTlZCQVlUQWtkQ01ROHdEUVlEVlFRSERBWk1iMjVrYjI0eER6QU5CZ05WQkFvTUJsQmhjblI1UVRBZQpGdzB5TURBM01qUXdNREF3TURCYUZ3MHlOekExTWpBd01EQXdNREJhTUM4eEN6QUpCZ05WQkFZVEFrZENNUTh3CkRRWURWUVFIREFaTWIyNWtiMjR4RHpBTkJnTlZCQW9NQmxCaGNuUjVRVEFxTUFVR0F5dGxjQU1oQU1NS2FSRUsKaGNUZ1NCTU16Szgxb1BVU1BvVm1HL2ZKTUxYcS91alNtc2U5bzRHSk1JR0dNQjBHQTFVZERnUVdCQlJNWHREcwpLRlp6VUxkUTNjMkRDVUV4M1QxQ1VEQVBCZ05WSFJNQkFmOEVCVEFEQVFIL01Bc0dBMVVkRHdRRUF3SUNoREFUCkJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREFqQWZCZ05WSFNNRUdEQVdnQlI0aHdMdUxnZklaTUVXekc0bjNBeHcKZmdQYmV6QVJCZ29yQmdFRUFZT0tZZ0VCQkFNQ0FRWXdGQVlJS29aSXpqMEVBd0lHQ0NxR1NNNDlBd0VIQTBjQQpNRVFDSUM3SjQ2U3hERHozTGpETnJFUGpqd1AycHJnTUVNaDdyL2dKcG91UUhCaytBaUErS3pYRDBkNW1pSTg2CkQybVlLNEMzdFJsaTNYM1ZnbkNlOENPcWZZeXVRZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0aBlBhcnR5QRLMAQpsW1NpbXBsZVN0YXRlKGtleT1ILCB2YWx1ZT0xLCBvd25lcj1PPVBhcnR5QSwgTD1Mb25kb24sIEM9R0IsIGxpbmVhcklkPTIzMTRkNmI3LTFlY2EtNDg5Mi04OGY4LTc2ZDg1YjhhODVjZCldElxsb2NhbGhvc3Q6OTA4MC9Db3JkYV9OZXR3b3JrL2xvY2FsaG9zdDoxMDAwNiNjb20uY29yZGFTaW1wbGVBcHBsaWNhdGlvbi5mbG93LkdldFN0YXRlQnlLZXk6SA==` - -var cordaMember = common.Member{ - Value: "-----BEGIN CERTIFICATE-----\nMIIBwjCCAV+gAwIBAgIIUJkQvmKm35YwFAYIKoZIzj0EAwIGCCqGSM49AwEHMC8x\nCzAJBgNVBAYTAkdCMQ8wDQYDVQQHDAZMb25kb24xDzANBgNVBAoMBlBhcnR5QTAe\nFw0yMDA3MjQwMDAwMDBaFw0yNzA1MjAwMDAwMDBaMC8xCzAJBgNVBAYTAkdCMQ8w\nDQYDVQQHDAZMb25kb24xDzANBgNVBAoMBlBhcnR5QTAqMAUGAytlcAMhAMMKaREK\nhcTgSBMMzK81oPUSPoVmG/fJMLXq/ujSmse9o4GJMIGGMB0GA1UdDgQWBBRMXtDs\nKFZzULdQ3c2DCUEx3T1CUDAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIChDAT\nBgNVHSUEDDAKBggrBgEFBQcDAjAfBgNVHSMEGDAWgBR4hwLuLgfIZMEWzG4n3Axw\nfgPbezARBgorBgEEAYOKYgEBBAMCAQYwFAYIKoZIzj0EAwIGCCqGSM49AwEHA0cA\nMEQCIC7J46SxDDz3LjDNrEPjjwP2prgMEMh7r/gJpouQHBk+AiA+KzXD0d5miI86\nD2mYK4C3tRli3X3VgnCe8COqfYyuQg==\n-----END CERTIFICATE-----", - Type: "certificate", - Chain: []string{}, -} - -var cordaMembership = common.Membership{ - SecurityDomain: "Corda_Network", - Members: map[string]*common.Member{"PartyA": &cordaMember}, -} - -var cordaVerificationPolicy = common.VerificationPolicy{ - SecurityDomain: "Corda_Network", - Identifiers: []*common.Identifier{{ - Pattern: "localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:*", - Policy: &common.Policy{ - Criteria: []string{"PartyA"}, - Type: "signature", - }, - }}, -} - -var fabricNetwork = "network1" -var fabricRelayEndpoint = "relay-network1:9080" -var fabricPattern = "mychannel:simplestate:Read:a" -var fabricViewAddress = fabricRelayEndpoint + "/" + fabricNetwork + "/" + fabricPattern - -var b64View = "CjIIAxIYMjAyMi0wOC0wNFQxMDoyNDo0Ny42MDVaGgxOb3Rhcml6YXRpb24iBlNUUklORxKLGgrFBwjIARq/BwoGMTcuNjcxEjlyZWxheS1uZXR3b3JrMTo5MDgwL25ldHdvcmsxL215Y2hhbm5lbDpzaW1wbGVzdGF0ZTpSZWFkOmEi0wYtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ1JqQ0NBZTJnQXdJQkFnSVVSUlJDZGJaNjNpNTlNM3c2OFA1STI1cnoyTEF3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRBMk5USXdNRm9YRFRJek1EZ3dOREEyTlRjd01Gb3dJVEVQTUEwRwpBMVVFQ3hNR1kyeHBaVzUwTVE0d0RBWURWUVFERXdWMWMyVnlNVEJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5CkF3RUhBMElBQk5PZ29SYnJndGZYeHFhL21iQlFObXl4MVBJWExBdWFNV3BxQUl1MUx3MUxNMjh0SnRoT0pxWFUKejZFd0hMR2VMbGJ2U0VUNnhtb1hyZ0l2QkIxWndHNmpnYnN3Z2Jnd0RnWURWUjBQQVFIL0JBUURBZ2VBTUF3RwpBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRk1zWFA3QmpNc21mVXVLZnVlVXNyWTc0cFgwR01COEdBMVVkCkl3UVlNQmFBRlB3ZTFMck51STMzVm0rRWRnTy9FL2pKaWhVMU1GZ0dDQ29EQkFVR0J3Z0JCRXg3SW1GMGRISnoKSWpwN0ltaG1Ma0ZtWm1sc2FXRjBhVzl1SWpvaUlpd2lhR1l1Ulc1eWIyeHNiV1Z1ZEVsRUlqb2lkWE5sY2pFaQpMQ0pvWmk1VWVYQmxJam9pWTJ4cFpXNTBJbjE5TUFvR0NDcUdTTTQ5QkFNQ0EwY0FNRVFDSUJCLzY4MVdmQlIrClFXSUdmaVlLT2szSHVSdE84SkZ3YlRpRWpuQWdDUnZuQWlCYTY5d1dZYVoyNVpSK0dheTY5ZVYrdkRaa1BNSFMKZ2RSakFJdGNLR3N0Rmc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCiokZWE3OWU2NjQtYTJmMi00YzlmLTg2NDMtZTYwNjAwODhmYzlhGpgKCiBVNNh9oMmGr6mjpkClfw32G8jILQMdz9o0hFOMbTk7vRLzCQqaAhJmCgpfbGlmZWN5Y2xlElgKKAoibmFtZXNwYWNlcy9maWVsZHMvaW50ZXJvcC9TZXF1ZW5jZRICCAYKLAombmFtZXNwYWNlcy9maWVsZHMvc2ltcGxlc3RhdGUvU2VxdWVuY2USAggDEn4KB2ludGVyb3AScwoeChgAYWNjZXNzQ29udHJvbABuZXR3b3JrMgASAggUChsKFQBtZW1iZXJzaGlwAG5ldHdvcmsyABICCBYKFgoQAPSPv79pbml0aWFsaXplZBICCAcKHAoWZTJlQ29uZmlkZW50aWFsaXR5RmxhZxICCAcSMAoLc2ltcGxlc3RhdGUSIQoWChAA9I+/v2luaXRpYWxpemVkEgIIBAoHCgFhEgIIGhrFBwjIARq/BwoGMTcuNjcxEjlyZWxheS1uZXR3b3JrMTo5MDgwL25ldHdvcmsxL215Y2hhbm5lbDpzaW1wbGVzdGF0ZTpSZWFkOmEi0wYtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ1JqQ0NBZTJnQXdJQkFnSVVSUlJDZGJaNjNpNTlNM3c2OFA1STI1cnoyTEF3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRBMk5USXdNRm9YRFRJek1EZ3dOREEyTlRjd01Gb3dJVEVQTUEwRwpBMVVFQ3hNR1kyeHBaVzUwTVE0d0RBWURWUVFERXdWMWMyVnlNVEJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5CkF3RUhBMElBQk5PZ29SYnJndGZYeHFhL21iQlFObXl4MVBJWExBdWFNV3BxQUl1MUx3MUxNMjh0SnRoT0pxWFUKejZFd0hMR2VMbGJ2U0VUNnhtb1hyZ0l2QkIxWndHNmpnYnN3Z2Jnd0RnWURWUjBQQVFIL0JBUURBZ2VBTUF3RwpBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRk1zWFA3QmpNc21mVXVLZnVlVXNyWTc0cFgwR01COEdBMVVkCkl3UVlNQmFBRlB3ZTFMck51STMzVm0rRWRnTy9FL2pKaWhVMU1GZ0dDQ29EQkFVR0J3Z0JCRXg3SW1GMGRISnoKSWpwN0ltaG1Ma0ZtWm1sc2FXRjBhVzl1SWpvaUlpd2lhR1l1Ulc1eWIyeHNiV1Z1ZEVsRUlqb2lkWE5sY2pFaQpMQ0pvWmk1VWVYQmxJam9pWTJ4cFpXNTBJbjE5TUFvR0NDcUdTTTQ5QkFNQ0EwY0FNRVFDSUJCLzY4MVdmQlIrClFXSUdmaVlLT2szSHVSdE84SkZ3YlRpRWpuQWdDUnZuQWlCYTY5d1dZYVoyNVpSK0dheTY5ZVYrdkRaa1BNSFMKZ2RSakFJdGNLR3N0Rmc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCiokZWE3OWU2NjQtYTJmMi00YzlmLTg2NDMtZTYwNjAwODhmYzlhIgwSB2ludGVyb3AaATEipQgK2QcKB09yZzFNU1ASzQctLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ29qQ0NBa21nQXdJQkFnSVVHeDlQUksyN0ZOR0RVN012S3V3eGFRZXRaMTh3Q2dZSUtvWkl6ajBFQXdJdwphREVMTUFrR0ExVUVCaE1DVlZNeEZ6QVZCZ05WQkFnVERrNXZjblJvSUVOaGNtOXNhVzVoTVJRd0VnWURWUVFLCkV3dEllWEJsY214bFpHZGxjakVQTUEwR0ExVUVDeE1HUm1GaWNtbGpNUmt3RndZRFZRUURFeEJtWVdKeWFXTXQKWTJFdGMyVnlkbVZ5TUI0WERUSXlNRGd3TkRBMk1ESXdNRm9YRFRJek1EZ3dOREEyTURjd01Gb3dXekVMTUFrRwpBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRS0V3dEllWEJsCmNteGxaR2RsY2pFTk1Bc0dBMVVFQ3hNRWNHVmxjakVPTUF3R0ExVUVBeE1GY0dWbGNqQXdXVEFUQmdjcWhrak8KUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVF5ZmFPOFJSUW1JNzY1MXBlOUliU0diSGc5dHh0QUpQS1F6cHIzYzBmQgpZV0tFWmZTR2hUYWVnb21jNkhUVCtGNXhpMkV1YVZkZFo2cTBwMlh4MmRKRm80SGRNSUhhTUE0R0ExVWREd0VCCi93UUVBd0lIZ0RBTUJnTlZIUk1CQWY4RUFqQUFNQjBHQTFVZERnUVdCQlNNVDJ2c0xQVm1xV0xMbEFwbVpmSGIKSnFEamlEQWZCZ05WSFNNRUdEQVdnQlFxRWRTWmIzMEYzckFLWjRsRnJYSXRYRjRqakRBaUJnTlZIUkVFR3pBWgpnaGR3WldWeU1DNXZjbWN4TG01bGRIZHZjbXN4TG1OdmJUQldCZ2dxQXdRRkJnY0lBUVJLZXlKaGRIUnljeUk2CmV5Sm9aaTVCWm1acGJHbGhkR2x2YmlJNklpSXNJbWhtTGtWdWNtOXNiRzFsYm5SSlJDSTZJbkJsWlhJd0lpd2kKYUdZdVZIbHdaU0k2SW5CbFpYSWlmWDB3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnWlE1YTNtekpaK3pmUDlyTwpjWU9vWEQ5UDVqeE1oUmNMQlBQZ0dnL2JLbllDSUNyM3FlSmdzeFgrRWlBV2drSjNHeFdjK1pRRnNzbTlqTWJBCnIxWGJmK0tJCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KEkcwRQIhAM1Gyv7e+SYniXLgB8iBuRqS4C/A9D36SLl4Zj/AkxrpAiByAoaBFpRIMEJsmGasggaQ4AUST+M2n8ctBZCHjDwRxQ==" - -var b64ViewConfidential = "CjIIAxIYMjAyMi0wOC0wNFQxMDozMjoyMC4zMTlaGgxOb3Rhcml6YXRpb24iBlNUUklORxLrHAr0CAjIARruCAqyAQqNAQRdCc5yPbVtY77Ow/6sH6V8AOwbumdSxFq5T62tOT8LIThrPue3yCQBp7P5/6NoKRZR9grAbP9mVHiZ5814qf/DnXULpdh5O5EbVKSZX5BtmXCqTwpmZaqrQzAGgNXVzB8L6QSEVz48fp9X9SuA3r74mzNM5Ip6WbsNXnENpfifEbUfHcDUK28KHN9U+xogYzlOibmMtRdSuUyam+LQmZ5Y4/9X7AyhqEGNe0INblsSOXJlbGF5LW5ldHdvcmsxOjkwODAvbmV0d29yazEvbXljaGFubmVsOnNpbXBsZXN0YXRlOlJlYWQ6YRgBItMGLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNSakNDQWUyZ0F3SUJBZ0lVUlJSQ2RiWjYzaTU5TTN3NjhQNUkyNXJ6MkxBd0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEl5TURnd05EQTJOVEl3TUZvWERUSXpNRGd3TkRBMk5UY3dNRm93SVRFUE1BMEcKQTFVRUN4TUdZMnhwWlc1ME1RNHdEQVlEVlFRREV3VjFjMlZ5TVRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OQpBd0VIQTBJQUJOT2dvUmJyZ3RmWHhxYS9tYkJRTm15eDFQSVhMQXVhTVdwcUFJdTFMdzFMTTI4dEp0aE9KcVhVCno2RXdITEdlTGxidlNFVDZ4bW9YcmdJdkJCMVp3RzZqZ2Jzd2diZ3dEZ1lEVlIwUEFRSC9CQVFEQWdlQU1Bd0cKQTFVZEV3RUIvd1FDTUFBd0hRWURWUjBPQkJZRUZNc1hQN0JqTXNtZlV1S2Z1ZVVzclk3NHBYMEdNQjhHQTFVZApJd1FZTUJhQUZQd2UxTHJOdUkzM1ZtK0VkZ08vRS9qSmloVTFNRmdHQ0NvREJBVUdCd2dCQkV4N0ltRjBkSEp6CklqcDdJbWhtTGtGbVptbHNhV0YwYVc5dUlqb2lJaXdpYUdZdVJXNXliMnhzYldWdWRFbEVJam9pZFhObGNqRWkKTENKb1ppNVVlWEJsSWpvaVkyeHBaVzUwSW4xOU1Bb0dDQ3FHU000OUJBTUNBMGNBTUVRQ0lCQi82ODFXZkJSKwpRV0lHZmlZS09rM0h1UnRPOEpGd2JUaUVqbkFnQ1J2bkFpQmE2OXdXWWFaMjVaUitHYXk2OWVWK3ZEWmtQTUhTCmdkUmpBSXRjS0dzdEZnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoqJDQwZTFjMGUxLWJkZDctNDQ2MC04YzhhLWRlMTZhOWQyOGYwYRrJCwogZOyCYqcgmQJccj0IkSL3t+oNKIzv0PmJqnzbH2jfIV8SpAsKnAISZgoKX2xpZmVjeWNsZRJYCigKIm5hbWVzcGFjZXMvZmllbGRzL2ludGVyb3AvU2VxdWVuY2USAggGCiwKJm5hbWVzcGFjZXMvZmllbGRzL3NpbXBsZXN0YXRlL1NlcXVlbmNlEgIIAxJ+CgdpbnRlcm9wEnMKHgoYAGFjY2Vzc0NvbnRyb2wAbmV0d29yazIAEgIIJwobChUAbWVtYmVyc2hpcABuZXR3b3JrMgASAggpChYKEAD0j7+/aW5pdGlhbGl6ZWQSAggHChwKFmUyZUNvbmZpZGVudGlhbGl0eUZsYWcSAggHEjIKC3NpbXBsZXN0YXRlEiMKFgoQAPSPv79pbml0aWFsaXplZBICCAQKCQoBYRIECBsQARr0CAjIARruCAqyAQqNAQRdCc5yPbVtY77Ow/6sH6V8AOwbumdSxFq5T62tOT8LIThrPue3yCQBp7P5/6NoKRZR9grAbP9mVHiZ5814qf/DnXULpdh5O5EbVKSZX5BtmXCqTwpmZaqrQzAGgNXVzB8L6QSEVz48fp9X9SuA3r74mzNM5Ip6WbsNXnENpfifEbUfHcDUK28KHN9U+xogYzlOibmMtRdSuUyam+LQmZ5Y4/9X7AyhqEGNe0INblsSOXJlbGF5LW5ldHdvcmsxOjkwODAvbmV0d29yazEvbXljaGFubmVsOnNpbXBsZXN0YXRlOlJlYWQ6YRgBItMGLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNSakNDQWUyZ0F3SUJBZ0lVUlJSQ2RiWjYzaTU5TTN3NjhQNUkyNXJ6MkxBd0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEl5TURnd05EQTJOVEl3TUZvWERUSXpNRGd3TkRBMk5UY3dNRm93SVRFUE1BMEcKQTFVRUN4TUdZMnhwWlc1ME1RNHdEQVlEVlFRREV3VjFjMlZ5TVRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OQpBd0VIQTBJQUJOT2dvUmJyZ3RmWHhxYS9tYkJRTm15eDFQSVhMQXVhTVdwcUFJdTFMdzFMTTI4dEp0aE9KcVhVCno2RXdITEdlTGxidlNFVDZ4bW9YcmdJdkJCMVp3RzZqZ2Jzd2diZ3dEZ1lEVlIwUEFRSC9CQVFEQWdlQU1Bd0cKQTFVZEV3RUIvd1FDTUFBd0hRWURWUjBPQkJZRUZNc1hQN0JqTXNtZlV1S2Z1ZVVzclk3NHBYMEdNQjhHQTFVZApJd1FZTUJhQUZQd2UxTHJOdUkzM1ZtK0VkZ08vRS9qSmloVTFNRmdHQ0NvREJBVUdCd2dCQkV4N0ltRjBkSEp6CklqcDdJbWhtTGtGbVptbHNhV0YwYVc5dUlqb2lJaXdpYUdZdVJXNXliMnhzYldWdWRFbEVJam9pZFhObGNqRWkKTENKb1ppNVVlWEJsSWpvaVkyeHBaVzUwSW4xOU1Bb0dDQ3FHU000OUJBTUNBMGNBTUVRQ0lCQi82ODFXZkJSKwpRV0lHZmlZS09rM0h1UnRPOEpGd2JUaUVqbkFnQ1J2bkFpQmE2OXdXWWFaMjVaUitHYXk2OWVWK3ZEWmtQTUhTCmdkUmpBSXRjS0dzdEZnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoqJDQwZTFjMGUxLWJkZDctNDQ2MC04YzhhLWRlMTZhOWQyOGYwYSIMEgdpbnRlcm9wGgExIqUICtkHCgdPcmcxTVNQEs0HLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNvakNDQWttZ0F3SUJBZ0lVR3g5UFJLMjdGTkdEVTdNdkt1d3hhUWV0WjE4d0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1SUXdFZ1lEVlFRSwpFd3RJZVhCbGNteGxaR2RsY2pFUE1BMEdBMVVFQ3hNR1JtRmljbWxqTVJrd0Z3WURWUVFERXhCbVlXSnlhV010ClkyRXRjMlZ5ZG1WeU1CNFhEVEl5TURnd05EQTJNREl3TUZvWERUSXpNRGd3TkRBMk1EY3dNRm93V3pFTE1Ba0cKQTFVRUJoTUNWVk14RnpBVkJnTlZCQWdURGs1dmNuUm9JRU5oY205c2FXNWhNUlF3RWdZRFZRUUtFd3RJZVhCbApjbXhsWkdkbGNqRU5NQXNHQTFVRUN4TUVjR1ZsY2pFT01Bd0dBMVVFQXhNRmNHVmxjakF3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFReWZhTzhSUlFtSTc2NTFwZTlJYlNHYkhnOXR4dEFKUEtRenByM2MwZkIKWVdLRVpmU0doVGFlZ29tYzZIVFQrRjV4aTJFdWFWZGRaNnEwcDJYeDJkSkZvNEhkTUlIYU1BNEdBMVVkRHdFQgovd1FFQXdJSGdEQU1CZ05WSFJNQkFmOEVBakFBTUIwR0ExVWREZ1FXQkJTTVQydnNMUFZtcVdMTGxBcG1aZkhiCkpxRGppREFmQmdOVkhTTUVHREFXZ0JRcUVkU1piMzBGM3JBS1o0bEZyWEl0WEY0ampEQWlCZ05WSFJFRUd6QVoKZ2hkd1pXVnlNQzV2Y21jeExtNWxkSGR2Y21zeExtTnZiVEJXQmdncUF3UUZCZ2NJQVFSS2V5SmhkSFJ5Y3lJNgpleUpvWmk1QlptWnBiR2xoZEdsdmJpSTZJaUlzSW1obUxrVnVjbTlzYkcxbGJuUkpSQ0k2SW5CbFpYSXdJaXdpCmFHWXVWSGx3WlNJNkluQmxaWElpZlgwd0NnWUlLb1pJemowRUF3SURSd0F3UkFJZ1pRNWEzbXpKWit6ZlA5ck8KY1lPb1hEOVA1anhNaFJjTEJQUGdHZy9iS25ZQ0lDcjNxZUpnc3hYK0VpQVdna0ozR3hXYytaUUZzc205ak1iQQpyMVhiZitLSQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tChJHMEUCIQC4MR1TNTeK+FHqEStQkXTM+9kgF4v3SldTn8G3T8Wb1wIgWnDGTnmhr4gL/UmYdB+uQrYaF3IvGtlKZ4r0rDhczxg=" - -var b64ViewContents = "CghBcmN0dXJ1cxIQTZKuC0jTLZxn3JowK/x2Xg==" - -var fabricCaCertNetwork1 = "-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUPB3O2Bl2ZRliIeSEesdgX0WDahwwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDA2MDIwMFoXDTM3MDczMTA2MDIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpn9XxzOTE3QD0G6q5i9dEnbR\nynT6X5YaFVEwAsdgQylYK7MbmmlkS2ZHBP4Qi5krf+Zwz9yU6zYAPqEZCemLFaNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFCoR1JlvfQXesApniUWtci1cXiOMMAoGCCqGSM49BAMCA0gAMEUCIQCiBaH7Javq\nm2FVNqBXsVn1uwbKYZVHxXH9CE7ANnUF3wIgJ4gjBRrPK4pwHFCd5Yg9Pn383pbd\nzQkhznMIF4SBF4k=\n-----END CERTIFICATE-----\n" - - -var network1Member = common.Member{ - Value: fabricCaCertNetwork1, - Type: "ca", - Chain: []string{}, -} - -var network1Membership = common.Membership{ - SecurityDomain: fabricNetwork, - Members: map[string]*common.Member{"Org1MSP": &network1Member}, -} - -var network1VerificationPolicy = common.VerificationPolicy{ - SecurityDomain: fabricNetwork, - Identifiers: []*common.Identifier{{ - Pattern: fabricPattern, - Policy: &common.Policy{ - Criteria: []string{"Org1MSP"}, - Type: "signature", - }, - }}, +type TestData struct { + B64View string `json:"view64"` + B64ViewConfidential string `json:"confidential_view64"` + B64ViewContents string `json:"confidential_view_content64"` } func TestWriteExternalState(t *testing.T) { + + + var cordaTestDataBytes, _ = ioutil.ReadFile("./test_data/corda_viewdata.json") + var cordaTestData TestData + json.Unmarshal(cordaTestDataBytes, &cordaTestData) + var cordaRootCACert, _ = ioutil.ReadFile("./test_data/corda_cacert_root.pem") + var cordaDoormanCACert, _ = ioutil.ReadFile("./test_data/corda_cacert_doorman.pem") + var cordaNodeCACert, _ = ioutil.ReadFile("./test_data/corda_cacert_node.pem") + + var cordaMember = common.Member{ + Value: "", + Type: "certificate", + Chain: []string{string(cordaRootCACert), string(cordaDoormanCACert), string(cordaNodeCACert)}, + } + + var cordaMembership = common.Membership{ + SecurityDomain: "Corda_Network", + Members: map[string]*common.Member{"PartyA": &cordaMember}, + } + + var cordaVerificationPolicy = common.VerificationPolicy{ + SecurityDomain: "Corda_Network", + Identifiers: []*common.Identifier{{ + Pattern: "localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:*", + Policy: &common.Policy{ + Criteria: []string{"PartyA"}, + Type: "signature", + }, + }}, + } + + var fabricNetwork = "network1" + var fabricRelayEndpoint = "relay-network1:9080" + var fabricPattern = "mychannel:simplestate:Read:a" + var fabricViewAddress = fabricRelayEndpoint + "/" + fabricNetwork + "/" + fabricPattern + + var fabricTestDataBytes, _ = ioutil.ReadFile("./test_data/fabric_viewdata.json") + var fabricTestData TestData + json.Unmarshal(fabricTestDataBytes, &fabricTestData) + + var fabricCaCertNetwork1, _ = ioutil.ReadFile("./test_data/fabric_cacert.pem") + + var network1Member = common.Member{ + Value: string(fabricCaCertNetwork1), + Type: "ca", + Chain: []string{}, + } + + var network1Membership = common.Membership{ + SecurityDomain: fabricNetwork, + Members: map[string]*common.Member{"Org1MSP": &network1Member}, + } + + var network1VerificationPolicy = common.VerificationPolicy{ + SecurityDomain: fabricNetwork, + Identifiers: []*common.Identifier{{ + Pattern: fabricPattern, + Policy: &common.Policy{ + Criteria: []string{"Org1MSP"}, + Type: "signature", + }, + }}, + } // Happy case: Fabric ctx, chaincodeStub := wtest.PrepMockStub() interopcc := SmartContract{} @@ -95,26 +105,26 @@ func TestWriteExternalState(t *testing.T) { Payload: []byte("I am a result"), }) - err = interopcc.WriteExternalState(ctx, fabricNetwork, "mychannel", "Write", []string{"test-key", ""}, []int{1}, []string{fabricViewAddress}, []string{b64View}, []string{""}) + err = interopcc.WriteExternalState(ctx, fabricNetwork, "mychannel", "Write", []string{"test-key", ""}, []int{1}, []string{fabricViewAddress}, []string{fabricTestData.B64View}, []string{""}) require.NoError(t, err) // Test success with encrypted view payload chaincodeStub.GetStateReturnsOnCall(2, network1VerificationPolicyBytes, nil) chaincodeStub.GetStateReturnsOnCall(3, network1MembershipBytes, nil) - err = interopcc.WriteExternalState(ctx, fabricNetwork, "mychannel", "Write", []string{"test-key", ""}, []int{1}, []string{fabricViewAddress}, []string{b64ViewConfidential}, []string{b64ViewContents}) + err = interopcc.WriteExternalState(ctx, fabricNetwork, "mychannel", "Write", []string{"test-key", ""}, []int{1}, []string{fabricViewAddress}, []string{fabricTestData.B64ViewConfidential}, []string{fabricTestData.B64ViewContents}) require.NoError(t, err) // Test failures when invalid or insufficient arguments are supplied - err = interopcc.WriteExternalState(ctx, fabricNetwork, "mychannel", "Write", []string{"test-key", ""}, []int{2}, []string{fabricViewAddress}, []string{b64View}, []string{""}) + err = interopcc.WriteExternalState(ctx, fabricNetwork, "mychannel", "Write", []string{"test-key", ""}, []int{2}, []string{fabricViewAddress}, []string{fabricTestData.B64View}, []string{""}) require.EqualError(t, err, "Index 2 out of bounds of array (length 2)") - err = interopcc.WriteExternalState(ctx, fabricNetwork, "mychannel", "Write", []string{"test-key", ""}, []int{0, 1}, []string{fabricViewAddress}, []string{b64View}, []string{""}) + err = interopcc.WriteExternalState(ctx, fabricNetwork, "mychannel", "Write", []string{"test-key", ""}, []int{0, 1}, []string{fabricViewAddress}, []string{fabricTestData.B64View}, []string{""}) require.EqualError(t, err, "Number of argument indices for substitution (2) does not match number of addresses (1)") err = interopcc.WriteExternalState(ctx, fabricNetwork, "mychannel", "Write", []string{"test-key", ""}, []int{1}, []string{fabricViewAddress}, []string{}, []string{""}) require.EqualError(t, err, "Number of addresses (1) does not match number of views (0)") - err = interopcc.WriteExternalState(ctx, fabricNetwork, "mychannel", "Write", []string{"test-key", ""}, []int{1}, []string{fabricViewAddress}, []string{b64View}, []string{}) + err = interopcc.WriteExternalState(ctx, fabricNetwork, "mychannel", "Write", []string{"test-key", ""}, []int{1}, []string{fabricViewAddress}, []string{fabricTestData.B64View}, []string{}) require.EqualError(t, err, "Number of addresses (1) does not match number of view contents (0)") // Happy case: Corda @@ -132,7 +142,7 @@ func TestWriteExternalState(t *testing.T) { Message: "", Payload: []byte("I am a result"), }) - err = interopcc.WriteExternalState(ctx, fabricNetwork, "mychannel", "Write", []string{"test-key", ""}, []int{1}, []string{"localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H"}, []string{cordaB64View}, []string{""}) + err = interopcc.WriteExternalState(ctx, fabricNetwork, "mychannel", "Write", []string{"test-key", ""}, []int{1}, []string{"localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H"}, []string{cordaTestData.B64View}, []string{""}) require.NoError(t, err) // Test case: Invalid cert in Membership @@ -143,7 +153,7 @@ func TestWriteExternalState(t *testing.T) { require.NoError(t, err) chaincodeStub.GetStateReturnsOnCall(0, network1VerificationPolicyBytes, nil) chaincodeStub.GetStateReturnsOnCall(1, invalidMembershipBytes, nil) - err = interopcc.WriteExternalState(ctx, fabricNetwork, "mychannel", "Write", []string{"test-key", ""}, []int{1}, []string{fabricViewAddress}, []string{b64View}, []string{""}) + err = interopcc.WriteExternalState(ctx, fabricNetwork, "mychannel", "Write", []string{"test-key", ""}, []int{1}, []string{fabricViewAddress}, []string{fabricTestData.B64View}, []string{""}) require.EqualError(t, err, "VerifyView error: Verify membership failed. Certificate not valid: Client cert not in a known PEM format") // Test case: Invalid policy in verification policy @@ -153,6 +163,6 @@ func TestWriteExternalState(t *testing.T) { invalidVerificationPolicyBytes, err := json.Marshal(&network1VerificationPolicy) require.NoError(t, err) chaincodeStub.GetStateReturnsOnCall(0, invalidVerificationPolicyBytes, nil) - err = interopcc.WriteExternalState(ctx, fabricNetwork, "mychannel", "Write", []string{"test-key", ""}, []int{1}, []string{fabricViewAddress}, []string{b64View}, []string{""}) + err = interopcc.WriteExternalState(ctx, fabricNetwork, "mychannel", "Write", []string{"test-key", ""}, []int{1}, []string{fabricViewAddress}, []string{fabricTestData.B64View}, []string{""}) require.EqualError(t, err, "VerifyView error: Unable to resolve verification policy: Verification Policy Error: Failed to find verification policy matching view address: " + fabricPattern) } From 70e610534ca8cf1894375068dbd04d72a21360b1 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Mon, 8 Aug 2022 19:10:22 +0530 Subject: [PATCH 086/150] updated instruction for cert update Signed-off-by: sandeep.nishad1 --- tests/network-setups/fabric/shared/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/network-setups/fabric/shared/README.md b/tests/network-setups/fabric/shared/README.md index a7ac018f1..892496806 100644 --- a/tests/network-setups/fabric/shared/README.md +++ b/tests/network-setups/fabric/shared/README.md @@ -49,5 +49,5 @@ All paths in following steps are relative to this folder (`tests/network-setups/ ``` make backup ``` -Note: Do Update the certs in `fabric-interop-cc` and `corda-interop-app` unit tests for `WriteExternalState`. +Note: Do Update the certs in `fabric-interop-cc/contracts/interop/test_data` and `corda-interop-app/interop-workflows/src/test/resources/test_data` folders for unit tests of `WriteExternalState`. --- From 3bc51e585639428cd75f0a518cf2ce0600975711 Mon Sep 17 00:00:00 2001 From: micky Date: Wed, 10 Aug 2022 12:57:34 +0300 Subject: [PATCH 087/150] Squashed commit of the following: commit f607df913fb727e6b22ca31b176f95b88d8cc95b Author: sandeep.nishad1 Date: Mon Aug 8 19:10:22 2022 +0530 add interoperability between ERC20, ERC721 and ERC1155 Signed-off-by: micky commit 9eb24967751708760a4b0ec5bd1ebd617586a1a9 Author: sannish Date: Thu Aug 4 19:03:43 2022 +0000 update unit tests; added fabric-cli debug log to help updating unit tests viewb64 in core contracts Signed-off-by: sannish commit 96bc4b1ff17b1822f35d2645f8ed4585bf4b5c26 Author: sannish Date: Thu Aug 4 18:43:39 2022 +0000 renew fabric certs for 10 years Signed-off-by: sannish commit 570a961b4c43e603a651f87d769e5f36b196e35a Author: sandeep.nishad1 Date: Thu Aug 4 17:14:57 2022 +0530 use 10 years as expiry for certs in testnet Signed-off-by: sandeep.nishad1 commit ca45fd12d6eb4e98a4dd4582fb3bcf0f3e37109b Author: sandeep.nishad1 Date: Mon Aug 8 19:07:30 2022 +0530 read test data from files for both fabric and corda interop unit tests Signed-off-by: sandeep.nishad1 commit ac10803350ca751a7b4341c6a5c2244002e5f1ef Author: sandeep.nishad1 Date: Thu Aug 4 16:31:46 2022 +0530 remove unncecessary files from fabric/shared (previous commit bug) Signed-off-by: sandeep.nishad1 commit 9dda203d259b0ff85c779aa4a6854a1c769f69a3 Author: sandeep.nishad1 Date: Thu Aug 4 16:29:57 2022 +0530 update unit tests and added that to readme Signed-off-by: sandeep.nishad1 commit 82d0f9a3774406d7decdd41b5f3bd52d5002c163 Author: sannish Date: Thu Aug 4 07:27:09 2022 +0000 update fabric/shared/README as per latest instructions Signed-off-by: sannish commit 00868b913cd5060abbf49b619b1781e488763436 Author: sannish Date: Thu Aug 4 07:20:30 2022 +0000 update expired fabric-certs Signed-off-by: sannish commit 06a774213df95ad3fe91f70faff33d94e13452b6 Author: sandeep.nishad1 Date: Tue Jul 26 14:48:40 2022 +0530 workflow to deploy weaver chaincode docker image Signed-off-by: sandeep.nishad1 commit 9a73b5e2368b58b2fb2fb541b6c714e337ccd66b Author: sandeep.nishad1 Date: Tue Jul 26 14:44:16 2022 +0530 weaver-cc image for external service added Signed-off-by: sandeep.nishad1 commit e32b842f83e5bef43908da3563d363e8c59ad3c5 Author: sandeep.nishad1 Date: Fri Jul 22 12:08:40 2022 +0530 added push latest tag for docker images in workflows Signed-off-by: sandeep.nishad1 commit 79bd3eef7969250cc28e7f21e7658d3d417e7d0e Author: sandeep.nishad1 Date: Fri Jul 22 12:08:13 2022 +0530 add latest tag to docker images; use latest tag in testnet; not push tag (except latest) if already exists Signed-off-by: sandeep.nishad1 commit 602713cd3b3dda7650bf2bbec273ccd0939c594f Author: micky Date: Mon Aug 8 12:46:13 2022 +0300 name refactor for exchange contract Signed-off-by: micky commit 7c7d27da3ce86c78c107e1bcd97ff2d8f54ed378 Author: micky Date: Mon Aug 8 12:39:52 2022 +0300 sc files relocation Signed-off-by: micky commit 50d3db351cf4fedd0a9ebbc42655e03396ae1785 Author: micky Date: Mon Aug 1 16:58:42 2022 +0300 add interoperability between ERC20, ERC721 and ERC1155 Signed-off-by: micky commit 2152eb94f1170aa170c44a667400d826abb37182 Author: Krishnasuri Narayanam Date: Fri Jul 29 18:39:45 2022 +0530 addressing code review comments Signed-off-by: Krishnasuri Narayanam commit 2dcb6eab19ba19d3a96f0ae194ce06be14ba0421 Author: Krishnasuri Narayanam Date: Fri Jul 29 18:27:46 2022 +0530 error handling in the DB layer Signed-off-by: Krishnasuri Narayanam commit 9a664024e6312adba2da5449ed0893e236255e18 Author: Krishnasuri Narayanam Date: Thu Jul 28 12:15:57 2022 +0000 minor edit for version dependency Signed-off-by: Krishnasuri Narayanam commit 4e94a6099bec817285c52078d82d13e1435e040a Author: Krishnasuri Narayanam Date: Thu Jul 28 12:11:24 2022 +0000 version changes Signed-off-by: Krishnasuri Narayanam commit cad7434770ece069ed30146f391e622b59607453 Author: Krishnasuri Narayanam Date: Thu Jul 28 11:24:04 2022 +0000 get the utf8 object in query event subscription Signed-off-by: Krishnasuri Narayanam commit cd61cd814ed564bc9e0cd0207961cd5bf233cc1b Author: Krishnasuri Narayanam Date: Wed Jul 27 13:12:07 2022 +0000 fabric driver doing a query instead of invoke to the ledger Signed-off-by: Krishnasuri Narayanam commit 2c06b9fdd0114f0462c794598a5707e2bba5d5f3 Author: Krishnasuri Narayanam Date: Wed Jul 27 10:24:24 2022 +0000 workaround fix with patch Signed-off-by: Krishnasuri Narayanam commit e5d0e9adfc0bdafa093366a0ece6dbef7080ac84 Author: Krishnasuri Narayanam Date: Wed Jul 27 03:38:54 2022 +0000 disconnect gateway at the end Signed-off-by: Krishnasuri Narayanam commit 3452d8296014cbf62e78ffa39653f6a4ed803183 Author: Krishnasuri Narayanam Date: Tue Jul 26 15:10:19 2022 +0530 changed Args to string array Signed-off-by: Krishnasuri Narayanam commit 29dc74fbc94933c1e0f4db6096c29040987574cd Author: Krishnasuri Narayanam Date: Tue Jul 26 03:02:06 2022 +0000 doc changes and minor edits Signed-off-by: Krishnasuri Narayanam commit 732f3289800cf6eda9944d0d5a803d1db53db25a Author: Krishnasuri Narayanam Date: Fri Jul 22 17:37:53 2022 +0530 code restructuring Signed-off-by: Krishnasuri Narayanam commit 49bd31daaf8243679fb6232f4c2b638d6df8c9fb Author: Krishnasuri Narayanam Date: Thu Jul 21 22:56:36 2022 +0530 destination driver endpoint for writing external ledger state Signed-off-by: Krishnasuri Narayanam commit 2ae92ac0bea65bab0cef004aec785bddf0665afc Author: sandeep.nishad1 Date: Thu Jul 21 19:07:30 2022 +0530 bug fix in fabric driver wallet Setup Signed-off-by: sandeep.nishad1 commit 380b26157c28a1f732d43781c177607bebf75aad Author: sandeep.nishad1 Date: Thu Jul 21 16:51:30 2022 +0530 updated RFC for RequestState proto Signed-off-by: sandeep.nishad1 commit 723a277534e2292b6ea23db53fb08f909bf61ba3 Author: sandeep.nishad1 Date: Thu Jul 21 16:32:26 2022 +0530 Krishna comments addressed; Dockerfile for relay updated Signed-off-by: sandeep.nishad1 commit 43617cc92872d90341d28d437b2abca9a09cd69d Author: sandeep.nishad1 Date: Thu Jul 21 12:38:48 2022 +0530 added unit test for event publish in relay; delete all event states once fetched by client Signed-off-by: sandeep.nishad1 commit ff382a2458441a281b11869a8e285ae8c19244e7 Author: sandeep.nishad1 Date: Wed Jul 20 22:35:52 2022 +0530 added new subscription for app_url target Signed-off-by: sandeep.nishad1 commit ae13c271e428c08ab3629aac09f0f00718e60bd6 Author: sandeep.nishad1 Date: Wed Jul 20 22:27:10 2022 +0530 relay version upgraded to v1.4.2; sdk to v1.4.2 Signed-off-by: sandeep.nishad1 commit f98b957922c41c759145d2c7ed4fd632121a61e4 Author: VRamakrishna Date: Wed Jul 20 14:16:59 2022 +0000 Fixed error message in Fabric Driver Signed-off-by: VRamakrishna commit bd5ca9b59e2732a9e239eb48dcc2fa49876d1b65 Author: VRamakrishna Date: Wed Jul 20 13:03:26 2022 +0000 Deleting event susbcription upon listener registration failure in Fabric Driver Signed-off-by: VRamakrishna commit 59f398079a4b882daa6f42250f7dd8ba38bf936b Author: VRamakrishna Date: Wed Jul 20 12:54:47 2022 +0000 Added event listener removal logic from Fabric Driver Updated the Fabric CLI to match driver changes. Signed-off-by: VRamakrishna commit 4b41a5da779a8144b1cffb87c170857caa740512 Author: VRamakrishna Date: Tue Jul 19 20:09:48 2022 +0000 Fabric driver event code error management and refactoring Also added counters for active listeners for tracking. Signed-off-by: VRamakrishna commit 647db0504bfe1174636f241af05d598d79387464 Author: VRamakrishna Date: Mon Jul 18 20:54:30 2022 +0000 Fixed event listening and CLI triggering logic Channelling events from Fabric driver to the right relay endpoint. Fixed error handling logic in promise-based functions. Managing database access contention in Fabric driver using retry and backoff logic. Updated event subsciption Fabric CLI logic to take multiple subscriptions as input. Added missing text in a tutorial doc. Signed-off-by: VRamakrishna commit ccf08eb21d6f55cda91d81e06b135f4314c3db0a Author: VRamakrishna Date: Thu Jul 14 20:24:37 2022 +0000 Added proof collection logic to Fabric driver event listeners Signed-off-by: VRamakrishna commit 8c860048dc078e8a205f05bf0842ec16c79783db Author: VRamakrishna Date: Thu Jul 14 19:17:12 2022 +0000 Added basic listener support in Fabric driver Added logic to start either a block or a contract listener depending on the content of an event subscription. Upgraded Fabric package dependencies in Fabric driver. Added event emission from 'simplestate' chaincode to test. Made minor fixes in Fabric interop SDK and Fabric CLI config files. Signed-off-by: VRamakrishna commit badd37a111f6acda91da7a93cea9413121778cc3 Author: Krishnasuri Narayanam Date: Thu Jul 14 15:19:26 2022 +0530 convert the sync functions for event subscribe/unsubscribe to async Signed-off-by: Krishnasuri Narayanam commit 2af1fcabf03cb4d29aeaf0c4d8598b666580aec7 Author: VRamakrishna Date: Thu Jul 14 09:34:35 2022 +0000 Updated Fabric CLI README file Signed-off-by: VRamakrishna commit ab58d570ef657f369a11ce88965dd99e46f1bdc0 Author: sandeep.nishad1 Date: Wed Jul 20 22:23:16 2022 +0530 bug fix in get event states relay endpoint; added sdk function to get event states; added fabric cli command for that Signed-off-by: sandeep.nishad1 commit ce133a34bbfe74d64e005cdd3f5a69ec05de3cf9 Author: sandeep.nishad1 Date: Wed Jul 20 22:04:33 2022 +0530 not to change status in case of app_url Signed-off-by: sandeep.nishad1 commit 1ff7a2f59d2aee90530fcb0d0678527ea9d62864 Author: sandeep.nishad1 Date: Wed Jul 20 20:17:00 2022 +0530 updated protos required for event publish, and protos version to 1.4.2 Signed-off-by: sandeep.nishad1 commit 263e610eaae061ab97e05bb9df5f6d41854d4d28 Author: sandeep.nishad1 Date: Wed Jul 20 20:12:13 2022 +0530 event publication support added in relay Signed-off-by: sandeep.nishad1 commit 9cb65c8855531f22b25bd711c54afd12cd87125a Author: Krishnasuri Narayanam Date: Wed Jul 13 14:31:54 2022 +0530 adding identity protos to makefile Signed-off-by: Krishnasuri Narayanam commit 8d7a4592d8ab47e31807198db2ba34c4400e88c4 Author: Krishnasuri Narayanam Date: Wed Jul 13 14:25:02 2022 +0530 updated lookupEventSubscriptions() to allow filtering based on partial key components Signed-off-by: Krishnasuri Narayanam commit efc48e0e403028c54e8425a94cef9b7d6a953c98 Author: Krishnasuri Narayanam Date: Tue Jul 12 16:34:03 2022 +0530 relay event publish stub service Signed-off-by: Krishnasuri Narayanam commit 23765c8d3d59180427bdb904e9953f86548782f3 Author: Krishnasuri Narayanam Date: Tue Jul 12 16:10:31 2022 +0530 version change to 1.4.1 Signed-off-by: Krishnasuri Narayanam commit 92454db362dcead61752f0da322250bded7c8992 Author: Krishnasuri Narayanam Date: Tue Jul 12 15:56:00 2022 +0530 removing DB_NAME env variable Signed-off-by: Krishnasuri Narayanam commit 3849fda4eba6f72d4de4479387ca7c0979f504bd Author: Krishnasuri Narayanam Date: Tue Jul 12 11:53:17 2022 +0530 minor config related edits Signed-off-by: Krishnasuri Narayanam commit 821b7e9590bcda139c08cd7bf9d0758578d0bf30 Author: Krishnasuri Narayanam Date: Tue Jul 12 11:27:44 2022 +0530 driver build-local with weaver-fabric-interop-sdk Signed-off-by: Krishnasuri Narayanam commit 65af748e378989a8d1cb2febe57ba47f5cca994b Author: Krishnasuri Narayanam Date: Mon Jul 11 20:14:49 2022 +0530 changes for event unsubscription Signed-off-by: Krishnasuri Narayanam commit 883482fd53976cbb7af8499e88fb0c70ae9a7c36 Author: Krishnasuri Narayanam Date: Sun Jul 10 23:07:28 2022 +0530 event subscription driver changes env var Signed-off-by: Krishnasuri Narayanam commit b7ea184eb5b7daa262585769c059455b0419ac6c Author: Krishnasuri Narayanam Date: Sat Jul 9 23:45:12 2022 +0530 function to check if policyLists are equal or not Signed-off-by: Krishnasuri Narayanam commit fb978ada886abd93fb2cb4b8d43908d43792e6e2 Author: Krishnasuri Narayanam Date: Sat Jul 9 17:23:20 2022 +0530 updates to dbUtils for event-subscription Signed-off-by: Krishnasuri Narayanam commit dcce6709ad21aecc40cbb9c08bc2c07ebdb5cd56 Author: Krishnasuri Narayanam Date: Fri Jul 8 00:30:26 2022 +0530 dbUtils changes for event-subscription Signed-off-by: Krishnasuri Narayanam commit c585f914a31c612b3b607fd90dc27a5d4009c3af Author: Krishnasuri Narayanam Date: Thu Jul 7 16:54:37 2022 +0530 driver changes for event-subscription Signed-off-by: Krishnasuri Narayanam Signed-off-by: micky --- .../besu/contracts/interop/manageAssetAny.sol | 244 ++++++++++++++++ .../asset-exchange/transferInterface.sol | 29 ++ .../interop/write_external_state_test.go | 1 + .../app/AssetExchangeERC1155_20.js | 268 ++++++++++++++++++ .../simpleasset/app/AssetExchangeERC20.js | 16 +- .../simpleasset/app/AssetExchangeERC721_20.js | 253 +++++++++++++++++ .../besu/simpleasset/contracts/AliceERC20.sol | 27 +- .../simpleasset/contracts/AliceERC721.sol | 50 ++++ .../simpleasset/contracts/AlliceERC1155.sol | 43 +++ .../besu/simpleasset/contracts/BobERC20.sol | 27 +- .../migrations/2_deploy_contracts.js | 9 +- samples/besu/simpleasset/package.json | 2 +- 12 files changed, 950 insertions(+), 19 deletions(-) create mode 100644 core/network/besu/contracts/interop/manageAssetAny.sol create mode 100644 core/network/besu/interface/asset-exchange/transferInterface.sol create mode 100644 samples/besu/simpleasset/app/AssetExchangeERC1155_20.js create mode 100644 samples/besu/simpleasset/app/AssetExchangeERC721_20.js create mode 100644 samples/besu/simpleasset/contracts/AliceERC721.sol create mode 100644 samples/besu/simpleasset/contracts/AlliceERC1155.sol diff --git a/core/network/besu/contracts/interop/manageAssetAny.sol b/core/network/besu/contracts/interop/manageAssetAny.sol new file mode 100644 index 000000000..eb6c9dcca --- /dev/null +++ b/core/network/besu/contracts/interop/manageAssetAny.sol @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.8; + +import "./transferInterface.sol"; +import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; + +/** + * Hashed Timelock Contract on Assets in an Ethereum network (Support only for ERC20, ERC721 and ERC1155 tokens) + **/ + +contract AssetExchangeContract is ERC1155Holder { + mapping(bytes32 => LockContract) public lockContracts; + + struct LockContract { + address sender; + address receiver; + address assetContract; + uint256 amount; + bytes32 hashLock; + uint256 expirationTime; + uint8 status; + uint256 tokenId; + bytes data; + } + + struct transferInfo { + address sender; + address receiver; + uint256 amount; + } + + uint8 constant UNUSED = 0; + uint8 constant LOCKED = 1; + + event Lock( + address indexed sender, + address indexed receiver, + address assetContract, + uint256 amount, + bytes32 hashLock, + uint256 expirationTime, + bytes32 lockContractId + ); + + event Claim( + address indexed sender, + address indexed receiver, + bytes32 indexed lockContractId, + bytes32 hashLock, + bytes32 preimage + ); + + event Unlock( + address indexed sender, + address indexed receiver, + bytes32 indexed lockContractId + ); + + // The sender locks a fungible asset with a hash lock and an expiry time + function lockAsset( + address receiver, + address assetContract, + uint256 amount, + bytes32 hashLock, + uint256 expirationTime, + uint256 tokenId, + bytes memory data + ) external returns (bytes32 lockContractId) { + address sender = msg.sender; + + // Checking the validity of the input parameters + require(amount > 0, "Amount should be greater than zero"); + transferStruct.Info memory transInfo = transferStruct.Info({ + sender: sender, + receiver: address(this), + amount: amount, + tokenId: tokenId, + data: data + }); + require( + transferInterface(assetContract).allowanceInterop(transInfo) == + true, + "Allowance of assets from the sender for the lock contract must be greater than the amount to be locked" + ); + require( + expirationTime > block.timestamp, + "Expiration time should be in the future" + ); + + // The identity of the lock contract is a hash of all the relevant parameters that will uniquely identify the contract + lockContractId = sha256( + abi.encodePacked( + sender, + receiver, + assetContract, + amount, + hashLock, + expirationTime + ) + ); + + require( + lockContracts[lockContractId].status == UNUSED, + "An active lock contract already exists with the same parameters" + ); + + // Locking amount by transfering them to the lockContract + + bool transferStatus = transferInterface(assetContract).transferInterop( + transInfo + ); + // bool transferStatus = ERC20(assetContract).transferFrom(sender, address(this), amount); + require( + transferStatus == true, + "ERC20 transferFrom failed from the sender to the lockContract" + ); + + lockContracts[lockContractId] = LockContract( + sender, + receiver, + assetContract, + amount, + hashLock, + expirationTime, + LOCKED, + tokenId, + data + ); + + emit Lock( + sender, + receiver, + assetContract, + amount, + hashLock, + expirationTime, + lockContractId + ); + } + + // The receiver claims the ownership of an asset locked for them once they obtain the preimage of the hashlock + function claimAsset(bytes32 lockContractId, bytes32 preimage) + external + returns (bool) + { + LockContract storage c = lockContracts[lockContractId]; + + // Check the validity of the claim + require(c.status == LOCKED, "lockContract is not active"); + require(block.timestamp < c.expirationTime, "lockContract has expired"); + require( + c.hashLock == sha256(abi.encodePacked(preimage)), + "Invalid preimage, its hash does not equal the hashLock" + ); + transferStruct.Info memory transInfo = transferStruct.Info({ + sender: address(this), + receiver: c.receiver, + amount: c.amount, + tokenId: c.tokenId, + data: c.data + }); + + c.assetContract.call( + abi.encodeWithSignature( + "approve(address,uint256)", + c.assetContract, + c.amount + ) + ); + c.assetContract.call( + abi.encodeWithSignature( + "setApprovalForAll(address,bool)", + c.assetContract, + true + ) + ); + + bool transferStatus = transferInterface(c.assetContract) + .transferInterop(transInfo); + require( + transferStatus == true, + "ERC20 transfer failed from the lockContract to the receiver" + ); + + emit Claim(c.sender, c.receiver, lockContractId, c.hashLock, preimage); + + return true; + } + + // Unlocking and reclaiming a locked asset for the sender after the expiration time. Can be called by anyone, not just the sender. + function unlockAsset(bytes32 lockContractId) + external + returns (bool) + { + LockContract storage c = lockContracts[lockContractId]; + + // Validation checks + require( + c.status == LOCKED, + "There is no active lockContract with the specified ID" + ); + require(c.sender != address(0), "Sender address is invalid"); + require( + block.timestamp >= c.expirationTime, + "Lock contract has expired" + ); + transferStruct.Info memory transInfo = transferStruct.Info({ + sender: address(this), + receiver: c.sender, + amount: c.amount, + tokenId: c.tokenId, + data: c.data + }); + bool transferStatus = transferInterface(c.assetContract) + .transferInterop(transInfo); + require( + transferStatus == true, + "ERC20 transfer failed from the lockContract back to the sender" + ); + + emit Unlock(c.sender, c.receiver, lockContractId); + + return true; + } + + // Function to check if there is an active contract with the input lockContractId. + function isFungibleAssetLocked(bytes32 lockContractId) + external + view + returns (bool) + { + LockContract storage c = lockContracts[lockContractId]; + + bool lockContractStatus; + if (c.status == LOCKED) { + lockContractStatus = true; + } else { + lockContractStatus = false; + } + + return lockContractStatus; + } +} diff --git a/core/network/besu/interface/asset-exchange/transferInterface.sol b/core/network/besu/interface/asset-exchange/transferInterface.sol new file mode 100644 index 000000000..1f96fc7fe --- /dev/null +++ b/core/network/besu/interface/asset-exchange/transferInterface.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.8; + +/** + * Transfer Interface for asset exchange on Assets in an Ethereum network + **/ + +library transferStruct { + struct Info { + address sender; + address receiver; + uint256 amount; + uint256 tokenId; + bytes data; + } +} + +abstract contract transferInterface { + function transferInterop(transferStruct.Info memory info) + external + virtual + returns (bool success); + + function allowanceInterop(transferStruct.Info memory info) + external + virtual + returns (bool success); +} diff --git a/core/network/fabric-interop-cc/contracts/interop/write_external_state_test.go b/core/network/fabric-interop-cc/contracts/interop/write_external_state_test.go index 449e39cdb..056645270 100644 --- a/core/network/fabric-interop-cc/contracts/interop/write_external_state_test.go +++ b/core/network/fabric-interop-cc/contracts/interop/write_external_state_test.go @@ -19,6 +19,7 @@ import ( wtest "github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/testutils" ) + type TestData struct { B64View string `json:"view64"` B64ViewConfidential string `json:"confidential_view64"` diff --git a/samples/besu/simpleasset/app/AssetExchangeERC1155_20.js b/samples/besu/simpleasset/app/AssetExchangeERC1155_20.js new file mode 100644 index 000000000..a2a97360c --- /dev/null +++ b/samples/besu/simpleasset/app/AssetExchangeERC1155_20.js @@ -0,0 +1,268 @@ +const promisify = require('util').promisify +const sleep = promisify(require('timers').setTimeout) +const fs = require('fs') +const path = require('path') +const contract = require("@truffle/contract"); +const Web3 = require ("web3") +const crypto = require('crypto') + +const networkHost1 = "localhost" +const networkPort1 = "8545" +const networkHost2 = "localhost" +const networkPort2 = "9544" + + +const AliceERC1155TokenContract = require('../build/contracts/AliceERC1155.json') +const BobERC20TokenContract = require('../build/contracts/BobERC20.json') + +let interopContract1 +let interopContract2 +let AliceERC1155 +let BobERC20 + + +// Function to obtain an instance of a smart contract when provided +// as input the path to its JSON file output by 'truffle compile'. +// (Assuming that the current folder is a sibling folder to build, +// the path to json would be ../build/contracts/ContractName.json) +async function getContractInstance(provider, pathToJson){ + const jsonFile = path.resolve(__dirname, pathToJson) + var jsonFileContents = fs.readFileSync(jsonFile) + var contractName = contract(JSON.parse(jsonFileContents)) + contractName.setProvider(provider) + var instance = await contractName.deployed().catch(function () { + console.log("Failed getting the contractName!"); + }) + return instance +} + + +// Initialization of the parameters +async function init(provider1, provider2, contractOwner1, contractOwner2, Alice1, Bob2, tokenSupply, senderInitialBalance) { + interopContract1 = await getContractInstance(provider1,'../build/contracts/AssetExchangeContract.json').catch(function () { + console.log("Failed getting interopContract1!"); + }) + interopContract2 = await getContractInstance(provider2,'../build/contracts/AssetExchangeContract.json').catch(function () { + console.log("Failed getting interopContract2!"); + }) + + AliceERC1155 = await getContractInstance(provider1, '../build/contracts/AliceERC1155.json').catch(function () { + console.log("Failed getting AliceERC1155 token contract!"); + }) + BobERC20 = await getContractInstance(provider2, '../build/contracts/BobERC20.json').catch(function () { + console.log("Failed getting BobERC20 token contract!"); + }) + + // Issue AliceERC1155 tokens to Alice in Network 1 and BobERC20 tokens + // to Bob in Network 2. A minimal number of tokens equal to the + // number of token being exchanged is issued to Alice and Bob to + // ensure that the exchange in this test application does not fail + // due to insufficient funds. + await AliceERC1155.safeTransferFrom(contractOwner1, Alice1, 1, 1, Web3.utils.utf8ToHex(""), {from: contractOwner1}).catch(function (e) { + console.log(e); + console.log("AliceERC1155 transfer threw an error; Probably the token supply is used up!"); + }) + await BobERC20.transfer(Bob2, senderInitialBalance, {from: contractOwner2}).catch(function () { + console.log("BobERC20 transfer threw an error; Probably the token supply is used up!"); + }) + +} + + +// Claim function of a fungible asset/token of type tokenContractId +// and amount tokenAmount locked using contractId for a receiver. +// preimage is the secret to unlock the asset corresponding to the commitment +// used when locking it +async function claimToken(interopContract, lockContractId, recipient, preimage) { + console.log("\n Claiming %s using preimage: %o", lockContractId, preimage) + // console.log(JSON.parse(JSON.stringify(preimage)).data.toString('utf8')) + var claimStatus = await interopContract.claimAsset(lockContractId, preimage, { + from: recipient + }).catch(function (err) { + console.log(err) + console.log("claimAsset threw an error"); + claimStatus = false + }) + + return claimStatus +} + + +// Unlock function of a locked fungible asset/token +async function unlockToken(interopContract, lockContractId, sender) { + var unlockStatus = await interopContract.unlockAsset(lockContractId, { + from: sender + }).catch(function () { + console.log("unlockAsset threw an error"); + unlockStatus = false + }) + + return unlockStatus +} + + +// Function to create a new smart contract for locking asset +// 'sender' locks 'tokenAmount' number of tokens of type 'tokenContract' +// for 'recipient' using the contract constructs of 'interopContract' +// with hashLock and timeLock providing the conditions for claiming/unlocking +async function lockToken(sender, recipient, tokenContract, tokenAmount, interopContract, hashLock, timeLock, type, tokenID, data) { + // initiator of the swap has to first designate the swap contract as a spender of his/her money + // with allowance matching the swap amount + if(type == "ERC1155"){ + await tokenContract.setApprovalForAll(tokenContract.address, true, {from: sender}).catch(function () { + console.log("Token approval failed!!!"); + return false + }) + }else{ + await tokenContract.approve(tokenContract.address, tokenAmount, {from: sender}).catch(function () { + console.log("Token approval failed!!!"); + return false + })} + var lockStatus = interopContract.lockAsset( + recipient, + tokenContract.address, + tokenAmount, + hashLock, + timeLock, + tokenID, + Web3.utils.utf8ToHex(data), + { + from: sender + } + ).catch(function (e) { + console.log(e) + console.log("lockAsset threw an error"); + lockStatus = false + }) + + return lockStatus +} + + +// A function to obtain and print the account balances of a pair +// of accounts in the two participating networks. +// Designed for printing the account balances of the sender and +// recipient at various stages of the exchange. +async function getBalances(Alice1, Bob1, Alice2, Bob2) { + var AliceAliceERC1155Balance = await AliceERC1155.balanceOf(Alice1,1) + console.log("Alice balance of AliceERC1155 in Network 1", AliceAliceERC1155Balance.toString()) + + var BobAliceERC1155Balance = await AliceERC1155.balanceOf(Bob1,1) + console.log("Bob balance of AliceERC1155 in Network 1", await BobAliceERC1155Balance.toString()) + + var AliceBobERC20Balance = await BobERC20.balanceOf(Alice2) + console.log("Alice balance of BobERC20 in Network 2", AliceBobERC20Balance.toString()) + + var BobBobERC20Balance = await BobERC20.balanceOf(Bob2) + console.log("Bob balance of BobERC20 in Network 2", await BobBobERC20Balance.toString()) +} + + +// Main entry point to the app +async function main() { + // Network 1 + const provider1 = new Web3.providers.HttpProvider('http://'+networkHost1+':'+networkPort1) + const web3N1 = new Web3(provider1) + const accounts1 = await web3N1.eth.getAccounts() + + const Alice1 = accounts1[1] // owner of AliceERC1155 and wants swap for BobERC20 + const Bob1 = accounts1[2] // owner of BobERC20 and wants to swap for AliceERC1155 + console.log("Alice address in Network 1", Alice1) + console.log("Bob address in Network 1", Bob1) + + const contractOwner1 = accounts1[0] // owner of all the minted tokens when the contract was created, given how truffleconfig.js is composed + + // Network 2 + const provider2 = new Web3.providers.HttpProvider('http://'+networkHost2+':'+networkPort2) + const web3N2 = new Web3(provider2) + const accounts2 = await web3N2.eth.getAccounts() + + const Alice2 = accounts2[1] // owner of AliceERC1155 and wants swap for BobERC20 + const Bob2 = accounts2[2] // owner of BobERC20 and wants to swap for AliceERC1155 + console.log("Alice address in Network 2", Alice2) + console.log("Bob address in Network 2", Bob2) + + const contractOwner2 = accounts2[0] // owner of all the minted tokens when the contract was created, given how truffleconfig.js is composed + + // Initialization + const tokenSupply = 1000 + const tokenAmount = 10 // Number of tokens to be exchanged + const tokenId = 1; + const senderInitialBalance = tokenAmount + + await init(provider1, provider2, contractOwner1, contractOwner2, Alice1, Bob2, tokenSupply, senderInitialBalance) + + console.log("\n Balances after init():") + await getBalances(Alice1, Bob1, Alice2, Bob2) + + preimage = crypto.randomBytes(32) // to sample a preimage for the hash + hash = crypto.createHash('sha256').update(preimage).digest() + console.log("Hash: ", hash) + + let timeOut = 15 + let timeLockSeconds = Math.floor(Date.now() / 1000) + 2*timeOut + + // Creating a HTLC contract for Alice locking her AliceERC1155 tokens for Bob + let lockTx1 = await lockToken(Alice1, Bob1, AliceERC1155, 1, interopContract1, hash, timeLockSeconds, "ERC1155", 1, "") + if (!lockTx1) { + console.log("\n !!! Locking of Alice's tokens failed in Netowrk 1. Aborting here !!!") + return + } + let lockContractId1 = lockTx1.logs[0].args.lockContractId + console.log("lockContractID1: ", lockContractId1) + + console.log("\n Balances after Alice locks her tokens in Network 1:") + await getBalances(Alice1, Bob1, Alice2, Bob2) + + // After he observes this lockContract created in Network 1, + // Bob creates a similar contract in Network 2 using the same + // hash to transfer the agreed upon amount of BobERC20 to Alice. + // Bob sets the timeLock such that he will have enough time to + // claim Alice's tokens in Network 1 after she claims Bob's + // tokens in Network 2. + timeLockSeconds = Math.floor(Date.now() / 1000) + timeOut + let lockTx2 = await lockToken(Bob2, Alice2, BobERC20, tokenAmount, interopContract2, hash, timeLockSeconds, "ERC20", 1, "") + if (!lockTx2) { + console.log("\n !!! Locking of Bob's tokens failed in Netowrk 2. Aborting here !!!") + return + } + let lockContractId2 = lockTx2.logs[0].args.lockContractId + console.log("lockContractID2: ", lockContractId2) + + console.log("\n Balances after creating Bob locks his tokens in Network 2:") + await getBalances(Alice1, Bob1, Alice2, Bob2) + + // Alice withdrawing Bob's BobERC20 token from lockContractId2 + let claimSuccess2 = await claimToken(interopContract2, lockContractId2, Alice2, preimage) + + console.log("\n Balances after Alice's attempt to claim in Network 2:") + await getBalances(Alice1, Bob1, Alice2, Bob2) + + // If Alice's claim is not successfull, then Alice and Bob unlock their locked tokens + if(!claimSuccess2){ + sleep(2*timeOut*1000) + console.log("\n !!! Claim by Alice not successfull !!! \n Unlocking and refunding tokens to Alice and Bob") + + let unlockSuccess2 = await unlockToken(interopContract2, lockContractId2, Bob2) + let unlockSuccess1 = await unlockToken(interopContract1, lockContractId1, Alice1) + + if(!unlockSuccess2) + console.log("\n !!! Unlocking Bob's tokens not successfull !!!") + if(!unlockSuccess1) + console.log("\n !!! Unlocking Alice's tokens not successfull !!!") + } + else{ + // If Alice's withdrawal is successful, Bob goes ahead and claims Alice's + // AliceERC1155 tokens locked in the lockContractId1 + let claimSuccess1 = await claimToken(interopContract1, lockContractId1, Bob1, preimage) // we assume Bob's claim to be successful if Alice's claim is successful + + if(!claimSuccess1){ + console.log("\n !!! Claim by Bob not successfull !!! \n We had assumed Bob's claim will be successful if Alice's claim is successful") + } + } + + console.log("\n Balances after Bob's attempt to claim in Network 1:") + await getBalances(Alice1, Bob1, Alice2, Bob2) +} + +main() diff --git a/samples/besu/simpleasset/app/AssetExchangeERC20.js b/samples/besu/simpleasset/app/AssetExchangeERC20.js index 917333fa5..23b3ed1a8 100644 --- a/samples/besu/simpleasset/app/AssetExchangeERC20.js +++ b/samples/besu/simpleasset/app/AssetExchangeERC20.js @@ -40,10 +40,10 @@ async function getContractInstance(provider, pathToJson){ // Initialization of the parameters async function init(provider1, provider2, contractOwner1, contractOwner2, Alice1, Bob2, tokenSupply, senderInitialBalance) { - interopContract1 = await getContractInstance(provider1,'../build/contracts/InteroperationBaseClassERC20.json').catch(function () { + interopContract1 = await getContractInstance(provider1,'../build/contracts/AssetExchangeContract.json').catch(function () { console.log("Failed getting interopContract1!"); }) - interopContract2 = await getContractInstance(provider2,'../build/contracts/InteroperationBaseClassERC20.json').catch(function () { + interopContract2 = await getContractInstance(provider2,'../build/contracts/AssetExchangeContract.json').catch(function () { console.log("Failed getting interopContract2!"); }) @@ -74,10 +74,10 @@ async function init(provider1, provider2, contractOwner1, contractOwner2, Alice1 // used when locking it async function claimToken(interopContract, lockContractId, recipient, preimage) { console.log("\n Claiming %s using preimage: %o", lockContractId, preimage) - var claimStatus = await interopContract.claimFungibleAsset(lockContractId, preimage, { + var claimStatus = await interopContract.claimAsset(lockContractId, preimage, { from: recipient }).catch(function () { - console.log("claimFungibleAsset threw an error"); + console.log("claimAsset threw an error"); claimStatus = false }) @@ -87,10 +87,10 @@ async function claimToken(interopContract, lockContractId, recipient, preimage) // Unlock function of a locked fungible asset/token async function unlockToken(interopContract, lockContractId, sender) { - var unlockStatus = await interopContract.unlockFungibleAsset(lockContractId, { + var unlockStatus = await interopContract.unlockAsset(lockContractId, { from: sender }).catch(function () { - console.log("unlockFungibleAsset threw an error"); + console.log("unlockAsset threw an error"); unlockStatus = false }) @@ -110,7 +110,7 @@ async function lockToken(sender, recipient, tokenContract, tokenAmount, interopC return false }) - var lockStatus = interopContract.lockFungibleAsset( + var lockStatus = interopContract.lockAsset( recipient, tokenContract.address, tokenAmount, @@ -120,7 +120,7 @@ async function lockToken(sender, recipient, tokenContract, tokenAmount, interopC from: sender } ).catch(function () { - console.log("lockFungibleAsset threw an error"); + console.log("lockAsset threw an error"); lockStatus = false }) diff --git a/samples/besu/simpleasset/app/AssetExchangeERC721_20.js b/samples/besu/simpleasset/app/AssetExchangeERC721_20.js new file mode 100644 index 000000000..7a84d27ac --- /dev/null +++ b/samples/besu/simpleasset/app/AssetExchangeERC721_20.js @@ -0,0 +1,253 @@ +const promisify = require('util').promisify +const sleep = promisify(require('timers').setTimeout) +const fs = require('fs') +const path = require('path') +const contract = require("@truffle/contract"); +const Web3 = require("web3") +const crypto = require('crypto') + +const networkHost1 = "localhost" +const networkPort1 = "8545" +const networkHost2 = "localhost" +const networkPort2 = "9544" + +let interopContract1 +let interopContract2 +let AliceERC721 +let BobERC20 + + +// Function to obtain an instance of a smart contract when provided +// as input the path to its JSON file output by 'truffle compile'. +// (Assuming that the current folder is a sibling folder to build, +// the path to json would be ../build/contracts/ContractName.json) +async function getContractInstance(provider, pathToJson) { + const jsonFile = path.resolve(__dirname, pathToJson) + var jsonFileContents = fs.readFileSync(jsonFile) + var contractName = contract(JSON.parse(jsonFileContents)) + contractName.setProvider(provider) + var instance = await contractName.deployed().catch(function () { + console.log("Failed getting the contractName!"); + }) + return instance +} + + +// Initialization of the parameters +async function init(provider1, provider2, contractOwner1, contractOwner2, Alice1, Bob2, tokenSupply, senderInitialBalance) { + interopContract1 = await getContractInstance(provider1, '../build/contracts/AssetExchangeContract.json').catch(function () { + console.log("Failed getting interopContract1!"); + }) + interopContract2 = await getContractInstance(provider2, '../build/contracts/AssetExchangeContract.json').catch(function () { + console.log("Failed getting interopContract2!"); + }) + + AliceERC721 = await getContractInstance(provider1, '../build/contracts/AliceERC721.json').catch(function () { + console.log("Failed getting AliceERC721 token contract!"); + }) + BobERC20 = await getContractInstance(provider2, '../build/contracts/BobERC20.json').catch(function () { + console.log("Failed getting BobERC20 token contract!"); + }) + + // Issue AliceERC721 tokens to Alice in Network 1 and BobERC20 tokens + // to Bob in Network 2. A minimal number of tokens equal to the + // number of token being exchanged is issued to Alice and Bob to + // ensure that the exchange in this test application does not fail + // due to insufficient funds. + await AliceERC721.transferFrom(contractOwner1, Alice1, 1, { from: contractOwner1 }).catch(function (e) { + console.log("AliceERC721 transfer threw an error; Probably the token supply is used up!"); + }) + await BobERC20.transfer(Bob2, senderInitialBalance, { from: contractOwner2 }).catch(function () { + console.log("BobERC20 transfer threw an error; Probably the token supply is used up!"); + }) +} + + +// Claim function of a fungible asset/token of type tokenContractId +// and amount tokenAmount locked using contractId for a receiver. +// preimage is the secret to unlock the asset corresponding to the commitment +// used when locking it +async function claimToken(interopContract, lockContractId, recipient, preimage) { + console.log("\n Claiming %s using preimage: %o", lockContractId, preimage) + // console.log(JSON.parse(JSON.stringify(preimage)).data.toString('utf8')) + var claimStatus = await interopContract.claimAsset(lockContractId, preimage, { + from: recipient + }).catch(function (err) { + console.log(err) + console.log("claimAsset threw an error"); + claimStatus = false + }) + + return claimStatus +} + + +// Unlock function of a locked fungible asset/token +async function unlockToken(interopContract, lockContractId, sender) { + var unlockStatus = await interopContract.unlockAsset(lockContractId, { + from: sender + }).catch(function () { + console.log("unlockAsset threw an error"); + unlockStatus = false + }) + + return unlockStatus +} + + +// Function to create a new smart contract for locking asset +// 'sender' locks 'tokenAmount' number of tokens of type 'tokenContract' +// for 'recipient' using the contract constructs of 'interopContract' +// with hashLock and timeLock providing the conditions for claiming/unlocking +async function lockToken(sender, recipient, tokenContract, tokenAmount, interopContract, hashLock, timeLock, tokenId = 0, data = "") { + // initiator of the swap has to first designate the swap contract as a spender of his/her money + // with allowance matching the swap amount + await tokenContract.approve(tokenContract.address, tokenAmount, { from: sender }).catch(function () { + console.log("Token approval failed!!!"); + return false + }) + var lockStatus = interopContract.lockAsset( + recipient, + tokenContract.address, + tokenAmount, + hashLock, + timeLock, + tokenId, + Web3.utils.utf8ToHex(data), + { + from: sender + } + ).catch(function () { + console.log("lockAsset threw an error"); + lockStatus = false + }) + + return lockStatus +} + + +// A function to obtain and print the account balances of a pair +// of accounts in the two participating networks. +// Designed for printing the account balances of the sender and +// recipient at various stages of the exchange. +async function getBalances(Alice1, Bob1, Alice2, Bob2) { + var AliceAliceERC721Balance = await AliceERC721.balanceOf(Alice1) + console.log("Alice balance of AliceERC721 in Network 1", AliceAliceERC721Balance.toString()) + + var BobAliceERC721Balance = await AliceERC721.balanceOf(Bob1) + console.log("Bob balance of AliceERC721 in Network 1", await BobAliceERC721Balance.toString()) + + var AliceBobERC20Balance = await BobERC20.balanceOf(Alice2) + console.log("Alice balance of BobERC20 in Network 2", AliceBobERC20Balance.toString()) + + var BobBobERC20Balance = await BobERC20.balanceOf(Bob2) + console.log("Bob balance of BobERC20 in Network 2", await BobBobERC20Balance.toString()) +} + + +// Main entry point to the app +async function main() { + // Network 1 + const provider1 = new Web3.providers.HttpProvider('http://' + networkHost1 + ':' + networkPort1) + const web3N1 = new Web3(provider1) + const accounts1 = await web3N1.eth.getAccounts() + + const Alice1 = accounts1[1] // owner of AliceERC721 and wants swap for BobERC20 + const Bob1 = accounts1[2] // owner of BobERC20 and wants to swap for AliceERC721 + console.log("Alice address in Network 1", Alice1) + console.log("Bob address in Network 1", Bob1) + + const contractOwner1 = accounts1[0] // owner of all the minted tokens when the contract was created, given how truffleconfig.js is composed + + // Network 2 + const provider2 = new Web3.providers.HttpProvider('http://' + networkHost2 + ':' + networkPort2) + const web3N2 = new Web3(provider2) + const accounts2 = await web3N2.eth.getAccounts() + + const Alice2 = accounts2[1] // owner of AliceERC721 and wants swap for BobERC20 + const Bob2 = accounts2[2] // owner of BobERC20 and wants to swap for AliceERC721 + console.log("Alice address in Network 2", Alice2) + console.log("Bob address in Network 2", Bob2) + + const contractOwner2 = accounts2[0] // owner of all the minted tokens when the contract was created, given how truffleconfig.js is composed + + // Initialization + const tokenSupply = 1000 + const tokenAmount = 10 // Number of tokens to be exchanged + const tokenId = 1; + const senderInitialBalance = tokenAmount + + await init(provider1, provider2, contractOwner1, contractOwner2, Alice1, Bob2, tokenSupply, senderInitialBalance) + + console.log("\n Balances after init():") + await getBalances(Alice1, Bob1, Alice2, Bob2) + + preimage = crypto.randomBytes(32) // to sample a preimage for the hash + hash = crypto.createHash('sha256').update(preimage).digest() + console.log("Hash: ", hash) + + let timeOut = 15 + let timeLockSeconds = Math.floor(Date.now() / 1000) + 2 * timeOut + + // Creating a HTLC contract for Alice locking her AliceERC721 tokens for Bob + let lockTx1 = await lockToken(Alice1, Bob1, AliceERC721, 1, interopContract1, hash, timeLockSeconds, tokenId) + if (!lockTx1) { + console.log("\n !!! Locking of Alice's tokens failed in Netowrk 1. Aborting here !!!") + return + } + let lockContractId1 = lockTx1.logs[0].args.lockContractId + + console.log("\n Balances after Alice locks her tokens in Network 1:") + await getBalances(Alice1, Bob1, Alice2, Bob2) + + // After he observes this lockContract created in Network 1, + // Bob creates a similar contract in Network 2 using the same + // hash to transfer the agreed upon amount of BobERC20 to Alice. + // Bob sets the timeLock such that he will have enough time to + // claim Alice's tokens in Network 1 after she claims Bob's + // tokens in Network 2. + timeLockSeconds = Math.floor(Date.now() / 1000) + timeOut + let lockTx2 = await lockToken(Bob2, Alice2, BobERC20, tokenAmount, interopContract2, hash, timeLockSeconds, tokenId) + if (!lockTx2) { + console.log("\n !!! Locking of Bob's tokens failed in Netowrk 2. Aborting here !!!") + return + } + let lockContractId2 = lockTx2.logs[0].args.lockContractId + + console.log("\n Balances after creating Bob locks his tokens in Network 2:") + await getBalances(Alice1, Bob1, Alice2, Bob2) + + // Alice withdrawing Bob's BobERC20 token from lockContractId2 + let claimSuccess2 = await claimToken(interopContract2, lockContractId2, Alice2, preimage) + + console.log("\n Balances after Alice's attempt to claim in Network 2:") + await getBalances(Alice1, Bob1, Alice2, Bob2) + + // If Alice's claim is not successfull, then Alice and Bob unlock their locked tokens + if (!claimSuccess2) { + sleep(2 * timeOut * 1000) + console.log("\n !!! Claim by Alice not successfull !!! \n Unlocking and refunding tokens to Alice and Bob") + + let unlockSuccess2 = await unlockToken(interopContract2, lockContractId2, Bob2) + let unlockSuccess1 = await unlockToken(interopContract1, lockContractId1, Alice1) + + if (!unlockSuccess2) + console.log("\n !!! Unlocking Bob's tokens not successfull !!!") + if (!unlockSuccess1) + console.log("\n !!! Unlocking Alice's tokens not successfull !!!") + } + else { + // If Alice's withdrawal is successful, Bob goes ahead and claims Alice's + // AliceERC721 tokens locked in the lockContractId1 + let claimSuccess1 = await claimToken(interopContract1, lockContractId1, Bob1, preimage) // we assume Bob's claim to be successful if Alice's claim is successful + + if (!claimSuccess1) { + console.log("\n !!! Claim by Bob not successfull !!! \n We had assumed Bob's claim will be successful if Alice's claim is successful") + } + } + + console.log("\n Balances after Bob's attempt to claim in Network 1:") + await getBalances(Alice1, Bob1, Alice2, Bob2) +} + +main() diff --git a/samples/besu/simpleasset/contracts/AliceERC20.sol b/samples/besu/simpleasset/contracts/AliceERC20.sol index b199ede9d..0e7edf897 100644 --- a/samples/besu/simpleasset/contracts/AliceERC20.sol +++ b/samples/besu/simpleasset/contracts/AliceERC20.sol @@ -3,12 +3,31 @@ pragma solidity ^0.8.8; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "./transferInterface.sol"; /** * A basic token for testing the HashedTimelockERC20. */ -contract AliceERC20 is ERC20 { - constructor(uint256 initialSupply) ERC20("Alice Token", "AliceToken") { - _mint(msg.sender, initialSupply); - } +contract AliceERC20 is ERC20, transferInterface { + constructor(uint256 initialSupply) ERC20("Alice Token", "AliceToken") { + _mint(msg.sender, initialSupply); + } + + function transferInterop(transferStruct.Info memory info) + public + override + returns (bool success) + { + this.transferFrom(info.sender, info.receiver, info.amount); + return true; + } + + function allowanceInterop(transferStruct.Info memory info) + public + view + override + returns (bool success) + { + return this.allowance(info.sender, address(this)) >= info.amount; + } } diff --git a/samples/besu/simpleasset/contracts/AliceERC721.sol b/samples/besu/simpleasset/contracts/AliceERC721.sol new file mode 100644 index 000000000..14592aef3 --- /dev/null +++ b/samples/besu/simpleasset/contracts/AliceERC721.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.8; + +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import "@openzeppelin/contracts/utils/Counters.sol"; +import "./transferInterface.sol"; + +/** + * A basic token for testing the HashedTimelockERC721. + */ +contract AliceERC721 is ERC721, transferInterface { + using Counters for Counters.Counter; + Counters.Counter public _tokenIds; + address owner; + + constructor() ERC721("Alice NFT", "AliceNFT") { + for (uint256 i = 0; i < 5; i++) { + _tokenIds.increment(); + uint256 newItemId = _tokenIds.current(); + _safeMint(msg.sender, newItemId); + } + owner = msg.sender; + } + + function mint(address to) public { + require(msg.sender == owner); + _tokenIds.increment(); + uint256 newItemId = _tokenIds.current(); + _safeMint(to, newItemId); + } + + function transferInterop(transferStruct.Info memory info) + public + override + returns (bool success) + { + this.transferFrom(info.sender, info.receiver, info.amount); + return true; + } + + function allowanceInterop(transferStruct.Info memory info) + public + view + override + returns (bool success) + { + return this.getApproved(info.tokenId) == address(this); + } +} diff --git a/samples/besu/simpleasset/contracts/AlliceERC1155.sol b/samples/besu/simpleasset/contracts/AlliceERC1155.sol new file mode 100644 index 000000000..72815425e --- /dev/null +++ b/samples/besu/simpleasset/contracts/AlliceERC1155.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.8; + +/** + * A basic token for testing the HashedTimelockERC20. + */ +import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; +import "./transferInterface.sol"; + +contract AliceERC1155 is ERC1155, transferInterface { + uint256 public constant AliceToken = 0; + uint256 public constant AliceNFT = 1; + + constructor() ERC1155("") { + _mint(msg.sender, AliceToken, 10**18, ""); + _mint(msg.sender, AliceNFT, 1, ""); + } + + function transferInterop(transferStruct.Info memory info) + public + override + returns (bool success) + { + this.safeTransferFrom( + info.sender, + info.receiver, + info.tokenId, + info.amount, + info.data + ); + return true; + } + + function allowanceInterop(transferStruct.Info memory info) + public + view + override + returns (bool success) + { + return this.isApprovedForAll(info.sender, address(this)); + } +} diff --git a/samples/besu/simpleasset/contracts/BobERC20.sol b/samples/besu/simpleasset/contracts/BobERC20.sol index d8ae3dc47..f2fe1c3ff 100644 --- a/samples/besu/simpleasset/contracts/BobERC20.sol +++ b/samples/besu/simpleasset/contracts/BobERC20.sol @@ -3,12 +3,31 @@ pragma solidity ^0.8.8; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "./transferInterface.sol"; /** * A basic token for testing the HashedTimelockERC20. */ -contract BobERC20 is ERC20 { - constructor(uint256 initialSupply) ERC20("Bob Token", "BobToken") { - _mint(msg.sender, initialSupply); - } +contract BobERC20 is ERC20, transferInterface { + constructor(uint256 initialSupply) ERC20("Bob Token", "BobToken") { + _mint(msg.sender, initialSupply); + } + + function transferInterop(transferStruct.Info memory info) + public + override + returns (bool success) + { + this.transferFrom(info.sender, info.receiver, info.amount); + return true; + } + + function allowanceInterop(transferStruct.Info memory info) + public + view + override + returns (bool success) + { + return this.allowance(info.sender, address(this)) >= info.amount; + } } diff --git a/samples/besu/simpleasset/migrations/2_deploy_contracts.js b/samples/besu/simpleasset/migrations/2_deploy_contracts.js index d776919d5..916d5a0e0 100644 --- a/samples/besu/simpleasset/migrations/2_deploy_contracts.js +++ b/samples/besu/simpleasset/migrations/2_deploy_contracts.js @@ -1,9 +1,14 @@ -const InteroperationBaseClassERC20 = artifacts.require('InteroperationBaseClassERC20') const AliceERC20 = artifacts.require('./AliceERC20.sol') const BobERC20 = artifacts.require('./BobERC20.sol') +const AliceERC721 = artifacts.require('./AliceERC721.sol') +const AssetExchangeContract = artifacts.require('AssetExchangeContract') +const AliceERC1155 = artifacts.require('./AliceERC1155.sol') + module.exports = function (deployer) { - deployer.deploy(InteroperationBaseClassERC20) deployer.deploy(AliceERC20, 1000) // Change intialSupply from 1000 as required deployer.deploy(BobERC20, 1000) // Change intialSupply from 1000 as required + deployer.deploy(AliceERC721) + deployer.deploy(AssetExchangeContract) + deployer.deploy(AliceERC1155) } diff --git a/samples/besu/simpleasset/package.json b/samples/besu/simpleasset/package.json index c1e47c171..ef315efa9 100644 --- a/samples/besu/simpleasset/package.json +++ b/samples/besu/simpleasset/package.json @@ -12,7 +12,7 @@ "test": "test" }, "scripts": { - "copy-interop-contracts": "cp ../../../core/network/besu/contracts/interop/manageAsset.sol contracts/", + "copy-interop-contracts": "cp ../../../core/network/besu/contracts/interop/manageAssetAny.sol contracts/ && cp ../../../core/network/besu/contracts/asset-exchange/transferInterface.sol contracts/", "update-truffle-config": "node get-network-details.js", "deploy-contract": "npm run copy-interop-contracts && npm install && npm run update-truffle-config && truffle compile && truffle migrate", "clean-run": "rm -rf package-lock.json build", From a61e0ce682496a92918eb0192e70e4783dbe9588 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Sat, 13 Aug 2022 20:03:11 +0000 Subject: [PATCH 088/150] changes for dynamic query arg support in events Signed-off-by: Krishnasuri Narayanam --- common/protos/common/events.proto | 5 + .../fabric-driver/server/fabric-code.ts | 19 ++- core/drivers/fabric-driver/server/listener.ts | 7 +- core/drivers/fabric-driver/server/server.ts | 4 +- core/drivers/fabric-driver/server/utils.ts | 13 +- .../interop/handle_external_request.go | 140 ++++++++++-------- 6 files changed, 121 insertions(+), 67 deletions(-) diff --git a/common/protos/common/events.proto b/common/protos/common/events.proto index 416247532..5588f6caa 100644 --- a/common/protos/common/events.proto +++ b/common/protos/common/events.proto @@ -28,6 +28,11 @@ enum EventSubOperation { UPDATE = 2; } +message EventQuery { + string query_bytes64 = 1; + bytes dynamic_query_arg = 2; +} + // Below message is used to communicate between dest-relay and src-relay; // and src-relay and src-driver. message EventSubscription { diff --git a/core/drivers/fabric-driver/server/fabric-code.ts b/core/drivers/fabric-driver/server/fabric-code.ts index e20e02011..441c5d110 100644 --- a/core/drivers/fabric-driver/server/fabric-code.ts +++ b/core/drivers/fabric-driver/server/fabric-code.ts @@ -16,6 +16,7 @@ import interopPayload from '@hyperledger-labs/weaver-protos-js/common/interop_pa import state_pb from '@hyperledger-labs/weaver-protos-js/common/state_pb'; import { Certificate } from '@fidm/x509'; import { getConfig } from './walletSetup'; +import { createEventQuerySerialized } from './utils'; const parseAddress = (address: string) => { const addressList = address.split('/'); @@ -77,6 +78,8 @@ const getNetworkGateway = async (networkName: string): Promise => { async function invoke( query: query_pb.Query, networkName: string, + funName: string, + dynamicArg: Buffer | undefined ): Promise { console.log('Running query on fabric network'); try { @@ -115,11 +118,21 @@ async function invoke( const idx = gateway.identityContext.calculateTransactionId(); const queryProposal = currentChannel.newQuery(chaincodeId); - const request = { - fcn: 'HandleExternalRequest', + let request; + if (funName == 'HandleExternalRequest') { + request = { + fcn: funName, args: [b64QueryBytes], generateTransactionId: false - }; + }; + } else { + const b64EventQueryBytes = createEventQuerySerialized(b64QueryBytes, dynamicArg) + request = { + fcn: funName, + args: [b64EventQueryBytes], + generateTransactionId: false + }; + } queryProposal.build(idx, request); queryProposal.sign(idx); // 3. Set the endorser list for the transaction, this enforces that the list provided will endorse the proposed transaction diff --git a/core/drivers/fabric-driver/server/listener.ts b/core/drivers/fabric-driver/server/listener.ts index fb043b6a6..33356adff 100644 --- a/core/drivers/fabric-driver/server/listener.ts +++ b/core/drivers/fabric-driver/server/listener.ts @@ -45,6 +45,7 @@ const initBlockEventListenerForChannel = async ( // Get transaction chaincode ID const chaincodeId = transaction.payload.chaincode_proposal_payload.input.chaincode_spec.chaincode_id.name; if (transaction.payload.chaincode_proposal_payload.input.chaincode_spec.input.args.length > 0) { + const responsePayload = transaction.payload.action.proposal_response_payload.extension.response.payload; // Get transaction function name: first argument according to convention const chaincodeFunc = transaction.payload.chaincode_proposal_payload.input.chaincode_spec.input.args[0].toString(); console.log('Trying to find match for channel', channelId, 'chaincode', chaincodeId, 'function', chaincodeFunc); @@ -76,6 +77,8 @@ const initBlockEventListenerForChannel = async ( invoke( eventSubscriptionQuery, networkName, + 'HandleEventRequest', + Buffer.from(responsePayload) ), ); if (!invokeError) { @@ -131,12 +134,14 @@ const initContractEventListener = ( } // Iterate through the view requests in the matching event subscriptions eventSubscriptionQueries.forEach(async (eventSubscriptionQuery: query_pb.Query) => { - console.log('Generating view and collecting proof for event class', event.eventName, 'channel', channelId, 'chaincode', chaincodeId); + console.log('Generating view and collecting proof for event class', event.eventName, 'channel', channelId, 'chaincode', chaincodeId, 'event.payload', event.payload.toString()); // Trigger proof collection const [result, invokeError] = await handlePromise( invoke( eventSubscriptionQuery, networkName, + 'HandleEventRequest', + event.payload ), ); if (!invokeError) { diff --git a/core/drivers/fabric-driver/server/server.ts b/core/drivers/fabric-driver/server/server.ts index a7e33780a..e9faa68ba 100644 --- a/core/drivers/fabric-driver/server/server.ts +++ b/core/drivers/fabric-driver/server/server.ts @@ -76,6 +76,8 @@ const fabricCommunication = async (query: query_pb.Query, networkName: string) = invoke( query, networkName, + 'HandleExternalRequest', + undefined ), ); const client = getRelayClientForQueryResponse(); @@ -253,7 +255,7 @@ server.addService(driver_pb_grpc.DriverCommunicationService, { // Prepares required crypto material for communication with the fabric network const configSetup = async () => { // uses the network name to create a unique wallet path - const walletPath = path.join(process.cwd(), `wallet-${process.env.NETWORK_NAME}`); + const walletPath = path.join(process.cwd(), `wallet-${process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1'}`); if (process.env.CONNECTION_PROFILE) { walletSetup( walletPath, diff --git a/core/drivers/fabric-driver/server/utils.ts b/core/drivers/fabric-driver/server/utils.ts index 1d7282ac3..a6425e473 100644 --- a/core/drivers/fabric-driver/server/utils.ts +++ b/core/drivers/fabric-driver/server/utils.ts @@ -8,6 +8,7 @@ import fs from 'fs'; import { credentials } from '@grpc/grpc-js'; import datatransfer_grpc_pb from '@hyperledger-labs/weaver-protos-js/relay/datatransfer_grpc_pb'; import events_grpc_pb from '@hyperledger-labs/weaver-protos-js/relay/events_grpc_pb'; +import eventsPb from '@hyperledger-labs/weaver-protos-js/common/events_pb'; function checkIfArraysAreEqual(x: Array, y: Array): boolean { if (x == y) { @@ -94,10 +95,20 @@ function getRelayClientForEventPublish() { return client; } +// Create an asset exchange agreement structure +function createEventQuerySerialized(queryBytes64: string, dynamicQueryArg: Buffer) +{ + const eventQuery = new eventsPb.EventQuery(); + eventQuery.setQueryBytes64(queryBytes64); + eventQuery.setDynamicQueryArg(dynamicQueryArg); + return Buffer.from(eventQuery.serializeBinary()).toString('base64'); +} + export { checkIfArraysAreEqual, handlePromise, relayCallback, getRelayClientForQueryResponse, - getRelayClientForEventPublish + getRelayClientForEventPublish, + createEventQuerySerialized } diff --git a/core/network/fabric-interop-cc/contracts/interop/handle_external_request.go b/core/network/fabric-interop-cc/contracts/interop/handle_external_request.go index 9c92e0167..3cb9a85aa 100644 --- a/core/network/fabric-interop-cc/contracts/interop/handle_external_request.go +++ b/core/network/fabric-interop-cc/contracts/interop/handle_external_request.go @@ -12,13 +12,14 @@ import ( "encoding/base64" "errors" "fmt" + "strings" + "github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go/common" + wutils "github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/utils" "github.com/hyperledger/fabric-chaincode-go/shim" "github.com/hyperledger/fabric-contract-api-go/contractapi" log "github.com/sirupsen/logrus" - "github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go/common" protoV2 "google.golang.org/protobuf/proto" - wutils "github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/utils" ) // HandleExternalRequest chaincode processes requests that come from external networks. @@ -29,47 +30,85 @@ import ( // 3. Checks the access control policy for the requester and view address is met // 4. Calls application chaincode func (s *SmartContract) HandleExternalRequest(ctx contractapi.TransactionContextInterface, b64QueryBytes string) (string, error) { - // Ensure that this function cannot be called by a client without relay permissions - relayAccessCheck, err := wutils.IsClientRelay(ctx.GetStub()) + queryBytes, err := base64.StdEncoding.DecodeString(b64QueryBytes) if err != nil { - return "", err + return "", logThenErrorf("Unable to base64 decode data: %s", err.Error()) } - if !relayAccessCheck { - return "", fmt.Errorf("Illegal access by relay") + var query common.Query + err = protoV2.Unmarshal(queryBytes, &query) + if err != nil { + return "", logThenErrorf("Unable to unmarshal query: %s", err.Error()) } - fmt.Println("Relay access check passed") + resp, err := handleRequest(s, ctx, query, query.Address) + return resp, err +} - queryBytes, err := base64.StdEncoding.DecodeString(b64QueryBytes) +func (s *SmartContract) HandleEventRequest(ctx contractapi.TransactionContextInterface, b64EventQueryBytes string) (string, error) { + eventQueryBytes, err := base64.StdEncoding.DecodeString(b64EventQueryBytes) + if err != nil { + return "", logThenErrorf("Unable to base64 decode data: %s", err.Error()) + } + var eventQuery common.EventQuery + err = protoV2.Unmarshal(eventQueryBytes, &eventQuery) if err != nil { - errorMessage := fmt.Sprintf("Unable to base64 decode data: %s", err.Error()) - log.Error(errorMessage) - return "", errors.New(errorMessage) + return "", logThenErrorf("Unable to unmarshal eventQuery: %s", err.Error()) + } + + queryBytes, err := base64.StdEncoding.DecodeString(eventQuery.QueryBytes64) + if err != nil { + return "", logThenErrorf("Unable to base64 decode data: %s", err.Error()) } var query common.Query err = protoV2.Unmarshal(queryBytes, &query) if err != nil { - errorMessage := fmt.Sprintf("Unable to unmarshal query: %s", err.Error()) - log.Error(errorMessage) - return "", errors.New(errorMessage) + return "", logThenErrorf("Unable to unmarshal query: %s", err.Error()) } + + queryAddress := query.Address + dynamicArgCount := strings.Count(query.Address, ":?") + if dynamicArgCount > 1 { + return "", logThenErrorf("Expected 1 dynamic arg, but found %d", dynamicArgCount) + } else if dynamicArgCount == 1 { + queryArg := string(eventQuery.DynamicQueryArg) + queryAddress = strings.Replace(query.Address, ":?", ":"+queryArg, 1) + } else { + fmt.Println("There are no dynamic arguments in the event query. queryArg: ", string(eventQuery.DynamicQueryArg)) + } + + resp, err := handleRequest(s, ctx, query, queryAddress) + return resp, err +} + +// handleRequest function requests that come from external networks. +// +// The flow coordinates the following: +// 1. Checks the validity of query signature +// 2. Checks that the certificate of the requester is valid according to the network's Membership +// 3. Checks the access control policy for the requester and view address is met +// 4. Calls application chaincode +func handleRequest(s *SmartContract, ctx contractapi.TransactionContextInterface, query common.Query, queryAddress string) (string, error) { + // Ensure that this function cannot be called by a client without relay permissions + relayAccessCheck, err := wutils.IsClientRelay(ctx.GetStub()) + if err != nil { + return "", err + } + if !relayAccessCheck { + return "", fmt.Errorf("Illegal access by client without relay permissions") + } + fmt.Println("Relay access check passed") + x509Cert, err := parseCert(query.Certificate) if err != nil { - errorMessage := fmt.Sprintf("Unable to parse certificate: %s", err) - log.Error(errorMessage) - return "", errors.New(errorMessage) + return "", logThenErrorf("Unable to parse certificate: %s", err) } // 1. Checks the validity of query signature signatureBytes, err := base64.StdEncoding.DecodeString(query.RequestorSignature) if err != nil { - errorMessage := fmt.Sprintf("Signature base64 decoding failed: %s", err) - log.Error(errorMessage) - return "", errors.New(errorMessage) + return "", logThenErrorf("Signature base64 decoding failed: %s", err) } err = validateSignature(query.Address+query.Nonce, x509Cert, string(signatureBytes)) if err != nil { - errorMessage := fmt.Sprintf("Invalid Signature: %s", err) - log.Error(errorMessage) - return "", errors.New(errorMessage) + return "", logThenErrorf("Invalid Signature: %s", err) } // 2. Checks that the certificate of the requester is valid according to the network's Membership if query.RequestingOrg == "" { @@ -78,28 +117,20 @@ func (s *SmartContract) HandleExternalRequest(ctx contractapi.TransactionContext err = verifyMemberInSecurityDomain(s, ctx, x509Cert, query.RequestingNetwork, query.RequestingOrg) if err != nil { - errorMessage := fmt.Sprintf("Membership Verification failed: %s", err) - log.Error(errorMessage) - return "", errors.New(errorMessage) + return "", logThenErrorf("Membership Verification failed: %s", err) } // 3. Checks the access control policy for the requester and view address is met - address, err := parseAddress(query.Address) + address, err := parseAddress(queryAddress) if err != nil { - errorMessage := fmt.Sprintf("Invalid address: %s", err) - log.Error(errorMessage) - return "", errors.New(errorMessage) + return "", logThenErrorf("Invalid address: %s", err) } viewAddress, err := parseFabricViewAddress(address.ViewSegment) if err != nil { - errorMessage := fmt.Sprintf("Invalid view address: %s", err) - log.Error(errorMessage) - return "", errors.New(errorMessage) + return "", logThenErrorf("Invalid view address: %s", err) } err = verifyAccessToCC(s, ctx, viewAddress, address.ViewSegment, &query) if err != nil { - errorMessage := fmt.Sprintf("CC Access Denied: %s", err) - log.Error(errorMessage) - return "", errors.New(errorMessage) + return "", logThenErrorf("CC Access Denied: %s", err) } // 4. Calls application chaincode arr := append([]string{viewAddress.CCFunc}, viewAddress.Args...) @@ -113,30 +144,22 @@ func (s *SmartContract) HandleExternalRequest(ctx contractapi.TransactionContext resp := "" if viewAddress.CCFunc == "GetHTLCHash" { if len(viewAddress.Args) > 2 { - errorMessage := fmt.Sprintf("Recieved more arguments than required 2 argument.") - log.Error(errorMessage) - return "", errors.New(errorMessage) + return "", logThenErrorf("Recieved more arguments than required 2 argument.") } resp, err = s.GetHTLCHash(ctx, viewAddress.Args[0], viewAddress.Args[1]) } else if viewAddress.CCFunc == "GetHTLCHashByContractId" { if len(viewAddress.Args) > 1 { - errorMessage := fmt.Sprintf("Recieved more arguments than required 1 argument.") - log.Error(errorMessage) - return "", errors.New(errorMessage) + return "", logThenErrorf("Recieved more arguments than required 1 argument.") } resp, err = s.GetHTLCHashByContractId(ctx, viewAddress.Args[0]) } else if viewAddress.CCFunc == "GetHTLCHashPreImage" { if len(viewAddress.Args) > 2 { - errorMessage := fmt.Sprintf("Recieved more arguments than required 2 argument.") - log.Error(errorMessage) - return "", errors.New(errorMessage) + return "", logThenErrorf("Recieved more arguments than required 2 argument.") } resp, err = s.GetHTLCHashPreImage(ctx, viewAddress.Args[0], viewAddress.Args[1]) } else if viewAddress.CCFunc == "GetHTLCHashPreImageByContractId" { if len(viewAddress.Args) > 1 { - errorMessage := fmt.Sprintf("Recieved more arguments than required 1 argument.") - log.Error(errorMessage) - return "", errors.New(errorMessage) + return "", logThenErrorf("Recieved more arguments than required 1 argument.") } resp, err = s.GetHTLCHashPreImageByContractId(ctx, viewAddress.Args[0]) } else { @@ -152,9 +175,7 @@ func (s *SmartContract) HandleExternalRequest(ctx contractapi.TransactionContext // General Interop Call to AppCC pbResp := ctx.GetStub().InvokeChaincode(viewAddress.Contract, byteArgs, viewAddress.Channel) if pbResp.Status != shim.OK { - errorMessage := fmt.Sprintf("Application chaincode invoke error: %s", string(pbResp.GetMessage())) - log.Error(errorMessage) - return "", errors.New(errorMessage) + return "", logThenErrorf("Application chaincode invoke error: %s", string(pbResp.GetMessage())) } // 5. Encrypt payload if necessary confFlag, err := ctx.GetStub().GetState(e2eConfidentialityKey) @@ -168,8 +189,7 @@ func (s *SmartContract) HandleExternalRequest(ctx contractapi.TransactionContext // Use already authenticated certificate as the source of the public key for encryption payload, err = generateConfidentialInteropPayloadAndHash(pbResp.Payload, query.Certificate) if err != nil { - log.Error(err) - return "", err + return "", logThenErrorf(err.Error()) } } else { payload = pbResp.Payload @@ -177,17 +197,15 @@ func (s *SmartContract) HandleExternalRequest(ctx contractapi.TransactionContext } interopPayloadStruct := common.InteropPayload{ - Address: query.Address, - Payload: payload, - Confidential: confidential, + Address: queryAddress, + Payload: payload, + Confidential: confidential, RequestorCertificate: query.Certificate, - Nonce: query.Nonce, + Nonce: query.Nonce, } interopPayloadBytes, err := protoV2.Marshal(&interopPayloadStruct) if err != nil { - errorMessage := fmt.Sprintf("Unable to marshal interop payload: %s", err) - log.Error(errorMessage) - return "", errors.New(errorMessage) + return "", logThenErrorf("Unable to marshal interop payload: %s", err) } return string(interopPayloadBytes), nil } From 21a6270f41281e375c43368b43abcff82b3d3b69 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Mon, 15 Aug 2022 03:00:52 +0000 Subject: [PATCH 089/150] BlockEventListener to fetch payload similar to ContractEventListener instead of from response Signed-off-by: Krishnasuri Narayanam --- core/drivers/fabric-driver/server/listener.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/core/drivers/fabric-driver/server/listener.ts b/core/drivers/fabric-driver/server/listener.ts index 33356adff..eae1a4297 100644 --- a/core/drivers/fabric-driver/server/listener.ts +++ b/core/drivers/fabric-driver/server/listener.ts @@ -45,7 +45,10 @@ const initBlockEventListenerForChannel = async ( // Get transaction chaincode ID const chaincodeId = transaction.payload.chaincode_proposal_payload.input.chaincode_spec.chaincode_id.name; if (transaction.payload.chaincode_proposal_payload.input.chaincode_spec.input.args.length > 0) { - const responsePayload = transaction.payload.action.proposal_response_payload.extension.response.payload; + // below way of fetching payload requires that the response has been set by the chaincode function via return value + //const responsePayload = transaction.payload.action.proposal_response_payload.extension.response.payload; + // below way of fetching payload is similar to ContractEventListener in which we fetch event.payload + const responsePayload = transaction.payload.action.proposal_response_payload.extension.events.payload; // Get transaction function name: first argument according to convention const chaincodeFunc = transaction.payload.chaincode_proposal_payload.input.chaincode_spec.input.args[0].toString(); console.log('Trying to find match for channel', channelId, 'chaincode', chaincodeId, 'function', chaincodeFunc); @@ -71,14 +74,14 @@ const initBlockEventListenerForChannel = async ( } // Iterate through the view requests in the matching event subscriptions eventSubscriptionQueries.forEach(async (eventSubscriptionQuery: query_pb.Query) => { - console.log('Generating view and collecting proof for channel', channelId, 'chaincode', chaincodeId, 'function', chaincodeFunc); + console.log('Generating view and collecting proof for channel', channelId, 'chaincode', chaincodeId, 'function', chaincodeFunc, 'responsePayload', responsePayload.toString()); // Trigger proof collection const [result, invokeError] = await handlePromise( invoke( eventSubscriptionQuery, networkName, 'HandleEventRequest', - Buffer.from(responsePayload) + responsePayload ), ); if (!invokeError) { From 6462cc0837ff04139dc4391e1773f448b5ef8ec8 Mon Sep 17 00:00:00 2001 From: micky Date: Mon, 15 Aug 2022 22:50:40 +0300 Subject: [PATCH 090/150] add github action for besu asset exchange & besu cli update Signed-off-by: micky --- .../workflows/test_asset-exchange-besu.yml | 124 +++++++++ .../besu/contracts/interop/manageAssetAny.sol | 23 +- .../besu/besu-cli/src/commands/asset/claim.ts | 6 +- .../besu-cli/src/commands/asset/exchange.ts | 32 +-- .../src/commands/asset/get-balance.ts | 1 + .../besu-cli/src/commands/asset/is-locked.ts | 4 +- .../besu/besu-cli/src/commands/asset/lock.ts | 30 ++- .../besu-cli/src/commands/asset/unlock.ts | 7 +- .../simpleasset/app/AssetExchangeERC20.js | 26 +- .../simpleasset/contracts/manageAssetAny.sol | 255 ++++++++++++++++++ .../contracts/transferInterface.sol | 29 ++ 11 files changed, 487 insertions(+), 50 deletions(-) create mode 100644 .github/workflows/test_asset-exchange-besu.yml create mode 100644 samples/besu/simpleasset/contracts/manageAssetAny.sol create mode 100644 samples/besu/simpleasset/contracts/transferInterface.sol diff --git a/.github/workflows/test_asset-exchange-besu.yml b/.github/workflows/test_asset-exchange-besu.yml new file mode 100644 index 000000000..f8c67ac23 --- /dev/null +++ b/.github/workflows/test_asset-exchange-besu.yml @@ -0,0 +1,124 @@ +# This is a basic workflow to help you get started with Actions + +name: Test Asset Exchange Besu + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the main branch + push: + branches: [ main ] + pull_request: + branches: [ main ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + + asset-exchange-corda: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v3 + + - name: Set up JDK 11 + uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'adopt' + + # CORDA NETWORK + - name: Generate github.properties + run: | + echo "Using ${GITHUB_ACTOR} user." + echo "username=${GITHUB_ACTOR}" >> github.properties + echo "password=${{ secrets.GITHUB_TOKEN }}" >> github.properties + echo "url=https://maven.pkg.github.com/${GITHUB_ACTOR}/weaver-dlt-interoperability" >> github.properties + + echo "Using ${GITHUB_ACTOR} user." + echo "username=${GITHUB_ACTOR}" >> github.main.properties + echo "password=${{ secrets.GITHUB_TOKEN }}" >> github.main.properties + echo "url=https://maven.pkg.github.com/hyperledger-labs/weaver-dlt-interoperability" >> github.main.properties + + ./scripts/get-cordapps.sh || mv github.main.properties github.properties + + cat github.properties + working-directory: tests/network-setups/besu + + # BESU NETWORK + - name: Start Besu Network + run: | + sudo apt install -y tmux jq + wget https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/22.7.0/besu-22.7.0.zip + unzip besu-22.7.0.zip + export PATH="${PWD}/besu-22.7.0/bin:$PATH" + wget https://artifacts.consensys.net/public/ethsigner/raw/names/ethsigner.zip/versions/22.1.3/ethsigner-22.1.3.zip + unzip ethsigner-22.1.3.zip + export PATH="${PWD}/ethsigner-22.1.3/bin:$PATH" + make start + sleep 100 + working-directory: tests/network-setups/besu + + # Deploy contracts + - name: Deploy contracts + run: | + make deploy-contracts + working-directory: samples/besu/simpleasset + + # BESU CLI + - name: Setup BESU CLI init + run: | + npm install . + export PATH="${PWD}/bin:$PATH" + cp config.template.json tmp.json + cp config.template.json tmp.json + jq -r '.network1.tokenContract |= "../simpleasset/build/contracts/AliceERC20.json"' tmp.json > config.json + cp config.json tmp.json + jq -r '.network2.tokenContract |= "../simpleasset/build/contracts/BobERC20.json"' tmp.json > config.json + rm tmp.json + working-directory: samples/besu/besu-cli + + - name: Asset Exchange Besu CLI Tests + run: | + COUNT=0 + TOTAL=3 + + # issue 10 tokens to account 1 + besu-cli asset issue --network=network1 --account=1 --amount=10 + + # lock 1 token for account 2 in network 2 + besu-cli asset lock --network=network1 --sender_account=1 --recipient_account=2 --amount=1 --timeout=1000 1> tmp.out + cat tmp.out | grep "Account balance of the sender in Network network1: 9" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + tmp_string=$(cat tmp.out | grep "Lock contract ID:") + arrIN=(${tmp_string//:/ }) + LOCK_ID=${arrIN[3]} + tmp_string=$(cat tmp.out | grep "Preimage:") + arrIN=(${tmp_string//:/ }) + PREIMAGE=${arrIN[1]} + + # Is Asset locked + besu-cli asset is-locked --network=network1 --lock_contract_id=$LOCK_ID 1> tmp.out + cat tmp.out | grep "in Network network1: true" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # Claim asset + besu-cli asset claim --network=network1 --lock_contract_id=$LOCK_ID --recipient_account=2 --preimage=&PREIMAGE 1> tmp.out + cat tmp.out | grep "Account balance of the recipient in Network network1 after claiming: 1" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # RESULT + echo "Passed $COUNT/$TOTAL Tests." + + if [ $COUNT == $TOTAL ]; then + exit 0 + else + exit 1 + fi + working-directory: samples/besu/besu-cli + diff --git a/core/network/besu/contracts/interop/manageAssetAny.sol b/core/network/besu/contracts/interop/manageAssetAny.sol index eb6c9dcca..162561959 100644 --- a/core/network/besu/contracts/interop/manageAssetAny.sol +++ b/core/network/besu/contracts/interop/manageAssetAny.sol @@ -57,7 +57,7 @@ contract AssetExchangeContract is ERC1155Holder { bytes32 indexed lockContractId ); - // The sender locks a fungible asset with a hash lock and an expiry time + // The sender locks a asset with a hash lock and an expiry time function lockAsset( address receiver, address assetContract, @@ -189,10 +189,7 @@ contract AssetExchangeContract is ERC1155Holder { } // Unlocking and reclaiming a locked asset for the sender after the expiration time. Can be called by anyone, not just the sender. - function unlockAsset(bytes32 lockContractId) - external - returns (bool) - { + function unlockAsset(bytes32 lockContractId) external returns (bool) { LockContract storage c = lockContracts[lockContractId]; // Validation checks @@ -212,6 +209,20 @@ contract AssetExchangeContract is ERC1155Holder { tokenId: c.tokenId, data: c.data }); + c.assetContract.call( + abi.encodeWithSignature( + "approve(address,uint256)", + c.assetContract, + c.amount + ) + ); + c.assetContract.call( + abi.encodeWithSignature( + "setApprovalForAll(address,bool)", + c.assetContract, + true + ) + ); bool transferStatus = transferInterface(c.assetContract) .transferInterop(transInfo); require( @@ -225,7 +236,7 @@ contract AssetExchangeContract is ERC1155Holder { } // Function to check if there is an active contract with the input lockContractId. - function isFungibleAssetLocked(bytes32 lockContractId) + function isAssetLocked(bytes32 lockContractId) external view returns (bool) diff --git a/samples/besu/besu-cli/src/commands/asset/claim.ts b/samples/besu/besu-cli/src/commands/asset/claim.ts index 0179f83de..e55cc1840 100644 --- a/samples/besu/besu-cli/src/commands/asset/claim.ts +++ b/samples/besu/besu-cli/src/commands/asset/claim.ts @@ -60,7 +60,7 @@ const command: GluegunCommand = { ) return } - print.info('Claim assets (fungible assets for now)') + print.info('Claim assets') // Retrieving networkConfig if(!options.network){ @@ -127,10 +127,10 @@ const command: GluegunCommand = { var recipientBalance = await tokenContract.balanceOf(recipient) console.log(`Account balance of the recipient in Network ${options.network} before claiming: ${recipientBalance.toString()}`) - await interopContract.claimFungibleAsset(lockContractId, options.preimage, { + await interopContract.claimAsset(lockContractId, preimage_bytes32, { from: recipient, }).catch((error) => { - console.log("claimFungibleAsset threw an error:", error); + console.log("claimAsset threw an error:", error); }) // Balance of the recipient after claiming diff --git a/samples/besu/besu-cli/src/commands/asset/exchange.ts b/samples/besu/besu-cli/src/commands/asset/exchange.ts index 2962abae0..925d8bdb5 100644 --- a/samples/besu/besu-cli/src/commands/asset/exchange.ts +++ b/samples/besu/besu-cli/src/commands/asset/exchange.ts @@ -141,7 +141,7 @@ const command: GluegunCommand = { return }) - const lockTx1 = await interopContract1.lockFungibleAsset( + const lockTx1 = await interopContract1.lockAsset( recipient1, tokenContract1.address, amount, @@ -151,7 +151,7 @@ const command: GluegunCommand = { from: sender1 } ).catch(function () { - console.log("lockFungibleAsset threw an error in Network 1"); + console.log("lockAsset threw an error in Network 1"); return }) const lockContractId1 = lockTx1.logs[0].args.lockContractId @@ -169,15 +169,15 @@ const command: GluegunCommand = { // Locking the asset (works only for ERC20 at this point) await tokenContract2.approve(interopContract2.address, amount, {from: sender2}).catch(async function () { console.log("Token2 approval failed!!!"); - await interopContract1.unlockFungibleAsset(lockContractId1, { + await interopContract1.unlockAsset(lockContractId1, { from: sender1 }).catch(function () { - console.log("unlockFungibleAsset threw an error in Network 1"); + console.log("unlockAsset threw an error in Network 1"); }) return }) - const lockTx2 = await interopContract2.lockFungibleAsset( + const lockTx2 = await interopContract2.lockAsset( recipient2, tokenContract2.address, amount, @@ -187,11 +187,11 @@ const command: GluegunCommand = { from: sender2 } ).catch(async function () { - console.log("lockFungibleAsset threw an error in Network 2"); - await interopContract1.unlockFungibleAsset(lockContractId1, { + console.log("lockAsset threw an error in Network 2"); + await interopContract1.unlockAsset(lockContractId1, { from: sender1 }).catch(function () { - console.log("unlockFungibleAsset threw an error in Network 1"); + console.log("unlockAsset threw an error in Network 1"); }) return }) @@ -203,17 +203,17 @@ const command: GluegunCommand = { await getBalances(tokenContract2, sender2, recipient2) // ------------ Withdrawal in Network 1 ------------- - await interopContract1.claimFungibleAsset(lockContractId1, preimage, {from: recipient1}).catch(async function () { - console.log("claimFungibleAsset threw an error in Network 1"); - await interopContract1.unlockFungibleAsset(lockContractId1, { + await interopContract1.claimAsset(lockContractId1, preimage, {from: recipient1}).catch(async function () { + console.log("claimAsset threw an error in Network 1"); + await interopContract1.unlockAsset(lockContractId1, { from: sender1 }).catch(function () { - console.log("unlockFungibleAsset threw an error in Network 1"); + console.log("unlockAsset threw an error in Network 1"); }) - await interopContract2.unlockFungibleAsset(lockContractId2, { + await interopContract2.unlockAsset(lockContractId2, { from: sender2 }).catch(function () { - console.log("unlockFungibleAsset threw an error in Network 2"); + console.log("unlockAsset threw an error in Network 2"); }) return }) @@ -221,8 +221,8 @@ const command: GluegunCommand = { await getBalances(tokenContract1, sender1, recipient1) // ------------ Withdrawal in Network 2 ------------- - await interopContract2.claimFungibleAsset(lockContractId2, preimage, {from: recipient2}).catch(function () { - console.log("claimFungibleAsset threw an error in Network 2"); + await interopContract2.claimAsset(lockContractId2, preimage, {from: recipient2}).catch(function () { + console.log("claimAsset threw an error in Network 2"); return }) console.log(`Account balances after withdrawal in Network 2`) diff --git a/samples/besu/besu-cli/src/commands/asset/get-balance.ts b/samples/besu/besu-cli/src/commands/asset/get-balance.ts index 3d04c2a26..48724f9eb 100644 --- a/samples/besu/besu-cli/src/commands/asset/get-balance.ts +++ b/samples/besu/besu-cli/src/commands/asset/get-balance.ts @@ -68,6 +68,7 @@ const command: GluegunCommand = { const web3N = new Web3(provider) const accounts = await web3N.eth.getAccounts() + console.log(networkConfig.tokenContract) const tokenContract = await getContractInstance(provider, networkConfig.tokenContract).catch(function () { console.log("Failed getting tokenContract!"); }) diff --git a/samples/besu/besu-cli/src/commands/asset/is-locked.ts b/samples/besu/besu-cli/src/commands/asset/is-locked.ts index 1aafea010..d1a103d55 100644 --- a/samples/besu/besu-cli/src/commands/asset/is-locked.ts +++ b/samples/besu/besu-cli/src/commands/asset/is-locked.ts @@ -74,10 +74,10 @@ const command: GluegunCommand = { const accounts = await web3N.eth.getAccounts() var sender = accounts[networkConfig.senderAccountIndex] - var isLocked = await interopContract.isFungibleAssetLocked(lockContractId, { + var isLocked = await interopContract.isAssetLocked(lockContractId, { from: sender }).catch(function () { - console.log("isFungibleAssetLocked threw an error"); + console.log("isAssetLocked threw an error"); }) console.log(`Is there an asset locked in ${lockContractId} in Network ${options.network}: ${isLocked}`) //Todo: Debug. isLocked is not printing correctly. } diff --git a/samples/besu/besu-cli/src/commands/asset/lock.ts b/samples/besu/besu-cli/src/commands/asset/lock.ts index 85d93688a..223fce050 100644 --- a/samples/besu/besu-cli/src/commands/asset/lock.ts +++ b/samples/besu/besu-cli/src/commands/asset/lock.ts @@ -6,7 +6,7 @@ const crypto = require('crypto') const command: GluegunCommand = { name: 'lock', - description: 'Lock assets (fungible assets for now)', + description: 'Lock assets', run: async toolbox => { const { @@ -69,6 +69,16 @@ const command: GluegunCommand = { name: '--network_port', description: 'The network port. Default value is taken from config.json' + }, + { + name: '--token_id', + description: + 'Specify the token id for which the asset is to be locked. This is an optional parameter only for ERC721 & ERC1155.' + }, + { + name: '--data', + description: + 'Specify the data for ERC1155 token. This is an optional parameter only for ERC1155.' } ], command, @@ -76,7 +86,7 @@ const command: GluegunCommand = { ) return } - print.info('Lock assets (fungible assets for now)') + print.info('Lock assets') // Retrieving networkConfig if(!options.network){ @@ -138,6 +148,12 @@ const command: GluegunCommand = { print.error('Timeout not provided.') return } + if(!options.token_id){ + options.token_id = 0 + } + if(!options.data){ + options.data = "" + } const timeLock = Math.floor(Date.now() / 1000) + options.timeout // The hash input has to be dealt with care. The smart contracts take in bytes as input. But the cli takes in strings as input. So to handle that, we take in the hash in its base64 version as input and then obtain the byte array from this. If a hash is not provided, we generate a base 64 encoding and then generate its corresponding byte array from it. This byte array will be input to generate the hash. var hash @@ -173,20 +189,22 @@ const command: GluegunCommand = { console.log(`Account balance of the recipient in Network ${options.network}: ${recipientBalance.toString()}`) // Locking the asset (works only for ERC20 at this point) - await tokenContract.approve(interopContract.address, amount, {from: sender}).catch(function () { + await tokenContract.approve(tokenContract.address, amount, {from: sender}).catch(function () { console.log("Token approval failed!!!"); }) - const lockTx = await interopContract.lockFungibleAsset( + const lockTx = await interopContract.lockAsset( recipient, tokenContract.address, amount, hash, timeLock, + options.token_id, + Web3.utils.utf8ToHex(options.data), { from: sender } - ).catch(function () { - console.log("lockFungibleAsset threw an error"); + ).catch(function (e) { + console.log("lockAsset threw an error"); }) const lockContractId = lockTx.logs[0].args.lockContractId console.log(`Lock contract ID: ${lockContractId.toString().substring(2)}`) diff --git a/samples/besu/besu-cli/src/commands/asset/unlock.ts b/samples/besu/besu-cli/src/commands/asset/unlock.ts index 7880b9338..36c89c6d5 100644 --- a/samples/besu/besu-cli/src/commands/asset/unlock.ts +++ b/samples/besu/besu-cli/src/commands/asset/unlock.ts @@ -112,10 +112,11 @@ const command: GluegunCommand = { var senderBalance = await tokenContract.balanceOf(sender) console.log(`Account balance of the sender in Network ${options.network} before unlocking: ${senderBalance.toString()}`) - await interopContract.unlockFungibleAsset(lockContractId, { + await interopContract.unlockAsset(lockContractId, { from: sender - }).catch(function () { - console.log("unlockFungibleAsset threw an error"); + }).catch(function (e) { + console.log(e) + console.log("unlockAsset threw an error"); }) // Balance of the recipient after claiming diff --git a/samples/besu/simpleasset/app/AssetExchangeERC20.js b/samples/besu/simpleasset/app/AssetExchangeERC20.js index 23b3ed1a8..4eda407d8 100644 --- a/samples/besu/simpleasset/app/AssetExchangeERC20.js +++ b/samples/besu/simpleasset/app/AssetExchangeERC20.js @@ -12,9 +12,6 @@ const networkHost2 = "localhost" const networkPort2 = "9544" -const AliceERC20TokenContract = require('../build/contracts/AliceERC20.json') -const BobERC20TokenContract = require('../build/contracts/BobERC20.json') - let interopContract1 let interopContract2 let AliceERC20 @@ -33,7 +30,6 @@ async function getContractInstance(provider, pathToJson){ var instance = await contractName.deployed().catch(function () { console.log("Failed getting the contractName!"); }) - return instance } @@ -46,7 +42,7 @@ async function init(provider1, provider2, contractOwner1, contractOwner2, Alice1 interopContract2 = await getContractInstance(provider2,'../build/contracts/AssetExchangeContract.json').catch(function () { console.log("Failed getting interopContract2!"); }) - + AliceERC20 = await getContractInstance(provider1, '../build/contracts/AliceERC20.json').catch(function () { console.log("Failed getting AliceERC20 token contract!"); }) @@ -59,7 +55,7 @@ async function init(provider1, provider2, contractOwner1, contractOwner2, Alice1 // number of token being exchanged is issued to Alice and Bob to // ensure that the exchange in this test application does not fail // due to insufficient funds. - await AliceERC20.transfer(Alice1, senderInitialBalance, {from: contractOwner1}).catch(function () { + await AliceERC20.transferFrom(contractOwner1, Alice1, 1, {from: contractOwner1}).catch(function (e) { console.log("AliceERC20 transfer threw an error; Probably the token supply is used up!"); }) await BobERC20.transfer(Bob2, senderInitialBalance, {from: contractOwner2}).catch(function () { @@ -74,9 +70,11 @@ async function init(provider1, provider2, contractOwner1, contractOwner2, Alice1 // used when locking it async function claimToken(interopContract, lockContractId, recipient, preimage) { console.log("\n Claiming %s using preimage: %o", lockContractId, preimage) + // console.log(JSON.parse(JSON.stringify(preimage)).data.toString('utf8')) var claimStatus = await interopContract.claimAsset(lockContractId, preimage, { from: recipient - }).catch(function () { + }).catch(function (err) { + console.log(err) console.log("claimAsset threw an error"); claimStatus = false }) @@ -102,20 +100,21 @@ async function unlockToken(interopContract, lockContractId, sender) { // 'sender' locks 'tokenAmount' number of tokens of type 'tokenContract' // for 'recipient' using the contract constructs of 'interopContract' // with hashLock and timeLock providing the conditions for claiming/unlocking -async function lockToken(sender, recipient, tokenContract, tokenAmount, interopContract, hashLock, timeLock) { +async function lockToken(sender, recipient, tokenContract, tokenAmount, interopContract, hashLock, timeLock, tokenId=0, data="") { // initiator of the swap has to first designate the swap contract as a spender of his/her money // with allowance matching the swap amount - await tokenContract.approve(interopContract.address, tokenAmount, {from: sender}).catch(function () { + await tokenContract.approve(tokenContract.address, tokenAmount, {from: sender}).catch(function () { console.log("Token approval failed!!!"); return false }) - var lockStatus = interopContract.lockAsset( recipient, tokenContract.address, tokenAmount, hashLock, timeLock, + tokenId, + Web3.utils.utf8ToHex(data), { from: sender } @@ -176,6 +175,7 @@ async function main() { // Initialization const tokenSupply = 1000 const tokenAmount = 10 // Number of tokens to be exchanged + const tokenId = 1; const senderInitialBalance = tokenAmount await init(provider1, provider2, contractOwner1, contractOwner2, Alice1, Bob2, tokenSupply, senderInitialBalance) @@ -191,13 +191,12 @@ async function main() { let timeLockSeconds = Math.floor(Date.now() / 1000) + 2*timeOut // Creating a HTLC contract for Alice locking her AliceERC20 tokens for Bob - let lockTx1 = await lockToken(Alice1, Bob1, AliceERC20, tokenAmount, interopContract1, hash, timeLockSeconds) + let lockTx1 = await lockToken(Alice1, Bob1, AliceERC20, 1, interopContract1, hash, timeLockSeconds, tokenId) if (!lockTx1) { console.log("\n !!! Locking of Alice's tokens failed in Netowrk 1. Aborting here !!!") return } let lockContractId1 = lockTx1.logs[0].args.lockContractId - console.log("lockContractID1: ", lockContractId1) console.log("\n Balances after Alice locks her tokens in Network 1:") await getBalances(Alice1, Bob1, Alice2, Bob2) @@ -209,13 +208,12 @@ async function main() { // claim Alice's tokens in Network 1 after she claims Bob's // tokens in Network 2. timeLockSeconds = Math.floor(Date.now() / 1000) + timeOut - let lockTx2 = await lockToken(Bob2, Alice2, BobERC20, tokenAmount, interopContract2, hash, timeLockSeconds) + let lockTx2 = await lockToken(Bob2, Alice2, BobERC20, tokenAmount, interopContract2, hash, timeLockSeconds, tokenId) if (!lockTx2) { console.log("\n !!! Locking of Bob's tokens failed in Netowrk 2. Aborting here !!!") return } let lockContractId2 = lockTx2.logs[0].args.lockContractId - console.log("lockContractID2: ", lockContractId2) console.log("\n Balances after creating Bob locks his tokens in Network 2:") await getBalances(Alice1, Bob1, Alice2, Bob2) diff --git a/samples/besu/simpleasset/contracts/manageAssetAny.sol b/samples/besu/simpleasset/contracts/manageAssetAny.sol new file mode 100644 index 000000000..162561959 --- /dev/null +++ b/samples/besu/simpleasset/contracts/manageAssetAny.sol @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.8; + +import "./transferInterface.sol"; +import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; + +/** + * Hashed Timelock Contract on Assets in an Ethereum network (Support only for ERC20, ERC721 and ERC1155 tokens) + **/ + +contract AssetExchangeContract is ERC1155Holder { + mapping(bytes32 => LockContract) public lockContracts; + + struct LockContract { + address sender; + address receiver; + address assetContract; + uint256 amount; + bytes32 hashLock; + uint256 expirationTime; + uint8 status; + uint256 tokenId; + bytes data; + } + + struct transferInfo { + address sender; + address receiver; + uint256 amount; + } + + uint8 constant UNUSED = 0; + uint8 constant LOCKED = 1; + + event Lock( + address indexed sender, + address indexed receiver, + address assetContract, + uint256 amount, + bytes32 hashLock, + uint256 expirationTime, + bytes32 lockContractId + ); + + event Claim( + address indexed sender, + address indexed receiver, + bytes32 indexed lockContractId, + bytes32 hashLock, + bytes32 preimage + ); + + event Unlock( + address indexed sender, + address indexed receiver, + bytes32 indexed lockContractId + ); + + // The sender locks a asset with a hash lock and an expiry time + function lockAsset( + address receiver, + address assetContract, + uint256 amount, + bytes32 hashLock, + uint256 expirationTime, + uint256 tokenId, + bytes memory data + ) external returns (bytes32 lockContractId) { + address sender = msg.sender; + + // Checking the validity of the input parameters + require(amount > 0, "Amount should be greater than zero"); + transferStruct.Info memory transInfo = transferStruct.Info({ + sender: sender, + receiver: address(this), + amount: amount, + tokenId: tokenId, + data: data + }); + require( + transferInterface(assetContract).allowanceInterop(transInfo) == + true, + "Allowance of assets from the sender for the lock contract must be greater than the amount to be locked" + ); + require( + expirationTime > block.timestamp, + "Expiration time should be in the future" + ); + + // The identity of the lock contract is a hash of all the relevant parameters that will uniquely identify the contract + lockContractId = sha256( + abi.encodePacked( + sender, + receiver, + assetContract, + amount, + hashLock, + expirationTime + ) + ); + + require( + lockContracts[lockContractId].status == UNUSED, + "An active lock contract already exists with the same parameters" + ); + + // Locking amount by transfering them to the lockContract + + bool transferStatus = transferInterface(assetContract).transferInterop( + transInfo + ); + // bool transferStatus = ERC20(assetContract).transferFrom(sender, address(this), amount); + require( + transferStatus == true, + "ERC20 transferFrom failed from the sender to the lockContract" + ); + + lockContracts[lockContractId] = LockContract( + sender, + receiver, + assetContract, + amount, + hashLock, + expirationTime, + LOCKED, + tokenId, + data + ); + + emit Lock( + sender, + receiver, + assetContract, + amount, + hashLock, + expirationTime, + lockContractId + ); + } + + // The receiver claims the ownership of an asset locked for them once they obtain the preimage of the hashlock + function claimAsset(bytes32 lockContractId, bytes32 preimage) + external + returns (bool) + { + LockContract storage c = lockContracts[lockContractId]; + + // Check the validity of the claim + require(c.status == LOCKED, "lockContract is not active"); + require(block.timestamp < c.expirationTime, "lockContract has expired"); + require( + c.hashLock == sha256(abi.encodePacked(preimage)), + "Invalid preimage, its hash does not equal the hashLock" + ); + transferStruct.Info memory transInfo = transferStruct.Info({ + sender: address(this), + receiver: c.receiver, + amount: c.amount, + tokenId: c.tokenId, + data: c.data + }); + + c.assetContract.call( + abi.encodeWithSignature( + "approve(address,uint256)", + c.assetContract, + c.amount + ) + ); + c.assetContract.call( + abi.encodeWithSignature( + "setApprovalForAll(address,bool)", + c.assetContract, + true + ) + ); + + bool transferStatus = transferInterface(c.assetContract) + .transferInterop(transInfo); + require( + transferStatus == true, + "ERC20 transfer failed from the lockContract to the receiver" + ); + + emit Claim(c.sender, c.receiver, lockContractId, c.hashLock, preimage); + + return true; + } + + // Unlocking and reclaiming a locked asset for the sender after the expiration time. Can be called by anyone, not just the sender. + function unlockAsset(bytes32 lockContractId) external returns (bool) { + LockContract storage c = lockContracts[lockContractId]; + + // Validation checks + require( + c.status == LOCKED, + "There is no active lockContract with the specified ID" + ); + require(c.sender != address(0), "Sender address is invalid"); + require( + block.timestamp >= c.expirationTime, + "Lock contract has expired" + ); + transferStruct.Info memory transInfo = transferStruct.Info({ + sender: address(this), + receiver: c.sender, + amount: c.amount, + tokenId: c.tokenId, + data: c.data + }); + c.assetContract.call( + abi.encodeWithSignature( + "approve(address,uint256)", + c.assetContract, + c.amount + ) + ); + c.assetContract.call( + abi.encodeWithSignature( + "setApprovalForAll(address,bool)", + c.assetContract, + true + ) + ); + bool transferStatus = transferInterface(c.assetContract) + .transferInterop(transInfo); + require( + transferStatus == true, + "ERC20 transfer failed from the lockContract back to the sender" + ); + + emit Unlock(c.sender, c.receiver, lockContractId); + + return true; + } + + // Function to check if there is an active contract with the input lockContractId. + function isAssetLocked(bytes32 lockContractId) + external + view + returns (bool) + { + LockContract storage c = lockContracts[lockContractId]; + + bool lockContractStatus; + if (c.status == LOCKED) { + lockContractStatus = true; + } else { + lockContractStatus = false; + } + + return lockContractStatus; + } +} diff --git a/samples/besu/simpleasset/contracts/transferInterface.sol b/samples/besu/simpleasset/contracts/transferInterface.sol new file mode 100644 index 000000000..1f96fc7fe --- /dev/null +++ b/samples/besu/simpleasset/contracts/transferInterface.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: Apache-2.0 + +pragma solidity ^0.8.8; + +/** + * Transfer Interface for asset exchange on Assets in an Ethereum network + **/ + +library transferStruct { + struct Info { + address sender; + address receiver; + uint256 amount; + uint256 tokenId; + bytes data; + } +} + +abstract contract transferInterface { + function transferInterop(transferStruct.Info memory info) + external + virtual + returns (bool success); + + function allowanceInterop(transferStruct.Info memory info) + external + virtual + returns (bool success); +} From eeb7bcaa4afc2086ff7b3c24f609ecd01f506bc0 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Tue, 16 Aug 2022 17:53:51 +0000 Subject: [PATCH 091/150] removed dynamic query arg from protos Signed-off-by: Krishnasuri Narayanam --- common/protos/common/events.proto | 5 -- .../fabric-driver/server/fabric-code.ts | 6 +-- core/drivers/fabric-driver/server/listener.ts | 4 +- core/drivers/fabric-driver/server/utils.ts | 12 +---- .../interop/handle_external_request.go | 22 +++------ .../fabric-cli/src/data/event_sub_sample.json | 46 +++++++++++++++++-- samples/fabric/simplestate/simplestate.go | 14 +++++- 7 files changed, 66 insertions(+), 43 deletions(-) diff --git a/common/protos/common/events.proto b/common/protos/common/events.proto index 5588f6caa..416247532 100644 --- a/common/protos/common/events.proto +++ b/common/protos/common/events.proto @@ -28,11 +28,6 @@ enum EventSubOperation { UPDATE = 2; } -message EventQuery { - string query_bytes64 = 1; - bytes dynamic_query_arg = 2; -} - // Below message is used to communicate between dest-relay and src-relay; // and src-relay and src-driver. message EventSubscription { diff --git a/core/drivers/fabric-driver/server/fabric-code.ts b/core/drivers/fabric-driver/server/fabric-code.ts index 441c5d110..c2b5c5297 100644 --- a/core/drivers/fabric-driver/server/fabric-code.ts +++ b/core/drivers/fabric-driver/server/fabric-code.ts @@ -16,7 +16,6 @@ import interopPayload from '@hyperledger-labs/weaver-protos-js/common/interop_pa import state_pb from '@hyperledger-labs/weaver-protos-js/common/state_pb'; import { Certificate } from '@fidm/x509'; import { getConfig } from './walletSetup'; -import { createEventQuerySerialized } from './utils'; const parseAddress = (address: string) => { const addressList = address.split('/'); @@ -126,10 +125,9 @@ async function invoke( generateTransactionId: false }; } else { - const b64EventQueryBytes = createEventQuerySerialized(b64QueryBytes, dynamicArg) request = { fcn: funName, - args: [b64EventQueryBytes], + args: [b64QueryBytes, dynamicArg ? dynamicArg.toString() : ""], generateTransactionId: false }; } @@ -160,7 +158,7 @@ async function invoke( // submit query transaction and get result from chaincode const proposalResponseResult = await queryProposal.send(proposalRequest); - console.log(JSON.stringify(proposalResponse, null, 2)) + console.log(JSON.stringify(proposalResponseResult, null, 2)) // 4. Prepare the view and return. const viewPayload = new view_data.FabricView(); diff --git a/core/drivers/fabric-driver/server/listener.ts b/core/drivers/fabric-driver/server/listener.ts index eae1a4297..aa0eff243 100644 --- a/core/drivers/fabric-driver/server/listener.ts +++ b/core/drivers/fabric-driver/server/listener.ts @@ -46,9 +46,9 @@ const initBlockEventListenerForChannel = async ( const chaincodeId = transaction.payload.chaincode_proposal_payload.input.chaincode_spec.chaincode_id.name; if (transaction.payload.chaincode_proposal_payload.input.chaincode_spec.input.args.length > 0) { // below way of fetching payload requires that the response has been set by the chaincode function via return value - //const responsePayload = transaction.payload.action.proposal_response_payload.extension.response.payload; + const responsePayload = transaction.payload.action.proposal_response_payload.extension.response.payload; // below way of fetching payload is similar to ContractEventListener in which we fetch event.payload - const responsePayload = transaction.payload.action.proposal_response_payload.extension.events.payload; + // const responsePayload = transaction.payload.action.proposal_response_payload.extension.events.payload; // Get transaction function name: first argument according to convention const chaincodeFunc = transaction.payload.chaincode_proposal_payload.input.chaincode_spec.input.args[0].toString(); console.log('Trying to find match for channel', channelId, 'chaincode', chaincodeId, 'function', chaincodeFunc); diff --git a/core/drivers/fabric-driver/server/utils.ts b/core/drivers/fabric-driver/server/utils.ts index a6425e473..9db89404b 100644 --- a/core/drivers/fabric-driver/server/utils.ts +++ b/core/drivers/fabric-driver/server/utils.ts @@ -95,20 +95,10 @@ function getRelayClientForEventPublish() { return client; } -// Create an asset exchange agreement structure -function createEventQuerySerialized(queryBytes64: string, dynamicQueryArg: Buffer) -{ - const eventQuery = new eventsPb.EventQuery(); - eventQuery.setQueryBytes64(queryBytes64); - eventQuery.setDynamicQueryArg(dynamicQueryArg); - return Buffer.from(eventQuery.serializeBinary()).toString('base64'); -} - export { checkIfArraysAreEqual, handlePromise, relayCallback, getRelayClientForQueryResponse, - getRelayClientForEventPublish, - createEventQuerySerialized + getRelayClientForEventPublish } diff --git a/core/network/fabric-interop-cc/contracts/interop/handle_external_request.go b/core/network/fabric-interop-cc/contracts/interop/handle_external_request.go index 3cb9a85aa..1900d1834 100644 --- a/core/network/fabric-interop-cc/contracts/interop/handle_external_request.go +++ b/core/network/fabric-interop-cc/contracts/interop/handle_external_request.go @@ -43,18 +43,8 @@ func (s *SmartContract) HandleExternalRequest(ctx contractapi.TransactionContext return resp, err } -func (s *SmartContract) HandleEventRequest(ctx contractapi.TransactionContextInterface, b64EventQueryBytes string) (string, error) { - eventQueryBytes, err := base64.StdEncoding.DecodeString(b64EventQueryBytes) - if err != nil { - return "", logThenErrorf("Unable to base64 decode data: %s", err.Error()) - } - var eventQuery common.EventQuery - err = protoV2.Unmarshal(eventQueryBytes, &eventQuery) - if err != nil { - return "", logThenErrorf("Unable to unmarshal eventQuery: %s", err.Error()) - } - - queryBytes, err := base64.StdEncoding.DecodeString(eventQuery.QueryBytes64) +func (s *SmartContract) HandleEventRequest(ctx contractapi.TransactionContextInterface, b64QueryBytes string, dynamicQueryArg string) (string, error) { + queryBytes, err := base64.StdEncoding.DecodeString(b64QueryBytes) if err != nil { return "", logThenErrorf("Unable to base64 decode data: %s", err.Error()) } @@ -67,12 +57,12 @@ func (s *SmartContract) HandleEventRequest(ctx contractapi.TransactionContextInt queryAddress := query.Address dynamicArgCount := strings.Count(query.Address, ":?") if dynamicArgCount > 1 { - return "", logThenErrorf("Expected 1 dynamic arg, but found %d", dynamicArgCount) + return "", logThenErrorf("Expected 1 dynamic argument in the event query address, but found %d", dynamicArgCount) } else if dynamicArgCount == 1 { - queryArg := string(eventQuery.DynamicQueryArg) - queryAddress = strings.Replace(query.Address, ":?", ":"+queryArg, 1) + queryAddress = strings.Replace(query.Address, ":?", ":"+dynamicQueryArg, 1) + fmt.Println("There is 1 dynamic argument in the event query address, queryArg: ", dynamicQueryArg) } else { - fmt.Println("There are no dynamic arguments in the event query. queryArg: ", string(eventQuery.DynamicQueryArg)) + fmt.Println("There are no dynamic arguments in the event query address, queryArg: ", dynamicQueryArg) } resp, err := handleRequest(s, ctx, query, queryAddress) diff --git a/samples/fabric/fabric-cli/src/data/event_sub_sample.json b/samples/fabric/fabric-cli/src/data/event_sub_sample.json index c72cc7c6e..36dc79306 100644 --- a/samples/fabric/fabric-cli/src/data/event_sub_sample.json +++ b/samples/fabric/fabric-cli/src/data/event_sub_sample.json @@ -8,16 +8,35 @@ "transactionFunc": "create" }, "event_publication_spec": { - "ccArgs": [], + "ccArgs": ["keyType", ""], "chaincodeId": "simplestate", "driverId": "network1", "ccFunc": "Create", "channelId": "mychannel", - "replaceArgIndex": "0" + "replaceArgIndex": 1 }, "view_address": "localhost:9083/network2/mychannel:simplestate:Read:a", "confidential": false }, + { + "event_matcher": { + "eventType": 1, + "eventClassId": "", + "transactionLedgerId": "mychannel", + "transactionContractId": "simplestate", + "transactionFunc": "createandreturnkey" + }, + "event_publication_spec": { + "ccArgs": ["keyTypeDynamic", ""], + "chaincodeId": "simplestate", + "driverId": "network1", + "ccFunc": "Create", + "channelId": "mychannel", + "replaceArgIndex": 1 + }, + "view_address": "localhost:9083/network2/mychannel:simplestate:Read:?", + "confidential": false + }, { "event_matcher": { "eventType": 1, @@ -27,16 +46,35 @@ "transactionFunc": "create" }, "event_publication_spec": { - "ccArgs": [], + "ccArgs": ["keyClass", ""], "chaincodeId": "simplestate", "driverId": "network1", "ccFunc": "Create", "channelId": "mychannel", - "replaceArgIndex": "0" + "replaceArgIndex": 1 }, "view_address": "localhost:9083/network2/mychannel:simplestate:Read:a", "confidential": false }, + { + "event_matcher": { + "eventType": 1, + "eventClassId": "CreateSimpleState", + "transactionLedgerId": "mychannel", + "transactionContractId": "simplestate", + "transactionFunc": "create" + }, + "event_publication_spec": { + "ccArgs": ["keyClassDynamic", ""], + "chaincodeId": "simplestate", + "driverId": "network1", + "ccFunc": "Create", + "channelId": "mychannel", + "replaceArgIndex": 1 + }, + "view_address": "localhost:9083/network2/mychannel:simplestate:Read:?", + "confidential": false + }, { "event_matcher": { "eventType": 1, diff --git a/samples/fabric/simplestate/simplestate.go b/samples/fabric/simplestate/simplestate.go index 18f6c06c7..f032c01d3 100755 --- a/samples/fabric/simplestate/simplestate.go +++ b/samples/fabric/simplestate/simplestate.go @@ -32,6 +32,18 @@ type SmartContract struct { contractapi.Contract } +// CreateAndReturnKey adds a new entry with the specified key and value, and returns the key +func (s *SmartContract) CreateAndReturnKey(ctx contractapi.TransactionContextInterface, key string, value string) (string, error) { + bytes := []byte(value) + fmt.Printf("CreateAndReturnKey called. Key: %s Value: %s\n", key, value) + + err := ctx.GetStub().PutState(key, bytes) + if err != nil { + return "", err + } + return key, nil +} + // Create adds a new entry with the specified key and value func (s *SmartContract) Create(ctx contractapi.TransactionContextInterface, key string, value string) error { bytes := []byte(value) @@ -41,7 +53,7 @@ func (s *SmartContract) Create(ctx contractapi.TransactionContextInterface, key if err != nil { return err } else { - err = ctx.GetStub().SetEvent("CreateSimpleState", []byte(key + ":" + value)) + err = ctx.GetStub().SetEvent("CreateSimpleState", []byte(key)) if err != nil { fmt.Printf("Unable to set 'CreateSimpleState' event: %+v\n", err) } From 31460c3c4d98bf8c03331e7861b19563a068b59e Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Wed, 17 Aug 2022 10:50:01 +0000 Subject: [PATCH 092/150] changes as part of the review comments Signed-off-by: Krishnasuri Narayanam --- core/drivers/fabric-driver/server/fabric-code.ts | 15 +++++++-------- core/drivers/fabric-driver/server/listener.ts | 6 +++--- core/drivers/fabric-driver/server/server.ts | 3 +-- core/drivers/fabric-driver/server/utils.ts | 1 - .../contracts/interop/handle_external_request.go | 3 ++- 5 files changed, 13 insertions(+), 15 deletions(-) diff --git a/core/drivers/fabric-driver/server/fabric-code.ts b/core/drivers/fabric-driver/server/fabric-code.ts index c2b5c5297..3f95bb5bb 100644 --- a/core/drivers/fabric-driver/server/fabric-code.ts +++ b/core/drivers/fabric-driver/server/fabric-code.ts @@ -4,11 +4,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { Gateway, Wallets, Network } from 'fabric-network'; +import { Gateway, Wallets } from 'fabric-network'; import { Endorser } from 'fabric-common'; import * as path from 'path'; import * as fs from 'fs'; -import * as fabproto6 from 'fabric-protos'; import query_pb from '@hyperledger-labs/weaver-protos-js/common/query_pb'; import view_data from '@hyperledger-labs/weaver-protos-js/fabric/view_data_pb'; import proposalResponse from '@hyperledger-labs/weaver-protos-js/peer/proposal_response_pb'; @@ -77,8 +76,8 @@ const getNetworkGateway = async (networkName: string): Promise => { async function invoke( query: query_pb.Query, networkName: string, - funName: string, - dynamicArg: Buffer | undefined + funcName: string, + dynamicArg?: Buffer ): Promise { console.log('Running query on fabric network'); try { @@ -118,15 +117,15 @@ async function invoke( const idx = gateway.identityContext.calculateTransactionId(); const queryProposal = currentChannel.newQuery(chaincodeId); let request; - if (funName == 'HandleExternalRequest') { + if (funcName == 'HandleExternalRequest') { request = { - fcn: funName, + fcn: funcName, args: [b64QueryBytes], generateTransactionId: false }; } else { request = { - fcn: funName, + fcn: funcName, args: [b64QueryBytes, dynamicArg ? dynamicArg.toString() : ""], generateTransactionId: false }; @@ -158,7 +157,7 @@ async function invoke( // submit query transaction and get result from chaincode const proposalResponseResult = await queryProposal.send(proposalRequest); - console.log(JSON.stringify(proposalResponseResult, null, 2)) + //console.debug(JSON.stringify(proposalResponseResult, null, 2)) // 4. Prepare the view and return. const viewPayload = new view_data.FabricView(); diff --git a/core/drivers/fabric-driver/server/listener.ts b/core/drivers/fabric-driver/server/listener.ts index aa0eff243..82244042f 100644 --- a/core/drivers/fabric-driver/server/listener.ts +++ b/core/drivers/fabric-driver/server/listener.ts @@ -5,7 +5,7 @@ */ import * as fabproto6 from 'fabric-protos'; -import { Gateway, Network, Contract, BlockListener, ContractListener } from 'fabric-network'; +import { Gateway, Network, Contract, ContractEvent, BlockListener, ContractListener, BlockEvent } from 'fabric-network'; import query_pb from '@hyperledger-labs/weaver-protos-js/common/query_pb'; import events_pb from '@hyperledger-labs/weaver-protos-js/common/events_pb'; import { lookupEventSubscriptions } from './events'; @@ -33,7 +33,7 @@ const initBlockEventListenerForChannel = async ( networkName: string, channelId: string, ): Promise => { - const listener: BlockListener = async (event) => { + const listener: BlockListener = async (event: BlockEvent) => { // Parse the block data; typically there is only one element in this array but we will interate over it just to be safe const blockData = ((event.blockData as fabproto6.common.Block).data as fabproto6.common.BlockData).data; blockData.forEach((item) => { @@ -113,7 +113,7 @@ const initContractEventListener = ( channelId: string, chaincodeId: string, ): any => { - const listener: ContractListener = async (event) => { + const listener: ContractListener = async (event: ContractEvent) => { console.log('Trying to find match for channel', channelId, 'chaincode', chaincodeId, 'event class', event.eventName); // Find all matching event subscriptions stored in the database let eventMatcher = new events_pb.EventMatcher(); diff --git a/core/drivers/fabric-driver/server/server.ts b/core/drivers/fabric-driver/server/server.ts index e9faa68ba..a09996ba4 100644 --- a/core/drivers/fabric-driver/server/server.ts +++ b/core/drivers/fabric-driver/server/server.ts @@ -76,8 +76,7 @@ const fabricCommunication = async (query: query_pb.Query, networkName: string) = invoke( query, networkName, - 'HandleExternalRequest', - undefined + 'HandleExternalRequest' ), ); const client = getRelayClientForQueryResponse(); diff --git a/core/drivers/fabric-driver/server/utils.ts b/core/drivers/fabric-driver/server/utils.ts index 9db89404b..1d7282ac3 100644 --- a/core/drivers/fabric-driver/server/utils.ts +++ b/core/drivers/fabric-driver/server/utils.ts @@ -8,7 +8,6 @@ import fs from 'fs'; import { credentials } from '@grpc/grpc-js'; import datatransfer_grpc_pb from '@hyperledger-labs/weaver-protos-js/relay/datatransfer_grpc_pb'; import events_grpc_pb from '@hyperledger-labs/weaver-protos-js/relay/events_grpc_pb'; -import eventsPb from '@hyperledger-labs/weaver-protos-js/common/events_pb'; function checkIfArraysAreEqual(x: Array, y: Array): boolean { if (x == y) { diff --git a/core/network/fabric-interop-cc/contracts/interop/handle_external_request.go b/core/network/fabric-interop-cc/contracts/interop/handle_external_request.go index 1900d1834..240cf24ef 100644 --- a/core/network/fabric-interop-cc/contracts/interop/handle_external_request.go +++ b/core/network/fabric-interop-cc/contracts/interop/handle_external_request.go @@ -56,6 +56,7 @@ func (s *SmartContract) HandleEventRequest(ctx contractapi.TransactionContextInt queryAddress := query.Address dynamicArgCount := strings.Count(query.Address, ":?") + // TODO: this is a stopgap logic and will be reviewed and possibly changed later if dynamicArgCount > 1 { return "", logThenErrorf("Expected 1 dynamic argument in the event query address, but found %d", dynamicArgCount) } else if dynamicArgCount == 1 { @@ -69,7 +70,7 @@ func (s *SmartContract) HandleEventRequest(ctx contractapi.TransactionContextInt return resp, err } -// handleRequest function requests that come from external networks. +// This function handleRequest handle requests that originate in external requests and have come through relays. // // The flow coordinates the following: // 1. Checks the validity of query signature From 7d9b60ef0f7b816c242ceb2f8307710b113b1269 Mon Sep 17 00:00:00 2001 From: micky Date: Wed, 17 Aug 2022 10:16:49 +0300 Subject: [PATCH 093/150] move copy contract file to github action Signed-off-by: micky --- .../workflows/test_asset-exchange-besu.yml | 24 +- samples/besu/besu-cli/config.template.json | 4 +- samples/besu/simpleasset/.gitignore | 5 +- .../simpleasset/contracts/manageAssetAny.sol | 255 ------------------ .../contracts/transferInterface.sol | 29 -- samples/besu/simpleasset/package.json | 2 +- 6 files changed, 10 insertions(+), 309 deletions(-) delete mode 100644 samples/besu/simpleasset/contracts/manageAssetAny.sol delete mode 100644 samples/besu/simpleasset/contracts/transferInterface.sol diff --git a/.github/workflows/test_asset-exchange-besu.yml b/.github/workflows/test_asset-exchange-besu.yml index f8c67ac23..97b4ac6d2 100644 --- a/.github/workflows/test_asset-exchange-besu.yml +++ b/.github/workflows/test_asset-exchange-besu.yml @@ -16,7 +16,7 @@ on: # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: - asset-exchange-corda: + asset-exchange-besu: # The type of runner that the job will run on runs-on: ubuntu-latest @@ -31,24 +31,6 @@ jobs: java-version: '11' distribution: 'adopt' - # CORDA NETWORK - - name: Generate github.properties - run: | - echo "Using ${GITHUB_ACTOR} user." - echo "username=${GITHUB_ACTOR}" >> github.properties - echo "password=${{ secrets.GITHUB_TOKEN }}" >> github.properties - echo "url=https://maven.pkg.github.com/${GITHUB_ACTOR}/weaver-dlt-interoperability" >> github.properties - - echo "Using ${GITHUB_ACTOR} user." - echo "username=${GITHUB_ACTOR}" >> github.main.properties - echo "password=${{ secrets.GITHUB_TOKEN }}" >> github.main.properties - echo "url=https://maven.pkg.github.com/hyperledger-labs/weaver-dlt-interoperability" >> github.main.properties - - ./scripts/get-cordapps.sh || mv github.main.properties github.properties - - cat github.properties - working-directory: tests/network-setups/besu - # BESU NETWORK - name: Start Besu Network run: | @@ -73,7 +55,6 @@ jobs: - name: Setup BESU CLI init run: | npm install . - export PATH="${PWD}/bin:$PATH" cp config.template.json tmp.json cp config.template.json tmp.json jq -r '.network1.tokenContract |= "../simpleasset/build/contracts/AliceERC20.json"' tmp.json > config.json @@ -84,6 +65,7 @@ jobs: - name: Asset Exchange Besu CLI Tests run: | + export PATH="${PWD}/bin:$PATH" COUNT=0 TOTAL=3 @@ -106,6 +88,8 @@ jobs: besu-cli asset is-locked --network=network1 --lock_contract_id=$LOCK_ID 1> tmp.out cat tmp.out | grep "in Network network1: true" && COUNT=$(( COUNT + 1 )) && echo "PASS" cat tmp.out + + sleep 30 # Claim asset besu-cli asset claim --network=network1 --lock_contract_id=$LOCK_ID --recipient_account=2 --preimage=&PREIMAGE 1> tmp.out diff --git a/samples/besu/besu-cli/config.template.json b/samples/besu/besu-cli/config.template.json index b4fe1ad1d..47e96ae87 100644 --- a/samples/besu/besu-cli/config.template.json +++ b/samples/besu/besu-cli/config.template.json @@ -3,7 +3,7 @@ "networkHost": "localhost", "networkPort": 8545, "tokenContract": "../simpleasset/build/contracts/AliceERC20.json", - "interopContract": "../simpleasset/build/contracts/InteroperationBaseClassERC20.json", + "interopContract": "../simpleasset/build/contracts/AssetExchangeContract.json", "senderAccountIndex": 1, "recipientAccountIndex": 2 }, @@ -11,7 +11,7 @@ "networkHost": "localhost", "networkPort": 9544, "tokenContract": "../simpleasset/build/contracts/BobERC20.json", - "interopContract": "../simpleasset/build/contracts/InteroperationBaseClassERC20.json", + "interopContract": "../simpleasset/build/contracts/AssetExchangeContract.json", "senderAccountIndex": 2, "recipientAccountIndex": 1 } diff --git a/samples/besu/simpleasset/.gitignore b/samples/besu/simpleasset/.gitignore index 96c15fb2a..35702d932 100644 --- a/samples/besu/simpleasset/.gitignore +++ b/samples/besu/simpleasset/.gitignore @@ -1,4 +1,5 @@ build node_modules -contracts/manageAsset.sol -package-lock.json +contracts/manageAssetAny.sol +contracts/transferInterface.sol +package-lock.json \ No newline at end of file diff --git a/samples/besu/simpleasset/contracts/manageAssetAny.sol b/samples/besu/simpleasset/contracts/manageAssetAny.sol deleted file mode 100644 index 162561959..000000000 --- a/samples/besu/simpleasset/contracts/manageAssetAny.sol +++ /dev/null @@ -1,255 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -pragma solidity ^0.8.8; - -import "./transferInterface.sol"; -import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; - -/** - * Hashed Timelock Contract on Assets in an Ethereum network (Support only for ERC20, ERC721 and ERC1155 tokens) - **/ - -contract AssetExchangeContract is ERC1155Holder { - mapping(bytes32 => LockContract) public lockContracts; - - struct LockContract { - address sender; - address receiver; - address assetContract; - uint256 amount; - bytes32 hashLock; - uint256 expirationTime; - uint8 status; - uint256 tokenId; - bytes data; - } - - struct transferInfo { - address sender; - address receiver; - uint256 amount; - } - - uint8 constant UNUSED = 0; - uint8 constant LOCKED = 1; - - event Lock( - address indexed sender, - address indexed receiver, - address assetContract, - uint256 amount, - bytes32 hashLock, - uint256 expirationTime, - bytes32 lockContractId - ); - - event Claim( - address indexed sender, - address indexed receiver, - bytes32 indexed lockContractId, - bytes32 hashLock, - bytes32 preimage - ); - - event Unlock( - address indexed sender, - address indexed receiver, - bytes32 indexed lockContractId - ); - - // The sender locks a asset with a hash lock and an expiry time - function lockAsset( - address receiver, - address assetContract, - uint256 amount, - bytes32 hashLock, - uint256 expirationTime, - uint256 tokenId, - bytes memory data - ) external returns (bytes32 lockContractId) { - address sender = msg.sender; - - // Checking the validity of the input parameters - require(amount > 0, "Amount should be greater than zero"); - transferStruct.Info memory transInfo = transferStruct.Info({ - sender: sender, - receiver: address(this), - amount: amount, - tokenId: tokenId, - data: data - }); - require( - transferInterface(assetContract).allowanceInterop(transInfo) == - true, - "Allowance of assets from the sender for the lock contract must be greater than the amount to be locked" - ); - require( - expirationTime > block.timestamp, - "Expiration time should be in the future" - ); - - // The identity of the lock contract is a hash of all the relevant parameters that will uniquely identify the contract - lockContractId = sha256( - abi.encodePacked( - sender, - receiver, - assetContract, - amount, - hashLock, - expirationTime - ) - ); - - require( - lockContracts[lockContractId].status == UNUSED, - "An active lock contract already exists with the same parameters" - ); - - // Locking amount by transfering them to the lockContract - - bool transferStatus = transferInterface(assetContract).transferInterop( - transInfo - ); - // bool transferStatus = ERC20(assetContract).transferFrom(sender, address(this), amount); - require( - transferStatus == true, - "ERC20 transferFrom failed from the sender to the lockContract" - ); - - lockContracts[lockContractId] = LockContract( - sender, - receiver, - assetContract, - amount, - hashLock, - expirationTime, - LOCKED, - tokenId, - data - ); - - emit Lock( - sender, - receiver, - assetContract, - amount, - hashLock, - expirationTime, - lockContractId - ); - } - - // The receiver claims the ownership of an asset locked for them once they obtain the preimage of the hashlock - function claimAsset(bytes32 lockContractId, bytes32 preimage) - external - returns (bool) - { - LockContract storage c = lockContracts[lockContractId]; - - // Check the validity of the claim - require(c.status == LOCKED, "lockContract is not active"); - require(block.timestamp < c.expirationTime, "lockContract has expired"); - require( - c.hashLock == sha256(abi.encodePacked(preimage)), - "Invalid preimage, its hash does not equal the hashLock" - ); - transferStruct.Info memory transInfo = transferStruct.Info({ - sender: address(this), - receiver: c.receiver, - amount: c.amount, - tokenId: c.tokenId, - data: c.data - }); - - c.assetContract.call( - abi.encodeWithSignature( - "approve(address,uint256)", - c.assetContract, - c.amount - ) - ); - c.assetContract.call( - abi.encodeWithSignature( - "setApprovalForAll(address,bool)", - c.assetContract, - true - ) - ); - - bool transferStatus = transferInterface(c.assetContract) - .transferInterop(transInfo); - require( - transferStatus == true, - "ERC20 transfer failed from the lockContract to the receiver" - ); - - emit Claim(c.sender, c.receiver, lockContractId, c.hashLock, preimage); - - return true; - } - - // Unlocking and reclaiming a locked asset for the sender after the expiration time. Can be called by anyone, not just the sender. - function unlockAsset(bytes32 lockContractId) external returns (bool) { - LockContract storage c = lockContracts[lockContractId]; - - // Validation checks - require( - c.status == LOCKED, - "There is no active lockContract with the specified ID" - ); - require(c.sender != address(0), "Sender address is invalid"); - require( - block.timestamp >= c.expirationTime, - "Lock contract has expired" - ); - transferStruct.Info memory transInfo = transferStruct.Info({ - sender: address(this), - receiver: c.sender, - amount: c.amount, - tokenId: c.tokenId, - data: c.data - }); - c.assetContract.call( - abi.encodeWithSignature( - "approve(address,uint256)", - c.assetContract, - c.amount - ) - ); - c.assetContract.call( - abi.encodeWithSignature( - "setApprovalForAll(address,bool)", - c.assetContract, - true - ) - ); - bool transferStatus = transferInterface(c.assetContract) - .transferInterop(transInfo); - require( - transferStatus == true, - "ERC20 transfer failed from the lockContract back to the sender" - ); - - emit Unlock(c.sender, c.receiver, lockContractId); - - return true; - } - - // Function to check if there is an active contract with the input lockContractId. - function isAssetLocked(bytes32 lockContractId) - external - view - returns (bool) - { - LockContract storage c = lockContracts[lockContractId]; - - bool lockContractStatus; - if (c.status == LOCKED) { - lockContractStatus = true; - } else { - lockContractStatus = false; - } - - return lockContractStatus; - } -} diff --git a/samples/besu/simpleasset/contracts/transferInterface.sol b/samples/besu/simpleasset/contracts/transferInterface.sol deleted file mode 100644 index 1f96fc7fe..000000000 --- a/samples/besu/simpleasset/contracts/transferInterface.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -pragma solidity ^0.8.8; - -/** - * Transfer Interface for asset exchange on Assets in an Ethereum network - **/ - -library transferStruct { - struct Info { - address sender; - address receiver; - uint256 amount; - uint256 tokenId; - bytes data; - } -} - -abstract contract transferInterface { - function transferInterop(transferStruct.Info memory info) - external - virtual - returns (bool success); - - function allowanceInterop(transferStruct.Info memory info) - external - virtual - returns (bool success); -} diff --git a/samples/besu/simpleasset/package.json b/samples/besu/simpleasset/package.json index ef315efa9..afb6065b8 100644 --- a/samples/besu/simpleasset/package.json +++ b/samples/besu/simpleasset/package.json @@ -12,7 +12,7 @@ "test": "test" }, "scripts": { - "copy-interop-contracts": "cp ../../../core/network/besu/contracts/interop/manageAssetAny.sol contracts/ && cp ../../../core/network/besu/contracts/asset-exchange/transferInterface.sol contracts/", + "copy-interop-contracts": "cp ../../../core/network/besu/contracts/interop/manageAssetAny.sol contracts/ && cp ../../../core/network/besu/interface/asset-exchange/transferInterface.sol contracts/", "update-truffle-config": "node get-network-details.js", "deploy-contract": "npm run copy-interop-contracts && npm install && npm run update-truffle-config && truffle compile && truffle migrate", "clean-run": "rm -rf package-lock.json build", From 666ea64fb115b804928503d64349c51972b0547e Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Wed, 17 Aug 2022 12:52:33 +0000 Subject: [PATCH 094/150] adding WALLET_PATH env variable Signed-off-by: Krishnasuri Narayanam --- core/drivers/fabric-driver/.env.docker.template | 1 + core/drivers/fabric-driver/.env.template | 1 + core/drivers/fabric-driver/docker-compose.yml | 2 +- core/drivers/fabric-driver/readme.md | 2 ++ core/drivers/fabric-driver/server/fabric-code.ts | 2 +- core/drivers/fabric-driver/server/server.ts | 2 +- core/drivers/fabric-driver/server/walletSetup.ts | 2 +- 7 files changed, 8 insertions(+), 4 deletions(-) diff --git a/core/drivers/fabric-driver/.env.docker.template b/core/drivers/fabric-driver/.env.docker.template index ef09d3136..0f4e633ca 100644 --- a/core/drivers/fabric-driver/.env.docker.template +++ b/core/drivers/fabric-driver/.env.docker.template @@ -10,6 +10,7 @@ DRIVER_TLS_CERT_PATH= DRIVER_TLS_KEY_PATH= INTEROP_CHAINCODE= DB_PATH=driverdbs +WALLET_PATH= DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-fabric-driver DOCKER_TAG=1.4.0 EXTERNAL_NETWORK= diff --git a/core/drivers/fabric-driver/.env.template b/core/drivers/fabric-driver/.env.template index bc57d9b42..9c3c1a8e0 100644 --- a/core/drivers/fabric-driver/.env.template +++ b/core/drivers/fabric-driver/.env.template @@ -11,3 +11,4 @@ DRIVER_CONFIG= INTEROP_CHAINCODE=interop MOCK=false DB_PATH=driverdbs +WALLET_PATH= diff --git a/core/drivers/fabric-driver/docker-compose.yml b/core/drivers/fabric-driver/docker-compose.yml index dcb2a6c1d..4c4140b2f 100644 --- a/core/drivers/fabric-driver/docker-compose.yml +++ b/core/drivers/fabric-driver/docker-compose.yml @@ -22,7 +22,7 @@ services: - DRIVER_TLS=${DRIVER_TLS} - DRIVER_TLS_CERT_PATH=${DRIVER_TLS_CERT_PATH} - DRIVER_TLS_KEY_PATH=${DRIVER_TLS_KEY_PATH} - - DB_PATH=${DB_PATH} + - WALLET_PATH=${WALLET_PATH} volumes: - ${CONNECTION_PROFILE}:/fabric-driver/ccp.json - ${DRIVER_CONFIG}:/fabric-driver/config.json diff --git a/core/drivers/fabric-driver/readme.md b/core/drivers/fabric-driver/readme.md index 190efac3a..a2b29d9bf 100644 --- a/core/drivers/fabric-driver/readme.md +++ b/core/drivers/fabric-driver/readme.md @@ -95,6 +95,8 @@ Can pass in a config file for the driver to be run with: `DRIVER_CONFIG` (ex: DR `DB_PATH` stores the path hosting the database files containing the event subscription information. +`WALLET_PATH` stores the path hosting the user wallets to access a network. + NOTE: When specifying ensure that they match the config that the relay is using. **For docker-compose:*** diff --git a/core/drivers/fabric-driver/server/fabric-code.ts b/core/drivers/fabric-driver/server/fabric-code.ts index 3f95bb5bb..117ba97b2 100644 --- a/core/drivers/fabric-driver/server/fabric-code.ts +++ b/core/drivers/fabric-driver/server/fabric-code.ts @@ -44,7 +44,7 @@ const getNetworkGateway = async (networkName: string): Promise => { const config = getConfig(); // Create a new file system-based wallet for managing identities. - const walletPath = path.join(process.cwd(), `wallet-${networkName}`); + const walletPath = process.env.WALLET_PATH ? process.env.WALLET_PATH : path.join(process.cwd(), `wallet-${networkName}`); const userName = config.relay.name; const wallet = await getWallet(walletPath); console.log(`Wallet path: ${walletPath}`); diff --git a/core/drivers/fabric-driver/server/server.ts b/core/drivers/fabric-driver/server/server.ts index a09996ba4..f795c0268 100644 --- a/core/drivers/fabric-driver/server/server.ts +++ b/core/drivers/fabric-driver/server/server.ts @@ -254,7 +254,7 @@ server.addService(driver_pb_grpc.DriverCommunicationService, { // Prepares required crypto material for communication with the fabric network const configSetup = async () => { // uses the network name to create a unique wallet path - const walletPath = path.join(process.cwd(), `wallet-${process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1'}`); + const walletPath = process.env.WALLET_PATH ? process.env.WALLET_PATH : path.join(process.cwd(), `wallet-${process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1'}`); if (process.env.CONNECTION_PROFILE) { walletSetup( walletPath, diff --git a/core/drivers/fabric-driver/server/walletSetup.ts b/core/drivers/fabric-driver/server/walletSetup.ts index e57ef2092..9fb7f9cc8 100644 --- a/core/drivers/fabric-driver/server/walletSetup.ts +++ b/core/drivers/fabric-driver/server/walletSetup.ts @@ -113,7 +113,7 @@ const walletSetup = async (walletPath: string, conn_profile_path: string, networ const getDriverKeyCert = async (): Promise => { - const walletPath = path.join(process.cwd(), `wallet-${process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1'}`); + const walletPath = process.env.WALLET_PATH ? process.env.WALLET_PATH : path.join(process.cwd(), `wallet-${process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1'}`); const config = getConfig(); const wallet = await Wallets.newFileSystemWallet(walletPath); console.log(`Wallet path: ${walletPath}`); From dc93ae7e16beb4540173eb1f1b42fb9cffa754b0 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Thu, 18 Aug 2022 10:07:38 +0000 Subject: [PATCH 095/150] compare with transaction function in lower case Signed-off-by: Krishnasuri Narayanam --- core/drivers/fabric-driver/makefile.variables.docker | 2 +- core/drivers/fabric-driver/server/events.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/drivers/fabric-driver/makefile.variables.docker b/core/drivers/fabric-driver/makefile.variables.docker index aa0cc0c7c..99e172204 100644 --- a/core/drivers/fabric-driver/makefile.variables.docker +++ b/core/drivers/fabric-driver/makefile.variables.docker @@ -1,4 +1,4 @@ DOCKER_IMAGE_NAME ?= weaver-fabric-driver -DOCKER_TAG ?= 1.4.2 +DOCKER_TAG ?= 1.4.3 DOCKER_REGISTRY ?= ghcr.io/hyperledger-labs GIT_URL = https://github.com/hyperledger-labs/weaver-dlt-interoperability/core/drivers/fabric-driver diff --git a/core/drivers/fabric-driver/server/events.ts b/core/drivers/fabric-driver/server/events.ts index a79172a2a..7d24184e1 100644 --- a/core/drivers/fabric-driver/server/events.ts +++ b/core/drivers/fabric-driver/server/events.ts @@ -270,7 +270,7 @@ function filterEventMatcher(keySerialized: string, eventMatcher: eventsPb.EventM if ((eventMatcher.getEventClassId() == '*' || eventMatcher.getEventClassId() == item.getEventClassId()) && (eventMatcher.getTransactionContractId() == '*' || eventMatcher.getTransactionContractId() == item.getTransactionContractId()) && (eventMatcher.getTransactionLedgerId() == '*' || eventMatcher.getTransactionLedgerId() == item.getTransactionLedgerId()) && - (eventMatcher.getTransactionFunc() == '*' || eventMatcher.getTransactionFunc() == item.getTransactionFunc())) { + (eventMatcher.getTransactionFunc() == '*' || eventMatcher.getTransactionFunc() == item.getTransactionFunc().toLowerCase())) { return true; } else { From b255a9415896dbe00720a888b86610378eee8904 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Thu, 18 Aug 2022 15:40:07 +0530 Subject: [PATCH 096/150] test cases for interop chaincode function HandleEventRequest Signed-off-by: Krishnasuri Narayanam --- .../interop/handle_external_request_test.go | 148 +++++++++++++++++- 1 file changed, 140 insertions(+), 8 deletions(-) diff --git a/core/network/fabric-interop-cc/contracts/interop/handle_external_request_test.go b/core/network/fabric-interop-cc/contracts/interop/handle_external_request_test.go index 9e0b21d5c..845afd8e6 100644 --- a/core/network/fabric-interop-cc/contracts/interop/handle_external_request_test.go +++ b/core/network/fabric-interop-cc/contracts/interop/handle_external_request_test.go @@ -23,14 +23,14 @@ import ( "testing" "time" + "github.com/golang/protobuf/proto" + "github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go/common" + wtest "github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/testutils" "github.com/hyperledger/fabric-chaincode-go/shim" + mspProtobuf "github.com/hyperledger/fabric-protos-go/msp" pb "github.com/hyperledger/fabric-protos-go/peer" "github.com/stretchr/testify/require" - "github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go/common" - "github.com/golang/protobuf/proto" protoV2 "google.golang.org/protobuf/proto" - mspProtobuf "github.com/hyperledger/fabric-protos-go/msp" - wtest "github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/testutils" ) // function that supplies value that is to be returned by ctx.GetStub().GetCreator() @@ -132,6 +132,11 @@ func TestHandleExternalRequest(t *testing.T) { testHandleExternalRequestECDSAHappyCase(t, &query, validCertificate, key, signature, pbResp, &accessControlAsset, &membershipAsset) // ed25519 Cert and Signature testHandleExternalRequestED25519Signature(t, &query, pbResp, &accessControlAsset, &membershipAsset, template) + // Test event requests + // Invalid Cert + testHandleEventRequestInvalidDynamicQueryArgs(t, &query, validCertificate, signature) + // Happy case. ECDSA Cert and Valid Signature + testHandleEventRequestECDSAHappyCase(t, &query, validCertificate, key, signature, pbResp, &accessControlAsset, &membershipAsset) } func testHandleExternalRequestInvalidJSON(t *testing.T) { @@ -195,6 +200,30 @@ func testHandleExternalRequestInvalidCert(t *testing.T, query *common.Query) { require.EqualError(t, err, fmt.Sprintf("Unable to parse certificate: Client cert not in a known PEM format")) } +func testHandleEventRequestInvalidDynamicQueryArgs(t *testing.T, query *common.Query, validCertificate string, signature []byte) { + ctx, chaincodeStub := wtest.PrepMockStub() + interopcc := SmartContract{} + chaincodeStub.GetCreatorReturns([]byte(getRelayCreator()), nil) + interopCCId := "interopcc" + wtest.SetMockStubCCId(chaincodeStub, interopCCId) + + // set incorrect values for this test case + queryAddress := query.Address + query.Address = "localhost:9080/network1/mychannel:interop:Read:?:?" + query.Certificate = validCertificate + b64Signature := base64.StdEncoding.EncodeToString(signature) + query.RequestorSignature = b64Signature + queryBytes, err := protoV2.Marshal(query) + require.NoError(t, err) + b64QueryBytes := base64.StdEncoding.EncodeToString(queryBytes) + + _, err = interopcc.HandleEventRequest(ctx, string(b64QueryBytes), "a") + require.EqualError(t, err, fmt.Sprintf("Expected 1 dynamic argument in the event query address, but found 2")) + + // restore the value of query.Address + query.Address = queryAddress +} + func testHandleExternalRequestECDSAHappyCase(t *testing.T, query *common.Query, validCertificate string, validPrivateKey *ecdsa.PrivateKey, signature []byte, pbResp pb.Response, accessControl *common.AccessControlPolicy, membership *common.Membership) { ctx, chaincodeStub := wtest.PrepMockStub() interopcc := SmartContract{} @@ -210,11 +239,11 @@ func testHandleExternalRequestECDSAHappyCase(t *testing.T, query *common.Query, require.NoError(t, err) b64QueryBytes := base64.StdEncoding.EncodeToString(queryBytes) interopPayload := common.InteropPayload{ - Payload: []byte("17.12"), - Address: "localhost:9080/network1/mychannel:interop:Read:a", - Confidential: false, + Payload: []byte("17.12"), + Address: "localhost:9080/network1/mychannel:interop:Read:a", + Confidential: false, RequestorCertificate: query.Certificate, - Nonce: query.Nonce, + Nonce: query.Nonce, } interopPayloadBytes, err := protoV2.Marshal(&interopPayload) require.NoError(t, err) @@ -267,6 +296,109 @@ func testHandleExternalRequestECDSAHappyCase(t *testing.T, query *common.Query, require.Equal(t, confPayload.Hash, fmac) } +func testHandleEventRequestECDSAHappyCase(t *testing.T, query *common.Query, validCertificate string, validPrivateKey *ecdsa.PrivateKey, signature []byte, pbResp pb.Response, accessControl *common.AccessControlPolicy, membership *common.Membership) { + ctx, chaincodeStub := wtest.PrepMockStub() + interopcc := SmartContract{} + chaincodeStub.GetCreatorReturns([]byte(getRelayCreator()), nil) + interopCCId := "interopcc" + wtest.SetMockStubCCId(chaincodeStub, interopCCId) + query.Confidential = false + + // set correct values for the success case + query.Certificate = validCertificate + // This tests the case of no dynamic arguments in the event query address (and signature is on query with no dynamic args) + b64Signature := base64.StdEncoding.EncodeToString(signature) + query.RequestorSignature = b64Signature + queryBytes, err := protoV2.Marshal(query) + require.NoError(t, err) + b64QueryBytes := base64.StdEncoding.EncodeToString(queryBytes) + interopPayload := common.InteropPayload{ + Payload: []byte("17.12"), + Address: "localhost:9080/network1/mychannel:interop:Read:a", + Confidential: false, + RequestorCertificate: query.Certificate, + Nonce: query.Nonce, + } + interopPayloadBytes, err := protoV2.Marshal(&interopPayload) + require.NoError(t, err) + + // mock all the calls to the chaincode stub + membershipBytes, err := json.Marshal(membership) + require.NoError(t, err) + accessControlBytes, err := json.Marshal(accessControl) + require.NoError(t, err) + chaincodeStub.GetStateReturnsOnCall(0, membershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(1, accessControlBytes, nil) + chaincodeStub.InvokeChaincodeReturns(pbResp) + + interopResponse, err := interopcc.HandleEventRequest(ctx, string(b64QueryBytes), "a") + require.NoError(t, err) + var interopPayloadResp common.InteropPayload + err = protoV2.Unmarshal([]byte(interopResponse), &interopPayloadResp) + require.NoError(t, err) + require.False(t, interopPayloadResp.Confidential) + require.Equal(t, interopPayloadBytes, []byte(interopResponse)) + require.NoError(t, err) + + // This tests the case of one dynamic argument in the event query address (and signature is on query with one dynamic arg) + query.Address = "localhost:9080/network1/mychannel:interop:Read:?" + random := rand.Reader + hashed, err := computeSHA2Hash([]byte(query.Address+query.Nonce), validPrivateKey.PublicKey.Params().BitSize) + require.NoError(t, err) + signatureDynamicArg, err := ecdsa.SignASN1(random, validPrivateKey, hashed) + require.NoError(t, err) + + b64Signature = base64.StdEncoding.EncodeToString(signatureDynamicArg) + query.RequestorSignature = b64Signature + queryBytes, err = protoV2.Marshal(query) + require.NoError(t, err) + b64QueryBytes = base64.StdEncoding.EncodeToString(queryBytes) + + // mock all the calls to the chaincode stub + chaincodeStub.GetStateReturnsOnCall(3, membershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(4, accessControlBytes, nil) + chaincodeStub.InvokeChaincodeReturns(pbResp) + + interopResponse, err = interopcc.HandleEventRequest(ctx, string(b64QueryBytes), "a") + require.NoError(t, err) + err = protoV2.Unmarshal([]byte(interopResponse), &interopPayloadResp) + require.NoError(t, err) + require.False(t, interopPayloadResp.Confidential) + require.Equal(t, interopPayloadBytes, []byte(interopResponse)) + require.NoError(t, err) + + // test the same request-response with encryption on + query.Confidential = true + queryBytes, err = protoV2.Marshal(query) + require.NoError(t, err) + b64QueryBytes = base64.StdEncoding.EncodeToString(queryBytes) + chaincodeStub.GetStateReturnsOnCall(6, membershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(7, accessControlBytes, nil) + chaincodeStub.InvokeChaincodeReturns(pbResp) + interopResponse, err = interopcc.HandleEventRequest(ctx, string(b64QueryBytes), "a") + require.NoError(t, err) + err = protoV2.Unmarshal([]byte(interopResponse), &interopPayloadResp) + require.NoError(t, err) + require.NotEqual(t, interopPayload.Payload, interopPayloadResp.Payload) + require.True(t, interopPayloadResp.Confidential) + require.Equal(t, interopPayloadResp.RequestorCertificate, validCertificate) + require.Equal(t, interopPayloadResp.Nonce, query.Nonce) + var confPayload common.ConfidentialPayload + err = protoV2.Unmarshal(interopPayloadResp.Payload, &confPayload) + require.NoError(t, err) + require.Equal(t, confPayload.HashType, common.ConfidentialPayload_HMAC) + decConfPayload, err := decryptDataWithPrivKey(validPrivateKey, confPayload.EncryptedPayload) + require.NoError(t, err) + var confPayloadContents common.ConfidentialPayloadContents + err = protoV2.Unmarshal(decConfPayload, &confPayloadContents) + require.NoError(t, err) + require.Equal(t, interopPayload.Payload, confPayloadContents.Payload) + mac := hmac.New(sha256.New, confPayloadContents.Random) + mac.Write(confPayloadContents.Payload) + fmac := mac.Sum(nil) + require.Equal(t, confPayload.Hash, fmac) +} + func testHandleExternalRequestED25519Signature(t *testing.T, query *common.Query, pbResp pb.Response, accessControl *common.AccessControlPolicy, fabricMembership *common.Membership, template x509.Certificate) { ctx, chaincodeStub := wtest.PrepMockStub() interopcc := SmartContract{} From 53d0ca56357c86fe996ddcdcaae002e4f3569856 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Fri, 19 Aug 2022 07:22:43 +0000 Subject: [PATCH 097/150] set WALLET_PATH to empty Signed-off-by: Krishnasuri Narayanam --- core/drivers/fabric-driver/.env.docker.template | 2 +- core/drivers/fabric-driver/.env.template | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/drivers/fabric-driver/.env.docker.template b/core/drivers/fabric-driver/.env.docker.template index 0f4e633ca..2340e435b 100644 --- a/core/drivers/fabric-driver/.env.docker.template +++ b/core/drivers/fabric-driver/.env.docker.template @@ -10,7 +10,7 @@ DRIVER_TLS_CERT_PATH= DRIVER_TLS_KEY_PATH= INTEROP_CHAINCODE= DB_PATH=driverdbs -WALLET_PATH= +WALLET_PATH= DOCKER_IMAGE_NAME=ghcr.io/hyperledger-labs/weaver-fabric-driver DOCKER_TAG=1.4.0 EXTERNAL_NETWORK= diff --git a/core/drivers/fabric-driver/.env.template b/core/drivers/fabric-driver/.env.template index 9c3c1a8e0..312e81bcb 100644 --- a/core/drivers/fabric-driver/.env.template +++ b/core/drivers/fabric-driver/.env.template @@ -11,4 +11,4 @@ DRIVER_CONFIG= INTEROP_CHAINCODE=interop MOCK=false DB_PATH=driverdbs -WALLET_PATH= +WALLET_PATH= From 36ff2b97c0abc98a3853947a023479a739613b50 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Sat, 20 Aug 2022 17:24:29 +0000 Subject: [PATCH 098/150] Updated protobufs for identity syncing Signed-off-by: VRamakrishna --- common/protos-go/identity/agent.pb.go | 461 +++++++++++++++--- common/protos-go/identity/agent_grpc.pb.go | 36 +- common/protos/identity/agent.proto | 31 +- .../iin-agent/src/common/ledgerBase.ts | 17 +- .../src/protocols/externalOperations.ts | 10 +- .../src/protocols/localOperations.ts | 8 +- .../iin-agent/src/server.ts | 6 +- 7 files changed, 465 insertions(+), 104 deletions(-) diff --git a/common/protos-go/identity/agent.pb.go b/common/protos-go/identity/agent.pb.go index 9349ceead..1872c0222 100644 --- a/common/protos-go/identity/agent.pb.go +++ b/common/protos-go/identity/agent.pb.go @@ -21,6 +21,7 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// Unique identifier for a unit of a network that runs an IIN agent type NetworkUnitIdentity struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -76,58 +77,332 @@ func (x *NetworkUnitIdentity) GetParticipantId() string { return "" } +// Association of signature (over arbitrary data) and signer identity +type Attestation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UnitIdentity *NetworkUnitIdentity `protobuf:"bytes,1,opt,name=unit_identity,json=unitIdentity,proto3" json:"unit_identity,omitempty"` + Certificate string `protobuf:"bytes,2,opt,name=certificate,proto3" json:"certificate,omitempty"` + Signature string `protobuf:"bytes,3,opt,name=signature,proto3" json:"signature,omitempty"` +} + +func (x *Attestation) Reset() { + *x = Attestation{} + if protoimpl.UnsafeEnabled { + mi := &file_identity_agent_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Attestation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Attestation) ProtoMessage() {} + +func (x *Attestation) ProtoReflect() protoreflect.Message { + mi := &file_identity_agent_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Attestation.ProtoReflect.Descriptor instead. +func (*Attestation) Descriptor() ([]byte, []int) { + return file_identity_agent_proto_rawDescGZIP(), []int{1} +} + +func (x *Attestation) GetUnitIdentity() *NetworkUnitIdentity { + if x != nil { + return x.UnitIdentity + } + return nil +} + +func (x *Attestation) GetCertificate() string { + if x != nil { + return x.Certificate + } + return "" +} + +func (x *Attestation) GetSignature() string { + if x != nil { + return x.Signature + } + return "" +} + +// Attested security domain membership by a single member +type AttestedMembership struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Membership *common.Membership `protobuf:"bytes,1,opt,name=membership,proto3" json:"membership,omitempty"` + Attestation *Attestation `protobuf:"bytes,2,opt,name=attestation,proto3" json:"attestation,omitempty"` +} + +func (x *AttestedMembership) Reset() { + *x = AttestedMembership{} + if protoimpl.UnsafeEnabled { + mi := &file_identity_agent_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AttestedMembership) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AttestedMembership) ProtoMessage() {} + +func (x *AttestedMembership) ProtoReflect() protoreflect.Message { + mi := &file_identity_agent_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AttestedMembership.ProtoReflect.Descriptor instead. +func (*AttestedMembership) Descriptor() ([]byte, []int) { + return file_identity_agent_proto_rawDescGZIP(), []int{2} +} + +func (x *AttestedMembership) GetMembership() *common.Membership { + if x != nil { + return x.Membership + } + return nil +} + +func (x *AttestedMembership) GetAttestation() *Attestation { + if x != nil { + return x.Attestation + } + return nil +} + +// Counter attestation over security domain membership attested by its participants +type AttestedSecurityDomain struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SecurityDomain *AttestedSecurityDomain_AttestedMembershipSet `protobuf:"bytes,1,opt,name=security_domain,json=securityDomain,proto3" json:"security_domain,omitempty"` + Attestations []*Attestation `protobuf:"bytes,2,rep,name=attestations,proto3" json:"attestations,omitempty"` +} + +func (x *AttestedSecurityDomain) Reset() { + *x = AttestedSecurityDomain{} + if protoimpl.UnsafeEnabled { + mi := &file_identity_agent_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AttestedSecurityDomain) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AttestedSecurityDomain) ProtoMessage() {} + +func (x *AttestedSecurityDomain) ProtoReflect() protoreflect.Message { + mi := &file_identity_agent_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AttestedSecurityDomain.ProtoReflect.Descriptor instead. +func (*AttestedSecurityDomain) Descriptor() ([]byte, []int) { + return file_identity_agent_proto_rawDescGZIP(), []int{3} +} + +func (x *AttestedSecurityDomain) GetSecurityDomain() *AttestedSecurityDomain_AttestedMembershipSet { + if x != nil { + return x.SecurityDomain + } + return nil +} + +func (x *AttestedSecurityDomain) GetAttestations() []*Attestation { + if x != nil { + return x.Attestations + } + return nil +} + +type AttestedSecurityDomain_AttestedMembershipSet struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Membership *common.Membership `protobuf:"bytes,1,opt,name=membership,proto3" json:"membership,omitempty"` + Attestations []*Attestation `protobuf:"bytes,2,rep,name=attestations,proto3" json:"attestations,omitempty"` +} + +func (x *AttestedSecurityDomain_AttestedMembershipSet) Reset() { + *x = AttestedSecurityDomain_AttestedMembershipSet{} + if protoimpl.UnsafeEnabled { + mi := &file_identity_agent_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AttestedSecurityDomain_AttestedMembershipSet) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AttestedSecurityDomain_AttestedMembershipSet) ProtoMessage() {} + +func (x *AttestedSecurityDomain_AttestedMembershipSet) ProtoReflect() protoreflect.Message { + mi := &file_identity_agent_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AttestedSecurityDomain_AttestedMembershipSet.ProtoReflect.Descriptor instead. +func (*AttestedSecurityDomain_AttestedMembershipSet) Descriptor() ([]byte, []int) { + return file_identity_agent_proto_rawDescGZIP(), []int{3, 0} +} + +func (x *AttestedSecurityDomain_AttestedMembershipSet) GetMembership() *common.Membership { + if x != nil { + return x.Membership + } + return nil +} + +func (x *AttestedSecurityDomain_AttestedMembershipSet) GetAttestations() []*Attestation { + if x != nil { + return x.Attestations + } + return nil +} + var File_identity_agent_proto protoreflect.FileDescriptor var file_identity_agent_proto_rawDesc = []byte{ 0x0a, 0x14, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x1a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x61, - 0x63, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x5b, 0x0a, 0x13, 0x4e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x55, 0x6e, 0x69, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, - 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x25, - 0x0a, 0x0e, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, - 0x61, 0x6e, 0x74, 0x49, 0x64, 0x32, 0xf2, 0x03, 0x0a, 0x08, 0x49, 0x49, 0x4e, 0x41, 0x67, 0x65, - 0x6e, 0x74, 0x12, 0x4b, 0x0a, 0x11, 0x53, 0x79, 0x6e, 0x63, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x23, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x55, 0x6e, 0x69, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, - 0x56, 0x0a, 0x1c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x23, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, - 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x55, 0x6e, 0x69, 0x74, 0x49, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, - 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x53, 0x0a, 0x19, 0x53, 0x65, 0x6e, 0x64, 0x49, + 0x63, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0x5b, 0x0a, 0x13, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x55, 0x6e, 0x69, 0x74, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x61, 0x72, 0x74, 0x69, + 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0d, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x97, + 0x01, 0x0a, 0x0b, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x48, + 0x0a, 0x0d, 0x75, 0x6e, 0x69, 0x74, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x55, 0x6e, + 0x69, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x0c, 0x75, 0x6e, 0x69, 0x74, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x92, 0x01, 0x0a, 0x12, 0x41, 0x74, 0x74, + 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, + 0x3d, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, + 0x69, 0x70, 0x52, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x3d, + 0x0a, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, + 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xda, 0x02, + 0x0a, 0x16, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, + 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x65, 0x0a, 0x0f, 0x73, 0x65, 0x63, 0x75, + 0x72, 0x69, 0x74, 0x79, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x3c, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, + 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, 0x75, 0x72, + 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, + 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x65, 0x74, 0x52, + 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, + 0x3f, 0x0a, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x1a, 0x97, 0x01, 0x0a, 0x15, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x65, 0x74, 0x12, 0x3d, 0x0a, 0x0a, 0x6d, 0x65, + 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, + 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x0a, 0x6d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x3f, 0x0a, 0x0c, 0x61, 0x74, 0x74, + 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, + 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x74, + 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0xf7, 0x03, 0x0a, 0x08, 0x49, + 0x49, 0x4e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x4b, 0x0a, 0x11, 0x53, 0x79, 0x6e, 0x63, 0x45, + 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x23, 0x2e, 0x69, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x55, 0x6e, 0x69, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, + 0x63, 0x6b, 0x22, 0x00, 0x12, 0x56, 0x0a, 0x1c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x55, 0x6e, 0x69, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x53, 0x0a, 0x19, - 0x46, 0x6c, 0x6f, 0x77, 0x41, 0x6e, 0x64, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x41, 0x74, 0x74, - 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x23, 0x2e, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x55, 0x6e, 0x69, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x0f, - 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, - 0x00, 0x12, 0x4c, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x74, 0x74, 0x65, - 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x55, 0x6e, 0x69, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, - 0x49, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x23, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x55, 0x6e, 0x69, 0x74, 0x49, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, 0x75, 0x0a, 0x20, 0x63, 0x6f, - 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5a, 0x51, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, - 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, - 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, - 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x19, + 0x53, 0x65, 0x6e, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x2e, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, + 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x1a, 0x0f, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, + 0x12, 0x53, 0x0a, 0x19, 0x46, 0x6c, 0x6f, 0x77, 0x41, 0x6e, 0x64, 0x52, 0x65, 0x63, 0x6f, 0x72, + 0x64, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x23, 0x2e, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x55, 0x6e, 0x69, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, + 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x2e, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, + 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, + 0x61, 0x69, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, + 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x74, + 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x2e, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, + 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, + 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, + 0x63, 0x6b, 0x22, 0x00, 0x42, 0x75, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, + 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5a, 0x51, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, + 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, + 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, + 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, + 0x67, 0x6f, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( @@ -142,29 +417,41 @@ func file_identity_agent_proto_rawDescGZIP() []byte { return file_identity_agent_proto_rawDescData } -var file_identity_agent_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_identity_agent_proto_msgTypes = make([]protoimpl.MessageInfo, 5) var file_identity_agent_proto_goTypes = []interface{}{ - (*NetworkUnitIdentity)(nil), // 0: identity.agent.NetworkUnitIdentity - (*common.Ack)(nil), // 1: common.ack.Ack + (*NetworkUnitIdentity)(nil), // 0: identity.agent.NetworkUnitIdentity + (*Attestation)(nil), // 1: identity.agent.Attestation + (*AttestedMembership)(nil), // 2: identity.agent.AttestedMembership + (*AttestedSecurityDomain)(nil), // 3: identity.agent.AttestedSecurityDomain + (*AttestedSecurityDomain_AttestedMembershipSet)(nil), // 4: identity.agent.AttestedSecurityDomain.AttestedMembershipSet + (*common.Membership)(nil), // 5: common.membership.Membership + (*common.Ack)(nil), // 6: common.ack.Ack } var file_identity_agent_proto_depIdxs = []int32{ - 0, // 0: identity.agent.IINAgent.SyncExternalState:input_type -> identity.agent.NetworkUnitIdentity - 0, // 1: identity.agent.IINAgent.RequestIdentityConfiguration:input_type -> identity.agent.NetworkUnitIdentity - 0, // 2: identity.agent.IINAgent.SendIdentityConfiguration:input_type -> identity.agent.NetworkUnitIdentity - 0, // 3: identity.agent.IINAgent.FlowAndRecordAttestations:input_type -> identity.agent.NetworkUnitIdentity - 0, // 4: identity.agent.IINAgent.RequestAttestation:input_type -> identity.agent.NetworkUnitIdentity - 0, // 5: identity.agent.IINAgent.SendAttestation:input_type -> identity.agent.NetworkUnitIdentity - 1, // 6: identity.agent.IINAgent.SyncExternalState:output_type -> common.ack.Ack - 1, // 7: identity.agent.IINAgent.RequestIdentityConfiguration:output_type -> common.ack.Ack - 1, // 8: identity.agent.IINAgent.SendIdentityConfiguration:output_type -> common.ack.Ack - 1, // 9: identity.agent.IINAgent.FlowAndRecordAttestations:output_type -> common.ack.Ack - 1, // 10: identity.agent.IINAgent.RequestAttestation:output_type -> common.ack.Ack - 1, // 11: identity.agent.IINAgent.SendAttestation:output_type -> common.ack.Ack - 6, // [6:12] is the sub-list for method output_type - 0, // [0:6] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name + 0, // 0: identity.agent.Attestation.unit_identity:type_name -> identity.agent.NetworkUnitIdentity + 5, // 1: identity.agent.AttestedMembership.membership:type_name -> common.membership.Membership + 1, // 2: identity.agent.AttestedMembership.attestation:type_name -> identity.agent.Attestation + 4, // 3: identity.agent.AttestedSecurityDomain.security_domain:type_name -> identity.agent.AttestedSecurityDomain.AttestedMembershipSet + 1, // 4: identity.agent.AttestedSecurityDomain.attestations:type_name -> identity.agent.Attestation + 5, // 5: identity.agent.AttestedSecurityDomain.AttestedMembershipSet.membership:type_name -> common.membership.Membership + 1, // 6: identity.agent.AttestedSecurityDomain.AttestedMembershipSet.attestations:type_name -> identity.agent.Attestation + 0, // 7: identity.agent.IINAgent.SyncExternalState:input_type -> identity.agent.NetworkUnitIdentity + 0, // 8: identity.agent.IINAgent.RequestIdentityConfiguration:input_type -> identity.agent.NetworkUnitIdentity + 2, // 9: identity.agent.IINAgent.SendIdentityConfiguration:input_type -> identity.agent.AttestedMembership + 0, // 10: identity.agent.IINAgent.FlowAndRecordAttestations:input_type -> identity.agent.NetworkUnitIdentity + 3, // 11: identity.agent.IINAgent.RequestAttestation:input_type -> identity.agent.AttestedSecurityDomain + 3, // 12: identity.agent.IINAgent.SendAttestation:input_type -> identity.agent.AttestedSecurityDomain + 6, // 13: identity.agent.IINAgent.SyncExternalState:output_type -> common.ack.Ack + 6, // 14: identity.agent.IINAgent.RequestIdentityConfiguration:output_type -> common.ack.Ack + 6, // 15: identity.agent.IINAgent.SendIdentityConfiguration:output_type -> common.ack.Ack + 6, // 16: identity.agent.IINAgent.FlowAndRecordAttestations:output_type -> common.ack.Ack + 6, // 17: identity.agent.IINAgent.RequestAttestation:output_type -> common.ack.Ack + 6, // 18: identity.agent.IINAgent.SendAttestation:output_type -> common.ack.Ack + 13, // [13:19] is the sub-list for method output_type + 7, // [7:13] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 7, // [7:7] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name } func init() { file_identity_agent_proto_init() } @@ -185,6 +472,54 @@ func file_identity_agent_proto_init() { return nil } } + file_identity_agent_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Attestation); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_identity_agent_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AttestedMembership); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_identity_agent_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AttestedSecurityDomain); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_identity_agent_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AttestedSecurityDomain_AttestedMembershipSet); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -192,7 +527,7 @@ func file_identity_agent_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_identity_agent_proto_rawDesc, NumEnums: 0, - NumMessages: 1, + NumMessages: 5, NumExtensions: 0, NumServices: 1, }, diff --git a/common/protos-go/identity/agent_grpc.pb.go b/common/protos-go/identity/agent_grpc.pb.go index 1d84d6a9e..6cc94634a 100644 --- a/common/protos-go/identity/agent_grpc.pb.go +++ b/common/protos-go/identity/agent_grpc.pb.go @@ -24,14 +24,14 @@ type IINAgentClient interface { // Requesting network unit's state from a foreign IIN agent. RequestIdentityConfiguration(ctx context.Context, in *NetworkUnitIdentity, opts ...grpc.CallOption) (*common.Ack, error) // Handling network unit's state sent by a foreign IIN agent. - SendIdentityConfiguration(ctx context.Context, in *NetworkUnitIdentity, opts ...grpc.CallOption) (*common.Ack, error) + SendIdentityConfiguration(ctx context.Context, in *AttestedMembership, opts ...grpc.CallOption) (*common.Ack, error) // user or agent triggers a flow to collect signatures attesting an // external/foreign network unit's state and recording to ledger FlowAndRecordAttestations(ctx context.Context, in *NetworkUnitIdentity, opts ...grpc.CallOption) (*common.Ack, error) // Requesting attestation from a local IIN agent. - RequestAttestation(ctx context.Context, in *NetworkUnitIdentity, opts ...grpc.CallOption) (*common.Ack, error) + RequestAttestation(ctx context.Context, in *AttestedSecurityDomain, opts ...grpc.CallOption) (*common.Ack, error) // Handling attestation sent by a local IIN agent. - SendAttestation(ctx context.Context, in *NetworkUnitIdentity, opts ...grpc.CallOption) (*common.Ack, error) + SendAttestation(ctx context.Context, in *AttestedSecurityDomain, opts ...grpc.CallOption) (*common.Ack, error) } type iINAgentClient struct { @@ -60,7 +60,7 @@ func (c *iINAgentClient) RequestIdentityConfiguration(ctx context.Context, in *N return out, nil } -func (c *iINAgentClient) SendIdentityConfiguration(ctx context.Context, in *NetworkUnitIdentity, opts ...grpc.CallOption) (*common.Ack, error) { +func (c *iINAgentClient) SendIdentityConfiguration(ctx context.Context, in *AttestedMembership, opts ...grpc.CallOption) (*common.Ack, error) { out := new(common.Ack) err := c.cc.Invoke(ctx, "/identity.agent.IINAgent/SendIdentityConfiguration", in, out, opts...) if err != nil { @@ -78,7 +78,7 @@ func (c *iINAgentClient) FlowAndRecordAttestations(ctx context.Context, in *Netw return out, nil } -func (c *iINAgentClient) RequestAttestation(ctx context.Context, in *NetworkUnitIdentity, opts ...grpc.CallOption) (*common.Ack, error) { +func (c *iINAgentClient) RequestAttestation(ctx context.Context, in *AttestedSecurityDomain, opts ...grpc.CallOption) (*common.Ack, error) { out := new(common.Ack) err := c.cc.Invoke(ctx, "/identity.agent.IINAgent/RequestAttestation", in, out, opts...) if err != nil { @@ -87,7 +87,7 @@ func (c *iINAgentClient) RequestAttestation(ctx context.Context, in *NetworkUnit return out, nil } -func (c *iINAgentClient) SendAttestation(ctx context.Context, in *NetworkUnitIdentity, opts ...grpc.CallOption) (*common.Ack, error) { +func (c *iINAgentClient) SendAttestation(ctx context.Context, in *AttestedSecurityDomain, opts ...grpc.CallOption) (*common.Ack, error) { out := new(common.Ack) err := c.cc.Invoke(ctx, "/identity.agent.IINAgent/SendAttestation", in, out, opts...) if err != nil { @@ -105,14 +105,14 @@ type IINAgentServer interface { // Requesting network unit's state from a foreign IIN agent. RequestIdentityConfiguration(context.Context, *NetworkUnitIdentity) (*common.Ack, error) // Handling network unit's state sent by a foreign IIN agent. - SendIdentityConfiguration(context.Context, *NetworkUnitIdentity) (*common.Ack, error) + SendIdentityConfiguration(context.Context, *AttestedMembership) (*common.Ack, error) // user or agent triggers a flow to collect signatures attesting an // external/foreign network unit's state and recording to ledger FlowAndRecordAttestations(context.Context, *NetworkUnitIdentity) (*common.Ack, error) // Requesting attestation from a local IIN agent. - RequestAttestation(context.Context, *NetworkUnitIdentity) (*common.Ack, error) + RequestAttestation(context.Context, *AttestedSecurityDomain) (*common.Ack, error) // Handling attestation sent by a local IIN agent. - SendAttestation(context.Context, *NetworkUnitIdentity) (*common.Ack, error) + SendAttestation(context.Context, *AttestedSecurityDomain) (*common.Ack, error) mustEmbedUnimplementedIINAgentServer() } @@ -126,16 +126,16 @@ func (UnimplementedIINAgentServer) SyncExternalState(context.Context, *NetworkUn func (UnimplementedIINAgentServer) RequestIdentityConfiguration(context.Context, *NetworkUnitIdentity) (*common.Ack, error) { return nil, status.Errorf(codes.Unimplemented, "method RequestIdentityConfiguration not implemented") } -func (UnimplementedIINAgentServer) SendIdentityConfiguration(context.Context, *NetworkUnitIdentity) (*common.Ack, error) { +func (UnimplementedIINAgentServer) SendIdentityConfiguration(context.Context, *AttestedMembership) (*common.Ack, error) { return nil, status.Errorf(codes.Unimplemented, "method SendIdentityConfiguration not implemented") } func (UnimplementedIINAgentServer) FlowAndRecordAttestations(context.Context, *NetworkUnitIdentity) (*common.Ack, error) { return nil, status.Errorf(codes.Unimplemented, "method FlowAndRecordAttestations not implemented") } -func (UnimplementedIINAgentServer) RequestAttestation(context.Context, *NetworkUnitIdentity) (*common.Ack, error) { +func (UnimplementedIINAgentServer) RequestAttestation(context.Context, *AttestedSecurityDomain) (*common.Ack, error) { return nil, status.Errorf(codes.Unimplemented, "method RequestAttestation not implemented") } -func (UnimplementedIINAgentServer) SendAttestation(context.Context, *NetworkUnitIdentity) (*common.Ack, error) { +func (UnimplementedIINAgentServer) SendAttestation(context.Context, *AttestedSecurityDomain) (*common.Ack, error) { return nil, status.Errorf(codes.Unimplemented, "method SendAttestation not implemented") } func (UnimplementedIINAgentServer) mustEmbedUnimplementedIINAgentServer() {} @@ -188,7 +188,7 @@ func _IINAgent_RequestIdentityConfiguration_Handler(srv interface{}, ctx context } func _IINAgent_SendIdentityConfiguration_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(NetworkUnitIdentity) + in := new(AttestedMembership) if err := dec(in); err != nil { return nil, err } @@ -200,7 +200,7 @@ func _IINAgent_SendIdentityConfiguration_Handler(srv interface{}, ctx context.Co FullMethod: "/identity.agent.IINAgent/SendIdentityConfiguration", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(IINAgentServer).SendIdentityConfiguration(ctx, req.(*NetworkUnitIdentity)) + return srv.(IINAgentServer).SendIdentityConfiguration(ctx, req.(*AttestedMembership)) } return interceptor(ctx, in, info, handler) } @@ -224,7 +224,7 @@ func _IINAgent_FlowAndRecordAttestations_Handler(srv interface{}, ctx context.Co } func _IINAgent_RequestAttestation_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(NetworkUnitIdentity) + in := new(AttestedSecurityDomain) if err := dec(in); err != nil { return nil, err } @@ -236,13 +236,13 @@ func _IINAgent_RequestAttestation_Handler(srv interface{}, ctx context.Context, FullMethod: "/identity.agent.IINAgent/RequestAttestation", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(IINAgentServer).RequestAttestation(ctx, req.(*NetworkUnitIdentity)) + return srv.(IINAgentServer).RequestAttestation(ctx, req.(*AttestedSecurityDomain)) } return interceptor(ctx, in, info, handler) } func _IINAgent_SendAttestation_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(NetworkUnitIdentity) + in := new(AttestedSecurityDomain) if err := dec(in); err != nil { return nil, err } @@ -254,7 +254,7 @@ func _IINAgent_SendAttestation_Handler(srv interface{}, ctx context.Context, dec FullMethod: "/identity.agent.IINAgent/SendAttestation", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(IINAgentServer).SendAttestation(ctx, req.(*NetworkUnitIdentity)) + return srv.(IINAgentServer).SendAttestation(ctx, req.(*AttestedSecurityDomain)) } return interceptor(ctx, in, info, handler) } diff --git a/common/protos/identity/agent.proto b/common/protos/identity/agent.proto index e4d116da1..3c21eef81 100644 --- a/common/protos/identity/agent.proto +++ b/common/protos/identity/agent.proto @@ -3,6 +3,7 @@ syntax = "proto3"; package identity.agent; import "common/ack.proto"; +import "common/membership.proto"; option java_package = "com.weaver.protos.identity.agent"; option go_package = "github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go/identity"; @@ -14,17 +15,41 @@ service IINAgent { // Requesting network unit's state from a foreign IIN agent. rpc RequestIdentityConfiguration(NetworkUnitIdentity) returns (common.ack.Ack){} // Handling network unit's state sent by a foreign IIN agent. - rpc SendIdentityConfiguration(NetworkUnitIdentity) returns (common.ack.Ack){} + rpc SendIdentityConfiguration(AttestedMembership) returns (common.ack.Ack){} // user or agent triggers a flow to collect signatures attesting an // external/foreign network unit's state and recording to ledger rpc FlowAndRecordAttestations(NetworkUnitIdentity) returns (common.ack.Ack) {} // Requesting attestation from a local IIN agent. - rpc RequestAttestation(NetworkUnitIdentity) returns (common.ack.Ack){} + rpc RequestAttestation(AttestedSecurityDomain) returns (common.ack.Ack){} // Handling attestation sent by a local IIN agent. - rpc SendAttestation(NetworkUnitIdentity) returns (common.ack.Ack){} + rpc SendAttestation(AttestedSecurityDomain) returns (common.ack.Ack){} } +// Unique identifier for a unit of a network that runs an IIN agent message NetworkUnitIdentity { string network_id = 1; string participant_id = 2; } + +// Association of signature (over arbitrary data) and signer identity +message Attestation { + NetworkUnitIdentity unit_identity = 1; + string certificate = 2; + string signature = 3; +} + +// Attested security domain membership by a single member +message AttestedMembership { + common.membership.Membership membership = 1; + Attestation attestation = 2; +} + +// Counter attestation over security domain membership attested by its participants +message AttestedSecurityDomain { + message AttestedMembershipSet { + common.membership.Membership membership = 1; + repeated Attestation attestations = 2; + } + AttestedMembershipSet security_domain = 1; + repeated Attestation attestations = 2; +} diff --git a/core/identity-management/iin-agent/src/common/ledgerBase.ts b/core/identity-management/iin-agent/src/common/ledgerBase.ts index 348f3d9d5..f6804acb4 100644 --- a/core/identity-management/iin-agent/src/common/ledgerBase.ts +++ b/core/identity-management/iin-agent/src/common/ledgerBase.ts @@ -1,12 +1,16 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + export class LedgerBase { ledgerId: string; // Unique ID of a ledger in which the Weaver interoperation module is installed contractId: string; // Unique ID of the contract corresponding to the Weaver interoperation module installed in 'ledgerId' - private _isConnected: boolean // Flag indicating whether we are ready to invoke contracts on the ledger constructor(ledgerId: string, contractId: string) { this.ledgerId = ledgerId; this.contractId = contractId; - this._isConnected = false; } getLedgerID(): string { @@ -17,19 +21,10 @@ export class LedgerBase { return this.contractId; } - isConnected(): boolean { - return this._isConnected; - } - // Setup a user (with wallet and one or more identities) with contract invocation credentials async setupWalletIdentity() { } - // Preliminary configuration as a prerequisite for contract invocation - async setupLedgerConnection() { - this._isConnected = true; - } - // Invoke a contract to drive a transaction // TODO: Add parameters corresponding to the output of a flow among IIN agents async invokeContract() { diff --git a/core/identity-management/iin-agent/src/protocols/externalOperations.ts b/core/identity-management/iin-agent/src/protocols/externalOperations.ts index c5ae8a44d..6fdbb8bb0 100644 --- a/core/identity-management/iin-agent/src/protocols/externalOperations.ts +++ b/core/identity-management/iin-agent/src/protocols/externalOperations.ts @@ -19,6 +19,12 @@ export const requestIdentityConfiguration = async (networkUnit: iin_agent_pb.Net }; // Processes foreign network unit's state/configuration received from a foreign IIN agent -export const sendIdentityConfiguration = async (networkUnit: iin_agent_pb.NetworkUnitIdentity) => { - console.log('sendIdentityConfiguration:', networkUnit.getNetworkId(), '-', networkUnit.getParticipantId()); +export const sendIdentityConfiguration = async (attestedMembership: iin_agent_pb.AttestedMembership) => { + const attestation = attestedMembership.getAttestation(); + if (attestation) { + const networkUnit = attestation.getUnitIdentity(); + if (networkUnit) { + console.log('sendIdentityConfiguration:', networkUnit.getNetworkId(), '-', networkUnit.getParticipantId()); + } + } }; diff --git a/core/identity-management/iin-agent/src/protocols/localOperations.ts b/core/identity-management/iin-agent/src/protocols/localOperations.ts index 1b6dcbfd7..90e44df14 100644 --- a/core/identity-management/iin-agent/src/protocols/localOperations.ts +++ b/core/identity-management/iin-agent/src/protocols/localOperations.ts @@ -14,11 +14,11 @@ export const flowAndRecordAttestationsOnLedger = async (networkUnit: iin_agent_p }; // Generates attestations on a foreign network unit's state -export const requestAttestation = async (networkUnit: iin_agent_pb.NetworkUnitIdentity) => { - console.log('requestAttestation:', networkUnit.getNetworkId(), '-', networkUnit.getParticipantId()); +export const requestAttestation = async (attestedSecurityDomain: iin_agent_pb.AttestedSecurityDomain) => { + console.log('requestAttestation:'); }; // Processes attestations on a foreign network unit's state received from a local IIN agent -export const sendAttestation = async (networkUnit: iin_agent_pb.NetworkUnitIdentity) => { - console.log('sendAttestation:', networkUnit.getNetworkId(), '-', networkUnit.getParticipantId()); +export const sendAttestation = async (attestedSecurityDomain: iin_agent_pb.AttestedSecurityDomain) => { + console.log('sendAttestation:'); }; diff --git a/core/identity-management/iin-agent/src/server.ts b/core/identity-management/iin-agent/src/server.ts index 644818508..231f873d2 100644 --- a/core/identity-management/iin-agent/src/server.ts +++ b/core/identity-management/iin-agent/src/server.ts @@ -64,7 +64,7 @@ iinAgentServer.addService(iin_agent_pb_grpc.IINAgentService, { } }, // Service for receiving network unit states from foreign IIN agents. Will communicate with the IIN agent caller and respond with an ack while the attestation is being processed. - sendIdentityConfiguration: (call: { request: iin_agent_pb.NetworkUnitIdentity }, callback: (_: any, object: ack_pb.Ack) => void) => { + sendIdentityConfiguration: (call: { request: iin_agent_pb.AttestedMembership }, callback: (_: any, object: ack_pb.Ack) => void) => { const ack_response = new ack_pb.Ack(); try { sendIdentityConfiguration(call.request); @@ -106,7 +106,7 @@ iinAgentServer.addService(iin_agent_pb_grpc.IINAgentService, { } }, // Service for receiving requests for attestations on foreign network unit states from local IIN agents. Will communicate with the IIN agent caller and respond with an ack while the attestation is being generated. - requestAttestation: (call: { request: iin_agent_pb.NetworkUnitIdentity }, callback: (_: any, object: ack_pb.Ack) => void) => { + requestAttestation: (call: { request: iin_agent_pb.AttestedSecurityDomain }, callback: (_: any, object: ack_pb.Ack) => void) => { const ack_response = new ack_pb.Ack(); try { requestAttestation(call.request); @@ -127,7 +127,7 @@ iinAgentServer.addService(iin_agent_pb_grpc.IINAgentService, { } }, // Service for receiving attestations on foreign network unit states from local IIN agents. Will communicate with the IIN agent caller and respond with an ack while the attestation is being processed. - sendAttestation: (call: { request: iin_agent_pb.NetworkUnitIdentity }, callback: (_: any, object: ack_pb.Ack) => void) => { + sendAttestation: (call: { request: iin_agent_pb.AttestedSecurityDomain }, callback: (_: any, object: ack_pb.Ack) => void) => { const ack_response = new ack_pb.Ack(); try { sendAttestation(call.request); From a5249038a4dc8cf13938b596a2b939aaf14c3d08 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Sat, 20 Aug 2022 17:30:30 +0000 Subject: [PATCH 099/150] Added basic code for Fabric IIN Agent Signed-off-by: VRamakrishna --- .../iin-agent/src/fabric-ledger/config.json | 14 +++ .../iin-agent/src/fabric-ledger/connector.ts | 49 ++++++++ .../src/fabric-ledger/networkUtils.ts | 117 ++++++++++++++++++ .../src/fabric-ledger/walletUtils.ts | 101 +++++++++++++++ 4 files changed, 281 insertions(+) create mode 100644 core/identity-management/iin-agent/src/fabric-ledger/config.json create mode 100644 core/identity-management/iin-agent/src/fabric-ledger/connector.ts create mode 100644 core/identity-management/iin-agent/src/fabric-ledger/networkUtils.ts create mode 100644 core/identity-management/iin-agent/src/fabric-ledger/walletUtils.ts diff --git a/core/identity-management/iin-agent/src/fabric-ledger/config.json b/core/identity-management/iin-agent/src/fabric-ledger/config.json new file mode 100644 index 000000000..d8274b8a1 --- /dev/null +++ b/core/identity-management/iin-agent/src/fabric-ledger/config.json @@ -0,0 +1,14 @@ +{ + "admin":{ + "name":"admin", + "secret":"adminpw" + }, + "agent": { + "name":"iin-agent", + "affiliation":"org1.department1", + "role": "client", + "attrs": [{ "name": "iin-agent", "value": "true", "ecert": true }] + }, + "mspId":"Org1MSP", + "caUrl":"" +} diff --git a/core/identity-management/iin-agent/src/fabric-ledger/connector.ts b/core/identity-management/iin-agent/src/fabric-ledger/connector.ts new file mode 100644 index 000000000..94e349dc3 --- /dev/null +++ b/core/identity-management/iin-agent/src/fabric-ledger/connector.ts @@ -0,0 +1,49 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Contract } from 'fabric-network'; +import { LedgerBase } from '../common/ledgerBase'; +import { walletSetup } from './walletUtils'; +import { invokeFabricChaincode, queryFabricChaincode } from './networkUtils'; +import * as path from 'path'; +import * as fs from 'fs'; + +export class FabricConnector extends LedgerBase { + connectionProfilePath: string; + configFilePath: string; + networkId: string; + orgMspId: string; + walletPath: string; + + constructor(ledgerId: string, contractId: string, connectionProfilePath: string, configFilePath: string, walletPath: string) { + super(ledgerId, contractId); + this.connectionProfilePath = connectionProfilePath ? connectionProfilePath : path.resolve(__dirname, './', 'connection_profile.json'); + this.configFilePath = configFilePath ? configFilePath : path.resolve(__dirname, './', 'config.json'); + this.networkId = process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1'; + if (!fs.existsSync(configFilePath)) { + throw new Error('Config does not exist at path: ' + configFilePath); + } + this.orgMspId = JSON.parse(fs.readFileSync(configFilePath, 'utf8').toString()).mspId; + this.walletPath = walletPath ? walletPath : path.join(process.cwd(), `wallet-${this.networkId}`); + } + + // Setup a user (with wallet and one or more identities) with contract invocation credentials + async setupWalletIdentity() { + walletSetup(this.walletPath, this.connectionProfilePath, this.configFilePath, this.networkId); + } + + // Invoke a contract to drive a transaction + // TODO: Add parameters corresponding to the output of a flow among IIN agents + async invokeContract() { + await invokeFabricChaincode(this.walletPath, this.connectionProfilePath, this.configFilePath, this.ledgerId, this.contractId, "", []); + } + + // Query a contract to fetch information from the ledger + async queryContract() { + const result = await queryFabricChaincode(this.walletPath, this.connectionProfilePath, this.configFilePath, this.ledgerId, this.contractId, "", []); + return result; + } +} diff --git a/core/identity-management/iin-agent/src/fabric-ledger/networkUtils.ts b/core/identity-management/iin-agent/src/fabric-ledger/networkUtils.ts new file mode 100644 index 000000000..0c0d8dde7 --- /dev/null +++ b/core/identity-management/iin-agent/src/fabric-ledger/networkUtils.ts @@ -0,0 +1,117 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Gateway } from 'fabric-network'; +import * as path from 'path'; +import * as fs from 'fs'; +import { getWallet } from './walletUtils'; + +// Get a handle to a network gateway using existing wallet credentials +const getNetworkGateway = async ( + walletPath: string, + connectionProfilePath: string, + configFilePath: string +): Promise => { + try { + // load the network configuration + if (!fs.existsSync(connectionProfilePath)) { + throw new Error('Connection profile does not exist at path: ' + connectionProfilePath); + } + const ccp = JSON.parse(fs.readFileSync(connectionProfilePath, 'utf8').toString()); + if (!fs.existsSync(configFilePath)) { + throw new Error('Config does not exist at path: ' + configFilePath); + } + const config = JSON.parse(fs.readFileSync(configFilePath, 'utf8').toString()); + + // Create a new file system-based wallet for managing identities. + const userName = config.agent.name; + const wallet = await getWallet(walletPath); + console.log(`Wallet path: ${walletPath}`); + // Check to see if we've already enrolled the user. + const identity = await wallet.get(userName); + if (!identity) { + console.log(`An identity for the user "${userName}.com" does not exist in the wallet`); + console.log('Run the registerUser.ts application before retrying'); + } + // Create a new gateway for connecting to our peer node. + const gateway = new Gateway(); + await gateway.connect(ccp, { + wallet, + identity: `${userName}`, + discovery: { enabled: true, asLocalhost: process.env.local === 'false' ? false : true }, + }); + return gateway; + } catch (error) { + console.error(`Failed to instantiate network (channel): ${error}`); + throw error; + } +} + +// Get a handle to a network gateway using existing wallet credentials +const getNetworkContract = async ( + walletPath: string, + connectionProfilePath: string, + configFilePath: string, + channelId: string, + chaincodeId: string, +): Promise => { + try { + const gateway = await getNetworkGateway(walletPath, connectionProfilePath, configFilePath); + if (!gateway) { + throw new Error('Unable to connect to the ledger!'); + } + const network = await gateway.getNetwork(channelId); + const contract = network.getContract(chaincodeId); + return { gateway: gateway, contract: contract }; + } catch (error) { + console.error(`Failed to connect to contract: ${error}`); + throw error; + } +} + +async function invokeFabricChaincode( + walletPath: string, + connectionProfilePath: string, + configFilePath: string, + channelId: string, + chaincodeId: string, + functionName: string, + args: Array, +): Promise { + console.log('Running invocation on Fabric channel and chaincode'); + try { + const gatewayAndContract = await getNetworkContract(walletPath, connectionProfilePath, configFilePath, channelId, chaincodeId); + await gatewayAndContract.contract.submitTransaction(functionName, ...args); + // Disconnect from the gateway. + gatewayAndContract.gateway.disconnect(); + } catch (error) { + console.error(`Failed to submit transaction: ${error}`); + throw error; + } +} + +async function queryFabricChaincode( + walletPath: string, + connectionProfilePath: string, + configFilePath: string, + channelId: string, + chaincodeId: string, + functionName: string, + args: Array, +): Promise { + console.log('Running query on Fabric channel and chaincode'); + try { + const gatewayAndContract = await getNetworkContract(walletPath, connectionProfilePath, configFilePath, channelId, chaincodeId); + const result = await gatewayAndContract.contract.evaluateTransaction(functionName, ...args); + // Disconnect from the gateway. + gatewayAndContract.gateway.disconnect(); + } catch (error) { + console.error(`Failed to submit query: ${error}`); + throw error; + } +} + +export { getNetworkGateway, getNetworkContract, invokeFabricChaincode, queryFabricChaincode }; diff --git a/core/identity-management/iin-agent/src/fabric-ledger/walletUtils.ts b/core/identity-management/iin-agent/src/fabric-ledger/walletUtils.ts new file mode 100644 index 000000000..57d4a8a76 --- /dev/null +++ b/core/identity-management/iin-agent/src/fabric-ledger/walletUtils.ts @@ -0,0 +1,101 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Wallets } from 'fabric-network'; +import FabricCAServices from 'fabric-ca-client'; +import * as path from 'path'; +import * as fs from 'fs'; + +const getWallet = async (walletPath: string) => { + return await Wallets.newFileSystemWallet(walletPath); +}; + +const walletSetup = async (walletPath: string, conn_profile_path: string, config_file_path: string, networkName: string): Promise => { + if (!fs.existsSync(conn_profile_path)) { + throw new Error('Connection profile does not exist at path: ' + conn_profile_path); + } + const ccp = JSON.parse(fs.readFileSync(conn_profile_path, 'utf8').toString()); + if (!fs.existsSync(config_file_path)) { + throw new Error('Config does not exist at path: ' + config_file_path); + } + const config = JSON.parse(fs.readFileSync(config_file_path, 'utf8').toString()); + // Create a new CA client for interacting with the CA. + const org = ccp.client["organization"]; + console.log('Org', org); + const caName = ccp.organizations[org]["certificateAuthorities"][0]; + console.log('CA Name', caName); + const caURL = config.caUrl ? config.caUrl : ccp.certificateAuthorities[caName].url; + console.log('CA URL', caURL); + const ca = new FabricCAServices(caURL); + const ident = ca.newIdentityService(); + + const wallet = await getWallet(walletPath); + const adminName = config.admin.name; + const adminSecret = config.admin.secret; + // build a user object for authenticating with the CA // Check to see if we've already enrolled the admin user. + let adminIdentity = await wallet.get(adminName); + + if (adminIdentity) { + console.log('An identity for the admin user "admin" already exists in the wallet'); + } else { + // Enroll the admin user, and import the new identity into the wallet. + console.log('Enrolling Admin...', adminName, adminSecret); + const enrollment = await ca.enroll({ + enrollmentID: adminName, + enrollmentSecret: adminSecret, + }); + const x509Identity = { + credentials: { + certificate: enrollment.certificate, + privateKey: enrollment.key.toBytes(), + }, + mspId: config.mspId, + type: 'X.509', + }; + await wallet.put(adminName, x509Identity); + adminIdentity = await wallet.get(adminName); + } + if (adminIdentity) { + console.log(`Creating ${config.agent.name} Identity`); + const provider = wallet.getProviderRegistry().getProvider(adminIdentity.type); + const adminUser = await provider.getUserContext(adminIdentity, adminName); + const identity = await wallet.get(config.agent.name); + if (!identity) { + const secret = await ca.register( + { + affiliation: config.agent.affiliation, + enrollmentID: config.agent.name, + role: config.agent.role, + attrs: config.agent.attrs, + }, + adminUser, + ); + const enrollment = await ca.enroll({ + enrollmentID: config.agent.name, + enrollmentSecret: secret, + }); + const x509Identity = { + credentials: { + certificate: enrollment.certificate, + privateKey: enrollment.key.toBytes(), + }, + mspId: config.mspId, + type: 'X.509', + }; + await wallet.put(config.agent.name, x509Identity); + console.log(`${config.agent.name} Identity Created`); + } else { + console.log(`${config.agent.name} Identity Already exists`); + } + + return wallet; + } else { + console.error('Admin was not registered'); + throw new Error('Admin was not registered'); + } +}; + +export { getWallet, walletSetup }; From f6ed229b495850557489f2f68daa6339a3e37a40 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Sun, 21 Aug 2022 19:02:03 +0000 Subject: [PATCH 100/150] Added security domain membership extraction functions in IIN Agent Signed-off-by: VRamakrishna --- .../iin-agent/src/common/ledgerBase.ts | 8 +- .../iin-agent/src/fabric-ledger/config.json | 1 + .../iin-agent/src/fabric-ledger/connector.ts | 14 +++- .../src/fabric-ledger/networkUtils.ts | 84 ++++++++++++++++++- 4 files changed, 103 insertions(+), 4 deletions(-) diff --git a/core/identity-management/iin-agent/src/common/ledgerBase.ts b/core/identity-management/iin-agent/src/common/ledgerBase.ts index f6804acb4..0915aed03 100644 --- a/core/identity-management/iin-agent/src/common/ledgerBase.ts +++ b/core/identity-management/iin-agent/src/common/ledgerBase.ts @@ -25,12 +25,18 @@ export class LedgerBase { async setupWalletIdentity() { } + // Collect security domain membership info + async getSecurityDomainMembership(): Promise { + return {}; + } + // Invoke a contract to drive a transaction // TODO: Add parameters corresponding to the output of a flow among IIN agents async invokeContract() { } // Query a contract to fetch information from the ledger - async queryContract() { + async queryContract(): Promise { + return ""; } } diff --git a/core/identity-management/iin-agent/src/fabric-ledger/config.json b/core/identity-management/iin-agent/src/fabric-ledger/config.json index d8274b8a1..f243fb64b 100644 --- a/core/identity-management/iin-agent/src/fabric-ledger/config.json +++ b/core/identity-management/iin-agent/src/fabric-ledger/config.json @@ -10,5 +10,6 @@ "attrs": [{ "name": "iin-agent", "value": "true", "ecert": true }] }, "mspId":"Org1MSP", + "ordererMspIds": ["OrdererMSP"], "caUrl":"" } diff --git a/core/identity-management/iin-agent/src/fabric-ledger/connector.ts b/core/identity-management/iin-agent/src/fabric-ledger/connector.ts index 94e349dc3..d08cc80b2 100644 --- a/core/identity-management/iin-agent/src/fabric-ledger/connector.ts +++ b/core/identity-management/iin-agent/src/fabric-ledger/connector.ts @@ -7,7 +7,7 @@ import { Contract } from 'fabric-network'; import { LedgerBase } from '../common/ledgerBase'; import { walletSetup } from './walletUtils'; -import { invokeFabricChaincode, queryFabricChaincode } from './networkUtils'; +import { getAllMSPConfigurations, invokeFabricChaincode, queryFabricChaincode } from './networkUtils'; import * as path from 'path'; import * as fs from 'fs'; @@ -35,6 +35,16 @@ export class FabricConnector extends LedgerBase { walletSetup(this.walletPath, this.connectionProfilePath, this.configFilePath, this.networkId); } + // Collect security domain membership info + async getSecurityDomainMembership(): Promise { + const memberships = getAllMSPConfigurations(this.walletPath, this.connectionProfilePath, this.configFilePath, this.ledgerId); + const securityDomainInfo = { + securityDomain: this.networkId, + members: memberships, + } + return securityDomainInfo; + } + // Invoke a contract to drive a transaction // TODO: Add parameters corresponding to the output of a flow among IIN agents async invokeContract() { @@ -42,7 +52,7 @@ export class FabricConnector extends LedgerBase { } // Query a contract to fetch information from the ledger - async queryContract() { + async queryContract(): Promise { const result = await queryFabricChaincode(this.walletPath, this.connectionProfilePath, this.configFilePath, this.ledgerId, this.contractId, "", []); return result; } diff --git a/core/identity-management/iin-agent/src/fabric-ledger/networkUtils.ts b/core/identity-management/iin-agent/src/fabric-ledger/networkUtils.ts index 0c0d8dde7..24328cd03 100644 --- a/core/identity-management/iin-agent/src/fabric-ledger/networkUtils.ts +++ b/core/identity-management/iin-agent/src/fabric-ledger/networkUtils.ts @@ -5,6 +5,7 @@ */ import { Gateway } from 'fabric-network'; +import { Channel } from 'fabric-common'; import * as path from 'path'; import * as fs from 'fs'; import { getWallet } from './walletUtils'; @@ -72,6 +73,87 @@ const getNetworkContract = async ( } } +function getMembershipUnit(channel: Channel, mspId: string) { + const mspConfig = channel.getMsp(mspId); + let certs = []; + if (Array.isArray(mspConfig.rootCerts)) { + for (let i = 0; i < mspConfig.rootCerts.length; i++) { + certs.push(mspConfig.rootCerts[i]); + } + } else if (mspConfig.rootCerts.length !== 0) { + certs.push(mspConfig.rootCerts); + } + if (Array.isArray(mspConfig.intermediateCerts)) { + for (let i = 0; i < mspConfig.intermediateCerts.length; i++) { + certs.push(mspConfig.intermediateCerts[i]); + } + } else if (mspConfig.intermediateCerts.length !== 0) { + certs.push(mspConfig.intermediateCerts); + } + let membershipUnit: {[key:string]: object} = {}; + membershipUnit[mspId] = { + type: "certificate", + value: "", + chain: certs, + }; + return membershipUnit; +} + +async function getMSPConfiguration( + walletPath: string, + connectionProfilePath: string, + configFilePath: string, + channelId: string, +): Promise { + console.log('Running invocation on Fabric channel and chaincode'); + try { + const gateway = await getNetworkGateway(walletPath, connectionProfilePath, configFilePath); + if (!gateway) { + throw new Error('Unable to connect to the ledger!'); + } + const network = await gateway.getNetwork(channelId); + const config = JSON.parse(fs.readFileSync(configFilePath, 'utf8').toString()); + const membership = getMembershipUnit(network.getChannel(), config.mspId); + // Disconnect from the gateway. + gateway.disconnect(); + return membership; + } catch (error) { + console.error(`Failed to submit transaction: ${error}`); + throw error; + } +} + +async function getAllMSPConfigurations( + walletPath: string, + connectionProfilePath: string, + configFilePath: string, + channelId: string, +): Promise { + console.log('Running invocation on Fabric channel and chaincode'); + try { + const gateway = await getNetworkGateway(walletPath, connectionProfilePath, configFilePath); + if (!gateway) { + throw new Error('Unable to connect to the ledger!'); + } + const network = await gateway.getNetwork(channelId); + const config = JSON.parse(fs.readFileSync(configFilePath, 'utf8').toString()); + const mspIds = network.getChannel().getMspids(); + let memberships: {[key:string]: object} = {}; + for (let i = 0 ; i < mspIds.length ; i++) { + if (!config.ordererMspIds.includes(mspIds[i])) { + const membership = getMembershipUnit(network.getChannel(), config.mspId); + memberships[mspIds[i]] = membership[mspIds[i]]; + } + } + // Disconnect from the gateway. + gateway.disconnect(); + return memberships; + } catch (error) { + console.error(`Failed to submit transaction: ${error}`); + throw error; + } +} + async function invokeFabricChaincode( walletPath: string, connectionProfilePath: string, @@ -114,4 +196,4 @@ async function queryFabricChaincode( } } -export { getNetworkGateway, getNetworkContract, invokeFabricChaincode, queryFabricChaincode }; +export { getNetworkGateway, getNetworkContract, getMSPConfiguration, getAllMSPConfigurations, invokeFabricChaincode, queryFabricChaincode }; From 0a16bc3aeea71cd74502607077f09ed961e5f815 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Mon, 22 Aug 2022 18:05:26 +0000 Subject: [PATCH 101/150] Updated and refactored security domain membership handling logic in Fabric Interop Chaincode Signed-off-by: VRamakrishna --- .../contracts/interop/certificate_utils.go | 2 +- .../interop/handle_external_request.go | 2 +- .../contracts/interop/membership.go | 42 +++++++++++++++---- .../contracts/interop/membership_test.go | 7 ++-- .../contracts/interop/write_external_state.go | 4 +- 5 files changed, 42 insertions(+), 15 deletions(-) diff --git a/core/network/fabric-interop-cc/contracts/interop/certificate_utils.go b/core/network/fabric-interop-cc/contracts/interop/certificate_utils.go index bf2d2270c..2f7218e25 100644 --- a/core/network/fabric-interop-cc/contracts/interop/certificate_utils.go +++ b/core/network/fabric-interop-cc/contracts/interop/certificate_utils.go @@ -112,7 +112,7 @@ func verifyCertificateChain(cert *x509.Certificate, certPEMs []string) error { errMsg := fmt.Sprintf("Certificate link for Subject %s with Parent Subject %s invalid", caCert.Subject.String(), parentCert.Subject.String()) return errors.New(errMsg) } - if i == len(certPEMs)-1 { + if i == len(certPEMs)-1 && cert != nil { err := validateCertificateUsingCA(cert, caCert, i == 1) if err != nil { return errors.New("Certificate link invalid for endorser") diff --git a/core/network/fabric-interop-cc/contracts/interop/handle_external_request.go b/core/network/fabric-interop-cc/contracts/interop/handle_external_request.go index 240cf24ef..d53472ce8 100644 --- a/core/network/fabric-interop-cc/contracts/interop/handle_external_request.go +++ b/core/network/fabric-interop-cc/contracts/interop/handle_external_request.go @@ -106,7 +106,7 @@ func handleRequest(s *SmartContract, ctx contractapi.TransactionContextInterface query.RequestingOrg = x509Cert.Issuer.Organization[0] } - err = verifyMemberInSecurityDomain(s, ctx, x509Cert, query.RequestingNetwork, query.RequestingOrg) + err = verifyMemberInSecurityDomain(s, ctx, query.Certificate, query.RequestingNetwork, query.RequestingOrg) if err != nil { return "", logThenErrorf("Membership Verification failed: %s", err) } diff --git a/core/network/fabric-interop-cc/contracts/interop/membership.go b/core/network/fabric-interop-cc/contracts/interop/membership.go index b217bc198..0c0170a17 100644 --- a/core/network/fabric-interop-cc/contracts/interop/membership.go +++ b/core/network/fabric-interop-cc/contracts/interop/membership.go @@ -9,22 +9,38 @@ package main import ( - "crypto/x509" "encoding/json" "fmt" "github.com/hyperledger/fabric-contract-api-go/contractapi" + "github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go/common" ) const membershipObjectType = "membership" +func validateMemberCertChains(members map[string]*common.Member, securityDomain string) error { + for member, creds := range members { + if len(creds.Chain) > 1 { + err := verifyCertificateChain(nil, creds.Chain) + if err != nil { + return fmt.Errorf("Certificate chain corresponding to member %s in security domain %s is invalid: %s", member, securityDomain, err) + } + } + } + return nil +} + // CreateMembership cc is used to store a Membership in the ledger -// TODO: Should we check here if certificates are valid func (s *SmartContract) CreateMembership(ctx contractapi.TransactionContextInterface, membershipJSON string) error { membership, err := decodeMembership([]byte(membershipJSON)) if err != nil { return fmt.Errorf("Unmarshal error: %s", err) } + // Check if certificates chains in this membership record are valid + err = validateMemberCertChains(membership.Members, membership.SecurityDomain) + if err != nil { + return err + } membershipKey, err := ctx.GetStub().CreateCompositeKey(membershipObjectType, []string{membership.SecurityDomain}) acp, getErr := ctx.GetStub().GetState(membershipKey) if getErr != nil { @@ -47,6 +63,11 @@ func (s *SmartContract) UpdateMembership(ctx contractapi.TransactionContextInter if err != nil { return fmt.Errorf("Unmarshal error: %s", err) } + // Check if certificates chains in this membership record are valid + err = validateMemberCertChains(membership.Members, membership.SecurityDomain) + if err != nil { + return err + } membershipKey, err := ctx.GetStub().CreateCompositeKey(membershipObjectType, []string{membership.SecurityDomain}) _, getErr := s.GetMembershipBySecurityDomain(ctx, membership.SecurityDomain) if getErr != nil { @@ -96,8 +117,12 @@ func (s *SmartContract) GetMembershipBySecurityDomain(ctx contractapi.Transactio // verifyMemberInSecurityDomain function verifies the identity of the requester according to // the Membership for the external network the request originated from. -func verifyMemberInSecurityDomain(s *SmartContract, ctx contractapi.TransactionContextInterface, cert *x509.Certificate, securityDomain string, requestingOrg string) error { - err := isCertificateWithinExpiry(cert) +func verifyMemberInSecurityDomain(s *SmartContract, ctx contractapi.TransactionContextInterface, certPEM string, securityDomain string, requestingOrg string) error { + cert, err := parseCert(certPEM) + if err != nil { + return fmt.Errorf("Unable to parse certificate: %s", err.Error()) + } + err = isCertificateWithinExpiry(cert) if err != nil { return err } @@ -115,10 +140,11 @@ func verifyMemberInSecurityDomain(s *SmartContract, ctx contractapi.TransactionC } switch member.Type { case "ca": - // TODO: Add check for if cert and member.Value are the same verifyCaCertificate(cert, member.Value, true) - err := verifyCaCertificate(cert, member.Value) - if err != nil { - return err + if certPEM != member.Value { // The CA is automatically a member of the security domain + err := verifyCaCertificate(cert, member.Value) + if err != nil { + return err + } } case "certificate": chain := member.Chain diff --git a/core/network/fabric-interop-cc/contracts/interop/membership_test.go b/core/network/fabric-interop-cc/contracts/interop/membership_test.go index c3a457f66..f7d3bdf5b 100644 --- a/core/network/fabric-interop-cc/contracts/interop/membership_test.go +++ b/core/network/fabric-interop-cc/contracts/interop/membership_test.go @@ -136,6 +136,7 @@ func TestVerifyMembership(t *testing.T) { // convert pem cert to x509 cert x509Cert, err := parseCert(string(pemCert)) require.NoError(t, err) + require.NotNil(t, x509Cert) // make membership var member = common.Member{ @@ -155,11 +156,11 @@ func TestVerifyMembership(t *testing.T) { // Test: Happy case chaincodeStub.GetStateReturns(membershipBytes, nil) - err = verifyMemberInSecurityDomain(&interopcc, ctx, x509Cert, "test", "member1") + err = verifyMemberInSecurityDomain(&interopcc, ctx, string(pemCert), "test", "member1") require.NoError(t, err) // Test: Unknown requesting Org - err = verifyMemberInSecurityDomain(&interopcc, ctx, x509Cert, "test", "unknown_member") + err = verifyMemberInSecurityDomain(&interopcc, ctx, string(pemCert), "test", "unknown_member") require.EqualError(t, err, "Member does not exist for org: unknown_member") // Test: Unknown cert type @@ -167,6 +168,6 @@ func TestVerifyMembership(t *testing.T) { membershipBytes, err = json.Marshal(&membershipAsset) require.NoError(t, err) chaincodeStub.GetStateReturns(membershipBytes, nil) - err = verifyMemberInSecurityDomain(&interopcc, ctx, x509Cert, "test", "member1") + err = verifyMemberInSecurityDomain(&interopcc, ctx, string(pemCert), "test", "member1") require.EqualError(t, err, "Certificate type not supported: unknown") } diff --git a/core/network/fabric-interop-cc/contracts/interop/write_external_state.go b/core/network/fabric-interop-cc/contracts/interop/write_external_state.go index 474118c63..aa5a93a70 100644 --- a/core/network/fabric-interop-cc/contracts/interop/write_external_state.go +++ b/core/network/fabric-interop-cc/contracts/interop/write_external_state.go @@ -248,7 +248,7 @@ func verifyCordaNotarization(s *SmartContract, ctx contractapi.TransactionContex } signerList = append(signerList, value.Id) // 4. Check the certificates are valid according to the Membership. - err = verifyMemberInSecurityDomain(s, ctx, x509Cert, securityDomain, value.Id) + err = verifyMemberInSecurityDomain(s, ctx, value.Certificate, securityDomain, value.Id) if err != nil { return fmt.Errorf("Verify membership failed. Certificate not valid: %s", err.Error()) } @@ -312,7 +312,7 @@ func verifyFabricNotarization(s *SmartContract, ctx contractapi.TransactionConte } org := serialisedIdentity.Mspid // 4. Check each of the endorser certificates matches the member's entry in the network's Membership. - err = verifyMemberInSecurityDomain(s, ctx, x509Cert, securityDomain, org) + err = verifyMemberInSecurityDomain(s, ctx, string(serialisedIdentity.IdBytes), securityDomain, org) if err != nil { return fmt.Errorf("Verify membership failed. Certificate not valid: %s", err.Error()) } From b01bb54e391b9d4fed2cb471e80853539b6c92ca Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Thu, 25 Aug 2022 12:21:08 +0000 Subject: [PATCH 102/150] Updated IIN Agent specifications Updated RFC models and formats. Made a small change to the IIN Agent protobuf service definition. Updated code based on change in protobuf. Signed-off-by: VRamakrishna --- common/protos-go/identity/agent.pb.go | 64 ++--- common/protos-go/identity/agent_grpc.pb.go | 40 --- common/protos/identity/agent.proto | 3 - .../src/protocols/localOperations.ts | 5 - .../iin-agent/src/server.ts | 23 +- rfcs/formats/network/identity.md | 87 +++--- .../models/identity/identity-update-policy.md | 76 ++--- rfcs/models/identity/iin-agent.md | 101 ++++--- rfcs/models/identity/iin.md | 15 +- .../identity/network-identity-management.md | 265 +++++++++--------- rfcs/models/infrastructure/relays.md | 4 +- rfcs/protocols/discovery/discovery.md | 6 +- rfcs/resources/images/identity-sync.png | Bin 0 -> 119899 bytes rfcs/resources/images/iin-agent-interface.png | Bin 0 -> 29923 bytes .../iin-agent-model-dlt-destination.png | Bin 0 -> 90504 bytes .../images/iin-agent-model-dlt-source.png | Bin 0 -> 41720 bytes .../images/iin-augmented-network.jpg | Bin 120095 -> 120075 bytes rfcs/resources/images/security-domain.png | Bin 42855 -> 22036 bytes 18 files changed, 317 insertions(+), 372 deletions(-) create mode 100755 rfcs/resources/images/identity-sync.png create mode 100755 rfcs/resources/images/iin-agent-interface.png create mode 100755 rfcs/resources/images/iin-agent-model-dlt-destination.png create mode 100755 rfcs/resources/images/iin-agent-model-dlt-source.png diff --git a/common/protos-go/identity/agent.pb.go b/common/protos-go/identity/agent.pb.go index 1872c0222..51069e0d9 100644 --- a/common/protos-go/identity/agent.pb.go +++ b/common/protos-go/identity/agent.pb.go @@ -362,7 +362,7 @@ var file_identity_agent_proto_rawDesc = []byte{ 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x74, - 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0xf7, 0x03, 0x0a, 0x08, 0x49, + 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0xa2, 0x03, 0x0a, 0x08, 0x49, 0x49, 0x4e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x4b, 0x0a, 0x11, 0x53, 0x79, 0x6e, 0x63, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x23, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x65, @@ -379,30 +379,24 @@ var file_identity_agent_proto_rawDesc = []byte{ 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, - 0x12, 0x53, 0x0a, 0x19, 0x46, 0x6c, 0x6f, 0x77, 0x41, 0x6e, 0x64, 0x52, 0x65, 0x63, 0x6f, 0x72, - 0x64, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x23, 0x2e, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4e, - 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x55, 0x6e, 0x69, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, - 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x2e, 0x69, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, - 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, - 0x61, 0x69, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, - 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x74, - 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x2e, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, - 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, - 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, - 0x63, 0x6b, 0x22, 0x00, 0x42, 0x75, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, - 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5a, 0x51, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, - 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, - 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, - 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, - 0x67, 0x6f, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x12, 0x4f, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x74, 0x74, 0x65, 0x73, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, + 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x0f, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, + 0x00, 0x12, 0x4c, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, + 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, + 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, + 0x75, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x5a, 0x51, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, + 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -438,17 +432,15 @@ var file_identity_agent_proto_depIdxs = []int32{ 0, // 7: identity.agent.IINAgent.SyncExternalState:input_type -> identity.agent.NetworkUnitIdentity 0, // 8: identity.agent.IINAgent.RequestIdentityConfiguration:input_type -> identity.agent.NetworkUnitIdentity 2, // 9: identity.agent.IINAgent.SendIdentityConfiguration:input_type -> identity.agent.AttestedMembership - 0, // 10: identity.agent.IINAgent.FlowAndRecordAttestations:input_type -> identity.agent.NetworkUnitIdentity - 3, // 11: identity.agent.IINAgent.RequestAttestation:input_type -> identity.agent.AttestedSecurityDomain - 3, // 12: identity.agent.IINAgent.SendAttestation:input_type -> identity.agent.AttestedSecurityDomain - 6, // 13: identity.agent.IINAgent.SyncExternalState:output_type -> common.ack.Ack - 6, // 14: identity.agent.IINAgent.RequestIdentityConfiguration:output_type -> common.ack.Ack - 6, // 15: identity.agent.IINAgent.SendIdentityConfiguration:output_type -> common.ack.Ack - 6, // 16: identity.agent.IINAgent.FlowAndRecordAttestations:output_type -> common.ack.Ack - 6, // 17: identity.agent.IINAgent.RequestAttestation:output_type -> common.ack.Ack - 6, // 18: identity.agent.IINAgent.SendAttestation:output_type -> common.ack.Ack - 13, // [13:19] is the sub-list for method output_type - 7, // [7:13] is the sub-list for method input_type + 3, // 10: identity.agent.IINAgent.RequestAttestation:input_type -> identity.agent.AttestedSecurityDomain + 3, // 11: identity.agent.IINAgent.SendAttestation:input_type -> identity.agent.AttestedSecurityDomain + 6, // 12: identity.agent.IINAgent.SyncExternalState:output_type -> common.ack.Ack + 6, // 13: identity.agent.IINAgent.RequestIdentityConfiguration:output_type -> common.ack.Ack + 6, // 14: identity.agent.IINAgent.SendIdentityConfiguration:output_type -> common.ack.Ack + 6, // 15: identity.agent.IINAgent.RequestAttestation:output_type -> common.ack.Ack + 6, // 16: identity.agent.IINAgent.SendAttestation:output_type -> common.ack.Ack + 12, // [12:17] is the sub-list for method output_type + 7, // [7:12] is the sub-list for method input_type 7, // [7:7] is the sub-list for extension type_name 7, // [7:7] is the sub-list for extension extendee 0, // [0:7] is the sub-list for field type_name diff --git a/common/protos-go/identity/agent_grpc.pb.go b/common/protos-go/identity/agent_grpc.pb.go index 6cc94634a..7dcfa1c96 100644 --- a/common/protos-go/identity/agent_grpc.pb.go +++ b/common/protos-go/identity/agent_grpc.pb.go @@ -25,9 +25,6 @@ type IINAgentClient interface { RequestIdentityConfiguration(ctx context.Context, in *NetworkUnitIdentity, opts ...grpc.CallOption) (*common.Ack, error) // Handling network unit's state sent by a foreign IIN agent. SendIdentityConfiguration(ctx context.Context, in *AttestedMembership, opts ...grpc.CallOption) (*common.Ack, error) - // user or agent triggers a flow to collect signatures attesting an - // external/foreign network unit's state and recording to ledger - FlowAndRecordAttestations(ctx context.Context, in *NetworkUnitIdentity, opts ...grpc.CallOption) (*common.Ack, error) // Requesting attestation from a local IIN agent. RequestAttestation(ctx context.Context, in *AttestedSecurityDomain, opts ...grpc.CallOption) (*common.Ack, error) // Handling attestation sent by a local IIN agent. @@ -69,15 +66,6 @@ func (c *iINAgentClient) SendIdentityConfiguration(ctx context.Context, in *Atte return out, nil } -func (c *iINAgentClient) FlowAndRecordAttestations(ctx context.Context, in *NetworkUnitIdentity, opts ...grpc.CallOption) (*common.Ack, error) { - out := new(common.Ack) - err := c.cc.Invoke(ctx, "/identity.agent.IINAgent/FlowAndRecordAttestations", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *iINAgentClient) RequestAttestation(ctx context.Context, in *AttestedSecurityDomain, opts ...grpc.CallOption) (*common.Ack, error) { out := new(common.Ack) err := c.cc.Invoke(ctx, "/identity.agent.IINAgent/RequestAttestation", in, out, opts...) @@ -106,9 +94,6 @@ type IINAgentServer interface { RequestIdentityConfiguration(context.Context, *NetworkUnitIdentity) (*common.Ack, error) // Handling network unit's state sent by a foreign IIN agent. SendIdentityConfiguration(context.Context, *AttestedMembership) (*common.Ack, error) - // user or agent triggers a flow to collect signatures attesting an - // external/foreign network unit's state and recording to ledger - FlowAndRecordAttestations(context.Context, *NetworkUnitIdentity) (*common.Ack, error) // Requesting attestation from a local IIN agent. RequestAttestation(context.Context, *AttestedSecurityDomain) (*common.Ack, error) // Handling attestation sent by a local IIN agent. @@ -129,9 +114,6 @@ func (UnimplementedIINAgentServer) RequestIdentityConfiguration(context.Context, func (UnimplementedIINAgentServer) SendIdentityConfiguration(context.Context, *AttestedMembership) (*common.Ack, error) { return nil, status.Errorf(codes.Unimplemented, "method SendIdentityConfiguration not implemented") } -func (UnimplementedIINAgentServer) FlowAndRecordAttestations(context.Context, *NetworkUnitIdentity) (*common.Ack, error) { - return nil, status.Errorf(codes.Unimplemented, "method FlowAndRecordAttestations not implemented") -} func (UnimplementedIINAgentServer) RequestAttestation(context.Context, *AttestedSecurityDomain) (*common.Ack, error) { return nil, status.Errorf(codes.Unimplemented, "method RequestAttestation not implemented") } @@ -205,24 +187,6 @@ func _IINAgent_SendIdentityConfiguration_Handler(srv interface{}, ctx context.Co return interceptor(ctx, in, info, handler) } -func _IINAgent_FlowAndRecordAttestations_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(NetworkUnitIdentity) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(IINAgentServer).FlowAndRecordAttestations(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/identity.agent.IINAgent/FlowAndRecordAttestations", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(IINAgentServer).FlowAndRecordAttestations(ctx, req.(*NetworkUnitIdentity)) - } - return interceptor(ctx, in, info, handler) -} - func _IINAgent_RequestAttestation_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(AttestedSecurityDomain) if err := dec(in); err != nil { @@ -278,10 +242,6 @@ var IINAgent_ServiceDesc = grpc.ServiceDesc{ MethodName: "SendIdentityConfiguration", Handler: _IINAgent_SendIdentityConfiguration_Handler, }, - { - MethodName: "FlowAndRecordAttestations", - Handler: _IINAgent_FlowAndRecordAttestations_Handler, - }, { MethodName: "RequestAttestation", Handler: _IINAgent_RequestAttestation_Handler, diff --git a/common/protos/identity/agent.proto b/common/protos/identity/agent.proto index 3c21eef81..5a64a3a26 100644 --- a/common/protos/identity/agent.proto +++ b/common/protos/identity/agent.proto @@ -16,9 +16,6 @@ service IINAgent { rpc RequestIdentityConfiguration(NetworkUnitIdentity) returns (common.ack.Ack){} // Handling network unit's state sent by a foreign IIN agent. rpc SendIdentityConfiguration(AttestedMembership) returns (common.ack.Ack){} - // user or agent triggers a flow to collect signatures attesting an - // external/foreign network unit's state and recording to ledger - rpc FlowAndRecordAttestations(NetworkUnitIdentity) returns (common.ack.Ack) {} // Requesting attestation from a local IIN agent. rpc RequestAttestation(AttestedSecurityDomain) returns (common.ack.Ack){} // Handling attestation sent by a local IIN agent. diff --git a/core/identity-management/iin-agent/src/protocols/localOperations.ts b/core/identity-management/iin-agent/src/protocols/localOperations.ts index 90e44df14..4853236e5 100644 --- a/core/identity-management/iin-agent/src/protocols/localOperations.ts +++ b/core/identity-management/iin-agent/src/protocols/localOperations.ts @@ -8,11 +8,6 @@ import iin_agent_pb from '@hyperledger-labs/weaver-protos-js/identity/agent_pb'; import { handlePromise} from '../common/utils'; -// Runs flows through local IIN agents -export const flowAndRecordAttestationsOnLedger = async (networkUnit: iin_agent_pb.NetworkUnitIdentity) => { - console.log('flowAndRecordAttestationsOnLedger:', networkUnit.getNetworkId(), '-', networkUnit.getParticipantId()); -}; - // Generates attestations on a foreign network unit's state export const requestAttestation = async (attestedSecurityDomain: iin_agent_pb.AttestedSecurityDomain) => { console.log('requestAttestation:'); diff --git a/core/identity-management/iin-agent/src/server.ts b/core/identity-management/iin-agent/src/server.ts index 231f873d2..c32749fe8 100644 --- a/core/identity-management/iin-agent/src/server.ts +++ b/core/identity-management/iin-agent/src/server.ts @@ -13,7 +13,7 @@ import 'dotenv/config'; import { Certificate } from '@fidm/x509'; import * as path from 'path'; import { syncExternalStateFromIINAgent, requestIdentityConfiguration, sendIdentityConfiguration } from './protocols/externalOperations'; -import { flowAndRecordAttestationsOnLedger, requestAttestation, sendAttestation } from './protocols/localOperations'; +import { requestAttestation, sendAttestation } from './protocols/localOperations'; const iinAgentServer = new Server(); @@ -84,27 +84,6 @@ iinAgentServer.addService(iin_agent_pb_grpc.IINAgentService, { callback(null, ack_response); } }, - // Service for starting a flow among local IIN agents to collect attestations on a foreign network unit's state. Will communicate with the user/agent triggering this process and respond with an ack to the caller while the flow is occurring. - flowAndRecordAttestations: (call: { request: iin_agent_pb.NetworkUnitIdentity }, callback: (_: any, object: ack_pb.Ack) => void) => { - const ack_response = new ack_pb.Ack(); - try { - flowAndRecordAttestationsOnLedger(call.request); - ack_response.setMessage(''); - ack_response.setStatus(ack_pb.Ack.STATUS.OK); - ack_response.setRequestId(''); - // gRPC response. - console.log('Responding to caller'); - callback(null, ack_response); - } catch (e) { - console.log(e); - ack_response.setMessage(`Error: ${e}`); - ack_response.setStatus(ack_pb.Ack.STATUS.ERROR); - ack_response.setRequestId(''); - // gRPC response. - console.log('Responding to caller'); - callback(null, ack_response); - } - }, // Service for receiving requests for attestations on foreign network unit states from local IIN agents. Will communicate with the IIN agent caller and respond with an ack while the attestation is being generated. requestAttestation: (call: { request: iin_agent_pb.AttestedSecurityDomain }, callback: (_: any, object: ack_pb.Ack) => void) => { const ack_response = new ack_pb.Ack(); diff --git a/rfcs/formats/network/identity.md b/rfcs/formats/network/identity.md index 08193970a..4d76cbda3 100644 --- a/rfcs/formats/network/identity.md +++ b/rfcs/formats/network/identity.md @@ -8,13 +8,13 @@ - RFC: 03-012 - Authors: Bishakh Chandra Ghosh, Venkatraman Ramakrishna, Krishnasuri Narayanam, Ermyas Abebe - Status: Proposed -- Since: 24-Sep-2021 +- Since: 25-Aug-2022 -## Participant Unit Identity +## Organizational Unit Identity -Each network participant (Fabric organizations / Corda node owners) has its identity on the identity plane as *Participant Unit Identity*, in the form of a **DID**. We also refer to it as *Participant Unit DID*. -The participant DID Document must specify one verification method with [authentication](https://w3c.github.io/did-core/#authentication) verification relationship. The *Participant Unit DID* must be registered in some IIN registry which is public and openly accessible for DID and VC validations. +Each network member (Fabric organizations, Corda node owners, etc.) has an *Organizational Unit DID* epresenting its identity in the identity plane. +This DID document must specify one verification method with [authentication](https://w3c.github.io/did-core/#authentication) verification relationship. The *Organizational Unit DID* must be registered in some IIN registry which is public and openly accessible for DID and VC validations. ### Example: @@ -33,61 +33,57 @@ The participant DID Document must specify one verification method with [authenti ``` -## Network Identity +## Security Domain Identity -The identity of a network as a single entity is represented by the *Network Identity* which is a DID called *Network DID*. +The identity of a network as a single entity is represented by the *Security Domain Identity* which is a DID called *Security Domain DID*. -A permissioned blockchain network is formed by mutual agreement among its participants. Participants, whether they be in a Fabric, Corda, or Ethereum network, typically control one or more peers and act as identity providers for those peers and associated clients. In Fabric, the notion of a participant is formalized in the role of an *organization*. The blockchain network as an entity is thus not controlled by any single member but together by its participant units. But inspite of having multiple controllers, the network as an entity must have its own unitary identity, through which it can be discovered. In this specification, each permissioned blockchain network which needs to exchange its identity for interoperation has a Network DID and a corresponding Network DID Document, that we describe in this section. +A permissioned blockchain network is formed by mutual agreement among its members. Whether it be a Fabric, Corda, or Ethereum network, members typically control one or more peers and act as identity providers for those peers and associated clients. In Fabric, the notion of a member is formalized in the role of an *organization*. The blockchain network as an entity is thus not controlled by any single member but rather collectively by several organizational units. But inspite of having multiple controllers, the network as an entity must have its own unitary identity, through which it can be discovered. In this specification, each permissioned blockchain network which needs to exchange its identity for interoperation has a Security Domain DID and a corresponding Security Domain DID Document, that we describe in this section. -A permissioned blockchain network has a Network DID that represents it. -The Network DID document conforms to the [did-core](https://www.w3.org/TR/did-core) specifications. +A permissioned blockchain/DLT network has a Security Domain DID that represents it. +This DID document conforms to the [did-core](https://www.w3.org/TR/did-core) specifications. **id** - This property is mandatory which is the DID URI for the network. This id (DID) can be used to resolve the DID Document of the network from the IIN DID registry. -**verificationMethod** - One verification method property must be present in the Network DID document, and it must be able to support [Group Control](https://www.w3.org/TR/did-core/#group-control), so that the network participant units can jointly control the Network DID Document. Additionally, the verification method must specify who can update the DID in case the network changes as participant units leave and new ones join. This group controlled `verificationMethod` also lets the network participants jointly validate the network's composition. We describe a multi-signature based `verificationMethod` type in the following sections. +**verificationMethod** - One verification method property must be present in the Security Domain DID document, and it must be able to support [Group Control](https://www.w3.org/TR/did-core/#group-control), so that the network members can jointly control the Security Domain DID Document. Additionally, the verification method must specify who can update the DID in case the network changes as members leave and new organizational units join. This group controlled `verificationMethod` also lets the network members jointly validate the network's composition. We describe a multi-signature based `verificationMethod` type in the following sections. -For interoperation in the data plane, network specific identity credentials such as certificates (X.509 certificates in Hyperledger Fabric networks) are required to be configured. For these data plane credentials, there can be optional `verificationMethods` in the Network DID document. For better privacy, without directly exposing the data plane credentials within the Network DID document, only their cryptographic hash may be included which will ensure no rogue network participant can produce tampered data plane credentials to deny/attack the interoperation. +For interoperation in the data plane, network specific identity credentials such as certificates (X.509 certificates in Hyperledger Fabric networks) are required to be configured. For these data plane credentials, there can be optional `verificationMethods` in the Security Domain DID document. For better privacy, without directly exposing the data plane credentials within the Security Domain DID document, only their cryptographic hash may be included which will ensure no rogue network member can produce tampered data plane credentials to deny/attack the interoperation. +**authentication** - The authentication verification relationship must point to the group controlled verification method of the Security Domain DID. -**authentication** - The authentication verification relationship must point to the group controlled verification method of the Network DID. - -**networkParticipants** - This is not a core property of the DID specification. This is a special property required for Network DIDs that specify the members in the network. It is a list of DIDs of the individual members. +**networkMembers** - This is not a core property of the DID specification. This is a special property required for Security Domain DIDs that specify the members in the network. It is a list of DIDs of the individual members. ### Multi-signature based verificationMethod -A network DID must be controlled jointly by the network's participant units for operations such as creation of the DID, and its updation with changing network structure, and for other operations such as rotating/refreshing keys, updating verification methods, etc. To enable this group control, we introduce a `verificationMethod` that uses multi-signatures and associated policies. +A network DID must be controlled jointly by the network's members for operations such as creation of the DID, and its updation with changing network structure, and for other operations such as rotating/refreshing keys, updating verification methods, etc. To enable this group control, we introduce a `verificationMethod` that uses multi-signatures and associated policies. The `verificationMethod` will have the following properties: -**id** - This will be the Network DID followed by a fragment forming a DID URI that points to this verification method. Eg: `did::#unique_verificationMethod_name` +**id** - This will be the Security Domain DID followed by a fragment forming a DID URI that points to this verification method. Eg: `did::#unique_verificationMethod_name` **type** - `BlockchainNetworkMultiSig` -**controller** - Controller of this DID must be the network itself, and thus its value should be same as the Network DID. +**controller** - Controller of this DID must be the network itself, and thus its value should be same as the Security Domain DID. **Verification Material for BlockchainNetworkMultiSig:** -**multisigKeys** - Map of participant DID to its verificationMethod. This contains one entry for each participant unit in `networkParticipants` list. The key is the participant unit's DID, and the value is a DID URI to the verification method of the participant DID. - - -Eg. If `network_participant_1` has a DID `did::`, then `multisigKeys` will contain one verification method of the DID Document like `"did::":"did::#verificationMethod1"` +**multisigKeys** - Map of organizational unit's DID to its verificationMethod. This contains one entry for each network member in the `networkMembers` list. The key is the DID of the organizational unit (corresponding to a network member), and the value is a DID URI to the verification method for that DID. -For creation of Network DID, the IIN registry must authenticate the DID creation request based on the `BlockchainNetworkMultiSig` verification method. This implies that the request must be authenticated based on each of the verificationMethods specified in `multisigKeys`. +Eg. If `network_member_1` has a DID `did::`, then `multisigKeys` will contain one verification method of the DID Document like `"did::":"did::#verificationMethod1"` -> NOTE on extensibility: The `networkParticipants` lets any DID to be specified, with a verification method in `BlockchainNetworkMultiSig.multisigKeys`. Thus another Network DID can also be represented as a participant unit of a network. This can be very useful in certain use cases where different blockchain networks may be stakeholders of a bigger network. +For creation of Security Domain DID, the IIN registry must authenticate the DID creation request based on the `BlockchainNetworkMultiSig` verification method. This implies that the request must be authenticated based on each of the verificationMethods specified in `multisigKeys`. - -**updatePolicy** - Defines a combination of participant units that must sign and authenticate a Network DID updation request. The `updatePolicy` is discussed in detail [here](./../models/identity-update-policy.md). +> NOTE on extensibility: Any kind of DID can be specified in the `networkMembers` list, with a corresponding verification method in `BlockchainNetworkMultiSig.multisigKeys`. Therefore, another Security Domain DID can also be represented as a network member. This can be very useful in use cases where different blockchain networks may be stakeholders of a bigger network, i.e., the networks are linked together in a hierarchy. +**updatePolicy** - Defines a combination of organizational units that must sign and authenticate a Security Domain DID updation request. The `updatePolicy` is discussed in detail [here](../../models/identity/identity-update-policy.md). ### verificationMethod for dataplane credentials -Blockchain interoperation in the data plane by means of verifiable data sharing rely on verification of some format of proofs that comes associated with the data from another network in response to a query ([cryptographic-proofs](https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/rfcs/models/cryptographic-proofs.md)). In proof by notarisation, and also most other proof formats, the foreign blockchain networks' members' cryptographic keys and certificates has to be known for validating the proofs. Therefore, to map these data plane cryptographic certificates to the identity plane, the Network DID may have a verifcation method that contains these directly, or provide pointers to them. +Blockchain interoperation in the data plane by means of verifiable data sharing rely on verification of some format of proofs that comes associated with the data from another network in response to a query ([cryptographic-proofs](https://github.com/hyperledger-labs/weaver-dlt-interoperability/blob/main/rfcs/models/cryptographic-proofs.md)). In proof by notarisation, and also most other proof formats, the foreign blockchain networks' members' cryptographic keys and certificates has to be known for validating the proofs. Therefore, to map these data plane cryptographic certificates to the identity plane, the Security Domain DID may have a verifcation method that contains these directly, or provide pointers to them. Depending on the blockchain platform being used by a network in the data plane, the type of the credentials may vary. This verification policy will have the parameters: @@ -96,43 +92,42 @@ This verification policy will have the parameters: **type** - `DataplaneCredentials` -**controller** - Network DID. +**controller** - Security Domain DID. -**[PLATFORM]Credentials** - Map of participant unit DID to Hash of dataplane platform specific credentials. +**[PLATFORM]Credentials** - Map of organizational unit DID to Hash of dataplane platform specific credentials. PLATFORM is the name of the dataplane platform such as Fabric/Corda/Burrow etc.. In this version we support X.509 certificates for Hyperledger Fabric's root and intermediate certificates. -In Fabric, each participant unit has a Membership Service Provider (MSP) that has a root certificate that can be used to validate proofs in the data plane. Publishing these root certificates in the Network DID directly may reveal the networks participants and thus a privacy concern. Instead, only including the cryptographic hash of the certificates in the Network DID ensures that no participant unit can provide its incorrect certificate towards denial of service attack , while still maintaining privacy. +In a Fabric network, each member has at least one Membership Service Provider (MSP) that has one or more root CA certificates (and optionally intermediate CA certificates) that can be used to validate proofs in the data plane. Publishing these certificates in the Security Domain DID directly may reveal private information about network members and thus raises privacy concerns. Instead, only including the cryptographic hash of the certificates in the Security Domain DID ensures that no organizational unit can provide fake certificates (or [membership info](../membership.md)) while still maintaining the network members' privacy. -Therefore for Fabric, `[PLATFORM]Credentials` will be `FabricCredentials`: Map of participant unit DID to Hash of fabric root certificates of the participant. +Therefore for Fabric, `[PLATFORM]Credentials` will be `FabricCredentials`: Map of organizational unit DID to Hash of the network member's membership info. ### relayEndpoints -This is a special property required for Network DIDs that specify addresses of the [relays](../models/relays.md) in the data plane that can be used for interoperation. It is a list of relayEndpoint objects containing `hostname` and `port` of the relay. - +This is a special property required for Security Domain DIDs that specify addresses of the [relays](../../models/infrastructure/relays.md) in the data plane that can be used for interoperation. It is a list of relayEndpoint objects containing `hostname` and `port` of the relay. -### Example of Network DID format: +### Example of Security Domain DID format: ```json { "id": "did::", - "networkParticipants": [ - "did::", - "did::", - "did::" + "networkMembers": [ + "did::", + "did::", + "did::" ], "verificationMethod": [{ "id": "did::#multisig", "type": "BlockchainNetworkMultiSig", "controller": "did::", "multisigKeys": [ - "did::#key1", - "did::#key3", - "did::#key1" + "did::#key1", + "did::#key3", + "did::#key1" ], "updatePolicy": { "id": "did::#updatepolicy", @@ -142,11 +137,11 @@ This is a special property required for Network DIDs that specify addresses of t "id": "did::#updatepolicy-1", "controller": "did::", "type": "VerifiableCondition2021", - "conditionOr": ["did::#key1", - "did::#key3" + "conditionOr": ["did::#key1", + "did::#key3" ] }, - "did::#key1" + "did::#key1" ] } }, @@ -156,9 +151,9 @@ This is a special property required for Network DIDs that specify addresses of t "type": "DataplaneCredentials", "controller": "did::", "FabricCredentials": { - "did::": "Certificate3_Hash", - "did::": "Certificate2_Hash", - "did::": "Certificate3_Hash" + "did::": "Certificate3_Hash", + "did::": "Certificate2_Hash", + "did::": "Certificate3_Hash" } } ], diff --git a/rfcs/models/identity/identity-update-policy.md b/rfcs/models/identity/identity-update-policy.md index 87f8bb18d..d415edd02 100644 --- a/rfcs/models/identity/identity-update-policy.md +++ b/rfcs/models/identity/identity-update-policy.md @@ -3,20 +3,20 @@ SPDX-License-Identifier: CC-BY-4.0 --> -# Network Identity Update Policies +# Security Domain Identity Update Policies - RFC: 01-015 - Authors: Bishakh Chandra Ghosh, Venkatraman Ramakrishna, Krishnasuri Narayanam, Ermyas Abebe - Status: Proposed -- Since: 24-Sep-2021 +- Since: 25-Aug-2022 ## updatePolicy -The memberships in a blockchain network are not guaranteed to be static. Often existing participant members of a network leave while new participants join. As a result, the `verificationMethod` and `networkParticipants` of the *Network DID* must also be updated to capture the updated network structure. +The memberships in a blockchain network are not guaranteed to be static. Often existing members of a network leave while new organizational units join as members. As a result, the `verificationMethod` and `networkMembers` of the *Security Domain DID* must also be updated to capture the updated network structure. -Based on the different governance policies of different networks, they might want to enforce different policies that dictate which combination of existing participants of the network are allowed to introduce a new member or expel existing members (or acknowledge members who left the network). These policies can be encoded into the `updatePolicy` property of the *BlockchainNetworkMultiSig* `verificationMethod` in the *Network DID*. +Based on the different governance policies of different networks, they might want to enforce different policies that dictate which combination of existing members of the network are allowed to introduce a new member or expel existing members (or acknowledge members who left the network). These policies can be encoded into the `updatePolicy` property of the *BlockchainNetworkMultiSig* `verificationMethod` in the *Security Domain DID*. -`updatePolicy` defines a combination of participant units that can sign and authorize a Network DID updation request. This `updatePolicy` has the condition format as specified in [`verifiablecondition2021`](https://w3c.github.io/did-spec-registries/#verifiablecondition2021) verification method. It can be used to combine different verification methods together to create complex conditional expressions such as logical operations, thresholds, weighted thresholds, relationships and a delegation to external verification methods. +`updatePolicy` defines a combination of organizational units that can sign and authorize a Security Domain DID updation request. This `updatePolicy` has the condition format as specified in [`verifiablecondition2021`](https://w3c.github.io/did-spec-registries/#verifiablecondition2021) verification method. It can be used to combine different verification methods together to create complex conditional expressions such as logical operations, thresholds, weighted thresholds, relationships and a delegation to external verification methods. Example of `updatePolicy`. @@ -29,51 +29,51 @@ Example of `updatePolicy`. "id": "did::#updatepolicy-1", "controller": "did::", "type": "VerifiableCondition2021", - "conditionOr": ["did::#key1", - "did::#key3" + "conditionOr": ["did::#key1", + "did::#key3" ] }, - "did::#key1" + "did::#key1" ] } ``` -## Network DID updates +## Security Domain DID updates -Any request to update the *Network DID* must be authenticated based on different policies for the different scenarios of (i) participants leaving the network, (ii) new participants joining the network, and (iii) other updates to the Network DID. +Any request to update the *Security Domain DID* must be authenticated based on different policies for the different scenarios of (i) members leaving the network, (ii) new organizational units joining the network, and (iii) other updates to the Security Domain DID. -### Participants leaving the network +### Members leaving the network -There can be two scenarios when an existing participant unit of a network leaves: (a) The participant itself willingly leaves the network. (b) Other participants of the network decide to expel that participant. Based on these two scenarios, any *Network DID* update request removing one participant from the `networkParticipants` property is authenticated as per the following conditions: +There can be two scenarios when an existing member of a network leaves: (a) The member itself willingly leaves the network. (b) Other members of the network decide to expel that member. Based on these two scenarios, any *Security Domain DID* update request removing one member from the `networkMembers` property is authenticated as per the following conditions: -A. The *Network DID* update request is attested by the participant who is leaving the network, that is the participant whose DID is being excluded from the `networkParticipants` property. This indicates voluntary exit from the network. +A. The *Security Domain DID* update request is attested by the member who is leaving the network, that is the member whose DID is being excluded from the `networkMembers` property. This indicates voluntary exit from the network. -B. If condition A is not satisfied, then the DID update request must be attested satisfying the `updatePolicy` property of the *BlockchainNetworkMultiSig* `verificationMethod` in the *Network DID*. The update request may also contain a new `updatePolicy` which does not depend on the member that is being removed from the `networkParticipants`. +B. If condition A is not satisfied, then the DID update request must be attested satisfying the `updatePolicy` property of the *BlockchainNetworkMultiSig* `verificationMethod` in the *Security Domain DID*. The update request may also contain a new `updatePolicy` which does not depend on the member that is being removed from the `networkMembers`. -### Participants joining the network +### Organizational Units joining the network -For new network participants joining the network, the DID update request must be authenticated based on `updatePolicy` property of the *BlockchainNetworkMultiSig* `verificationMethod` in the *Network DID*. The DID update request must also be attested by the participant which is being added to the `networkParticipants`. +For new network organizational units joining the network, the DID update request must be authenticated based on `updatePolicy` property of the *BlockchainNetworkMultiSig* `verificationMethod` in the *Security Domain DID*. The DID update request must also be attested by the organizational unit which is being added to the `networkMembers`. -### Other updates to the Network DID +### Other updates to the Security Domain DID -For *Network DID* update requests, where the `networkParticipants` property is not altered, indicating that the participant list is unchanged, the requests are authenticated based on attestations satisfying `updatePolicy` property of the *BlockchainNetworkMultiSig* `verificationMethod`. +For *Security Domain DID* update requests, where the `networkMembers` property is not altered, indicating that the member list is unchanged, the requests are authenticated based on attestations satisfying `updatePolicy` property of the *BlockchainNetworkMultiSig* `verificationMethod`. - + # Choice of `updatePolicy` -The `updatePolicy` of a network is constructed through a consensus of different participants that need to attest any request to change the *Network DID* in future. The initial policy created for a Network DID creation requires unanimity, while subsequent policy updates are governed by existing policy. Situations might arrive due to a poor choice of `updatePolicy` which cannot be satisfied by network the participants, where the *Network DID* can no longer be controlled by the network. In those cases the members of the network have to form a separate *Network DID* (a new network in the identity plane), and advertise the new DID as the new network address for the same network. +The `updatePolicy` of a network is constructed through a consensus of different members that need to attest any request to change the *Security Domain DID* in future. The initial policy created for a Security Domain DID creation requires unanimity, while subsequent policy updates are governed by existing policy. Situations might arrive due to a poor choice of `updatePolicy` which cannot be satisfied by network members, where the *Security Domain DID* can no longer be controlled by the network. In those cases the members of the network have to form a separate *Security Domain DID* (a new network in the identity plane), and advertise the new DID as the new network address for the same network. -During the creation of a *Network DID*, if no `updatePolicy` is set in the Network DID Document, then a default `updatePolicy` may be set by the IIN as a threshold condition requiring the attestation of `> N/2` network participants. +During the creation of a *Security Domain DID*, if no `updatePolicy` is set in the Security Domain DID Document, then a default `updatePolicy` may be set by the IIN as a threshold condition requiring the attestation of `> N/2` network members. Example: @@ -84,18 +84,18 @@ Example: "type": "VerifiableCondition2021", "threshold": 4, "conditionThreshold": [ - "did::#key1", - "did::#key3", - "did::#key2", - "did::#key1", - "did::#key1", - "did::#key1", - "did::#key1" + "did::#key1", + "did::#key3", + "did::#key2", + "did::#key1", + "did::#key1", + "did::#key1", + "did::#key1" ] } ``` -If the network members explicitly want to create a "static" network where the network members are not supposed to be changed, then the threshold is set to a value more than the number of participants in the network. +If the network members explicitly want to keep the network's membership "static" (i.e., unchanging), the threshold is set to a value larger than the total number of network members. Example: @@ -106,13 +106,13 @@ Example: "type": "VerifiableCondition2021", "threshold": 8, "conditionThreshold": [ - "did::#key1", - "did::#key3", - "did::#key2", - "did::#key1", - "did::#key1", - "did::#key1", - "did::#key1" + "did::#key1", + "did::#key3", + "did::#key2", + "did::#key1", + "did::#key1", + "did::#key1", + "did::#key1" ] } ``` diff --git a/rfcs/models/identity/iin-agent.md b/rfcs/models/identity/iin-agent.md index 512e2cfdc..c04701407 100644 --- a/rfcs/models/identity/iin-agent.md +++ b/rfcs/models/identity/iin-agent.md @@ -8,7 +8,7 @@ - RFC: 01-013 - Authors: Venkatraman Ramakrishna, Krishnasuri Narayanam, Bishakh Chandra Ghosh, Ermyas Abebe - Status: Proposed -- Since: 24-Sep-2021 +- Since: 25-Aug-2022 # Summary @@ -19,63 +19,94 @@ This document specifies a component of a DLT network's participant unit that is In our view, a DLT network seeking to interoperate with another using any of our protocols is composed of units that are consituent members of that network, and are assumed to have identities independent of the network in the identity plane. Representing each unit in an IIN is an IIN Agent, managing the participant unit's DID. Furthermore, these IIN agents are used to discover, resolve, and verify other participant units' identities as well as network identities. We also assume that each nework unit is a root identity provider within the data plane of its DLT network. In Fabric: an MSP root CA server (typically, but not mandatorially, having a 1-1 relationship with an organization). In Corda: network root CA. -This view is illustrated in the figure below (Fig.1), which maps quite naturally to Fabric networks where each organization is a unit, but is general enough to encompass other permissioned DLTs like Corda and Besu too. +This view is illustrated in the figure below (Fig.1), which maps quite naturally to Fabric networks where each organization is a member, but is general enough to fit other permissioned DLTs like Corda and Besu too.

-
Fig.1 - IIN Agent.
+
Fig.1 - IIN Agents as Components of DLT Networks.

- # Data Plane Identity Artifacts The following artifacts in the data plane are relevant to identity plane protocols: * _Identity trust store_: this is a set of IINs and Trust anchors `,`. It implies that the network trusts a given trust anchor or all trust anchors in a given IIN to certify the identity/membership credentials of foreign network units. * The IIN definition can additionally contain peer connectivity information (to access the IIN ledger). This data will be looked up in the identity sharing protocol, while fetching membership information for a foreign network. It can also be used in proof verification (or view validation) in data plane protocols. -* _Foreign network identities and configurations_: these are [security domains](../security-domains.md), containing identities and certificates corresponding to a foreign network's units. (_Each security domain is augmented with a DID attribute denoting the identity owned by the IIN Agent associated with this network unit/security domain_). The IIN Agent of the network participants together update these configurations from the identity plane information. +* _Security Domain identities and configurations_: these are identities and certificates corresponding to foreign [security domains](../security/security-domains.md) and their members. See the [security domain identity](../../formats/network/identity.md#security-domain-identity) and [membership](../../formats/network/membership.md) for more details. (_Each security domain is also associated with an Organizational Unit Identity, or a DID record maintained in an IIN_). The IIN Agent of the network members collectively update these configurations using an [identity plane protocol](../../protocols/identity/id-config-sharing.md). + + +# IIN Agent Design and Interface + +An IIN Agent has two distinct roles: +1. As a client of one or more IINs and a DID-and-VC holder for a member of a DLT network member that represents a real world Organization Unit. +2. As a client of a member of a DLT network or security domain with special permissions to update security domain identities and configurations on the ledger via the network's [interoperation module](../infrastructure/interoperation-modules.md). + +This IIN Agent model and interface is represented in Fig. 2. An agent is built and deployed as a gRPC service that is reachable from other local or foreign security domains' agents. Simultaneously, it also offers gRPC client services to reach other agents, local or foreign. Each agent is capable of participating in DID and VC/VP protocols yb communicating with IINs and trust anchors too. + + +
+ +
+
Fig.2 - IIN Agent Model and Interface.
+
+
+ + +## IIN Agent as Organizational Representative and DID holder + +_This is work in progress_. + +## IIN Agent as a Security Domain Representative + +The agent is bootstrapped with a wallet identity with special permissions (in a Fabric network, we can represent this by embedding an `iin-agent` attribute in the identity certificate). + +The agent can serve in two modes as a security domain representative. In one mode, it serves a source network or security domain by serving up that domain's [membership information](../../formats/network/membership.md) with authentication as illustrated in Fig. 3. + + +
+ +
+
Fig.3 - IIN Agent in Security Domain Source Mode.
+
+
+ + +In another mode, it serves a destination (or identity syncing) network or security domain by requesting and validating another security domain's membership information from that domain's agents, collect attestations from all other local agents, and record this to the local ledger using the network's [interoperation module](../infrastructure/interoperation-modules.md). This is illustrated in Fig. 4. + + +
+ +
+
Fig.4 - IIN Agent in Security Domain Destination Mode.
+
+
-# Hyperledger Indy implementation of IIN Agent +Collectively, IIN Agents in source and destination modes can sync and register a foreign security domain's identity and membership info for use in data plane protocols. See the [description](../../protocols/identity/id-config-sharing.md) of the identity plane protocol that performs this sync for more details. The protocol relies on the DID infrastructure (IINs and trust anchors) as a root of trust but is otherwise bilateral (network-to-network). -An IIN Agent represents a network unit that is also a self-certified identity provider for some subset of the network, as stated earlier in the summary. It is simultaneously an IIN (Indy) client and a network (Fabric, Corda, etc.) client. Therefore, there are different ways in which it can be implemented, but its core feature is that it lies within the trust boundary of a root identity provider of a network. +### IIN Agent Functional API -Being an IIN client, the IIN Agent, like an [IIN Steward Agent](../iin-steward-agent.md), or some portion of it, must be built according to the canonical specification of an Indy Agent with the capability to create a wallet, interact with other agents (including stewards), and access an Indy ledger. These form the trust anchros in the IINs. Another portion of the IIN Agent must be built as a regular network client with the ability to exercise smart contracts for looking up and recording ledger data. +Here we specify API functions exposed to other foreign and local IIN agents. These all are RPC endpoints that can be implemented directly in a well-known protocol like gRPC. See the [membership](../../formats/network/membership.md) format specifications for more details. -The IIN Agent can be built and deployed in the following configurations: -* As an augmentation of a network root identity provider or CA: in Fabric, this would mean augmenting the Fabric CA Server to perform the functions of an IIN Agent -* As a separate service with a trusted communication channel (e.g., using gRPC) to a network root identity provider or CA -* As two separate services, one resembling an IIN Agent and another a network client (e.g., a Fabric Client SDK-based application). These two services will communicate with each other and with the network root identity provider or CA using a trusted communication channel -(As shown in the above diagram (Fig.1), there must be exactly one IIN Agent service, however configured, for every network unit) +#### API for Foreign Security Domains' IIN Agents -## Bootstrap/Initialize an IIN Agent -* Start a [Hyperleder Aries](https://www.hyperledger.org/use/aries) service, which consists of a <_controller_, _agent_> pair, with the agent built using [Aries Cloud Agent - Python](https://github.com/hyperledger/aries-cloudagent-python) as it supports persistent storage. This service has the capability to communicate with other agents using the peer-to-peer Aries protocol. It is recommended that this service be launched in a Docker container. Post-launch, the following actions must be carried out: - 1. Initialize a wallet to store DIDs, keys, and any other crypto material - 2. Obtain and load the service endpoints for an IIN and a Steward this network unit is associated with - 3. Register a verinym (DID record) through the standard Indy protocol (described [here](../../protocols/id-config-sharing-protocol/README.md)) - 4. Obtain and load the local network's ID - 5. Fetch membership list and endpoint info for other units of the local network from the steward (_Consider: this can be done without IIN involvement too_) - At this point, the IIN Agent has ownership of its DID that is recorded on its IIN's ledger. Its IIN Steward Agent now recognizes it as a member of its network and is ready to make a presentation of the member list of the network to any requestor. -* Start a network client service (if this is to be a standalone service) or initialize one according to the network's native procedure. Example: in Fabric, do the following: - 1. Initialize a Fabric wallet to store keys, certificates, and MSP configurations - 2. Initialize configuration information with the network's interoperation contract deployment ID: this is needed to record security domain info on the ledger - 3. Import a connection profile and connect to a network gateway +- **SyncExternalState(NetworkUnitIdentity): returns common.ack.Ack** + Endpoint for user/client/agent to request a syncing of membership info from a foreign network's member described using the `NetworkUnitIdentity` structure. -## Interact with Network Units' IIN Agents -The IIN Agent interacts with other IIN Agents in the following ways: -* With local network agents: to launch or participate in a flow that collects a multi-signature over a foreign network's unit's security domain -* With foreign network agents: to request/offer membership and security domain presentations, prove membership within its network, and prove ownership of a security domain +- **RequestIdentityConfiguration(NetworkUnitIdentity): returns common.ack.Ack** + Endpoint for foreign IIN Agent to request attested local security domain's membership information. -Details of these protocols can be found [here](../../protocols/identity/readme.md). +- **SendIdentityConfiguration(AttestedMembership): returns common.ack.Ack** + Endpoint for foreign IIN Agent to supply attested foreign security domain's membership information. -## IIN Agents for Trust Anchors -Trust anchors associated with IINs, or DID registries in general, and which issue identity and membership VCs to individual network participants (see [IIN model](./iin.md)), also must run an agent to interact with network members' IIN agents. The model for an IIN agent specified earlier in this document can be used for trust anchor agents with some salient differences: -* The trust anchor agent will need to be equipped with the capability to issue VCs, and return VPs when an IIN agent sends a valid request for one. -* The trust anchor agent will not need to understand a DLT protocol for the purpose of recording identities to a network's ledger. +#### API for Local Security Domain's IIN Agents -(_Note_: If the IIN is built on Hyperledger Indy, where trust anchors are referred to as _stewards_, the corresponding agent will register the verinym (DID) for its steward along with key-generation seed values (generated using a random number generator) in the Indy ledger. This registration occurs at genesis (or bootstrap) time.) +- **RequestAttestation(AttestedSecurityDomain): returns common.ack.Ack** + Endpoint for local IIN Agent to request attestation over a foreign security domain's membership info as part of a signature collection flow. +- **SendAttestation(AttestedSecurityDomain): returns common.ack.Ack** + Endpoint for local IIN Agent to supply attestation over a foreign security domain's membership info as part of a signature collection flow. diff --git a/rfcs/models/identity/iin.md b/rfcs/models/identity/iin.md index e8a8d0f0a..bab3c6e2d 100644 --- a/rfcs/models/identity/iin.md +++ b/rfcs/models/identity/iin.md @@ -8,7 +8,7 @@ - RFC: 01-012 - Authors: Venkatraman Ramakrishna, Bishakh Chandra Ghosh, Krishnasuri Narayanam, Ermyas Abebe - Status: Proposed -- Since: 24-Sep-2021 +- Since: 25-Aug-2022 # Summary @@ -30,7 +30,7 @@ The IIN can be built on existing DLT based DID registry technologies such as [H # IIN Ledger Artifacts An IIN must have be able to record the following artifacts perferably in a distributed ledger: -* _DID Documents_ where each document is associated with a single unique DID. The DID Document can be for a blockchain network as a whole - [*Network Identity*](../../formats/identity.md) or member participant units - [*Participant Unit Identity*](../../formats/identity.md). +* _DID Documents_ where each document is associated with a single unique DID. The DID Document can be for a blockchain network as a whole - [*Security Domain Identity*](../../formats/network/identity.md#security-domain-identity) or member participant units - [*Organizational Unit Identity*](../../formats/network/identity.md#organizational-unit-identity). * _Verifiable Credential Schemas_: data structure describing a verifiable credential. ([vc-data-model](https://www.w3.org/TR/vc-data-model/#dfn-verifiable-data-registries)) @@ -38,10 +38,10 @@ An IIN must have be able to record the following artifacts perferably in a distr * _Revocation Registry_: to allow VC issuers to revoke credentials. -## Participant Unit Identity and Network Identity +## Organizational Unit Identity and Security Domain Identity -The IIN ledger holds the DID documents of network participants as well as the network as a whole. -See specifications of *Network Identity* and *Participant Unit Identity* DID formats [here](../../formats/identity.md). +The IIN ledger holds the DID documents of individual network members as well as that of the network as a whole. +See [specifications of these DID formats](../../formats/network/identity.md) for details. ## Credential Schema, Verification Keys and Revocation Lists @@ -50,8 +50,7 @@ A DID Document is not inherently mapped to any entity's physical identity [did-c The IIN must support two kinds of claims to be issued by trust anchors to the DIDs: -1. Identity VCs - for associating real world identity to individuals/organizations which are participating units - *Participant Identity VC*, or to a network as a whole - *Network Identity VC*. (See [Network Identity Validation - protocol](../../protocols/identity/network-identity-validation.md) for details.) +1. Identity VCs - for associating real world identity to individuals/organizations which are members of networks - *Organizational Unit Identity VC*, or to a network as a whole - *security Domain Identity VC*. (See [Network Identity Validation protocol](../../protocols/identity/network-identity-validation.md) for details.) 2. Membership VCs - to assert the membership of an individual/organization in a blockchain network. @@ -92,4 +91,4 @@ These trust anchors are entities that the participants trust and whose identity ## IIN Agents -DLT networks interact with the IINs through a components called IIN Agent. Each participant unit in a DLT network has have atleast one IIN Agent using which it exposes its identity as well as discovers and verifies foreign network identities. The IIN Agents are detailed [here](./iin-agent.md). +DLT networks interact with the IINs and with each other through components called IIN Agents. Each participant unit in a DLT network must have at least one IIN Agent using which it exposes its identity as well as discovers and verifies foreign network identities. The IIN Agents are detailed [here](./iin-agent.md). diff --git a/rfcs/models/identity/network-identity-management.md b/rfcs/models/identity/network-identity-management.md index 2598c4280..85870efa0 100644 --- a/rfcs/models/identity/network-identity-management.md +++ b/rfcs/models/identity/network-identity-management.md @@ -1,134 +1,131 @@ - -# Decentralized Network-Identity Discovery and Management for Interoperation - -- RFC: 01-011 -- Authors: Venkatraman Ramakrishna, Krishnasuri Narayanam, Bishakh Chandra Ghosh, Ermyas Abebe -- Status: Proposed -- Since: 24-Sep-2021 - - -# Overview - -During interoperation through the [data sharing protocol](../../protocols/data-sharing/generic.md), the primary functions performed through consensus in the _endpoint_ peer networks, namely _request access control_ and _view proof validation_, depend on the availability of authentic information about the counterparty network's identity providers and their credentials. Snapshots of these _identity configurations_, changing at punctuated intervals, act as essential trust basis for access control checks and proof validations. As Fig.1 indicates, our protocol has two distinct planes of operation, an _identity plane_ that syncs identity information as necessary and a _data plane_ where requests and responses occur. (_Note_: data query is just one example of a protocol operating in the data plane, independent of the protocol operating in the identity plane yet dependent on the information obtained through the latter.) - -
- -
-
Fig.1 - Data plane and identity plane in cross network data sharing protocol.
-
-
- -In the data sharing protocol, the protocol in the identity plane is implemented through the simplistic means of each network exposing a single public (i.e., without any access control) REST API function, from one of its active web servers, that reveals portions of the latest network configuration: -* In Fabric, this is the channel configuration containing root CA and intermediate CA certificates and other possibly relevant metadata for every organization participating in the channel. -* In Corda, this is a set of certificate chains, typically network root --> doorman --> node for each network node. - -This solution, implemented as a stopgap measure, suffers from various drawbacks: -1. First, it is insecure, relying on a single designated spokesperson to expose identity information in a participating network, and further not enforcing access controls on the information being exposed. -2. Second, it relies on apriori configuration of information about the REST API endpoints of the foreign networks, such as their addresses. There is no mechanism of discovering the interoperating networks. -3. Third, it assumes a priori trust between the two networks, while in the real world, parties rely on common trusted authorities for the introductory step. -4. Fourth, it again relies on a single designated member (participant unit) of a network to configure the identity information of foreign networks. - - -To enable data and asset exchange protocols between permissioned networks on-demand, we need a more secure and systematized process for exposing, discovering, verifying, and configuring network identity information. Further, this process should be decentralized in a way that allows participating networks and their units to own, control, and expose their identity information as they see fit and not have to rely on centralized parties as mediums of exchange. The process should also ensure extensibility, and scalability to the extent possible, by enabling a network with units owning decentralized identities (DIDs) which can be verified by well-known and trusted identity providers to exchange data or assets with permissioned networks already part of the ecosystem. Finally, trust in identity providers should be based on blockchain (or distributed ledger) principles, mitigating the possibility of collusion between networks and identity providers. - -A slightly amended figure (Fig.2) illustrates our view of the solution below, where you can see that the identity plane protocol relies both on bilateral communication and a "cloud" of identity providers that provides the fundamental trust basis for interoperation. We will sketch out the details of this cloud and the identity information exchanges later. - -
- -
-
Fig.2 - Identity plane using some identity providers and verifiers as a trust basis.

-
-
- -Having established our mode of blockchain interoperation as a two-plane networking system, we can focus on the components and mechanisms in the identity plane. Other specifications in this repository cover the gamut of features implemented in the data plane. - - -# Design Approaches and Choices - -There is a range, or spectrum, of architectural choices available to build identity plane infrastructure and protocols, which are described at length [here](./design-choices.md). In this document and in the rest of the specification, we will select one of those choices: "DID Registry for Identity Exchange", and describe a reference architecture and set of protocols in detail. Before doing that, we will describe the landscape as we see it, list our assumptions, and provide some reasoning for our design choices. - -The concepts of _Decentralized Identity (DID)_ and _Verifiable Credential (VC)_ already exist and are in W3C draft status. There are several examples of DID registries where user identities can be stored and looked up from in controllable ways. Credential issuers have existed on the Web for many years, and we expect that most will soon provide VCs to DID holders as this is the most promising approach to ensuring decentralized, controllable, and privacy-preserving authentication. Entities that participate in blockchain networks may already possess DIDs in one or more of these registries, and if not, can easily get DIDs created. They can also obtain VCs from reputed certifiers if they do not already possess them for proving their identity and other claims. Therefore, our design relies on blockchain network participants possessing DIDs and VCs issued by entities outside those networks. - -What we cannot know beforehand is what configuration of DID registries or VC issuers will exist at any given time nor should we make any assumptions that will limit our choices in the future. We can also not know the complete trust calculus beforehand that tells us how to connect two interoperating networks via common DID registries and VC issuers. We can only rely on the existence of DID and VC standards that everyone will eventually converges to. But for the purpose of our design, we can (and will) select a particular configuration that shows how the basis of interoperation can be built using DIDs and VCs. Our mechanisms can be easily adapted for different configurations of DID registries and VC issuers than the one we will describe in detail in this RFC. - - -# Distributed Identity Management Architecture - -The below figure (Fig. 3) illustrates our identity plane architecture: -* A set of identity providers and verifiers to establish a trust basis for exchange of identity and any other network configuration information. We assume, without loss of generality, that such identity providers belong to networks which we term as _Interoperation Identity Networks (IINs)_. -* A set of agents, called *IIN Agents* that act on behalf of members (participant units) within a network that collectively supply and fetch membership, identity, and any other configuration information, of the counterparty network. - -
- -
-
Fig.3 - Identity plane architecture overview

-
-
- -_Some Notes on IINs (Pertaining to the Design Choices Described Earlier)_: - - - - -* _The term 'Interoperation Identity Network' is a placeholder to describe a unit of our proposed architecture, and is subject to change in the future. A term that may replace it is 'Distributed Identity Registry', which captures both the role and the nature of this entity, and which practitioners may already be familiar with_. -* _An IIN is not a new concept or system we are inventing for interoperation purposes but is rather an extrapolation of the concept of a DID registry, many varieties of which exist today, to a distributed system that may maintain DID records through consensus among a committee on a shared ledger rather than maintain them in a centralized repository_. -* _An IIN brings within its purview both a DID registry maintained as a shared ledger as well as well-known issuers of DIDs and verifiable credentials (VCs) who collectively maintain that ledger. In the real-world, registries as well as issuers already exist, though not necessarily part of a single network. The design and protocol we describe can accommodate existing DID registries and VC issuers, even though they be independent (and centralized) entities, but in our discussion we will assume, without loss of generality, that they belong to one or the other network (labeled as an IIN). Our mechanisms rely on the ability to negotiate with issuers and read/write to DID registries; neither function is constrained by the nature of the issuers or the registries_. - -The following figure (Fig. 4) illustrates a representative instance of the generalized architecture. We envision an ecosystem consisting of multiple independent DLT networks, each of which chooses to interoperate for data or asset exchanges with another network bilaterally on a need basis. In this ecosystem, there also exist one or more IINs, each of which consist of one or more reputable trust anchors. These trust anchors issue VCs to support claims of the networks and their participants, thus forming the trust basis for identity verification. - -
- -
-
Fig.4 - IINs in Identity plane architecture

-
-
- - -#### Condition for successful identity configuration: - -Suppose there are two networks N1 and N2, and there are two IINs, IIN1 and IIN2. There are also two trust anchors, T1 in IIN1 and T2 in IIN2. - -Prerequisites for interoperation between network N1 connected to trust anchor T1 on IIN1 and N2 connected to trust anchor T2 on IIN2: -* N1 must have access privileges to IIN2's ledger and N2 must have access privileges to IIN1's ledger. Here access means ability to read the ledger to resolve DID Documents from it. -* N1 must trust T2 as an identity provider and verifier, and N2 must trust T1 similarly - -> (_Note_: this calculus becomes simpler if IIN1 and IIN2 are the same network, and even simpler if T1 and T2 are the same. In the latter case, the scenario devolves into N1 and N2 having a common root of trust.) - - -## Reference Architecture and Functional Requirements - -From a functional perspective, the mechanism to exchange identity information and to keep it in sync across network boundaries is agnostic of the trust relationship between networks. The simplest way to implement our architecture would be using a single IIN with multiple trust anchors representing either individual network consortiums or authorities trusted by the networks' constituent members, as mentioned earlier in this document. Functionally, this will be identical to a multi-IIN setup and so we will use this as the canonical architecture to describe the exchange protocol. The specification for IINs and the network components will leave room for multiple IINs though. - -## Interoperation Identity Network - IIN - -Our canonical IIN is a distributed shared ledger based DID registry that supports [Group Control](https://www.w3.org/TR/did-core/#group-control) to allow the group of network members (participant units) to control a single DID for the network. Along with this DID registry the IIN also has trust anchors, that issue VCs to support claims by different units. - -See specification for IINs [here](./iin.md). - - -## Forms of Identity - -Our framework consists of both hierarchical and decentralized identities. Decentralized identities belong to constituent units of participating DLT networks, each of whom is assumed to be an independent actor with an identity that is may not owe its existence to the network in question. Yet, for interoperation purposes, that decentralized identity will be associated with the corresponding network's identity, as will the identities of all the other units of that network. Below are the different identities that will be maintained and used in identity plane protocols: -* _Participant Unit Identity_: In a participating DLT network, each participant entity (individual/organization) of that network will have its independent identity. This identity is also a decentralized identity in the form of a DID, registered in an IIN DID registry. -* _Network Identity_: The identity of a network in the form of a DID, registered in an IIN. This identity is controlled by the participants of the network. -* _Trust Anchors_: Trust anchors are well known identities of units that issue VCs to attest the real identity of both Participant Unit Identities and Network Identities. -* _Data Plane Participant Identity_: In the data plane, DLT network participants may use different identities according to the DLT platform in use. Such identities are not a requirement in the identity plane. But participant units use _Participant Unit Identity_ of the identity plane to self attest their _Data Plane Participant Identity_. - -The the data format specifications [here](../../formats/identity.md). - - - -## Network Identity Creation, Exchange and Validation - -The DLT networks and its participant units must create and configure their identities in the identity plane. During interoperation, two different networks have to exchange their identity information and validate them. These are carried out with through the protocols specified [here](../../protocols/identity/readme.md). - -## Network Identity Discovery - -To allow seamless interoperation across two different DLT networks, the identity of the counterparty networks have to be configured. But, even before that, some means of discovering the networks is required through which any identity protocol can start. Discovery of networks in the identity plane is facilitated by discovery of the Network Identities, which are represented as Network DIDs and registered in the IINs. Each Network thus has a unique Network DID which can be considered equivalent to a domain name in Internet parlance. Thus Network DID facilitates discovery of networks with the help of the IIN infrastructure. - -The network discovery protocols specifications are elaborated [here](../../protocols/discovery/readme.md). - + +# Decentralized Network-Identity Discovery and Management for Interoperation + +- RFC: 01-011 +- Authors: Venkatraman Ramakrishna, Krishnasuri Narayanam, Bishakh Chandra Ghosh, Ermyas Abebe +- Status: Proposed +- Since: 25-Aug-2022 + + +# Overview + +During interoperation through the [data sharing protocol](../../protocols/data-sharing/generic.md), the primary functions performed through consensus in the _endpoint_ peer networks, namely _request access control_ and _view proof validation_, depend on the availability of authentic information about the counterparty network's identity providers and their credentials. Snapshots of these _identity configurations_, changing at punctuated intervals, act as essential trust basis for access control checks and proof validations. As Fig.1 indicates, our protocol has two distinct planes of operation, an _identity plane_ that syncs identity information as necessary and a _data plane_ where requests and responses occur. (_Note_: data query is just one example of a protocol operating in the data plane, independent of the protocol operating in the identity plane yet dependent on the information obtained through the latter.) + +
+ +
+
Fig.1 - Data plane and identity plane in cross network data sharing protocol.
+
+
+ +In the data sharing protocol, the protocol in the identity plane is implemented through the simplistic means of each network exposing a single public (i.e., without any access control) REST API function, from one of its active web servers, that reveals portions of the latest network configuration: +* In Fabric, this is the channel configuration containing root CA and intermediate CA certificates and other possibly relevant metadata for every organization participating in the channel. +* In Corda, this is a set of certificate chains, typically network root --> doorman --> node for each network node. + +This solution, implemented as a stopgap measure, suffers from various drawbacks: +1. First, it is insecure, relying on a single designated spokesperson to expose identity information in a participating network, and further not enforcing access controls on the information being exposed. +2. Second, it relies on apriori configuration of information about the REST API endpoints of the foreign networks, such as their addresses. There is no mechanism of discovering the interoperating networks. +3. Third, it assumes a priori trust between the two networks, while in the real world, parties rely on common trusted authorities for the introductory step. +4. Fourth, it again relies on a single designated member (participant unit) of a network to configure the identity information of foreign networks. + + +To enable data and asset exchange protocols between permissioned networks on-demand, we need a more secure and systematized process for exposing, discovering, verifying, and configuring network identity information. Further, this process should be decentralized in a way that allows participating networks and their units to own, control, and expose their identity information as they see fit and not have to rely on centralized parties as mediums of exchange. The process should also ensure extensibility, and scalability to the extent possible, by enabling a network with units owning decentralized identities (DIDs) which can be verified by well-known and trusted identity providers to exchange data or assets with permissioned networks already part of the ecosystem. Finally, trust in identity providers should be based on blockchain (or distributed ledger) principles, mitigating the possibility of collusion between networks and identity providers. + +A slightly amended figure (Fig.2) illustrates our view of the solution below, where you can see that the identity plane protocol relies both on bilateral communication and a "cloud" of identity providers that provides the fundamental trust basis for interoperation. We will sketch out the details of this cloud and the identity information exchanges later. + +
+ +
+
Fig.2 - Identity plane using some identity providers and verifiers as a trust basis.

+
+
+ +Having established our mode of blockchain interoperation as a two-plane networking system, we can focus on the components and mechanisms in the identity plane. Other specifications in this repository cover the gamut of features implemented in the data plane. + + +# Design Approaches and Choices + +There is a range, or spectrum, of architectural choices available to build identity plane infrastructure and protocols, which are described at length [here](./design-choices.md). In this document and in the rest of the specification, we will select one of those choices: "DID Registry for Identity Exchange", and describe a reference architecture and set of protocols in detail. Before doing that, we will describe the landscape as we see it, list our assumptions, and provide some reasoning for our design choices. + +The concepts of _Decentralized Identity (DID)_ and _Verifiable Credential (VC)_ already exist and are in W3C draft status. There are several examples of DID registries where user identities can be stored and looked up from in controllable ways. Credential issuers have existed on the Web for many years, and we expect that most will soon provide VCs to DID holders as this is the most promising approach to ensuring decentralized, controllable, and privacy-preserving authentication. Entities that participate in blockchain networks may already possess DIDs in one or more of these registries, and if not, can easily get DIDs created. They can also obtain VCs from reputed certifiers if they do not already possess them for proving their identity and other claims. Therefore, our design relies on blockchain network participants possessing DIDs and VCs issued by entities outside those networks. + +What we cannot know beforehand is what configuration of DID registries or VC issuers will exist at any given time nor should we make any assumptions that will limit our choices in the future. We can also not know the complete trust calculus beforehand that tells us how to connect two interoperating networks via common DID registries and VC issuers. We can only rely on the existence of DID and VC standards that everyone will eventually converges to. But for the purpose of our design, we can (and will) select a particular configuration that shows how the basis of interoperation can be built using DIDs and VCs. Our mechanisms can be easily adapted for different configurations of DID registries and VC issuers than the one we will describe in detail in this RFC. + + +# Distributed Identity Management Architecture + +The below figure (Fig. 3) illustrates our identity plane architecture: +* A set of identity providers and verifiers to establish a trust basis for exchange of identity and any other network configuration information. We assume, without loss of generality, that such identity providers belong to networks which we term as _Interoperation Identity Networks (IINs)_. +* A set of agents, called *IIN Agents* that act on behalf of members (participant units) within a network that collectively supply and fetch membership, identity, and any other configuration information, of the counterparty network. + +
+ +
+
Fig.3 - Identity plane architecture overview

+
+
+ +_Some Notes on IINs (Pertaining to the Design Choices Described Earlier)_: + +* _The term 'Interoperation Identity Network' is a placeholder to describe a unit of our proposed architecture, and is subject to change in the future. A term that may replace it is 'Distributed Identity Registry', which captures both the role and the nature of this entity, and which practitioners may already be familiar with_. +* _An IIN is not a new concept or system we are inventing for interoperation purposes but is rather an extrapolation of the concept of a DID registry, many varieties of which exist today, to a distributed system that may maintain DID records through consensus among a committee on a shared ledger rather than maintain them in a centralized repository_. +* _An IIN brings within its purview both a DID registry maintained as a shared ledger as well as well-known issuers of DIDs and verifiable credentials (VCs) who collectively maintain that ledger. In the real-world, registries as well as issuers already exist, though not necessarily part of a single network. The design and protocol we describe can accommodate existing DID registries and VC issuers, even though they be independent (and centralized) entities, but in our discussion we will assume, without loss of generality, that they belong to one or the other network (labeled as an IIN). Our mechanisms rely on the ability to negotiate with issuers and read/write to DID registries; neither function is constrained by the nature of the issuers or the registries_. + +The following figure (Fig. 4) illustrates a representative instance of the generalized architecture. We envision an ecosystem consisting of multiple independent DLT networks, each of which chooses to interoperate for data or asset exchanges with another network bilaterally on a need basis. In this ecosystem, there also exist one or more IINs, each of which consist of one or more reputable trust anchors. These trust anchors issue VCs to support claims of the networks and their participants, thus forming the trust basis for identity verification. + +
+ +
+
Fig.4 - IINs in Identity plane architecture

+
+
+ + +#### Condition for successful identity configuration: + +Suppose there are two networks N1 and N2, and there are two IINs, IIN1 and IIN2. There are also two trust anchors, T1 in IIN1 and T2 in IIN2. + +Prerequisites for interoperation between network N1 connected to trust anchor T1 on IIN1 and N2 connected to trust anchor T2 on IIN2: +* N1 must have access privileges to IIN2's ledger and N2 must have access privileges to IIN1's ledger. Here access means ability to read the ledger to resolve DID Documents from it. +* N1 must trust T2 as an identity provider and verifier, and N2 must trust T1 similarly + +> (_Note_: this calculus becomes simpler if IIN1 and IIN2 are the same network, and even simpler if T1 and T2 are the same. In the latter case, the scenario devolves into N1 and N2 having a common root of trust.) + + +## Reference Architecture and Functional Requirements + +From a functional perspective, the mechanism to exchange identity information and to keep it in sync across network boundaries is agnostic of the trust relationship between networks. The simplest way to implement our architecture would be using a single IIN with multiple trust anchors representing either individual network consortiums or authorities trusted by the networks' constituent members, as mentioned earlier in this document. Functionally, this will be identical to a multi-IIN setup and so we will use this as the canonical architecture to describe the exchange protocol. The specification for IINs and the network components will leave room for multiple IINs though. + +## Interoperation Identity Network - IIN + +Our canonical IIN is a distributed shared ledger based DID registry that supports [Group Control](https://www.w3.org/TR/did-core/#group-control) to allow the group of network members (participant units) to control a single DID for the network. Along with this DID registry the IIN also has trust anchors, that issue VCs to support claims by different units. + +See specification for IINs [here](./iin.md). + + +## Forms of Identity + +Our framework consists of both hierarchical and decentralized identities. Decentralized identities belong to constituent units of participating DLT networks, each of whom is assumed to be an independent actor with an identity that is may not owe its existence to the network in question. Yet, for interoperation purposes, that decentralized identity will be associated with the corresponding network's identity, as will the identities of all the other units of that network. Below are the different identities that will be maintained and used in identity plane protocols: +* _Organizational Unit Identity_: Each member (individual/organization) of a DLT network will have a real world identity independent of its affiliation with that network. This identity is also a decentralized identity (DID), registered in an IIN DID registry. +* _Security Domain Identity_: The identity of a network, which is also a [security domain](../security/security-domains.md), in the form of a DID, registered in an IIN. This identity is controlled collectively by the members of the network. +* _Trust Anchors_: Trust anchors are identities of well-known entities that issue VCs to attest the real world identities of both Organizational Units and Security Domains. +* _Security Domain Member Identity_: In the data plane, network members may use different identities scoped within their security domain as necessitated by the DLT platform on which the network is built. Such identities are not a requirement in the identity plane. But a member uses its _Organizational Unit Identity_ (in the identity plane) to self attest its _Security Domain Member Identity_. + +See the [data format specifications](../../network/identity.md) for more details. + + +## Security Domain Identity Creation, Exchange and Validation + +DLT networks and their members must create and configure their respective identities in the identity plane. See the protocols for [cross-network identity exchange and validation](../../protocols/identity/readme.md) for more details. + + +## Security Domain Identity Discovery + +For two different DLT networks to interoperate seamlessly, a network must fetch, validate, and record its counterparty network's members' identities on its ledger. But discovering the counterparty network and obtaining its security domain identity is a prerequisite for any identity plane protocol in which members' identities can be synced. IIN infrastructure facilitates such discovery by allowing networks to register and record their security domain identities in the forms of Network DIDs. We will assume that each network will have a unique Network DID, analogous to a domain name in the Internet. + +See the [network discovery protocols specifications](../../protocols/discovery/discovery.md) for more details. + diff --git a/rfcs/models/infrastructure/relays.md b/rfcs/models/infrastructure/relays.md index 4aac3b247..6b00f6b2b 100644 --- a/rfcs/models/infrastructure/relays.md +++ b/rfcs/models/infrastructure/relays.md @@ -73,7 +73,7 @@ Once a driver is designed for a given DLT, it can be reused in any network built ## Relay Functional API -Here we list API function specs exposed to [application clients](#api-for-application-client), [relay](#api-for-other-relays) and [drivers](#api-for-driver). These all are RPC endpoints that can be implemented directly in a well-known protocol like gRPC. Message formats will be described in [relay](../../formats/communication/relay.md) and [request](../../formats/views/request.md). +Here we list API function specs exposed to [application clients](#api-for-application-client), [relay](#api-for-other-relays) and [drivers](#api-for-driver). These all are RPC endpoints that can be implemented directly in a well-known protocol like gRPC. See the [relay](../../formats/communication/relay.md) and [view request](../../formats/views/request.md) format specifications for more details. ### API for Application Client @@ -99,7 +99,7 @@ Here we list API function specs exposed to [application clients](#api-for-applic ## Driver Functional API -Here we list API function specs exposed to relays by the drivers. These are RPC endpoints that can be implemented directly in a well-known protocol like gRPC. Message formats will be described in [request](../../formats/views/request.md). +Here we list API function specs exposed to relays by the drivers. These are RPC endpoints that can be implemented directly in a well-known protocol like gRPC. See the [view request](../../formats/views/request.md) format specifications for more details. - **RequestDriverState(common.query.Query): returns (common.ack.Ack)** The remote relay sends a request to the driver, identified by the [view address](../../formats/views/addressing), with a query defining the data it wants to receive. This is where driver unpacks the view address, makes a call to the requested contract using given arguments, and collects the response along with the proof, packages them into a DLT-specific view message, and then encapsulating it to a DLT-neutral view message. This final message is then sent back to remote relay using above relay's API (SendDriverState). It takes a message of type takes [Query](../../formats/views/request.md#query) as argument, and returns [Ack](../../formats/views/request.md#ack). diff --git a/rfcs/protocols/discovery/discovery.md b/rfcs/protocols/discovery/discovery.md index 125028cea..a3c23380c 100644 --- a/rfcs/protocols/discovery/discovery.md +++ b/rfcs/protocols/discovery/discovery.md @@ -8,14 +8,14 @@ - RFC: 02-013 - Authors: Bishakh Chandra Ghosh, Venkatraman Ramakrishna, Krishnasuri Narayanam, Ermyas Abebe - Status: Draft -- Since: 25-Jul-2021 +- Since: 25-Aug-2022 ## Summary -When a network ("local network" from here on) tries to configure the identity of another network ("foreign network" from here on) for interoperation, the broad steps involved are (i) Network Discovery (ii) Network Identity Validation. Both these steps are carried out by the IIN agent of the participants of the local network. +When a network ("local network" from here on) tries to configure the identity of another network ("foreign network" from here on) for interoperation, the broad steps involved are (i) Network Discovery (ii) Security Domain Identity Validation. Both these steps are carried out by the IIN agent of the participants of the local network. -Whether each participant needs to carry out the discovery and validation, or a subset of participants will do it depends entirely on the trust basis of the network. This is covered in Network Identity Configuration step. +Whether each participant needs to carry out the discovery and validation, or a subset of participants will do it depends entirely on the trust basis of the network. This is covered in Security Domain Identity Configuration step. > Note: It is the IIN's responsibility to authenticate a Network DID creation or updation. Therefore, local network must trust the IIN to trust the fact that the resolved Network DID is created by proper attestations from its controller participants. Given a DLT based IIN which allows anyone to monitor the ledger, any IIN agent can validate the authenticity of a Network DID by validating the Network DID creation/updation requests from the ledger. diff --git a/rfcs/resources/images/identity-sync.png b/rfcs/resources/images/identity-sync.png new file mode 100755 index 0000000000000000000000000000000000000000..a0a8e8380d442135eda750eebfc9911b8adf87a7 GIT binary patch literal 119899 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 A00000 literal 0 HcmV?d00001 diff --git a/rfcs/resources/images/iin-agent-interface.png b/rfcs/resources/images/iin-agent-interface.png new file mode 100755 index 0000000000000000000000000000000000000000..d0d270e6f6514d8e0dd5262ec49172c9f85fa0af GIT binary patch literal 29923 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
wzb)p<>OPF!v1t45eg!qG)F4gLI8FTJ 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

Wtu|SmRX)twsOw3{v^cRq2?(b*k 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%0D&(?x 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ℜqPOtp-)LcM69=wxI|ETfH-SGnrve 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 K9&M*W1pfn6A(lJ< literal 0 HcmV?d00001 diff --git a/rfcs/resources/images/iin-augmented-network.jpg b/rfcs/resources/images/iin-augmented-network.jpg index 51c166353a2676b549071f6fe50fb86f501f72d7..8a1e9144d8153476d2f34589eeafd3d2c93885ae 100755 GIT binary patch delta 81362 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≈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

Im`Q27MSr{adb%T?t85>#JVPZ|h}vwF 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

TP{=Y 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 EKan*V!2kdN delta 81233 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 diff --git a/rfcs/resources/images/security-domain.png b/rfcs/resources/images/security-domain.png index b5025c84e2662482072f84f8b8eb42f956ca921d..0187941c1368f478726b43029f62b8322f89850a 100755 GIT binary patch literal 22036 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 literal 42855 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 From 4baaaa988ce8bef40929a2762097b159508ad24d Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Thu, 25 Aug 2022 20:10:05 +0000 Subject: [PATCH 103/150] Updated Identity Sync Protocol RFCs and made minor code augmentations Exposed a chaincode function to validate and extract confidential payloads in the Fabric Interop SDK. Minor error handling logic change in Fabric driver. Signed-off-by: VRamakrishna --- core/drivers/fabric-driver/server/events.ts | 4 ++- .../data-plane-identity-configuration.md | 34 +++++++++--------- .../identity/identity-change-updates.md | 27 -------------- rfcs/protocols/identity/identity-syncing.md | 28 +++++++++------ .../images/protocol-identity-overview.jpg | Bin 81430 -> 99135 bytes .../src/InteroperableHelper.ts | 13 +++++++ 6 files changed, 52 insertions(+), 54 deletions(-) delete mode 100644 rfcs/protocols/identity/identity-change-updates.md diff --git a/core/drivers/fabric-driver/server/events.ts b/core/drivers/fabric-driver/server/events.ts index 7d24184e1..b94b2c633 100644 --- a/core/drivers/fabric-driver/server/events.ts +++ b/core/drivers/fabric-driver/server/events.ts @@ -51,7 +51,9 @@ async function subscribeEventHelper( const errorString: string = `${JSON.stringify(err)}`; console.error(errorString); } - ack_send.setMessage('Event subscription error: listener registration failed'); + const errorString2 = JSON.stringify(error); + console.error(errorString2); + ack_send.setMessage(`Event subscription error: listener registration failed with error: ${errorString2}`); ack_send.setStatus(ack_pb.Ack.STATUS.ERROR); } else { ack_send.setMessage('Event subscription is successful!'); diff --git a/rfcs/protocols/identity/data-plane-identity-configuration.md b/rfcs/protocols/identity/data-plane-identity-configuration.md index 201a21de1..d5ed4c504 100644 --- a/rfcs/protocols/identity/data-plane-identity-configuration.md +++ b/rfcs/protocols/identity/data-plane-identity-configuration.md @@ -3,31 +3,33 @@ SPDX-License-Identifier: CC-BY-4.0 --> -# Data Plane Identity Configuration +# Security Domain Membership Syncing - RFC: 02-012-appendix-b - Authors: Venkatraman Ramakrishna, Krishnasuri Narayanam, Bishakh Chandra Ghosh, Ermyas Abebe - Status: Proposed -- Since: 24-Sep-2021 +- Since: 25-Aug-2022 ## Overview -For interoperation in the data plane, the identities in terms of data plane certificates/credentials of the foreign network units have to be configured. Along with that, the relay endopint information has to be configured. +Data plane interoperation requires the syncing and configuration of a foreign security domain's [membership information](../../formats/network/membership.md) as well as the relay endpoints for that security domain (or network). -The Network DID of a foreign network contains `relayEndpoints` and `DataplaneCredentials` verification method which are used to configure the realys and the data plane certidicates required for interoperation respectively. +The Security Domain DID of a foreign security domain contains `relayEndpoints` and `DataplaneCredentials` verification methods, used to configure relay endpoints and certificates (part of membership info) respectively. -## Protocol +## Sync Protocol -Considering two networks `NETWORK 1` and `NETWORK 2`, we specify a protocol where the IIN Agent of a participant unit, say `Org2` in `NETWORK 1` is configuring the identity and relay for `NETWORK 2`. +Consider two security domains governing ledgers `Ledger A` and Ledger B` respectively. The first has two IIN Agents `A1` and `A2` representing two organizational units that are members of its security domain. The second has agents `B1` and `B2`. The security domain governing `Ledger A` is trying to sync the latest identity and membership info of the security domain governing `Ledger B`. Without loss of generality, we can pick `A2` as the initiator of the cross-network identity plane protocol that results in `Ledger B`'s security domain membership and relay endpoints info getting recorded in `Ledger A`. The protocol is illustrated in the figure below. (_Note_: this represents the "happy path". We will add more diagrams subsequently illustrating failures and race conditions.) -* IIN Agent of a network unit that intends to update the foreign network identity information in the data plane initiates a flow to collect signatures over the identity (Security Domain info) of the network units of `NETWORK 2`. These are obtained from `relayEndpoints` and `DataplaneCredentials` verification method of the Network DID, after the Network DID is validated (see [protocol](./network-identity-validation.md)). -* IIN Agent of a network unit starts a flow to collect signatures over the identity (Security Domain info) and relay endpoint of `NETWORK 2`. + -The steps of this application level flow for updating data plane identity information are as follows: -1. `IIN Agent Org2` constructs a _signature collection procedure_ request message consisting of the following: `{, [],[ -> ]},` (here, `` is generated over the preceding structure. -2. `IIN Agent Org2` triggers a _signature collection procedure_ by sending the request to every other IIN Agent in `NETWORK 1`. For example, on if `Org1` is another unit of `NETWORK 1`, it is sent to `IIN Agent Org1`. The requestees return signatures over the structure generated above to `IIN Agent Org2`. - * This can be orchestrated completely by the triggering agent, which sends requests and receives responses from every other IIN Agent. - * Alternatively, this could be a flow, where the trigger agent is simply the first node to generate a signature after which the request is handed off to another node. Eventually, when enough signatures are collected, a ledger update can be triggered (see Step 6 further below) -3. (_Optional_) Requestee's IIN Agent (`IIN Agent Org1`) confirms the presence and validity of the Network DID of `NETWORK 2` on the IIN ledger and fetches the network DID document. This replicates what `IIN Agent Org2` did in Network Identity Validation [protocol](./network-identity-validation.md). This step is optional since the identity validation might already be done by the requestee and hence the validation information might be cached and used for providing the attestation. -4. The requestee (`IIN Agent Org1`) validates the Security Domain info for `NETWORK 2` units, as well as the relay endpoints. -5. When the requester unit - `IIN Agent Org2` obtains signatures from all IIN Agents in `NETWORK 1`, it updates the Security Domain info on the network ledger by submitting a transaction to the Interoperation module (a chaincode in the Fabric implementation, a Cordapp in the Corda implementation). The transaction payload consists of: `{, [],[ -> ]},[,]}`. The signatures are validated by multiple peers and committed to the ledger after passing through a consensus protocol. +The first phase in the above diagram, involving [registration](./identity-syncing.md), [discovery](../discovery/discovery.md), and [validation])(./network-identity-validation.md) are covered in other specifications. In this draft, we only specify the bilateral protocol occurring between sets of IIN Agents representing two independent security domains' members. + +The communication among IIN Agents of the security domain governing `Ledger A` to collect attestations can occur in one of two ways: + * It can be orchestrated completely by the triggering agent (in this case `A2`), which sends requests and receives responses from every other local IIN Agent. + * Alternatively, it could be a flow, where the trigger agent is simply the first node to produce an attestation after which the request is passed to another agent. This proces concludes when enough attestations are collected. + +(We recommend the first approach in Weaver for simplicity of implementation.) + +The validation procedures marked in the figure above may include an agent confirming the presence and validity of its security domain's DID record in an IIN. But in case two networks are attempting to interoperate without relying on DID infrastructure (IINs and trust anchors), these checks can be skipped. Even if DID infrastructure is present and relied upon, these checks need not be done as part of the protocol; the result of a past check can be cached and retrieved as needed (assuming freshness of cached records is ascertained). + +Finally, a foreign security domain's membership info is recorded via the [interoperation module](../../models/infrastructure/interoperation-modules.md) deployed in the network (a chaincode in Fabric, a CorDapp in Corda, etc.). The logic in this module must validate and authenticate the various signatures in the transaction payload before committing to the ledger via the network's native consensus protocol. diff --git a/rfcs/protocols/identity/identity-change-updates.md b/rfcs/protocols/identity/identity-change-updates.md deleted file mode 100644 index 3dbd3fca4..000000000 --- a/rfcs/protocols/identity/identity-change-updates.md +++ /dev/null @@ -1,27 +0,0 @@ - -# Credentials update with changes in identity plane - -- RFC: 02-012-appendix-c -- Authors: Venkatraman Ramakrishna, Krishnasuri Narayanam, Bishakh Chandra Ghosh, Ermyas Abebe -- Status: Proposed -- Since: 24-Sep-2021 - - -# Overview - -As mentioned in the [identity exchange protocol](./identity-syncing.md), there are three phases in the process between a network making itself known via an IIN to the point when its identity and certificates are accepted and recorded by a foreign network with which an interoperation (in the data plane) may occur in the future. These phases are separate protocol instances in themselves, though they must follow a particular chronological order. The full process is illustrated in the figure below: - - - -First, each network unit of a network (above, without loss of generality, `NETWORK 1`) must register its network identity with an IIN. So Step 1 in the above figure must be carried out the network units before a network is ready to interoperate with another. - -Second, any of the network units of a network (above, without loss of generality, `NETWORK 2`) can fetch the latest identity and certificate information for a foreign network (again, without loss of generality, `NETWORK 1`) based on a trigger, which can be any of the following: -* Manual trigger applied by a network administrator -* Timeout after a poll interval: the network unit in `NETWORK 1` polls for updates to `NETWORK 2` -* Event notification: a network unit in `NETWORK 1` receives an event notifying it about a change in `NETWORK 2` - -Third, any of the network units of a network that have obtained updated information about another network can run a process leading up the recording of this information as a set of security domains to its local ledger using the interoperation module (in Fabric, the interoperation chaincode; in Corda, the interoperation Cordapp). This process involves a flow among the various network units to collect a multi-signature, as is described in the [data plane identity configuration protocol](./data-plane-identity-configuration.md). diff --git a/rfcs/protocols/identity/identity-syncing.md b/rfcs/protocols/identity/identity-syncing.md index 66c96141f..c879c8d99 100644 --- a/rfcs/protocols/identity/identity-syncing.md +++ b/rfcs/protocols/identity/identity-syncing.md @@ -3,18 +3,18 @@ SPDX-License-Identifier: CC-BY-4.0 --> -# Protocols for Decentralized Network-Identity Configuration, Exchannge and Validation, for Interoperation +# Security Domain Identity and Membership Exchanges - RFC: 02-012 - Authors: Venkatraman Ramakrishna, Krishnasuri Narayanam, Bishakh Chandra Ghosh, Ermyas Abebe - Status: Proposed - Supersedes: 02-011 -- Since: 24-Sep-2021 +- Since: 25-Aug-2022 ## Summary -This is an identity plane protocol to exchange identity information between two interoperating blockchain networks. This establishes a basis (or trust anchor) for proof-based data sharing. For background and component information, start [here](../../models/identity/network-identity-management.md). +This is an identity plane protocol to exchange identity information between two interoperating blockchain networks. This establishes a trust basis for proof-based data sharing. For background and component information, start [here](../../models/identity/network-identity-management.md). The entire Network Identity Discovery and Management protocol involves the following protocols for different steps: @@ -110,7 +110,7 @@ A DID registration request, that is the DID create method of the IIN registry, m **Step 5. Trust anchors issue identity VC to participant DID.** -A DID and a DID document do not inherently carry any personal data such as physical identity / real worl identity ([binding did to physical identity](https://w3c.github.io/did-core/#binding-to-physical-identity)). Therefore, to map a participant's did to its physical identity, some trust anchor must issue VCs attesting the real world physical identity of the participant , to the participant's DID. The participant itself becomes the holder of those identity VCs and can present it to others to prove its physical identity. +A DID and a DID document do not inherently carry any personal data such as physical identity / real world identity ([binding did to physical identity](https://w3c.github.io/did-core/#binding-to-physical-identity)). Therefore, to map a participant's did to its physical identity, some trust anchor must issue VCs attesting the real world physical identity of the participant , to the participant's DID. The participant itself becomes the holder of those identity VCs and can present it to others to prove its physical identity. > Step 5 has flexibility in terms of how many trust anchors and which trust anchors issue identity VC to a particular participant. These identity VCs might be used for validating network identity by other network participants. See *Network Identity Validation* step. @@ -266,16 +266,17 @@ The first step towards interoperation between two blockchain networks is discove Given the DID of a foreign network in the format `did::` (example `did:iinindy:tradelens`), the foreign network can be discovered by standard DID resolution. The IIN agent of a participant of a local network contacts the DID registry (example: `iinindy`) and resolves the DID to download the Network DID document. -Find the network discovery protocol specifications [here](../discovery/readme.md). +See the [network discovery protocol specifications](../discovery/discovery.md) for more details. -## Network Identity Validation +## Security Domain Identity Validation + +After a network has been discovered, and its Security Domain DID document has been fetched, the authenticity of that DID must be verified. See the [Security Domain Identity Validation protocol](./network-identity-validation.md) for details of how the network's identity is validated. -After discovery of the network and fetching the Network DID document, the authenticity of it has to be verified by validating the identity of the network. This is carried out through the Network Identity Validation protocol described [here](./network-identity-validation.md). ## Data Plane Identity Configuration -After foreign network identities are validated, it has to be configured in the data plane for interoperation. A single participant unit cannot update identity information in the network's ledger. This needs agreement among all the participanting units. This agreement is ensured through collection of signatures through an application level flow as discussed in detail [here](./data-plane-identity-configuration.md). +After a foreign network's (or security domain's) identity is validated, its membership information must be configured in the network's ledger for interoperation protocols to work in the data plane. A single organizational unit (or network member) cannot unilaterally update this membership information; instead, members must agree on that information before it is deemed acceptable for recording on the ledger. See the [Membership Syncing protocol specifications](./data-plane-identity-configuration.md) for details on how this is achieved by the IIN Agents representing the members self-orchestrating a flow to collect attestations. ## Updating Network DID with changing Network Structure @@ -304,6 +305,13 @@ The IIN registry authenticates a Network DID updation request based on two condi (1) The signatures must satisfy the `updatePolicy` in the `BlockchainNetworkMultiSig` verification method of the existing Network DID document. -## Dataplane credentials update with changes in identity plane +## Data Plane credentials update with changes in identity plane + +The security domain validation and membership syncing protocols must be re-run every time there is a change in a security domain's identity (DID document) or in its membership configuration. The flow diagram below illustrates the complete process from the time a change occurs in one network up to the point where its updated identity and membership info is reflected in another network's ledger as a prerequisite for data plane interoperation. Each step in this diagram represents a separate protocol: (1) is described in this document above, (2) is described in the [security domain identity validation specification](./network-identity-validation.md), and (3) in the [membership syncing specification](./data-plane-identity-configuration.md). + + -The identity exchange and validation has to be done whenever there is a change in the identity of any network. Thus, the identity exchange protocol steps explained in this document must be triggered within a network whenever the identities of the participant units of any network it wishes to interoperate with change. This is further explained [here](./identity-change-updates.md). +The trigger for Step 2 can be any of the following: +* Manual trigger applied by a network administrator +* Timeout after a poll interval: the network unit in `SECURITY DOMAIN 1` polls for updates to `SECURITY DOMAIN 2` +* Event notification: a network unit in `SECURITY DOMAIN 1` receives an event notifying it about a change in `SECURITY DOMAIN 2` diff --git a/rfcs/resources/images/protocol-identity-overview.jpg b/rfcs/resources/images/protocol-identity-overview.jpg index 24c6f878a027d40a81c41c281fce5d94425823a9..e886fce03e32b193e7b83e9feacf16cbc103f888 100755 GIT binary patch literal 99135 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

F6kv#<9g%B51q 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 => { + try { + const viewPayload = await contract.evaluateTransaction("ParseAndValidateView", address, base64ViewProto, b64ViewContent); + return viewPayload; + } catch (e) { + throw new Error(`Unable to parse and validate view: ${e}`); + } +}; + /** * Creates an address string based on a query object, networkid and remote url. **/ @@ -652,6 +664,7 @@ export { getKeyAndCertForRemoteRequestbyUserName, getPolicyCriteriaForAddress, verifyView, + parseAndValidateView, decryptRemoteChaincodeOutput, decryptRemoteProposalResponse, verifyRemoteProposalResponse, From 73995807521a580ced96da19880766866dfa5a7a Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Thu, 25 Aug 2022 20:16:02 +0000 Subject: [PATCH 104/150] Fixed image resolutions in identity protocol RFCs Signed-off-by: VRamakrishna --- rfcs/protocols/identity/data-plane-identity-configuration.md | 2 +- rfcs/protocols/identity/identity-syncing.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rfcs/protocols/identity/data-plane-identity-configuration.md b/rfcs/protocols/identity/data-plane-identity-configuration.md index d5ed4c504..ade61d466 100644 --- a/rfcs/protocols/identity/data-plane-identity-configuration.md +++ b/rfcs/protocols/identity/data-plane-identity-configuration.md @@ -20,7 +20,7 @@ The Security Domain DID of a foreign security domain contains `relayEndpoints` a Consider two security domains governing ledgers `Ledger A` and Ledger B` respectively. The first has two IIN Agents `A1` and `A2` representing two organizational units that are members of its security domain. The second has agents `B1` and `B2`. The security domain governing `Ledger A` is trying to sync the latest identity and membership info of the security domain governing `Ledger B`. Without loss of generality, we can pick `A2` as the initiator of the cross-network identity plane protocol that results in `Ledger B`'s security domain membership and relay endpoints info getting recorded in `Ledger A`. The protocol is illustrated in the figure below. (_Note_: this represents the "happy path". We will add more diagrams subsequently illustrating failures and race conditions.) - + The first phase in the above diagram, involving [registration](./identity-syncing.md), [discovery](../discovery/discovery.md), and [validation])(./network-identity-validation.md) are covered in other specifications. In this draft, we only specify the bilateral protocol occurring between sets of IIN Agents representing two independent security domains' members. diff --git a/rfcs/protocols/identity/identity-syncing.md b/rfcs/protocols/identity/identity-syncing.md index c879c8d99..231262ab3 100644 --- a/rfcs/protocols/identity/identity-syncing.md +++ b/rfcs/protocols/identity/identity-syncing.md @@ -309,7 +309,7 @@ The IIN registry authenticates a Network DID updation request based on two condi The security domain validation and membership syncing protocols must be re-run every time there is a change in a security domain's identity (DID document) or in its membership configuration. The flow diagram below illustrates the complete process from the time a change occurs in one network up to the point where its updated identity and membership info is reflected in another network's ledger as a prerequisite for data plane interoperation. Each step in this diagram represents a separate protocol: (1) is described in this document above, (2) is described in the [security domain identity validation specification](./network-identity-validation.md), and (3) in the [membership syncing specification](./data-plane-identity-configuration.md). - + The trigger for Step 2 can be any of the following: * Manual trigger applied by a network administrator From 03e8f5471bfe8c40e3299008343dc46a8672af06 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Thu, 25 Aug 2022 20:18:38 +0000 Subject: [PATCH 105/150] Fixed typos and images in RFCs Signed-off-by: VRamakrishna --- .../data-plane-identity-configuration.md | 2 +- rfcs/resources/images/interop-module.png | Bin 54453 -> 78544 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/rfcs/protocols/identity/data-plane-identity-configuration.md b/rfcs/protocols/identity/data-plane-identity-configuration.md index ade61d466..5a4a3aba0 100644 --- a/rfcs/protocols/identity/data-plane-identity-configuration.md +++ b/rfcs/protocols/identity/data-plane-identity-configuration.md @@ -22,7 +22,7 @@ Consider two security domains governing ledgers `Ledger A` and Ledger B` respect -The first phase in the above diagram, involving [registration](./identity-syncing.md), [discovery](../discovery/discovery.md), and [validation])(./network-identity-validation.md) are covered in other specifications. In this draft, we only specify the bilateral protocol occurring between sets of IIN Agents representing two independent security domains' members. +The first phase in the above diagram, involving [registration](./identity-syncing.md), [discovery](../discovery/discovery.md), and [validation](./network-identity-validation.md) are covered in other specifications. In this draft, we only specify the bilateral protocol occurring between sets of IIN Agents representing two independent security domains' members. The communication among IIN Agents of the security domain governing `Ledger A` to collect attestations can occur in one of two ways: * It can be orchestrated completely by the triggering agent (in this case `A2`), which sends requests and receives responses from every other local IIN Agent. diff --git a/rfcs/resources/images/interop-module.png b/rfcs/resources/images/interop-module.png index dcd73fbd0cb70fa70106189d2e15d67156abdd6b..15b77460b817336c4bb1bb65fa57cb541915b620 100755 GIT binary patch literal 78544 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 Phv%ZAsHuRGe-Q9rFjK{r From bb5ca73b570a58edcac04689edb8c9724055f2c0 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Fri, 26 Aug 2022 12:31:13 +0000 Subject: [PATCH 106/150] Minor updates and code fixes Signed-off-by: VRamakrishna --- common/protos-go/identity/agent.pb.go | 156 ++++++++++-------- common/protos/identity/agent.proto | 1 + .../iin-agent/src/fabric-ledger/connector.ts | 11 +- .../src/fabric-ledger/networkUtils.ts | 17 +- .../package-local.json | 2 +- .../interoperation-node-sdk/package.json | 2 +- 6 files changed, 106 insertions(+), 83 deletions(-) diff --git a/common/protos-go/identity/agent.pb.go b/common/protos-go/identity/agent.pb.go index 51069e0d9..375ecdd75 100644 --- a/common/protos-go/identity/agent.pb.go +++ b/common/protos-go/identity/agent.pb.go @@ -29,6 +29,7 @@ type NetworkUnitIdentity struct { NetworkId string `protobuf:"bytes,1,opt,name=network_id,json=networkId,proto3" json:"network_id,omitempty"` ParticipantId string `protobuf:"bytes,2,opt,name=participant_id,json=participantId,proto3" json:"participant_id,omitempty"` + Nonce string `protobuf:"bytes,3,opt,name=nonce,proto3" json:"nonce,omitempty"` } func (x *NetworkUnitIdentity) Reset() { @@ -77,6 +78,13 @@ func (x *NetworkUnitIdentity) GetParticipantId() string { return "" } +func (x *NetworkUnitIdentity) GetNonce() string { + if x != nil { + return x.Nonce + } + return "" +} + // Association of signature (over arbitrary data) and signer identity type Attestation struct { state protoimpl.MessageState @@ -316,87 +324,89 @@ var file_identity_agent_proto_rawDesc = []byte{ 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x1a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x61, 0x63, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x22, 0x5b, 0x0a, 0x13, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x55, 0x6e, 0x69, 0x74, + 0x6f, 0x22, 0x71, 0x0a, 0x13, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x55, 0x6e, 0x69, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0d, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x97, - 0x01, 0x0a, 0x0b, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x48, - 0x0a, 0x0d, 0x75, 0x6e, 0x69, 0x74, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x55, 0x6e, - 0x69, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x0c, 0x75, 0x6e, 0x69, 0x74, - 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, - 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, - 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x92, 0x01, 0x0a, 0x12, 0x41, 0x74, 0x74, - 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, - 0x3d, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, - 0x69, 0x70, 0x52, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x3d, - 0x0a, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xda, 0x02, - 0x0a, 0x16, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, - 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x65, 0x0a, 0x0f, 0x73, 0x65, 0x63, 0x75, - 0x72, 0x69, 0x74, 0x79, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x3c, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, - 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, 0x75, 0x72, - 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, - 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x65, 0x74, 0x52, - 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, + 0x0d, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x14, + 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6e, + 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x97, 0x01, 0x0a, 0x0b, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x48, 0x0a, 0x0d, 0x75, 0x6e, 0x69, 0x74, 0x5f, 0x69, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x55, 0x6e, 0x69, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x52, 0x0c, 0x75, 0x6e, 0x69, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x20, + 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x92, + 0x01, 0x0a, 0x12, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x3d, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, + 0x68, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2e, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, + 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x68, 0x69, 0x70, 0x12, 0x3d, 0x0a, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x22, 0xda, 0x02, 0x0a, 0x16, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, + 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x65, + 0x0a, 0x0f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, + 0x64, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, + 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, + 0x69, 0x70, 0x53, 0x65, 0x74, 0x52, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, + 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x3f, 0x0a, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, + 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x97, 0x01, 0x0a, 0x15, 0x41, 0x74, 0x74, 0x65, 0x73, + 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x65, 0x74, + 0x12, 0x3d, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x65, + 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, + 0x68, 0x69, 0x70, 0x52, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x3f, 0x0a, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x1a, 0x97, 0x01, 0x0a, 0x15, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x65, 0x74, 0x12, 0x3d, 0x0a, 0x0a, 0x6d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, - 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, - 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x0a, 0x6d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x3f, 0x0a, 0x0c, 0x61, 0x74, 0x74, - 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, - 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x74, - 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0xa2, 0x03, 0x0a, 0x08, 0x49, - 0x49, 0x4e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x4b, 0x0a, 0x11, 0x53, 0x79, 0x6e, 0x63, 0x45, - 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x23, 0x2e, 0x69, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x55, 0x6e, 0x69, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, - 0x63, 0x6b, 0x22, 0x00, 0x12, 0x56, 0x0a, 0x1c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, - 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x55, 0x6e, 0x69, - 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x19, - 0x53, 0x65, 0x6e, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x2e, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, - 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x1a, 0x0f, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, - 0x12, 0x4f, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x74, 0x74, 0x65, 0x73, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, - 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x0f, - 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, - 0x00, 0x12, 0x4c, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, - 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, - 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, - 0x75, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x5a, 0x51, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, - 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x69, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x32, 0xa2, 0x03, 0x0a, 0x08, 0x49, 0x49, 0x4e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x4b, 0x0a, + 0x11, 0x53, 0x79, 0x6e, 0x63, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x12, 0x23, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x55, 0x6e, 0x69, 0x74, 0x49, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x56, 0x0a, 0x1c, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x2e, 0x69, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x55, 0x6e, 0x69, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, + 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, + 0x22, 0x00, 0x12, 0x52, 0x0a, 0x19, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x22, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, + 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, + 0x68, 0x69, 0x70, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, + 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x2e, 0x69, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, + 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, + 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, + 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x41, + 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x2e, 0x69, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, + 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, + 0x69, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, + 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, 0x75, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, + 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5a, 0x51, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, + 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, + 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, + 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, + 0x2d, 0x67, 0x6f, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/common/protos/identity/agent.proto b/common/protos/identity/agent.proto index 5a64a3a26..61d4f44b2 100644 --- a/common/protos/identity/agent.proto +++ b/common/protos/identity/agent.proto @@ -26,6 +26,7 @@ service IINAgent { message NetworkUnitIdentity { string network_id = 1; string participant_id = 2; + string nonce = 3; } // Association of signature (over arbitrary data) and signer identity diff --git a/core/identity-management/iin-agent/src/fabric-ledger/connector.ts b/core/identity-management/iin-agent/src/fabric-ledger/connector.ts index d08cc80b2..044fc017c 100644 --- a/core/identity-management/iin-agent/src/fabric-ledger/connector.ts +++ b/core/identity-management/iin-agent/src/fabric-ledger/connector.ts @@ -18,11 +18,11 @@ export class FabricConnector extends LedgerBase { orgMspId: string; walletPath: string; - constructor(ledgerId: string, contractId: string, connectionProfilePath: string, configFilePath: string, walletPath: string) { + constructor(ledgerId: string, contractId: string, networkId: string, connectionProfilePath: string, configFilePath: string, walletPath: string) { super(ledgerId, contractId); this.connectionProfilePath = connectionProfilePath ? connectionProfilePath : path.resolve(__dirname, './', 'connection_profile.json'); this.configFilePath = configFilePath ? configFilePath : path.resolve(__dirname, './', 'config.json'); - this.networkId = process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1'; + this.networkId = networkId ? networkId : 'network1'; if (!fs.existsSync(configFilePath)) { throw new Error('Config does not exist at path: ' + configFilePath); } @@ -47,13 +47,12 @@ export class FabricConnector extends LedgerBase { // Invoke a contract to drive a transaction // TODO: Add parameters corresponding to the output of a flow among IIN agents - async invokeContract() { - await invokeFabricChaincode(this.walletPath, this.connectionProfilePath, this.configFilePath, this.ledgerId, this.contractId, "", []); + async invokeContract(): Promise { + return await invokeFabricChaincode(this.walletPath, this.connectionProfilePath, this.configFilePath, this.ledgerId, this.contractId, "", []); } // Query a contract to fetch information from the ledger async queryContract(): Promise { - const result = await queryFabricChaincode(this.walletPath, this.connectionProfilePath, this.configFilePath, this.ledgerId, this.contractId, "", []); - return result; + return await queryFabricChaincode(this.walletPath, this.connectionProfilePath, this.configFilePath, this.ledgerId, this.contractId, "", []); } } diff --git a/core/identity-management/iin-agent/src/fabric-ledger/networkUtils.ts b/core/identity-management/iin-agent/src/fabric-ledger/networkUtils.ts index 24328cd03..fc1a6640a 100644 --- a/core/identity-management/iin-agent/src/fabric-ledger/networkUtils.ts +++ b/core/identity-management/iin-agent/src/fabric-ledger/networkUtils.ts @@ -9,6 +9,7 @@ import { Channel } from 'fabric-common'; import * as path from 'path'; import * as fs from 'fs'; import { getWallet } from './walletUtils'; +import * as utils from "../common/utils"; // Get a handle to a network gateway using existing wallet credentials const getNetworkGateway = async ( @@ -166,9 +167,15 @@ async function invokeFabricChaincode( console.log('Running invocation on Fabric channel and chaincode'); try { const gatewayAndContract = await getNetworkContract(walletPath, connectionProfilePath, configFilePath, channelId, chaincodeId); - await gatewayAndContract.contract.submitTransaction(functionName, ...args); + const [result, submitError] = await utils.handlePromise( + gatewayAndContract.contract.submitTransaction(functionName, ...args), + ); + if (submitError) { + throw new Error(`submitTransaction Error: ${submitError}`); + } // Disconnect from the gateway. gatewayAndContract.gateway.disconnect(); + return result; } catch (error) { console.error(`Failed to submit transaction: ${error}`); throw error; @@ -187,9 +194,15 @@ async function queryFabricChaincode( console.log('Running query on Fabric channel and chaincode'); try { const gatewayAndContract = await getNetworkContract(walletPath, connectionProfilePath, configFilePath, channelId, chaincodeId); - const result = await gatewayAndContract.contract.evaluateTransaction(functionName, ...args); + const [result, evalError] = await utils.handlePromise( + gatewayAndContract.contract.evaluateTransaction(functionName, ...args), + ); + if (evalError) { + throw new Error(`evaluateTransaction Error: ${evalError}`); + } // Disconnect from the gateway. gatewayAndContract.gateway.disconnect(); + return result; } catch (error) { console.error(`Failed to submit query: ${error}`); throw error; diff --git a/sdks/fabric/interoperation-node-sdk/package-local.json b/sdks/fabric/interoperation-node-sdk/package-local.json index 0e2dcf91a..d2636a3ae 100644 --- a/sdks/fabric/interoperation-node-sdk/package-local.json +++ b/sdks/fabric/interoperation-node-sdk/package-local.json @@ -6,7 +6,7 @@ "blockchain", "interoperability" ], - "version": "1.4.2", + "version": "1.4.3", "author": "V. Ramakrishna", "tag": "latest", "main": "build/index.js", diff --git a/sdks/fabric/interoperation-node-sdk/package.json b/sdks/fabric/interoperation-node-sdk/package.json index 55b96c8d0..e030663a3 100644 --- a/sdks/fabric/interoperation-node-sdk/package.json +++ b/sdks/fabric/interoperation-node-sdk/package.json @@ -6,7 +6,7 @@ "blockchain", "interoperability" ], - "version": "1.4.2", + "version": "1.4.3", "author": "V. Ramakrishna", "tag": "latest", "main": "build/index.js", From 00e91d8f5c51d4bf6b540d3d92bf4932913c7a59 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Sun, 28 Aug 2022 18:47:47 +0000 Subject: [PATCH 107/150] Edited Identity Protocol RFCs Signed-off-by: VRamakrishna --- rfcs/README.md | 108 +++++----- rfcs/protocols/discovery/discovery.md | 11 +- rfcs/protocols/discovery/negotiation.md | 4 +- rfcs/protocols/identity/identity-syncing.md | 202 +++++++++--------- ...configuration.md => membership-syncing.md} | 6 +- .../identity/network-identity-validation.md | 6 +- .../resources/images/network_did_creation.jpg | Bin 73132 -> 104036 bytes .../participant_identity_configuration.jpg | Bin 66253 -> 74235 bytes 8 files changed, 167 insertions(+), 170 deletions(-) rename rfcs/protocols/identity/{data-plane-identity-configuration.md => membership-syncing.md} (76%) diff --git a/rfcs/README.md b/rfcs/README.md index 79cf573a7..a8ece98ab 100644 --- a/rfcs/README.md +++ b/rfcs/README.md @@ -26,59 +26,61 @@ The RFC numbering convention is: `:`. The list of types (``) is | 02 | Protocols and Mechanisms | | 03 | Data Structures and Formats | -| RFC # | Title | Category | Status | -|--------|----------------------------------|----------|-----------------------------------------------------------------| -| 01-001 | Views | Model | [Proposed](./models/ledger/views.md) | -| 01-002 | Cryptographic Proofs | Model | [Proposed](./models/ledger/cryptographic-proofs.md) | -| 01-003 | Verifiable Observation of State | Model | [Draft](./models/ledger/observation-of-state.md) | -| 01-004 | Events | Model | [Draft](./models/ledger/events.md) | -| 01-005 | Cross-Ledger Operations | Model | [Draft](./models/ledger/cross-ledger-operations.md) | -| 01-006 | Atomic Cross-Ledger Transactions | Model | [Proposed](./models/ledger/atomic-cross-ledger-transactions.md) | -| 01-007 | Security Domains | Model | [Proposed](./models/security/security-domains.md) | -| 01-008 | End-to-End Confidentiality | Model | [Proposed](./models/security/confidentiality.md) | -| 01-009 | Relays | Model | [Proposed](./models/infrastructure/relays.md) | -| 01-010 | Interoperation Modules | Model | [Proposed](./models/infrastructure/interoperation-modules.md) | -| 01-011 | Identity Management | Model | [Proposed](./models/identity/network-identity-management.md) | -| 01-012 | Identity Registry | Model | [Proposed](./models/identity/iin.md) | -| 01-013 | Identity Agent | Model | [Proposed](./models/identity/iin-agent.md) | -| 01-014 | Identity Trust Anchor Agent | Model | [Retired](./models/identity/iin-steward-agent.md) | -| 01-015 | Network Identity Updates | Model | [Proposed](./models/identity/identity-update-policy.md) | -| 02-001 | Data Sharing | Protocol | [Proposed](./protocols/data-sharing/generic.md) | -| 02-002 | Data Sharing in Fabric | Protocol | [Proposed](./protocols/data-sharing/fabric.md) | -| 02-003 | Data Sharing in Corda | Protocol | [Proposed](./protocols/data-sharing/corda.md) | -| 02-004 | Asset Exchange through HTLC | Protocol | [Proposed](./protocols/asset-exchange/generic-htlc.md) | -| 02-005 | Asset Exchange in Fabric | Protocol | [Proposed](./protocols/asset-exchange/fabric-htlc.md) | -| 02-006 | Asset Exchange in Corda | Protocol | [Proposed](./protocols/asset-exchange/corda-htlc.md) | -| 02-007 | Asset Exchange in Besu | Protocol | [Draft](./protocols/asset-exchange/besu-htlc.md) | -| 02-008 | Asset Transfer | Protocol | [Proposed](./protocols/asset-transfer/generic.md) | -| 02-009 | Asset Transfer in Fabric | Protocol | [Proposed](./protocols/asset-transfer/fabric.md) | -| 02-010 | Asset Transfer in Corda | Protocol | [Proposed](./protocols/asset-transfer/corda.md) | -| 02-011 | Identity and Config Sharing | Protocol | [Superseded](./protocols/identity/id-config-sharing.md) | -| 02-012 | Identity Syncing | Protocol | [Proposed](./protocols/identity/identity-syncing.md) | -| 02-013 | Discovery | Protocol | [Draft](./protocols/discovery/discovery.md) | -| 02-014 | Negotiation | Protocol | [Draft](./protocols/discovery/negotiation.md) | -| 02-015 | Transaction Invocation | Protocol | [Draft](./protocols/contract-invocation/invocation.md) | -| 02-016 | Event Bus | Protocol | [Draft](./protocols/events/event-bus.md) | -| 03-001 | View Address | Format | [Proposed](./formats/views/addressing.md) | -| 03-002 | Generic View | Format | [Proposed](./formats/views/definition.md) | -| 03-003 | Fabric View | Format | [Proposed](./formats/views/fabric.md) | -| 03-004 | Corda View | Format | [Proposed](./formats/views/corda.md) | -| 03-005 | Besu View | Format | [Draft](./formats/views/besu.md) | -| 03-006 | Ethereum View | Format | [Draft](./formats/views/ethereum.md) | -| 03-007 | View Request | Format | [Proposed](./formats/views/request.md) | -| 03-008 | Access Control Policy | Format | [Proposed](./formats/policies/access-control.md) | -| 03-009 | Proof Verification Policy | Format | [Proposed](./formats/policies/proof-verification.md) | -| 03-010 | Verification Policy DSL | Format | [Draft](./formats/policies/dsl.md) | -| 03-011 | Membership | Format | [Proposed](./formats/network/membership.md) | -| 03-012 | Network Identities | Format | [Proposed](./formats/network/identity.md) | -| 03-013 | Asset Exchange Units | Format | [Proposed](./formats/assets/exchange.md) | -| 03-014 | Asset Transfer Units | Format | [Proposed](./formats/assets/transfer.md) | -| 03-015 | Relay Messages | Format | [Proposed](./formats/communication/relay.md) | -| 03-016 | Fabric Interop Chaincode API | Format | [Proposed](./formats/network/fabric-interop-chaincode.md) | -| 03-017 | Interoperation CorDapp API | Format | [Proposed](./formats/network/interop-cordapp.md) | -| 03-018 | Besu Interop Contract API | Format | [Proposed](./formats/network/besu-interop-contract.md) | -| 03-019 | Application SDK | Format | [Proposed](./formats/network/application-sdk.md) | -| 03-020 | DID Method for DLT Networks | Format | [Proposed](./formats/network/iin_method.md) | +| RFC # | Title | Category | Status | +|--------|-------------------------------------|----------|-----------------------------------------------------------------| +| 01-001 | Views | Model | [Proposed](./models/ledger/views.md) | +| 01-002 | Cryptographic Proofs | Model | [Proposed](./models/ledger/cryptographic-proofs.md) | +| 01-003 | Verifiable Observation of State | Model | [Draft](./models/ledger/observation-of-state.md) | +| 01-004 | Events | Model | [Draft](./models/ledger/events.md) | +| 01-005 | Cross-Ledger Operations | Model | [Draft](./models/ledger/cross-ledger-operations.md) | +| 01-006 | Atomic Cross-Ledger Transactions | Model | [Proposed](./models/ledger/atomic-cross-ledger-transactions.md) | +| 01-007 | Security Domains | Model | [Proposed](./models/security/security-domains.md) | +| 01-008 | End-to-End Confidentiality | Model | [Proposed](./models/security/confidentiality.md) | +| 01-009 | Relays | Model | [Proposed](./models/infrastructure/relays.md) | +| 01-010 | Interoperation Modules | Model | [Proposed](./models/infrastructure/interoperation-modules.md) | +| 01-011 | Identity Management | Model | [Proposed](./models/identity/network-identity-management.md) | +| 01-012 | Identity Registry | Model | [Proposed](./models/identity/iin.md) | +| 01-013 | Identity Agent | Model | [Proposed](./models/identity/iin-agent.md) | +| 01-014 | Identity Trust Anchor Agent | Model | [Retired](./models/identity/iin-steward-agent.md) | +| 01-015 | Network Identity Updates | Model | [Proposed](./models/identity/identity-update-policy.md) | +| 02-001 | Data Sharing | Protocol | [Proposed](./protocols/data-sharing/generic.md) | +| 02-002 | Data Sharing in Fabric | Protocol | [Proposed](./protocols/data-sharing/fabric.md) | +| 02-003 | Data Sharing in Corda | Protocol | [Proposed](./protocols/data-sharing/corda.md) | +| 02-004 | Asset Exchange through HTLC | Protocol | [Proposed](./protocols/asset-exchange/generic-htlc.md) | +| 02-005 | Asset Exchange in Fabric | Protocol | [Proposed](./protocols/asset-exchange/fabric-htlc.md) | +| 02-006 | Asset Exchange in Corda | Protocol | [Proposed](./protocols/asset-exchange/corda-htlc.md) | +| 02-007 | Asset Exchange in Besu | Protocol | [Draft](./protocols/asset-exchange/besu-htlc.md) | +| 02-008 | Asset Transfer | Protocol | [Proposed](./protocols/asset-transfer/generic.md) | +| 02-009 | Asset Transfer in Fabric | Protocol | [Proposed](./protocols/asset-transfer/fabric.md) | +| 02-010 | Asset Transfer in Corda | Protocol | [Proposed](./protocols/asset-transfer/corda.md) | +| 02-011 | Identity and Config Sharing | Protocol | [Superseded](./protocols/identity/id-config-sharing.md) | +| 02-012 | Cross-Domain Identity Management | Protocol | [Proposed](./protocols/identity/identity-syncing.md) | +| 02-013 | Security Domain Discovery | Protocol | [Draft](./protocols/discovery/discovery.md) | +| 02-014 | Cross-Domain Negotiation | Protocol | [Draft](./protocols/discovery/negotiation.md) | +| 02-015 | Transaction Invocation | Protocol | [Draft](./protocols/contract-invocation/invocation.md) | +| 02-016 | Event Bus | Protocol | [Draft](./protocols/events/event-bus.md) | +| 02-017 | Security Domain Identity Validation | Protocol | [Proposed](./protocols/events/network-identity-validation.md) | +| 02-018 | Cross-Domain Membership Syncing | Protocol | [Proposed](./protocols/events/membership-syncing.md) | +| 03-001 | View Address | Format | [Proposed](./formats/views/addressing.md) | +| 03-002 | Generic View | Format | [Proposed](./formats/views/definition.md) | +| 03-003 | Fabric View | Format | [Proposed](./formats/views/fabric.md) | +| 03-004 | Corda View | Format | [Proposed](./formats/views/corda.md) | +| 03-005 | Besu View | Format | [Draft](./formats/views/besu.md) | +| 03-006 | Ethereum View | Format | [Draft](./formats/views/ethereum.md) | +| 03-007 | View Request | Format | [Proposed](./formats/views/request.md) | +| 03-008 | Access Control Policy | Format | [Proposed](./formats/policies/access-control.md) | +| 03-009 | Proof Verification Policy | Format | [Proposed](./formats/policies/proof-verification.md) | +| 03-010 | Verification Policy DSL | Format | [Draft](./formats/policies/dsl.md) | +| 03-011 | Membership | Format | [Proposed](./formats/network/membership.md) | +| 03-012 | Network Identities | Format | [Proposed](./formats/network/identity.md) | +| 03-013 | Asset Exchange Units | Format | [Proposed](./formats/assets/exchange.md) | +| 03-014 | Asset Transfer Units | Format | [Proposed](./formats/assets/transfer.md) | +| 03-015 | Relay Messages | Format | [Proposed](./formats/communication/relay.md) | +| 03-016 | Fabric Interop Chaincode API | Format | [Proposed](./formats/network/fabric-interop-chaincode.md) | +| 03-017 | Interoperation CorDapp API | Format | [Proposed](./formats/network/interop-cordapp.md) | +| 03-018 | Besu Interop Contract API | Format | [Proposed](./formats/network/besu-interop-contract.md) | +| 03-019 | Application SDK | Format | [Proposed](./formats/network/application-sdk.md) | +| 03-020 | DID Method for DLT Networks | Format | [Proposed](./formats/network/iin_method.md) | ## RFC Process diff --git a/rfcs/protocols/discovery/discovery.md b/rfcs/protocols/discovery/discovery.md index a3c23380c..1cd2656cd 100644 --- a/rfcs/protocols/discovery/discovery.md +++ b/rfcs/protocols/discovery/discovery.md @@ -3,19 +3,16 @@ SPDX-License-Identifier: CC-BY-4.0 --> -# Discovery Protocol +# Discovering Foreign Security Domains - RFC: 02-013 - Authors: Bishakh Chandra Ghosh, Venkatraman Ramakrishna, Krishnasuri Narayanam, Ermyas Abebe - Status: Draft -- Since: 25-Aug-2022 +- Since: 27-Aug-2022 ## Summary -When a network ("local network" from here on) tries to configure the identity of another network ("foreign network" from here on) for interoperation, the broad steps involved are (i) Network Discovery (ii) Security Domain Identity Validation. Both these steps are carried out by the IIN agent of the participants of the local network. +This document covers the process by which a network (or security domain) discovers the identity of another as a prelude to [validation](../identity/network-identity-validation.md) and [syncing of membership information](../identity/membership-syncing.md). -Whether each participant needs to carry out the discovery and validation, or a subset of participants will do it depends entirely on the trust basis of the network. This is covered in Security Domain Identity Configuration step. - - -> Note: It is the IIN's responsibility to authenticate a Network DID creation or updation. Therefore, local network must trust the IIN to trust the fact that the resolved Network DID is created by proper attestations from its controller participants. Given a DLT based IIN which allows anyone to monitor the ledger, any IIN agent can validate the authenticity of a Network DID by validating the Network DID creation/updation requests from the ledger. +At its simplest, this can be a trivial exercise of hitting a well-known website that serves DID records for the security domains one is interesting in interoperating with. But more complex situations are possible, involving multiple IINs and name resolution services. diff --git a/rfcs/protocols/discovery/negotiation.md b/rfcs/protocols/discovery/negotiation.md index 9b27deec7..9c9f9d57f 100644 --- a/rfcs/protocols/discovery/negotiation.md +++ b/rfcs/protocols/discovery/negotiation.md @@ -3,12 +3,12 @@ SPDX-License-Identifier: CC-BY-4.0 --> -# Negotiation Protocol for End-to-End Connection Setup +# Cross-Security Domain Negotiation for Data Plane Connection Setup - RFC: 02-014 - Authors: Venkatraman Ramakrishna, Krishnasuri Narayanam, Sandeep Nishad, Dhinakaran Vinayagamurthy - Status: Draft -- Since: 02-Apr-2022 +- Since: 27-Aug-2022 ## Summary diff --git a/rfcs/protocols/identity/identity-syncing.md b/rfcs/protocols/identity/identity-syncing.md index 231262ab3..550be3701 100644 --- a/rfcs/protocols/identity/identity-syncing.md +++ b/rfcs/protocols/identity/identity-syncing.md @@ -3,7 +3,7 @@ SPDX-License-Identifier: CC-BY-4.0 --> -# Security Domain Identity and Membership Exchanges +# Cross-Domain Identity and Membership Syncing - RFC: 02-012 - Authors: Venkatraman Ramakrishna, Krishnasuri Narayanam, Bishakh Chandra Ghosh, Ermyas Abebe @@ -14,58 +14,55 @@ ## Summary -This is an identity plane protocol to exchange identity information between two interoperating blockchain networks. This establishes a trust basis for proof-based data sharing. For background and component information, start [here](../../models/identity/network-identity-management.md). +This is set of identity plane protocols to enable two interoperating blockchain networks, i.e., two independent security domains, to discover, offer, and validate each other's identities and memberships. This establishes a trust basis for proof-based [data sharing](../data-sharing/generic.md) and [asset transfer](../asset-transfer/generic.md) data plane protocols. For background information and an overview of the architectural assumptions, start with the [identity management specs](../../models/identity/network-identity-management.md). -The entire Network Identity Discovery and Management protocol involves the following protocols for different steps: +We can list the protocols that comprise an end-to-end process from network creation to setting the basis for data plane interoperation in sequence as follows: -1. Particpant Unit Identity Creation -2. Network Identity Creation as Network DID -3. Netwrok Discovery -4. Network Identity Validation -5. Data Plane Identity Configuration -6. Updating Network DID with changing Network Structure +1. Organizational Unit Identity Creation +2. Creation of a Security Domain DID for a Network +3. Security Domain Discovery +4. Security Domain Identity Validation +5. Security Domain Membership Syncing +6. Syncing Identity and Membership upon Network Structure Change ## Roles There are different units in the identity plane with different roles as follows: -**participant** - A blockchain network's participant unit such as an organization or individual. +**member** - An organizationa unit that is also a blockchain/DLT network's member. -**network** - A blockchain network that is formed of participants. +**security domain** - A blockchain/DLT network or subgroup of a blockchain/DLT network that is self-sovereign for identity issuance and governance purposes. -**IIN** - The Interoperation Identity Network consisting of the `IIN registry`, `IIN nodes`, and `trust anchors`. +**IIN** - The Interoperation Identity Network consisting of an `IIN registry`, `IIN nodes`, and `trust anchors`. See the [IIN spec](../../models/identity/iin.md) for more details. +**IIN registry** - Verifiable data registry maintaining DID records. -**IIN registry** - DID registry and verifiable data registry provided by the IIN. +**IIN nodes** - IIN nodes that maintain a shared DLT-based registry and act as validators/miners of transactions. -**IIN nodes** - Nodes that maintain the IIN DLT based registry acting as validators/miners of transactions. +**trust anchor** - A well-known entity (individual/organization) that issues VCs to assert claims about an organizational unit or security domain. These claims include, but are not limited to, identity and network membership. Different networks/domains and the organization units that constitute their memberships may trust different trust anchors. -**trust anchor** - An entity (individual/organization) that issues VCs to assert claims about identity or membership or others to participant as well as networks. Different networks and participants can trust different trust anchors. +**IIN Agents** - Each security domain member controls at least one IIN Agent, which interfaces with at least one IIN and one trust anchor and with other members' (local or foreign) IIN Agents. -**IIN Agents** - Each `participant` has one or more IIN Agent, which is the identity plane component of the participant that interacts with the IIN and other participant's IIN Agents. -## Particpant Unit Identity Creation - -Each network participant unit such as individuals or organizations participating in any blockchain network must have their DID registered in some IIN. To create a DID in an IIN registry, the following steps are performed. +## Network Member (Organizational Unit) Identity Creation +The organizational unit corresponding to each network member must have its DID record registered in some IIN. The following steps must be performed to create a DID record in an IIN registry. +**Step 1. member chooses a unique DID** -**Step 1. participant chooses a unique DID** - -The DID is a globally unique [identifier](https://w3c.github.io/did-core/#identifier) (`did::`) which is constructed using a `method-name` and a `method-specific-id` that is unique wthin the method. Each IIN registry will have its unique `method-name` and specify how to generate the `method-specific-id` component of a DID. - +The DID is a globally unique [identifier](https://w3c.github.io/did-core/#identifier) (`did::`) which is constructed using a `method-name` and a `method-specific-id` that is unique wthin the method. Each IIN registry will have its unique `method-name` and specify how to generate the `method-specific-id` component of a DID. Example: -If `method-name` of an IIN registry is `exampleiin`, and the participant chooses a `method-specific-id` as `org1`, then `org1` must be unique within `exampleiin`, and `did:exampleiin:org1` must be unique globally. +If `method-name` of an IIN registry is `exampleiin`, and the organizational unit chooses a `method-specific-id` as `org1`, then `org1` must be unique within `exampleiin`, and `did:exampleiin:org1` must be unique globally. -> Note: An IIN registry may enforce participant DIDs to have a fixed prefix in the `method-specific-id` to determine that it is a participant DID and not a network DID. Eg: if the fixed prefix is `participant:`, then a valid participant did will be `did:exampleiin:participant:org1`. Similarly a network DID can be `did:exampleiin:network:tradelens`. +> Note: An IIN registry may mandate organizational unit DIDs to have a fixed prefix in the `method-specific-id` to signal that it is a network member's DID and not a network's (or security domain's) DID. Eg: if the fixed prefix is `member:`, then a valid participant did will be `did:exampleiin:member:org1`. Similarly a security domain DID can be `did:exampleiin:security-domain:tradelens`. -**Step 2. participant creates a DID Document** +**Step 2. member creates a DID Document** -The participant DID Document must specify one verification method with [authentication](https://w3c.github.io/did-core/#authentication) verification relationship. An example of participant DID document: +The member DID Document must specify one verification method (`verificationMethod`) with its [authentication](https://w3c.github.io/did-core/#authentication) [verification relationship](https://w3c.github.io/did-core/#dfn-verification-relationship). An example of such a member DID document is as follows: ```json { @@ -81,9 +78,9 @@ The participant DID Document must specify one verification method with [authenti } ``` -**Step 3. participant send a DID registration request to the IIN (IIN registry).** +**Step 3. member send a DID registration request to the IIN (IIN registry)** -The DID registration (create method) request must contain the DID document, as well as a signature that can be verified against the `authentication` verification method specified in the DID document. This request is sent by the `IIN Agent` of the participant. The underlying protocol dictating how the DID registration request will be sent to the IIN depends on the create method of the IIN registry. +The DID registration (`create` method) request must contain the DID document as well as a signature that can be verified against the verification method associated with the `authentication` field specified in the DID document. This request is sent by the member's IIN Agent using the appropriate DID registration protocol (i.e., `create` method) for the IIN registry. Example DID registration request: ```json @@ -102,67 +99,68 @@ Example DID registration request: "signature": "..." } ``` -Here signature is done on the DIDDocument. +Here, the `signature` is generated over the `DIDDocument`. **Step 4. IIN validates a DID registration request and creates the DID** -A DID registration request, that is the DID create method of the IIN registry, must authenticate the request. This authentication is to be done by validating the signature in the request with the help of the authentication method present in the DID Document of the request. +When an IIN registry receives a DID registration request, i.e., the DID `create` method, it must first authenticate the request by validating the `signature` in the request with reference to the authentication method present in the DID Document of the request. -**Step 5. Trust anchors issue identity VC to participant DID.** +**Step 5. Trust anchors issue identity VC to member DID** -A DID and a DID document do not inherently carry any personal data such as physical identity / real world identity ([binding did to physical identity](https://w3c.github.io/did-core/#binding-to-physical-identity)). Therefore, to map a participant's did to its physical identity, some trust anchor must issue VCs attesting the real world physical identity of the participant , to the participant's DID. The participant itself becomes the holder of those identity VCs and can present it to others to prove its physical identity. +A DID document does not contain any personal information about its holderi, like physical identity or real world identity (see [binding DID to physical identity](https://w3c.github.io/did-core/#binding-to-physical-identity) for reference). Therefore, to map a participant's DID to its physical identity, some trust anchor must issue VCs attesting real world identities of the member to its DID. The member can hold these VCs in a wallet and present them to others to prove various identities or affiliations as required in particular scenarios. -> Step 5 has flexibility in terms of how many trust anchors and which trust anchors issue identity VC to a particular participant. These identity VCs might be used for validating network identity by other network participants. See *Network Identity Validation* step. +> Any nummber of trust anchors may issue identity VCs to a member in Step 5. These identity VCs may be used for validating its security domain's identity by other members of that domain. See the *Security Domain Identity Validation* section for more details. -## Network Identity Creation as Network DID +## Security Domain Identity Creation as Security Domain DID -A network formed of participants creates its own Network DID in an IIN registry. The Network DID is controlled jointly by its participants ([group controller](https://w3c.github.io/did-core/#group-control)). This Network DID can be used as an address to the network, to discover and configure its identity during interoperation. +A security domain creates its own DID record in an IIN registry. The Security Domain DID is controlled jointly by its members according to the [group controller specification](https://w3c.github.io/did-core/#group-control). This DID can then be used as a way of addressing the network/domain, to discover and configure its identity and membership for interoperation. -Creation of a Network DID involves the following steps: +Creation of a Security Domain DID involves the following steps: -**Step 1. Creating Network DID Document** +**Step 1. Creating Securtiy Domain DID Document** -In addition to the usual fields of a DID Document, a Network DID document must contain a `verificationMethod` of type `BlockchainNetworkMultiSig`, and `networkParticipants` property listing the DIDs of the participants. -The `BlockchainNetworkMultiSig` verificationMethod defines the group controller of the Network DID. +In addition to the typical fields found in a DID Document, a Security Domain DID document must contain a `verificationMethod` of type `BlockchainNetworkMultiSig`, and `networkMembers` property listing the DIDs of the network's members. This method defines the group controller of the Security Domain DID. -Each participant in `networkParticipants` must already have a registered DID in some IIN registry. +Each member in `networkMembers` must already have a registered DID in some IIN registry. -The DID, that is the `id` property in the Network DID document can be chosen by the network. +The unique identity in the DID document, i.e., the `id` property, can be chosen by the network. -See [Network DID Identity format](../../formats/identity.md) for details about Network DID format. +See the [Security Domain DID Identity format specs](../../formats/identity.md) for more details. -**Step 2. Preparing Network DID creation request** +**Step 2. Preparing Security Domain DID creation request** -Creating a Network DID is only possible by the DID's controller. Therefore to create a Network DID for the first time, the request has to be authenticated by verifying attestations of all participants of the network. This is done while forming the Network DID creation request. +A Security Group DID can only be created by its group controller. Therefore, to create such a DID for the first time, the `create` request must be authenticated by verifying attestations of all members of the network, which are included in the DID creation request. -A Network DID creation request has a `NetworkDIDDocument` and `signatures`. `NetworkDIDDocument` contains the Network DID Document with the `networkParticipants` and a `BlockchainNetworkMultiSig` verificationMethod. The `signatures` is a set of signatures from all participants. +The Security Domain DID creation request must have the following fields: +* `SecurityDomainDIDDocument`: the security domain's DID Document with a `networkMembers` field and a `verificationMethod` of type `BlockchainNetworkMultiSig`. +* `signatures`: a set of signatures from all network members. -> Note: During NetworkDID creation, the `updatePolicy` of the `BlockchainNetworkMultiSig` verificationMethod is not used. Instead. the request has to be authenticated against all the participants in `networkParticipants` list. +> Note: During the DID creation, the `updatePolicy` field in the `verificationMethod` is not used. Instead. the request must be authorized by all the members listed in the `networkMembers` field using their signatures. -Example NetworkDID creation request: +Example Security Domain DID creation request: ```json { - "NetworkDIDDocument": { + "SecurityDomainDIDDocument": { "id": "did::", - "networkParticipants": [ - "did::", - "did::", - "did::" + "networkMembers": [ + "did::", + "did::", + "did::" ], "verificationMethod": [{ "id": "did::#multisig", "type": "BlockchainNetworkMultiSig", "controller": "did::", "multisigKeys": [ - "did::#key1", - "did::#key3", - "did::#key1" + "did::#key1", + "did::#key3", + "did::#key1" ], "updatePolicy": { "id": "did::#updatepolicy", @@ -172,11 +170,11 @@ Example NetworkDID creation request: "id": "did::#updatepolicy-1", "controller": "did::", "type": "VerifiableCondition2021", - "conditionOr": ["did::#key1", - "did::#key3" + "conditionOr": ["did::#key1", + "did::#key3" ] }, - "did::#key1" + "did::#key1" ] } }, @@ -186,9 +184,9 @@ Example NetworkDID creation request: "type": "DataplaneCredentials", "controller": "did::", "FabricCredentials": { - "did::": "Certificate3_Hash", - "did::": "Certificate2_Hash", - "did::": "Certificate3_Hash" + "did::": "Certificate3_Hash", + "did::": "Certificate2_Hash", + "did::": "Certificate3_Hash" } } ], @@ -207,42 +205,43 @@ Example NetworkDID creation request: ] }, "signatures": { - "did::": "...", - "did::": "...", - "did::": "..." + "did::": "...", + "did::": "...", + "did::": "..." } } ``` -How this request is created is out of the scopt of this specification. However, generally it is recommended that the signatures of the request are collected through a smart contract in the network blockchain itself. +A protocol among network members to collectively create uch a request is out of scope for this specification. However, we recommended that request be collecteded using a multisig smart contract deployed in the IIN, where the smart contract state machine waits for a set of signatures before automatically composing and recording the DID document for a security domain. -**Step 3. Network sends the Network DID creation request to IIN** -The Network DID creation request containing signatures from all the participants can then be sent to an IIN. This can be done by any entity's IIN agent, for example by the IIN agent of a participant of the network. How the participant is selected can vary from implementation to implementation. +**Step 3. Security Domain sends the Security Domain DID creation request to IIN** +The Security Domain DID creation request containing signatures from all the participants can be sent to an IIN by the IIN agent of any of the network members. The member selection criteria can vary across implementations. Multiple IIN agents may submit identical creation requests without causing any harm as these requests will be idempotent. -**Step 4. IIN validates a Network DID creation request** -The DID create method of the IIN registry must authenticate the a Network DID creation request differently from other DIDs. For a Network DID, the IIN first validates if the DID Document has the requisite properties: `networkParticipants`, and a verificationMethod of type `BlockchainNetworkMultiSig`. Additionally, the request must contain the signatures from all participants of the network authenticating it. +**Step 4. IIN validates a Security Domain DID creation request** -The authentication process is carried out by validating signature from each participant in the `networkParticipants` as follows: +An IIN registry must authenticate a Security Domain DID creation request differently from creation requests for other DID types. First, the IIN checks that the DID Document has the requisite properties: `networkMembers`, and a `verificationMethod` of type `BlockchainNetworkMultiSig`. Additionally, the request must contain the signatures from all members of the network as listed in the request structure. -1. The participant DID is obtained from `networkParticipants`. - - Example: `did::` -2. From the `BlockchainNetworkMultiSig` verification, which verification method for the participant will be used is determined. - - Example: `did::#key1` indicates that key1 will be used which is specified by the fragment at the end of the URI. -3. The DID Document of the participant is obtained by resolving the DID, and the required verification method is obtained. +The authentication process is carried out by validating signature from each member listed in `networkMembers` as follows: + +1. The member's organizational unit DID is obtained from `networkMembers`. + - Example: `did::` +2. The appropriate verification method for this member is looked up from the `BlockchainNetworkMultiSig` specification. + - Example: `did::#key1` indicates that key1 will be used which is specified by the fragment at the end of the URI. +3. The DID Document of the member is obtained by resolving the DID, and its verification method is looked up. - Example: ```json {​ -   "id": "did::",​ +   "id": "did::",​   ...​   "verificationMethod": [ { - "id": "did::#key1", + "id": "did::#key1", "type": "Bls12381G2Key2020", - "controller": "did::", + "controller": "did::", "publicKeyBase58": "25ETdUZDVnME6yYuAMjFRCnCPcDmYQcoZDcZuXAfeMhXPvjZg35QmZ7uctBcovA69YDM3Jf7s5BHo4u1y89nY6mHiji8yphZ4AMm4iNCRh35edSg76Dkasu3MY2VS9LnuaVQ", }] @@ -251,12 +250,12 @@ The authentication process is carried out by validating signature from each part }​ ``` -4. From `singatures` in Network DID creation request, the participant is validated with the help of the verificationMethod obtained in the previous step. +4. From the `signatures` field of the Security Domain DID creation request, the member's authenticity is verified using the `verificationMethod` obtained in the previous step. -Once each participant's signature is validated, the Network DID is registered in the IIN registry. +Once each member's signature is validated, the Security Domain DID is recorded in the IIN registry. -Since the IIN registry is a decentralized registry, the validation of a Network DID creation request is carried out by multiple peers so that consensus is reached, and the DID is committed in the registry. +Since the IIN registry is typically built on a decentralized ledger, the Security Domain DID creation request validation occurs through a consensus protocol among the IIN nodes before the DID record is committed in the registry. @@ -274,42 +273,41 @@ See the [network discovery protocol specifications](../discovery/discovery.md) f After a network has been discovered, and its Security Domain DID document has been fetched, the authenticity of that DID must be verified. See the [Security Domain Identity Validation protocol](./network-identity-validation.md) for details of how the network's identity is validated. -## Data Plane Identity Configuration - -After a foreign network's (or security domain's) identity is validated, its membership information must be configured in the network's ledger for interoperation protocols to work in the data plane. A single organizational unit (or network member) cannot unilaterally update this membership information; instead, members must agree on that information before it is deemed acceptable for recording on the ledger. See the [Membership Syncing protocol specifications](./data-plane-identity-configuration.md) for details on how this is achieved by the IIN Agents representing the members self-orchestrating a flow to collect attestations. - -## Updating Network DID with changing Network Structure +## Security Domain Membership Fetching and Recording -Permissioned blockchain networks might change with time with existing participants leaving and new participants joining the network. As a result, the Network DID also needs to be updated with the new list of participants forming the group controller. Updating the Network DID involves the following steps: +After a foreign network's (or security domain's) identity is validated, its membership information must be configured in the network's ledger for interoperation protocols to work in the data plane. A single organizational unit (or network member) cannot unilaterally update this membership information; instead, members must agree on that information before it is deemed acceptable for recording on the ledger. See the [Membership Syncing protocol specifications](./membership-syncing.md) for details on how this is achieved by the IIN Agents representing the members self-orchestrating a flow to collect attestations. -**Step 1. Creating updated Network DID Document** +## Updating Security Domain DID upon a Change in Security Domain Identity or Structure -While updating a Network DID for changing network structure, primarily two properties need to be updated: `BlockchainNetworkMultiSig` verification method, and `networkParticipants`. +Permissioned blockchain networks might morph over time, with existing members leaving and new organizational units joining. The Security Domain DID must be updated whenever the members' list comprising the group controller changes. This is done through the following steps: -The `networkParticipants` is updated with the new list of DIDs of the network participants. +**Step 1. Creating updated Security Domain DID Document** -`BlockchainNetworkMultiSig` verification method is updated with the changed updation policy. +The `BlockchainNetworkMultiSig` verification method, and `networkMembers` list must be updated to reflect the new network membership. +* `networkMembers` is updated with the list of DIDs of the new network members. +* A new update policy is associated with the `BlockchainNetworkMultiSig` verification method. -**Step 2. Network DID updation request** +**Step 2. Security Domain DID updation request** -Updating a Network DID requires the request to be authenticated against the `BlockchainNetworkMultiSig` verification method's `updatePolicy`. +A Security Domain DID update request must be validated against the `updatePolicy` associated with the current DID document's `BlockchainNetworkMultiSig` verification method. -Similar to the Network DID creation request, the updation request has a NetworkDIDDocument and signatures. NetworkDIDDocument contains the updated Network DID document and signatures is a set of signatures satisfying the `updatePolicy` in the `BlockchainNetworkMultiSig` verification method of the existing DID document, as well as the `networkParticipants`. +Similar to the creation request, the update request has the following fields: +* `SecurityDomainDIDDocument`: updated security domain's DID Document with a `networkMembers` field and a `verificationMethod` of type `BlockchainNetworkMultiSig`. +* `signatures`: a set of signatures satisfying the `updatePolicy` in the `BlockchainNetworkMultiSig` verification method of the existing DID document. -The updation request can be made by IIN agent of any participant of the network. +The update request can be made by the IIN agent of any existing (i.e., before the change) member of the network. -**Step 3. IIN validates a Network DID updation request** +**Step 3. IIN validates a Security Domain DID updation request** -The IIN registry authenticates a Network DID updation request based on two conditions: -(1) The signatures must satisfy the `updatePolicy` in the `BlockchainNetworkMultiSig` verification method of the existing Network DID document. +The IIN registry authenticates a Security Domain DID update request the same way it validates a creation request except for one change: the signature set must be validated against the existing `updatePolicy` rather than against tne entire list of `networkMembers. -## Data Plane credentials update with changes in identity plane +## Syncing Security Domain Membership Changes -The security domain validation and membership syncing protocols must be re-run every time there is a change in a security domain's identity (DID document) or in its membership configuration. The flow diagram below illustrates the complete process from the time a change occurs in one network up to the point where its updated identity and membership info is reflected in another network's ledger as a prerequisite for data plane interoperation. Each step in this diagram represents a separate protocol: (1) is described in this document above, (2) is described in the [security domain identity validation specification](./network-identity-validation.md), and (3) in the [membership syncing specification](./data-plane-identity-configuration.md). +The security domain validation and membership syncing protocols must be re-run every time there is a change in a security domain's identity (DID document) or in its membership configuration. The flow diagram below illustrates the complete process from the time a change occurs in one network up to the point where its updated identity and membership info is reflected in another network's ledger as a prerequisite for data plane interoperation. Each step in this diagram represents a separate protocol: (1) is described in this document above, (2) is described in the [security domain identity validation specification](./network-identity-validation.md), and (3) in the [membership syncing specification](./membership-syncing.md). - + The trigger for Step 2 can be any of the following: * Manual trigger applied by a network administrator diff --git a/rfcs/protocols/identity/data-plane-identity-configuration.md b/rfcs/protocols/identity/membership-syncing.md similarity index 76% rename from rfcs/protocols/identity/data-plane-identity-configuration.md rename to rfcs/protocols/identity/membership-syncing.md index 5a4a3aba0..8f0164560 100644 --- a/rfcs/protocols/identity/data-plane-identity-configuration.md +++ b/rfcs/protocols/identity/membership-syncing.md @@ -5,10 +5,10 @@ --> # Security Domain Membership Syncing -- RFC: 02-012-appendix-b +- RFC: 02-018 - Authors: Venkatraman Ramakrishna, Krishnasuri Narayanam, Bishakh Chandra Ghosh, Ermyas Abebe - Status: Proposed -- Since: 25-Aug-2022 +- Since: 27-Aug-2022 ## Overview @@ -18,7 +18,7 @@ The Security Domain DID of a foreign security domain contains `relayEndpoints` a ## Sync Protocol -Consider two security domains governing ledgers `Ledger A` and Ledger B` respectively. The first has two IIN Agents `A1` and `A2` representing two organizational units that are members of its security domain. The second has agents `B1` and `B2`. The security domain governing `Ledger A` is trying to sync the latest identity and membership info of the security domain governing `Ledger B`. Without loss of generality, we can pick `A2` as the initiator of the cross-network identity plane protocol that results in `Ledger B`'s security domain membership and relay endpoints info getting recorded in `Ledger A`. The protocol is illustrated in the figure below. (_Note_: this represents the "happy path". We will add more diagrams subsequently illustrating failures and race conditions.) +Consider two security domains governing ledgers `Ledger A` and `Ledger B` respectively. The first has two IIN Agents `A1` and `A2` representing two organizational units that are members of its security domain. The second has agents `B1` and `B2`. The security domain governing `Ledger A` is trying to sync the latest identity and membership info of the security domain governing `Ledger B`. Without loss of generality, we can pick `A2` as the initiator of the cross-network identity plane protocol that results in `Ledger B`'s security domain membership and relay endpoints info getting recorded in `Ledger A`. The protocol is illustrated in the figure below. (_Note_: this represents the "happy path". We will add more diagrams subsequently illustrating failures and race conditions.) diff --git a/rfcs/protocols/identity/network-identity-validation.md b/rfcs/protocols/identity/network-identity-validation.md index e9e0f7a27..f8ae13fb0 100644 --- a/rfcs/protocols/identity/network-identity-validation.md +++ b/rfcs/protocols/identity/network-identity-validation.md @@ -3,12 +3,12 @@ SPDX-License-Identifier: CC-BY-4.0 --> -# Network Identity Validation +# Security Domain Identity Validation -- RFC: 02-012-appendix-a +- RFC: 02-017 - Authors: Venkatraman Ramakrishna, Krishnasuri Narayanam, Bishakh Chandra Ghosh, Ermyas Abebe - Status: Proposed -- Since: 24-Sep-2021 +- Since: 27-Aug-2022 ## Summary When a network ("local network" from here on) tries to configure the idetntity of another network ("foreign network" from here on) for interoperation, the broad steps involved are (i) Network Discovery (ii) Network Identity Validation. Both these steps are carried out by the IIN agent of the participants of the local network. diff --git a/rfcs/resources/images/network_did_creation.jpg b/rfcs/resources/images/network_did_creation.jpg index e460f7171072f1bc510c79990564973f460ceaa0..66f07e97a4cce964980970984288ed776b61c99f 100644 GIT binary patch literal 104036 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

D32^5!u8*>_X6a0199Z-D0N1VO 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 Date: Tue, 30 Aug 2022 16:37:52 +0530 Subject: [PATCH 108/150] Added automated publishing of go modules Signed-off-by: sandeep.nishad1 --- .github/workflows/deploy_corda-pkgs.yml | 4 + .github/workflows/deploy_docs.yml | 4 + .github/workflows/deploy_fabric-pkgs.yml | 4 + .github/workflows/deploy_go-pkgs.yml | 315 +++++++++++++++--- .github/workflows/deploy_relay-server.yml | 4 + .github/workflows/deploy_weaver-fabric-cc.yml | 8 +- .github/workflows/manual_deploy_go-pkgs.yml | 80 +++++ .../workflows/test_asset-exchange-corda.yml | 4 + .../workflows/test_asset-exchange-fabric.yml | 4 + .github/workflows/test_asset-transfer.yml | 4 + .github/workflows/test_corda-interop-app.yml | 4 + .github/workflows/test_data-sharing.yml | 4 + .github/workflows/test_docker-build.yml | 4 + .github/workflows/test_go.yml | 4 + .github/workflows/test_node-sdk.yml | 4 + .github/workflows/test_relay.yml | 4 + common/protos-go/VERSION | 1 + .../contracts/interop/Makefile | 4 +- .../contracts/interop/README.md | 6 + .../contracts/interop/VERSION | 1 + .../interfaces/asset-mgmt/README.md | 6 + .../interfaces/asset-mgmt/VERSION | 1 + .../libs/assetexchange/README.md | 6 + .../libs/assetexchange/VERSION | 1 + .../fabric-interop-cc/libs/utils/README.md | 6 + .../fabric-interop-cc/libs/utils/VERSION | 1 + core/network/fabric-interop-cc/makefile | 8 +- .../makefile.variables.docker | 4 - sdks/fabric/go-sdk/VERSION | 1 + 29 files changed, 451 insertions(+), 50 deletions(-) create mode 100644 .github/workflows/manual_deploy_go-pkgs.yml create mode 100644 common/protos-go/VERSION create mode 100644 core/network/fabric-interop-cc/contracts/interop/README.md create mode 100644 core/network/fabric-interop-cc/contracts/interop/VERSION create mode 100644 core/network/fabric-interop-cc/interfaces/asset-mgmt/README.md create mode 100644 core/network/fabric-interop-cc/interfaces/asset-mgmt/VERSION create mode 100644 core/network/fabric-interop-cc/libs/assetexchange/README.md create mode 100644 core/network/fabric-interop-cc/libs/assetexchange/VERSION create mode 100644 core/network/fabric-interop-cc/libs/utils/README.md create mode 100644 core/network/fabric-interop-cc/libs/utils/VERSION delete mode 100644 core/network/fabric-interop-cc/makefile.variables.docker create mode 100644 sdks/fabric/go-sdk/VERSION diff --git a/.github/workflows/deploy_corda-pkgs.yml b/.github/workflows/deploy_corda-pkgs.yml index 9bd6a4f74..d05052161 100644 --- a/.github/workflows/deploy_corda-pkgs.yml +++ b/.github/workflows/deploy_corda-pkgs.yml @@ -1,3 +1,7 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: CC-BY-4.0 + name: Deploy Corda Packages on: diff --git a/.github/workflows/deploy_docs.yml b/.github/workflows/deploy_docs.yml index 561a3b2ee..676c087aa 100644 --- a/.github/workflows/deploy_docs.yml +++ b/.github/workflows/deploy_docs.yml @@ -1,3 +1,7 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: CC-BY-4.0 + name: Deploy Docs (Github Pages) on: diff --git a/.github/workflows/deploy_fabric-pkgs.yml b/.github/workflows/deploy_fabric-pkgs.yml index 253a94b05..4949a9bff 100644 --- a/.github/workflows/deploy_fabric-pkgs.yml +++ b/.github/workflows/deploy_fabric-pkgs.yml @@ -1,3 +1,7 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: CC-BY-4.0 + name: Deploy Fabric Packages on: diff --git a/.github/workflows/deploy_go-pkgs.yml b/.github/workflows/deploy_go-pkgs.yml index 31b29e299..5ae1ad2dd 100644 --- a/.github/workflows/deploy_go-pkgs.yml +++ b/.github/workflows/deploy_go-pkgs.yml @@ -1,65 +1,296 @@ -name: Deploy General Go Module +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: CC-BY-4.0 + +name: Deploy Go Modules on: - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - inputs: - module: - description: 'Go Module name' - default: 'protos-go' - required: true - version: - description: 'Version for Go Release' - default: 'v0.0.0' - required: true + push: + branches: + - test + paths: + - 'common/protos-go/VERSION' + - 'core/network/fabric-interop-cc/libs/utils/VERSION' + - 'core/network/fabric-interop-cc/libs/assetexchange/VERSION' + - 'core/network/fabric-interop-cc/interfaces/asset-mgmt/VERSION' + - 'core/network/fabric-interop-cc/contracts/interop/VERSION' + - 'sdks/fabric/go-sdk/VERSION' jobs: - release: + publish-protos: + if: github.repository_owner == 'hyperledger-labs' + runs-on: ubuntu-latest + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + - name: Set current date as env + run: echo "RELEASE_DATE=$(date +%b\ %d,\ %Y)" >> $GITHUB_ENV + + - name: Set module tag and description + run: | + echo "MODULE_TAG=common/protos-go" >> $GITHUB_ENV + echo "MODULE_DESC=GO Weaver Protos" >> $GITHUB_ENV + + - name: Set module version + run: echo "VERSION=$(cat VERSION)" >> $GITHUB_ENV + working-directory: common/protos-go + + - name: Create Release + id: protos-go-release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token + with: + tag_name: ${{ env.MODULE_TAG }}/${{ env.VERSION }} + release_name: ${{ env.VERSION }} - ${{ env.MODULE_DESC }} - ${{ env.RELEASE_DATE }} + body: | + - Go Module: `github.com/${{ github.repository_owner }}/weaver-dlt-interoperability/${{ env.MODULE_TAG }}` + - Release: ${{ env.VERSION }} + - Readme: [Here](https://github.com/${{ github.repository_owner }}/weaver-dlt-interoperability/blob/${{ env.MODULE_TAG }}/${{ env.VERSION }}/${{ env.MODULE_TAG }}/README.md). + - Source: [Here](https://github.com/${{ github.repository_owner }}/weaver-dlt-interoperability/blob/${{ env.MODULE_TAG }}/${{ env.VERSION }}/${{ env.MODULE_TAG }}) + draft: false + prerelease: false + + - name: Wait for release to be reflected + run: sleep 300 + + publish-lib-utils: + if: ${{ always() && github.repository_owner == 'hyperledger-labs' }} + needs: publish-protos + runs-on: ubuntu-latest + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.16 + + - name: Set current date as env + run: echo "RELEASE_DATE=$(date +%b\ %d,\ %Y)" >> $GITHUB_ENV + + - name: Set module tag and description + run: | + echo "MODULE_TAG=core/network/fabric-interop-cc/libs/utils" >> $GITHUB_ENV + echo "MODULE_DESC=GO Fabric Utils Library for Interoperation" >> $GITHUB_ENV + + - name: Set module version + run: echo "VERSION=$(cat VERSION)" >> $GITHUB_ENV + working-directory: core/network/fabric-interop-cc/libs/utils + + - name: Build test + run: go build -v ./... + working-directory: core/network/fabric-interop-cc/libs/utils + + - name: Create Release + id: lib-utils-release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token + with: + tag_name: ${{ env.MODULE_TAG }}/${{ env.VERSION }} + release_name: ${{ env.VERSION }} - ${{ env.MODULE_DESC }} - ${{ env.RELEASE_DATE }} + body: | + - Go Module: `github.com/${{ github.repository_owner }}/weaver-dlt-interoperability/${{ env.MODULE_TAG }}` + - Release: ${{ env.VERSION }} + - Readme: [Here](https://github.com/${{ github.repository_owner }}/weaver-dlt-interoperability/blob/${{ env.MODULE_TAG }}/${{ env.VERSION }}/${{ env.MODULE_TAG }}/README.md). + - Source: [Here](https://github.com/${{ github.repository_owner }}/weaver-dlt-interoperability/blob/${{ env.MODULE_TAG }}/${{ env.VERSION }}/${{ env.MODULE_TAG }}) + draft: false + prerelease: false + + - name: Wait for release to be reflected + run: sleep 300 + + publish-lib-asset-exchange: + if: ${{ always() && github.repository_owner == 'hyperledger-labs' }} + needs: publish-protos + runs-on: ubuntu-latest + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.16 + + - name: Set current date as env + run: echo "RELEASE_DATE=$(date +%b\ %d,\ %Y)" >> $GITHUB_ENV + + - name: Set module tag and description + run: | + echo "MODULE_TAG=core/network/fabric-interop-cc/libs/assetexchange" >> $GITHUB_ENV + echo "MODULE_DESC=GO Fabric Library for Asset Exchange" >> $GITHUB_ENV + + - name: Set module version + run: echo "VERSION=$(cat VERSION)" >> $GITHUB_ENV + working-directory: core/network/fabric-interop-cc/libs/assetexchange + + - name: Build test + run: go build -v ./... + working-directory: core/network/fabric-interop-cc/libs/assetexchange + + - name: Create Release + id: lib-asset-exchange-release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token + with: + tag_name: ${{ env.MODULE_TAG }}/${{ env.VERSION }} + release_name: ${{ env.VERSION }} - ${{ env.MODULE_DESC }} - ${{ env.RELEASE_DATE }} + body: | + - Go Module: `github.com/${{ github.repository_owner }}/weaver-dlt-interoperability/${{ env.MODULE_TAG }}` + - Release: ${{ env.VERSION }} + - Readme: [Here](https://github.com/${{ github.repository_owner }}/weaver-dlt-interoperability/blob/${{ env.MODULE_TAG }}/${{ env.VERSION }}/${{ env.MODULE_TAG }}/README.md). + - Source: [Here](https://github.com/${{ github.repository_owner }}/weaver-dlt-interoperability/blob/${{ env.MODULE_TAG }}/${{ env.VERSION }}/${{ env.MODULE_TAG }}) + draft: false + prerelease: false + + - name: Wait for release to be reflected + run: sleep 300 + + publish-interface-asset-mgmt: + if: ${{ always() && github.repository_owner == 'hyperledger-labs' }} + needs: [publish-protos] runs-on: ubuntu-latest steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v2 + + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.16 - name: Set current date as env run: echo "RELEASE_DATE=$(date +%b\ %d,\ %Y)" >> $GITHUB_ENV + + - name: Set module tag and description + run: | + echo "MODULE_TAG=core/network/fabric-interop-cc/interfaces/asset-mgmt" >> $GITHUB_ENV + echo "MODULE_DESC=GO Fabric Asset Management Interface" >> $GITHUB_ENV - - name: Get Full path + - name: Set module version + run: echo "VERSION=$(cat VERSION)" >> $GITHUB_ENV + working-directory: core/network/fabric-interop-cc/interfaces/asset-mgmt + + - name: Build test + run: go build -v ./... + working-directory: core/network/fabric-interop-cc/interfaces/asset-mgmt + + - name: Create Release + id: asset-mgmt-release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token + with: + tag_name: ${{ env.MODULE_TAG }}/${{ env.VERSION }} + release_name: ${{ env.VERSION }} - ${{ env.MODULE_DESC }} - ${{ env.RELEASE_DATE }} + body: | + - Go Module: `github.com/${{ github.repository_owner }}/weaver-dlt-interoperability/${{ env.MODULE_TAG }}` + - Release: ${{ env.VERSION }} + - Readme: [Here](https://github.com/${{ github.repository_owner }}/weaver-dlt-interoperability/blob/${{ env.MODULE_TAG }}/${{ env.VERSION }}/${{ env.MODULE_TAG }}/README.md). + - Source: [Here](https://github.com/${{ github.repository_owner }}/weaver-dlt-interoperability/blob/${{ env.MODULE_TAG }}/${{ env.VERSION }}/${{ env.MODULE_TAG }}) + draft: false + prerelease: false + + - name: Wait for release to be reflected + run: sleep 300 + + publish-interop-cc: + if: ${{ always() && github.repository_owner == 'hyperledger-labs' }} + needs: [publish-protos, publish-lib-utils, publish-lib-asset-exchange] + runs-on: ubuntu-latest + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.16 + + - name: Set current date as env + run: echo "RELEASE_DATE=$(date +%b\ %d,\ %Y)" >> $GITHUB_ENV + + - name: Set module tag and description + run: | + echo "MODULE_TAG=core/network/fabric-interop-cc/contracts/interop" >> $GITHUB_ENV + echo "MODULE_DESC=GO Fabric Interop Chaincode" >> $GITHUB_ENV + + - name: Set module version + run: echo "VERSION=$(cat VERSION)" >> $GITHUB_ENV + working-directory: core/network/fabric-interop-cc/contracts/interop + + - name: Build test + run: make build + working-directory: core/network/fabric-interop-cc/contracts/interop + + - name: Create Release + id: interop-cc-release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token + with: + tag_name: ${{ env.MODULE_TAG }}/${{ env.VERSION }} + release_name: ${{ env.VERSION }} - ${{ env.MODULE_DESC }} - ${{ env.RELEASE_DATE }} + body: | + - Go Module: `github.com/${{ github.repository_owner }}/weaver-dlt-interoperability/${{ env.MODULE_TAG }}` + - Release: ${{ env.VERSION }} + - Readme: [Here](https://github.com/${{ github.repository_owner }}/weaver-dlt-interoperability/blob/${{ env.MODULE_TAG }}/${{ env.VERSION }}/${{ env.MODULE_TAG }}/README.md). + - Source: [Here](https://github.com/${{ github.repository_owner }}/weaver-dlt-interoperability/blob/${{ env.MODULE_TAG }}/${{ env.VERSION }}/${{ env.MODULE_TAG }}) + draft: false + prerelease: false + + - name: Wait for release to be reflected + run: sleep 300 + + publish-go-sdk: + if: ${{ always() && github.repository_owner == 'hyperledger-labs' }} + needs: [publish-protos] + runs-on: ubuntu-latest + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.16 + + - name: Set current date as env + run: echo "RELEASE_DATE=$(date +%b\ %d,\ %Y)" >> $GITHUB_ENV + + - name: Set module tag and description run: | - if [ "${{ github.event.inputs.module }}" = "protos-go" ]; then - echo "MODULE_TAG=common/protos-go" >> $GITHUB_ENV - echo "MODULE_DESC=GO Weaver Protos" >> $GITHUB_ENV - elif [ "${{ github.event.inputs.module }}" = "interop" ]; then - echo "MODULE_TAG=core/network/fabric-interop-cc/contracts/interop" >> $GITHUB_ENV - echo "MODULE_DESC=GO Fabric Interop Chaincode" >> $GITHUB_ENV - elif [ "${{ github.event.inputs.module }}" = "utils" ]; then - echo "MODULE_TAG=core/network/fabric-interop-cc/libs/utils" >> $GITHUB_ENV - echo "MODULE_DESC=GO Fabric Utils Library for Interoperation" >> $GITHUB_ENV - elif [ "${{ github.event.inputs.module }}" = "assetexchange" ]; then - echo "MODULE_TAG=core/network/fabric-interop-cc/libs/assetexchange" >> $GITHUB_ENV - echo "MODULE_DESC=GO Fabric Library for Asset Exchange" >> $GITHUB_ENV - elif [ "${{ github.event.inputs.module }}" = "asset-mgmt" ]; then - echo "MODULE_TAG=core/network/fabric-interop-cc/interfaces/asset-mgmt" >> $GITHUB_ENV - echo "MODULE_DESC=GO Fabric Asset Management Interface" >> $GITHUB_ENV - elif [ "${{ github.event.inputs.module }}" = "go-sdk" ]; then echo "MODULE_TAG=sdks/fabric/go-sdk" >> $GITHUB_ENV echo "MODULE_DESC=GO Fabric Weaver SDK" >> $GITHUB_ENV - else - echo "Module not known to the workflow. Exiting." - exit 1 - fi - - name: Create GO Release - id: go-release + - name: Set module version + run: echo "VERSION=$(cat VERSION)" >> $GITHUB_ENV + working-directory: sdks/fabric/go-sdk + + - name: Build test + run: go build -v ./... + working-directory: sdks/fabric/go-sdk + + - name: Create Release + id: go-sdk-release uses: actions/create-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token with: - tag_name: ${{ env.MODULE_TAG }}/${{ github.event.inputs.version }} - release_name: ${{ github.event.inputs.version }} - ${{ env.MODULE_DESC }} - ${{ env.RELEASE_DATE }} + tag_name: ${{ env.MODULE_TAG }}/${{ env.VERSION }} + release_name: ${{ env.VERSION }} - ${{ env.MODULE_DESC }} - ${{ env.RELEASE_DATE }} body: | - Go Module: `github.com/${{ github.repository_owner }}/weaver-dlt-interoperability/${{ env.MODULE_TAG }}` - - Release: ${{ github.event.inputs.version }} - - Readme: [Here](https://github.com/${{ github.repository_owner }}/weaver-dlt-interoperability/blob/${{ env.MODULE_TAG }}/${{ github.event.inputs.version }}/${{ env.MODULE_TAG }}/README.md). - - Source: [Here](https://github.com/${{ github.repository_owner }}/weaver-dlt-interoperability/blob/${{ env.MODULE_TAG }}/${{ github.event.inputs.version }}/${{ env.MODULE_TAG }}) + - Release: ${{ env.VERSION }} + - Readme: [Here](https://github.com/${{ github.repository_owner }}/weaver-dlt-interoperability/blob/${{ env.MODULE_TAG }}/${{ env.VERSION }}/${{ env.MODULE_TAG }}/README.md). + - Source: [Here](https://github.com/${{ github.repository_owner }}/weaver-dlt-interoperability/blob/${{ env.MODULE_TAG }}/${{ env.VERSION }}/${{ env.MODULE_TAG }}) draft: false - prerelease: false \ No newline at end of file + prerelease: false + + - name: Wait for release to be reflected + run: sleep 300 diff --git a/.github/workflows/deploy_relay-server.yml b/.github/workflows/deploy_relay-server.yml index 3e4bcc27e..cd0e9bccf 100644 --- a/.github/workflows/deploy_relay-server.yml +++ b/.github/workflows/deploy_relay-server.yml @@ -1,3 +1,7 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: CC-BY-4.0 + name: Deploy Relay Docker Image on: diff --git a/.github/workflows/deploy_weaver-fabric-cc.yml b/.github/workflows/deploy_weaver-fabric-cc.yml index c66ff9fe0..8d9f4ae77 100644 --- a/.github/workflows/deploy_weaver-fabric-cc.yml +++ b/.github/workflows/deploy_weaver-fabric-cc.yml @@ -1,3 +1,7 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: CC-BY-4.0 + name: Deploy Weaver Fabric CC Docker Image on: @@ -5,13 +9,13 @@ on: branches: - main paths: - - 'core/network/fabric-interop-cc/Makefile.variables.docker' + - 'core/network/fabric-interop-cc/contracts/interop' # Allows you to run this workflow manually from the Actions tab workflow_dispatch: jobs: - relay-image: + weaver-fabric-cc-image: if: github.repository_owner == 'hyperledger-labs' runs-on: ubuntu-latest steps: diff --git a/.github/workflows/manual_deploy_go-pkgs.yml b/.github/workflows/manual_deploy_go-pkgs.yml new file mode 100644 index 000000000..551ef8fcb --- /dev/null +++ b/.github/workflows/manual_deploy_go-pkgs.yml @@ -0,0 +1,80 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: CC-BY-4.0 + +name: Deploy General Go Module + +on: + # Allows this to be a reusable workflow + workflow_call: + inputs: + module: + description: 'Go Module name' + required: true + type: string + version: + description: 'Version for Go Release' + required: true + type: string + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + inputs: + module: + description: 'Go Module name' + default: 'protos-go' + required: true + version: + description: 'Version for Go Release' + default: 'v0.0.0' + required: true + +jobs: + release: + runs-on: ubuntu-latest + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + - name: Set current date as env + run: echo "RELEASE_DATE=$(date +%b\ %d,\ %Y)" >> $GITHUB_ENV + + - name: Get Full path + run: | + if [ "${{ inputs.module }}" = "protos-go" ]; then + echo "MODULE_TAG=common/protos-go" >> $GITHUB_ENV + echo "MODULE_DESC=GO Weaver Protos" >> $GITHUB_ENV + elif [ "${{ inputs.module }}" = "interop" ]; then + echo "MODULE_TAG=core/network/fabric-interop-cc/contracts/interop" >> $GITHUB_ENV + echo "MODULE_DESC=GO Fabric Interop Chaincode" >> $GITHUB_ENV + elif [ "${{ inputs.module }}" = "utils" ]; then + echo "MODULE_TAG=core/network/fabric-interop-cc/libs/utils" >> $GITHUB_ENV + echo "MODULE_DESC=GO Fabric Utils Library for Interoperation" >> $GITHUB_ENV + elif [ "${{ inputs.module }}" = "assetexchange" ]; then + echo "MODULE_TAG=core/network/fabric-interop-cc/libs/assetexchange" >> $GITHUB_ENV + echo "MODULE_DESC=GO Fabric Library for Asset Exchange" >> $GITHUB_ENV + elif [ "${{ inputs.module }}" = "asset-mgmt" ]; then + echo "MODULE_TAG=core/network/fabric-interop-cc/interfaces/asset-mgmt" >> $GITHUB_ENV + echo "MODULE_DESC=GO Fabric Asset Management Interface" >> $GITHUB_ENV + elif [ "${{ inputs.module }}" = "go-sdk" ]; then + echo "MODULE_TAG=sdks/fabric/go-sdk" >> $GITHUB_ENV + echo "MODULE_DESC=GO Fabric Weaver SDK" >> $GITHUB_ENV + else + echo "Module not known to the workflow. Exiting." + exit 1 + fi + + - name: Create GO Release + id: go-release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token + with: + tag_name: ${{ env.MODULE_TAG }}/${{ inputs.version }} + release_name: ${{ inputs.version }} - ${{ env.MODULE_DESC }} - ${{ env.RELEASE_DATE }} + body: | + - Go Module: `github.com/${{ github.repository_owner }}/weaver-dlt-interoperability/${{ env.MODULE_TAG }}` + - Release: ${{ inputs.version }} + - Readme: [Here](https://github.com/${{ github.repository_owner }}/weaver-dlt-interoperability/blob/${{ env.MODULE_TAG }}/${{ inputs.version }}/${{ env.MODULE_TAG }}/README.md). + - Source: [Here](https://github.com/${{ github.repository_owner }}/weaver-dlt-interoperability/blob/${{ env.MODULE_TAG }}/${{ inputs.version }}/${{ env.MODULE_TAG }}) + draft: false + prerelease: false \ No newline at end of file diff --git a/.github/workflows/test_asset-exchange-corda.yml b/.github/workflows/test_asset-exchange-corda.yml index 3345c06c8..d3a270611 100644 --- a/.github/workflows/test_asset-exchange-corda.yml +++ b/.github/workflows/test_asset-exchange-corda.yml @@ -1,3 +1,7 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: CC-BY-4.0 + # This is a basic workflow to help you get started with Actions name: Test Asset Exchange Corda diff --git a/.github/workflows/test_asset-exchange-fabric.yml b/.github/workflows/test_asset-exchange-fabric.yml index 845ce2273..25d61529a 100644 --- a/.github/workflows/test_asset-exchange-fabric.yml +++ b/.github/workflows/test_asset-exchange-fabric.yml @@ -1,3 +1,7 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: CC-BY-4.0 + # This is a basic workflow to help you get started with Actions name: Test Asset Exchange Fabric diff --git a/.github/workflows/test_asset-transfer.yml b/.github/workflows/test_asset-transfer.yml index 9effcdbc0..b55183a5c 100644 --- a/.github/workflows/test_asset-transfer.yml +++ b/.github/workflows/test_asset-transfer.yml @@ -1,3 +1,7 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: CC-BY-4.0 + # This is a basic workflow to help you get started with Actions name: Test Asset Transfer diff --git a/.github/workflows/test_corda-interop-app.yml b/.github/workflows/test_corda-interop-app.yml index 1f7751829..6ada7ed84 100644 --- a/.github/workflows/test_corda-interop-app.yml +++ b/.github/workflows/test_corda-interop-app.yml @@ -1,3 +1,7 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: CC-BY-4.0 + # This workflow will build a Java project with Gradle # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle diff --git a/.github/workflows/test_data-sharing.yml b/.github/workflows/test_data-sharing.yml index d44eef541..3f7733524 100644 --- a/.github/workflows/test_data-sharing.yml +++ b/.github/workflows/test_data-sharing.yml @@ -1,3 +1,7 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: CC-BY-4.0 + # This is a basic workflow to help you get started with Actions name: Test Data Sharing diff --git a/.github/workflows/test_docker-build.yml b/.github/workflows/test_docker-build.yml index 4280a9088..114af1493 100644 --- a/.github/workflows/test_docker-build.yml +++ b/.github/workflows/test_docker-build.yml @@ -1,3 +1,7 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: CC-BY-4.0 + name: Test All Docker Images Build on: diff --git a/.github/workflows/test_go.yml b/.github/workflows/test_go.yml index ae953134e..a0f401963 100644 --- a/.github/workflows/test_go.yml +++ b/.github/workflows/test_go.yml @@ -1,3 +1,7 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: CC-BY-4.0 + name: Unit Test Fabric Interop CC and Sample Chaincode on: diff --git a/.github/workflows/test_node-sdk.yml b/.github/workflows/test_node-sdk.yml index f211848c0..298d52051 100644 --- a/.github/workflows/test_node-sdk.yml +++ b/.github/workflows/test_node-sdk.yml @@ -1,3 +1,7 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: CC-BY-4.0 + # This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions diff --git a/.github/workflows/test_relay.yml b/.github/workflows/test_relay.yml index 6ce645de5..923755172 100644 --- a/.github/workflows/test_relay.yml +++ b/.github/workflows/test_relay.yml @@ -1,3 +1,7 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: CC-BY-4.0 + name: Unit Test Relay on: diff --git a/common/protos-go/VERSION b/common/protos-go/VERSION new file mode 100644 index 000000000..bc80560fa --- /dev/null +++ b/common/protos-go/VERSION @@ -0,0 +1 @@ +1.5.0 diff --git a/core/network/fabric-interop-cc/contracts/interop/Makefile b/core/network/fabric-interop-cc/contracts/interop/Makefile index e58c48a9b..6ebd5ed20 100644 --- a/core/network/fabric-interop-cc/contracts/interop/Makefile +++ b/core/network/fabric-interop-cc/contracts/interop/Makefile @@ -1,5 +1,7 @@ -run-vendor: +vendor: go mod vendor + +run-vendor: vendor cp -r ../../../../../common/protos-go/* vendor/github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go/ cp -r ../../libs/* vendor/github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/ diff --git a/core/network/fabric-interop-cc/contracts/interop/README.md b/core/network/fabric-interop-cc/contracts/interop/README.md new file mode 100644 index 000000000..0eba78818 --- /dev/null +++ b/core/network/fabric-interop-cc/contracts/interop/README.md @@ -0,0 +1,6 @@ + +# Weaver Fabric Interop Chaincode \ No newline at end of file diff --git a/core/network/fabric-interop-cc/contracts/interop/VERSION b/core/network/fabric-interop-cc/contracts/interop/VERSION new file mode 100644 index 000000000..3c80e4f0f --- /dev/null +++ b/core/network/fabric-interop-cc/contracts/interop/VERSION @@ -0,0 +1 @@ +1.4.3 \ No newline at end of file diff --git a/core/network/fabric-interop-cc/interfaces/asset-mgmt/README.md b/core/network/fabric-interop-cc/interfaces/asset-mgmt/README.md new file mode 100644 index 000000000..51321fdec --- /dev/null +++ b/core/network/fabric-interop-cc/interfaces/asset-mgmt/README.md @@ -0,0 +1,6 @@ + +# Asset Management Interface \ No newline at end of file diff --git a/core/network/fabric-interop-cc/interfaces/asset-mgmt/VERSION b/core/network/fabric-interop-cc/interfaces/asset-mgmt/VERSION new file mode 100644 index 000000000..3c80e4f0f --- /dev/null +++ b/core/network/fabric-interop-cc/interfaces/asset-mgmt/VERSION @@ -0,0 +1 @@ +1.4.3 \ No newline at end of file diff --git a/core/network/fabric-interop-cc/libs/assetexchange/README.md b/core/network/fabric-interop-cc/libs/assetexchange/README.md new file mode 100644 index 000000000..190c2221d --- /dev/null +++ b/core/network/fabric-interop-cc/libs/assetexchange/README.md @@ -0,0 +1,6 @@ + +# Asset Exchange Library \ No newline at end of file diff --git a/core/network/fabric-interop-cc/libs/assetexchange/VERSION b/core/network/fabric-interop-cc/libs/assetexchange/VERSION new file mode 100644 index 000000000..3c80e4f0f --- /dev/null +++ b/core/network/fabric-interop-cc/libs/assetexchange/VERSION @@ -0,0 +1 @@ +1.4.3 \ No newline at end of file diff --git a/core/network/fabric-interop-cc/libs/utils/README.md b/core/network/fabric-interop-cc/libs/utils/README.md new file mode 100644 index 000000000..b9af0ac48 --- /dev/null +++ b/core/network/fabric-interop-cc/libs/utils/README.md @@ -0,0 +1,6 @@ + +# Utils Library \ No newline at end of file diff --git a/core/network/fabric-interop-cc/libs/utils/VERSION b/core/network/fabric-interop-cc/libs/utils/VERSION new file mode 100644 index 000000000..3c80e4f0f --- /dev/null +++ b/core/network/fabric-interop-cc/libs/utils/VERSION @@ -0,0 +1 @@ +1.4.3 \ No newline at end of file diff --git a/core/network/fabric-interop-cc/makefile b/core/network/fabric-interop-cc/makefile index 5eb946d79..f448cb080 100644 --- a/core/network/fabric-interop-cc/makefile +++ b/core/network/fabric-interop-cc/makefile @@ -1,4 +1,7 @@ -include makefile.variables.docker +DOCKER_IMAGE_NAME ?= weaver-fabric-cc +DOCKER_TAG ?= `cat contracts/interop/VERSION` +DOCKER_REGISTRY ?= ghcr.io/hyperledger-labs +GIT_URL = https://github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc .PHONY: build protos all clean image push-image check-if-tag-exists @@ -8,6 +11,9 @@ build: echo "Building chaincode binary" ./scripts/build.sh +list-names: + echo ${DOCKER_IMAGE_NAME}:$(DOCKER_TAG) + image: (cd contracts/interop && make run-vendor) docker build --build-arg GIT_URL=$(GIT_URL) -t ${DOCKER_IMAGE_NAME}:$(DOCKER_TAG) . diff --git a/core/network/fabric-interop-cc/makefile.variables.docker b/core/network/fabric-interop-cc/makefile.variables.docker deleted file mode 100644 index 75d2b1855..000000000 --- a/core/network/fabric-interop-cc/makefile.variables.docker +++ /dev/null @@ -1,4 +0,0 @@ -DOCKER_IMAGE_NAME ?= weaver-fabric-cc -DOCKER_TAG ?= 1.4.0 -DOCKER_REGISTRY ?= ghcr.io/hyperledger-labs -GIT_URL = https://github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc \ No newline at end of file diff --git a/sdks/fabric/go-sdk/VERSION b/sdks/fabric/go-sdk/VERSION new file mode 100644 index 000000000..e2cac26c1 --- /dev/null +++ b/sdks/fabric/go-sdk/VERSION @@ -0,0 +1 @@ +1.2.3 \ No newline at end of file From cd1a3d61b42019d511b7facbfe6d4e85f57b67ae Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Fri, 2 Sep 2022 11:17:50 +0530 Subject: [PATCH 109/150] rename network to security domain; fixed case for security domain Signed-off-by: sandeep.nishad1 --- common/protos-go/common/access_control.pb.go | 50 +-- common/protos-go/common/membership.pb.go | 56 +-- common/protos-go/common/state.pb.go | 4 +- .../common/verification_policy.pb.go | 54 +-- common/protos-go/identity/agent.pb.go | 374 +++++++++++------- common/protos-go/identity/agent_grpc.pb.go | 24 +- common/protos-js/.npmignore | 3 +- common/protos-js/build-protos.sh | 25 ++ common/protos-js/package.json | 4 +- common/protos/common/access_control.proto | 2 +- common/protos/common/membership.proto | 2 +- .../protos/common/verification_policy.proto | 2 +- common/protos/identity/agent.proto | 19 +- 13 files changed, 368 insertions(+), 251 deletions(-) create mode 100755 common/protos-js/build-protos.sh diff --git a/common/protos-go/common/access_control.pb.go b/common/protos-go/common/access_control.pb.go index ac5fd10cf..bd556d3df 100644 --- a/common/protos-go/common/access_control.pb.go +++ b/common/protos-go/common/access_control.pb.go @@ -27,7 +27,7 @@ type AccessControlPolicy struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - SecurityDomain string `protobuf:"bytes,1,opt,name=securityDomain,proto3" json:"securityDomain,omitempty"` + SecurityDomain string `protobuf:"bytes,1,opt,name=security_domain,json=securityDomain,proto3" json:"security_domain,omitempty"` Rules []*Rule `protobuf:"bytes,2,rep,name=rules,proto3" json:"rules,omitempty"` } @@ -155,30 +155,30 @@ var file_common_access_control_proto_rawDesc = []byte{ 0x0a, 0x1b, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x22, 0x70, 0x0a, 0x13, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x73, - 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, - 0x61, 0x69, 0x6e, 0x12, 0x31, 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x52, 0x75, 0x6c, 0x65, 0x52, - 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x7a, 0x0a, 0x04, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x1c, - 0x0a, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x12, 0x24, 0x0a, 0x0d, - 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, - 0x0a, 0x04, 0x72, 0x65, 0x61, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x72, 0x65, - 0x61, 0x64, 0x42, 0x7a, 0x0a, 0x27, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5a, 0x4f, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, - 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, - 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, - 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x72, 0x6f, 0x6c, 0x22, 0x71, 0x0a, 0x13, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x27, 0x0a, 0x0f, 0x73, + 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, + 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x31, 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x52, 0x75, 0x6c, 0x65, + 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x7a, 0x0a, 0x04, 0x52, 0x75, 0x6c, 0x65, 0x12, + 0x1c, 0x0a, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x12, 0x24, 0x0a, + 0x0d, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, + 0x12, 0x0a, 0x04, 0x72, 0x65, 0x61, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x72, + 0x65, 0x61, 0x64, 0x42, 0x7a, 0x0a, 0x27, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, + 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5a, 0x4f, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, + 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, + 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, + 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/common/protos-go/common/membership.pb.go b/common/protos-go/common/membership.pb.go index 98180bb7a..337e5a80d 100644 --- a/common/protos-go/common/membership.pb.go +++ b/common/protos-go/common/membership.pb.go @@ -27,7 +27,7 @@ type Membership struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - SecurityDomain string `protobuf:"bytes,1,opt,name=securityDomain,proto3" json:"securityDomain,omitempty"` + SecurityDomain string `protobuf:"bytes,1,opt,name=security_domain,json=securityDomain,proto3" json:"security_domain,omitempty"` Members map[string]*Member `protobuf:"bytes,2,rep,name=members,proto3" json:"members,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } @@ -147,33 +147,33 @@ var File_common_membership_proto protoreflect.FileDescriptor var file_common_membership_proto_rawDesc = []byte{ 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x11, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x22, 0xd1, 0x01, 0x0a, - 0x0a, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x26, 0x0a, 0x0e, 0x73, - 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, - 0x61, 0x69, 0x6e, 0x12, 0x44, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, - 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x1a, 0x55, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2f, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, - 0x22, 0x48, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x76, 0x0a, 0x23, 0x63, 0x6f, - 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, - 0x70, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, - 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, - 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, - 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x2e, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x22, 0xd2, 0x01, 0x0a, + 0x0a, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x27, 0x0a, 0x0f, 0x73, + 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, + 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x44, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x1a, 0x55, 0x0a, 0x0c, 0x4d, 0x65, + 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2f, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, + 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x22, 0x48, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x76, 0x0a, 0x23, 0x63, + 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, + 0x69, 0x70, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, + 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, + 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/common/protos-go/common/state.pb.go b/common/protos-go/common/state.pb.go index 3f22d0359..ca236f331 100644 --- a/common/protos-go/common/state.pb.go +++ b/common/protos-go/common/state.pb.go @@ -82,9 +82,9 @@ const ( RequestState_ERROR RequestState_STATUS = 2 // View is not there, received error from remote relay RequestState_COMPLETED RequestState_STATUS = 3 // Data Sharing completed Successfully RequestState_EVENT_RECEIVED RequestState_STATUS = 4 // View is there and event is received from remote relay - RequestState_EVENT_WRITTEN RequestState_STATUS = 5 // Driver Successfully wrote the view to ledger, hence view is not stored anymore. + RequestState_EVENT_WRITTEN RequestState_STATUS = 5 // Driver Successfully wrote the view to ledger RequestState_EVENT_WRITE_ERROR RequestState_STATUS = 6 // View is there but driver failed to write - RequestState_DELETED RequestState_STATUS = 7 // Once network fetches this request state, mark it delete for cleanup later on. + RequestState_DELETED RequestState_STATUS = 7 // Once network fetches this request state, mark it delete for cleanup later on ) // Enum value maps for RequestState_STATUS. diff --git a/common/protos-go/common/verification_policy.pb.go b/common/protos-go/common/verification_policy.pb.go index 2a26bc03f..b6f7197b1 100644 --- a/common/protos-go/common/verification_policy.pb.go +++ b/common/protos-go/common/verification_policy.pb.go @@ -28,7 +28,7 @@ type VerificationPolicy struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - SecurityDomain string `protobuf:"bytes,1,opt,name=securityDomain,proto3" json:"securityDomain,omitempty"` + SecurityDomain string `protobuf:"bytes,1,opt,name=security_domain,json=securityDomain,proto3" json:"security_domain,omitempty"` Identifiers []*Identifier `protobuf:"bytes,2,rep,name=identifiers,proto3" json:"identifiers,omitempty"` } @@ -199,34 +199,34 @@ var file_common_verification_policy_proto_rawDesc = []byte{ 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x86, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x87, 0x01, 0x0a, 0x12, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, - 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, - 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x48, 0x0a, - 0x0b, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x65, 0x72, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, - 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0b, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x22, 0x38, 0x0a, 0x06, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69, - 0x61, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69, - 0x61, 0x22, 0x62, 0x0a, 0x0a, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, - 0x18, 0x0a, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x12, 0x3a, 0x0a, 0x06, 0x70, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, + 0x79, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, + 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x48, + 0x0a, 0x0b, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x65, 0x72, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0b, 0x69, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x22, 0x38, 0x0a, 0x06, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, + 0x69, 0x61, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, + 0x69, 0x61, 0x22, 0x62, 0x0a, 0x0a, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, + 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x12, 0x3a, 0x0a, 0x06, 0x70, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x06, + 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x42, 0x7f, 0x0a, 0x2c, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, + 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x06, 0x70, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x42, 0x7f, 0x0a, 0x2c, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, - 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, - 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, + 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, + 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/common/protos-go/identity/agent.pb.go b/common/protos-go/identity/agent.pb.go index 375ecdd75..a5ec292d3 100644 --- a/common/protos-go/identity/agent.pb.go +++ b/common/protos-go/identity/agent.pb.go @@ -22,18 +22,17 @@ const ( ) // Unique identifier for a unit of a network that runs an IIN agent -type NetworkUnitIdentity struct { +type SecurityDomainMemberIdentity struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - NetworkId string `protobuf:"bytes,1,opt,name=network_id,json=networkId,proto3" json:"network_id,omitempty"` - ParticipantId string `protobuf:"bytes,2,opt,name=participant_id,json=participantId,proto3" json:"participant_id,omitempty"` - Nonce string `protobuf:"bytes,3,opt,name=nonce,proto3" json:"nonce,omitempty"` + SecurityDomain string `protobuf:"bytes,1,opt,name=security_domain,json=securityDomain,proto3" json:"security_domain,omitempty"` + MemberId string `protobuf:"bytes,2,opt,name=member_id,json=memberId,proto3" json:"member_id,omitempty"` } -func (x *NetworkUnitIdentity) Reset() { - *x = NetworkUnitIdentity{} +func (x *SecurityDomainMemberIdentity) Reset() { + *x = SecurityDomainMemberIdentity{} if protoimpl.UnsafeEnabled { mi := &file_identity_agent_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -41,13 +40,13 @@ func (x *NetworkUnitIdentity) Reset() { } } -func (x *NetworkUnitIdentity) String() string { +func (x *SecurityDomainMemberIdentity) String() string { return protoimpl.X.MessageStringOf(x) } -func (*NetworkUnitIdentity) ProtoMessage() {} +func (*SecurityDomainMemberIdentity) ProtoMessage() {} -func (x *NetworkUnitIdentity) ProtoReflect() protoreflect.Message { +func (x *SecurityDomainMemberIdentity) ProtoReflect() protoreflect.Message { mi := &file_identity_agent_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -59,26 +58,82 @@ func (x *NetworkUnitIdentity) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use NetworkUnitIdentity.ProtoReflect.Descriptor instead. -func (*NetworkUnitIdentity) Descriptor() ([]byte, []int) { +// Deprecated: Use SecurityDomainMemberIdentity.ProtoReflect.Descriptor instead. +func (*SecurityDomainMemberIdentity) Descriptor() ([]byte, []int) { return file_identity_agent_proto_rawDescGZIP(), []int{0} } -func (x *NetworkUnitIdentity) GetNetworkId() string { +func (x *SecurityDomainMemberIdentity) GetSecurityDomain() string { if x != nil { - return x.NetworkId + return x.SecurityDomain } return "" } -func (x *NetworkUnitIdentity) GetParticipantId() string { +func (x *SecurityDomainMemberIdentity) GetMemberId() string { if x != nil { - return x.ParticipantId + return x.MemberId } return "" } -func (x *NetworkUnitIdentity) GetNonce() string { +type SecurityDomainMemberIdentityRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SourceNetwork *SecurityDomainMemberIdentity `protobuf:"bytes,1,opt,name=source_network,json=sourceNetwork,proto3" json:"source_network,omitempty"` + RequestingNetwork *SecurityDomainMemberIdentity `protobuf:"bytes,2,opt,name=requesting_network,json=requestingNetwork,proto3" json:"requesting_network,omitempty"` + Nonce string `protobuf:"bytes,3,opt,name=nonce,proto3" json:"nonce,omitempty"` +} + +func (x *SecurityDomainMemberIdentityRequest) Reset() { + *x = SecurityDomainMemberIdentityRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_identity_agent_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SecurityDomainMemberIdentityRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SecurityDomainMemberIdentityRequest) ProtoMessage() {} + +func (x *SecurityDomainMemberIdentityRequest) ProtoReflect() protoreflect.Message { + mi := &file_identity_agent_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SecurityDomainMemberIdentityRequest.ProtoReflect.Descriptor instead. +func (*SecurityDomainMemberIdentityRequest) Descriptor() ([]byte, []int) { + return file_identity_agent_proto_rawDescGZIP(), []int{1} +} + +func (x *SecurityDomainMemberIdentityRequest) GetSourceNetwork() *SecurityDomainMemberIdentity { + if x != nil { + return x.SourceNetwork + } + return nil +} + +func (x *SecurityDomainMemberIdentityRequest) GetRequestingNetwork() *SecurityDomainMemberIdentity { + if x != nil { + return x.RequestingNetwork + } + return nil +} + +func (x *SecurityDomainMemberIdentityRequest) GetNonce() string { if x != nil { return x.Nonce } @@ -91,15 +146,15 @@ type Attestation struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - UnitIdentity *NetworkUnitIdentity `protobuf:"bytes,1,opt,name=unit_identity,json=unitIdentity,proto3" json:"unit_identity,omitempty"` - Certificate string `protobuf:"bytes,2,opt,name=certificate,proto3" json:"certificate,omitempty"` - Signature string `protobuf:"bytes,3,opt,name=signature,proto3" json:"signature,omitempty"` + UnitIdentity *SecurityDomainMemberIdentity `protobuf:"bytes,1,opt,name=unit_identity,json=unitIdentity,proto3" json:"unit_identity,omitempty"` + Certificate string `protobuf:"bytes,2,opt,name=certificate,proto3" json:"certificate,omitempty"` + Signature string `protobuf:"bytes,3,opt,name=signature,proto3" json:"signature,omitempty"` } func (x *Attestation) Reset() { *x = Attestation{} if protoimpl.UnsafeEnabled { - mi := &file_identity_agent_proto_msgTypes[1] + mi := &file_identity_agent_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -112,7 +167,7 @@ func (x *Attestation) String() string { func (*Attestation) ProtoMessage() {} func (x *Attestation) ProtoReflect() protoreflect.Message { - mi := &file_identity_agent_proto_msgTypes[1] + mi := &file_identity_agent_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -125,10 +180,10 @@ func (x *Attestation) ProtoReflect() protoreflect.Message { // Deprecated: Use Attestation.ProtoReflect.Descriptor instead. func (*Attestation) Descriptor() ([]byte, []int) { - return file_identity_agent_proto_rawDescGZIP(), []int{1} + return file_identity_agent_proto_rawDescGZIP(), []int{2} } -func (x *Attestation) GetUnitIdentity() *NetworkUnitIdentity { +func (x *Attestation) GetUnitIdentity() *SecurityDomainMemberIdentity { if x != nil { return x.UnitIdentity } @@ -162,7 +217,7 @@ type AttestedMembership struct { func (x *AttestedMembership) Reset() { *x = AttestedMembership{} if protoimpl.UnsafeEnabled { - mi := &file_identity_agent_proto_msgTypes[2] + mi := &file_identity_agent_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -175,7 +230,7 @@ func (x *AttestedMembership) String() string { func (*AttestedMembership) ProtoMessage() {} func (x *AttestedMembership) ProtoReflect() protoreflect.Message { - mi := &file_identity_agent_proto_msgTypes[2] + mi := &file_identity_agent_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -188,7 +243,7 @@ func (x *AttestedMembership) ProtoReflect() protoreflect.Message { // Deprecated: Use AttestedMembership.ProtoReflect.Descriptor instead. func (*AttestedMembership) Descriptor() ([]byte, []int) { - return file_identity_agent_proto_rawDescGZIP(), []int{2} + return file_identity_agent_proto_rawDescGZIP(), []int{3} } func (x *AttestedMembership) GetMembership() *common.Membership { @@ -218,7 +273,7 @@ type AttestedSecurityDomain struct { func (x *AttestedSecurityDomain) Reset() { *x = AttestedSecurityDomain{} if protoimpl.UnsafeEnabled { - mi := &file_identity_agent_proto_msgTypes[3] + mi := &file_identity_agent_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -231,7 +286,7 @@ func (x *AttestedSecurityDomain) String() string { func (*AttestedSecurityDomain) ProtoMessage() {} func (x *AttestedSecurityDomain) ProtoReflect() protoreflect.Message { - mi := &file_identity_agent_proto_msgTypes[3] + mi := &file_identity_agent_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -244,7 +299,7 @@ func (x *AttestedSecurityDomain) ProtoReflect() protoreflect.Message { // Deprecated: Use AttestedSecurityDomain.ProtoReflect.Descriptor instead. func (*AttestedSecurityDomain) Descriptor() ([]byte, []int) { - return file_identity_agent_proto_rawDescGZIP(), []int{3} + return file_identity_agent_proto_rawDescGZIP(), []int{4} } func (x *AttestedSecurityDomain) GetSecurityDomain() *AttestedSecurityDomain_AttestedMembershipSet { @@ -273,7 +328,7 @@ type AttestedSecurityDomain_AttestedMembershipSet struct { func (x *AttestedSecurityDomain_AttestedMembershipSet) Reset() { *x = AttestedSecurityDomain_AttestedMembershipSet{} if protoimpl.UnsafeEnabled { - mi := &file_identity_agent_proto_msgTypes[4] + mi := &file_identity_agent_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -286,7 +341,7 @@ func (x *AttestedSecurityDomain_AttestedMembershipSet) String() string { func (*AttestedSecurityDomain_AttestedMembershipSet) ProtoMessage() {} func (x *AttestedSecurityDomain_AttestedMembershipSet) ProtoReflect() protoreflect.Message { - mi := &file_identity_agent_proto_msgTypes[4] + mi := &file_identity_agent_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -299,7 +354,7 @@ func (x *AttestedSecurityDomain_AttestedMembershipSet) ProtoReflect() protorefle // Deprecated: Use AttestedSecurityDomain_AttestedMembershipSet.ProtoReflect.Descriptor instead. func (*AttestedSecurityDomain_AttestedMembershipSet) Descriptor() ([]byte, []int) { - return file_identity_agent_proto_rawDescGZIP(), []int{3, 0} + return file_identity_agent_proto_rawDescGZIP(), []int{4, 0} } func (x *AttestedSecurityDomain_AttestedMembershipSet) GetMembership() *common.Membership { @@ -324,89 +379,105 @@ var file_identity_agent_proto_rawDesc = []byte{ 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x1a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x61, 0x63, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x22, 0x71, 0x0a, 0x13, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x55, 0x6e, 0x69, 0x74, - 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x61, 0x72, 0x74, 0x69, - 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0d, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x14, - 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6e, - 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x97, 0x01, 0x0a, 0x0b, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x48, 0x0a, 0x0d, 0x75, 0x6e, 0x69, 0x74, 0x5f, 0x69, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x69, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x55, 0x6e, 0x69, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x52, 0x0c, 0x75, 0x6e, 0x69, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x20, - 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x92, - 0x01, 0x0a, 0x12, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x3d, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, - 0x68, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x68, 0x69, 0x70, 0x12, 0x3d, 0x0a, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x22, 0xda, 0x02, 0x0a, 0x16, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, - 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x65, - 0x0a, 0x0f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, - 0x64, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, - 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, - 0x69, 0x70, 0x53, 0x65, 0x74, 0x52, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, - 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x3f, 0x0a, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, - 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x97, 0x01, 0x0a, 0x15, 0x41, 0x74, 0x74, 0x65, 0x73, - 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x65, 0x74, - 0x12, 0x3d, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, - 0x68, 0x69, 0x70, 0x52, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, - 0x3f, 0x0a, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x6f, 0x22, 0x64, 0x0a, 0x1c, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, + 0x61, 0x69, 0x6e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x64, 0x6f, + 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x63, 0x75, + 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x65, + 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, 0x22, 0xed, 0x01, 0x0a, 0x23, 0x53, 0x65, 0x63, 0x75, + 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x53, 0x0a, 0x0e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, + 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x0d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x5b, 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, + 0x6e, 0x67, 0x5f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2c, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, + 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x11, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0xa0, 0x01, 0x0a, 0x0b, 0x41, 0x74, 0x74, 0x65, + 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x51, 0x0a, 0x0d, 0x75, 0x6e, 0x69, 0x74, 0x5f, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, + 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, + 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x65, + 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x0c, 0x75, 0x6e, + 0x69, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x0a, 0x09, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x92, 0x01, 0x0a, 0x12, 0x41, + 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, + 0x70, 0x12, 0x3d, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x68, 0x69, 0x70, 0x52, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, + 0x12, 0x3d, 0x0a, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x32, 0xa2, 0x03, 0x0a, 0x08, 0x49, 0x49, 0x4e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x4b, 0x0a, - 0x11, 0x53, 0x79, 0x6e, 0x63, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x12, 0x23, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x55, 0x6e, 0x69, 0x74, 0x49, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x56, 0x0a, 0x1c, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x2e, 0x69, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x55, 0x6e, 0x69, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, - 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, - 0x22, 0x00, 0x12, 0x52, 0x0a, 0x19, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, + 0xda, 0x02, 0x0a, 0x16, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, 0x75, + 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x65, 0x0a, 0x0f, 0x73, 0x65, + 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, + 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, + 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x41, 0x74, 0x74, 0x65, + 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x65, + 0x74, 0x52, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, + 0x6e, 0x12, 0x3f, 0x0a, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x1a, 0x97, 0x01, 0x0a, 0x15, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x65, 0x74, 0x12, 0x3d, 0x0a, 0x0a, + 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, + 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x3f, 0x0a, 0x0c, 0x61, + 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, + 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, + 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0xb4, 0x03, 0x0a, + 0x08, 0x49, 0x49, 0x4e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x54, 0x0a, 0x11, 0x53, 0x79, 0x6e, + 0x63, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2c, + 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, + 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x65, + 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, + 0x5f, 0x0a, 0x1c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x22, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, - 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, - 0x68, 0x69, 0x70, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, - 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x2e, 0x69, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, - 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, - 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, - 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x41, + 0x2c, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, + 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x0f, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, + 0x12, 0x52, 0x0a, 0x19, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x2e, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, + 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, + 0x70, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, + 0x63, 0x6b, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, - 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, 0x75, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, - 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5a, 0x51, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, - 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, - 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, - 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, - 0x2d, 0x67, 0x6f, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x74, 0x74, + 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, + 0x65, 0x64, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, + 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, + 0x6b, 0x22, 0x00, 0x42, 0x75, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, + 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5a, 0x51, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, + 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, + 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, + 0x6f, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( @@ -421,39 +492,42 @@ func file_identity_agent_proto_rawDescGZIP() []byte { return file_identity_agent_proto_rawDescData } -var file_identity_agent_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_identity_agent_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_identity_agent_proto_goTypes = []interface{}{ - (*NetworkUnitIdentity)(nil), // 0: identity.agent.NetworkUnitIdentity - (*Attestation)(nil), // 1: identity.agent.Attestation - (*AttestedMembership)(nil), // 2: identity.agent.AttestedMembership - (*AttestedSecurityDomain)(nil), // 3: identity.agent.AttestedSecurityDomain - (*AttestedSecurityDomain_AttestedMembershipSet)(nil), // 4: identity.agent.AttestedSecurityDomain.AttestedMembershipSet - (*common.Membership)(nil), // 5: common.membership.Membership - (*common.Ack)(nil), // 6: common.ack.Ack + (*SecurityDomainMemberIdentity)(nil), // 0: identity.agent.SecurityDomainMemberIdentity + (*SecurityDomainMemberIdentityRequest)(nil), // 1: identity.agent.SecurityDomainMemberIdentityRequest + (*Attestation)(nil), // 2: identity.agent.Attestation + (*AttestedMembership)(nil), // 3: identity.agent.AttestedMembership + (*AttestedSecurityDomain)(nil), // 4: identity.agent.AttestedSecurityDomain + (*AttestedSecurityDomain_AttestedMembershipSet)(nil), // 5: identity.agent.AttestedSecurityDomain.AttestedMembershipSet + (*common.Membership)(nil), // 6: common.membership.Membership + (*common.Ack)(nil), // 7: common.ack.Ack } var file_identity_agent_proto_depIdxs = []int32{ - 0, // 0: identity.agent.Attestation.unit_identity:type_name -> identity.agent.NetworkUnitIdentity - 5, // 1: identity.agent.AttestedMembership.membership:type_name -> common.membership.Membership - 1, // 2: identity.agent.AttestedMembership.attestation:type_name -> identity.agent.Attestation - 4, // 3: identity.agent.AttestedSecurityDomain.security_domain:type_name -> identity.agent.AttestedSecurityDomain.AttestedMembershipSet - 1, // 4: identity.agent.AttestedSecurityDomain.attestations:type_name -> identity.agent.Attestation - 5, // 5: identity.agent.AttestedSecurityDomain.AttestedMembershipSet.membership:type_name -> common.membership.Membership - 1, // 6: identity.agent.AttestedSecurityDomain.AttestedMembershipSet.attestations:type_name -> identity.agent.Attestation - 0, // 7: identity.agent.IINAgent.SyncExternalState:input_type -> identity.agent.NetworkUnitIdentity - 0, // 8: identity.agent.IINAgent.RequestIdentityConfiguration:input_type -> identity.agent.NetworkUnitIdentity - 2, // 9: identity.agent.IINAgent.SendIdentityConfiguration:input_type -> identity.agent.AttestedMembership - 3, // 10: identity.agent.IINAgent.RequestAttestation:input_type -> identity.agent.AttestedSecurityDomain - 3, // 11: identity.agent.IINAgent.SendAttestation:input_type -> identity.agent.AttestedSecurityDomain - 6, // 12: identity.agent.IINAgent.SyncExternalState:output_type -> common.ack.Ack - 6, // 13: identity.agent.IINAgent.RequestIdentityConfiguration:output_type -> common.ack.Ack - 6, // 14: identity.agent.IINAgent.SendIdentityConfiguration:output_type -> common.ack.Ack - 6, // 15: identity.agent.IINAgent.RequestAttestation:output_type -> common.ack.Ack - 6, // 16: identity.agent.IINAgent.SendAttestation:output_type -> common.ack.Ack - 12, // [12:17] is the sub-list for method output_type - 7, // [7:12] is the sub-list for method input_type - 7, // [7:7] is the sub-list for extension type_name - 7, // [7:7] is the sub-list for extension extendee - 0, // [0:7] is the sub-list for field type_name + 0, // 0: identity.agent.SecurityDomainMemberIdentityRequest.source_network:type_name -> identity.agent.SecurityDomainMemberIdentity + 0, // 1: identity.agent.SecurityDomainMemberIdentityRequest.requesting_network:type_name -> identity.agent.SecurityDomainMemberIdentity + 0, // 2: identity.agent.Attestation.unit_identity:type_name -> identity.agent.SecurityDomainMemberIdentity + 6, // 3: identity.agent.AttestedMembership.membership:type_name -> common.membership.Membership + 2, // 4: identity.agent.AttestedMembership.attestation:type_name -> identity.agent.Attestation + 5, // 5: identity.agent.AttestedSecurityDomain.security_domain:type_name -> identity.agent.AttestedSecurityDomain.AttestedMembershipSet + 2, // 6: identity.agent.AttestedSecurityDomain.attestations:type_name -> identity.agent.Attestation + 6, // 7: identity.agent.AttestedSecurityDomain.AttestedMembershipSet.membership:type_name -> common.membership.Membership + 2, // 8: identity.agent.AttestedSecurityDomain.AttestedMembershipSet.attestations:type_name -> identity.agent.Attestation + 0, // 9: identity.agent.IINAgent.SyncExternalState:input_type -> identity.agent.SecurityDomainMemberIdentity + 0, // 10: identity.agent.IINAgent.RequestIdentityConfiguration:input_type -> identity.agent.SecurityDomainMemberIdentity + 3, // 11: identity.agent.IINAgent.SendIdentityConfiguration:input_type -> identity.agent.AttestedMembership + 4, // 12: identity.agent.IINAgent.RequestAttestation:input_type -> identity.agent.AttestedSecurityDomain + 4, // 13: identity.agent.IINAgent.SendAttestation:input_type -> identity.agent.AttestedSecurityDomain + 7, // 14: identity.agent.IINAgent.SyncExternalState:output_type -> common.ack.Ack + 7, // 15: identity.agent.IINAgent.RequestIdentityConfiguration:output_type -> common.ack.Ack + 7, // 16: identity.agent.IINAgent.SendIdentityConfiguration:output_type -> common.ack.Ack + 7, // 17: identity.agent.IINAgent.RequestAttestation:output_type -> common.ack.Ack + 7, // 18: identity.agent.IINAgent.SendAttestation:output_type -> common.ack.Ack + 14, // [14:19] is the sub-list for method output_type + 9, // [9:14] is the sub-list for method input_type + 9, // [9:9] is the sub-list for extension type_name + 9, // [9:9] is the sub-list for extension extendee + 0, // [0:9] is the sub-list for field type_name } func init() { file_identity_agent_proto_init() } @@ -463,7 +537,7 @@ func file_identity_agent_proto_init() { } if !protoimpl.UnsafeEnabled { file_identity_agent_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NetworkUnitIdentity); i { + switch v := v.(*SecurityDomainMemberIdentity); i { case 0: return &v.state case 1: @@ -475,7 +549,7 @@ func file_identity_agent_proto_init() { } } file_identity_agent_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Attestation); i { + switch v := v.(*SecurityDomainMemberIdentityRequest); i { case 0: return &v.state case 1: @@ -487,7 +561,7 @@ func file_identity_agent_proto_init() { } } file_identity_agent_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AttestedMembership); i { + switch v := v.(*Attestation); i { case 0: return &v.state case 1: @@ -499,7 +573,7 @@ func file_identity_agent_proto_init() { } } file_identity_agent_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AttestedSecurityDomain); i { + switch v := v.(*AttestedMembership); i { case 0: return &v.state case 1: @@ -511,6 +585,18 @@ func file_identity_agent_proto_init() { } } file_identity_agent_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AttestedSecurityDomain); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_identity_agent_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AttestedSecurityDomain_AttestedMembershipSet); i { case 0: return &v.state @@ -529,7 +615,7 @@ func file_identity_agent_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_identity_agent_proto_rawDesc, NumEnums: 0, - NumMessages: 5, + NumMessages: 6, NumExtensions: 0, NumServices: 1, }, diff --git a/common/protos-go/identity/agent_grpc.pb.go b/common/protos-go/identity/agent_grpc.pb.go index 7dcfa1c96..93f102ea5 100644 --- a/common/protos-go/identity/agent_grpc.pb.go +++ b/common/protos-go/identity/agent_grpc.pb.go @@ -20,9 +20,9 @@ const _ = grpc.SupportPackageIsVersion7 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type IINAgentClient interface { // user or agent triggers a sync of external/foreign network unit's state - SyncExternalState(ctx context.Context, in *NetworkUnitIdentity, opts ...grpc.CallOption) (*common.Ack, error) + SyncExternalState(ctx context.Context, in *SecurityDomainMemberIdentity, opts ...grpc.CallOption) (*common.Ack, error) // Requesting network unit's state from a foreign IIN agent. - RequestIdentityConfiguration(ctx context.Context, in *NetworkUnitIdentity, opts ...grpc.CallOption) (*common.Ack, error) + RequestIdentityConfiguration(ctx context.Context, in *SecurityDomainMemberIdentity, opts ...grpc.CallOption) (*common.Ack, error) // Handling network unit's state sent by a foreign IIN agent. SendIdentityConfiguration(ctx context.Context, in *AttestedMembership, opts ...grpc.CallOption) (*common.Ack, error) // Requesting attestation from a local IIN agent. @@ -39,7 +39,7 @@ func NewIINAgentClient(cc grpc.ClientConnInterface) IINAgentClient { return &iINAgentClient{cc} } -func (c *iINAgentClient) SyncExternalState(ctx context.Context, in *NetworkUnitIdentity, opts ...grpc.CallOption) (*common.Ack, error) { +func (c *iINAgentClient) SyncExternalState(ctx context.Context, in *SecurityDomainMemberIdentity, opts ...grpc.CallOption) (*common.Ack, error) { out := new(common.Ack) err := c.cc.Invoke(ctx, "/identity.agent.IINAgent/SyncExternalState", in, out, opts...) if err != nil { @@ -48,7 +48,7 @@ func (c *iINAgentClient) SyncExternalState(ctx context.Context, in *NetworkUnitI return out, nil } -func (c *iINAgentClient) RequestIdentityConfiguration(ctx context.Context, in *NetworkUnitIdentity, opts ...grpc.CallOption) (*common.Ack, error) { +func (c *iINAgentClient) RequestIdentityConfiguration(ctx context.Context, in *SecurityDomainMemberIdentity, opts ...grpc.CallOption) (*common.Ack, error) { out := new(common.Ack) err := c.cc.Invoke(ctx, "/identity.agent.IINAgent/RequestIdentityConfiguration", in, out, opts...) if err != nil { @@ -89,9 +89,9 @@ func (c *iINAgentClient) SendAttestation(ctx context.Context, in *AttestedSecuri // for forward compatibility type IINAgentServer interface { // user or agent triggers a sync of external/foreign network unit's state - SyncExternalState(context.Context, *NetworkUnitIdentity) (*common.Ack, error) + SyncExternalState(context.Context, *SecurityDomainMemberIdentity) (*common.Ack, error) // Requesting network unit's state from a foreign IIN agent. - RequestIdentityConfiguration(context.Context, *NetworkUnitIdentity) (*common.Ack, error) + RequestIdentityConfiguration(context.Context, *SecurityDomainMemberIdentity) (*common.Ack, error) // Handling network unit's state sent by a foreign IIN agent. SendIdentityConfiguration(context.Context, *AttestedMembership) (*common.Ack, error) // Requesting attestation from a local IIN agent. @@ -105,10 +105,10 @@ type IINAgentServer interface { type UnimplementedIINAgentServer struct { } -func (UnimplementedIINAgentServer) SyncExternalState(context.Context, *NetworkUnitIdentity) (*common.Ack, error) { +func (UnimplementedIINAgentServer) SyncExternalState(context.Context, *SecurityDomainMemberIdentity) (*common.Ack, error) { return nil, status.Errorf(codes.Unimplemented, "method SyncExternalState not implemented") } -func (UnimplementedIINAgentServer) RequestIdentityConfiguration(context.Context, *NetworkUnitIdentity) (*common.Ack, error) { +func (UnimplementedIINAgentServer) RequestIdentityConfiguration(context.Context, *SecurityDomainMemberIdentity) (*common.Ack, error) { return nil, status.Errorf(codes.Unimplemented, "method RequestIdentityConfiguration not implemented") } func (UnimplementedIINAgentServer) SendIdentityConfiguration(context.Context, *AttestedMembership) (*common.Ack, error) { @@ -134,7 +134,7 @@ func RegisterIINAgentServer(s grpc.ServiceRegistrar, srv IINAgentServer) { } func _IINAgent_SyncExternalState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(NetworkUnitIdentity) + in := new(SecurityDomainMemberIdentity) if err := dec(in); err != nil { return nil, err } @@ -146,13 +146,13 @@ func _IINAgent_SyncExternalState_Handler(srv interface{}, ctx context.Context, d FullMethod: "/identity.agent.IINAgent/SyncExternalState", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(IINAgentServer).SyncExternalState(ctx, req.(*NetworkUnitIdentity)) + return srv.(IINAgentServer).SyncExternalState(ctx, req.(*SecurityDomainMemberIdentity)) } return interceptor(ctx, in, info, handler) } func _IINAgent_RequestIdentityConfiguration_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(NetworkUnitIdentity) + in := new(SecurityDomainMemberIdentity) if err := dec(in); err != nil { return nil, err } @@ -164,7 +164,7 @@ func _IINAgent_RequestIdentityConfiguration_Handler(srv interface{}, ctx context FullMethod: "/identity.agent.IINAgent/RequestIdentityConfiguration", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(IINAgentServer).RequestIdentityConfiguration(ctx, req.(*NetworkUnitIdentity)) + return srv.(IINAgentServer).RequestIdentityConfiguration(ctx, req.(*SecurityDomainMemberIdentity)) } return interceptor(ctx, in, info, handler) } diff --git a/common/protos-js/.npmignore b/common/protos-js/.npmignore index c7725bfb1..257a76b70 100644 --- a/common/protos-js/.npmignore +++ b/common/protos-js/.npmignore @@ -4,4 +4,5 @@ node_modules/ package-lock.json Makefile .gitignore -.npmignore \ No newline at end of file +.npmignore +build-protos.sh \ No newline at end of file diff --git a/common/protos-js/build-protos.sh b/common/protos-js/build-protos.sh new file mode 100755 index 000000000..ee85c16f8 --- /dev/null +++ b/common/protos-js/build-protos.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +BUILDDIR=./ +PROTOSDIR=../protos +FABRIC_PROTOSDIR=../fabric-protos + +# NodeJS Build +grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/common/interop_payload.proto $PROTOSDIR/common/asset_locks.proto $PROTOSDIR/common/asset_transfer.proto $PROTOSDIR/common/ack.proto $PROTOSDIR/common/query.proto $PROTOSDIR/common/state.proto $PROTOSDIR/common/proofs.proto $PROTOSDIR/common/verification_policy.proto $PROTOSDIR/common/membership.proto $PROTOSDIR/common/access_control.proto $PROTOSDIR/common/events.proto +grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/corda/view_data.proto +grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/driver/driver.proto +grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/fabric/view_data.proto +grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/identity/agent.proto +grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/networks/networks.proto +grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/relay/datatransfer.proto $PROTOSDIR/relay/events.proto +#grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $FABRIC_PROTOSDIR/msp/identities.proto $FABRIC_PROTOSDIR/peer/proposal_response.proto $FABRIC_PROTOSDIR/peer/proposal.proto $FABRIC_PROTOSDIR/peer/chaincode.proto $FABRIC_PROTOSDIR/common/policies.proto $FABRIC_PROTOSDIR/msp/msp_principal.proto + +# Typescript Build +protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/common/interop_payload.proto $PROTOSDIR/common/asset_locks.proto $PROTOSDIR/common/asset_transfer.proto $PROTOSDIR/common/ack.proto $PROTOSDIR/common/query.proto $PROTOSDIR/common/state.proto $PROTOSDIR/common/proofs.proto $PROTOSDIR/common/verification_policy.proto $PROTOSDIR/common/membership.proto $PROTOSDIR/common/access_control.proto $PROTOSDIR/common/events.proto +protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/corda/view_data.proto +protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/driver/driver.proto +protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/fabric/view_data.proto +protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/identity/agent.proto +protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/networks/networks.proto +protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/relay/datatransfer.proto $PROTOSDIR/relay/events.proto +# protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $FABRIC_PROTOSDIR/msp/identities.proto $FABRIC_PROTOSDIR/peer/proposal_response.proto $FABRIC_PROTOSDIR/peer/proposal.proto $FABRIC_PROTOSDIR/peer/chaincode.proto $FABRIC_PROTOSDIR/common/policies.proto $FABRIC_PROTOSDIR/msp/msp_principal.proto diff --git a/common/protos-js/package.json b/common/protos-js/package.json index 749577aa8..855c62230 100644 --- a/common/protos-js/package.json +++ b/common/protos-js/package.json @@ -1,6 +1,6 @@ { "name": "@hyperledger-labs/weaver-protos-js", - "version": "1.4.2", + "version": "1.4.3", "description": "Interop protos for Node JS (Weaver)", "main": "index.js", "exports": { @@ -16,7 +16,7 @@ }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "build": "grpc_tools_node_protoc --proto_path=../protos --proto_path=../fabric-protos --js_out=import_style=commonjs,binary:./ --grpc_out=grpc_js:./ --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` ../protos/relay/datatransfer.proto ../protos/relay/events.proto ../protos/networks/networks.proto ../protos/driver/driver.proto ../protos/identity/agent.proto ../protos/common/interop_payload.proto ../protos/common/asset_locks.proto ../protos/common/asset_transfer.proto ../protos/common/ack.proto ../protos/common/query.proto ../protos/fabric/view_data.proto ../protos/corda/view_data.proto ../protos/common/state.proto ../protos/common/proofs.proto ../protos/common/verification_policy.proto ../protos/common/events.proto ../fabric-protos/msp/identities.proto ../fabric-protos/peer/proposal_response.proto ../fabric-protos/peer/proposal.proto ../fabric-protos/peer/chaincode.proto ../fabric-protos/common/policies.proto ../fabric-protos/msp/msp_principal.proto && protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=./ -I ../protos -I ../fabric-protos ../protos/relay/datatransfer.proto ../protos/relay/events.proto ../protos/networks/networks.proto ../protos/driver/driver.proto ../protos/identity/agent.proto ../protos/common/interop_payload.proto ../protos/common/asset_locks.proto ../protos/common/asset_transfer.proto ../protos/common/ack.proto ../protos/common/query.proto ../protos/fabric/view_data.proto ../protos/corda/view_data.proto ../protos/common/state.proto ../protos/common/proofs.proto ../protos/common/verification_policy.proto ../protos/common/events.proto ../fabric-protos/msp/identities.proto ../fabric-protos/peer/proposal_response.proto ../fabric-protos/peer/proposal.proto ../fabric-protos/peer/chaincode.proto ../fabric-protos/common/policies.proto ../fabric-protos/msp/msp_principal.proto" + "build": "sh ./build-protos.sh" }, "repository": { "type": "git", diff --git a/common/protos/common/access_control.proto b/common/protos/common/access_control.proto index 183aba26b..6bbf84666 100644 --- a/common/protos/common/access_control.proto +++ b/common/protos/common/access_control.proto @@ -8,7 +8,7 @@ option go_package = "github.com/hyperledger-labs/weaver-dlt-interoperability/com // AccessControlPolicy specifies a set of data that can be accessed by some // SecurityGroup message AccessControlPolicy { - string securityDomain = 1; + string security_domain = 1; repeated Rule rules = 2; } diff --git a/common/protos/common/membership.proto b/common/protos/common/membership.proto index f32125a2e..9d66021d2 100644 --- a/common/protos/common/membership.proto +++ b/common/protos/common/membership.proto @@ -8,7 +8,7 @@ option go_package = "github.com/hyperledger-labs/weaver-dlt-interoperability/com // Membership captures the members of an external entity such as a thing, // person, organization or groups of entities such as networks message Membership { - string securityDomain = 1; + string security_domain = 1; map members = 2; } diff --git a/common/protos/common/verification_policy.proto b/common/protos/common/verification_policy.proto index cad871485..70c92a685 100644 --- a/common/protos/common/verification_policy.proto +++ b/common/protos/common/verification_policy.proto @@ -9,7 +9,7 @@ option go_package = "github.com/hyperledger-labs/weaver-dlt-interoperability/com // network need to provide proof of a view in order for it to be deemed valid by // the Fabric network message VerificationPolicy { - string securityDomain = 1; + string security_domain = 1; repeated Identifier identifiers = 2; } diff --git a/common/protos/identity/agent.proto b/common/protos/identity/agent.proto index 61d4f44b2..d1f592aa6 100644 --- a/common/protos/identity/agent.proto +++ b/common/protos/identity/agent.proto @@ -11,9 +11,9 @@ option go_package = "github.com/hyperledger-labs/weaver-dlt-interoperability/com // definitions of all messages used in the datatransfer protocol service IINAgent { // user or agent triggers a sync of external/foreign network unit's state - rpc SyncExternalState(NetworkUnitIdentity) returns (common.ack.Ack) {} + rpc SyncExternalState(SecurityDomainMemberIdentity) returns (common.ack.Ack) {} // Requesting network unit's state from a foreign IIN agent. - rpc RequestIdentityConfiguration(NetworkUnitIdentity) returns (common.ack.Ack){} + rpc RequestIdentityConfiguration(SecurityDomainMemberIdentity) returns (common.ack.Ack){} // Handling network unit's state sent by a foreign IIN agent. rpc SendIdentityConfiguration(AttestedMembership) returns (common.ack.Ack){} // Requesting attestation from a local IIN agent. @@ -23,15 +23,20 @@ service IINAgent { } // Unique identifier for a unit of a network that runs an IIN agent -message NetworkUnitIdentity { - string network_id = 1; - string participant_id = 2; - string nonce = 3; +message SecurityDomainMemberIdentity { + string security_domain = 1; + string member_id = 2; +} + +message SecurityDomainMemberIdentityRequest{ + SecurityDomainMemberIdentity source_network = 1; + SecurityDomainMemberIdentity requesting_network = 2; + string nonce = 3; } // Association of signature (over arbitrary data) and signer identity message Attestation { - NetworkUnitIdentity unit_identity = 1; + SecurityDomainMemberIdentity unit_identity = 1; string certificate = 2; string signature = 3; } From 54152257ed16b0cc9dee8f5938343c73189e3c42 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Fri, 2 Sep 2022 11:31:01 +0530 Subject: [PATCH 110/150] fix protos-js build to include fabric protos Signed-off-by: sandeep.nishad1 --- common/protos-js/build-protos.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/common/protos-js/build-protos.sh b/common/protos-js/build-protos.sh index ee85c16f8..dd0e6acaa 100755 --- a/common/protos-js/build-protos.sh +++ b/common/protos-js/build-protos.sh @@ -5,14 +5,16 @@ PROTOSDIR=../protos FABRIC_PROTOSDIR=../fabric-protos # NodeJS Build -grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/common/interop_payload.proto $PROTOSDIR/common/asset_locks.proto $PROTOSDIR/common/asset_transfer.proto $PROTOSDIR/common/ack.proto $PROTOSDIR/common/query.proto $PROTOSDIR/common/state.proto $PROTOSDIR/common/proofs.proto $PROTOSDIR/common/verification_policy.proto $PROTOSDIR/common/membership.proto $PROTOSDIR/common/access_control.proto $PROTOSDIR/common/events.proto -grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/corda/view_data.proto +# Following build is without GRPC out, use this when no rpc services defined in proto. +grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/common/interop_payload.proto $PROTOSDIR/common/asset_locks.proto $PROTOSDIR/common/asset_transfer.proto $PROTOSDIR/common/ack.proto $PROTOSDIR/common/query.proto $PROTOSDIR/common/state.proto $PROTOSDIR/common/proofs.proto $PROTOSDIR/common/verification_policy.proto $PROTOSDIR/common/membership.proto $PROTOSDIR/common/access_control.proto $PROTOSDIR/common/events.proto +grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/corda/view_data.proto +# Following build is with GRPC out, use this to build rpc proto services. grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/driver/driver.proto -grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/fabric/view_data.proto +grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/fabric/view_data.proto grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/identity/agent.proto grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/networks/networks.proto grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/relay/datatransfer.proto $PROTOSDIR/relay/events.proto -#grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $FABRIC_PROTOSDIR/msp/identities.proto $FABRIC_PROTOSDIR/peer/proposal_response.proto $FABRIC_PROTOSDIR/peer/proposal.proto $FABRIC_PROTOSDIR/peer/chaincode.proto $FABRIC_PROTOSDIR/common/policies.proto $FABRIC_PROTOSDIR/msp/msp_principal.proto +grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $FABRIC_PROTOSDIR/msp/identities.proto $FABRIC_PROTOSDIR/peer/proposal_response.proto $FABRIC_PROTOSDIR/peer/proposal.proto $FABRIC_PROTOSDIR/peer/chaincode.proto $FABRIC_PROTOSDIR/common/policies.proto $FABRIC_PROTOSDIR/msp/msp_principal.proto # Typescript Build protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/common/interop_payload.proto $PROTOSDIR/common/asset_locks.proto $PROTOSDIR/common/asset_transfer.proto $PROTOSDIR/common/ack.proto $PROTOSDIR/common/query.proto $PROTOSDIR/common/state.proto $PROTOSDIR/common/proofs.proto $PROTOSDIR/common/verification_policy.proto $PROTOSDIR/common/membership.proto $PROTOSDIR/common/access_control.proto $PROTOSDIR/common/events.proto @@ -22,4 +24,4 @@ protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDD protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/identity/agent.proto protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/networks/networks.proto protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/relay/datatransfer.proto $PROTOSDIR/relay/events.proto -# protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $FABRIC_PROTOSDIR/msp/identities.proto $FABRIC_PROTOSDIR/peer/proposal_response.proto $FABRIC_PROTOSDIR/peer/proposal.proto $FABRIC_PROTOSDIR/peer/chaincode.proto $FABRIC_PROTOSDIR/common/policies.proto $FABRIC_PROTOSDIR/msp/msp_principal.proto +protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $FABRIC_PROTOSDIR/msp/identities.proto $FABRIC_PROTOSDIR/peer/proposal_response.proto $FABRIC_PROTOSDIR/peer/proposal.proto $FABRIC_PROTOSDIR/peer/chaincode.proto $FABRIC_PROTOSDIR/common/policies.proto $FABRIC_PROTOSDIR/msp/msp_principal.proto From bc4d4599e8d6e41e09f2939127fcdb69a9434235 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Fri, 2 Sep 2022 11:52:52 +0530 Subject: [PATCH 111/150] renamed networkId with security domain in iin-agent Signed-off-by: sandeep.nishad1 --- .../iin-agent/src/common/ledgerBase.ts | 2 +- .../iin-agent/src/fabric-ledger/connector.ts | 8 ++++---- .../iin-agent/src/fabric-ledger/walletUtils.ts | 2 +- .../src/protocols/externalOperations.ts | 18 +++++++++--------- .../iin-agent/src/protocols/localOperations.ts | 4 ++-- .../iin-agent/src/server.ts | 14 +++++++------- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/core/identity-management/iin-agent/src/common/ledgerBase.ts b/core/identity-management/iin-agent/src/common/ledgerBase.ts index 0915aed03..27b83a286 100644 --- a/core/identity-management/iin-agent/src/common/ledgerBase.ts +++ b/core/identity-management/iin-agent/src/common/ledgerBase.ts @@ -26,7 +26,7 @@ export class LedgerBase { } // Collect security domain membership info - async getSecurityDomainMembership(): Promise { + async getSecurityDomainMembership(securityDomain: string): Promise { return {}; } diff --git a/core/identity-management/iin-agent/src/fabric-ledger/connector.ts b/core/identity-management/iin-agent/src/fabric-ledger/connector.ts index 044fc017c..1edd10089 100644 --- a/core/identity-management/iin-agent/src/fabric-ledger/connector.ts +++ b/core/identity-management/iin-agent/src/fabric-ledger/connector.ts @@ -27,19 +27,19 @@ export class FabricConnector extends LedgerBase { throw new Error('Config does not exist at path: ' + configFilePath); } this.orgMspId = JSON.parse(fs.readFileSync(configFilePath, 'utf8').toString()).mspId; - this.walletPath = walletPath ? walletPath : path.join(process.cwd(), `wallet-${this.networkId}`); + this.walletPath = walletPath ? walletPath : path.join(process.cwd(), `wallet-${this.networkId}-${this.orgMspId}`); } // Setup a user (with wallet and one or more identities) with contract invocation credentials async setupWalletIdentity() { - walletSetup(this.walletPath, this.connectionProfilePath, this.configFilePath, this.networkId); + walletSetup(this.walletPath, this.connectionProfilePath, this.configFilePath); } // Collect security domain membership info - async getSecurityDomainMembership(): Promise { + async getSecurityDomainMembership(securityDomain: string): Promise { const memberships = getAllMSPConfigurations(this.walletPath, this.connectionProfilePath, this.configFilePath, this.ledgerId); const securityDomainInfo = { - securityDomain: this.networkId, + securityDomain: securityDomain, members: memberships, } return securityDomainInfo; diff --git a/core/identity-management/iin-agent/src/fabric-ledger/walletUtils.ts b/core/identity-management/iin-agent/src/fabric-ledger/walletUtils.ts index 57d4a8a76..46bc05932 100644 --- a/core/identity-management/iin-agent/src/fabric-ledger/walletUtils.ts +++ b/core/identity-management/iin-agent/src/fabric-ledger/walletUtils.ts @@ -13,7 +13,7 @@ const getWallet = async (walletPath: string) => { return await Wallets.newFileSystemWallet(walletPath); }; -const walletSetup = async (walletPath: string, conn_profile_path: string, config_file_path: string, networkName: string): Promise => { +const walletSetup = async (walletPath: string, conn_profile_path: string, config_file_path: string): Promise => { if (!fs.existsSync(conn_profile_path)) { throw new Error('Connection profile does not exist at path: ' + conn_profile_path); } diff --git a/core/identity-management/iin-agent/src/protocols/externalOperations.ts b/core/identity-management/iin-agent/src/protocols/externalOperations.ts index 6fdbb8bb0..b93509490 100644 --- a/core/identity-management/iin-agent/src/protocols/externalOperations.ts +++ b/core/identity-management/iin-agent/src/protocols/externalOperations.ts @@ -9,22 +9,22 @@ import { handlePromise} from '../common/utils'; // Handles communication with foreign IIN agents -export const syncExternalStateFromIINAgent = async (networkUnit: iin_agent_pb.NetworkUnitIdentity) => { - console.log('syncExternalStateFromIINAgent:', networkUnit.getNetworkId(), '-', networkUnit.getParticipantId()); +export const syncExternalStateFromIINAgent = async (securityDomainUnit: iin_agent_pb.SecurityDomainMemberIdentity) => { + console.log('syncExternalStateFromIINAgent:', securityDomainUnit.getSecurityDomain(), '-', securityDomainUnit.getMemberId()); }; -// Generates network unit's state/configuration -export const requestIdentityConfiguration = async (networkUnit: iin_agent_pb.NetworkUnitIdentity) => { - console.log('requestIdentityConfiguration:', networkUnit.getNetworkId(), '-', networkUnit.getParticipantId()); +// Generates security domain unit's state/configuration +export const requestIdentityConfiguration = async (securityDomainUnit: iin_agent_pb.SecurityDomainMemberIdentity) => { + console.log('requestIdentityConfiguration:', securityDomainUnit.getSecurityDomain(), '-', securityDomainUnit.getMemberId()); }; -// Processes foreign network unit's state/configuration received from a foreign IIN agent +// Processes foreign security domain unit's state/configuration received from a foreign IIN agent export const sendIdentityConfiguration = async (attestedMembership: iin_agent_pb.AttestedMembership) => { const attestation = attestedMembership.getAttestation(); if (attestation) { - const networkUnit = attestation.getUnitIdentity(); - if (networkUnit) { - console.log('sendIdentityConfiguration:', networkUnit.getNetworkId(), '-', networkUnit.getParticipantId()); + const securityDomainUnit = attestation.getUnitIdentity(); + if (securityDomainUnit) { + console.log('sendIdentityConfiguration:', securityDomainUnit.getSecurityDomain(), '-', securityDomainUnit.getMemberId()); } } }; diff --git a/core/identity-management/iin-agent/src/protocols/localOperations.ts b/core/identity-management/iin-agent/src/protocols/localOperations.ts index 4853236e5..20ab695e3 100644 --- a/core/identity-management/iin-agent/src/protocols/localOperations.ts +++ b/core/identity-management/iin-agent/src/protocols/localOperations.ts @@ -8,12 +8,12 @@ import iin_agent_pb from '@hyperledger-labs/weaver-protos-js/identity/agent_pb'; import { handlePromise} from '../common/utils'; -// Generates attestations on a foreign network unit's state +// Generates attestations on a foreign security domain unit's state export const requestAttestation = async (attestedSecurityDomain: iin_agent_pb.AttestedSecurityDomain) => { console.log('requestAttestation:'); }; -// Processes attestations on a foreign network unit's state received from a local IIN agent +// Processes attestations on a foreign security domain unit's state received from a local IIN agent export const sendAttestation = async (attestedSecurityDomain: iin_agent_pb.AttestedSecurityDomain) => { console.log('sendAttestation:'); }; diff --git a/core/identity-management/iin-agent/src/server.ts b/core/identity-management/iin-agent/src/server.ts index c32749fe8..fb11fc36e 100644 --- a/core/identity-management/iin-agent/src/server.ts +++ b/core/identity-management/iin-agent/src/server.ts @@ -21,8 +21,8 @@ console.log('iin agent def', JSON.stringify(iin_agent_pb_grpc)); //@ts-ignore iinAgentServer.addService(iin_agent_pb_grpc.IINAgentService, { - // Service for syncing foreign network unit's state from its IIN agent. Will communicate with the user/agent triggering this process and respond with an ack to the caller while the sync is occurring. - syncExternalState: (call: { request: iin_agent_pb.NetworkUnitIdentity }, callback: (_: any, object: ack_pb.Ack) => void) => { + // Service for syncing foreign security domain unit's state from its IIN agent. Will communicate with the user/agent triggering this process and respond with an ack to the caller while the sync is occurring. + syncExternalState: (call: { request: iin_agent_pb.SecurityDomainMemberIdentity }, callback: (_: any, object: ack_pb.Ack) => void) => { const ack_response = new ack_pb.Ack(); try { syncExternalStateFromIINAgent(call.request); @@ -42,8 +42,8 @@ iinAgentServer.addService(iin_agent_pb_grpc.IINAgentService, { callback(null, ack_response); } }, - // Service for receiving requests for one's network unit's state from foreign IIN agents. Will communicate with the IIN agent caller and respond with an ack while the attestation is being generated. - requestIdentityConfiguration: (call: { request: iin_agent_pb.NetworkUnitIdentity }, callback: (_: any, object: ack_pb.Ack) => void) => { + // Service for receiving requests for one's security domain unit's state from foreign IIN agents. Will communicate with the IIN agent caller and respond with an ack while the attestation is being generated. + requestIdentityConfiguration: (call: { request: iin_agent_pb.SecurityDomainMemberIdentity }, callback: (_: any, object: ack_pb.Ack) => void) => { const ack_response = new ack_pb.Ack(); try { requestIdentityConfiguration(call.request); @@ -63,7 +63,7 @@ iinAgentServer.addService(iin_agent_pb_grpc.IINAgentService, { callback(null, ack_response); } }, - // Service for receiving network unit states from foreign IIN agents. Will communicate with the IIN agent caller and respond with an ack while the attestation is being processed. + // Service for receiving security domain unit states from foreign IIN agents. Will communicate with the IIN agent caller and respond with an ack while the attestation is being processed. sendIdentityConfiguration: (call: { request: iin_agent_pb.AttestedMembership }, callback: (_: any, object: ack_pb.Ack) => void) => { const ack_response = new ack_pb.Ack(); try { @@ -84,7 +84,7 @@ iinAgentServer.addService(iin_agent_pb_grpc.IINAgentService, { callback(null, ack_response); } }, - // Service for receiving requests for attestations on foreign network unit states from local IIN agents. Will communicate with the IIN agent caller and respond with an ack while the attestation is being generated. + // Service for receiving requests for attestations on foreign security domain unit states from local IIN agents. Will communicate with the IIN agent caller and respond with an ack while the attestation is being generated. requestAttestation: (call: { request: iin_agent_pb.AttestedSecurityDomain }, callback: (_: any, object: ack_pb.Ack) => void) => { const ack_response = new ack_pb.Ack(); try { @@ -105,7 +105,7 @@ iinAgentServer.addService(iin_agent_pb_grpc.IINAgentService, { callback(null, ack_response); } }, - // Service for receiving attestations on foreign network unit states from local IIN agents. Will communicate with the IIN agent caller and respond with an ack while the attestation is being processed. + // Service for receiving attestations on foreign security domain unit states from local IIN agents. Will communicate with the IIN agent caller and respond with an ack while the attestation is being processed. sendAttestation: (call: { request: iin_agent_pb.AttestedSecurityDomain }, callback: (_: any, object: ack_pb.Ack) => void) => { const ack_response = new ack_pb.Ack(); try { From 15f76ebb1f2a341fcb73007121ff87d0e3ee2a37 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Fri, 2 Sep 2022 12:32:20 +0530 Subject: [PATCH 112/150] fix input to requestIdentityConfiguration rpc service Signed-off-by: sandeep.nishad1 --- common/protos-go/identity/agent.pb.go | 60 +++++++++---------- common/protos-go/identity/agent_grpc.pb.go | 12 ++-- common/protos/identity/agent.proto | 2 +- .../src/protocols/externalOperations.ts | 4 +- .../iin-agent/src/server.ts | 2 +- 5 files changed, 40 insertions(+), 40 deletions(-) diff --git a/common/protos-go/identity/agent.pb.go b/common/protos-go/identity/agent.pb.go index a5ec292d3..25317ec44 100644 --- a/common/protos-go/identity/agent.pb.go +++ b/common/protos-go/identity/agent.pb.go @@ -441,43 +441,43 @@ var file_identity_agent_proto_rawDesc = []byte{ 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, - 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0xb4, 0x03, 0x0a, + 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0xbb, 0x03, 0x0a, 0x08, 0x49, 0x49, 0x4e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x54, 0x0a, 0x11, 0x53, 0x79, 0x6e, 0x63, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2c, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, - 0x5f, 0x0a, 0x1c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x66, 0x0a, 0x1c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x2c, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, + 0x33, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x0f, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, - 0x12, 0x52, 0x0a, 0x19, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x2e, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, - 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, - 0x70, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, - 0x63, 0x6b, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, - 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x2e, 0x69, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, - 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, - 0x69, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, - 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x74, 0x74, - 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, - 0x65, 0x64, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, - 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, - 0x6b, 0x22, 0x00, 0x42, 0x75, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, - 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5a, 0x51, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, - 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, - 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, - 0x6f, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, + 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x19, 0x53, 0x65, 0x6e, 0x64, 0x49, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, + 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, + 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x12, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x26, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, + 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, 0x75, 0x72, + 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x0f, + 0x53, 0x65, 0x6e, 0x64, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x26, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, + 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, + 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, 0x75, 0x0a, 0x20, 0x63, 0x6f, + 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5a, 0x51, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, + 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, + 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, + 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -514,7 +514,7 @@ var file_identity_agent_proto_depIdxs = []int32{ 6, // 7: identity.agent.AttestedSecurityDomain.AttestedMembershipSet.membership:type_name -> common.membership.Membership 2, // 8: identity.agent.AttestedSecurityDomain.AttestedMembershipSet.attestations:type_name -> identity.agent.Attestation 0, // 9: identity.agent.IINAgent.SyncExternalState:input_type -> identity.agent.SecurityDomainMemberIdentity - 0, // 10: identity.agent.IINAgent.RequestIdentityConfiguration:input_type -> identity.agent.SecurityDomainMemberIdentity + 1, // 10: identity.agent.IINAgent.RequestIdentityConfiguration:input_type -> identity.agent.SecurityDomainMemberIdentityRequest 3, // 11: identity.agent.IINAgent.SendIdentityConfiguration:input_type -> identity.agent.AttestedMembership 4, // 12: identity.agent.IINAgent.RequestAttestation:input_type -> identity.agent.AttestedSecurityDomain 4, // 13: identity.agent.IINAgent.SendAttestation:input_type -> identity.agent.AttestedSecurityDomain diff --git a/common/protos-go/identity/agent_grpc.pb.go b/common/protos-go/identity/agent_grpc.pb.go index 93f102ea5..35dd958d0 100644 --- a/common/protos-go/identity/agent_grpc.pb.go +++ b/common/protos-go/identity/agent_grpc.pb.go @@ -22,7 +22,7 @@ type IINAgentClient interface { // user or agent triggers a sync of external/foreign network unit's state SyncExternalState(ctx context.Context, in *SecurityDomainMemberIdentity, opts ...grpc.CallOption) (*common.Ack, error) // Requesting network unit's state from a foreign IIN agent. - RequestIdentityConfiguration(ctx context.Context, in *SecurityDomainMemberIdentity, opts ...grpc.CallOption) (*common.Ack, error) + RequestIdentityConfiguration(ctx context.Context, in *SecurityDomainMemberIdentityRequest, opts ...grpc.CallOption) (*common.Ack, error) // Handling network unit's state sent by a foreign IIN agent. SendIdentityConfiguration(ctx context.Context, in *AttestedMembership, opts ...grpc.CallOption) (*common.Ack, error) // Requesting attestation from a local IIN agent. @@ -48,7 +48,7 @@ func (c *iINAgentClient) SyncExternalState(ctx context.Context, in *SecurityDoma return out, nil } -func (c *iINAgentClient) RequestIdentityConfiguration(ctx context.Context, in *SecurityDomainMemberIdentity, opts ...grpc.CallOption) (*common.Ack, error) { +func (c *iINAgentClient) RequestIdentityConfiguration(ctx context.Context, in *SecurityDomainMemberIdentityRequest, opts ...grpc.CallOption) (*common.Ack, error) { out := new(common.Ack) err := c.cc.Invoke(ctx, "/identity.agent.IINAgent/RequestIdentityConfiguration", in, out, opts...) if err != nil { @@ -91,7 +91,7 @@ type IINAgentServer interface { // user or agent triggers a sync of external/foreign network unit's state SyncExternalState(context.Context, *SecurityDomainMemberIdentity) (*common.Ack, error) // Requesting network unit's state from a foreign IIN agent. - RequestIdentityConfiguration(context.Context, *SecurityDomainMemberIdentity) (*common.Ack, error) + RequestIdentityConfiguration(context.Context, *SecurityDomainMemberIdentityRequest) (*common.Ack, error) // Handling network unit's state sent by a foreign IIN agent. SendIdentityConfiguration(context.Context, *AttestedMembership) (*common.Ack, error) // Requesting attestation from a local IIN agent. @@ -108,7 +108,7 @@ type UnimplementedIINAgentServer struct { func (UnimplementedIINAgentServer) SyncExternalState(context.Context, *SecurityDomainMemberIdentity) (*common.Ack, error) { return nil, status.Errorf(codes.Unimplemented, "method SyncExternalState not implemented") } -func (UnimplementedIINAgentServer) RequestIdentityConfiguration(context.Context, *SecurityDomainMemberIdentity) (*common.Ack, error) { +func (UnimplementedIINAgentServer) RequestIdentityConfiguration(context.Context, *SecurityDomainMemberIdentityRequest) (*common.Ack, error) { return nil, status.Errorf(codes.Unimplemented, "method RequestIdentityConfiguration not implemented") } func (UnimplementedIINAgentServer) SendIdentityConfiguration(context.Context, *AttestedMembership) (*common.Ack, error) { @@ -152,7 +152,7 @@ func _IINAgent_SyncExternalState_Handler(srv interface{}, ctx context.Context, d } func _IINAgent_RequestIdentityConfiguration_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(SecurityDomainMemberIdentity) + in := new(SecurityDomainMemberIdentityRequest) if err := dec(in); err != nil { return nil, err } @@ -164,7 +164,7 @@ func _IINAgent_RequestIdentityConfiguration_Handler(srv interface{}, ctx context FullMethod: "/identity.agent.IINAgent/RequestIdentityConfiguration", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(IINAgentServer).RequestIdentityConfiguration(ctx, req.(*SecurityDomainMemberIdentity)) + return srv.(IINAgentServer).RequestIdentityConfiguration(ctx, req.(*SecurityDomainMemberIdentityRequest)) } return interceptor(ctx, in, info, handler) } diff --git a/common/protos/identity/agent.proto b/common/protos/identity/agent.proto index d1f592aa6..b544646cb 100644 --- a/common/protos/identity/agent.proto +++ b/common/protos/identity/agent.proto @@ -13,7 +13,7 @@ service IINAgent { // user or agent triggers a sync of external/foreign network unit's state rpc SyncExternalState(SecurityDomainMemberIdentity) returns (common.ack.Ack) {} // Requesting network unit's state from a foreign IIN agent. - rpc RequestIdentityConfiguration(SecurityDomainMemberIdentity) returns (common.ack.Ack){} + rpc RequestIdentityConfiguration(SecurityDomainMemberIdentityRequest) returns (common.ack.Ack){} // Handling network unit's state sent by a foreign IIN agent. rpc SendIdentityConfiguration(AttestedMembership) returns (common.ack.Ack){} // Requesting attestation from a local IIN agent. diff --git a/core/identity-management/iin-agent/src/protocols/externalOperations.ts b/core/identity-management/iin-agent/src/protocols/externalOperations.ts index b93509490..fdd690adf 100644 --- a/core/identity-management/iin-agent/src/protocols/externalOperations.ts +++ b/core/identity-management/iin-agent/src/protocols/externalOperations.ts @@ -14,8 +14,8 @@ export const syncExternalStateFromIINAgent = async (securityDomainUnit: iin_agen }; // Generates security domain unit's state/configuration -export const requestIdentityConfiguration = async (securityDomainUnit: iin_agent_pb.SecurityDomainMemberIdentity) => { - console.log('requestIdentityConfiguration:', securityDomainUnit.getSecurityDomain(), '-', securityDomainUnit.getMemberId()); +export const requestIdentityConfiguration = async (securityDomainUnit: iin_agent_pb.SecurityDomainMemberIdentityRequest) => { + console.log('requestIdentityConfiguration:', securityDomainUnit.getSourceNetwork()!.getSecurityDomain(), '-', securityDomainUnit.getSourceNetwork()!.getMemberId()); }; // Processes foreign security domain unit's state/configuration received from a foreign IIN agent diff --git a/core/identity-management/iin-agent/src/server.ts b/core/identity-management/iin-agent/src/server.ts index fb11fc36e..0faaafcfe 100644 --- a/core/identity-management/iin-agent/src/server.ts +++ b/core/identity-management/iin-agent/src/server.ts @@ -43,7 +43,7 @@ iinAgentServer.addService(iin_agent_pb_grpc.IINAgentService, { } }, // Service for receiving requests for one's security domain unit's state from foreign IIN agents. Will communicate with the IIN agent caller and respond with an ack while the attestation is being generated. - requestIdentityConfiguration: (call: { request: iin_agent_pb.SecurityDomainMemberIdentity }, callback: (_: any, object: ack_pb.Ack) => void) => { + requestIdentityConfiguration: (call: { request: iin_agent_pb.SecurityDomainMemberIdentityRequest }, callback: (_: any, object: ack_pb.Ack) => void) => { const ack_response = new ack_pb.Ack(); try { requestIdentityConfiguration(call.request); From c0768c6e1787323caf609a06aa81bd24e127ff6f Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Fri, 2 Sep 2022 12:34:57 +0530 Subject: [PATCH 113/150] rename input var Signed-off-by: sandeep.nishad1 --- .../iin-agent/src/protocols/externalOperations.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/identity-management/iin-agent/src/protocols/externalOperations.ts b/core/identity-management/iin-agent/src/protocols/externalOperations.ts index fdd690adf..f078da8d4 100644 --- a/core/identity-management/iin-agent/src/protocols/externalOperations.ts +++ b/core/identity-management/iin-agent/src/protocols/externalOperations.ts @@ -14,8 +14,8 @@ export const syncExternalStateFromIINAgent = async (securityDomainUnit: iin_agen }; // Generates security domain unit's state/configuration -export const requestIdentityConfiguration = async (securityDomainUnit: iin_agent_pb.SecurityDomainMemberIdentityRequest) => { - console.log('requestIdentityConfiguration:', securityDomainUnit.getSourceNetwork()!.getSecurityDomain(), '-', securityDomainUnit.getSourceNetwork()!.getMemberId()); +export const requestIdentityConfiguration = async (request: iin_agent_pb.SecurityDomainMemberIdentityRequest) => { + console.log('requestIdentityConfiguration:', request.getSourceNetwork()!.getSecurityDomain(), '-', request.getSourceNetwork()!.getMemberId()); }; // Processes foreign security domain unit's state/configuration received from a foreign IIN agent From dc9e7bbc5df5c363f415d8ea5cd136562890ed15 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Fri, 2 Sep 2022 13:50:51 +0530 Subject: [PATCH 114/150] space fix Signed-off-by: sandeep.nishad1 --- common/protos/identity/agent.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/protos/identity/agent.proto b/common/protos/identity/agent.proto index b544646cb..1bf68dec5 100644 --- a/common/protos/identity/agent.proto +++ b/common/protos/identity/agent.proto @@ -28,7 +28,7 @@ message SecurityDomainMemberIdentity { string member_id = 2; } -message SecurityDomainMemberIdentityRequest{ +message SecurityDomainMemberIdentityRequest { SecurityDomainMemberIdentity source_network = 1; SecurityDomainMemberIdentity requesting_network = 2; string nonce = 3; From c080aa7902d3a3609ef8617bed8452c989358454 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Fri, 2 Sep 2022 16:25:35 +0530 Subject: [PATCH 115/150] revert back security_domain to securityDomain Signed-off-by: sandeep.nishad1 --- common/protos-go/common/access_control.pb.go | 50 ++--- common/protos-go/common/membership.pb.go | 56 ++--- .../common/verification_policy.pb.go | 54 ++--- common/protos-go/identity/agent.pb.go | 192 +++++++++--------- common/protos-go/identity/agent_grpc.pb.go | 24 +-- common/protos/common/access_control.proto | 2 +- common/protos/common/membership.proto | 2 +- .../protos/common/verification_policy.proto | 2 +- common/protos/identity/agent.proto | 8 +- .../src/protocols/localOperations.ts | 4 +- .../iin-agent/src/server.ts | 4 +- 11 files changed, 200 insertions(+), 198 deletions(-) diff --git a/common/protos-go/common/access_control.pb.go b/common/protos-go/common/access_control.pb.go index bd556d3df..ac5fd10cf 100644 --- a/common/protos-go/common/access_control.pb.go +++ b/common/protos-go/common/access_control.pb.go @@ -27,7 +27,7 @@ type AccessControlPolicy struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - SecurityDomain string `protobuf:"bytes,1,opt,name=security_domain,json=securityDomain,proto3" json:"security_domain,omitempty"` + SecurityDomain string `protobuf:"bytes,1,opt,name=securityDomain,proto3" json:"securityDomain,omitempty"` Rules []*Rule `protobuf:"bytes,2,rep,name=rules,proto3" json:"rules,omitempty"` } @@ -155,30 +155,30 @@ var file_common_access_control_proto_rawDesc = []byte{ 0x0a, 0x1b, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x22, 0x71, 0x0a, 0x13, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x27, 0x0a, 0x0f, 0x73, - 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, - 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x31, 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x52, 0x75, 0x6c, 0x65, - 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x7a, 0x0a, 0x04, 0x52, 0x75, 0x6c, 0x65, 0x12, - 0x1c, 0x0a, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x12, 0x24, 0x0a, - 0x0d, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x54, - 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, - 0x12, 0x0a, 0x04, 0x72, 0x65, 0x61, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x72, - 0x65, 0x61, 0x64, 0x42, 0x7a, 0x0a, 0x27, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, - 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, - 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5a, 0x4f, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, - 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, - 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, - 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x72, 0x6f, 0x6c, 0x22, 0x70, 0x0a, 0x13, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x73, + 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, + 0x61, 0x69, 0x6e, 0x12, 0x31, 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x52, 0x75, 0x6c, 0x65, 0x52, + 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x7a, 0x0a, 0x04, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x1c, + 0x0a, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x12, 0x24, 0x0a, 0x0d, + 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x72, 0x65, 0x61, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x72, 0x65, + 0x61, 0x64, 0x42, 0x7a, 0x0a, 0x27, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5a, 0x4f, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, + 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, + 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, + 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/common/protos-go/common/membership.pb.go b/common/protos-go/common/membership.pb.go index 337e5a80d..98180bb7a 100644 --- a/common/protos-go/common/membership.pb.go +++ b/common/protos-go/common/membership.pb.go @@ -27,7 +27,7 @@ type Membership struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - SecurityDomain string `protobuf:"bytes,1,opt,name=security_domain,json=securityDomain,proto3" json:"security_domain,omitempty"` + SecurityDomain string `protobuf:"bytes,1,opt,name=securityDomain,proto3" json:"securityDomain,omitempty"` Members map[string]*Member `protobuf:"bytes,2,rep,name=members,proto3" json:"members,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } @@ -147,33 +147,33 @@ var File_common_membership_proto protoreflect.FileDescriptor var file_common_membership_proto_rawDesc = []byte{ 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x11, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x22, 0xd2, 0x01, 0x0a, - 0x0a, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x27, 0x0a, 0x0f, 0x73, - 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, - 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x44, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x1a, 0x55, 0x0a, 0x0c, 0x4d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2f, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, - 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, - 0x01, 0x22, 0x48, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x03, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x76, 0x0a, 0x23, 0x63, - 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, - 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, - 0x69, 0x70, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, - 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, - 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x2e, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x22, 0xd1, 0x01, 0x0a, + 0x0a, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x26, 0x0a, 0x0e, 0x73, + 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, + 0x61, 0x69, 0x6e, 0x12, 0x44, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x65, + 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, + 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x1a, 0x55, 0x0a, 0x0c, 0x4d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2f, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x22, 0x48, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x76, 0x0a, 0x23, 0x63, 0x6f, + 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, + 0x70, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, + 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, + 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, + 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/common/protos-go/common/verification_policy.pb.go b/common/protos-go/common/verification_policy.pb.go index b6f7197b1..2a26bc03f 100644 --- a/common/protos-go/common/verification_policy.pb.go +++ b/common/protos-go/common/verification_policy.pb.go @@ -28,7 +28,7 @@ type VerificationPolicy struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - SecurityDomain string `protobuf:"bytes,1,opt,name=security_domain,json=securityDomain,proto3" json:"security_domain,omitempty"` + SecurityDomain string `protobuf:"bytes,1,opt,name=securityDomain,proto3" json:"securityDomain,omitempty"` Identifiers []*Identifier `protobuf:"bytes,2,rep,name=identifiers,proto3" json:"identifiers,omitempty"` } @@ -199,34 +199,34 @@ var file_common_verification_policy_proto_rawDesc = []byte{ 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1a, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x87, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x86, 0x01, 0x0a, 0x12, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, - 0x79, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, - 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x48, - 0x0a, 0x0b, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x65, 0x72, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0b, 0x69, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x22, 0x38, 0x0a, 0x06, 0x50, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, - 0x69, 0x61, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, - 0x69, 0x61, 0x22, 0x62, 0x0a, 0x0a, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, - 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x12, 0x3a, 0x0a, 0x06, 0x70, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x06, - 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x42, 0x7f, 0x0a, 0x2c, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, - 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, + 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, + 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x48, 0x0a, + 0x0b, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x65, 0x72, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0b, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x22, 0x38, 0x0a, 0x06, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69, + 0x61, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, 0x72, 0x69, 0x74, 0x65, 0x72, 0x69, + 0x61, 0x22, 0x62, 0x0a, 0x0a, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, + 0x18, 0x0a, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x12, 0x3a, 0x0a, 0x06, 0x70, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, - 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, - 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, - 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x06, 0x70, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x42, 0x7f, 0x0a, 0x2c, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, + 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, + 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/common/protos-go/identity/agent.pb.go b/common/protos-go/identity/agent.pb.go index 25317ec44..da81b6fb3 100644 --- a/common/protos-go/identity/agent.pb.go +++ b/common/protos-go/identity/agent.pb.go @@ -261,17 +261,17 @@ func (x *AttestedMembership) GetAttestation() *Attestation { } // Counter attestation over security domain membership attested by its participants -type AttestedSecurityDomain struct { +type CounterAttestedMembership struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - SecurityDomain *AttestedSecurityDomain_AttestedMembershipSet `protobuf:"bytes,1,opt,name=security_domain,json=securityDomain,proto3" json:"security_domain,omitempty"` - Attestations []*Attestation `protobuf:"bytes,2,rep,name=attestations,proto3" json:"attestations,omitempty"` + AttestedMembershipSet *CounterAttestedMembership_AttestedMembershipSet `protobuf:"bytes,1,opt,name=attested_membership_set,json=attestedMembershipSet,proto3" json:"attested_membership_set,omitempty"` + Attestations []*Attestation `protobuf:"bytes,2,rep,name=attestations,proto3" json:"attestations,omitempty"` } -func (x *AttestedSecurityDomain) Reset() { - *x = AttestedSecurityDomain{} +func (x *CounterAttestedMembership) Reset() { + *x = CounterAttestedMembership{} if protoimpl.UnsafeEnabled { mi := &file_identity_agent_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -279,13 +279,13 @@ func (x *AttestedSecurityDomain) Reset() { } } -func (x *AttestedSecurityDomain) String() string { +func (x *CounterAttestedMembership) String() string { return protoimpl.X.MessageStringOf(x) } -func (*AttestedSecurityDomain) ProtoMessage() {} +func (*CounterAttestedMembership) ProtoMessage() {} -func (x *AttestedSecurityDomain) ProtoReflect() protoreflect.Message { +func (x *CounterAttestedMembership) ProtoReflect() protoreflect.Message { mi := &file_identity_agent_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -297,26 +297,26 @@ func (x *AttestedSecurityDomain) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use AttestedSecurityDomain.ProtoReflect.Descriptor instead. -func (*AttestedSecurityDomain) Descriptor() ([]byte, []int) { +// Deprecated: Use CounterAttestedMembership.ProtoReflect.Descriptor instead. +func (*CounterAttestedMembership) Descriptor() ([]byte, []int) { return file_identity_agent_proto_rawDescGZIP(), []int{4} } -func (x *AttestedSecurityDomain) GetSecurityDomain() *AttestedSecurityDomain_AttestedMembershipSet { +func (x *CounterAttestedMembership) GetAttestedMembershipSet() *CounterAttestedMembership_AttestedMembershipSet { if x != nil { - return x.SecurityDomain + return x.AttestedMembershipSet } return nil } -func (x *AttestedSecurityDomain) GetAttestations() []*Attestation { +func (x *CounterAttestedMembership) GetAttestations() []*Attestation { if x != nil { return x.Attestations } return nil } -type AttestedSecurityDomain_AttestedMembershipSet struct { +type CounterAttestedMembership_AttestedMembershipSet struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -325,8 +325,8 @@ type AttestedSecurityDomain_AttestedMembershipSet struct { Attestations []*Attestation `protobuf:"bytes,2,rep,name=attestations,proto3" json:"attestations,omitempty"` } -func (x *AttestedSecurityDomain_AttestedMembershipSet) Reset() { - *x = AttestedSecurityDomain_AttestedMembershipSet{} +func (x *CounterAttestedMembership_AttestedMembershipSet) Reset() { + *x = CounterAttestedMembership_AttestedMembershipSet{} if protoimpl.UnsafeEnabled { mi := &file_identity_agent_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -334,13 +334,13 @@ func (x *AttestedSecurityDomain_AttestedMembershipSet) Reset() { } } -func (x *AttestedSecurityDomain_AttestedMembershipSet) String() string { +func (x *CounterAttestedMembership_AttestedMembershipSet) String() string { return protoimpl.X.MessageStringOf(x) } -func (*AttestedSecurityDomain_AttestedMembershipSet) ProtoMessage() {} +func (*CounterAttestedMembership_AttestedMembershipSet) ProtoMessage() {} -func (x *AttestedSecurityDomain_AttestedMembershipSet) ProtoReflect() protoreflect.Message { +func (x *CounterAttestedMembership_AttestedMembershipSet) ProtoReflect() protoreflect.Message { mi := &file_identity_agent_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -352,19 +352,19 @@ func (x *AttestedSecurityDomain_AttestedMembershipSet) ProtoReflect() protorefle return mi.MessageOf(x) } -// Deprecated: Use AttestedSecurityDomain_AttestedMembershipSet.ProtoReflect.Descriptor instead. -func (*AttestedSecurityDomain_AttestedMembershipSet) Descriptor() ([]byte, []int) { +// Deprecated: Use CounterAttestedMembership_AttestedMembershipSet.ProtoReflect.Descriptor instead. +func (*CounterAttestedMembership_AttestedMembershipSet) Descriptor() ([]byte, []int) { return file_identity_agent_proto_rawDescGZIP(), []int{4, 0} } -func (x *AttestedSecurityDomain_AttestedMembershipSet) GetMembership() *common.Membership { +func (x *CounterAttestedMembership_AttestedMembershipSet) GetMembership() *common.Membership { if x != nil { return x.Membership } return nil } -func (x *AttestedSecurityDomain_AttestedMembershipSet) GetAttestations() []*Attestation { +func (x *CounterAttestedMembership_AttestedMembershipSet) GetAttestations() []*Attestation { if x != nil { return x.Attestations } @@ -420,64 +420,66 @@ var file_identity_agent_proto_rawDesc = []byte{ 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, - 0xda, 0x02, 0x0a, 0x16, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, 0x75, - 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x65, 0x0a, 0x0f, 0x73, 0x65, - 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, - 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x41, 0x74, 0x74, 0x65, - 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x65, - 0x74, 0x52, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, - 0x6e, 0x12, 0x3f, 0x0a, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x1a, 0x97, 0x01, 0x0a, 0x15, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x65, 0x74, 0x12, 0x3d, 0x0a, 0x0a, - 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, - 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x3f, 0x0a, 0x0c, 0x61, - 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, - 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, - 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0xbb, 0x03, 0x0a, - 0x08, 0x49, 0x49, 0x4e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x54, 0x0a, 0x11, 0x53, 0x79, 0x6e, - 0x63, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2c, + 0xef, 0x02, 0x0a, 0x19, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x41, 0x74, 0x74, 0x65, 0x73, + 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x77, 0x0a, + 0x17, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x68, 0x69, 0x70, 0x5f, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, - 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, - 0x66, 0x0a, 0x1c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x33, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, - 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, - 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x19, 0x53, 0x65, 0x6e, 0x64, 0x49, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, + 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x65, 0x74, 0x52, + 0x15, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, + 0x68, 0x69, 0x70, 0x53, 0x65, 0x74, 0x12, 0x3f, 0x0a, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, + 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x97, 0x01, 0x0a, 0x15, 0x41, 0x74, 0x74, 0x65, + 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x65, + 0x74, 0x12, 0x3d, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x68, 0x69, 0x70, 0x52, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, + 0x12, 0x3f, 0x0a, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x32, 0xc1, 0x03, 0x0a, 0x08, 0x49, 0x49, 0x4e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x54, + 0x0a, 0x11, 0x53, 0x79, 0x6e, 0x63, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x12, 0x2c, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, + 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, + 0x61, 0x69, 0x6e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, + 0x63, 0x6b, 0x22, 0x00, 0x12, 0x66, 0x0a, 0x1c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, - 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x12, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x26, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, - 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, 0x75, 0x72, - 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x0f, - 0x53, 0x65, 0x6e, 0x64, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x26, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, - 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, - 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, 0x75, 0x0a, 0x20, 0x63, 0x6f, - 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5a, 0x51, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, - 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, - 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, - 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, + 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, + 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x19, + 0x53, 0x65, 0x6e, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x2e, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, + 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x1a, 0x0f, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, + 0x12, 0x52, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x74, 0x74, 0x65, 0x73, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x41, + 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, + 0x70, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, + 0x63, 0x6b, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x74, 0x74, 0x65, + 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, + 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, + 0x69, 0x70, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, + 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, 0x75, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, + 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5a, 0x51, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, + 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, + 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, + 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, + 0x2d, 0x67, 0x6f, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -494,14 +496,14 @@ func file_identity_agent_proto_rawDescGZIP() []byte { var file_identity_agent_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_identity_agent_proto_goTypes = []interface{}{ - (*SecurityDomainMemberIdentity)(nil), // 0: identity.agent.SecurityDomainMemberIdentity - (*SecurityDomainMemberIdentityRequest)(nil), // 1: identity.agent.SecurityDomainMemberIdentityRequest - (*Attestation)(nil), // 2: identity.agent.Attestation - (*AttestedMembership)(nil), // 3: identity.agent.AttestedMembership - (*AttestedSecurityDomain)(nil), // 4: identity.agent.AttestedSecurityDomain - (*AttestedSecurityDomain_AttestedMembershipSet)(nil), // 5: identity.agent.AttestedSecurityDomain.AttestedMembershipSet - (*common.Membership)(nil), // 6: common.membership.Membership - (*common.Ack)(nil), // 7: common.ack.Ack + (*SecurityDomainMemberIdentity)(nil), // 0: identity.agent.SecurityDomainMemberIdentity + (*SecurityDomainMemberIdentityRequest)(nil), // 1: identity.agent.SecurityDomainMemberIdentityRequest + (*Attestation)(nil), // 2: identity.agent.Attestation + (*AttestedMembership)(nil), // 3: identity.agent.AttestedMembership + (*CounterAttestedMembership)(nil), // 4: identity.agent.CounterAttestedMembership + (*CounterAttestedMembership_AttestedMembershipSet)(nil), // 5: identity.agent.CounterAttestedMembership.AttestedMembershipSet + (*common.Membership)(nil), // 6: common.membership.Membership + (*common.Ack)(nil), // 7: common.ack.Ack } var file_identity_agent_proto_depIdxs = []int32{ 0, // 0: identity.agent.SecurityDomainMemberIdentityRequest.source_network:type_name -> identity.agent.SecurityDomainMemberIdentity @@ -509,15 +511,15 @@ var file_identity_agent_proto_depIdxs = []int32{ 0, // 2: identity.agent.Attestation.unit_identity:type_name -> identity.agent.SecurityDomainMemberIdentity 6, // 3: identity.agent.AttestedMembership.membership:type_name -> common.membership.Membership 2, // 4: identity.agent.AttestedMembership.attestation:type_name -> identity.agent.Attestation - 5, // 5: identity.agent.AttestedSecurityDomain.security_domain:type_name -> identity.agent.AttestedSecurityDomain.AttestedMembershipSet - 2, // 6: identity.agent.AttestedSecurityDomain.attestations:type_name -> identity.agent.Attestation - 6, // 7: identity.agent.AttestedSecurityDomain.AttestedMembershipSet.membership:type_name -> common.membership.Membership - 2, // 8: identity.agent.AttestedSecurityDomain.AttestedMembershipSet.attestations:type_name -> identity.agent.Attestation + 5, // 5: identity.agent.CounterAttestedMembership.attested_membership_set:type_name -> identity.agent.CounterAttestedMembership.AttestedMembershipSet + 2, // 6: identity.agent.CounterAttestedMembership.attestations:type_name -> identity.agent.Attestation + 6, // 7: identity.agent.CounterAttestedMembership.AttestedMembershipSet.membership:type_name -> common.membership.Membership + 2, // 8: identity.agent.CounterAttestedMembership.AttestedMembershipSet.attestations:type_name -> identity.agent.Attestation 0, // 9: identity.agent.IINAgent.SyncExternalState:input_type -> identity.agent.SecurityDomainMemberIdentity 1, // 10: identity.agent.IINAgent.RequestIdentityConfiguration:input_type -> identity.agent.SecurityDomainMemberIdentityRequest 3, // 11: identity.agent.IINAgent.SendIdentityConfiguration:input_type -> identity.agent.AttestedMembership - 4, // 12: identity.agent.IINAgent.RequestAttestation:input_type -> identity.agent.AttestedSecurityDomain - 4, // 13: identity.agent.IINAgent.SendAttestation:input_type -> identity.agent.AttestedSecurityDomain + 4, // 12: identity.agent.IINAgent.RequestAttestation:input_type -> identity.agent.CounterAttestedMembership + 4, // 13: identity.agent.IINAgent.SendAttestation:input_type -> identity.agent.CounterAttestedMembership 7, // 14: identity.agent.IINAgent.SyncExternalState:output_type -> common.ack.Ack 7, // 15: identity.agent.IINAgent.RequestIdentityConfiguration:output_type -> common.ack.Ack 7, // 16: identity.agent.IINAgent.SendIdentityConfiguration:output_type -> common.ack.Ack @@ -585,7 +587,7 @@ func file_identity_agent_proto_init() { } } file_identity_agent_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AttestedSecurityDomain); i { + switch v := v.(*CounterAttestedMembership); i { case 0: return &v.state case 1: @@ -597,7 +599,7 @@ func file_identity_agent_proto_init() { } } file_identity_agent_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AttestedSecurityDomain_AttestedMembershipSet); i { + switch v := v.(*CounterAttestedMembership_AttestedMembershipSet); i { case 0: return &v.state case 1: diff --git a/common/protos-go/identity/agent_grpc.pb.go b/common/protos-go/identity/agent_grpc.pb.go index 35dd958d0..2f49c04b2 100644 --- a/common/protos-go/identity/agent_grpc.pb.go +++ b/common/protos-go/identity/agent_grpc.pb.go @@ -26,9 +26,9 @@ type IINAgentClient interface { // Handling network unit's state sent by a foreign IIN agent. SendIdentityConfiguration(ctx context.Context, in *AttestedMembership, opts ...grpc.CallOption) (*common.Ack, error) // Requesting attestation from a local IIN agent. - RequestAttestation(ctx context.Context, in *AttestedSecurityDomain, opts ...grpc.CallOption) (*common.Ack, error) + RequestAttestation(ctx context.Context, in *CounterAttestedMembership, opts ...grpc.CallOption) (*common.Ack, error) // Handling attestation sent by a local IIN agent. - SendAttestation(ctx context.Context, in *AttestedSecurityDomain, opts ...grpc.CallOption) (*common.Ack, error) + SendAttestation(ctx context.Context, in *CounterAttestedMembership, opts ...grpc.CallOption) (*common.Ack, error) } type iINAgentClient struct { @@ -66,7 +66,7 @@ func (c *iINAgentClient) SendIdentityConfiguration(ctx context.Context, in *Atte return out, nil } -func (c *iINAgentClient) RequestAttestation(ctx context.Context, in *AttestedSecurityDomain, opts ...grpc.CallOption) (*common.Ack, error) { +func (c *iINAgentClient) RequestAttestation(ctx context.Context, in *CounterAttestedMembership, opts ...grpc.CallOption) (*common.Ack, error) { out := new(common.Ack) err := c.cc.Invoke(ctx, "/identity.agent.IINAgent/RequestAttestation", in, out, opts...) if err != nil { @@ -75,7 +75,7 @@ func (c *iINAgentClient) RequestAttestation(ctx context.Context, in *AttestedSec return out, nil } -func (c *iINAgentClient) SendAttestation(ctx context.Context, in *AttestedSecurityDomain, opts ...grpc.CallOption) (*common.Ack, error) { +func (c *iINAgentClient) SendAttestation(ctx context.Context, in *CounterAttestedMembership, opts ...grpc.CallOption) (*common.Ack, error) { out := new(common.Ack) err := c.cc.Invoke(ctx, "/identity.agent.IINAgent/SendAttestation", in, out, opts...) if err != nil { @@ -95,9 +95,9 @@ type IINAgentServer interface { // Handling network unit's state sent by a foreign IIN agent. SendIdentityConfiguration(context.Context, *AttestedMembership) (*common.Ack, error) // Requesting attestation from a local IIN agent. - RequestAttestation(context.Context, *AttestedSecurityDomain) (*common.Ack, error) + RequestAttestation(context.Context, *CounterAttestedMembership) (*common.Ack, error) // Handling attestation sent by a local IIN agent. - SendAttestation(context.Context, *AttestedSecurityDomain) (*common.Ack, error) + SendAttestation(context.Context, *CounterAttestedMembership) (*common.Ack, error) mustEmbedUnimplementedIINAgentServer() } @@ -114,10 +114,10 @@ func (UnimplementedIINAgentServer) RequestIdentityConfiguration(context.Context, func (UnimplementedIINAgentServer) SendIdentityConfiguration(context.Context, *AttestedMembership) (*common.Ack, error) { return nil, status.Errorf(codes.Unimplemented, "method SendIdentityConfiguration not implemented") } -func (UnimplementedIINAgentServer) RequestAttestation(context.Context, *AttestedSecurityDomain) (*common.Ack, error) { +func (UnimplementedIINAgentServer) RequestAttestation(context.Context, *CounterAttestedMembership) (*common.Ack, error) { return nil, status.Errorf(codes.Unimplemented, "method RequestAttestation not implemented") } -func (UnimplementedIINAgentServer) SendAttestation(context.Context, *AttestedSecurityDomain) (*common.Ack, error) { +func (UnimplementedIINAgentServer) SendAttestation(context.Context, *CounterAttestedMembership) (*common.Ack, error) { return nil, status.Errorf(codes.Unimplemented, "method SendAttestation not implemented") } func (UnimplementedIINAgentServer) mustEmbedUnimplementedIINAgentServer() {} @@ -188,7 +188,7 @@ func _IINAgent_SendIdentityConfiguration_Handler(srv interface{}, ctx context.Co } func _IINAgent_RequestAttestation_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(AttestedSecurityDomain) + in := new(CounterAttestedMembership) if err := dec(in); err != nil { return nil, err } @@ -200,13 +200,13 @@ func _IINAgent_RequestAttestation_Handler(srv interface{}, ctx context.Context, FullMethod: "/identity.agent.IINAgent/RequestAttestation", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(IINAgentServer).RequestAttestation(ctx, req.(*AttestedSecurityDomain)) + return srv.(IINAgentServer).RequestAttestation(ctx, req.(*CounterAttestedMembership)) } return interceptor(ctx, in, info, handler) } func _IINAgent_SendAttestation_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(AttestedSecurityDomain) + in := new(CounterAttestedMembership) if err := dec(in); err != nil { return nil, err } @@ -218,7 +218,7 @@ func _IINAgent_SendAttestation_Handler(srv interface{}, ctx context.Context, dec FullMethod: "/identity.agent.IINAgent/SendAttestation", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(IINAgentServer).SendAttestation(ctx, req.(*AttestedSecurityDomain)) + return srv.(IINAgentServer).SendAttestation(ctx, req.(*CounterAttestedMembership)) } return interceptor(ctx, in, info, handler) } diff --git a/common/protos/common/access_control.proto b/common/protos/common/access_control.proto index 6bbf84666..183aba26b 100644 --- a/common/protos/common/access_control.proto +++ b/common/protos/common/access_control.proto @@ -8,7 +8,7 @@ option go_package = "github.com/hyperledger-labs/weaver-dlt-interoperability/com // AccessControlPolicy specifies a set of data that can be accessed by some // SecurityGroup message AccessControlPolicy { - string security_domain = 1; + string securityDomain = 1; repeated Rule rules = 2; } diff --git a/common/protos/common/membership.proto b/common/protos/common/membership.proto index 9d66021d2..f32125a2e 100644 --- a/common/protos/common/membership.proto +++ b/common/protos/common/membership.proto @@ -8,7 +8,7 @@ option go_package = "github.com/hyperledger-labs/weaver-dlt-interoperability/com // Membership captures the members of an external entity such as a thing, // person, organization or groups of entities such as networks message Membership { - string security_domain = 1; + string securityDomain = 1; map members = 2; } diff --git a/common/protos/common/verification_policy.proto b/common/protos/common/verification_policy.proto index 70c92a685..cad871485 100644 --- a/common/protos/common/verification_policy.proto +++ b/common/protos/common/verification_policy.proto @@ -9,7 +9,7 @@ option go_package = "github.com/hyperledger-labs/weaver-dlt-interoperability/com // network need to provide proof of a view in order for it to be deemed valid by // the Fabric network message VerificationPolicy { - string security_domain = 1; + string securityDomain = 1; repeated Identifier identifiers = 2; } diff --git a/common/protos/identity/agent.proto b/common/protos/identity/agent.proto index 1bf68dec5..84e5ef7af 100644 --- a/common/protos/identity/agent.proto +++ b/common/protos/identity/agent.proto @@ -17,9 +17,9 @@ service IINAgent { // Handling network unit's state sent by a foreign IIN agent. rpc SendIdentityConfiguration(AttestedMembership) returns (common.ack.Ack){} // Requesting attestation from a local IIN agent. - rpc RequestAttestation(AttestedSecurityDomain) returns (common.ack.Ack){} + rpc RequestAttestation(CounterAttestedMembership) returns (common.ack.Ack){} // Handling attestation sent by a local IIN agent. - rpc SendAttestation(AttestedSecurityDomain) returns (common.ack.Ack){} + rpc SendAttestation(CounterAttestedMembership) returns (common.ack.Ack){} } // Unique identifier for a unit of a network that runs an IIN agent @@ -48,11 +48,11 @@ message AttestedMembership { } // Counter attestation over security domain membership attested by its participants -message AttestedSecurityDomain { +message CounterAttestedMembership { message AttestedMembershipSet { common.membership.Membership membership = 1; repeated Attestation attestations = 2; } - AttestedMembershipSet security_domain = 1; + AttestedMembershipSet attested_membership_set = 1; repeated Attestation attestations = 2; } diff --git a/core/identity-management/iin-agent/src/protocols/localOperations.ts b/core/identity-management/iin-agent/src/protocols/localOperations.ts index 20ab695e3..3111f0ba0 100644 --- a/core/identity-management/iin-agent/src/protocols/localOperations.ts +++ b/core/identity-management/iin-agent/src/protocols/localOperations.ts @@ -9,11 +9,11 @@ import { handlePromise} from '../common/utils'; // Generates attestations on a foreign security domain unit's state -export const requestAttestation = async (attestedSecurityDomain: iin_agent_pb.AttestedSecurityDomain) => { +export const requestAttestation = async (counterAttestedMembership: iin_agent_pb.CounterAttestedMembership) => { console.log('requestAttestation:'); }; // Processes attestations on a foreign security domain unit's state received from a local IIN agent -export const sendAttestation = async (attestedSecurityDomain: iin_agent_pb.AttestedSecurityDomain) => { +export const sendAttestation = async (counterAttestedMembership: iin_agent_pb.CounterAttestedMembership) => { console.log('sendAttestation:'); }; diff --git a/core/identity-management/iin-agent/src/server.ts b/core/identity-management/iin-agent/src/server.ts index 0faaafcfe..57b184209 100644 --- a/core/identity-management/iin-agent/src/server.ts +++ b/core/identity-management/iin-agent/src/server.ts @@ -85,7 +85,7 @@ iinAgentServer.addService(iin_agent_pb_grpc.IINAgentService, { } }, // Service for receiving requests for attestations on foreign security domain unit states from local IIN agents. Will communicate with the IIN agent caller and respond with an ack while the attestation is being generated. - requestAttestation: (call: { request: iin_agent_pb.AttestedSecurityDomain }, callback: (_: any, object: ack_pb.Ack) => void) => { + requestAttestation: (call: { request: iin_agent_pb.CounterAttestedMembership }, callback: (_: any, object: ack_pb.Ack) => void) => { const ack_response = new ack_pb.Ack(); try { requestAttestation(call.request); @@ -106,7 +106,7 @@ iinAgentServer.addService(iin_agent_pb_grpc.IINAgentService, { } }, // Service for receiving attestations on foreign security domain unit states from local IIN agents. Will communicate with the IIN agent caller and respond with an ack while the attestation is being processed. - sendAttestation: (call: { request: iin_agent_pb.AttestedSecurityDomain }, callback: (_: any, object: ack_pb.Ack) => void) => { + sendAttestation: (call: { request: iin_agent_pb.CounterAttestedMembership }, callback: (_: any, object: ack_pb.Ack) => void) => { const ack_response = new ack_pb.Ack(); try { sendAttestation(call.request); From fd2113250f46219a56cd42e23fb90ea92c28d3b5 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Tue, 6 Sep 2022 12:27:17 +0530 Subject: [PATCH 116/150] 1. Use VERSION file instead of makefile.variables to update version of docker modules 2. Update Workflows accordingly. 3. Added Participants in ContractTransaction Proto. 4. Added endorsingOrgs in SDK for write external state transaction. 5. Driver now uses participants from Ctx to set endorsingOrgs for write transaction during event publication Signed-off-by: sandeep.nishad1 --- .github/workflows/deploy_corda-pkgs.yml | 2 +- .github/workflows/deploy_fabric-pkgs.yml | 2 +- .github/workflows/deploy_go-pkgs.yml | 5 +- .github/workflows/deploy_relay-server.yml | 2 +- .github/workflows/deploy_weaver-fabric-cc.yml | 2 +- common/protos-go/common/events.pb.go | 84 +++++++++++-------- common/protos/common/events.proto | 1 + core/drivers/corda-driver/VERSION | 1 + core/drivers/corda-driver/makefile | 5 +- .../corda-driver/makefile.variables.docker | 4 - core/drivers/fabric-driver/VERSION | 1 + core/drivers/fabric-driver/makefile | 7 +- .../fabric-driver/makefile.variables.docker | 4 - core/drivers/fabric-driver/package-local.json | 2 +- core/drivers/fabric-driver/package.json | 6 +- core/drivers/fabric-driver/server/events.ts | 30 +++++-- core/relay/Makefile | 5 +- core/relay/Makefile.variables.docker | 4 - core/relay/VERSION | 1 + .../package-local.json | 2 +- .../interoperation-node-sdk/package.json | 2 +- .../src/InteroperableHelper.ts | 10 ++- 22 files changed, 109 insertions(+), 73 deletions(-) create mode 100644 core/drivers/corda-driver/VERSION delete mode 100644 core/drivers/corda-driver/makefile.variables.docker create mode 100644 core/drivers/fabric-driver/VERSION delete mode 100644 core/drivers/fabric-driver/makefile.variables.docker delete mode 100644 core/relay/Makefile.variables.docker create mode 100644 core/relay/VERSION diff --git a/.github/workflows/deploy_corda-pkgs.yml b/.github/workflows/deploy_corda-pkgs.yml index d05052161..d860ef45d 100644 --- a/.github/workflows/deploy_corda-pkgs.yml +++ b/.github/workflows/deploy_corda-pkgs.yml @@ -12,7 +12,7 @@ on: - 'common/protos-java-kt/gradle.properties' - 'core/network/corda-interop-app/gradle.properties' - 'sdks/corda/gradle.properties' - - 'core/drivers/corda-driver/makefile.variables.docker' + - 'core/drivers/corda-driver/VERSION' # Allows you to run this workflow manually from the Actions tab workflow_dispatch: diff --git a/.github/workflows/deploy_fabric-pkgs.yml b/.github/workflows/deploy_fabric-pkgs.yml index 4949a9bff..efdd81c6c 100644 --- a/.github/workflows/deploy_fabric-pkgs.yml +++ b/.github/workflows/deploy_fabric-pkgs.yml @@ -11,7 +11,7 @@ on: paths: - 'common/protos-js/package.json' - 'sdks/fabric/interoperation-node-sdk/package.json' - - 'core/drivers/fabric-driver/makefile.variables.docker' + - 'core/drivers/fabric-driver/VERSION' # Allows you to run this workflow manually from the Actions tab workflow_dispatch: diff --git a/.github/workflows/deploy_go-pkgs.yml b/.github/workflows/deploy_go-pkgs.yml index 5ae1ad2dd..e526ffe9d 100644 --- a/.github/workflows/deploy_go-pkgs.yml +++ b/.github/workflows/deploy_go-pkgs.yml @@ -7,7 +7,7 @@ name: Deploy Go Modules on: push: branches: - - test + - main paths: - 'common/protos-go/VERSION' - 'core/network/fabric-interop-cc/libs/utils/VERSION' @@ -15,6 +15,9 @@ on: - 'core/network/fabric-interop-cc/interfaces/asset-mgmt/VERSION' - 'core/network/fabric-interop-cc/contracts/interop/VERSION' - 'sdks/fabric/go-sdk/VERSION' + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: jobs: publish-protos: diff --git a/.github/workflows/deploy_relay-server.yml b/.github/workflows/deploy_relay-server.yml index cd0e9bccf..54fee7c05 100644 --- a/.github/workflows/deploy_relay-server.yml +++ b/.github/workflows/deploy_relay-server.yml @@ -9,7 +9,7 @@ on: branches: - main paths: - - 'core/relay/Makefile.variables.docker' + - 'core/relay/VERSION' # Allows you to run this workflow manually from the Actions tab workflow_dispatch: diff --git a/.github/workflows/deploy_weaver-fabric-cc.yml b/.github/workflows/deploy_weaver-fabric-cc.yml index 8d9f4ae77..4c01f53ca 100644 --- a/.github/workflows/deploy_weaver-fabric-cc.yml +++ b/.github/workflows/deploy_weaver-fabric-cc.yml @@ -9,7 +9,7 @@ on: branches: - main paths: - - 'core/network/fabric-interop-cc/contracts/interop' + - 'core/network/fabric-interop-cc/contracts/interop/VERSION' # Allows you to run this workflow manually from the Actions tab workflow_dispatch: diff --git a/common/protos-go/common/events.pb.go b/common/protos-go/common/events.pb.go index 76160920d..43ed43b54 100644 --- a/common/protos-go/common/events.pb.go +++ b/common/protos-go/common/events.pb.go @@ -415,6 +415,7 @@ type ContractTransaction struct { Func string `protobuf:"bytes,4,opt,name=func,proto3" json:"func,omitempty"` Args [][]byte `protobuf:"bytes,5,rep,name=args,proto3" json:"args,omitempty"` ReplaceArgIndex uint64 `protobuf:"varint,6,opt,name=replace_arg_index,json=replaceArgIndex,proto3" json:"replace_arg_index,omitempty"` + Participants []string `protobuf:"bytes,7,rep,name=participants,proto3" json:"participants,omitempty"` } func (x *ContractTransaction) Reset() { @@ -491,6 +492,13 @@ func (x *ContractTransaction) GetReplaceArgIndex() uint64 { return 0 } +func (x *ContractTransaction) GetParticipants() []string { + if x != nil { + return x.Participants + } + return nil +} + type EventPublication struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -748,7 +756,7 @@ var file_common_events_proto_rawDesc = []byte{ 0x4b, 0x10, 0x03, 0x12, 0x17, 0x0a, 0x13, 0x55, 0x4e, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x04, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x44, 0x10, 0x05, 0x12, 0x09, - 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x06, 0x22, 0xc4, 0x01, 0x0a, 0x13, 0x43, 0x6f, + 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x06, 0x22, 0xe8, 0x01, 0x0a, 0x13, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1b, @@ -761,42 +769,44 @@ var file_common_events_proto_rawDesc = []byte{ 0x61, 0x72, 0x67, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x5f, 0x61, 0x72, 0x67, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x41, 0x72, 0x67, 0x49, 0x6e, 0x64, 0x65, 0x78, - 0x22, 0x7b, 0x0a, 0x10, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x03, 0x63, 0x74, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x03, 0x63, 0x74, 0x78, 0x12, 0x19, 0x0a, 0x07, - 0x61, 0x70, 0x70, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, - 0x06, 0x61, 0x70, 0x70, 0x55, 0x72, 0x6c, 0x42, 0x14, 0x0a, 0x12, 0x70, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0x40, 0x0a, - 0x0b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x12, 0x31, 0x0a, 0x06, - 0x73, 0x74, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x65, 0x73, 0x22, - 0x73, 0x0a, 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x30, 0x0a, - 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, - 0x19, 0x0a, 0x08, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x2a, 0x3e, 0x0a, 0x09, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x4c, 0x45, 0x44, 0x47, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, - 0x45, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x53, 0x53, 0x45, 0x54, 0x5f, 0x4c, 0x4f, 0x43, - 0x4b, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x53, 0x53, 0x45, 0x54, 0x5f, 0x43, 0x4c, 0x41, - 0x49, 0x4d, 0x10, 0x02, 0x2a, 0x3f, 0x0a, 0x11, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, - 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x55, 0x42, - 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x55, - 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x50, 0x44, - 0x41, 0x54, 0x45, 0x10, 0x02, 0x42, 0x72, 0x0a, 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, - 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, - 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, - 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, - 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, - 0x67, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, + 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, + 0x61, 0x6e, 0x74, 0x73, 0x22, 0x7b, 0x0a, 0x10, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x03, 0x63, 0x74, 0x78, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x03, 0x63, 0x74, 0x78, + 0x12, 0x19, 0x0a, 0x07, 0x61, 0x70, 0x70, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x00, 0x52, 0x06, 0x61, 0x70, 0x70, 0x55, 0x72, 0x6c, 0x42, 0x14, 0x0a, 0x12, 0x70, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, + 0x74, 0x22, 0x40, 0x0a, 0x0b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, + 0x12, 0x31, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, + 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x73, 0x22, 0x73, 0x0a, 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x18, + 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2a, 0x3e, 0x0a, 0x09, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x4c, 0x45, 0x44, 0x47, 0x45, 0x52, 0x5f, + 0x53, 0x54, 0x41, 0x54, 0x45, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x53, 0x53, 0x45, 0x54, + 0x5f, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x53, 0x53, 0x45, 0x54, + 0x5f, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x10, 0x02, 0x2a, 0x3f, 0x0a, 0x11, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x53, 0x75, 0x62, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0d, 0x0a, + 0x09, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, + 0x55, 0x4e, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x10, 0x01, 0x12, 0x0a, 0x0a, + 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x02, 0x42, 0x72, 0x0a, 0x1f, 0x63, 0x6f, 0x6d, + 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x5a, 0x4f, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, + 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, + 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, + 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/common/protos/common/events.proto b/common/protos/common/events.proto index 416247532..dee3fd8bd 100644 --- a/common/protos/common/events.proto +++ b/common/protos/common/events.proto @@ -62,6 +62,7 @@ message ContractTransaction { string func = 4; repeated bytes args = 5; uint64 replace_arg_index = 6; + repeated string participants = 7; } message EventPublication { diff --git a/core/drivers/corda-driver/VERSION b/core/drivers/corda-driver/VERSION new file mode 100644 index 000000000..434dcac4f --- /dev/null +++ b/core/drivers/corda-driver/VERSION @@ -0,0 +1 @@ +1.2.9 \ No newline at end of file diff --git a/core/drivers/corda-driver/makefile b/core/drivers/corda-driver/makefile index 61778c35d..44cd992a3 100644 --- a/core/drivers/corda-driver/makefile +++ b/core/drivers/corda-driver/makefile @@ -1,4 +1,7 @@ -include makefile.variables.docker +DOCKER_IMAGE_NAME ?= weaver-corda-driver +DOCKER_TAG ?= `cat ./VERSION` +DOCKER_REGISTRY ?= ghcr.io/hyperledger-labs +GIT_URL = https://github.com/hyperledger-labs/weaver-dlt-interoperability/core/drivers/corda-driver COMPOSE_ARG ?= diff --git a/core/drivers/corda-driver/makefile.variables.docker b/core/drivers/corda-driver/makefile.variables.docker deleted file mode 100644 index 00feb6a87..000000000 --- a/core/drivers/corda-driver/makefile.variables.docker +++ /dev/null @@ -1,4 +0,0 @@ -DOCKER_IMAGE_NAME ?= weaver-corda-driver -DOCKER_TAG ?= 1.2.9 -DOCKER_REGISTRY ?= ghcr.io/hyperledger-labs -GIT_URL = https://github.com/hyperledger-labs/weaver-dlt-interoperability/core/drivers/corda-driver \ No newline at end of file diff --git a/core/drivers/fabric-driver/VERSION b/core/drivers/fabric-driver/VERSION new file mode 100644 index 000000000..e1df5de7a --- /dev/null +++ b/core/drivers/fabric-driver/VERSION @@ -0,0 +1 @@ +1.4.4 \ No newline at end of file diff --git a/core/drivers/fabric-driver/makefile b/core/drivers/fabric-driver/makefile index 909b03d3e..654c498a9 100644 --- a/core/drivers/fabric-driver/makefile +++ b/core/drivers/fabric-driver/makefile @@ -1,7 +1,10 @@ -include makefile.variables.docker +DOCKER_IMAGE_NAME ?= weaver-fabric-driver +DOCKER_TAG ?= `cat ./VERSION` +DOCKER_REGISTRY ?= ghcr.io/hyperledger-labs +GIT_URL = https://github.com/hyperledger-labs/weaver-dlt-interoperability/core/drivers/fabric-driver COMPOSE_ARG ?= - + build: .npmrc npm install npm run build diff --git a/core/drivers/fabric-driver/makefile.variables.docker b/core/drivers/fabric-driver/makefile.variables.docker deleted file mode 100644 index 99e172204..000000000 --- a/core/drivers/fabric-driver/makefile.variables.docker +++ /dev/null @@ -1,4 +0,0 @@ -DOCKER_IMAGE_NAME ?= weaver-fabric-driver -DOCKER_TAG ?= 1.4.3 -DOCKER_REGISTRY ?= ghcr.io/hyperledger-labs -GIT_URL = https://github.com/hyperledger-labs/weaver-dlt-interoperability/core/drivers/fabric-driver diff --git a/core/drivers/fabric-driver/package-local.json b/core/drivers/fabric-driver/package-local.json index b584df8d9..cd0454cf9 100644 --- a/core/drivers/fabric-driver/package-local.json +++ b/core/drivers/fabric-driver/package-local.json @@ -1,6 +1,6 @@ { "name": "fabric-driver", - "version": "1.4.2", + "version": "1.4.4", "description": "", "main": "out/server.js", "scripts": { diff --git a/core/drivers/fabric-driver/package.json b/core/drivers/fabric-driver/package.json index 69199c63d..cd0454cf9 100644 --- a/core/drivers/fabric-driver/package.json +++ b/core/drivers/fabric-driver/package.json @@ -1,6 +1,6 @@ { "name": "fabric-driver", - "version": "1.4.2", + "version": "1.4.4", "description": "", "main": "out/server.js", "scripts": { @@ -19,8 +19,8 @@ "author": "", "license": "ISC", "dependencies": { - "@hyperledger-labs/weaver-protos-js": "^1.4.2", - "@hyperledger-labs/weaver-fabric-interop-sdk": "^1.4.0", + "@hyperledger-labs/weaver-protos-js": "file:./protos-js", + "@hyperledger-labs/weaver-fabric-interop-sdk": "file:./weaver-fabric-interop-sdk", "@fidm/x509": "^1.2.1", "@grpc/grpc-js": "^1.1.1", "@typescript-eslint/eslint-plugin": "^3.5.0", diff --git a/core/drivers/fabric-driver/server/events.ts b/core/drivers/fabric-driver/server/events.ts index b94b2c633..f62e2966b 100644 --- a/core/drivers/fabric-driver/server/events.ts +++ b/core/drivers/fabric-driver/server/events.ts @@ -48,10 +48,10 @@ async function subscribeEventHelper( const [deletedSubscription, err] = await handlePromise(deleteEventSubscription(call_request.getEventMatcher()!, newRequestId)); if (err) { - const errorString: string = `${JSON.stringify(err)}`; + const errorString: string = err.toString(); console.error(errorString); } - const errorString2 = JSON.stringify(error); + const errorString2 = error.toString(); console.error(errorString2); ack_send.setMessage(`Event subscription error: listener registration failed with error: ${errorString2}`); ack_send.setStatus(ack_pb.Ack.STATUS.ERROR); @@ -386,6 +386,23 @@ async function writeExternalStateHelper( ccArgsStr.push(Buffer.from(ccArgB64).toString('utf8')); } + let gateway: Gateway = await getNetworkGateway(networkName); + const network: Network = await gateway.getNetwork(ctx.getLedgerId()); + const interopContract: Contract = network.getContract(process.env.INTEROP_CHAINCODE ? process.env.INTEROP_CHAINCODE : 'interop'); + + const endorsingOrgs = ctx.getParticipantsList(); + // const endorsers = network.getChannel().getEndorsers(); + // let endorserList = []; + // if (endorsingOrgs.length > 0) { + // endorserList = endorsers.filter((endorser: Endorser) => { + // //@ts-ignore + // const cert = Certificate.fromPEM(endorser.options.pem); + // const orgName = cert.issuer.organizationName; + // return endorsingOrgs.includes(endorser.mspid) || endorsingOrgs.includes(orgName); + // }); + // console.log('Set endorserList', endorserList); + // } + const invokeObject = { channel: ctx.getLedgerId(), ccFunc: ctx.getFunc(), @@ -393,18 +410,15 @@ async function writeExternalStateHelper( contractName: ctx.getContractId() } console.debug(`invokeObject.ccArgs: ${invokeObject.ccArgs}`) - - let gateway: Gateway = await getNetworkGateway(networkName); - const network: Network = await gateway.getNetwork(ctx.getLedgerId()); - const interopContract: Contract = network.getContract(process.env.INTEROP_CHAINCODE ? process.env.INTEROP_CHAINCODE : 'interop'); - + const [ response, responseError ] = await handlePromise(InteroperableHelper.submitTransactionWithRemoteViews( interopContract, invokeObject, interopArgIndices, addresses, viewsSerializedBase64, - viewContentsBase64 + viewContentsBase64, + endorsingOrgs )); if (responseError) { console.log(`Failed writing to the ledger with error: ${responseError}`); diff --git a/core/relay/Makefile b/core/relay/Makefile index 99ba561a6..caa9ebb60 100644 --- a/core/relay/Makefile +++ b/core/relay/Makefile @@ -1,4 +1,7 @@ -include Makefile.variables.docker +DOCKER_IMAGE_NAME ?= weaver-relay +DOCKER_TAG ?= `cat ./VERSION` +DOCKER_REGISTRY ?= ghcr.io/hyperledger-labs +GIT_URL = https://github.com/hyperledger-labs/weaver-dlt-interoperability PROTOS_TAG ?= v1.4.2 diff --git a/core/relay/Makefile.variables.docker b/core/relay/Makefile.variables.docker deleted file mode 100644 index 2b4f55040..000000000 --- a/core/relay/Makefile.variables.docker +++ /dev/null @@ -1,4 +0,0 @@ -DOCKER_IMAGE_NAME ?= weaver-relay -DOCKER_TAG ?= 1.4.2 -DOCKER_REGISTRY ?= ghcr.io/hyperledger-labs -GIT_URL = https://github.com/hyperledger-labs/weaver-dlt-interoperability \ No newline at end of file diff --git a/core/relay/VERSION b/core/relay/VERSION new file mode 100644 index 000000000..c9929e36a --- /dev/null +++ b/core/relay/VERSION @@ -0,0 +1 @@ +1.4.2 \ No newline at end of file diff --git a/sdks/fabric/interoperation-node-sdk/package-local.json b/sdks/fabric/interoperation-node-sdk/package-local.json index d2636a3ae..b521559e7 100644 --- a/sdks/fabric/interoperation-node-sdk/package-local.json +++ b/sdks/fabric/interoperation-node-sdk/package-local.json @@ -6,7 +6,7 @@ "blockchain", "interoperability" ], - "version": "1.4.3", + "version": "1.4.4", "author": "V. Ramakrishna", "tag": "latest", "main": "build/index.js", diff --git a/sdks/fabric/interoperation-node-sdk/package.json b/sdks/fabric/interoperation-node-sdk/package.json index e030663a3..ccba4d3ee 100644 --- a/sdks/fabric/interoperation-node-sdk/package.json +++ b/sdks/fabric/interoperation-node-sdk/package.json @@ -6,7 +6,7 @@ "blockchain", "interoperability" ], - "version": "1.4.3", + "version": "1.4.4", "author": "V. Ramakrishna", "tag": "latest", "main": "build/index.js", diff --git a/sdks/fabric/interoperation-node-sdk/src/InteroperableHelper.ts b/sdks/fabric/interoperation-node-sdk/src/InteroperableHelper.ts index 54cd465f3..48ff74f4a 100644 --- a/sdks/fabric/interoperation-node-sdk/src/InteroperableHelper.ts +++ b/sdks/fabric/interoperation-node-sdk/src/InteroperableHelper.ts @@ -409,6 +409,7 @@ const interopFlow = async ( interopArgIndices: Array, interopJSONs: Array, keyCert: { key: ICryptoKey; cert: any }, + endorsingOrgs: Array = [], returnWithoutLocalInvocation: boolean = false, useTls: boolean = false, tlsRootCACertPaths?: Array, @@ -465,6 +466,7 @@ const interopFlow = async ( computedAddresses, viewsSerializedBase64, viewContentsBase64, + endorsingOrgs ); return { views, result }; }; @@ -509,6 +511,7 @@ const submitTransactionWithRemoteViews = async ( viewAddresses: Array, viewsSerializedBase64: Array, viewContentsBase64: Array, + endorsingOrgs: Array ): Promise => { const ccArgs = getCCArgsForProofVerification( invokeObject, @@ -517,8 +520,13 @@ const submitTransactionWithRemoteViews = async ( viewsSerializedBase64, viewContentsBase64, ); + + const tx = interopContract.createTransaction("WriteExternalState") + if (endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } const [result, submitError] = await helpers.handlePromise( - interopContract.submitTransaction("WriteExternalState", ...ccArgs), + tx.submit(...ccArgs) ); if (submitError) { throw new Error(`submitTransaction Error: ${submitError}`); From e5d3a3c426a536400693281b80442c4c51a28e54 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Wed, 7 Sep 2022 14:03:32 +0000 Subject: [PATCH 117/150] Updated Membership Management Logic in Fabric Interop CC Updated the IIN Agent protos to use serialized protobufs for deterministic signature validation. Upgraded membership chaincode and unit tests to handle attested memberships from foreign security domains. Fixed Go package publishing workflow. Updated terminology in identity RFCs. Signed-off-by: VRamakrishna --- .github/workflows/deploy_go-pkgs.yml | 5 +- common/protos-go/identity/agent.pb.go | 170 ++-- common/protos/identity/agent.proto | 6 +- .../contracts/interop/certificate_utils.go | 19 +- .../contracts/interop/decoders.go | 12 + .../interop/handle_external_request_test.go | 2 +- .../contracts/interop/membership.go | 388 +++++++- .../contracts/interop/membership_test.go | 853 +++++++++++++++++- .../fabric-interop-cc/libs/utils/utils.go | 19 +- .../identity/network-identity-validation.md | 105 --- .../security-domain-identity-validation.md | 103 +++ 11 files changed, 1409 insertions(+), 273 deletions(-) delete mode 100644 rfcs/protocols/identity/network-identity-validation.md create mode 100644 rfcs/protocols/identity/security-domain-identity-validation.md diff --git a/.github/workflows/deploy_go-pkgs.yml b/.github/workflows/deploy_go-pkgs.yml index 5ae1ad2dd..ffc66d96b 100644 --- a/.github/workflows/deploy_go-pkgs.yml +++ b/.github/workflows/deploy_go-pkgs.yml @@ -7,7 +7,7 @@ name: Deploy Go Modules on: push: branches: - - test + - main paths: - 'common/protos-go/VERSION' - 'core/network/fabric-interop-cc/libs/utils/VERSION' @@ -16,6 +16,9 @@ on: - 'core/network/fabric-interop-cc/contracts/interop/VERSION' - 'sdks/fabric/go-sdk/VERSION' +# Allows you to run this workflow manually from the Actions tab +workflow_dispatch: + jobs: publish-protos: if: github.repository_owner == 'hyperledger-labs' diff --git a/common/protos-go/identity/agent.pb.go b/common/protos-go/identity/agent.pb.go index da81b6fb3..1470acf79 100644 --- a/common/protos-go/identity/agent.pb.go +++ b/common/protos-go/identity/agent.pb.go @@ -210,8 +210,8 @@ type AttestedMembership struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Membership *common.Membership `protobuf:"bytes,1,opt,name=membership,proto3" json:"membership,omitempty"` - Attestation *Attestation `protobuf:"bytes,2,opt,name=attestation,proto3" json:"attestation,omitempty"` + Membership []byte `protobuf:"bytes,1,opt,name=membership,proto3" json:"membership,omitempty"` // 'common.membership.Membership' + Attestation *Attestation `protobuf:"bytes,2,opt,name=attestation,proto3" json:"attestation,omitempty"` } func (x *AttestedMembership) Reset() { @@ -246,7 +246,7 @@ func (*AttestedMembership) Descriptor() ([]byte, []int) { return file_identity_agent_proto_rawDescGZIP(), []int{3} } -func (x *AttestedMembership) GetMembership() *common.Membership { +func (x *AttestedMembership) GetMembership() []byte { if x != nil { return x.Membership } @@ -266,8 +266,8 @@ type CounterAttestedMembership struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - AttestedMembershipSet *CounterAttestedMembership_AttestedMembershipSet `protobuf:"bytes,1,opt,name=attested_membership_set,json=attestedMembershipSet,proto3" json:"attested_membership_set,omitempty"` - Attestations []*Attestation `protobuf:"bytes,2,rep,name=attestations,proto3" json:"attestations,omitempty"` + AttestedMembershipSet []byte `protobuf:"bytes,1,opt,name=attested_membership_set,json=attestedMembershipSet,proto3" json:"attested_membership_set,omitempty"` // 'AttestedMembershipSet' + Attestations []*Attestation `protobuf:"bytes,2,rep,name=attestations,proto3" json:"attestations,omitempty"` } func (x *CounterAttestedMembership) Reset() { @@ -302,7 +302,7 @@ func (*CounterAttestedMembership) Descriptor() ([]byte, []int) { return file_identity_agent_proto_rawDescGZIP(), []int{4} } -func (x *CounterAttestedMembership) GetAttestedMembershipSet() *CounterAttestedMembership_AttestedMembershipSet { +func (x *CounterAttestedMembership) GetAttestedMembershipSet() []byte { if x != nil { return x.AttestedMembershipSet } @@ -321,8 +321,8 @@ type CounterAttestedMembership_AttestedMembershipSet struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Membership *common.Membership `protobuf:"bytes,1,opt,name=membership,proto3" json:"membership,omitempty"` - Attestations []*Attestation `protobuf:"bytes,2,rep,name=attestations,proto3" json:"attestations,omitempty"` + Membership []byte `protobuf:"bytes,1,opt,name=membership,proto3" json:"membership,omitempty"` // 'common.membership.Membership' + Attestations []*Attestation `protobuf:"bytes,2,rep,name=attestations,proto3" json:"attestations,omitempty"` } func (x *CounterAttestedMembership_AttestedMembershipSet) Reset() { @@ -357,7 +357,7 @@ func (*CounterAttestedMembership_AttestedMembershipSet) Descriptor() ([]byte, [] return file_identity_agent_proto_rawDescGZIP(), []int{4, 0} } -func (x *CounterAttestedMembership_AttestedMembershipSet) GetMembership() *common.Membership { +func (x *CounterAttestedMembership_AttestedMembershipSet) GetMembership() []byte { if x != nil { return x.Membership } @@ -410,76 +410,68 @@ var file_identity_agent_proto_rawDesc = []byte{ 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x92, 0x01, 0x0a, 0x12, 0x41, - 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, - 0x70, 0x12, 0x3d, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x68, 0x69, 0x70, 0x52, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, + 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x73, 0x0a, 0x12, 0x41, 0x74, + 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, + 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x3d, 0x0a, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, - 0xef, 0x02, 0x0a, 0x19, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x41, 0x74, 0x74, 0x65, 0x73, - 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x77, 0x0a, + 0x8e, 0x02, 0x0a, 0x19, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x41, 0x74, 0x74, 0x65, 0x73, + 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x36, 0x0a, 0x17, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x68, 0x69, 0x70, 0x5f, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, - 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, - 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, - 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x65, 0x74, 0x52, - 0x15, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, - 0x68, 0x69, 0x70, 0x53, 0x65, 0x74, 0x12, 0x3f, 0x0a, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, - 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x97, 0x01, 0x0a, 0x15, 0x41, 0x74, 0x74, 0x65, - 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x65, - 0x74, 0x12, 0x3d, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x68, 0x69, 0x70, 0x52, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, - 0x12, 0x3f, 0x0a, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x32, 0xc1, 0x03, 0x0a, 0x08, 0x49, 0x49, 0x4e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x54, - 0x0a, 0x11, 0x53, 0x79, 0x6e, 0x63, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x12, 0x2c, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, + 0x73, 0x68, 0x69, 0x70, 0x5f, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x15, + 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, + 0x69, 0x70, 0x53, 0x65, 0x74, 0x12, 0x3f, 0x0a, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, + 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x78, 0x0a, 0x15, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, + 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x65, 0x74, 0x12, + 0x1e, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, + 0x3f, 0x0a, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x32, 0xc1, 0x03, 0x0a, 0x08, 0x49, 0x49, 0x4e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x54, 0x0a, + 0x11, 0x53, 0x79, 0x6e, 0x63, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x12, 0x2c, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, + 0x69, 0x6e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, + 0x6b, 0x22, 0x00, 0x12, 0x66, 0x0a, 0x1c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, - 0x63, 0x6b, 0x22, 0x00, 0x12, 0x66, 0x0a, 0x1c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, - 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, - 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x19, - 0x53, 0x65, 0x6e, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x2e, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, - 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x1a, 0x0f, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, - 0x12, 0x52, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x74, 0x74, 0x65, 0x73, + 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x19, 0x53, + 0x65, 0x6e, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, + 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x1a, 0x0f, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, + 0x52, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x41, 0x74, + 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, + 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, + 0x6b, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, - 0x63, 0x6b, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x74, 0x74, 0x65, - 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, - 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, - 0x69, 0x70, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, - 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, 0x75, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, - 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5a, 0x51, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, - 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, - 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, - 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, - 0x2d, 0x67, 0x6f, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x63, 0x6b, 0x22, 0x00, 0x42, 0x75, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, + 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5a, 0x51, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, + 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, + 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, + 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, + 0x67, 0x6f, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( @@ -502,34 +494,30 @@ var file_identity_agent_proto_goTypes = []interface{}{ (*AttestedMembership)(nil), // 3: identity.agent.AttestedMembership (*CounterAttestedMembership)(nil), // 4: identity.agent.CounterAttestedMembership (*CounterAttestedMembership_AttestedMembershipSet)(nil), // 5: identity.agent.CounterAttestedMembership.AttestedMembershipSet - (*common.Membership)(nil), // 6: common.membership.Membership - (*common.Ack)(nil), // 7: common.ack.Ack + (*common.Ack)(nil), // 6: common.ack.Ack } var file_identity_agent_proto_depIdxs = []int32{ 0, // 0: identity.agent.SecurityDomainMemberIdentityRequest.source_network:type_name -> identity.agent.SecurityDomainMemberIdentity 0, // 1: identity.agent.SecurityDomainMemberIdentityRequest.requesting_network:type_name -> identity.agent.SecurityDomainMemberIdentity 0, // 2: identity.agent.Attestation.unit_identity:type_name -> identity.agent.SecurityDomainMemberIdentity - 6, // 3: identity.agent.AttestedMembership.membership:type_name -> common.membership.Membership - 2, // 4: identity.agent.AttestedMembership.attestation:type_name -> identity.agent.Attestation - 5, // 5: identity.agent.CounterAttestedMembership.attested_membership_set:type_name -> identity.agent.CounterAttestedMembership.AttestedMembershipSet - 2, // 6: identity.agent.CounterAttestedMembership.attestations:type_name -> identity.agent.Attestation - 6, // 7: identity.agent.CounterAttestedMembership.AttestedMembershipSet.membership:type_name -> common.membership.Membership - 2, // 8: identity.agent.CounterAttestedMembership.AttestedMembershipSet.attestations:type_name -> identity.agent.Attestation - 0, // 9: identity.agent.IINAgent.SyncExternalState:input_type -> identity.agent.SecurityDomainMemberIdentity - 1, // 10: identity.agent.IINAgent.RequestIdentityConfiguration:input_type -> identity.agent.SecurityDomainMemberIdentityRequest - 3, // 11: identity.agent.IINAgent.SendIdentityConfiguration:input_type -> identity.agent.AttestedMembership - 4, // 12: identity.agent.IINAgent.RequestAttestation:input_type -> identity.agent.CounterAttestedMembership - 4, // 13: identity.agent.IINAgent.SendAttestation:input_type -> identity.agent.CounterAttestedMembership - 7, // 14: identity.agent.IINAgent.SyncExternalState:output_type -> common.ack.Ack - 7, // 15: identity.agent.IINAgent.RequestIdentityConfiguration:output_type -> common.ack.Ack - 7, // 16: identity.agent.IINAgent.SendIdentityConfiguration:output_type -> common.ack.Ack - 7, // 17: identity.agent.IINAgent.RequestAttestation:output_type -> common.ack.Ack - 7, // 18: identity.agent.IINAgent.SendAttestation:output_type -> common.ack.Ack - 14, // [14:19] is the sub-list for method output_type - 9, // [9:14] is the sub-list for method input_type - 9, // [9:9] is the sub-list for extension type_name - 9, // [9:9] is the sub-list for extension extendee - 0, // [0:9] is the sub-list for field type_name + 2, // 3: identity.agent.AttestedMembership.attestation:type_name -> identity.agent.Attestation + 2, // 4: identity.agent.CounterAttestedMembership.attestations:type_name -> identity.agent.Attestation + 2, // 5: identity.agent.CounterAttestedMembership.AttestedMembershipSet.attestations:type_name -> identity.agent.Attestation + 0, // 6: identity.agent.IINAgent.SyncExternalState:input_type -> identity.agent.SecurityDomainMemberIdentity + 1, // 7: identity.agent.IINAgent.RequestIdentityConfiguration:input_type -> identity.agent.SecurityDomainMemberIdentityRequest + 3, // 8: identity.agent.IINAgent.SendIdentityConfiguration:input_type -> identity.agent.AttestedMembership + 4, // 9: identity.agent.IINAgent.RequestAttestation:input_type -> identity.agent.CounterAttestedMembership + 4, // 10: identity.agent.IINAgent.SendAttestation:input_type -> identity.agent.CounterAttestedMembership + 6, // 11: identity.agent.IINAgent.SyncExternalState:output_type -> common.ack.Ack + 6, // 12: identity.agent.IINAgent.RequestIdentityConfiguration:output_type -> common.ack.Ack + 6, // 13: identity.agent.IINAgent.SendIdentityConfiguration:output_type -> common.ack.Ack + 6, // 14: identity.agent.IINAgent.RequestAttestation:output_type -> common.ack.Ack + 6, // 15: identity.agent.IINAgent.SendAttestation:output_type -> common.ack.Ack + 11, // [11:16] is the sub-list for method output_type + 6, // [6:11] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name } func init() { file_identity_agent_proto_init() } diff --git a/common/protos/identity/agent.proto b/common/protos/identity/agent.proto index 84e5ef7af..af72037fd 100644 --- a/common/protos/identity/agent.proto +++ b/common/protos/identity/agent.proto @@ -43,16 +43,16 @@ message Attestation { // Attested security domain membership by a single member message AttestedMembership { - common.membership.Membership membership = 1; + bytes membership = 1; // 'common.membership.Membership' Attestation attestation = 2; } // Counter attestation over security domain membership attested by its participants message CounterAttestedMembership { message AttestedMembershipSet { - common.membership.Membership membership = 1; + bytes membership = 1; // 'common.membership.Membership' repeated Attestation attestations = 2; } - AttestedMembershipSet attested_membership_set = 1; + bytes attested_membership_set = 1; // 'AttestedMembershipSet' repeated Attestation attestations = 2; } diff --git a/core/network/fabric-interop-cc/contracts/interop/certificate_utils.go b/core/network/fabric-interop-cc/contracts/interop/certificate_utils.go index 2f7218e25..01c451d9d 100644 --- a/core/network/fabric-interop-cc/contracts/interop/certificate_utils.go +++ b/core/network/fabric-interop-cc/contracts/interop/certificate_utils.go @@ -14,7 +14,6 @@ import ( "crypto/sha256" "crypto/sha512" "crypto/x509" - "encoding/asn1" "encoding/base64" "encoding/pem" "errors" @@ -90,9 +89,9 @@ func verifyCaCertificate(cert *x509.Certificate, memberCertificate string) error return nil } -/* This function works for a Corda network's configuration - The assumption is that a Corda network has a single Root CA and Doorman CA, and one or more Node CAs corresponding to nodes. - This function will receive arguments for exactly one node with the following cert chain assumed: -> -> +/* This function will receive arguments for exactly one node with the following cert chain assumed: -> -> -> ...... + In a Fabric network, we assume that there are multiple MSPs, each having one or more Root CAs and zero or more Intermediate CAs. + In a Corda network, we assume that there is a single Root CA and Doorman CA, and one or more Node CAs corresponding to nodes. */ func verifyCertificateChain(cert *x509.Certificate, certPEMs []string) error { var parentCert *x509.Certificate @@ -193,14 +192,7 @@ func getHashSHA2(bitsize int) (hash.Hash, error) { } func ecdsaVerify(verKey *ecdsa.PublicKey, msgHash, signature []byte) error { - ecdsaSignature := new(ECDSASignature) - _, err := asn1.Unmarshal(signature, ecdsaSignature) - if err != nil { - return err - } - - result := ecdsa.Verify(verKey, msgHash, ecdsaSignature.R, ecdsaSignature.S) - // result := ecdsa.VerifyASN1(verKey, msgHash, signature) + result := ecdsa.VerifyASN1(verKey, msgHash, signature) if result == false { return errors.New("Signature Verification failed. ECDSA VERIFY") } @@ -227,7 +219,7 @@ func validateSignature(message string, cert *x509.Certificate, signature string) pubKey := getECDSAPublicKeyFromCertificate(cert) if pubKey != nil { // Construct the message that was signed - hashed, err := computeSHA2Hash([]byte(message), 256) + hashed, err := computeSHA2Hash([]byte(message), pubKey.Params().BitSize) if err != nil { return err } @@ -241,6 +233,7 @@ func validateSignature(message string, cert *x509.Certificate, signature string) return errors.New("Missing or unsupported public key type") } } + func parseCert(certString string) (*x509.Certificate, error) { certBytes, _ := pem.Decode([]byte(certString)) diff --git a/core/network/fabric-interop-cc/contracts/interop/decoders.go b/core/network/fabric-interop-cc/contracts/interop/decoders.go index d05fd3cf0..e8532ca1f 100644 --- a/core/network/fabric-interop-cc/contracts/interop/decoders.go +++ b/core/network/fabric-interop-cc/contracts/interop/decoders.go @@ -16,6 +16,7 @@ import ( "strings" "github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go/common" + "github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go/identity" ) func decodeMembership(jsonBytes []byte) (*common.Membership, error) { @@ -29,6 +30,17 @@ func decodeMembership(jsonBytes []byte) (*common.Membership, error) { return &decodeObj, nil } +func decodeCounterAttestedMembership(jsonBytes []byte) (*identity.CounterAttestedMembership, error) { + var decodeObj identity.CounterAttestedMembership + dec := json.NewDecoder(strings.NewReader(string(jsonBytes))) + dec.DisallowUnknownFields() + err := dec.Decode(&decodeObj) + if err != nil { + return nil, err + } + return &decodeObj, nil +} + func decodeVerificationPolicy(jsonBytes []byte) (*common.VerificationPolicy, error) { var decodeObj common.VerificationPolicy dec := json.NewDecoder(strings.NewReader(string(jsonBytes))) diff --git a/core/network/fabric-interop-cc/contracts/interop/handle_external_request_test.go b/core/network/fabric-interop-cc/contracts/interop/handle_external_request_test.go index 845afd8e6..6f04565cf 100644 --- a/core/network/fabric-interop-cc/contracts/interop/handle_external_request_test.go +++ b/core/network/fabric-interop-cc/contracts/interop/handle_external_request_test.go @@ -180,7 +180,7 @@ func testHandleExternalRequestSignatureCertificateMismatch(t *testing.T, query * b64QueryBytes := base64.StdEncoding.EncodeToString(queryBytes) _, err = interopcc.HandleExternalRequest(ctx, string(b64QueryBytes)) - require.EqualError(t, err, fmt.Sprintf("Invalid Signature: asn1: structure error: tags don't match (16 vs {class:1 tag:19 length:105 isCompound:false}) {optional:false explicit:false application:false private:false defaultValue: tag: stringType:0 timeType:0 set:false omitEmpty:false} ECDSASignature @2")) + require.EqualError(t, err, "Invalid Signature: Signature Verification failed. ECDSA VERIFY") } func testHandleExternalRequestInvalidCert(t *testing.T, query *common.Query) { diff --git a/core/network/fabric-interop-cc/contracts/interop/membership.go b/core/network/fabric-interop-cc/contracts/interop/membership.go index 0c0170a17..2f6975363 100644 --- a/core/network/fabric-interop-cc/contracts/interop/membership.go +++ b/core/network/fabric-interop-cc/contracts/interop/membership.go @@ -9,48 +9,281 @@ package main import ( + "crypto/x509" + "encoding/base64" "encoding/json" + "encoding/pem" "fmt" "github.com/hyperledger/fabric-contract-api-go/contractapi" "github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go/common" + "github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go/identity" + protoV2 "google.golang.org/protobuf/proto" ) const membershipObjectType = "membership" +const membershipLocalSecurityDomain = "local-security-domain" -func validateMemberCertChains(members map[string]*common.Member, securityDomain string) error { - for member, creds := range members { - if len(creds.Chain) > 1 { - err := verifyCertificateChain(nil, creds.Chain) +// Check if the calling client has an attribute in its signing certificate indicating that it is a privileged network administrator +//func isClientNetworkAdmin(stub shim.ChaincodeStubInterface) (bool, error) { +func isClientNetworkAdmin(ctx contractapi.TransactionContextInterface) (bool, error) { + // check if caller certificate has the attribute "network-admin" + // we don't care about the actual value of the attribute for now + _, ok, err := ctx.GetClientIdentity().GetAttributeValue("network-admin") + return ok, err +} + +// Check if the calling client has an IIN Agent attribute in its signing certificate +//func isClientIINAgent(stub shim.ChaincodeStubInterface) (bool, error) { +func isClientIINAgent(ctx contractapi.TransactionContextInterface) (bool, error) { + // check if caller certificate has the attribute "iin-agent" + // we don't care about the actual value of the attribute for now + _, ok, err := ctx.GetClientIdentity().GetAttributeValue("iin-agent") + return ok, err +} + +// Check the validity of each certificate chain in this membership +func validateMemberCertChains(membership *common.Membership) error { + for _, member := range membership.Members { + if len(member.Chain) > 1 { + err := verifyCertificateChain(nil, member.Chain) if err != nil { - return fmt.Errorf("Certificate chain corresponding to member %s in security domain %s is invalid: %s", member, securityDomain, err) + return fmt.Errorf("Certificate chain corresponding to member %+v in security domain %s is invalid: %s", member, membership.SecurityDomain, err) } } } return nil } -// CreateMembership cc is used to store a Membership in the ledger -func (s *SmartContract) CreateMembership(ctx contractapi.TransactionContextInterface, membershipJSON string) error { +// Check whether the given user certificate belongs to the given security domain membership +func checkUserInMembership(userCert *x509.Certificate, membership *common.Membership) error { + for _, member := range membership.Members { + if member.Type == "ca" && member.Value != "" { + decodedCACert, _ := pem.Decode([]byte(member.Value)) + if decodedCACert == nil { + fmt.Printf("Unable to decode CA cert PEM: %s\n", member.Value) + } + caCert, err := x509.ParseCertificate(decodedCACert.Bytes) + if err != nil { + fmt.Printf("Unable to parse CA certificate: %s\n", member.Value) + } + err = validateCertificateUsingCA(userCert, caCert, true) + if err == nil { + return nil + } + } else if member.Type == "certificate" && len(member.Chain) > 0 { + err := verifyCertificateChain(userCert, member.Chain) + if err == nil { + return nil + } + } else { + fmt.Printf("Invalid member info: %+v\n", member) + } + } + return fmt.Errorf("User cert %+v could not be validated against any CA certificate chain in membership %+v", userCert, membership) +} + +// Validate 'identity.Attestation' object against a message byte array +func validateAttestation(attestation *identity.Attestation, messageBytes []byte) error { + // Parse local IIN Agent's certificate + certDecoded, _ := pem.Decode([]byte(attestation.Certificate)) + if certDecoded == nil { + fmt.Printf("Unable to decode cert PEM: %s\n", attestation.Certificate) + } + cert, err := x509.ParseCertificate(certDecoded.Bytes) + if err != nil { + fmt.Printf("Unable to parse certificate: %s\n", attestation.Certificate) + } + // We assume the signature is base64-encoded as it is a string type in the 'Attestation' protobuf + decodedSignature, err := base64.StdEncoding.DecodeString(attestation.Signature) + if err != nil { + return fmt.Errorf("Attestation signature could not be decoded from base64: %s", err.Error()) + } + err = validateSignature(string(messageBytes), cert, string(decodedSignature)) + if err != nil { + return fmt.Errorf("Unable to Validate Signature: %s", err.Error()) + } + return nil +} + +// CreateLocalMembership cc is used to store the local security domain's Membership in the ledger +func (s *SmartContract) CreateLocalMembership(ctx contractapi.TransactionContextInterface, membershipJSON string) error { + // Check if the caller has network admin privileges + if isAdmin, err := isClientNetworkAdmin(ctx); err != nil { + return fmt.Errorf("Admin client check error: %s", err) + } else if !isAdmin { + return fmt.Errorf("Caller not a network admin; access denied") + } + + membership, err := decodeMembership([]byte(membershipJSON)) + if err != nil { + return fmt.Errorf("Unmarshal error: %s", err) + } + + membershipLocalKey, err := ctx.GetStub().CreateCompositeKey(membershipObjectType, []string{membershipLocalSecurityDomain}) + acp, getErr := ctx.GetStub().GetState(membershipLocalKey) + if getErr != nil { + return getErr + } + if acp != nil { + return fmt.Errorf("Membership already exists for local membership id: %s. Use 'UpdateLocalMembership' to update.", membershipLocalSecurityDomain) + } + + // Check if certificates chains in this membership record are valid + err = validateMemberCertChains(membership) + if err != nil { + return err + } + + membershipBytes, err := json.Marshal(membership) + if err != nil { + return fmt.Errorf("Marshal error: %s", err) + } + return ctx.GetStub().PutState(membershipLocalKey, membershipBytes) +} + +// UpdateLocalMembership cc is used to update the existing local security domain's Membership in the ledger +func (s *SmartContract) UpdateLocalMembership(ctx contractapi.TransactionContextInterface, membershipJSON string) error { + // Check if the caller has network admin privileges + if isAdmin, err := isClientNetworkAdmin(ctx); err != nil { + return fmt.Errorf("Admin client check error: %+v", err) + } else if !isAdmin { + return fmt.Errorf("Caller not a network admin; access denied") + } + membership, err := decodeMembership([]byte(membershipJSON)) if err != nil { return fmt.Errorf("Unmarshal error: %s", err) } + + membershipLocalKey, err := ctx.GetStub().CreateCompositeKey(membershipObjectType, []string{membershipLocalSecurityDomain}) + _, getErr := s.GetMembershipBySecurityDomain(ctx, membership.SecurityDomain) + if getErr != nil { + return getErr + } + // Check if certificates chains in this membership record are valid - err = validateMemberCertChains(membership.Members, membership.SecurityDomain) + err = validateMemberCertChains(membership) + if err != nil { + return err + } + + membershipBytes, err := json.Marshal(membership) + if err != nil { + return fmt.Errorf("Marshal error: %s", err) + } + return ctx.GetStub().PutState(membershipLocalKey, membershipBytes) + +} + +// CreateMembership cc is used to store a Membership in the ledger +func (s *SmartContract) CreateMembership(ctx contractapi.TransactionContextInterface, counterAttestedMembershipJSON string) error { + // Check if the caller has IIN agent privileges + if isIINAgent, err := isClientIINAgent(ctx); err != nil { + return fmt.Errorf("IIN Agent client check error: %s", err) + } else if !isIINAgent { + return fmt.Errorf("Caller not an IIN Agent; access denied") + } + + // Check if caller is one of the authorized IIN agents + membershipLocal, err := s.GetMembershipBySecurityDomain(ctx, membershipLocalSecurityDomain) if err != nil { return err } - membershipKey, err := ctx.GetStub().CreateCompositeKey(membershipObjectType, []string{membership.SecurityDomain}) + membershipLocalDecoded, err := decodeMembership([]byte(membershipLocal)) + if err != nil { + return fmt.Errorf("Local Membership JSON Unmarshal error: %s", err) + } + callerId := ctx.GetClientIdentity() + callerCert, err := callerId.GetX509Certificate() + if err != nil { + return err + } + err = checkUserInMembership(callerCert, membershipLocalDecoded) + if err != nil { + return fmt.Errorf("Caller with identity %+v is not a designated IIN Agent: %+v", callerId, err) + } + + counterAttestedMembership, err := decodeCounterAttestedMembership([]byte(counterAttestedMembershipJSON)) + if err != nil { + return fmt.Errorf("Counter Attested Membership Unmarshal error: %s", err) + } + var attestedMembershipSet identity.CounterAttestedMembership_AttestedMembershipSet + err = protoV2.Unmarshal(counterAttestedMembership.AttestedMembershipSet, &attestedMembershipSet) + if err != nil { + return fmt.Errorf("Unable to unmarshal attested membership set: %s", err.Error()) + } + var foreignMembership common.Membership + err = protoV2.Unmarshal(attestedMembershipSet.Membership, &foreignMembership) + if err != nil { + return fmt.Errorf("Unable to unmarshal membership: %s", err.Error()) + } + + // Ensure valid attestations from all local IIN Agents + for _, attestation := range counterAttestedMembership.Attestations { + err = validateAttestation(attestation, counterAttestedMembership.AttestedMembershipSet) + if err != nil { + return err + } + } + + // Validate foreign membership cert chains + err = validateMemberCertChains(&foreignMembership) + if err != nil { + return err + } + + // Ensure authentic and valid attestations from all foreign IIN Agents + for _, attestation := range attestedMembershipSet.Attestations { + if attestation.UnitIdentity.SecurityDomain != foreignMembership.SecurityDomain { + return fmt.Errorf("Foreign agent security domain %s does not match attested membership security domain %s", + attestation.UnitIdentity.SecurityDomain, foreignMembership.SecurityDomain) + } + foundMemberMatch := false + for _, member := range foreignMembership.Members { + var isSignerRoot bool + var leafCertPEM string + if member.Type == "ca" { + leafCertPEM = member.Value + isSignerRoot = true + } else if member.Type == "certificate" { + leafCertPEM = member.Chain[len(member.Chain) - 1] + isSignerRoot = (len(member.Chain) == 1) + } + attesterCert, err := parseCert(attestation.Certificate) + if err != nil { + continue + } + leafCert, err := parseCert(leafCertPEM) + if err != nil { + continue + } + err = validateCertificateUsingCA(attesterCert, leafCert, isSignerRoot) + if err == nil { + foundMemberMatch = true + break + } + } + if !foundMemberMatch { + return fmt.Errorf("No matching member certificate chain found for attester") + } + // Validate signature + err = validateAttestation(attestation, attestedMembershipSet.Membership) + if err != nil { + return err + } + } + + membershipKey, err := ctx.GetStub().CreateCompositeKey(membershipObjectType, []string{foreignMembership.SecurityDomain}) acp, getErr := ctx.GetStub().GetState(membershipKey) if getErr != nil { return getErr } if acp != nil { - return fmt.Errorf("Membership already exists for membership id: %s", membership.SecurityDomain) + return fmt.Errorf("Membership already exists for membership id: %s. Use 'UpdateMembership' to update.", foreignMembership.SecurityDomain) } - membershipBytes, err := json.Marshal(membership) + membershipBytes, err := json.Marshal(attestedMembershipSet.Membership) if err != nil { return fmt.Errorf("Marshal error: %s", err) } @@ -58,23 +291,110 @@ func (s *SmartContract) CreateMembership(ctx contractapi.TransactionContextInter } // UpdateMembership cc is used to update an existing Membership in the ledger -func (s *SmartContract) UpdateMembership(ctx contractapi.TransactionContextInterface, membershipJSON string) error { - membership, err := decodeMembership([]byte(membershipJSON)) +func (s *SmartContract) UpdateMembership(ctx contractapi.TransactionContextInterface, counterAttestedMembershipJSON string) error { + // Check if the caller has IIN agent privileges + if isIINAgent, err := isClientIINAgent(ctx); err != nil { + return fmt.Errorf("IIN Agent client check error: %s", err) + } else if !isIINAgent { + return fmt.Errorf("Caller not an IIN Agent; access denied") + } + + // Check if caller is one of the authorized IIN agents + membershipLocal, err := s.GetMembershipBySecurityDomain(ctx, membershipLocalSecurityDomain) + if err != nil { + return err + } + membershipLocalDecoded, err := decodeMembership([]byte(membershipLocal)) if err != nil { return fmt.Errorf("Unmarshal error: %s", err) } - // Check if certificates chains in this membership record are valid - err = validateMemberCertChains(membership.Members, membership.SecurityDomain) + callerId := ctx.GetClientIdentity() + callerCert, err := callerId.GetX509Certificate() if err != nil { return err } - membershipKey, err := ctx.GetStub().CreateCompositeKey(membershipObjectType, []string{membership.SecurityDomain}) - _, getErr := s.GetMembershipBySecurityDomain(ctx, membership.SecurityDomain) + err = checkUserInMembership(callerCert, membershipLocalDecoded) + if err != nil { + return fmt.Errorf("Caller with identity %+v is not a designated IIN Agent: %+v", callerId, err) + } + + counterAttestedMembership, err := decodeCounterAttestedMembership([]byte(counterAttestedMembershipJSON)) + if err != nil { + return fmt.Errorf("Unmarshal error: %s", err) + } + var attestedMembershipSet identity.CounterAttestedMembership_AttestedMembershipSet + err = protoV2.Unmarshal(counterAttestedMembership.AttestedMembershipSet, &attestedMembershipSet) + if err != nil { + return fmt.Errorf("Unable to unmarshal attested membership set: %s", err.Error()) + } + var foreignMembership common.Membership + err = protoV2.Unmarshal(attestedMembershipSet.Membership, &foreignMembership) + if err != nil { + return fmt.Errorf("Unable to unmarshal membership: %s", err.Error()) + } + + // Ensure valid attestations from all local IIN Agents + for _, attestation := range counterAttestedMembership.Attestations { + err = validateAttestation(attestation, counterAttestedMembership.AttestedMembershipSet) + if err != nil { + return err + } + } + + // Validate foreign membership cert chains + err = validateMemberCertChains(&foreignMembership) + if err != nil { + return err + } + + // Ensure authentic and valid attestations from all foreign IIN Agents + for _, attestation := range attestedMembershipSet.Attestations { + if attestation.UnitIdentity.SecurityDomain != foreignMembership.SecurityDomain { + return fmt.Errorf("Foreign agent security domain %s does not match attested membership security domain %s", + attestation.UnitIdentity.SecurityDomain, foreignMembership.SecurityDomain) + } + foundMemberMatch := false + for _, member := range foreignMembership.Members { + var isSignerRoot bool + var leafCertPEM string + if member.Type == "ca" { + leafCertPEM = member.Value + isSignerRoot = true + } else if member.Type == "certificate" { + leafCertPEM = member.Chain[len(member.Chain) - 1] + isSignerRoot = (len(member.Chain) == 1) + } + attesterCert, err := parseCert(attestation.Certificate) + if err != nil { + continue + } + leafCert, err := parseCert(leafCertPEM) + if err != nil { + continue + } + err = validateCertificateUsingCA(attesterCert, leafCert, isSignerRoot) + if err == nil { + foundMemberMatch = true + break + } + } + if !foundMemberMatch { + return fmt.Errorf("No matching member certificate chain found for attester") + } + // Validate signature + err = validateAttestation(attestation, attestedMembershipSet.Membership) + if err != nil { + return err + } + } + + membershipKey, err := ctx.GetStub().CreateCompositeKey(membershipObjectType, []string{foreignMembership.SecurityDomain}) + _, getErr := s.GetMembershipBySecurityDomain(ctx, foreignMembership.SecurityDomain) if getErr != nil { return getErr } - membershipBytes, err := json.Marshal(membership) + membershipBytes, err := json.Marshal(attestedMembershipSet.Membership) if err != nil { return fmt.Errorf("Marshal error: %s", err) } @@ -82,8 +402,40 @@ func (s *SmartContract) UpdateMembership(ctx contractapi.TransactionContextInter } +// DeleteLocalMembership cc is used to delete the local security domain Membership in the ledger +func (s *SmartContract) DeleteLocalMembership(ctx contractapi.TransactionContextInterface) error { + // Check if the caller has network admin privileges + if isAdmin, err := isClientNetworkAdmin(ctx); err != nil { + return fmt.Errorf("Admin client check error: %s", err) + } else if !isAdmin { + return fmt.Errorf("Caller not a network admin; access denied") + } + + membershipLocalKey, err := ctx.GetStub().CreateCompositeKey(membershipObjectType, []string{membershipLocalSecurityDomain}) + bytes, err := ctx.GetStub().GetState(membershipLocalKey) + if err != nil { + return err + } + if bytes == nil { + return fmt.Errorf("Local membership with id: %s does not exist", membershipLocalSecurityDomain) + } + err = ctx.GetStub().DelState(membershipLocalKey) + if err != nil { + return fmt.Errorf("failed to delete asset %s: %v", membershipLocalKey, err) + } + + return nil +} + // DeleteMembership cc is used to delete an existing Membership in the ledger func (s *SmartContract) DeleteMembership(ctx contractapi.TransactionContextInterface, membershipID string) error { + // Check if the caller has IIN agent privileges + if isIINAgent, err := isClientIINAgent(ctx); err != nil { + return fmt.Errorf("IIN Agent client check error: %s", err) + } else if !isIINAgent { + return fmt.Errorf("Caller not an IIN Agent; access denied") + } + membershipKey, err := ctx.GetStub().CreateCompositeKey(membershipObjectType, []string{membershipID}) bytes, err := ctx.GetStub().GetState(membershipKey) if err != nil { diff --git a/core/network/fabric-interop-cc/contracts/interop/membership_test.go b/core/network/fabric-interop-cc/contracts/interop/membership_test.go index f7d3bdf5b..737430ed4 100644 --- a/core/network/fabric-interop-cc/contracts/interop/membership_test.go +++ b/core/network/fabric-interop-cc/contracts/interop/membership_test.go @@ -8,8 +8,13 @@ package main import ( "bytes" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/rsa" "crypto/x509" "crypto/x509/pkix" + "encoding/base64" "encoding/json" "encoding/pem" "fmt" @@ -17,93 +22,879 @@ import ( "testing" "time" + "github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/testutils/mocks" "github.com/stretchr/testify/require" "github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go/common" + "github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go/identity" + protoV2 "google.golang.org/protobuf/proto" wtest "github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/testutils" ) -var member = common.Member{ - Value: "membervalue", - Type: "membertype", - Chain: []string{"chain"}, +var securityDomainId = "2345" +var foreignMemberId1 = "foreign-member1" +var foreignMemberId2 = "foreign-member2" +var localSecurityDomainId = "6789" +var localMemberId1 = "local-member1" +var localMemberId2 = "local-member2" + +func getMembership() (common.Member, common.Member) { + member1 := common.Member{ + Value: "", + Type: "certificate", + Chain: []string{"chain1"}, + } + + member2 := common.Member{ + Value: "", + Type: "certificate", + Chain: []string{"chain2"}, + } + + return member1, member2 } -var membershipAsset = common.Membership{ - SecurityDomain: "2345", - Members: map[string]*common.Member{"member1": &member}, +func publicKey(priv interface{}) interface{} { + switch k := priv.(type) { + case *rsa.PrivateKey: + return &k.PublicKey + case *ecdsa.PrivateKey: + return &k.PublicKey + default: + return nil + } +} + +func createX509Certificate(caCert *x509.Certificate, caCertPrivKey *ecdsa.PrivateKey) ([]byte, *ecdsa.PrivateKey, error) { + var priv, privKey interface{} + serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) + serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) + if err != nil { + return nil, nil, fmt.Errorf("failed to generate serial number: %s", err) + } + template := x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + Organization: []string{"Hyperledger"}, + }, + NotBefore: time.Now(), + NotAfter: time.Now().AddDate(1, 0, 0), // 1 year expiry duration + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + SignatureAlgorithm: x509.ECDSAWithSHA384, + //SignatureAlgorithm: x509.ECDSAWithSHA256, + } + priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader) + //priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if caCertPrivKey == nil { + privKey = priv + } else { + privKey = caCertPrivKey + } + var newCertBytes []byte + // the 'x509.CreateCertificate' function returns the certificate data in asn1 form. + if caCert == nil { + newCertBytes, err = x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), privKey) + } else { + newCertBytes, err = x509.CreateCertificate(rand.Reader, &template, caCert, publicKey(priv), privKey) + } + if err != nil { + return nil, nil, fmt.Errorf("failed to create certificate: %s", err) + } + + return newCertBytes, priv.(*ecdsa.PrivateKey), err +} + +func x509CertToPem(certBytes []byte) (string, error) { + certBlock := &pem.Block{ Type: "CERTIFICATE", Bytes: certBytes } + var certBuf bytes.Buffer + err := pem.Encode(&certBuf, certBlock) + if err != nil { + return "", fmt.Errorf("failed to encode in PEM format: %s", err) + } + return certBuf.String(), err +} + +func generateCertChain(length int) ([]string, []*ecdsa.PrivateKey, error) { + var certChain = make([]string, length) + var keyChain = make([]*ecdsa.PrivateKey, length) + caCertBytes, caKey, err := createX509Certificate(nil, nil) + keyChain[0] = caKey + if err != nil { + return []string{}, []*ecdsa.PrivateKey{}, err + } + caCert, _ := x509.ParseCertificate(caCertBytes) + certChain[0], err = x509CertToPem(caCertBytes) + if err != nil { + return []string{}, []*ecdsa.PrivateKey{}, err + } + for i := 1; i < length; i++ { + certBytes, key, err := createX509Certificate(caCert, caKey) + if err != nil { + return []string{}, []*ecdsa.PrivateKey{}, err + } + caKey = key + keyChain[i] = key + caCert, _ = x509.ParseCertificate(certBytes) + certChain[i], err = x509CertToPem(certBytes) + if err != nil { + return []string{}, []*ecdsa.PrivateKey{}, err + } + } + return certChain, keyChain, nil } func TestGetMembershipBySecurityDomain(t *testing.T) { ctx, chaincodeStub := wtest.PrepMockStub() interopcc := SmartContract{} + member1, member2 := getMembership() + membershipAsset := common.Membership{ + SecurityDomain: securityDomainId, + Members: map[string]*common.Member{ "member1": &member1, "member2": &member2}, + } + // Case when no Membership is found - acString, getError := interopcc.GetMembershipBySecurityDomain(ctx, "2345") - require.EqualError(t, getError, fmt.Sprintf("Membership with id: %s does not exist", "2345")) + acString, getError := interopcc.GetMembershipBySecurityDomain(ctx, securityDomainId) + require.EqualError(t, getError, fmt.Sprintf("Membership with id: %s does not exist", securityDomainId)) require.Equal(t, acString, "") value, err := json.Marshal(&membershipAsset) require.NoError(t, err) chaincodeStub.GetStateReturns(value, nil) // Case when Membership is found - assetRead, err := interopcc.GetMembershipBySecurityDomain(ctx, "2345") + assetRead, err := interopcc.GetMembershipBySecurityDomain(ctx, securityDomainId) require.NoError(t, err) require.Equal(t, assetRead, string(value)) } -func TestCreateMembership(t *testing.T) { +func setClientAdmin(attr string) (string, bool, error) { + if attr == "network-admin" { + return "", true, nil + } else { + return "", false, nil + } +} + +func setClientIINAgent(attr string) (string, bool, error) { + if attr == "iin-agent" { + return "", true, nil + } else { + return "", false, nil + } +} + +func TestCreateLocalMembership(t *testing.T) { ctx, chaincodeStub := wtest.PrepMockStub() interopcc := SmartContract{} + member1, member2 := getMembership() + membershipAsset := common.Membership{ + SecurityDomain: securityDomainId, + Members: map[string]*common.Member{ "member1": &member1, "member2": &member2}, + } + membershipBytes, err := json.Marshal(&membershipAsset) require.NoError(t, err) - // Case when no a Membership is found - err = interopcc.CreateMembership(ctx, string(membershipBytes)) + + // Case when caller is not an admin + err = interopcc.CreateLocalMembership(ctx, string(membershipBytes)) + require.EqualError(t, err, "Caller not a network admin; access denied") + // Case when no Membership is found + clientIdentity := &mocks.ClientIdentity{} + clientIdentity.GetAttributeValueCalls(setClientAdmin) + ctx.GetClientIdentityReturns(clientIdentity) + err = interopcc.CreateLocalMembership(ctx, string(membershipBytes)) require.NoError(t, err) + + // Valid cert chain + member := &member1 + member.Chain, _, _ = generateCertChain(3) + membershipBytes, err = json.Marshal(&membershipAsset) + require.NoError(t, err) + err = interopcc.CreateLocalMembership(ctx, string(membershipBytes)) + require.NoError(t, err) + + // Invalid cert chain + cert_0 := member.Chain[0] + member.Chain[0] = member.Chain[2] + member.Chain[2] = cert_0 + membershipBytes, err = json.Marshal(&membershipAsset) + require.NoError(t, err) + err = interopcc.CreateLocalMembership(ctx, string(membershipBytes)) + require.Error(t, err) + // Invalid Input check - err = interopcc.CreateMembership(ctx, "Invalid Input") + cert_0 = member.Chain[0] + member.Chain[0] = member.Chain[2] + member.Chain[2] = cert_0 + membershipBytes, err = json.Marshal(&membershipAsset) + require.NoError(t, err) + err = interopcc.CreateLocalMembership(ctx, "Invalid Input") require.EqualError(t, err, fmt.Sprintf("Unmarshal error: invalid character 'I' looking for beginning of value")) // Membership already exists chaincodeStub.GetStateReturns([]byte{}, nil) - err = interopcc.CreateMembership(ctx, string(membershipBytes)) - require.EqualError(t, err, fmt.Sprintf("Membership already exists for membership id: %s", membershipAsset.SecurityDomain)) + err = interopcc.CreateLocalMembership(ctx, string(membershipBytes)) + require.EqualError(t, err, fmt.Sprintf("Membership already exists for local membership id: %s. Use 'UpdateLocalMembership' to update.", membershipLocalSecurityDomain)) } -func TestUpdateMembership(t *testing.T) { +func TestUpdateLocalMembership(t *testing.T) { ctx, chaincodeStub := wtest.PrepMockStub() interopcc := SmartContract{} + member1, member2 := getMembership() + membershipAsset := common.Membership{ + SecurityDomain: securityDomainId, + Members: map[string]*common.Member{ "member1": &member1, "member2": &member2}, + } + membershipBytes, err := json.Marshal(&membershipAsset) require.NoError(t, err) - err = interopcc.UpdateMembership(ctx, string(membershipBytes)) + + // Case when caller is not an admin + err = interopcc.UpdateLocalMembership(ctx, string(membershipBytes)) + require.EqualError(t, err, "Caller not a network admin; access denied") + // Case when no Membership is found + clientIdentity := &mocks.ClientIdentity{} + clientIdentity.GetAttributeValueCalls(setClientAdmin) + ctx.GetClientIdentityReturns(clientIdentity) + err = interopcc.UpdateLocalMembership(ctx, string(membershipBytes)) + require.EqualError(t, err, fmt.Sprintf("Membership with id: %s does not exist", membershipAsset.SecurityDomain)) + + // Valid cert chain + member := &member1 + member.Chain, _, _ = generateCertChain(3) + membershipBytes, err = json.Marshal(&membershipAsset) + require.NoError(t, err) + err = interopcc.UpdateLocalMembership(ctx, string(membershipBytes)) require.EqualError(t, err, fmt.Sprintf("Membership with id: %s does not exist", membershipAsset.SecurityDomain)) - // Invalid Input check - chaincodeStub.GetStateReturns(membershipBytes, nil) - err = interopcc.UpdateMembership(ctx, "Invalid Input") - require.EqualError(t, err, fmt.Sprintf("Unmarshal error: invalid character 'I' looking for beginning of value")) // Membership already exists update the Membership chaincodeStub.GetStateReturns(membershipBytes, nil) - err = interopcc.UpdateMembership(ctx, string(membershipBytes)) + err = interopcc.UpdateLocalMembership(ctx, string(membershipBytes)) + require.NoError(t, err) + + // Invalid cert chain + cert_0 := member.Chain[0] + member.Chain[0] = member.Chain[2] + member.Chain[2] = cert_0 + membershipBytes, err = json.Marshal(&membershipAsset) + require.NoError(t, err) + err = interopcc.UpdateLocalMembership(ctx, string(membershipBytes)) + require.Error(t, err) + + // Invalid Input check + cert_0 = member.Chain[0] + member.Chain[0] = member.Chain[2] + member.Chain[2] = cert_0 + membershipBytes, err = json.Marshal(&membershipAsset) require.NoError(t, err) + err = interopcc.UpdateLocalMembership(ctx, "Invalid Input") + require.EqualError(t, err, fmt.Sprintf("Unmarshal error: invalid character 'I' looking for beginning of value")) +} + +func TestCreateMembership(t *testing.T) { + ctx, chaincodeStub := wtest.PrepMockStub() + interopcc := SmartContract{} + + member1, member2 := getMembership() + membershipAsset := common.Membership{ + SecurityDomain: securityDomainId, + Members: map[string]*common.Member{ "member1": &member1, "member2": &member2}, + } + + // Generate foreign network member 1 CA structure and client credentials + certChain1, keys1, _ := generateCertChain(3) + member1.Chain = certChain1 + decodedCert1, _ := pem.Decode([]byte(member1.Chain[2])) + cert1, _ := x509.ParseCertificate(decodedCert1.Bytes) + certBytes1, key1, err := createX509Certificate(cert1, keys1[2]) + certPem1, _ := x509CertToPem(certBytes1) + attestation1 := identity.Attestation { + UnitIdentity: &identity.SecurityDomainMemberIdentity { + SecurityDomain: securityDomainId, + MemberId: foreignMemberId1, + }, + Certificate: certPem1, + Signature: "", + } + // Generate foreign network member 2 CA structure and client credentials + certChain2, keys2, _ := generateCertChain(3) + member2.Chain = certChain2 + decodedCert2, _ := pem.Decode([]byte(member2.Chain[2])) + cert2, _ := x509.ParseCertificate(decodedCert2.Bytes) + certBytes2, key2, err := createX509Certificate(cert2, keys2[2]) + certPem2, _ := x509CertToPem(certBytes2) + attestation2 := identity.Attestation { + UnitIdentity: &identity.SecurityDomainMemberIdentity { + SecurityDomain: securityDomainId, + MemberId: foreignMemberId2, + }, + Certificate: certPem2, + Signature: "", + } + // Marshal membership for signature + membershipBytes, err := protoV2.Marshal(&membershipAsset) + require.NoError(t, err) + // Generate member 2 attestation + random1 := rand.Reader + hashed1, err := computeSHA2Hash(membershipBytes, key1.PublicKey.Params().BitSize) + require.NoError(t, err) + signature1, err := ecdsa.SignASN1(random1, key1, hashed1) + require.NoError(t, err) + attestation1.Signature = base64.StdEncoding.EncodeToString(signature1) + // Generate member 2 attestation + random2 := rand.Reader + hashed2, err := computeSHA2Hash(membershipBytes, key2.PublicKey.Params().BitSize) + require.NoError(t, err) + signature2, err := ecdsa.SignASN1(random2, key2, hashed2) + require.NoError(t, err) + attestation2.Signature = base64.StdEncoding.EncodeToString(signature2) + // Generate attested foreign membership + attestedMembershipSet := identity.CounterAttestedMembership_AttestedMembershipSet { + Membership: membershipBytes, + Attestations: []*identity.Attestation{&attestation1, &attestation2}, + } + + // Generate local members + localCertChain1, localKeyChain1, _ := generateCertChain(3) + localMember1 := common.Member{ + Value: "", + Type: "certificate", + Chain: localCertChain1, + } + localCertChain2, localKeyChain2, _ := generateCertChain(3) + localMember2 := common.Member{ + Value: "", + Type: "certificate", + Chain: localCertChain2, + } + localMembershipAsset := common.Membership{ + SecurityDomain: localSecurityDomainId, + Members: map[string]*common.Member{ "member1": &localMember1, "member2": &localMember2}, + } + + // Generate local attesters + decodedLocalCert1, _ := pem.Decode([]byte(localCertChain1[2])) + certLocal1, _ := x509.ParseCertificate(decodedLocalCert1.Bytes) + certLocalBytes1, keyLocal1, err := createX509Certificate(certLocal1, localKeyChain1[2]) + certLocalPem1, _ := x509CertToPem(certLocalBytes1) + attestationLocal1 := identity.Attestation { + UnitIdentity: &identity.SecurityDomainMemberIdentity { + SecurityDomain: localSecurityDomainId, + MemberId: localMemberId1, + }, + Certificate: certLocalPem1, + Signature: "", + } + decodedLocalCert2, _ := pem.Decode([]byte(localCertChain2[2])) + certLocal2, _ := x509.ParseCertificate(decodedLocalCert2.Bytes) + certLocalBytes2, keyLocal2, err := createX509Certificate(certLocal2, localKeyChain2[2]) + certLocalPem2, _ := x509CertToPem(certLocalBytes2) + attestationLocal2 := identity.Attestation { + UnitIdentity: &identity.SecurityDomainMemberIdentity { + SecurityDomain: localSecurityDomainId, + MemberId: localMemberId2, + }, + Certificate: certLocalPem2, + Signature: "", + } + // Marshal attested membership set for signature + attestedMembershipSetBytes, err := protoV2.Marshal(&attestedMembershipSet) + require.NoError(t, err) + // Generate member 2 attestation + randomLocal1 := rand.Reader + hashedLocal1, err := computeSHA2Hash(attestedMembershipSetBytes, keyLocal1.PublicKey.Params().BitSize) + require.NoError(t, err) + signatureLocal1, err := ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) + require.NoError(t, err) + attestationLocal1.Signature = base64.StdEncoding.EncodeToString(signatureLocal1) + // Generate member 2 attestation + randomLocal2 := rand.Reader + hashedLocal2, err := computeSHA2Hash(attestedMembershipSetBytes, keyLocal2.PublicKey.Params().BitSize) + require.NoError(t, err) + signatureLocal2, err := ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) + require.NoError(t, err) + attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) + // Generate counter attested foreign membership + counterAttestedMembership := identity.CounterAttestedMembership{ + AttestedMembershipSet: attestedMembershipSetBytes, + Attestations: []*identity.Attestation{&attestationLocal1, &attestationLocal2}, + } + + // Record membership info: should fail because the caller is not an IIN Agent + counterAttestedMembershipBytes, err := json.Marshal(&counterAttestedMembership) + require.NoError(t, err) + err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + require.EqualError(t, err, "Caller not an IIN Agent; access denied") + + // Record membership info: should fail because the local IIN Agent is not registered + clientIdentity := &mocks.ClientIdentity{} + clientIdentity.GetAttributeValueCalls(setClientIINAgent) + ctx.GetClientIdentityReturns(clientIdentity) + err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + require.Error(t, err) + + // Record local membership info + localMembershipBytes, err := json.Marshal(&localMembershipAsset) + require.NoError(t, err) + clientIdentity.GetAttributeValueCalls(setClientAdmin) + ctx.GetClientIdentityReturns(clientIdentity) + err = interopcc.CreateLocalMembership(ctx, string(localMembershipBytes)) + require.NoError(t, err) + + // Record membership info: should succeed now + chaincodeStub.GetStateReturnsOnCall(2, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(3, nil, nil) + clientIdentity.GetAttributeValueCalls(setClientIINAgent) + ctx.GetClientIdentityReturns(clientIdentity) + err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + require.NoError(t, err) + + // Record membership info again: should fail because membership has already been recorded against this security domain + chaincodeStub.GetStateReturnsOnCall(4, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(5, []byte{}, nil) + err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + require.EqualError(t, err, fmt.Sprintf("Membership already exists for membership id: %s. Use 'UpdateMembership' to update.", membershipAsset.SecurityDomain)) + + // One of the local signatures is invalid: should fail + hashedLocal2, err = computeSHA2Hash([]byte("invalid"), keyLocal2.PublicKey.Params().BitSize) + require.NoError(t, err) + signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) + require.NoError(t, err) + attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) + counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) + require.NoError(t, err) + chaincodeStub.GetStateReturnsOnCall(6, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(7, nil, nil) + err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + require.EqualError(t, err, "Unable to Validate Signature: Signature Verification failed. ECDSA VERIFY") + + // One of the foreign signatures is invalid: should fail + hashed2, err = computeSHA2Hash([]byte("invalid"), key2.PublicKey.Params().BitSize) + require.NoError(t, err) + signature2, err = ecdsa.SignASN1(random2, key2, hashed2) + require.NoError(t, err) + attestation2.Signature = base64.StdEncoding.EncodeToString(signature2) + attestedMembershipSetBytes, err = protoV2.Marshal(&attestedMembershipSet) + require.NoError(t, err) + hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytes, keyLocal1.PublicKey.Params().BitSize) + require.NoError(t, err) + signatureLocal1, err = ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) + require.NoError(t, err) + attestationLocal1.Signature = base64.StdEncoding.EncodeToString(signatureLocal1) + hashedLocal2, err = computeSHA2Hash(attestedMembershipSetBytes, keyLocal2.PublicKey.Params().BitSize) + require.NoError(t, err) + signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) + require.NoError(t, err) + attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) + counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes + counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) + require.NoError(t, err) + chaincodeStub.GetStateReturnsOnCall(7, localMembershipBytes, nil) + err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + require.EqualError(t, err, "Unable to Validate Signature: Signature Verification failed. ECDSA VERIFY") + + // Foreign membership has an invalid cert chain: should fail + tmpCert := member1.Chain[0] + member1.Chain[0] = member1.Chain[1] + member1.Chain[1] = tmpCert + membershipBytes, err = protoV2.Marshal(&membershipAsset) + require.NoError(t, err) + hashed1, err = computeSHA2Hash(membershipBytes, key1.PublicKey.Params().BitSize) + require.NoError(t, err) + signature1, err = ecdsa.SignASN1(random1, key1, hashed1) + require.NoError(t, err) + attestation1.Signature = base64.StdEncoding.EncodeToString(signature1) + hashed2, err = computeSHA2Hash(membershipBytes, key2.PublicKey.Params().BitSize) + require.NoError(t, err) + signature2, err = ecdsa.SignASN1(random2, key2, hashed2) + require.NoError(t, err) + attestation2.Signature = base64.StdEncoding.EncodeToString(signature2) + attestedMembershipSet.Membership = membershipBytes + attestedMembershipSetBytes, err = protoV2.Marshal(&attestedMembershipSet) + require.NoError(t, err) + hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytes, keyLocal1.PublicKey.Params().BitSize) + require.NoError(t, err) + signatureLocal1, err = ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) + require.NoError(t, err) + attestationLocal1.Signature = base64.StdEncoding.EncodeToString(signatureLocal1) + hashedLocal2, err = computeSHA2Hash(attestedMembershipSetBytes, keyLocal2.PublicKey.Params().BitSize) + require.NoError(t, err) + signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) + require.NoError(t, err) + attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) + counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes + counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) + require.NoError(t, err) + chaincodeStub.GetStateReturnsOnCall(8, localMembershipBytes, nil) + err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + require.Error(t, err) + + // Foreign attestation has invalid security domain: should fail + tmpCert = member1.Chain[0] + member1.Chain[0] = member1.Chain[1] + member1.Chain[1] = tmpCert + membershipAsset.SecurityDomain = "invalid" + membershipBytes, err = protoV2.Marshal(&membershipAsset) + require.NoError(t, err) + hashed1, err = computeSHA2Hash(membershipBytes, key1.PublicKey.Params().BitSize) + require.NoError(t, err) + signature1, err = ecdsa.SignASN1(random1, key1, hashed1) + require.NoError(t, err) + attestation1.Signature = base64.StdEncoding.EncodeToString(signature1) + hashed2, err = computeSHA2Hash(membershipBytes, key2.PublicKey.Params().BitSize) + require.NoError(t, err) + signature2, err = ecdsa.SignASN1(random2, key2, hashed2) + require.NoError(t, err) + attestation2.Signature = base64.StdEncoding.EncodeToString(signature2) + attestedMembershipSet.Membership = membershipBytes + attestedMembershipSetBytes, err = protoV2.Marshal(&attestedMembershipSet) + require.NoError(t, err) + hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytes, keyLocal1.PublicKey.Params().BitSize) + require.NoError(t, err) + signatureLocal1, err = ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) + require.NoError(t, err) + attestationLocal1.Signature = base64.StdEncoding.EncodeToString(signatureLocal1) + hashedLocal2, err = computeSHA2Hash(attestedMembershipSetBytes, keyLocal2.PublicKey.Params().BitSize) + require.NoError(t, err) + signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) + require.NoError(t, err) + attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) + counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes + counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) + require.NoError(t, err) + chaincodeStub.GetStateReturnsOnCall(9, localMembershipBytes, nil) + err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + require.EqualError(t, err, fmt.Sprintf("Foreign agent security domain %s does not match attested membership security domain invalid", securityDomainId)) +} + +func TestUpdateMembership(t *testing.T) { + ctx, chaincodeStub := wtest.PrepMockStub() + interopcc := SmartContract{} + + member1, member2 := getMembership() + membershipAsset := common.Membership{ + SecurityDomain: securityDomainId, + Members: map[string]*common.Member{ "member1": &member1, "member2": &member2}, + } + + // Generate foreign network member 1 CA structure and client credentials + certChain1, keys1, _ := generateCertChain(3) + member1.Chain = certChain1 + decodedCert1, _ := pem.Decode([]byte(member1.Chain[2])) + cert1, _ := x509.ParseCertificate(decodedCert1.Bytes) + certBytes1, key1, err := createX509Certificate(cert1, keys1[2]) + certPem1, _ := x509CertToPem(certBytes1) + attestation1 := identity.Attestation { + UnitIdentity: &identity.SecurityDomainMemberIdentity { + SecurityDomain: securityDomainId, + MemberId: foreignMemberId1, + }, + Certificate: certPem1, + Signature: "", + } + // Generate foreign network member 2 CA structure and client credentials + certChain2, keys2, _ := generateCertChain(3) + member2.Chain = certChain2 + decodedCert2, _ := pem.Decode([]byte(member2.Chain[2])) + cert2, _ := x509.ParseCertificate(decodedCert2.Bytes) + certBytes2, key2, err := createX509Certificate(cert2, keys2[2]) + certPem2, _ := x509CertToPem(certBytes2) + attestation2 := identity.Attestation { + UnitIdentity: &identity.SecurityDomainMemberIdentity { + SecurityDomain: securityDomainId, + MemberId: foreignMemberId2, + }, + Certificate: certPem2, + Signature: "", + } + // Marshal membership for signature + membershipBytes, err := protoV2.Marshal(&membershipAsset) + require.NoError(t, err) + // Generate member 2 attestation + random1 := rand.Reader + hashed1, err := computeSHA2Hash(membershipBytes, key1.PublicKey.Params().BitSize) + require.NoError(t, err) + signature1, err := ecdsa.SignASN1(random1, key1, hashed1) + require.NoError(t, err) + attestation1.Signature = base64.StdEncoding.EncodeToString(signature1) + // Generate member 2 attestation + random2 := rand.Reader + hashed2, err := computeSHA2Hash(membershipBytes, key2.PublicKey.Params().BitSize) + require.NoError(t, err) + signature2, err := ecdsa.SignASN1(random2, key2, hashed2) + require.NoError(t, err) + attestation2.Signature = base64.StdEncoding.EncodeToString(signature2) + // Generate attested foreign membership + attestedMembershipSet := identity.CounterAttestedMembership_AttestedMembershipSet { + Membership: membershipBytes, + Attestations: []*identity.Attestation{&attestation1, &attestation2}, + } + + // Generate local members + localCertChain1, localKeyChain1, _ := generateCertChain(3) + localMember1 := common.Member{ + Value: "", + Type: "certificate", + Chain: localCertChain1, + } + localCertChain2, localKeyChain2, _ := generateCertChain(3) + localMember2 := common.Member{ + Value: "", + Type: "certificate", + Chain: localCertChain2, + } + localMembershipAsset := common.Membership{ + SecurityDomain: localSecurityDomainId, + Members: map[string]*common.Member{ "member1": &localMember1, "member2": &localMember2}, + } + + // Generate local attesters + decodedLocalCert1, _ := pem.Decode([]byte(localCertChain1[2])) + certLocal1, _ := x509.ParseCertificate(decodedLocalCert1.Bytes) + certLocalBytes1, keyLocal1, err := createX509Certificate(certLocal1, localKeyChain1[2]) + certLocalPem1, _ := x509CertToPem(certLocalBytes1) + attestationLocal1 := identity.Attestation { + UnitIdentity: &identity.SecurityDomainMemberIdentity { + SecurityDomain: localSecurityDomainId, + MemberId: localMemberId1, + }, + Certificate: certLocalPem1, + Signature: "", + } + decodedLocalCert2, _ := pem.Decode([]byte(localCertChain2[2])) + certLocal2, _ := x509.ParseCertificate(decodedLocalCert2.Bytes) + certLocalBytes2, keyLocal2, err := createX509Certificate(certLocal2, localKeyChain2[2]) + certLocalPem2, _ := x509CertToPem(certLocalBytes2) + attestationLocal2 := identity.Attestation { + UnitIdentity: &identity.SecurityDomainMemberIdentity { + SecurityDomain: localSecurityDomainId, + MemberId: localMemberId2, + }, + Certificate: certLocalPem2, + Signature: "", + } + // Marshal attested membership set for signature + attestedMembershipSetBytes, err := protoV2.Marshal(&attestedMembershipSet) + require.NoError(t, err) + // Generate member 2 attestation + randomLocal1 := rand.Reader + hashedLocal1, err := computeSHA2Hash(attestedMembershipSetBytes, keyLocal1.PublicKey.Params().BitSize) + require.NoError(t, err) + signatureLocal1, err := ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) + require.NoError(t, err) + attestationLocal1.Signature = base64.StdEncoding.EncodeToString(signatureLocal1) + // Generate member 2 attestation + randomLocal2 := rand.Reader + hashedLocal2, err := computeSHA2Hash(attestedMembershipSetBytes, keyLocal2.PublicKey.Params().BitSize) + require.NoError(t, err) + signatureLocal2, err := ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) + require.NoError(t, err) + attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) + // Generate counter attested foreign membership + counterAttestedMembership := identity.CounterAttestedMembership{ + AttestedMembershipSet: attestedMembershipSetBytes, + Attestations: []*identity.Attestation{&attestationLocal1, &attestationLocal2}, + } + + // Record membership info: should fail because the caller is not an IIN Agent + counterAttestedMembershipBytes, err := json.Marshal(&counterAttestedMembership) + require.NoError(t, err) + err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + require.EqualError(t, err, "Caller not an IIN Agent; access denied") + + // Record membership info: should fail because the local IIN Agent is not registered + clientIdentity := &mocks.ClientIdentity{} + clientIdentity.GetAttributeValueCalls(setClientIINAgent) + ctx.GetClientIdentityReturns(clientIdentity) + err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + require.Error(t, err) + + // Record local membership info + localMembershipBytes, err := json.Marshal(&localMembershipAsset) + require.NoError(t, err) + clientIdentity.GetAttributeValueCalls(setClientAdmin) + ctx.GetClientIdentityReturns(clientIdentity) + err = interopcc.CreateLocalMembership(ctx, string(localMembershipBytes)) + require.NoError(t, err) + + // Record membership info: should fail because membership has not been recorded previously + chaincodeStub.GetStateReturnsOnCall(2, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(3, nil, nil) + clientIdentity.GetAttributeValueCalls(setClientIINAgent) + ctx.GetClientIdentityReturns(clientIdentity) + err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + require.EqualError(t, err, fmt.Sprintf("Membership with id: %s does not exist", securityDomainId)) + + // Record membership info again: should succeed now + chaincodeStub.GetStateReturnsOnCall(4, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(5, []byte{}, nil) + err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + require.NoError(t, err) + + // One of the local signatures is invalid: should fail + hashedLocal2, err = computeSHA2Hash([]byte("invalid"), keyLocal2.PublicKey.Params().BitSize) + require.NoError(t, err) + signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) + require.NoError(t, err) + attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) + counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) + require.NoError(t, err) + chaincodeStub.GetStateReturnsOnCall(6, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(7, []byte{}, nil) + err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + require.EqualError(t, err, "Unable to Validate Signature: Signature Verification failed. ECDSA VERIFY") + + // One of the foreign signatures is invalid: should fail + hashed2, err = computeSHA2Hash([]byte("invalid"), key2.PublicKey.Params().BitSize) + require.NoError(t, err) + signature2, err = ecdsa.SignASN1(random2, key2, hashed2) + require.NoError(t, err) + attestation2.Signature = base64.StdEncoding.EncodeToString(signature2) + attestedMembershipSetBytes, err = protoV2.Marshal(&attestedMembershipSet) + require.NoError(t, err) + hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytes, keyLocal1.PublicKey.Params().BitSize) + require.NoError(t, err) + signatureLocal1, err = ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) + require.NoError(t, err) + attestationLocal1.Signature = base64.StdEncoding.EncodeToString(signatureLocal1) + hashedLocal2, err = computeSHA2Hash(attestedMembershipSetBytes, keyLocal2.PublicKey.Params().BitSize) + require.NoError(t, err) + signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) + require.NoError(t, err) + attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) + counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes + counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) + require.NoError(t, err) + chaincodeStub.GetStateReturnsOnCall(7, localMembershipBytes, nil) + err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + require.EqualError(t, err, "Unable to Validate Signature: Signature Verification failed. ECDSA VERIFY") + + // Foreign membership has an invalid cert chain: should fail + tmpCert := member1.Chain[0] + member1.Chain[0] = member1.Chain[1] + member1.Chain[1] = tmpCert + membershipBytes, err = protoV2.Marshal(&membershipAsset) + require.NoError(t, err) + hashed1, err = computeSHA2Hash(membershipBytes, key1.PublicKey.Params().BitSize) + require.NoError(t, err) + signature1, err = ecdsa.SignASN1(random1, key1, hashed1) + require.NoError(t, err) + attestation1.Signature = base64.StdEncoding.EncodeToString(signature1) + hashed2, err = computeSHA2Hash(membershipBytes, key2.PublicKey.Params().BitSize) + require.NoError(t, err) + signature2, err = ecdsa.SignASN1(random2, key2, hashed2) + require.NoError(t, err) + attestation2.Signature = base64.StdEncoding.EncodeToString(signature2) + attestedMembershipSet.Membership = membershipBytes + attestedMembershipSetBytes, err = protoV2.Marshal(&attestedMembershipSet) + require.NoError(t, err) + hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytes, keyLocal1.PublicKey.Params().BitSize) + require.NoError(t, err) + signatureLocal1, err = ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) + require.NoError(t, err) + attestationLocal1.Signature = base64.StdEncoding.EncodeToString(signatureLocal1) + hashedLocal2, err = computeSHA2Hash(attestedMembershipSetBytes, keyLocal2.PublicKey.Params().BitSize) + require.NoError(t, err) + signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) + require.NoError(t, err) + attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) + counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes + counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) + require.NoError(t, err) + chaincodeStub.GetStateReturnsOnCall(8, localMembershipBytes, nil) + err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + require.Error(t, err) + + // Foreign attestation has invalid security domain: should fail + tmpCert = member1.Chain[0] + member1.Chain[0] = member1.Chain[1] + member1.Chain[1] = tmpCert + membershipAsset.SecurityDomain = "invalid" + membershipBytes, err = protoV2.Marshal(&membershipAsset) + require.NoError(t, err) + hashed1, err = computeSHA2Hash(membershipBytes, key1.PublicKey.Params().BitSize) + require.NoError(t, err) + signature1, err = ecdsa.SignASN1(random1, key1, hashed1) + require.NoError(t, err) + attestation1.Signature = base64.StdEncoding.EncodeToString(signature1) + hashed2, err = computeSHA2Hash(membershipBytes, key2.PublicKey.Params().BitSize) + require.NoError(t, err) + signature2, err = ecdsa.SignASN1(random2, key2, hashed2) + require.NoError(t, err) + attestation2.Signature = base64.StdEncoding.EncodeToString(signature2) + attestedMembershipSet.Membership = membershipBytes + attestedMembershipSetBytes, err = protoV2.Marshal(&attestedMembershipSet) + require.NoError(t, err) + hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytes, keyLocal1.PublicKey.Params().BitSize) + require.NoError(t, err) + signatureLocal1, err = ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) + require.NoError(t, err) + attestationLocal1.Signature = base64.StdEncoding.EncodeToString(signatureLocal1) + hashedLocal2, err = computeSHA2Hash(attestedMembershipSetBytes, keyLocal2.PublicKey.Params().BitSize) + require.NoError(t, err) + signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) + require.NoError(t, err) + attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) + counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes + counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) + require.NoError(t, err) + chaincodeStub.GetStateReturnsOnCall(9, localMembershipBytes, nil) + err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + require.EqualError(t, err, fmt.Sprintf("Foreign agent security domain %s does not match attested membership security domain invalid", securityDomainId)) +} + +func TestDeleteLocalMembership(t *testing.T) { + ctx, chaincodeStub := wtest.PrepMockStub() + interopcc := SmartContract{} + + // Case when caller is not an IIN Agent + err := interopcc.DeleteLocalMembership(ctx) + require.EqualError(t, err, "Caller not a network admin; access denied") + + // Case when a Membership exists + clientIdentity := &mocks.ClientIdentity{} + clientIdentity.GetAttributeValueCalls(setClientAdmin) + ctx.GetClientIdentityReturns(clientIdentity) + chaincodeStub.GetStateReturns([]byte{}, nil) + err = interopcc.DeleteLocalMembership(ctx) + require.NoError(t, err) + + // Case when no Membership is found + chaincodeStub.GetStateReturns(nil, nil) + err = interopcc.DeleteLocalMembership(ctx) + require.EqualError(t, err, fmt.Sprintf("Local membership with id: %s does not exist", membershipLocalSecurityDomain)) + + // Handle GetState Error + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + err = interopcc.DeleteLocalMembership(ctx) + require.EqualError(t, err, fmt.Sprintf("unable to retrieve asset")) } func TestDeleteMembership(t *testing.T) { ctx, chaincodeStub := wtest.PrepMockStub() interopcc := SmartContract{} + // Case when caller is not an IIN Agent + err := interopcc.DeleteMembership(ctx, securityDomainId) + require.EqualError(t, err, "Caller not an IIN Agent; access denied") + // Case when a Membership exists + clientIdentity := &mocks.ClientIdentity{} + clientIdentity.GetAttributeValueCalls(setClientIINAgent) + ctx.GetClientIdentityReturns(clientIdentity) chaincodeStub.GetStateReturns([]byte{}, nil) - err := interopcc.DeleteMembership(ctx, "2343") + err = interopcc.DeleteMembership(ctx, securityDomainId) require.NoError(t, err) // Case when no Membership is found chaincodeStub.GetStateReturns(nil, nil) - err = interopcc.DeleteMembership(ctx, "2343") - require.EqualError(t, err, fmt.Sprintf("Membership with id: %s does not exist", "2343")) + err = interopcc.DeleteMembership(ctx, securityDomainId) + require.EqualError(t, err, fmt.Sprintf("Membership with id: %s does not exist", securityDomainId)) // Handle GetState Error chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) - err = interopcc.DeleteMembership(ctx, "2343") + err = interopcc.DeleteMembership(ctx, securityDomainId) require.EqualError(t, err, fmt.Sprintf("unable to retrieve asset")) } @@ -120,8 +911,8 @@ func TestVerifyMembership(t *testing.T) { Subject: pkix.Name{ CommonName: "example-a.com", }, - NotBefore: now.Add(-threeDays), - NotAfter: now.Add(threeDays), + NotBefore: now.Add(-threeDays), + NotAfter: now.Add(threeDays), SerialNumber: big.NewInt(1337), } @@ -146,8 +937,8 @@ func TestVerifyMembership(t *testing.T) { } var membershipAsset = common.Membership{ - SecurityDomain: "2345", - Members: map[string]*common.Member{"member1": &member}, + SecurityDomain: securityDomainId, + Members: map[string]*common.Member{"member1": &member}, } membershipBytes, err := json.Marshal(&membershipAsset) require.NoError(t, err) diff --git a/core/network/fabric-interop-cc/libs/utils/utils.go b/core/network/fabric-interop-cc/libs/utils/utils.go index fd9c33dcf..df765d7bf 100644 --- a/core/network/fabric-interop-cc/libs/utils/utils.go +++ b/core/network/fabric-interop-cc/libs/utils/utils.go @@ -150,7 +150,7 @@ func marshalAssetPledge(pledge *common.AssetPledge) (string, error) { return "", err } assetPledgeBase64 := base64.StdEncoding.EncodeToString(assetPledgeBytes) - return assetPledgeBase64, nil + return assetPledgeBase64, nil } func unmarshalAssetPledge(assetPledgeBase64 string) (*common.AssetPledge, error) { pledge := &common.AssetPledge{} @@ -190,7 +190,6 @@ func unmarshalAssetClaimStatus(claimStatusBase64 string) (*common.AssetClaimStat return claimStatus, err } return claimStatus, nil - } // PledgeAsset locks an asset for transfer to a different ledger/network. @@ -198,9 +197,9 @@ func PledgeAsset(ctx contractapi.TransactionContextInterface, assetJSON []byte, if assetIdOrQuantity == "" { return "", fmt.Errorf("no asset ID or unit count provided") } - + pledgeId := generatePledgeId(ctx, assetType, assetIdOrQuantity, owner, remoteNetworkId, recipientCert, expiryTimeSecs) - + pledgeKey := getAssetPledgeKey(pledgeId) pledgeBytes, err := ctx.GetStub().GetState(pledgeKey) if err != nil { @@ -253,7 +252,7 @@ func ClaimRemoteAsset(ctx contractapi.TransactionContextInterface, pledgeId, cla if pledgeId == "" { return nil, fmt.Errorf("pledgeId can not be empty") } - + pledge, err := unmarshalAssetPledge(pledgeBytes64) if err != nil { return nil, err @@ -299,13 +298,13 @@ func ClaimRemoteAsset(ctx contractapi.TransactionContextInterface, pledgeId, cla if err != nil { // No Record of claim return pledge.AssetDetails, ctx.GetStub().PutState(claimKey, claimBytes) } - + lookupClaimStatus := &common.AssetClaimStatus{} err = proto.Unmarshal(lookupClaimBytes, lookupClaimStatus) if lookupClaimStatus.ClaimStatus { // Previous claim was successful return nil, fmt.Errorf("asset has already been claimed") } - + // Else proceed to claim return pledge.AssetDetails, ctx.GetStub().PutState(claimKey, claimBytes) } @@ -420,12 +419,12 @@ func GetAssetPledgeStatus(ctx contractapi.TransactionContextInterface, pledgeId, if lookupPledge.Recipient != recipientCert || lookupPledge.RemoteNetworkID != recipientNetworkId { return nil, pledgeBytes64, pledgeBytes64, nil // Return blank } - + lookupPledgeBytes64, err := marshalAssetPledge(lookupPledge) if err != nil { return nil, pledgeBytes64, pledgeBytes64, err } - + return lookupPledge.AssetDetails, lookupPledgeBytes64, pledgeBytes64, nil } @@ -451,7 +450,7 @@ func GetAssetPledgeDetails(ctx contractapi.TransactionContextInterface, pledgeId if err != nil { return nil, "", err } - + return lookupPledge.AssetDetails, lookupPledgeBytes64, nil } diff --git a/rfcs/protocols/identity/network-identity-validation.md b/rfcs/protocols/identity/network-identity-validation.md deleted file mode 100644 index f8ae13fb0..000000000 --- a/rfcs/protocols/identity/network-identity-validation.md +++ /dev/null @@ -1,105 +0,0 @@ - -# Security Domain Identity Validation - -- RFC: 02-017 -- Authors: Venkatraman Ramakrishna, Krishnasuri Narayanam, Bishakh Chandra Ghosh, Ermyas Abebe -- Status: Proposed -- Since: 27-Aug-2022 - -## Summary -When a network ("local network" from here on) tries to configure the idetntity of another network ("foreign network" from here on) for interoperation, the broad steps involved are (i) Network Discovery (ii) Network Identity Validation. Both these steps are carried out by the IIN agent of the participants of the local network. - -Whether each participant needs to carry out the discovery and validation, or a subset of participants will do it depends entirely on the trust basis of the network. This is explained in [*Data Plane Identity Configuration*](./identity-syncing.md). - -Merely fetching the Network DID Document in the [discovery step](../discovery/readme.md) does not prove the identity of the network or the genuinity of the Network DID Document. -Resolving a Network DID from the IIN only ensures that the the DID controllers in `networkParticipants` property of the DID document attested the network DID. However, these attestor's physical identity are not known up front to the local network participants. This is because, DIDs are not implicitely tied to any physical identity. Therefore, to validate the authenticty of the network, a local network participant must use some trust basis. This specification provides three network identity validation protocol levels, from which one or more can be carried out depending on the availability of different trust basis, and the level of decentralization desired. - -The three network identity validation protocols, each using a different type trust basis are as follows: - -> Note: The common assumption across all the protocols is the IIN DID registry is not malicious. Given a DLT based IIN which allows anyone to monitor the ledger, any IIN agent can validate the authenticity of a Network DID by validating the Network DID creation/updation requests from the ledger. - -## A. Well Known Network DID - -A Network DID registered in an IIN DID registry (IIN ledger) is controlled by the group controller specified by the `networkParticipants` and `BlockchainNetworkMultiSig` verification method. Thus, provided that the IIN registry is not compromised, the Network DID document will remain under the control of its creators. Even if the network structure changes with members joining and leaving, the `updatePolicy` ensures that the stakeholders of the network remain in control of the Network DID. Therefore, given that the local network knows the Network DID of the foreign network it wants to interoperate with, there is no need for explicit validation of the Network DID document. - -### Protocol: - -Step 1. Local network participants obtain the foreign network's Network DID from some trusted source. The trusted source of the Network DID may be offline physical interaction directly with the foreign network, or some well known webpage for the network, or something else. - -Step 2. Through the [discovery protocol](../discovery/readme.md), the local network participant's IIN agent obtains the Network DID document. - -### Assumptions: - - - The source from which the Network DID URI is obtained is trusted. This source is the trust basis. - -### Possible Attacks: -- Since the IIN is open to accepting DID registrations from anyone, a Network DID can be created by with similar URIs by attackers. Therefore, through phishing attacks and compromising the DID URI sources such as websites, the original Network DID might be replaced with a malicious one. Without further validations, the local network starts interoperation with the attacker's network. - -### Limitations: - -- The source of the Network DID itself can be considered as a trust basis only for well known networks. Moreover, the security of the source such as a webpage is also a factor in the security of this protocol. For smaller networks whose webpage or some other well known source of obtaining the Network DID is not available, relying to this level of validation only is enough. - - - - -## B. Network Identity VC - -The Network DID document is implicitely not tied to any physical identity. Thus after discovery, the obtained Network DID document has to be validated based on some trust basis. For this validation the local network participants may rely on some [trust anchors](../../models/identity/iin.md). These trust anchors attest the physical identity of a Network DID by issuing VC. For example, for the DID `did:iin_indy:tradelensnetwork`, a trust anchor would attest that the DID is the Network DID for the network named "TradeLens", and optionally provide additional information like the name and address of the organizations involving the network. - -### Protocol: - -Step 1. Trust anchor issues a verifiable credential to the Network DID. This VC attests the identity of the network as a whole, called `Network Identity VC`. - -Step 2. From the Network DID document, local network participant obtains the service endpoint for requesting VCs ([DIDcomm](https://w3c.github.io/did-spec-registries/#didcommmessaging)). - -Step 3. Local netowrk participant requests `Network Identity VC` - -Step 4. The verifiable presentation obtained in response from the network service endoint is validated. - -### Assumptions: - -Atleast one trust anchor exists that issues the `Network Identity VC` to the foreign network DID, which is also trusted by the local network participants. - -The trust anchor is not malicious. - -### Possible Attacks: - -If the DID URI is incorrect as well as the trust anchor (s) used to validate `Network Identity VC` are malicous then the local network might configure a malicious network instead of the network it intended to interoperate with. - -### Limitations: - -For issuing a VC for a DID, as well as requisting VPs for a credential, service endpoints are required. Since the Network DID represents a blockchain network with a group controller of its participants, having a single service endpoint can lead to centralization in control of the credentials. - -In order to attest identity of a network, the trust anchor must validate the structure of the network as well as the identity of each of its participants. As a result, the availability of such trust anchors might be limited since such validation will often require physical verification of the agreements between the participants forming the network. - -## C. Participant Identity VC - -Without relying on the DID URI, in the unavailability of any trust basis attesting the identity of a foreign network directly, the identity of the individual network participants can be used to validate the Network DID. - -A Network DID must have attestations from all participants during creation, and each update must satisfy the update policy (see Network DID creation protocol). Therefore, a Network DID implies the agreement on network formation by the participants, and validating the participant identities is enough to validate the identity of the network as a whole. - -### Protocol: - -- Trust anchors issue `Identity VC` to the individual network participants. - -- For each foreign network participant specified in `networkParticipants` of the Network DID, validate its identity thorugh `Identity VC` issued to them by trust anchor through the following steps: - - - Resolve the participant DID document from the DID. - - Get address of the participant's IIN agent from service endpoints in the DID document. ([DIDcomm](https://w3c.github.io/did-spec-registries/#didcommmessaging) service endpoint) - - [Optional] negotiate a trust anchor. - - Request `Identity VC`. - - Validate `Identity VC` - - -### Limitations: - -The protocol can only complete successfully if there are trust anchors available to validate the identity of the foreign network participants. Even after that, this protocol only ensures the validation of network formation by these participants. Therefore, an attack is possible by the subset of network participants of a larger network. - - -### Possible Attacks: - -Consider a hypothetical foreign network named "Supernet", with `N` participants. The Network DID of Supernet is `did:iin_indy:supernet`. A subset of `f < N` participants of Supernet are maliscious, and they create a Network DID with URI almost similar to "Supernet": `did:iin_indy:supernetwork`. Then, if the local network wanting to interoperate with Supernet somehow gets the wrong Network DID (for example through phishing), then the discovered Network DID document would be of the maliscious network. Here, validation through the identity validaiton of the particpants will also succeed. If none of `N-f` the non-maliscious participants of Supernet are known to the local network validators then the attack would be successful. diff --git a/rfcs/protocols/identity/security-domain-identity-validation.md b/rfcs/protocols/identity/security-domain-identity-validation.md new file mode 100644 index 000000000..7c5736ed7 --- /dev/null +++ b/rfcs/protocols/identity/security-domain-identity-validation.md @@ -0,0 +1,103 @@ + +# Security Domain Identity Validation + +- RFC: 02-017 +- Authors: Venkatraman Ramakrishna, Krishnasuri Narayanam, Bishakh Chandra Ghosh, Ermyas Abebe +- Status: Proposed +- Since: 27-Aug-2022 + +## Summary +When a security domain ("local security domain" from here on) tries to sync the identity and membership of another security domain ("foreign security domain" from here on) for interoperation, its members' IIN Agents must carry out the following steps: (i) Security Domain Discovery (ii) Security Domain Identity Validation. + +Merely fetching the Security Domain DID Document in the [discovery step](../discovery/discovery.md) does not prove that the associated security domain is a genuine collective of organizational units. +Resolving a Security Domain DID maintained in an IIN registry only ensures that the entities specified as the group DID controllers in the `networkMembers` property of the DID document have attested it. However, these attestors' real worls identities are not known a priori to the local security domain's members. This is because DIDs are not (implicitly or explicitly) tied to any real world identity. Therefore, to validate the authenticity of the foreign security domain, a local security domain's member must rely on some trust basis. This specification provides three alternative security domain identity validation protocols. Which one is selected by a given security domain in a given scenario depends on pre-existing trust relationships between the networks as well as the desired level of decentralization. + +The three security domain identity validation protocols, each built on a different kind of trust basis, are as follows: + +> Note: The common assumption in all these protocols is that the IIN DID registry is not malicious. Given a DLT-based IIN which allows anyone to monitor the ledger, any IIN agent can validate the authenticity of a Security Domain DID by auditing DID create/updtate transactions recorded on the ledger. + +## A. Well Known Network DID + +A Network DID registered in an IIN DID registry (IIN ledger) is controlled by the group controller specified by the `networkMembers` and `BlockchainNetworkMultiSig` verification method. Thus, provided that the IIN registry is not compromised, the Network DID document will remain under the control of its creators. Even if the network structure changes with members joining and leaving, the `updatePolicy` ensures that the stakeholders of the network remain in control of the Network DID. Therefore, given that the local security domain knows the Network DID of the foreign security domain it wants to interoperate with, there is no need for explicit validation of the Network DID document. + +### Protocol: + +Step 1. Local network participants obtain the foreign security domain's Network DID from some trusted source. The trusted source of the Network DID may be offline physical interaction directly with the foreign security domain, or some well known webpage for the network, or something else. + +Step 2. Through the [discovery protocol](../discovery/readme.md), the local security domain participant's IIN agent obtains the Network DID document. + +### Assumptions: + + - The source from which the Network DID URI is obtained is trusted. This source is the trust basis. + +### Possible Attacks: +- Since the IIN is open to accepting DID registrations from anyone, a Network DID can be created by with similar URIs by attackers. Therefore, through phishing attacks and compromising the DID URI sources such as websites, the original Network DID might be replaced with a malicious one. Without further validations, the local security domain starts interoperation with the attacker's network. + +### Limitations: + +- The source of the Network DID itself can be considered as a trust basis only for well known networks. Moreover, the security of the source such as a webpage is also a factor in the security of this protocol. For smaller networks whose webpage or some other well known source of obtaining the Network DID is not available, relying to this level of validation only is enough. + + + + +## B. Network Identity VC + +The Network DID document is implicitely not tied to any physical identity. Thus after discovery, the obtained Network DID document has to be validated based on some trust basis. For this validation the local security domain participants may rely on some [trust anchors](../../models/identity/iin.md). These trust anchors attest the physical identity of a Network DID by issuing VC. For example, for the DID `did:iin_indy:tradelensnetwork`, a trust anchor would attest that the DID is the Network DID for the network named "TradeLens", and optionally provide additional information like the name and address of the organizations involving the network. + +### Protocol: + +Step 1. Trust anchor issues a verifiable credential to the Network DID. This VC attests the identity of the network as a whole, called `Network Identity VC`. + +Step 2. From the Network DID document, local security domain participant obtains the service endpoint for requesting VCs ([DIDcomm](https://w3c.github.io/did-spec-registries/#didcommmessaging)). + +Step 3. Local netowrk participant requests `Network Identity VC` + +Step 4. The verifiable presentation obtained in response from the network service endoint is validated. + +### Assumptions: + +Atleast one trust anchor exists that issues the `Network Identity VC` to the foreign security domain DID, which is also trusted by the local security domain participants. + +The trust anchor is not malicious. + +### Possible Attacks: + +If the DID URI is incorrect as well as the trust anchor (s) used to validate `Network Identity VC` are malicous then the local security domain might configure a malicious network instead of the network it intended to interoperate with. + +### Limitations: + +For issuing a VC for a DID, as well as requisting VPs for a credential, service endpoints are required. Since the Network DID represents a blockchain network with a group controller of its participants, having a single service endpoint can lead to centralization in control of the credentials. + +In order to attest identity of a network, the trust anchor must validate the structure of the network as well as the identity of each of its participants. As a result, the availability of such trust anchors might be limited since such validation will often require physical verification of the agreements between the participants forming the network. + +## C. Participant Identity VC + +Without relying on the DID URI, in the unavailability of any trust basis attesting the identity of a foreign security domain directly, the identity of the individual network participants can be used to validate the Network DID. + +A Network DID must have attestations from all participants during creation, and each update must satisfy the update policy (see Network DID creation protocol). Therefore, a Network DID implies the agreement on network formation by the participants, and validating the participant identities is enough to validate the identity of the network as a whole. + +### Protocol: + +- Trust anchors issue `Identity VC` to the individual network participants. + +- For each foreign security domain participant specified in `networkMembers` of the Network DID, validate its identity thorugh `Identity VC` issued to them by trust anchor through the following steps: + + - Resolve the participant DID document from the DID. + - Get address of the participant's IIN agent from service endpoints in the DID document. ([DIDcomm](https://w3c.github.io/did-spec-registries/#didcommmessaging) service endpoint) + - [Optional] negotiate a trust anchor. + - Request `Identity VC`. + - Validate `Identity VC` + + +### Limitations: + +The protocol can only complete successfully if there are trust anchors available to validate the identity of the foreign security domain participants. Even after that, this protocol only ensures the validation of network formation by these participants. Therefore, an attack is possible by the subset of network participants of a larger network. + + +### Possible Attacks: + +Consider a hypothetical foreign security domain named "Supernet", with `N` participants. The Network DID of Supernet is `did:iin_indy:supernet`. A subset of `f < N` participants of Supernet are maliscious, and they create a Network DID with URI almost similar to "Supernet": `did:iin_indy:supernetwork`. Then, if the local security domain wanting to interoperate with Supernet somehow gets the wrong Network DID (for example through phishing), then the discovered Network DID document would be of the maliscious network. Here, validation through the identity validaiton of the particpants will also succeed. If none of `N-f` the non-maliscious participants of Supernet are known to the local security domain validators then the attack would be successful. From b81cbffd62bcb8364684d517c575ac452168c62f Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Thu, 8 Sep 2022 10:54:14 +0000 Subject: [PATCH 118/150] Added nonce addition and validation logic to IIN Agent attestations Signed-off-by: VRamakrishna --- common/protos-go/identity/agent.pb.go | 135 ++++++------ common/protos/identity/agent.proto | 13 +- .../contracts/interop/membership.go | 66 ++++-- .../contracts/interop/membership_test.go | 203 ++++++++++++++---- 4 files changed, 289 insertions(+), 128 deletions(-) diff --git a/common/protos-go/identity/agent.pb.go b/common/protos-go/identity/agent.pb.go index 1470acf79..22470194e 100644 --- a/common/protos-go/identity/agent.pb.go +++ b/common/protos-go/identity/agent.pb.go @@ -149,6 +149,7 @@ type Attestation struct { UnitIdentity *SecurityDomainMemberIdentity `protobuf:"bytes,1,opt,name=unit_identity,json=unitIdentity,proto3" json:"unit_identity,omitempty"` Certificate string `protobuf:"bytes,2,opt,name=certificate,proto3" json:"certificate,omitempty"` Signature string `protobuf:"bytes,3,opt,name=signature,proto3" json:"signature,omitempty"` + Nonce string `protobuf:"bytes,4,opt,name=nonce,proto3" json:"nonce,omitempty"` } func (x *Attestation) Reset() { @@ -204,13 +205,20 @@ func (x *Attestation) GetSignature() string { return "" } +func (x *Attestation) GetNonce() string { + if x != nil { + return x.Nonce + } + return "" +} + // Attested security domain membership by a single member type AttestedMembership struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Membership []byte `protobuf:"bytes,1,opt,name=membership,proto3" json:"membership,omitempty"` // 'common.membership.Membership' + Membership []byte `protobuf:"bytes,1,opt,name=membership,proto3" json:"membership,omitempty"` // 'common.membership.Membership': Base64-encoded Attestation *Attestation `protobuf:"bytes,2,opt,name=attestation,proto3" json:"attestation,omitempty"` } @@ -266,7 +274,7 @@ type CounterAttestedMembership struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - AttestedMembershipSet []byte `protobuf:"bytes,1,opt,name=attested_membership_set,json=attestedMembershipSet,proto3" json:"attested_membership_set,omitempty"` // 'AttestedMembershipSet' + AttestedMembershipSet []byte `protobuf:"bytes,1,opt,name=attested_membership_set,json=attestedMembershipSet,proto3" json:"attested_membership_set,omitempty"` // 'AttestedMembershipSet': Base64-encoded Attestations []*Attestation `protobuf:"bytes,2,rep,name=attestations,proto3" json:"attestations,omitempty"` } @@ -321,7 +329,7 @@ type CounterAttestedMembership_AttestedMembershipSet struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Membership []byte `protobuf:"bytes,1,opt,name=membership,proto3" json:"membership,omitempty"` // 'common.membership.Membership' + Membership []byte `protobuf:"bytes,1,opt,name=membership,proto3" json:"membership,omitempty"` // 'common.membership.Membership': Base64-encoded Attestations []*Attestation `protobuf:"bytes,2,rep,name=attestations,proto3" json:"attestations,omitempty"` } @@ -400,7 +408,7 @@ var file_identity_agent_proto_rawDesc = []byte{ 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x11, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0xa0, 0x01, 0x0a, 0x0b, 0x41, 0x74, 0x74, 0x65, + 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0xb6, 0x01, 0x0a, 0x0b, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x51, 0x0a, 0x0d, 0x75, 0x6e, 0x69, 0x74, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, @@ -410,68 +418,69 @@ var file_identity_agent_proto_rawDesc = []byte{ 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x73, 0x0a, 0x12, 0x41, 0x74, - 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, - 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, - 0x12, 0x3d, 0x0a, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, - 0x8e, 0x02, 0x0a, 0x19, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x41, 0x74, 0x74, 0x65, 0x73, - 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x36, 0x0a, - 0x17, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x68, 0x69, 0x70, 0x5f, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x15, - 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, - 0x69, 0x70, 0x53, 0x65, 0x74, 0x12, 0x3f, 0x0a, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, + 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, + 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, + 0x22, 0x73, 0x0a, 0x12, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x68, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x6d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x3d, 0x0a, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, + 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x8e, 0x02, 0x0a, 0x19, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, + 0x72, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, + 0x68, 0x69, 0x70, 0x12, 0x36, 0x0a, 0x17, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, + 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x5f, 0x73, 0x65, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x15, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, + 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x65, 0x74, 0x12, 0x3f, 0x0a, 0x0c, 0x61, + 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, + 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, + 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x78, 0x0a, 0x15, + 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, + 0x69, 0x70, 0x53, 0x65, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, + 0x68, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x3f, 0x0a, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x78, 0x0a, 0x15, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, - 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x65, 0x74, 0x12, - 0x1e, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, - 0x3f, 0x0a, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x32, 0xc1, 0x03, 0x0a, 0x08, 0x49, 0x49, 0x4e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x54, 0x0a, - 0x11, 0x53, 0x79, 0x6e, 0x63, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x12, 0x2c, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, - 0x69, 0x6e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, - 0x6b, 0x22, 0x00, 0x12, 0x66, 0x0a, 0x1c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, - 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, - 0x61, 0x69, 0x6e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x19, 0x53, - 0x65, 0x6e, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, - 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x1a, 0x0f, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, - 0x52, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, - 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x41, 0x74, - 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, - 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, - 0x6b, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x74, 0x74, 0x65, 0x73, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x41, - 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, - 0x70, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, - 0x63, 0x6b, 0x22, 0x00, 0x42, 0x75, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, - 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5a, 0x51, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, - 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, - 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, - 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, - 0x67, 0x6f, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0xc1, 0x03, 0x0a, 0x08, 0x49, 0x49, 0x4e, 0x41, 0x67, + 0x65, 0x6e, 0x74, 0x12, 0x54, 0x0a, 0x11, 0x53, 0x79, 0x6e, 0x63, 0x45, 0x78, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2c, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, + 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x66, 0x0a, 0x1c, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x2e, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, + 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, + 0x00, 0x12, 0x52, 0x0a, 0x19, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x22, + 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, + 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, + 0x69, 0x70, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, + 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x65, 0x72, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x0f, 0x53, 0x65, 0x6e, + 0x64, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x69, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x65, 0x72, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, 0x75, 0x0a, 0x20, 0x63, 0x6f, + 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5a, 0x51, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, + 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, + 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, + 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/common/protos/identity/agent.proto b/common/protos/identity/agent.proto index af72037fd..5e711070e 100644 --- a/common/protos/identity/agent.proto +++ b/common/protos/identity/agent.proto @@ -29,9 +29,9 @@ message SecurityDomainMemberIdentity { } message SecurityDomainMemberIdentityRequest { - SecurityDomainMemberIdentity source_network = 1; - SecurityDomainMemberIdentity requesting_network = 2; - string nonce = 3; + SecurityDomainMemberIdentity source_network = 1; + SecurityDomainMemberIdentity requesting_network = 2; + string nonce = 3; } // Association of signature (over arbitrary data) and signer identity @@ -39,20 +39,21 @@ message Attestation { SecurityDomainMemberIdentity unit_identity = 1; string certificate = 2; string signature = 3; + string nonce = 4; } // Attested security domain membership by a single member message AttestedMembership { - bytes membership = 1; // 'common.membership.Membership' + bytes membership = 1; // 'common.membership.Membership': Base64-encoded Attestation attestation = 2; } // Counter attestation over security domain membership attested by its participants message CounterAttestedMembership { message AttestedMembershipSet { - bytes membership = 1; // 'common.membership.Membership' + bytes membership = 1; // 'common.membership.Membership': Base64-encoded repeated Attestation attestations = 2; } - bytes attested_membership_set = 1; // 'AttestedMembershipSet' + bytes attested_membership_set = 1; // 'AttestedMembershipSet': Base64-encoded repeated Attestation attestations = 2; } diff --git a/core/network/fabric-interop-cc/contracts/interop/membership.go b/core/network/fabric-interop-cc/contracts/interop/membership.go index 2f6975363..ba1a3ae1a 100644 --- a/core/network/fabric-interop-cc/contracts/interop/membership.go +++ b/core/network/fabric-interop-cc/contracts/interop/membership.go @@ -201,27 +201,47 @@ func (s *SmartContract) CreateMembership(ctx contractapi.TransactionContextInter } err = checkUserInMembership(callerCert, membershipLocalDecoded) if err != nil { - return fmt.Errorf("Caller with identity %+v is not a designated IIN Agent: %+v", callerId, err) + return fmt.Errorf("Caller with identity %+v is not a designated IIN Agent: %+v", callerId, err) } counterAttestedMembership, err := decodeCounterAttestedMembership([]byte(counterAttestedMembershipJSON)) if err != nil { return fmt.Errorf("Counter Attested Membership Unmarshal error: %s", err) } + decodedAttestedMembershipSet, err := base64.StdEncoding.DecodeString(string(counterAttestedMembership.AttestedMembershipSet)) + if err != nil { + return fmt.Errorf("Attested membership set could not be decoded from base64: %s", err.Error()) + } var attestedMembershipSet identity.CounterAttestedMembership_AttestedMembershipSet - err = protoV2.Unmarshal(counterAttestedMembership.AttestedMembershipSet, &attestedMembershipSet) + err = protoV2.Unmarshal(decodedAttestedMembershipSet, &attestedMembershipSet) if err != nil { return fmt.Errorf("Unable to unmarshal attested membership set: %s", err.Error()) } + decodedForeignMembership, err := base64.StdEncoding.DecodeString(string(attestedMembershipSet.Membership)) + if err != nil { + return fmt.Errorf("Foreign membership could not be decoded from base64: %s", err.Error()) + } var foreignMembership common.Membership - err = protoV2.Unmarshal(attestedMembershipSet.Membership, &foreignMembership) + err = protoV2.Unmarshal(decodedForeignMembership, &foreignMembership) if err != nil { return fmt.Errorf("Unable to unmarshal membership: %s", err.Error()) } + // Match nonces across all attestations, local and foreign + matchedNonce := "" + for _, attestation := range append(counterAttestedMembership.Attestations, attestedMembershipSet.Attestations...) { + if matchedNonce == "" { + matchedNonce = attestation.Nonce + } else { + if matchedNonce != attestation.Nonce { + return fmt.Errorf("Mismatched nonces across two attestations: %s, %s", matchedNonce, attestation.Nonce) + } + } + } + // Ensure valid attestations from all local IIN Agents for _, attestation := range counterAttestedMembership.Attestations { - err = validateAttestation(attestation, counterAttestedMembership.AttestedMembershipSet) + err = validateAttestation(attestation, append(counterAttestedMembership.AttestedMembershipSet, attestation.Nonce...)) if err != nil { return err } @@ -239,7 +259,7 @@ func (s *SmartContract) CreateMembership(ctx contractapi.TransactionContextInter return fmt.Errorf("Foreign agent security domain %s does not match attested membership security domain %s", attestation.UnitIdentity.SecurityDomain, foreignMembership.SecurityDomain) } - foundMemberMatch := false + foundMemberMatch := false for _, member := range foreignMembership.Members { var isSignerRoot bool var leafCertPEM string @@ -268,7 +288,7 @@ func (s *SmartContract) CreateMembership(ctx contractapi.TransactionContextInter return fmt.Errorf("No matching member certificate chain found for attester") } // Validate signature - err = validateAttestation(attestation, attestedMembershipSet.Membership) + err = validateAttestation(attestation, append(attestedMembershipSet.Membership, attestation.Nonce...)) if err != nil { return err } @@ -315,27 +335,47 @@ func (s *SmartContract) UpdateMembership(ctx contractapi.TransactionContextInter } err = checkUserInMembership(callerCert, membershipLocalDecoded) if err != nil { - return fmt.Errorf("Caller with identity %+v is not a designated IIN Agent: %+v", callerId, err) + return fmt.Errorf("Caller with identity %+v is not a designated IIN Agent: %+v", callerId, err) } counterAttestedMembership, err := decodeCounterAttestedMembership([]byte(counterAttestedMembershipJSON)) if err != nil { - return fmt.Errorf("Unmarshal error: %s", err) + return fmt.Errorf("Counter Attested Membership Unmarshal error: %s", err) + } + decodedAttestedMembershipSet, err := base64.StdEncoding.DecodeString(string(counterAttestedMembership.AttestedMembershipSet)) + if err != nil { + return fmt.Errorf("Attested membership set could not be decoded from base64: %s", err.Error()) } var attestedMembershipSet identity.CounterAttestedMembership_AttestedMembershipSet - err = protoV2.Unmarshal(counterAttestedMembership.AttestedMembershipSet, &attestedMembershipSet) + err = protoV2.Unmarshal(decodedAttestedMembershipSet, &attestedMembershipSet) if err != nil { return fmt.Errorf("Unable to unmarshal attested membership set: %s", err.Error()) } + decodedForeignMembership, err := base64.StdEncoding.DecodeString(string(attestedMembershipSet.Membership)) + if err != nil { + return fmt.Errorf("Foreign membership could not be decoded from base64: %s", err.Error()) + } var foreignMembership common.Membership - err = protoV2.Unmarshal(attestedMembershipSet.Membership, &foreignMembership) + err = protoV2.Unmarshal(decodedForeignMembership, &foreignMembership) if err != nil { return fmt.Errorf("Unable to unmarshal membership: %s", err.Error()) } + // Match nonces across all attestations, local and foreign + matchedNonce := "" + for _, attestation := range append(counterAttestedMembership.Attestations, attestedMembershipSet.Attestations...) { + if matchedNonce == "" { + matchedNonce = attestation.Nonce + } else { + if matchedNonce != attestation.Nonce { + return fmt.Errorf("Mismatched nonces across two attestations: %s, %s", matchedNonce, attestation.Nonce) + } + } + } + // Ensure valid attestations from all local IIN Agents for _, attestation := range counterAttestedMembership.Attestations { - err = validateAttestation(attestation, counterAttestedMembership.AttestedMembershipSet) + err = validateAttestation(attestation, append(counterAttestedMembership.AttestedMembershipSet, attestation.Nonce...)) if err != nil { return err } @@ -353,7 +393,7 @@ func (s *SmartContract) UpdateMembership(ctx contractapi.TransactionContextInter return fmt.Errorf("Foreign agent security domain %s does not match attested membership security domain %s", attestation.UnitIdentity.SecurityDomain, foreignMembership.SecurityDomain) } - foundMemberMatch := false + foundMemberMatch := false for _, member := range foreignMembership.Members { var isSignerRoot bool var leafCertPEM string @@ -382,7 +422,7 @@ func (s *SmartContract) UpdateMembership(ctx contractapi.TransactionContextInter return fmt.Errorf("No matching member certificate chain found for attester") } // Validate signature - err = validateAttestation(attestation, attestedMembershipSet.Membership) + err = validateAttestation(attestation, append(attestedMembershipSet.Membership, attestation.Nonce...)) if err != nil { return err } diff --git a/core/network/fabric-interop-cc/contracts/interop/membership_test.go b/core/network/fabric-interop-cc/contracts/interop/membership_test.go index 737430ed4..253259888 100644 --- a/core/network/fabric-interop-cc/contracts/interop/membership_test.go +++ b/core/network/fabric-interop-cc/contracts/interop/membership_test.go @@ -36,6 +36,7 @@ var foreignMemberId2 = "foreign-member2" var localSecurityDomainId = "6789" var localMemberId1 = "local-member1" var localMemberId2 = "local-member2" +var nonce = "nonce" func getMembership() (common.Member, common.Member) { member1 := common.Member{ @@ -316,6 +317,7 @@ func TestCreateMembership(t *testing.T) { }, Certificate: certPem1, Signature: "", + Nonce: nonce, } // Generate foreign network member 2 CA structure and client credentials certChain2, keys2, _ := generateCertChain(3) @@ -331,20 +333,24 @@ func TestCreateMembership(t *testing.T) { }, Certificate: certPem2, Signature: "", + Nonce: nonce, } // Marshal membership for signature - membershipBytes, err := protoV2.Marshal(&membershipAsset) + membershipBytesPlain, err := protoV2.Marshal(&membershipAsset) require.NoError(t, err) + membershipBytesStr := base64.StdEncoding.EncodeToString(membershipBytesPlain) + membershipBytes := []byte(membershipBytesStr) + membershipBytesWithNonce := []byte(membershipBytesStr + nonce) // Generate member 2 attestation random1 := rand.Reader - hashed1, err := computeSHA2Hash(membershipBytes, key1.PublicKey.Params().BitSize) + hashed1, err := computeSHA2Hash(membershipBytesWithNonce, key1.PublicKey.Params().BitSize) require.NoError(t, err) signature1, err := ecdsa.SignASN1(random1, key1, hashed1) require.NoError(t, err) attestation1.Signature = base64.StdEncoding.EncodeToString(signature1) // Generate member 2 attestation random2 := rand.Reader - hashed2, err := computeSHA2Hash(membershipBytes, key2.PublicKey.Params().BitSize) + hashed2, err := computeSHA2Hash(membershipBytesWithNonce, key2.PublicKey.Params().BitSize) require.NoError(t, err) signature2, err := ecdsa.SignASN1(random2, key2, hashed2) require.NoError(t, err) @@ -385,6 +391,7 @@ func TestCreateMembership(t *testing.T) { }, Certificate: certLocalPem1, Signature: "", + Nonce: nonce, } decodedLocalCert2, _ := pem.Decode([]byte(localCertChain2[2])) certLocal2, _ := x509.ParseCertificate(decodedLocalCert2.Bytes) @@ -397,20 +404,24 @@ func TestCreateMembership(t *testing.T) { }, Certificate: certLocalPem2, Signature: "", + Nonce: nonce, } // Marshal attested membership set for signature - attestedMembershipSetBytes, err := protoV2.Marshal(&attestedMembershipSet) + attestedMembershipSetBytesPlain, err := protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) + attestedMembershipSetBytesStr := base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) + attestedMembershipSetBytes := []byte(attestedMembershipSetBytesStr) + attestedMembershipSetBytesWithNonce := []byte(attestedMembershipSetBytesStr + nonce) // Generate member 2 attestation randomLocal1 := rand.Reader - hashedLocal1, err := computeSHA2Hash(attestedMembershipSetBytes, keyLocal1.PublicKey.Params().BitSize) + hashedLocal1, err := computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) require.NoError(t, err) signatureLocal1, err := ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) require.NoError(t, err) attestationLocal1.Signature = base64.StdEncoding.EncodeToString(signatureLocal1) // Generate member 2 attestation randomLocal2 := rand.Reader - hashedLocal2, err := computeSHA2Hash(attestedMembershipSetBytes, keyLocal2.PublicKey.Params().BitSize) + hashedLocal2, err := computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal2.PublicKey.Params().BitSize) require.NoError(t, err) signatureLocal2, err := ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) require.NoError(t, err) @@ -475,14 +486,17 @@ func TestCreateMembership(t *testing.T) { signature2, err = ecdsa.SignASN1(random2, key2, hashed2) require.NoError(t, err) attestation2.Signature = base64.StdEncoding.EncodeToString(signature2) - attestedMembershipSetBytes, err = protoV2.Marshal(&attestedMembershipSet) + attestedMembershipSetBytesPlain, err = protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) - hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytes, keyLocal1.PublicKey.Params().BitSize) + attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) + attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) + attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) + hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) require.NoError(t, err) signatureLocal1, err = ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) require.NoError(t, err) attestationLocal1.Signature = base64.StdEncoding.EncodeToString(signatureLocal1) - hashedLocal2, err = computeSHA2Hash(attestedMembershipSetBytes, keyLocal2.PublicKey.Params().BitSize) + hashedLocal2, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal2.PublicKey.Params().BitSize) require.NoError(t, err) signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) require.NoError(t, err) @@ -494,31 +508,67 @@ func TestCreateMembership(t *testing.T) { err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, "Unable to Validate Signature: Signature Verification failed. ECDSA VERIFY") + // One of the foreign attestations has an invalid nonce: should fail + hashed2, err = computeSHA2Hash(membershipBytesWithNonce, key2.PublicKey.Params().BitSize) + require.NoError(t, err) + signature2, err = ecdsa.SignASN1(random2, key2, hashed2) + require.NoError(t, err) + attestation2.Signature = base64.StdEncoding.EncodeToString(signature2) + attestation1.Nonce = "invalid-nonce" + attestedMembershipSetBytesPlain, err = protoV2.Marshal(&attestedMembershipSet) + require.NoError(t, err) + attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) + attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) + attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) + hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) + require.NoError(t, err) + signatureLocal1, err = ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) + require.NoError(t, err) + attestationLocal1.Signature = base64.StdEncoding.EncodeToString(signatureLocal1) + hashedLocal2, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal2.PublicKey.Params().BitSize) + require.NoError(t, err) + signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) + require.NoError(t, err) + attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) + counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes + counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) + require.NoError(t, err) + chaincodeStub.GetStateReturnsOnCall(8, localMembershipBytes, nil) + err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + require.EqualError(t, err, fmt.Sprintf("Mismatched nonces across two attestations: %s, %s", nonce, attestation1.Nonce)) + // Foreign membership has an invalid cert chain: should fail + attestation1.Nonce = nonce tmpCert := member1.Chain[0] member1.Chain[0] = member1.Chain[1] member1.Chain[1] = tmpCert - membershipBytes, err = protoV2.Marshal(&membershipAsset) + membershipBytesPlain, err = protoV2.Marshal(&membershipAsset) require.NoError(t, err) - hashed1, err = computeSHA2Hash(membershipBytes, key1.PublicKey.Params().BitSize) + membershipBytesStr = base64.StdEncoding.EncodeToString(membershipBytesPlain) + membershipBytes = []byte(membershipBytesStr) + membershipBytesWithNonce = []byte(membershipBytesStr + nonce) + hashed1, err = computeSHA2Hash(membershipBytesWithNonce, key1.PublicKey.Params().BitSize) require.NoError(t, err) signature1, err = ecdsa.SignASN1(random1, key1, hashed1) require.NoError(t, err) attestation1.Signature = base64.StdEncoding.EncodeToString(signature1) - hashed2, err = computeSHA2Hash(membershipBytes, key2.PublicKey.Params().BitSize) + hashed2, err = computeSHA2Hash(membershipBytesWithNonce, key2.PublicKey.Params().BitSize) require.NoError(t, err) signature2, err = ecdsa.SignASN1(random2, key2, hashed2) require.NoError(t, err) attestation2.Signature = base64.StdEncoding.EncodeToString(signature2) attestedMembershipSet.Membership = membershipBytes - attestedMembershipSetBytes, err = protoV2.Marshal(&attestedMembershipSet) + attestedMembershipSetBytesPlain, err = protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) - hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytes, keyLocal1.PublicKey.Params().BitSize) + attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) + attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) + attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) + hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) require.NoError(t, err) signatureLocal1, err = ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) require.NoError(t, err) attestationLocal1.Signature = base64.StdEncoding.EncodeToString(signatureLocal1) - hashedLocal2, err = computeSHA2Hash(attestedMembershipSetBytes, keyLocal2.PublicKey.Params().BitSize) + hashedLocal2, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal2.PublicKey.Params().BitSize) require.NoError(t, err) signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) require.NoError(t, err) @@ -526,7 +576,7 @@ func TestCreateMembership(t *testing.T) { counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) require.NoError(t, err) - chaincodeStub.GetStateReturnsOnCall(8, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(9, localMembershipBytes, nil) err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) require.Error(t, err) @@ -535,27 +585,33 @@ func TestCreateMembership(t *testing.T) { member1.Chain[0] = member1.Chain[1] member1.Chain[1] = tmpCert membershipAsset.SecurityDomain = "invalid" - membershipBytes, err = protoV2.Marshal(&membershipAsset) + membershipBytesPlain, err = protoV2.Marshal(&membershipAsset) require.NoError(t, err) - hashed1, err = computeSHA2Hash(membershipBytes, key1.PublicKey.Params().BitSize) + membershipBytesStr = base64.StdEncoding.EncodeToString(membershipBytesPlain) + membershipBytes = []byte(membershipBytesStr) + membershipBytesWithNonce = []byte(membershipBytesStr + nonce) + hashed1, err = computeSHA2Hash(membershipBytesWithNonce, key1.PublicKey.Params().BitSize) require.NoError(t, err) signature1, err = ecdsa.SignASN1(random1, key1, hashed1) require.NoError(t, err) attestation1.Signature = base64.StdEncoding.EncodeToString(signature1) - hashed2, err = computeSHA2Hash(membershipBytes, key2.PublicKey.Params().BitSize) + hashed2, err = computeSHA2Hash(membershipBytesWithNonce, key2.PublicKey.Params().BitSize) require.NoError(t, err) signature2, err = ecdsa.SignASN1(random2, key2, hashed2) require.NoError(t, err) attestation2.Signature = base64.StdEncoding.EncodeToString(signature2) attestedMembershipSet.Membership = membershipBytes - attestedMembershipSetBytes, err = protoV2.Marshal(&attestedMembershipSet) + attestedMembershipSetBytesPlain, err = protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) - hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytes, keyLocal1.PublicKey.Params().BitSize) + attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) + attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) + attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) + hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) require.NoError(t, err) signatureLocal1, err = ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) require.NoError(t, err) attestationLocal1.Signature = base64.StdEncoding.EncodeToString(signatureLocal1) - hashedLocal2, err = computeSHA2Hash(attestedMembershipSetBytes, keyLocal2.PublicKey.Params().BitSize) + hashedLocal2, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal2.PublicKey.Params().BitSize) require.NoError(t, err) signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) require.NoError(t, err) @@ -563,7 +619,7 @@ func TestCreateMembership(t *testing.T) { counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) require.NoError(t, err) - chaincodeStub.GetStateReturnsOnCall(9, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(10, localMembershipBytes, nil) err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, fmt.Sprintf("Foreign agent security domain %s does not match attested membership security domain invalid", securityDomainId)) } @@ -592,6 +648,7 @@ func TestUpdateMembership(t *testing.T) { }, Certificate: certPem1, Signature: "", + Nonce: nonce, } // Generate foreign network member 2 CA structure and client credentials certChain2, keys2, _ := generateCertChain(3) @@ -607,20 +664,24 @@ func TestUpdateMembership(t *testing.T) { }, Certificate: certPem2, Signature: "", + Nonce: nonce, } // Marshal membership for signature - membershipBytes, err := protoV2.Marshal(&membershipAsset) + membershipBytesPlain, err := protoV2.Marshal(&membershipAsset) require.NoError(t, err) + membershipBytesStr := base64.StdEncoding.EncodeToString(membershipBytesPlain) + membershipBytes := []byte(membershipBytesStr) + membershipBytesWithNonce := []byte(membershipBytesStr + nonce) // Generate member 2 attestation random1 := rand.Reader - hashed1, err := computeSHA2Hash(membershipBytes, key1.PublicKey.Params().BitSize) + hashed1, err := computeSHA2Hash(membershipBytesWithNonce, key1.PublicKey.Params().BitSize) require.NoError(t, err) signature1, err := ecdsa.SignASN1(random1, key1, hashed1) require.NoError(t, err) attestation1.Signature = base64.StdEncoding.EncodeToString(signature1) // Generate member 2 attestation random2 := rand.Reader - hashed2, err := computeSHA2Hash(membershipBytes, key2.PublicKey.Params().BitSize) + hashed2, err := computeSHA2Hash(membershipBytesWithNonce, key2.PublicKey.Params().BitSize) require.NoError(t, err) signature2, err := ecdsa.SignASN1(random2, key2, hashed2) require.NoError(t, err) @@ -661,6 +722,7 @@ func TestUpdateMembership(t *testing.T) { }, Certificate: certLocalPem1, Signature: "", + Nonce: nonce, } decodedLocalCert2, _ := pem.Decode([]byte(localCertChain2[2])) certLocal2, _ := x509.ParseCertificate(decodedLocalCert2.Bytes) @@ -673,20 +735,24 @@ func TestUpdateMembership(t *testing.T) { }, Certificate: certLocalPem2, Signature: "", + Nonce: nonce, } // Marshal attested membership set for signature - attestedMembershipSetBytes, err := protoV2.Marshal(&attestedMembershipSet) + attestedMembershipSetBytesPlain, err := protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) + attestedMembershipSetBytesStr := base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) + attestedMembershipSetBytes := []byte(attestedMembershipSetBytesStr) + attestedMembershipSetBytesWithNonce := []byte(attestedMembershipSetBytesStr + nonce) // Generate member 2 attestation randomLocal1 := rand.Reader - hashedLocal1, err := computeSHA2Hash(attestedMembershipSetBytes, keyLocal1.PublicKey.Params().BitSize) + hashedLocal1, err := computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) require.NoError(t, err) signatureLocal1, err := ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) require.NoError(t, err) attestationLocal1.Signature = base64.StdEncoding.EncodeToString(signatureLocal1) // Generate member 2 attestation randomLocal2 := rand.Reader - hashedLocal2, err := computeSHA2Hash(attestedMembershipSetBytes, keyLocal2.PublicKey.Params().BitSize) + hashedLocal2, err := computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal2.PublicKey.Params().BitSize) require.NoError(t, err) signatureLocal2, err := ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) require.NoError(t, err) @@ -751,14 +817,17 @@ func TestUpdateMembership(t *testing.T) { signature2, err = ecdsa.SignASN1(random2, key2, hashed2) require.NoError(t, err) attestation2.Signature = base64.StdEncoding.EncodeToString(signature2) - attestedMembershipSetBytes, err = protoV2.Marshal(&attestedMembershipSet) + attestedMembershipSetBytesPlain, err = protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) - hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytes, keyLocal1.PublicKey.Params().BitSize) + attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) + attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) + attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) + hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) require.NoError(t, err) signatureLocal1, err = ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) require.NoError(t, err) attestationLocal1.Signature = base64.StdEncoding.EncodeToString(signatureLocal1) - hashedLocal2, err = computeSHA2Hash(attestedMembershipSetBytes, keyLocal2.PublicKey.Params().BitSize) + hashedLocal2, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal2.PublicKey.Params().BitSize) require.NoError(t, err) signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) require.NoError(t, err) @@ -770,31 +839,67 @@ func TestUpdateMembership(t *testing.T) { err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, "Unable to Validate Signature: Signature Verification failed. ECDSA VERIFY") + // One of the foreign attestations has an invalid nonce: should fail + hashed2, err = computeSHA2Hash(membershipBytesWithNonce, key2.PublicKey.Params().BitSize) + require.NoError(t, err) + signature2, err = ecdsa.SignASN1(random2, key2, hashed2) + require.NoError(t, err) + attestation2.Signature = base64.StdEncoding.EncodeToString(signature2) + attestation1.Nonce = "invalid-nonce" + attestedMembershipSetBytesPlain, err = protoV2.Marshal(&attestedMembershipSet) + require.NoError(t, err) + attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) + attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) + attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) + hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) + require.NoError(t, err) + signatureLocal1, err = ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) + require.NoError(t, err) + attestationLocal1.Signature = base64.StdEncoding.EncodeToString(signatureLocal1) + hashedLocal2, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal2.PublicKey.Params().BitSize) + require.NoError(t, err) + signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) + require.NoError(t, err) + attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) + counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes + counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) + require.NoError(t, err) + chaincodeStub.GetStateReturnsOnCall(8, localMembershipBytes, nil) + err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + require.EqualError(t, err, fmt.Sprintf("Mismatched nonces across two attestations: %s, %s", nonce, attestation1.Nonce)) + // Foreign membership has an invalid cert chain: should fail + attestation1.Nonce = nonce tmpCert := member1.Chain[0] member1.Chain[0] = member1.Chain[1] member1.Chain[1] = tmpCert - membershipBytes, err = protoV2.Marshal(&membershipAsset) + membershipBytesPlain, err = protoV2.Marshal(&membershipAsset) require.NoError(t, err) - hashed1, err = computeSHA2Hash(membershipBytes, key1.PublicKey.Params().BitSize) + membershipBytesStr = base64.StdEncoding.EncodeToString(membershipBytesPlain) + membershipBytes = []byte(membershipBytesStr) + membershipBytesWithNonce = []byte(membershipBytesStr + nonce) + hashed1, err = computeSHA2Hash(membershipBytesWithNonce, key1.PublicKey.Params().BitSize) require.NoError(t, err) signature1, err = ecdsa.SignASN1(random1, key1, hashed1) require.NoError(t, err) attestation1.Signature = base64.StdEncoding.EncodeToString(signature1) - hashed2, err = computeSHA2Hash(membershipBytes, key2.PublicKey.Params().BitSize) + hashed2, err = computeSHA2Hash(membershipBytesWithNonce, key2.PublicKey.Params().BitSize) require.NoError(t, err) signature2, err = ecdsa.SignASN1(random2, key2, hashed2) require.NoError(t, err) attestation2.Signature = base64.StdEncoding.EncodeToString(signature2) attestedMembershipSet.Membership = membershipBytes - attestedMembershipSetBytes, err = protoV2.Marshal(&attestedMembershipSet) + attestedMembershipSetBytesPlain, err = protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) - hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytes, keyLocal1.PublicKey.Params().BitSize) + attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) + attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) + attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) + hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) require.NoError(t, err) signatureLocal1, err = ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) require.NoError(t, err) attestationLocal1.Signature = base64.StdEncoding.EncodeToString(signatureLocal1) - hashedLocal2, err = computeSHA2Hash(attestedMembershipSetBytes, keyLocal2.PublicKey.Params().BitSize) + hashedLocal2, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal2.PublicKey.Params().BitSize) require.NoError(t, err) signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) require.NoError(t, err) @@ -802,7 +907,7 @@ func TestUpdateMembership(t *testing.T) { counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) require.NoError(t, err) - chaincodeStub.GetStateReturnsOnCall(8, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(9, localMembershipBytes, nil) err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) require.Error(t, err) @@ -811,27 +916,33 @@ func TestUpdateMembership(t *testing.T) { member1.Chain[0] = member1.Chain[1] member1.Chain[1] = tmpCert membershipAsset.SecurityDomain = "invalid" - membershipBytes, err = protoV2.Marshal(&membershipAsset) + membershipBytesPlain, err = protoV2.Marshal(&membershipAsset) require.NoError(t, err) - hashed1, err = computeSHA2Hash(membershipBytes, key1.PublicKey.Params().BitSize) + membershipBytesStr = base64.StdEncoding.EncodeToString(membershipBytesPlain) + membershipBytes = []byte(membershipBytesStr) + membershipBytesWithNonce = []byte(membershipBytesStr + nonce) + hashed1, err = computeSHA2Hash(membershipBytesWithNonce, key1.PublicKey.Params().BitSize) require.NoError(t, err) signature1, err = ecdsa.SignASN1(random1, key1, hashed1) require.NoError(t, err) attestation1.Signature = base64.StdEncoding.EncodeToString(signature1) - hashed2, err = computeSHA2Hash(membershipBytes, key2.PublicKey.Params().BitSize) + hashed2, err = computeSHA2Hash(membershipBytesWithNonce, key2.PublicKey.Params().BitSize) require.NoError(t, err) signature2, err = ecdsa.SignASN1(random2, key2, hashed2) require.NoError(t, err) attestation2.Signature = base64.StdEncoding.EncodeToString(signature2) attestedMembershipSet.Membership = membershipBytes - attestedMembershipSetBytes, err = protoV2.Marshal(&attestedMembershipSet) + attestedMembershipSetBytesPlain, err = protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) - hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytes, keyLocal1.PublicKey.Params().BitSize) + attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) + attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) + attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) + hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) require.NoError(t, err) signatureLocal1, err = ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) require.NoError(t, err) attestationLocal1.Signature = base64.StdEncoding.EncodeToString(signatureLocal1) - hashedLocal2, err = computeSHA2Hash(attestedMembershipSetBytes, keyLocal2.PublicKey.Params().BitSize) + hashedLocal2, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal2.PublicKey.Params().BitSize) require.NoError(t, err) signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) require.NoError(t, err) @@ -839,7 +950,7 @@ func TestUpdateMembership(t *testing.T) { counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) require.NoError(t, err) - chaincodeStub.GetStateReturnsOnCall(9, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(10, localMembershipBytes, nil) err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, fmt.Sprintf("Foreign agent security domain %s does not match attested membership security domain invalid", securityDomainId)) } From ec46d8917d7a95c2ea65eda79156b9a7061bdf0c Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Thu, 8 Sep 2022 11:48:44 +0000 Subject: [PATCH 119/150] Finished updating terminology in Identity Protocol RFCs Signed-off-by: VRamakrishna --- .../security-domain-identity-validation.md | 70 +++++++++---------- 1 file changed, 33 insertions(+), 37 deletions(-) diff --git a/rfcs/protocols/identity/security-domain-identity-validation.md b/rfcs/protocols/identity/security-domain-identity-validation.md index 7c5736ed7..fa3ceae50 100644 --- a/rfcs/protocols/identity/security-domain-identity-validation.md +++ b/rfcs/protocols/identity/security-domain-identity-validation.md @@ -20,84 +20,80 @@ The three security domain identity validation protocols, each built on a differe > Note: The common assumption in all these protocols is that the IIN DID registry is not malicious. Given a DLT-based IIN which allows anyone to monitor the ledger, any IIN agent can validate the authenticity of a Security Domain DID by auditing DID create/updtate transactions recorded on the ledger. -## A. Well Known Network DID +## A. Well Known Security Domain DID -A Network DID registered in an IIN DID registry (IIN ledger) is controlled by the group controller specified by the `networkMembers` and `BlockchainNetworkMultiSig` verification method. Thus, provided that the IIN registry is not compromised, the Network DID document will remain under the control of its creators. Even if the network structure changes with members joining and leaving, the `updatePolicy` ensures that the stakeholders of the network remain in control of the Network DID. Therefore, given that the local security domain knows the Network DID of the foreign security domain it wants to interoperate with, there is no need for explicit validation of the Network DID document. +A Security Domain DID registered in an IIN DID registry (IIN ledger) is maintained by a group controller, with the members of the groups and their authentication methods specified in the `networkMembers` and `BlockchainNetworkMultiSig` verification method attributes respectively. Thus, provided that the IIN registry is not compromised, the Security Domain DID document will remain under the control of its creators. Even if the network structure of the domain changes with members joining and leaving, the `updatePolicy` ensures that the network's members remain in control of the Security Domain DID. To interoperate with another security domain, all that domain needs to have is a reference to this Security Domain DID with embedded validation logic. No other external validation need be done on that DID document. ### Protocol: -Step 1. Local network participants obtain the foreign security domain's Network DID from some trusted source. The trusted source of the Network DID may be offline physical interaction directly with the foreign security domain, or some well known webpage for the network, or something else. +Step 1. Local security domain members obtain the foreign security domain's DID from a well-known or trusted source (e.g., a secure website or web service or database maintained by a public authority). -Step 2. Through the [discovery protocol](../discovery/readme.md), the local security domain participant's IIN agent obtains the Network DID document. +Step 2. Through the [discovery protocol](../discovery/doscovery.md), any of the local security domain's members' IIN agents obtains the Security Domain DID document. ### Assumptions: - - The source from which the Network DID URI is obtained is trusted. This source is the trust basis. +- The source from which the Security Domain DID URI is obtained is well-known or trusted. Therefore, that source, or its reputation, is the trust basis. ### Possible Attacks: -- Since the IIN is open to accepting DID registrations from anyone, a Network DID can be created by with similar URIs by attackers. Therefore, through phishing attacks and compromising the DID URI sources such as websites, the original Network DID might be replaced with a malicious one. Without further validations, the local security domain starts interoperation with the attacker's network. +- Since the IIN is open to accepting DID registrations from anyone, a genuine-looking Security Domain DID (i.e., a URI) can be created by attackers (masquerading as genuine network members). Therefore, using phishing attacks and compromising DID URI sources (like websites), the discovery process might lead to a fake Security Domain DID. In the absence of other validation of this DID, the local security domain will start to interoperate with the attacker's network. ### Limitations: -- The source of the Network DID itself can be considered as a trust basis only for well known networks. Moreover, the security of the source such as a webpage is also a factor in the security of this protocol. For smaller networks whose webpage or some other well known source of obtaining the Network DID is not available, relying to this level of validation only is enough. +- For well-known networks, the reputation of the DID source itself is a sufficient trust basis. The discovery process should take the possibility of the source being attacked/compromised into account using standard network security mechanisms. +- For smaller or lesser-known networks, the IDD source may or may not require additional validation. We do not mandate this; it is left to the interoperating network to decide. As with a more well-known DID source, attack/compromise should be take into account. +## B. Security Domain Identity Verifiable Credential (VC) - - -## B. Network Identity VC - -The Network DID document is implicitely not tied to any physical identity. Thus after discovery, the obtained Network DID document has to be validated based on some trust basis. For this validation the local security domain participants may rely on some [trust anchors](../../models/identity/iin.md). These trust anchors attest the physical identity of a Network DID by issuing VC. For example, for the DID `did:iin_indy:tradelensnetwork`, a trust anchor would attest that the DID is the Network DID for the network named "TradeLens", and optionally provide additional information like the name and address of the organizations involving the network. +The Security Domain DID document is not explicitly tied to any real world identity (nor implicitly in many DID registries, though Hyperledger Indy enables such an association when desired by the DID owners). Thus, after discovery, the obtained Security Domain DID document has to be validated using some trust basis. For this validation, the local security domain's members may rely on [trust anchors](../../models/identity/iin.md). These trust anchors attest the association of a Security Domain DID with a real world identity by issuing a VC to that DID. For example, for the DID `did:iin_indy:tradelensnetwork`, a trust anchor would attest to it belonging to the network named "TradeLens", and optionally provide additional information about the [TradeLens network](https://www.tradelens.com), like the names and addresses of the organizations that are its members. ### Protocol: -Step 1. Trust anchor issues a verifiable credential to the Network DID. This VC attests the identity of the network as a whole, called `Network Identity VC`. +Step 1. Trust anchor issues a verifiable credential to the Security Domain DID. This VC attests the identity of the security domain as a whole, called `Security Domain Identity VC`. -Step 2. From the Network DID document, local security domain participant obtains the service endpoint for requesting VCs ([DIDcomm](https://w3c.github.io/did-spec-registries/#didcommmessaging)). +Step 2. After a local security domain's member has discovered and fetched a foreign security domain's DID, it looks up a service endpoint from that DID document from which VCs can be requested (see the [DIDcomm](https://w3c.github.io/did-spec-registries/#didcommmessaging) mechanism for details). -Step 3. Local netowrk participant requests `Network Identity VC` +Step 3. Local security domain member requests `Security Domain Identity VC` -Step 4. The verifiable presentation obtained in response from the network service endoint is validated. +Step 4. The verifiable presentation (VP) obtained in response from the security domain's network's service endoint is validated. This concludes the attestation and validation of a security domain (i.e., group of members). ### Assumptions: -Atleast one trust anchor exists that issues the `Network Identity VC` to the foreign security domain DID, which is also trusted by the local security domain participants. +At least one trust anchor exists that both: +1. Issues a `Security Domain Identity VC` to a foreign security domain's DID, and +2. Is trusted by the local security domain's members. -The trust anchor is not malicious. +The trust anchor does not behave maliciously. ### Possible Attacks: -If the DID URI is incorrect as well as the trust anchor (s) used to validate `Network Identity VC` are malicous then the local security domain might configure a malicious network instead of the network it intended to interoperate with. +If the DID URI is incorrect (or fake) AND the trust anchor(s) used to request a `Security Domain Identity VC` from are malicouis, the local security domain will end up syncing the membership of a different (possibly fake) network instead of the network it intended to interoperate with. ### Limitations: -For issuing a VC for a DID, as well as requisting VPs for a credential, service endpoints are required. Since the Network DID represents a blockchain network with a group controller of its participants, having a single service endpoint can lead to centralization in control of the credentials. +Every DID owner needs service endpoints to issue a VC against its DID and to serve VP requests for a given credential. Since the Security Domain DID represents a blockchain/DLT network with a group controller collectively maintained by its members, having a single service endpoint can lead to centralized control of credentials. -In order to attest identity of a network, the trust anchor must validate the structure of the network as well as the identity of each of its participants. As a result, the availability of such trust anchors might be limited since such validation will often require physical verification of the agreements between the participants forming the network. +To attest the identity of a security domain, the trust anchor must do its due diligence by validating the structure of the domain's network as well as the identity of each of its members. Because this may involve physical and document verification (of the existence of a network's members and their agreement), few trust anchors of this kind may exist in the real world and the ones that exist may serve a limited clientele or offer limited availabiity. -## C. Participant Identity VC +## C. Security Domain Member Identity VC -Without relying on the DID URI, in the unavailability of any trust basis attesting the identity of a foreign security domain directly, the identity of the individual network participants can be used to validate the Network DID. +A more decentralized way of attestation and validation of a security domain's DID and membership is possible by leveraging the identities of the domain's members. Here we do not rely on the knowledge of a DID URI nor a trust anchor who can issue a VC to a security domain as a whole. -A Network DID must have attestations from all participants during creation, and each update must satisfy the update policy (see Network DID creation protocol). Therefore, a Network DID implies the agreement on network formation by the participants, and validating the participant identities is enough to validate the identity of the network as a whole. +For this method to work, a Security Domain DID must contain attestations from all the members of the domain during its creation, and every subsequent update must satisfy the update policy (see [Security Domain DID creation protocol](./identity-syncing.md#security-domain-identity-creation-as-security-domain-did)). Therefore, the existence of a Security Domain DID is proof that a network was formed through mutual agreement among its members; validating the members' identities is enough to validate the identity of the network (security domain) as a whole. ### Protocol: -- Trust anchors issue `Identity VC` to the individual network participants. - -- For each foreign security domain participant specified in `networkMembers` of the Network DID, validate its identity thorugh `Identity VC` issued to them by trust anchor through the following steps: - - - Resolve the participant DID document from the DID. - - Get address of the participant's IIN agent from service endpoints in the DID document. ([DIDcomm](https://w3c.github.io/did-spec-registries/#didcommmessaging) service endpoint) - - [Optional] negotiate a trust anchor. - - Request `Identity VC`. - - Validate `Identity VC` - +- Trust anchors issue `Identity VC`s to the individual security domain members. +- A member of a local security domain validates the identity of each member of a foreign security domain specified in the `networkMembers` property of the latter's Security Domain DID, represented by an `Identity VC`. Thhe validation comprises of the following steps: + * Resolve the foreign security domain's member's DID document from its DID URI. + * Get address of the member's IIN agent by looking up the agent's service endpoint from the DID document. (See [DIDcomm](https://w3c.github.io/did-spec-registries/#didcommmessaging) mechanism for details.) + * [Optional] determine a common trust anchor using some form of negotiation (this is beyond the scope of this spec). + * Request member's `Identity VC`. + * Validate member's `Identity VC` using standard mechanisms listed in the W3C DID recommendation. ### Limitations: -The protocol can only complete successfully if there are trust anchors available to validate the identity of the foreign security domain participants. Even after that, this protocol only ensures the validation of network formation by these participants. Therefore, an attack is possible by the subset of network participants of a larger network. - +The protocol can only complete successfully if there are trust anchors available to validate the identity of the foreign security domain's members. Even after that, this protocol only confirms the validity of network formation by these members. A subset of members of a larger network may successfully mount an attack by masquerading as the sole members' list of that network. ### Possible Attacks: -Consider a hypothetical foreign security domain named "Supernet", with `N` participants. The Network DID of Supernet is `did:iin_indy:supernet`. A subset of `f < N` participants of Supernet are maliscious, and they create a Network DID with URI almost similar to "Supernet": `did:iin_indy:supernetwork`. Then, if the local security domain wanting to interoperate with Supernet somehow gets the wrong Network DID (for example through phishing), then the discovered Network DID document would be of the maliscious network. Here, validation through the identity validaiton of the particpants will also succeed. If none of `N-f` the non-maliscious participants of Supernet are known to the local security domain validators then the attack would be successful. +Consider a hypothetical foreign security domain named "Supernet", with `N` members. The Security Domain DID of Supernet is `did:iin_indy:supernet`. A subset of members (of size `f < N`) of Supernet are malicious, and they create a fake Security Domain DID with URI almost similar to "Supernet": `did:iin_indy:supernetwork`. Then, if the local security domain that wishes to interoperate with Supernet somehow gets the fake Security Domain DID (e.g. using a phishing attack), then the discovered Security Domain DID document would belong to the fake network formed by the `f` malicious members. Individually, each member's Identity will be successfully validated (using their Identity VCs), so that procedure does not detect or prevent this attack. If none of `N-f` non-malicious members of Supernet are known to the local security domain's members, such an attack is likely to succeed. From ef4f4b062ec002322971eb0c2e9c0942d5e7d21d Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Thu, 8 Sep 2022 12:20:31 +0000 Subject: [PATCH 120/150] Reverting Fabric Interop CC changes that don't work for Go version less than 1.16 The chaincode gets built in Fabric containers, which don't support Go 1.16 yet. Signed-off-by: VRamakrishna --- .../contracts/interop/certificate_utils.go | 10 +++++++++- .../contracts/interop/handle_external_request_test.go | 3 ++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/core/network/fabric-interop-cc/contracts/interop/certificate_utils.go b/core/network/fabric-interop-cc/contracts/interop/certificate_utils.go index 01c451d9d..0e87d5f31 100644 --- a/core/network/fabric-interop-cc/contracts/interop/certificate_utils.go +++ b/core/network/fabric-interop-cc/contracts/interop/certificate_utils.go @@ -14,6 +14,7 @@ import ( "crypto/sha256" "crypto/sha512" "crypto/x509" + "encoding/asn1" "encoding/base64" "encoding/pem" "errors" @@ -192,7 +193,14 @@ func getHashSHA2(bitsize int) (hash.Hash, error) { } func ecdsaVerify(verKey *ecdsa.PublicKey, msgHash, signature []byte) error { - result := ecdsa.VerifyASN1(verKey, msgHash, signature) + ecdsaSignature := new(ECDSASignature) + _, err := asn1.Unmarshal(signature, ecdsaSignature) + if err != nil { + return err + } + + result := ecdsa.Verify(verKey, msgHash, ecdsaSignature.R, ecdsaSignature.S) + // result := ecdsa.VerifyASN1(verKey, msgHash, signature) if result == false { return errors.New("Signature Verification failed. ECDSA VERIFY") } diff --git a/core/network/fabric-interop-cc/contracts/interop/handle_external_request_test.go b/core/network/fabric-interop-cc/contracts/interop/handle_external_request_test.go index 6f04565cf..1e3a24ef5 100644 --- a/core/network/fabric-interop-cc/contracts/interop/handle_external_request_test.go +++ b/core/network/fabric-interop-cc/contracts/interop/handle_external_request_test.go @@ -180,7 +180,8 @@ func testHandleExternalRequestSignatureCertificateMismatch(t *testing.T, query * b64QueryBytes := base64.StdEncoding.EncodeToString(queryBytes) _, err = interopcc.HandleExternalRequest(ctx, string(b64QueryBytes)) - require.EqualError(t, err, "Invalid Signature: Signature Verification failed. ECDSA VERIFY") + require.EqualError(t, err, fmt.Sprintf("Invalid Signature: asn1: structure error: tags don't match (16 vs {class:1 tag:19 length:105 isCompound:false}) {optional:false explicit:false application:false private:false defaultValue: tag: stringType:0 timeType:0 set:false omitEmpty:false} ECDSASignature @2")) + //require.EqualError(t, err, "Invalid Signature: Signature Verification failed. ECDSA VERIFY") } func testHandleExternalRequestInvalidCert(t *testing.T, query *common.Query) { From bb2ea3292ac1c1547a40082b14a5727a5d686aeb Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Fri, 9 Sep 2022 11:22:34 +0530 Subject: [PATCH 121/150] fabric-cli added empty args for endorser list Signed-off-by: sandeep.nishad1 --- samples/fabric/fabric-cli/src/helpers/helpers.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/fabric/fabric-cli/src/helpers/helpers.ts b/samples/fabric/fabric-cli/src/helpers/helpers.ts index b8c61c606..4acba481b 100644 --- a/samples/fabric/fabric-cli/src/helpers/helpers.ts +++ b/samples/fabric/fabric-cli/src/helpers/helpers.ts @@ -830,6 +830,7 @@ const interopHelper = async ( Sign: true }], keyCert, + [], false, options['relay-tls'] === 'true', relayTlsCAFiles, From b43d3c1a71d288e34a24badb3f69d2d84246ea61 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Fri, 9 Sep 2022 11:31:05 +0530 Subject: [PATCH 122/150] update protos-js package, and dependencies of fabric-driver Signed-off-by: sandeep.nishad1 --- common/protos-js/package.json | 2 +- core/drivers/fabric-driver/package.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/protos-js/package.json b/common/protos-js/package.json index 855c62230..0a5bb728a 100644 --- a/common/protos-js/package.json +++ b/common/protos-js/package.json @@ -1,6 +1,6 @@ { "name": "@hyperledger-labs/weaver-protos-js", - "version": "1.4.3", + "version": "1.4.4", "description": "Interop protos for Node JS (Weaver)", "main": "index.js", "exports": { diff --git a/core/drivers/fabric-driver/package.json b/core/drivers/fabric-driver/package.json index cd0454cf9..6416ee328 100644 --- a/core/drivers/fabric-driver/package.json +++ b/core/drivers/fabric-driver/package.json @@ -19,8 +19,8 @@ "author": "", "license": "ISC", "dependencies": { - "@hyperledger-labs/weaver-protos-js": "file:./protos-js", - "@hyperledger-labs/weaver-fabric-interop-sdk": "file:./weaver-fabric-interop-sdk", + "@hyperledger-labs/weaver-protos-js": "^1.4.4", + "@hyperledger-labs/weaver-fabric-interop-sdk": "^1.4.4", "@fidm/x509": "^1.2.1", "@grpc/grpc-js": "^1.1.1", "@typescript-eslint/eslint-plugin": "^3.5.0", From eb3b73d44f5fe32e4ec3ff6afb743e6283790696 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Fri, 9 Sep 2022 12:01:48 +0530 Subject: [PATCH 123/150] update relay client test using ContractTransaction Signed-off-by: sandeep.nishad1 --- core/relay/src/client.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/relay/src/client.rs b/core/relay/src/client.rs index 6d4599d64..15a86ede5 100644 --- a/core/relay/src/client.rs +++ b/core/relay/src/client.rs @@ -135,6 +135,7 @@ async fn event_suscribe(driver: bool) -> Result<(), Box> func: "abc".to_string(), args: vec![], replace_arg_index: 0, + participants: vec![], }; tmp = event_publication::PublicationTarget::Ctx(ctx); } else { @@ -215,6 +216,7 @@ async fn event_unsuscribe(request_id: String, driver: bool) -> Result<(), Box Date: Fri, 9 Sep 2022 12:37:32 +0530 Subject: [PATCH 124/150] fix interopFlow unit test in fabric node sdk Signed-off-by: sandeep.nishad1 --- .../test/InteroperableHelper.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/sdks/fabric/interoperation-node-sdk/test/InteroperableHelper.js b/sdks/fabric/interoperation-node-sdk/test/InteroperableHelper.js index abb076303..36407ad64 100644 --- a/sdks/fabric/interoperation-node-sdk/test/InteroperableHelper.js +++ b/sdks/fabric/interoperation-node-sdk/test/InteroperableHelper.js @@ -19,6 +19,7 @@ chai.should(); const { Wallets } = require("fabric-network"); const { ContractImpl } = require("fabric-network/lib/contract"); const { NetworkImpl } = require("fabric-network/lib/network"); +const { Transaction } = require("fabric-network/lib/transaction"); const ecies = require("../src/eciesCrypto"); const { decryptRemoteProposalResponse, @@ -46,6 +47,8 @@ describe("InteroperableHelper", () => { let wallet; let interopcc; + let interopccStub; + let writeExternalStateTransaction; // Initialize wallet with a single user identity async function initializeWallet() { const privKeyFile = `${__dirname}/data/privKey.pem`; @@ -65,6 +68,8 @@ describe("InteroperableHelper", () => { await initializeWallet(); const network = sinon.createStubInstance(NetworkImpl); interopcc = new ContractImpl(network, "interopcc", "InteroperableHelper"); + writeExternalStateTransaction = sinon.createStubInstance(Transaction) + interopccStub = sinon.stub(interopcc, "createTransaction").withArgs('WriteExternalState').returns(writeExternalStateTransaction); }); afterEach(() => { @@ -367,11 +372,9 @@ describe("InteroperableHelper", () => { ], viewPatterns: [], }; - const interopccStub = sinon.stub(interopcc, "submitTransaction").resolves(false); - // interopccStub.withArgs("Write", "w", "value").resolves(true); - interopccStub + writeExternalStateTransaction.submit.resolves(false); + writeExternalStateTransaction.submit .withArgs( - "WriteExternalState", appId, channel, appFn, From 1f08f35a17828fedadac3828fed033e989589b30 Mon Sep 17 00:00:00 2001 From: "sandeep.nishad1" Date: Fri, 9 Sep 2022 15:36:49 +0530 Subject: [PATCH 125/150] participants renamed to members in ContractTransaction proto Signed-off-by: sandeep.nishad1 --- common/protos-go/common/events.pb.go | 83 +++++++++---------- common/protos/common/events.proto | 2 +- core/drivers/fabric-driver/server/events.ts | 14 +--- core/relay/src/client.rs | 4 +- .../src/EventsManager.ts | 7 +- 5 files changed, 51 insertions(+), 59 deletions(-) diff --git a/common/protos-go/common/events.pb.go b/common/protos-go/common/events.pb.go index 43ed43b54..4ece08844 100644 --- a/common/protos-go/common/events.pb.go +++ b/common/protos-go/common/events.pb.go @@ -415,7 +415,7 @@ type ContractTransaction struct { Func string `protobuf:"bytes,4,opt,name=func,proto3" json:"func,omitempty"` Args [][]byte `protobuf:"bytes,5,rep,name=args,proto3" json:"args,omitempty"` ReplaceArgIndex uint64 `protobuf:"varint,6,opt,name=replace_arg_index,json=replaceArgIndex,proto3" json:"replace_arg_index,omitempty"` - Participants []string `protobuf:"bytes,7,rep,name=participants,proto3" json:"participants,omitempty"` + Members []string `protobuf:"bytes,7,rep,name=members,proto3" json:"members,omitempty"` } func (x *ContractTransaction) Reset() { @@ -492,9 +492,9 @@ func (x *ContractTransaction) GetReplaceArgIndex() uint64 { return 0 } -func (x *ContractTransaction) GetParticipants() []string { +func (x *ContractTransaction) GetMembers() []string { if x != nil { - return x.Participants + return x.Members } return nil } @@ -756,7 +756,7 @@ var file_common_events_proto_rawDesc = []byte{ 0x4b, 0x10, 0x03, 0x12, 0x17, 0x0a, 0x13, 0x55, 0x4e, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x04, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x44, 0x10, 0x05, 0x12, 0x09, - 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x06, 0x22, 0xe8, 0x01, 0x0a, 0x13, 0x43, 0x6f, + 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x06, 0x22, 0xde, 0x01, 0x0a, 0x13, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1b, @@ -769,44 +769,43 @@ var file_common_events_proto_rawDesc = []byte{ 0x61, 0x72, 0x67, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x5f, 0x61, 0x72, 0x67, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x41, 0x72, 0x67, 0x49, 0x6e, 0x64, 0x65, 0x78, - 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, - 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, - 0x61, 0x6e, 0x74, 0x73, 0x22, 0x7b, 0x0a, 0x10, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x03, 0x63, 0x74, 0x78, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, - 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x03, 0x63, 0x74, 0x78, - 0x12, 0x19, 0x0a, 0x07, 0x61, 0x70, 0x70, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x48, 0x00, 0x52, 0x06, 0x61, 0x70, 0x70, 0x55, 0x72, 0x6c, 0x42, 0x14, 0x0a, 0x12, 0x70, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, - 0x74, 0x22, 0x40, 0x0a, 0x0b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, - 0x12, 0x31, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, - 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x65, 0x73, 0x22, 0x73, 0x0a, 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, - 0x65, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x18, - 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2a, 0x3e, 0x0a, 0x09, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x4c, 0x45, 0x44, 0x47, 0x45, 0x52, 0x5f, - 0x53, 0x54, 0x41, 0x54, 0x45, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x53, 0x53, 0x45, 0x54, - 0x5f, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x53, 0x53, 0x45, 0x54, - 0x5f, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x10, 0x02, 0x2a, 0x3f, 0x0a, 0x11, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x53, 0x75, 0x62, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0d, 0x0a, - 0x09, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, - 0x55, 0x4e, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, 0x10, 0x01, 0x12, 0x0a, 0x0a, - 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x02, 0x42, 0x72, 0x0a, 0x1f, 0x63, 0x6f, 0x6d, - 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x5a, 0x4f, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, - 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, - 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, - 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x22, 0x7b, 0x0a, 0x10, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x36, + 0x0a, 0x03, 0x63, 0x74, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x48, + 0x00, 0x52, 0x03, 0x63, 0x74, 0x78, 0x12, 0x19, 0x0a, 0x07, 0x61, 0x70, 0x70, 0x5f, 0x75, 0x72, + 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x61, 0x70, 0x70, 0x55, 0x72, + 0x6c, 0x42, 0x14, 0x0a, 0x12, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0x40, 0x0a, 0x0b, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x12, 0x31, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x65, 0x73, 0x22, 0x73, 0x0a, 0x0a, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2a, 0x3e, + 0x0a, 0x09, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x4c, + 0x45, 0x44, 0x47, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x10, 0x00, 0x12, 0x0e, 0x0a, + 0x0a, 0x41, 0x53, 0x53, 0x45, 0x54, 0x5f, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x01, 0x12, 0x0f, 0x0a, + 0x0b, 0x41, 0x53, 0x53, 0x45, 0x54, 0x5f, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x10, 0x02, 0x2a, 0x3f, + 0x0a, 0x11, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, 0x45, + 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x42, + 0x45, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x02, 0x42, + 0x72, 0x0a, 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x73, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, + 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, + 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2d, 0x64, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6f, 0x70, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/common/protos/common/events.proto b/common/protos/common/events.proto index dee3fd8bd..aa3603398 100644 --- a/common/protos/common/events.proto +++ b/common/protos/common/events.proto @@ -62,7 +62,7 @@ message ContractTransaction { string func = 4; repeated bytes args = 5; uint64 replace_arg_index = 6; - repeated string participants = 7; + repeated string members = 7; } message EventPublication { diff --git a/core/drivers/fabric-driver/server/events.ts b/core/drivers/fabric-driver/server/events.ts index f62e2966b..de89e625d 100644 --- a/core/drivers/fabric-driver/server/events.ts +++ b/core/drivers/fabric-driver/server/events.ts @@ -390,19 +390,7 @@ async function writeExternalStateHelper( const network: Network = await gateway.getNetwork(ctx.getLedgerId()); const interopContract: Contract = network.getContract(process.env.INTEROP_CHAINCODE ? process.env.INTEROP_CHAINCODE : 'interop'); - const endorsingOrgs = ctx.getParticipantsList(); - // const endorsers = network.getChannel().getEndorsers(); - // let endorserList = []; - // if (endorsingOrgs.length > 0) { - // endorserList = endorsers.filter((endorser: Endorser) => { - // //@ts-ignore - // const cert = Certificate.fromPEM(endorser.options.pem); - // const orgName = cert.issuer.organizationName; - // return endorsingOrgs.includes(endorser.mspid) || endorsingOrgs.includes(orgName); - // }); - // console.log('Set endorserList', endorserList); - // } - + const endorsingOrgs = ctx.getMembersList(); const invokeObject = { channel: ctx.getLedgerId(), ccFunc: ctx.getFunc(), diff --git a/core/relay/src/client.rs b/core/relay/src/client.rs index 15a86ede5..2c279b4ae 100644 --- a/core/relay/src/client.rs +++ b/core/relay/src/client.rs @@ -135,7 +135,7 @@ async fn event_suscribe(driver: bool) -> Result<(), Box> func: "abc".to_string(), args: vec![], replace_arg_index: 0, - participants: vec![], + members: vec![], }; tmp = event_publication::PublicationTarget::Ctx(ctx); } else { @@ -216,7 +216,7 @@ async fn event_unsuscribe(request_id: String, driver: bool) -> Result<(), Box Date: Fri, 9 Sep 2022 14:24:28 +0000 Subject: [PATCH 126/150] Added older membership handling code in Fabric Interop CC for backward compatibility Updated relay and driver makefiles to tag locally built images with 'latest'. Signed-off-by: VRamakrishna --- core/drivers/corda-driver/makefile | 1 + core/drivers/fabric-driver/makefile | 1 + .../contracts/interop/membership.go | 90 +++++++- .../contracts/interop/membership_test.go | 211 ++++++++++++------ core/relay/Makefile | 1 + 5 files changed, 228 insertions(+), 76 deletions(-) diff --git a/core/drivers/corda-driver/makefile b/core/drivers/corda-driver/makefile index 61778c35d..8e7bff30f 100644 --- a/core/drivers/corda-driver/makefile +++ b/core/drivers/corda-driver/makefile @@ -23,6 +23,7 @@ build-refresh-dependencies: github.properties .PHONY: image-local image-local: build-local docker build -f Dockerfile.local -t $(DOCKER_IMAGE_NAME):$(DOCKER_TAG) . + docker tag $(DOCKER_IMAGE_NAME):$(DOCKER_TAG) $(DOCKER_IMAGE_NAME):latest .PHONY: image image: github.properties diff --git a/core/drivers/fabric-driver/makefile b/core/drivers/fabric-driver/makefile index 909b03d3e..ac3d4fcc0 100644 --- a/core/drivers/fabric-driver/makefile +++ b/core/drivers/fabric-driver/makefile @@ -40,6 +40,7 @@ build-image-local: protos-js weaver-fabric-interop-sdk (mv package-remote.json package.json && exit 1) # Only if fails mv package-remote.json package.json # Only if success rm -rf protos-js + docker tag ${DOCKER_IMAGE_NAME}:$(DOCKER_TAG) $(DOCKER_IMAGE_NAME):latest build-image: .npmrc docker build --build-arg BUILD_TAG="remote" --build-arg GIT_URL=$(GIT_URL) -t ${DOCKER_IMAGE_NAME}:$(DOCKER_TAG) -f fabricDriver.dockerfile . diff --git a/core/network/fabric-interop-cc/contracts/interop/membership.go b/core/network/fabric-interop-cc/contracts/interop/membership.go index ba1a3ae1a..94e742250 100644 --- a/core/network/fabric-interop-cc/contracts/interop/membership.go +++ b/core/network/fabric-interop-cc/contracts/interop/membership.go @@ -176,8 +176,9 @@ func (s *SmartContract) UpdateLocalMembership(ctx contractapi.TransactionContext } -// CreateMembership cc is used to store a Membership in the ledger -func (s *SmartContract) CreateMembership(ctx contractapi.TransactionContextInterface, counterAttestedMembershipJSON string) error { +// CreateMembershipIIN cc is used to store a Membership in the ledger +// TODO: Replace 'CreateMembership' with this function after updating the Fabric CLI. +func (s *SmartContract) CreateMembershipIIN(ctx contractapi.TransactionContextInterface, counterAttestedMembershipJSON string) error { // Check if the caller has IIN agent privileges if isIINAgent, err := isClientIINAgent(ctx); err != nil { return fmt.Errorf("IIN Agent client check error: %s", err) @@ -310,8 +311,38 @@ func (s *SmartContract) CreateMembership(ctx contractapi.TransactionContextInter return ctx.GetStub().PutState(membershipKey, membershipBytes) } -// UpdateMembership cc is used to update an existing Membership in the ledger -func (s *SmartContract) UpdateMembership(ctx contractapi.TransactionContextInterface, counterAttestedMembershipJSON string) error { +// CreateMembership cc is used to store a Membership in the ledger +// TODO: Replace this function with 'CreateMembership' after updating the Fabric CLI. Retaining this temporarily for backward compatibility. +func (s *SmartContract) CreateMembership(ctx contractapi.TransactionContextInterface, membershipJSON string) error { + membership, err := decodeMembership([]byte(membershipJSON)) + if err != nil { + return fmt.Errorf("Unmarshal error: %s", err) + } + // Check if certificates chains in this membership record are valid + err = validateMemberCertChains(membership) + if err != nil { + return err + } + + membershipKey, err := ctx.GetStub().CreateCompositeKey(membershipObjectType, []string{membership.SecurityDomain}) + acp, getErr := ctx.GetStub().GetState(membershipKey) + if getErr != nil { + return getErr + } + if acp != nil { + return fmt.Errorf("Membership already exists for membership id: %s. Use 'UpdateMembership' to update.", membership.SecurityDomain) + } + + membershipBytes, err := json.Marshal(membership) + if err != nil { + return fmt.Errorf("Marshal error: %s", err) + } + return ctx.GetStub().PutState(membershipKey, membershipBytes) +} + +// UpdateMembershipIIN cc is used to update an existing Membership in the ledger +// TODO: Replace 'UpdateMembership' with this function after updating the Fabric CLI. +func (s *SmartContract) UpdateMembershipIIN(ctx contractapi.TransactionContextInterface, counterAttestedMembershipJSON string) error { // Check if the caller has IIN agent privileges if isIINAgent, err := isClientIINAgent(ctx); err != nil { return fmt.Errorf("IIN Agent client check error: %s", err) @@ -442,6 +473,33 @@ func (s *SmartContract) UpdateMembership(ctx contractapi.TransactionContextInter } +// UpdateMembership cc is used to update an existing Membership in the ledger +// TODO: Replace this function with 'UpdateMembership' after updating the Fabric CLI. Retaining this temporarily for backward compatibility. +func (s *SmartContract) UpdateMembership(ctx contractapi.TransactionContextInterface, membershipJSON string) error { + membership, err := decodeMembership([]byte(membershipJSON)) + if err != nil { + return fmt.Errorf("Unmarshal error: %s", err) + } + // Check if certificates chains in this membership record are valid + err = validateMemberCertChains(membership) + if err != nil { + return err + } + + membershipKey, err := ctx.GetStub().CreateCompositeKey(membershipObjectType, []string{membership.SecurityDomain}) + _, getErr := s.GetMembershipBySecurityDomain(ctx, membership.SecurityDomain) + if getErr != nil { + return getErr + } + + membershipBytes, err := json.Marshal(membership) + if err != nil { + return fmt.Errorf("Marshal error: %s", err) + } + return ctx.GetStub().PutState(membershipKey, membershipBytes) + +} + // DeleteLocalMembership cc is used to delete the local security domain Membership in the ledger func (s *SmartContract) DeleteLocalMembership(ctx contractapi.TransactionContextInterface) error { // Check if the caller has network admin privileges @@ -467,8 +525,9 @@ func (s *SmartContract) DeleteLocalMembership(ctx contractapi.TransactionContext return nil } -// DeleteMembership cc is used to delete an existing Membership in the ledger -func (s *SmartContract) DeleteMembership(ctx contractapi.TransactionContextInterface, membershipID string) error { +// DeleteMembershipIIN cc is used to delete an existing Membership in the ledger +// TODO: Replace 'DeleteMembership' with this function after updating the Fabric CLI. +func (s *SmartContract) DeleteMembershipIIN(ctx contractapi.TransactionContextInterface, membershipID string) error { // Check if the caller has IIN agent privileges if isIINAgent, err := isClientIINAgent(ctx); err != nil { return fmt.Errorf("IIN Agent client check error: %s", err) @@ -492,6 +551,25 @@ func (s *SmartContract) DeleteMembership(ctx contractapi.TransactionContextInter return nil } +// DeleteMembership cc is used to delete an existing Membership in the ledger +// TODO: Replace this function with 'DeleteMembership' after updating the Fabric CLI. Retaining this temporarily for backward compatibility. +func (s *SmartContract) DeleteMembership(ctx contractapi.TransactionContextInterface, membershipID string) error { + membershipKey, err := ctx.GetStub().CreateCompositeKey(membershipObjectType, []string{membershipID}) + bytes, err := ctx.GetStub().GetState(membershipKey) + if err != nil { + return err + } + if bytes == nil { + return fmt.Errorf("Membership with id: %s does not exist", membershipID) + } + err = ctx.GetStub().DelState(membershipKey) + if err != nil { + return fmt.Errorf("failed to delete asset %s: %v", membershipKey, err) + } + + return nil +} + // GetMembershipBySecurityDomain cc gets the Membership for the provided id func (s *SmartContract) GetMembershipBySecurityDomain(ctx contractapi.TransactionContextInterface, securityDomain string) (string, error) { membershipKey, err := ctx.GetStub().CreateCompositeKey(membershipObjectType, []string{securityDomain}) diff --git a/core/network/fabric-interop-cc/contracts/interop/membership_test.go b/core/network/fabric-interop-cc/contracts/interop/membership_test.go index 253259888..fd74aa964 100644 --- a/core/network/fabric-interop-cc/contracts/interop/membership_test.go +++ b/core/network/fabric-interop-cc/contracts/interop/membership_test.go @@ -293,6 +293,7 @@ func TestUpdateLocalMembership(t *testing.T) { require.EqualError(t, err, fmt.Sprintf("Unmarshal error: invalid character 'I' looking for beginning of value")) } +// TODO: Remove later. Keeping for backward compatibility. func TestCreateMembership(t *testing.T) { ctx, chaincodeStub := wtest.PrepMockStub() interopcc := SmartContract{} @@ -303,6 +304,30 @@ func TestCreateMembership(t *testing.T) { Members: map[string]*common.Member{ "member1": &member1, "member2": &member2}, } + membershipBytes, err := json.Marshal(&membershipAsset) + require.NoError(t, err) + err = interopcc.CreateMembership(ctx, string(membershipBytes)) + require.NoError(t, err) + // Invalid Input check + err = interopcc.CreateMembership(ctx, "Invalid Input") + require.EqualError(t, err, fmt.Sprintf("Unmarshal error: invalid character 'I' looking for beginning of value")) + // Membership already exists + chaincodeStub.GetStateReturns([]byte{}, nil) + err = interopcc.CreateMembership(ctx, string(membershipBytes)) + require.EqualError(t, err, fmt.Sprintf("Membership already exists for membership id: %s. Use 'UpdateMembership' to update.", membershipAsset.SecurityDomain)) +} + +// TODO: Rename later. +func TestCreateMembershipIIN(t *testing.T) { + ctx, chaincodeStub := wtest.PrepMockStub() + interopcc := SmartContract{} + + member1, member2 := getMembership() + membershipAsset := common.Membership{ + SecurityDomain: securityDomainId, + Members: map[string]*common.Member{ "member1": &member1, "member2": &member2}, + } + // Generate foreign network member 1 CA structure and client credentials certChain1, keys1, _ := generateCertChain(3) member1.Chain = certChain1 @@ -338,9 +363,9 @@ func TestCreateMembership(t *testing.T) { // Marshal membership for signature membershipBytesPlain, err := protoV2.Marshal(&membershipAsset) require.NoError(t, err) - membershipBytesStr := base64.StdEncoding.EncodeToString(membershipBytesPlain) - membershipBytes := []byte(membershipBytesStr) - membershipBytesWithNonce := []byte(membershipBytesStr + nonce) + membershipBytesStr := base64.StdEncoding.EncodeToString(membershipBytesPlain) + membershipBytes := []byte(membershipBytesStr) + membershipBytesWithNonce := []byte(membershipBytesStr + nonce) // Generate member 2 attestation random1 := rand.Reader hashed1, err := computeSHA2Hash(membershipBytesWithNonce, key1.PublicKey.Params().BitSize) @@ -409,9 +434,9 @@ func TestCreateMembership(t *testing.T) { // Marshal attested membership set for signature attestedMembershipSetBytesPlain, err := protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) - attestedMembershipSetBytesStr := base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) - attestedMembershipSetBytes := []byte(attestedMembershipSetBytesStr) - attestedMembershipSetBytesWithNonce := []byte(attestedMembershipSetBytesStr + nonce) + attestedMembershipSetBytesStr := base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) + attestedMembershipSetBytes := []byte(attestedMembershipSetBytesStr) + attestedMembershipSetBytesWithNonce := []byte(attestedMembershipSetBytesStr + nonce) // Generate member 2 attestation randomLocal1 := rand.Reader hashedLocal1, err := computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) @@ -435,14 +460,14 @@ func TestCreateMembership(t *testing.T) { // Record membership info: should fail because the caller is not an IIN Agent counterAttestedMembershipBytes, err := json.Marshal(&counterAttestedMembership) require.NoError(t, err) - err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, "Caller not an IIN Agent; access denied") // Record membership info: should fail because the local IIN Agent is not registered clientIdentity := &mocks.ClientIdentity{} clientIdentity.GetAttributeValueCalls(setClientIINAgent) ctx.GetClientIdentityReturns(clientIdentity) - err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) require.Error(t, err) // Record local membership info @@ -458,13 +483,13 @@ func TestCreateMembership(t *testing.T) { chaincodeStub.GetStateReturnsOnCall(3, nil, nil) clientIdentity.GetAttributeValueCalls(setClientIINAgent) ctx.GetClientIdentityReturns(clientIdentity) - err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) require.NoError(t, err) // Record membership info again: should fail because membership has already been recorded against this security domain chaincodeStub.GetStateReturnsOnCall(4, localMembershipBytes, nil) chaincodeStub.GetStateReturnsOnCall(5, []byte{}, nil) - err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, fmt.Sprintf("Membership already exists for membership id: %s. Use 'UpdateMembership' to update.", membershipAsset.SecurityDomain)) // One of the local signatures is invalid: should fail @@ -477,7 +502,7 @@ func TestCreateMembership(t *testing.T) { require.NoError(t, err) chaincodeStub.GetStateReturnsOnCall(6, localMembershipBytes, nil) chaincodeStub.GetStateReturnsOnCall(7, nil, nil) - err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, "Unable to Validate Signature: Signature Verification failed. ECDSA VERIFY") // One of the foreign signatures is invalid: should fail @@ -488,9 +513,9 @@ func TestCreateMembership(t *testing.T) { attestation2.Signature = base64.StdEncoding.EncodeToString(signature2) attestedMembershipSetBytesPlain, err = protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) - attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) - attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) - attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) + attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) + attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) + attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) require.NoError(t, err) signatureLocal1, err = ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) @@ -505,7 +530,7 @@ func TestCreateMembership(t *testing.T) { counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) require.NoError(t, err) chaincodeStub.GetStateReturnsOnCall(7, localMembershipBytes, nil) - err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, "Unable to Validate Signature: Signature Verification failed. ECDSA VERIFY") // One of the foreign attestations has an invalid nonce: should fail @@ -517,9 +542,9 @@ func TestCreateMembership(t *testing.T) { attestation1.Nonce = "invalid-nonce" attestedMembershipSetBytesPlain, err = protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) - attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) - attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) - attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) + attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) + attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) + attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) require.NoError(t, err) signatureLocal1, err = ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) @@ -534,7 +559,7 @@ func TestCreateMembership(t *testing.T) { counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) require.NoError(t, err) chaincodeStub.GetStateReturnsOnCall(8, localMembershipBytes, nil) - err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, fmt.Sprintf("Mismatched nonces across two attestations: %s, %s", nonce, attestation1.Nonce)) // Foreign membership has an invalid cert chain: should fail @@ -544,9 +569,9 @@ func TestCreateMembership(t *testing.T) { member1.Chain[1] = tmpCert membershipBytesPlain, err = protoV2.Marshal(&membershipAsset) require.NoError(t, err) - membershipBytesStr = base64.StdEncoding.EncodeToString(membershipBytesPlain) - membershipBytes = []byte(membershipBytesStr) - membershipBytesWithNonce = []byte(membershipBytesStr + nonce) + membershipBytesStr = base64.StdEncoding.EncodeToString(membershipBytesPlain) + membershipBytes = []byte(membershipBytesStr) + membershipBytesWithNonce = []byte(membershipBytesStr + nonce) hashed1, err = computeSHA2Hash(membershipBytesWithNonce, key1.PublicKey.Params().BitSize) require.NoError(t, err) signature1, err = ecdsa.SignASN1(random1, key1, hashed1) @@ -560,9 +585,9 @@ func TestCreateMembership(t *testing.T) { attestedMembershipSet.Membership = membershipBytes attestedMembershipSetBytesPlain, err = protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) - attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) - attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) - attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) + attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) + attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) + attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) require.NoError(t, err) signatureLocal1, err = ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) @@ -577,7 +602,7 @@ func TestCreateMembership(t *testing.T) { counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) require.NoError(t, err) chaincodeStub.GetStateReturnsOnCall(9, localMembershipBytes, nil) - err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) require.Error(t, err) // Foreign attestation has invalid security domain: should fail @@ -587,9 +612,9 @@ func TestCreateMembership(t *testing.T) { membershipAsset.SecurityDomain = "invalid" membershipBytesPlain, err = protoV2.Marshal(&membershipAsset) require.NoError(t, err) - membershipBytesStr = base64.StdEncoding.EncodeToString(membershipBytesPlain) - membershipBytes = []byte(membershipBytesStr) - membershipBytesWithNonce = []byte(membershipBytesStr + nonce) + membershipBytesStr = base64.StdEncoding.EncodeToString(membershipBytesPlain) + membershipBytes = []byte(membershipBytesStr) + membershipBytesWithNonce = []byte(membershipBytesStr + nonce) hashed1, err = computeSHA2Hash(membershipBytesWithNonce, key1.PublicKey.Params().BitSize) require.NoError(t, err) signature1, err = ecdsa.SignASN1(random1, key1, hashed1) @@ -603,9 +628,9 @@ func TestCreateMembership(t *testing.T) { attestedMembershipSet.Membership = membershipBytes attestedMembershipSetBytesPlain, err = protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) - attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) - attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) - attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) + attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) + attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) + attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) require.NoError(t, err) signatureLocal1, err = ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) @@ -620,10 +645,11 @@ func TestCreateMembership(t *testing.T) { counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) require.NoError(t, err) chaincodeStub.GetStateReturnsOnCall(10, localMembershipBytes, nil) - err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, fmt.Sprintf("Foreign agent security domain %s does not match attested membership security domain invalid", securityDomainId)) } +// TODO: Remove later. Keeping for backward compatibility. func TestUpdateMembership(t *testing.T) { ctx, chaincodeStub := wtest.PrepMockStub() interopcc := SmartContract{} @@ -634,6 +660,31 @@ func TestUpdateMembership(t *testing.T) { Members: map[string]*common.Member{ "member1": &member1, "member2": &member2}, } + membershipBytes, err := json.Marshal(&membershipAsset) + require.NoError(t, err) + err = interopcc.UpdateMembership(ctx, string(membershipBytes)) + require.EqualError(t, err, fmt.Sprintf("Membership with id: %s does not exist", membershipAsset.SecurityDomain)) + // Invalid Input check + chaincodeStub.GetStateReturns([]byte{}, nil) + err = interopcc.UpdateMembership(ctx, "Invalid Input") + require.EqualError(t, err, fmt.Sprintf("Unmarshal error: invalid character 'I' looking for beginning of value")) + // Membership already exists; Update it + chaincodeStub.GetStateReturns([]byte{}, nil) + err = interopcc.UpdateMembership(ctx, string(membershipBytes)) + require.NoError(t, err) +} + +// TODO: Rename later. +func TestUpdateMembershipIIN(t *testing.T) { + ctx, chaincodeStub := wtest.PrepMockStub() + interopcc := SmartContract{} + + member1, member2 := getMembership() + membershipAsset := common.Membership{ + SecurityDomain: securityDomainId, + Members: map[string]*common.Member{ "member1": &member1, "member2": &member2}, + } + // Generate foreign network member 1 CA structure and client credentials certChain1, keys1, _ := generateCertChain(3) member1.Chain = certChain1 @@ -669,9 +720,9 @@ func TestUpdateMembership(t *testing.T) { // Marshal membership for signature membershipBytesPlain, err := protoV2.Marshal(&membershipAsset) require.NoError(t, err) - membershipBytesStr := base64.StdEncoding.EncodeToString(membershipBytesPlain) - membershipBytes := []byte(membershipBytesStr) - membershipBytesWithNonce := []byte(membershipBytesStr + nonce) + membershipBytesStr := base64.StdEncoding.EncodeToString(membershipBytesPlain) + membershipBytes := []byte(membershipBytesStr) + membershipBytesWithNonce := []byte(membershipBytesStr + nonce) // Generate member 2 attestation random1 := rand.Reader hashed1, err := computeSHA2Hash(membershipBytesWithNonce, key1.PublicKey.Params().BitSize) @@ -740,9 +791,9 @@ func TestUpdateMembership(t *testing.T) { // Marshal attested membership set for signature attestedMembershipSetBytesPlain, err := protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) - attestedMembershipSetBytesStr := base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) - attestedMembershipSetBytes := []byte(attestedMembershipSetBytesStr) - attestedMembershipSetBytesWithNonce := []byte(attestedMembershipSetBytesStr + nonce) + attestedMembershipSetBytesStr := base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) + attestedMembershipSetBytes := []byte(attestedMembershipSetBytesStr) + attestedMembershipSetBytesWithNonce := []byte(attestedMembershipSetBytesStr + nonce) // Generate member 2 attestation randomLocal1 := rand.Reader hashedLocal1, err := computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) @@ -766,14 +817,14 @@ func TestUpdateMembership(t *testing.T) { // Record membership info: should fail because the caller is not an IIN Agent counterAttestedMembershipBytes, err := json.Marshal(&counterAttestedMembership) require.NoError(t, err) - err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, "Caller not an IIN Agent; access denied") // Record membership info: should fail because the local IIN Agent is not registered clientIdentity := &mocks.ClientIdentity{} clientIdentity.GetAttributeValueCalls(setClientIINAgent) ctx.GetClientIdentityReturns(clientIdentity) - err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) require.Error(t, err) // Record local membership info @@ -789,13 +840,13 @@ func TestUpdateMembership(t *testing.T) { chaincodeStub.GetStateReturnsOnCall(3, nil, nil) clientIdentity.GetAttributeValueCalls(setClientIINAgent) ctx.GetClientIdentityReturns(clientIdentity) - err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, fmt.Sprintf("Membership with id: %s does not exist", securityDomainId)) // Record membership info again: should succeed now chaincodeStub.GetStateReturnsOnCall(4, localMembershipBytes, nil) chaincodeStub.GetStateReturnsOnCall(5, []byte{}, nil) - err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) require.NoError(t, err) // One of the local signatures is invalid: should fail @@ -808,7 +859,7 @@ func TestUpdateMembership(t *testing.T) { require.NoError(t, err) chaincodeStub.GetStateReturnsOnCall(6, localMembershipBytes, nil) chaincodeStub.GetStateReturnsOnCall(7, []byte{}, nil) - err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, "Unable to Validate Signature: Signature Verification failed. ECDSA VERIFY") // One of the foreign signatures is invalid: should fail @@ -819,9 +870,9 @@ func TestUpdateMembership(t *testing.T) { attestation2.Signature = base64.StdEncoding.EncodeToString(signature2) attestedMembershipSetBytesPlain, err = protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) - attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) - attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) - attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) + attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) + attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) + attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) require.NoError(t, err) signatureLocal1, err = ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) @@ -836,7 +887,7 @@ func TestUpdateMembership(t *testing.T) { counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) require.NoError(t, err) chaincodeStub.GetStateReturnsOnCall(7, localMembershipBytes, nil) - err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, "Unable to Validate Signature: Signature Verification failed. ECDSA VERIFY") // One of the foreign attestations has an invalid nonce: should fail @@ -848,9 +899,9 @@ func TestUpdateMembership(t *testing.T) { attestation1.Nonce = "invalid-nonce" attestedMembershipSetBytesPlain, err = protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) - attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) - attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) - attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) + attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) + attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) + attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) require.NoError(t, err) signatureLocal1, err = ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) @@ -865,7 +916,7 @@ func TestUpdateMembership(t *testing.T) { counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) require.NoError(t, err) chaincodeStub.GetStateReturnsOnCall(8, localMembershipBytes, nil) - err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, fmt.Sprintf("Mismatched nonces across two attestations: %s, %s", nonce, attestation1.Nonce)) // Foreign membership has an invalid cert chain: should fail @@ -875,9 +926,9 @@ func TestUpdateMembership(t *testing.T) { member1.Chain[1] = tmpCert membershipBytesPlain, err = protoV2.Marshal(&membershipAsset) require.NoError(t, err) - membershipBytesStr = base64.StdEncoding.EncodeToString(membershipBytesPlain) - membershipBytes = []byte(membershipBytesStr) - membershipBytesWithNonce = []byte(membershipBytesStr + nonce) + membershipBytesStr = base64.StdEncoding.EncodeToString(membershipBytesPlain) + membershipBytes = []byte(membershipBytesStr) + membershipBytesWithNonce = []byte(membershipBytesStr + nonce) hashed1, err = computeSHA2Hash(membershipBytesWithNonce, key1.PublicKey.Params().BitSize) require.NoError(t, err) signature1, err = ecdsa.SignASN1(random1, key1, hashed1) @@ -891,9 +942,9 @@ func TestUpdateMembership(t *testing.T) { attestedMembershipSet.Membership = membershipBytes attestedMembershipSetBytesPlain, err = protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) - attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) - attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) - attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) + attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) + attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) + attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) require.NoError(t, err) signatureLocal1, err = ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) @@ -908,7 +959,7 @@ func TestUpdateMembership(t *testing.T) { counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) require.NoError(t, err) chaincodeStub.GetStateReturnsOnCall(9, localMembershipBytes, nil) - err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) require.Error(t, err) // Foreign attestation has invalid security domain: should fail @@ -918,9 +969,9 @@ func TestUpdateMembership(t *testing.T) { membershipAsset.SecurityDomain = "invalid" membershipBytesPlain, err = protoV2.Marshal(&membershipAsset) require.NoError(t, err) - membershipBytesStr = base64.StdEncoding.EncodeToString(membershipBytesPlain) - membershipBytes = []byte(membershipBytesStr) - membershipBytesWithNonce = []byte(membershipBytesStr + nonce) + membershipBytesStr = base64.StdEncoding.EncodeToString(membershipBytesPlain) + membershipBytes = []byte(membershipBytesStr) + membershipBytesWithNonce = []byte(membershipBytesStr + nonce) hashed1, err = computeSHA2Hash(membershipBytesWithNonce, key1.PublicKey.Params().BitSize) require.NoError(t, err) signature1, err = ecdsa.SignASN1(random1, key1, hashed1) @@ -934,9 +985,9 @@ func TestUpdateMembership(t *testing.T) { attestedMembershipSet.Membership = membershipBytes attestedMembershipSetBytesPlain, err = protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) - attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) - attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) - attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) + attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) + attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) + attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) require.NoError(t, err) signatureLocal1, err = ecdsa.SignASN1(randomLocal1, keyLocal1, hashedLocal1) @@ -951,7 +1002,7 @@ func TestUpdateMembership(t *testing.T) { counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) require.NoError(t, err) chaincodeStub.GetStateReturnsOnCall(10, localMembershipBytes, nil) - err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, fmt.Sprintf("Foreign agent security domain %s does not match attested membership security domain invalid", securityDomainId)) } @@ -986,8 +1037,28 @@ func TestDeleteMembership(t *testing.T) { ctx, chaincodeStub := wtest.PrepMockStub() interopcc := SmartContract{} - // Case when caller is not an IIN Agent + // Case when a Membership exists + chaincodeStub.GetStateReturns([]byte{}, nil) err := interopcc.DeleteMembership(ctx, securityDomainId) + require.NoError(t, err) + + // Case when no Membership is found + chaincodeStub.GetStateReturns(nil, nil) + err = interopcc.DeleteMembership(ctx, securityDomainId) + require.EqualError(t, err, fmt.Sprintf("Membership with id: %s does not exist", securityDomainId)) + + // Handle GetState Error + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + err = interopcc.DeleteMembership(ctx, securityDomainId) + require.EqualError(t, err, fmt.Sprintf("unable to retrieve asset")) +} + +func TestDeleteMembershipIIN(t *testing.T) { + ctx, chaincodeStub := wtest.PrepMockStub() + interopcc := SmartContract{} + + // Case when caller is not an IIN Agent + err := interopcc.DeleteMembershipIIN(ctx, securityDomainId) require.EqualError(t, err, "Caller not an IIN Agent; access denied") // Case when a Membership exists @@ -995,17 +1066,17 @@ func TestDeleteMembership(t *testing.T) { clientIdentity.GetAttributeValueCalls(setClientIINAgent) ctx.GetClientIdentityReturns(clientIdentity) chaincodeStub.GetStateReturns([]byte{}, nil) - err = interopcc.DeleteMembership(ctx, securityDomainId) + err = interopcc.DeleteMembershipIIN(ctx, securityDomainId) require.NoError(t, err) // Case when no Membership is found chaincodeStub.GetStateReturns(nil, nil) - err = interopcc.DeleteMembership(ctx, securityDomainId) + err = interopcc.DeleteMembershipIIN(ctx, securityDomainId) require.EqualError(t, err, fmt.Sprintf("Membership with id: %s does not exist", securityDomainId)) // Handle GetState Error chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) - err = interopcc.DeleteMembership(ctx, securityDomainId) + err = interopcc.DeleteMembershipIIN(ctx, securityDomainId) require.EqualError(t, err, fmt.Sprintf("unable to retrieve asset")) } diff --git a/core/relay/Makefile b/core/relay/Makefile index 99ba561a6..6a86fb9f5 100644 --- a/core/relay/Makefile +++ b/core/relay/Makefile @@ -85,6 +85,7 @@ build-local: protos-local build-server-local: protos-local fingerprint.json @echo -e "\033[1mBUILD\033[0m - Building Docker image (relay server)..." docker build --build-arg COMMIT=$(COMMIT) --build-arg BRANCH=$(BRANCH) --build-arg PROTOS_VERSION=$(PROTOS_TAG) --build-arg VERSION=$(DOCKER_TAG) --build-arg GIT_URL=$(GIT_URL) -t $(DOCKER_IMAGE_SERVER) -f Dockerfile.server . + docker tag $(DOCKER_IMAGE_SERVER) $(DOCKER_IMAGE_SERVER_LATEST) .PHONY: build-client-local build-client-local: protos-local fingerprint.json From 2e1b478ad408500d82eef2e3dcc14ba1e64665fe Mon Sep 17 00:00:00 2001 From: micky Date: Wed, 17 Aug 2022 14:34:46 +0300 Subject: [PATCH 127/150] fix github action for asset excahnge of besu Signed-off-by: micky --- .../workflows/test_asset-exchange-besu.yml | 56 ++++++++-- .../besu/besu-cli/src/commands/asset/claim.ts | 82 ++++++++------ .../besu/besu-cli/src/commands/asset/issue.ts | 103 ++++++++++++------ .../besu/besu-cli/src/commands/asset/lock.ts | 102 ++++++++++------- .../besu-cli/src/commands/asset/unlock.ts | 24 +++- .../simpleasset/contracts/AliceERC721.sol | 14 +-- .../simpleasset/contracts/AlliceERC1155.sol | 7 ++ 7 files changed, 267 insertions(+), 121 deletions(-) diff --git a/.github/workflows/test_asset-exchange-besu.yml b/.github/workflows/test_asset-exchange-besu.yml index 97b4ac6d2..80f41d2b0 100644 --- a/.github/workflows/test_asset-exchange-besu.yml +++ b/.github/workflows/test_asset-exchange-besu.yml @@ -67,14 +67,31 @@ jobs: run: | export PATH="${PWD}/bin:$PATH" COUNT=0 - TOTAL=3 + TOTAL=15 + tokencontract=( "AliceERC1155" "AliceERC20" "AliceERC721") + for (( count=0; count<3; count++ )) + do + cp config.template.json tmp.json + cp config.template.json tmp.json + jq -r ".network1.tokenContract |= \"../simpleasset/build/contracts/${tokencontract[$count]}.json\"" tmp.json > config.json + cp config.json tmp.json + jq -r '.network2.tokenContract |= "../simpleasset/build/contracts/BobERC20.json"' tmp.json > config.json + rm tmp.json - # issue 10 tokens to account 1 - besu-cli asset issue --network=network1 --account=1 --amount=10 + # issue 1 tokens to account 1 + # & lock 1 token for account 2 in network 2 + if [ ${tokencontract[$count]} == "AliceERC20" ]; then + besu-cli asset issue --network=network1 --account=1 --amount=1 --asset_type=ERC20 + besu-cli asset lock --network=network1 --sender_account=1 --recipient_account=2 --amount=1 --timeout=1000 1> tmp.out + elif [ ${tokencontract[$count]} == "AliceERC1155" ]; then + besu-cli asset issue --network=network1 --account=1 --amount=1 --token_id=0 --token_data="" --asset_type=ERC1155 + besu-cli asset lock --network=network1 --sender_account=1 --recipient_account=2 --amount=1 --token_id=0 --timeout=1000 --asset_type=ERC1155 1> tmp.out + else + besu-cli asset issue --network=network1 --account=1 --amount=1 --token_id=0 --asset_type=ERC721 + besu-cli asset lock --network=network1 --sender_account=1 --recipient_account=2 --amount=1 --token_id=0 --asset_type=ERC721 --timeout=1000 1> tmp.out + fi - # lock 1 token for account 2 in network 2 - besu-cli asset lock --network=network1 --sender_account=1 --recipient_account=2 --amount=1 --timeout=1000 1> tmp.out - cat tmp.out | grep "Account balance of the sender in Network network1: 9" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out | grep "Account balance of the sender in Network network1: 1" && COUNT=$(( COUNT + 1 )) && echo "PASS" cat tmp.out tmp_string=$(cat tmp.out | grep "Lock contract ID:") @@ -92,10 +109,35 @@ jobs: sleep 30 # Claim asset - besu-cli asset claim --network=network1 --lock_contract_id=$LOCK_ID --recipient_account=2 --preimage=&PREIMAGE 1> tmp.out + besu-cli asset claim --network=network1 --lock_contract_id=$LOCK_ID --recipient_account=2 --preimage=$PREIMAGE 1> tmp.out cat tmp.out | grep "Account balance of the recipient in Network network1 after claiming: 1" && COUNT=$(( COUNT + 1 )) && echo "PASS" cat tmp.out + # test unlock + if [ ${tokencontract[$count]} == "AliceERC20" ]; then + besu-cli asset issue --network=network1 --account=1 --amount=1 --asset_type=ERC20 + besu-cli asset lock --network=network1 --sender_account=1 --recipient_account=2 --amount=1 --timeout=5 1> tmp.out + elif [ ${tokencontract[$count]} == "AliceERC1155" ]; then + besu-cli asset issue --network=network1 --account=1 --amount=1 --token_id=1 --token_data="" --asset_type=ERC1155 + besu-cli asset lock --network=network1 --sender_account=1 --recipient_account=2 --amount=1 --token_id=1 --timeout=5 --asset_type=ERC1155 1> tmp.out + else + besu-cli asset issue --network=network1 --account=1 --amount=1 --token_id=1 --asset_type=ERC721 + besu-cli asset lock --network=network1 --sender_account=1 --recipient_account=2 --amount=1 --token_id=1 --asset_type=ERC721 --timeout=5 1> tmp.out + fi + cat tmp.out | grep "Account balance of the sender in Network network1: 0" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + tmp_string=$(cat tmp.out | grep "Lock contract ID:") + arrIN=(${tmp_string//:/ }) + LOCK_ID=${arrIN[3]} + tmp_string=$(cat tmp.out | grep "Preimage:") + arrIN=(${tmp_string//:/ }) + PREIMAGE=${arrIN[1]} + + besu-cli asset unlock --network=network1 --lock_contract_id=$LOCK_ID --sender_account=1 --token_id=1 1> tmp.out + cat tmp.out | grep "after unlocking: 1" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + done # RESULT echo "Passed $COUNT/$TOTAL Tests." diff --git a/samples/besu/besu-cli/src/commands/asset/claim.ts b/samples/besu/besu-cli/src/commands/asset/claim.ts index e55cc1840..8b3bf8c98 100644 --- a/samples/besu/besu-cli/src/commands/asset/claim.ts +++ b/samples/besu/besu-cli/src/commands/asset/claim.ts @@ -1,7 +1,19 @@ import { GluegunCommand } from 'gluegun' import { getNetworkConfig, commandHelp } from '../../helper/helper' import { getContractInstance } from '../../helper/besu-functions' -const Web3 = require ("web3") +const Web3 = require("web3") + +async function getBalances(tokenContract, address, token_id = 0) { + try { + var balance = await tokenContract.balanceOf(address, token_id) + } catch { + var balance = null; + } + if (!balance) + return await tokenContract.balanceOf(address) + else + return balance; +} const command: GluegunCommand = { name: 'claim', @@ -40,20 +52,20 @@ const command: GluegunCommand = { 'The preimage of hash with which the asset was locked with.' }, { - name: '--recipient_account_address', - description: - 'The address of the recipient account. We can set this parameter if we want to use account address instead of account index ' - }, - { - name: '--network_host', - description: - 'The network host. Default value is taken from config.json' - }, - { - name: '--network_port', - description: - 'The network port. Default value is taken from config.json' - } + name: '--recipient_account_address', + description: + 'The address of the recipient account. We can set this parameter if we want to use account address instead of account index ' + }, + { + name: '--network_host', + description: + 'The network host. Default value is taken from config.json' + }, + { + name: '--network_port', + description: + 'The network port. Default value is taken from config.json' + } ], command, ['asset', 'claim'] @@ -63,24 +75,24 @@ const command: GluegunCommand = { print.info('Claim assets') // Retrieving networkConfig - if(!options.network){ + if (!options.network) { print.error('Network ID not provided.') return } const networkConfig = getNetworkConfig(options.network) - var networkPort = networkConfig.networkPort - if (options.network_port){ - networkPort = options.network_port - console.log('Use network port : ', networkPort) - } - var networkHost = networkConfig.networkHost - if(options.network_host){ - networkHost = options.network_host - console.log('Use network host : ', networkHost) - } + var networkPort = networkConfig.networkPort + if (options.network_port) { + networkPort = options.network_port + console.log('Use network port : ', networkPort) + } + var networkHost = networkConfig.networkHost + if (options.network_host) { + networkHost = options.network_host + console.log('Use network host : ', networkHost) + } - const provider = new Web3.providers.HttpProvider('http://'+networkHost+':'+networkPort) + const provider = new Web3.providers.HttpProvider('http://' + networkHost + ':' + networkPort) const web3N = new Web3(provider) @@ -94,22 +106,22 @@ const command: GluegunCommand = { // Receiving the input parameters var recipient - if(options.recipient_account){ + if (options.recipient_account) { recipient = accounts[options.recipient_account] } - else if(options.recipient_account_address){ - recipient = '0x'+ options.recipient_account_address + else if (options.recipient_account_address) { + recipient = '0x' + options.recipient_account_address } - else{ + else { print.info('Recipient account index not provided. Taking from networkConfig..') recipient = accounts[networkConfig.recipientAccountIndex] } - if(!options.lock_contract_id){ + if (!options.lock_contract_id) { print.error('Lock contract ID not provided.') return } const lockContractId = '0x' + options.lock_contract_id - if(!options.preimage){ + if (!options.preimage) { print.error('Preimage not provided.') return } @@ -124,7 +136,7 @@ const command: GluegunCommand = { console.log('Preimage bytes32:', preimage_bytes32) // Balance of the recipient before claiming - var recipientBalance = await tokenContract.balanceOf(recipient) + var recipientBalance = await getBalances(tokenContract, recipient) console.log(`Account balance of the recipient in Network ${options.network} before claiming: ${recipientBalance.toString()}`) await interopContract.claimAsset(lockContractId, preimage_bytes32, { @@ -134,7 +146,7 @@ const command: GluegunCommand = { }) // Balance of the recipient after claiming - var recipientBalance = await tokenContract.balanceOf(recipient) + var recipientBalance = await getBalances(tokenContract, recipient) console.log(`Account balance of the recipient in Network ${options.network} after claiming: ${recipientBalance.toString()}`) } } diff --git a/samples/besu/besu-cli/src/commands/asset/issue.ts b/samples/besu/besu-cli/src/commands/asset/issue.ts index 292565732..48f1044a4 100644 --- a/samples/besu/besu-cli/src/commands/asset/issue.ts +++ b/samples/besu/besu-cli/src/commands/asset/issue.ts @@ -1,14 +1,14 @@ import { GluegunCommand } from 'gluegun' import { getNetworkConfig, commandHelp } from '../../helper/helper' import { getContractInstance } from '../../helper/besu-functions' -const Web3 = require ("web3") +const Web3 = require("web3") const command: GluegunCommand = { name: 'issue', description: 'Issuance of tokens', run: async toolbox => { const { - print, + print, parameters: { options } } = toolbox if (options.help || options.h) { @@ -16,7 +16,7 @@ const command: GluegunCommand = { print, toolbox, `besu-cli asset issue --network=network1 --account=1 --amount=10`, - 'besu-cli asset issue --network= --account= --account_address= --contract_owner_address= --amount= --network_port= --network_host= ' , + 'besu-cli asset issue --network= --account= --account_address= --contract_owner_address= --amount= --network_port= --network_host= ', [ { name: '--network', @@ -32,7 +32,7 @@ const command: GluegunCommand = { name: '--account_address', description: 'The address of the account. We can set this parameter if we want to use account address instead of account index ' - }, { + }, { name: '--contract_owner_address', description: 'The address of the contract owner. The default value is accounts[0] ' @@ -51,7 +51,23 @@ const command: GluegunCommand = { name: '--network_port', description: 'The network port. Default value is taken from config.json' + }, + { + name: '--asset_type', + description: + 'Asset type for issuing tokens. Default value is ERC20, other options are ERC721, ERC1155' + }, + { + name: '--token_id', + description: + 'token ID for issuing tokens. Only applicable for ERC721, ERC1155' + }, + { + name: '--token_data', + description: + 'token data for issuing tokens. Only applicable for ERC1155' } + ], command, ['asset', 'issue'] @@ -59,26 +75,26 @@ const command: GluegunCommand = { return } print.info('Issuance of tokens') - if(!options.network){ + if (!options.network) { print.error('Network ID not provided.') return } const networkConfig = getNetworkConfig(options.network) console.log('networkConfig', networkConfig) - var networkPort = networkConfig.networkPort - if(options.network_port){ - networkPort = options.network_port - console.log('Use network port : ', networkPort) - } - var networkHost = networkConfig.networkHost - if(options.network_host){ - networkHost = options.network_host - console.log('Use network host : ', networkHost) - } + var networkPort = networkConfig.networkPort + if (options.network_port) { + networkPort = options.network_port + console.log('Use network port : ', networkPort) + } + var networkHost = networkConfig.networkHost + if (options.network_host) { + networkHost = options.network_host + console.log('Use network host : ', networkHost) + } - const provider = new Web3.providers.HttpProvider('http://'+networkHost+':'+networkPort) + const provider = new Web3.providers.HttpProvider('http://' + networkHost + ':' + networkPort) const web3N = new Web3(provider) const tokenContract = await getContractInstance(provider, networkConfig.tokenContract).catch(function () { console.log("Failed getting tokenContract!"); @@ -87,33 +103,58 @@ const command: GluegunCommand = { var contractOwner = accounts[0] - if(options.contract_owner_address){ - contractOwner = '0x'+ options.contract_owner_address - } + if (options.contract_owner_address) { + contractOwner = '0x' + options.contract_owner_address + } var account - if(options.account){ + if (options.account) { account = accounts[options.account] } - else if(options.account_address){ - account = '0x'+ options.account_address - }else{ + else if (options.account_address) { + account = '0x' + options.account_address + } else { account = accounts[networkConfig.senderAccountIndex] } - if(!options.amount){ + if (!options.amount) { print.error('Amount not provided') return } - console.log(`Contract owner address is ${contractOwner} `) - console.log(`Receiver address is ${account} `) - // Transfer from the contract owner to the account specified - await tokenContract.transfer(account, options.amount, {from: contractOwner}).catch(function () { - console.log("tokenContract transfer threw an error; Probably the token supply is used up!"); - }) + if(!options.asset_type) { + options.asset_type = "ERC20" + } - var balance = await tokenContract.balanceOf(account) + if(!options.token_id) { + options.token_id = 0 + } + + if(!options.token_data) { + options.token_data = 0 + } + + console.log(`Contract owner address is ${contractOwner} `) + console.log(`Receiver address is ${account} `) + console.log(`Token contract is ${tokenContract.address} `) + // Transfer from the contract owner to the account specified + if (options.asset_type == 'ERC20') { + await tokenContract.transfer(account, options.amount, { from: contractOwner }).catch(function () { + console.log("tokenContract transfer threw an error; Probably the token supply is used up!"); + }) + } else if (options.asset_type == 'ERC721') { + await tokenContract.mint(account, { from: contractOwner }).catch(function () { + console.log("tokenContract transfer threw an error; Probably the token supply is used up!"); + }) + } else if (options.asset_type == 'ERC1155'){ + await tokenContract.mint(account, options.token_id, options.amount, Web3.utils.utf8ToHex(options.token_data), { from: contractOwner }).catch(function () { + console.log("tokenContract transfer threw an error; Probably the token supply is used up!"); + }) + } + if(options.asset_type == 'ERC1155'){ + var balance = await tokenContract.balanceOf(account, options.token_id)} + else + var balance = await tokenContract.balanceOf(account); console.log(`Account balance of ${account} in Network ${options.network}: ${balance.toString()}`) } } diff --git a/samples/besu/besu-cli/src/commands/asset/lock.ts b/samples/besu/besu-cli/src/commands/asset/lock.ts index 223fce050..cda26c833 100644 --- a/samples/besu/besu-cli/src/commands/asset/lock.ts +++ b/samples/besu/besu-cli/src/commands/asset/lock.ts @@ -1,12 +1,18 @@ import { GluegunCommand } from 'gluegun' import { getNetworkConfig, commandHelp } from '../../helper/helper' import { getContractInstance } from '../../helper/besu-functions' -const Web3 = require ("web3") +const Web3 = require("web3") const crypto = require('crypto') +async function getBalances(tokenContract, address, token_id=0, asset_type="ERC20"){ + if (asset_type=="ERC1155") + return tokenContract.balanceOf(address, token_id) + return tokenContract.balanceOf(address) +} + const command: GluegunCommand = { name: 'lock', - description: 'Lock assets', + description: 'Lock assets', run: async toolbox => { const { @@ -79,6 +85,11 @@ const command: GluegunCommand = { name: '--data', description: 'Specify the data for ERC1155 token. This is an optional parameter only for ERC1155.' + }, + { + name: '--asset_type', + description: + 'Specify the asset type. This is an optional parameter only for ERC721 & ERC1155.' } ], command, @@ -89,24 +100,28 @@ const command: GluegunCommand = { print.info('Lock assets') // Retrieving networkConfig - if(!options.network){ + if (!options.network) { print.error('Network ID not provided.') return } const networkConfig = getNetworkConfig(options.network) - var networkPort = networkConfig.networkPort - if(options.network_port){ - networkPort = options.network_port - console.log('Use network port : ', networkPort) - } - var networkHost = networkConfig.networkHost - if(options.network_host){ - networkHost = options.network_host - console.log('Use network host : ', networkHost) - } + var networkPort = networkConfig.networkPort + if (options.network_port) { + networkPort = options.network_port + console.log('Use network port : ', networkPort) + } + var networkHost = networkConfig.networkHost + if (options.network_host) { + networkHost = options.network_host + console.log('Use network host : ', networkHost) + } + + if (!options.asset_type) { + options.asset_type = "ERC20"; + } - const provider = new Web3.providers.HttpProvider('http://'+networkHost+':'+networkPort) + const provider = new Web3.providers.HttpProvider('http://' + networkHost + ':' + networkPort) const web3N = new Web3(provider) const interopContract = await getContractInstance(provider, networkConfig.interopContract).catch(function () { console.log("Failed getting interopContract!"); @@ -117,41 +132,41 @@ const command: GluegunCommand = { const accounts = await web3N.eth.getAccounts() // Receving the input parameters - if(!options.amount){ + if (!options.amount) { print.error('Amount not provided.') return } const amount = options.amount var sender - if(options.sender_account){ + if (options.sender_account) { sender = accounts[options.sender_account] } - else if(options.sender_account_address){ - sender = '0x'+ options.sender_account_address + else if (options.sender_account_address) { + sender = '0x' + options.sender_account_address } - else{ + else { print.info('Sender account index not provided. Taking from networkConfig..') sender = accounts[networkConfig.senderAccountIndex] } var recipient - if(options.recipient_account){ + if (options.recipient_account) { recipient = accounts[options.recipient_account] } - else if(options.recipient_account_address){ - recipient = '0x'+ options.recipient_account_address + else if (options.recipient_account_address) { + recipient = '0x' + options.recipient_account_address } - else{ + else { print.info('Recipient account index not provided. Taking from networkConfig..') recipient = accounts[networkConfig.recipientAccountIndex] } - if(!options.timeout){ + if (!options.timeout) { print.error('Timeout not provided.') return } - if(!options.token_id){ + if (!options.token_id) { options.token_id = 0 } - if(!options.data){ + if (!options.data) { options.data = "" } const timeLock = Math.floor(Date.now() / 1000) + options.timeout @@ -160,10 +175,10 @@ const command: GluegunCommand = { var preimage var hash_base64 var preimage_bytes - if(options.hash_base64){ + if (options.hash_base64) { hash_base64 = options.hash_base64 } - else{ + else { // Generate a hash pair if not provided as an input parameter preimage = crypto.randomBytes(22).toString('base64') hash_base64 = crypto.createHash('sha256').update(preimage).digest('base64') @@ -171,7 +186,7 @@ const command: GluegunCommand = { console.log('Length of preimage byte array', preimage_bytes.length) } hash = Buffer.from(hash_base64, 'base64') - + console.log('Parameters:') console.log('networkConfig', networkConfig) console.log('Sender', sender) @@ -180,18 +195,30 @@ const command: GluegunCommand = { console.log('Timeout', timeLock) console.log('Hash (base64): ', hash_base64) console.log('Preimage: ', preimage) - + // Balances of sender and receiver before locking console.log(`Account balances before locking`) - var senderBalance = await tokenContract.balanceOf(sender) + var senderBalance = await getBalances(tokenContract, sender, options.token_id, options.asset_type) console.log(`Account balance of the sender in Network ${options.network}: ${senderBalance.toString()}`) - var recipientBalance = await tokenContract.balanceOf(recipient) + var recipientBalance = await getBalances(tokenContract, recipient, options.token_id, options.asset_type) console.log(`Account balance of the recipient in Network ${options.network}: ${recipientBalance.toString()}`) // Locking the asset (works only for ERC20 at this point) - await tokenContract.approve(tokenContract.address, amount, {from: sender}).catch(function () { - console.log("Token approval failed!!!"); - }) + if (options.asset_type == "ERC721") { + await tokenContract.approve(tokenContract.address, options.token_id, { from: sender }).catch(function () { + console.log("ERC 721 Token approval failed!!!"); + return false; + }) + } else if (options.asset_type == "ERC1155") { + await tokenContract.setApprovalForAll(tokenContract.address, true, { from: sender }).catch(function () { + console.log("Token approval failed!!!"); + }) + }else{ + await tokenContract.approve(tokenContract.address, amount, { from: sender }).catch(function () { + console.log("Token approval failed!!!"); + }) + } + const lockTx = await interopContract.lockAsset( recipient, tokenContract.address, @@ -204,6 +231,7 @@ const command: GluegunCommand = { from: sender } ).catch(function (e) { + console.log(e) console.log("lockAsset threw an error"); }) const lockContractId = lockTx.logs[0].args.lockContractId @@ -211,9 +239,9 @@ const command: GluegunCommand = { // Balances of sender and receiver after locking console.log(`Account balances after locking`) - var senderBalance = await tokenContract.balanceOf(sender) + var senderBalance = await getBalances(tokenContract, sender, options.token_id, options.asset_type) console.log(`Account balance of the sender in Network ${options.network}: ${senderBalance.toString()}`) - var recipientBalance = await tokenContract.balanceOf(recipient) + var recipientBalance = await getBalances(tokenContract, recipient, options.token_id, options.asset_type) console.log(`Account balance of the recipient in Network ${options.network}: ${recipientBalance.toString()}`) } } diff --git a/samples/besu/besu-cli/src/commands/asset/unlock.ts b/samples/besu/besu-cli/src/commands/asset/unlock.ts index 36c89c6d5..ce39d3bae 100644 --- a/samples/besu/besu-cli/src/commands/asset/unlock.ts +++ b/samples/besu/besu-cli/src/commands/asset/unlock.ts @@ -1,8 +1,19 @@ import { GluegunCommand } from 'gluegun' import { getNetworkConfig, commandHelp } from '../../helper/helper' import { getContractInstance } from '../../helper/besu-functions' +// import { send } from 'process' const Web3 = require ("web3") - +async function getBalances(tokenContract, address, token_id=0, asset_type="ERC20"){ + try{ + var balance = await tokenContract.balanceOf(address, token_id) + }catch{ + var balance = null; + } + if (!balance) + return await tokenContract.balanceOf(address) + else + return balance; +} const command: GluegunCommand = { name: 'unlock', description: 'Unlock and reclaim assets after timeout (fungible assets for now)', @@ -48,7 +59,12 @@ const command: GluegunCommand = { name: '--network_port', description: 'The network port. Default value is taken from config.json' - } + }, + { + name: '--token_id', + description: + 'token ID for issuing tokens. Only applicable for ERC1155' + }, ], command, ['asset', 'unlock'] @@ -109,7 +125,7 @@ const command: GluegunCommand = { console.log('Lock Contract ID', lockContractId) // Balance of the recipient before claiming - var senderBalance = await tokenContract.balanceOf(sender) + var senderBalance = await getBalances(tokenContract, sender, options.token_id) console.log(`Account balance of the sender in Network ${options.network} before unlocking: ${senderBalance.toString()}`) await interopContract.unlockAsset(lockContractId, { @@ -120,7 +136,7 @@ const command: GluegunCommand = { }) // Balance of the recipient after claiming - var senderBalance = await tokenContract.balanceOf(sender) + var senderBalance = await getBalances(tokenContract, sender, options.token_id) console.log(`Account balance of the sender in Network ${options.network} after unlocking: ${senderBalance.toString()}`) } } diff --git a/samples/besu/simpleasset/contracts/AliceERC721.sol b/samples/besu/simpleasset/contracts/AliceERC721.sol index 14592aef3..c0e276cfc 100644 --- a/samples/besu/simpleasset/contracts/AliceERC721.sol +++ b/samples/besu/simpleasset/contracts/AliceERC721.sol @@ -15,19 +15,19 @@ contract AliceERC721 is ERC721, transferInterface { address owner; constructor() ERC721("Alice NFT", "AliceNFT") { - for (uint256 i = 0; i < 5; i++) { - _tokenIds.increment(); - uint256 newItemId = _tokenIds.current(); - _safeMint(msg.sender, newItemId); - } + // for (uint256 i = 0; i < 5; i++) { + // _tokenIds.increment(); + // uint256 newItemId = _tokenIds.current(); + // _safeMint(msg.sender, newItemId); + // } owner = msg.sender; } function mint(address to) public { require(msg.sender == owner); - _tokenIds.increment(); uint256 newItemId = _tokenIds.current(); _safeMint(to, newItemId); + _tokenIds.increment(); } function transferInterop(transferStruct.Info memory info) @@ -35,7 +35,7 @@ contract AliceERC721 is ERC721, transferInterface { override returns (bool success) { - this.transferFrom(info.sender, info.receiver, info.amount); + this.transferFrom(info.sender, info.receiver, info.tokenId); return true; } diff --git a/samples/besu/simpleasset/contracts/AlliceERC1155.sol b/samples/besu/simpleasset/contracts/AlliceERC1155.sol index 72815425e..3dd6ff2fe 100644 --- a/samples/besu/simpleasset/contracts/AlliceERC1155.sol +++ b/samples/besu/simpleasset/contracts/AlliceERC1155.sol @@ -11,10 +11,12 @@ import "./transferInterface.sol"; contract AliceERC1155 is ERC1155, transferInterface { uint256 public constant AliceToken = 0; uint256 public constant AliceNFT = 1; + address owner; constructor() ERC1155("") { _mint(msg.sender, AliceToken, 10**18, ""); _mint(msg.sender, AliceNFT, 1, ""); + owner = msg.sender; } function transferInterop(transferStruct.Info memory info) @@ -40,4 +42,9 @@ contract AliceERC1155 is ERC1155, transferInterface { { return this.isApprovedForAll(info.sender, address(this)); } + + function mint(address to, uint256 tokenId, uint256 amount, bytes memory data) public { + require(msg.sender == owner); + _mint(to, tokenId, amount, data); + } } From c5d10015f719ba91e8721bf61d74bc6050140ed7 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Mon, 19 Sep 2022 19:06:43 +0000 Subject: [PATCH 128/150] Added filters to Corda package publishing Github workflows Signed-off-by: VRamakrishna --- .github/workflows/deploy_corda-pkgs.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy_corda-pkgs.yml b/.github/workflows/deploy_corda-pkgs.yml index d860ef45d..6638b4a06 100644 --- a/.github/workflows/deploy_corda-pkgs.yml +++ b/.github/workflows/deploy_corda-pkgs.yml @@ -19,6 +19,7 @@ on: jobs: publish-protos: + if: github.repository_owner == 'hyperledger-labs' runs-on: ubuntu-latest steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it @@ -45,7 +46,7 @@ jobs: publish-interop-app: - if: always() + if: ${{ always() && github.repository_owner == 'hyperledger-labs' }} needs: publish-protos runs-on: ubuntu-latest steps: @@ -76,7 +77,7 @@ jobs: working-directory: core/network/corda-interop-app publish-sdk: - if: always() + if: ${{ always() && github.repository_owner == 'hyperledger-labs' }} needs: [publish-protos, publish-interop-app] runs-on: ubuntu-latest steps: From b838904d7b8ed7b6054b18a5bfa4e13e17564a75 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Thu, 22 Sep 2022 18:09:17 +0000 Subject: [PATCH 129/150] Fabric CLI Upgrade to handle IIN Agents and Counter Attested Foreign Memberships Updated and debugged Fabric Interop CC to ensure consistent data formatting across modules. Signed-off-by: VRamakrishna --- .../contracts/interop/decoders.go | 15 +- .../contracts/interop/membership.go | 74 ++++---- .../contracts/interop/membership_test.go | 135 ++++++++------- samples/fabric/fabric-cli/.gitignore | 4 + .../fabric-cli/src/commands/configure/all.ts | 17 +- .../src/commands/configure/network.ts | 3 + .../fabric-cli/src/commands/user/add.ts | 34 ++-- .../src/helpers/fabric-functions.ts | 159 +++++++++++++++--- .../interop-setup/configure-network.ts | 78 ++++++++- .../src/wallet-Dummy_Network/admin.id | 1 - .../src/wallet-Dummy_Network/alice.id | 1 - .../src/wallet-Dummy_Network/bob.id | 1 - .../src/wallet-Dummy_Network/user1.id | 1 - 13 files changed, 360 insertions(+), 163 deletions(-) delete mode 100644 samples/fabric/fabric-cli/src/wallet-Dummy_Network/admin.id delete mode 100644 samples/fabric/fabric-cli/src/wallet-Dummy_Network/alice.id delete mode 100644 samples/fabric/fabric-cli/src/wallet-Dummy_Network/bob.id delete mode 100644 samples/fabric/fabric-cli/src/wallet-Dummy_Network/user1.id diff --git a/core/network/fabric-interop-cc/contracts/interop/decoders.go b/core/network/fabric-interop-cc/contracts/interop/decoders.go index e8532ca1f..e8b5fee0c 100644 --- a/core/network/fabric-interop-cc/contracts/interop/decoders.go +++ b/core/network/fabric-interop-cc/contracts/interop/decoders.go @@ -12,11 +12,14 @@ package main import ( + "encoding/base64" "encoding/json" "strings" + "fmt" "github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go/common" "github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go/identity" + protoV2 "google.golang.org/protobuf/proto" ) func decodeMembership(jsonBytes []byte) (*common.Membership, error) { @@ -30,13 +33,15 @@ func decodeMembership(jsonBytes []byte) (*common.Membership, error) { return &decodeObj, nil } -func decodeCounterAttestedMembership(jsonBytes []byte) (*identity.CounterAttestedMembership, error) { +func decodeCounterAttestedMembership(protoBytesBase64 string) (*identity.CounterAttestedMembership, error) { var decodeObj identity.CounterAttestedMembership - dec := json.NewDecoder(strings.NewReader(string(jsonBytes))) - dec.DisallowUnknownFields() - err := dec.Decode(&decodeObj) + protoBytes, err := base64.StdEncoding.DecodeString(protoBytesBase64) if err != nil { - return nil, err + return nil, fmt.Errorf("Counter attested membership could not be decoded from base64: %s", err.Error()) + } + err = protoV2.Unmarshal(protoBytes, &decodeObj) + if err != nil { + return nil, fmt.Errorf("Unable to unmarshal counter attested membership: %s", err.Error()) } return &decodeObj, nil } diff --git a/core/network/fabric-interop-cc/contracts/interop/membership.go b/core/network/fabric-interop-cc/contracts/interop/membership.go index 94e742250..5770406ef 100644 --- a/core/network/fabric-interop-cc/contracts/interop/membership.go +++ b/core/network/fabric-interop-cc/contracts/interop/membership.go @@ -157,7 +157,7 @@ func (s *SmartContract) UpdateLocalMembership(ctx contractapi.TransactionContext } membershipLocalKey, err := ctx.GetStub().CreateCompositeKey(membershipObjectType, []string{membershipLocalSecurityDomain}) - _, getErr := s.GetMembershipBySecurityDomain(ctx, membership.SecurityDomain) + _, getErr := s.GetMembershipBySecurityDomain(ctx, membershipLocalSecurityDomain) if getErr != nil { return getErr } @@ -176,14 +176,20 @@ func (s *SmartContract) UpdateLocalMembership(ctx contractapi.TransactionContext } -// CreateMembershipIIN cc is used to store a Membership in the ledger -// TODO: Replace 'CreateMembership' with this function after updating the Fabric CLI. -func (s *SmartContract) CreateMembershipIIN(ctx contractapi.TransactionContextInterface, counterAttestedMembershipJSON string) error { +// CreateMembership cc is used to store a Membership in the ledger +// TODO: Remove call to 'createMembership' after creating Corda IIN Agents. +func (s *SmartContract) CreateMembership(ctx contractapi.TransactionContextInterface, counterAttestedMembershipSerialized string) error { // Check if the caller has IIN agent privileges if isIINAgent, err := isClientIINAgent(ctx); err != nil { return fmt.Errorf("IIN Agent client check error: %s", err) } else if !isIINAgent { - return fmt.Errorf("Caller not an IIN Agent; access denied") + // Check if the caller has network admin privileges + if isAdmin, err := isClientNetworkAdmin(ctx); err != nil { + return fmt.Errorf("Admin client check error: %s", err) + } else if !isAdmin { + return fmt.Errorf("Caller neither a network admin nor an IIN Agent; access denied") + } + return s.createMembership(ctx, counterAttestedMembershipSerialized) // HACK to handle unattested memberships (for Corda) for backward compatibility } // Check if caller is one of the authorized IIN agents @@ -205,7 +211,7 @@ func (s *SmartContract) CreateMembershipIIN(ctx contractapi.TransactionContextIn return fmt.Errorf("Caller with identity %+v is not a designated IIN Agent: %+v", callerId, err) } - counterAttestedMembership, err := decodeCounterAttestedMembership([]byte(counterAttestedMembershipJSON)) + counterAttestedMembership, err := decodeCounterAttestedMembership(counterAttestedMembershipSerialized) if err != nil { return fmt.Errorf("Counter Attested Membership Unmarshal error: %s", err) } @@ -304,16 +310,16 @@ func (s *SmartContract) CreateMembershipIIN(ctx contractapi.TransactionContextIn return fmt.Errorf("Membership already exists for membership id: %s. Use 'UpdateMembership' to update.", foreignMembership.SecurityDomain) } - membershipBytes, err := json.Marshal(attestedMembershipSet.Membership) + membershipBytes, err := json.Marshal(foreignMembership) if err != nil { return fmt.Errorf("Marshal error: %s", err) } return ctx.GetStub().PutState(membershipKey, membershipBytes) } -// CreateMembership cc is used to store a Membership in the ledger -// TODO: Replace this function with 'CreateMembership' after updating the Fabric CLI. Retaining this temporarily for backward compatibility. -func (s *SmartContract) CreateMembership(ctx contractapi.TransactionContextInterface, membershipJSON string) error { +// createMembership is used by a network admin to store a Membership in the ledger with an unattested membership +// TODO: Remove this function after creating Corda IIN Agents. Retaining this temporarily for backward compatibility. +func (s *SmartContract) createMembership(ctx contractapi.TransactionContextInterface, membershipJSON string) error { membership, err := decodeMembership([]byte(membershipJSON)) if err != nil { return fmt.Errorf("Unmarshal error: %s", err) @@ -340,14 +346,20 @@ func (s *SmartContract) CreateMembership(ctx contractapi.TransactionContextInter return ctx.GetStub().PutState(membershipKey, membershipBytes) } -// UpdateMembershipIIN cc is used to update an existing Membership in the ledger -// TODO: Replace 'UpdateMembership' with this function after updating the Fabric CLI. -func (s *SmartContract) UpdateMembershipIIN(ctx contractapi.TransactionContextInterface, counterAttestedMembershipJSON string) error { +// UpdateMembership cc is used to update an existing Membership in the ledger +// TODO: Remove call to 'updateMembership' after creating Corda IIN Agents. +func (s *SmartContract) UpdateMembership(ctx contractapi.TransactionContextInterface, counterAttestedMembershipSerialized string) error { // Check if the caller has IIN agent privileges if isIINAgent, err := isClientIINAgent(ctx); err != nil { return fmt.Errorf("IIN Agent client check error: %s", err) } else if !isIINAgent { - return fmt.Errorf("Caller not an IIN Agent; access denied") + // Check if the caller has network admin privileges + if isAdmin, err := isClientNetworkAdmin(ctx); err != nil { + return fmt.Errorf("Admin client check error: %s", err) + } else if !isAdmin { + return fmt.Errorf("Caller neither a network admin nor an IIN Agent; access denied") + } + return s.updateMembership(ctx, counterAttestedMembershipSerialized) // HACK to handle unattested memberships (for Corda) for backward compatibility } // Check if caller is one of the authorized IIN agents @@ -369,7 +381,7 @@ func (s *SmartContract) UpdateMembershipIIN(ctx contractapi.TransactionContextIn return fmt.Errorf("Caller with identity %+v is not a designated IIN Agent: %+v", callerId, err) } - counterAttestedMembership, err := decodeCounterAttestedMembership([]byte(counterAttestedMembershipJSON)) + counterAttestedMembership, err := decodeCounterAttestedMembership(counterAttestedMembershipSerialized) if err != nil { return fmt.Errorf("Counter Attested Membership Unmarshal error: %s", err) } @@ -465,7 +477,7 @@ func (s *SmartContract) UpdateMembershipIIN(ctx contractapi.TransactionContextIn return getErr } - membershipBytes, err := json.Marshal(attestedMembershipSet.Membership) + membershipBytes, err := json.Marshal(foreignMembership) if err != nil { return fmt.Errorf("Marshal error: %s", err) } @@ -473,9 +485,9 @@ func (s *SmartContract) UpdateMembershipIIN(ctx contractapi.TransactionContextIn } -// UpdateMembership cc is used to update an existing Membership in the ledger -// TODO: Replace this function with 'UpdateMembership' after updating the Fabric CLI. Retaining this temporarily for backward compatibility. -func (s *SmartContract) UpdateMembership(ctx contractapi.TransactionContextInterface, membershipJSON string) error { +// updateMembership is used by a network admin to update an existing Membership in the ledger with an unattested membership +// TODO: Remove this function after creating Corda IIN Agents. Retaining this temporarily for backward compatibility. +func (s *SmartContract) updateMembership(ctx contractapi.TransactionContextInterface, membershipJSON string) error { membership, err := decodeMembership([]byte(membershipJSON)) if err != nil { return fmt.Errorf("Unmarshal error: %s", err) @@ -525,9 +537,8 @@ func (s *SmartContract) DeleteLocalMembership(ctx contractapi.TransactionContext return nil } -// DeleteMembershipIIN cc is used to delete an existing Membership in the ledger -// TODO: Replace 'DeleteMembership' with this function after updating the Fabric CLI. -func (s *SmartContract) DeleteMembershipIIN(ctx contractapi.TransactionContextInterface, membershipID string) error { +// DeleteMembership cc is used to delete an existing Membership in the ledger +func (s *SmartContract) DeleteMembership(ctx contractapi.TransactionContextInterface, membershipID string) error { // Check if the caller has IIN agent privileges if isIINAgent, err := isClientIINAgent(ctx); err != nil { return fmt.Errorf("IIN Agent client check error: %s", err) @@ -551,25 +562,6 @@ func (s *SmartContract) DeleteMembershipIIN(ctx contractapi.TransactionContextIn return nil } -// DeleteMembership cc is used to delete an existing Membership in the ledger -// TODO: Replace this function with 'DeleteMembership' after updating the Fabric CLI. Retaining this temporarily for backward compatibility. -func (s *SmartContract) DeleteMembership(ctx contractapi.TransactionContextInterface, membershipID string) error { - membershipKey, err := ctx.GetStub().CreateCompositeKey(membershipObjectType, []string{membershipID}) - bytes, err := ctx.GetStub().GetState(membershipKey) - if err != nil { - return err - } - if bytes == nil { - return fmt.Errorf("Membership with id: %s does not exist", membershipID) - } - err = ctx.GetStub().DelState(membershipKey) - if err != nil { - return fmt.Errorf("failed to delete asset %s: %v", membershipKey, err) - } - - return nil -} - // GetMembershipBySecurityDomain cc gets the Membership for the provided id func (s *SmartContract) GetMembershipBySecurityDomain(ctx contractapi.TransactionContextInterface, securityDomain string) (string, error) { membershipKey, err := ctx.GetStub().CreateCompositeKey(membershipObjectType, []string{securityDomain}) diff --git a/core/network/fabric-interop-cc/contracts/interop/membership_test.go b/core/network/fabric-interop-cc/contracts/interop/membership_test.go index fd74aa964..112d92cb7 100644 --- a/core/network/fabric-interop-cc/contracts/interop/membership_test.go +++ b/core/network/fabric-interop-cc/contracts/interop/membership_test.go @@ -259,7 +259,7 @@ func TestUpdateLocalMembership(t *testing.T) { clientIdentity.GetAttributeValueCalls(setClientAdmin) ctx.GetClientIdentityReturns(clientIdentity) err = interopcc.UpdateLocalMembership(ctx, string(membershipBytes)) - require.EqualError(t, err, fmt.Sprintf("Membership with id: %s does not exist", membershipAsset.SecurityDomain)) + require.EqualError(t, err, fmt.Sprintf("Membership with id: %s does not exist", membershipLocalSecurityDomain)) // Valid cert chain member := &member1 @@ -267,7 +267,7 @@ func TestUpdateLocalMembership(t *testing.T) { membershipBytes, err = json.Marshal(&membershipAsset) require.NoError(t, err) err = interopcc.UpdateLocalMembership(ctx, string(membershipBytes)) - require.EqualError(t, err, fmt.Sprintf("Membership with id: %s does not exist", membershipAsset.SecurityDomain)) + require.EqualError(t, err, fmt.Sprintf("Membership with id: %s does not exist", membershipLocalSecurityDomain)) // Membership already exists update the Membership chaincodeStub.GetStateReturns(membershipBytes, nil) @@ -294,7 +294,7 @@ func TestUpdateLocalMembership(t *testing.T) { } // TODO: Remove later. Keeping for backward compatibility. -func TestCreateMembership(t *testing.T) { +func TestCreateMembershipUnattested(t *testing.T) { ctx, chaincodeStub := wtest.PrepMockStub() interopcc := SmartContract{} @@ -306,6 +306,14 @@ func TestCreateMembership(t *testing.T) { membershipBytes, err := json.Marshal(&membershipAsset) require.NoError(t, err) + + // Case when caller is not an admin + err = interopcc.CreateMembership(ctx, string(membershipBytes)) + require.EqualError(t, err, "Caller neither a network admin nor an IIN Agent; access denied") + // Case when no Membership is found + clientIdentity := &mocks.ClientIdentity{} + clientIdentity.GetAttributeValueCalls(setClientAdmin) + ctx.GetClientIdentityReturns(clientIdentity) err = interopcc.CreateMembership(ctx, string(membershipBytes)) require.NoError(t, err) // Invalid Input check @@ -317,8 +325,7 @@ func TestCreateMembership(t *testing.T) { require.EqualError(t, err, fmt.Sprintf("Membership already exists for membership id: %s. Use 'UpdateMembership' to update.", membershipAsset.SecurityDomain)) } -// TODO: Rename later. -func TestCreateMembershipIIN(t *testing.T) { +func TestCreateMembership(t *testing.T) { ctx, chaincodeStub := wtest.PrepMockStub() interopcc := SmartContract{} @@ -458,16 +465,17 @@ func TestCreateMembershipIIN(t *testing.T) { } // Record membership info: should fail because the caller is not an IIN Agent - counterAttestedMembershipBytes, err := json.Marshal(&counterAttestedMembership) + counterAttestedMembershipBytesPlain, err := protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) - err = interopcc.CreateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) - require.EqualError(t, err, "Caller not an IIN Agent; access denied") + counterAttestedMembershipBytes := base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) + err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + require.EqualError(t, err, "Caller neither a network admin nor an IIN Agent; access denied") // Record membership info: should fail because the local IIN Agent is not registered clientIdentity := &mocks.ClientIdentity{} clientIdentity.GetAttributeValueCalls(setClientIINAgent) ctx.GetClientIdentityReturns(clientIdentity) - err = interopcc.CreateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) require.Error(t, err) // Record local membership info @@ -483,13 +491,13 @@ func TestCreateMembershipIIN(t *testing.T) { chaincodeStub.GetStateReturnsOnCall(3, nil, nil) clientIdentity.GetAttributeValueCalls(setClientIINAgent) ctx.GetClientIdentityReturns(clientIdentity) - err = interopcc.CreateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) require.NoError(t, err) // Record membership info again: should fail because membership has already been recorded against this security domain chaincodeStub.GetStateReturnsOnCall(4, localMembershipBytes, nil) chaincodeStub.GetStateReturnsOnCall(5, []byte{}, nil) - err = interopcc.CreateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, fmt.Sprintf("Membership already exists for membership id: %s. Use 'UpdateMembership' to update.", membershipAsset.SecurityDomain)) // One of the local signatures is invalid: should fail @@ -498,11 +506,12 @@ func TestCreateMembershipIIN(t *testing.T) { signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) require.NoError(t, err) attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) - counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) + counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) + counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) chaincodeStub.GetStateReturnsOnCall(6, localMembershipBytes, nil) chaincodeStub.GetStateReturnsOnCall(7, nil, nil) - err = interopcc.CreateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, "Unable to Validate Signature: Signature Verification failed. ECDSA VERIFY") // One of the foreign signatures is invalid: should fail @@ -527,10 +536,11 @@ func TestCreateMembershipIIN(t *testing.T) { require.NoError(t, err) attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes - counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) + counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) + counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) chaincodeStub.GetStateReturnsOnCall(7, localMembershipBytes, nil) - err = interopcc.CreateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, "Unable to Validate Signature: Signature Verification failed. ECDSA VERIFY") // One of the foreign attestations has an invalid nonce: should fail @@ -556,10 +566,11 @@ func TestCreateMembershipIIN(t *testing.T) { require.NoError(t, err) attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes - counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) + counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) + counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) chaincodeStub.GetStateReturnsOnCall(8, localMembershipBytes, nil) - err = interopcc.CreateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, fmt.Sprintf("Mismatched nonces across two attestations: %s, %s", nonce, attestation1.Nonce)) // Foreign membership has an invalid cert chain: should fail @@ -599,10 +610,11 @@ func TestCreateMembershipIIN(t *testing.T) { require.NoError(t, err) attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes - counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) + counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) + counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) chaincodeStub.GetStateReturnsOnCall(9, localMembershipBytes, nil) - err = interopcc.CreateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) require.Error(t, err) // Foreign attestation has invalid security domain: should fail @@ -642,15 +654,16 @@ func TestCreateMembershipIIN(t *testing.T) { require.NoError(t, err) attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes - counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) + counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) + counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) chaincodeStub.GetStateReturnsOnCall(10, localMembershipBytes, nil) - err = interopcc.CreateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, fmt.Sprintf("Foreign agent security domain %s does not match attested membership security domain invalid", securityDomainId)) } // TODO: Remove later. Keeping for backward compatibility. -func TestUpdateMembership(t *testing.T) { +func TestUpdateMembershipUnattested(t *testing.T) { ctx, chaincodeStub := wtest.PrepMockStub() interopcc := SmartContract{} @@ -662,6 +675,14 @@ func TestUpdateMembership(t *testing.T) { membershipBytes, err := json.Marshal(&membershipAsset) require.NoError(t, err) + + // Case when caller is not an admin + err = interopcc.UpdateMembership(ctx, string(membershipBytes)) + require.EqualError(t, err, "Caller neither a network admin nor an IIN Agent; access denied") + // Case when no Membership is found + clientIdentity := &mocks.ClientIdentity{} + clientIdentity.GetAttributeValueCalls(setClientAdmin) + ctx.GetClientIdentityReturns(clientIdentity) err = interopcc.UpdateMembership(ctx, string(membershipBytes)) require.EqualError(t, err, fmt.Sprintf("Membership with id: %s does not exist", membershipAsset.SecurityDomain)) // Invalid Input check @@ -674,8 +695,7 @@ func TestUpdateMembership(t *testing.T) { require.NoError(t, err) } -// TODO: Rename later. -func TestUpdateMembershipIIN(t *testing.T) { +func TestUpdateMembership(t *testing.T) { ctx, chaincodeStub := wtest.PrepMockStub() interopcc := SmartContract{} @@ -815,16 +835,18 @@ func TestUpdateMembershipIIN(t *testing.T) { } // Record membership info: should fail because the caller is not an IIN Agent - counterAttestedMembershipBytes, err := json.Marshal(&counterAttestedMembership) + counterAttestedMembershipBytesPlain, err := protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) - err = interopcc.UpdateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) - require.EqualError(t, err, "Caller not an IIN Agent; access denied") + counterAttestedMembershipBytes := base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) + require.NoError(t, err) + err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + require.EqualError(t, err, "Caller neither a network admin nor an IIN Agent; access denied") // Record membership info: should fail because the local IIN Agent is not registered clientIdentity := &mocks.ClientIdentity{} clientIdentity.GetAttributeValueCalls(setClientIINAgent) ctx.GetClientIdentityReturns(clientIdentity) - err = interopcc.UpdateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) require.Error(t, err) // Record local membership info @@ -840,13 +862,13 @@ func TestUpdateMembershipIIN(t *testing.T) { chaincodeStub.GetStateReturnsOnCall(3, nil, nil) clientIdentity.GetAttributeValueCalls(setClientIINAgent) ctx.GetClientIdentityReturns(clientIdentity) - err = interopcc.UpdateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, fmt.Sprintf("Membership with id: %s does not exist", securityDomainId)) // Record membership info again: should succeed now chaincodeStub.GetStateReturnsOnCall(4, localMembershipBytes, nil) chaincodeStub.GetStateReturnsOnCall(5, []byte{}, nil) - err = interopcc.UpdateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) require.NoError(t, err) // One of the local signatures is invalid: should fail @@ -855,11 +877,12 @@ func TestUpdateMembershipIIN(t *testing.T) { signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) require.NoError(t, err) attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) - counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) + counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) + counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) chaincodeStub.GetStateReturnsOnCall(6, localMembershipBytes, nil) chaincodeStub.GetStateReturnsOnCall(7, []byte{}, nil) - err = interopcc.UpdateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, "Unable to Validate Signature: Signature Verification failed. ECDSA VERIFY") // One of the foreign signatures is invalid: should fail @@ -884,10 +907,11 @@ func TestUpdateMembershipIIN(t *testing.T) { require.NoError(t, err) attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes - counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) + counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) + counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) chaincodeStub.GetStateReturnsOnCall(7, localMembershipBytes, nil) - err = interopcc.UpdateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, "Unable to Validate Signature: Signature Verification failed. ECDSA VERIFY") // One of the foreign attestations has an invalid nonce: should fail @@ -913,10 +937,11 @@ func TestUpdateMembershipIIN(t *testing.T) { require.NoError(t, err) attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes - counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) + counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) + counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) chaincodeStub.GetStateReturnsOnCall(8, localMembershipBytes, nil) - err = interopcc.UpdateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, fmt.Sprintf("Mismatched nonces across two attestations: %s, %s", nonce, attestation1.Nonce)) // Foreign membership has an invalid cert chain: should fail @@ -956,10 +981,11 @@ func TestUpdateMembershipIIN(t *testing.T) { require.NoError(t, err) attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes - counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) + counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) + counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) chaincodeStub.GetStateReturnsOnCall(9, localMembershipBytes, nil) - err = interopcc.UpdateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) require.Error(t, err) // Foreign attestation has invalid security domain: should fail @@ -999,10 +1025,11 @@ func TestUpdateMembershipIIN(t *testing.T) { require.NoError(t, err) attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes - counterAttestedMembershipBytes, err = json.Marshal(&counterAttestedMembership) + counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) + counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) chaincodeStub.GetStateReturnsOnCall(10, localMembershipBytes, nil) - err = interopcc.UpdateMembershipIIN(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) require.EqualError(t, err, fmt.Sprintf("Foreign agent security domain %s does not match attested membership security domain invalid", securityDomainId)) } @@ -1037,28 +1064,8 @@ func TestDeleteMembership(t *testing.T) { ctx, chaincodeStub := wtest.PrepMockStub() interopcc := SmartContract{} - // Case when a Membership exists - chaincodeStub.GetStateReturns([]byte{}, nil) - err := interopcc.DeleteMembership(ctx, securityDomainId) - require.NoError(t, err) - - // Case when no Membership is found - chaincodeStub.GetStateReturns(nil, nil) - err = interopcc.DeleteMembership(ctx, securityDomainId) - require.EqualError(t, err, fmt.Sprintf("Membership with id: %s does not exist", securityDomainId)) - - // Handle GetState Error - chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) - err = interopcc.DeleteMembership(ctx, securityDomainId) - require.EqualError(t, err, fmt.Sprintf("unable to retrieve asset")) -} - -func TestDeleteMembershipIIN(t *testing.T) { - ctx, chaincodeStub := wtest.PrepMockStub() - interopcc := SmartContract{} - // Case when caller is not an IIN Agent - err := interopcc.DeleteMembershipIIN(ctx, securityDomainId) + err := interopcc.DeleteMembership(ctx, securityDomainId) require.EqualError(t, err, "Caller not an IIN Agent; access denied") // Case when a Membership exists @@ -1066,17 +1073,17 @@ func TestDeleteMembershipIIN(t *testing.T) { clientIdentity.GetAttributeValueCalls(setClientIINAgent) ctx.GetClientIdentityReturns(clientIdentity) chaincodeStub.GetStateReturns([]byte{}, nil) - err = interopcc.DeleteMembershipIIN(ctx, securityDomainId) + err = interopcc.DeleteMembership(ctx, securityDomainId) require.NoError(t, err) // Case when no Membership is found chaincodeStub.GetStateReturns(nil, nil) - err = interopcc.DeleteMembershipIIN(ctx, securityDomainId) + err = interopcc.DeleteMembership(ctx, securityDomainId) require.EqualError(t, err, fmt.Sprintf("Membership with id: %s does not exist", securityDomainId)) // Handle GetState Error chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) - err = interopcc.DeleteMembershipIIN(ctx, securityDomainId) + err = interopcc.DeleteMembership(ctx, securityDomainId) require.EqualError(t, err, fmt.Sprintf("unable to retrieve asset")) } diff --git a/samples/fabric/fabric-cli/.gitignore b/samples/fabric/fabric-cli/.gitignore index de9b193dc..797eaadb3 100644 --- a/samples/fabric/fabric-cli/.gitignore +++ b/samples/fabric/fabric-cli/.gitignore @@ -18,3 +18,7 @@ src/wallet-network1 src/wallet-network2 chaincode.json remote-network-config.json +admin.id +networkadmin.id +iinagent.id +*.proto.serialized diff --git a/samples/fabric/fabric-cli/src/commands/configure/all.ts b/samples/fabric/fabric-cli/src/commands/configure/all.ts index 65fe891d1..b5754eee5 100644 --- a/samples/fabric/fabric-cli/src/commands/configure/all.ts +++ b/samples/fabric/fabric-cli/src/commands/configure/all.ts @@ -7,6 +7,7 @@ import { GluegunCommand } from 'gluegun' import * as path from 'path' import { commandHelp, addData, getNetworkConfig } from '../../helpers/helpers' +import { enrollAndRecordWalletIdentity } from '../../helpers/fabric-functions' import { generateMembership, generateAccessControl, @@ -52,8 +53,19 @@ const command: GluegunCommand = { logger.level = 'debug' logger.debug('Debugging is enabled') } + // for each network, generate network admin identity and IIN Agent identity (there's only one org per network) + const networkAdminUser = 'networkadmin' + const iinAgentUser = 'iinagent' + for (const network of array) { + // Create a network admin + print.info(`Creating network admin wallet identity for network: ${network}`) + await enrollAndRecordWalletIdentity(networkAdminUser, null, network, true, false) + // Create an IIN Agent + print.info(`Creating IIN Agent wallet identity for network: ${network}`) + await enrollAndRecordWalletIdentity(iinAgentUser, null, network, false, true) + } // for each network it - // 1. Generate network configs (membership, access control and verification policy) + // 1. Generate network configs (membership, access control, and verification policy) // 2. Add default data // 3. Loads configs from other networks in the credentials folder for (const network of array) { @@ -67,9 +79,10 @@ const command: GluegunCommand = { ) return } + const username = currusername || `user1` print.info(`Generating membership for network: ${network}`) - // 1. Generate network configs (membership, access control and verification policy) + // 1. Generate network configs (membership, access control, and verification policy) await generateMembership( process.env.DEFAULT_CHANNEL ? process.env.DEFAULT_CHANNEL : 'mychannel', process.env.DEFAULT_CHAINCODE diff --git a/samples/fabric/fabric-cli/src/commands/configure/network.ts b/samples/fabric/fabric-cli/src/commands/configure/network.ts index d31a79aca..6c90ed5cf 100644 --- a/samples/fabric/fabric-cli/src/commands/configure/network.ts +++ b/samples/fabric/fabric-cli/src/commands/configure/network.ts @@ -6,6 +6,7 @@ import { GluegunCommand } from 'gluegun' import { commandHelp } from '../../helpers/helpers' +import { enrollAndRecordWalletIdentity } from '../../helpers/fabric-functions' import { configureNetwork } from '../../helpers/interop-setup/configure-network' import logger from '../../helpers/logger' import * as path from 'path' @@ -47,6 +48,8 @@ const command: GluegunCommand = { logger.level = 'debug' logger.debug('Debugging is enabled') } + await enrollAndRecordWalletIdentity('networkadmin', null, options['local-network'], true, false) // Create a network admin + await enrollAndRecordWalletIdentity('iinagent', null, options['local-network'], false, true) // Create an IIN Agent await configureNetwork(options['local-network'], logger) process.exit() } diff --git a/samples/fabric/fabric-cli/src/commands/user/add.ts b/samples/fabric/fabric-cli/src/commands/user/add.ts index 727800c1f..2c4329c08 100644 --- a/samples/fabric/fabric-cli/src/commands/user/add.ts +++ b/samples/fabric/fabric-cli/src/commands/user/add.ts @@ -5,10 +5,10 @@ */ import { GluegunCommand } from 'gluegun' -import { commandHelp, getNetworkConfig, saveUserCertToFile } from '../../helpers/helpers' +import { commandHelp } from '../../helpers/helpers' import * as fs from 'fs' import * as path from 'path' -import { walletSetup } from '../../helpers/fabric-functions' +import { enrollAndRecordWalletIdentity } from '../../helpers/fabric-functions' const command: GluegunCommand = { name: 'add', @@ -23,7 +23,7 @@ const command: GluegunCommand = { print, toolbox, `fabric-cli user add --target-network=network1 --id=user --secret=userpw`, - `fabric-cli user add --target-network= --id= --secret=`, + `fabric-cli user add --target-network= --id= --secret= [--network-admin] [--iin-agent]`, [ { name: '--target-network', @@ -39,6 +39,16 @@ const command: GluegunCommand = { name: '--secret', description: 'password for the username being added (Optional: random password is used)' + }, + { + name: '--network-admin', + description: + 'Flag to indicate whether this user should have a network admin attribute.' + }, + { + name: '--iin-agent', + description: + 'Flag to indicate whether this user should have an IIN agent attribute.' } ], command, @@ -53,23 +63,7 @@ const command: GluegunCommand = { print.error('--id is required arguement, please specify the username here') } - const userName = options['id'] - const userPwd = options['secret'] - const net = getNetworkConfig(options['target-network']) - - const ccpPath = path.resolve(__dirname, net.connProfilePath) - const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8')) - console.log(net) - - let wallet = await walletSetup(options['target-network'], - ccp, - net.mspId, - userName, - userPwd, - true - ) - - saveUserCertToFile(userName, options['target-network']) + await enrollAndRecordWalletIdentity(options['id'], options['secret'], options['target-network'], options['network-admin'], options['iin-agent']) process.exit() } } diff --git a/samples/fabric/fabric-cli/src/helpers/fabric-functions.ts b/samples/fabric/fabric-cli/src/helpers/fabric-functions.ts index 72f756829..0f25a2854 100644 --- a/samples/fabric/fabric-cli/src/helpers/fabric-functions.ts +++ b/samples/fabric/fabric-cli/src/helpers/fabric-functions.ts @@ -5,10 +5,13 @@ */ import { Gateway, Wallets, Contract, X509Identity } from 'fabric-network' -import { handlePromise } from './helpers' +import { commandHelp, getNetworkConfig, saveUserCertToFile, handlePromise } from './helpers' import * as FabricCAServices from 'fabric-ca-client' import { Certificate } from '@fidm/x509' import { Utils, ICryptoKey } from 'fabric-common' +import * as membership_pb from "@hyperledger-labs/weaver-protos-js/common/membership_pb" +import * as iin_agent_pb from "@hyperledger-labs/weaver-protos-js/identity/agent_pb" +import { InteroperableHelper } from '@hyperledger-labs/weaver-fabric-interop-sdk' import * as path from 'path' import * as dotenv from 'dotenv' dotenv.config({ path: path.resolve(__dirname, '../../.env') }) @@ -25,10 +28,7 @@ const getUserCertBase64 = async ( networkName: string, username: string ) => { - const walletPath = process.env.WALLET_PATH - ? process.env.WALLET_PATH - : path.join(__dirname, '../', `wallet-${networkName}`) - const wallet = await Wallets.newFileSystemWallet(walletPath) + const wallet = await getWalletForNetwork(networkName) const userId = await wallet.get(username) if (!userId) { throw new Error(`User ${username} not present in wallet of ${networkName}.`) @@ -42,10 +42,11 @@ const walletSetup = async ( mspId: string, userName: string, userPwd: string = '', + isNetworkAdmin: boolean = false, + isIINAgent: boolean = false, register: boolean = false, logger: any = console ) => { - // Create a new CA client for interacting with the CA. // Create a new CA client for interacting with the CA. const org = ccp.client['organization'] const caName = ccp.organizations[org]['certificateAuthorities'][0] @@ -53,14 +54,10 @@ const walletSetup = async ( const ca = new FabricCAServices(caURL) const ident = ca.newIdentityService() - const walletPath = process.env.WALLET_PATH - ? process.env.WALLET_PATH - : path.join(__dirname, '../', `wallet-${networkName}`) - const wallet = await Wallets.newFileSystemWallet(walletPath) - - logger.debug(`Wallet Setup: wallet path: ${walletPath}`) + const wallet = await getWalletForNetwork(networkName) - // build a user object for authenticating with the CA // Check to see if we've already enrolled the admin user. + // build a user object for authenticating with the CA + // Check to see if we've already enrolled the admin user. let adminIdentity = await wallet.get('admin') if (adminIdentity) { @@ -94,8 +91,15 @@ const walletSetup = async ( logger.error(`Identity ${userName} does not exist. Please add user in the network.\n`) return } - var secret, enrollment; + var secret, enrollment var enrollmentDone = false + var attributes = [] + if (isNetworkAdmin) { + attributes.push({ "name": "network-admin", "value": "true", "ecert": true }) + } + if (isIINAgent) { + attributes.push({ "name": "iin-agent", "value": "true", "ecert": true }) + } try { if (!userPwd) { secret = await ca.register( @@ -103,7 +107,8 @@ const walletSetup = async ( affiliation: 'org1.department1', enrollmentID: userName, maxEnrollments: -1, - role: 'client' + role: 'client', + attrs: attributes }, adminUser ) @@ -115,7 +120,8 @@ const walletSetup = async ( enrollmentID: userName, enrollmentSecret: userPwd, maxEnrollments: -1, - role: 'client' + role: 'client', + attrs: attributes }, adminUser ) @@ -161,18 +167,40 @@ const walletSetup = async ( return wallet } + +const enrollAndRecordWalletIdentity = async ( + userName: string, + userPwd: string, + networkName: string, + isNetworkAdmin: boolean = false, + isIINAgent: boolean = false, + logger: any = console +) => { + const net = getNetworkConfig(networkName) + const ccpPath = path.resolve(__dirname, net.connProfilePath) + const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8')) + logger.info(net) + + const wallet = await walletSetup(networkName, ccp, net.mspId, userName, userPwd, isNetworkAdmin, isIINAgent, true) + saveUserCertToFile(userName, networkName) + + return wallet +} + const getCurrentNetworkCredentialPath = (networkName: string): string => { const credentialsPath = process.env.MEMBER_CREDENTIAL_FOLDER ? path.resolve(__dirname, process.env.MEMBER_CREDENTIAL_FOLDER, networkName) : path.join(__dirname, '../data', 'credentials', networkName) return credentialsPath } + const getCredentialPath = (): string => { const credentialsPath = process.env.MEMBER_CREDENTIAL_FOLDER ? path.resolve(__dirname, process.env.MEMBER_CREDENTIAL_FOLDER) : path.join(__dirname, '../data', 'credentials') return credentialsPath } + const generateAccessControl = async ( channel: string, contractName: string, @@ -269,6 +297,7 @@ const generateVerificationPolicy = async ( JSON.stringify(verificationPolicy) ) } + const generateMembership = async ( channel: string, contractName: string, @@ -289,7 +318,8 @@ const generateMembership = async ( const network = await gateway.getNetwork(channel) const mspConfig = await getMspConfig(network, logger) const membershipJSON = formatMSP(mspConfig, networkName) - logger.debug(`membershipJSON: ${JSON.stringify(membershipJSON)}`) + const membershipJSONStr = JSON.stringify(membershipJSON) + logger.debug(`membershipJSON: ${membershipJSONStr}`) const credentialsPath = getCurrentNetworkCredentialPath(networkName) logger.debug(`Credentials Path: ${credentialsPath}`) @@ -300,9 +330,84 @@ const generateMembership = async ( fs.writeFileSync( path.join(credentialsPath, `membership.json`), - JSON.stringify(membershipJSON) + membershipJSONStr ) - return mspConfig + + // Generate protobufs and attestations for all other networks that have IIN Agents + const credentialFolderPath = getCredentialPath() + const otherNetworkNames = fs + .readdirSync(credentialFolderPath, { withFileTypes: true }) + .filter(dirent => dirent.isDirectory()) + .filter(item => item.name.startsWith('network')) // HACK until we add IIN Agents for Corda networks + .map(item => item.name) + // Reorder the array so that the local network is the first element + // We need to record local membership before recording other networks' memberships + otherNetworkNames.splice(otherNetworkNames.indexOf(networkName), 1) + + if (otherNetworkNames.length > 0) { + // Convert membership object to protobuf + let membershipProto = new membership_pb.Membership() + membershipProto.setSecuritydomain(membershipJSON.securityDomain) + Object.keys(membershipJSON.members).forEach( (memberName, index) => { + const certInfo = membershipJSON.members[memberName] + let memberProto = new membership_pb.Member() + memberProto.setType(certInfo.type) + memberProto.setValue(certInfo.value) + membershipProto.getMembersMap().set(memberName, memberProto) + }) + + // For every other network, generate a counter attested membership set + const serializedMembership = membershipProto.serializeBinary() + const serializedMembershipBase64 = Buffer.from(serializedMembership).toString('base64') + const nonce = 'j849j94j40f440fkfjkld0e043' // Some random string + const membershipBase64WithNonce = serializedMembershipBase64 + nonce + // Get wallet key and cert for this network's IIN Agent + const localWallet = await getWalletForNetwork(networkName) + const localKeyCert = await getKeyAndCertForRemoteRequestbyUserName(localWallet, 'iinagent') + // Sign using wallet identity + let securityDomainMember = new iin_agent_pb.SecurityDomainMemberIdentity() + securityDomainMember.setSecurityDomain(membershipJSON.securityDomain) + securityDomainMember.setMemberId(Object.keys(membershipJSON.members)[0]) + let localAttestation = new iin_agent_pb.Attestation() + localAttestation.setUnitIdentity(securityDomainMember) + localAttestation.setCertificate(localKeyCert.cert) + const localSig = InteroperableHelper.signMessage(membershipBase64WithNonce, localKeyCert.key.toBytes()).toString("base64") + localAttestation.setSignature(localSig) + localAttestation.setNonce(nonce) + let attestedMembershipSet = new iin_agent_pb.CounterAttestedMembership.AttestedMembershipSet() + attestedMembershipSet.setMembership(Buffer.from(serializedMembershipBase64)) + attestedMembershipSet.setAttestationsList( [ localAttestation ] ) + const serializedAttestedMembershipSet = attestedMembershipSet.serializeBinary() + const serializedttestedMembershipSetBase64 = Buffer.from(serializedAttestedMembershipSet).toString('base64') + const serializedttestedMembershipSetBase64WithNonce = serializedttestedMembershipSetBase64 + nonce + for (const otherNetworkName of otherNetworkNames) { + // Get wallet key and cert for other network's IIN Agent + const otherWallet = await getWalletForNetwork(otherNetworkName) + const otherKeyCert = await getKeyAndCertForRemoteRequestbyUserName(otherWallet, 'iinagent') + // Sign using wallet identity + let otherSecurityDomainMember = new iin_agent_pb.SecurityDomainMemberIdentity() + otherSecurityDomainMember.setSecurityDomain(otherNetworkName) + otherSecurityDomainMember.setMemberId(getNetworkConfig(otherNetworkName).mspId) + let otherAttestation = new iin_agent_pb.Attestation() + otherAttestation.setUnitIdentity(otherSecurityDomainMember) + otherAttestation.setCertificate(otherKeyCert.cert) + const otherSig = InteroperableHelper.signMessage(serializedttestedMembershipSetBase64WithNonce, otherKeyCert.key.toBytes()).toString("base64") + otherAttestation.setSignature(otherSig) + otherAttestation.setNonce(nonce) + + // Generate chaincode argument and save it in a file + let counterAttestedMembership = new iin_agent_pb.CounterAttestedMembership() + counterAttestedMembership.setAttestedMembershipSet(Buffer.from(serializedttestedMembershipSetBase64)) + counterAttestedMembership.setAttestationsList( [ otherAttestation ] ) + + fs.writeFileSync( + path.join(credentialsPath, `attested-membership-${otherNetworkName}.proto.serialized`), + Buffer.from(counterAttestedMembership.serializeBinary()).toString('base64') + ) + } + } + + return membershipJSON } const formatMSP = (mspConfig: MspConfig, networkId: string) => { @@ -448,7 +553,7 @@ async function fabricHelper({ userPwd = `user1pw` } - const wallet = await walletSetup(networkName, ccp, mspId, userString, userPwd, registerUser, logger) + const wallet = await walletSetup(networkName, ccp, mspId, userString, userPwd, false, false, registerUser, logger) // Check to see if we've already enrolled the user. const identity = await wallet.get(userString) if (!identity) { @@ -514,6 +619,7 @@ async function query( throw new Error(error) } } + async function invoke( query: Query, connProfilePath: string, @@ -554,6 +660,7 @@ async function invoke( throw new Error(error) } } + const getKeyAndCertForRemoteRequestbyUserName = async ( wallet: any, username: string @@ -577,12 +684,24 @@ const getKeyAndCertForRemoteRequestbyUserName = async ( return { key: privKey, cert: identity.credentials.certificate } } +const getWalletForNetwork = async ( + networkName: string, +) => { + const walletPath = process.env.WALLET_PATH + ? process.env.WALLET_PATH + : path.join(__dirname, '../', `wallet-${networkName}`) + + const wallet = await Wallets.newFileSystemWallet(walletPath) + return wallet +} + export { getUserCertBase64, walletSetup, invoke, query, + enrollAndRecordWalletIdentity, fabricHelper, generateMembership, generateAccessControl, diff --git a/samples/fabric/fabric-cli/src/helpers/interop-setup/configure-network.ts b/samples/fabric/fabric-cli/src/helpers/interop-setup/configure-network.ts index c56b701cd..2a627a7ae 100644 --- a/samples/fabric/fabric-cli/src/helpers/interop-setup/configure-network.ts +++ b/samples/fabric/fabric-cli/src/helpers/interop-setup/configure-network.ts @@ -13,7 +13,7 @@ import { } from '../fabric-functions' import { handlePromise, getNetworkConfig } from '../helpers' -const helperInvoke = async (ccFunc, ccArg, ...args) => { +const helperInvoke = async (userId, ccFunc, ccArg, ...args) => { const [contractName, channelName, connProfilePath, networkName, logger] = args const [invokeResponse, invokeError] = await handlePromise( invoke( @@ -26,17 +26,20 @@ const helperInvoke = async (ccFunc, ccArg, ...args) => { connProfilePath, networkName, global.__DEFAULT_MSPID__, - logger + logger, + userId, + (userId === '') ) ) logger.debug(`${ccFunc} Invoke ${JSON.stringify(invokeResponse)}`) if (invokeError) { - logger.error(`${ccFunc} Invoke Error: ${ccArg}`) + logger.error(`${ccFunc} Invoke Error: ${ccFunc}: ${ccArg}`) throw new Error(`${ccFunc} Invoke Error ${invokeError}`) } else { logger.info(`Successfully invoked ${ccFunc}`) } } + const configureNetwork = async (mainNetwork: string, logger: any = console) => { const networkEnv = getNetworkConfig(mainNetwork) logger.debug(`NetworkEnv: ${JSON.stringify(networkEnv)}`) @@ -52,15 +55,44 @@ const configureNetwork = async (mainNetwork: string, logger: any = console) => { .readdirSync(credentialFolderPath, { withFileTypes: true }) .filter(dirent => dirent.isDirectory()) .map(item => item.name) + // Reorder the array so that the local network is the first element + // We need to record local membership before recording other networks' memberships + networkFolders.splice(networkFolders.indexOf(mainNetwork), 1) + networkFolders.splice(0, 0, mainNetwork) + for (const index in networkFolders) { const network = networkFolders[index] + if (network === mainNetwork) { + // A network needs to load/record only other networks' credentials + const localMembershipPath = path.join( + getCurrentNetworkCredentialPath(network), + 'membership.json' + ) + if ( + !fs.existsSync(localMembershipPath) + ) { + logger.error(`Missing credential file for network: ${network}`) + } else { + await loadLocalHelper( + networkEnv.connProfilePath, + mainNetwork, + process.env.DEFAULT_CHANNEL ? process.env.DEFAULT_CHANNEL : 'mychannel', + process.env.DEFAULT_CHAINCODE + ? process.env.DEFAULT_CHAINCODE + : 'interop', + localMembershipPath, + logger + ) + } + continue; + } const accessControlPath = path.join( getCurrentNetworkCredentialPath(network), 'access-control.json' ) const membershipPath = path.join( getCurrentNetworkCredentialPath(network), - 'membership.json' + (network.startsWith('network') ? 'attested-membership-' + mainNetwork + '.proto.serialized' : 'membership.json') ) const verificationPolicyPath = path.join( getCurrentNetworkCredentialPath(network), @@ -80,6 +112,7 @@ const configureNetwork = async (mainNetwork: string, logger: any = console) => { process.env.DEFAULT_CHAINCODE ? process.env.DEFAULT_CHAINCODE : 'interop', + network, accessControlPath, membershipPath, verificationPolicyPath, @@ -88,11 +121,37 @@ const configureNetwork = async (mainNetwork: string, logger: any = console) => { } } } + +const loadLocalHelper = async ( + connProfilePath: string, + networkName: string, + channelName: string, + contractName: string, + localMembershipPath: string, + logger: any = console +): Promise => { + const localMembership = Buffer.from(fs.readFileSync(localMembershipPath)).toString() + const helperInvokeArgs = [ + contractName, + channelName, + connProfilePath, + networkName, + logger + ] + try { + await helperInvoke('networkadmin', 'CreateLocalMembership', localMembership, ...helperInvokeArgs) + } catch (e) { + logger.info('CreateLocalMembership attempting Update') + await helperInvoke('networkadmin', 'UpdateLocalMembership', localMembership, ...helperInvokeArgs) + } +} + const configureNetworkHelper = async ( connProfilePath: string, networkName: string, channelName: string, contractName: string, + targetNetwork: string, accessControlPath: string, membershipPath: string, verificationPolicyPath: string, @@ -106,7 +165,7 @@ const configureNetworkHelper = async ( fs.readFileSync(verificationPolicyPath) ).toString() - const membership = Buffer.from(fs.readFileSync(membershipPath)).toString() + const attestedMembership = Buffer.from(fs.readFileSync(membershipPath)).toString() const helperInvokeArgs = [ contractName, channelName, @@ -116,6 +175,7 @@ const configureNetworkHelper = async ( ] try { await helperInvoke( + '', 'CreateAccessControlPolicy', accessControl, ...helperInvokeArgs @@ -123,6 +183,7 @@ const configureNetworkHelper = async ( } catch (e) { logger.info('CreateAccessControlPolicy attempting Update') await helperInvoke( + '', 'UpdateAccessControlPolicy', accessControl, ...helperInvokeArgs @@ -130,6 +191,7 @@ const configureNetworkHelper = async ( } try { await helperInvoke( + '', 'CreateVerificationPolicy', verificationPolicy, ...helperInvokeArgs @@ -137,16 +199,18 @@ const configureNetworkHelper = async ( } catch (e) { logger.info('CreateVerificationPolicy attempting Update') await helperInvoke( + '', 'UpdateVerificationPolicy', verificationPolicy, ...helperInvokeArgs ) } + const memberRecordingUser = (targetNetwork.startsWith('network') ? 'iinagent': 'networkadmin') // HACK until we add IIN Agents for Corda networks try { - await helperInvoke('CreateMembership', membership, ...helperInvokeArgs) + await helperInvoke(memberRecordingUser, 'CreateMembership', attestedMembership, ...helperInvokeArgs) } catch (e) { logger.info('CreateMembership attempting Update') - await helperInvoke('UpdateMembership', membership, ...helperInvokeArgs) + await helperInvoke(memberRecordingUser, 'UpdateMembership', attestedMembership, ...helperInvokeArgs) } } diff --git a/samples/fabric/fabric-cli/src/wallet-Dummy_Network/admin.id b/samples/fabric/fabric-cli/src/wallet-Dummy_Network/admin.id deleted file mode 100644 index 5728d610d..000000000 --- a/samples/fabric/fabric-cli/src/wallet-Dummy_Network/admin.id +++ /dev/null @@ -1 +0,0 @@ -{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIIB6zCCAZGgAwIBAgIUGdKilZLHRbBMNKIJkfJW/txCmycwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMTIyMjEyNDcwMFoXDTIyMTIyMjEyNTIwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwVhZG1pbjBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABAgC75qKkepz3qmN2mXtOvZcBTY+jpPj7JfZulgbtHRNGM+IuLNY1Ba6\nXtCq+aE2L0hCrixdeU57Pv2kfe304fKjYDBeMA4GA1UdDwEB/wQEAwIHgDAMBgNV\nHRMBAf8EAjAAMB0GA1UdDgQWBBS82LliVtb0bSkNlAUSopxdVOTiHDAfBgNVHSME\nGDAWgBRyhvWC+jgvOsuRSF6arXu2zl0g/DAKBggqhkjOPQQDAgNIADBFAiEAvVwm\nR5bED0bGKh0a5I0SgFhbWWJqsB3TdTkDH6VG2uYCIDTQxhdKFEYjt/zD8hfo7Viv\nJcSUDK4i6VBl0kNc7fiw\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg5/h+UW63+O946lp+\r\n69A03VKnE5IB/FyAJt6/vDc+sGKhRANCAAQIAu+aipHqc96pjdpl7Tr2XAU2Po6T\r\n4+yX2bpYG7R0TRjPiLizWNQWul7QqvmhNi9IQq4sXXlOez79pH3t9OHy\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file diff --git a/samples/fabric/fabric-cli/src/wallet-Dummy_Network/alice.id b/samples/fabric/fabric-cli/src/wallet-Dummy_Network/alice.id deleted file mode 100644 index 29b71059c..000000000 --- a/samples/fabric/fabric-cli/src/wallet-Dummy_Network/alice.id +++ /dev/null @@ -1 +0,0 @@ -{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIICdzCCAh6gAwIBAgIURDTyar4rqQHsdS+e3SNfXWPA4MgwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMTIyMjEyNDcwMFoXDTIyMTIyMjEyNTIwMFowQjEwMA0G\nA1UECxMGY2xpZW50MAsGA1UECxMEb3JnMTASBgNVBAsTC2RlcGFydG1lbnQxMQ4w\nDAYDVQQDEwVhbGljZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABN81GZdxlkqc\nCmjrFFFoRTu52bH8W8aZ1jlNm63WEHdTkhBokpYhz3CKOLtfcvXEo5gRMFEwiebw\nnBMCXY4X4cmjgcswgcgwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYD\nVR0OBBYEFG0ENsxu+zkEC3WEtr5LjvjXroH3MB8GA1UdIwQYMBaAFHKG9YL6OC86\ny5FIXpqte7bOXSD8MGgGCCoDBAUGBwgBBFx7ImF0dHJzIjp7ImhmLkFmZmlsaWF0\naW9uIjoib3JnMS5kZXBhcnRtZW50MSIsImhmLkVucm9sbG1lbnRJRCI6ImFsaWNl\nIiwiaGYuVHlwZSI6ImNsaWVudCJ9fTAKBggqhkjOPQQDAgNHADBEAiBLH04OFthd\nlKJstFwzia4E7/7j4dm/0QSS2TDdzatJbAIgIKcEmZEHg5fyygrUBXdB204mVVuD\nBQrjKcyqDb3j1OM=\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQggiIMoz/H/In441zW\r\nhkWBymQqawT3iOBIkLM/87xIx+OhRANCAATfNRmXcZZKnApo6xRRaEU7udmx/FvG\r\nmdY5TZut1hB3U5IQaJKWIc9wiji7X3L1xKOYETBRMInm8JwTAl2OF+HJ\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file diff --git a/samples/fabric/fabric-cli/src/wallet-Dummy_Network/bob.id b/samples/fabric/fabric-cli/src/wallet-Dummy_Network/bob.id deleted file mode 100644 index 607805e97..000000000 --- a/samples/fabric/fabric-cli/src/wallet-Dummy_Network/bob.id +++ /dev/null @@ -1 +0,0 @@ -{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIICdDCCAhqgAwIBAgIUQt/AkTbCRgPAQf8WzYTr75bGaj0wCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMTIyMjEyNDgwMFoXDTIyMTIyMjEyNTMwMFowQDEwMA0G\nA1UECxMGY2xpZW50MAsGA1UECxMEb3JnMTASBgNVBAsTC2RlcGFydG1lbnQxMQww\nCgYDVQQDEwNib2IwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAT05/C4elB82Jgf\nJmK5GecjY/xNELBdsR4g441WB8ocZ/5JEYy5mM0aMZJfOi0vVn+OVzQMJ5sOz0k5\nHdxvkPc/o4HJMIHGMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMB0GA1Ud\nDgQWBBR1+ssr8ZO4lLO+IkgYhChfHz6yETAfBgNVHSMEGDAWgBRyhvWC+jgvOsuR\nSF6arXu2zl0g/DBmBggqAwQFBgcIAQRaeyJhdHRycyI6eyJoZi5BZmZpbGlhdGlv\nbiI6Im9yZzEuZGVwYXJ0bWVudDEiLCJoZi5FbnJvbGxtZW50SUQiOiJib2IiLCJo\nZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQCNIwE4oXMQqgXK\n1cpsPU7PWhAr0oy7P4TpsR1SN64GmwIgVmPNb7O77M63U756XPdLW0HCTQSdZSHK\n1EoNob1WC5o=\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgsj1o70bbnyEugrQa\r\nTehiIXbHnzCKK0xaQuuI7lIUeVahRANCAAT05/C4elB82JgfJmK5GecjY/xNELBd\r\nsR4g441WB8ocZ/5JEYy5mM0aMZJfOi0vVn+OVzQMJ5sOz0k5HdxvkPc/\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file diff --git a/samples/fabric/fabric-cli/src/wallet-Dummy_Network/user1.id b/samples/fabric/fabric-cli/src/wallet-Dummy_Network/user1.id deleted file mode 100644 index 6107739f7..000000000 --- a/samples/fabric/fabric-cli/src/wallet-Dummy_Network/user1.id +++ /dev/null @@ -1 +0,0 @@ -{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIICRjCCAe2gAwIBAgIUBMI+vcDI6Z/4bMZN2Cjp6vAXDtgwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDkwNzA5MTQwMFoXDTIyMDkwNzA5MTkwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABFoZaE1MsLtrLRYFzJRyj5uelfL/Fa5pLN2kiO+M5tnxf0+wAotEeC8z\nLCS1KHVIQ7UJD/AOL1OFkbJCHKSdFJGjgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFPzrPjhbfwF/wxP8iFKy4NspQw0uMB8GA1Ud\nIwQYMBaAFHKG9YL6OC86y5FIXpqte7bOXSD8MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0cAMEQCIDP8WLlE4btz\niw6tI/EFdLY/CSOW1P8bOFquaz5YwjYhAiBxEKH6+udDehvHU+wmRaC/Kp1VJNJZ\ndbjNTs65n8zfbQ==\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgdSo5uIgF2yX79LXZ\r\nmP1USII6QeIYwfNCUQvo0rtKkZyhRANCAARaGWhNTLC7ay0WBcyUco+bnpXy/xWu\r\naSzdpIjvjObZ8X9PsAKLRHgvMywktSh1SEO1CQ/wDi9ThZGyQhyknRSR\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file From 876f61cb35a892523fd809863d70c36a95623b54 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Thu, 22 Sep 2022 18:40:54 +0000 Subject: [PATCH 130/150] Added missing step in Fabric CLI for asset transfer logic Signed-off-by: VRamakrishna --- .../fabric/fabric-cli/src/commands/configure/create/all.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/samples/fabric/fabric-cli/src/commands/configure/create/all.ts b/samples/fabric/fabric-cli/src/commands/configure/create/all.ts index 53fb2b41e..ac649e484 100644 --- a/samples/fabric/fabric-cli/src/commands/configure/create/all.ts +++ b/samples/fabric/fabric-cli/src/commands/configure/create/all.ts @@ -6,6 +6,7 @@ import { GluegunCommand } from 'gluegun' import { commandHelp, getNetworkConfig } from '../../../helpers/helpers' +import { enrollAndRecordWalletIdentity } from '../../helpers/fabric-functions' import logger from '../../../helpers/logger' import * as path from 'path' import * as dotenv from 'dotenv' @@ -65,6 +66,10 @@ const command: GluegunCommand = { return } + // Create an IIN Agent + print.info(`Creating IIN Agent wallet identity for network: ${network}`) + await enrollAndRecordWalletIdentity('iinagent', null, options['local-network'], false, true) + // Membership logger.info(`Generating membership for ${options['local-network']}`) await generateMembership( From 1385354e7d04fecafbc1f7403cdd34154f2c2eb2 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Thu, 22 Sep 2022 18:53:24 +0000 Subject: [PATCH 131/150] Fixed import path in Fabric CLI source file Signed-off-by: VRamakrishna --- samples/fabric/fabric-cli/src/commands/configure/create/all.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/fabric/fabric-cli/src/commands/configure/create/all.ts b/samples/fabric/fabric-cli/src/commands/configure/create/all.ts index ac649e484..882cc4b45 100644 --- a/samples/fabric/fabric-cli/src/commands/configure/create/all.ts +++ b/samples/fabric/fabric-cli/src/commands/configure/create/all.ts @@ -6,7 +6,7 @@ import { GluegunCommand } from 'gluegun' import { commandHelp, getNetworkConfig } from '../../../helpers/helpers' -import { enrollAndRecordWalletIdentity } from '../../helpers/fabric-functions' +import { enrollAndRecordWalletIdentity } from '../../../helpers/fabric-functions' import logger from '../../../helpers/logger' import * as path from 'path' import * as dotenv from 'dotenv' From c9330213a2fadebae1c98ab2146df333b0b0320b Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Thu, 22 Sep 2022 19:08:31 +0000 Subject: [PATCH 132/150] Fixed logging bug in Fabric CLI Signed-off-by: VRamakrishna --- samples/fabric/fabric-cli/src/commands/configure/create/all.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/fabric/fabric-cli/src/commands/configure/create/all.ts b/samples/fabric/fabric-cli/src/commands/configure/create/all.ts index 882cc4b45..95cb1f9eb 100644 --- a/samples/fabric/fabric-cli/src/commands/configure/create/all.ts +++ b/samples/fabric/fabric-cli/src/commands/configure/create/all.ts @@ -67,7 +67,7 @@ const command: GluegunCommand = { } // Create an IIN Agent - print.info(`Creating IIN Agent wallet identity for network: ${network}`) + print.info(`Creating IIN Agent wallet identity for local network`) await enrollAndRecordWalletIdentity('iinagent', null, options['local-network'], false, true) // Membership From f9e1f48af687bcab68720f6c1afcd093e7eb8443 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Thu, 22 Sep 2022 19:52:36 +0000 Subject: [PATCH 133/150] Added necessary user credential creation logic to Fabric CLI scripts Signed-off-by: VRamakrishna --- .../src/commands/configure/create/all.ts | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/samples/fabric/fabric-cli/src/commands/configure/create/all.ts b/samples/fabric/fabric-cli/src/commands/configure/create/all.ts index 95cb1f9eb..4acad0681 100644 --- a/samples/fabric/fabric-cli/src/commands/configure/create/all.ts +++ b/samples/fabric/fabric-cli/src/commands/configure/create/all.ts @@ -6,10 +6,11 @@ import { GluegunCommand } from 'gluegun' import { commandHelp, getNetworkConfig } from '../../../helpers/helpers' -import { enrollAndRecordWalletIdentity } from '../../../helpers/fabric-functions' +import { getCredentialPath, enrollAndRecordWalletIdentity } from '../../../helpers/fabric-functions' import logger from '../../../helpers/logger' import * as path from 'path' import * as dotenv from 'dotenv' +import * as fs from 'fs' dotenv.config({ path: path.resolve(__dirname, '../../.env') }) import { @@ -66,9 +67,19 @@ const command: GluegunCommand = { return } - // Create an IIN Agent - print.info(`Creating IIN Agent wallet identity for local network`) - await enrollAndRecordWalletIdentity('iinagent', null, options['local-network'], false, true) + // Create IIN Agents + const credentialFolderPath = getCredentialPath() + const networkNames = fs + .readdirSync(credentialFolderPath, { withFileTypes: true }) + .filter(dirent => dirent.isDirectory()) + .filter(item => item.name.startsWith('network')) // HACK until we add IIN Agents for Corda networks + .map(item => item.name) + for (const networkName of networkNames) { + print.info(`Creating network admin wallet identity for network: ${networkName}`) + await enrollAndRecordWalletIdentity('networkadmin', null, networkName, false, true) + print.info(`Creating IIN Agent wallet identity for network ${networkName}`) + await enrollAndRecordWalletIdentity('iinagent', null, networkName, false, true) + } // Membership logger.info(`Generating membership for ${options['local-network']}`) From abe84d4dd65cf9f2056fe01865b43a8c93d4f567 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Thu, 22 Sep 2022 20:20:17 +0000 Subject: [PATCH 134/150] Bug fixes in Fabric CLI credential creation logic Signed-off-by: VRamakrishna --- .../src/commands/configure/create/all.ts | 6 +++--- .../src/commands/configure/network.ts | 20 ++++++++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/samples/fabric/fabric-cli/src/commands/configure/create/all.ts b/samples/fabric/fabric-cli/src/commands/configure/create/all.ts index 4acad0681..e02b3562e 100644 --- a/samples/fabric/fabric-cli/src/commands/configure/create/all.ts +++ b/samples/fabric/fabric-cli/src/commands/configure/create/all.ts @@ -67,7 +67,7 @@ const command: GluegunCommand = { return } - // Create IIN Agents + // Create wallet credentials const credentialFolderPath = getCredentialPath() const networkNames = fs .readdirSync(credentialFolderPath, { withFileTypes: true }) @@ -76,9 +76,9 @@ const command: GluegunCommand = { .map(item => item.name) for (const networkName of networkNames) { print.info(`Creating network admin wallet identity for network: ${networkName}`) - await enrollAndRecordWalletIdentity('networkadmin', null, networkName, false, true) + await enrollAndRecordWalletIdentity('networkadmin', null, networkName, true, false) // Create a network admin print.info(`Creating IIN Agent wallet identity for network ${networkName}`) - await enrollAndRecordWalletIdentity('iinagent', null, networkName, false, true) + await enrollAndRecordWalletIdentity('iinagent', null, networkName, false, true) // Create an IIN Agent } // Membership diff --git a/samples/fabric/fabric-cli/src/commands/configure/network.ts b/samples/fabric/fabric-cli/src/commands/configure/network.ts index 6c90ed5cf..c560d5640 100644 --- a/samples/fabric/fabric-cli/src/commands/configure/network.ts +++ b/samples/fabric/fabric-cli/src/commands/configure/network.ts @@ -6,11 +6,12 @@ import { GluegunCommand } from 'gluegun' import { commandHelp } from '../../helpers/helpers' -import { enrollAndRecordWalletIdentity } from '../../helpers/fabric-functions' +import { getCredentialPath, enrollAndRecordWalletIdentity } from '../../helpers/fabric-functions' import { configureNetwork } from '../../helpers/interop-setup/configure-network' import logger from '../../helpers/logger' import * as path from 'path' import * as dotenv from 'dotenv' +import * as fs from 'fs' dotenv.config({ path: path.resolve(__dirname, '../../.env') }) const command: GluegunCommand = { @@ -48,8 +49,21 @@ const command: GluegunCommand = { logger.level = 'debug' logger.debug('Debugging is enabled') } - await enrollAndRecordWalletIdentity('networkadmin', null, options['local-network'], true, false) // Create a network admin - await enrollAndRecordWalletIdentity('iinagent', null, options['local-network'], false, true) // Create an IIN Agent + + // Create wallet credentials + const credentialFolderPath = getCredentialPath() + const networkNames = fs + .readdirSync(credentialFolderPath, { withFileTypes: true }) + .filter(dirent => dirent.isDirectory()) + .filter(item => item.name.startsWith('network')) // HACK until we add IIN Agents for Corda networks + .map(item => item.name) + for (const networkName of networkNames) { + print.info(`Creating network admin wallet identity for network: ${networkName}`) + await enrollAndRecordWalletIdentity('networkadmin', null, networkName, true, false) // Create a network admin + print.info(`Creating IIN Agent wallet identity for network ${networkName}`) + await enrollAndRecordWalletIdentity('iinagent', null, networkName, false, true) // Create an IIN Agent + } + await configureNetwork(options['local-network'], logger) process.exit() } From 889303dfa6dcc0835dca66e90dde03c861823b91 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Fri, 23 Sep 2022 06:32:33 +0000 Subject: [PATCH 135/150] Disabling tests dependent on updated protos The updated Fabric CLI uses a version of protos that is not yet published as a package. The tests will be re-enabled after the next PR merge and package update. Signed-off-by: VRamakrishna --- .github/workflows/test_asset-exchange-fabric.yml | 2 +- .github/workflows/test_asset-transfer.yml | 2 +- .github/workflows/test_data-sharing.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test_asset-exchange-fabric.yml b/.github/workflows/test_asset-exchange-fabric.yml index 25d61529a..c70c33647 100644 --- a/.github/workflows/test_asset-exchange-fabric.yml +++ b/.github/workflows/test_asset-exchange-fabric.yml @@ -21,7 +21,7 @@ on: jobs: asset-exchange-fabric: - # if: ${{ false }} # disable + if: ${{ false }} # disable # The type of runner that the job will run on runs-on: ubuntu-latest diff --git a/.github/workflows/test_asset-transfer.yml b/.github/workflows/test_asset-transfer.yml index b55183a5c..b45a59ca1 100644 --- a/.github/workflows/test_asset-transfer.yml +++ b/.github/workflows/test_asset-transfer.yml @@ -20,7 +20,7 @@ on: # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: fabric-asset-transfer: - # if: ${{ false }} # disable + if: ${{ false }} # disable # The type of runner that the job will run on runs-on: ubuntu-latest diff --git a/.github/workflows/test_data-sharing.yml b/.github/workflows/test_data-sharing.yml index 3f7733524..0f6c96b88 100644 --- a/.github/workflows/test_data-sharing.yml +++ b/.github/workflows/test_data-sharing.yml @@ -20,7 +20,7 @@ on: # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: data-sharing: - # if: ${{ false }} # disable + if: ${{ false }} # disable # The type of runner that the job will run on runs-on: ubuntu-latest From 0ad48b04f7123f845d2e32d14c735d17e1f71c37 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Fri, 23 Sep 2022 10:11:05 +0000 Subject: [PATCH 136/150] Changed bytes fields to strings for serialized parameters in IIN Agent protobuf Signed-off-by: VRamakrishna --- .github/workflows/deploy_go-pkgs.yml | 3 - common/protos-go/identity/agent.pb.go | 24 ++--- common/protos/identity/agent.proto | 6 +- .../contracts/interop/membership.go | 20 ++--- .../contracts/interop/membership_test.go | 88 ++++++++----------- .../src/helpers/fabric-functions.ts | 4 +- 6 files changed, 63 insertions(+), 82 deletions(-) diff --git a/.github/workflows/deploy_go-pkgs.yml b/.github/workflows/deploy_go-pkgs.yml index ca5d7cb37..e526ffe9d 100644 --- a/.github/workflows/deploy_go-pkgs.yml +++ b/.github/workflows/deploy_go-pkgs.yml @@ -19,9 +19,6 @@ on: # Allows you to run this workflow manually from the Actions tab workflow_dispatch: -# Allows you to run this workflow manually from the Actions tab -workflow_dispatch: - jobs: publish-protos: if: github.repository_owner == 'hyperledger-labs' diff --git a/common/protos-go/identity/agent.pb.go b/common/protos-go/identity/agent.pb.go index 22470194e..15212105f 100644 --- a/common/protos-go/identity/agent.pb.go +++ b/common/protos-go/identity/agent.pb.go @@ -218,7 +218,7 @@ type AttestedMembership struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Membership []byte `protobuf:"bytes,1,opt,name=membership,proto3" json:"membership,omitempty"` // 'common.membership.Membership': Base64-encoded + Membership string `protobuf:"bytes,1,opt,name=membership,proto3" json:"membership,omitempty"` // 'common.membership.Membership': Serialized and Base64-encoded Attestation *Attestation `protobuf:"bytes,2,opt,name=attestation,proto3" json:"attestation,omitempty"` } @@ -254,11 +254,11 @@ func (*AttestedMembership) Descriptor() ([]byte, []int) { return file_identity_agent_proto_rawDescGZIP(), []int{3} } -func (x *AttestedMembership) GetMembership() []byte { +func (x *AttestedMembership) GetMembership() string { if x != nil { return x.Membership } - return nil + return "" } func (x *AttestedMembership) GetAttestation() *Attestation { @@ -274,7 +274,7 @@ type CounterAttestedMembership struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - AttestedMembershipSet []byte `protobuf:"bytes,1,opt,name=attested_membership_set,json=attestedMembershipSet,proto3" json:"attested_membership_set,omitempty"` // 'AttestedMembershipSet': Base64-encoded + AttestedMembershipSet string `protobuf:"bytes,1,opt,name=attested_membership_set,json=attestedMembershipSet,proto3" json:"attested_membership_set,omitempty"` // 'AttestedMembershipSet': Serialized and Base64-encoded Attestations []*Attestation `protobuf:"bytes,2,rep,name=attestations,proto3" json:"attestations,omitempty"` } @@ -310,11 +310,11 @@ func (*CounterAttestedMembership) Descriptor() ([]byte, []int) { return file_identity_agent_proto_rawDescGZIP(), []int{4} } -func (x *CounterAttestedMembership) GetAttestedMembershipSet() []byte { +func (x *CounterAttestedMembership) GetAttestedMembershipSet() string { if x != nil { return x.AttestedMembershipSet } - return nil + return "" } func (x *CounterAttestedMembership) GetAttestations() []*Attestation { @@ -329,7 +329,7 @@ type CounterAttestedMembership_AttestedMembershipSet struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Membership []byte `protobuf:"bytes,1,opt,name=membership,proto3" json:"membership,omitempty"` // 'common.membership.Membership': Base64-encoded + Membership string `protobuf:"bytes,1,opt,name=membership,proto3" json:"membership,omitempty"` // 'common.membership.Membership': Serialized and Base64-encoded Attestations []*Attestation `protobuf:"bytes,2,rep,name=attestations,proto3" json:"attestations,omitempty"` } @@ -365,11 +365,11 @@ func (*CounterAttestedMembership_AttestedMembershipSet) Descriptor() ([]byte, [] return file_identity_agent_proto_rawDescGZIP(), []int{4, 0} } -func (x *CounterAttestedMembership_AttestedMembershipSet) GetMembership() []byte { +func (x *CounterAttestedMembership_AttestedMembershipSet) GetMembership() string { if x != nil { return x.Membership } - return nil + return "" } func (x *CounterAttestedMembership_AttestedMembershipSet) GetAttestations() []*Attestation { @@ -422,7 +422,7 @@ var file_identity_agent_proto_rawDesc = []byte{ 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x73, 0x0a, 0x12, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x68, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x6d, 0x65, 0x6d, 0x62, + 0x73, 0x68, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x3d, 0x0a, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, @@ -431,7 +431,7 @@ var file_identity_agent_proto_rawDesc = []byte{ 0x72, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x36, 0x0a, 0x17, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x5f, 0x73, 0x65, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x15, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x65, 0x74, 0x12, 0x3f, 0x0a, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, @@ -439,7 +439,7 @@ var file_identity_agent_proto_rawDesc = []byte{ 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x78, 0x0a, 0x15, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x65, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, - 0x68, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, + 0x68, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x3f, 0x0a, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, diff --git a/common/protos/identity/agent.proto b/common/protos/identity/agent.proto index 5e711070e..70c05ead3 100644 --- a/common/protos/identity/agent.proto +++ b/common/protos/identity/agent.proto @@ -44,16 +44,16 @@ message Attestation { // Attested security domain membership by a single member message AttestedMembership { - bytes membership = 1; // 'common.membership.Membership': Base64-encoded + string membership = 1; // 'common.membership.Membership': Serialized and Base64-encoded Attestation attestation = 2; } // Counter attestation over security domain membership attested by its participants message CounterAttestedMembership { message AttestedMembershipSet { - bytes membership = 1; // 'common.membership.Membership': Base64-encoded + string membership = 1; // 'common.membership.Membership': Serialized and Base64-encoded repeated Attestation attestations = 2; } - bytes attested_membership_set = 1; // 'AttestedMembershipSet': Base64-encoded + string attested_membership_set = 1; // 'AttestedMembershipSet': Serialized and Base64-encoded repeated Attestation attestations = 2; } diff --git a/core/network/fabric-interop-cc/contracts/interop/membership.go b/core/network/fabric-interop-cc/contracts/interop/membership.go index 5770406ef..6215475c0 100644 --- a/core/network/fabric-interop-cc/contracts/interop/membership.go +++ b/core/network/fabric-interop-cc/contracts/interop/membership.go @@ -84,7 +84,7 @@ func checkUserInMembership(userCert *x509.Certificate, membership *common.Member } // Validate 'identity.Attestation' object against a message byte array -func validateAttestation(attestation *identity.Attestation, messageBytes []byte) error { +func validateAttestation(attestation *identity.Attestation, messageBytes string) error { // Parse local IIN Agent's certificate certDecoded, _ := pem.Decode([]byte(attestation.Certificate)) if certDecoded == nil { @@ -99,7 +99,7 @@ func validateAttestation(attestation *identity.Attestation, messageBytes []byte) if err != nil { return fmt.Errorf("Attestation signature could not be decoded from base64: %s", err.Error()) } - err = validateSignature(string(messageBytes), cert, string(decodedSignature)) + err = validateSignature(messageBytes, cert, string(decodedSignature)) if err != nil { return fmt.Errorf("Unable to Validate Signature: %s", err.Error()) } @@ -215,7 +215,7 @@ func (s *SmartContract) CreateMembership(ctx contractapi.TransactionContextInter if err != nil { return fmt.Errorf("Counter Attested Membership Unmarshal error: %s", err) } - decodedAttestedMembershipSet, err := base64.StdEncoding.DecodeString(string(counterAttestedMembership.AttestedMembershipSet)) + decodedAttestedMembershipSet, err := base64.StdEncoding.DecodeString(counterAttestedMembership.AttestedMembershipSet) if err != nil { return fmt.Errorf("Attested membership set could not be decoded from base64: %s", err.Error()) } @@ -224,7 +224,7 @@ func (s *SmartContract) CreateMembership(ctx contractapi.TransactionContextInter if err != nil { return fmt.Errorf("Unable to unmarshal attested membership set: %s", err.Error()) } - decodedForeignMembership, err := base64.StdEncoding.DecodeString(string(attestedMembershipSet.Membership)) + decodedForeignMembership, err := base64.StdEncoding.DecodeString(attestedMembershipSet.Membership) if err != nil { return fmt.Errorf("Foreign membership could not be decoded from base64: %s", err.Error()) } @@ -248,7 +248,7 @@ func (s *SmartContract) CreateMembership(ctx contractapi.TransactionContextInter // Ensure valid attestations from all local IIN Agents for _, attestation := range counterAttestedMembership.Attestations { - err = validateAttestation(attestation, append(counterAttestedMembership.AttestedMembershipSet, attestation.Nonce...)) + err = validateAttestation(attestation, counterAttestedMembership.AttestedMembershipSet + attestation.Nonce) if err != nil { return err } @@ -295,7 +295,7 @@ func (s *SmartContract) CreateMembership(ctx contractapi.TransactionContextInter return fmt.Errorf("No matching member certificate chain found for attester") } // Validate signature - err = validateAttestation(attestation, append(attestedMembershipSet.Membership, attestation.Nonce...)) + err = validateAttestation(attestation, attestedMembershipSet.Membership + attestation.Nonce) if err != nil { return err } @@ -385,7 +385,7 @@ func (s *SmartContract) UpdateMembership(ctx contractapi.TransactionContextInter if err != nil { return fmt.Errorf("Counter Attested Membership Unmarshal error: %s", err) } - decodedAttestedMembershipSet, err := base64.StdEncoding.DecodeString(string(counterAttestedMembership.AttestedMembershipSet)) + decodedAttestedMembershipSet, err := base64.StdEncoding.DecodeString(counterAttestedMembership.AttestedMembershipSet) if err != nil { return fmt.Errorf("Attested membership set could not be decoded from base64: %s", err.Error()) } @@ -394,7 +394,7 @@ func (s *SmartContract) UpdateMembership(ctx contractapi.TransactionContextInter if err != nil { return fmt.Errorf("Unable to unmarshal attested membership set: %s", err.Error()) } - decodedForeignMembership, err := base64.StdEncoding.DecodeString(string(attestedMembershipSet.Membership)) + decodedForeignMembership, err := base64.StdEncoding.DecodeString(attestedMembershipSet.Membership) if err != nil { return fmt.Errorf("Foreign membership could not be decoded from base64: %s", err.Error()) } @@ -418,7 +418,7 @@ func (s *SmartContract) UpdateMembership(ctx contractapi.TransactionContextInter // Ensure valid attestations from all local IIN Agents for _, attestation := range counterAttestedMembership.Attestations { - err = validateAttestation(attestation, append(counterAttestedMembership.AttestedMembershipSet, attestation.Nonce...)) + err = validateAttestation(attestation, counterAttestedMembership.AttestedMembershipSet + attestation.Nonce) if err != nil { return err } @@ -465,7 +465,7 @@ func (s *SmartContract) UpdateMembership(ctx contractapi.TransactionContextInter return fmt.Errorf("No matching member certificate chain found for attester") } // Validate signature - err = validateAttestation(attestation, append(attestedMembershipSet.Membership, attestation.Nonce...)) + err = validateAttestation(attestation, attestedMembershipSet.Membership + attestation.Nonce) if err != nil { return err } diff --git a/core/network/fabric-interop-cc/contracts/interop/membership_test.go b/core/network/fabric-interop-cc/contracts/interop/membership_test.go index 112d92cb7..ef0126ab9 100644 --- a/core/network/fabric-interop-cc/contracts/interop/membership_test.go +++ b/core/network/fabric-interop-cc/contracts/interop/membership_test.go @@ -371,7 +371,6 @@ func TestCreateMembership(t *testing.T) { membershipBytesPlain, err := protoV2.Marshal(&membershipAsset) require.NoError(t, err) membershipBytesStr := base64.StdEncoding.EncodeToString(membershipBytesPlain) - membershipBytes := []byte(membershipBytesStr) membershipBytesWithNonce := []byte(membershipBytesStr + nonce) // Generate member 2 attestation random1 := rand.Reader @@ -389,8 +388,8 @@ func TestCreateMembership(t *testing.T) { attestation2.Signature = base64.StdEncoding.EncodeToString(signature2) // Generate attested foreign membership attestedMembershipSet := identity.CounterAttestedMembership_AttestedMembershipSet { - Membership: membershipBytes, - Attestations: []*identity.Attestation{&attestation1, &attestation2}, + Membership: membershipBytesStr, + Attestations: []*identity.Attestation{&attestation1, &attestation2}, } // Generate local members @@ -442,7 +441,6 @@ func TestCreateMembership(t *testing.T) { attestedMembershipSetBytesPlain, err := protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) attestedMembershipSetBytesStr := base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) - attestedMembershipSetBytes := []byte(attestedMembershipSetBytesStr) attestedMembershipSetBytesWithNonce := []byte(attestedMembershipSetBytesStr + nonce) // Generate member 2 attestation randomLocal1 := rand.Reader @@ -460,7 +458,7 @@ func TestCreateMembership(t *testing.T) { attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) // Generate counter attested foreign membership counterAttestedMembership := identity.CounterAttestedMembership{ - AttestedMembershipSet: attestedMembershipSetBytes, + AttestedMembershipSet: attestedMembershipSetBytesStr, Attestations: []*identity.Attestation{&attestationLocal1, &attestationLocal2}, } @@ -468,14 +466,14 @@ func TestCreateMembership(t *testing.T) { counterAttestedMembershipBytesPlain, err := protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) counterAttestedMembershipBytes := base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) - err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembership(ctx, counterAttestedMembershipBytes) require.EqualError(t, err, "Caller neither a network admin nor an IIN Agent; access denied") // Record membership info: should fail because the local IIN Agent is not registered clientIdentity := &mocks.ClientIdentity{} clientIdentity.GetAttributeValueCalls(setClientIINAgent) ctx.GetClientIdentityReturns(clientIdentity) - err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembership(ctx, counterAttestedMembershipBytes) require.Error(t, err) // Record local membership info @@ -491,13 +489,13 @@ func TestCreateMembership(t *testing.T) { chaincodeStub.GetStateReturnsOnCall(3, nil, nil) clientIdentity.GetAttributeValueCalls(setClientIINAgent) ctx.GetClientIdentityReturns(clientIdentity) - err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembership(ctx, counterAttestedMembershipBytes) require.NoError(t, err) // Record membership info again: should fail because membership has already been recorded against this security domain chaincodeStub.GetStateReturnsOnCall(4, localMembershipBytes, nil) chaincodeStub.GetStateReturnsOnCall(5, []byte{}, nil) - err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembership(ctx, counterAttestedMembershipBytes) require.EqualError(t, err, fmt.Sprintf("Membership already exists for membership id: %s. Use 'UpdateMembership' to update.", membershipAsset.SecurityDomain)) // One of the local signatures is invalid: should fail @@ -511,7 +509,7 @@ func TestCreateMembership(t *testing.T) { counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) chaincodeStub.GetStateReturnsOnCall(6, localMembershipBytes, nil) chaincodeStub.GetStateReturnsOnCall(7, nil, nil) - err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembership(ctx, counterAttestedMembershipBytes) require.EqualError(t, err, "Unable to Validate Signature: Signature Verification failed. ECDSA VERIFY") // One of the foreign signatures is invalid: should fail @@ -523,7 +521,6 @@ func TestCreateMembership(t *testing.T) { attestedMembershipSetBytesPlain, err = protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) - attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) require.NoError(t, err) @@ -535,12 +532,12 @@ func TestCreateMembership(t *testing.T) { signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) require.NoError(t, err) attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) - counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes + counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytesStr counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) chaincodeStub.GetStateReturnsOnCall(7, localMembershipBytes, nil) - err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembership(ctx, counterAttestedMembershipBytes) require.EqualError(t, err, "Unable to Validate Signature: Signature Verification failed. ECDSA VERIFY") // One of the foreign attestations has an invalid nonce: should fail @@ -553,7 +550,6 @@ func TestCreateMembership(t *testing.T) { attestedMembershipSetBytesPlain, err = protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) - attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) require.NoError(t, err) @@ -565,12 +561,12 @@ func TestCreateMembership(t *testing.T) { signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) require.NoError(t, err) attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) - counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes + counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytesStr counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) chaincodeStub.GetStateReturnsOnCall(8, localMembershipBytes, nil) - err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembership(ctx, counterAttestedMembershipBytes) require.EqualError(t, err, fmt.Sprintf("Mismatched nonces across two attestations: %s, %s", nonce, attestation1.Nonce)) // Foreign membership has an invalid cert chain: should fail @@ -581,7 +577,6 @@ func TestCreateMembership(t *testing.T) { membershipBytesPlain, err = protoV2.Marshal(&membershipAsset) require.NoError(t, err) membershipBytesStr = base64.StdEncoding.EncodeToString(membershipBytesPlain) - membershipBytes = []byte(membershipBytesStr) membershipBytesWithNonce = []byte(membershipBytesStr + nonce) hashed1, err = computeSHA2Hash(membershipBytesWithNonce, key1.PublicKey.Params().BitSize) require.NoError(t, err) @@ -593,11 +588,10 @@ func TestCreateMembership(t *testing.T) { signature2, err = ecdsa.SignASN1(random2, key2, hashed2) require.NoError(t, err) attestation2.Signature = base64.StdEncoding.EncodeToString(signature2) - attestedMembershipSet.Membership = membershipBytes + attestedMembershipSet.Membership = membershipBytesStr attestedMembershipSetBytesPlain, err = protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) - attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) require.NoError(t, err) @@ -609,12 +603,12 @@ func TestCreateMembership(t *testing.T) { signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) require.NoError(t, err) attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) - counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes + counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytesStr counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) chaincodeStub.GetStateReturnsOnCall(9, localMembershipBytes, nil) - err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembership(ctx, counterAttestedMembershipBytes) require.Error(t, err) // Foreign attestation has invalid security domain: should fail @@ -625,7 +619,6 @@ func TestCreateMembership(t *testing.T) { membershipBytesPlain, err = protoV2.Marshal(&membershipAsset) require.NoError(t, err) membershipBytesStr = base64.StdEncoding.EncodeToString(membershipBytesPlain) - membershipBytes = []byte(membershipBytesStr) membershipBytesWithNonce = []byte(membershipBytesStr + nonce) hashed1, err = computeSHA2Hash(membershipBytesWithNonce, key1.PublicKey.Params().BitSize) require.NoError(t, err) @@ -637,11 +630,10 @@ func TestCreateMembership(t *testing.T) { signature2, err = ecdsa.SignASN1(random2, key2, hashed2) require.NoError(t, err) attestation2.Signature = base64.StdEncoding.EncodeToString(signature2) - attestedMembershipSet.Membership = membershipBytes + attestedMembershipSet.Membership = membershipBytesStr attestedMembershipSetBytesPlain, err = protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) - attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) require.NoError(t, err) @@ -653,12 +645,12 @@ func TestCreateMembership(t *testing.T) { signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) require.NoError(t, err) attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) - counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes + counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytesStr counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) chaincodeStub.GetStateReturnsOnCall(10, localMembershipBytes, nil) - err = interopcc.CreateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.CreateMembership(ctx, counterAttestedMembershipBytes) require.EqualError(t, err, fmt.Sprintf("Foreign agent security domain %s does not match attested membership security domain invalid", securityDomainId)) } @@ -741,7 +733,6 @@ func TestUpdateMembership(t *testing.T) { membershipBytesPlain, err := protoV2.Marshal(&membershipAsset) require.NoError(t, err) membershipBytesStr := base64.StdEncoding.EncodeToString(membershipBytesPlain) - membershipBytes := []byte(membershipBytesStr) membershipBytesWithNonce := []byte(membershipBytesStr + nonce) // Generate member 2 attestation random1 := rand.Reader @@ -759,8 +750,8 @@ func TestUpdateMembership(t *testing.T) { attestation2.Signature = base64.StdEncoding.EncodeToString(signature2) // Generate attested foreign membership attestedMembershipSet := identity.CounterAttestedMembership_AttestedMembershipSet { - Membership: membershipBytes, - Attestations: []*identity.Attestation{&attestation1, &attestation2}, + Membership: membershipBytesStr, + Attestations: []*identity.Attestation{&attestation1, &attestation2}, } // Generate local members @@ -812,7 +803,6 @@ func TestUpdateMembership(t *testing.T) { attestedMembershipSetBytesPlain, err := protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) attestedMembershipSetBytesStr := base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) - attestedMembershipSetBytes := []byte(attestedMembershipSetBytesStr) attestedMembershipSetBytesWithNonce := []byte(attestedMembershipSetBytesStr + nonce) // Generate member 2 attestation randomLocal1 := rand.Reader @@ -830,7 +820,7 @@ func TestUpdateMembership(t *testing.T) { attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) // Generate counter attested foreign membership counterAttestedMembership := identity.CounterAttestedMembership{ - AttestedMembershipSet: attestedMembershipSetBytes, + AttestedMembershipSet: attestedMembershipSetBytesStr, Attestations: []*identity.Attestation{&attestationLocal1, &attestationLocal2}, } @@ -839,14 +829,14 @@ func TestUpdateMembership(t *testing.T) { require.NoError(t, err) counterAttestedMembershipBytes := base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) require.NoError(t, err) - err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembership(ctx, counterAttestedMembershipBytes) require.EqualError(t, err, "Caller neither a network admin nor an IIN Agent; access denied") // Record membership info: should fail because the local IIN Agent is not registered clientIdentity := &mocks.ClientIdentity{} clientIdentity.GetAttributeValueCalls(setClientIINAgent) ctx.GetClientIdentityReturns(clientIdentity) - err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembership(ctx, counterAttestedMembershipBytes) require.Error(t, err) // Record local membership info @@ -862,13 +852,13 @@ func TestUpdateMembership(t *testing.T) { chaincodeStub.GetStateReturnsOnCall(3, nil, nil) clientIdentity.GetAttributeValueCalls(setClientIINAgent) ctx.GetClientIdentityReturns(clientIdentity) - err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembership(ctx, counterAttestedMembershipBytes) require.EqualError(t, err, fmt.Sprintf("Membership with id: %s does not exist", securityDomainId)) // Record membership info again: should succeed now chaincodeStub.GetStateReturnsOnCall(4, localMembershipBytes, nil) chaincodeStub.GetStateReturnsOnCall(5, []byte{}, nil) - err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembership(ctx, counterAttestedMembershipBytes) require.NoError(t, err) // One of the local signatures is invalid: should fail @@ -882,7 +872,7 @@ func TestUpdateMembership(t *testing.T) { counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) chaincodeStub.GetStateReturnsOnCall(6, localMembershipBytes, nil) chaincodeStub.GetStateReturnsOnCall(7, []byte{}, nil) - err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembership(ctx, counterAttestedMembershipBytes) require.EqualError(t, err, "Unable to Validate Signature: Signature Verification failed. ECDSA VERIFY") // One of the foreign signatures is invalid: should fail @@ -894,7 +884,6 @@ func TestUpdateMembership(t *testing.T) { attestedMembershipSetBytesPlain, err = protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) - attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) require.NoError(t, err) @@ -906,12 +895,12 @@ func TestUpdateMembership(t *testing.T) { signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) require.NoError(t, err) attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) - counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes + counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytesStr counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) chaincodeStub.GetStateReturnsOnCall(7, localMembershipBytes, nil) - err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembership(ctx, counterAttestedMembershipBytes) require.EqualError(t, err, "Unable to Validate Signature: Signature Verification failed. ECDSA VERIFY") // One of the foreign attestations has an invalid nonce: should fail @@ -924,7 +913,6 @@ func TestUpdateMembership(t *testing.T) { attestedMembershipSetBytesPlain, err = protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) - attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) require.NoError(t, err) @@ -936,12 +924,12 @@ func TestUpdateMembership(t *testing.T) { signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) require.NoError(t, err) attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) - counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes + counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytesStr counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) chaincodeStub.GetStateReturnsOnCall(8, localMembershipBytes, nil) - err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembership(ctx, counterAttestedMembershipBytes) require.EqualError(t, err, fmt.Sprintf("Mismatched nonces across two attestations: %s, %s", nonce, attestation1.Nonce)) // Foreign membership has an invalid cert chain: should fail @@ -952,7 +940,6 @@ func TestUpdateMembership(t *testing.T) { membershipBytesPlain, err = protoV2.Marshal(&membershipAsset) require.NoError(t, err) membershipBytesStr = base64.StdEncoding.EncodeToString(membershipBytesPlain) - membershipBytes = []byte(membershipBytesStr) membershipBytesWithNonce = []byte(membershipBytesStr + nonce) hashed1, err = computeSHA2Hash(membershipBytesWithNonce, key1.PublicKey.Params().BitSize) require.NoError(t, err) @@ -964,11 +951,10 @@ func TestUpdateMembership(t *testing.T) { signature2, err = ecdsa.SignASN1(random2, key2, hashed2) require.NoError(t, err) attestation2.Signature = base64.StdEncoding.EncodeToString(signature2) - attestedMembershipSet.Membership = membershipBytes + attestedMembershipSet.Membership = membershipBytesStr attestedMembershipSetBytesPlain, err = protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) - attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) require.NoError(t, err) @@ -980,12 +966,12 @@ func TestUpdateMembership(t *testing.T) { signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) require.NoError(t, err) attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) - counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes + counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytesStr counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) chaincodeStub.GetStateReturnsOnCall(9, localMembershipBytes, nil) - err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembership(ctx, counterAttestedMembershipBytes) require.Error(t, err) // Foreign attestation has invalid security domain: should fail @@ -996,7 +982,6 @@ func TestUpdateMembership(t *testing.T) { membershipBytesPlain, err = protoV2.Marshal(&membershipAsset) require.NoError(t, err) membershipBytesStr = base64.StdEncoding.EncodeToString(membershipBytesPlain) - membershipBytes = []byte(membershipBytesStr) membershipBytesWithNonce = []byte(membershipBytesStr + nonce) hashed1, err = computeSHA2Hash(membershipBytesWithNonce, key1.PublicKey.Params().BitSize) require.NoError(t, err) @@ -1008,11 +993,10 @@ func TestUpdateMembership(t *testing.T) { signature2, err = ecdsa.SignASN1(random2, key2, hashed2) require.NoError(t, err) attestation2.Signature = base64.StdEncoding.EncodeToString(signature2) - attestedMembershipSet.Membership = membershipBytes + attestedMembershipSet.Membership = membershipBytesStr attestedMembershipSetBytesPlain, err = protoV2.Marshal(&attestedMembershipSet) require.NoError(t, err) attestedMembershipSetBytesStr = base64.StdEncoding.EncodeToString(attestedMembershipSetBytesPlain) - attestedMembershipSetBytes = []byte(attestedMembershipSetBytesStr) attestedMembershipSetBytesWithNonce = []byte(attestedMembershipSetBytesStr + nonce) hashedLocal1, err = computeSHA2Hash(attestedMembershipSetBytesWithNonce, keyLocal1.PublicKey.Params().BitSize) require.NoError(t, err) @@ -1024,12 +1008,12 @@ func TestUpdateMembership(t *testing.T) { signatureLocal2, err = ecdsa.SignASN1(randomLocal2, keyLocal2, hashedLocal2) require.NoError(t, err) attestationLocal2.Signature = base64.StdEncoding.EncodeToString(signatureLocal2) - counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytes + counterAttestedMembership.AttestedMembershipSet = attestedMembershipSetBytesStr counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) chaincodeStub.GetStateReturnsOnCall(10, localMembershipBytes, nil) - err = interopcc.UpdateMembership(ctx, string(counterAttestedMembershipBytes)) + err = interopcc.UpdateMembership(ctx, counterAttestedMembershipBytes) require.EqualError(t, err, fmt.Sprintf("Foreign agent security domain %s does not match attested membership security domain invalid", securityDomainId)) } diff --git a/samples/fabric/fabric-cli/src/helpers/fabric-functions.ts b/samples/fabric/fabric-cli/src/helpers/fabric-functions.ts index 0f25a2854..76b1c3580 100644 --- a/samples/fabric/fabric-cli/src/helpers/fabric-functions.ts +++ b/samples/fabric/fabric-cli/src/helpers/fabric-functions.ts @@ -375,7 +375,7 @@ const generateMembership = async ( localAttestation.setSignature(localSig) localAttestation.setNonce(nonce) let attestedMembershipSet = new iin_agent_pb.CounterAttestedMembership.AttestedMembershipSet() - attestedMembershipSet.setMembership(Buffer.from(serializedMembershipBase64)) + attestedMembershipSet.setMembership(serializedMembershipBase64) attestedMembershipSet.setAttestationsList( [ localAttestation ] ) const serializedAttestedMembershipSet = attestedMembershipSet.serializeBinary() const serializedttestedMembershipSetBase64 = Buffer.from(serializedAttestedMembershipSet).toString('base64') @@ -397,7 +397,7 @@ const generateMembership = async ( // Generate chaincode argument and save it in a file let counterAttestedMembership = new iin_agent_pb.CounterAttestedMembership() - counterAttestedMembership.setAttestedMembershipSet(Buffer.from(serializedttestedMembershipSetBase64)) + counterAttestedMembership.setAttestedMembershipSet(serializedttestedMembershipSetBase64) counterAttestedMembership.setAttestationsList( [ otherAttestation ] ) fs.writeFileSync( From f59c8dfdb24c576d8d9802470a620190cb25c9ad Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Sun, 25 Sep 2022 17:55:31 +0530 Subject: [PATCH 137/150] update the connection profile yaml file Signed-off-by: Krishnasuri Narayanam --- .../fabric/go-cli/wallets/network1/user1.id | 2 +- .../fabric/go-cli/wallets/network2/user1.id | 2 +- .../org1.network1.com/connection-org1.yaml | 65 ++++++++++++++----- .../org1.network2.com/connection-org1.yaml | 65 ++++++++++++++----- 4 files changed, 102 insertions(+), 32 deletions(-) diff --git a/samples/fabric/go-cli/wallets/network1/user1.id b/samples/fabric/go-cli/wallets/network1/user1.id index b23fd07dd..6e9517319 100644 --- a/samples/fabric/go-cli/wallets/network1/user1.id +++ b/samples/fabric/go-cli/wallets/network1/user1.id @@ -1 +1 @@ -{"version":1,"mspId":"Org1MSP","type":"X.509","credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIICZjCCAg2gAwIBAgIUa9XejI7rCs6lT+z9xaDa1v3khXkwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDkwNzA3NTYwMFoXDTIyMDkwNzA4MDEwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABPrNkU/R+C7+sciksTBFPw7lRsdJj7wupR9rT1WJ9YapjoRfYXL8jGZT\nZPsBWO6+LYXQTo75daCCk954m/PUZqujgdswgdgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFJAWeJdCDTTontmzGGN3I3EibBBqMB8GA1Ud\nIwQYMBaAFHKG9YL6OC86y5FIXpqte7bOXSD8MB4GA1UdEQQXMBWCE2tuYXJheWFu\nLVZpcnR1YWxCb3gwWAYIKgMEBQYHCAEETHsiYXR0cnMiOnsiaGYuQWZmaWxpYXRp\nb24iOiIiLCJoZi5FbnJvbGxtZW50SUQiOiJ1c2VyMSIsImhmLlR5cGUiOiJjbGll\nbnQifX0wCgYIKoZIzj0EAwIDRwAwRAIgcJvGxokVsJz0aNIQ0AJcFIVfel7UIGfI\nEhGMdNnSlcoCIGyS4hw2RdblOfnMhI1JFC6aXIouQOPjNx/bfSsPgKsX\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\nMHcCAQEEIItkSuKip24gxx1z3yoZtAKua4U5HfyVCzFlBGX4ec6ioAoGCCqGSM49\nAwEHoUQDQgAE+s2RT9H4Lv6xyKSxMEU/DuVGx0mPvC6lH2tPVYn1hqmOhF9hcvyM\nZlNk+wFY7r4thdBOjvl1oIKT3nib89Rmqw==\n-----END PRIVATE KEY-----\n"}} \ No newline at end of file +{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUf+IGiJyyyaGWwjRnjpnO0D7uzngwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjgwMFoXDTMyMDgwNDA2MzMwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABNoLyPx0DGMc4ilZlCtQw+vu2r1ZeHJukaaEk6U57gMXlpi6mU80E0xi\n7bIjQQDVdhH//zyFREjp/R5QyCRW66mjgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFAwA6h6ex1yPFlxuw5MP5UFdy0SkMB8GA1Ud\nIwQYMBaAFM7HDMehiHl8b92QSMN4Q1FB7JU/MFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQDhDvnTZ0/+\n623lX153M/EESY5wCeSIu8V6BUfAn/VC6gIgJLkdVHwWNfqtI7+9pHD4uTE86QoP\nTyegatE7P10qwNc=\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg2uMP8qtgRmGFz1hg\r\nM/uqEoKd6QFbPO41toS9q1i4Kg6hRANCAATaC8j8dAxjHOIpWZQrUMPr7tq9WXhy\r\nbpGmhJOlOe4DF5aYuplPNBNMYu2yI0EA1XYR//88hURI6f0eUMgkVuup\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file diff --git a/samples/fabric/go-cli/wallets/network2/user1.id b/samples/fabric/go-cli/wallets/network2/user1.id index 6c1020ac8..4b2a8fdd3 100644 --- a/samples/fabric/go-cli/wallets/network2/user1.id +++ b/samples/fabric/go-cli/wallets/network2/user1.id @@ -1 +1 @@ -{"version":1,"mspId":"Org1MSP","type":"X.509","credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIICZzCCAg2gAwIBAgIUF7vsVKxc1Mb37NgQE6S7eX/QgLcwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDkwNzA3NTEwMFoXDTIyMDkwNzA3NTYwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABJmkBl667bb9xK+sXnFh+dHiHRve2u4RpFjEhQhTEx+7ny8p9IWmYtWB\nWQHkSxgs60UZk/CyuxqOZYmkpznjzE+jgdswgdgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFGQmPQPOSI5/bbJDqqcK+wGc8IxvMB8GA1Ud\nIwQYMBaAFLnEbQNd9VY+cDmSDvzqxI0cKJnxMB4GA1UdEQQXMBWCE2tuYXJheWFu\nLVZpcnR1YWxCb3gwWAYIKgMEBQYHCAEETHsiYXR0cnMiOnsiaGYuQWZmaWxpYXRp\nb24iOiIiLCJoZi5FbnJvbGxtZW50SUQiOiJ1c2VyMSIsImhmLlR5cGUiOiJjbGll\nbnQifX0wCgYIKoZIzj0EAwIDSAAwRQIhAJ1e8r16W244LM7Pm098tM4LRfwUp3Ia\nOUt4BLbOUoOTAiBL9ndmCgyT4HrRzghkHBLjUypNpsneT5tOsVJr+x7PbA==\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\nMHcCAQEEINxvSt11T8eMkKLHRy/2bajMip4/xRRVeJF65uZ1pjM6oAoGCCqGSM49\nAwEHoUQDQgAEmaQGXrrttv3Er6xecWH50eIdG97a7hGkWMSFCFMTH7ufLyn0haZi\n1YFZAeRLGCzrRRmT8LK7Go5liaSnOePMTw==\n-----END PRIVATE KEY-----\n"}} \ No newline at end of file +{"credentials":{"certificate":"-----BEGIN CERTIFICATE-----\nMIICRzCCAe2gAwIBAgIUJjZQPlP6RXYv+XfLI66gBJ4dxmIwCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjgwMFoXDTMyMDgwNDA2MzMwMFowITEPMA0G\nA1UECxMGY2xpZW50MQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49\nAwEHA0IABEOUMDwPOOLjs2UGvIhWiMLuwC+GoDNV2nz6st9Gzua2h01M8o95Iio6\nmzdln9L4pZm/2HzMnBoyPKrrjYRmciajgbswgbgwDgYDVR0PAQH/BAQDAgeAMAwG\nA1UdEwEB/wQCMAAwHQYDVR0OBBYEFCCYZMhh/FIOW6zkBBBINwBobdpDMB8GA1Ud\nIwQYMBaAFOE41wEfBgHf+cfjQzayE/Q8pm2bMFgGCCoDBAUGBwgBBEx7ImF0dHJz\nIjp7ImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5yb2xsbWVudElEIjoidXNlcjEi\nLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gAMEUCIQDyUvNXt6nM\nl0/7G/oJjeBywsQeL4IU2QDBSmi7Zk1oOQIgIkQtsg+duHOWCX60zUEThXeZsg9U\ndQHFXVncLBWQhLk=\n-----END CERTIFICATE-----\n","privateKey":"-----BEGIN PRIVATE KEY-----\r\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgJ3VTKbfrMI3dm+iI\r\nTGcMCwgmi+8JhUVYZIZfjl9okWChRANCAARDlDA8Dzji47NlBryIVojC7sAvhqAz\r\nVdp8+rLfRs7mtodNTPKPeSIqOps3ZZ/S+KWZv9h8zJwaMjyq642EZnIm\r\n-----END PRIVATE KEY-----\r\n"},"mspId":"Org1MSP","type":"X.509","version":1} \ No newline at end of file diff --git a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.yaml b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.yaml index ba9fa56e6..5dcdec480 100644 --- a/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.yaml +++ b/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.yaml @@ -16,10 +16,44 @@ client: organizations: Org1: mspid: Org1MSP + cryptoPath: users/{username}@org1.network1.com/msp peers: - peer0.org1.network1.com certificateAuthorities: - ca.org1.network1.com +channels: + mychannel: + orderers: + - orderer.network1.com + peers: + peer0.org1.network1.com: + endorsingPeer: true + chaincodeQuery: true + ledgerQuery: true + eventSource: true + +orderers: + orderer.network1.com: + url: grpcs://localhost:7050 + tlsCACerts: + pem: | + -----BEGIN CERTIFICATE----- + MIICFjCCAb2gAwIBAgIUM6cOj4I4iM/mzV1zDRWHdggGlW0wCgYIKoZIzj0EAwIw + aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK + EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt + Y2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG + A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl + cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy + dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdJBRx8CYboiYFTl5R0XQq14+ + E4ekzCf6EHG2Srqh8u4oIFD+QeyR+4wwSJbJf9PWS3ngrnuoFYGwzOp0P4trUaNF + MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE + FPwe+lWvofc06dG7IQQ32tIduAHkMAoGCCqGSM49BAMCA0cAMEQCIBykgEh65XUl + yNUvDx2rMKwiyPL1A6rr7hoiFJX7KRN4AiBQpctKYeXqe/qDWFB+KaiC1YHalCrb + FQNkBAC+kBjBjQ== + -----END CERTIFICATE----- + grpcOptions: + ssl-target-name-override: orderer.network1.com + hostnameOverride: orderer.network1.com peers: peer0.org1.network1.com: url: grpcs://localhost:7051 @@ -48,21 +82,22 @@ certificateAuthorities: url: https://localhost:7054 caName: ca-org1 tlsCACerts: - pem: | - -----BEGIN CERTIFICATE----- - MIICFjCCAb2gAwIBAgIUYxHjCF1HdZexrgAM73ec4jdHy8owCgYIKoZIzj0EAwIw - aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK - EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt - Y2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG - A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl - cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy - dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE76ubZH/VHJszsYLHVKaUwKBR - UZv8P+Jq6Op5PeBf02JUKPM15DSF9n56RJq+7mrM9zBzPvBsUySFd+rr/BrsW6NF - MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE - FM7HDMehiHl8b92QSMN4Q1FB7JU/MAoGCCqGSM49BAMCA0cAMEQCIH4UJq+qY2OP - 7DzBAwY7woYuy4zoT2kxyiexlix38aY4AiAo+8OKE1wFM+XKLUqI4zzgq2bpg1qb - U5aIsTpdz3N2tg== - -----END CERTIFICATE----- + pem: + - | + -----BEGIN CERTIFICATE----- + MIICFjCCAb2gAwIBAgIUYxHjCF1HdZexrgAM73ec4jdHy8owCgYIKoZIzj0EAwIw + aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK + EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt + Y2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG + A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl + cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy + dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE76ubZH/VHJszsYLHVKaUwKBR + UZv8P+Jq6Op5PeBf02JUKPM15DSF9n56RJq+7mrM9zBzPvBsUySFd+rr/BrsW6NF + MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE + FM7HDMehiHl8b92QSMN4Q1FB7JU/MAoGCCqGSM49BAMCA0cAMEQCIH4UJq+qY2OP + 7DzBAwY7woYuy4zoT2kxyiexlix38aY4AiAo+8OKE1wFM+XKLUqI4zzgq2bpg1qb + U5aIsTpdz3N2tg== + -----END CERTIFICATE----- httpOptions: verify: false diff --git a/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/connection-org1.yaml b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/connection-org1.yaml index e8cb62089..68034f2bc 100644 --- a/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/connection-org1.yaml +++ b/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/connection-org1.yaml @@ -16,10 +16,44 @@ client: organizations: Org1: mspid: Org1MSP + cryptoPath: users/{username}@org1.network2.com/msp peers: - peer0.org1.network2.com certificateAuthorities: - ca.org1.network2.com +channels: + mychannel: + orderers: + - orderer.network2.com + peers: + peer0.org1.network2.com: + endorsingPeer: true + chaincodeQuery: true + ledgerQuery: true + eventSource: true + +orderers: + orderer.network2.com: + url: grpcs://localhost:9050 + tlsCACerts: + pem: | + -----BEGIN CERTIFICATE----- + MIICFzCCAb2gAwIBAgIUD9fr2Th1T0hW7NLkDt6bj+Mf5JQwCgYIKoZIzj0EAwIw + aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK + EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt + Y2Etc2VydmVyMB4XDTIyMDgwNDE4MjQwMFoXDTM3MDczMTE4MjQwMFowaDELMAkG + A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl + cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy + dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYY0yhu38vAnYpSaEBt/B+lUn + Xo+FFctZYT2RT0H9/kqeUv8TbsrkS9sXUW1ACdFVngqmx67CWvK129HR3CobwaNF + MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE + FJCcwMtpUWb4vhGyerjwaXnKJZbQMAoGCCqGSM49BAMCA0gAMEUCIQCKyWEsYE8w + o+Bsvaytvli1PqM8hvMh+yUk+8bz8/AQBgIgAueAOZkBpteDoXQQxB8yi0jPNV3O + tQmBzAip3hsih1s= + -----END CERTIFICATE----- + grpcOptions: + ssl-target-name-override: orderer.network2.com + hostnameOverride: orderer.network2.com peers: peer0.org1.network2.com: url: grpcs://localhost:9051 @@ -48,21 +82,22 @@ certificateAuthorities: url: https://localhost:5054 caName: ca-org1 tlsCACerts: - pem: | - -----BEGIN CERTIFICATE----- - MIICFzCCAb2gAwIBAgIUajWU/EzwkVocqYksNXUdm04WvCswCgYIKoZIzj0EAwIw - aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK - EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt - Y2Etc2VydmVyMB4XDTIyMDgwNDE4MjQwMFoXDTM3MDczMTE4MjQwMFowaDELMAkG - A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl - cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy - dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5is5AaAg+nbhzGDEQG+liqNH - hl876WuMbeT8k6dRNAsBpIwpxRWlg9iNrnvlkkhCBjb9AUyczQ7+BY1+NfUYlKNF - MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE - FOE41wEfBgHf+cfjQzayE/Q8pm2bMAoGCCqGSM49BAMCA0gAMEUCIQCDmJzZfO1n - VX5eMdDkDDtDz+eAXhPsu7upJW0ukhxkTAIgJceBfxJYwM1Tof1ADInIY+M+U8y+ - TL2JfaeZkJJz42E= - -----END CERTIFICATE----- + pem: + - | + -----BEGIN CERTIFICATE----- + MIICFzCCAb2gAwIBAgIUajWU/EzwkVocqYksNXUdm04WvCswCgYIKoZIzj0EAwIw + aDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK + EwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt + Y2Etc2VydmVyMB4XDTIyMDgwNDE4MjQwMFoXDTM3MDczMTE4MjQwMFowaDELMAkG + A1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl + cmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy + dmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5is5AaAg+nbhzGDEQG+liqNH + hl876WuMbeT8k6dRNAsBpIwpxRWlg9iNrnvlkkhCBjb9AUyczQ7+BY1+NfUYlKNF + MEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE + FOE41wEfBgHf+cfjQzayE/Q8pm2bMAoGCCqGSM49BAMCA0gAMEUCIQCDmJzZfO1n + VX5eMdDkDDtDz+eAXhPsu7upJW0ukhxkTAIgJceBfxJYwM1Tof1ADInIY+M+U8y+ + TL2JfaeZkJJz42E= + -----END CERTIFICATE----- httpOptions: verify: false From 66be3aadbdc56463ddfa8f853515bcfcec7e97c3 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Sun, 25 Sep 2022 19:01:23 +0000 Subject: [PATCH 138/150] Reverting unnecessary Github action change Signed-off-by: VRamakrishna --- .github/workflows/deploy_corda-pkgs.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy_corda-pkgs.yml b/.github/workflows/deploy_corda-pkgs.yml index 6638b4a06..d860ef45d 100644 --- a/.github/workflows/deploy_corda-pkgs.yml +++ b/.github/workflows/deploy_corda-pkgs.yml @@ -19,7 +19,6 @@ on: jobs: publish-protos: - if: github.repository_owner == 'hyperledger-labs' runs-on: ubuntu-latest steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it @@ -46,7 +45,7 @@ jobs: publish-interop-app: - if: ${{ always() && github.repository_owner == 'hyperledger-labs' }} + if: always() needs: publish-protos runs-on: ubuntu-latest steps: @@ -77,7 +76,7 @@ jobs: working-directory: core/network/corda-interop-app publish-sdk: - if: ${{ always() && github.repository_owner == 'hyperledger-labs' }} + if: always() needs: [publish-protos, publish-interop-app] runs-on: ubuntu-latest steps: From 7aa74854bf350cccc28735ee75dcb0fe0c5a9a6a Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Tue, 27 Sep 2022 06:13:09 +0000 Subject: [PATCH 139/150] Refactored memership handling code in Fabric Interop CC to eliminate code redundancy Signed-off-by: VRamakrishna --- .../contracts/interop/membership.go | 224 ++++++------------ .../contracts/interop/membership_test.go | 38 ++- .../interop/write_external_state_test.go | 14 +- .../fabric-interop-cc/libs/utils/utils.go | 16 ++ 4 files changed, 127 insertions(+), 165 deletions(-) diff --git a/core/network/fabric-interop-cc/contracts/interop/membership.go b/core/network/fabric-interop-cc/contracts/interop/membership.go index 6215475c0..561beac89 100644 --- a/core/network/fabric-interop-cc/contracts/interop/membership.go +++ b/core/network/fabric-interop-cc/contracts/interop/membership.go @@ -19,29 +19,12 @@ import ( "github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go/common" "github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go/identity" protoV2 "google.golang.org/protobuf/proto" + wutils "github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/utils" ) const membershipObjectType = "membership" const membershipLocalSecurityDomain = "local-security-domain" -// Check if the calling client has an attribute in its signing certificate indicating that it is a privileged network administrator -//func isClientNetworkAdmin(stub shim.ChaincodeStubInterface) (bool, error) { -func isClientNetworkAdmin(ctx contractapi.TransactionContextInterface) (bool, error) { - // check if caller certificate has the attribute "network-admin" - // we don't care about the actual value of the attribute for now - _, ok, err := ctx.GetClientIdentity().GetAttributeValue("network-admin") - return ok, err -} - -// Check if the calling client has an IIN Agent attribute in its signing certificate -//func isClientIINAgent(stub shim.ChaincodeStubInterface) (bool, error) { -func isClientIINAgent(ctx contractapi.TransactionContextInterface) (bool, error) { - // check if caller certificate has the attribute "iin-agent" - // we don't care about the actual value of the attribute for now - _, ok, err := ctx.GetClientIdentity().GetAttributeValue("iin-agent") - return ok, err -} - // Check the validity of each certificate chain in this membership func validateMemberCertChains(membership *common.Membership) error { for _, member := range membership.Members { @@ -55,34 +38,6 @@ func validateMemberCertChains(membership *common.Membership) error { return nil } -// Check whether the given user certificate belongs to the given security domain membership -func checkUserInMembership(userCert *x509.Certificate, membership *common.Membership) error { - for _, member := range membership.Members { - if member.Type == "ca" && member.Value != "" { - decodedCACert, _ := pem.Decode([]byte(member.Value)) - if decodedCACert == nil { - fmt.Printf("Unable to decode CA cert PEM: %s\n", member.Value) - } - caCert, err := x509.ParseCertificate(decodedCACert.Bytes) - if err != nil { - fmt.Printf("Unable to parse CA certificate: %s\n", member.Value) - } - err = validateCertificateUsingCA(userCert, caCert, true) - if err == nil { - return nil - } - } else if member.Type == "certificate" && len(member.Chain) > 0 { - err := verifyCertificateChain(userCert, member.Chain) - if err == nil { - return nil - } - } else { - fmt.Printf("Invalid member info: %+v\n", member) - } - } - return fmt.Errorf("User cert %+v could not be validated against any CA certificate chain in membership %+v", userCert, membership) -} - // Validate 'identity.Attestation' object against a message byte array func validateAttestation(attestation *identity.Attestation, messageBytes string) error { // Parse local IIN Agent's certificate @@ -109,7 +64,7 @@ func validateAttestation(attestation *identity.Attestation, messageBytes string) // CreateLocalMembership cc is used to store the local security domain's Membership in the ledger func (s *SmartContract) CreateLocalMembership(ctx contractapi.TransactionContextInterface, membershipJSON string) error { // Check if the caller has network admin privileges - if isAdmin, err := isClientNetworkAdmin(ctx); err != nil { + if isAdmin, err := wutils.IsClientNetworkAdmin(ctx); err != nil { return fmt.Errorf("Admin client check error: %s", err) } else if !isAdmin { return fmt.Errorf("Caller not a network admin; access denied") @@ -145,7 +100,7 @@ func (s *SmartContract) CreateLocalMembership(ctx contractapi.TransactionContext // UpdateLocalMembership cc is used to update the existing local security domain's Membership in the ledger func (s *SmartContract) UpdateLocalMembership(ctx contractapi.TransactionContextInterface, membershipJSON string) error { // Check if the caller has network admin privileges - if isAdmin, err := isClientNetworkAdmin(ctx); err != nil { + if isAdmin, err := wutils.IsClientNetworkAdmin(ctx); err != nil { return fmt.Errorf("Admin client check error: %+v", err) } else if !isAdmin { return fmt.Errorf("Caller not a network admin; access denied") @@ -180,35 +135,31 @@ func (s *SmartContract) UpdateLocalMembership(ctx contractapi.TransactionContext // TODO: Remove call to 'createMembership' after creating Corda IIN Agents. func (s *SmartContract) CreateMembership(ctx contractapi.TransactionContextInterface, counterAttestedMembershipSerialized string) error { // Check if the caller has IIN agent privileges - if isIINAgent, err := isClientIINAgent(ctx); err != nil { + if isIINAgent, err := wutils.IsClientIINAgent(ctx); err != nil { return fmt.Errorf("IIN Agent client check error: %s", err) } else if !isIINAgent { // Check if the caller has network admin privileges - if isAdmin, err := isClientNetworkAdmin(ctx); err != nil { + if isAdmin, err := wutils.IsClientNetworkAdmin(ctx); err != nil { return fmt.Errorf("Admin client check error: %s", err) } else if !isAdmin { return fmt.Errorf("Caller neither a network admin nor an IIN Agent; access denied") } - return s.createMembership(ctx, counterAttestedMembershipSerialized) // HACK to handle unattested memberships (for Corda) for backward compatibility + return createMembership(ctx, counterAttestedMembershipSerialized) // HACK to handle unattested memberships (for Corda) for backward compatibility } // Check if caller is one of the authorized IIN agents - membershipLocal, err := s.GetMembershipBySecurityDomain(ctx, membershipLocalSecurityDomain) + callerId := ctx.GetClientIdentity() + callerCert, err := callerId.GetX509Certificate() if err != nil { return err } - membershipLocalDecoded, err := decodeMembership([]byte(membershipLocal)) - if err != nil { - return fmt.Errorf("Local Membership JSON Unmarshal error: %s", err) - } - callerId := ctx.GetClientIdentity() - callerCert, err := callerId.GetX509Certificate() + callerMemberUnit, err := callerId.GetMSPID() if err != nil { return err } - err = checkUserInMembership(callerCert, membershipLocalDecoded) + err = verifyMemberInSecurityDomain1(s, ctx, "", callerCert, membershipLocalSecurityDomain, callerMemberUnit) if err != nil { - return fmt.Errorf("Caller with identity %+v is not a designated IIN Agent: %+v", callerId, err) + return fmt.Errorf("Caller with identity %+v is not a designated IIN Agent of org %s: %+v", callerId, callerMemberUnit, err) } counterAttestedMembership, err := decodeCounterAttestedMembership(counterAttestedMembershipSerialized) @@ -234,6 +185,16 @@ func (s *SmartContract) CreateMembership(ctx contractapi.TransactionContextInter return fmt.Errorf("Unable to unmarshal membership: %s", err.Error()) } + // Check presence of membership on ledger first + membershipKey, err := ctx.GetStub().CreateCompositeKey(membershipObjectType, []string{foreignMembership.SecurityDomain}) + acp, getErr := ctx.GetStub().GetState(membershipKey) + if getErr != nil { + return getErr + } + if acp != nil { + return fmt.Errorf("Membership already exists for membership id: %s. Use 'UpdateMembership' to update.", foreignMembership.SecurityDomain) + } + // Match nonces across all attestations, local and foreign matchedNonce := "" for _, attestation := range append(counterAttestedMembership.Attestations, attestedMembershipSet.Attestations...) { @@ -266,33 +227,14 @@ func (s *SmartContract) CreateMembership(ctx contractapi.TransactionContextInter return fmt.Errorf("Foreign agent security domain %s does not match attested membership security domain %s", attestation.UnitIdentity.SecurityDomain, foreignMembership.SecurityDomain) } - foundMemberMatch := false - for _, member := range foreignMembership.Members { - var isSignerRoot bool - var leafCertPEM string - if member.Type == "ca" { - leafCertPEM = member.Value - isSignerRoot = true - } else if member.Type == "certificate" { - leafCertPEM = member.Chain[len(member.Chain) - 1] - isSignerRoot = (len(member.Chain) == 1) - } - attesterCert, err := parseCert(attestation.Certificate) - if err != nil { - continue - } - leafCert, err := parseCert(leafCertPEM) - if err != nil { - continue - } - err = validateCertificateUsingCA(attesterCert, leafCert, isSignerRoot) - if err == nil { - foundMemberMatch = true - break - } + attesterCert, err := parseCert(attestation.Certificate) + if err != nil { + return fmt.Errorf("Unable to parse attester certificate") } - if !foundMemberMatch { - return fmt.Errorf("No matching member certificate chain found for attester") + err = verifyMemberInSecurityDomain2(s, ctx, "", attesterCert, &foreignMembership, attestation.UnitIdentity.MemberId) + if err != nil { + return fmt.Errorf("Attester with certificate %+v is not a designated IIN Agent of org %s in security domain %s: %+v", + attesterCert, attestation.UnitIdentity.MemberId, attestation.UnitIdentity.SecurityDomain, err) } // Validate signature err = validateAttestation(attestation, attestedMembershipSet.Membership + attestation.Nonce) @@ -301,15 +243,6 @@ func (s *SmartContract) CreateMembership(ctx contractapi.TransactionContextInter } } - membershipKey, err := ctx.GetStub().CreateCompositeKey(membershipObjectType, []string{foreignMembership.SecurityDomain}) - acp, getErr := ctx.GetStub().GetState(membershipKey) - if getErr != nil { - return getErr - } - if acp != nil { - return fmt.Errorf("Membership already exists for membership id: %s. Use 'UpdateMembership' to update.", foreignMembership.SecurityDomain) - } - membershipBytes, err := json.Marshal(foreignMembership) if err != nil { return fmt.Errorf("Marshal error: %s", err) @@ -319,7 +252,7 @@ func (s *SmartContract) CreateMembership(ctx contractapi.TransactionContextInter // createMembership is used by a network admin to store a Membership in the ledger with an unattested membership // TODO: Remove this function after creating Corda IIN Agents. Retaining this temporarily for backward compatibility. -func (s *SmartContract) createMembership(ctx contractapi.TransactionContextInterface, membershipJSON string) error { +func createMembership(ctx contractapi.TransactionContextInterface, membershipJSON string) error { membership, err := decodeMembership([]byte(membershipJSON)) if err != nil { return fmt.Errorf("Unmarshal error: %s", err) @@ -350,33 +283,29 @@ func (s *SmartContract) createMembership(ctx contractapi.TransactionContextInter // TODO: Remove call to 'updateMembership' after creating Corda IIN Agents. func (s *SmartContract) UpdateMembership(ctx contractapi.TransactionContextInterface, counterAttestedMembershipSerialized string) error { // Check if the caller has IIN agent privileges - if isIINAgent, err := isClientIINAgent(ctx); err != nil { + if isIINAgent, err := wutils.IsClientIINAgent(ctx); err != nil { return fmt.Errorf("IIN Agent client check error: %s", err) } else if !isIINAgent { // Check if the caller has network admin privileges - if isAdmin, err := isClientNetworkAdmin(ctx); err != nil { + if isAdmin, err := wutils.IsClientNetworkAdmin(ctx); err != nil { return fmt.Errorf("Admin client check error: %s", err) } else if !isAdmin { return fmt.Errorf("Caller neither a network admin nor an IIN Agent; access denied") } - return s.updateMembership(ctx, counterAttestedMembershipSerialized) // HACK to handle unattested memberships (for Corda) for backward compatibility + return updateMembership(s, ctx, counterAttestedMembershipSerialized) // HACK to handle unattested memberships (for Corda) for backward compatibility } // Check if caller is one of the authorized IIN agents - membershipLocal, err := s.GetMembershipBySecurityDomain(ctx, membershipLocalSecurityDomain) + callerId := ctx.GetClientIdentity() + callerCert, err := callerId.GetX509Certificate() if err != nil { return err } - membershipLocalDecoded, err := decodeMembership([]byte(membershipLocal)) - if err != nil { - return fmt.Errorf("Unmarshal error: %s", err) - } - callerId := ctx.GetClientIdentity() - callerCert, err := callerId.GetX509Certificate() + callerMemberUnit, err := callerId.GetMSPID() if err != nil { return err } - err = checkUserInMembership(callerCert, membershipLocalDecoded) + err = verifyMemberInSecurityDomain1(s, ctx, "", callerCert, membershipLocalSecurityDomain, callerMemberUnit) if err != nil { return fmt.Errorf("Caller with identity %+v is not a designated IIN Agent: %+v", callerId, err) } @@ -404,6 +333,13 @@ func (s *SmartContract) UpdateMembership(ctx contractapi.TransactionContextInter return fmt.Errorf("Unable to unmarshal membership: %s", err.Error()) } + // Check presence of membership on ledger first + membershipKey, err := ctx.GetStub().CreateCompositeKey(membershipObjectType, []string{foreignMembership.SecurityDomain}) + _, getErr := s.GetMembershipBySecurityDomain(ctx, foreignMembership.SecurityDomain) + if getErr != nil { + return getErr + } + // Match nonces across all attestations, local and foreign matchedNonce := "" for _, attestation := range append(counterAttestedMembership.Attestations, attestedMembershipSet.Attestations...) { @@ -436,33 +372,14 @@ func (s *SmartContract) UpdateMembership(ctx contractapi.TransactionContextInter return fmt.Errorf("Foreign agent security domain %s does not match attested membership security domain %s", attestation.UnitIdentity.SecurityDomain, foreignMembership.SecurityDomain) } - foundMemberMatch := false - for _, member := range foreignMembership.Members { - var isSignerRoot bool - var leafCertPEM string - if member.Type == "ca" { - leafCertPEM = member.Value - isSignerRoot = true - } else if member.Type == "certificate" { - leafCertPEM = member.Chain[len(member.Chain) - 1] - isSignerRoot = (len(member.Chain) == 1) - } - attesterCert, err := parseCert(attestation.Certificate) - if err != nil { - continue - } - leafCert, err := parseCert(leafCertPEM) - if err != nil { - continue - } - err = validateCertificateUsingCA(attesterCert, leafCert, isSignerRoot) - if err == nil { - foundMemberMatch = true - break - } + attesterCert, err := parseCert(attestation.Certificate) + if err != nil { + return fmt.Errorf("Unable to parse attester certificate") } - if !foundMemberMatch { - return fmt.Errorf("No matching member certificate chain found for attester") + err = verifyMemberInSecurityDomain2(s, ctx, "", attesterCert, &foreignMembership, attestation.UnitIdentity.MemberId) + if err != nil { + return fmt.Errorf("Attester with certificate %+v is not a designated IIN Agent of org %s in security domain %s: %+v", + attesterCert, attestation.UnitIdentity.MemberId, attestation.UnitIdentity.SecurityDomain, err) } // Validate signature err = validateAttestation(attestation, attestedMembershipSet.Membership + attestation.Nonce) @@ -471,12 +388,6 @@ func (s *SmartContract) UpdateMembership(ctx contractapi.TransactionContextInter } } - membershipKey, err := ctx.GetStub().CreateCompositeKey(membershipObjectType, []string{foreignMembership.SecurityDomain}) - _, getErr := s.GetMembershipBySecurityDomain(ctx, foreignMembership.SecurityDomain) - if getErr != nil { - return getErr - } - membershipBytes, err := json.Marshal(foreignMembership) if err != nil { return fmt.Errorf("Marshal error: %s", err) @@ -487,7 +398,7 @@ func (s *SmartContract) UpdateMembership(ctx contractapi.TransactionContextInter // updateMembership is used by a network admin to update an existing Membership in the ledger with an unattested membership // TODO: Remove this function after creating Corda IIN Agents. Retaining this temporarily for backward compatibility. -func (s *SmartContract) updateMembership(ctx contractapi.TransactionContextInterface, membershipJSON string) error { +func updateMembership(s *SmartContract, ctx contractapi.TransactionContextInterface, membershipJSON string) error { membership, err := decodeMembership([]byte(membershipJSON)) if err != nil { return fmt.Errorf("Unmarshal error: %s", err) @@ -515,7 +426,7 @@ func (s *SmartContract) updateMembership(ctx contractapi.TransactionContextInter // DeleteLocalMembership cc is used to delete the local security domain Membership in the ledger func (s *SmartContract) DeleteLocalMembership(ctx contractapi.TransactionContextInterface) error { // Check if the caller has network admin privileges - if isAdmin, err := isClientNetworkAdmin(ctx); err != nil { + if isAdmin, err := wutils.IsClientNetworkAdmin(ctx); err != nil { return fmt.Errorf("Admin client check error: %s", err) } else if !isAdmin { return fmt.Errorf("Caller not a network admin; access denied") @@ -540,7 +451,7 @@ func (s *SmartContract) DeleteLocalMembership(ctx contractapi.TransactionContext // DeleteMembership cc is used to delete an existing Membership in the ledger func (s *SmartContract) DeleteMembership(ctx contractapi.TransactionContextInterface, membershipID string) error { // Check if the caller has IIN agent privileges - if isIINAgent, err := isClientIINAgent(ctx); err != nil { + if isIINAgent, err := wutils.IsClientIINAgent(ctx); err != nil { return fmt.Errorf("IIN Agent client check error: %s", err) } else if !isIINAgent { return fmt.Errorf("Caller not an IIN Agent; access denied") @@ -579,15 +490,21 @@ func (s *SmartContract) GetMembershipBySecurityDomain(ctx contractapi.Transactio // verifyMemberInSecurityDomain function verifies the identity of the requester according to // the Membership for the external network the request originated from. +// This takes a certificate encoded in PEM format as argument. +// It assumes that the relevant membership info is on the ledger. func verifyMemberInSecurityDomain(s *SmartContract, ctx contractapi.TransactionContextInterface, certPEM string, securityDomain string, requestingOrg string) error { cert, err := parseCert(certPEM) if err != nil { return fmt.Errorf("Unable to parse certificate: %s", err.Error()) } - err = isCertificateWithinExpiry(cert) - if err != nil { - return err - } + return verifyMemberInSecurityDomain1(s, ctx, certPEM, cert, securityDomain, requestingOrg) +} + +// verifyMemberInSecurityDomain1 function verifies the identity of the requester according to +// the Membership for the external network the request originated from. +// This takes a decoded X.509 certificate as argument (and optionally the certificate in PEM format too). +// It assumes that the relevant membership info is on the ledger. +func verifyMemberInSecurityDomain1(s *SmartContract, ctx contractapi.TransactionContextInterface, certPEM string, cert *x509.Certificate, securityDomain string, requestingOrg string) error { membershipString, err := s.GetMembershipBySecurityDomain(ctx, securityDomain) if err != nil { return err @@ -596,12 +513,27 @@ func verifyMemberInSecurityDomain(s *SmartContract, ctx contractapi.TransactionC if err != nil { return fmt.Errorf("Failed to unmarshal membership: %s", err.Error()) } + return verifyMemberInSecurityDomain2(s, ctx, certPEM, cert, membership, requestingOrg) +} + +// verifyMemberInSecurityDomain2 function verifies the identity of the requester according to +// the Membership for the external network the request originated from. +// This takes a decoded X.509 certificate as argument (and optionally the certificate in PEM format too). +// It takes a membership structure as argument. +func verifyMemberInSecurityDomain2(s *SmartContract, ctx contractapi.TransactionContextInterface, certPEM string, cert *x509.Certificate, membership *common.Membership, requestingOrg string) error { + err := isCertificateWithinExpiry(cert) + if err != nil { + return err + } member, ok := membership.Members[requestingOrg] if ok == false { return fmt.Errorf("Member does not exist for org: %s", requestingOrg) } switch member.Type { case "ca": + if member.Value == "" { + return fmt.Errorf("CA member certificate is blank") + } if certPEM != member.Value { // The CA is automatically a member of the security domain err := verifyCaCertificate(cert, member.Value) if err != nil { diff --git a/core/network/fabric-interop-cc/contracts/interop/membership_test.go b/core/network/fabric-interop-cc/contracts/interop/membership_test.go index ef0126ab9..127ef773a 100644 --- a/core/network/fabric-interop-cc/contracts/interop/membership_test.go +++ b/core/network/fabric-interop-cc/contracts/interop/membership_test.go @@ -332,7 +332,7 @@ func TestCreateMembership(t *testing.T) { member1, member2 := getMembership() membershipAsset := common.Membership{ SecurityDomain: securityDomainId, - Members: map[string]*common.Member{ "member1": &member1, "member2": &member2}, + Members: map[string]*common.Member{ foreignMemberId1: &member1, foreignMemberId2: &member2}, } // Generate foreign network member 1 CA structure and client credentials @@ -407,7 +407,7 @@ func TestCreateMembership(t *testing.T) { } localMembershipAsset := common.Membership{ SecurityDomain: localSecurityDomainId, - Members: map[string]*common.Member{ "member1": &localMember1, "member2": &localMember2}, + Members: map[string]*common.Member{ localMemberId1: &localMember1, localMemberId2: &localMember2}, } // Generate local attesters @@ -488,6 +488,9 @@ func TestCreateMembership(t *testing.T) { chaincodeStub.GetStateReturnsOnCall(2, localMembershipBytes, nil) chaincodeStub.GetStateReturnsOnCall(3, nil, nil) clientIdentity.GetAttributeValueCalls(setClientIINAgent) + certLocalAgent2, _ := x509.ParseCertificate(certLocalBytes2) + clientIdentity.GetX509CertificateReturns(certLocalAgent2, nil) + clientIdentity.GetMSPIDReturns(localMemberId2, nil) ctx.GetClientIdentityReturns(clientIdentity) err = interopcc.CreateMembership(ctx, counterAttestedMembershipBytes) require.NoError(t, err) @@ -536,7 +539,8 @@ func TestCreateMembership(t *testing.T) { counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) - chaincodeStub.GetStateReturnsOnCall(7, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(8, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(9, nil, nil) err = interopcc.CreateMembership(ctx, counterAttestedMembershipBytes) require.EqualError(t, err, "Unable to Validate Signature: Signature Verification failed. ECDSA VERIFY") @@ -565,7 +569,8 @@ func TestCreateMembership(t *testing.T) { counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) - chaincodeStub.GetStateReturnsOnCall(8, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(10, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(11, nil, nil) err = interopcc.CreateMembership(ctx, counterAttestedMembershipBytes) require.EqualError(t, err, fmt.Sprintf("Mismatched nonces across two attestations: %s, %s", nonce, attestation1.Nonce)) @@ -607,7 +612,8 @@ func TestCreateMembership(t *testing.T) { counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) - chaincodeStub.GetStateReturnsOnCall(9, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(12, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(13, nil, nil) err = interopcc.CreateMembership(ctx, counterAttestedMembershipBytes) require.Error(t, err) @@ -649,7 +655,8 @@ func TestCreateMembership(t *testing.T) { counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) - chaincodeStub.GetStateReturnsOnCall(10, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(14, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(15, nil, nil) err = interopcc.CreateMembership(ctx, counterAttestedMembershipBytes) require.EqualError(t, err, fmt.Sprintf("Foreign agent security domain %s does not match attested membership security domain invalid", securityDomainId)) } @@ -694,7 +701,7 @@ func TestUpdateMembership(t *testing.T) { member1, member2 := getMembership() membershipAsset := common.Membership{ SecurityDomain: securityDomainId, - Members: map[string]*common.Member{ "member1": &member1, "member2": &member2}, + Members: map[string]*common.Member{ foreignMemberId1: &member1, foreignMemberId2: &member2}, } // Generate foreign network member 1 CA structure and client credentials @@ -769,7 +776,7 @@ func TestUpdateMembership(t *testing.T) { } localMembershipAsset := common.Membership{ SecurityDomain: localSecurityDomainId, - Members: map[string]*common.Member{ "member1": &localMember1, "member2": &localMember2}, + Members: map[string]*common.Member{ localMemberId1: &localMember1, localMemberId2: &localMember2}, } // Generate local attesters @@ -851,6 +858,9 @@ func TestUpdateMembership(t *testing.T) { chaincodeStub.GetStateReturnsOnCall(2, localMembershipBytes, nil) chaincodeStub.GetStateReturnsOnCall(3, nil, nil) clientIdentity.GetAttributeValueCalls(setClientIINAgent) + certLocalAgent2, _ := x509.ParseCertificate(certLocalBytes2) + clientIdentity.GetX509CertificateReturns(certLocalAgent2, nil) + clientIdentity.GetMSPIDReturns(localMemberId2, nil) ctx.GetClientIdentityReturns(clientIdentity) err = interopcc.UpdateMembership(ctx, counterAttestedMembershipBytes) require.EqualError(t, err, fmt.Sprintf("Membership with id: %s does not exist", securityDomainId)) @@ -899,7 +909,8 @@ func TestUpdateMembership(t *testing.T) { counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) - chaincodeStub.GetStateReturnsOnCall(7, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(8, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(9, []byte{}, nil) err = interopcc.UpdateMembership(ctx, counterAttestedMembershipBytes) require.EqualError(t, err, "Unable to Validate Signature: Signature Verification failed. ECDSA VERIFY") @@ -928,7 +939,8 @@ func TestUpdateMembership(t *testing.T) { counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) - chaincodeStub.GetStateReturnsOnCall(8, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(10, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(11, []byte{}, nil) err = interopcc.UpdateMembership(ctx, counterAttestedMembershipBytes) require.EqualError(t, err, fmt.Sprintf("Mismatched nonces across two attestations: %s, %s", nonce, attestation1.Nonce)) @@ -970,7 +982,8 @@ func TestUpdateMembership(t *testing.T) { counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) - chaincodeStub.GetStateReturnsOnCall(9, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(12, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(13, []byte{}, nil) err = interopcc.UpdateMembership(ctx, counterAttestedMembershipBytes) require.Error(t, err) @@ -1012,7 +1025,8 @@ func TestUpdateMembership(t *testing.T) { counterAttestedMembershipBytesPlain, err = protoV2.Marshal(&counterAttestedMembership) require.NoError(t, err) counterAttestedMembershipBytes = base64.StdEncoding.EncodeToString(counterAttestedMembershipBytesPlain) - chaincodeStub.GetStateReturnsOnCall(10, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(14, localMembershipBytes, nil) + chaincodeStub.GetStateReturnsOnCall(15, []byte{}, nil) err = interopcc.UpdateMembership(ctx, counterAttestedMembershipBytes) require.EqualError(t, err, fmt.Sprintf("Foreign agent security domain %s does not match attested membership security domain invalid", securityDomainId)) } diff --git a/core/network/fabric-interop-cc/contracts/interop/write_external_state_test.go b/core/network/fabric-interop-cc/contracts/interop/write_external_state_test.go index 056645270..4401afa99 100644 --- a/core/network/fabric-interop-cc/contracts/interop/write_external_state_test.go +++ b/core/network/fabric-interop-cc/contracts/interop/write_external_state_test.go @@ -21,21 +21,21 @@ import ( type TestData struct { - B64View string `json:"view64"` + B64View string `json:"view64"` B64ViewConfidential string `json:"confidential_view64"` - B64ViewContents string `json:"confidential_view_content64"` + B64ViewContents string `json:"confidential_view_content64"` } func TestWriteExternalState(t *testing.T) { - - + + var cordaTestDataBytes, _ = ioutil.ReadFile("./test_data/corda_viewdata.json") var cordaTestData TestData json.Unmarshal(cordaTestDataBytes, &cordaTestData) var cordaRootCACert, _ = ioutil.ReadFile("./test_data/corda_cacert_root.pem") var cordaDoormanCACert, _ = ioutil.ReadFile("./test_data/corda_cacert_doorman.pem") var cordaNodeCACert, _ = ioutil.ReadFile("./test_data/corda_cacert_node.pem") - + var cordaMember = common.Member{ Value: "", Type: "certificate", @@ -62,11 +62,11 @@ func TestWriteExternalState(t *testing.T) { var fabricRelayEndpoint = "relay-network1:9080" var fabricPattern = "mychannel:simplestate:Read:a" var fabricViewAddress = fabricRelayEndpoint + "/" + fabricNetwork + "/" + fabricPattern - + var fabricTestDataBytes, _ = ioutil.ReadFile("./test_data/fabric_viewdata.json") var fabricTestData TestData json.Unmarshal(fabricTestDataBytes, &fabricTestData) - + var fabricCaCertNetwork1, _ = ioutil.ReadFile("./test_data/fabric_cacert.pem") var network1Member = common.Member{ diff --git a/core/network/fabric-interop-cc/libs/utils/utils.go b/core/network/fabric-interop-cc/libs/utils/utils.go index df765d7bf..e84f4c1b4 100644 --- a/core/network/fabric-interop-cc/libs/utils/utils.go +++ b/core/network/fabric-interop-cc/libs/utils/utils.go @@ -80,6 +80,22 @@ func IsClientRelay(stub shim.ChaincodeStubInterface) (bool, error) { return ok, err } +// Check if the calling client has an attribute in its signing certificate indicating that it is a privileged network administrator +func IsClientNetworkAdmin(ctx contractapi.TransactionContextInterface) (bool, error) { + // check if caller certificate has the attribute "network-admin" + // we don't care about the actual value of the attribute for now + _, ok, err := ctx.GetClientIdentity().GetAttributeValue("network-admin") + return ok, err +} + +// Check if the calling client has an IIN Agent attribute in its signing certificate +func IsClientIINAgent(ctx contractapi.TransactionContextInterface) (bool, error) { + // check if caller certificate has the attribute "iin-agent" + // we don't care about the actual value of the attribute for now + _, ok, err := ctx.GetClientIdentity().GetAttributeValue("iin-agent") + return ok, err +} + // Check if the caller is the Interop Chaincode func IsCallerInteropChaincode(stub shim.ChaincodeStubInterface) (bool, error) { interopChaincodeID, err := stub.GetState(GetInteropChaincodeIDKey()) From ba63f7575b71db18e0b8ffd2bfad834db49019d1 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Tue, 27 Sep 2022 07:46:14 +0000 Subject: [PATCH 140/150] Refactored membership logic in Fabric Interoperation Chaincode to extract common functions Signed-off-by: VRamakrishna --- .../contracts/interop/membership.go | 222 ++++++++---------- 1 file changed, 93 insertions(+), 129 deletions(-) diff --git a/core/network/fabric-interop-cc/contracts/interop/membership.go b/core/network/fabric-interop-cc/contracts/interop/membership.go index 561beac89..5c8e38cb4 100644 --- a/core/network/fabric-interop-cc/contracts/interop/membership.go +++ b/core/network/fabric-interop-cc/contracts/interop/membership.go @@ -61,6 +61,88 @@ func validateAttestation(attestation *identity.Attestation, messageBytes string) return nil } +// Parse 'identity.CounterAttestedMembership' object and extract structures +func parseCounterAttestedMembership(counterAttestedMembershipSerialized string) (*identity.CounterAttestedMembership, *identity.CounterAttestedMembership_AttestedMembershipSet, *common.Membership, error) { + counterAttestedMembership, err := decodeCounterAttestedMembership(counterAttestedMembershipSerialized) + if err != nil { + return nil, nil, nil, fmt.Errorf("Counter Attested Membership Unmarshal error: %s", err) + } + decodedAttestedMembershipSet, err := base64.StdEncoding.DecodeString(counterAttestedMembership.AttestedMembershipSet) + if err != nil { + return nil, nil, nil, fmt.Errorf("Attested membership set could not be decoded from base64: %s", err.Error()) + } + var attestedMembershipSet identity.CounterAttestedMembership_AttestedMembershipSet + err = protoV2.Unmarshal(decodedAttestedMembershipSet, &attestedMembershipSet) + if err != nil { + return nil, nil, nil, fmt.Errorf("Unable to unmarshal attested membership set: %s", err.Error()) + } + decodedForeignMembership, err := base64.StdEncoding.DecodeString(attestedMembershipSet.Membership) + if err != nil { + return nil, nil, nil, fmt.Errorf("Foreign membership could not be decoded from base64: %s", err.Error()) + } + var foreignMembership common.Membership + err = protoV2.Unmarshal(decodedForeignMembership, &foreignMembership) + if err != nil { + return nil, nil, nil, fmt.Errorf("Unable to unmarshal membership: %s", err.Error()) + } + return counterAttestedMembership, &attestedMembershipSet, &foreignMembership, nil +} + +// Validate 'identity.CounterAttestedMembership' object and its embedded structures +func validateCounterAttestedMembership(s *SmartContract, ctx contractapi.TransactionContextInterface, counterAttestedMembership *identity.CounterAttestedMembership, attestedMembershipSet *identity.CounterAttestedMembership_AttestedMembershipSet, foreignMembership *common.Membership) error { + var err error + + // Match nonces across all attestations, local and foreign + matchedNonce := "" + for _, attestation := range append(counterAttestedMembership.Attestations, attestedMembershipSet.Attestations...) { + if matchedNonce == "" { + matchedNonce = attestation.Nonce + } else { + if matchedNonce != attestation.Nonce { + return fmt.Errorf("Mismatched nonces across two attestations: %s, %s", matchedNonce, attestation.Nonce) + } + } + } + + // Ensure valid attestations from all local IIN Agents + for _, attestation := range counterAttestedMembership.Attestations { + err = validateAttestation(attestation, counterAttestedMembership.AttestedMembershipSet + attestation.Nonce) + if err != nil { + return err + } + } + + // Validate foreign membership cert chains + err = validateMemberCertChains(foreignMembership) + if err != nil { + return err + } + + // Ensure authentic and valid attestations from all foreign IIN Agents + for _, attestation := range attestedMembershipSet.Attestations { + if attestation.UnitIdentity.SecurityDomain != foreignMembership.SecurityDomain { + return fmt.Errorf("Foreign agent security domain %s does not match attested membership security domain %s", + attestation.UnitIdentity.SecurityDomain, foreignMembership.SecurityDomain) + } + attesterCert, err := parseCert(attestation.Certificate) + if err != nil { + return fmt.Errorf("Unable to parse attester certificate") + } + err = verifyMemberInSecurityDomain2(s, ctx, "", attesterCert, foreignMembership, attestation.UnitIdentity.MemberId) + if err != nil { + return fmt.Errorf("Attester with certificate %+v is not a designated IIN Agent of org %s in security domain %s: %+v", + attesterCert, attestation.UnitIdentity.MemberId, attestation.UnitIdentity.SecurityDomain, err) + } + // Validate signature + err = validateAttestation(attestation, attestedMembershipSet.Membership + attestation.Nonce) + if err != nil { + return err + } + } + + return nil +} + // CreateLocalMembership cc is used to store the local security domain's Membership in the ledger func (s *SmartContract) CreateLocalMembership(ctx contractapi.TransactionContextInterface, membershipJSON string) error { // Check if the caller has network admin privileges @@ -162,27 +244,10 @@ func (s *SmartContract) CreateMembership(ctx contractapi.TransactionContextInter return fmt.Errorf("Caller with identity %+v is not a designated IIN Agent of org %s: %+v", callerId, callerMemberUnit, err) } - counterAttestedMembership, err := decodeCounterAttestedMembership(counterAttestedMembershipSerialized) + // Parse the counter attested membership structure and extract the relevant objects + counterAttestedMembership, attestedMembershipSet, foreignMembership, err := parseCounterAttestedMembership(counterAttestedMembershipSerialized) if err != nil { - return fmt.Errorf("Counter Attested Membership Unmarshal error: %s", err) - } - decodedAttestedMembershipSet, err := base64.StdEncoding.DecodeString(counterAttestedMembership.AttestedMembershipSet) - if err != nil { - return fmt.Errorf("Attested membership set could not be decoded from base64: %s", err.Error()) - } - var attestedMembershipSet identity.CounterAttestedMembership_AttestedMembershipSet - err = protoV2.Unmarshal(decodedAttestedMembershipSet, &attestedMembershipSet) - if err != nil { - return fmt.Errorf("Unable to unmarshal attested membership set: %s", err.Error()) - } - decodedForeignMembership, err := base64.StdEncoding.DecodeString(attestedMembershipSet.Membership) - if err != nil { - return fmt.Errorf("Foreign membership could not be decoded from base64: %s", err.Error()) - } - var foreignMembership common.Membership - err = protoV2.Unmarshal(decodedForeignMembership, &foreignMembership) - if err != nil { - return fmt.Errorf("Unable to unmarshal membership: %s", err.Error()) + return err } // Check presence of membership on ledger first @@ -195,54 +260,12 @@ func (s *SmartContract) CreateMembership(ctx contractapi.TransactionContextInter return fmt.Errorf("Membership already exists for membership id: %s. Use 'UpdateMembership' to update.", foreignMembership.SecurityDomain) } - // Match nonces across all attestations, local and foreign - matchedNonce := "" - for _, attestation := range append(counterAttestedMembership.Attestations, attestedMembershipSet.Attestations...) { - if matchedNonce == "" { - matchedNonce = attestation.Nonce - } else { - if matchedNonce != attestation.Nonce { - return fmt.Errorf("Mismatched nonces across two attestations: %s, %s", matchedNonce, attestation.Nonce) - } - } - } - - // Ensure valid attestations from all local IIN Agents - for _, attestation := range counterAttestedMembership.Attestations { - err = validateAttestation(attestation, counterAttestedMembership.AttestedMembershipSet + attestation.Nonce) - if err != nil { - return err - } - } - - // Validate foreign membership cert chains - err = validateMemberCertChains(&foreignMembership) + // Validate the counter attested membership structure and the structures embedded in it + err = validateCounterAttestedMembership(s, ctx, counterAttestedMembership, attestedMembershipSet, foreignMembership) if err != nil { return err } - // Ensure authentic and valid attestations from all foreign IIN Agents - for _, attestation := range attestedMembershipSet.Attestations { - if attestation.UnitIdentity.SecurityDomain != foreignMembership.SecurityDomain { - return fmt.Errorf("Foreign agent security domain %s does not match attested membership security domain %s", - attestation.UnitIdentity.SecurityDomain, foreignMembership.SecurityDomain) - } - attesterCert, err := parseCert(attestation.Certificate) - if err != nil { - return fmt.Errorf("Unable to parse attester certificate") - } - err = verifyMemberInSecurityDomain2(s, ctx, "", attesterCert, &foreignMembership, attestation.UnitIdentity.MemberId) - if err != nil { - return fmt.Errorf("Attester with certificate %+v is not a designated IIN Agent of org %s in security domain %s: %+v", - attesterCert, attestation.UnitIdentity.MemberId, attestation.UnitIdentity.SecurityDomain, err) - } - // Validate signature - err = validateAttestation(attestation, attestedMembershipSet.Membership + attestation.Nonce) - if err != nil { - return err - } - } - membershipBytes, err := json.Marshal(foreignMembership) if err != nil { return fmt.Errorf("Marshal error: %s", err) @@ -310,27 +333,10 @@ func (s *SmartContract) UpdateMembership(ctx contractapi.TransactionContextInter return fmt.Errorf("Caller with identity %+v is not a designated IIN Agent: %+v", callerId, err) } - counterAttestedMembership, err := decodeCounterAttestedMembership(counterAttestedMembershipSerialized) - if err != nil { - return fmt.Errorf("Counter Attested Membership Unmarshal error: %s", err) - } - decodedAttestedMembershipSet, err := base64.StdEncoding.DecodeString(counterAttestedMembership.AttestedMembershipSet) - if err != nil { - return fmt.Errorf("Attested membership set could not be decoded from base64: %s", err.Error()) - } - var attestedMembershipSet identity.CounterAttestedMembership_AttestedMembershipSet - err = protoV2.Unmarshal(decodedAttestedMembershipSet, &attestedMembershipSet) - if err != nil { - return fmt.Errorf("Unable to unmarshal attested membership set: %s", err.Error()) - } - decodedForeignMembership, err := base64.StdEncoding.DecodeString(attestedMembershipSet.Membership) - if err != nil { - return fmt.Errorf("Foreign membership could not be decoded from base64: %s", err.Error()) - } - var foreignMembership common.Membership - err = protoV2.Unmarshal(decodedForeignMembership, &foreignMembership) + // Parse the counter attested membership structure and extract the relevant objects + counterAttestedMembership, attestedMembershipSet, foreignMembership, err := parseCounterAttestedMembership(counterAttestedMembershipSerialized) if err != nil { - return fmt.Errorf("Unable to unmarshal membership: %s", err.Error()) + return err } // Check presence of membership on ledger first @@ -340,54 +346,12 @@ func (s *SmartContract) UpdateMembership(ctx contractapi.TransactionContextInter return getErr } - // Match nonces across all attestations, local and foreign - matchedNonce := "" - for _, attestation := range append(counterAttestedMembership.Attestations, attestedMembershipSet.Attestations...) { - if matchedNonce == "" { - matchedNonce = attestation.Nonce - } else { - if matchedNonce != attestation.Nonce { - return fmt.Errorf("Mismatched nonces across two attestations: %s, %s", matchedNonce, attestation.Nonce) - } - } - } - - // Ensure valid attestations from all local IIN Agents - for _, attestation := range counterAttestedMembership.Attestations { - err = validateAttestation(attestation, counterAttestedMembership.AttestedMembershipSet + attestation.Nonce) - if err != nil { - return err - } - } - - // Validate foreign membership cert chains - err = validateMemberCertChains(&foreignMembership) + // Validate the counter attested membership structure and the structures embedded in it + err = validateCounterAttestedMembership(s, ctx, counterAttestedMembership, attestedMembershipSet, foreignMembership) if err != nil { return err } - // Ensure authentic and valid attestations from all foreign IIN Agents - for _, attestation := range attestedMembershipSet.Attestations { - if attestation.UnitIdentity.SecurityDomain != foreignMembership.SecurityDomain { - return fmt.Errorf("Foreign agent security domain %s does not match attested membership security domain %s", - attestation.UnitIdentity.SecurityDomain, foreignMembership.SecurityDomain) - } - attesterCert, err := parseCert(attestation.Certificate) - if err != nil { - return fmt.Errorf("Unable to parse attester certificate") - } - err = verifyMemberInSecurityDomain2(s, ctx, "", attesterCert, &foreignMembership, attestation.UnitIdentity.MemberId) - if err != nil { - return fmt.Errorf("Attester with certificate %+v is not a designated IIN Agent of org %s in security domain %s: %+v", - attesterCert, attestation.UnitIdentity.MemberId, attestation.UnitIdentity.SecurityDomain, err) - } - // Validate signature - err = validateAttestation(attestation, attestedMembershipSet.Membership + attestation.Nonce) - if err != nil { - return err - } - } - membershipBytes, err := json.Marshal(foreignMembership) if err != nil { return fmt.Errorf("Marshal error: %s", err) @@ -521,7 +485,7 @@ func verifyMemberInSecurityDomain1(s *SmartContract, ctx contractapi.Transaction // This takes a decoded X.509 certificate as argument (and optionally the certificate in PEM format too). // It takes a membership structure as argument. func verifyMemberInSecurityDomain2(s *SmartContract, ctx contractapi.TransactionContextInterface, certPEM string, cert *x509.Certificate, membership *common.Membership, requestingOrg string) error { - err := isCertificateWithinExpiry(cert) + err := isCertificateWithinExpiry(cert) if err != nil { return err } From 04a28c0ce90d3e1ae3b91eef3c71205efed94920 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Wed, 28 Sep 2022 11:39:54 +0530 Subject: [PATCH 141/150] go sdk changes when confidential is set to false Signed-off-by: Krishnasuri Narayanam --- .../interoperable-helper.go | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/sdks/fabric/go-sdk/interoperablehelper/interoperable-helper.go b/sdks/fabric/go-sdk/interoperablehelper/interoperable-helper.go index 3c2c81cad..0174d658c 100644 --- a/sdks/fabric/go-sdk/interoperablehelper/interoperable-helper.go +++ b/sdks/fabric/go-sdk/interoperablehelper/interoperable-helper.go @@ -41,7 +41,7 @@ func logThenErrorf(format string, args ...interface{}) error { } func InteropFlow(interopContract GatewayContract, networkId string, invokeObject types.Query, org, localRelayEndpoint string, - interopArgIndices []int, interopJSONs []types.InteropJSON, signer Signer, certUser string, returnWithoutLocalInvocation bool) ([]*common.View, []byte, error) { + interopArgIndices []int, interopJSONs []types.InteropJSON, signer Signer, certUser string, returnWithoutLocalInvocation bool, confidential bool) ([]*common.View, []byte, error) { if len(interopArgIndices) != len(interopJSONs) { logThenErrorf("number of argument indices %d does not match number of view addresses %d", len(interopArgIndices), len(interopJSONs)) } @@ -50,6 +50,7 @@ func InteropFlow(interopContract GatewayContract, networkId string, invokeObject var views []*common.View var viewsSerializedBase64 []string var computedAddresses []string + var viewContentsBase64 []string for i := 0; i < len(interopJSONs); i++ { requestResponseView, requestResponseAddress, err := getRemoteView(interopContract, networkId, org, localRelayEndpoint, interopJSONs[i], signer, certUser) @@ -66,11 +67,18 @@ func InteropFlow(interopContract GatewayContract, networkId string, invokeObject computedAddresses = append(computedAddresses, requestResponseAddress) viewsSerializedBase64 = append(viewsSerializedBase64, base64.StdEncoding.EncodeToString(viewBytes)) + if confidential { + // TODO + respDataContents, _ := GetResponseDataFromView(requestResponseView) + viewContentsBase64 = append(viewContentsBase64, base64.StdEncoding.EncodeToString(respDataContents)) + } else { + viewContentsBase64 = append(viewContentsBase64, "") + } } // Return here if caller just wants the views and doesn't want to invoke a local chaincode if returnWithoutLocalInvocation { - ccArgs, err := getCCArgsForProofVerification(invokeObject, interopArgIndices, computedAddresses, viewsSerializedBase64) + ccArgs, err := getCCArgsForProofVerification(invokeObject, interopArgIndices, computedAddresses, viewsSerializedBase64, viewContentsBase64) if err != nil { return views, nil, logThenErrorf("InteropFlow getCCArgsForProofVerification error: %s", err.Error()) } @@ -82,7 +90,7 @@ func InteropFlow(interopContract GatewayContract, networkId string, invokeObject } // Step 2 - result, err := submitTransactionWithRemoteViews(interopContract, invokeObject, interopArgIndices, computedAddresses, viewsSerializedBase64) + result, err := submitTransactionWithRemoteViews(interopContract, invokeObject, interopArgIndices, computedAddresses, viewsSerializedBase64, viewContentsBase64) if err != nil { return views, nil, logThenErrorf("InteropFlow submit transaction with remote view error: %s", err.Error()) } @@ -95,8 +103,8 @@ func InteropFlow(interopContract GatewayContract, networkId string, invokeObject * - Prepare arguments and call WriteExternalState. **/ func submitTransactionWithRemoteViews(interopContract GatewayContract, invokeObject types.Query, - interopArgIndices []int, viewAddresses []string, viewsSerializedBase64 []string) ([]byte, error) { - ccArgs, err := getCCArgsForProofVerification(invokeObject, interopArgIndices, viewAddresses, viewsSerializedBase64) + interopArgIndices []int, viewAddresses []string, viewsSerializedBase64 []string, viewContentsBase64 []string) ([]byte, error) { + ccArgs, err := getCCArgsForProofVerification(invokeObject, interopArgIndices, viewAddresses, viewsSerializedBase64, viewContentsBase64) if err != nil { return nil, logThenErrorf("failed calling getCCArgsForProofVerification with error: %s", err.Error()) } @@ -104,6 +112,7 @@ func submitTransactionWithRemoteViews(interopContract GatewayContract, invokeObj if err != nil { return result, logThenErrorf("submitTransaction Error: %s", err.Error()) } + return result, nil } @@ -250,7 +259,7 @@ func verifyView(contract GatewayContract, b64ViewProto string, address string) e * Prepare arguments for WriteExternalState chaincode transaction to verify a view and write data to ledger. **/ func getCCArgsForProofVerification(invokeObject types.Query, interopArgIndices []int, viewAddresses []string, - viewsSerializedBase64 []string) ([]string, error) { + viewsSerializedBase64 []string, viewContentsBase64 []string) ([]string, error) { invokeObjectCcArgsBytes, err := json.Marshal(invokeObject.CcArgs) if err != nil { @@ -272,6 +281,11 @@ func getCCArgsForProofVerification(invokeObject types.Query, interopArgIndices [ return nil, logThenErrorf("failed to Marshal viewsSerializedBase64: %s", viewsSerializedBase64) } + viewContentsBase64Bytes, err := json.Marshal(viewContentsBase64) + if err != nil { + return nil, logThenErrorf("failed to Marshal viewContentsBase64: %s", viewContentsBase64) + } + ccArgs := []string{ invokeObject.ContractName, invokeObject.Channel, @@ -279,7 +293,8 @@ func getCCArgsForProofVerification(invokeObject types.Query, interopArgIndices [ string(invokeObjectCcArgsBytes), string(interopArgIndicesBytes), string(viewAddressesBytes), - string(viewsSerializedBase64Bytes)} + string(viewsSerializedBase64Bytes), + string(viewContentsBase64Bytes)} return ccArgs, nil } From c1f70e4bb4eb75cc75fecb6953335406607dde4b Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Wed, 28 Sep 2022 12:00:38 +0530 Subject: [PATCH 142/150] go sdk changes when confidential is set to false Signed-off-by: Krishnasuri Narayanam --- samples/fabric/go-cli/exerciseSDK.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/samples/fabric/go-cli/exerciseSDK.go b/samples/fabric/go-cli/exerciseSDK.go index 059351ecb..51b8c6b55 100644 --- a/samples/fabric/go-cli/exerciseSDK.go +++ b/samples/fabric/go-cli/exerciseSDK.go @@ -877,7 +877,7 @@ func interop(key string, localNetwork string, requestingOrg string, address stri signkeyPEM: []byte(keyUser), } - interopFlowResponse, _, err := interoperablehelper.InteropFlow(contract, networkName, invokeObject, requestingOrg, relayEnv.RelayEndPoint, interopArgIndices, interopJSONs, signer, certUser, false) + interopFlowResponse, _, err := interoperablehelper.InteropFlow(contract, networkName, invokeObject, requestingOrg, relayEnv.RelayEndPoint, interopArgIndices, interopJSONs, signer, certUser, false, false) if err != nil { log.Fatalf("failed interoperablehelper.InteropFlow with error: %s", err.Error()) } @@ -891,7 +891,9 @@ func interop(key string, localNetwork string, requestingOrg string, address stri func main() { + // need the chaincodes simplestate and interop to exercise the below interop calls //interop("a", "network1", "Org1MSP", "localhost:9080/network1/mychannel:simplestate:Read:a") + //interop("a", "network1", "Org1MSP", "localhost:9083/network2/mychannel:simplestate:Read:Arcturus") //configureNetwork("network1") //fetchAccessControlPolicy("network1") From 2c9e0e57045bb1699bb9625726028fb58a16992b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Sep 2022 07:17:01 +0000 Subject: [PATCH 143/150] Bump got and ava in /common/policy-dsl Removes [got](https://github.com/sindresorhus/got). It's no longer used after updating ancestor dependency [ava](https://github.com/avajs/ava). These dependencies need to be updated together. Removes `got` Updates `ava` from 3.15.0 to 4.3.3 - [Release notes](https://github.com/avajs/ava/releases) - [Commits](https://github.com/avajs/ava/compare/v3.15.0...v4.3.3) --- updated-dependencies: - dependency-name: got dependency-type: indirect - dependency-name: ava dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- common/policy-dsl/package-lock.json | 1243 ++++++++------------------- common/policy-dsl/package.json | 2 +- 2 files changed, 381 insertions(+), 864 deletions(-) diff --git a/common/policy-dsl/package-lock.json b/common/policy-dsl/package-lock.json index bb28dc4fc..2f2d102de 100644 --- a/common/policy-dsl/package-lock.json +++ b/common/policy-dsl/package-lock.json @@ -430,23 +430,6 @@ "minimist": "^1.2.0" } }, - "@concordance/react": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@concordance/react/-/react-2.0.0.tgz", - "integrity": "sha512-huLSkUuM2/P+U0uy2WwlKuixMsTODD8p4JVQBI4VKeopkiN0C7M3N9XYVawb4M+4spN5RrO/eLhk7KoQX6nsfA==", - "dev": true, - "requires": { - "arrify": "^1.0.1" - }, - "dependencies": { - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "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", @@ -714,12 +697,6 @@ "fastq": "^1.6.0" } }, - "@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", - "dev": true - }, "@sinonjs/commons": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", @@ -738,15 +715,6 @@ "@sinonjs/commons": "^1.7.0" } }, - "@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "dev": true, - "requires": { - "defer-to-connect": "^1.0.1" - } - }, "@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -925,15 +893,14 @@ "requires": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" - } - }, - "ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dev": true, - "requires": { - "string-width": "^4.1.0" + }, + "dependencies": { + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + } } }, "ansi-escapes": { @@ -960,9 +927,9 @@ "dev": true }, "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==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.1.tgz", + "integrity": "sha512-qDOv24WjnYuL+wbwHdlsYZFy+cgPtrYw0Tn7GLORicQp9BkQLzrgI3Pm4VyR9ERZ41YTn7KlMPuL1n05WdZvmg==", "dev": true }, "antlr4": { @@ -1010,7 +977,7 @@ "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", "dev": true }, "array-union": { @@ -1032,9 +999,9 @@ "dev": true }, "arrify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-3.0.0.tgz", + "integrity": "sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==", "dev": true }, "assign-symbols": { @@ -1043,12 +1010,6 @@ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", "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 - }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -1062,67 +1023,107 @@ "dev": true }, "ava": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/ava/-/ava-3.15.0.tgz", - "integrity": "sha512-HGAnk1SHPk4Sx6plFAUkzV/XC1j9+iQhOzt4vBly18/yo0AV8Oytx7mtJd/CR8igCJ5p160N/Oo/cNJi2uSeWA==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/ava/-/ava-4.3.3.tgz", + "integrity": "sha512-9Egq/d9R74ExrWohHeqUlexjDbgZJX5jA1Wq4KCTqc3wIfpGEK79zVy4rBtofJ9YKIxs4PzhJ8BgbW5PlAYe6w==", "dev": true, "requires": { - "@concordance/react": "^2.0.0", - "acorn": "^8.0.4", - "acorn-walk": "^8.0.0", - "ansi-styles": "^5.0.0", + "acorn": "^8.7.1", + "acorn-walk": "^8.2.0", + "ansi-styles": "^6.1.0", "arrgv": "^1.0.2", - "arrify": "^2.0.1", - "callsites": "^3.1.0", - "chalk": "^4.1.0", - "chokidar": "^3.4.3", + "arrify": "^3.0.0", + "callsites": "^4.0.0", + "cbor": "^8.1.0", + "chalk": "^5.0.1", + "chokidar": "^3.5.3", "chunkd": "^2.0.1", - "ci-info": "^2.0.0", + "ci-info": "^3.3.1", "ci-parallel-vars": "^1.0.1", "clean-yaml-object": "^0.1.0", - "cli-cursor": "^3.1.0", - "cli-truncate": "^2.1.0", - "code-excerpt": "^3.0.0", + "cli-truncate": "^3.1.0", + "code-excerpt": "^4.0.0", "common-path-prefix": "^3.0.0", - "concordance": "^5.0.1", - "convert-source-map": "^1.7.0", + "concordance": "^5.0.4", "currently-unhandled": "^0.4.1", - "debug": "^4.3.1", - "del": "^6.0.0", - "emittery": "^0.8.0", - "equal-length": "^1.0.0", - "figures": "^3.2.0", - "globby": "^11.0.1", - "ignore-by-default": "^2.0.0", - "import-local": "^3.0.2", - "indent-string": "^4.0.0", + "debug": "^4.3.4", + "del": "^6.1.1", + "emittery": "^0.11.0", + "figures": "^4.0.1", + "globby": "^13.1.1", + "ignore-by-default": "^2.1.0", + "indent-string": "^5.0.0", "is-error": "^2.2.2", "is-plain-object": "^5.0.0", "is-promise": "^4.0.0", - "lodash": "^4.17.20", - "matcher": "^3.0.0", - "md5-hex": "^3.0.1", - "mem": "^8.0.0", + "matcher": "^5.0.0", + "mem": "^9.0.2", "ms": "^2.1.3", - "ora": "^5.2.0", - "p-event": "^4.2.0", - "p-map": "^4.0.0", - "picomatch": "^2.2.2", - "pkg-conf": "^3.1.0", - "plur": "^4.0.0", + "p-event": "^5.0.1", + "p-map": "^5.4.0", + "picomatch": "^2.3.1", + "pkg-conf": "^4.0.0", + "plur": "^5.1.0", "pretty-ms": "^7.0.1", - "read-pkg": "^5.2.0", "resolve-cwd": "^3.0.0", "slash": "^3.0.0", - "source-map-support": "^0.5.19", - "stack-utils": "^2.0.3", - "strip-ansi": "^6.0.0", - "supertap": "^2.0.0", + "stack-utils": "^2.0.5", + "strip-ansi": "^7.0.1", + "supertap": "^3.0.1", "temp-dir": "^2.0.0", - "trim-off-newlines": "^1.0.1", - "update-notifier": "^5.0.1", - "write-file-atomic": "^3.0.3", - "yargs": "^16.2.0" + "write-file-atomic": "^4.0.1", + "yargs": "^17.5.1" + }, + "dependencies": { + "acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "dev": true + }, + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true + }, + "callsites": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-4.0.0.tgz", + "integrity": "sha512-y3jRROutgpKdz5vzEhWM34TidDU8vkJppF8dszITeb1PQmSqV3DTxyV8G/lyO/DNvtE1YTedehmw9MPZsCBHxQ==", + "dev": true + }, + "chalk": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", + "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", + "dev": true + }, + "ci-info": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.4.0.tgz", + "integrity": "sha512-t5QdPT5jq3o262DOQ8zA6E1tlH2upmUc4Hlvrbx1pGYJuiiHl7O7rvVNI+l8HTVhd/q3Qc9vqimkNk5yiXsAug==", + "dev": true + }, + "strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + } } }, "babel-jest": { @@ -1278,59 +1279,18 @@ } } }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true - }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, "blueimp-md5": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/blueimp-md5/-/blueimp-md5-2.19.0.tgz", "integrity": "sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==", "dev": true }, - "boxen": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", - "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", - "dev": true, - "requires": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.1", - "string-width": "^4.2.2", - "type-fest": "^0.20.2", - "widest-line": "^3.1.0", - "wrap-ansi": "^7.0.0" - }, - "dependencies": { - "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 - } - } - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1378,16 +1338,6 @@ "node-int64": "^0.4.0" } }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -1411,38 +1361,6 @@ "unset-value": "^1.0.0" } }, - "cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "dev": true, - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "dependencies": { - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true - } - } - }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1470,6 +1388,15 @@ "rsvp": "^4.8.4" } }, + "cbor": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz", + "integrity": "sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==", + "dev": true, + "requires": { + "nofilter": "^3.1.0" + } + }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -1569,38 +1496,51 @@ "clean-yaml-object": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/clean-yaml-object/-/clean-yaml-object-0.1.0.tgz", - "integrity": "sha1-Y/sRDcLOGoTcIfbZM0h20BCui2g=", - "dev": true - }, - "cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", - "dev": true - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "cli-spinners": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", + "integrity": "sha512-3yONmlN9CSAkzNwnRCiJQ7Q2xK5mWuEfL3PuTZcAUzhObbXsfsnMptJzXwz93nc5zn9V9TwCVMmV7w4xsm43dw==", "dev": true }, "cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", + "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", "dev": true, "requires": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + } } }, "cliui": { @@ -1614,21 +1554,6 @@ "wrap-ansi": "^7.0.0" } }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "dev": true - }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -1636,12 +1561,12 @@ "dev": true }, "code-excerpt": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-3.0.0.tgz", - "integrity": "sha512-VHNTVhd7KsLGOqfX3SyeO8RyYPMp1GJOg194VITk04WMYCv4plV68YWe6TJZxd9MhobjtpMRnVky01gqZsalaw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-4.0.0.tgz", + "integrity": "sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==", "dev": true, "requires": { - "convert-to-spaces": "^1.0.1" + "convert-to-spaces": "^2.0.1" } }, "collect-v8-coverage": { @@ -1718,20 +1643,6 @@ "well-known-symbols": "^2.0.0" } }, - "configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - } - }, "convert-source-map": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", @@ -1742,9 +1653,9 @@ } }, "convert-to-spaces": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-1.0.2.tgz", - "integrity": "sha1-fj5Iu+bZl7FBfdyihoIEtNPYVxU=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-2.0.1.tgz", + "integrity": "sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==", "dev": true }, "copy-descriptor": { @@ -1774,12 +1685,6 @@ } } }, - "crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "dev": true - }, "cssom": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", @@ -1806,7 +1711,7 @@ "currently-unhandled": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "integrity": "sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==", "dev": true, "requires": { "array-find-index": "^1.0.1" @@ -1867,21 +1772,6 @@ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, "deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -1894,21 +1784,6 @@ "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", "dev": true }, - "defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", - "dev": true, - "requires": { - "clone": "^1.0.2" - } - }, - "defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", - "dev": true - }, "define-property": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", @@ -1951,9 +1826,9 @@ } }, "del": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", - "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", "dev": true, "requires": { "globby": "^11.0.1", @@ -1964,6 +1839,31 @@ "p-map": "^4.0.0", "rimraf": "^3.0.2", "slash": "^3.0.0" + }, + "dependencies": { + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + } } }, "delayed-stream": { @@ -2010,19 +1910,10 @@ } } }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "requires": { - "is-obj": "^2.0.0" - } - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, "electron-to-chromium": { @@ -2032,9 +1923,9 @@ "dev": true }, "emittery": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", - "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.11.0.tgz", + "integrity": "sha512-S/7tzL6v5i+4iJd627Nhv9cLFIo5weAIlGccqJFpnBoDB8U1TF2k5tez4J/QNuxyyhWuFqHg1L84Kd3m7iXg6g==", "dev": true }, "emoji-regex": { @@ -2052,12 +1943,6 @@ "once": "^1.4.0" } }, - "equal-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/equal-length/-/equal-length-1.0.1.tgz", - "integrity": "sha1-IcoRLUirJLTh5//A5TOdMf38J0w=", - "dev": true - }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -2073,12 +1958,6 @@ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", "dev": true }, - "escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", - "dev": true - }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -2320,9 +2199,9 @@ "dev": true }, "fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -2363,12 +2242,21 @@ } }, "figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/figures/-/figures-4.0.1.tgz", + "integrity": "sha512-rElJwkA/xS04Vfg+CaZodpso7VqBknOYbzi6I76hI4X80RUjkSxO2oAyPmGbuXUppywjqndOrQDl817hDnI++w==", "dev": true, "requires": { - "escape-string-regexp": "^1.0.5" + "escape-string-regexp": "^5.0.0", + "is-unicode-supported": "^1.2.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true + } } }, "fill-range": { @@ -2491,15 +2379,6 @@ "is-glob": "^4.0.1" } }, - "global-dirs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", - "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", - "dev": true, - "requires": { - "ini": "2.0.0" - } - }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -2507,36 +2386,24 @@ "dev": true }, "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.2.tgz", + "integrity": "sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==", "dev": true, "requires": { - "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", + "fast-glob": "^3.2.11", "ignore": "^5.2.0", "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "dev": true, - "requires": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" + "slash": "^4.0.0" + }, + "dependencies": { + "slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true + } } }, "graceful-fs": { @@ -2619,12 +2486,6 @@ } } }, - "has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", - "dev": true - }, "hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -2646,12 +2507,6 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true - }, "http-proxy-agent": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", @@ -2688,12 +2543,6 @@ "safer-buffer": ">= 2.1.2 < 3" } }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true - }, "ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -2701,15 +2550,9 @@ "dev": true }, "ignore-by-default": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-2.0.0.tgz", - "integrity": "sha512-+mQSgMRiFD3L3AOxLYOCxjIq4OnAmo5CIuC+lj5ehCJcPtV++QacEV7FdpzvYxH6DaOySWzQU6RR0lPLy37ckA==", - "dev": true - }, - "import-lazy": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-2.1.0.tgz", + "integrity": "sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==", "dev": true }, "import-local": { @@ -2729,9 +2572,9 @@ "dev": true }, "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", "dev": true }, "inflight": { @@ -2750,12 +2593,6 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true - }, "irregular-plurals": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.3.0.tgz", @@ -2882,7 +2719,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true }, "is-fullwidth-code-point": { @@ -2906,40 +2743,12 @@ "is-extglob": "^2.1.1" } }, - "is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "dev": true, - "requires": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - } - }, - "is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "dev": true - }, - "is-npm": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", - "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", - "dev": true - }, "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 }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true - }, "is-path-cwd": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", @@ -2983,9 +2792,9 @@ "dev": true }, "is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", "dev": true }, "is-windows": { @@ -3004,12 +2813,6 @@ "is-docker": "^2.0.0" } }, - "is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", - "dev": true - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -3760,7 +3563,7 @@ "js-string-escape": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", - "integrity": "sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8=", + "integrity": "sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==", "dev": true }, "js-tokens": { @@ -3820,18 +3623,6 @@ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, - "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", - "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-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -3844,15 +3635,6 @@ "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", "dev": true }, - "keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "dev": true, - "requires": { - "json-buffer": "3.0.0" - } - }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -3865,15 +3647,6 @@ "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true }, - "latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", - "dev": true, - "requires": { - "package-json": "^6.3.0" - } - }, "leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -3897,17 +3670,10 @@ "dev": true }, "load-json-file": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", - "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.15", - "parse-json": "^4.0.0", - "pify": "^4.0.1", - "strip-bom": "^3.0.0", - "type-fest": "^0.3.0" - } + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-7.0.1.tgz", + "integrity": "sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==", + "dev": true }, "locate-path": { "version": "5.0.0", @@ -3924,22 +3690,6 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true - }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -4000,18 +3750,18 @@ } }, "matcher": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", - "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-5.0.0.tgz", + "integrity": "sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw==", "dev": true, "requires": { - "escape-string-regexp": "^4.0.0" + "escape-string-regexp": "^5.0.0" }, "dependencies": { "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==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", "dev": true } } @@ -4026,19 +3776,19 @@ } }, "mem": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/mem/-/mem-8.1.1.tgz", - "integrity": "sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/mem/-/mem-9.0.2.tgz", + "integrity": "sha512-F2t4YIv9XQUBHt6AOJ0y7lSmP1+cY7Fm1DRh9GClTGzKST7UWLMx6ly9WZdLH/G/ppM5RL4MlQfRT71ri9t19A==", "dev": true, "requires": { "map-age-cleaner": "^0.1.3", - "mimic-fn": "^3.1.0" + "mimic-fn": "^4.0.0" }, "dependencies": { "mimic-fn": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz", - "integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", "dev": true } } @@ -4086,12 +3836,6 @@ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true - }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -4213,6 +3957,12 @@ "integrity": "sha512-maHFz6OLqYxz+VQyCAtA3PTX4UP/53pa05fyDNc9CwjvJ0yEh6+xBwKsgCxMNhS8taUKBFYxfuiaD9U/55iFaw==", "dev": true }, + "nofilter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", + "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", + "dev": true + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -4239,12 +3989,6 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, - "normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", - "dev": true - }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -4341,33 +4085,10 @@ "word-wrap": "~1.2.3" } }, - "ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dev": true, - "requires": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - } - }, - "p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", - "dev": true - }, "p-defer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==", "dev": true }, "p-each-series": { @@ -4377,12 +4098,12 @@ "dev": true }, "p-event": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", - "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-5.0.1.tgz", + "integrity": "sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==", "dev": true, "requires": { - "p-timeout": "^3.1.0" + "p-timeout": "^5.0.2" } }, "p-finally": { @@ -4410,22 +4131,46 @@ } }, "p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-5.5.0.tgz", + "integrity": "sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==", "dev": true, "requires": { - "aggregate-error": "^3.0.0" + "aggregate-error": "^4.0.0" + }, + "dependencies": { + "aggregate-error": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz", + "integrity": "sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==", + "dev": true, + "requires": { + "clean-stack": "^4.0.0", + "indent-string": "^5.0.0" + } + }, + "clean-stack": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz", + "integrity": "sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==", + "dev": true, + "requires": { + "escape-string-regexp": "5.0.0" + } + }, + "escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true + } } }, "p-timeout": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", - "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", - "dev": true, - "requires": { - "p-finally": "^1.0.0" - } + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-5.1.0.tgz", + "integrity": "sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==", + "dev": true }, "p-try": { "version": "2.2.0", @@ -4433,36 +4178,6 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, - "package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", - "dev": true, - "requires": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.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 - } - } - }, - "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" - } - }, "parse-ms": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", @@ -4523,12 +4238,6 @@ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "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 - }, "pirates": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", @@ -4536,47 +4245,56 @@ "dev": true }, "pkg-conf": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-3.1.0.tgz", - "integrity": "sha512-m0OTbR/5VPNPqO1ph6Fqbj7Hv6QU7gR/tQW40ZqrL1rjgCU85W6C1bJn0BItuJqnR98PWzw7Z8hHeChD1WrgdQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-4.0.0.tgz", + "integrity": "sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w==", "dev": true, "requires": { - "find-up": "^3.0.0", - "load-json-file": "^5.2.0" + "find-up": "^6.0.0", + "load-json-file": "^7.0.0" }, "dependencies": { "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", "dev": true, "requires": { - "locate-path": "^3.0.0" + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" } }, "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.1.1.tgz", + "integrity": "sha512-vJXaRMJgRVD3+cUZs3Mncj2mxpt5mP0EmNOsxRSZRMlbqjvxzDEOIUWXGmavo0ZC9+tNZCBLQ66reA11nbpHZg==", + "dev": true, + "requires": { + "p-locate": "^6.0.0" + } + }, + "p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", "dev": true, "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "yocto-queue": "^1.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==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", "dev": true, "requires": { - "p-limit": "^2.0.0" + "p-limit": "^4.0.0" } }, "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", "dev": true } } @@ -4591,12 +4309,12 @@ } }, "plur": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/plur/-/plur-4.0.0.tgz", - "integrity": "sha512-4UGewrYgqDFw9vV6zNV+ADmPAUAfJPKtGvb/VdpQAx25X5f3xXdGdyOEVFwkl8Hl/tl7+xbeHqSEM+D5/TirUg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/plur/-/plur-5.1.0.tgz", + "integrity": "sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==", "dev": true, "requires": { - "irregular-plurals": "^3.2.0" + "irregular-plurals": "^3.3.0" } }, "posix-character-classes": { @@ -4611,12 +4329,6 @@ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", "dev": true }, - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", - "dev": true - }, "pretty-format": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", @@ -4681,41 +4393,12 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, - "pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", - "dev": true, - "requires": { - "escape-goat": "^2.0.0" - } - }, "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 }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - } - } - }, "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -4773,17 +4456,6 @@ } } }, - "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" - } - }, "readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -4803,24 +4475,6 @@ "safe-regex": "^1.1.0" } }, - "registry-auth-token": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", - "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", - "dev": true, - "requires": { - "rc": "^1.2.8" - } - }, - "registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", - "dev": true, - "requires": { - "rc": "^1.2.8" - } - }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -4883,25 +4537,6 @@ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", "dev": true }, - "responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", - "dev": true, - "requires": { - "lowercase-keys": "^1.0.0" - } - }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - } - }, "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", @@ -5118,23 +4753,6 @@ "lru-cache": "^6.0.0" } }, - "semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", - "dev": true, - "requires": { - "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 - } - } - }, "serialize-error": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", @@ -5142,14 +4760,6 @@ "dev": true, "requires": { "type-fest": "^0.13.1" - }, - "dependencies": { - "type-fest": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", - "dev": true - } } }, "set-blocking": { @@ -5231,24 +4841,20 @@ "dev": true }, "slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", "dev": true, "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.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" - } + "is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true } } }, @@ -5521,23 +5127,6 @@ "strip-ansi": "^6.0.1" } }, - "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.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -5547,12 +5136,6 @@ "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 - }, "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", @@ -5565,23 +5148,33 @@ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - }, "supertap": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supertap/-/supertap-2.0.0.tgz", - "integrity": "sha512-jRzcXlCeDYvKoZGA5oRhYyR3jUIYu0enkSxtmAgHRlD7HwrovTpH4bDSi0py9FtuA8si9cW/fKommJHuaoDHJA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/supertap/-/supertap-3.0.1.tgz", + "integrity": "sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw==", "dev": true, "requires": { - "arrify": "^2.0.1", - "indent-string": "^4.0.0", - "js-yaml": "^3.14.0", + "indent-string": "^5.0.0", + "js-yaml": "^3.14.1", "serialize-error": "^7.0.1", - "strip-ansi": "^6.0.0" + "strip-ansi": "^7.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true + }, + "strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + } } }, "supports-color": { @@ -5651,7 +5244,7 @@ "time-zone": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-1.0.0.tgz", - "integrity": "sha1-mcW/VZWJZq9tBtg73zgA3IL67F0=", + "integrity": "sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==", "dev": true }, "tmpl": { @@ -5686,12 +5279,6 @@ } } }, - "to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "dev": true - }, "to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", @@ -5733,12 +5320,6 @@ "punycode": "^2.1.1" } }, - "trim-off-newlines": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.3.tgz", - "integrity": "sha512-kh6Tu6GbeSNMGfrrZh6Bb/4ZEHV1QlB4xNDBeog8Y9/QwFlKTRyWvY3Fs9tRDAMZliVUwieMgEdIeL/FtqjkJg==", - "dev": true - }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -5755,9 +5336,9 @@ "dev": true }, "type-fest": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", - "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", "dev": true }, "typedarray-to-buffer": { @@ -5781,15 +5362,6 @@ "set-value": "^2.0.1" } }, - "unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dev": true, - "requires": { - "crypto-random-string": "^2.0.0" - } - }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -5836,55 +5408,18 @@ } } }, - "update-notifier": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", - "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", - "dev": true, - "requires": { - "boxen": "^5.0.0", - "chalk": "^4.1.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.4.0", - "is-npm": "^5.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.1.0", - "pupa": "^2.1.1", - "semver": "^7.3.4", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.0" - } - }, "urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", "dev": true }, - "url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "dev": true, - "requires": { - "prepend-http": "^2.0.0" - } - }, "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "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 - }, "uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -5948,15 +5483,6 @@ "makeerror": "1.0.12" } }, - "wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", - "dev": true, - "requires": { - "defaults": "^1.0.3" - } - }, "webidl-conversions": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", @@ -6010,15 +5536,6 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, - "widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "dev": true, - "requires": { - "string-width": "^4.0.0" - } - }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -6071,12 +5588,6 @@ "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", "dev": true }, - "xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", - "dev": true - }, "xml-name-validator": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", @@ -6102,24 +5613,30 @@ "dev": true }, "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", "dev": true, "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", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.0.0" } }, "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==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true + }, + "yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", "dev": true } } diff --git a/common/policy-dsl/package.json b/common/policy-dsl/package.json index f8826f03c..96c19187c 100644 --- a/common/policy-dsl/package.json +++ b/common/policy-dsl/package.json @@ -25,7 +25,7 @@ "author": "", "license": "ISC", "devDependencies": { - "ava": "^3.13.0", + "ava": "^4.3.3", "jest": "^26.6.3" }, "dependencies": { From 16b635e936a328405bd3bfacf40ce94eb897ea54 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Thu, 29 Sep 2022 12:50:33 +0000 Subject: [PATCH 144/150] Package version upgrades and RFC updates Signed-off-by: VRamakrishna --- common/protos-go/VERSION | 2 +- common/protos-js/package.json | 2 +- .../iin-agent/package-local.json | 2 +- .../iin-agent/package.json | 4 +- .../contracts/interop/VERSION | 2 +- rfcs/README.md | 110 +++++++++--------- rfcs/models/identity/iin.md | 2 +- rfcs/protocols/discovery/discovery.md | 2 +- rfcs/protocols/identity/identity-syncing.md | 12 +- rfcs/protocols/identity/membership-syncing.md | 2 +- 10 files changed, 70 insertions(+), 70 deletions(-) diff --git a/common/protos-go/VERSION b/common/protos-go/VERSION index bc80560fa..26ca59460 100644 --- a/common/protos-go/VERSION +++ b/common/protos-go/VERSION @@ -1 +1 @@ -1.5.0 +1.5.1 diff --git a/common/protos-js/package.json b/common/protos-js/package.json index 0a5bb728a..3603879f9 100644 --- a/common/protos-js/package.json +++ b/common/protos-js/package.json @@ -1,6 +1,6 @@ { "name": "@hyperledger-labs/weaver-protos-js", - "version": "1.4.4", + "version": "1.5.1", "description": "Interop protos for Node JS (Weaver)", "main": "index.js", "exports": { diff --git a/core/identity-management/iin-agent/package-local.json b/core/identity-management/iin-agent/package-local.json index f4946df75..c24d1cdba 100644 --- a/core/identity-management/iin-agent/package-local.json +++ b/core/identity-management/iin-agent/package-local.json @@ -1,6 +1,6 @@ { "name": "iin-agent", - "version": "1.3.0", + "version": "1.5.0", "description": "", "main": "index.js", "scripts": { diff --git a/core/identity-management/iin-agent/package.json b/core/identity-management/iin-agent/package.json index ae832cd19..392e005f5 100644 --- a/core/identity-management/iin-agent/package.json +++ b/core/identity-management/iin-agent/package.json @@ -1,6 +1,6 @@ { "name": "iin-agent", - "version": "1.3.0", + "version": "1.5.0", "description": "", "main": "index.js", "scripts": { @@ -19,7 +19,7 @@ "author": "", "license": "ISC", "dependencies": { - "@hyperledger-labs/weaver-protos-js": "^1.3.0", + "@hyperledger-labs/weaver-protos-js": "^1.5.0", "@fidm/x509": "^1.2.1", "@grpc/grpc-js": "^1.1.1", "@typescript-eslint/eslint-plugin": "^3.5.0", diff --git a/core/network/fabric-interop-cc/contracts/interop/VERSION b/core/network/fabric-interop-cc/contracts/interop/VERSION index 3c80e4f0f..26ca59460 100644 --- a/core/network/fabric-interop-cc/contracts/interop/VERSION +++ b/core/network/fabric-interop-cc/contracts/interop/VERSION @@ -1 +1 @@ -1.4.3 \ No newline at end of file +1.5.1 diff --git a/rfcs/README.md b/rfcs/README.md index a8ece98ab..ba6ed0b52 100644 --- a/rfcs/README.md +++ b/rfcs/README.md @@ -26,61 +26,61 @@ The RFC numbering convention is: `:`. The list of types (``) is | 02 | Protocols and Mechanisms | | 03 | Data Structures and Formats | -| RFC # | Title | Category | Status | -|--------|-------------------------------------|----------|-----------------------------------------------------------------| -| 01-001 | Views | Model | [Proposed](./models/ledger/views.md) | -| 01-002 | Cryptographic Proofs | Model | [Proposed](./models/ledger/cryptographic-proofs.md) | -| 01-003 | Verifiable Observation of State | Model | [Draft](./models/ledger/observation-of-state.md) | -| 01-004 | Events | Model | [Draft](./models/ledger/events.md) | -| 01-005 | Cross-Ledger Operations | Model | [Draft](./models/ledger/cross-ledger-operations.md) | -| 01-006 | Atomic Cross-Ledger Transactions | Model | [Proposed](./models/ledger/atomic-cross-ledger-transactions.md) | -| 01-007 | Security Domains | Model | [Proposed](./models/security/security-domains.md) | -| 01-008 | End-to-End Confidentiality | Model | [Proposed](./models/security/confidentiality.md) | -| 01-009 | Relays | Model | [Proposed](./models/infrastructure/relays.md) | -| 01-010 | Interoperation Modules | Model | [Proposed](./models/infrastructure/interoperation-modules.md) | -| 01-011 | Identity Management | Model | [Proposed](./models/identity/network-identity-management.md) | -| 01-012 | Identity Registry | Model | [Proposed](./models/identity/iin.md) | -| 01-013 | Identity Agent | Model | [Proposed](./models/identity/iin-agent.md) | -| 01-014 | Identity Trust Anchor Agent | Model | [Retired](./models/identity/iin-steward-agent.md) | -| 01-015 | Network Identity Updates | Model | [Proposed](./models/identity/identity-update-policy.md) | -| 02-001 | Data Sharing | Protocol | [Proposed](./protocols/data-sharing/generic.md) | -| 02-002 | Data Sharing in Fabric | Protocol | [Proposed](./protocols/data-sharing/fabric.md) | -| 02-003 | Data Sharing in Corda | Protocol | [Proposed](./protocols/data-sharing/corda.md) | -| 02-004 | Asset Exchange through HTLC | Protocol | [Proposed](./protocols/asset-exchange/generic-htlc.md) | -| 02-005 | Asset Exchange in Fabric | Protocol | [Proposed](./protocols/asset-exchange/fabric-htlc.md) | -| 02-006 | Asset Exchange in Corda | Protocol | [Proposed](./protocols/asset-exchange/corda-htlc.md) | -| 02-007 | Asset Exchange in Besu | Protocol | [Draft](./protocols/asset-exchange/besu-htlc.md) | -| 02-008 | Asset Transfer | Protocol | [Proposed](./protocols/asset-transfer/generic.md) | -| 02-009 | Asset Transfer in Fabric | Protocol | [Proposed](./protocols/asset-transfer/fabric.md) | -| 02-010 | Asset Transfer in Corda | Protocol | [Proposed](./protocols/asset-transfer/corda.md) | -| 02-011 | Identity and Config Sharing | Protocol | [Superseded](./protocols/identity/id-config-sharing.md) | -| 02-012 | Cross-Domain Identity Management | Protocol | [Proposed](./protocols/identity/identity-syncing.md) | -| 02-013 | Security Domain Discovery | Protocol | [Draft](./protocols/discovery/discovery.md) | -| 02-014 | Cross-Domain Negotiation | Protocol | [Draft](./protocols/discovery/negotiation.md) | -| 02-015 | Transaction Invocation | Protocol | [Draft](./protocols/contract-invocation/invocation.md) | -| 02-016 | Event Bus | Protocol | [Draft](./protocols/events/event-bus.md) | -| 02-017 | Security Domain Identity Validation | Protocol | [Proposed](./protocols/events/network-identity-validation.md) | -| 02-018 | Cross-Domain Membership Syncing | Protocol | [Proposed](./protocols/events/membership-syncing.md) | -| 03-001 | View Address | Format | [Proposed](./formats/views/addressing.md) | -| 03-002 | Generic View | Format | [Proposed](./formats/views/definition.md) | -| 03-003 | Fabric View | Format | [Proposed](./formats/views/fabric.md) | -| 03-004 | Corda View | Format | [Proposed](./formats/views/corda.md) | -| 03-005 | Besu View | Format | [Draft](./formats/views/besu.md) | -| 03-006 | Ethereum View | Format | [Draft](./formats/views/ethereum.md) | -| 03-007 | View Request | Format | [Proposed](./formats/views/request.md) | -| 03-008 | Access Control Policy | Format | [Proposed](./formats/policies/access-control.md) | -| 03-009 | Proof Verification Policy | Format | [Proposed](./formats/policies/proof-verification.md) | -| 03-010 | Verification Policy DSL | Format | [Draft](./formats/policies/dsl.md) | -| 03-011 | Membership | Format | [Proposed](./formats/network/membership.md) | -| 03-012 | Network Identities | Format | [Proposed](./formats/network/identity.md) | -| 03-013 | Asset Exchange Units | Format | [Proposed](./formats/assets/exchange.md) | -| 03-014 | Asset Transfer Units | Format | [Proposed](./formats/assets/transfer.md) | -| 03-015 | Relay Messages | Format | [Proposed](./formats/communication/relay.md) | -| 03-016 | Fabric Interop Chaincode API | Format | [Proposed](./formats/network/fabric-interop-chaincode.md) | -| 03-017 | Interoperation CorDapp API | Format | [Proposed](./formats/network/interop-cordapp.md) | -| 03-018 | Besu Interop Contract API | Format | [Proposed](./formats/network/besu-interop-contract.md) | -| 03-019 | Application SDK | Format | [Proposed](./formats/network/application-sdk.md) | -| 03-020 | DID Method for DLT Networks | Format | [Proposed](./formats/network/iin_method.md) | +| RFC # | Title | Category | Status | +|--------|-------------------------------------|----------|-------------------------------------------------------------------------| +| 01-001 | Views | Model | [Proposed](./models/ledger/views.md) | +| 01-002 | Cryptographic Proofs | Model | [Proposed](./models/ledger/cryptographic-proofs.md) | +| 01-003 | Verifiable Observation of State | Model | [Draft](./models/ledger/observation-of-state.md) | +| 01-004 | Events | Model | [Draft](./models/ledger/events.md) | +| 01-005 | Cross-Ledger Operations | Model | [Draft](./models/ledger/cross-ledger-operations.md) | +| 01-006 | Atomic Cross-Ledger Transactions | Model | [Proposed](./models/ledger/atomic-cross-ledger-transactions.md) | +| 01-007 | Security Domains | Model | [Proposed](./models/security/security-domains.md) | +| 01-008 | End-to-End Confidentiality | Model | [Proposed](./models/security/confidentiality.md) | +| 01-009 | Relays | Model | [Proposed](./models/infrastructure/relays.md) | +| 01-010 | Interoperation Modules | Model | [Proposed](./models/infrastructure/interoperation-modules.md) | +| 01-011 | Identity Management | Model | [Proposed](./models/identity/network-identity-management.md) | +| 01-012 | Identity Registry | Model | [Proposed](./models/identity/iin.md) | +| 01-013 | Identity Agent | Model | [Proposed](./models/identity/iin-agent.md) | +| 01-014 | Identity Trust Anchor Agent | Model | [Retired](./models/identity/iin-steward-agent.md) | +| 01-015 | Network Identity Updates | Model | [Proposed](./models/identity/identity-update-policy.md) | +| 02-001 | Data Sharing | Protocol | [Proposed](./protocols/data-sharing/generic.md) | +| 02-002 | Data Sharing in Fabric | Protocol | [Proposed](./protocols/data-sharing/fabric.md) | +| 02-003 | Data Sharing in Corda | Protocol | [Proposed](./protocols/data-sharing/corda.md) | +| 02-004 | Asset Exchange through HTLC | Protocol | [Proposed](./protocols/asset-exchange/generic-htlc.md) | +| 02-005 | Asset Exchange in Fabric | Protocol | [Proposed](./protocols/asset-exchange/fabric-htlc.md) | +| 02-006 | Asset Exchange in Corda | Protocol | [Proposed](./protocols/asset-exchange/corda-htlc.md) | +| 02-007 | Asset Exchange in Besu | Protocol | [Draft](./protocols/asset-exchange/besu-htlc.md) | +| 02-008 | Asset Transfer | Protocol | [Proposed](./protocols/asset-transfer/generic.md) | +| 02-009 | Asset Transfer in Fabric | Protocol | [Proposed](./protocols/asset-transfer/fabric.md) | +| 02-010 | Asset Transfer in Corda | Protocol | [Proposed](./protocols/asset-transfer/corda.md) | +| 02-011 | Identity and Config Sharing | Protocol | [Superseded](./protocols/identity/id-config-sharing.md) | +| 02-012 | Cross-Domain Identity Management | Protocol | [Proposed](./protocols/identity/identity-syncing.md) | +| 02-013 | Security Domain Discovery | Protocol | [Draft](./protocols/discovery/discovery.md) | +| 02-014 | Cross-Domain Negotiation | Protocol | [Draft](./protocols/discovery/negotiation.md) | +| 02-015 | Transaction Invocation | Protocol | [Draft](./protocols/contract-invocation/invocation.md) | +| 02-016 | Event Bus | Protocol | [Draft](./protocols/events/event-bus.md) | +| 02-017 | Security Domain Identity Validation | Protocol | [Proposed](./protocols/identity/security-domain-identity-validation.md) | +| 02-018 | Cross-Domain Membership Syncing | Protocol | [Proposed](./protocols/identity/membership-syncing.md) | +| 03-001 | View Address | Format | [Proposed](./formats/views/addressing.md) | +| 03-002 | Generic View | Format | [Proposed](./formats/views/definition.md) | +| 03-003 | Fabric View | Format | [Proposed](./formats/views/fabric.md) | +| 03-004 | Corda View | Format | [Proposed](./formats/views/corda.md) | +| 03-005 | Besu View | Format | [Draft](./formats/views/besu.md) | +| 03-006 | Ethereum View | Format | [Draft](./formats/views/ethereum.md) | +| 03-007 | View Request | Format | [Proposed](./formats/views/request.md) | +| 03-008 | Access Control Policy | Format | [Proposed](./formats/policies/access-control.md) | +| 03-009 | Proof Verification Policy | Format | [Proposed](./formats/policies/proof-verification.md) | +| 03-010 | Verification Policy DSL | Format | [Draft](./formats/policies/dsl.md) | +| 03-011 | Membership | Format | [Proposed](./formats/network/membership.md) | +| 03-012 | Network Identities | Format | [Proposed](./formats/network/identity.md) | +| 03-013 | Asset Exchange Units | Format | [Proposed](./formats/assets/exchange.md) | +| 03-014 | Asset Transfer Units | Format | [Proposed](./formats/assets/transfer.md) | +| 03-015 | Relay Messages | Format | [Proposed](./formats/communication/relay.md) | +| 03-016 | Fabric Interop Chaincode API | Format | [Proposed](./formats/network/fabric-interop-chaincode.md) | +| 03-017 | Interoperation CorDapp API | Format | [Proposed](./formats/network/interop-cordapp.md) | +| 03-018 | Besu Interop Contract API | Format | [Proposed](./formats/network/besu-interop-contract.md) | +| 03-019 | Application SDK | Format | [Proposed](./formats/network/application-sdk.md) | +| 03-020 | DID Method for DLT Networks | Format | [Proposed](./formats/network/iin_method.md) | ## RFC Process diff --git a/rfcs/models/identity/iin.md b/rfcs/models/identity/iin.md index bab3c6e2d..a2ee6ac31 100644 --- a/rfcs/models/identity/iin.md +++ b/rfcs/models/identity/iin.md @@ -50,7 +50,7 @@ A DID Document is not inherently mapped to any entity's physical identity [did-c The IIN must support two kinds of claims to be issued by trust anchors to the DIDs: -1. Identity VCs - for associating real world identity to individuals/organizations which are members of networks - *Organizational Unit Identity VC*, or to a network as a whole - *security Domain Identity VC*. (See [Network Identity Validation protocol](../../protocols/identity/network-identity-validation.md) for details.) +1. Identity VCs - for associating real world identity to individuals/organizations which are members of networks - *Organizational Unit Identity VC*, or to a network as a whole - *security Domain Identity VC*. (See [Network Identity Validation protocol](../../protocols/identity/security-domain-identity-validation.md) for details.) 2. Membership VCs - to assert the membership of an individual/organization in a blockchain network. diff --git a/rfcs/protocols/discovery/discovery.md b/rfcs/protocols/discovery/discovery.md index 1cd2656cd..b5ffb08b7 100644 --- a/rfcs/protocols/discovery/discovery.md +++ b/rfcs/protocols/discovery/discovery.md @@ -13,6 +13,6 @@ ## Summary -This document covers the process by which a network (or security domain) discovers the identity of another as a prelude to [validation](../identity/network-identity-validation.md) and [syncing of membership information](../identity/membership-syncing.md). +This document covers the process by which a network (or security domain) discovers the identity of another as a prelude to [validation](../identity/security-domain-identity-validation.md) and [syncing of membership information](../identity/membership-syncing.md). At its simplest, this can be a trivial exercise of hitting a well-known website that serves DID records for the security domains one is interesting in interoperating with. But more complex situations are possible, involving multiple IINs and name resolution services. diff --git a/rfcs/protocols/identity/identity-syncing.md b/rfcs/protocols/identity/identity-syncing.md index 550be3701..f6cc44850 100644 --- a/rfcs/protocols/identity/identity-syncing.md +++ b/rfcs/protocols/identity/identity-syncing.md @@ -58,7 +58,7 @@ Example: If `method-name` of an IIN registry is `exampleiin`, and the organizational unit chooses a `method-specific-id` as `org1`, then `org1` must be unique within `exampleiin`, and `did:exampleiin:org1` must be unique globally. -> Note: An IIN registry may mandate organizational unit DIDs to have a fixed prefix in the `method-specific-id` to signal that it is a network member's DID and not a network's (or security domain's) DID. Eg: if the fixed prefix is `member:`, then a valid participant did will be `did:exampleiin:member:org1`. Similarly a security domain DID can be `did:exampleiin:security-domain:tradelens`. +> Note: An IIN registry may mandate organizational unit DIDs to have a fixed prefix in the `method-specific-id` to signal that it is a network member's DID and not a network's (or security domain's) DID. Eg: if the fixed prefix is `member:`, then a valid organizational unit DID will be `did:exampleiin:member:org1`. Similarly a security domain DID can be `did:exampleiin:security-domain:tradelens`. **Step 2. member creates a DID Document** @@ -107,7 +107,7 @@ When an IIN registry receives a DID registration request, i.e., the DID `create` **Step 5. Trust anchors issue identity VC to member DID** -A DID document does not contain any personal information about its holderi, like physical identity or real world identity (see [binding DID to physical identity](https://w3c.github.io/did-core/#binding-to-physical-identity) for reference). Therefore, to map a participant's DID to its physical identity, some trust anchor must issue VCs attesting real world identities of the member to its DID. The member can hold these VCs in a wallet and present them to others to prove various identities or affiliations as required in particular scenarios. +A DID document does not contain any personal information about its holder, like physical identity or real world identity (see [binding DID to physical identity](https://w3c.github.io/did-core/#binding-to-physical-identity) for reference). Therefore, to map an organization unit's DID to its physical identity, some trust anchor must issue VCs attesting real world identities of the member to its DID. The member can hold these VCs in a wallet and present them to others to prove various identities or affiliations as required in particular scenarios. > Any nummber of trust anchors may issue identity VCs to a member in Step 5. These identity VCs may be used for validating its security domain's identity by other members of that domain. See the *Security Domain Identity Validation* section for more details. @@ -261,16 +261,16 @@ Since the IIN registry is typically built on a decentralized ledger, the Securit ## Network Discovery -The first step towards interoperation between two blockchain networks is discovery. Any network with a registered Network DID in an IIN can be discovered using the DID only. +The first step towards interoperation between two blockchain networks is discovery. Any network with a registered Security Domain DID in an IIN can be discovered using the DID only. -Given the DID of a foreign network in the format `did::` (example `did:iinindy:tradelens`), the foreign network can be discovered by standard DID resolution. The IIN agent of a participant of a local network contacts the DID registry (example: `iinindy`) and resolves the DID to download the Network DID document. +Given the DID of a foreign network in the format `did::` (example `did:iinindy:tradelens`), the foreign network can be discovered by standard DID resolution. The IIN agent of a participant of a local network contacts the DID registry (example: `iinindy`) and resolves the DID to download the Security Domain DID document. See the [network discovery protocol specifications](../discovery/discovery.md) for more details. ## Security Domain Identity Validation -After a network has been discovered, and its Security Domain DID document has been fetched, the authenticity of that DID must be verified. See the [Security Domain Identity Validation protocol](./network-identity-validation.md) for details of how the network's identity is validated. +After a network has been discovered, and its Security Domain DID document has been fetched, the authenticity of that DID must be verified. See the [Security Domain Identity Validation protocol](./security-domain-identity-validation.md) for details of how the network's identity is validated. ## Security Domain Membership Fetching and Recording @@ -305,7 +305,7 @@ The IIN registry authenticates a Security Domain DID update request the same way ## Syncing Security Domain Membership Changes -The security domain validation and membership syncing protocols must be re-run every time there is a change in a security domain's identity (DID document) or in its membership configuration. The flow diagram below illustrates the complete process from the time a change occurs in one network up to the point where its updated identity and membership info is reflected in another network's ledger as a prerequisite for data plane interoperation. Each step in this diagram represents a separate protocol: (1) is described in this document above, (2) is described in the [security domain identity validation specification](./network-identity-validation.md), and (3) in the [membership syncing specification](./membership-syncing.md). +The security domain validation and membership syncing protocols must be re-run every time there is a change in a security domain's identity (DID document) or in its membership configuration. The flow diagram below illustrates the complete process from the time a change occurs in one network up to the point where its updated identity and membership info is reflected in another network's ledger as a prerequisite for data plane interoperation. Each step in this diagram represents a separate protocol: (1) is described in this document above, (2) is described in the [security domain identity validation specification](./security-domain-identity-validation.md), and (3) in the [membership syncing specification](./membership-syncing.md). diff --git a/rfcs/protocols/identity/membership-syncing.md b/rfcs/protocols/identity/membership-syncing.md index 8f0164560..5d57e0fc3 100644 --- a/rfcs/protocols/identity/membership-syncing.md +++ b/rfcs/protocols/identity/membership-syncing.md @@ -22,7 +22,7 @@ Consider two security domains governing ledgers `Ledger A` and `Ledger B` respec -The first phase in the above diagram, involving [registration](./identity-syncing.md), [discovery](../discovery/discovery.md), and [validation](./network-identity-validation.md) are covered in other specifications. In this draft, we only specify the bilateral protocol occurring between sets of IIN Agents representing two independent security domains' members. +The first phase in the above diagram, involving [registration](./identity-syncing.md), [discovery](../discovery/discovery.md), and [validation](./security-domain-identity-validation.md) are covered in other specifications. In this draft, we only specify the bilateral protocol occurring between sets of IIN Agents representing two independent security domains' members. The communication among IIN Agents of the security domain governing `Ledger A` to collect attestations can occur in one of two ways: * It can be orchestrated completely by the triggering agent (in this case `A2`), which sends requests and receives responses from every other local IIN Agent. From b7bd52c4375ea9e4de29e91621c3bfd86d6eb0a8 Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Mon, 3 Oct 2022 08:18:19 +0000 Subject: [PATCH 145/150] Reverting Corda image versions from 4.8.4 to 4.8 because of missing images in Docker Hub Signed-off-by: VRamakrishna --- core/drivers/corda-driver/build.gradle | 4 ++-- core/network/corda-interop-app/constants.properties | 4 ++-- sdks/corda/build.gradle | 4 ++-- .../corda/dev/Corda_Network/constants.properties | 6 +++--- .../corda/dev/Corda_Network/docker-compose.yml | 8 ++++---- .../corda/dev/Corda_Network2/constants.properties | 4 ++-- .../corda/dev/Corda_Network2/docker-compose.yml | 8 ++++---- tests/network-setups/corda/scripts/start-nodes.sh | 2 +- 8 files changed, 20 insertions(+), 20 deletions(-) diff --git a/core/drivers/corda-driver/build.gradle b/core/drivers/corda-driver/build.gradle index 220aac829..4102f5035 100644 --- a/core/drivers/corda-driver/build.gradle +++ b/core/drivers/corda-driver/build.gradle @@ -7,8 +7,8 @@ buildscript { ext.grpc_kotlin_version = "0.1.3" // CURRENT_GRPC_KOTLIN_VERSION ext.corda_release_group = "net.corda" ext.corda_core_release_group = "net.corda" - ext.corda_version = "4.8.4" - ext.corda_core_version = "4.8.4" + ext.corda_version = "4.8" + ext.corda_core_version = "4.8" ext.arrow_version = "0.10.4" ext.weaver_protos_version = "1.4.2" ext.weaver_corda_version = "1.2.9" diff --git a/core/network/corda-interop-app/constants.properties b/core/network/corda-interop-app/constants.properties index 0e6ae6940..d01dafec3 100644 --- a/core/network/corda-interop-app/constants.properties +++ b/core/network/corda-interop-app/constants.properties @@ -1,7 +1,7 @@ cordaReleaseGroup=net.corda cordaCoreReleaseGroup=net.corda -cordaVersion=4.8.4 -cordaCoreVersion=4.8.4 +cordaVersion=4.8 +cordaCoreVersion=4.8 gradlePluginsVersion=5.0.12 kotlinVersion=1.3.72 junitVersion=4.12 diff --git a/sdks/corda/build.gradle b/sdks/corda/build.gradle index 87e32cbec..3f9af553d 100644 --- a/sdks/corda/build.gradle +++ b/sdks/corda/build.gradle @@ -7,8 +7,8 @@ buildscript { ext.grpc_kotlin_version = "0.1.3" // CURRENT_GRPC_KOTLIN_VERSION ext.corda_release_group = "net.corda" ext.corda_core_release_group = "net.corda" - ext.corda_version = "4.8.4" - ext.corda_core_version = "4.8.4" + ext.corda_version = "4.8" + ext.corda_core_version = "4.8" ext.arrow_version = "0.10.4" ext.corda_gradle_plugins_version = "5.0.12" ext.log4j_version = "2.16.0" diff --git a/tests/network-setups/corda/dev/Corda_Network/constants.properties b/tests/network-setups/corda/dev/Corda_Network/constants.properties index bf03d320c..e0cbc6acc 100644 --- a/tests/network-setups/corda/dev/Corda_Network/constants.properties +++ b/tests/network-setups/corda/dev/Corda_Network/constants.properties @@ -1,7 +1,7 @@ cordaReleaseGroup=net.corda cordaCoreReleaseGroup=net.corda -cordaVersion=4.8.4 -cordaCoreVersion=4.8.4 +cordaVersion=4.8 +cordaCoreVersion=4.8 gradlePluginsVersion=5.0.12 kotlinVersion=1.3.72 junitVersion=4.12 @@ -17,4 +17,4 @@ partyAAdminRpcAddress=localhost:10046 partyBRpcAddress=localhost:10009 partyBAdminRpcAddress=localhost:10049 partyCRpcAddress=localhost:10012 -partyCAdminRpcAddress=localhost:10052 \ No newline at end of file +partyCAdminRpcAddress=localhost:10052 diff --git a/tests/network-setups/corda/dev/Corda_Network/docker-compose.yml b/tests/network-setups/corda/dev/Corda_Network/docker-compose.yml index 479e01ed4..767bb606d 100644 --- a/tests/network-setups/corda/dev/Corda_Network/docker-compose.yml +++ b/tests/network-setups/corda/dev/Corda_Network/docker-compose.yml @@ -22,7 +22,7 @@ services: ports: - 10003:10003 - 22022 - image: corda/corda-zulu-java1.8-4.8.4 + image: corda/corda-zulu-java1.8-4.8 container_name: corda_notary_1 partya: profiles: ["1-node", "2-nodes", "3-nodes"] @@ -41,7 +41,7 @@ services: ports: - 10006:10003 - 22022 - image: corda/corda-zulu-java1.8-4.8.4 + image: corda/corda-zulu-java1.8-4.8 container_name: corda_partya_1 partyb: profiles: ["2-nodes", "3-nodes"] @@ -60,7 +60,7 @@ services: ports: - 10009:10003 - 22022 - image: corda/corda-zulu-java1.8-4.8.4 + image: corda/corda-zulu-java1.8-4.8 container_name: corda_partyb_1 partyc: profiles: ["3-nodes"] @@ -79,5 +79,5 @@ services: ports: - 10012:10003 - 22022 - image: corda/corda-zulu-java1.8-4.8.4 + image: corda/corda-zulu-java1.8-4.8 container_name: corda_partyc_1 diff --git a/tests/network-setups/corda/dev/Corda_Network2/constants.properties b/tests/network-setups/corda/dev/Corda_Network2/constants.properties index 4aade9130..aa3b4e514 100644 --- a/tests/network-setups/corda/dev/Corda_Network2/constants.properties +++ b/tests/network-setups/corda/dev/Corda_Network2/constants.properties @@ -1,7 +1,7 @@ cordaReleaseGroup=net.corda cordaCoreReleaseGroup=net.corda -cordaVersion=4.8.4 -cordaCoreVersion=4.8.4 +cordaVersion=4.8 +cordaCoreVersion=4.8 gradlePluginsVersion=5.0.12 kotlinVersion=1.3.72 junitVersion=4.12 diff --git a/tests/network-setups/corda/dev/Corda_Network2/docker-compose.yml b/tests/network-setups/corda/dev/Corda_Network2/docker-compose.yml index b106643db..f735b7e67 100644 --- a/tests/network-setups/corda/dev/Corda_Network2/docker-compose.yml +++ b/tests/network-setups/corda/dev/Corda_Network2/docker-compose.yml @@ -22,7 +22,7 @@ services: ports: - 30003:10003 - 22022 - image: corda/corda-zulu-java1.8-4.8.4 + image: corda/corda-zulu-java1.8-4.8 container_name: corda_network2_notary_1 partya: profiles: ["1-node", "2-nodes", "3-nodes"] @@ -41,7 +41,7 @@ services: ports: - 30006:10003 - 22022 - image: corda/corda-zulu-java1.8-4.8.4 + image: corda/corda-zulu-java1.8-4.8 container_name: corda_network2_partya_1 partyb: profiles: ["2-nodes", "3-nodes"] @@ -60,7 +60,7 @@ services: ports: - 30009:10003 - 22022 - image: corda/corda-zulu-java1.8-4.8.4 + image: corda/corda-zulu-java1.8-4.8 container_name: corda_network2_partyb_1 partyc: profiles: ["3-nodes"] @@ -79,5 +79,5 @@ services: ports: - 30012:10003 - 22022 - image: corda/corda-zulu-java1.8-4.8.4 + image: corda/corda-zulu-java1.8-4.8 container_name: corda_network2_partyc_1 diff --git a/tests/network-setups/corda/scripts/start-nodes.sh b/tests/network-setups/corda/scripts/start-nodes.sh index f2caa8826..776f4b5aa 100755 --- a/tests/network-setups/corda/scripts/start-nodes.sh +++ b/tests/network-setups/corda/scripts/start-nodes.sh @@ -14,7 +14,7 @@ weaverProtosVersion="1.4.2" parties="Notary PartyA PartyB PartyC" -echo "Starting Netowrk: ${nw}, profile: ${profile}, with App: ${app} Cordapp..." +echo "Starting Network: ${nw}, profile: ${profile}, with App: ${app} Cordapp..." for party in ${parties}; do if [ "simple" = "$app" ]; then From e6694ce62525b7f9ecb2fa47a8e0600586181a3f Mon Sep 17 00:00:00 2001 From: VRamakrishna Date: Mon, 3 Oct 2022 11:11:42 +0000 Subject: [PATCH 146/150] Bug fix in Go Package publish workflow and updating Fabric Interop CC package versions to 1.5.1 Signed-off-by: VRamakrishna --- .github/workflows/deploy_go-pkgs.yml | 12 ++++++------ .../fabric-interop-cc/interfaces/asset-mgmt/VERSION | 2 +- .../fabric-interop-cc/libs/assetexchange/VERSION | 2 +- core/network/fabric-interop-cc/libs/utils/VERSION | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/deploy_go-pkgs.yml b/.github/workflows/deploy_go-pkgs.yml index e526ffe9d..dba2edb54 100644 --- a/.github/workflows/deploy_go-pkgs.yml +++ b/.github/workflows/deploy_go-pkgs.yml @@ -36,7 +36,7 @@ jobs: echo "MODULE_DESC=GO Weaver Protos" >> $GITHUB_ENV - name: Set module version - run: echo "VERSION=$(cat VERSION)" >> $GITHUB_ENV + run: echo "VERSION=v$(cat VERSION)" >> $GITHUB_ENV working-directory: common/protos-go - name: Create Release @@ -80,7 +80,7 @@ jobs: echo "MODULE_DESC=GO Fabric Utils Library for Interoperation" >> $GITHUB_ENV - name: Set module version - run: echo "VERSION=$(cat VERSION)" >> $GITHUB_ENV + run: echo "VERSION=v$(cat VERSION)" >> $GITHUB_ENV working-directory: core/network/fabric-interop-cc/libs/utils - name: Build test @@ -128,7 +128,7 @@ jobs: echo "MODULE_DESC=GO Fabric Library for Asset Exchange" >> $GITHUB_ENV - name: Set module version - run: echo "VERSION=$(cat VERSION)" >> $GITHUB_ENV + run: echo "VERSION=v$(cat VERSION)" >> $GITHUB_ENV working-directory: core/network/fabric-interop-cc/libs/assetexchange - name: Build test @@ -176,7 +176,7 @@ jobs: echo "MODULE_DESC=GO Fabric Asset Management Interface" >> $GITHUB_ENV - name: Set module version - run: echo "VERSION=$(cat VERSION)" >> $GITHUB_ENV + run: echo "VERSION=v$(cat VERSION)" >> $GITHUB_ENV working-directory: core/network/fabric-interop-cc/interfaces/asset-mgmt - name: Build test @@ -224,7 +224,7 @@ jobs: echo "MODULE_DESC=GO Fabric Interop Chaincode" >> $GITHUB_ENV - name: Set module version - run: echo "VERSION=$(cat VERSION)" >> $GITHUB_ENV + run: echo "VERSION=v$(cat VERSION)" >> $GITHUB_ENV working-directory: core/network/fabric-interop-cc/contracts/interop - name: Build test @@ -272,7 +272,7 @@ jobs: echo "MODULE_DESC=GO Fabric Weaver SDK" >> $GITHUB_ENV - name: Set module version - run: echo "VERSION=$(cat VERSION)" >> $GITHUB_ENV + run: echo "VERSION=v$(cat VERSION)" >> $GITHUB_ENV working-directory: sdks/fabric/go-sdk - name: Build test diff --git a/core/network/fabric-interop-cc/interfaces/asset-mgmt/VERSION b/core/network/fabric-interop-cc/interfaces/asset-mgmt/VERSION index 3c80e4f0f..26ca59460 100644 --- a/core/network/fabric-interop-cc/interfaces/asset-mgmt/VERSION +++ b/core/network/fabric-interop-cc/interfaces/asset-mgmt/VERSION @@ -1 +1 @@ -1.4.3 \ No newline at end of file +1.5.1 diff --git a/core/network/fabric-interop-cc/libs/assetexchange/VERSION b/core/network/fabric-interop-cc/libs/assetexchange/VERSION index 3c80e4f0f..26ca59460 100644 --- a/core/network/fabric-interop-cc/libs/assetexchange/VERSION +++ b/core/network/fabric-interop-cc/libs/assetexchange/VERSION @@ -1 +1 @@ -1.4.3 \ No newline at end of file +1.5.1 diff --git a/core/network/fabric-interop-cc/libs/utils/VERSION b/core/network/fabric-interop-cc/libs/utils/VERSION index 3c80e4f0f..26ca59460 100644 --- a/core/network/fabric-interop-cc/libs/utils/VERSION +++ b/core/network/fabric-interop-cc/libs/utils/VERSION @@ -1 +1 @@ -1.4.3 \ No newline at end of file +1.5.1 From 6caf2fa5f96d20bcbd6bbe0ebfae52ee3cae17e1 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Tue, 4 Oct 2022 09:56:07 +0530 Subject: [PATCH 147/150] go sdk readme changes when confidential is set to false Signed-off-by: Krishnasuri Narayanam --- core/relay/config/Fabric_Relay2.toml | 5 +++++ .../go-cli/data/credentials/network1/membership.json | 2 +- .../data/credentials/network2/access-control.json | 11 +++++++++++ .../go-cli/data/credentials/network2/membership.json | 1 + .../credentials/network2/verification-policy.json | 1 + sdks/fabric/go-sdk/VERSION | 2 +- sdks/fabric/go-sdk/readme.md | 12 +++++++++--- 7 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 samples/fabric/go-cli/data/credentials/network2/access-control.json create mode 100644 samples/fabric/go-cli/data/credentials/network2/membership.json create mode 100644 samples/fabric/go-cli/data/credentials/network2/verification-policy.json diff --git a/core/relay/config/Fabric_Relay2.toml b/core/relay/config/Fabric_Relay2.toml index 4c002ae73..8f8e82715 100644 --- a/core/relay/config/Fabric_Relay2.toml +++ b/core/relay/config/Fabric_Relay2.toml @@ -32,6 +32,11 @@ hostname="localhost" port="9080" tls=false tlsca_cert_path="credentials/fabric_ca_cert.pem" +[relays.Fabric_Relay2] +hostname="localhost" +port="9083" +tls=false +tlsca_cert_path="credentials/fabric_ca_cert.pem" [drivers] diff --git a/samples/fabric/go-cli/data/credentials/network1/membership.json b/samples/fabric/go-cli/data/credentials/network1/membership.json index 5b3966c67..2bfc66886 100644 --- a/samples/fabric/go-cli/data/credentials/network1/membership.json +++ b/samples/fabric/go-cli/data/credentials/network1/membership.json @@ -1 +1 @@ -{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUYyc2soSqUtWVHTOtud7D1FbCHp0wCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIxMDczMDA1NDYwMFoXDTM2MDcyNjA1NDYwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEM/GelSlifY6+rMOE3G95SXF+\ndTHpG8j5cYK82EVCaLCSvNlCKgpupuQnbkLy+V6dgf9tKSnEsZgiHeB6AyJK/6NF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFHKG9YL6OC86y5FIXpqte7bOXSD8MAoGCCqGSM49BAMCA0cAMEQCIA9iMqQ/aJiC\na++ft4tN7io83jB17/fzG3BRC9soRR3bAiALgWNYk5118DKTkhFdJVQ0VIoopEtq\nGzi+/j4j7fu/wQ==\n-----END CERTIFICATE-----\n"}},"securityDomain":"network1"} +{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFjCCAb2gAwIBAgIUYxHjCF1HdZexrgAM73ec4jdHy8owCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjIwMFoXDTM3MDczMTE4MjIwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE76ubZH/VHJszsYLHVKaUwKBR\nUZv8P+Jq6Op5PeBf02JUKPM15DSF9n56RJq+7mrM9zBzPvBsUySFd+rr/BrsW6NF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFM7HDMehiHl8b92QSMN4Q1FB7JU/MAoGCCqGSM49BAMCA0cAMEQCIH4UJq+qY2OP\n7DzBAwY7woYuy4zoT2kxyiexlix38aY4AiAo+8OKE1wFM+XKLUqI4zzgq2bpg1qb\nU5aIsTpdz3N2tg==\n-----END CERTIFICATE-----\n"}},"securityDomain":"network1"} diff --git a/samples/fabric/go-cli/data/credentials/network2/access-control.json b/samples/fabric/go-cli/data/credentials/network2/access-control.json new file mode 100644 index 000000000..0ca6baabe --- /dev/null +++ b/samples/fabric/go-cli/data/credentials/network2/access-control.json @@ -0,0 +1,11 @@ +{ + "securityDomain": "network2", + "rules": [ + { + "principal": "Org1MSP", + "principalType": "ca", + "resource": "mychannel:simplestate:Read:*", + "read": true + } + ] +} diff --git a/samples/fabric/go-cli/data/credentials/network2/membership.json b/samples/fabric/go-cli/data/credentials/network2/membership.json new file mode 100644 index 000000000..e12052a74 --- /dev/null +++ b/samples/fabric/go-cli/data/credentials/network2/membership.json @@ -0,0 +1 @@ +{"members":{"Org1MSP":{"type":"ca","value":"-----BEGIN CERTIFICATE-----\nMIICFzCCAb2gAwIBAgIUajWU/EzwkVocqYksNXUdm04WvCswCgYIKoZIzj0EAwIw\naDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMt\nY2Etc2VydmVyMB4XDTIyMDgwNDE4MjQwMFoXDTM3MDczMTE4MjQwMFowaDELMAkG\nA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBl\ncmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRkwFwYDVQQDExBmYWJyaWMtY2Etc2Vy\ndmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5is5AaAg+nbhzGDEQG+liqNH\nhl876WuMbeT8k6dRNAsBpIwpxRWlg9iNrnvlkkhCBjb9AUyczQ7+BY1+NfUYlKNF\nMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFOE41wEfBgHf+cfjQzayE/Q8pm2bMAoGCCqGSM49BAMCA0gAMEUCIQCDmJzZfO1n\nVX5eMdDkDDtDz+eAXhPsu7upJW0ukhxkTAIgJceBfxJYwM1Tof1ADInIY+M+U8y+\nTL2JfaeZkJJz42E=\n-----END CERTIFICATE-----\n"}},"securityDomain":"network2"} diff --git a/samples/fabric/go-cli/data/credentials/network2/verification-policy.json b/samples/fabric/go-cli/data/credentials/network2/verification-policy.json new file mode 100644 index 000000000..d3de6d665 --- /dev/null +++ b/samples/fabric/go-cli/data/credentials/network2/verification-policy.json @@ -0,0 +1 @@ +{"securityDomain":"network2","identifiers":[{"pattern":"mychannel:simplestate:Read:*","policy":{"type":"Signature","criteria":["Org1MSP"]}}]} diff --git a/sdks/fabric/go-sdk/VERSION b/sdks/fabric/go-sdk/VERSION index e2cac26c1..e8ea05db8 100644 --- a/sdks/fabric/go-sdk/VERSION +++ b/sdks/fabric/go-sdk/VERSION @@ -1 +1 @@ -1.2.3 \ No newline at end of file +1.2.4 diff --git a/sdks/fabric/go-sdk/readme.md b/sdks/fabric/go-sdk/readme.md index 2de9409e8..fba18d715 100644 --- a/sdks/fabric/go-sdk/readme.md +++ b/sdks/fabric/go-sdk/readme.md @@ -3,15 +3,21 @@ SPDX-License-Identifier: CC-BY-4.0 --> - # Integration tests for `asset-exchange` using go-sdk + +## Integration tests for `asset-exchange` using go-sdk A sample of integration tests for asset-exchange can be exercised by running the file `exerciseSDK.go`. Before executing `go run exerciseSDK.go`, please ensure that the below `keys` are populated appropriately in the network connection profile (e.g., in the network1 connection profile available at `../../../tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json`). -## keys in the connection profile `json` file: channels, orderers, certificateAuthorities +### keys in the connection profile `json` file: channels, orderers, certificateAuthorities Sample content for the values of these keys can be found in the file `helpers/testdata/example/peerOrganizations/org1.example.com/connection-tls.json` (please note that the value of the key "certificateAuthorities"."ca.org1.example.com"."tlsCACerts"."pem" in this file is an array). Also note that similar checks need to be carried out for the connection profile `yaml` file if you want to use the yaml file instead of json. Sample content for the values of these keys can be found in the file `helpers/testdata/example/peerOrganizations/org1.example.com/connection-tls.yaml`. +## Configurations - +- Set the output of the below command as the value of the key `"members"."Org1MSP"."value"` in the file `data/credentials/network1/membership.json` (similarly for `network2`). + ```bash + awk 'NF {sub(/\r/, ""); printf "%s\\n",$0;}' ../../../tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/peers/peer0.org1.network1.com/msp/cacerts/localhost-7054-ca-org1-network1-com.pem + ``` +- Set the chaincode value (e.g., `simplestate`) appropriately in the file `data/credentials/network1/access-control.json` (similarly for `network2`). From aaf0dcf3018be62f85f1b57837e27d95565b55dc Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Tue, 4 Oct 2022 10:04:29 +0530 Subject: [PATCH 148/150] set the chaincode to simplestate from simpleasset in access-control.json Signed-off-by: Krishnasuri Narayanam --- .../fabric/go-cli/data/credentials/network1/access-control.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/fabric/go-cli/data/credentials/network1/access-control.json b/samples/fabric/go-cli/data/credentials/network1/access-control.json index a67541517..e23c305bb 100644 --- a/samples/fabric/go-cli/data/credentials/network1/access-control.json +++ b/samples/fabric/go-cli/data/credentials/network1/access-control.json @@ -4,7 +4,7 @@ { "principal": "Org1MSP", "principalType": "ca", - "resource": "mychannel:simpleasset:Read:*", + "resource": "mychannel:simplestate:Read:*", "read": true } ] From d89e38d0414a24ad2240070f0918e31c3b0b2157 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Thu, 6 Oct 2022 13:47:42 +0530 Subject: [PATCH 149/150] minor edits as per the PR review comments Signed-off-by: Krishnasuri Narayanam --- .github/workflows/test_asset-exchange-fabric.yml | 1 - .github/workflows/test_asset-transfer.yml | 1 - .github/workflows/test_data-sharing.yml | 1 - core/relay/config/Fabric_Relay2.toml | 5 ----- 4 files changed, 8 deletions(-) diff --git a/.github/workflows/test_asset-exchange-fabric.yml b/.github/workflows/test_asset-exchange-fabric.yml index 25d61529a..c9fd6b631 100644 --- a/.github/workflows/test_asset-exchange-fabric.yml +++ b/.github/workflows/test_asset-exchange-fabric.yml @@ -21,7 +21,6 @@ on: jobs: asset-exchange-fabric: - # if: ${{ false }} # disable # The type of runner that the job will run on runs-on: ubuntu-latest diff --git a/.github/workflows/test_asset-transfer.yml b/.github/workflows/test_asset-transfer.yml index b55183a5c..2dbbbfaf4 100644 --- a/.github/workflows/test_asset-transfer.yml +++ b/.github/workflows/test_asset-transfer.yml @@ -20,7 +20,6 @@ on: # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: fabric-asset-transfer: - # if: ${{ false }} # disable # The type of runner that the job will run on runs-on: ubuntu-latest diff --git a/.github/workflows/test_data-sharing.yml b/.github/workflows/test_data-sharing.yml index 3f7733524..2d8859f8a 100644 --- a/.github/workflows/test_data-sharing.yml +++ b/.github/workflows/test_data-sharing.yml @@ -20,7 +20,6 @@ on: # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: data-sharing: - # if: ${{ false }} # disable # The type of runner that the job will run on runs-on: ubuntu-latest diff --git a/core/relay/config/Fabric_Relay2.toml b/core/relay/config/Fabric_Relay2.toml index 8f8e82715..4c002ae73 100644 --- a/core/relay/config/Fabric_Relay2.toml +++ b/core/relay/config/Fabric_Relay2.toml @@ -32,11 +32,6 @@ hostname="localhost" port="9080" tls=false tlsca_cert_path="credentials/fabric_ca_cert.pem" -[relays.Fabric_Relay2] -hostname="localhost" -port="9083" -tls=false -tlsca_cert_path="credentials/fabric_ca_cert.pem" [drivers] From af8a892b351b283aa2c20a652ab52abb86587bc2 Mon Sep 17 00:00:00 2001 From: Krishnasuri Narayanam Date: Thu, 6 Oct 2022 10:20:21 +0000 Subject: [PATCH 150/150] interop cc go files Signed-off-by: Krishnasuri Narayanam --- .../fabric-interop-cc/contracts/interop/go.mod | 6 +++--- .../fabric-interop-cc/contracts/interop/go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/network/fabric-interop-cc/contracts/interop/go.mod b/core/network/fabric-interop-cc/contracts/interop/go.mod index 4cab15322..cd3a68ec9 100644 --- a/core/network/fabric-interop-cc/contracts/interop/go.mod +++ b/core/network/fabric-interop-cc/contracts/interop/go.mod @@ -5,10 +5,10 @@ go 1.16 require ( github.com/ethereum/go-ethereum v1.10.17 github.com/golang/protobuf v1.5.2 - github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go v1.3.1 - github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/assetexchange v1.3.1 + github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go v1.5.1 + github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/assetexchange v1.5.1 github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/testutils v0.0.0-20220522111555-ae96e46bf4a1 - github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/utils v1.3.1 + github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/utils v1.5.1 github.com/hyperledger/fabric-chaincode-go v0.0.0-20210718160520-38d29fabecb9 github.com/hyperledger/fabric-contract-api-go v1.1.1 github.com/hyperledger/fabric-protos-go v0.0.0-20210720123151-f0dc3e2a0871 diff --git a/core/network/fabric-interop-cc/contracts/interop/go.sum b/core/network/fabric-interop-cc/contracts/interop/go.sum index b5f888342..14f59d869 100644 --- a/core/network/fabric-interop-cc/contracts/interop/go.sum +++ b/core/network/fabric-interop-cc/contracts/interop/go.sum @@ -220,14 +220,14 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/huin/goupnp v1.0.3-0.20220313090229-ca81a64b4204/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go v1.3.0/go.mod h1:POCGO/RK9YDfgdhuyqjoD9tRNtWfK7Rh5AYYmsb1Chc= -github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go v1.3.1 h1:83ZKi0fyaNfHjnc59Cqgr8Zma11hSqYSW46VIhBKaWo= -github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go v1.3.1/go.mod h1:POCGO/RK9YDfgdhuyqjoD9tRNtWfK7Rh5AYYmsb1Chc= -github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/assetexchange v1.3.1 h1:oi2G8OoM2cdilGb+PeTDQRZx6mn15744NGkwJimiAOM= -github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/assetexchange v1.3.1/go.mod h1:u6CH8sOTS8ioB0ITKLIAvEvIK+UFzS/xDmQFYEmFVuw= +github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go v1.5.1 h1:IaZCvIAkkRgeyU5T+D1npd2L/7zQESOYNR09XZFS8u8= +github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go v1.5.1/go.mod h1:POCGO/RK9YDfgdhuyqjoD9tRNtWfK7Rh5AYYmsb1Chc= +github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/assetexchange v1.5.1 h1:psneVt+MFOQY9K3a3Ur7tkZOSHCkNoTy9znU6qf5JXI= +github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/assetexchange v1.5.1/go.mod h1:u6CH8sOTS8ioB0ITKLIAvEvIK+UFzS/xDmQFYEmFVuw= github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/testutils v0.0.0-20220522111555-ae96e46bf4a1 h1:F4AWvGjRRWSCWtW0wMD1SkYGnW5yly9NqmHICxHIrUw= github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/testutils v0.0.0-20220522111555-ae96e46bf4a1/go.mod h1:Nke1cGAeCHSgK8x/+tjzojTAT5L/V6e7ERxPUSbnA/8= -github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/utils v1.3.1 h1:0lAsGVvJD4/iTU6TVS3GUtAvaRnqGD/+sunSiOmoZq0= -github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/utils v1.3.1/go.mod h1:GyKdWTtYDkT0CDiGJHRUWvQQ8jw+KlwBhiG8tATVVi4= +github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/utils v1.5.1 h1:Ly857aoRE5TFL91dI6n5Ml9b71I2F4EY4vos6VIStbk= +github.com/hyperledger-labs/weaver-dlt-interoperability/core/network/fabric-interop-cc/libs/utils v1.5.1/go.mod h1:GyKdWTtYDkT0CDiGJHRUWvQQ8jw+KlwBhiG8tATVVi4= 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-20210718160520-38d29fabecb9 h1:1cAZHHrBYFrX3bwQGhOZtOB4sCM9QWVppd81O8vsPXs= github.com/hyperledger/fabric-chaincode-go v0.0.0-20210718160520-38d29fabecb9/go.mod h1:N7H3sA7Tx4k/YzFq7U0EPdqJtqvM4Kild0JoCc7C0Dc=