From d0bede0149e11b5e5f191ea7d392a184cf940ca1 Mon Sep 17 00:00:00 2001 From: Calvin Date: Sun, 30 Mar 2025 17:45:36 +0530 Subject: [PATCH] Project --- README.md | 83 +- StudentDBInit.txt | 29 + asset-transfer-abac/README.md | 173 - asset-transfer-abac/chaincode-go/go.mod | 26 - asset-transfer-abac/chaincode-go/go.sum | 61 - .../chaincode-go/smart-contract/abac.go | 214 - .../chaincode-go/smartContract.go | 23 - .../application-gateway-go/assetTransfer.go | 296 -- .../application-gateway-go/go.mod | 19 - .../application-gateway-go/go.sum | 32 - .../application-gateway-java/build.gradle | 39 - .../gradle/wrapper/gradle-wrapper.jar | Bin 43462 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - .../application-gateway-java/gradlew | 249 - .../application-gateway-java/gradlew.bat | 92 - .../application-gateway-java/pom.xml | 96 - .../application-gateway-java/settings.gradle | 10 - .../src/main/java/App.java | 244 - .../application-gateway-javascript/.gitignore | 11 - .../application-gateway-javascript/.npmrc | 1 - .../eslint.config.mjs | 15 - .../package.json | 25 - .../application-gateway-javascript/src/app.js | 301 -- .../application-gateway-typescript/.gitignore | 14 - .../application-gateway-typescript/.npmrc | 1 - .../eslint.config.mjs | 13 - .../package.json | 33 - .../application-gateway-typescript/src/app.ts | 247 - .../tsconfig.json | 15 - .../chaincode-external/.dockerignore | 5 - .../chaincode-external/.gitignore | 3 - .../chaincode-external/Dockerfile | 17 - .../chaincode-external/README.md | 252 - .../chaincode-external/assetTransfer.go | 297 -- .../chaincode-external/chaincode.env | 24 - .../chaincode-external/chaincode1.env | 24 - .../chaincode-external/chaincode2.env | 24 - .../chaincode-external/connection.json | 5 - .../chaincode-external/crypto/.gitkeep | 0 .../docker-compose-chaincode.yaml | 32 - .../chaincode-external/go.mod | 28 - .../chaincode-external/go.sum | 61 - .../chaincode-external/metadata.json | 4 - .../sampleBuilder/bin/build | 21 - .../sampleBuilder/bin/detect | 14 - .../sampleBuilder/bin/release | 22 - .../chaincode-go/assetTransfer.go | 23 - .../chaincode/mocks/chaincodestub.go | 2991 ----------- .../chaincode/mocks/statequeryiterator.go | 235 - .../chaincode/mocks/transaction.go | 166 - .../chaincode-go/chaincode/smartcontract.go | 194 - .../chaincode/smartcontract_test.go | 184 - asset-transfer-basic/chaincode-go/go.mod | 31 - asset-transfer-basic/chaincode-go/go.sum | 61 - .../chaincode-java/.gitattributes | 6 - .../chaincode-java/.gitignore | 2 - .../chaincode-java/Dockerfile | 31 - asset-transfer-basic/chaincode-java/README.md | 10 - .../chaincode-java/build.gradle | 92 - .../config/checkstyle/checkstyle.xml | 171 - .../config/checkstyle/suppressions.xml | 9 - .../docker/docker-entrypoint.sh | 16 - .../gradle/wrapper/gradle-wrapper.jar | Bin 43462 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - asset-transfer-basic/chaincode-java/gradlew | 249 - .../chaincode-java/gradlew.bat | 92 - .../chaincode-java/settings.gradle | 4 - .../fabric/samples/assettransfer/Asset.java | 93 - .../samples/assettransfer/AssetTransfer.java | 223 - .../samples/assettransfer/AssetTest.java | 74 - .../assettransfer/AssetTransferTest.java | 305 -- .../chaincode-javascript/.eslintignore | 5 - .../chaincode-javascript/.eslintrc.js | 39 - .../chaincode-javascript/.gitignore | 15 - .../chaincode-javascript/index.js | 12 - .../chaincode-javascript/lib/assetTransfer.js | 167 - .../chaincode-javascript/npm-shrinkwrap.json | 4025 --------------- .../chaincode-javascript/package.json | 50 - .../test/assetTransfer.test.js | 268 - .../chaincode-typescript/src/asset.ts | 26 - .../chaincode-typescript/src/assetTransfer.ts | 173 - .../src/assetTransferCustom.ts | 253 + .../chaincode-typescript/src/customAsset.ts | 90 + .../chaincode-typescript/src/index.ts | 4 +- asset-transfer-basic/rest-api-go/.gitignore | 2 - asset-transfer-basic/rest-api-go/README.md | 39 - asset-transfer-basic/rest-api-go/go.mod | 19 - asset-transfer-basic/rest-api-go/go.sum | 32 - asset-transfer-basic/rest-api-go/main.go | 26 - asset-transfer-basic/rest-api-go/web/app.go | 31 - .../rest-api-go/web/initialize.go | 108 - .../rest-api-go/web/invoke.go | 40 - asset-transfer-basic/rest-api-go/web/query.go | 25 - .../rest-api-typescript/README.md | 2 +- .../scripts/generateEnv.sh | 8 +- .../rest-api-typescript/src/assets.router.ts | 537 +- .../rest-api-typescript/src/server.ts | 3 + asset-transfer-events/README.md | 84 - .../application-gateway-go/app.go | 172 - .../application-gateway-go/connect.go | 114 - .../application-gateway-go/go.mod | 19 - .../application-gateway-go/go.sum | 32 - .../application-gateway-java/build.gradle | 28 - .../gradle/wrapper/gradle-wrapper.jar | Bin 43462 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - .../application-gateway-java/gradlew | 249 - .../application-gateway-java/gradlew.bat | 92 - .../application-gateway-java/pom.xml | 101 - .../application-gateway-java/settings.gradle | 10 - .../src/main/java/App.java | 175 - .../src/main/java/Connections.java | 70 - .../application-gateway-typescript/.gitignore | 14 - .../application-gateway-typescript/.npmrc | 1 - .../eslint.config.mjs | 13 - .../package.json | 33 - .../application-gateway-typescript/src/app.ts | 158 - .../src/connect.ts | 58 - .../tsconfig.json | 15 - .../chaincode-go/assetTransferEvents.go | 23 - .../chaincode-go/chaincode/smartcontract.go | 134 - asset-transfer-events/chaincode-go/go.mod | 26 - asset-transfer-events/chaincode-go/go.sum | 61 - .../chaincode-java/build.gradle | 69 - .../config/checkstyle/checkstyle.xml | 171 - .../config/checkstyle/suppressions.xml | 8 - .../gradle/wrapper/gradle-wrapper.jar | Bin 43462 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - asset-transfer-events/chaincode-java/gradlew | 249 - .../chaincode-java/gradlew.bat | 92 - .../chaincode-java/settings.gradle | 5 - .../fabric/samples/events/Asset.java | 158 - .../fabric/samples/events/AssetTransfer.java | 299 -- .../chaincode-javascript/.eslintignore | 5 - .../chaincode-javascript/.eslintrc.js | 39 - .../chaincode-javascript/.gitignore | 15 - .../chaincode-javascript/index.js | 12 - .../lib/assetTransferEvents.js | 128 - .../chaincode-javascript/npm-shrinkwrap.json | 3982 --------------- .../chaincode-javascript/package.json | 48 - .../test/assetTransferEvents.test.js | 229 - .../application-java/.gitattributes | 6 - .../application-java/build.gradle | 42 - .../gradle/wrapper/gradle-wrapper.jar | Bin 43462 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - .../application-java/gradlew | 249 - .../application-java/gradlew.bat | 92 - .../application-java/settings.gradle | 10 - .../src/main/java/application/java/App.java | 143 - .../java/application/java/EnrollAdmin.java | 53 - .../java/application/java/RegisterUser.java | 107 - .../src/main/resources/log4j.properties | 19 - .../application-javascript/.eslintignore | 5 - .../application-javascript/.eslintrc.js | 37 - .../application-javascript/.gitignore | 14 - .../application-javascript/app.js | 252 - .../application-javascript/package.json | 23 - .../statedb/couchdb/indexes/indexOwner.json | 1 - .../asset_transfer_ledger_chaincode.go | 469 -- .../chaincode-go/go.mod | 28 - .../chaincode-go/go.sum | 61 - .../chaincode-javascript/.eslintignore | 5 - .../chaincode-javascript/.eslintrc.js | 37 - .../statedb/couchdb/indexes/indexOwner.json | 1 - .../chaincode-javascript/index.js | 13 - .../lib/asset_transfer_ledger_chaincode.js | 411 -- .../chaincode-javascript/npm-shrinkwrap.json | 1733 ------- .../chaincode-javascript/package.json | 23 - asset-transfer-private-data/README.md | 79 - .../application-gateway-go/app.go | 398 -- .../application-gateway-go/connect.go | 111 - .../application-gateway-go/go.mod | 23 - .../application-gateway-go/go.sum | 223 - .../application-gateway-typescript/.gitignore | 14 - .../application-gateway-typescript/.npmrc | 1 - .../application-gateway-typescript/README.md | 10 - .../eslint.config.mjs | 13 - .../package.json | 33 - .../application-gateway-typescript/src/app.ts | 302 -- .../src/connect.ts | 135 - .../tsconfig.json | 15 - .../assetCollection/indexes/indexOwner.json | 12 - .../chaincode-go/README.md | 1 - .../chaincode-go/chaincode/asset_queries.go | 190 - .../chaincode/asset_queries_test.go | 185 - .../chaincode-go/chaincode/asset_transfer.go | 652 --- .../chaincode/asset_transfer_test.go | 445 -- .../chaincode/mocks/chaincodestub.go | 2991 ----------- .../chaincode/mocks/clientIdentity.go | 404 -- .../chaincode/mocks/statequeryiterator.go | 235 - .../chaincode/mocks/transaction.go | 166 - .../chaincode-go/collections_config.json | 38 - .../chaincode-go/go.mod | 31 - .../chaincode-go/go.sum | 61 - .../chaincode-go/main.go | 23 - .../chaincode-java/.gitattributes | 6 - .../assetCollection/indexes/indexOwner.json | 11 - .../chaincode-java/build.gradle | 79 - .../chaincode-java/collections_config.json | 38 - .../config/checkstyle/checkstyle.xml | 171 - .../config/checkstyle/suppressions.xml | 8 - .../gradle/wrapper/gradle-wrapper.jar | Bin 43462 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - .../chaincode-java/gradlew | 249 - .../chaincode-java/gradlew.bat | 92 - .../chaincode-java/settings.gradle | 5 - .../fabric/samples/privatedata/Asset.java | 126 - .../privatedata/AssetPrivateDetails.java | 51 - .../samples/privatedata/AssetTransfer.java | 643 --- .../privatedata/TransferAgreement.java | 51 - .../privatedata/AssetTransferTest.java | 168 - .../org.mockito.plugins.MockMaker | 1 - .../chaincode-typescript/.dockerignore | 1 - .../chaincode-typescript/.gitignore | 16 - .../chaincode-typescript/Dockerfile | 36 - .../chaincode-typescript/Readme.md | 9 - .../collections_config.json | 38 - .../docker/docker-entrypoint.sh | 16 - .../chaincode-typescript/eslint.config.mjs | 13 - .../chaincode-typescript/npm-shrinkwrap.json | 2256 --------- .../chaincode-typescript/package.json | 41 - .../chaincode-typescript/src/asset.ts | 42 - .../chaincode-typescript/src/assetTransfer.ts | 374 -- .../src/assetTransferDetails.ts | 32 - .../src/assetTransferTransientInput.ts | 115 - .../chaincode-typescript/src/index.ts | 10 - .../src/transferAgreement.ts | 14 - .../chaincode-typescript/src/utils.ts | 19 - .../chaincode-typescript/tsconfig.json | 17 - asset-transfer-sbe/README.md | 169 - .../application-javascript/.eslintignore | 5 - .../application-javascript/.eslintrc.js | 37 - .../application-javascript/.gitignore | 14 - .../application-javascript/app.js | 356 -- .../application-javascript/package.json | 22 - .../chaincode-java/.gitattributes | 6 - asset-transfer-sbe/chaincode-java/.gitignore | 10 - .../chaincode-java/build.gradle | 86 - .../config/checkstyle/checkstyle.xml | 172 - .../config/checkstyle/suppressions.xml | 9 - .../gradle/wrapper/gradle-wrapper.jar | Bin 43462 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - asset-transfer-sbe/chaincode-java/gradlew | 249 - asset-transfer-sbe/chaincode-java/gradlew.bat | 92 - .../chaincode-java/settings.gradle | 5 - .../hyperledger/fabric/samples/sbe/Asset.java | 96 - .../fabric/samples/sbe/AssetContract.java | 269 - .../chaincode-typescript/.gitignore | 20 - .../chaincode-typescript/eslint.config.mjs | 13 - .../chaincode-typescript/npm-shrinkwrap.json | 2205 --------- .../chaincode-typescript/package.json | 35 - .../chaincode-typescript/src/asset.ts | 20 - .../chaincode-typescript/src/assetContract.ts | 121 - .../chaincode-typescript/src/index.ts | 8 - .../chaincode-typescript/tsconfig.json | 17 - asset-transfer-secured-agreement/README.md | 61 - .../application-gateway-typescript/.gitignore | 14 - .../eslint.config.mjs | 13 - .../package.json | 33 - .../application-gateway-typescript/src/app.ts | 217 - .../src/connect.ts | 111 - .../src/contractWrapper.ts | 271 - .../src/utils.ts | 13 - .../tsconfig.json | 15 - .../chaincode-go/README.md | 1 - .../chaincode-go/asset_transfer.go | 619 --- .../chaincode-go/asset_transfer_queries.go | 172 - .../chaincode-go/go.mod | 28 - .../chaincode-go/go.sum | 61 - auction-dutch/README.md | 615 --- .../application-javascript/.eslintignore | 5 - .../application-javascript/.eslintrc.js | 36 - auction-dutch/application-javascript/bid.js | 98 - .../application-javascript/closeAuction.js | 90 - .../application-javascript/createAuction.js | 78 - .../application-javascript/endAuction.js | 91 - .../endAuctionwithAuditor.js | 83 - .../application-javascript/enrollAdmin.js | 62 - .../application-javascript/package.json | 26 - .../application-javascript/queryAuction.js | 68 - .../application-javascript/queryBid.js | 69 - .../registerEnrollUser.js | 63 - .../application-javascript/revealBid.js | 100 - .../application-javascript/submitBid.js | 89 - auction-dutch/chaincode-go-auditor/go.mod | 28 - auction-dutch/chaincode-go-auditor/go.sum | 61 - .../smart-contract/auction.go | 440 -- .../smart-contract/auctionQueries.go | 92 - .../smart-contract/utils.go | 203 - .../chaincode-go-auditor/smartContract.go | 23 - auction-dutch/chaincode-go/go.mod | 28 - auction-dutch/chaincode-go/go.sum | 61 - .../chaincode-go/smart-contract/auction.go | 513 -- .../smart-contract/auctionQueries.go | 137 - .../chaincode-go/smart-contract/utils.go | 205 - auction-dutch/chaincode-go/smartContract.go | 23 - auction-simple/README.md | 410 -- .../application-javascript/.eslintignore | 5 - .../application-javascript/.eslintrc.js | 36 - auction-simple/application-javascript/bid.js | 101 - .../application-javascript/closeAuction.js | 93 - .../application-javascript/createAuction.js | 79 - .../application-javascript/endAuction.js | 93 - .../application-javascript/enrollAdmin.js | 67 - .../application-javascript/package.json | 22 - .../application-javascript/queryAuction.js | 72 - .../application-javascript/queryBid.js | 73 - .../registerEnrollUser.js | 68 - .../application-javascript/revealBid.js | 103 - .../application-javascript/submitBid.js | 104 - auction-simple/chaincode-go/go.mod | 28 - auction-simple/chaincode-go/go.sum | 61 - .../chaincode-go/smart-contract/auction.go | 448 -- .../smart-contract/auctionQueries.go | 137 - .../chaincode-go/smart-contract/utils.go | 121 - auction-simple/chaincode-go/smartContract.go | 23 - full-stack-asset-transfer-guide/.gitignore | 17 - full-stack-asset-transfer-guide/LICENSE | 201 - full-stack-asset-transfer-guide/README.md | 108 - full-stack-asset-transfer-guide/SETUP.md | 138 - .../applications/conga-cards/.eslintrc.js | 12 - .../applications/conga-cards/.gitignore | 18 - .../applications/conga-cards/.npmrc | 1 - .../applications/conga-cards/README.md | 73 - .../conga-cards/assets/appleplectic.png | Bin 64230 -> 0 bytes .../conga-cards/assets/bananomatopoeia.png | Bin 113103 -> 0 bytes .../conga-cards/assets/block-norris.png | Bin 63532 -> 0 bytes .../conga-cards/assets/blockbert.png | Bin 52261 -> 0 bytes .../conga-cards/assets/count-blockula.png | Bin 54899 -> 0 bytes .../conga-cards/assets/darth-conga.png | Bin 51057 -> 0 bytes .../conga-cards/assets/no-pun-intended.png | Bin 60247 -> 0 bytes .../conga-cards/assets/template.png | Bin 52421 -> 0 bytes .../conga-cards/hooks/captain-hook.json | 5 - .../conga-cards/images/interaction.png | Bin 355869 -> 0 bytes .../applications/conga-cards/package.json | 36 - .../applications/conga-cards/src/app.ts | 54 - .../conga-cards/src/commands/create.ts | 26 - .../conga-cards/src/commands/delete.ts | 20 - .../conga-cards/src/commands/discord.ts | 175 - .../conga-cards/src/commands/getAllAssets.ts | 20 - .../conga-cards/src/commands/index.ts | 24 - .../conga-cards/src/commands/read.ts | 23 - .../conga-cards/src/commands/transfer.ts | 20 - .../applications/conga-cards/src/config.ts | 45 - .../applications/conga-cards/src/connect.ts | 67 - .../applications/conga-cards/src/contract.ts | 104 - .../conga-cards/src/expectedError.ts | 12 - .../applications/conga-cards/src/utils.ts | 75 - .../applications/conga-cards/tsconfig.json | 19 - .../applications/frontend/.browserslistrc | 16 - .../applications/frontend/.editorconfig | 16 - .../applications/frontend/.gitignore | 42 - .../applications/frontend/Dockerfile | 11 - .../applications/frontend/README.md | 18 - .../applications/frontend/angular.json | 112 - .../applications/frontend/karma.conf.js | 44 - .../applications/frontend/package.json | 40 - .../frontend/screenshots/Create.png | Bin 125795 -> 0 bytes .../frontend/screenshots/list.png | Bin 109676 -> 0 bytes .../frontend/src/app/app-routing.module.ts | 10 - .../frontend/src/app/app.component.html | 66 - .../frontend/src/app/app.component.scss | 6 - .../frontend/src/app/app.component.spec.ts | 35 - .../frontend/src/app/app.component.ts | 82 - .../frontend/src/app/app.module.ts | 32 - .../asset-dialog/asset-dialog.component.html | 51 - .../asset-dialog/asset-dialog.component.scss | 3 - .../asset-dialog.component.spec.ts | 23 - .../asset-dialog/asset-dialog.component.ts | 74 - .../applications/frontend/src/app/urls.ts | 8 - .../applications/frontend/src/assets/.gitkeep | 0 .../src/environments/environment.prod.ts | 3 - .../frontend/src/environments/environment.ts | 16 - .../applications/frontend/src/favicon.ico | Bin 948 -> 0 bytes .../applications/frontend/src/index.html | 19 - .../applications/frontend/src/main.ts | 12 - .../applications/frontend/src/polyfills.ts | 53 - .../applications/frontend/src/styles.scss | 4 - .../applications/frontend/src/test.ts | 26 - .../applications/frontend/tsconfig.app.json | 15 - .../applications/frontend/tsconfig.json | 32 - .../applications/frontend/tsconfig.spec.json | 18 - .../applications/ping-chaincode/.gitignore | 2 - .../applications/ping-chaincode/app.env | 7 - .../applications/ping-chaincode/package.json | 36 - .../applications/ping-chaincode/src/app.ts | 98 - .../src/fabric-connection-profile.ts | 85 - .../ping-chaincode/src/jsonid-adapter.ts | 130 - .../applications/ping-chaincode/tsconfig.json | 17 - .../applications/rest-api/.gitignore | 2 - .../applications/rest-api/Dockerfile | 6 - .../applications/rest-api/LICENSE | 17 - .../applications/rest-api/README.md | 37 - .../asset-transfer.postman_collection.json | 145 - .../applications/rest-api/deployment.yaml | 81 - .../applications/rest-api/package.json | 38 - .../applications/rest-api/renovate.json | 5 - .../applications/rest-api/src/app.ts | 27 - .../rest-api/src/assets.router.ts | 110 - .../applications/rest-api/src/connection.ts | 102 - .../applications/rest-api/src/server.ts | 6 - .../applications/rest-api/tsconfig.json | 13 - .../applications/trader-typescript/.gitignore | 18 - .../applications/trader-typescript/.npmrc | 1 - .../applications/trader-typescript/README.md | 43 - .../trader-typescript/eslint.config.mjs | 13 - .../trader-typescript/package.json | 33 - .../applications/trader-typescript/src/app.ts | 51 - .../trader-typescript/src/commands/create.ts | 30 - .../trader-typescript/src/commands/delete.ts | 20 - .../src/commands/getAllAssets.ts | 23 - .../trader-typescript/src/commands/index.ts | 26 - .../trader-typescript/src/commands/listen.ts | 64 - .../trader-typescript/src/commands/read.ts | 23 - .../src/commands/transact.ts | 72 - .../src/commands/transfer.ts | 24 - .../trader-typescript/src/config.ts | 45 - .../trader-typescript/src/connect.ts | 67 - .../trader-typescript/src/contract.ts | 105 - .../trader-typescript/src/expectedError.ts | 12 - .../trader-typescript/src/utils.ts | 71 - .../trader-typescript/tsconfig.json | 15 - full-stack-asset-transfer-guide/check.sh | 167 - .../checks/check-chaincode.sh | 30 - .../checks/check-kube.sh | 40 - .../checks/check-network.sh | 72 - .../checks/utils.sh | 39 - .../asset-transfer-typescript/.gitignore | 18 - .../asset-transfer-typescript/.npmrc | 1 - .../asset-transfer-typescript/Dockerfile | 69 - .../asset-transfer-chaincode-vars.yml | 11 - .../docker/docker-entrypoint.sh | 21 - .../eslint.config.mjs | 13 - .../npm-shrinkwrap.json | 2274 --------- .../asset-transfer-typescript/package.json | 62 - .../asset-transfer-typescript/src/asset.ts | 41 - .../src/assetTransfer.ts | 225 - .../asset-transfer-typescript/src/index.ts | 9 - .../src/untyped.d.ts | 10 - .../asset-transfer-typescript/tsconfig.json | 17 - .../docs/ApplicationDev/01-FabricGateway.md | 76 - .../02-Exercise-RunApplication.md | 43 - .../ApplicationDev/03-ApplicationOverview.md | 132 - .../04-Exercise-AssetTransfer.md | 31 - .../docs/ApplicationDev/05-ChaincodeEvents.md | 20 - .../06-Exercise-ChaincodeEvents.md | 46 - .../docs/ApplicationDev/README.md | 10 - .../docs/CloudReady/00-setup-zh.md | 92 - .../docs/CloudReady/00-setup.md | 112 - .../docs/CloudReady/10-kube-zh.md | 67 - .../docs/CloudReady/10-kube.md | 68 - .../docs/CloudReady/11-kube-multipass.md | 110 - .../docs/CloudReady/12-kube-ec2-vm.md | 136 - .../docs/CloudReady/13-kube-public-cloud.md | 135 - .../docs/CloudReady/20-fabric-zh.md | 107 - .../docs/CloudReady/20-fabric.md | 118 - .../21-fabric-operations-console.md | 46 - .../22-fabric-ansible-collection.md | 144 - .../docs/CloudReady/30-chaincode-zh.md | 213 - .../docs/CloudReady/30-chaincode.md | 225 - .../CloudReady/31-fabric-ansible-chaincode.md | 182 - .../docs/CloudReady/40-bananas-zh.md | 150 - .../docs/CloudReady/40-bananas.md | 159 - .../CloudReady/50-OpenShift-Deployment.md | 41 - .../docs/CloudReady/90-teardown.md | 56 - .../docs/CloudReady/README.md | 15 - .../SmartContractDev/00-Introduction-ES.md | 121 - .../docs/SmartContractDev/00-Introduction.md | 119 - .../01-Exercise-Getting-Started-ES.md | 351 -- .../01-Exercise-Getting-Started.md | 351 -- .../02-Exercise-Adding-tx-function-ES.md | 52 - .../02-Exercise-Adding-tx-function.md | 52 - .../03-Test-And-Debug-Reference-ES.md | 122 - .../03-Test-And-Debug-Reference.md | 134 - .../docs/images/ApplicationDev.pptx | Bin 55266 -> 0 bytes .../fabric-gateway-deployment.png | Bin 28063 -> 0 bytes .../ApplicationDev/fabric-gateway-model.png | Bin 35408 -> 0 bytes .../ApplicationDev/legacy-sdk-model.png | Bin 34162 -> 0 bytes .../transaction-submit-flow.png | Bin 18965 -> 0 bytes .../docs/images/CloudReady.pptx | Bin 293310 -> 0 bytes .../images/CloudReady/00-cloud-ready-2.png | Bin 90315 -> 0 bytes .../docs/images/CloudReady/10-kube.png | Bin 86274 -> 0 bytes .../docs/images/CloudReady/12-kube-ec2-vm.png | Bin 95455 -> 0 bytes .../docs/images/CloudReady/20-fabric.png | Bin 116063 -> 0 bytes .../docs/images/CloudReady/30-chaincode.png | Bin 224186 -> 0 bytes .../CloudReady/40-gateway-client-app.png | Bin 168232 -> 0 bytes .../docs/images/CloudReady/kube-ec2-vm.png | Bin 71008 -> 0 bytes .../images/cloud-vm-with-operator-network.png | Bin 138856 -> 0 bytes .../images/multipass-operator-network.png | Bin 142107 -> 0 bytes .../docs/images/multipass-test-network.png | Bin 144440 -> 0 bytes .../docs/images/readme_diagram.png | Bin 218848 -> 0 bytes .../docs/tips-for-windows-dev.md | 56 - .../configuration/fabric-common-vars.yml | 23 - .../fabric-ordering-org-vars.yml | 13 - .../configuration/fabric-org1-vars.yml | 17 - .../configuration/fabric-org2-vars.yml | 17 - .../configuration/fabric-sail.yaml | 36 - .../configuration/operator-console-vars.yml | 39 - .../infrastructure/ec2-cloud-config.yaml | 59 - .../fabric_network_playbooks/00-complete.yml | 22 - ...reate-ordering-organization-components.yml | 16 - ...eate-endorsing-organization-components.yml | 18 - .../05-enable-capabilities.yml | 84 - .../06-add-organization-to-consortium.yml | 89 - .../09-admins-policy.json.j2 | 24 - .../09-create-channel.yml | 79 - .../09-endorsement-policy.json.j2 | 24 - .../09-lifecycle-endorsement-policy.json.j2 | 24 - .../09-readers-policy.json.j2 | 24 - .../09-writers-policy.json.j2 | 24 - .../10-join-peer-to-channel.yml | 39 - .../11-add-anchor-peer-to-channel.yml | 91 - ...eate-endorsing-organization-components.yml | 18 - .../15-add-organization-to-channel.yml | 124 - .../15-admins-policy.json.j2 | 34 - .../15-endorsement-policy.json.j2 | 34 - .../15-lifecycle-endorsement-policy.json.j2 | 34 - .../15-readers-policy.json.j2 | 34 - .../15-writers-policy.json.j2 | 34 - .../16-import-ordering-service.yml | 18 - .../17-join-peer-to-channel.yml | 39 - .../18-add-anchor-peer-to-channel.yml | 91 - .../kind_console_ingress/90-KIND-ingress.yml | 37 - .../templates/coredns/coredns.yaml.j2 | 33 - .../ingress/ingress-nginx-controller.yaml | 39 - .../templates/ingress/kustomization.yaml | 36 - .../infrastructure/kind_with_nginx.sh | 191 - .../multipass-cloud-config.yaml | 133 - .../01-operator-install.yml | 13 - .../02-console-install.yml | 13 - .../infrastructure/pkgcc.sh | 103 - .../19-install-and-approve-chaincode.yml | 44 - .../20-install-and-approve-chaincode.yml | 44 - .../21-commit-chaincode.yml | 33 - .../22-register-application.yml | 57 - .../asset-transfer_appid.json | 7 - .../infrastructure/sample-network/.gitignore | 4 - .../config/cas/kustomization.yaml | 25 - .../sample-network/config/cas/org0-ca.yaml | 135 - .../sample-network/config/cas/org1-ca.yaml | 128 - .../sample-network/config/cas/org2-ca.yaml | 130 - .../config/configtx-template.yaml | 428 -- .../console/hlf-operations-console.yaml | 80 - .../config/console/kustomization.yaml | 5 - .../sample-network/config/core.yaml | 775 --- .../config/gateway/kustomization.yaml | 24 - .../config/gateway/org1-peer-gateway.yaml | 76 - .../config/gateway/org2-peer-gateway.yaml | 76 - .../manager/fabric-operator-manager.yaml | 123 - .../config/manager/kustomization.yaml | 22 - .../config/orderers/kustomization.yaml | 24 - .../config/orderers/org0-orderers.yaml | 151 - .../config/peers/kustomization.yaml | 27 - .../config/peers/org1-peer1.yaml | 103 - .../config/peers/org1-peer2.yaml | 103 - .../config/peers/org2-peer1.yaml | 103 - .../config/peers/org2-peer2.yaml | 103 - .../rbac/fabric-operator-clusterrole.yaml | 197 - .../fabric-operator-clusterrolebinding.yaml | 36 - .../rbac/fabric-operator-serviceaccount.yaml | 22 - .../config/rbac/kustomization.yaml | 24 - .../infrastructure/sample-network/network | 198 - .../sample-network/scripts/channel.sh | 269 - .../sample-network/scripts/console.sh | 50 - .../sample-network/scripts/frontend_build.sh | 16 - .../scripts/frontend_deployment.yaml | 67 - .../sample-network/scripts/prereqs.sh | 58 - .../scripts/rest_deployment.yaml | 72 - .../sample-network/scripts/rest_sample.sh | 47 - .../sample-network/scripts/sample_network.sh | 200 - .../sample-network/scripts/utils.sh | 158 - .../infrastructure/setup_storage_classes.sh | 45 - full-stack-asset-transfer-guide/justfile | 521 -- .../tests/00-chaincode-e2e.sh | 12 - .../tests/10-appdev-e2e.sh | 56 - .../tests/20-cloud-e2e.sh | 438 -- .../tests/30-ansible-e2e.sh | 113 - .../tests/40-console.sh | 88 - hardware-security-module/.gitignore | 1 - hardware-security-module/README.md | 122 - .../application-go/go.mod | 19 - .../application-go/go.sum | 32 - .../application-go/hsm-sample.go | 217 - .../application-typescript/.gitignore | 3 - .../application-typescript/eslint.config.mjs | 13 - .../application-typescript/package.json | 33 - .../application-typescript/src/hsm-sample.ts | 174 - .../application-typescript/tsconfig.json | 15 - .../ca-client-config/.gitignore | 1 - .../fabric-ca-client-config-template.yaml | 168 - .../scripts/generate-hsm-user.sh | 82 - high-throughput/README.md | 201 - high-throughput/application-go/.gitignore | 4 - high-throughput/application-go/app.go | 70 - .../application-go/functions/deletePrune.go | 69 - .../application-go/functions/manyUpdates.go | 86 - .../application-go/functions/query.go | 69 - .../application-go/functions/update.go | 74 - .../application-go/functions/util.go | 55 - high-throughput/application-go/go.mod | 50 - high-throughput/application-go/go.sum | 239 - high-throughput/chaincode-go/go.mod | 18 - high-throughput/chaincode-go/go.sum | 33 - .../chaincode-go/high-throughput.go | 396 -- high-throughput/networkDown.sh | 17 - high-throughput/startFabric.sh | 28 - off_chain_data/README.md | 115 - off_chain_data/application-java/.gitignore | 15 - .../application-java/app/build.gradle | 38 - off_chain_data/application-java/app/pom.xml | 101 - .../app/src/main/java/App.java | 76 - .../app/src/main/java/Asset.java | 57 - .../app/src/main/java/AssetTransferBasic.java | 51 - .../app/src/main/java/BlockProcessor.java | 74 - .../app/src/main/java/Command.java | 11 - .../app/src/main/java/Connections.java | 117 - .../app/src/main/java/ExpectedException.java | 11 - .../app/src/main/java/GetAllAssets.java | 37 - .../app/src/main/java/Listen.java | 80 - .../app/src/main/java/Store.java | 13 - .../app/src/main/java/Transact.java | 27 - .../app/src/main/java/TransactApp.java | 77 - .../src/main/java/TransactionProcessor.java | 70 - .../app/src/main/java/Utils.java | 58 - .../app/src/main/java/Write.java | 68 - .../app/src/main/java/parser/Block.java | 17 - .../app/src/main/java/parser/BlockParser.java | 15 - .../java/parser/NamespaceReadWriteSet.java | 17 - .../app/src/main/java/parser/ParsedBlock.java | 76 - .../src/main/java/parser/ParsedPayload.java | 52 - .../main/java/parser/ParsedReadWriteSet.java | 51 - .../main/java/parser/ParsedTransaction.java | 89 - .../java/parser/ParsedTransactionAction.java | 48 - .../app/src/main/java/parser/Transaction.java | 24 - .../app/src/main/java/parser/Utils.java | 51 - .../config/checkstyle/checkstyle.xml | 197 - .../checkstyle/java-copyright-header.txt | 5 - .../gradle/wrapper/gradle-wrapper.jar | Bin 43462 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - off_chain_data/application-java/gradlew | 249 - off_chain_data/application-java/gradlew.bat | 92 - .../application-java/settings.gradle | 8 - .../application-typescript/.gitignore | 17 - off_chain_data/application-typescript/.npmrc | 1 - .../application-typescript/eslint.config.mjs | 13 - .../application-typescript/package.json | 33 - .../application-typescript/src/app.ts | 57 - .../application-typescript/src/blockParser.ts | 229 - .../application-typescript/src/connect.ts | 82 - .../application-typescript/src/contract.ts | 54 - .../src/expectedError.ts | 12 - .../src/getAllAssets.ts | 30 - .../application-typescript/src/listen.ts | 254 - .../application-typescript/src/transact.ts | 77 - .../application-typescript/src/utils.ts | 76 - .../application-typescript/tsconfig.json | 15 - test-application/javascript/AppUtil.js | 66 - test-application/javascript/CAUtil.js | 98 - test-network-k8s/.gitignore | 7 - test-network-k8s/README.md | 117 - .../config/org0/configtx-template.yaml | 415 -- .../config/org0/fabric-ca-server-config.yaml | 506 -- test-network-k8s/config/org0/orderer.yaml | 420 -- test-network-k8s/config/org1/core.yaml | 766 --- .../config/org1/fabric-ca-server-config.yaml | 506 -- .../config/org2/fabric-ca-server-config.yaml | 506 -- test-network-k8s/docs/APPLICATIONS.md | 106 - test-network-k8s/docs/CA.md | 198 - test-network-k8s/docs/CALIPER.md | 205 - test-network-k8s/docs/CHAINCODE.md | 217 - .../docs/CHAINCODE_AS_A_SERVICE.md | 171 - test-network-k8s/docs/CHANNELS.md | 150 - test-network-k8s/docs/HIGH_AVAILABILITY.md | 71 - test-network-k8s/docs/KUBERNETES.md | 261 - test-network-k8s/docs/README.md | 47 - test-network-k8s/docs/TEST_NETWORK.md | 183 - test-network-k8s/docs/images/test-network.png | Bin 225031 -> 0 bytes .../kube/application-deployment.yaml | 48 - .../kube/fabric-builder-role.yaml | 27 - .../kube/fabric-builder-rolebinding.yaml | 18 - test-network-k8s/kube/fabric-rest-sample.yaml | 261 - test-network-k8s/kube/ingress-nginx-k3s.yaml | 683 --- test-network-k8s/kube/ingress-nginx-kind.yaml | 694 --- test-network-k8s/kube/ns-test-network.yaml | 10 - test-network-k8s/kube/org0/org0-ca.yaml | 124 - .../org0/org0-job-scrub-fabric-volumes.yaml | 32 - test-network-k8s/kube/org0/org0-orderer1.yaml | 159 - test-network-k8s/kube/org0/org0-orderer2.yaml | 159 - test-network-k8s/kube/org0/org0-orderer3.yaml | 159 - .../kube/org0/org0-tls-cert-issuer.yaml | 34 - test-network-k8s/kube/org1/org1-ca.yaml | 124 - .../kube/org1/org1-cc-template.yaml | 46 - .../kube/org1/org1-install-k8s-builder.yaml | 34 - .../org1/org1-job-scrub-fabric-volumes.yaml | 32 - test-network-k8s/kube/org1/org1-peer1.yaml | 184 - test-network-k8s/kube/org1/org1-peer2.yaml | 161 - .../kube/org1/org1-tls-cert-issuer.yaml | 32 - test-network-k8s/kube/org2/org2-ca.yaml | 124 - .../kube/org2/org2-cc-template.yaml | 46 - .../kube/org2/org2-install-k8s-builder.yaml | 34 - .../org2/org2-job-scrub-fabric-volumes.yaml | 33 - test-network-k8s/kube/org2/org2-peer1.yaml | 184 - test-network-k8s/kube/org2/org2-peer2.yaml | 159 - .../kube/org2/org2-tls-cert-issuer.yaml | 32 - test-network-k8s/kube/pvc-fabric-org0.yaml | 17 - test-network-k8s/kube/pvc-fabric-org1.yaml | 17 - test-network-k8s/kube/pvc-fabric-org2.yaml | 17 - .../kube/root-tls-cert-issuer.yaml | 12 - test-network-k8s/network | 171 - .../scripts/application_connection.sh | 124 - test-network-k8s/scripts/appuser.id.template | 9 - test-network-k8s/scripts/ccp-template.json | 49 - test-network-k8s/scripts/chaincode.sh | 399 -- test-network-k8s/scripts/channel.sh | 276 -- test-network-k8s/scripts/cluster.sh | 145 - test-network-k8s/scripts/fabric_CAs.sh | 81 - test-network-k8s/scripts/fabric_config.sh | 82 - test-network-k8s/scripts/kind.sh | 142 - test-network-k8s/scripts/prereqs.sh | 92 - test-network-k8s/scripts/rest_sample.sh | 82 - test-network-k8s/scripts/set_anchor_peer.sh | 110 - test-network-k8s/scripts/test_network.sh | 204 - test-network-k8s/scripts/utils.sh | 114 - test-network-nano-bash/.gitignore | 7 - test-network-nano-bash/README.md | 247 - .../bft-config/configtx.yaml | 320 -- .../ca_config/ca/fabric-ca-server-config.yaml | 511 -- .../tlsca/fabric-ca-server-config.yaml | 494 -- test-network-nano-bash/ca/ca_utils.sh | 117 - test-network-nano-bash/ca/config.yaml | 14 - .../ca/createEnrollments.sh | 118 - test-network-nano-bash/ca_terminal_setup.png | Bin 61294 -> 0 bytes .../chaincode-external/connection.json | 5 - .../chaincode-external/metadata.json | 4 - .../chaincode_interaction.sh | 13 - test-network-nano-bash/configtx.yaml | 298 -- .../configureExternalBuilders.sh | 6 - test-network-nano-bash/crypto-config.yaml | 54 - .../external_builders/core_yaml_change.yaml | 12 - .../external_builders/golang/bin/build | 16 - .../external_builders/golang/bin/detect | 11 - .../external_builders/golang/bin/release | 12 - .../external_builders/golang/bin/run | 56 - .../external_builders/node/bin/build | 17 - .../external_builders/node/bin/detect | 11 - .../external_builders/node/bin/release | 11 - .../external_builders/node/bin/run | 58 - test-network-nano-bash/generate_artifacts.sh | 69 - .../install&approve&commit_chaincode_peer1.sh | 22 - test-network-nano-bash/join_channel.sh | 8 - test-network-nano-bash/join_orderers.sh | 28 - test-network-nano-bash/network.sh | 187 - test-network-nano-bash/orderer1.sh | 38 - test-network-nano-bash/orderer2.sh | 38 - test-network-nano-bash/orderer3.sh | 38 - test-network-nano-bash/orderer4.sh | 38 - test-network-nano-bash/ordererca.sh | 39 - test-network-nano-bash/org1ca.sh | 39 - test-network-nano-bash/org2ca.sh | 39 - test-network-nano-bash/peer1.sh | 50 - test-network-nano-bash/peer1admin.sh | 15 - test-network-nano-bash/peer2.sh | 50 - test-network-nano-bash/peer2admin.sh | 15 - test-network-nano-bash/peer3.sh | 50 - test-network-nano-bash/peer3admin.sh | 15 - test-network-nano-bash/peer4.sh | 50 - test-network-nano-bash/peer4admin.sh | 15 - test-network-nano-bash/terminal_setup.png | Bin 167149 -> 0 bytes .../config/org2 => test-network}/core.yaml | 101 +- token-erc-1155/README.md | 276 -- .../chaincode-go/chaincode/contract.go | 1161 ----- token-erc-1155/chaincode-go/erc1155.go | 27 - token-erc-1155/chaincode-go/go.mod | 26 - token-erc-1155/chaincode-go/go.sum | 61 - token-erc-20/README.md | 466 -- .../chaincode-go/chaincode/token_contract.go | 733 --- token-erc-20/chaincode-go/go.mod | 26 - token-erc-20/chaincode-go/go.sum | 61 - token-erc-20/chaincode-go/token_erc_20.go | 23 - token-erc-20/chaincode-java/Dockerfile | 32 - token-erc-20/chaincode-java/build.gradle | 94 - .../config/checkstyle/checkstyle.xml | 171 - .../config/checkstyle/suppressions.xml | 10 - .../docker/docker-entrypoint.sh | 16 - .../gradle/wrapper/gradle-wrapper.jar | Bin 43462 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - token-erc-20/chaincode-java/gradlew | 249 - token-erc-20/chaincode-java/gradlew.bat | 92 - token-erc-20/chaincode-java/settings.gradle | 5 - .../samples/erc20/ContractConstants.java | 28 - .../fabric/samples/erc20/ContractErrors.java | 19 - .../samples/erc20/ERC20TokenContract.java | 526 -- .../fabric/samples/erc20/model/Approval.java | 58 - .../fabric/samples/erc20/model/Transfer.java | 58 - .../samples/erc20/utils/ContractUtility.java | 19 - .../samples/erc20/TokenERC20ContractTest.java | 590 --- .../org.mockito.plugins.MockMaker | 1 - .../chaincode-javascript/.editorconfig | 16 - .../chaincode-javascript/.eslintignore | 5 - .../chaincode-javascript/.eslintrc.js | 39 - token-erc-20/chaincode-javascript/.gitignore | 78 - token-erc-20/chaincode-javascript/index.js | 12 - .../chaincode-javascript/lib/tokenERC20.js | 503 -- .../chaincode-javascript/npm-shrinkwrap.json | 4396 ----------------- .../chaincode-javascript/package.json | 51 - .../test/tokenERC20.test.js | 296 -- token-erc-721/README.md | 477 -- .../chaincode-go/chaincode/erc721-contract.go | 789 --- .../chaincode/erc721-contract_test.go | 282 -- .../chaincode-go/chaincode/erc721.go | 25 - token-erc-721/chaincode-go/go.mod | 32 - token-erc-721/chaincode-go/go.sum | 61 - token-erc-721/chaincode-go/main.go | 35 - token-erc-721/chaincode-java/Dockerfile | 30 - token-erc-721/chaincode-java/build.gradle | 97 - .../config/checkstyle/checkstyle.xml | 174 - .../config/checkstyle/suppressions.xml | 13 - .../docker/docker-entrypoint.sh | 16 - .../gradle/wrapper/gradle-wrapper.jar | Bin 43462 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - token-erc-721/chaincode-java/gradlew | 249 - token-erc-721/chaincode-java/gradlew.bat | 92 - token-erc-721/chaincode-java/settings.gradle | 5 - .../samples/erc721/ContractConstants.java | 24 - .../fabric/samples/erc721/ContractErrors.java | 13 - .../samples/erc721/ERC721TokenContract.java | 491 -- .../samples/erc721/models/Approval.java | 108 - .../fabric/samples/erc721/models/NFT.java | 122 - .../samples/erc721/models/Transfer.java | 91 - .../samples/erc721/utils/ContractUtility.java | 19 - .../erc721/ERC721TokenContractTest.java | 507 -- .../org.mockito.plugins.MockMaker | 1 - .../chaincode-javascript/.editorconfig | 16 - .../chaincode-javascript/.eslintignore | 5 - .../chaincode-javascript/.eslintrc.js | 39 - token-erc-721/chaincode-javascript/.gitignore | 78 - token-erc-721/chaincode-javascript/index.js | 10 - .../chaincode-javascript/lib/tokenERC721.js | 464 -- .../chaincode-javascript/npm-shrinkwrap.json | 4396 ----------------- .../chaincode-javascript/package.json | 51 - .../test/tokenERC721.test.js | 338 -- token-sdk/.dockerignore | 1 - token-sdk/.gitignore | 8 - token-sdk/Dockerfile | 19 - token-sdk/README.md | 413 -- token-sdk/auditor/conf/core.yaml | 112 - token-sdk/auditor/go.mod | 245 - token-sdk/auditor/go.sum | 2020 -------- token-sdk/auditor/main.go | 114 - token-sdk/auditor/oapi-server.yaml | 11 - token-sdk/auditor/routes/operations.go | 31 - token-sdk/auditor/routes/routes.gen.go | 579 --- token-sdk/auditor/routes/routes.go | 100 - token-sdk/auditor/routes/server.go | 65 - token-sdk/auditor/service/audit.go | 68 - token-sdk/auditor/service/balance.go | 51 - token-sdk/auditor/service/history.go | 105 - token-sdk/components.png | Bin 34856 -> 0 bytes token-sdk/compose-ca.yaml | 23 - token-sdk/dependencies.png | Bin 29381 -> 0 bytes token-sdk/docker-compose.yaml | 101 - token-sdk/e2e/client.gen.go | 1591 ------ token-sdk/e2e/e2e_test.go | 249 - token-sdk/e2e/go.mod | 79 - token-sdk/e2e/go.sum | 258 - token-sdk/e2e/oapi-client.yaml | 5 - token-sdk/explorer/.env | 4 - token-sdk/explorer/config.json | 9 - .../connection-profile/test-network.json | 48 - token-sdk/explorer/docker-compose.yaml | 63 - token-sdk/go.work | 8 - token-sdk/go.work.sum | 285 -- token-sdk/issuer/conf/core.yaml | 116 - token-sdk/issuer/go.mod | 245 - token-sdk/issuer/go.sum | 2020 -------- token-sdk/issuer/main.go | 108 - token-sdk/issuer/oapi-server.yaml | 11 - token-sdk/issuer/routes/operations.go | 31 - token-sdk/issuer/routes/routes.gen.go | 448 -- token-sdk/issuer/routes/routes.go | 49 - token-sdk/issuer/routes/server.go | 65 - token-sdk/issuer/service/issue.go | 158 - token-sdk/owner/conf/owner1/core.yaml | 119 - token-sdk/owner/conf/owner2/core.yaml | 119 - token-sdk/owner/go.mod | 245 - token-sdk/owner/go.sum | 2020 -------- token-sdk/owner/main.go | 114 - token-sdk/owner/oapi-server.yaml | 11 - token-sdk/owner/routes/operations.go | 33 - token-sdk/owner/routes/routes.gen.go | 897 ---- token-sdk/owner/routes/routes.go | 191 - token-sdk/owner/routes/server.go | 65 - token-sdk/owner/service/accept.go | 83 - token-sdk/owner/service/balance.go | 69 - token-sdk/owner/service/history.go | 93 - token-sdk/owner/service/redeem.go | 130 - token-sdk/owner/service/transfer.go | 159 - token-sdk/scripts/down.sh | 21 - token-sdk/scripts/enroll-users.sh | 39 - token-sdk/scripts/up.sh | 48 - token-sdk/swagger.yaml | 519 -- token-sdk/tokenchaincode/Dockerfile | 22 - token-sdk/transfer.png | Bin 79460 -> 0 bytes token-utxo/README.md | 231 - .../chaincode-go/chaincode/token_contract.go | 379 -- token-utxo/chaincode-go/go.mod | 26 - token-utxo/chaincode-go/go.sum | 61 - token-utxo/chaincode-go/token_utxo.go | 23 - 907 files changed, 819 insertions(+), 120196 deletions(-) create mode 100644 StudentDBInit.txt delete mode 100644 asset-transfer-abac/README.md delete mode 100644 asset-transfer-abac/chaincode-go/go.mod delete mode 100644 asset-transfer-abac/chaincode-go/go.sum delete mode 100644 asset-transfer-abac/chaincode-go/smart-contract/abac.go delete mode 100644 asset-transfer-abac/chaincode-go/smartContract.go delete mode 100755 asset-transfer-basic/application-gateway-go/assetTransfer.go delete mode 100644 asset-transfer-basic/application-gateway-go/go.mod delete mode 100644 asset-transfer-basic/application-gateway-go/go.sum delete mode 100644 asset-transfer-basic/application-gateway-java/build.gradle delete mode 100644 asset-transfer-basic/application-gateway-java/gradle/wrapper/gradle-wrapper.jar delete mode 100644 asset-transfer-basic/application-gateway-java/gradle/wrapper/gradle-wrapper.properties delete mode 100755 asset-transfer-basic/application-gateway-java/gradlew delete mode 100644 asset-transfer-basic/application-gateway-java/gradlew.bat delete mode 100644 asset-transfer-basic/application-gateway-java/pom.xml delete mode 100644 asset-transfer-basic/application-gateway-java/settings.gradle delete mode 100644 asset-transfer-basic/application-gateway-java/src/main/java/App.java delete mode 100644 asset-transfer-basic/application-gateway-javascript/.gitignore delete mode 100644 asset-transfer-basic/application-gateway-javascript/.npmrc delete mode 100644 asset-transfer-basic/application-gateway-javascript/eslint.config.mjs delete mode 100644 asset-transfer-basic/application-gateway-javascript/package.json delete mode 100644 asset-transfer-basic/application-gateway-javascript/src/app.js delete mode 100644 asset-transfer-basic/application-gateway-typescript/.gitignore delete mode 100644 asset-transfer-basic/application-gateway-typescript/.npmrc delete mode 100644 asset-transfer-basic/application-gateway-typescript/eslint.config.mjs delete mode 100644 asset-transfer-basic/application-gateway-typescript/package.json delete mode 100644 asset-transfer-basic/application-gateway-typescript/src/app.ts delete mode 100644 asset-transfer-basic/application-gateway-typescript/tsconfig.json delete mode 100644 asset-transfer-basic/chaincode-external/.dockerignore delete mode 100644 asset-transfer-basic/chaincode-external/.gitignore delete mode 100644 asset-transfer-basic/chaincode-external/Dockerfile delete mode 100755 asset-transfer-basic/chaincode-external/README.md delete mode 100644 asset-transfer-basic/chaincode-external/assetTransfer.go delete mode 100644 asset-transfer-basic/chaincode-external/chaincode.env delete mode 100644 asset-transfer-basic/chaincode-external/chaincode1.env delete mode 100644 asset-transfer-basic/chaincode-external/chaincode2.env delete mode 100644 asset-transfer-basic/chaincode-external/connection.json delete mode 100644 asset-transfer-basic/chaincode-external/crypto/.gitkeep delete mode 100644 asset-transfer-basic/chaincode-external/docker-compose-chaincode.yaml delete mode 100644 asset-transfer-basic/chaincode-external/go.mod delete mode 100644 asset-transfer-basic/chaincode-external/go.sum delete mode 100644 asset-transfer-basic/chaincode-external/metadata.json delete mode 100755 asset-transfer-basic/chaincode-external/sampleBuilder/bin/build delete mode 100755 asset-transfer-basic/chaincode-external/sampleBuilder/bin/detect delete mode 100755 asset-transfer-basic/chaincode-external/sampleBuilder/bin/release delete mode 100644 asset-transfer-basic/chaincode-go/assetTransfer.go delete mode 100644 asset-transfer-basic/chaincode-go/chaincode/mocks/chaincodestub.go delete mode 100644 asset-transfer-basic/chaincode-go/chaincode/mocks/statequeryiterator.go delete mode 100644 asset-transfer-basic/chaincode-go/chaincode/mocks/transaction.go delete mode 100644 asset-transfer-basic/chaincode-go/chaincode/smartcontract.go delete mode 100644 asset-transfer-basic/chaincode-go/chaincode/smartcontract_test.go delete mode 100644 asset-transfer-basic/chaincode-go/go.mod delete mode 100644 asset-transfer-basic/chaincode-go/go.sum delete mode 100644 asset-transfer-basic/chaincode-java/.gitattributes delete mode 100644 asset-transfer-basic/chaincode-java/.gitignore delete mode 100755 asset-transfer-basic/chaincode-java/Dockerfile delete mode 100644 asset-transfer-basic/chaincode-java/README.md delete mode 100644 asset-transfer-basic/chaincode-java/build.gradle delete mode 100644 asset-transfer-basic/chaincode-java/config/checkstyle/checkstyle.xml delete mode 100644 asset-transfer-basic/chaincode-java/config/checkstyle/suppressions.xml delete mode 100755 asset-transfer-basic/chaincode-java/docker/docker-entrypoint.sh delete mode 100644 asset-transfer-basic/chaincode-java/gradle/wrapper/gradle-wrapper.jar delete mode 100644 asset-transfer-basic/chaincode-java/gradle/wrapper/gradle-wrapper.properties delete mode 100755 asset-transfer-basic/chaincode-java/gradlew delete mode 100644 asset-transfer-basic/chaincode-java/gradlew.bat delete mode 100644 asset-transfer-basic/chaincode-java/settings.gradle delete mode 100644 asset-transfer-basic/chaincode-java/src/main/java/org/hyperledger/fabric/samples/assettransfer/Asset.java delete mode 100644 asset-transfer-basic/chaincode-java/src/main/java/org/hyperledger/fabric/samples/assettransfer/AssetTransfer.java delete mode 100644 asset-transfer-basic/chaincode-java/src/test/java/org/hyperledger/fabric/samples/assettransfer/AssetTest.java delete mode 100644 asset-transfer-basic/chaincode-java/src/test/java/org/hyperledger/fabric/samples/assettransfer/AssetTransferTest.java delete mode 100644 asset-transfer-basic/chaincode-javascript/.eslintignore delete mode 100644 asset-transfer-basic/chaincode-javascript/.eslintrc.js delete mode 100644 asset-transfer-basic/chaincode-javascript/.gitignore delete mode 100644 asset-transfer-basic/chaincode-javascript/index.js delete mode 100644 asset-transfer-basic/chaincode-javascript/lib/assetTransfer.js delete mode 100644 asset-transfer-basic/chaincode-javascript/npm-shrinkwrap.json delete mode 100644 asset-transfer-basic/chaincode-javascript/package.json delete mode 100644 asset-transfer-basic/chaincode-javascript/test/assetTransfer.test.js delete mode 100644 asset-transfer-basic/chaincode-typescript/src/asset.ts delete mode 100644 asset-transfer-basic/chaincode-typescript/src/assetTransfer.ts create mode 100644 asset-transfer-basic/chaincode-typescript/src/assetTransferCustom.ts create mode 100644 asset-transfer-basic/chaincode-typescript/src/customAsset.ts delete mode 100644 asset-transfer-basic/rest-api-go/.gitignore delete mode 100644 asset-transfer-basic/rest-api-go/README.md delete mode 100644 asset-transfer-basic/rest-api-go/go.mod delete mode 100644 asset-transfer-basic/rest-api-go/go.sum delete mode 100644 asset-transfer-basic/rest-api-go/main.go delete mode 100644 asset-transfer-basic/rest-api-go/web/app.go delete mode 100644 asset-transfer-basic/rest-api-go/web/initialize.go delete mode 100644 asset-transfer-basic/rest-api-go/web/invoke.go delete mode 100644 asset-transfer-basic/rest-api-go/web/query.go delete mode 100644 asset-transfer-events/README.md delete mode 100755 asset-transfer-events/application-gateway-go/app.go delete mode 100755 asset-transfer-events/application-gateway-go/connect.go delete mode 100644 asset-transfer-events/application-gateway-go/go.mod delete mode 100644 asset-transfer-events/application-gateway-go/go.sum delete mode 100644 asset-transfer-events/application-gateway-java/build.gradle delete mode 100644 asset-transfer-events/application-gateway-java/gradle/wrapper/gradle-wrapper.jar delete mode 100644 asset-transfer-events/application-gateway-java/gradle/wrapper/gradle-wrapper.properties delete mode 100755 asset-transfer-events/application-gateway-java/gradlew delete mode 100644 asset-transfer-events/application-gateway-java/gradlew.bat delete mode 100644 asset-transfer-events/application-gateway-java/pom.xml delete mode 100644 asset-transfer-events/application-gateway-java/settings.gradle delete mode 100644 asset-transfer-events/application-gateway-java/src/main/java/App.java delete mode 100644 asset-transfer-events/application-gateway-java/src/main/java/Connections.java delete mode 100644 asset-transfer-events/application-gateway-typescript/.gitignore delete mode 100644 asset-transfer-events/application-gateway-typescript/.npmrc delete mode 100644 asset-transfer-events/application-gateway-typescript/eslint.config.mjs delete mode 100755 asset-transfer-events/application-gateway-typescript/package.json delete mode 100755 asset-transfer-events/application-gateway-typescript/src/app.ts delete mode 100644 asset-transfer-events/application-gateway-typescript/src/connect.ts delete mode 100644 asset-transfer-events/application-gateway-typescript/tsconfig.json delete mode 100644 asset-transfer-events/chaincode-go/assetTransferEvents.go delete mode 100644 asset-transfer-events/chaincode-go/chaincode/smartcontract.go delete mode 100644 asset-transfer-events/chaincode-go/go.mod delete mode 100644 asset-transfer-events/chaincode-go/go.sum delete mode 100644 asset-transfer-events/chaincode-java/build.gradle delete mode 100644 asset-transfer-events/chaincode-java/config/checkstyle/checkstyle.xml delete mode 100644 asset-transfer-events/chaincode-java/config/checkstyle/suppressions.xml delete mode 100644 asset-transfer-events/chaincode-java/gradle/wrapper/gradle-wrapper.jar delete mode 100644 asset-transfer-events/chaincode-java/gradle/wrapper/gradle-wrapper.properties delete mode 100755 asset-transfer-events/chaincode-java/gradlew delete mode 100644 asset-transfer-events/chaincode-java/gradlew.bat delete mode 100644 asset-transfer-events/chaincode-java/settings.gradle delete mode 100644 asset-transfer-events/chaincode-java/src/main/java/org/hyperledger/fabric/samples/events/Asset.java delete mode 100644 asset-transfer-events/chaincode-java/src/main/java/org/hyperledger/fabric/samples/events/AssetTransfer.java delete mode 100644 asset-transfer-events/chaincode-javascript/.eslintignore delete mode 100644 asset-transfer-events/chaincode-javascript/.eslintrc.js delete mode 100644 asset-transfer-events/chaincode-javascript/.gitignore delete mode 100644 asset-transfer-events/chaincode-javascript/index.js delete mode 100644 asset-transfer-events/chaincode-javascript/lib/assetTransferEvents.js delete mode 100644 asset-transfer-events/chaincode-javascript/npm-shrinkwrap.json delete mode 100644 asset-transfer-events/chaincode-javascript/package.json delete mode 100644 asset-transfer-events/chaincode-javascript/test/assetTransferEvents.test.js delete mode 100644 asset-transfer-ledger-queries/application-java/.gitattributes delete mode 100644 asset-transfer-ledger-queries/application-java/build.gradle delete mode 100644 asset-transfer-ledger-queries/application-java/gradle/wrapper/gradle-wrapper.jar delete mode 100644 asset-transfer-ledger-queries/application-java/gradle/wrapper/gradle-wrapper.properties delete mode 100755 asset-transfer-ledger-queries/application-java/gradlew delete mode 100644 asset-transfer-ledger-queries/application-java/gradlew.bat delete mode 100644 asset-transfer-ledger-queries/application-java/settings.gradle delete mode 100644 asset-transfer-ledger-queries/application-java/src/main/java/application/java/App.java delete mode 100644 asset-transfer-ledger-queries/application-java/src/main/java/application/java/EnrollAdmin.java delete mode 100644 asset-transfer-ledger-queries/application-java/src/main/java/application/java/RegisterUser.java delete mode 100644 asset-transfer-ledger-queries/application-java/src/main/resources/log4j.properties delete mode 100644 asset-transfer-ledger-queries/application-javascript/.eslintignore delete mode 100644 asset-transfer-ledger-queries/application-javascript/.eslintrc.js delete mode 100644 asset-transfer-ledger-queries/application-javascript/.gitignore delete mode 100644 asset-transfer-ledger-queries/application-javascript/app.js delete mode 100644 asset-transfer-ledger-queries/application-javascript/package.json delete mode 100644 asset-transfer-ledger-queries/chaincode-go/META-INF/statedb/couchdb/indexes/indexOwner.json delete mode 100644 asset-transfer-ledger-queries/chaincode-go/asset_transfer_ledger_chaincode.go delete mode 100644 asset-transfer-ledger-queries/chaincode-go/go.mod delete mode 100644 asset-transfer-ledger-queries/chaincode-go/go.sum delete mode 100644 asset-transfer-ledger-queries/chaincode-javascript/.eslintignore delete mode 100644 asset-transfer-ledger-queries/chaincode-javascript/.eslintrc.js delete mode 100644 asset-transfer-ledger-queries/chaincode-javascript/META-INF/statedb/couchdb/indexes/indexOwner.json delete mode 100644 asset-transfer-ledger-queries/chaincode-javascript/index.js delete mode 100644 asset-transfer-ledger-queries/chaincode-javascript/lib/asset_transfer_ledger_chaincode.js delete mode 100644 asset-transfer-ledger-queries/chaincode-javascript/npm-shrinkwrap.json delete mode 100644 asset-transfer-ledger-queries/chaincode-javascript/package.json delete mode 100644 asset-transfer-private-data/README.md delete mode 100644 asset-transfer-private-data/application-gateway-go/app.go delete mode 100644 asset-transfer-private-data/application-gateway-go/connect.go delete mode 100644 asset-transfer-private-data/application-gateway-go/go.mod delete mode 100644 asset-transfer-private-data/application-gateway-go/go.sum delete mode 100644 asset-transfer-private-data/application-gateway-typescript/.gitignore delete mode 100644 asset-transfer-private-data/application-gateway-typescript/.npmrc delete mode 100644 asset-transfer-private-data/application-gateway-typescript/README.md delete mode 100644 asset-transfer-private-data/application-gateway-typescript/eslint.config.mjs delete mode 100644 asset-transfer-private-data/application-gateway-typescript/package.json delete mode 100644 asset-transfer-private-data/application-gateway-typescript/src/app.ts delete mode 100644 asset-transfer-private-data/application-gateway-typescript/src/connect.ts delete mode 100644 asset-transfer-private-data/application-gateway-typescript/tsconfig.json delete mode 100644 asset-transfer-private-data/chaincode-go/META-INF/statedb/couchdb/collections/assetCollection/indexes/indexOwner.json delete mode 100644 asset-transfer-private-data/chaincode-go/README.md delete mode 100644 asset-transfer-private-data/chaincode-go/chaincode/asset_queries.go delete mode 100644 asset-transfer-private-data/chaincode-go/chaincode/asset_queries_test.go delete mode 100644 asset-transfer-private-data/chaincode-go/chaincode/asset_transfer.go delete mode 100644 asset-transfer-private-data/chaincode-go/chaincode/asset_transfer_test.go delete mode 100644 asset-transfer-private-data/chaincode-go/chaincode/mocks/chaincodestub.go delete mode 100644 asset-transfer-private-data/chaincode-go/chaincode/mocks/clientIdentity.go delete mode 100644 asset-transfer-private-data/chaincode-go/chaincode/mocks/statequeryiterator.go delete mode 100644 asset-transfer-private-data/chaincode-go/chaincode/mocks/transaction.go delete mode 100644 asset-transfer-private-data/chaincode-go/collections_config.json delete mode 100644 asset-transfer-private-data/chaincode-go/go.mod delete mode 100644 asset-transfer-private-data/chaincode-go/go.sum delete mode 100644 asset-transfer-private-data/chaincode-go/main.go delete mode 100644 asset-transfer-private-data/chaincode-java/.gitattributes delete mode 100644 asset-transfer-private-data/chaincode-java/META-INF/statedb/couchdb/collections/assetCollection/indexes/indexOwner.json delete mode 100644 asset-transfer-private-data/chaincode-java/build.gradle delete mode 100644 asset-transfer-private-data/chaincode-java/collections_config.json delete mode 100644 asset-transfer-private-data/chaincode-java/config/checkstyle/checkstyle.xml delete mode 100644 asset-transfer-private-data/chaincode-java/config/checkstyle/suppressions.xml delete mode 100644 asset-transfer-private-data/chaincode-java/gradle/wrapper/gradle-wrapper.jar delete mode 100644 asset-transfer-private-data/chaincode-java/gradle/wrapper/gradle-wrapper.properties delete mode 100755 asset-transfer-private-data/chaincode-java/gradlew delete mode 100644 asset-transfer-private-data/chaincode-java/gradlew.bat delete mode 100644 asset-transfer-private-data/chaincode-java/settings.gradle delete mode 100644 asset-transfer-private-data/chaincode-java/src/main/java/org/hyperledger/fabric/samples/privatedata/Asset.java delete mode 100644 asset-transfer-private-data/chaincode-java/src/main/java/org/hyperledger/fabric/samples/privatedata/AssetPrivateDetails.java delete mode 100644 asset-transfer-private-data/chaincode-java/src/main/java/org/hyperledger/fabric/samples/privatedata/AssetTransfer.java delete mode 100644 asset-transfer-private-data/chaincode-java/src/main/java/org/hyperledger/fabric/samples/privatedata/TransferAgreement.java delete mode 100644 asset-transfer-private-data/chaincode-java/src/test/java/org/hyperledger/fabric/samples/privatedata/AssetTransferTest.java delete mode 100644 asset-transfer-private-data/chaincode-java/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker delete mode 100644 asset-transfer-private-data/chaincode-typescript/.dockerignore delete mode 100644 asset-transfer-private-data/chaincode-typescript/.gitignore delete mode 100644 asset-transfer-private-data/chaincode-typescript/Dockerfile delete mode 100644 asset-transfer-private-data/chaincode-typescript/Readme.md delete mode 100644 asset-transfer-private-data/chaincode-typescript/collections_config.json delete mode 100644 asset-transfer-private-data/chaincode-typescript/docker/docker-entrypoint.sh delete mode 100644 asset-transfer-private-data/chaincode-typescript/eslint.config.mjs delete mode 100644 asset-transfer-private-data/chaincode-typescript/npm-shrinkwrap.json delete mode 100755 asset-transfer-private-data/chaincode-typescript/package.json delete mode 100644 asset-transfer-private-data/chaincode-typescript/src/asset.ts delete mode 100644 asset-transfer-private-data/chaincode-typescript/src/assetTransfer.ts delete mode 100644 asset-transfer-private-data/chaincode-typescript/src/assetTransferDetails.ts delete mode 100644 asset-transfer-private-data/chaincode-typescript/src/assetTransferTransientInput.ts delete mode 100644 asset-transfer-private-data/chaincode-typescript/src/index.ts delete mode 100644 asset-transfer-private-data/chaincode-typescript/src/transferAgreement.ts delete mode 100644 asset-transfer-private-data/chaincode-typescript/src/utils.ts delete mode 100644 asset-transfer-private-data/chaincode-typescript/tsconfig.json delete mode 100644 asset-transfer-sbe/README.md delete mode 100644 asset-transfer-sbe/application-javascript/.eslintignore delete mode 100644 asset-transfer-sbe/application-javascript/.eslintrc.js delete mode 100644 asset-transfer-sbe/application-javascript/.gitignore delete mode 100644 asset-transfer-sbe/application-javascript/app.js delete mode 100644 asset-transfer-sbe/application-javascript/package.json delete mode 100644 asset-transfer-sbe/chaincode-java/.gitattributes delete mode 100644 asset-transfer-sbe/chaincode-java/.gitignore delete mode 100644 asset-transfer-sbe/chaincode-java/build.gradle delete mode 100644 asset-transfer-sbe/chaincode-java/config/checkstyle/checkstyle.xml delete mode 100644 asset-transfer-sbe/chaincode-java/config/checkstyle/suppressions.xml delete mode 100644 asset-transfer-sbe/chaincode-java/gradle/wrapper/gradle-wrapper.jar delete mode 100644 asset-transfer-sbe/chaincode-java/gradle/wrapper/gradle-wrapper.properties delete mode 100755 asset-transfer-sbe/chaincode-java/gradlew delete mode 100644 asset-transfer-sbe/chaincode-java/gradlew.bat delete mode 100644 asset-transfer-sbe/chaincode-java/settings.gradle delete mode 100644 asset-transfer-sbe/chaincode-java/src/main/java/org/hyperledger/fabric/samples/sbe/Asset.java delete mode 100644 asset-transfer-sbe/chaincode-java/src/main/java/org/hyperledger/fabric/samples/sbe/AssetContract.java delete mode 100644 asset-transfer-sbe/chaincode-typescript/.gitignore delete mode 100644 asset-transfer-sbe/chaincode-typescript/eslint.config.mjs delete mode 100644 asset-transfer-sbe/chaincode-typescript/npm-shrinkwrap.json delete mode 100644 asset-transfer-sbe/chaincode-typescript/package.json delete mode 100644 asset-transfer-sbe/chaincode-typescript/src/asset.ts delete mode 100644 asset-transfer-sbe/chaincode-typescript/src/assetContract.ts delete mode 100644 asset-transfer-sbe/chaincode-typescript/src/index.ts delete mode 100644 asset-transfer-sbe/chaincode-typescript/tsconfig.json delete mode 100644 asset-transfer-secured-agreement/README.md delete mode 100644 asset-transfer-secured-agreement/application-gateway-typescript/.gitignore delete mode 100644 asset-transfer-secured-agreement/application-gateway-typescript/eslint.config.mjs delete mode 100644 asset-transfer-secured-agreement/application-gateway-typescript/package.json delete mode 100644 asset-transfer-secured-agreement/application-gateway-typescript/src/app.ts delete mode 100644 asset-transfer-secured-agreement/application-gateway-typescript/src/connect.ts delete mode 100644 asset-transfer-secured-agreement/application-gateway-typescript/src/contractWrapper.ts delete mode 100644 asset-transfer-secured-agreement/application-gateway-typescript/src/utils.ts delete mode 100644 asset-transfer-secured-agreement/application-gateway-typescript/tsconfig.json delete mode 100644 asset-transfer-secured-agreement/chaincode-go/README.md delete mode 100644 asset-transfer-secured-agreement/chaincode-go/asset_transfer.go delete mode 100644 asset-transfer-secured-agreement/chaincode-go/asset_transfer_queries.go delete mode 100644 asset-transfer-secured-agreement/chaincode-go/go.mod delete mode 100644 asset-transfer-secured-agreement/chaincode-go/go.sum delete mode 100644 auction-dutch/README.md delete mode 100644 auction-dutch/application-javascript/.eslintignore delete mode 100644 auction-dutch/application-javascript/.eslintrc.js delete mode 100644 auction-dutch/application-javascript/bid.js delete mode 100644 auction-dutch/application-javascript/closeAuction.js delete mode 100644 auction-dutch/application-javascript/createAuction.js delete mode 100644 auction-dutch/application-javascript/endAuction.js delete mode 100644 auction-dutch/application-javascript/endAuctionwithAuditor.js delete mode 100644 auction-dutch/application-javascript/enrollAdmin.js delete mode 100644 auction-dutch/application-javascript/package.json delete mode 100644 auction-dutch/application-javascript/queryAuction.js delete mode 100644 auction-dutch/application-javascript/queryBid.js delete mode 100644 auction-dutch/application-javascript/registerEnrollUser.js delete mode 100644 auction-dutch/application-javascript/revealBid.js delete mode 100644 auction-dutch/application-javascript/submitBid.js delete mode 100644 auction-dutch/chaincode-go-auditor/go.mod delete mode 100644 auction-dutch/chaincode-go-auditor/go.sum delete mode 100644 auction-dutch/chaincode-go-auditor/smart-contract/auction.go delete mode 100644 auction-dutch/chaincode-go-auditor/smart-contract/auctionQueries.go delete mode 100644 auction-dutch/chaincode-go-auditor/smart-contract/utils.go delete mode 100644 auction-dutch/chaincode-go-auditor/smartContract.go delete mode 100644 auction-dutch/chaincode-go/go.mod delete mode 100644 auction-dutch/chaincode-go/go.sum delete mode 100644 auction-dutch/chaincode-go/smart-contract/auction.go delete mode 100644 auction-dutch/chaincode-go/smart-contract/auctionQueries.go delete mode 100644 auction-dutch/chaincode-go/smart-contract/utils.go delete mode 100644 auction-dutch/chaincode-go/smartContract.go delete mode 100644 auction-simple/README.md delete mode 100644 auction-simple/application-javascript/.eslintignore delete mode 100644 auction-simple/application-javascript/.eslintrc.js delete mode 100644 auction-simple/application-javascript/bid.js delete mode 100644 auction-simple/application-javascript/closeAuction.js delete mode 100644 auction-simple/application-javascript/createAuction.js delete mode 100644 auction-simple/application-javascript/endAuction.js delete mode 100644 auction-simple/application-javascript/enrollAdmin.js delete mode 100644 auction-simple/application-javascript/package.json delete mode 100644 auction-simple/application-javascript/queryAuction.js delete mode 100644 auction-simple/application-javascript/queryBid.js delete mode 100644 auction-simple/application-javascript/registerEnrollUser.js delete mode 100644 auction-simple/application-javascript/revealBid.js delete mode 100644 auction-simple/application-javascript/submitBid.js delete mode 100644 auction-simple/chaincode-go/go.mod delete mode 100644 auction-simple/chaincode-go/go.sum delete mode 100644 auction-simple/chaincode-go/smart-contract/auction.go delete mode 100644 auction-simple/chaincode-go/smart-contract/auctionQueries.go delete mode 100644 auction-simple/chaincode-go/smart-contract/utils.go delete mode 100644 auction-simple/chaincode-go/smartContract.go delete mode 100644 full-stack-asset-transfer-guide/.gitignore delete mode 100644 full-stack-asset-transfer-guide/LICENSE delete mode 100644 full-stack-asset-transfer-guide/README.md delete mode 100644 full-stack-asset-transfer-guide/SETUP.md delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/.eslintrc.js delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/.gitignore delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/.npmrc delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/README.md delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/assets/appleplectic.png delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/assets/bananomatopoeia.png delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/assets/block-norris.png delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/assets/blockbert.png delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/assets/count-blockula.png delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/assets/darth-conga.png delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/assets/no-pun-intended.png delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/assets/template.png delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/hooks/captain-hook.json delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/images/interaction.png delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/package.json delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/src/app.ts delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/src/commands/create.ts delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/src/commands/delete.ts delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/src/commands/discord.ts delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/src/commands/getAllAssets.ts delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/src/commands/index.ts delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/src/commands/read.ts delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/src/commands/transfer.ts delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/src/config.ts delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/src/connect.ts delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/src/contract.ts delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/src/expectedError.ts delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/src/utils.ts delete mode 100644 full-stack-asset-transfer-guide/applications/conga-cards/tsconfig.json delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/.browserslistrc delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/.editorconfig delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/.gitignore delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/Dockerfile delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/README.md delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/angular.json delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/karma.conf.js delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/package.json delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/screenshots/Create.png delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/screenshots/list.png delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/src/app/app-routing.module.ts delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/src/app/app.component.html delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/src/app/app.component.scss delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/src/app/app.component.spec.ts delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/src/app/app.component.ts delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/src/app/app.module.ts delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/src/app/asset-dialog/asset-dialog.component.html delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/src/app/asset-dialog/asset-dialog.component.scss delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/src/app/asset-dialog/asset-dialog.component.spec.ts delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/src/app/asset-dialog/asset-dialog.component.ts delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/src/app/urls.ts delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/src/assets/.gitkeep delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/src/environments/environment.prod.ts delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/src/environments/environment.ts delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/src/favicon.ico delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/src/index.html delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/src/main.ts delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/src/polyfills.ts delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/src/styles.scss delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/src/test.ts delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/tsconfig.app.json delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/tsconfig.json delete mode 100644 full-stack-asset-transfer-guide/applications/frontend/tsconfig.spec.json delete mode 100644 full-stack-asset-transfer-guide/applications/ping-chaincode/.gitignore delete mode 100644 full-stack-asset-transfer-guide/applications/ping-chaincode/app.env delete mode 100644 full-stack-asset-transfer-guide/applications/ping-chaincode/package.json delete mode 100644 full-stack-asset-transfer-guide/applications/ping-chaincode/src/app.ts delete mode 100644 full-stack-asset-transfer-guide/applications/ping-chaincode/src/fabric-connection-profile.ts delete mode 100644 full-stack-asset-transfer-guide/applications/ping-chaincode/src/jsonid-adapter.ts delete mode 100644 full-stack-asset-transfer-guide/applications/ping-chaincode/tsconfig.json delete mode 100644 full-stack-asset-transfer-guide/applications/rest-api/.gitignore delete mode 100644 full-stack-asset-transfer-guide/applications/rest-api/Dockerfile delete mode 100644 full-stack-asset-transfer-guide/applications/rest-api/LICENSE delete mode 100644 full-stack-asset-transfer-guide/applications/rest-api/README.md delete mode 100644 full-stack-asset-transfer-guide/applications/rest-api/asset-transfer.postman_collection.json delete mode 100644 full-stack-asset-transfer-guide/applications/rest-api/deployment.yaml delete mode 100644 full-stack-asset-transfer-guide/applications/rest-api/package.json delete mode 100644 full-stack-asset-transfer-guide/applications/rest-api/renovate.json delete mode 100644 full-stack-asset-transfer-guide/applications/rest-api/src/app.ts delete mode 100644 full-stack-asset-transfer-guide/applications/rest-api/src/assets.router.ts delete mode 100644 full-stack-asset-transfer-guide/applications/rest-api/src/connection.ts delete mode 100644 full-stack-asset-transfer-guide/applications/rest-api/src/server.ts delete mode 100644 full-stack-asset-transfer-guide/applications/rest-api/tsconfig.json delete mode 100644 full-stack-asset-transfer-guide/applications/trader-typescript/.gitignore delete mode 100644 full-stack-asset-transfer-guide/applications/trader-typescript/.npmrc delete mode 100644 full-stack-asset-transfer-guide/applications/trader-typescript/README.md delete mode 100644 full-stack-asset-transfer-guide/applications/trader-typescript/eslint.config.mjs delete mode 100644 full-stack-asset-transfer-guide/applications/trader-typescript/package.json delete mode 100644 full-stack-asset-transfer-guide/applications/trader-typescript/src/app.ts delete mode 100644 full-stack-asset-transfer-guide/applications/trader-typescript/src/commands/create.ts delete mode 100644 full-stack-asset-transfer-guide/applications/trader-typescript/src/commands/delete.ts delete mode 100644 full-stack-asset-transfer-guide/applications/trader-typescript/src/commands/getAllAssets.ts delete mode 100644 full-stack-asset-transfer-guide/applications/trader-typescript/src/commands/index.ts delete mode 100644 full-stack-asset-transfer-guide/applications/trader-typescript/src/commands/listen.ts delete mode 100644 full-stack-asset-transfer-guide/applications/trader-typescript/src/commands/read.ts delete mode 100644 full-stack-asset-transfer-guide/applications/trader-typescript/src/commands/transact.ts delete mode 100644 full-stack-asset-transfer-guide/applications/trader-typescript/src/commands/transfer.ts delete mode 100644 full-stack-asset-transfer-guide/applications/trader-typescript/src/config.ts delete mode 100644 full-stack-asset-transfer-guide/applications/trader-typescript/src/connect.ts delete mode 100644 full-stack-asset-transfer-guide/applications/trader-typescript/src/contract.ts delete mode 100644 full-stack-asset-transfer-guide/applications/trader-typescript/src/expectedError.ts delete mode 100644 full-stack-asset-transfer-guide/applications/trader-typescript/src/utils.ts delete mode 100644 full-stack-asset-transfer-guide/applications/trader-typescript/tsconfig.json delete mode 100755 full-stack-asset-transfer-guide/check.sh delete mode 100755 full-stack-asset-transfer-guide/checks/check-chaincode.sh delete mode 100755 full-stack-asset-transfer-guide/checks/check-kube.sh delete mode 100755 full-stack-asset-transfer-guide/checks/check-network.sh delete mode 100644 full-stack-asset-transfer-guide/checks/utils.sh delete mode 100644 full-stack-asset-transfer-guide/contracts/asset-transfer-typescript/.gitignore delete mode 100644 full-stack-asset-transfer-guide/contracts/asset-transfer-typescript/.npmrc delete mode 100644 full-stack-asset-transfer-guide/contracts/asset-transfer-typescript/Dockerfile delete mode 100644 full-stack-asset-transfer-guide/contracts/asset-transfer-typescript/asset-transfer-chaincode-vars.yml delete mode 100755 full-stack-asset-transfer-guide/contracts/asset-transfer-typescript/docker/docker-entrypoint.sh delete mode 100644 full-stack-asset-transfer-guide/contracts/asset-transfer-typescript/eslint.config.mjs delete mode 100644 full-stack-asset-transfer-guide/contracts/asset-transfer-typescript/npm-shrinkwrap.json delete mode 100644 full-stack-asset-transfer-guide/contracts/asset-transfer-typescript/package.json delete mode 100644 full-stack-asset-transfer-guide/contracts/asset-transfer-typescript/src/asset.ts delete mode 100644 full-stack-asset-transfer-guide/contracts/asset-transfer-typescript/src/assetTransfer.ts delete mode 100644 full-stack-asset-transfer-guide/contracts/asset-transfer-typescript/src/index.ts delete mode 100644 full-stack-asset-transfer-guide/contracts/asset-transfer-typescript/src/untyped.d.ts delete mode 100644 full-stack-asset-transfer-guide/contracts/asset-transfer-typescript/tsconfig.json delete mode 100644 full-stack-asset-transfer-guide/docs/ApplicationDev/01-FabricGateway.md delete mode 100644 full-stack-asset-transfer-guide/docs/ApplicationDev/02-Exercise-RunApplication.md delete mode 100644 full-stack-asset-transfer-guide/docs/ApplicationDev/03-ApplicationOverview.md delete mode 100644 full-stack-asset-transfer-guide/docs/ApplicationDev/04-Exercise-AssetTransfer.md delete mode 100644 full-stack-asset-transfer-guide/docs/ApplicationDev/05-ChaincodeEvents.md delete mode 100644 full-stack-asset-transfer-guide/docs/ApplicationDev/06-Exercise-ChaincodeEvents.md delete mode 100644 full-stack-asset-transfer-guide/docs/ApplicationDev/README.md delete mode 100644 full-stack-asset-transfer-guide/docs/CloudReady/00-setup-zh.md delete mode 100644 full-stack-asset-transfer-guide/docs/CloudReady/00-setup.md delete mode 100644 full-stack-asset-transfer-guide/docs/CloudReady/10-kube-zh.md delete mode 100644 full-stack-asset-transfer-guide/docs/CloudReady/10-kube.md delete mode 100644 full-stack-asset-transfer-guide/docs/CloudReady/11-kube-multipass.md delete mode 100644 full-stack-asset-transfer-guide/docs/CloudReady/12-kube-ec2-vm.md delete mode 100644 full-stack-asset-transfer-guide/docs/CloudReady/13-kube-public-cloud.md delete mode 100644 full-stack-asset-transfer-guide/docs/CloudReady/20-fabric-zh.md delete mode 100644 full-stack-asset-transfer-guide/docs/CloudReady/20-fabric.md delete mode 100644 full-stack-asset-transfer-guide/docs/CloudReady/21-fabric-operations-console.md delete mode 100644 full-stack-asset-transfer-guide/docs/CloudReady/22-fabric-ansible-collection.md delete mode 100644 full-stack-asset-transfer-guide/docs/CloudReady/30-chaincode-zh.md delete mode 100644 full-stack-asset-transfer-guide/docs/CloudReady/30-chaincode.md delete mode 100644 full-stack-asset-transfer-guide/docs/CloudReady/31-fabric-ansible-chaincode.md delete mode 100644 full-stack-asset-transfer-guide/docs/CloudReady/40-bananas-zh.md delete mode 100644 full-stack-asset-transfer-guide/docs/CloudReady/40-bananas.md delete mode 100644 full-stack-asset-transfer-guide/docs/CloudReady/50-OpenShift-Deployment.md delete mode 100644 full-stack-asset-transfer-guide/docs/CloudReady/90-teardown.md delete mode 100644 full-stack-asset-transfer-guide/docs/CloudReady/README.md delete mode 100644 full-stack-asset-transfer-guide/docs/SmartContractDev/00-Introduction-ES.md delete mode 100644 full-stack-asset-transfer-guide/docs/SmartContractDev/00-Introduction.md delete mode 100644 full-stack-asset-transfer-guide/docs/SmartContractDev/01-Exercise-Getting-Started-ES.md delete mode 100644 full-stack-asset-transfer-guide/docs/SmartContractDev/01-Exercise-Getting-Started.md delete mode 100644 full-stack-asset-transfer-guide/docs/SmartContractDev/02-Exercise-Adding-tx-function-ES.md delete mode 100644 full-stack-asset-transfer-guide/docs/SmartContractDev/02-Exercise-Adding-tx-function.md delete mode 100644 full-stack-asset-transfer-guide/docs/SmartContractDev/03-Test-And-Debug-Reference-ES.md delete mode 100644 full-stack-asset-transfer-guide/docs/SmartContractDev/03-Test-And-Debug-Reference.md delete mode 100644 full-stack-asset-transfer-guide/docs/images/ApplicationDev.pptx delete mode 100644 full-stack-asset-transfer-guide/docs/images/ApplicationDev/fabric-gateway-deployment.png delete mode 100644 full-stack-asset-transfer-guide/docs/images/ApplicationDev/fabric-gateway-model.png delete mode 100644 full-stack-asset-transfer-guide/docs/images/ApplicationDev/legacy-sdk-model.png delete mode 100644 full-stack-asset-transfer-guide/docs/images/ApplicationDev/transaction-submit-flow.png delete mode 100644 full-stack-asset-transfer-guide/docs/images/CloudReady.pptx delete mode 100644 full-stack-asset-transfer-guide/docs/images/CloudReady/00-cloud-ready-2.png delete mode 100644 full-stack-asset-transfer-guide/docs/images/CloudReady/10-kube.png delete mode 100644 full-stack-asset-transfer-guide/docs/images/CloudReady/12-kube-ec2-vm.png delete mode 100644 full-stack-asset-transfer-guide/docs/images/CloudReady/20-fabric.png delete mode 100644 full-stack-asset-transfer-guide/docs/images/CloudReady/30-chaincode.png delete mode 100644 full-stack-asset-transfer-guide/docs/images/CloudReady/40-gateway-client-app.png delete mode 100644 full-stack-asset-transfer-guide/docs/images/CloudReady/kube-ec2-vm.png delete mode 100644 full-stack-asset-transfer-guide/docs/images/cloud-vm-with-operator-network.png delete mode 100644 full-stack-asset-transfer-guide/docs/images/multipass-operator-network.png delete mode 100644 full-stack-asset-transfer-guide/docs/images/multipass-test-network.png delete mode 100644 full-stack-asset-transfer-guide/docs/images/readme_diagram.png delete mode 100644 full-stack-asset-transfer-guide/docs/tips-for-windows-dev.md delete mode 100644 full-stack-asset-transfer-guide/infrastructure/configuration/fabric-common-vars.yml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/configuration/fabric-ordering-org-vars.yml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/configuration/fabric-org1-vars.yml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/configuration/fabric-org2-vars.yml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/configuration/fabric-sail.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/configuration/operator-console-vars.yml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/ec2-cloud-config.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/fabric_network_playbooks/00-complete.yml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/fabric_network_playbooks/01-create-ordering-organization-components.yml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/fabric_network_playbooks/02-create-endorsing-organization-components.yml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/fabric_network_playbooks/05-enable-capabilities.yml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/fabric_network_playbooks/06-add-organization-to-consortium.yml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/fabric_network_playbooks/09-admins-policy.json.j2 delete mode 100644 full-stack-asset-transfer-guide/infrastructure/fabric_network_playbooks/09-create-channel.yml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/fabric_network_playbooks/09-endorsement-policy.json.j2 delete mode 100644 full-stack-asset-transfer-guide/infrastructure/fabric_network_playbooks/09-lifecycle-endorsement-policy.json.j2 delete mode 100644 full-stack-asset-transfer-guide/infrastructure/fabric_network_playbooks/09-readers-policy.json.j2 delete mode 100644 full-stack-asset-transfer-guide/infrastructure/fabric_network_playbooks/09-writers-policy.json.j2 delete mode 100644 full-stack-asset-transfer-guide/infrastructure/fabric_network_playbooks/10-join-peer-to-channel.yml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/fabric_network_playbooks/11-add-anchor-peer-to-channel.yml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/fabric_network_playbooks/12-create-endorsing-organization-components.yml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/fabric_network_playbooks/15-add-organization-to-channel.yml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/fabric_network_playbooks/15-admins-policy.json.j2 delete mode 100644 full-stack-asset-transfer-guide/infrastructure/fabric_network_playbooks/15-endorsement-policy.json.j2 delete mode 100644 full-stack-asset-transfer-guide/infrastructure/fabric_network_playbooks/15-lifecycle-endorsement-policy.json.j2 delete mode 100644 full-stack-asset-transfer-guide/infrastructure/fabric_network_playbooks/15-readers-policy.json.j2 delete mode 100644 full-stack-asset-transfer-guide/infrastructure/fabric_network_playbooks/15-writers-policy.json.j2 delete mode 100644 full-stack-asset-transfer-guide/infrastructure/fabric_network_playbooks/16-import-ordering-service.yml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/fabric_network_playbooks/17-join-peer-to-channel.yml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/fabric_network_playbooks/18-add-anchor-peer-to-channel.yml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/kind_console_ingress/90-KIND-ingress.yml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/kind_console_ingress/templates/coredns/coredns.yaml.j2 delete mode 100644 full-stack-asset-transfer-guide/infrastructure/kind_console_ingress/templates/ingress/ingress-nginx-controller.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/kind_console_ingress/templates/ingress/kustomization.yaml delete mode 100755 full-stack-asset-transfer-guide/infrastructure/kind_with_nginx.sh delete mode 100644 full-stack-asset-transfer-guide/infrastructure/multipass-cloud-config.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/operator_console_playbooks/01-operator-install.yml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/operator_console_playbooks/02-console-install.yml delete mode 100755 full-stack-asset-transfer-guide/infrastructure/pkgcc.sh delete mode 100644 full-stack-asset-transfer-guide/infrastructure/production_chaincode_playbooks/19-install-and-approve-chaincode.yml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/production_chaincode_playbooks/20-install-and-approve-chaincode.yml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/production_chaincode_playbooks/21-commit-chaincode.yml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/production_chaincode_playbooks/22-register-application.yml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/production_chaincode_playbooks/asset-transfer_appid.json delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/.gitignore delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/config/cas/kustomization.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/config/cas/org0-ca.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/config/cas/org1-ca.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/config/cas/org2-ca.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/config/configtx-template.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/config/console/hlf-operations-console.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/config/console/kustomization.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/config/core.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/config/gateway/kustomization.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/config/gateway/org1-peer-gateway.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/config/gateway/org2-peer-gateway.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/config/manager/fabric-operator-manager.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/config/manager/kustomization.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/config/orderers/kustomization.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/config/orderers/org0-orderers.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/config/peers/kustomization.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/config/peers/org1-peer1.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/config/peers/org1-peer2.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/config/peers/org2-peer1.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/config/peers/org2-peer2.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/config/rbac/fabric-operator-clusterrole.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/config/rbac/fabric-operator-clusterrolebinding.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/config/rbac/fabric-operator-serviceaccount.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/config/rbac/kustomization.yaml delete mode 100755 full-stack-asset-transfer-guide/infrastructure/sample-network/network delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/scripts/channel.sh delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/scripts/console.sh delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/scripts/frontend_build.sh delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/scripts/frontend_deployment.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/scripts/prereqs.sh delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/scripts/rest_deployment.yaml delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/scripts/rest_sample.sh delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/scripts/sample_network.sh delete mode 100644 full-stack-asset-transfer-guide/infrastructure/sample-network/scripts/utils.sh delete mode 100755 full-stack-asset-transfer-guide/infrastructure/setup_storage_classes.sh delete mode 100644 full-stack-asset-transfer-guide/justfile delete mode 100755 full-stack-asset-transfer-guide/tests/00-chaincode-e2e.sh delete mode 100755 full-stack-asset-transfer-guide/tests/10-appdev-e2e.sh delete mode 100755 full-stack-asset-transfer-guide/tests/20-cloud-e2e.sh delete mode 100755 full-stack-asset-transfer-guide/tests/30-ansible-e2e.sh delete mode 100755 full-stack-asset-transfer-guide/tests/40-console.sh delete mode 100644 hardware-security-module/.gitignore delete mode 100644 hardware-security-module/README.md delete mode 100644 hardware-security-module/application-go/go.mod delete mode 100644 hardware-security-module/application-go/go.sum delete mode 100644 hardware-security-module/application-go/hsm-sample.go delete mode 100644 hardware-security-module/application-typescript/.gitignore delete mode 100644 hardware-security-module/application-typescript/eslint.config.mjs delete mode 100644 hardware-security-module/application-typescript/package.json delete mode 100644 hardware-security-module/application-typescript/src/hsm-sample.ts delete mode 100644 hardware-security-module/application-typescript/tsconfig.json delete mode 100644 hardware-security-module/ca-client-config/.gitignore delete mode 100644 hardware-security-module/ca-client-config/fabric-ca-client-config-template.yaml delete mode 100755 hardware-security-module/scripts/generate-hsm-user.sh delete mode 100644 high-throughput/README.md delete mode 100755 high-throughput/application-go/.gitignore delete mode 100644 high-throughput/application-go/app.go delete mode 100644 high-throughput/application-go/functions/deletePrune.go delete mode 100644 high-throughput/application-go/functions/manyUpdates.go delete mode 100644 high-throughput/application-go/functions/query.go delete mode 100644 high-throughput/application-go/functions/update.go delete mode 100644 high-throughput/application-go/functions/util.go delete mode 100644 high-throughput/application-go/go.mod delete mode 100644 high-throughput/application-go/go.sum delete mode 100644 high-throughput/chaincode-go/go.mod delete mode 100644 high-throughput/chaincode-go/go.sum delete mode 100644 high-throughput/chaincode-go/high-throughput.go delete mode 100755 high-throughput/networkDown.sh delete mode 100755 high-throughput/startFabric.sh delete mode 100644 off_chain_data/README.md delete mode 100644 off_chain_data/application-java/.gitignore delete mode 100644 off_chain_data/application-java/app/build.gradle delete mode 100644 off_chain_data/application-java/app/pom.xml delete mode 100644 off_chain_data/application-java/app/src/main/java/App.java delete mode 100644 off_chain_data/application-java/app/src/main/java/Asset.java delete mode 100644 off_chain_data/application-java/app/src/main/java/AssetTransferBasic.java delete mode 100644 off_chain_data/application-java/app/src/main/java/BlockProcessor.java delete mode 100644 off_chain_data/application-java/app/src/main/java/Command.java delete mode 100644 off_chain_data/application-java/app/src/main/java/Connections.java delete mode 100644 off_chain_data/application-java/app/src/main/java/ExpectedException.java delete mode 100644 off_chain_data/application-java/app/src/main/java/GetAllAssets.java delete mode 100644 off_chain_data/application-java/app/src/main/java/Listen.java delete mode 100644 off_chain_data/application-java/app/src/main/java/Store.java delete mode 100644 off_chain_data/application-java/app/src/main/java/Transact.java delete mode 100644 off_chain_data/application-java/app/src/main/java/TransactApp.java delete mode 100644 off_chain_data/application-java/app/src/main/java/TransactionProcessor.java delete mode 100644 off_chain_data/application-java/app/src/main/java/Utils.java delete mode 100644 off_chain_data/application-java/app/src/main/java/Write.java delete mode 100644 off_chain_data/application-java/app/src/main/java/parser/Block.java delete mode 100644 off_chain_data/application-java/app/src/main/java/parser/BlockParser.java delete mode 100644 off_chain_data/application-java/app/src/main/java/parser/NamespaceReadWriteSet.java delete mode 100644 off_chain_data/application-java/app/src/main/java/parser/ParsedBlock.java delete mode 100644 off_chain_data/application-java/app/src/main/java/parser/ParsedPayload.java delete mode 100644 off_chain_data/application-java/app/src/main/java/parser/ParsedReadWriteSet.java delete mode 100644 off_chain_data/application-java/app/src/main/java/parser/ParsedTransaction.java delete mode 100644 off_chain_data/application-java/app/src/main/java/parser/ParsedTransactionAction.java delete mode 100644 off_chain_data/application-java/app/src/main/java/parser/Transaction.java delete mode 100644 off_chain_data/application-java/app/src/main/java/parser/Utils.java delete mode 100644 off_chain_data/application-java/config/checkstyle/checkstyle.xml delete mode 100644 off_chain_data/application-java/config/checkstyle/java-copyright-header.txt delete mode 100644 off_chain_data/application-java/gradle/wrapper/gradle-wrapper.jar delete mode 100644 off_chain_data/application-java/gradle/wrapper/gradle-wrapper.properties delete mode 100755 off_chain_data/application-java/gradlew delete mode 100644 off_chain_data/application-java/gradlew.bat delete mode 100644 off_chain_data/application-java/settings.gradle delete mode 100644 off_chain_data/application-typescript/.gitignore delete mode 100644 off_chain_data/application-typescript/.npmrc delete mode 100644 off_chain_data/application-typescript/eslint.config.mjs delete mode 100644 off_chain_data/application-typescript/package.json delete mode 100644 off_chain_data/application-typescript/src/app.ts delete mode 100644 off_chain_data/application-typescript/src/blockParser.ts delete mode 100644 off_chain_data/application-typescript/src/connect.ts delete mode 100644 off_chain_data/application-typescript/src/contract.ts delete mode 100644 off_chain_data/application-typescript/src/expectedError.ts delete mode 100644 off_chain_data/application-typescript/src/getAllAssets.ts delete mode 100644 off_chain_data/application-typescript/src/listen.ts delete mode 100644 off_chain_data/application-typescript/src/transact.ts delete mode 100644 off_chain_data/application-typescript/src/utils.ts delete mode 100644 off_chain_data/application-typescript/tsconfig.json delete mode 100644 test-application/javascript/AppUtil.js delete mode 100644 test-application/javascript/CAUtil.js delete mode 100644 test-network-k8s/.gitignore delete mode 100644 test-network-k8s/README.md delete mode 100644 test-network-k8s/config/org0/configtx-template.yaml delete mode 100644 test-network-k8s/config/org0/fabric-ca-server-config.yaml delete mode 100644 test-network-k8s/config/org0/orderer.yaml delete mode 100644 test-network-k8s/config/org1/core.yaml delete mode 100644 test-network-k8s/config/org1/fabric-ca-server-config.yaml delete mode 100644 test-network-k8s/config/org2/fabric-ca-server-config.yaml delete mode 100644 test-network-k8s/docs/APPLICATIONS.md delete mode 100644 test-network-k8s/docs/CA.md delete mode 100644 test-network-k8s/docs/CALIPER.md delete mode 100644 test-network-k8s/docs/CHAINCODE.md delete mode 100644 test-network-k8s/docs/CHAINCODE_AS_A_SERVICE.md delete mode 100644 test-network-k8s/docs/CHANNELS.md delete mode 100644 test-network-k8s/docs/HIGH_AVAILABILITY.md delete mode 100644 test-network-k8s/docs/KUBERNETES.md delete mode 100644 test-network-k8s/docs/README.md delete mode 100644 test-network-k8s/docs/TEST_NETWORK.md delete mode 100644 test-network-k8s/docs/images/test-network.png delete mode 100644 test-network-k8s/kube/application-deployment.yaml delete mode 100644 test-network-k8s/kube/fabric-builder-role.yaml delete mode 100644 test-network-k8s/kube/fabric-builder-rolebinding.yaml delete mode 100644 test-network-k8s/kube/fabric-rest-sample.yaml delete mode 100644 test-network-k8s/kube/ingress-nginx-k3s.yaml delete mode 100644 test-network-k8s/kube/ingress-nginx-kind.yaml delete mode 100644 test-network-k8s/kube/ns-test-network.yaml delete mode 100644 test-network-k8s/kube/org0/org0-ca.yaml delete mode 100644 test-network-k8s/kube/org0/org0-job-scrub-fabric-volumes.yaml delete mode 100644 test-network-k8s/kube/org0/org0-orderer1.yaml delete mode 100644 test-network-k8s/kube/org0/org0-orderer2.yaml delete mode 100644 test-network-k8s/kube/org0/org0-orderer3.yaml delete mode 100644 test-network-k8s/kube/org0/org0-tls-cert-issuer.yaml delete mode 100644 test-network-k8s/kube/org1/org1-ca.yaml delete mode 100644 test-network-k8s/kube/org1/org1-cc-template.yaml delete mode 100644 test-network-k8s/kube/org1/org1-install-k8s-builder.yaml delete mode 100644 test-network-k8s/kube/org1/org1-job-scrub-fabric-volumes.yaml delete mode 100644 test-network-k8s/kube/org1/org1-peer1.yaml delete mode 100644 test-network-k8s/kube/org1/org1-peer2.yaml delete mode 100644 test-network-k8s/kube/org1/org1-tls-cert-issuer.yaml delete mode 100644 test-network-k8s/kube/org2/org2-ca.yaml delete mode 100644 test-network-k8s/kube/org2/org2-cc-template.yaml delete mode 100644 test-network-k8s/kube/org2/org2-install-k8s-builder.yaml delete mode 100644 test-network-k8s/kube/org2/org2-job-scrub-fabric-volumes.yaml delete mode 100644 test-network-k8s/kube/org2/org2-peer1.yaml delete mode 100644 test-network-k8s/kube/org2/org2-peer2.yaml delete mode 100644 test-network-k8s/kube/org2/org2-tls-cert-issuer.yaml delete mode 100644 test-network-k8s/kube/pvc-fabric-org0.yaml delete mode 100644 test-network-k8s/kube/pvc-fabric-org1.yaml delete mode 100644 test-network-k8s/kube/pvc-fabric-org2.yaml delete mode 100644 test-network-k8s/kube/root-tls-cert-issuer.yaml delete mode 100755 test-network-k8s/network delete mode 100755 test-network-k8s/scripts/application_connection.sh delete mode 100644 test-network-k8s/scripts/appuser.id.template delete mode 100755 test-network-k8s/scripts/ccp-template.json delete mode 100755 test-network-k8s/scripts/chaincode.sh delete mode 100644 test-network-k8s/scripts/channel.sh delete mode 100644 test-network-k8s/scripts/cluster.sh delete mode 100755 test-network-k8s/scripts/fabric_CAs.sh delete mode 100755 test-network-k8s/scripts/fabric_config.sh delete mode 100755 test-network-k8s/scripts/kind.sh delete mode 100755 test-network-k8s/scripts/prereqs.sh delete mode 100755 test-network-k8s/scripts/rest_sample.sh delete mode 100755 test-network-k8s/scripts/set_anchor_peer.sh delete mode 100755 test-network-k8s/scripts/test_network.sh delete mode 100644 test-network-k8s/scripts/utils.sh delete mode 100644 test-network-nano-bash/.gitignore delete mode 100644 test-network-nano-bash/README.md delete mode 100644 test-network-nano-bash/bft-config/configtx.yaml delete mode 100644 test-network-nano-bash/ca/ca_config/ca/fabric-ca-server-config.yaml delete mode 100644 test-network-nano-bash/ca/ca_config/tlsca/fabric-ca-server-config.yaml delete mode 100755 test-network-nano-bash/ca/ca_utils.sh delete mode 100644 test-network-nano-bash/ca/config.yaml delete mode 100755 test-network-nano-bash/ca/createEnrollments.sh delete mode 100644 test-network-nano-bash/ca_terminal_setup.png delete mode 100644 test-network-nano-bash/chaincode-external/connection.json delete mode 100644 test-network-nano-bash/chaincode-external/metadata.json delete mode 100755 test-network-nano-bash/chaincode_interaction.sh delete mode 100644 test-network-nano-bash/configtx.yaml delete mode 100755 test-network-nano-bash/configureExternalBuilders.sh delete mode 100644 test-network-nano-bash/crypto-config.yaml delete mode 100644 test-network-nano-bash/external_builders/core_yaml_change.yaml delete mode 100755 test-network-nano-bash/external_builders/golang/bin/build delete mode 100755 test-network-nano-bash/external_builders/golang/bin/detect delete mode 100755 test-network-nano-bash/external_builders/golang/bin/release delete mode 100755 test-network-nano-bash/external_builders/golang/bin/run delete mode 100755 test-network-nano-bash/external_builders/node/bin/build delete mode 100755 test-network-nano-bash/external_builders/node/bin/detect delete mode 100755 test-network-nano-bash/external_builders/node/bin/release delete mode 100755 test-network-nano-bash/external_builders/node/bin/run delete mode 100755 test-network-nano-bash/generate_artifacts.sh delete mode 100755 test-network-nano-bash/install&approve&commit_chaincode_peer1.sh delete mode 100755 test-network-nano-bash/join_channel.sh delete mode 100755 test-network-nano-bash/join_orderers.sh delete mode 100755 test-network-nano-bash/network.sh delete mode 100755 test-network-nano-bash/orderer1.sh delete mode 100755 test-network-nano-bash/orderer2.sh delete mode 100755 test-network-nano-bash/orderer3.sh delete mode 100755 test-network-nano-bash/orderer4.sh delete mode 100755 test-network-nano-bash/ordererca.sh delete mode 100755 test-network-nano-bash/org1ca.sh delete mode 100755 test-network-nano-bash/org2ca.sh delete mode 100755 test-network-nano-bash/peer1.sh delete mode 100755 test-network-nano-bash/peer1admin.sh delete mode 100755 test-network-nano-bash/peer2.sh delete mode 100755 test-network-nano-bash/peer2admin.sh delete mode 100755 test-network-nano-bash/peer3.sh delete mode 100755 test-network-nano-bash/peer3admin.sh delete mode 100755 test-network-nano-bash/peer4.sh delete mode 100755 test-network-nano-bash/peer4admin.sh delete mode 100644 test-network-nano-bash/terminal_setup.png rename {test-network-k8s/config/org2 => test-network}/core.yaml (90%) delete mode 100644 token-erc-1155/README.md delete mode 100644 token-erc-1155/chaincode-go/chaincode/contract.go delete mode 100644 token-erc-1155/chaincode-go/erc1155.go delete mode 100644 token-erc-1155/chaincode-go/go.mod delete mode 100644 token-erc-1155/chaincode-go/go.sum delete mode 100644 token-erc-20/README.md delete mode 100644 token-erc-20/chaincode-go/chaincode/token_contract.go delete mode 100644 token-erc-20/chaincode-go/go.mod delete mode 100644 token-erc-20/chaincode-go/go.sum delete mode 100644 token-erc-20/chaincode-go/token_erc_20.go delete mode 100755 token-erc-20/chaincode-java/Dockerfile delete mode 100755 token-erc-20/chaincode-java/build.gradle delete mode 100755 token-erc-20/chaincode-java/config/checkstyle/checkstyle.xml delete mode 100755 token-erc-20/chaincode-java/config/checkstyle/suppressions.xml delete mode 100755 token-erc-20/chaincode-java/docker/docker-entrypoint.sh delete mode 100755 token-erc-20/chaincode-java/gradle/wrapper/gradle-wrapper.jar delete mode 100755 token-erc-20/chaincode-java/gradle/wrapper/gradle-wrapper.properties delete mode 100755 token-erc-20/chaincode-java/gradlew delete mode 100755 token-erc-20/chaincode-java/gradlew.bat delete mode 100755 token-erc-20/chaincode-java/settings.gradle delete mode 100644 token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/ContractConstants.java delete mode 100644 token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/ContractErrors.java delete mode 100644 token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/ERC20TokenContract.java delete mode 100644 token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/model/Approval.java delete mode 100644 token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/model/Transfer.java delete mode 100644 token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/utils/ContractUtility.java delete mode 100644 token-erc-20/chaincode-java/src/test/java/org/hyperledger/fabric/samples/erc20/TokenERC20ContractTest.java delete mode 100644 token-erc-20/chaincode-java/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker delete mode 100755 token-erc-20/chaincode-javascript/.editorconfig delete mode 100644 token-erc-20/chaincode-javascript/.eslintignore delete mode 100644 token-erc-20/chaincode-javascript/.eslintrc.js delete mode 100644 token-erc-20/chaincode-javascript/.gitignore delete mode 100644 token-erc-20/chaincode-javascript/index.js delete mode 100644 token-erc-20/chaincode-javascript/lib/tokenERC20.js delete mode 100644 token-erc-20/chaincode-javascript/npm-shrinkwrap.json delete mode 100644 token-erc-20/chaincode-javascript/package.json delete mode 100644 token-erc-20/chaincode-javascript/test/tokenERC20.test.js delete mode 100644 token-erc-721/README.md delete mode 100644 token-erc-721/chaincode-go/chaincode/erc721-contract.go delete mode 100644 token-erc-721/chaincode-go/chaincode/erc721-contract_test.go delete mode 100644 token-erc-721/chaincode-go/chaincode/erc721.go delete mode 100644 token-erc-721/chaincode-go/go.mod delete mode 100644 token-erc-721/chaincode-go/go.sum delete mode 100644 token-erc-721/chaincode-go/main.go delete mode 100755 token-erc-721/chaincode-java/Dockerfile delete mode 100755 token-erc-721/chaincode-java/build.gradle delete mode 100644 token-erc-721/chaincode-java/config/checkstyle/checkstyle.xml delete mode 100644 token-erc-721/chaincode-java/config/checkstyle/suppressions.xml delete mode 100755 token-erc-721/chaincode-java/docker/docker-entrypoint.sh delete mode 100644 token-erc-721/chaincode-java/gradle/wrapper/gradle-wrapper.jar delete mode 100644 token-erc-721/chaincode-java/gradle/wrapper/gradle-wrapper.properties delete mode 100755 token-erc-721/chaincode-java/gradlew delete mode 100755 token-erc-721/chaincode-java/gradlew.bat delete mode 100755 token-erc-721/chaincode-java/settings.gradle delete mode 100644 token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/ContractConstants.java delete mode 100644 token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/ContractErrors.java delete mode 100644 token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/ERC721TokenContract.java delete mode 100644 token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/models/Approval.java delete mode 100644 token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/models/NFT.java delete mode 100644 token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/models/Transfer.java delete mode 100644 token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/utils/ContractUtility.java delete mode 100644 token-erc-721/chaincode-java/src/test/java/org/hyperledger/fabric/samples/erc721/ERC721TokenContractTest.java delete mode 100644 token-erc-721/chaincode-java/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker delete mode 100755 token-erc-721/chaincode-javascript/.editorconfig delete mode 100644 token-erc-721/chaincode-javascript/.eslintignore delete mode 100644 token-erc-721/chaincode-javascript/.eslintrc.js delete mode 100644 token-erc-721/chaincode-javascript/.gitignore delete mode 100644 token-erc-721/chaincode-javascript/index.js delete mode 100644 token-erc-721/chaincode-javascript/lib/tokenERC721.js delete mode 100644 token-erc-721/chaincode-javascript/npm-shrinkwrap.json delete mode 100644 token-erc-721/chaincode-javascript/package.json delete mode 100644 token-erc-721/chaincode-javascript/test/tokenERC721.test.js delete mode 100644 token-sdk/.dockerignore delete mode 100644 token-sdk/.gitignore delete mode 100644 token-sdk/Dockerfile delete mode 100644 token-sdk/README.md delete mode 100644 token-sdk/auditor/conf/core.yaml delete mode 100644 token-sdk/auditor/go.mod delete mode 100644 token-sdk/auditor/go.sum delete mode 100644 token-sdk/auditor/main.go delete mode 100644 token-sdk/auditor/oapi-server.yaml delete mode 100644 token-sdk/auditor/routes/operations.go delete mode 100644 token-sdk/auditor/routes/routes.gen.go delete mode 100644 token-sdk/auditor/routes/routes.go delete mode 100644 token-sdk/auditor/routes/server.go delete mode 100644 token-sdk/auditor/service/audit.go delete mode 100644 token-sdk/auditor/service/balance.go delete mode 100644 token-sdk/auditor/service/history.go delete mode 100644 token-sdk/components.png delete mode 100644 token-sdk/compose-ca.yaml delete mode 100644 token-sdk/dependencies.png delete mode 100644 token-sdk/docker-compose.yaml delete mode 100644 token-sdk/e2e/client.gen.go delete mode 100644 token-sdk/e2e/e2e_test.go delete mode 100644 token-sdk/e2e/go.mod delete mode 100644 token-sdk/e2e/go.sum delete mode 100644 token-sdk/e2e/oapi-client.yaml delete mode 100644 token-sdk/explorer/.env delete mode 100644 token-sdk/explorer/config.json delete mode 100644 token-sdk/explorer/connection-profile/test-network.json delete mode 100644 token-sdk/explorer/docker-compose.yaml delete mode 100644 token-sdk/go.work delete mode 100644 token-sdk/go.work.sum delete mode 100644 token-sdk/issuer/conf/core.yaml delete mode 100644 token-sdk/issuer/go.mod delete mode 100644 token-sdk/issuer/go.sum delete mode 100644 token-sdk/issuer/main.go delete mode 100644 token-sdk/issuer/oapi-server.yaml delete mode 100644 token-sdk/issuer/routes/operations.go delete mode 100644 token-sdk/issuer/routes/routes.gen.go delete mode 100644 token-sdk/issuer/routes/routes.go delete mode 100644 token-sdk/issuer/routes/server.go delete mode 100644 token-sdk/issuer/service/issue.go delete mode 100644 token-sdk/owner/conf/owner1/core.yaml delete mode 100644 token-sdk/owner/conf/owner2/core.yaml delete mode 100644 token-sdk/owner/go.mod delete mode 100644 token-sdk/owner/go.sum delete mode 100644 token-sdk/owner/main.go delete mode 100644 token-sdk/owner/oapi-server.yaml delete mode 100644 token-sdk/owner/routes/operations.go delete mode 100644 token-sdk/owner/routes/routes.gen.go delete mode 100644 token-sdk/owner/routes/routes.go delete mode 100644 token-sdk/owner/routes/server.go delete mode 100644 token-sdk/owner/service/accept.go delete mode 100644 token-sdk/owner/service/balance.go delete mode 100644 token-sdk/owner/service/history.go delete mode 100644 token-sdk/owner/service/redeem.go delete mode 100644 token-sdk/owner/service/transfer.go delete mode 100755 token-sdk/scripts/down.sh delete mode 100755 token-sdk/scripts/enroll-users.sh delete mode 100755 token-sdk/scripts/up.sh delete mode 100644 token-sdk/swagger.yaml delete mode 100644 token-sdk/tokenchaincode/Dockerfile delete mode 100644 token-sdk/transfer.png delete mode 100644 token-utxo/README.md delete mode 100644 token-utxo/chaincode-go/chaincode/token_contract.go delete mode 100644 token-utxo/chaincode-go/go.mod delete mode 100644 token-utxo/chaincode-go/go.sum delete mode 100644 token-utxo/chaincode-go/token_utxo.go diff --git a/README.md b/README.md index 6fda756f..dca4d01e 100644 --- a/README.md +++ b/README.md @@ -1,73 +1,28 @@ -[//]: # (SPDX-License-Identifier: CC-BY-4.0) -# Hyperledger Fabric Samples - -You can use Fabric samples to get started working with Hyperledger Fabric, explore important Fabric features, and learn how to build applications that can interact with blockchain networks using the Fabric SDKs. To learn more about Hyperledger Fabric, visit the [Fabric documentation](https://hyperledger-fabric.readthedocs.io/en/latest). - -Note that this branch contains samples for the latest Fabric release. For older Fabric versions, refer to the corresponding branches: - -- [release-2.2](https://github.com/hyperledger/fabric-samples/tree/release-2.2) -- [release-1.4](https://github.com/hyperledger/fabric-samples/tree/release-1.4) - -## Getting started with the Fabric samples - -To use the Fabric samples, you need to download the Fabric Docker images and the Fabric CLI tools. First, make sure that you have installed all of the [Fabric prerequisites](https://hyperledger-fabric.readthedocs.io/en/latest/prereqs.html). You can then follow the instructions to [Install the Fabric Samples, Binaries, and Docker Images](https://hyperledger-fabric.readthedocs.io/en/latest/install.html) in the Fabric documentation. In addition to downloading the Fabric images and tool binaries, the Fabric samples will also be cloned to your local machine. - -## Test network - -The [Fabric test network](test-network) in the samples repository provides a Docker Compose based test network with two -Organization peers and an ordering service node. You can use it on your local machine to run the samples listed below. -You can also use it to deploy and test your own Fabric chaincodes and applications. To get started, see -the [test network tutorial](https://hyperledger-fabric.readthedocs.io/en/latest/test_network.html). - -The [Kubernetes Test Network](test-network-k8s) sample builds upon the Compose network, constructing a Fabric -network with peer, orderer, and CA infrastructure nodes running on Kubernetes. In addition to providing a sample -Kubernetes guide, the Kube test network can be used as a platform to author and debug _cloud ready_ Fabric Client -applications on a development or CI workstation. +# Required: +Docker +GO lang +Node 16 -## Asset transfer samples and tutorials +# Network Startup -The asset transfer series provides a series of sample smart contracts and applications to demonstrate how to store and transfer assets using Hyperledger Fabric. -Each sample and associated tutorial in the series demonstrates a different core capability in Hyperledger Fabric. The **Basic** sample provides an introduction on how -to write smart contracts and how to interact with a Fabric network using the Fabric SDKs. The **Ledger queries**, **Private data**, and **State-based endorsement** -samples demonstrate these additional capabilities. Finally, the **Secured agreement** sample demonstrates how to bring all the capabilities together to securely -transfer an asset in a more realistic transfer scenario. +cd test-network -| **Smart Contract** | **Description** | **Tutorial** | **Smart contract languages** | **Application languages** | -| -----------|------------------------------|----------|---------|---------| -| [Basic](asset-transfer-basic) | The Basic sample smart contract that allows you to create and transfer an asset by putting data on the ledger and retrieving it. This sample is recommended for new Fabric users. | [Writing your first application](https://hyperledger-fabric.readthedocs.io/en/latest/write_first_app.html) | Go, JavaScript, TypeScript, Java | Go, TypeScript, Java | -| [Ledger queries](asset-transfer-ledger-queries) | The ledger queries sample demonstrates range queries and transaction updates using range queries (applicable for both LevelDB and CouchDB state databases), and how to deploy an index with your chaincode to support JSON queries (applicable for CouchDB state database only). | [Using CouchDB](https://hyperledger-fabric.readthedocs.io/en/latest/couchdb_tutorial.html) | Go, JavaScript | Java, JavaScript | -| [Private data](asset-transfer-private-data) | This sample demonstrates the use of private data collections, how to manage private data collections with the chaincode lifecycle, and how the private data hash can be used to verify private data on the ledger. It also demonstrates how to control asset updates and transfers using client-based ownership and access control. | [Using Private Data](https://hyperledger-fabric.readthedocs.io/en/latest/private_data_tutorial.html) | Go, TypeScript, Java | TypeScript | -| [State-Based Endorsement](asset-transfer-sbe) | This sample demonstrates how to override the chaincode-level endorsement policy to set endorsement policies at the key-level (data/asset level). | [Using State-based endorsement](https://github.com/hyperledger/fabric-samples/tree/main/asset-transfer-sbe) | Java, TypeScript | JavaScript | -| [Secured agreement](asset-transfer-secured-agreement) | Smart contract that uses implicit private data collections, state-based endorsement, and organization-based ownership and access control to keep data private and securely transfer an asset with the consent of both the current owner and buyer. | [Secured asset transfer](https://hyperledger-fabric.readthedocs.io/en/latest/secured_asset_transfer/secured_private_asset_transfer_tutorial.html) | Go | TypeScript | -| [Events](asset-transfer-events) | The events sample demonstrates how smart contracts can emit events that are read by the applications interacting with the network. | [README](asset-transfer-events/README.md) | Go, JavaScript, Java | Go, TypeScript, Java | -| [Attribute-based access control](asset-transfer-abac) | Demonstrates the use of attribute and identity based access control using a simple asset transfer scenario | [README](asset-transfer-abac/README.md) | Go | _None_ | +./network.sh up createChannel -c mychannel -ca -## Full stack asset transfer guide - -The [full stack asset transfer guide](full-stack-asset-transfer-guide#readme) workshop demonstrates how a generic asset transfer solution for Hyperledger Fabric can be developed and deployed. This covers chaincode development, client application development, and deployment to a production-like environment. - -## Additional samples - -Additional samples demonstrate various Fabric use cases and application patterns. - -| **Sample** | **Description** | **Documentation** | -| -------------|------------------------------|------------------| -| [Off chain data](off_chain_data) | Learn how to use block events to build an off-chain database for reporting and analytics. | [Peer channel-based event services](https://hyperledger-fabric.readthedocs.io/en/latest/peer_event_services.html) | -| [Token SDK](token-sdk) | Sample REST API around the Hyperledger Labs [Token SDK](https://github.com/hyperledger-labs/fabric-token-sdk) for privacy friendly (zero knowledge proof) UTXO transactions. | [README](token-sdk/README.md) | -| [Token ERC-20](token-erc-20) | Smart contract demonstrating how to create and transfer fungible tokens using an account-based model. | [README](token-erc-20/README.md) | -| [Token UTXO](token-utxo) | Smart contract demonstrating how to create and transfer fungible tokens using a UTXO (unspent transaction output) model. | [README](token-utxo/README.md) | -| [Token ERC-1155](token-erc-1155) | Smart contract demonstrating how to create and transfer multiple tokens (both fungible and non-fungible) using an account based model. | [README](token-erc-1155/README.md) | -| [Token ERC-721](token-erc-721) | Smart contract demonstrating how to create and transfer non-fungible tokens using an account-based model. | [README](token-erc-721/README.md) | -| [High throughput](high-throughput) | Learn how you can design your smart contract to avoid transaction collisions in high volume environments. | [README](high-throughput/README.md) | -| [Simple Auction](auction-simple) | Run an auction where bids are kept private until the auction is closed, after which users can reveal their bid. | [README](auction-simple/README.md) | -| [Dutch Auction](auction-dutch) | Run an auction in which multiple items of the same type can be sold to more than one buyer. This example also includes the ability to add an auditor organization. | [README](auction-dutch/README.md) | +./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-typescript/ -ccl typescript -## License +# Backend Startup -Hyperledger Project source code files are made available under the Apache -License, Version 2.0 (Apache-2.0), located in the [LICENSE](LICENSE) file. -Hyperledger Project documentation files are made available under the Creative -Commons Attribution 4.0 International License (CC-BY-4.0), available at http://creativecommons.org/licenses/by/4.0/. +cd asset-transfer-basic/rest-api-typescript + +TEST_NETWORK_HOME=/home/calvin/go/src/github.com/delete_me0/sandbx/fabric-samples/test-network npm run generateEnv + +export REDIS_PASSWORD=$(uuidgen) +npm run start:redis + +npm run build + +npm run start:dev diff --git a/StudentDBInit.txt b/StudentDBInit.txt new file mode 100644 index 00000000..a32fdeb3 --- /dev/null +++ b/StudentDBInit.txt @@ -0,0 +1,29 @@ + +Required: +Docker +GO lang +Node 16 + + +#Network Startup + +cd test-network + +./network.sh up createChannel -c mychannel -ca + +./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-typescript/ -ccl typescript + + + +#Backend Startup + +cd asset-transfer-basic/rest-api-typescript + +TEST_NETWORK_HOME=/home/calvin/go/src/github.com/delete_me0/sandbx/fabric-samples/test-network npm run generateEnv + +export REDIS_PASSWORD=$(uuidgen) +npm run start:redis + +npm run build + +npm run start:dev diff --git a/asset-transfer-abac/README.md b/asset-transfer-abac/README.md deleted file mode 100644 index 09cb106c..00000000 --- a/asset-transfer-abac/README.md +++ /dev/null @@ -1,173 +0,0 @@ -# Attribute based access control - -The `asset-transfer-abac` sample demonstrates the use of Attribute-based access control within the context of a simple asset transfer scenario. The sample also uses authorization based on individual client identities to allow the users that interact with the network to own assets on the blockchain ledger. - -Attribute-Based Access Control (ABAC) refers to the ability to restrict access to certain functionality within a smart contract based on the attributes within a users certificate. For example, you may want certain functions within a smart contract to be used only by application administrators. ABAC allows organizations to provide elevated access to certain users without requiring those users be administrators of the network. For more information, see [Attribute-based access control](https://hyperledger-fabric-ca.readthedocs.io/en/latest/users-guide.html#attribute-based-access-control) in the Fabric CA users guide. - -The `asset-transfer-abac` smart contract allows you to create assets that can be updated or transferred by the asset owner. However, the ability to create or remove assets from the ledger is restricted to identities with the `abac.creator=true` attribute. The identity that creates the asset is assigned as the asset owner. Only the owner can transfer the asset to a new owner or update the asset properties. In the course of the tutorial, we will use the Fabric CA client to create identities with the attribute required to create a new asset. We will then transfer the asset to another identity and demonstrate how the `GetID()` function can be used to enforce asset ownership. We will then use the owner identity to delete the asset. Both Attribute based access control and the `GetID()` function are provided by the [Client Identity Chaincode Library](https://github.com/hyperledger/fabric-chaincode-go/blob/master/pkg/cid/README.md). - -## Start the network and deploy the smart contract - -We can use the Fabric test network to deploy and interact with the `asset-transfer-abac` smart contract. Run the following command to change into the test network directory and bring down any running nodes: -``` -cd fabric-samples/test-network -./network.sh down -``` - -Run the following command to deploy the test network using Certificate Authorities: -``` -./network.sh up createChannel -ca -``` - -You can then use the test network script to deploy the `asset-transfer-abac` smart contract to a channel on the network: -``` -./network.sh deployCC -ccn abac -ccp ../asset-transfer-abac/chaincode-go/ -ccl go -``` - -## Register identities with attributes - -We can use the one of the test network Certificate Authorities to register and enroll identities with the attribute of `abac.creator=true`. First, we need to set the following environment variables in order to use the Fabric CA client. -``` -export PATH=${PWD}/../bin:${PWD}:$PATH -export FABRIC_CFG_PATH=$PWD/../config/ -``` - -We will create the identities using the Org1 CA. Set the Fabric CA client home to the MSP of the Org1 CA admin: -``` -export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/org1.example.com/ -``` - -There are two ways to generate certificates with attributes added. We will use both methods and create two identities in the process. The first method is to specify that the attribute be added to the certificate by default when the identity is registered. The following command will register an identity named creator1 with the attribute of `abac.creator=true`. - -``` -fabric-ca-client register --id.name creator1 --id.secret creator1pw --id.type client --id.affiliation org1 --id.attrs 'abac.creator=true:ecert' --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" -``` - -The `ecert` suffix adds the attribute to the certificate automatically when the identity is enrolled. As a result, the following enroll command will contain the attribute that was provided in the registration command. - -``` -fabric-ca-client enroll -u https://creator1:creator1pw@localhost:7054 --caname ca-org1 -M "${PWD}/organizations/peerOrganizations/org1.example.com/users/creator1@org1.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" -``` - -Now that we have enrolled the identity, run the command below to copy the Node OU configuration file into the creator1 MSP folder. -``` -cp "${PWD}/organizations/peerOrganizations/org1.example.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/org1.example.com/users/creator1@org1.example.com/msp/config.yaml" -``` - -The second method is to request that the attribute be added upon enrollment. The following command will register an identity named creator2 with the same `abac.creator` attribute. -``` -fabric-ca-client register --id.name creator2 --id.secret creator2pw --id.type client --id.affiliation org1 --id.attrs 'abac.creator=true:' --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" -``` - -The following enroll command will add the attribute to the certificate: - -``` -fabric-ca-client enroll -u https://creator2:creator2pw@localhost:7054 --caname ca-org1 --enrollment.attrs "abac.creator" -M "${PWD}/organizations/peerOrganizations/org1.example.com/users/creator2@org1.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" -``` - -Run the command below to copy the Node OU configuration file into the creator2 MSP folder. -``` -cp "${PWD}/organizations/peerOrganizations/org1.example.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/org1.example.com/users/creator2@org1.example.com/msp/config.yaml" -``` - -## Create an asset - -You can use either identity with the `abac.creator=true` attribute to create an asset using the `asset-transfer-abac` smart contract. We will set the following environment variables to use the first identity that was generated, creator1: - -``` -export CORE_PEER_TLS_ENABLED=true -export CORE_PEER_LOCALMSPID=Org1MSP -export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/creator1@org1.example.com/msp -export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt -export CORE_PEER_ADDRESS=localhost:7051 -export TARGET_TLS_OPTIONS=(-o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --peerAddresses localhost:7051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt") -``` - -Run the following command to create Asset1: -``` -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n abac -c '{"function":"CreateAsset","Args":["Asset1","blue","20","100"]}' -``` - -You can use the command below to query the asset on the ledger: -``` -peer chaincode query -C mychannel -n abac -c '{"function":"ReadAsset","Args":["Asset1"]}' -``` -The result will list the creator1 identity as the asset owner. The `GetID()` API reads the name and issuer from the certificate of the identity that submitted the transaction and assigns that identity as the asset owner: -``` -{"ID":"Asset1","color":"blue","size":20,"owner":"x509::CN=creator1,OU=client+OU=org1,O=Hyperledger,ST=North Carolina,C=US::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US","appraisedValue":100} -``` - -## Transfer the asset - -As the owner of Asset1, the creator1 identity has the ability to transfer the asset to another owner. In order to transfer the asset, the owner needs to provide the name and issuer of the new owner to the `TransferAsset` function. The `asset-transfer-abac` smart contract has a `GetSubmittingClientIdentity` function that allows users to retrieve their certificate information and provide it to the asset owner out of band (we omit this step). Issue the command below to transfer Asset1 to the user1 identity from Org1 that was created when the test network was deployed: -``` -export RECIPIENT="x509::CN=user1,OU=client,O=Hyperledger,ST=North Carolina,C=US::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US" -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n abac -c '{"function":"TransferAsset","Args":["Asset1","'"$RECIPIENT"'"]}' -``` -Query the ledger to verify that the asset has a new owner: -``` -peer chaincode query -C mychannel -n abac -c '{"function":"ReadAsset","Args":["Asset1"]}' -``` -We can see that Asset1 with is now owned by User1: -``` -{"ID":"Asset1","color":"blue","size":20,"owner":"x509::CN=user1,OU=client,O=Hyperledger,ST=North Carolina,C=US::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US","appraisedValue":100} -``` - -## Update the asset - -Now that the asset has been transferred, the new owner can update the asset properties. The smart contract uses the `GetID()` API to ensure that the update is being submitted by the asset owner. To demonstrate the difference between identity and attribute based access control, lets try to update the asset using the creator1 identity first: -``` -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n abac -c '{"function":"UpdateAsset","Args":["Asset1","green","20","100"]}' -``` - -Even though creator1 can create new assets, the smart contract detects that the transaction was not submitted by the identity that owns the asset, user1. The command returns the following error: -``` -Error: endorsement failure during invoke. response: status:500 message:"submitting client not authorized to update asset, does not own asset" -``` - -Run the following command to operate as the asset owner by setting the MSP path to User1: -``` -export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp -``` - -We can now update the asset. Run the following command to change the asset color from blue to green. All other aspects of the asset will remain unchanged. -``` -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n abac -c '{"function":"UpdateAsset","Args":["Asset1","green","20","100"]}' -``` -Run the query command again to verify that the asset has changed color: -``` -peer chaincode query -C mychannel -n abac -c '{"function":"ReadAsset","Args":["Asset1"]}' -``` -The result will display that Asset1 is now green: -``` -{"ID":"Asset1","color":"green","size":20,"owner":"x509::CN=user1,OU=client,O=Hyperledger,ST=North Carolina,C=US::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US","appraisedValue":100} -``` - -## Delete the asset - -The owner also has the ability to delete the asset. Run the following command to remove Asset1 from the ledger: -``` -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n abac -c '{"function":"DeleteAsset","Args":["Asset1"]}' -``` - -If you query the ledger once more, you will see that Asset1 no longer exists: -``` -peer chaincode query -C mychannel -n abac -c '{"function":"ReadAsset","Args":["Asset1"]}' -``` - -While we are operating as User1, we can demonstrate attribute based access control by trying to create an asset using an identity without the `abac.creator=true` attribute. Run the following command to try to create Asset1 as User1: -``` -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n abac -c '{"function":"CreateAsset","Args":["Asset2","red","20","100"]}' -``` - -The smart contract will return the following error: -``` -Error: endorsement failure during invoke. response: status:500 message:"submitting client not authorized to create asset, does not have abac.creator role" -``` - -## Clean up - -When you are finished, you can run the following command to bring down the test network: -``` -./network.sh down -``` diff --git a/asset-transfer-abac/chaincode-go/go.mod b/asset-transfer-abac/chaincode-go/go.mod deleted file mode 100644 index 7111955e..00000000 --- a/asset-transfer-abac/chaincode-go/go.mod +++ /dev/null @@ -1,26 +0,0 @@ -module github.com/hyperledger/fabric-samples/asset-transfer-abac/chaincode-go - -go 1.22.0 - -require github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0 - -require ( - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0 // indirect - github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xeipuuv/gojsonschema v1.2.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect - google.golang.org/grpc v1.67.0 // indirect - google.golang.org/protobuf v1.36.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/asset-transfer-abac/chaincode-go/go.sum b/asset-transfer-abac/chaincode-go/go.sum deleted file mode 100644 index fa4d3b24..00000000 --- a/asset-transfer-abac/chaincode-go/go.sum +++ /dev/null @@ -1,61 +0,0 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0 h1:IhkHfrl5X/fVnmB6pWeCYCdIJRi9bxj+WTnVN8DtW3c= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0/go.mod h1:PHHaFffjw7p7n9bmCfcm7RqDqYdivNEsJdiNIKZo5Lk= -github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0 h1:rmUoBmciB0GL/miqcbJmJbgp5QTWoJUrZo+CNxrNLF4= -github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0/go.mod h1:FeWeO/jwGjiME7ak3GufqKIcwkejtzrDG4QxbfKydWs= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 h1:YJrd+gMaeY0/vsN0aS0QkEKTivGoUnSRIXxGJ7KI+Pc= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4/go.mod h1:bau/6AJhvEcu9GKKYHlDXAxXKzYNfhP6xu2GXuxEcFk= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= -google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= -google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/asset-transfer-abac/chaincode-go/smart-contract/abac.go b/asset-transfer-abac/chaincode-go/smart-contract/abac.go deleted file mode 100644 index 30816c64..00000000 --- a/asset-transfer-abac/chaincode-go/smart-contract/abac.go +++ /dev/null @@ -1,214 +0,0 @@ -package abac - -import ( - "encoding/base64" - "encoding/json" - "fmt" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -// SmartContract provides functions for managing an Asset -type SmartContract struct { - contractapi.Contract -} - -// Asset describes basic details of what makes up a simple asset -type Asset struct { - ID string `json:"ID"` - Color string `json:"color"` - Size int `json:"size"` - Owner string `json:"owner"` - AppraisedValue int `json:"appraisedValue"` -} - -// CreateAsset issues a new asset to the world state with given details. -func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, id string, color string, size int, appraisedValue int) error { - - // Demonstrate the use of Attribute-Based Access Control (ABAC) by checking - // to see if the caller has the "abac.creator" attribute with a value of true; - // if not, return an error. - - err := ctx.GetClientIdentity().AssertAttributeValue("abac.creator", "true") - if err != nil { - return fmt.Errorf("submitting client not authorized to create asset, does not have abac.creator role") - } - - exists, err := s.AssetExists(ctx, id) - if err != nil { - return err - } - if exists { - return fmt.Errorf("the asset %s already exists", id) - } - - // Get ID of submitting client identity - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return err - } - - asset := Asset{ - ID: id, - Color: color, - Size: size, - Owner: clientID, - AppraisedValue: appraisedValue, - } - assetJSON, err := json.Marshal(asset) - if err != nil { - return err - } - - return ctx.GetStub().PutState(id, assetJSON) -} - -// UpdateAsset updates an existing asset in the world state with provided parameters. -func (s *SmartContract) UpdateAsset(ctx contractapi.TransactionContextInterface, id string, newColor string, newSize int, newValue int) error { - - asset, err := s.ReadAsset(ctx, id) - if err != nil { - return err - } - - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return err - } - - if clientID != asset.Owner { - return fmt.Errorf("submitting client not authorized to update asset, does not own asset") - } - - asset.Color = newColor - asset.Size = newSize - asset.AppraisedValue = newValue - - assetJSON, err := json.Marshal(asset) - if err != nil { - return err - } - - return ctx.GetStub().PutState(id, assetJSON) -} - -// DeleteAsset deletes a given asset from the world state. -func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface, id string) error { - - asset, err := s.ReadAsset(ctx, id) - if err != nil { - return err - } - - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return err - } - - if clientID != asset.Owner { - return fmt.Errorf("submitting client not authorized to update asset, does not own asset") - } - - return ctx.GetStub().DelState(id) -} - -// TransferAsset updates the owner field of asset with given id in world state. -func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) error { - - asset, err := s.ReadAsset(ctx, id) - if err != nil { - return err - } - - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return err - } - - if clientID != asset.Owner { - return fmt.Errorf("submitting client not authorized to update asset, does not own asset") - } - - asset.Owner = newOwner - assetJSON, err := json.Marshal(asset) - if err != nil { - return err - } - - return ctx.GetStub().PutState(id, assetJSON) -} - -// ReadAsset returns the asset stored in the world state with given id. -func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, id string) (*Asset, error) { - - assetJSON, err := ctx.GetStub().GetState(id) - if err != nil { - return nil, fmt.Errorf("failed to read from world state: %v", err) - } - if assetJSON == nil { - return nil, fmt.Errorf("the asset %s does not exist", id) - } - - var asset Asset - err = json.Unmarshal(assetJSON, &asset) - if err != nil { - return nil, err - } - - return &asset, nil -} - -// GetAllAssets returns all assets found in world state -func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface) ([]*Asset, error) { - // range query with empty string for startKey and endKey does an - // open-ended query of all assets in the chaincode namespace. - resultsIterator, err := ctx.GetStub().GetStateByRange("", "") - if err != nil { - return nil, err - } - defer resultsIterator.Close() - - var assets []*Asset - for resultsIterator.HasNext() { - queryResponse, err := resultsIterator.Next() - if err != nil { - return nil, err - } - - var asset Asset - err = json.Unmarshal(queryResponse.Value, &asset) - if err != nil { - return nil, err - } - assets = append(assets, &asset) - } - - return assets, nil -} - -// AssetExists returns true when asset with given ID exists in world state -func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, id string) (bool, error) { - - assetJSON, err := ctx.GetStub().GetState(id) - if err != nil { - return false, fmt.Errorf("failed to read from world state: %v", err) - } - - return assetJSON != nil, nil -} - -// GetSubmittingClientIdentity returns the name and issuer of the identity that -// invokes the smart contract. This function base64 decodes the identity string -// before returning the value to the client or smart contract. -func (s *SmartContract) GetSubmittingClientIdentity(ctx contractapi.TransactionContextInterface) (string, error) { - - b64ID, err := ctx.GetClientIdentity().GetID() - if err != nil { - return "", fmt.Errorf("Failed to read clientID: %v", err) - } - decodeID, err := base64.StdEncoding.DecodeString(b64ID) - if err != nil { - return "", fmt.Errorf("failed to base64 decode clientID: %v", err) - } - return string(decodeID), nil -} diff --git a/asset-transfer-abac/chaincode-go/smartContract.go b/asset-transfer-abac/chaincode-go/smartContract.go deleted file mode 100644 index cef4262b..00000000 --- a/asset-transfer-abac/chaincode-go/smartContract.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "log" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" - abac "github.com/hyperledger/fabric-samples/asset-transfer-abac/chaincode-go/smart-contract" -) - -func main() { - abacSmartContract, err := contractapi.NewChaincode(&abac.SmartContract{}) - if err != nil { - log.Panicf("Error creating abac chaincode: %v", err) - } - - if err := abacSmartContract.Start(); err != nil { - log.Panicf("Error starting abac chaincode: %v", err) - } -} diff --git a/asset-transfer-basic/application-gateway-go/assetTransfer.go b/asset-transfer-basic/application-gateway-go/assetTransfer.go deleted file mode 100755 index 348d2341..00000000 --- a/asset-transfer-basic/application-gateway-go/assetTransfer.go +++ /dev/null @@ -1,296 +0,0 @@ -/* -Copyright 2021 IBM All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "bytes" - "context" - "crypto/x509" - "encoding/json" - "errors" - "fmt" - "os" - "path" - "time" - - "github.com/hyperledger/fabric-gateway/pkg/client" - "github.com/hyperledger/fabric-gateway/pkg/hash" - "github.com/hyperledger/fabric-gateway/pkg/identity" - "github.com/hyperledger/fabric-protos-go-apiv2/gateway" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/status" -) - -const ( - mspID = "Org1MSP" - cryptoPath = "../../test-network/organizations/peerOrganizations/org1.example.com" - certPath = cryptoPath + "/users/User1@org1.example.com/msp/signcerts" - keyPath = cryptoPath + "/users/User1@org1.example.com/msp/keystore" - tlsCertPath = cryptoPath + "/peers/peer0.org1.example.com/tls/ca.crt" - peerEndpoint = "dns:///localhost:7051" - gatewayPeer = "peer0.org1.example.com" -) - -var now = time.Now() -var assetId = fmt.Sprintf("asset%d", now.Unix()*1e3+int64(now.Nanosecond())/1e6) - -func main() { - // The gRPC client connection should be shared by all Gateway connections to this endpoint - clientConnection := newGrpcConnection() - defer clientConnection.Close() - - id := newIdentity() - sign := newSign() - - // Create a Gateway connection for a specific client identity - gw, err := client.Connect( - id, - client.WithSign(sign), - client.WithHash(hash.SHA256), - client.WithClientConnection(clientConnection), - // Default timeouts for different gRPC calls - client.WithEvaluateTimeout(5*time.Second), - client.WithEndorseTimeout(15*time.Second), - client.WithSubmitTimeout(5*time.Second), - client.WithCommitStatusTimeout(1*time.Minute), - ) - if err != nil { - panic(err) - } - defer gw.Close() - - // Override default values for chaincode and channel name as they may differ in testing contexts. - chaincodeName := "basic" - if ccname := os.Getenv("CHAINCODE_NAME"); ccname != "" { - chaincodeName = ccname - } - - channelName := "mychannel" - if cname := os.Getenv("CHANNEL_NAME"); cname != "" { - channelName = cname - } - - network := gw.GetNetwork(channelName) - contract := network.GetContract(chaincodeName) - - initLedger(contract) - getAllAssets(contract) - createAsset(contract) - readAssetByID(contract) - transferAssetAsync(contract) - exampleErrorHandling(contract) -} - -// newGrpcConnection creates a gRPC connection to the Gateway server. -func newGrpcConnection() *grpc.ClientConn { - certificatePEM, err := os.ReadFile(tlsCertPath) - if err != nil { - panic(fmt.Errorf("failed to read TLS certifcate file: %w", err)) - } - - certificate, err := identity.CertificateFromPEM(certificatePEM) - if err != nil { - panic(err) - } - - certPool := x509.NewCertPool() - certPool.AddCert(certificate) - transportCredentials := credentials.NewClientTLSFromCert(certPool, gatewayPeer) - - connection, err := grpc.NewClient(peerEndpoint, grpc.WithTransportCredentials(transportCredentials)) - if err != nil { - panic(fmt.Errorf("failed to create gRPC connection: %w", err)) - } - - return connection -} - -// newIdentity creates a client identity for this Gateway connection using an X.509 certificate. -func newIdentity() *identity.X509Identity { - certificatePEM, err := readFirstFile(certPath) - if err != nil { - panic(fmt.Errorf("failed to read certificate file: %w", err)) - } - - certificate, err := identity.CertificateFromPEM(certificatePEM) - if err != nil { - panic(err) - } - - id, err := identity.NewX509Identity(mspID, certificate) - if err != nil { - panic(err) - } - - return id -} - -// newSign creates a function that generates a digital signature from a message digest using a private key. -func newSign() identity.Sign { - privateKeyPEM, err := readFirstFile(keyPath) - if err != nil { - panic(fmt.Errorf("failed to read private key file: %w", err)) - } - - privateKey, err := identity.PrivateKeyFromPEM(privateKeyPEM) - if err != nil { - panic(err) - } - - sign, err := identity.NewPrivateKeySign(privateKey) - if err != nil { - panic(err) - } - - return sign -} - -func readFirstFile(dirPath string) ([]byte, error) { - dir, err := os.Open(dirPath) - if err != nil { - return nil, err - } - - fileNames, err := dir.Readdirnames(1) - if err != nil { - return nil, err - } - - return os.ReadFile(path.Join(dirPath, fileNames[0])) -} - -// This type of transaction would typically only be run once by an application the first time it was started after its -// initial deployment. A new version of the chaincode deployed later would likely not need to run an "init" function. -func initLedger(contract *client.Contract) { - fmt.Printf("\n--> Submit Transaction: InitLedger, function creates the initial set of assets on the ledger \n") - - _, err := contract.SubmitTransaction("InitLedger") - if err != nil { - panic(fmt.Errorf("failed to submit transaction: %w", err)) - } - - fmt.Printf("*** Transaction committed successfully\n") -} - -// Evaluate a transaction to query ledger state. -func getAllAssets(contract *client.Contract) { - fmt.Println("\n--> Evaluate Transaction: GetAllAssets, function returns all the current assets on the ledger") - - evaluateResult, err := contract.EvaluateTransaction("GetAllAssets") - if err != nil { - panic(fmt.Errorf("failed to evaluate transaction: %w", err)) - } - result := formatJSON(evaluateResult) - - fmt.Printf("*** Result:%s\n", result) -} - -// Submit a transaction synchronously, blocking until it has been committed to the ledger. -func createAsset(contract *client.Contract) { - fmt.Printf("\n--> Submit Transaction: CreateAsset, creates new asset with ID, Color, Size, Owner and AppraisedValue arguments \n") - - _, err := contract.SubmitTransaction("CreateAsset", assetId, "yellow", "5", "Tom", "1300") - if err != nil { - panic(fmt.Errorf("failed to submit transaction: %w", err)) - } - - fmt.Printf("*** Transaction committed successfully\n") -} - -// Evaluate a transaction by assetID to query ledger state. -func readAssetByID(contract *client.Contract) { - fmt.Printf("\n--> Evaluate Transaction: ReadAsset, function returns asset attributes\n") - - evaluateResult, err := contract.EvaluateTransaction("ReadAsset", assetId) - if err != nil { - panic(fmt.Errorf("failed to evaluate transaction: %w", err)) - } - result := formatJSON(evaluateResult) - - fmt.Printf("*** Result:%s\n", result) -} - -// Submit transaction asynchronously, blocking until the transaction has been sent to the orderer, and allowing -// this thread to process the chaincode response (e.g. update a UI) without waiting for the commit notification -func transferAssetAsync(contract *client.Contract) { - fmt.Printf("\n--> Async Submit Transaction: TransferAsset, updates existing asset owner") - - submitResult, commit, err := contract.SubmitAsync("TransferAsset", client.WithArguments(assetId, "Mark")) - if err != nil { - panic(fmt.Errorf("failed to submit transaction asynchronously: %w", err)) - } - - fmt.Printf("\n*** Successfully submitted transaction to transfer ownership from %s to Mark. \n", string(submitResult)) - fmt.Println("*** Waiting for transaction commit.") - - if commitStatus, err := commit.Status(); err != nil { - panic(fmt.Errorf("failed to get commit status: %w", err)) - } else if !commitStatus.Successful { - panic(fmt.Errorf("transaction %s failed to commit with status: %d", commitStatus.TransactionID, int32(commitStatus.Code))) - } - - fmt.Printf("*** Transaction committed successfully\n") -} - -// Submit transaction, passing in the wrong number of arguments ,expected to throw an error containing details of any error responses from the smart contract. -func exampleErrorHandling(contract *client.Contract) { - fmt.Println("\n--> Submit Transaction: UpdateAsset asset70, asset70 does not exist and should return an error") - - _, err := contract.SubmitTransaction("UpdateAsset", "asset70", "blue", "5", "Tomoko", "300") - if err == nil { - panic("******** FAILED to return an error") - } - - fmt.Println("*** Successfully caught the error:") - - var endorseErr *client.EndorseError - var submitErr *client.SubmitError - var commitStatusErr *client.CommitStatusError - var commitErr *client.CommitError - - if errors.As(err, &endorseErr) { - fmt.Printf("Endorse error for transaction %s with gRPC status %v: %s\n", endorseErr.TransactionID, status.Code(endorseErr), endorseErr) - } else if errors.As(err, &submitErr) { - fmt.Printf("Submit error for transaction %s with gRPC status %v: %s\n", submitErr.TransactionID, status.Code(submitErr), submitErr) - } else if errors.As(err, &commitStatusErr) { - if errors.Is(err, context.DeadlineExceeded) { - fmt.Printf("Timeout waiting for transaction %s commit status: %s", commitStatusErr.TransactionID, commitStatusErr) - } else { - fmt.Printf("Error obtaining commit status for transaction %s with gRPC status %v: %s\n", commitStatusErr.TransactionID, status.Code(commitStatusErr), commitStatusErr) - } - } else if errors.As(err, &commitErr) { - fmt.Printf("Transaction %s failed to commit with status %d: %s\n", commitErr.TransactionID, int32(commitErr.Code), err) - } else { - panic(fmt.Errorf("unexpected error type %T: %w", err, err)) - } - - // Any error that originates from a peer or orderer node external to the gateway will have its details - // embedded within the gRPC status error. The following code shows how to extract that. - statusErr := status.Convert(err) - - details := statusErr.Details() - if len(details) > 0 { - fmt.Println("Error Details:") - - for _, detail := range details { - switch detail := detail.(type) { - case *gateway.ErrorDetail: - fmt.Printf("- address: %s; mspId: %s; message: %s\n", detail.Address, detail.MspId, detail.Message) - } - } - } -} - -// Format JSON data -func formatJSON(data []byte) string { - var prettyJSON bytes.Buffer - if err := json.Indent(&prettyJSON, data, "", " "); err != nil { - panic(fmt.Errorf("failed to parse JSON: %w", err)) - } - return prettyJSON.String() -} diff --git a/asset-transfer-basic/application-gateway-go/go.mod b/asset-transfer-basic/application-gateway-go/go.mod deleted file mode 100644 index 7261969c..00000000 --- a/asset-transfer-basic/application-gateway-go/go.mod +++ /dev/null @@ -1,19 +0,0 @@ -module assetTransfer - -go 1.22.0 - -require ( - github.com/hyperledger/fabric-gateway v1.7.0 - github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 - google.golang.org/grpc v1.67.1 -) - -require ( - github.com/miekg/pkcs11 v1.1.1 // indirect - golang.org/x/crypto v0.28.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.26.0 // indirect - golang.org/x/text v0.19.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect - google.golang.org/protobuf v1.35.1 // indirect -) diff --git a/asset-transfer-basic/application-gateway-go/go.sum b/asset-transfer-basic/application-gateway-go/go.sum deleted file mode 100644 index 01eab6a8..00000000 --- a/asset-transfer-basic/application-gateway-go/go.sum +++ /dev/null @@ -1,32 +0,0 @@ -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hyperledger/fabric-gateway v1.7.0 h1:bd1quU8qYPYqYO69m1tPIDSjB+D+u/rBJfE1eWFcpjY= -github.com/hyperledger/fabric-gateway v1.7.0/go.mod h1:TItDGnq71eJcgz5TW+m5Sq3kWGp0AEI1HPCNxj0Eu7k= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 h1:YJrd+gMaeY0/vsN0aS0QkEKTivGoUnSRIXxGJ7KI+Pc= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4/go.mod h1:bau/6AJhvEcu9GKKYHlDXAxXKzYNfhP6xu2GXuxEcFk= -github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= -github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= -golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= -google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= -google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/asset-transfer-basic/application-gateway-java/build.gradle b/asset-transfer-basic/application-gateway-java/build.gradle deleted file mode 100644 index 7db92de8..00000000 --- a/asset-transfer-basic/application-gateway-java/build.gradle +++ /dev/null @@ -1,39 +0,0 @@ -/* - * This file was generated by the Gradle 'init' task. - * - * This generated file contains a sample Java project to get you started. - * For more details take a look at the Java Quickstart chapter in the Gradle - * User Manual available at https://docs.gradle.org/6.5/userguide/tutorial_java_projects.html - */ -plugins { - // Apply the application plugin to add support for building a CLI application. - id 'application' -} - -ext { - javaMainClass = "application.java.App" -} - -repositories { - mavenCentral() -} - -dependencies { - implementation 'org.hyperledger.fabric:fabric-gateway:1.7.0' - implementation platform('com.google.protobuf:protobuf-bom:4.28.2') - implementation platform('io.grpc:grpc-bom:1.67.1') - compileOnly 'io.grpc:grpc-api' - runtimeOnly 'io.grpc:grpc-netty-shaded' - implementation 'com.google.code.gson:gson:2.11.0' -} - -java { - toolchain { - languageVersion = JavaLanguageVersion.of(11) - } -} - -application { - // Define the main class for the application. - mainClass = 'App' -} diff --git a/asset-transfer-basic/application-gateway-java/gradle/wrapper/gradle-wrapper.jar b/asset-transfer-basic/application-gateway-java/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index d64cd4917707c1f8861d8cb53dd15194d4248596..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43462 zcma&NWl&^owk(X(xVyW%ySuwf;qI=D6|RlDJ2cR^yEKh!@I- zp9QeisK*rlxC>+~7Dk4IxIRsKBHqdR9b3+fyL=ynHmIDe&|>O*VlvO+%z5;9Z$|DJ zb4dO}-R=MKr^6EKJiOrJdLnCJn>np?~vU-1sSFgPu;pthGwf}bG z(1db%xwr#x)r+`4AGu$j7~u2MpVs3VpLp|mx&;>`0p0vH6kF+D2CY0fVdQOZ@h;A` z{infNyvmFUiu*XG}RNMNwXrbec_*a3N=2zJ|Wh5z* z5rAX$JJR{#zP>KY**>xHTuw?|-Rg|o24V)74HcfVT;WtQHXlE+_4iPE8QE#DUm%x0 zEKr75ur~W%w#-My3Tj`hH6EuEW+8K-^5P62$7Sc5OK+22qj&Pd1;)1#4tKihi=~8C zHiQSst0cpri6%OeaR`PY>HH_;CPaRNty%WTm4{wDK8V6gCZlG@U3$~JQZ;HPvDJcT1V{ z?>H@13MJcCNe#5z+MecYNi@VT5|&UiN1D4ATT+%M+h4c$t;C#UAs3O_q=GxK0}8%8 z8J(_M9bayxN}69ex4dzM_P3oh@ZGREjVvn%%r7=xjkqxJP4kj}5tlf;QosR=%4L5y zWhgejO=vao5oX%mOHbhJ8V+SG&K5dABn6!WiKl{|oPkq(9z8l&Mm%(=qGcFzI=eLu zWc_oCLyf;hVlB@dnwY98?75B20=n$>u3b|NB28H0u-6Rpl((%KWEBOfElVWJx+5yg z#SGqwza7f}$z;n~g%4HDU{;V{gXIhft*q2=4zSezGK~nBgu9-Q*rZ#2f=Q}i2|qOp z!!y4p)4o=LVUNhlkp#JL{tfkhXNbB=Ox>M=n6soptJw-IDI|_$is2w}(XY>a=H52d z3zE$tjPUhWWS+5h=KVH&uqQS=$v3nRs&p$%11b%5qtF}S2#Pc`IiyBIF4%A!;AVoI zXU8-Rpv!DQNcF~(qQnyyMy=-AN~U>#&X1j5BLDP{?K!%h!;hfJI>$mdLSvktEr*89 zdJHvby^$xEX0^l9g$xW-d?J;L0#(`UT~zpL&*cEh$L|HPAu=P8`OQZV!-}l`noSp_ zQ-1$q$R-gDL)?6YaM!=8H=QGW$NT2SeZlb8PKJdc=F-cT@j7Xags+Pr*jPtlHFnf- zh?q<6;)27IdPc^Wdy-mX%2s84C1xZq9Xms+==F4);O`VUASmu3(RlgE#0+#giLh-& zcxm3_e}n4{%|X zJp{G_j+%`j_q5}k{eW&TlP}J2wtZ2^<^E(O)4OQX8FDp6RJq!F{(6eHWSD3=f~(h} zJXCf7=r<16X{pHkm%yzYI_=VDP&9bmI1*)YXZeB}F? z(%QsB5fo*FUZxK$oX~X^69;x~j7ms8xlzpt-T15e9}$4T-pC z6PFg@;B-j|Ywajpe4~bk#S6(fO^|mm1hKOPfA%8-_iGCfICE|=P_~e;Wz6my&)h_~ zkv&_xSAw7AZ%ThYF(4jADW4vg=oEdJGVOs>FqamoL3Np8>?!W#!R-0%2Bg4h?kz5I zKV-rKN2n(vUL%D<4oj@|`eJ>0i#TmYBtYmfla;c!ATW%;xGQ0*TW@PTlGG><@dxUI zg>+3SiGdZ%?5N=8uoLA|$4isK$aJ%i{hECP$bK{J#0W2gQ3YEa zZQ50Stn6hqdfxJ*9#NuSLwKFCUGk@c=(igyVL;;2^wi4o30YXSIb2g_ud$ zgpCr@H0qWtk2hK8Q|&wx)}4+hTYlf;$a4#oUM=V@Cw#!$(nOFFpZ;0lc!qd=c$S}Z zGGI-0jg~S~cgVT=4Vo)b)|4phjStD49*EqC)IPwyeKBLcN;Wu@Aeph;emROAwJ-0< z_#>wVm$)ygH|qyxZaet&(Vf%pVdnvKWJn9`%DAxj3ot;v>S$I}jJ$FLBF*~iZ!ZXE zkvui&p}fI0Y=IDX)mm0@tAd|fEHl~J&K}ZX(Mm3cm1UAuwJ42+AO5@HwYfDH7ipIc zmI;1J;J@+aCNG1M`Btf>YT>~c&3j~Qi@Py5JT6;zjx$cvOQW@3oQ>|}GH?TW-E z1R;q^QFjm5W~7f}c3Ww|awg1BAJ^slEV~Pk`Kd`PS$7;SqJZNj->it4DW2l15}xP6 zoCl$kyEF%yJni0(L!Z&14m!1urXh6Btj_5JYt1{#+H8w?5QI%% zo-$KYWNMJVH?Hh@1n7OSu~QhSswL8x0=$<8QG_zepi_`y_79=nK=_ZP_`Em2UI*tyQoB+r{1QYZCpb?2OrgUw#oRH$?^Tj!Req>XiE#~B|~ z+%HB;=ic+R@px4Ld8mwpY;W^A%8%l8$@B@1m5n`TlKI6bz2mp*^^^1mK$COW$HOfp zUGTz-cN9?BGEp}5A!mDFjaiWa2_J2Iq8qj0mXzk; z66JBKRP{p%wN7XobR0YjhAuW9T1Gw3FDvR5dWJ8ElNYF94eF3ebu+QwKjtvVu4L zI9ip#mQ@4uqVdkl-TUQMb^XBJVLW(-$s;Nq;@5gr4`UfLgF$adIhd?rHOa%D);whv z=;krPp~@I+-Z|r#s3yCH+c1US?dnm+C*)r{m+86sTJusLdNu^sqLrfWed^ndHXH`m zd3#cOe3>w-ga(Dus_^ppG9AC>Iq{y%%CK+Cro_sqLCs{VLuK=dev>OL1dis4(PQ5R zcz)>DjEkfV+MO;~>VUlYF00SgfUo~@(&9$Iy2|G0T9BSP?&T22>K46D zL*~j#yJ?)^*%J3!16f)@Y2Z^kS*BzwfAQ7K96rFRIh>#$*$_Io;z>ux@}G98!fWR@ zGTFxv4r~v)Gsd|pF91*-eaZ3Qw1MH$K^7JhWIdX%o$2kCbvGDXy)a?@8T&1dY4`;L z4Kn+f%SSFWE_rpEpL9bnlmYq`D!6F%di<&Hh=+!VI~j)2mfil03T#jJ_s?}VV0_hp z7T9bWxc>Jm2Z0WMU?`Z$xE74Gu~%s{mW!d4uvKCx@WD+gPUQ zV0vQS(Ig++z=EHN)BR44*EDSWIyT~R4$FcF*VEY*8@l=218Q05D2$|fXKFhRgBIEE zdDFB}1dKkoO^7}{5crKX!p?dZWNz$m>1icsXG2N+((x0OIST9Zo^DW_tytvlwXGpn zs8?pJXjEG;T@qrZi%#h93?FP$!&P4JA(&H61tqQi=opRzNpm zkrG}$^t9&XduK*Qa1?355wd8G2CI6QEh@Ua>AsD;7oRUNLPb76m4HG3K?)wF~IyS3`fXuNM>${?wmB zpVz;?6_(Fiadfd{vUCBM*_kt$+F3J+IojI;9L(gc9n3{sEZyzR9o!_mOwFC#tQ{Q~ zP3-`#uK#tP3Q7~Q;4H|wjZHO8h7e4IuBxl&vz2w~D8)w=Wtg31zpZhz%+kzSzL*dV zwp@{WU4i;hJ7c2f1O;7Mz6qRKeASoIv0_bV=i@NMG*l<#+;INk-^`5w@}Dj~;k=|}qM1vq_P z|GpBGe_IKq|LNy9SJhKOQ$c=5L{Dv|Q_lZl=-ky*BFBJLW9&y_C|!vyM~rQx=!vun z?rZJQB5t}Dctmui5i31C_;_}CEn}_W%>oSXtt>@kE1=JW*4*v4tPp;O6 zmAk{)m!)}34pTWg8{i>($%NQ(Tl;QC@J@FfBoc%Gr&m560^kgSfodAFrIjF}aIw)X zoXZ`@IsMkc8_=w%-7`D6Y4e*CG8k%Ud=GXhsTR50jUnm+R*0A(O3UKFg0`K;qp1bl z7``HN=?39ic_kR|^R^~w-*pa?Vj#7|e9F1iRx{GN2?wK!xR1GW!qa=~pjJb-#u1K8 zeR?Y2i-pt}yJq;SCiVHODIvQJX|ZJaT8nO+(?HXbLefulKKgM^B(UIO1r+S=7;kLJ zcH}1J=Px2jsh3Tec&v8Jcbng8;V-`#*UHt?hB(pmOipKwf3Lz8rG$heEB30Sg*2rx zV<|KN86$soN(I!BwO`1n^^uF2*x&vJ$2d$>+`(romzHP|)K_KkO6Hc>_dwMW-M(#S zK(~SiXT1@fvc#U+?|?PniDRm01)f^#55;nhM|wi?oG>yBsa?~?^xTU|fX-R(sTA+5 zaq}-8Tx7zrOy#3*JLIIVsBmHYLdD}!0NP!+ITW+Thn0)8SS!$@)HXwB3tY!fMxc#1 zMp3H?q3eD?u&Njx4;KQ5G>32+GRp1Ee5qMO0lZjaRRu&{W<&~DoJNGkcYF<5(Ab+J zgO>VhBl{okDPn78<%&e2mR{jwVCz5Og;*Z;;3%VvoGo_;HaGLWYF7q#jDX=Z#Ml`H z858YVV$%J|e<1n`%6Vsvq7GmnAV0wW4$5qQ3uR@1i>tW{xrl|ExywIc?fNgYlA?C5 zh$ezAFb5{rQu6i7BSS5*J-|9DQ{6^BVQ{b*lq`xS@RyrsJN?-t=MTMPY;WYeKBCNg z^2|pN!Q^WPJuuO4!|P@jzt&tY1Y8d%FNK5xK(!@`jO2aEA*4 zkO6b|UVBipci?){-Ke=+1;mGlND8)6+P;8sq}UXw2hn;fc7nM>g}GSMWu&v&fqh

iViYT=fZ(|3Ox^$aWPp4a8h24tD<|8-!aK0lHgL$N7Efw}J zVIB!7=T$U`ao1?upi5V4Et*-lTG0XvExbf!ya{cua==$WJyVG(CmA6Of*8E@DSE%L z`V^$qz&RU$7G5mg;8;=#`@rRG`-uS18$0WPN@!v2d{H2sOqP|!(cQ@ zUHo!d>>yFArLPf1q`uBvY32miqShLT1B@gDL4XoVTK&@owOoD)OIHXrYK-a1d$B{v zF^}8D3Y^g%^cnvScOSJR5QNH+BI%d|;J;wWM3~l>${fb8DNPg)wrf|GBP8p%LNGN# z3EaIiItgwtGgT&iYCFy9-LG}bMI|4LdmmJt@V@% zb6B)1kc=T)(|L@0;wr<>=?r04N;E&ef+7C^`wPWtyQe(*pD1pI_&XHy|0gIGHMekd zF_*M4yi6J&Z4LQj65)S zXwdM{SwUo%3SbPwFsHgqF@V|6afT|R6?&S;lw=8% z3}@9B=#JI3@B*#4s!O))~z zc>2_4Q_#&+5V`GFd?88^;c1i7;Vv_I*qt!_Yx*n=;rj!82rrR2rQ8u5(Ejlo{15P% zs~!{%XJ>FmJ})H^I9bn^Re&38H{xA!0l3^89k(oU;bZWXM@kn$#aoS&Y4l^-WEn-fH39Jb9lA%s*WsKJQl?n9B7_~P z-XM&WL7Z!PcoF6_D>V@$CvUIEy=+Z&0kt{szMk=f1|M+r*a43^$$B^MidrT0J;RI` z(?f!O<8UZkm$_Ny$Hth1J#^4ni+im8M9mr&k|3cIgwvjAgjH z8`N&h25xV#v*d$qBX5jkI|xOhQn!>IYZK7l5#^P4M&twe9&Ey@@GxYMxBZq2e7?`q z$~Szs0!g{2fGcp9PZEt|rdQ6bhAgpcLHPz?f-vB?$dc*!9OL?Q8mn7->bFD2Si60* z!O%y)fCdMSV|lkF9w%x~J*A&srMyYY3{=&$}H zGQ4VG_?$2X(0|vT0{=;W$~icCI{b6W{B!Q8xdGhF|D{25G_5_+%s(46lhvNLkik~R z>nr(&C#5wwOzJZQo9m|U<;&Wk!_#q|V>fsmj1g<6%hB{jGoNUPjgJslld>xmODzGjYc?7JSuA?A_QzjDw5AsRgi@Y|Z0{F{!1=!NES-#*f^s4l0Hu zz468))2IY5dmD9pa*(yT5{EyP^G>@ZWumealS-*WeRcZ}B%gxq{MiJ|RyX-^C1V=0 z@iKdrGi1jTe8Ya^x7yyH$kBNvM4R~`fbPq$BzHum-3Zo8C6=KW@||>zsA8-Y9uV5V z#oq-f5L5}V<&wF4@X@<3^C%ptp6+Ce)~hGl`kwj)bsAjmo_GU^r940Z-|`<)oGnh7 zFF0Tde3>ui?8Yj{sF-Z@)yQd~CGZ*w-6p2U<8}JO-sRsVI5dBji`01W8A&3$?}lxBaC&vn0E$c5tW* zX>5(zzZ=qn&!J~KdsPl;P@bmA-Pr8T*)eh_+Dv5=Ma|XSle6t(k8qcgNyar{*ReQ8 zTXwi=8vr>!3Ywr+BhggHDw8ke==NTQVMCK`$69fhzEFB*4+H9LIvdt-#IbhZvpS}} zO3lz;P?zr0*0$%-Rq_y^k(?I{Mk}h@w}cZpMUp|ucs55bcloL2)($u%mXQw({Wzc~ z;6nu5MkjP)0C(@%6Q_I_vsWrfhl7Zpoxw#WoE~r&GOSCz;_ro6i(^hM>I$8y>`!wW z*U^@?B!MMmb89I}2(hcE4zN2G^kwyWCZp5JG>$Ez7zP~D=J^LMjSM)27_0B_X^C(M z`fFT+%DcKlu?^)FCK>QzSnV%IsXVcUFhFdBP!6~se&xxrIxsvySAWu++IrH;FbcY$ z2DWTvSBRfLwdhr0nMx+URA$j3i7_*6BWv#DXfym?ZRDcX9C?cY9sD3q)uBDR3uWg= z(lUIzB)G$Hr!){>E{s4Dew+tb9kvToZp-1&c?y2wn@Z~(VBhqz`cB;{E4(P3N2*nJ z_>~g@;UF2iG{Kt(<1PyePTKahF8<)pozZ*xH~U-kfoAayCwJViIrnqwqO}7{0pHw$ zs2Kx?s#vQr7XZ264>5RNKSL8|Ty^=PsIx^}QqOOcfpGUU4tRkUc|kc7-!Ae6!+B{o~7nFpm3|G5^=0#Bnm6`V}oSQlrX(u%OWnC zoLPy&Q;1Jui&7ST0~#+}I^&?vcE*t47~Xq#YwvA^6^} z`WkC)$AkNub|t@S!$8CBlwbV~?yp&@9h{D|3z-vJXgzRC5^nYm+PyPcgRzAnEi6Q^gslXYRv4nycsy-SJu?lMps-? zV`U*#WnFsdPLL)Q$AmD|0`UaC4ND07+&UmOu!eHruzV|OUox<+Jl|Mr@6~C`T@P%s zW7sgXLF2SSe9Fl^O(I*{9wsFSYb2l%-;&Pi^dpv!{)C3d0AlNY6!4fgmSgj_wQ*7Am7&$z;Jg&wgR-Ih;lUvWS|KTSg!&s_E9_bXBkZvGiC6bFKDWZxsD$*NZ#_8bl zG1P-#@?OQzED7@jlMJTH@V!6k;W>auvft)}g zhoV{7$q=*;=l{O>Q4a@ ziMjf_u*o^PsO)#BjC%0^h>Xp@;5$p{JSYDt)zbb}s{Kbt!T*I@Pk@X0zds6wsefuU zW$XY%yyRGC94=6mf?x+bbA5CDQ2AgW1T-jVAJbm7K(gp+;v6E0WI#kuACgV$r}6L? zd|Tj?^%^*N&b>Dd{Wr$FS2qI#Ucs1yd4N+RBUQiSZGujH`#I)mG&VKoDh=KKFl4=G z&MagXl6*<)$6P}*Tiebpz5L=oMaPrN+caUXRJ`D?=K9!e0f{@D&cZLKN?iNP@X0aF zE(^pl+;*T5qt?1jRC=5PMgV!XNITRLS_=9{CJExaQj;lt!&pdzpK?8p>%Mb+D z?yO*uSung=-`QQ@yX@Hyd4@CI^r{2oiu`%^bNkz+Nkk!IunjwNC|WcqvX~k=><-I3 zDQdbdb|!v+Iz01$w@aMl!R)koD77Xp;eZwzSl-AT zr@Vu{=xvgfq9akRrrM)}=!=xcs+U1JO}{t(avgz`6RqiiX<|hGG1pmop8k6Q+G_mv zJv|RfDheUp2L3=^C=4aCBMBn0aRCU(DQwX-W(RkRwmLeuJYF<0urcaf(=7)JPg<3P zQs!~G)9CT18o!J4{zX{_e}4eS)U-E)0FAt}wEI(c0%HkxgggW;(1E=>J17_hsH^sP z%lT0LGgbUXHx-K*CI-MCrP66UP0PvGqM$MkeLyqHdbgP|_Cm!7te~b8p+e6sQ_3k| zVcwTh6d83ltdnR>D^)BYQpDKlLk3g0Hdcgz2}%qUs9~~Rie)A-BV1mS&naYai#xcZ z(d{8=-LVpTp}2*y)|gR~;qc7fp26}lPcLZ#=JpYcn3AT9(UIdOyg+d(P5T7D&*P}# zQCYplZO5|7+r19%9e`v^vfSS1sbX1c%=w1;oyruXB%Kl$ACgKQ6=qNWLsc=28xJjg zwvsI5-%SGU|3p>&zXVl^vVtQT3o-#$UT9LI@Npz~6=4!>mc431VRNN8od&Ul^+G_kHC`G=6WVWM z%9eWNyy(FTO|A+@x}Ou3CH)oi;t#7rAxdIXfNFwOj_@Y&TGz6P_sqiB`Q6Lxy|Q{`|fgmRG(k+!#b*M+Z9zFce)f-7;?Km5O=LHV9f9_87; zF7%R2B+$?@sH&&-$@tzaPYkw0;=i|;vWdI|Wl3q_Zu>l;XdIw2FjV=;Mq5t1Q0|f< zs08j54Bp`3RzqE=2enlkZxmX6OF+@|2<)A^RNQpBd6o@OXl+i)zO%D4iGiQNuXd+zIR{_lb96{lc~bxsBveIw6umhShTX+3@ZJ=YHh@ zWY3(d0azg;7oHn>H<>?4@*RQbi>SmM=JrHvIG(~BrvI)#W(EAeO6fS+}mxxcc+X~W6&YVl86W9WFSS}Vz-f9vS?XUDBk)3TcF z8V?$4Q)`uKFq>xT=)Y9mMFVTUk*NIA!0$?RP6Ig0TBmUFrq*Q-Agq~DzxjStQyJ({ zBeZ;o5qUUKg=4Hypm|}>>L=XKsZ!F$yNTDO)jt4H0gdQ5$f|d&bnVCMMXhNh)~mN z@_UV6D7MVlsWz+zM+inZZp&P4fj=tm6fX)SG5H>OsQf_I8c~uGCig$GzuwViK54bcgL;VN|FnyQl>Ed7(@>=8$a_UKIz|V6CeVSd2(P z0Uu>A8A+muM%HLFJQ9UZ5c)BSAv_zH#1f02x?h9C}@pN@6{>UiAp>({Fn(T9Q8B z^`zB;kJ5b`>%dLm+Ol}ty!3;8f1XDSVX0AUe5P#@I+FQ-`$(a;zNgz)4x5hz$Hfbg z!Q(z26wHLXko(1`;(BAOg_wShpX0ixfWq3ponndY+u%1gyX)_h=v1zR#V}#q{au6; z!3K=7fQwnRfg6FXtNQmP>`<;!N137paFS%y?;lb1@BEdbvQHYC{976l`cLqn;b8lp zIDY>~m{gDj(wfnK!lpW6pli)HyLEiUrNc%eXTil|F2s(AY+LW5hkKb>TQ3|Q4S9rr zpDs4uK_co6XPsn_z$LeS{K4jFF`2>U`tbgKdyDne`xmR<@6AA+_hPNKCOR-Zqv;xk zu5!HsBUb^!4uJ7v0RuH-7?l?}b=w5lzzXJ~gZcxRKOovSk@|#V+MuX%Y+=;14i*%{)_gSW9(#4%)AV#3__kac1|qUy!uyP{>?U#5wYNq}y$S9pCc zFc~4mgSC*G~j0u#qqp9 z${>3HV~@->GqEhr_Xwoxq?Hjn#=s2;i~g^&Hn|aDKpA>Oc%HlW(KA1?BXqpxB;Ydx)w;2z^MpjJ(Qi(X!$5RC z*P{~%JGDQqojV>2JbEeCE*OEu!$XJ>bWA9Oa_Hd;y)F%MhBRi*LPcdqR8X`NQ&1L# z5#9L*@qxrx8n}LfeB^J{%-?SU{FCwiWyHp682F+|pa+CQa3ZLzBqN1{)h4d6+vBbV zC#NEbQLC;}me3eeYnOG*nXOJZEU$xLZ1<1Y=7r0(-U0P6-AqwMAM`a(Ed#7vJkn6plb4eI4?2y3yOTGmmDQ!z9`wzbf z_OY#0@5=bnep;MV0X_;;SJJWEf^E6Bd^tVJ9znWx&Ks8t*B>AM@?;D4oWUGc z!H*`6d7Cxo6VuyS4Eye&L1ZRhrRmN6Lr`{NL(wDbif|y&z)JN>Fl5#Wi&mMIr5i;x zBx}3YfF>>8EC(fYnmpu~)CYHuHCyr5*`ECap%t@y=jD>!_%3iiE|LN$mK9>- zHdtpy8fGZtkZF?%TW~29JIAfi2jZT8>OA7=h;8T{{k?c2`nCEx9$r zS+*&vt~2o^^J+}RDG@+9&M^K*z4p{5#IEVbz`1%`m5c2};aGt=V?~vIM}ZdPECDI)47|CWBCfDWUbxBCnmYivQ*0Nu_xb*C>~C9(VjHM zxe<*D<#dQ8TlpMX2c@M<9$w!RP$hpG4cs%AI){jp*Sj|*`m)5(Bw*A0$*i-(CA5#%>a)$+jI2C9r6|(>J8InryENI z$NohnxDUB;wAYDwrb*!N3noBTKPpPN}~09SEL18tkG zxgz(RYU_;DPT{l?Q$+eaZaxnsWCA^ds^0PVRkIM%bOd|G2IEBBiz{&^JtNsODs;5z zICt_Zj8wo^KT$7Bg4H+y!Df#3mbl%%?|EXe!&(Vmac1DJ*y~3+kRKAD=Ovde4^^%~ zw<9av18HLyrf*_>Slp;^i`Uy~`mvBjZ|?Ad63yQa#YK`4+c6;pW4?XIY9G1(Xh9WO8{F-Aju+nS9Vmv=$Ac0ienZ+p9*O%NG zMZKy5?%Z6TAJTE?o5vEr0r>f>hb#2w2U3DL64*au_@P!J!TL`oH2r*{>ffu6|A7tv zL4juf$DZ1MW5ZPsG!5)`k8d8c$J$o;%EIL0va9&GzWvkS%ZsGb#S(?{!UFOZ9<$a| zY|a+5kmD5N&{vRqkgY>aHsBT&`rg|&kezoD)gP0fsNYHsO#TRc_$n6Lf1Z{?+DLziXlHrq4sf(!>O{?Tj;Eh@%)+nRE_2VxbN&&%%caU#JDU%vL3}Cb zsb4AazPI{>8H&d=jUaZDS$-0^AxE@utGs;-Ez_F(qC9T=UZX=>ok2k2 ziTn{K?y~a5reD2A)P${NoI^>JXn>`IeArow(41c-Wm~)wiryEP(OS{YXWi7;%dG9v zI?mwu1MxD{yp_rrk!j^cKM)dc4@p4Ezyo%lRN|XyD}}>v=Xoib0gOcdXrQ^*61HNj z=NP|pd>@yfvr-=m{8$3A8TQGMTE7g=z!%yt`8`Bk-0MMwW~h^++;qyUP!J~ykh1GO z(FZ59xuFR$(WE;F@UUyE@Sp>`aVNjyj=Ty>_Vo}xf`e7`F;j-IgL5`1~-#70$9_=uBMq!2&1l zomRgpD58@)YYfvLtPW}{C5B35R;ZVvB<<#)x%srmc_S=A7F@DW8>QOEGwD6suhwCg z>Pa+YyULhmw%BA*4yjDp|2{!T98~<6Yfd(wo1mQ!KWwq0eg+6)o1>W~f~kL<-S+P@$wx*zeI|1t7z#Sxr5 zt6w+;YblPQNplq4Z#T$GLX#j6yldXAqj>4gAnnWtBICUnA&-dtnlh=t0Ho_vEKwV` z)DlJi#!@nkYV#$!)@>udAU*hF?V`2$Hf=V&6PP_|r#Iv*J$9)pF@X3`k;5})9^o4y z&)~?EjX5yX12O(BsFy-l6}nYeuKkiq`u9145&3Ssg^y{5G3Pse z9w(YVa0)N-fLaBq1`P!_#>SS(8fh_5!f{UrgZ~uEdeMJIz7DzI5!NHHqQtm~#CPij z?=N|J>nPR6_sL7!f4hD_|KH`vf8(Wpnj-(gPWH+ZvID}%?~68SwhPTC3u1_cB`otq z)U?6qo!ZLi5b>*KnYHWW=3F!p%h1;h{L&(Q&{qY6)_qxNfbP6E3yYpW!EO+IW3?@J z);4>g4gnl^8klu7uA>eGF6rIGSynacogr)KUwE_R4E5Xzi*Qir@b-jy55-JPC8c~( zo!W8y9OGZ&`xmc8;=4-U9=h{vCqfCNzYirONmGbRQlR`WWlgnY+1wCXbMz&NT~9*| z6@FrzP!LX&{no2!Ln_3|I==_4`@}V?4a;YZKTdw;vT<+K+z=uWbW(&bXEaWJ^W8Td z-3&1bY^Z*oM<=M}LVt>_j+p=2Iu7pZmbXrhQ_k)ysE9yXKygFNw$5hwDn(M>H+e1&9BM5!|81vd%r%vEm zqxY3?F@fb6O#5UunwgAHR9jp_W2zZ}NGp2%mTW@(hz7$^+a`A?mb8|_G*GNMJ) zjqegXQio=i@AINre&%ofexAr95aop5C+0MZ0m-l=MeO8m3epm7U%vZB8+I+C*iNFM z#T3l`gknX;D$-`2XT^Cg*vrv=RH+P;_dfF++cP?B_msQI4j+lt&rX2)3GaJx%W*Nn zkML%D{z5tpHH=dksQ*gzc|}gzW;lwAbxoR07VNgS*-c3d&8J|;@3t^ zVUz*J*&r7DFRuFVDCJDK8V9NN5hvpgGjwx+5n)qa;YCKe8TKtdnh{I7NU9BCN!0dq zczrBk8pE{{@vJa9ywR@mq*J=v+PG;?fwqlJVhijG!3VmIKs>9T6r7MJpC)m!Tc#>g zMtVsU>wbwFJEfwZ{vB|ZlttNe83)$iz`~#8UJ^r)lJ@HA&G#}W&ZH*;k{=TavpjWE z7hdyLZPf*X%Gm}i`Y{OGeeu^~nB8=`{r#TUrM-`;1cBvEd#d!kPqIgYySYhN-*1;L z^byj%Yi}Gx)Wnkosi337BKs}+5H5dth1JA{Ir-JKN$7zC)*}hqeoD(WfaUDPT>0`- z(6sa0AoIqASwF`>hP}^|)a_j2s^PQn*qVC{Q}htR z5-)duBFXT_V56-+UohKXlq~^6uf!6sA#ttk1o~*QEy_Y-S$gAvq47J9Vtk$5oA$Ct zYhYJ@8{hsC^98${!#Ho?4y5MCa7iGnfz}b9jE~h%EAAv~Qxu)_rAV;^cygV~5r_~?l=B`zObj7S=H=~$W zPtI_m%g$`kL_fVUk9J@>EiBH zOO&jtn~&`hIFMS5S`g8w94R4H40mdNUH4W@@XQk1sr17b{@y|JB*G9z1|CrQjd+GX z6+KyURG3;!*BQrentw{B2R&@2&`2}n(z-2&X7#r!{yg@Soy}cRD~j zj9@UBW+N|4HW4AWapy4wfUI- zZ`gSL6DUlgj*f1hSOGXG0IVH8HxK?o2|3HZ;KW{K+yPAlxtb)NV_2AwJm|E)FRs&& z=c^e7bvUsztY|+f^k7NXs$o1EUq>cR7C0$UKi6IooHWlK_#?IWDkvywnzg&ThWo^? z2O_N{5X39#?eV9l)xI(>@!vSB{DLt*oY!K1R8}_?%+0^C{d9a%N4 zoxHVT1&Lm|uDX%$QrBun5e-F`HJ^T$ zmzv)p@4ZHd_w9!%Hf9UYNvGCw2TTTbrj9pl+T9%-_-}L(tES>Or-}Z4F*{##n3~L~TuxjirGuIY#H7{%$E${?p{Q01 zi6T`n;rbK1yIB9jmQNycD~yZq&mbIsFWHo|ZAChSFPQa<(%d8mGw*V3fh|yFoxOOiWJd(qvVb!Z$b88cg->N=qO*4k~6;R==|9ihg&riu#P~s4Oap9O7f%crSr^rljeIfXDEg>wi)&v*a%7zpz<9w z*r!3q9J|390x`Zk;g$&OeN&ctp)VKRpDSV@kU2Q>jtok($Y-*x8_$2piTxun81@vt z!Vj?COa0fg2RPXMSIo26T=~0d`{oGP*eV+$!0I<(4azk&Vj3SiG=Q!6mX0p$z7I}; z9BJUFgT-K9MQQ-0@Z=^7R<{bn2Fm48endsSs`V7_@%8?Bxkqv>BDoVcj?K#dV#uUP zL1ND~?D-|VGKe3Rw_7-Idpht>H6XRLh*U7epS6byiGvJpr%d}XwfusjH9g;Z98H`x zyde%%5mhGOiL4wljCaWCk-&uE4_OOccb9c!ZaWt4B(wYl!?vyzl%7n~QepN&eFUrw zFIOl9c({``6~QD+43*_tzP{f2x41h(?b43^y6=iwyB)2os5hBE!@YUS5?N_tXd=h( z)WE286Fbd>R4M^P{!G)f;h<3Q>Fipuy+d2q-)!RyTgt;wr$(?9ox3;q+{E*ZQHhOn;lM`cjnu9 zXa48ks-v(~b*;MAI<>YZH(^NV8vjb34beE<_cwKlJoR;k6lJNSP6v}uiyRD?|0w+X@o1ONrH8a$fCxXpf? z?$DL0)7|X}Oc%h^zrMKWc-NS9I0Utu@>*j}b@tJ=ixQSJ={4@854wzW@E>VSL+Y{i z#0b=WpbCZS>kUCO_iQz)LoE>P5LIG-hv9E+oG}DtlIDF>$tJ1aw9^LuhLEHt?BCj& z(O4I8v1s#HUi5A>nIS-JK{v!7dJx)^Yg%XjNmlkWAq2*cv#tHgz`Y(bETc6CuO1VkN^L-L3j_x<4NqYb5rzrLC-7uOv z!5e`GZt%B782C5-fGnn*GhDF$%(qP<74Z}3xx+{$4cYKy2ikxI7B2N+2r07DN;|-T->nU&!=Cm#rZt%O_5c&1Z%nlWq3TKAW0w zQqemZw_ue--2uKQsx+niCUou?HjD`xhEjjQd3%rrBi82crq*~#uA4+>vR<_S{~5ce z-2EIl?~s z1=GVL{NxP1N3%=AOaC}j_Fv=ur&THz zyO!d9kHq|c73kpq`$+t+8Bw7MgeR5~`d7ChYyGCBWSteTB>8WAU(NPYt2Dk`@#+}= zI4SvLlyk#pBgVigEe`?NG*vl7V6m+<}%FwPV=~PvvA)=#ths==DRTDEYh4V5}Cf$z@#;< zyWfLY_5sP$gc3LLl2x+Ii)#b2nhNXJ{R~vk`s5U7Nyu^3yFg&D%Txwj6QezMX`V(x z=C`{76*mNb!qHHs)#GgGZ_7|vkt9izl_&PBrsu@}L`X{95-2jf99K)0=*N)VxBX2q z((vkpP2RneSIiIUEnGb?VqbMb=Zia+rF~+iqslydE34cSLJ&BJW^3knX@M;t*b=EA zNvGzv41Ld_T+WT#XjDB840vovUU^FtN_)G}7v)1lPetgpEK9YS^OWFkPoE{ovj^=@ zO9N$S=G$1ecndT_=5ehth2Lmd1II-PuT~C9`XVePw$y8J#dpZ?Tss<6wtVglm(Ok7 z3?^oi@pPio6l&!z8JY(pJvG=*pI?GIOu}e^EB6QYk$#FJQ%^AIK$I4epJ+9t?KjqA+bkj&PQ*|vLttme+`9G=L% ziadyMw_7-M)hS(3E$QGNCu|o23|%O+VN7;Qggp?PB3K-iSeBa2b}V4_wY`G1Jsfz4 z9|SdB^;|I8E8gWqHKx!vj_@SMY^hLEIbSMCuE?WKq=c2mJK z8LoG-pnY!uhqFv&L?yEuxo{dpMTsmCn)95xanqBrNPTgXP((H$9N${Ow~Is-FBg%h z53;|Y5$MUN)9W2HBe2TD`ct^LHI<(xWrw}$qSoei?}s)&w$;&!14w6B6>Yr6Y8b)S z0r71`WmAvJJ`1h&poLftLUS6Ir zC$bG9!Im_4Zjse)#K=oJM9mHW1{%l8sz$1o?ltdKlLTxWWPB>Vk22czVt|1%^wnN@*!l)}?EgtvhC>vlHm^t+ogpgHI1_$1ox9e;>0!+b(tBrmXRB`PY1vp-R**8N7 zGP|QqI$m(Rdu#=(?!(N}G9QhQ%o!aXE=aN{&wtGP8|_qh+7a_j_sU5|J^)vxq;# zjvzLn%_QPHZZIWu1&mRAj;Sa_97p_lLq_{~j!M9N^1yp3U_SxRqK&JnR%6VI#^E12 z>CdOVI^_9aPK2eZ4h&^{pQs}xsijXgFYRIxJ~N7&BB9jUR1fm!(xl)mvy|3e6-B3j zJn#ajL;bFTYJ2+Q)tDjx=3IklO@Q+FFM}6UJr6km7hj7th9n_&JR7fnqC!hTZoM~T zBeaVFp%)0cbPhejX<8pf5HyRUj2>aXnXBqDJe73~J%P(2C?-RT{c3NjE`)om! zl$uewSgWkE66$Kb34+QZZvRn`fob~Cl9=cRk@Es}KQm=?E~CE%spXaMO6YmrMl%9Q zlA3Q$3|L1QJ4?->UjT&CBd!~ru{Ih^in&JXO=|<6J!&qp zRe*OZ*cj5bHYlz!!~iEKcuE|;U4vN1rk$xq6>bUWD*u(V@8sG^7>kVuo(QL@Ki;yL zWC!FT(q{E8#on>%1iAS0HMZDJg{Z{^!De(vSIq&;1$+b)oRMwA3nc3mdTSG#3uYO_ z>+x;7p4I;uHz?ZB>dA-BKl+t-3IB!jBRgdvAbW!aJ(Q{aT>+iz?91`C-xbe)IBoND z9_Xth{6?(y3rddwY$GD65IT#f3<(0o#`di{sh2gm{dw*#-Vnc3r=4==&PU^hCv$qd zjw;>i&?L*Wq#TxG$mFIUf>eK+170KG;~+o&1;Tom9}}mKo23KwdEM6UonXgc z!6N(@k8q@HPw{O8O!lAyi{rZv|DpgfU{py+j(X_cwpKqcalcqKIr0kM^%Br3SdeD> zHSKV94Yxw;pjzDHo!Q?8^0bb%L|wC;4U^9I#pd5O&eexX+Im{ z?jKnCcsE|H?{uGMqVie_C~w7GX)kYGWAg%-?8|N_1#W-|4F)3YTDC+QSq1s!DnOML3@d`mG%o2YbYd#jww|jD$gotpa)kntakp#K;+yo-_ZF9qrNZw<%#C zuPE@#3RocLgPyiBZ+R_-FJ_$xP!RzWm|aN)S+{$LY9vvN+IW~Kf3TsEIvP+B9Mtm! zpfNNxObWQpLoaO&cJh5>%slZnHl_Q~(-Tfh!DMz(dTWld@LG1VRF`9`DYKhyNv z2pU|UZ$#_yUx_B_|MxUq^glT}O5Xt(Vm4Mr02><%C)@v;vPb@pT$*yzJ4aPc_FZ3z z3}PLoMBIM>q_9U2rl^sGhk1VUJ89=*?7|v`{!Z{6bqFMq(mYiA?%KbsI~JwuqVA9$H5vDE+VocjX+G^%bieqx->s;XWlKcuv(s%y%D5Xbc9+ zc(_2nYS1&^yL*ey664&4`IoOeDIig}y-E~_GS?m;D!xv5-xwz+G`5l6V+}CpeJDi^ z%4ed$qowm88=iYG+(`ld5Uh&>Dgs4uPHSJ^TngXP_V6fPyl~>2bhi20QB%lSd#yYn zO05?KT1z@?^-bqO8Cg`;ft>ilejsw@2%RR7;`$Vs;FmO(Yr3Fp`pHGr@P2hC%QcA|X&N2Dn zYf`MqXdHi%cGR@%y7Rg7?d3?an){s$zA{!H;Ie5exE#c~@NhQUFG8V=SQh%UxUeiV zd7#UcYqD=lk-}sEwlpu&H^T_V0{#G?lZMxL7ih_&{(g)MWBnCZxtXg znr#}>U^6!jA%e}@Gj49LWG@*&t0V>Cxc3?oO7LSG%~)Y5}f7vqUUnQ;STjdDU}P9IF9d9<$;=QaXc zL1^X7>fa^jHBu_}9}J~#-oz3Oq^JmGR#?GO7b9a(=R@fw@}Q{{@`Wy1vIQ#Bw?>@X z-_RGG@wt|%u`XUc%W{J z>iSeiz8C3H7@St3mOr_mU+&bL#Uif;+Xw-aZdNYUpdf>Rvu0i0t6k*}vwU`XNO2he z%miH|1tQ8~ZK!zmL&wa3E;l?!!XzgV#%PMVU!0xrDsNNZUWKlbiOjzH-1Uoxm8E#r`#2Sz;-o&qcqB zC-O_R{QGuynW14@)7&@yw1U}uP(1cov)twxeLus0s|7ayrtT8c#`&2~Fiu2=R;1_4bCaD=*E@cYI>7YSnt)nQc zohw5CsK%m?8Ack)qNx`W0_v$5S}nO|(V|RZKBD+btO?JXe|~^Qqur%@eO~<8-L^9d z=GA3-V14ng9L29~XJ>a5k~xT2152zLhM*@zlp2P5Eu}bywkcqR;ISbas&#T#;HZSf z2m69qTV(V@EkY(1Dk3`}j)JMo%ZVJ*5eB zYOjIisi+igK0#yW*gBGj?@I{~mUOvRFQR^pJbEbzFxTubnrw(Muk%}jI+vXmJ;{Q6 zrSobKD>T%}jV4Ub?L1+MGOD~0Ir%-`iTnWZN^~YPrcP5y3VMAzQ+&en^VzKEb$K!Q z<7Dbg&DNXuow*eD5yMr+#08nF!;%4vGrJI++5HdCFcGLfMW!KS*Oi@=7hFwDG!h2< zPunUEAF+HncQkbfFj&pbzp|MU*~60Z(|Ik%Tn{BXMN!hZOosNIseT?R;A`W?=d?5X zK(FB=9mZusYahp|K-wyb={rOpdn=@;4YI2W0EcbMKyo~-#^?h`BA9~o285%oY zfifCh5Lk$SY@|2A@a!T2V+{^!psQkx4?x0HSV`(w9{l75QxMk!)U52Lbhn{8ol?S) zCKo*7R(z!uk<6*qO=wh!Pul{(qq6g6xW;X68GI_CXp`XwO zxuSgPRAtM8K7}5E#-GM!*ydOOG_{A{)hkCII<|2=ma*71ci_-}VPARm3crFQjLYV! z9zbz82$|l01mv`$WahE2$=fAGWkd^X2kY(J7iz}WGS z@%MyBEO=A?HB9=^?nX`@nh;7;laAjs+fbo!|K^mE!tOB>$2a_O0y-*uaIn8k^6Y zSbuv;5~##*4Y~+y7Z5O*3w4qgI5V^17u*ZeupVGH^nM&$qmAk|anf*>r zWc5CV;-JY-Z@Uq1Irpb^O`L_7AGiqd*YpGUShb==os$uN3yYvb`wm6d=?T*it&pDk zo`vhw)RZX|91^^Wa_ti2zBFyWy4cJu#g)_S6~jT}CC{DJ_kKpT`$oAL%b^!2M;JgT zM3ZNbUB?}kP(*YYvXDIH8^7LUxz5oE%kMhF!rnPqv!GiY0o}NR$OD=ITDo9r%4E>E0Y^R(rS^~XjWyVI6 zMOR5rPXhTp*G*M&X#NTL`Hu*R+u*QNoiOKg4CtNPrjgH>c?Hi4MUG#I917fx**+pJfOo!zFM&*da&G_x)L(`k&TPI*t3e^{crd zX<4I$5nBQ8Ax_lmNRa~E*zS-R0sxkz`|>7q_?*e%7bxqNm3_eRG#1ae3gtV9!fQpY z+!^a38o4ZGy9!J5sylDxZTx$JmG!wg7;>&5H1)>f4dXj;B+@6tMlL=)cLl={jLMxY zbbf1ax3S4>bwB9-$;SN2?+GULu;UA-35;VY*^9Blx)Jwyb$=U!D>HhB&=jSsd^6yw zL)?a|>GxU!W}ocTC(?-%z3!IUhw^uzc`Vz_g>-tv)(XA#JK^)ZnC|l1`@CdX1@|!| z_9gQ)7uOf?cR@KDp97*>6X|;t@Y`k_N@)aH7gY27)COv^P3ya9I{4z~vUjLR9~z1Z z5=G{mVtKH*&$*t0@}-i_v|3B$AHHYale7>E+jP`ClqG%L{u;*ff_h@)al?RuL7tOO z->;I}>%WI{;vbLP3VIQ^iA$4wl6@0sDj|~112Y4OFjMs`13!$JGkp%b&E8QzJw_L5 zOnw9joc0^;O%OpF$Qp)W1HI!$4BaXX84`%@#^dk^hFp^pQ@rx4g(8Xjy#!X%+X5Jd@fs3amGT`}mhq#L97R>OwT5-m|h#yT_-v@(k$q7P*9X~T*3)LTdzP!*B} z+SldbVWrrwQo9wX*%FyK+sRXTa@O?WM^FGWOE?S`R(0P{<6p#f?0NJvnBia?k^fX2 zNQs7K-?EijgHJY}&zsr;qJ<*PCZUd*x|dD=IQPUK_nn)@X4KWtqoJNHkT?ZWL_hF? zS8lp2(q>;RXR|F;1O}EE#}gCrY~#n^O`_I&?&z5~7N;zL0)3Tup`%)oHMK-^r$NT% zbFg|o?b9w(q@)6w5V%si<$!U<#}s#x@0aX-hP>zwS#9*75VXA4K*%gUc>+yzupTDBOKH8WR4V0pM(HrfbQ&eJ79>HdCvE=F z|J>s;;iDLB^3(9}?biKbxf1$lI!*Z%*0&8UUq}wMyPs_hclyQQi4;NUY+x2qy|0J; zhn8;5)4ED1oHwg+VZF|80<4MrL97tGGXc5Sw$wAI#|2*cvQ=jB5+{AjMiDHmhUC*a zlmiZ`LAuAn_}hftXh;`Kq0zblDk8?O-`tnilIh|;3lZp@F_osJUV9`*R29M?7H{Fy z`nfVEIDIWXmU&YW;NjU8)EJpXhxe5t+scf|VXM!^bBlwNh)~7|3?fWwo_~ZFk(22% zTMesYw+LNx3J-_|DM~`v93yXe=jPD{q;li;5PD?Dyk+b? zo21|XpT@)$BM$%F=P9J19Vi&1#{jM3!^Y&fr&_`toi`XB1!n>sbL%U9I5<7!@?t)~ z;&H%z>bAaQ4f$wIzkjH70;<8tpUoxzKrPhn#IQfS%9l5=Iu))^XC<58D!-O z{B+o5R^Z21H0T9JQ5gNJnqh#qH^na|z92=hONIM~@_iuOi|F>jBh-?aA20}Qx~EpDGElELNn~|7WRXRFnw+Wdo`|# zBpU=Cz3z%cUJ0mx_1($X<40XEIYz(`noWeO+x#yb_pwj6)R(__%@_Cf>txOQ74wSJ z0#F3(zWWaR-jMEY$7C*3HJrohc79>MCUu26mfYN)f4M~4gD`}EX4e}A!U}QV8!S47 z6y-U-%+h`1n`*pQuKE%Av0@)+wBZr9mH}@vH@i{v(m-6QK7Ncf17x_D=)32`FOjjo zg|^VPf5c6-!FxN{25dvVh#fog=NNpXz zfB$o+0jbRkHH{!TKhE709f+jI^$3#v1Nmf80w`@7-5$1Iv_`)W^px8P-({xwb;D0y z7LKDAHgX<84?l!I*Dvi2#D@oAE^J|g$3!)x1Ua;_;<@#l1fD}lqU2_tS^6Ht$1Wl} zBESo7o^)9-Tjuz$8YQSGhfs{BQV6zW7dA?0b(Dbt=UnQs&4zHfe_sj{RJ4uS-vQpC zX;Bbsuju4%!o8?&m4UZU@~ZZjeFF6ex2ss5_60_JS_|iNc+R0GIjH1@Z z=rLT9%B|WWgOrR7IiIwr2=T;Ne?30M!@{%Qf8o`!>=s<2CBpCK_TWc(DX51>e^xh8 z&@$^b6CgOd7KXQV&Y4%}_#uN*mbanXq(2=Nj`L7H7*k(6F8s6{FOw@(DzU`4-*77{ zF+dxpv}%mFpYK?>N_2*#Y?oB*qEKB}VoQ@bzm>ptmVS_EC(#}Lxxx730trt0G)#$b zE=wVvtqOct1%*9}U{q<)2?{+0TzZzP0jgf9*)arV)*e!f`|jgT{7_9iS@e)recI#z zbzolURQ+TOzE!ymqvBY7+5NnAbWxvMLsLTwEbFqW=CPyCsmJ}P1^V30|D5E|p3BC5 z)3|qgw@ra7aXb-wsa|l^in~1_fm{7bS9jhVRkYVO#U{qMp z)Wce+|DJ}4<2gp8r0_xfZpMo#{Hl2MfjLcZdRB9(B(A(f;+4s*FxV{1F|4d`*sRNd zp4#@sEY|?^FIJ;tmH{@keZ$P(sLh5IdOk@k^0uB^BWr@pk6mHy$qf&~rI>P*a;h0C{%oA*i!VjWn&D~O#MxN&f@1Po# zKN+ zrGrkSjcr?^R#nGl<#Q722^wbYcgW@{+6CBS<1@%dPA8HC!~a`jTz<`g_l5N1M@9wn9GOAZ>nqNgq!yOCbZ@1z`U_N`Z>}+1HIZxk*5RDc&rd5{3qjRh8QmT$VyS;jK z;AF+r6XnnCp=wQYoG|rT2@8&IvKq*IB_WvS%nt%e{MCFm`&W*#LXc|HrD?nVBo=(8*=Aq?u$sDA_sC_RPDUiQ+wnIJET8vx$&fxkW~kP9qXKt zozR)@xGC!P)CTkjeWvXW5&@2?)qt)jiYWWBU?AUtzAN}{JE1I)dfz~7$;}~BmQF`k zpn11qmObXwRB8&rnEG*#4Xax3XBkKlw(;tb?Np^i+H8m(Wyz9k{~ogba@laiEk;2! zV*QV^6g6(QG%vX5Um#^sT&_e`B1pBW5yVth~xUs#0}nv?~C#l?W+9Lsb_5)!71rirGvY zTIJ$OPOY516Y|_014sNv+Z8cc5t_V=i>lWV=vNu#!58y9Zl&GsMEW#pPYPYGHQ|;vFvd*9eM==$_=vc7xnyz0~ zY}r??$<`wAO?JQk@?RGvkWVJlq2dk9vB(yV^vm{=NVI8dhsX<)O(#nr9YD?I?(VmQ z^r7VfUBn<~p3()8yOBjm$#KWx!5hRW)5Jl7wY@ky9lNM^jaT##8QGVsYeaVywmpv>X|Xj7gWE1Ezai&wVLt3p)k4w~yrskT-!PR!kiyQlaxl(( zXhF%Q9x}1TMt3~u@|#wWm-Vq?ZerK={8@~&@9r5JW}r#45#rWii};t`{5#&3$W)|@ zbAf2yDNe0q}NEUvq_Quq3cTjcw z@H_;$hu&xllCI9CFDLuScEMg|x{S7GdV8<&Mq=ezDnRZAyX-8gv97YTm0bg=d)(>N z+B2FcqvI9>jGtnK%eO%y zoBPkJTk%y`8TLf4)IXPBn`U|9>O~WL2C~C$z~9|0m*YH<-vg2CD^SX#&)B4ngOSG$ zV^wmy_iQk>dfN@Pv(ckfy&#ak@MLC7&Q6Ro#!ezM*VEh`+b3Jt%m(^T&p&WJ2Oqvj zs-4nq0TW6cv~(YI$n0UkfwN}kg3_fp?(ijSV#tR9L0}l2qjc7W?i*q01=St0eZ=4h zyGQbEw`9OEH>NMuIe)hVwYHsGERWOD;JxEiO7cQv%pFCeR+IyhwQ|y@&^24k+|8fD zLiOWFNJ2&vu2&`Jv96_z-Cd5RLgmeY3*4rDOQo?Jm`;I_(+ejsPM03!ly!*Cu}Cco zrQSrEDHNyzT(D5s1rZq!8#?f6@v6dB7a-aWs(Qk>N?UGAo{gytlh$%_IhyL7h?DLXDGx zgxGEBQoCAWo-$LRvM=F5MTle`M})t3vVv;2j0HZY&G z22^iGhV@uaJh(XyyY%} zd4iH_UfdV#T=3n}(Lj^|n;O4|$;xhu*8T3hR1mc_A}fK}jfZ7LX~*n5+`8N2q#rI$ z@<_2VANlYF$vIH$ zl<)+*tIWW78IIINA7Rr7i{<;#^yzxoLNkXL)eSs=%|P>$YQIh+ea_3k z_s7r4%j7%&*NHSl?R4k%1>Z=M9o#zxY!n8sL5>BO-ZP;T3Gut>iLS@U%IBrX6BA3k z)&@q}V8a{X<5B}K5s(c(LQ=%v1ocr`t$EqqY0EqVjr65usa=0bkf|O#ky{j3)WBR(((L^wmyHRzoWuL2~WTC=`yZ zn%VX`L=|Ok0v7?s>IHg?yArBcync5rG#^+u)>a%qjES%dRZoIyA8gQ;StH z1Ao7{<&}6U=5}4v<)1T7t!J_CL%U}CKNs-0xWoTTeqj{5{?Be$L0_tk>M9o8 zo371}S#30rKZFM{`H_(L`EM9DGp+Mifk&IP|C2Zu_)Ghr4Qtpmkm1osCf@%Z$%t+7 zYH$Cr)Ro@3-QDeQJ8m+x6%;?YYT;k6Z0E-?kr>x33`H%*ueBD7Zx~3&HtWn0?2Wt} zTG}*|v?{$ajzt}xPzV%lL1t-URi8*Zn)YljXNGDb>;!905Td|mpa@mHjIH%VIiGx- zd@MqhpYFu4_?y5N4xiHn3vX&|e6r~Xt> zZG`aGq|yTNjv;9E+Txuoa@A(9V7g?1_T5FzRI;!=NP1Kqou1z5?%X~Wwb{trRfd>i z8&y^H)8YnKyA_Fyx>}RNmQIczT?w2J4SNvI{5J&}Wto|8FR(W;Qw#b1G<1%#tmYzQ zQ2mZA-PAdi%RQOhkHy9Ea#TPSw?WxwL@H@cbkZwIq0B!@ns}niALidmn&W?!Vd4Gj zO7FiuV4*6Mr^2xlFSvM;Cp_#r8UaqIzHJQg_z^rEJw&OMm_8NGAY2)rKvki|o1bH~ z$2IbfVeY2L(^*rMRU1lM5Y_sgrDS`Z??nR2lX;zyR=c%UyGb*%TC-Dil?SihkjrQy~TMv6;BMs7P8il`H7DmpVm@rJ;b)hW)BL)GjS154b*xq-NXq2cwE z^;VP7ua2pxvCmxrnqUYQMH%a%nHmwmI33nJM(>4LznvY*k&C0{8f*%?zggpDgkuz&JBx{9mfb@wegEl2v!=}Sq2Gaty0<)UrOT0{MZtZ~j5y&w zXlYa_jY)I_+VA-^#mEox#+G>UgvM!Ac8zI<%JRXM_73Q!#i3O|)lOP*qBeJG#BST0 zqohi)O!|$|2SeJQo(w6w7%*92S})XfnhrH_Z8qe!G5>CglP=nI7JAOW?(Z29;pXJ9 zR9`KzQ=WEhy*)WH>$;7Cdz|>*i>=##0bB)oU0OR>>N<21e4rMCHDemNi2LD>Nc$;& zQRFthpWniC1J6@Zh~iJCoLOxN`oCKD5Q4r%ynwgUKPlIEd#?QViIqovY|czyK8>6B zSP%{2-<;%;1`#0mG^B(8KbtXF;Nf>K#Di72UWE4gQ%(_26Koiad)q$xRL~?pN71ZZ zujaaCx~jXjygw;rI!WB=xrOJO6HJ!!w}7eiivtCg5K|F6$EXa)=xUC za^JXSX98W`7g-tm@uo|BKj39Dl;sg5ta;4qjo^pCh~{-HdLl6qI9Ix6f$+qiZ$}s= zNguKrU;u+T@ko(Vr1>)Q%h$?UKXCY>3se%&;h2osl2D zE4A9bd7_|^njDd)6cI*FupHpE3){4NQ*$k*cOWZ_?CZ>Z4_fl@n(mMnYK62Q1d@+I zr&O))G4hMihgBqRIAJkLdk(p(D~X{-oBUA+If@B}j& zsHbeJ3RzTq96lB7d($h$xTeZ^gP0c{t!Y0c)aQE;$FY2!mACg!GDEMKXFOPI^)nHZ z`aSPJpvV0|bbrzhWWkuPURlDeN%VT8tndV8?d)eN*i4I@u zVKl^6{?}A?P)Fsy?3oi#clf}L18t;TjNI2>eI&(ezDK7RyqFxcv%>?oxUlonv(px) z$vnPzRH`y5A(x!yOIfL0bmgeMQB$H5wenx~!ujQK*nUBW;@Em&6Xv2%s(~H5WcU2R z;%Nw<$tI)a`Ve!>x+qegJnQsN2N7HaKzrFqM>`6R*gvh%O*-%THt zrB$Nk;lE;z{s{r^PPm5qz(&lM{sO*g+W{sK+m3M_z=4=&CC>T`{X}1Vg2PEfSj2x_ zmT*(x;ov%3F?qoEeeM>dUn$a*?SIGyO8m806J1W1o+4HRhc2`9$s6hM#qAm zChQ87b~GEw{ADfs+5}FJ8+|bIlIv(jT$Ap#hSHoXdd9#w<#cA<1Rkq^*EEkknUd4& zoIWIY)sAswy6fSERVm&!SO~#iN$OgOX*{9@_BWFyJTvC%S++ilSfCrO(?u=Dc?CXZ zzCG&0yVR{Z`|ZF0eEApWEo#s9osV>F{uK{QA@BES#&;#KsScf>y zvs?vIbI>VrT<*!;XmQS=bhq%46-aambZ(8KU-wOO2=en~D}MCToB_u;Yz{)1ySrPZ z@=$}EvjTdzTWU7c0ZI6L8=yP+YRD_eMMos}b5vY^S*~VZysrkq<`cK3>>v%uy7jgq z0ilW9KjVDHLv0b<1K_`1IkbTOINs0=m-22c%M~l=^S}%hbli-3?BnNq?b`hx^HX2J zIe6ECljRL0uBWb`%{EA=%!i^4sMcj+U_TaTZRb+~GOk z^ZW!nky0n*Wb*r+Q|9H@ml@Z5gU&W`(z4-j!OzC1wOke`TRAYGZVl$PmQ16{3196( zO*?`--I}Qf(2HIwb2&1FB^!faPA2=sLg(@6P4mN)>Dc3i(B0;@O-y2;lM4akD>@^v z=u>*|!s&9zem70g7zfw9FXl1bpJW(C#5w#uy5!V?Q(U35A~$dR%LDVnq@}kQm13{} zd53q3N(s$Eu{R}k2esbftfjfOITCL;jWa$}(mmm}d(&7JZ6d3%IABCapFFYjdEjdK z&4Edqf$G^MNAtL=uCDRs&Fu@FXRgX{*0<(@c3|PNHa>L%zvxWS={L8%qw`STm+=Rd zA}FLspESSIpE_^41~#5yI2bJ=9`oc;GIL!JuW&7YetZ?0H}$$%8rW@*J37L-~Rsx!)8($nI4 zZhcZ2^=Y+p4YPl%j!nFJA|*M^gc(0o$i3nlphe+~-_m}jVkRN{spFs(o0ajW@f3K{ zDV!#BwL322CET$}Y}^0ixYj2w>&Xh12|R8&yEw|wLDvF!lZ#dOTHM9pK6@Nm-@9Lnng4ZHBgBSrr7KI8YCC9DX5Kg|`HsiwJHg2(7#nS;A{b3tVO?Z% za{m5b3rFV6EpX;=;n#wltDv1LE*|g5pQ+OY&*6qCJZc5oDS6Z6JD#6F)bWxZSF@q% z+1WV;m!lRB!n^PC>RgQCI#D1br_o^#iPk>;K2hB~0^<~)?p}LG%kigm@moD#q3PE+ zA^Qca)(xnqw6x>XFhV6ku9r$E>bWNrVH9fum0?4s?Rn2LG{Vm_+QJHse6xa%nzQ?k zKug4PW~#Gtb;#5+9!QBgyB@q=sk9=$S{4T>wjFICStOM?__fr+Kei1 z3j~xPqW;W@YkiUM;HngG!;>@AITg}vAE`M2Pj9Irl4w1fo4w<|Bu!%rh%a(Ai^Zhi zs92>v5;@Y(Zi#RI*ua*h`d_7;byQSa*v9E{2x$<-_=5Z<7{%)}4XExANcz@rK69T0x3%H<@frW>RA8^swA+^a(FxK| zFl3LD*ImHN=XDUkrRhp6RY5$rQ{bRgSO*(vEHYV)3Mo6Jy3puiLmU&g82p{qr0F?ohmbz)f2r{X2|T2 z$4fdQ=>0BeKbiVM!e-lIIs8wVTuC_m7}y4A_%ikI;Wm5$9j(^Y z(cD%U%k)X>_>9~t8;pGzL6L-fmQO@K; zo&vQzMlgY95;1BSkngY)e{`n0!NfVgf}2mB3t}D9@*N;FQ{HZ3Pb%BK6;5#-O|WI( zb6h@qTLU~AbVW#_6?c!?Dj65Now7*pU{h!1+eCV^KCuPAGs28~3k@ueL5+u|Z-7}t z9|lskE`4B7W8wMs@xJa{#bsCGDFoRSNSnmNYB&U7 zVGKWe%+kFB6kb)e;TyHfqtU6~fRg)f|>=5(N36)0+C z`hv65J<$B}WUc!wFAb^QtY31yNleq4dzmG`1wHTj=c*=hay9iD071Hc?oYoUk|M*_ zU1GihAMBsM@5rUJ(qS?9ZYJ6@{bNqJ`2Mr+5#hKf?doa?F|+^IR!8lq9)wS3tF_9n zW_?hm)G(M+MYb?V9YoX^_mu5h-LP^TL^!Q9Z7|@sO(rg_4+@=PdI)WL(B7`!K^ND- z-uIuVDCVEdH_C@c71YGYT^_Scf_dhB8Z2Xy6vGtBSlYud9vggOqv^L~F{BraSE_t} zIkP+Hp2&nH^-MNEs}^`oMLy11`PQW$T|K(`Bu*(f@)mv1-qY(_YG&J2M2<7k;;RK~ zL{Fqj9yCz8(S{}@c)S!65aF<=&eLI{hAMErCx&>i7OeDN>okvegO87OaG{Jmi<|}D zaT@b|0X{d@OIJ7zvT>r+eTzgLq~|Dpu)Z&db-P4z*`M$UL51lf>FLlq6rfG)%doyp z)3kk_YIM!03eQ8Vu_2fg{+osaEJPtJ-s36R+5_AEG12`NG)IQ#TF9c@$99%0iye+ zUzZ57=m2)$D(5Nx!n)=5Au&O0BBgwxIBaeI(mro$#&UGCr<;C{UjJVAbVi%|+WP(a zL$U@TYCxJ=1{Z~}rnW;7UVb7+ZnzgmrogDxhjLGo>c~MiJAWs&&;AGg@%U?Y^0JhL ze(x6Z74JG6FlOFK(T}SXQfhr}RIFl@QXKnIcXYF)5|V~e-}suHILKT-k|<*~Ij|VF zC;t@=uj=hot~*!C68G8hTA%8SzOfETOXQ|3FSaIEjvBJp(A)7SWUi5!Eu#yWgY+;n zlm<$+UDou*V+246_o#V4kMdto8hF%%Lki#zPh}KYXmMf?hrN0;>Mv%`@{0Qn`Ujp) z=lZe+13>^Q!9zT);H<(#bIeRWz%#*}sgUX9P|9($kexOyKIOc`dLux}c$7It4u|Rl z6SSkY*V~g_B-hMPo_ak>>z@AVQ(_N)VY2kB3IZ0G(iDUYw+2d7W^~(Jq}KY=JnWS( z#rzEa&0uNhJ>QE8iiyz;n2H|SV#Og+wEZv=f2%1ELX!SX-(d3tEj$5$1}70Mp<&eI zCkfbByL7af=qQE@5vDVxx1}FSGt_a1DoE3SDI+G)mBAna)KBG4p8Epxl9QZ4BfdAN zFnF|Y(umr;gRgG6NLQ$?ZWgllEeeq~z^ZS7L?<(~O&$5|y)Al^iMKy}&W+eMm1W z7EMU)u^ke(A1#XCV>CZ71}P}0x)4wtHO8#JRG3MA-6g=`ZM!FcICCZ{IEw8Dm2&LQ z1|r)BUG^0GzI6f946RrBlfB1Vs)~8toZf~7)+G;pv&XiUO(%5bm)pl=p>nV^o*;&T z;}@oZSibzto$arQgfkp|z4Z($P>dTXE{4O=vY0!)kDO* zGF8a4wq#VaFpLfK!iELy@?-SeRrdz%F*}hjKcA*y@mj~VD3!it9lhRhX}5YOaR9$} z3mS%$2Be7{l(+MVx3 z(4?h;P!jnRmX9J9sYN#7i=iyj_5q7n#X(!cdqI2lnr8T$IfOW<_v`eB!d9xY1P=2q&WtOXY=D9QYteP)De?S4}FK6#6Ma z=E*V+#s8>L;8aVroK^6iKo=MH{4yEZ_>N-N z`(|;aOATba1^asjxlILk<4}f~`39dBFlxj>Dw(hMYKPO3EEt1@S`1lxFNM+J@uB7T zZ8WKjz7HF1-5&2=l=fqF-*@>n5J}jIxdDwpT?oKM3s8Nr`x8JnN-kCE?~aM1H!hAE z%%w(3kHfGwMnMmNj(SU(w42OrC-euI>Dsjk&jz3ts}WHqmMpzQ3vZrsXrZ|}+MHA7 z068obeXZTsO*6RS@o3x80E4ok``rV^Y3hr&C1;|ZZ0|*EKO`$lECUYG2gVFtUTw)R z4Um<0ZzlON`zTdvVdL#KFoMFQX*a5wM0Czp%wTtfK4Sjs)P**RW&?lP$(<}q%r68Z zS53Y!d@&~ne9O)A^tNrXHhXBkj~$8j%pT1%%mypa9AW5E&s9)rjF4@O3ytH{0z6riz|@< zB~UPh*wRFg2^7EbQrHf0y?E~dHlkOxof_a?M{LqQ^C!i2dawHTPYUE=X@2(3<=OOxs8qn_(y>pU>u^}3y&df{JarR0@VJn0f+U%UiF=$Wyq zQvnVHESil@d|8&R<%}uidGh7@u^(%?$#|&J$pvFC-n8&A>utA=n3#)yMkz+qnG3wd zP7xCnF|$9Dif@N~L)Vde3hW8W!UY0BgT2v(wzp;tlLmyk2%N|0jfG$%<;A&IVrOI< z!L)o>j>;dFaqA3pL}b-Je(bB@VJ4%!JeX@3x!i{yIeIso^=n?fDX`3bU=eG7sTc%g%ye8$v8P@yKE^XD=NYxTb zbf!Mk=h|otpqjFaA-vs5YOF-*GwWPc7VbaOW&stlANnCN8iftFMMrUdYNJ_Bnn5Vt zxfz@Ah|+4&P;reZxp;MmEI7C|FOv8NKUm8njF7Wb6Gi7DeODLl&G~}G4be&*Hi0Qw z5}77vL0P+7-B%UL@3n1&JPxW^d@vVwp?u#gVcJqY9#@-3X{ok#UfW3<1fb%FT`|)V~ggq z(3AUoUS-;7)^hCjdT0Kf{i}h)mBg4qhtHHBti=~h^n^OTH5U*XMgDLIR@sre`AaB$ zg)IGBET_4??m@cx&c~bA80O7B8CHR7(LX7%HThkeC*@vi{-pL%e)yXp!B2InafbDF zjPXf1mko3h59{lT6EEbxKO1Z5GF71)WwowO6kY|6tjSVSWdQ}NsK2x{>i|MKZK8%Q zfu&_0D;CO-Jg0#YmyfctyJ!mRJp)e#@O0mYdp|8x;G1%OZQ3Q847YWTyy|%^cpA;m zze0(5p{tMu^lDkpe?HynyO?a1$_LJl2L&mpeKu%8YvgRNr=%2z${%WThHG=vrWY@4 zsA`OP#O&)TetZ>s%h!=+CE15lOOls&nvC~$Qz0Ph7tHiP;O$i|eDwpT{cp>+)0-|; zY$|bB+Gbel>5aRN3>c0x)4U=|X+z+{ zn*_p*EQoquRL+=+p;=lm`d71&1NqBz&_ph)MXu(Nv6&XE7(RsS)^MGj5Q?Fwude-(sq zjJ>aOq!7!EN>@(fK7EE#;i_BGvli`5U;r!YA{JRodLBc6-`n8K+Fjgwb%sX;j=qHQ z7&Tr!)!{HXoO<2BQrV9Sw?JRaLXV8HrsNevvnf>Y-6|{T!pYLl7jp$-nEE z#X!4G4L#K0qG_4Z;Cj6=;b|Be$hi4JvMH!-voxqx^@8cXp`B??eFBz2lLD8RRaRGh zn7kUfy!YV~p(R|p7iC1Rdgt$_24i0cd-S8HpG|`@my70g^y`gu%#Tf_L21-k?sRRZHK&at(*ED0P8iw{7?R$9~OF$Ko;Iu5)ur5<->x!m93Eb zFYpIx60s=Wxxw=`$aS-O&dCO_9?b1yKiPCQmSQb>T)963`*U+Ydj5kI(B(B?HNP8r z*bfSBpSu)w(Z3j7HQoRjUG(+d=IaE~tv}y14zHHs|0UcN52fT8V_<@2ep_ee{QgZG zmgp8iv4V{k;~8@I%M3<#B;2R>Ef(Gg_cQM7%}0s*^)SK6!Ym+~P^58*wnwV1BW@eG z4sZLqsUvBbFsr#8u7S1r4teQ;t)Y@jnn_m5jS$CsW1um!p&PqAcc8!zyiXHVta9QC zY~wCwCF0U%xiQPD_INKtTb;A|Zf29(mu9NI;E zc-e>*1%(LSXB`g}kd`#}O;veb<(sk~RWL|f3ljxCnEZDdNSTDV6#Td({6l&y4IjKF z^}lIUq*ZUqgTPumD)RrCN{M^jhY>E~1pn|KOZ5((%F)G|*ZQ|r4zIbrEiV%42hJV8 z3xS)=!X1+=olbdGJ=yZil?oXLct8FM{(6ikLL3E%=q#O6(H$p~gQu6T8N!plf!96| z&Q3=`L~>U0zZh;z(pGR2^S^{#PrPxTRHD1RQOON&f)Siaf`GLj#UOk&(|@0?zm;Sx ztsGt8=29-MZs5CSf1l1jNFtNt5rFNZxJPvkNu~2}7*9468TWm>nN9TP&^!;J{-h)_ z7WsHH9|F%I`Pb!>KAS3jQWKfGivTVkMJLO-HUGM_a4UQ_%RgL6WZvrW+Z4ujZn;y@ zz9$=oO!7qVTaQAA^BhX&ZxS*|5dj803M=k&2%QrXda`-Q#IoZL6E(g+tN!6CA!CP* zCpWtCujIea)ENl0liwVfj)Nc<9mV%+e@=d`haoZ*`B7+PNjEbXBkv=B+Pi^~L#EO$D$ZqTiD8f<5$eyb54-(=3 zh)6i8i|jp(@OnRrY5B8t|LFXFQVQ895n*P16cEKTrT*~yLH6Z4e*bZ5otpRDri&+A zfNbK1D5@O=sm`fN=WzWyse!za5n%^+6dHPGX#8DyIK>?9qyX}2XvBWVqbP%%D)7$= z=#$WulZlZR<{m#gU7lwqK4WS1Ne$#_P{b17qe$~UOXCl>5b|6WVh;5vVnR<%d+Lnp z$uEmML38}U4vaW8>shm6CzB(Wei3s#NAWE3)a2)z@i{4jTn;;aQS)O@l{rUM`J@K& l00vQ5JBs~;vo!vr%%-k{2_Fq1Mn4QF81S)AQ99zk{{c4yR+0b! diff --git a/asset-transfer-basic/application-gateway-java/gradle/wrapper/gradle-wrapper.properties b/asset-transfer-basic/application-gateway-java/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index e2847c82..00000000 --- a/asset-transfer-basic/application-gateway-java/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/asset-transfer-basic/application-gateway-java/gradlew b/asset-transfer-basic/application-gateway-java/gradlew deleted file mode 100755 index 1aa94a42..00000000 --- a/asset-transfer-basic/application-gateway-java/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/asset-transfer-basic/application-gateway-java/gradlew.bat b/asset-transfer-basic/application-gateway-java/gradlew.bat deleted file mode 100644 index 7101f8e4..00000000 --- a/asset-transfer-basic/application-gateway-java/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/asset-transfer-basic/application-gateway-java/pom.xml b/asset-transfer-basic/application-gateway-java/pom.xml deleted file mode 100644 index 76c7dc7b..00000000 --- a/asset-transfer-basic/application-gateway-java/pom.xml +++ /dev/null @@ -1,96 +0,0 @@ - - - 4.0.0 - - org.hyperledger.fabric.example - asset-transfer-basic - 1.0-SNAPSHOT - - - UTF-8 - 11 - - - - - - com.google.protobuf - protobuf-bom - 4.28.2 - pom - import - - - io.grpc - grpc-bom - 1.67.1 - pom - import - - - - - - - org.hyperledger.fabric - fabric-gateway - 1.7.0 - - - io.grpc - grpc-api - - - io.grpc - grpc-netty-shaded - runtime - - - - - - - - - maven-clean-plugin - 3.4.0 - - - - maven-resources-plugin - 3.3.1 - - - maven-compiler-plugin - 3.13.0 - - - maven-surefire-plugin - 3.3.0 - - - maven-jar-plugin - 3.4.2 - - - maven-install-plugin - 3.1.2 - - - maven-deploy-plugin - 3.1.2 - - - - maven-site-plugin - 3.12.1 - - - maven-project-info-reports-plugin - 3.6.1 - - - - - diff --git a/asset-transfer-basic/application-gateway-java/settings.gradle b/asset-transfer-basic/application-gateway-java/settings.gradle deleted file mode 100644 index be3a1b3b..00000000 --- a/asset-transfer-basic/application-gateway-java/settings.gradle +++ /dev/null @@ -1,10 +0,0 @@ -/* - * This file was generated by the Gradle 'init' task. - * - * The settings file is used to specify which projects to include in your build. - * - * Detailed information about configuring a multi-project build in Gradle can be found - * in the user manual at https://docs.gradle.org/6.5/userguide/multi_project_builds.html - */ - -rootProject.name = 'asset-transfer-basic' diff --git a/asset-transfer-basic/application-gateway-java/src/main/java/App.java b/asset-transfer-basic/application-gateway-java/src/main/java/App.java deleted file mode 100644 index 57285ef8..00000000 --- a/asset-transfer-basic/application-gateway-java/src/main/java/App.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonParser; -import io.grpc.Grpc; -import io.grpc.ManagedChannel; -import io.grpc.TlsChannelCredentials; -import org.hyperledger.fabric.client.CommitException; -import org.hyperledger.fabric.client.CommitStatusException; -import org.hyperledger.fabric.client.Contract; -import org.hyperledger.fabric.client.EndorseException; -import org.hyperledger.fabric.client.Gateway; -import org.hyperledger.fabric.client.GatewayException; -import org.hyperledger.fabric.client.Hash; -import org.hyperledger.fabric.client.SubmitException; -import org.hyperledger.fabric.client.identity.Identities; -import org.hyperledger.fabric.client.identity.Identity; -import org.hyperledger.fabric.client.identity.Signer; -import org.hyperledger.fabric.client.identity.Signers; -import org.hyperledger.fabric.client.identity.X509Identity; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.security.InvalidKeyException; -import java.security.cert.CertificateException; -import java.time.Instant; -import java.util.concurrent.TimeUnit; - -public final class App { - private static final String MSP_ID = System.getenv().getOrDefault("MSP_ID", "Org1MSP"); - private static final String CHANNEL_NAME = System.getenv().getOrDefault("CHANNEL_NAME", "mychannel"); - private static final String CHAINCODE_NAME = System.getenv().getOrDefault("CHAINCODE_NAME", "basic"); - - // Path to crypto materials. - private static final Path CRYPTO_PATH = Paths.get("../../test-network/organizations/peerOrganizations/org1.example.com"); - // Path to user certificate. - private static final Path CERT_DIR_PATH = CRYPTO_PATH.resolve(Paths.get("users/User1@org1.example.com/msp/signcerts")); - // Path to user private key directory. - private static final Path KEY_DIR_PATH = CRYPTO_PATH.resolve(Paths.get("users/User1@org1.example.com/msp/keystore")); - // Path to peer tls certificate. - private static final Path TLS_CERT_PATH = CRYPTO_PATH.resolve(Paths.get("peers/peer0.org1.example.com/tls/ca.crt")); - - // Gateway peer end point. - private static final String PEER_ENDPOINT = "localhost:7051"; - private static final String OVERRIDE_AUTH = "peer0.org1.example.com"; - - private final Contract contract; - private final String assetId = "asset" + Instant.now().toEpochMilli(); - private final Gson gson = new GsonBuilder().setPrettyPrinting().create(); - - public static void main(final String[] args) throws Exception { - // The gRPC client connection should be shared by all Gateway connections to - // this endpoint. - var channel = newGrpcConnection(); - - var builder = Gateway.newInstance() - .identity(newIdentity()) - .signer(newSigner()) - .hash(Hash.SHA256) - .connection(channel) - // Default timeouts for different gRPC calls - .evaluateOptions(options -> options.withDeadlineAfter(5, TimeUnit.SECONDS)) - .endorseOptions(options -> options.withDeadlineAfter(15, TimeUnit.SECONDS)) - .submitOptions(options -> options.withDeadlineAfter(5, TimeUnit.SECONDS)) - .commitStatusOptions(options -> options.withDeadlineAfter(1, TimeUnit.MINUTES)); - - try (var gateway = builder.connect()) { - new App(gateway).run(); - } finally { - channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS); - } - } - - private static ManagedChannel newGrpcConnection() throws IOException { - var credentials = TlsChannelCredentials.newBuilder() - .trustManager(TLS_CERT_PATH.toFile()) - .build(); - return Grpc.newChannelBuilder(PEER_ENDPOINT, credentials) - .overrideAuthority(OVERRIDE_AUTH) - .build(); - } - - private static Identity newIdentity() throws IOException, CertificateException { - try (var certReader = Files.newBufferedReader(getFirstFilePath(CERT_DIR_PATH))) { - var certificate = Identities.readX509Certificate(certReader); - return new X509Identity(MSP_ID, certificate); - } - } - - private static Signer newSigner() throws IOException, InvalidKeyException { - try (var keyReader = Files.newBufferedReader(getFirstFilePath(KEY_DIR_PATH))) { - var privateKey = Identities.readPrivateKey(keyReader); - return Signers.newPrivateKeySigner(privateKey); - } - } - - private static Path getFirstFilePath(Path dirPath) throws IOException { - try (var keyFiles = Files.list(dirPath)) { - return keyFiles.findFirst().orElseThrow(); - } - } - - public App(final Gateway gateway) { - // Get a network instance representing the channel where the smart contract is - // deployed. - var network = gateway.getNetwork(CHANNEL_NAME); - - // Get the smart contract from the network. - contract = network.getContract(CHAINCODE_NAME); - } - - public void run() throws GatewayException, CommitException { - // Initialize a set of asset data on the ledger using the chaincode 'InitLedger' function. - initLedger(); - - // Return all the current assets on the ledger. - getAllAssets(); - - // Create a new asset on the ledger. - createAsset(); - - // Update an existing asset asynchronously. - transferAssetAsync(); - - // Get the asset details by assetID. - readAssetById(); - - // Update an asset which does not exist. - updateNonExistentAsset(); - } - - /** - * This type of transaction would typically only be run once by an application - * the first time it was started after its initial deployment. A new version of - * the chaincode deployed later would likely not need to run an "init" function. - */ - private void initLedger() throws EndorseException, SubmitException, CommitStatusException, CommitException { - System.out.println("\n--> Submit Transaction: InitLedger, function creates the initial set of assets on the ledger"); - - contract.submitTransaction("InitLedger"); - - System.out.println("*** Transaction committed successfully"); - } - - /** - * Evaluate a transaction to query ledger state. - */ - private void getAllAssets() throws GatewayException { - System.out.println("\n--> Evaluate Transaction: GetAllAssets, function returns all the current assets on the ledger"); - - var result = contract.evaluateTransaction("GetAllAssets"); - - System.out.println("*** Result: " + prettyJson(result)); - } - - private String prettyJson(final byte[] json) { - return prettyJson(new String(json, StandardCharsets.UTF_8)); - } - - private String prettyJson(final String json) { - var parsedJson = JsonParser.parseString(json); - return gson.toJson(parsedJson); - } - - /** - * Submit a transaction synchronously, blocking until it has been committed to - * the ledger. - */ - private void createAsset() throws EndorseException, SubmitException, CommitStatusException, CommitException { - System.out.println("\n--> Submit Transaction: CreateAsset, creates new asset with ID, Color, Size, Owner and AppraisedValue arguments"); - - contract.submitTransaction("CreateAsset", assetId, "yellow", "5", "Tom", "1300"); - - System.out.println("*** Transaction committed successfully"); - } - - /** - * Submit transaction asynchronously, allowing the application to process the - * smart contract response (e.g. update a UI) while waiting for the commit - * notification. - */ - private void transferAssetAsync() throws EndorseException, SubmitException, CommitStatusException { - System.out.println("\n--> Async Submit Transaction: TransferAsset, updates existing asset owner"); - - var commit = contract.newProposal("TransferAsset") - .addArguments(assetId, "Saptha") - .build() - .endorse() - .submitAsync(); - - var result = commit.getResult(); - var oldOwner = new String(result, StandardCharsets.UTF_8); - - System.out.println("*** Successfully submitted transaction to transfer ownership from " + oldOwner + " to Saptha"); - System.out.println("*** Waiting for transaction commit"); - - var status = commit.getStatus(); - if (!status.isSuccessful()) { - throw new RuntimeException("Transaction " + status.getTransactionId() + - " failed to commit with status code " + status.getCode()); - } - - System.out.println("*** Transaction committed successfully"); - } - - private void readAssetById() throws GatewayException { - System.out.println("\n--> Evaluate Transaction: ReadAsset, function returns asset attributes"); - - var evaluateResult = contract.evaluateTransaction("ReadAsset", assetId); - - System.out.println("*** Result:" + prettyJson(evaluateResult)); - } - - /** - * submitTransaction() will throw an error containing details of any error - * responses from the smart contract. - */ - private void updateNonExistentAsset() { - try { - System.out.println("\n--> Submit Transaction: UpdateAsset asset70, asset70 does not exist and should return an error"); - - contract.submitTransaction("UpdateAsset", "asset70", "blue", "5", "Tomoko", "300"); - - System.out.println("******** FAILED to return an error"); - } catch (EndorseException | SubmitException | CommitStatusException e) { - System.out.println("*** Successfully caught the error:"); - e.printStackTrace(System.out); - System.out.println("Transaction ID: " + e.getTransactionId()); - } catch (CommitException e) { - System.out.println("*** Successfully caught the error:"); - e.printStackTrace(System.out); - System.out.println("Transaction ID: " + e.getTransactionId()); - System.out.println("Status code: " + e.getCode()); - } - } -} diff --git a/asset-transfer-basic/application-gateway-javascript/.gitignore b/asset-transfer-basic/application-gateway-javascript/.gitignore deleted file mode 100644 index 24a64171..00000000 --- a/asset-transfer-basic/application-gateway-javascript/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - - -# Coverage directory used by tools like istanbul -coverage - -# Dependency directories -node_modules/ -jspm_packages/ diff --git a/asset-transfer-basic/application-gateway-javascript/.npmrc b/asset-transfer-basic/application-gateway-javascript/.npmrc deleted file mode 100644 index b6f27f13..00000000 --- a/asset-transfer-basic/application-gateway-javascript/.npmrc +++ /dev/null @@ -1 +0,0 @@ -engine-strict=true diff --git a/asset-transfer-basic/application-gateway-javascript/eslint.config.mjs b/asset-transfer-basic/application-gateway-javascript/eslint.config.mjs deleted file mode 100644 index 861b4f0d..00000000 --- a/asset-transfer-basic/application-gateway-javascript/eslint.config.mjs +++ /dev/null @@ -1,15 +0,0 @@ -import js from '@eslint/js'; -import globals from 'globals'; - -export default [ - js.configs.recommended, - { - languageOptions: { - ecmaVersion: 2023, - sourceType: 'commonjs', - globals: { - ...globals.node, - }, - }, - }, -]; diff --git a/asset-transfer-basic/application-gateway-javascript/package.json b/asset-transfer-basic/application-gateway-javascript/package.json deleted file mode 100644 index 896e6339..00000000 --- a/asset-transfer-basic/application-gateway-javascript/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "asset-transfer-basic", - "version": "1.0.0", - "description": "Asset Transfer Basic Application implemented in JavaScript using fabric-gateway", - "engines": { - "node": ">=18" - }, - "scripts": { - "lint": "eslint src", - "pretest": "npm run lint", - "start": "node src/app.js" - }, - "engineStrict": true, - "author": "Hyperledger", - "license": "Apache-2.0", - "dependencies": { - "@grpc/grpc-js": "^1.12.2", - "@hyperledger/fabric-gateway": "^1.7.0" - }, - "devDependencies": { - "@eslint/js": "^9.5.0", - "eslint": "^9.5.0", - "globals": "^15.6.0" - } -} diff --git a/asset-transfer-basic/application-gateway-javascript/src/app.js b/asset-transfer-basic/application-gateway-javascript/src/app.js deleted file mode 100644 index 389d4821..00000000 --- a/asset-transfer-basic/application-gateway-javascript/src/app.js +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -const grpc = require('@grpc/grpc-js'); -const { connect, hash, signers } = require('@hyperledger/fabric-gateway'); -const crypto = require('node:crypto'); -const fs = require('node:fs/promises'); -const path = require('node:path'); -const { TextDecoder } = require('node:util'); - -const channelName = envOrDefault('CHANNEL_NAME', 'mychannel'); -const chaincodeName = envOrDefault('CHAINCODE_NAME', 'basic'); -const mspId = envOrDefault('MSP_ID', 'Org1MSP'); - -// Path to crypto materials. -const cryptoPath = envOrDefault( - 'CRYPTO_PATH', - path.resolve( - __dirname, - '..', - '..', - '..', - 'test-network', - 'organizations', - 'peerOrganizations', - 'org1.example.com' - ) -); - -// Path to user private key directory. -const keyDirectoryPath = envOrDefault( - 'KEY_DIRECTORY_PATH', - path.resolve( - cryptoPath, - 'users', - 'User1@org1.example.com', - 'msp', - 'keystore' - ) -); - -// Path to user certificate directory. -const certDirectoryPath = envOrDefault( - 'CERT_DIRECTORY_PATH', - path.resolve( - cryptoPath, - 'users', - 'User1@org1.example.com', - 'msp', - 'signcerts' - ) -); - -// Path to peer tls certificate. -const tlsCertPath = envOrDefault( - 'TLS_CERT_PATH', - path.resolve(cryptoPath, 'peers', 'peer0.org1.example.com', 'tls', 'ca.crt') -); - -// Gateway peer endpoint. -const peerEndpoint = envOrDefault('PEER_ENDPOINT', 'localhost:7051'); - -// Gateway peer SSL host name override. -const peerHostAlias = envOrDefault('PEER_HOST_ALIAS', 'peer0.org1.example.com'); - -const utf8Decoder = new TextDecoder(); -const assetId = `asset${String(Date.now())}`; - -async function main() { - displayInputParameters(); - - // The gRPC client connection should be shared by all Gateway connections to this endpoint. - const client = await newGrpcConnection(); - - const gateway = connect({ - client, - identity: await newIdentity(), - signer: await newSigner(), - hash: hash.sha256, - // Default timeouts for different gRPC calls - evaluateOptions: () => { - return { deadline: Date.now() + 5000 }; // 5 seconds - }, - endorseOptions: () => { - return { deadline: Date.now() + 15000 }; // 15 seconds - }, - submitOptions: () => { - return { deadline: Date.now() + 5000 }; // 5 seconds - }, - commitStatusOptions: () => { - return { deadline: Date.now() + 60000 }; // 1 minute - }, - }); - - try { - // Get a network instance representing the channel where the smart contract is deployed. - const network = gateway.getNetwork(channelName); - - // Get the smart contract from the network. - const contract = network.getContract(chaincodeName); - - // Initialize a set of asset data on the ledger using the chaincode 'InitLedger' function. - await initLedger(contract); - - // Return all the current assets on the ledger. - await getAllAssets(contract); - - // Create a new asset on the ledger. - await createAsset(contract); - - // Update an existing asset asynchronously. - await transferAssetAsync(contract); - - // Get the asset details by assetID. - await readAssetByID(contract); - - // Update an asset which does not exist. - await updateNonExistentAsset(contract); - } finally { - gateway.close(); - client.close(); - } -} - -main().catch((error) => { - console.error('******** FAILED to run the application:', error); - process.exitCode = 1; -}); - -async function newGrpcConnection() { - const tlsRootCert = await fs.readFile(tlsCertPath); - const tlsCredentials = grpc.credentials.createSsl(tlsRootCert); - return new grpc.Client(peerEndpoint, tlsCredentials, { - 'grpc.ssl_target_name_override': peerHostAlias, - }); -} - -async function newIdentity() { - const certPath = await getFirstDirFileName(certDirectoryPath); - const credentials = await fs.readFile(certPath); - return { mspId, credentials }; -} - -async function getFirstDirFileName(dirPath) { - const files = await fs.readdir(dirPath); - const file = files[0]; - if (!file) { - throw new Error(`No files in directory: ${dirPath}`); - } - return path.join(dirPath, file); -} - -async function newSigner() { - const keyPath = await getFirstDirFileName(keyDirectoryPath); - const privateKeyPem = await fs.readFile(keyPath); - const privateKey = crypto.createPrivateKey(privateKeyPem); - return signers.newPrivateKeySigner(privateKey); -} - -/** - * This type of transaction would typically only be run once by an application the first time it was started after its - * initial deployment. A new version of the chaincode deployed later would likely not need to run an "init" function. - */ -async function initLedger(contract) { - console.log( - '\n--> Submit Transaction: InitLedger, function creates the initial set of assets on the ledger' - ); - - await contract.submitTransaction('InitLedger'); - - console.log('*** Transaction committed successfully'); -} - -/** - * Evaluate a transaction to query ledger state. - */ -async function getAllAssets(contract) { - console.log( - '\n--> Evaluate Transaction: GetAllAssets, function returns all the current assets on the ledger' - ); - - const resultBytes = await contract.evaluateTransaction('GetAllAssets'); - - const resultJson = utf8Decoder.decode(resultBytes); - const result = JSON.parse(resultJson); - console.log('*** Result:', result); -} - -/** - * Submit a transaction synchronously, blocking until it has been committed to the ledger. - */ -async function createAsset(contract) { - console.log( - '\n--> Submit Transaction: CreateAsset, creates new asset with ID, Color, Size, Owner and AppraisedValue arguments' - ); - - await contract.submitTransaction( - 'CreateAsset', - assetId, - 'yellow', - '5', - 'Tom', - '1300' - ); - - console.log('*** Transaction committed successfully'); -} - -/** - * Submit transaction asynchronously, allowing the application to process the smart contract response (e.g. update a UI) - * while waiting for the commit notification. - */ -async function transferAssetAsync(contract) { - console.log( - '\n--> Async Submit Transaction: TransferAsset, updates existing asset owner' - ); - - const commit = await contract.submitAsync('TransferAsset', { - arguments: [assetId, 'Saptha'], - }); - const oldOwner = utf8Decoder.decode(commit.getResult()); - - console.log( - `*** Successfully submitted transaction to transfer ownership from ${oldOwner} to Saptha` - ); - console.log('*** Waiting for transaction commit'); - - const status = await commit.getStatus(); - if (!status.successful) { - throw new Error( - `Transaction ${ - status.transactionId - } failed to commit with status code ${String(status.code)}` - ); - } - - console.log('*** Transaction committed successfully'); -} - -async function readAssetByID(contract) { - console.log( - '\n--> Evaluate Transaction: ReadAsset, function returns asset attributes' - ); - - const resultBytes = await contract.evaluateTransaction( - 'ReadAsset', - assetId - ); - - const resultJson = utf8Decoder.decode(resultBytes); - const result = JSON.parse(resultJson); - console.log('*** Result:', result); -} - -/** - * submitTransaction() will throw an error containing details of any error responses from the smart contract. - */ -async function updateNonExistentAsset(contract) { - console.log( - '\n--> Submit Transaction: UpdateAsset asset70, asset70 does not exist and should return an error' - ); - - try { - await contract.submitTransaction( - 'UpdateAsset', - 'asset70', - 'blue', - '5', - 'Tomoko', - '300' - ); - console.log('******** FAILED to return an error'); - } catch (error) { - console.log('*** Successfully caught the error: \n', error); - } -} - -/** - * envOrDefault() will return the value of an environment variable, or a default value if the variable is undefined. - */ -function envOrDefault(key, defaultValue) { - return process.env[key] || defaultValue; -} - -/** - * displayInputParameters() will print the global scope parameters used by the main driver routine. - */ -function displayInputParameters() { - console.log(`channelName: ${channelName}`); - console.log(`chaincodeName: ${chaincodeName}`); - console.log(`mspId: ${mspId}`); - console.log(`cryptoPath: ${cryptoPath}`); - console.log(`keyDirectoryPath: ${keyDirectoryPath}`); - console.log(`certDirectoryPath: ${certDirectoryPath}`); - console.log(`tlsCertPath: ${tlsCertPath}`); - console.log(`peerEndpoint: ${peerEndpoint}`); - console.log(`peerHostAlias: ${peerHostAlias}`); -} diff --git a/asset-transfer-basic/application-gateway-typescript/.gitignore b/asset-transfer-basic/application-gateway-typescript/.gitignore deleted file mode 100644 index 99e5af9f..00000000 --- a/asset-transfer-basic/application-gateway-typescript/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - - -# Coverage directory used by tools like istanbul -coverage - -# Dependency directories -node_modules/ -jspm_packages/ - -# Compiled TypeScript files -dist diff --git a/asset-transfer-basic/application-gateway-typescript/.npmrc b/asset-transfer-basic/application-gateway-typescript/.npmrc deleted file mode 100644 index b6f27f13..00000000 --- a/asset-transfer-basic/application-gateway-typescript/.npmrc +++ /dev/null @@ -1 +0,0 @@ -engine-strict=true diff --git a/asset-transfer-basic/application-gateway-typescript/eslint.config.mjs b/asset-transfer-basic/application-gateway-typescript/eslint.config.mjs deleted file mode 100644 index 9ef6b243..00000000 --- a/asset-transfer-basic/application-gateway-typescript/eslint.config.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import js from '@eslint/js'; -import tseslint from 'typescript-eslint'; - -export default tseslint.config(js.configs.recommended, ...tseslint.configs.strictTypeChecked, { - languageOptions: { - ecmaVersion: 2023, - sourceType: 'module', - parserOptions: { - project: 'tsconfig.json', - tsconfigRootDir: import.meta.dirname, - }, - }, -}); diff --git a/asset-transfer-basic/application-gateway-typescript/package.json b/asset-transfer-basic/application-gateway-typescript/package.json deleted file mode 100644 index 5327cb76..00000000 --- a/asset-transfer-basic/application-gateway-typescript/package.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "asset-transfer-basic", - "version": "1.0.0", - "description": "Asset Transfer Basic Application implemented in typeScript using fabric-gateway", - "main": "dist/index.js", - "typings": "dist/index.d.ts", - "engines": { - "node": ">=18" - }, - "scripts": { - "build": "tsc", - "build:watch": "tsc -w", - "lint": "eslint src", - "prepare": "npm run build", - "pretest": "npm run lint", - "start": "node dist/app.js" - }, - "engineStrict": true, - "author": "Hyperledger", - "license": "Apache-2.0", - "dependencies": { - "@grpc/grpc-js": "^1.12.2", - "@hyperledger/fabric-gateway": "^1.7.0" - }, - "devDependencies": { - "@eslint/js": "^9.3.0", - "@tsconfig/node18": "^18.2.2", - "@types/node": "^18.18.6", - "eslint": "^8.57.0", - "typescript": "~5.4", - "typescript-eslint": "^7.13.0" - } -} diff --git a/asset-transfer-basic/application-gateway-typescript/src/app.ts b/asset-transfer-basic/application-gateway-typescript/src/app.ts deleted file mode 100644 index fd4bdc95..00000000 --- a/asset-transfer-basic/application-gateway-typescript/src/app.ts +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as grpc from '@grpc/grpc-js'; -import { connect, Contract, hash, Identity, Signer, signers } from '@hyperledger/fabric-gateway'; -import * as crypto from 'crypto'; -import { promises as fs } from 'fs'; -import * as path from 'path'; -import { TextDecoder } from 'util'; - -const channelName = envOrDefault('CHANNEL_NAME', 'mychannel'); -const chaincodeName = envOrDefault('CHAINCODE_NAME', 'basic'); -const mspId = envOrDefault('MSP_ID', 'Org1MSP'); - -// Path to crypto materials. -const cryptoPath = envOrDefault('CRYPTO_PATH', path.resolve(__dirname, '..', '..', '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.example.com')); - -// Path to user private key directory. -const keyDirectoryPath = envOrDefault('KEY_DIRECTORY_PATH', path.resolve(cryptoPath, 'users', 'User1@org1.example.com', 'msp', 'keystore')); - -// Path to user certificate directory. -const certDirectoryPath = envOrDefault('CERT_DIRECTORY_PATH', path.resolve(cryptoPath, 'users', 'User1@org1.example.com', 'msp', 'signcerts')); - -// Path to peer tls certificate. -const tlsCertPath = envOrDefault('TLS_CERT_PATH', path.resolve(cryptoPath, 'peers', 'peer0.org1.example.com', 'tls', 'ca.crt')); - -// Gateway peer endpoint. -const peerEndpoint = envOrDefault('PEER_ENDPOINT', 'localhost:7051'); - -// Gateway peer SSL host name override. -const peerHostAlias = envOrDefault('PEER_HOST_ALIAS', 'peer0.org1.example.com'); - -const utf8Decoder = new TextDecoder(); -const assetId = `asset${String(Date.now())}`; - -async function main(): Promise { - displayInputParameters(); - - // The gRPC client connection should be shared by all Gateway connections to this endpoint. - const client = await newGrpcConnection(); - - const gateway = connect({ - client, - identity: await newIdentity(), - signer: await newSigner(), - hash: hash.sha256, - // Default timeouts for different gRPC calls - evaluateOptions: () => { - return { deadline: Date.now() + 5000 }; // 5 seconds - }, - endorseOptions: () => { - return { deadline: Date.now() + 15000 }; // 15 seconds - }, - submitOptions: () => { - return { deadline: Date.now() + 5000 }; // 5 seconds - }, - commitStatusOptions: () => { - return { deadline: Date.now() + 60000 }; // 1 minute - }, - }); - - try { - // Get a network instance representing the channel where the smart contract is deployed. - const network = gateway.getNetwork(channelName); - - // Get the smart contract from the network. - const contract = network.getContract(chaincodeName); - - // Initialize a set of asset data on the ledger using the chaincode 'InitLedger' function. - await initLedger(contract); - - // Return all the current assets on the ledger. - await getAllAssets(contract); - - // Create a new asset on the ledger. - await createAsset(contract); - - // Update an existing asset asynchronously. - await transferAssetAsync(contract); - - // Get the asset details by assetID. - await readAssetByID(contract); - - // Update an asset which does not exist. - await updateNonExistentAsset(contract) - } finally { - gateway.close(); - client.close(); - } -} - -main().catch((error: unknown) => { - console.error('******** FAILED to run the application:', error); - process.exitCode = 1; -}); - -async function newGrpcConnection(): Promise { - const tlsRootCert = await fs.readFile(tlsCertPath); - const tlsCredentials = grpc.credentials.createSsl(tlsRootCert); - return new grpc.Client(peerEndpoint, tlsCredentials, { - 'grpc.ssl_target_name_override': peerHostAlias, - }); -} - -async function newIdentity(): Promise { - const certPath = await getFirstDirFileName(certDirectoryPath); - const credentials = await fs.readFile(certPath); - return { mspId, credentials }; -} - -async function getFirstDirFileName(dirPath: string): Promise { - const files = await fs.readdir(dirPath); - const file = files[0]; - if (!file) { - throw new Error(`No files in directory: ${dirPath}`); - } - return path.join(dirPath, file); -} - -async function newSigner(): Promise { - const keyPath = await getFirstDirFileName(keyDirectoryPath); - const privateKeyPem = await fs.readFile(keyPath); - const privateKey = crypto.createPrivateKey(privateKeyPem); - return signers.newPrivateKeySigner(privateKey); -} - -/** - * This type of transaction would typically only be run once by an application the first time it was started after its - * initial deployment. A new version of the chaincode deployed later would likely not need to run an "init" function. - */ -async function initLedger(contract: Contract): Promise { - console.log('\n--> Submit Transaction: InitLedger, function creates the initial set of assets on the ledger'); - - await contract.submitTransaction('InitLedger'); - - console.log('*** Transaction committed successfully'); -} - -/** - * Evaluate a transaction to query ledger state. - */ -async function getAllAssets(contract: Contract): Promise { - console.log('\n--> Evaluate Transaction: GetAllAssets, function returns all the current assets on the ledger'); - - const resultBytes = await contract.evaluateTransaction('GetAllAssets'); - - const resultJson = utf8Decoder.decode(resultBytes); - const result: unknown = JSON.parse(resultJson); - console.log('*** Result:', result); -} - -/** - * Submit a transaction synchronously, blocking until it has been committed to the ledger. - */ -async function createAsset(contract: Contract): Promise { - console.log('\n--> Submit Transaction: CreateAsset, creates new asset with ID, Color, Size, Owner and AppraisedValue arguments'); - - await contract.submitTransaction( - 'CreateAsset', - assetId, - 'yellow', - '5', - 'Tom', - '1300', - ); - - console.log('*** Transaction committed successfully'); -} - -/** - * Submit transaction asynchronously, allowing the application to process the smart contract response (e.g. update a UI) - * while waiting for the commit notification. - */ -async function transferAssetAsync(contract: Contract): Promise { - console.log('\n--> Async Submit Transaction: TransferAsset, updates existing asset owner'); - - const commit = await contract.submitAsync('TransferAsset', { - arguments: [assetId, 'Saptha'], - }); - const oldOwner = utf8Decoder.decode(commit.getResult()); - - console.log(`*** Successfully submitted transaction to transfer ownership from ${oldOwner} to Saptha`); - console.log('*** Waiting for transaction commit'); - - const status = await commit.getStatus(); - if (!status.successful) { - throw new Error(`Transaction ${status.transactionId} failed to commit with status code ${String(status.code)}`); - } - - console.log('*** Transaction committed successfully'); -} - -async function readAssetByID(contract: Contract): Promise { - console.log('\n--> Evaluate Transaction: ReadAsset, function returns asset attributes'); - - const resultBytes = await contract.evaluateTransaction('ReadAsset', assetId); - - const resultJson = utf8Decoder.decode(resultBytes); - const result: unknown = JSON.parse(resultJson); - console.log('*** Result:', result); -} - -/** - * submitTransaction() will throw an error containing details of any error responses from the smart contract. - */ -async function updateNonExistentAsset(contract: Contract): Promise{ - console.log('\n--> Submit Transaction: UpdateAsset asset70, asset70 does not exist and should return an error'); - - try { - await contract.submitTransaction( - 'UpdateAsset', - 'asset70', - 'blue', - '5', - 'Tomoko', - '300', - ); - console.log('******** FAILED to return an error'); - } catch (error) { - console.log('*** Successfully caught the error: \n', error); - } -} - -/** - * envOrDefault() will return the value of an environment variable, or a default value if the variable is undefined. - */ -function envOrDefault(key: string, defaultValue: string): string { - return process.env[key] || defaultValue; -} - -/** - * displayInputParameters() will print the global scope parameters used by the main driver routine. - */ -function displayInputParameters(): void { - console.log(`channelName: ${channelName}`); - console.log(`chaincodeName: ${chaincodeName}`); - console.log(`mspId: ${mspId}`); - console.log(`cryptoPath: ${cryptoPath}`); - console.log(`keyDirectoryPath: ${keyDirectoryPath}`); - console.log(`certDirectoryPath: ${certDirectoryPath}`); - console.log(`tlsCertPath: ${tlsCertPath}`); - console.log(`peerEndpoint: ${peerEndpoint}`); - console.log(`peerHostAlias: ${peerHostAlias}`); -} diff --git a/asset-transfer-basic/application-gateway-typescript/tsconfig.json b/asset-transfer-basic/application-gateway-typescript/tsconfig.json deleted file mode 100644 index 4c20df24..00000000 --- a/asset-transfer-basic/application-gateway-typescript/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "@tsconfig/node18/tsconfig.json", - "compilerOptions": { - "outDir": "dist", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "noUnusedLocals": true, - "noImplicitReturns": true, - "noUncheckedIndexedAccess": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["./src/**/*"], - "exclude": ["./src/**/*.spec.ts"] -} diff --git a/asset-transfer-basic/chaincode-external/.dockerignore b/asset-transfer-basic/chaincode-external/.dockerignore deleted file mode 100644 index 61260e58..00000000 --- a/asset-transfer-basic/chaincode-external/.dockerignore +++ /dev/null @@ -1,5 +0,0 @@ -chaincode.env* -*.json -*.md -*.tar.gz -*.tgz diff --git a/asset-transfer-basic/chaincode-external/.gitignore b/asset-transfer-basic/chaincode-external/.gitignore deleted file mode 100644 index 438df6cb..00000000 --- a/asset-transfer-basic/chaincode-external/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.tar.gz -*.tgz -crypto/*.pem diff --git a/asset-transfer-basic/chaincode-external/Dockerfile b/asset-transfer-basic/chaincode-external/Dockerfile deleted file mode 100644 index 8341e6fd..00000000 --- a/asset-transfer-basic/chaincode-external/Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 - -ARG GO_VER=1.22 -ARG ALPINE_VER=3.20 - -FROM golang:${GO_VER}-alpine${ALPINE_VER} - -WORKDIR /go/src/github.com/hyperledger/fabric-samples/asset-transfer-basic/chaincode-external -COPY . . - -RUN go get -d -v ./... -RUN go install -v ./... - -EXPOSE 9999 -CMD ["chaincode-external"] diff --git a/asset-transfer-basic/chaincode-external/README.md b/asset-transfer-basic/chaincode-external/README.md deleted file mode 100755 index 2a20da90..00000000 --- a/asset-transfer-basic/chaincode-external/README.md +++ /dev/null @@ -1,252 +0,0 @@ -# Asset-Transfer-Basic as an external service - -This sample provides an introduction to how to use external builder and launcher scripts to run chaincode as an external service to your peer. For more information, see the [Chaincode as an external service](https://hyperledger-fabric.readthedocs.io/en/latest/cc_service.html) topic in the Fabric documentation. - -**Note:** each organization in a real network would need to setup and host their own instance of the external service. In this tutorial, we use the same instance for both organizations for simplicity. - -## Setting up the external builder and launcher - -External Builders and Launchers is an advanced feature that typically requires custom packaging of the peer image so that it contains all the tools your builder and launcher require. This sample uses very simple (and crude) shell scripts that can be run directly within the default Fabric peer images. - -Open the `config/core.yaml` file at the top of the `fabric-samples` directory. If you do not have this file, follow the instructions to [Install the Samples, Binaries and Docker Images](https://hyperledger-fabric.readthedocs.io/en/latest/install.html) to download the Fabric binaries and configuration files alongside the Fabric samples. - -Modify the `externalBuilders` field in the `core.yaml` file to resemble the configuration below: - -``` -externalBuilders: - - path: /opt/gopath/src/github.com/hyperledger/fabric-samples/asset-transfer-basic/chaincode-external/sampleBuilder - name: external-sample-builder -``` - -This update sets the name of the external builder as `external-sample-builder`, and the path of the builder to the scripts provided in this sample. Note that this is the path within the peer container, not your local machine. - -To set the path within the peer container, you will need to modify the docker compose file to mount a couple of additional volumes. Open the file `test-network/compose/docker/docker-compose-test-net.yaml`, and add to the `volumes` section of both `peer0.org1.example.com` and `peer0.org2.example.com` the following two lines: - -``` - - ../..:/opt/gopath/src/github.com/hyperledger/fabric-samples - - ../../config/core.yaml:/etc/hyperledger/peercfg/core.yaml -``` - -This update will mount the `core.yaml` that you modified into the peer container and override the configuration file within the peer image. The update also mounts the fabric-sample builder so that it can be found at the location that you specified in `core.yaml`. You also have the option of commenting out the line `- /var/run/docker.sock:/host/var/run/docker.sock`, since we no longer need to access the docker daemon from inside the peer container to launch the chaincode. - -## Packaging and installing Chaincode - -The Asset-Transfer-Basic external chaincode requires two environment variables to run, `CHAINCODE_SERVER_ADDRESS` and `CHAINCODE_ID`, which are described and set in the `chaincode.env` file. - -You need to provide a `connection.json` configuration file to your peer in order to connect to the external Asset-Transfer-Basic service. The address specified in the `connection.json` must correspond to the `CHAINCODE_SERVER_ADDRESS` value in `chaincode.env`, which is `asset-transfer-basic.org1.example.com:9999` in our example. - -Because we will run our chaincode as an external service, the chaincode itself does not need to be included in the chaincode -package that gets installed to each peer. Only the configuration and metadata information needs to be included -in the package. Since the packaging is trivial, we can manually create the chaincode package. - -Open a new terminal and navigate to the `fabric-samples/asset-transfer-basic/chaincode-external` directory. - -``` -cd fabric-samples/asset-transfer-basic/chaincode-external -``` - -First, create a `code.tar.gz` archive containing the `connection.json` file: - -``` -tar cfz code.tar.gz connection.json -``` - -Then, create the chaincode package, including the `code.tar.gz` file and the supplied `metadata.json` file: - -``` -tar cfz asset-transfer-basic-external.tgz metadata.json code.tar.gz -``` - -You are now ready to deploy the external chaincode sample. - -## Starting the test network - -We will use the Fabric test network to run the external chaincode. Open a new terminal and navigate to the `fabric-samples/test-network` directory. - -``` -cd fabric-samples/test-network -``` - -Run the following command to deploy the test network and create a new channel: - -``` -./network.sh up createChannel -c mychannel -ca -``` - -We are now ready to deploy the external chaincode. - -## Installing the external chaincode - -We can't use the test network script to install an external chaincode so we will have to do a bit more work. However, we can still leverage part of the test-network scripts to make this easier. - -From the `test-network` directory, set the following environment variables to use the Fabric binaries: - -``` -export PATH=${PWD}/../bin:$PATH -export FABRIC_CFG_PATH=$PWD/../config/ -``` - -Run the following command to import functions from the `envVar.sh` script into your terminal. These functions allow you to act as either test network organization. - -``` -. ./scripts/envVar.sh -``` - -Run the following commands to install the `asset-transfer-basic-external.tar.gz` chaincode on org1. The `setGlobals` function simply sets the environment variables that allow you to act as org1 or org2. - -``` -setGlobals 1 -peer lifecycle chaincode install ../asset-transfer-basic/chaincode-external/asset-transfer-basic-external.tgz -``` - -Install the chaincode package on the org2 peer: - -``` -setGlobals 2 -peer lifecycle chaincode install ../asset-transfer-basic/chaincode-external/asset-transfer-basic-external.tgz -``` - -Run the following command to query the package ID of the chaincode that you just installed: - -``` -setGlobals 1 -peer lifecycle chaincode queryinstalled --peerAddresses localhost:7051 --tlsRootCertFiles organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt -``` - -The command will return output similar to the following: - -``` -Installed chaincodes on peer: -Package ID: basic_1.0:ecfc83f251b7c2d9ef376bc3fc20fc6b9744c0fc0a8923092af6542af94790c3, Label: basic_1.0 -``` - -Save the package ID that was returned by the command as an environment variable. The ID will not be the same for all users, so you need to set the variable using the ID from your command window: - -``` -export CHAINCODE_ID=basic_1.0:ecfc83f251b7c2d9ef376bc3fc20fc6b9744c0fc0a8923092af6542af94790c3 -``` - -## Running the Asset-Transfer-Basic external service - -We are going to run the smart contract as an external service by first building and then starting a docker container. Open a new terminal and navigate back to the `chaincode-external` directory: - -``` -cd fabric-samples/asset-transfer-basic/chaincode-external -``` - -In this directory, open the `chaincode.env` file to set the `CHAINCODE_ID` variable to the same package ID that was returned by the `peer lifecycle chaincode queryinstalled` command. The value should be the same as the environment variable that you set in the previous terminal. - -After you edit the `chaincode.env` file, you can use the `Dockerfile` to build an image of the external Asset-Transfer-Basic chaincode: - -``` -docker build -t hyperledger/asset-transfer-basic . -``` - -You can then run the image to start the Asset-Transfer-Basic service: - -``` -docker run -it --rm --name asset-transfer-basic.org1.example.com --hostname asset-transfer-basic.org1.example.com --env-file chaincode.env --network=fabric_test hyperledger/asset-transfer-basic -``` - -This will start and run the external chaincode service within the container. - -## Deploy the Asset-Transfer-Basic external chaincode definition to the channel - -Navigate back to the `test-network` directory to finish deploying the chaincode definition of the external smart contract to the channel. Make sure that your environment variables are still set. - -``` -setGlobals 2 -peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "$PWD/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --channelID mychannel --name basic --version 1.0 --package-id $CHAINCODE_ID --sequence 1 - -setGlobals 1 -peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "$PWD/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --channelID mychannel --name basic --version 1.0 --package-id $CHAINCODE_ID --sequence 1 - -peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "$PWD/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --channelID mychannel --name basic --peerAddresses localhost:7051 --tlsRootCertFiles "$PWD/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --version 1.0 --sequence 1 -``` - -The commands above approve the chaincode definition for the external chaincode and commits the definition to the channel. The resulting output should be similar to the following: - -``` -2020-08-05 15:41:44.982 PDT [chaincodeCmd] ClientWait -> INFO 001 txid [6bdbe040b99a45cc90a23ec21f02ea5da7be8b70590eb04ff3323ef77fdedfc7] committed with status (VALID) at localhost:7051 -2020-08-05 15:41:44.983 PDT [chaincodeCmd] ClientWait -> INFO 002 txid [6bdbe040b99a45cc90a23ec21f02ea5da7be8b70590eb04ff3323ef77fdedfc7] committed with status (VALID) at localhost:9051 -``` - -Now that we have started the chaincode service and deployed it to the channel, we can submit transactions as we would with a normal chaincode. - -## Using the Asset-Transfer-Basic external chaincode - -Open yet another terminal and navigate to the `fabric-samples/asset-transfer-basic/application-gateway-go` directory: - -``` -cd fabric-samples/asset-transfer-basic/application-gateway-go -``` - -Run the following commands to use the node application in this directory to test the external smart contract: - -``` -go run . -``` - -If all goes well, the program should run exactly the same as described in the "Writing Your First Application" tutorial. - -## Enabling TLS for chaincode and peer communication - -**Note:** This section uses an example of self-signed certificate. You may use your organization hosted CA to issue the certificate and generate a key for production deployment. - -In the sample so far, you connected both peers in `test-network` to the single instance of chaincode server. However, if you would like to enable TLS between the peer nodes and the chaincode server, each peer node needs to have its own CA certificate. Enabling TLS is made possible at runtime in the chaincode. - -- As a first step generate a keypair that can be used. Run these commands from the `fabric-samples/asset-transfer-basic/chaincode-external` directory. - -_Find instructions to install `openssl` in [openssl.org](https://www.openssl.org/)_ - -For `org1.example.com` - -``` -openssl req -nodes -x509 -newkey rsa:4096 -keyout crypto/key1.pem -out crypto/cert1.pem -subj "/C=IN/ST=KA/L=Bangalore/O=example Inc/OU=Developer/CN=asset-transfer-basic.org1.example.com/emailAddress=dev@asset-transfer-basic.org1.example.com" -``` - -For `org2.example.com` - -``` -openssl req -nodes -x509 -newkey rsa:4096 -keyout crypto/key2.pem -out crypto/cert2.pem -subj "/C=IN/ST=KA/L=Bangalore/O=example Inc/OU=Developer/CN=asset-transfer-basic.org2.example.com/emailAddress=dev@asset-transfer-basic.org2.example.com" -``` - -- Copy the CA file contents for both `org1.example.com` & `org2.example.com` - -``` -cp ../../test-network/organizations/peerOrganizations/org1.example.com/ca/ca.org1.example.com-cert.pem crypto/rootcert1.pem -cp ../../test-network/organizations/peerOrganizations/org2.example.com/ca/ca.org2.example.com-cert.pem crypto/rootcert2.pem -``` - -- Generate a client key and cert for auth purpose. You need a key and cert generated from the CA of each organization. Peer nodes act as clients to chaincode server. - -- Change the `connection.json` with the below contents. The `root_cert` parameter is the root CA certificate which the chaincode server is run with. You may run the below commands to get the certificate file contents as strings and copy them when needed. - -``` -awk 'NF {sub(/\r/, ""); printf "%s\\n",$0;}' crypto/cert1.pem -awk 'NF {sub(/\r/, ""); printf "%s\\n",$0;}' crypto/cert2.pem -``` - -Similarly, replace the `client_key` and the `client_cert` contents with the values from the previous step. - -``` -{ - "address": "asset-transfer-basic.org1.example.com:9999", - "dial_timeout": "10s", - "tls_required": true, - "client_auth_required": true, - "client_key": "-----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY-----", - "client_cert": "-----BEGIN CERTIFICATE---- ... -----END CERTIFICATE-----", - "root_cert": "-----BEGIN CERTIFICATE---- ... -----END CERTIFICATE-----" -} -``` - -- Follow the instructions in [Package](#packaging-and-installing-chaincode) and [Install](#installing-the-external-chaincode) steps for each organization. Remember that the chaincode server's address for the second organization is `asset-transfer-basic.org2.example.com:9999`. - -- Copy the appropriate `CHAINCODE_ID` to both [chaincode1.env](./chaincode1.env) and [chaincode2.env](./chaincode2.env) files. Bring up the chaincode containers using the docker-compose command below - -``` -docker-compose up -f docker-compose-chaincode.yaml up --build -d -``` - -- Follow the instructions in [Finish Deployment](#finish-deploying-the-asset-transfer-basic-external-chaincode-) for each organization seperately. diff --git a/asset-transfer-basic/chaincode-external/assetTransfer.go b/asset-transfer-basic/chaincode-external/assetTransfer.go deleted file mode 100644 index 665ccf53..00000000 --- a/asset-transfer-basic/chaincode-external/assetTransfer.go +++ /dev/null @@ -1,297 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "encoding/json" - "fmt" - "log" - "os" - "strconv" - - "github.com/hyperledger/fabric-chaincode-go/v2/shim" - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -type serverConfig struct { - CCID string - Address string -} - -// SmartContract provides functions for managing an asset -type SmartContract struct { - contractapi.Contract -} - -// Asset describes basic details of what makes up a simple asset -type Asset struct { - ID string `json:"ID"` - Color string `json:"color"` - Size int `json:"size"` - Owner string `json:"owner"` - AppraisedValue int `json:"appraisedValue"` -} - -// QueryResult structure used for handling result of query -type QueryResult struct { - Key string `json:"Key"` - Record *Asset -} - -// InitLedger adds a base set of cars to the ledger -func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error { - assets := []Asset{ - {ID: "asset1", Color: "blue", Size: 5, Owner: "Tomoko", AppraisedValue: 300}, - {ID: "asset2", Color: "red", Size: 5, Owner: "Brad", AppraisedValue: 400}, - {ID: "asset3", Color: "green", Size: 10, Owner: "Jin Soo", AppraisedValue: 500}, - {ID: "asset4", Color: "yellow", Size: 10, Owner: "Max", AppraisedValue: 600}, - {ID: "asset5", Color: "black", Size: 15, Owner: "Adriana", AppraisedValue: 700}, - {ID: "asset6", Color: "white", Size: 15, Owner: "Michel", AppraisedValue: 800}, - } - - for _, asset := range assets { - assetJSON, err := json.Marshal(asset) - if err != nil { - return err - } - - err = ctx.GetStub().PutState(asset.ID, assetJSON) - if err != nil { - return fmt.Errorf("failed to put to world state: %v", err) - } - } - - return nil -} - -// CreateAsset issues a new asset to the world state with given details. -func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, id, color string, size int, owner string, appraisedValue int) error { - exists, err := s.AssetExists(ctx, id) - if err != nil { - return err - } - if exists { - return fmt.Errorf("the asset %s already exists", id) - } - asset := Asset{ - ID: id, - Color: color, - Size: size, - Owner: owner, - AppraisedValue: appraisedValue, - } - - assetJSON, err := json.Marshal(asset) - if err != nil { - return err - } - - return ctx.GetStub().PutState(id, assetJSON) -} - -// ReadAsset returns the asset stored in the world state with given id. -func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, id string) (*Asset, error) { - assetJSON, err := ctx.GetStub().GetState(id) - if err != nil { - return nil, fmt.Errorf("failed to read from world state. %s", err.Error()) - } - if assetJSON == nil { - return nil, fmt.Errorf("the asset %s does not exist", id) - } - - var asset Asset - err = json.Unmarshal(assetJSON, &asset) - if err != nil { - return nil, err - } - - return &asset, nil -} - -// UpdateAsset updates an existing asset in the world state with provided parameters. -func (s *SmartContract) UpdateAsset(ctx contractapi.TransactionContextInterface, id, color string, size int, owner string, appraisedValue int) error { - exists, err := s.AssetExists(ctx, id) - if err != nil { - return err - } - if !exists { - return fmt.Errorf("the asset %s does not exist", id) - } - - // overwriting original asset with new asset - asset := Asset{ - ID: id, - Color: color, - Size: size, - Owner: owner, - AppraisedValue: appraisedValue, - } - - assetJSON, err := json.Marshal(asset) - if err != nil { - return err - } - - return ctx.GetStub().PutState(id, assetJSON) -} - -// DeleteAsset deletes a given asset from the world state. -func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface, id string) error { - exists, err := s.AssetExists(ctx, id) - if err != nil { - return err - } - if !exists { - return fmt.Errorf("the asset %s does not exist", id) - } - - return ctx.GetStub().DelState(id) -} - -// AssetExists returns true when asset with given ID exists in world state -func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, id string) (bool, error) { - assetJSON, err := ctx.GetStub().GetState(id) - if err != nil { - return false, fmt.Errorf("failed to read from world state. %s", err.Error()) - } - - return assetJSON != nil, nil -} - -// TransferAsset updates the owner field of asset with given id in world state, and returns the old owner. -func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) (string, error) { - asset, err := s.ReadAsset(ctx, id) - if err != nil { - return "", err - } - - oldOwner := asset.Owner - asset.Owner = newOwner - - assetJSON, err := json.Marshal(asset) - if err != nil { - return "", err - } - - err = ctx.GetStub().PutState(id, assetJSON) - if err != nil { - return "", err - } - - return oldOwner, nil -} - -// GetAllAssets returns all assets found in world state -func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface) ([]QueryResult, error) { - // range query with empty string for startKey and endKey does an open-ended query of all assets in the chaincode namespace. - resultsIterator, err := ctx.GetStub().GetStateByRange("", "") - - if err != nil { - return nil, err - } - defer resultsIterator.Close() - - var results []QueryResult - - for resultsIterator.HasNext() { - queryResponse, err := resultsIterator.Next() - - if err != nil { - return nil, err - } - - var asset Asset - err = json.Unmarshal(queryResponse.Value, &asset) - if err != nil { - return nil, err - } - - queryResult := QueryResult{Key: queryResponse.Key, Record: &asset} - results = append(results, queryResult) - } - - return results, nil -} - -func main() { - // See chaincode.env.example - config := serverConfig{ - CCID: os.Getenv("CHAINCODE_ID"), - Address: os.Getenv("CHAINCODE_SERVER_ADDRESS"), - } - - chaincode, err := contractapi.NewChaincode(&SmartContract{}) - - if err != nil { - log.Panicf("error create asset-transfer-basic chaincode: %s", err) - } - - server := &shim.ChaincodeServer{ - CCID: config.CCID, - Address: config.Address, - CC: chaincode, - TLSProps: getTLSProperties(), - } - - if err := server.Start(); err != nil { - log.Panicf("error starting asset-transfer-basic chaincode: %s", err) - } -} - -func getTLSProperties() shim.TLSProperties { - // Check if chaincode is TLS enabled - tlsDisabledStr := getEnvOrDefault("CHAINCODE_TLS_DISABLED", "true") - key := getEnvOrDefault("CHAINCODE_TLS_KEY", "") - cert := getEnvOrDefault("CHAINCODE_TLS_CERT", "") - clientCACert := getEnvOrDefault("CHAINCODE_CLIENT_CA_CERT", "") - - // convert tlsDisabledStr to boolean - tlsDisabled := getBoolOrDefault(tlsDisabledStr, false) - var keyBytes, certBytes, clientCACertBytes []byte - var err error - - if !tlsDisabled { - keyBytes, err = os.ReadFile(key) - if err != nil { - log.Panicf("error while reading the crypto file: %s", err) - } - certBytes, err = os.ReadFile(cert) - if err != nil { - log.Panicf("error while reading the crypto file: %s", err) - } - } - // Did not request for the peer cert verification - if clientCACert != "" { - clientCACertBytes, err = os.ReadFile(clientCACert) - if err != nil { - log.Panicf("error while reading the crypto file: %s", err) - } - } - - return shim.TLSProperties{ - Disabled: tlsDisabled, - Key: keyBytes, - Cert: certBytes, - ClientCACerts: clientCACertBytes, - } -} - -func getEnvOrDefault(env, defaultVal string) string { - value, ok := os.LookupEnv(env) - if !ok { - value = defaultVal - } - return value -} - -// Note that the method returns default value if the string -// cannot be parsed! -func getBoolOrDefault(value string, defaultVal bool) bool { - parsed, err := strconv.ParseBool(value) - if err != nil { - return defaultVal - } - return parsed -} diff --git a/asset-transfer-basic/chaincode-external/chaincode.env b/asset-transfer-basic/chaincode-external/chaincode.env deleted file mode 100644 index 3daa988c..00000000 --- a/asset-transfer-basic/chaincode-external/chaincode.env +++ /dev/null @@ -1,24 +0,0 @@ -# CHAINCODE_SERVER_ADDRESS must be set to the host and port where the peer can -# connect to the chaincode server -CHAINCODE_SERVER_ADDRESS=asset-transfer-basic.org1.example.com:9999 - -# CHAINCODE_ID must be set to the Package ID that is assigned to the chaincode -# on install. The `peer lifecycle chaincode queryinstalled` command can be -# used to get the ID after install if required -CHAINCODE_ID=basic_1.0:0262396ccaffaa2174bc09f750f742319c4f14d60b16334d2c8921b6842c090c - -# Optional parameters that will be used for TLS connection between peer node -# and the chaincode. -# TLS is disabled by default, uncomment the following line to enable TLS connection -# CHAINCODE_TLS_DISABLED=false - -# Following variables will be ignored if TLS is not enabled. -# They need to be in PEM format -# CHAINCODE_TLS_KEY=/path/to/private/key/file -# CHAINCODE_TLS_CERT=/path/to/public/cert/file - -# The following variable will be used by the chaincode server to verify the -# connection from the peer node. -# Note that when this is set a single chaincode server cannot be shared -# across organizations unless their root CA is same. -# CHAINCODE_CLIENT_CA_CERT=/path/to/peer/organization/root/ca/cert/file diff --git a/asset-transfer-basic/chaincode-external/chaincode1.env b/asset-transfer-basic/chaincode-external/chaincode1.env deleted file mode 100644 index 26319adb..00000000 --- a/asset-transfer-basic/chaincode-external/chaincode1.env +++ /dev/null @@ -1,24 +0,0 @@ -# CHAINCODE_SERVER_ADDRESS must be set to the host and port where the peer can -# connect to the chaincode server -CHAINCODE_SERVER_ADDRESS=asset-transfer-basic.org1.example.com:9999 - -# CHAINCODE_ID must be set to the Package ID that is assigned to the chaincode -# on install. The `peer lifecycle chaincode queryinstalled` command can be -# used to get the ID after install if required -CHAINCODE_ID=basic_1.0:6726c6b6d8ff66fcf5710b72c6ce512d24f118c51c3de510b3d43e51fa592a7d - -# Optional parameters that will be used for TLS connection between peer node -# and the chaincode. -# TLS is disabled by default, uncomment the following line to enable TLS connection -CHAINCODE_TLS_DISABLED=false - -# Following variables will be ignored if TLS is not enabled. -# They need to be in PEM format -CHAINCODE_TLS_KEY=/crypto/key1.pem -CHAINCODE_TLS_CERT=/crypto/cert1.pem - -# The following variable will be used by the chaincode server to verify the -# connection from the peer node. -# Note that when this is set a single chaincode server cannot be shared -# across organizations unless their root CA is same. -CHAINCODE_CLIENT_CA_CERT=/crypto/rootcert1.pem diff --git a/asset-transfer-basic/chaincode-external/chaincode2.env b/asset-transfer-basic/chaincode-external/chaincode2.env deleted file mode 100644 index 7884f24a..00000000 --- a/asset-transfer-basic/chaincode-external/chaincode2.env +++ /dev/null @@ -1,24 +0,0 @@ -# CHAINCODE_SERVER_ADDRESS must be set to the host and port where the peer can -# connect to the chaincode server -CHAINCODE_SERVER_ADDRESS=asset-transfer-basic.org2.example.com:9999 - -# CHAINCODE_ID must be set to the Package ID that is assigned to the chaincode -# on install. The `peer lifecycle chaincode queryinstalled` command can be -# used to get the ID after install if required -CHAINCODE_ID=basic_1.0:e8f9052385e3763ecf5635591155da05d8efbb6905ccbfc1c7229eb6bd28df1b - -# Optional parameters that will be used for TLS connection between peer node -# and the chaincode. -# TLS is disabled by default, uncomment the following line to enable TLS connection -CHAINCODE_TLS_DISABLED=false - -# Following variables will be ignored if TLS is not enabled. -# They need to be in PEM format -CHAINCODE_TLS_KEY=/crypto/key2.pem -CHAINCODE_TLS_CERT=/crypto/cert2.pem - -# The following variable will be used by the chaincode server to verify the -# connection from the peer node. -# Note that when this is set a single chaincode server cannot be shared -# across organizations unless their root CA is same. -CHAINCODE_CLIENT_CA_CERT=/crypto/rootcert2.pem diff --git a/asset-transfer-basic/chaincode-external/connection.json b/asset-transfer-basic/chaincode-external/connection.json deleted file mode 100644 index d97f8f12..00000000 --- a/asset-transfer-basic/chaincode-external/connection.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "address": "asset-transfer-basic.org1.example.com:9999", - "dial_timeout": "10s", - "tls_required": false -} diff --git a/asset-transfer-basic/chaincode-external/crypto/.gitkeep b/asset-transfer-basic/chaincode-external/crypto/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/asset-transfer-basic/chaincode-external/docker-compose-chaincode.yaml b/asset-transfer-basic/chaincode-external/docker-compose-chaincode.yaml deleted file mode 100644 index f7aa6f29..00000000 --- a/asset-transfer-basic/chaincode-external/docker-compose-chaincode.yaml +++ /dev/null @@ -1,32 +0,0 @@ -version: "3.6" - -networks: - docker_test: - external: true - -services: - asset-transfer-basic.org1.example.com: - build: . - container_name: asset-transfer-basic.org1.example.com - hostname: asset-transfer-basic.org1.example.com - volumes: - - ./crypto:/crypto - env_file: - - chaincode1.env - networks: - docker_test: - expose: - - 9999 - - asset-transfer-basic.org2.example.com: - build: . - container_name: asset-transfer-basic.org2.example.com - hostname: asset-transfer-basic.org2.example.com - volumes: - - ./crypto:/crypto - env_file: - - chaincode2.env - networks: - docker_test: - expose: - - 9999 diff --git a/asset-transfer-basic/chaincode-external/go.mod b/asset-transfer-basic/chaincode-external/go.mod deleted file mode 100644 index b3bde4a4..00000000 --- a/asset-transfer-basic/chaincode-external/go.mod +++ /dev/null @@ -1,28 +0,0 @@ -module github.com/hyperledger/fabric-samples/asset-transfer-basic/chaincode-external - -go 1.22.0 - -require ( - github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0 - github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0 -) - -require ( - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xeipuuv/gojsonschema v1.2.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect - google.golang.org/grpc v1.67.0 // indirect - google.golang.org/protobuf v1.36.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/asset-transfer-basic/chaincode-external/go.sum b/asset-transfer-basic/chaincode-external/go.sum deleted file mode 100644 index fa4d3b24..00000000 --- a/asset-transfer-basic/chaincode-external/go.sum +++ /dev/null @@ -1,61 +0,0 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0 h1:IhkHfrl5X/fVnmB6pWeCYCdIJRi9bxj+WTnVN8DtW3c= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0/go.mod h1:PHHaFffjw7p7n9bmCfcm7RqDqYdivNEsJdiNIKZo5Lk= -github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0 h1:rmUoBmciB0GL/miqcbJmJbgp5QTWoJUrZo+CNxrNLF4= -github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0/go.mod h1:FeWeO/jwGjiME7ak3GufqKIcwkejtzrDG4QxbfKydWs= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 h1:YJrd+gMaeY0/vsN0aS0QkEKTivGoUnSRIXxGJ7KI+Pc= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4/go.mod h1:bau/6AJhvEcu9GKKYHlDXAxXKzYNfhP6xu2GXuxEcFk= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= -google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= -google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/asset-transfer-basic/chaincode-external/metadata.json b/asset-transfer-basic/chaincode-external/metadata.json deleted file mode 100644 index ae238606..00000000 --- a/asset-transfer-basic/chaincode-external/metadata.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "external", - "label": "basic_1.0" -} diff --git a/asset-transfer-basic/chaincode-external/sampleBuilder/bin/build b/asset-transfer-basic/chaincode-external/sampleBuilder/bin/build deleted file mode 100755 index 57e90f35..00000000 --- a/asset-transfer-basic/chaincode-external/sampleBuilder/bin/build +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -SOURCE=$1 -OUTPUT=$3 - -#external chaincodes expect connection.json file in the chaincode package -if [ ! -f "$SOURCE/connection.json" ]; then - >&2 echo "$SOURCE/connection.json not found" - exit 1 -fi - -#simply copy the endpoint information to specified output location -cp $SOURCE/connection.json $OUTPUT/connection.json - -if [ -d "$SOURCE/metadata" ]; then - cp -a $SOURCE/metadata $OUTPUT/metadata -fi - -exit 0 diff --git a/asset-transfer-basic/chaincode-external/sampleBuilder/bin/detect b/asset-transfer-basic/chaincode-external/sampleBuilder/bin/detect deleted file mode 100755 index d6ed2edc..00000000 --- a/asset-transfer-basic/chaincode-external/sampleBuilder/bin/detect +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -METADIR=$2 -# check if the "type" field is set to "external" -# crude way without jq which is not in the default fabric peer image -TYPE=$(tr -d '\n' < "$METADIR/metadata.json" | awk -F':' '{ for (i = 1; i < NF; i++){ if ($i~/type/) { print $(i+1); break }}}'| cut -d\" -f2) - -if [ "$TYPE" = "external" ]; then - exit 0 -fi - -exit 1 diff --git a/asset-transfer-basic/chaincode-external/sampleBuilder/bin/release b/asset-transfer-basic/chaincode-external/sampleBuilder/bin/release deleted file mode 100755 index cd3cd1b5..00000000 --- a/asset-transfer-basic/chaincode-external/sampleBuilder/bin/release +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -BLD="$1" -RELEASE="$2" - -if [ -d "$BLD/metadata" ]; then - cp -a "$BLD/metadata/"* "$RELEASE/" -fi - -#external chaincodes expect artifacts to be placed under "$RELEASE"/chaincode/server -if [ -f $BLD/connection.json ]; then - mkdir -p "$RELEASE"/chaincode/server - cp $BLD/connection.json "$RELEASE"/chaincode/server - - #if tls_required is true, copy TLS files (using above example, the fully qualified path for these fils would be "$RELEASE"/chaincode/server/tls) - - exit 0 -fi - -exit 1 diff --git a/asset-transfer-basic/chaincode-go/assetTransfer.go b/asset-transfer-basic/chaincode-go/assetTransfer.go deleted file mode 100644 index f86fcac1..00000000 --- a/asset-transfer-basic/chaincode-go/assetTransfer.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "log" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" - "github.com/hyperledger/fabric-samples/asset-transfer-basic/chaincode-go/chaincode" -) - -func main() { - assetChaincode, err := contractapi.NewChaincode(&chaincode.SmartContract{}) - if err != nil { - log.Panicf("Error creating asset-transfer-basic chaincode: %v", err) - } - - if err := assetChaincode.Start(); err != nil { - log.Panicf("Error starting asset-transfer-basic chaincode: %v", err) - } -} diff --git a/asset-transfer-basic/chaincode-go/chaincode/mocks/chaincodestub.go b/asset-transfer-basic/chaincode-go/chaincode/mocks/chaincodestub.go deleted file mode 100644 index 06248e33..00000000 --- a/asset-transfer-basic/chaincode-go/chaincode/mocks/chaincodestub.go +++ /dev/null @@ -1,2991 +0,0 @@ -// Code generated by counterfeiter. DO NOT EDIT. -package mocks - -import ( - "sync" - - "github.com/hyperledger/fabric-chaincode-go/v2/shim" - "github.com/hyperledger/fabric-protos-go-apiv2/peer" - "google.golang.org/protobuf/types/known/timestamppb" -) - -type ChaincodeStub struct { - CreateCompositeKeyStub func(string, []string) (string, error) - createCompositeKeyMutex sync.RWMutex - createCompositeKeyArgsForCall []struct { - arg1 string - arg2 []string - } - createCompositeKeyReturns struct { - result1 string - result2 error - } - createCompositeKeyReturnsOnCall map[int]struct { - result1 string - result2 error - } - DelPrivateDataStub func(string, string) error - delPrivateDataMutex sync.RWMutex - delPrivateDataArgsForCall []struct { - arg1 string - arg2 string - } - delPrivateDataReturns struct { - result1 error - } - delPrivateDataReturnsOnCall map[int]struct { - result1 error - } - DelStateStub func(string) error - delStateMutex sync.RWMutex - delStateArgsForCall []struct { - arg1 string - } - delStateReturns struct { - result1 error - } - delStateReturnsOnCall map[int]struct { - result1 error - } - GetArgsStub func() [][]byte - getArgsMutex sync.RWMutex - getArgsArgsForCall []struct { - } - getArgsReturns struct { - result1 [][]byte - } - getArgsReturnsOnCall map[int]struct { - result1 [][]byte - } - GetArgsSliceStub func() ([]byte, error) - getArgsSliceMutex sync.RWMutex - getArgsSliceArgsForCall []struct { - } - getArgsSliceReturns struct { - result1 []byte - result2 error - } - getArgsSliceReturnsOnCall map[int]struct { - result1 []byte - result2 error - } - GetBindingStub func() ([]byte, error) - getBindingMutex sync.RWMutex - getBindingArgsForCall []struct { - } - getBindingReturns struct { - result1 []byte - result2 error - } - getBindingReturnsOnCall map[int]struct { - result1 []byte - result2 error - } - GetChannelIDStub func() string - getChannelIDMutex sync.RWMutex - getChannelIDArgsForCall []struct { - } - getChannelIDReturns struct { - result1 string - } - getChannelIDReturnsOnCall map[int]struct { - result1 string - } - GetCreatorStub func() ([]byte, error) - getCreatorMutex sync.RWMutex - getCreatorArgsForCall []struct { - } - getCreatorReturns struct { - result1 []byte - result2 error - } - getCreatorReturnsOnCall map[int]struct { - result1 []byte - result2 error - } - GetDecorationsStub func() map[string][]byte - getDecorationsMutex sync.RWMutex - getDecorationsArgsForCall []struct { - } - getDecorationsReturns struct { - result1 map[string][]byte - } - getDecorationsReturnsOnCall map[int]struct { - result1 map[string][]byte - } - GetFunctionAndParametersStub func() (string, []string) - getFunctionAndParametersMutex sync.RWMutex - getFunctionAndParametersArgsForCall []struct { - } - getFunctionAndParametersReturns struct { - result1 string - result2 []string - } - getFunctionAndParametersReturnsOnCall map[int]struct { - result1 string - result2 []string - } - GetHistoryForKeyStub func(string) (shim.HistoryQueryIteratorInterface, error) - getHistoryForKeyMutex sync.RWMutex - getHistoryForKeyArgsForCall []struct { - arg1 string - } - getHistoryForKeyReturns struct { - result1 shim.HistoryQueryIteratorInterface - result2 error - } - getHistoryForKeyReturnsOnCall map[int]struct { - result1 shim.HistoryQueryIteratorInterface - result2 error - } - GetPrivateDataStub func(string, string) ([]byte, error) - getPrivateDataMutex sync.RWMutex - getPrivateDataArgsForCall []struct { - arg1 string - arg2 string - } - getPrivateDataReturns struct { - result1 []byte - result2 error - } - getPrivateDataReturnsOnCall map[int]struct { - result1 []byte - result2 error - } - GetPrivateDataByPartialCompositeKeyStub func(string, string, []string) (shim.StateQueryIteratorInterface, error) - getPrivateDataByPartialCompositeKeyMutex sync.RWMutex - getPrivateDataByPartialCompositeKeyArgsForCall []struct { - arg1 string - arg2 string - arg3 []string - } - getPrivateDataByPartialCompositeKeyReturns struct { - result1 shim.StateQueryIteratorInterface - result2 error - } - getPrivateDataByPartialCompositeKeyReturnsOnCall map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 error - } - GetPrivateDataByRangeStub func(string, string, string) (shim.StateQueryIteratorInterface, error) - getPrivateDataByRangeMutex sync.RWMutex - getPrivateDataByRangeArgsForCall []struct { - arg1 string - arg2 string - arg3 string - } - getPrivateDataByRangeReturns struct { - result1 shim.StateQueryIteratorInterface - result2 error - } - getPrivateDataByRangeReturnsOnCall map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 error - } - GetPrivateDataHashStub func(string, string) ([]byte, error) - getPrivateDataHashMutex sync.RWMutex - getPrivateDataHashArgsForCall []struct { - arg1 string - arg2 string - } - getPrivateDataHashReturns struct { - result1 []byte - result2 error - } - getPrivateDataHashReturnsOnCall map[int]struct { - result1 []byte - result2 error - } - GetPrivateDataQueryResultStub func(string, string) (shim.StateQueryIteratorInterface, error) - getPrivateDataQueryResultMutex sync.RWMutex - getPrivateDataQueryResultArgsForCall []struct { - arg1 string - arg2 string - } - getPrivateDataQueryResultReturns struct { - result1 shim.StateQueryIteratorInterface - result2 error - } - getPrivateDataQueryResultReturnsOnCall map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 error - } - GetPrivateDataValidationParameterStub func(string, string) ([]byte, error) - getPrivateDataValidationParameterMutex sync.RWMutex - getPrivateDataValidationParameterArgsForCall []struct { - arg1 string - arg2 string - } - getPrivateDataValidationParameterReturns struct { - result1 []byte - result2 error - } - getPrivateDataValidationParameterReturnsOnCall map[int]struct { - result1 []byte - result2 error - } - GetQueryResultStub func(string) (shim.StateQueryIteratorInterface, error) - getQueryResultMutex sync.RWMutex - getQueryResultArgsForCall []struct { - arg1 string - } - getQueryResultReturns struct { - result1 shim.StateQueryIteratorInterface - result2 error - } - getQueryResultReturnsOnCall map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 error - } - GetQueryResultWithPaginationStub func(string, int32, string) (shim.StateQueryIteratorInterface, *peer.QueryResponseMetadata, error) - getQueryResultWithPaginationMutex sync.RWMutex - getQueryResultWithPaginationArgsForCall []struct { - arg1 string - arg2 int32 - arg3 string - } - getQueryResultWithPaginationReturns struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - } - getQueryResultWithPaginationReturnsOnCall map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - } - GetSignedProposalStub func() (*peer.SignedProposal, error) - getSignedProposalMutex sync.RWMutex - getSignedProposalArgsForCall []struct { - } - getSignedProposalReturns struct { - result1 *peer.SignedProposal - result2 error - } - getSignedProposalReturnsOnCall map[int]struct { - result1 *peer.SignedProposal - result2 error - } - GetStateStub func(string) ([]byte, error) - getStateMutex sync.RWMutex - getStateArgsForCall []struct { - arg1 string - } - getStateReturns struct { - result1 []byte - result2 error - } - getStateReturnsOnCall map[int]struct { - result1 []byte - result2 error - } - GetStateByPartialCompositeKeyStub func(string, []string) (shim.StateQueryIteratorInterface, error) - getStateByPartialCompositeKeyMutex sync.RWMutex - getStateByPartialCompositeKeyArgsForCall []struct { - arg1 string - arg2 []string - } - getStateByPartialCompositeKeyReturns struct { - result1 shim.StateQueryIteratorInterface - result2 error - } - getStateByPartialCompositeKeyReturnsOnCall map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 error - } - GetStateByPartialCompositeKeyWithPaginationStub func(string, []string, int32, string) (shim.StateQueryIteratorInterface, *peer.QueryResponseMetadata, error) - getStateByPartialCompositeKeyWithPaginationMutex sync.RWMutex - getStateByPartialCompositeKeyWithPaginationArgsForCall []struct { - arg1 string - arg2 []string - arg3 int32 - arg4 string - } - getStateByPartialCompositeKeyWithPaginationReturns struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - } - getStateByPartialCompositeKeyWithPaginationReturnsOnCall map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - } - GetStateByRangeStub func(string, string) (shim.StateQueryIteratorInterface, error) - getStateByRangeMutex sync.RWMutex - getStateByRangeArgsForCall []struct { - arg1 string - arg2 string - } - getStateByRangeReturns struct { - result1 shim.StateQueryIteratorInterface - result2 error - } - getStateByRangeReturnsOnCall map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 error - } - GetStateByRangeWithPaginationStub func(string, string, int32, string) (shim.StateQueryIteratorInterface, *peer.QueryResponseMetadata, error) - getStateByRangeWithPaginationMutex sync.RWMutex - getStateByRangeWithPaginationArgsForCall []struct { - arg1 string - arg2 string - arg3 int32 - arg4 string - } - getStateByRangeWithPaginationReturns struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - } - getStateByRangeWithPaginationReturnsOnCall map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - } - GetStateValidationParameterStub func(string) ([]byte, error) - getStateValidationParameterMutex sync.RWMutex - getStateValidationParameterArgsForCall []struct { - arg1 string - } - getStateValidationParameterReturns struct { - result1 []byte - result2 error - } - getStateValidationParameterReturnsOnCall map[int]struct { - result1 []byte - result2 error - } - GetStringArgsStub func() []string - getStringArgsMutex sync.RWMutex - getStringArgsArgsForCall []struct { - } - getStringArgsReturns struct { - result1 []string - } - getStringArgsReturnsOnCall map[int]struct { - result1 []string - } - GetTransientStub func() (map[string][]byte, error) - getTransientMutex sync.RWMutex - getTransientArgsForCall []struct { - } - getTransientReturns struct { - result1 map[string][]byte - result2 error - } - getTransientReturnsOnCall map[int]struct { - result1 map[string][]byte - result2 error - } - GetTxIDStub func() string - getTxIDMutex sync.RWMutex - getTxIDArgsForCall []struct { - } - getTxIDReturns struct { - result1 string - } - getTxIDReturnsOnCall map[int]struct { - result1 string - } - GetTxTimestampStub func() (*timestamppb.Timestamp, error) - getTxTimestampMutex sync.RWMutex - getTxTimestampArgsForCall []struct { - } - getTxTimestampReturns struct { - result1 *timestamppb.Timestamp - result2 error - } - getTxTimestampReturnsOnCall map[int]struct { - result1 *timestamppb.Timestamp - result2 error - } - InvokeChaincodeStub func(string, [][]byte, string) *peer.Response - invokeChaincodeMutex sync.RWMutex - invokeChaincodeArgsForCall []struct { - arg1 string - arg2 [][]byte - arg3 string - } - invokeChaincodeReturns struct { - result1 *peer.Response - } - invokeChaincodeReturnsOnCall map[int]struct { - result1 *peer.Response - } - PurgePrivateDataStub func(string, string) error - purgePrivateDataMutex sync.RWMutex - purgePrivateDataArgsForCall []struct { - arg1 string - arg2 string - } - purgePrivateDataReturns struct { - result1 error - } - purgePrivateDataReturnsOnCall map[int]struct { - result1 error - } - PutPrivateDataStub func(string, string, []byte) error - putPrivateDataMutex sync.RWMutex - putPrivateDataArgsForCall []struct { - arg1 string - arg2 string - arg3 []byte - } - putPrivateDataReturns struct { - result1 error - } - putPrivateDataReturnsOnCall map[int]struct { - result1 error - } - PutStateStub func(string, []byte) error - putStateMutex sync.RWMutex - putStateArgsForCall []struct { - arg1 string - arg2 []byte - } - putStateReturns struct { - result1 error - } - putStateReturnsOnCall map[int]struct { - result1 error - } - SetEventStub func(string, []byte) error - setEventMutex sync.RWMutex - setEventArgsForCall []struct { - arg1 string - arg2 []byte - } - setEventReturns struct { - result1 error - } - setEventReturnsOnCall map[int]struct { - result1 error - } - SetPrivateDataValidationParameterStub func(string, string, []byte) error - setPrivateDataValidationParameterMutex sync.RWMutex - setPrivateDataValidationParameterArgsForCall []struct { - arg1 string - arg2 string - arg3 []byte - } - setPrivateDataValidationParameterReturns struct { - result1 error - } - setPrivateDataValidationParameterReturnsOnCall map[int]struct { - result1 error - } - SetStateValidationParameterStub func(string, []byte) error - setStateValidationParameterMutex sync.RWMutex - setStateValidationParameterArgsForCall []struct { - arg1 string - arg2 []byte - } - setStateValidationParameterReturns struct { - result1 error - } - setStateValidationParameterReturnsOnCall map[int]struct { - result1 error - } - SplitCompositeKeyStub func(string) (string, []string, error) - splitCompositeKeyMutex sync.RWMutex - splitCompositeKeyArgsForCall []struct { - arg1 string - } - splitCompositeKeyReturns struct { - result1 string - result2 []string - result3 error - } - splitCompositeKeyReturnsOnCall map[int]struct { - result1 string - result2 []string - result3 error - } - invocations map[string][][]interface{} - invocationsMutex sync.RWMutex -} - -func (fake *ChaincodeStub) CreateCompositeKey(arg1 string, arg2 []string) (string, error) { - var arg2Copy []string - if arg2 != nil { - arg2Copy = make([]string, len(arg2)) - copy(arg2Copy, arg2) - } - fake.createCompositeKeyMutex.Lock() - ret, specificReturn := fake.createCompositeKeyReturnsOnCall[len(fake.createCompositeKeyArgsForCall)] - fake.createCompositeKeyArgsForCall = append(fake.createCompositeKeyArgsForCall, struct { - arg1 string - arg2 []string - }{arg1, arg2Copy}) - stub := fake.CreateCompositeKeyStub - fakeReturns := fake.createCompositeKeyReturns - fake.recordInvocation("CreateCompositeKey", []interface{}{arg1, arg2Copy}) - fake.createCompositeKeyMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) CreateCompositeKeyCallCount() int { - fake.createCompositeKeyMutex.RLock() - defer fake.createCompositeKeyMutex.RUnlock() - return len(fake.createCompositeKeyArgsForCall) -} - -func (fake *ChaincodeStub) CreateCompositeKeyCalls(stub func(string, []string) (string, error)) { - fake.createCompositeKeyMutex.Lock() - defer fake.createCompositeKeyMutex.Unlock() - fake.CreateCompositeKeyStub = stub -} - -func (fake *ChaincodeStub) CreateCompositeKeyArgsForCall(i int) (string, []string) { - fake.createCompositeKeyMutex.RLock() - defer fake.createCompositeKeyMutex.RUnlock() - argsForCall := fake.createCompositeKeyArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ChaincodeStub) CreateCompositeKeyReturns(result1 string, result2 error) { - fake.createCompositeKeyMutex.Lock() - defer fake.createCompositeKeyMutex.Unlock() - fake.CreateCompositeKeyStub = nil - fake.createCompositeKeyReturns = struct { - result1 string - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) CreateCompositeKeyReturnsOnCall(i int, result1 string, result2 error) { - fake.createCompositeKeyMutex.Lock() - defer fake.createCompositeKeyMutex.Unlock() - fake.CreateCompositeKeyStub = nil - if fake.createCompositeKeyReturnsOnCall == nil { - fake.createCompositeKeyReturnsOnCall = make(map[int]struct { - result1 string - result2 error - }) - } - fake.createCompositeKeyReturnsOnCall[i] = struct { - result1 string - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) DelPrivateData(arg1 string, arg2 string) error { - fake.delPrivateDataMutex.Lock() - ret, specificReturn := fake.delPrivateDataReturnsOnCall[len(fake.delPrivateDataArgsForCall)] - fake.delPrivateDataArgsForCall = append(fake.delPrivateDataArgsForCall, struct { - arg1 string - arg2 string - }{arg1, arg2}) - stub := fake.DelPrivateDataStub - fakeReturns := fake.delPrivateDataReturns - fake.recordInvocation("DelPrivateData", []interface{}{arg1, arg2}) - fake.delPrivateDataMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) DelPrivateDataCallCount() int { - fake.delPrivateDataMutex.RLock() - defer fake.delPrivateDataMutex.RUnlock() - return len(fake.delPrivateDataArgsForCall) -} - -func (fake *ChaincodeStub) DelPrivateDataCalls(stub func(string, string) error) { - fake.delPrivateDataMutex.Lock() - defer fake.delPrivateDataMutex.Unlock() - fake.DelPrivateDataStub = stub -} - -func (fake *ChaincodeStub) DelPrivateDataArgsForCall(i int) (string, string) { - fake.delPrivateDataMutex.RLock() - defer fake.delPrivateDataMutex.RUnlock() - argsForCall := fake.delPrivateDataArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ChaincodeStub) DelPrivateDataReturns(result1 error) { - fake.delPrivateDataMutex.Lock() - defer fake.delPrivateDataMutex.Unlock() - fake.DelPrivateDataStub = nil - fake.delPrivateDataReturns = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) DelPrivateDataReturnsOnCall(i int, result1 error) { - fake.delPrivateDataMutex.Lock() - defer fake.delPrivateDataMutex.Unlock() - fake.DelPrivateDataStub = nil - if fake.delPrivateDataReturnsOnCall == nil { - fake.delPrivateDataReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.delPrivateDataReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) DelState(arg1 string) error { - fake.delStateMutex.Lock() - ret, specificReturn := fake.delStateReturnsOnCall[len(fake.delStateArgsForCall)] - fake.delStateArgsForCall = append(fake.delStateArgsForCall, struct { - arg1 string - }{arg1}) - stub := fake.DelStateStub - fakeReturns := fake.delStateReturns - fake.recordInvocation("DelState", []interface{}{arg1}) - fake.delStateMutex.Unlock() - if stub != nil { - return stub(arg1) - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) DelStateCallCount() int { - fake.delStateMutex.RLock() - defer fake.delStateMutex.RUnlock() - return len(fake.delStateArgsForCall) -} - -func (fake *ChaincodeStub) DelStateCalls(stub func(string) error) { - fake.delStateMutex.Lock() - defer fake.delStateMutex.Unlock() - fake.DelStateStub = stub -} - -func (fake *ChaincodeStub) DelStateArgsForCall(i int) string { - fake.delStateMutex.RLock() - defer fake.delStateMutex.RUnlock() - argsForCall := fake.delStateArgsForCall[i] - return argsForCall.arg1 -} - -func (fake *ChaincodeStub) DelStateReturns(result1 error) { - fake.delStateMutex.Lock() - defer fake.delStateMutex.Unlock() - fake.DelStateStub = nil - fake.delStateReturns = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) DelStateReturnsOnCall(i int, result1 error) { - fake.delStateMutex.Lock() - defer fake.delStateMutex.Unlock() - fake.DelStateStub = nil - if fake.delStateReturnsOnCall == nil { - fake.delStateReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.delStateReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) GetArgs() [][]byte { - fake.getArgsMutex.Lock() - ret, specificReturn := fake.getArgsReturnsOnCall[len(fake.getArgsArgsForCall)] - fake.getArgsArgsForCall = append(fake.getArgsArgsForCall, struct { - }{}) - stub := fake.GetArgsStub - fakeReturns := fake.getArgsReturns - fake.recordInvocation("GetArgs", []interface{}{}) - fake.getArgsMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) GetArgsCallCount() int { - fake.getArgsMutex.RLock() - defer fake.getArgsMutex.RUnlock() - return len(fake.getArgsArgsForCall) -} - -func (fake *ChaincodeStub) GetArgsCalls(stub func() [][]byte) { - fake.getArgsMutex.Lock() - defer fake.getArgsMutex.Unlock() - fake.GetArgsStub = stub -} - -func (fake *ChaincodeStub) GetArgsReturns(result1 [][]byte) { - fake.getArgsMutex.Lock() - defer fake.getArgsMutex.Unlock() - fake.GetArgsStub = nil - fake.getArgsReturns = struct { - result1 [][]byte - }{result1} -} - -func (fake *ChaincodeStub) GetArgsReturnsOnCall(i int, result1 [][]byte) { - fake.getArgsMutex.Lock() - defer fake.getArgsMutex.Unlock() - fake.GetArgsStub = nil - if fake.getArgsReturnsOnCall == nil { - fake.getArgsReturnsOnCall = make(map[int]struct { - result1 [][]byte - }) - } - fake.getArgsReturnsOnCall[i] = struct { - result1 [][]byte - }{result1} -} - -func (fake *ChaincodeStub) GetArgsSlice() ([]byte, error) { - fake.getArgsSliceMutex.Lock() - ret, specificReturn := fake.getArgsSliceReturnsOnCall[len(fake.getArgsSliceArgsForCall)] - fake.getArgsSliceArgsForCall = append(fake.getArgsSliceArgsForCall, struct { - }{}) - stub := fake.GetArgsSliceStub - fakeReturns := fake.getArgsSliceReturns - fake.recordInvocation("GetArgsSlice", []interface{}{}) - fake.getArgsSliceMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetArgsSliceCallCount() int { - fake.getArgsSliceMutex.RLock() - defer fake.getArgsSliceMutex.RUnlock() - return len(fake.getArgsSliceArgsForCall) -} - -func (fake *ChaincodeStub) GetArgsSliceCalls(stub func() ([]byte, error)) { - fake.getArgsSliceMutex.Lock() - defer fake.getArgsSliceMutex.Unlock() - fake.GetArgsSliceStub = stub -} - -func (fake *ChaincodeStub) GetArgsSliceReturns(result1 []byte, result2 error) { - fake.getArgsSliceMutex.Lock() - defer fake.getArgsSliceMutex.Unlock() - fake.GetArgsSliceStub = nil - fake.getArgsSliceReturns = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetArgsSliceReturnsOnCall(i int, result1 []byte, result2 error) { - fake.getArgsSliceMutex.Lock() - defer fake.getArgsSliceMutex.Unlock() - fake.GetArgsSliceStub = nil - if fake.getArgsSliceReturnsOnCall == nil { - fake.getArgsSliceReturnsOnCall = make(map[int]struct { - result1 []byte - result2 error - }) - } - fake.getArgsSliceReturnsOnCall[i] = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetBinding() ([]byte, error) { - fake.getBindingMutex.Lock() - ret, specificReturn := fake.getBindingReturnsOnCall[len(fake.getBindingArgsForCall)] - fake.getBindingArgsForCall = append(fake.getBindingArgsForCall, struct { - }{}) - stub := fake.GetBindingStub - fakeReturns := fake.getBindingReturns - fake.recordInvocation("GetBinding", []interface{}{}) - fake.getBindingMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetBindingCallCount() int { - fake.getBindingMutex.RLock() - defer fake.getBindingMutex.RUnlock() - return len(fake.getBindingArgsForCall) -} - -func (fake *ChaincodeStub) GetBindingCalls(stub func() ([]byte, error)) { - fake.getBindingMutex.Lock() - defer fake.getBindingMutex.Unlock() - fake.GetBindingStub = stub -} - -func (fake *ChaincodeStub) GetBindingReturns(result1 []byte, result2 error) { - fake.getBindingMutex.Lock() - defer fake.getBindingMutex.Unlock() - fake.GetBindingStub = nil - fake.getBindingReturns = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetBindingReturnsOnCall(i int, result1 []byte, result2 error) { - fake.getBindingMutex.Lock() - defer fake.getBindingMutex.Unlock() - fake.GetBindingStub = nil - if fake.getBindingReturnsOnCall == nil { - fake.getBindingReturnsOnCall = make(map[int]struct { - result1 []byte - result2 error - }) - } - fake.getBindingReturnsOnCall[i] = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetChannelID() string { - fake.getChannelIDMutex.Lock() - ret, specificReturn := fake.getChannelIDReturnsOnCall[len(fake.getChannelIDArgsForCall)] - fake.getChannelIDArgsForCall = append(fake.getChannelIDArgsForCall, struct { - }{}) - stub := fake.GetChannelIDStub - fakeReturns := fake.getChannelIDReturns - fake.recordInvocation("GetChannelID", []interface{}{}) - fake.getChannelIDMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) GetChannelIDCallCount() int { - fake.getChannelIDMutex.RLock() - defer fake.getChannelIDMutex.RUnlock() - return len(fake.getChannelIDArgsForCall) -} - -func (fake *ChaincodeStub) GetChannelIDCalls(stub func() string) { - fake.getChannelIDMutex.Lock() - defer fake.getChannelIDMutex.Unlock() - fake.GetChannelIDStub = stub -} - -func (fake *ChaincodeStub) GetChannelIDReturns(result1 string) { - fake.getChannelIDMutex.Lock() - defer fake.getChannelIDMutex.Unlock() - fake.GetChannelIDStub = nil - fake.getChannelIDReturns = struct { - result1 string - }{result1} -} - -func (fake *ChaincodeStub) GetChannelIDReturnsOnCall(i int, result1 string) { - fake.getChannelIDMutex.Lock() - defer fake.getChannelIDMutex.Unlock() - fake.GetChannelIDStub = nil - if fake.getChannelIDReturnsOnCall == nil { - fake.getChannelIDReturnsOnCall = make(map[int]struct { - result1 string - }) - } - fake.getChannelIDReturnsOnCall[i] = struct { - result1 string - }{result1} -} - -func (fake *ChaincodeStub) GetCreator() ([]byte, error) { - fake.getCreatorMutex.Lock() - ret, specificReturn := fake.getCreatorReturnsOnCall[len(fake.getCreatorArgsForCall)] - fake.getCreatorArgsForCall = append(fake.getCreatorArgsForCall, struct { - }{}) - stub := fake.GetCreatorStub - fakeReturns := fake.getCreatorReturns - fake.recordInvocation("GetCreator", []interface{}{}) - fake.getCreatorMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetCreatorCallCount() int { - fake.getCreatorMutex.RLock() - defer fake.getCreatorMutex.RUnlock() - return len(fake.getCreatorArgsForCall) -} - -func (fake *ChaincodeStub) GetCreatorCalls(stub func() ([]byte, error)) { - fake.getCreatorMutex.Lock() - defer fake.getCreatorMutex.Unlock() - fake.GetCreatorStub = stub -} - -func (fake *ChaincodeStub) GetCreatorReturns(result1 []byte, result2 error) { - fake.getCreatorMutex.Lock() - defer fake.getCreatorMutex.Unlock() - fake.GetCreatorStub = nil - fake.getCreatorReturns = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetCreatorReturnsOnCall(i int, result1 []byte, result2 error) { - fake.getCreatorMutex.Lock() - defer fake.getCreatorMutex.Unlock() - fake.GetCreatorStub = nil - if fake.getCreatorReturnsOnCall == nil { - fake.getCreatorReturnsOnCall = make(map[int]struct { - result1 []byte - result2 error - }) - } - fake.getCreatorReturnsOnCall[i] = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetDecorations() map[string][]byte { - fake.getDecorationsMutex.Lock() - ret, specificReturn := fake.getDecorationsReturnsOnCall[len(fake.getDecorationsArgsForCall)] - fake.getDecorationsArgsForCall = append(fake.getDecorationsArgsForCall, struct { - }{}) - stub := fake.GetDecorationsStub - fakeReturns := fake.getDecorationsReturns - fake.recordInvocation("GetDecorations", []interface{}{}) - fake.getDecorationsMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) GetDecorationsCallCount() int { - fake.getDecorationsMutex.RLock() - defer fake.getDecorationsMutex.RUnlock() - return len(fake.getDecorationsArgsForCall) -} - -func (fake *ChaincodeStub) GetDecorationsCalls(stub func() map[string][]byte) { - fake.getDecorationsMutex.Lock() - defer fake.getDecorationsMutex.Unlock() - fake.GetDecorationsStub = stub -} - -func (fake *ChaincodeStub) GetDecorationsReturns(result1 map[string][]byte) { - fake.getDecorationsMutex.Lock() - defer fake.getDecorationsMutex.Unlock() - fake.GetDecorationsStub = nil - fake.getDecorationsReturns = struct { - result1 map[string][]byte - }{result1} -} - -func (fake *ChaincodeStub) GetDecorationsReturnsOnCall(i int, result1 map[string][]byte) { - fake.getDecorationsMutex.Lock() - defer fake.getDecorationsMutex.Unlock() - fake.GetDecorationsStub = nil - if fake.getDecorationsReturnsOnCall == nil { - fake.getDecorationsReturnsOnCall = make(map[int]struct { - result1 map[string][]byte - }) - } - fake.getDecorationsReturnsOnCall[i] = struct { - result1 map[string][]byte - }{result1} -} - -func (fake *ChaincodeStub) GetFunctionAndParameters() (string, []string) { - fake.getFunctionAndParametersMutex.Lock() - ret, specificReturn := fake.getFunctionAndParametersReturnsOnCall[len(fake.getFunctionAndParametersArgsForCall)] - fake.getFunctionAndParametersArgsForCall = append(fake.getFunctionAndParametersArgsForCall, struct { - }{}) - stub := fake.GetFunctionAndParametersStub - fakeReturns := fake.getFunctionAndParametersReturns - fake.recordInvocation("GetFunctionAndParameters", []interface{}{}) - fake.getFunctionAndParametersMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetFunctionAndParametersCallCount() int { - fake.getFunctionAndParametersMutex.RLock() - defer fake.getFunctionAndParametersMutex.RUnlock() - return len(fake.getFunctionAndParametersArgsForCall) -} - -func (fake *ChaincodeStub) GetFunctionAndParametersCalls(stub func() (string, []string)) { - fake.getFunctionAndParametersMutex.Lock() - defer fake.getFunctionAndParametersMutex.Unlock() - fake.GetFunctionAndParametersStub = stub -} - -func (fake *ChaincodeStub) GetFunctionAndParametersReturns(result1 string, result2 []string) { - fake.getFunctionAndParametersMutex.Lock() - defer fake.getFunctionAndParametersMutex.Unlock() - fake.GetFunctionAndParametersStub = nil - fake.getFunctionAndParametersReturns = struct { - result1 string - result2 []string - }{result1, result2} -} - -func (fake *ChaincodeStub) GetFunctionAndParametersReturnsOnCall(i int, result1 string, result2 []string) { - fake.getFunctionAndParametersMutex.Lock() - defer fake.getFunctionAndParametersMutex.Unlock() - fake.GetFunctionAndParametersStub = nil - if fake.getFunctionAndParametersReturnsOnCall == nil { - fake.getFunctionAndParametersReturnsOnCall = make(map[int]struct { - result1 string - result2 []string - }) - } - fake.getFunctionAndParametersReturnsOnCall[i] = struct { - result1 string - result2 []string - }{result1, result2} -} - -func (fake *ChaincodeStub) GetHistoryForKey(arg1 string) (shim.HistoryQueryIteratorInterface, error) { - fake.getHistoryForKeyMutex.Lock() - ret, specificReturn := fake.getHistoryForKeyReturnsOnCall[len(fake.getHistoryForKeyArgsForCall)] - fake.getHistoryForKeyArgsForCall = append(fake.getHistoryForKeyArgsForCall, struct { - arg1 string - }{arg1}) - stub := fake.GetHistoryForKeyStub - fakeReturns := fake.getHistoryForKeyReturns - fake.recordInvocation("GetHistoryForKey", []interface{}{arg1}) - fake.getHistoryForKeyMutex.Unlock() - if stub != nil { - return stub(arg1) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetHistoryForKeyCallCount() int { - fake.getHistoryForKeyMutex.RLock() - defer fake.getHistoryForKeyMutex.RUnlock() - return len(fake.getHistoryForKeyArgsForCall) -} - -func (fake *ChaincodeStub) GetHistoryForKeyCalls(stub func(string) (shim.HistoryQueryIteratorInterface, error)) { - fake.getHistoryForKeyMutex.Lock() - defer fake.getHistoryForKeyMutex.Unlock() - fake.GetHistoryForKeyStub = stub -} - -func (fake *ChaincodeStub) GetHistoryForKeyArgsForCall(i int) string { - fake.getHistoryForKeyMutex.RLock() - defer fake.getHistoryForKeyMutex.RUnlock() - argsForCall := fake.getHistoryForKeyArgsForCall[i] - return argsForCall.arg1 -} - -func (fake *ChaincodeStub) GetHistoryForKeyReturns(result1 shim.HistoryQueryIteratorInterface, result2 error) { - fake.getHistoryForKeyMutex.Lock() - defer fake.getHistoryForKeyMutex.Unlock() - fake.GetHistoryForKeyStub = nil - fake.getHistoryForKeyReturns = struct { - result1 shim.HistoryQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetHistoryForKeyReturnsOnCall(i int, result1 shim.HistoryQueryIteratorInterface, result2 error) { - fake.getHistoryForKeyMutex.Lock() - defer fake.getHistoryForKeyMutex.Unlock() - fake.GetHistoryForKeyStub = nil - if fake.getHistoryForKeyReturnsOnCall == nil { - fake.getHistoryForKeyReturnsOnCall = make(map[int]struct { - result1 shim.HistoryQueryIteratorInterface - result2 error - }) - } - fake.getHistoryForKeyReturnsOnCall[i] = struct { - result1 shim.HistoryQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetPrivateData(arg1 string, arg2 string) ([]byte, error) { - fake.getPrivateDataMutex.Lock() - ret, specificReturn := fake.getPrivateDataReturnsOnCall[len(fake.getPrivateDataArgsForCall)] - fake.getPrivateDataArgsForCall = append(fake.getPrivateDataArgsForCall, struct { - arg1 string - arg2 string - }{arg1, arg2}) - stub := fake.GetPrivateDataStub - fakeReturns := fake.getPrivateDataReturns - fake.recordInvocation("GetPrivateData", []interface{}{arg1, arg2}) - fake.getPrivateDataMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetPrivateDataCallCount() int { - fake.getPrivateDataMutex.RLock() - defer fake.getPrivateDataMutex.RUnlock() - return len(fake.getPrivateDataArgsForCall) -} - -func (fake *ChaincodeStub) GetPrivateDataCalls(stub func(string, string) ([]byte, error)) { - fake.getPrivateDataMutex.Lock() - defer fake.getPrivateDataMutex.Unlock() - fake.GetPrivateDataStub = stub -} - -func (fake *ChaincodeStub) GetPrivateDataArgsForCall(i int) (string, string) { - fake.getPrivateDataMutex.RLock() - defer fake.getPrivateDataMutex.RUnlock() - argsForCall := fake.getPrivateDataArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ChaincodeStub) GetPrivateDataReturns(result1 []byte, result2 error) { - fake.getPrivateDataMutex.Lock() - defer fake.getPrivateDataMutex.Unlock() - fake.GetPrivateDataStub = nil - fake.getPrivateDataReturns = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetPrivateDataReturnsOnCall(i int, result1 []byte, result2 error) { - fake.getPrivateDataMutex.Lock() - defer fake.getPrivateDataMutex.Unlock() - fake.GetPrivateDataStub = nil - if fake.getPrivateDataReturnsOnCall == nil { - fake.getPrivateDataReturnsOnCall = make(map[int]struct { - result1 []byte - result2 error - }) - } - fake.getPrivateDataReturnsOnCall[i] = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetPrivateDataByPartialCompositeKey(arg1 string, arg2 string, arg3 []string) (shim.StateQueryIteratorInterface, error) { - var arg3Copy []string - if arg3 != nil { - arg3Copy = make([]string, len(arg3)) - copy(arg3Copy, arg3) - } - fake.getPrivateDataByPartialCompositeKeyMutex.Lock() - ret, specificReturn := fake.getPrivateDataByPartialCompositeKeyReturnsOnCall[len(fake.getPrivateDataByPartialCompositeKeyArgsForCall)] - fake.getPrivateDataByPartialCompositeKeyArgsForCall = append(fake.getPrivateDataByPartialCompositeKeyArgsForCall, struct { - arg1 string - arg2 string - arg3 []string - }{arg1, arg2, arg3Copy}) - stub := fake.GetPrivateDataByPartialCompositeKeyStub - fakeReturns := fake.getPrivateDataByPartialCompositeKeyReturns - fake.recordInvocation("GetPrivateDataByPartialCompositeKey", []interface{}{arg1, arg2, arg3Copy}) - fake.getPrivateDataByPartialCompositeKeyMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetPrivateDataByPartialCompositeKeyCallCount() int { - fake.getPrivateDataByPartialCompositeKeyMutex.RLock() - defer fake.getPrivateDataByPartialCompositeKeyMutex.RUnlock() - return len(fake.getPrivateDataByPartialCompositeKeyArgsForCall) -} - -func (fake *ChaincodeStub) GetPrivateDataByPartialCompositeKeyCalls(stub func(string, string, []string) (shim.StateQueryIteratorInterface, error)) { - fake.getPrivateDataByPartialCompositeKeyMutex.Lock() - defer fake.getPrivateDataByPartialCompositeKeyMutex.Unlock() - fake.GetPrivateDataByPartialCompositeKeyStub = stub -} - -func (fake *ChaincodeStub) GetPrivateDataByPartialCompositeKeyArgsForCall(i int) (string, string, []string) { - fake.getPrivateDataByPartialCompositeKeyMutex.RLock() - defer fake.getPrivateDataByPartialCompositeKeyMutex.RUnlock() - argsForCall := fake.getPrivateDataByPartialCompositeKeyArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 -} - -func (fake *ChaincodeStub) GetPrivateDataByPartialCompositeKeyReturns(result1 shim.StateQueryIteratorInterface, result2 error) { - fake.getPrivateDataByPartialCompositeKeyMutex.Lock() - defer fake.getPrivateDataByPartialCompositeKeyMutex.Unlock() - fake.GetPrivateDataByPartialCompositeKeyStub = nil - fake.getPrivateDataByPartialCompositeKeyReturns = struct { - result1 shim.StateQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetPrivateDataByPartialCompositeKeyReturnsOnCall(i int, result1 shim.StateQueryIteratorInterface, result2 error) { - fake.getPrivateDataByPartialCompositeKeyMutex.Lock() - defer fake.getPrivateDataByPartialCompositeKeyMutex.Unlock() - fake.GetPrivateDataByPartialCompositeKeyStub = nil - if fake.getPrivateDataByPartialCompositeKeyReturnsOnCall == nil { - fake.getPrivateDataByPartialCompositeKeyReturnsOnCall = make(map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 error - }) - } - fake.getPrivateDataByPartialCompositeKeyReturnsOnCall[i] = struct { - result1 shim.StateQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetPrivateDataByRange(arg1 string, arg2 string, arg3 string) (shim.StateQueryIteratorInterface, error) { - fake.getPrivateDataByRangeMutex.Lock() - ret, specificReturn := fake.getPrivateDataByRangeReturnsOnCall[len(fake.getPrivateDataByRangeArgsForCall)] - fake.getPrivateDataByRangeArgsForCall = append(fake.getPrivateDataByRangeArgsForCall, struct { - arg1 string - arg2 string - arg3 string - }{arg1, arg2, arg3}) - stub := fake.GetPrivateDataByRangeStub - fakeReturns := fake.getPrivateDataByRangeReturns - fake.recordInvocation("GetPrivateDataByRange", []interface{}{arg1, arg2, arg3}) - fake.getPrivateDataByRangeMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetPrivateDataByRangeCallCount() int { - fake.getPrivateDataByRangeMutex.RLock() - defer fake.getPrivateDataByRangeMutex.RUnlock() - return len(fake.getPrivateDataByRangeArgsForCall) -} - -func (fake *ChaincodeStub) GetPrivateDataByRangeCalls(stub func(string, string, string) (shim.StateQueryIteratorInterface, error)) { - fake.getPrivateDataByRangeMutex.Lock() - defer fake.getPrivateDataByRangeMutex.Unlock() - fake.GetPrivateDataByRangeStub = stub -} - -func (fake *ChaincodeStub) GetPrivateDataByRangeArgsForCall(i int) (string, string, string) { - fake.getPrivateDataByRangeMutex.RLock() - defer fake.getPrivateDataByRangeMutex.RUnlock() - argsForCall := fake.getPrivateDataByRangeArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 -} - -func (fake *ChaincodeStub) GetPrivateDataByRangeReturns(result1 shim.StateQueryIteratorInterface, result2 error) { - fake.getPrivateDataByRangeMutex.Lock() - defer fake.getPrivateDataByRangeMutex.Unlock() - fake.GetPrivateDataByRangeStub = nil - fake.getPrivateDataByRangeReturns = struct { - result1 shim.StateQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetPrivateDataByRangeReturnsOnCall(i int, result1 shim.StateQueryIteratorInterface, result2 error) { - fake.getPrivateDataByRangeMutex.Lock() - defer fake.getPrivateDataByRangeMutex.Unlock() - fake.GetPrivateDataByRangeStub = nil - if fake.getPrivateDataByRangeReturnsOnCall == nil { - fake.getPrivateDataByRangeReturnsOnCall = make(map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 error - }) - } - fake.getPrivateDataByRangeReturnsOnCall[i] = struct { - result1 shim.StateQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetPrivateDataHash(arg1 string, arg2 string) ([]byte, error) { - fake.getPrivateDataHashMutex.Lock() - ret, specificReturn := fake.getPrivateDataHashReturnsOnCall[len(fake.getPrivateDataHashArgsForCall)] - fake.getPrivateDataHashArgsForCall = append(fake.getPrivateDataHashArgsForCall, struct { - arg1 string - arg2 string - }{arg1, arg2}) - stub := fake.GetPrivateDataHashStub - fakeReturns := fake.getPrivateDataHashReturns - fake.recordInvocation("GetPrivateDataHash", []interface{}{arg1, arg2}) - fake.getPrivateDataHashMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetPrivateDataHashCallCount() int { - fake.getPrivateDataHashMutex.RLock() - defer fake.getPrivateDataHashMutex.RUnlock() - return len(fake.getPrivateDataHashArgsForCall) -} - -func (fake *ChaincodeStub) GetPrivateDataHashCalls(stub func(string, string) ([]byte, error)) { - fake.getPrivateDataHashMutex.Lock() - defer fake.getPrivateDataHashMutex.Unlock() - fake.GetPrivateDataHashStub = stub -} - -func (fake *ChaincodeStub) GetPrivateDataHashArgsForCall(i int) (string, string) { - fake.getPrivateDataHashMutex.RLock() - defer fake.getPrivateDataHashMutex.RUnlock() - argsForCall := fake.getPrivateDataHashArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ChaincodeStub) GetPrivateDataHashReturns(result1 []byte, result2 error) { - fake.getPrivateDataHashMutex.Lock() - defer fake.getPrivateDataHashMutex.Unlock() - fake.GetPrivateDataHashStub = nil - fake.getPrivateDataHashReturns = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetPrivateDataHashReturnsOnCall(i int, result1 []byte, result2 error) { - fake.getPrivateDataHashMutex.Lock() - defer fake.getPrivateDataHashMutex.Unlock() - fake.GetPrivateDataHashStub = nil - if fake.getPrivateDataHashReturnsOnCall == nil { - fake.getPrivateDataHashReturnsOnCall = make(map[int]struct { - result1 []byte - result2 error - }) - } - fake.getPrivateDataHashReturnsOnCall[i] = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetPrivateDataQueryResult(arg1 string, arg2 string) (shim.StateQueryIteratorInterface, error) { - fake.getPrivateDataQueryResultMutex.Lock() - ret, specificReturn := fake.getPrivateDataQueryResultReturnsOnCall[len(fake.getPrivateDataQueryResultArgsForCall)] - fake.getPrivateDataQueryResultArgsForCall = append(fake.getPrivateDataQueryResultArgsForCall, struct { - arg1 string - arg2 string - }{arg1, arg2}) - stub := fake.GetPrivateDataQueryResultStub - fakeReturns := fake.getPrivateDataQueryResultReturns - fake.recordInvocation("GetPrivateDataQueryResult", []interface{}{arg1, arg2}) - fake.getPrivateDataQueryResultMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetPrivateDataQueryResultCallCount() int { - fake.getPrivateDataQueryResultMutex.RLock() - defer fake.getPrivateDataQueryResultMutex.RUnlock() - return len(fake.getPrivateDataQueryResultArgsForCall) -} - -func (fake *ChaincodeStub) GetPrivateDataQueryResultCalls(stub func(string, string) (shim.StateQueryIteratorInterface, error)) { - fake.getPrivateDataQueryResultMutex.Lock() - defer fake.getPrivateDataQueryResultMutex.Unlock() - fake.GetPrivateDataQueryResultStub = stub -} - -func (fake *ChaincodeStub) GetPrivateDataQueryResultArgsForCall(i int) (string, string) { - fake.getPrivateDataQueryResultMutex.RLock() - defer fake.getPrivateDataQueryResultMutex.RUnlock() - argsForCall := fake.getPrivateDataQueryResultArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ChaincodeStub) GetPrivateDataQueryResultReturns(result1 shim.StateQueryIteratorInterface, result2 error) { - fake.getPrivateDataQueryResultMutex.Lock() - defer fake.getPrivateDataQueryResultMutex.Unlock() - fake.GetPrivateDataQueryResultStub = nil - fake.getPrivateDataQueryResultReturns = struct { - result1 shim.StateQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetPrivateDataQueryResultReturnsOnCall(i int, result1 shim.StateQueryIteratorInterface, result2 error) { - fake.getPrivateDataQueryResultMutex.Lock() - defer fake.getPrivateDataQueryResultMutex.Unlock() - fake.GetPrivateDataQueryResultStub = nil - if fake.getPrivateDataQueryResultReturnsOnCall == nil { - fake.getPrivateDataQueryResultReturnsOnCall = make(map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 error - }) - } - fake.getPrivateDataQueryResultReturnsOnCall[i] = struct { - result1 shim.StateQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetPrivateDataValidationParameter(arg1 string, arg2 string) ([]byte, error) { - fake.getPrivateDataValidationParameterMutex.Lock() - ret, specificReturn := fake.getPrivateDataValidationParameterReturnsOnCall[len(fake.getPrivateDataValidationParameterArgsForCall)] - fake.getPrivateDataValidationParameterArgsForCall = append(fake.getPrivateDataValidationParameterArgsForCall, struct { - arg1 string - arg2 string - }{arg1, arg2}) - stub := fake.GetPrivateDataValidationParameterStub - fakeReturns := fake.getPrivateDataValidationParameterReturns - fake.recordInvocation("GetPrivateDataValidationParameter", []interface{}{arg1, arg2}) - fake.getPrivateDataValidationParameterMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetPrivateDataValidationParameterCallCount() int { - fake.getPrivateDataValidationParameterMutex.RLock() - defer fake.getPrivateDataValidationParameterMutex.RUnlock() - return len(fake.getPrivateDataValidationParameterArgsForCall) -} - -func (fake *ChaincodeStub) GetPrivateDataValidationParameterCalls(stub func(string, string) ([]byte, error)) { - fake.getPrivateDataValidationParameterMutex.Lock() - defer fake.getPrivateDataValidationParameterMutex.Unlock() - fake.GetPrivateDataValidationParameterStub = stub -} - -func (fake *ChaincodeStub) GetPrivateDataValidationParameterArgsForCall(i int) (string, string) { - fake.getPrivateDataValidationParameterMutex.RLock() - defer fake.getPrivateDataValidationParameterMutex.RUnlock() - argsForCall := fake.getPrivateDataValidationParameterArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ChaincodeStub) GetPrivateDataValidationParameterReturns(result1 []byte, result2 error) { - fake.getPrivateDataValidationParameterMutex.Lock() - defer fake.getPrivateDataValidationParameterMutex.Unlock() - fake.GetPrivateDataValidationParameterStub = nil - fake.getPrivateDataValidationParameterReturns = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetPrivateDataValidationParameterReturnsOnCall(i int, result1 []byte, result2 error) { - fake.getPrivateDataValidationParameterMutex.Lock() - defer fake.getPrivateDataValidationParameterMutex.Unlock() - fake.GetPrivateDataValidationParameterStub = nil - if fake.getPrivateDataValidationParameterReturnsOnCall == nil { - fake.getPrivateDataValidationParameterReturnsOnCall = make(map[int]struct { - result1 []byte - result2 error - }) - } - fake.getPrivateDataValidationParameterReturnsOnCall[i] = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetQueryResult(arg1 string) (shim.StateQueryIteratorInterface, error) { - fake.getQueryResultMutex.Lock() - ret, specificReturn := fake.getQueryResultReturnsOnCall[len(fake.getQueryResultArgsForCall)] - fake.getQueryResultArgsForCall = append(fake.getQueryResultArgsForCall, struct { - arg1 string - }{arg1}) - stub := fake.GetQueryResultStub - fakeReturns := fake.getQueryResultReturns - fake.recordInvocation("GetQueryResult", []interface{}{arg1}) - fake.getQueryResultMutex.Unlock() - if stub != nil { - return stub(arg1) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetQueryResultCallCount() int { - fake.getQueryResultMutex.RLock() - defer fake.getQueryResultMutex.RUnlock() - return len(fake.getQueryResultArgsForCall) -} - -func (fake *ChaincodeStub) GetQueryResultCalls(stub func(string) (shim.StateQueryIteratorInterface, error)) { - fake.getQueryResultMutex.Lock() - defer fake.getQueryResultMutex.Unlock() - fake.GetQueryResultStub = stub -} - -func (fake *ChaincodeStub) GetQueryResultArgsForCall(i int) string { - fake.getQueryResultMutex.RLock() - defer fake.getQueryResultMutex.RUnlock() - argsForCall := fake.getQueryResultArgsForCall[i] - return argsForCall.arg1 -} - -func (fake *ChaincodeStub) GetQueryResultReturns(result1 shim.StateQueryIteratorInterface, result2 error) { - fake.getQueryResultMutex.Lock() - defer fake.getQueryResultMutex.Unlock() - fake.GetQueryResultStub = nil - fake.getQueryResultReturns = struct { - result1 shim.StateQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetQueryResultReturnsOnCall(i int, result1 shim.StateQueryIteratorInterface, result2 error) { - fake.getQueryResultMutex.Lock() - defer fake.getQueryResultMutex.Unlock() - fake.GetQueryResultStub = nil - if fake.getQueryResultReturnsOnCall == nil { - fake.getQueryResultReturnsOnCall = make(map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 error - }) - } - fake.getQueryResultReturnsOnCall[i] = struct { - result1 shim.StateQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetQueryResultWithPagination(arg1 string, arg2 int32, arg3 string) (shim.StateQueryIteratorInterface, *peer.QueryResponseMetadata, error) { - fake.getQueryResultWithPaginationMutex.Lock() - ret, specificReturn := fake.getQueryResultWithPaginationReturnsOnCall[len(fake.getQueryResultWithPaginationArgsForCall)] - fake.getQueryResultWithPaginationArgsForCall = append(fake.getQueryResultWithPaginationArgsForCall, struct { - arg1 string - arg2 int32 - arg3 string - }{arg1, arg2, arg3}) - stub := fake.GetQueryResultWithPaginationStub - fakeReturns := fake.getQueryResultWithPaginationReturns - fake.recordInvocation("GetQueryResultWithPagination", []interface{}{arg1, arg2, arg3}) - fake.getQueryResultWithPaginationMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3) - } - if specificReturn { - return ret.result1, ret.result2, ret.result3 - } - return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3 -} - -func (fake *ChaincodeStub) GetQueryResultWithPaginationCallCount() int { - fake.getQueryResultWithPaginationMutex.RLock() - defer fake.getQueryResultWithPaginationMutex.RUnlock() - return len(fake.getQueryResultWithPaginationArgsForCall) -} - -func (fake *ChaincodeStub) GetQueryResultWithPaginationCalls(stub func(string, int32, string) (shim.StateQueryIteratorInterface, *peer.QueryResponseMetadata, error)) { - fake.getQueryResultWithPaginationMutex.Lock() - defer fake.getQueryResultWithPaginationMutex.Unlock() - fake.GetQueryResultWithPaginationStub = stub -} - -func (fake *ChaincodeStub) GetQueryResultWithPaginationArgsForCall(i int) (string, int32, string) { - fake.getQueryResultWithPaginationMutex.RLock() - defer fake.getQueryResultWithPaginationMutex.RUnlock() - argsForCall := fake.getQueryResultWithPaginationArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 -} - -func (fake *ChaincodeStub) GetQueryResultWithPaginationReturns(result1 shim.StateQueryIteratorInterface, result2 *peer.QueryResponseMetadata, result3 error) { - fake.getQueryResultWithPaginationMutex.Lock() - defer fake.getQueryResultWithPaginationMutex.Unlock() - fake.GetQueryResultWithPaginationStub = nil - fake.getQueryResultWithPaginationReturns = struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - }{result1, result2, result3} -} - -func (fake *ChaincodeStub) GetQueryResultWithPaginationReturnsOnCall(i int, result1 shim.StateQueryIteratorInterface, result2 *peer.QueryResponseMetadata, result3 error) { - fake.getQueryResultWithPaginationMutex.Lock() - defer fake.getQueryResultWithPaginationMutex.Unlock() - fake.GetQueryResultWithPaginationStub = nil - if fake.getQueryResultWithPaginationReturnsOnCall == nil { - fake.getQueryResultWithPaginationReturnsOnCall = make(map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - }) - } - fake.getQueryResultWithPaginationReturnsOnCall[i] = struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - }{result1, result2, result3} -} - -func (fake *ChaincodeStub) GetSignedProposal() (*peer.SignedProposal, error) { - fake.getSignedProposalMutex.Lock() - ret, specificReturn := fake.getSignedProposalReturnsOnCall[len(fake.getSignedProposalArgsForCall)] - fake.getSignedProposalArgsForCall = append(fake.getSignedProposalArgsForCall, struct { - }{}) - stub := fake.GetSignedProposalStub - fakeReturns := fake.getSignedProposalReturns - fake.recordInvocation("GetSignedProposal", []interface{}{}) - fake.getSignedProposalMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetSignedProposalCallCount() int { - fake.getSignedProposalMutex.RLock() - defer fake.getSignedProposalMutex.RUnlock() - return len(fake.getSignedProposalArgsForCall) -} - -func (fake *ChaincodeStub) GetSignedProposalCalls(stub func() (*peer.SignedProposal, error)) { - fake.getSignedProposalMutex.Lock() - defer fake.getSignedProposalMutex.Unlock() - fake.GetSignedProposalStub = stub -} - -func (fake *ChaincodeStub) GetSignedProposalReturns(result1 *peer.SignedProposal, result2 error) { - fake.getSignedProposalMutex.Lock() - defer fake.getSignedProposalMutex.Unlock() - fake.GetSignedProposalStub = nil - fake.getSignedProposalReturns = struct { - result1 *peer.SignedProposal - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetSignedProposalReturnsOnCall(i int, result1 *peer.SignedProposal, result2 error) { - fake.getSignedProposalMutex.Lock() - defer fake.getSignedProposalMutex.Unlock() - fake.GetSignedProposalStub = nil - if fake.getSignedProposalReturnsOnCall == nil { - fake.getSignedProposalReturnsOnCall = make(map[int]struct { - result1 *peer.SignedProposal - result2 error - }) - } - fake.getSignedProposalReturnsOnCall[i] = struct { - result1 *peer.SignedProposal - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetState(arg1 string) ([]byte, error) { - fake.getStateMutex.Lock() - ret, specificReturn := fake.getStateReturnsOnCall[len(fake.getStateArgsForCall)] - fake.getStateArgsForCall = append(fake.getStateArgsForCall, struct { - arg1 string - }{arg1}) - stub := fake.GetStateStub - fakeReturns := fake.getStateReturns - fake.recordInvocation("GetState", []interface{}{arg1}) - fake.getStateMutex.Unlock() - if stub != nil { - return stub(arg1) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetStateCallCount() int { - fake.getStateMutex.RLock() - defer fake.getStateMutex.RUnlock() - return len(fake.getStateArgsForCall) -} - -func (fake *ChaincodeStub) GetStateCalls(stub func(string) ([]byte, error)) { - fake.getStateMutex.Lock() - defer fake.getStateMutex.Unlock() - fake.GetStateStub = stub -} - -func (fake *ChaincodeStub) GetStateArgsForCall(i int) string { - fake.getStateMutex.RLock() - defer fake.getStateMutex.RUnlock() - argsForCall := fake.getStateArgsForCall[i] - return argsForCall.arg1 -} - -func (fake *ChaincodeStub) GetStateReturns(result1 []byte, result2 error) { - fake.getStateMutex.Lock() - defer fake.getStateMutex.Unlock() - fake.GetStateStub = nil - fake.getStateReturns = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetStateReturnsOnCall(i int, result1 []byte, result2 error) { - fake.getStateMutex.Lock() - defer fake.getStateMutex.Unlock() - fake.GetStateStub = nil - if fake.getStateReturnsOnCall == nil { - fake.getStateReturnsOnCall = make(map[int]struct { - result1 []byte - result2 error - }) - } - fake.getStateReturnsOnCall[i] = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetStateByPartialCompositeKey(arg1 string, arg2 []string) (shim.StateQueryIteratorInterface, error) { - var arg2Copy []string - if arg2 != nil { - arg2Copy = make([]string, len(arg2)) - copy(arg2Copy, arg2) - } - fake.getStateByPartialCompositeKeyMutex.Lock() - ret, specificReturn := fake.getStateByPartialCompositeKeyReturnsOnCall[len(fake.getStateByPartialCompositeKeyArgsForCall)] - fake.getStateByPartialCompositeKeyArgsForCall = append(fake.getStateByPartialCompositeKeyArgsForCall, struct { - arg1 string - arg2 []string - }{arg1, arg2Copy}) - stub := fake.GetStateByPartialCompositeKeyStub - fakeReturns := fake.getStateByPartialCompositeKeyReturns - fake.recordInvocation("GetStateByPartialCompositeKey", []interface{}{arg1, arg2Copy}) - fake.getStateByPartialCompositeKeyMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetStateByPartialCompositeKeyCallCount() int { - fake.getStateByPartialCompositeKeyMutex.RLock() - defer fake.getStateByPartialCompositeKeyMutex.RUnlock() - return len(fake.getStateByPartialCompositeKeyArgsForCall) -} - -func (fake *ChaincodeStub) GetStateByPartialCompositeKeyCalls(stub func(string, []string) (shim.StateQueryIteratorInterface, error)) { - fake.getStateByPartialCompositeKeyMutex.Lock() - defer fake.getStateByPartialCompositeKeyMutex.Unlock() - fake.GetStateByPartialCompositeKeyStub = stub -} - -func (fake *ChaincodeStub) GetStateByPartialCompositeKeyArgsForCall(i int) (string, []string) { - fake.getStateByPartialCompositeKeyMutex.RLock() - defer fake.getStateByPartialCompositeKeyMutex.RUnlock() - argsForCall := fake.getStateByPartialCompositeKeyArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ChaincodeStub) GetStateByPartialCompositeKeyReturns(result1 shim.StateQueryIteratorInterface, result2 error) { - fake.getStateByPartialCompositeKeyMutex.Lock() - defer fake.getStateByPartialCompositeKeyMutex.Unlock() - fake.GetStateByPartialCompositeKeyStub = nil - fake.getStateByPartialCompositeKeyReturns = struct { - result1 shim.StateQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetStateByPartialCompositeKeyReturnsOnCall(i int, result1 shim.StateQueryIteratorInterface, result2 error) { - fake.getStateByPartialCompositeKeyMutex.Lock() - defer fake.getStateByPartialCompositeKeyMutex.Unlock() - fake.GetStateByPartialCompositeKeyStub = nil - if fake.getStateByPartialCompositeKeyReturnsOnCall == nil { - fake.getStateByPartialCompositeKeyReturnsOnCall = make(map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 error - }) - } - fake.getStateByPartialCompositeKeyReturnsOnCall[i] = struct { - result1 shim.StateQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetStateByPartialCompositeKeyWithPagination(arg1 string, arg2 []string, arg3 int32, arg4 string) (shim.StateQueryIteratorInterface, *peer.QueryResponseMetadata, error) { - var arg2Copy []string - if arg2 != nil { - arg2Copy = make([]string, len(arg2)) - copy(arg2Copy, arg2) - } - fake.getStateByPartialCompositeKeyWithPaginationMutex.Lock() - ret, specificReturn := fake.getStateByPartialCompositeKeyWithPaginationReturnsOnCall[len(fake.getStateByPartialCompositeKeyWithPaginationArgsForCall)] - fake.getStateByPartialCompositeKeyWithPaginationArgsForCall = append(fake.getStateByPartialCompositeKeyWithPaginationArgsForCall, struct { - arg1 string - arg2 []string - arg3 int32 - arg4 string - }{arg1, arg2Copy, arg3, arg4}) - stub := fake.GetStateByPartialCompositeKeyWithPaginationStub - fakeReturns := fake.getStateByPartialCompositeKeyWithPaginationReturns - fake.recordInvocation("GetStateByPartialCompositeKeyWithPagination", []interface{}{arg1, arg2Copy, arg3, arg4}) - fake.getStateByPartialCompositeKeyWithPaginationMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3, arg4) - } - if specificReturn { - return ret.result1, ret.result2, ret.result3 - } - return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3 -} - -func (fake *ChaincodeStub) GetStateByPartialCompositeKeyWithPaginationCallCount() int { - fake.getStateByPartialCompositeKeyWithPaginationMutex.RLock() - defer fake.getStateByPartialCompositeKeyWithPaginationMutex.RUnlock() - return len(fake.getStateByPartialCompositeKeyWithPaginationArgsForCall) -} - -func (fake *ChaincodeStub) GetStateByPartialCompositeKeyWithPaginationCalls(stub func(string, []string, int32, string) (shim.StateQueryIteratorInterface, *peer.QueryResponseMetadata, error)) { - fake.getStateByPartialCompositeKeyWithPaginationMutex.Lock() - defer fake.getStateByPartialCompositeKeyWithPaginationMutex.Unlock() - fake.GetStateByPartialCompositeKeyWithPaginationStub = stub -} - -func (fake *ChaincodeStub) GetStateByPartialCompositeKeyWithPaginationArgsForCall(i int) (string, []string, int32, string) { - fake.getStateByPartialCompositeKeyWithPaginationMutex.RLock() - defer fake.getStateByPartialCompositeKeyWithPaginationMutex.RUnlock() - argsForCall := fake.getStateByPartialCompositeKeyWithPaginationArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 -} - -func (fake *ChaincodeStub) GetStateByPartialCompositeKeyWithPaginationReturns(result1 shim.StateQueryIteratorInterface, result2 *peer.QueryResponseMetadata, result3 error) { - fake.getStateByPartialCompositeKeyWithPaginationMutex.Lock() - defer fake.getStateByPartialCompositeKeyWithPaginationMutex.Unlock() - fake.GetStateByPartialCompositeKeyWithPaginationStub = nil - fake.getStateByPartialCompositeKeyWithPaginationReturns = struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - }{result1, result2, result3} -} - -func (fake *ChaincodeStub) GetStateByPartialCompositeKeyWithPaginationReturnsOnCall(i int, result1 shim.StateQueryIteratorInterface, result2 *peer.QueryResponseMetadata, result3 error) { - fake.getStateByPartialCompositeKeyWithPaginationMutex.Lock() - defer fake.getStateByPartialCompositeKeyWithPaginationMutex.Unlock() - fake.GetStateByPartialCompositeKeyWithPaginationStub = nil - if fake.getStateByPartialCompositeKeyWithPaginationReturnsOnCall == nil { - fake.getStateByPartialCompositeKeyWithPaginationReturnsOnCall = make(map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - }) - } - fake.getStateByPartialCompositeKeyWithPaginationReturnsOnCall[i] = struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - }{result1, result2, result3} -} - -func (fake *ChaincodeStub) GetStateByRange(arg1 string, arg2 string) (shim.StateQueryIteratorInterface, error) { - fake.getStateByRangeMutex.Lock() - ret, specificReturn := fake.getStateByRangeReturnsOnCall[len(fake.getStateByRangeArgsForCall)] - fake.getStateByRangeArgsForCall = append(fake.getStateByRangeArgsForCall, struct { - arg1 string - arg2 string - }{arg1, arg2}) - stub := fake.GetStateByRangeStub - fakeReturns := fake.getStateByRangeReturns - fake.recordInvocation("GetStateByRange", []interface{}{arg1, arg2}) - fake.getStateByRangeMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetStateByRangeCallCount() int { - fake.getStateByRangeMutex.RLock() - defer fake.getStateByRangeMutex.RUnlock() - return len(fake.getStateByRangeArgsForCall) -} - -func (fake *ChaincodeStub) GetStateByRangeCalls(stub func(string, string) (shim.StateQueryIteratorInterface, error)) { - fake.getStateByRangeMutex.Lock() - defer fake.getStateByRangeMutex.Unlock() - fake.GetStateByRangeStub = stub -} - -func (fake *ChaincodeStub) GetStateByRangeArgsForCall(i int) (string, string) { - fake.getStateByRangeMutex.RLock() - defer fake.getStateByRangeMutex.RUnlock() - argsForCall := fake.getStateByRangeArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ChaincodeStub) GetStateByRangeReturns(result1 shim.StateQueryIteratorInterface, result2 error) { - fake.getStateByRangeMutex.Lock() - defer fake.getStateByRangeMutex.Unlock() - fake.GetStateByRangeStub = nil - fake.getStateByRangeReturns = struct { - result1 shim.StateQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetStateByRangeReturnsOnCall(i int, result1 shim.StateQueryIteratorInterface, result2 error) { - fake.getStateByRangeMutex.Lock() - defer fake.getStateByRangeMutex.Unlock() - fake.GetStateByRangeStub = nil - if fake.getStateByRangeReturnsOnCall == nil { - fake.getStateByRangeReturnsOnCall = make(map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 error - }) - } - fake.getStateByRangeReturnsOnCall[i] = struct { - result1 shim.StateQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetStateByRangeWithPagination(arg1 string, arg2 string, arg3 int32, arg4 string) (shim.StateQueryIteratorInterface, *peer.QueryResponseMetadata, error) { - fake.getStateByRangeWithPaginationMutex.Lock() - ret, specificReturn := fake.getStateByRangeWithPaginationReturnsOnCall[len(fake.getStateByRangeWithPaginationArgsForCall)] - fake.getStateByRangeWithPaginationArgsForCall = append(fake.getStateByRangeWithPaginationArgsForCall, struct { - arg1 string - arg2 string - arg3 int32 - arg4 string - }{arg1, arg2, arg3, arg4}) - stub := fake.GetStateByRangeWithPaginationStub - fakeReturns := fake.getStateByRangeWithPaginationReturns - fake.recordInvocation("GetStateByRangeWithPagination", []interface{}{arg1, arg2, arg3, arg4}) - fake.getStateByRangeWithPaginationMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3, arg4) - } - if specificReturn { - return ret.result1, ret.result2, ret.result3 - } - return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3 -} - -func (fake *ChaincodeStub) GetStateByRangeWithPaginationCallCount() int { - fake.getStateByRangeWithPaginationMutex.RLock() - defer fake.getStateByRangeWithPaginationMutex.RUnlock() - return len(fake.getStateByRangeWithPaginationArgsForCall) -} - -func (fake *ChaincodeStub) GetStateByRangeWithPaginationCalls(stub func(string, string, int32, string) (shim.StateQueryIteratorInterface, *peer.QueryResponseMetadata, error)) { - fake.getStateByRangeWithPaginationMutex.Lock() - defer fake.getStateByRangeWithPaginationMutex.Unlock() - fake.GetStateByRangeWithPaginationStub = stub -} - -func (fake *ChaincodeStub) GetStateByRangeWithPaginationArgsForCall(i int) (string, string, int32, string) { - fake.getStateByRangeWithPaginationMutex.RLock() - defer fake.getStateByRangeWithPaginationMutex.RUnlock() - argsForCall := fake.getStateByRangeWithPaginationArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 -} - -func (fake *ChaincodeStub) GetStateByRangeWithPaginationReturns(result1 shim.StateQueryIteratorInterface, result2 *peer.QueryResponseMetadata, result3 error) { - fake.getStateByRangeWithPaginationMutex.Lock() - defer fake.getStateByRangeWithPaginationMutex.Unlock() - fake.GetStateByRangeWithPaginationStub = nil - fake.getStateByRangeWithPaginationReturns = struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - }{result1, result2, result3} -} - -func (fake *ChaincodeStub) GetStateByRangeWithPaginationReturnsOnCall(i int, result1 shim.StateQueryIteratorInterface, result2 *peer.QueryResponseMetadata, result3 error) { - fake.getStateByRangeWithPaginationMutex.Lock() - defer fake.getStateByRangeWithPaginationMutex.Unlock() - fake.GetStateByRangeWithPaginationStub = nil - if fake.getStateByRangeWithPaginationReturnsOnCall == nil { - fake.getStateByRangeWithPaginationReturnsOnCall = make(map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - }) - } - fake.getStateByRangeWithPaginationReturnsOnCall[i] = struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - }{result1, result2, result3} -} - -func (fake *ChaincodeStub) GetStateValidationParameter(arg1 string) ([]byte, error) { - fake.getStateValidationParameterMutex.Lock() - ret, specificReturn := fake.getStateValidationParameterReturnsOnCall[len(fake.getStateValidationParameterArgsForCall)] - fake.getStateValidationParameterArgsForCall = append(fake.getStateValidationParameterArgsForCall, struct { - arg1 string - }{arg1}) - stub := fake.GetStateValidationParameterStub - fakeReturns := fake.getStateValidationParameterReturns - fake.recordInvocation("GetStateValidationParameter", []interface{}{arg1}) - fake.getStateValidationParameterMutex.Unlock() - if stub != nil { - return stub(arg1) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetStateValidationParameterCallCount() int { - fake.getStateValidationParameterMutex.RLock() - defer fake.getStateValidationParameterMutex.RUnlock() - return len(fake.getStateValidationParameterArgsForCall) -} - -func (fake *ChaincodeStub) GetStateValidationParameterCalls(stub func(string) ([]byte, error)) { - fake.getStateValidationParameterMutex.Lock() - defer fake.getStateValidationParameterMutex.Unlock() - fake.GetStateValidationParameterStub = stub -} - -func (fake *ChaincodeStub) GetStateValidationParameterArgsForCall(i int) string { - fake.getStateValidationParameterMutex.RLock() - defer fake.getStateValidationParameterMutex.RUnlock() - argsForCall := fake.getStateValidationParameterArgsForCall[i] - return argsForCall.arg1 -} - -func (fake *ChaincodeStub) GetStateValidationParameterReturns(result1 []byte, result2 error) { - fake.getStateValidationParameterMutex.Lock() - defer fake.getStateValidationParameterMutex.Unlock() - fake.GetStateValidationParameterStub = nil - fake.getStateValidationParameterReturns = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetStateValidationParameterReturnsOnCall(i int, result1 []byte, result2 error) { - fake.getStateValidationParameterMutex.Lock() - defer fake.getStateValidationParameterMutex.Unlock() - fake.GetStateValidationParameterStub = nil - if fake.getStateValidationParameterReturnsOnCall == nil { - fake.getStateValidationParameterReturnsOnCall = make(map[int]struct { - result1 []byte - result2 error - }) - } - fake.getStateValidationParameterReturnsOnCall[i] = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetStringArgs() []string { - fake.getStringArgsMutex.Lock() - ret, specificReturn := fake.getStringArgsReturnsOnCall[len(fake.getStringArgsArgsForCall)] - fake.getStringArgsArgsForCall = append(fake.getStringArgsArgsForCall, struct { - }{}) - stub := fake.GetStringArgsStub - fakeReturns := fake.getStringArgsReturns - fake.recordInvocation("GetStringArgs", []interface{}{}) - fake.getStringArgsMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) GetStringArgsCallCount() int { - fake.getStringArgsMutex.RLock() - defer fake.getStringArgsMutex.RUnlock() - return len(fake.getStringArgsArgsForCall) -} - -func (fake *ChaincodeStub) GetStringArgsCalls(stub func() []string) { - fake.getStringArgsMutex.Lock() - defer fake.getStringArgsMutex.Unlock() - fake.GetStringArgsStub = stub -} - -func (fake *ChaincodeStub) GetStringArgsReturns(result1 []string) { - fake.getStringArgsMutex.Lock() - defer fake.getStringArgsMutex.Unlock() - fake.GetStringArgsStub = nil - fake.getStringArgsReturns = struct { - result1 []string - }{result1} -} - -func (fake *ChaincodeStub) GetStringArgsReturnsOnCall(i int, result1 []string) { - fake.getStringArgsMutex.Lock() - defer fake.getStringArgsMutex.Unlock() - fake.GetStringArgsStub = nil - if fake.getStringArgsReturnsOnCall == nil { - fake.getStringArgsReturnsOnCall = make(map[int]struct { - result1 []string - }) - } - fake.getStringArgsReturnsOnCall[i] = struct { - result1 []string - }{result1} -} - -func (fake *ChaincodeStub) GetTransient() (map[string][]byte, error) { - fake.getTransientMutex.Lock() - ret, specificReturn := fake.getTransientReturnsOnCall[len(fake.getTransientArgsForCall)] - fake.getTransientArgsForCall = append(fake.getTransientArgsForCall, struct { - }{}) - stub := fake.GetTransientStub - fakeReturns := fake.getTransientReturns - fake.recordInvocation("GetTransient", []interface{}{}) - fake.getTransientMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetTransientCallCount() int { - fake.getTransientMutex.RLock() - defer fake.getTransientMutex.RUnlock() - return len(fake.getTransientArgsForCall) -} - -func (fake *ChaincodeStub) GetTransientCalls(stub func() (map[string][]byte, error)) { - fake.getTransientMutex.Lock() - defer fake.getTransientMutex.Unlock() - fake.GetTransientStub = stub -} - -func (fake *ChaincodeStub) GetTransientReturns(result1 map[string][]byte, result2 error) { - fake.getTransientMutex.Lock() - defer fake.getTransientMutex.Unlock() - fake.GetTransientStub = nil - fake.getTransientReturns = struct { - result1 map[string][]byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetTransientReturnsOnCall(i int, result1 map[string][]byte, result2 error) { - fake.getTransientMutex.Lock() - defer fake.getTransientMutex.Unlock() - fake.GetTransientStub = nil - if fake.getTransientReturnsOnCall == nil { - fake.getTransientReturnsOnCall = make(map[int]struct { - result1 map[string][]byte - result2 error - }) - } - fake.getTransientReturnsOnCall[i] = struct { - result1 map[string][]byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetTxID() string { - fake.getTxIDMutex.Lock() - ret, specificReturn := fake.getTxIDReturnsOnCall[len(fake.getTxIDArgsForCall)] - fake.getTxIDArgsForCall = append(fake.getTxIDArgsForCall, struct { - }{}) - stub := fake.GetTxIDStub - fakeReturns := fake.getTxIDReturns - fake.recordInvocation("GetTxID", []interface{}{}) - fake.getTxIDMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) GetTxIDCallCount() int { - fake.getTxIDMutex.RLock() - defer fake.getTxIDMutex.RUnlock() - return len(fake.getTxIDArgsForCall) -} - -func (fake *ChaincodeStub) GetTxIDCalls(stub func() string) { - fake.getTxIDMutex.Lock() - defer fake.getTxIDMutex.Unlock() - fake.GetTxIDStub = stub -} - -func (fake *ChaincodeStub) GetTxIDReturns(result1 string) { - fake.getTxIDMutex.Lock() - defer fake.getTxIDMutex.Unlock() - fake.GetTxIDStub = nil - fake.getTxIDReturns = struct { - result1 string - }{result1} -} - -func (fake *ChaincodeStub) GetTxIDReturnsOnCall(i int, result1 string) { - fake.getTxIDMutex.Lock() - defer fake.getTxIDMutex.Unlock() - fake.GetTxIDStub = nil - if fake.getTxIDReturnsOnCall == nil { - fake.getTxIDReturnsOnCall = make(map[int]struct { - result1 string - }) - } - fake.getTxIDReturnsOnCall[i] = struct { - result1 string - }{result1} -} - -func (fake *ChaincodeStub) GetTxTimestamp() (*timestamppb.Timestamp, error) { - fake.getTxTimestampMutex.Lock() - ret, specificReturn := fake.getTxTimestampReturnsOnCall[len(fake.getTxTimestampArgsForCall)] - fake.getTxTimestampArgsForCall = append(fake.getTxTimestampArgsForCall, struct { - }{}) - stub := fake.GetTxTimestampStub - fakeReturns := fake.getTxTimestampReturns - fake.recordInvocation("GetTxTimestamp", []interface{}{}) - fake.getTxTimestampMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetTxTimestampCallCount() int { - fake.getTxTimestampMutex.RLock() - defer fake.getTxTimestampMutex.RUnlock() - return len(fake.getTxTimestampArgsForCall) -} - -func (fake *ChaincodeStub) GetTxTimestampCalls(stub func() (*timestamppb.Timestamp, error)) { - fake.getTxTimestampMutex.Lock() - defer fake.getTxTimestampMutex.Unlock() - fake.GetTxTimestampStub = stub -} - -func (fake *ChaincodeStub) GetTxTimestampReturns(result1 *timestamppb.Timestamp, result2 error) { - fake.getTxTimestampMutex.Lock() - defer fake.getTxTimestampMutex.Unlock() - fake.GetTxTimestampStub = nil - fake.getTxTimestampReturns = struct { - result1 *timestamppb.Timestamp - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetTxTimestampReturnsOnCall(i int, result1 *timestamppb.Timestamp, result2 error) { - fake.getTxTimestampMutex.Lock() - defer fake.getTxTimestampMutex.Unlock() - fake.GetTxTimestampStub = nil - if fake.getTxTimestampReturnsOnCall == nil { - fake.getTxTimestampReturnsOnCall = make(map[int]struct { - result1 *timestamppb.Timestamp - result2 error - }) - } - fake.getTxTimestampReturnsOnCall[i] = struct { - result1 *timestamppb.Timestamp - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) InvokeChaincode(arg1 string, arg2 [][]byte, arg3 string) *peer.Response { - var arg2Copy [][]byte - if arg2 != nil { - arg2Copy = make([][]byte, len(arg2)) - copy(arg2Copy, arg2) - } - fake.invokeChaincodeMutex.Lock() - ret, specificReturn := fake.invokeChaincodeReturnsOnCall[len(fake.invokeChaincodeArgsForCall)] - fake.invokeChaincodeArgsForCall = append(fake.invokeChaincodeArgsForCall, struct { - arg1 string - arg2 [][]byte - arg3 string - }{arg1, arg2Copy, arg3}) - stub := fake.InvokeChaincodeStub - fakeReturns := fake.invokeChaincodeReturns - fake.recordInvocation("InvokeChaincode", []interface{}{arg1, arg2Copy, arg3}) - fake.invokeChaincodeMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3) - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) InvokeChaincodeCallCount() int { - fake.invokeChaincodeMutex.RLock() - defer fake.invokeChaincodeMutex.RUnlock() - return len(fake.invokeChaincodeArgsForCall) -} - -func (fake *ChaincodeStub) InvokeChaincodeCalls(stub func(string, [][]byte, string) *peer.Response) { - fake.invokeChaincodeMutex.Lock() - defer fake.invokeChaincodeMutex.Unlock() - fake.InvokeChaincodeStub = stub -} - -func (fake *ChaincodeStub) InvokeChaincodeArgsForCall(i int) (string, [][]byte, string) { - fake.invokeChaincodeMutex.RLock() - defer fake.invokeChaincodeMutex.RUnlock() - argsForCall := fake.invokeChaincodeArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 -} - -func (fake *ChaincodeStub) InvokeChaincodeReturns(result1 *peer.Response) { - fake.invokeChaincodeMutex.Lock() - defer fake.invokeChaincodeMutex.Unlock() - fake.InvokeChaincodeStub = nil - fake.invokeChaincodeReturns = struct { - result1 *peer.Response - }{result1} -} - -func (fake *ChaincodeStub) InvokeChaincodeReturnsOnCall(i int, result1 *peer.Response) { - fake.invokeChaincodeMutex.Lock() - defer fake.invokeChaincodeMutex.Unlock() - fake.InvokeChaincodeStub = nil - if fake.invokeChaincodeReturnsOnCall == nil { - fake.invokeChaincodeReturnsOnCall = make(map[int]struct { - result1 *peer.Response - }) - } - fake.invokeChaincodeReturnsOnCall[i] = struct { - result1 *peer.Response - }{result1} -} - -func (fake *ChaincodeStub) PurgePrivateData(arg1 string, arg2 string) error { - fake.purgePrivateDataMutex.Lock() - ret, specificReturn := fake.purgePrivateDataReturnsOnCall[len(fake.purgePrivateDataArgsForCall)] - fake.purgePrivateDataArgsForCall = append(fake.purgePrivateDataArgsForCall, struct { - arg1 string - arg2 string - }{arg1, arg2}) - stub := fake.PurgePrivateDataStub - fakeReturns := fake.purgePrivateDataReturns - fake.recordInvocation("PurgePrivateData", []interface{}{arg1, arg2}) - fake.purgePrivateDataMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) PurgePrivateDataCallCount() int { - fake.purgePrivateDataMutex.RLock() - defer fake.purgePrivateDataMutex.RUnlock() - return len(fake.purgePrivateDataArgsForCall) -} - -func (fake *ChaincodeStub) PurgePrivateDataCalls(stub func(string, string) error) { - fake.purgePrivateDataMutex.Lock() - defer fake.purgePrivateDataMutex.Unlock() - fake.PurgePrivateDataStub = stub -} - -func (fake *ChaincodeStub) PurgePrivateDataArgsForCall(i int) (string, string) { - fake.purgePrivateDataMutex.RLock() - defer fake.purgePrivateDataMutex.RUnlock() - argsForCall := fake.purgePrivateDataArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ChaincodeStub) PurgePrivateDataReturns(result1 error) { - fake.purgePrivateDataMutex.Lock() - defer fake.purgePrivateDataMutex.Unlock() - fake.PurgePrivateDataStub = nil - fake.purgePrivateDataReturns = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) PurgePrivateDataReturnsOnCall(i int, result1 error) { - fake.purgePrivateDataMutex.Lock() - defer fake.purgePrivateDataMutex.Unlock() - fake.PurgePrivateDataStub = nil - if fake.purgePrivateDataReturnsOnCall == nil { - fake.purgePrivateDataReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.purgePrivateDataReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) PutPrivateData(arg1 string, arg2 string, arg3 []byte) error { - var arg3Copy []byte - if arg3 != nil { - arg3Copy = make([]byte, len(arg3)) - copy(arg3Copy, arg3) - } - fake.putPrivateDataMutex.Lock() - ret, specificReturn := fake.putPrivateDataReturnsOnCall[len(fake.putPrivateDataArgsForCall)] - fake.putPrivateDataArgsForCall = append(fake.putPrivateDataArgsForCall, struct { - arg1 string - arg2 string - arg3 []byte - }{arg1, arg2, arg3Copy}) - stub := fake.PutPrivateDataStub - fakeReturns := fake.putPrivateDataReturns - fake.recordInvocation("PutPrivateData", []interface{}{arg1, arg2, arg3Copy}) - fake.putPrivateDataMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3) - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) PutPrivateDataCallCount() int { - fake.putPrivateDataMutex.RLock() - defer fake.putPrivateDataMutex.RUnlock() - return len(fake.putPrivateDataArgsForCall) -} - -func (fake *ChaincodeStub) PutPrivateDataCalls(stub func(string, string, []byte) error) { - fake.putPrivateDataMutex.Lock() - defer fake.putPrivateDataMutex.Unlock() - fake.PutPrivateDataStub = stub -} - -func (fake *ChaincodeStub) PutPrivateDataArgsForCall(i int) (string, string, []byte) { - fake.putPrivateDataMutex.RLock() - defer fake.putPrivateDataMutex.RUnlock() - argsForCall := fake.putPrivateDataArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 -} - -func (fake *ChaincodeStub) PutPrivateDataReturns(result1 error) { - fake.putPrivateDataMutex.Lock() - defer fake.putPrivateDataMutex.Unlock() - fake.PutPrivateDataStub = nil - fake.putPrivateDataReturns = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) PutPrivateDataReturnsOnCall(i int, result1 error) { - fake.putPrivateDataMutex.Lock() - defer fake.putPrivateDataMutex.Unlock() - fake.PutPrivateDataStub = nil - if fake.putPrivateDataReturnsOnCall == nil { - fake.putPrivateDataReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.putPrivateDataReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) PutState(arg1 string, arg2 []byte) error { - var arg2Copy []byte - if arg2 != nil { - arg2Copy = make([]byte, len(arg2)) - copy(arg2Copy, arg2) - } - fake.putStateMutex.Lock() - ret, specificReturn := fake.putStateReturnsOnCall[len(fake.putStateArgsForCall)] - fake.putStateArgsForCall = append(fake.putStateArgsForCall, struct { - arg1 string - arg2 []byte - }{arg1, arg2Copy}) - stub := fake.PutStateStub - fakeReturns := fake.putStateReturns - fake.recordInvocation("PutState", []interface{}{arg1, arg2Copy}) - fake.putStateMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) PutStateCallCount() int { - fake.putStateMutex.RLock() - defer fake.putStateMutex.RUnlock() - return len(fake.putStateArgsForCall) -} - -func (fake *ChaincodeStub) PutStateCalls(stub func(string, []byte) error) { - fake.putStateMutex.Lock() - defer fake.putStateMutex.Unlock() - fake.PutStateStub = stub -} - -func (fake *ChaincodeStub) PutStateArgsForCall(i int) (string, []byte) { - fake.putStateMutex.RLock() - defer fake.putStateMutex.RUnlock() - argsForCall := fake.putStateArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ChaincodeStub) PutStateReturns(result1 error) { - fake.putStateMutex.Lock() - defer fake.putStateMutex.Unlock() - fake.PutStateStub = nil - fake.putStateReturns = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) PutStateReturnsOnCall(i int, result1 error) { - fake.putStateMutex.Lock() - defer fake.putStateMutex.Unlock() - fake.PutStateStub = nil - if fake.putStateReturnsOnCall == nil { - fake.putStateReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.putStateReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) SetEvent(arg1 string, arg2 []byte) error { - var arg2Copy []byte - if arg2 != nil { - arg2Copy = make([]byte, len(arg2)) - copy(arg2Copy, arg2) - } - fake.setEventMutex.Lock() - ret, specificReturn := fake.setEventReturnsOnCall[len(fake.setEventArgsForCall)] - fake.setEventArgsForCall = append(fake.setEventArgsForCall, struct { - arg1 string - arg2 []byte - }{arg1, arg2Copy}) - stub := fake.SetEventStub - fakeReturns := fake.setEventReturns - fake.recordInvocation("SetEvent", []interface{}{arg1, arg2Copy}) - fake.setEventMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) SetEventCallCount() int { - fake.setEventMutex.RLock() - defer fake.setEventMutex.RUnlock() - return len(fake.setEventArgsForCall) -} - -func (fake *ChaincodeStub) SetEventCalls(stub func(string, []byte) error) { - fake.setEventMutex.Lock() - defer fake.setEventMutex.Unlock() - fake.SetEventStub = stub -} - -func (fake *ChaincodeStub) SetEventArgsForCall(i int) (string, []byte) { - fake.setEventMutex.RLock() - defer fake.setEventMutex.RUnlock() - argsForCall := fake.setEventArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ChaincodeStub) SetEventReturns(result1 error) { - fake.setEventMutex.Lock() - defer fake.setEventMutex.Unlock() - fake.SetEventStub = nil - fake.setEventReturns = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) SetEventReturnsOnCall(i int, result1 error) { - fake.setEventMutex.Lock() - defer fake.setEventMutex.Unlock() - fake.SetEventStub = nil - if fake.setEventReturnsOnCall == nil { - fake.setEventReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.setEventReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) SetPrivateDataValidationParameter(arg1 string, arg2 string, arg3 []byte) error { - var arg3Copy []byte - if arg3 != nil { - arg3Copy = make([]byte, len(arg3)) - copy(arg3Copy, arg3) - } - fake.setPrivateDataValidationParameterMutex.Lock() - ret, specificReturn := fake.setPrivateDataValidationParameterReturnsOnCall[len(fake.setPrivateDataValidationParameterArgsForCall)] - fake.setPrivateDataValidationParameterArgsForCall = append(fake.setPrivateDataValidationParameterArgsForCall, struct { - arg1 string - arg2 string - arg3 []byte - }{arg1, arg2, arg3Copy}) - stub := fake.SetPrivateDataValidationParameterStub - fakeReturns := fake.setPrivateDataValidationParameterReturns - fake.recordInvocation("SetPrivateDataValidationParameter", []interface{}{arg1, arg2, arg3Copy}) - fake.setPrivateDataValidationParameterMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3) - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) SetPrivateDataValidationParameterCallCount() int { - fake.setPrivateDataValidationParameterMutex.RLock() - defer fake.setPrivateDataValidationParameterMutex.RUnlock() - return len(fake.setPrivateDataValidationParameterArgsForCall) -} - -func (fake *ChaincodeStub) SetPrivateDataValidationParameterCalls(stub func(string, string, []byte) error) { - fake.setPrivateDataValidationParameterMutex.Lock() - defer fake.setPrivateDataValidationParameterMutex.Unlock() - fake.SetPrivateDataValidationParameterStub = stub -} - -func (fake *ChaincodeStub) SetPrivateDataValidationParameterArgsForCall(i int) (string, string, []byte) { - fake.setPrivateDataValidationParameterMutex.RLock() - defer fake.setPrivateDataValidationParameterMutex.RUnlock() - argsForCall := fake.setPrivateDataValidationParameterArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 -} - -func (fake *ChaincodeStub) SetPrivateDataValidationParameterReturns(result1 error) { - fake.setPrivateDataValidationParameterMutex.Lock() - defer fake.setPrivateDataValidationParameterMutex.Unlock() - fake.SetPrivateDataValidationParameterStub = nil - fake.setPrivateDataValidationParameterReturns = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) SetPrivateDataValidationParameterReturnsOnCall(i int, result1 error) { - fake.setPrivateDataValidationParameterMutex.Lock() - defer fake.setPrivateDataValidationParameterMutex.Unlock() - fake.SetPrivateDataValidationParameterStub = nil - if fake.setPrivateDataValidationParameterReturnsOnCall == nil { - fake.setPrivateDataValidationParameterReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.setPrivateDataValidationParameterReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) SetStateValidationParameter(arg1 string, arg2 []byte) error { - var arg2Copy []byte - if arg2 != nil { - arg2Copy = make([]byte, len(arg2)) - copy(arg2Copy, arg2) - } - fake.setStateValidationParameterMutex.Lock() - ret, specificReturn := fake.setStateValidationParameterReturnsOnCall[len(fake.setStateValidationParameterArgsForCall)] - fake.setStateValidationParameterArgsForCall = append(fake.setStateValidationParameterArgsForCall, struct { - arg1 string - arg2 []byte - }{arg1, arg2Copy}) - stub := fake.SetStateValidationParameterStub - fakeReturns := fake.setStateValidationParameterReturns - fake.recordInvocation("SetStateValidationParameter", []interface{}{arg1, arg2Copy}) - fake.setStateValidationParameterMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) SetStateValidationParameterCallCount() int { - fake.setStateValidationParameterMutex.RLock() - defer fake.setStateValidationParameterMutex.RUnlock() - return len(fake.setStateValidationParameterArgsForCall) -} - -func (fake *ChaincodeStub) SetStateValidationParameterCalls(stub func(string, []byte) error) { - fake.setStateValidationParameterMutex.Lock() - defer fake.setStateValidationParameterMutex.Unlock() - fake.SetStateValidationParameterStub = stub -} - -func (fake *ChaincodeStub) SetStateValidationParameterArgsForCall(i int) (string, []byte) { - fake.setStateValidationParameterMutex.RLock() - defer fake.setStateValidationParameterMutex.RUnlock() - argsForCall := fake.setStateValidationParameterArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ChaincodeStub) SetStateValidationParameterReturns(result1 error) { - fake.setStateValidationParameterMutex.Lock() - defer fake.setStateValidationParameterMutex.Unlock() - fake.SetStateValidationParameterStub = nil - fake.setStateValidationParameterReturns = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) SetStateValidationParameterReturnsOnCall(i int, result1 error) { - fake.setStateValidationParameterMutex.Lock() - defer fake.setStateValidationParameterMutex.Unlock() - fake.SetStateValidationParameterStub = nil - if fake.setStateValidationParameterReturnsOnCall == nil { - fake.setStateValidationParameterReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.setStateValidationParameterReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) SplitCompositeKey(arg1 string) (string, []string, error) { - fake.splitCompositeKeyMutex.Lock() - ret, specificReturn := fake.splitCompositeKeyReturnsOnCall[len(fake.splitCompositeKeyArgsForCall)] - fake.splitCompositeKeyArgsForCall = append(fake.splitCompositeKeyArgsForCall, struct { - arg1 string - }{arg1}) - stub := fake.SplitCompositeKeyStub - fakeReturns := fake.splitCompositeKeyReturns - fake.recordInvocation("SplitCompositeKey", []interface{}{arg1}) - fake.splitCompositeKeyMutex.Unlock() - if stub != nil { - return stub(arg1) - } - if specificReturn { - return ret.result1, ret.result2, ret.result3 - } - return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3 -} - -func (fake *ChaincodeStub) SplitCompositeKeyCallCount() int { - fake.splitCompositeKeyMutex.RLock() - defer fake.splitCompositeKeyMutex.RUnlock() - return len(fake.splitCompositeKeyArgsForCall) -} - -func (fake *ChaincodeStub) SplitCompositeKeyCalls(stub func(string) (string, []string, error)) { - fake.splitCompositeKeyMutex.Lock() - defer fake.splitCompositeKeyMutex.Unlock() - fake.SplitCompositeKeyStub = stub -} - -func (fake *ChaincodeStub) SplitCompositeKeyArgsForCall(i int) string { - fake.splitCompositeKeyMutex.RLock() - defer fake.splitCompositeKeyMutex.RUnlock() - argsForCall := fake.splitCompositeKeyArgsForCall[i] - return argsForCall.arg1 -} - -func (fake *ChaincodeStub) SplitCompositeKeyReturns(result1 string, result2 []string, result3 error) { - fake.splitCompositeKeyMutex.Lock() - defer fake.splitCompositeKeyMutex.Unlock() - fake.SplitCompositeKeyStub = nil - fake.splitCompositeKeyReturns = struct { - result1 string - result2 []string - result3 error - }{result1, result2, result3} -} - -func (fake *ChaincodeStub) SplitCompositeKeyReturnsOnCall(i int, result1 string, result2 []string, result3 error) { - fake.splitCompositeKeyMutex.Lock() - defer fake.splitCompositeKeyMutex.Unlock() - fake.SplitCompositeKeyStub = nil - if fake.splitCompositeKeyReturnsOnCall == nil { - fake.splitCompositeKeyReturnsOnCall = make(map[int]struct { - result1 string - result2 []string - result3 error - }) - } - fake.splitCompositeKeyReturnsOnCall[i] = struct { - result1 string - result2 []string - result3 error - }{result1, result2, result3} -} - -func (fake *ChaincodeStub) Invocations() map[string][][]interface{} { - fake.invocationsMutex.RLock() - defer fake.invocationsMutex.RUnlock() - fake.createCompositeKeyMutex.RLock() - defer fake.createCompositeKeyMutex.RUnlock() - fake.delPrivateDataMutex.RLock() - defer fake.delPrivateDataMutex.RUnlock() - fake.delStateMutex.RLock() - defer fake.delStateMutex.RUnlock() - fake.getArgsMutex.RLock() - defer fake.getArgsMutex.RUnlock() - fake.getArgsSliceMutex.RLock() - defer fake.getArgsSliceMutex.RUnlock() - fake.getBindingMutex.RLock() - defer fake.getBindingMutex.RUnlock() - fake.getChannelIDMutex.RLock() - defer fake.getChannelIDMutex.RUnlock() - fake.getCreatorMutex.RLock() - defer fake.getCreatorMutex.RUnlock() - fake.getDecorationsMutex.RLock() - defer fake.getDecorationsMutex.RUnlock() - fake.getFunctionAndParametersMutex.RLock() - defer fake.getFunctionAndParametersMutex.RUnlock() - fake.getHistoryForKeyMutex.RLock() - defer fake.getHistoryForKeyMutex.RUnlock() - fake.getPrivateDataMutex.RLock() - defer fake.getPrivateDataMutex.RUnlock() - fake.getPrivateDataByPartialCompositeKeyMutex.RLock() - defer fake.getPrivateDataByPartialCompositeKeyMutex.RUnlock() - fake.getPrivateDataByRangeMutex.RLock() - defer fake.getPrivateDataByRangeMutex.RUnlock() - fake.getPrivateDataHashMutex.RLock() - defer fake.getPrivateDataHashMutex.RUnlock() - fake.getPrivateDataQueryResultMutex.RLock() - defer fake.getPrivateDataQueryResultMutex.RUnlock() - fake.getPrivateDataValidationParameterMutex.RLock() - defer fake.getPrivateDataValidationParameterMutex.RUnlock() - fake.getQueryResultMutex.RLock() - defer fake.getQueryResultMutex.RUnlock() - fake.getQueryResultWithPaginationMutex.RLock() - defer fake.getQueryResultWithPaginationMutex.RUnlock() - fake.getSignedProposalMutex.RLock() - defer fake.getSignedProposalMutex.RUnlock() - fake.getStateMutex.RLock() - defer fake.getStateMutex.RUnlock() - fake.getStateByPartialCompositeKeyMutex.RLock() - defer fake.getStateByPartialCompositeKeyMutex.RUnlock() - fake.getStateByPartialCompositeKeyWithPaginationMutex.RLock() - defer fake.getStateByPartialCompositeKeyWithPaginationMutex.RUnlock() - fake.getStateByRangeMutex.RLock() - defer fake.getStateByRangeMutex.RUnlock() - fake.getStateByRangeWithPaginationMutex.RLock() - defer fake.getStateByRangeWithPaginationMutex.RUnlock() - fake.getStateValidationParameterMutex.RLock() - defer fake.getStateValidationParameterMutex.RUnlock() - fake.getStringArgsMutex.RLock() - defer fake.getStringArgsMutex.RUnlock() - fake.getTransientMutex.RLock() - defer fake.getTransientMutex.RUnlock() - fake.getTxIDMutex.RLock() - defer fake.getTxIDMutex.RUnlock() - fake.getTxTimestampMutex.RLock() - defer fake.getTxTimestampMutex.RUnlock() - fake.invokeChaincodeMutex.RLock() - defer fake.invokeChaincodeMutex.RUnlock() - fake.purgePrivateDataMutex.RLock() - defer fake.purgePrivateDataMutex.RUnlock() - fake.putPrivateDataMutex.RLock() - defer fake.putPrivateDataMutex.RUnlock() - fake.putStateMutex.RLock() - defer fake.putStateMutex.RUnlock() - fake.setEventMutex.RLock() - defer fake.setEventMutex.RUnlock() - fake.setPrivateDataValidationParameterMutex.RLock() - defer fake.setPrivateDataValidationParameterMutex.RUnlock() - fake.setStateValidationParameterMutex.RLock() - defer fake.setStateValidationParameterMutex.RUnlock() - fake.splitCompositeKeyMutex.RLock() - defer fake.splitCompositeKeyMutex.RUnlock() - copiedInvocations := map[string][][]interface{}{} - for key, value := range fake.invocations { - copiedInvocations[key] = value - } - return copiedInvocations -} - -func (fake *ChaincodeStub) recordInvocation(key string, args []interface{}) { - fake.invocationsMutex.Lock() - defer fake.invocationsMutex.Unlock() - if fake.invocations == nil { - fake.invocations = map[string][][]interface{}{} - } - if fake.invocations[key] == nil { - fake.invocations[key] = [][]interface{}{} - } - fake.invocations[key] = append(fake.invocations[key], args) -} diff --git a/asset-transfer-basic/chaincode-go/chaincode/mocks/statequeryiterator.go b/asset-transfer-basic/chaincode-go/chaincode/mocks/statequeryiterator.go deleted file mode 100644 index 76cdcaa1..00000000 --- a/asset-transfer-basic/chaincode-go/chaincode/mocks/statequeryiterator.go +++ /dev/null @@ -1,235 +0,0 @@ -// Code generated by counterfeiter. DO NOT EDIT. -package mocks - -import ( - "sync" - - "github.com/hyperledger/fabric-protos-go-apiv2/ledger/queryresult" -) - -type StateQueryIterator struct { - CloseStub func() error - closeMutex sync.RWMutex - closeArgsForCall []struct { - } - closeReturns struct { - result1 error - } - closeReturnsOnCall map[int]struct { - result1 error - } - HasNextStub func() bool - hasNextMutex sync.RWMutex - hasNextArgsForCall []struct { - } - hasNextReturns struct { - result1 bool - } - hasNextReturnsOnCall map[int]struct { - result1 bool - } - NextStub func() (*queryresult.KV, error) - nextMutex sync.RWMutex - nextArgsForCall []struct { - } - nextReturns struct { - result1 *queryresult.KV - result2 error - } - nextReturnsOnCall map[int]struct { - result1 *queryresult.KV - result2 error - } - invocations map[string][][]interface{} - invocationsMutex sync.RWMutex -} - -func (fake *StateQueryIterator) Close() error { - fake.closeMutex.Lock() - ret, specificReturn := fake.closeReturnsOnCall[len(fake.closeArgsForCall)] - fake.closeArgsForCall = append(fake.closeArgsForCall, struct { - }{}) - stub := fake.CloseStub - fakeReturns := fake.closeReturns - fake.recordInvocation("Close", []interface{}{}) - fake.closeMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *StateQueryIterator) CloseCallCount() int { - fake.closeMutex.RLock() - defer fake.closeMutex.RUnlock() - return len(fake.closeArgsForCall) -} - -func (fake *StateQueryIterator) CloseCalls(stub func() error) { - fake.closeMutex.Lock() - defer fake.closeMutex.Unlock() - fake.CloseStub = stub -} - -func (fake *StateQueryIterator) CloseReturns(result1 error) { - fake.closeMutex.Lock() - defer fake.closeMutex.Unlock() - fake.CloseStub = nil - fake.closeReturns = struct { - result1 error - }{result1} -} - -func (fake *StateQueryIterator) CloseReturnsOnCall(i int, result1 error) { - fake.closeMutex.Lock() - defer fake.closeMutex.Unlock() - fake.CloseStub = nil - if fake.closeReturnsOnCall == nil { - fake.closeReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.closeReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *StateQueryIterator) HasNext() bool { - fake.hasNextMutex.Lock() - ret, specificReturn := fake.hasNextReturnsOnCall[len(fake.hasNextArgsForCall)] - fake.hasNextArgsForCall = append(fake.hasNextArgsForCall, struct { - }{}) - stub := fake.HasNextStub - fakeReturns := fake.hasNextReturns - fake.recordInvocation("HasNext", []interface{}{}) - fake.hasNextMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *StateQueryIterator) HasNextCallCount() int { - fake.hasNextMutex.RLock() - defer fake.hasNextMutex.RUnlock() - return len(fake.hasNextArgsForCall) -} - -func (fake *StateQueryIterator) HasNextCalls(stub func() bool) { - fake.hasNextMutex.Lock() - defer fake.hasNextMutex.Unlock() - fake.HasNextStub = stub -} - -func (fake *StateQueryIterator) HasNextReturns(result1 bool) { - fake.hasNextMutex.Lock() - defer fake.hasNextMutex.Unlock() - fake.HasNextStub = nil - fake.hasNextReturns = struct { - result1 bool - }{result1} -} - -func (fake *StateQueryIterator) HasNextReturnsOnCall(i int, result1 bool) { - fake.hasNextMutex.Lock() - defer fake.hasNextMutex.Unlock() - fake.HasNextStub = nil - if fake.hasNextReturnsOnCall == nil { - fake.hasNextReturnsOnCall = make(map[int]struct { - result1 bool - }) - } - fake.hasNextReturnsOnCall[i] = struct { - result1 bool - }{result1} -} - -func (fake *StateQueryIterator) Next() (*queryresult.KV, error) { - fake.nextMutex.Lock() - ret, specificReturn := fake.nextReturnsOnCall[len(fake.nextArgsForCall)] - fake.nextArgsForCall = append(fake.nextArgsForCall, struct { - }{}) - stub := fake.NextStub - fakeReturns := fake.nextReturns - fake.recordInvocation("Next", []interface{}{}) - fake.nextMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *StateQueryIterator) NextCallCount() int { - fake.nextMutex.RLock() - defer fake.nextMutex.RUnlock() - return len(fake.nextArgsForCall) -} - -func (fake *StateQueryIterator) NextCalls(stub func() (*queryresult.KV, error)) { - fake.nextMutex.Lock() - defer fake.nextMutex.Unlock() - fake.NextStub = stub -} - -func (fake *StateQueryIterator) NextReturns(result1 *queryresult.KV, result2 error) { - fake.nextMutex.Lock() - defer fake.nextMutex.Unlock() - fake.NextStub = nil - fake.nextReturns = struct { - result1 *queryresult.KV - result2 error - }{result1, result2} -} - -func (fake *StateQueryIterator) NextReturnsOnCall(i int, result1 *queryresult.KV, result2 error) { - fake.nextMutex.Lock() - defer fake.nextMutex.Unlock() - fake.NextStub = nil - if fake.nextReturnsOnCall == nil { - fake.nextReturnsOnCall = make(map[int]struct { - result1 *queryresult.KV - result2 error - }) - } - fake.nextReturnsOnCall[i] = struct { - result1 *queryresult.KV - result2 error - }{result1, result2} -} - -func (fake *StateQueryIterator) Invocations() map[string][][]interface{} { - fake.invocationsMutex.RLock() - defer fake.invocationsMutex.RUnlock() - fake.closeMutex.RLock() - defer fake.closeMutex.RUnlock() - fake.hasNextMutex.RLock() - defer fake.hasNextMutex.RUnlock() - fake.nextMutex.RLock() - defer fake.nextMutex.RUnlock() - copiedInvocations := map[string][][]interface{}{} - for key, value := range fake.invocations { - copiedInvocations[key] = value - } - return copiedInvocations -} - -func (fake *StateQueryIterator) recordInvocation(key string, args []interface{}) { - fake.invocationsMutex.Lock() - defer fake.invocationsMutex.Unlock() - if fake.invocations == nil { - fake.invocations = map[string][][]interface{}{} - } - if fake.invocations[key] == nil { - fake.invocations[key] = [][]interface{}{} - } - fake.invocations[key] = append(fake.invocations[key], args) -} diff --git a/asset-transfer-basic/chaincode-go/chaincode/mocks/transaction.go b/asset-transfer-basic/chaincode-go/chaincode/mocks/transaction.go deleted file mode 100644 index 5e98d069..00000000 --- a/asset-transfer-basic/chaincode-go/chaincode/mocks/transaction.go +++ /dev/null @@ -1,166 +0,0 @@ -// Code generated by counterfeiter. DO NOT EDIT. -package mocks - -import ( - "sync" - - "github.com/hyperledger/fabric-chaincode-go/v2/pkg/cid" - "github.com/hyperledger/fabric-chaincode-go/v2/shim" -) - -type TransactionContext struct { - GetClientIdentityStub func() cid.ClientIdentity - getClientIdentityMutex sync.RWMutex - getClientIdentityArgsForCall []struct { - } - getClientIdentityReturns struct { - result1 cid.ClientIdentity - } - getClientIdentityReturnsOnCall map[int]struct { - result1 cid.ClientIdentity - } - GetStubStub func() shim.ChaincodeStubInterface - getStubMutex sync.RWMutex - getStubArgsForCall []struct { - } - getStubReturns struct { - result1 shim.ChaincodeStubInterface - } - getStubReturnsOnCall map[int]struct { - result1 shim.ChaincodeStubInterface - } - invocations map[string][][]interface{} - invocationsMutex sync.RWMutex -} - -func (fake *TransactionContext) GetClientIdentity() cid.ClientIdentity { - fake.getClientIdentityMutex.Lock() - ret, specificReturn := fake.getClientIdentityReturnsOnCall[len(fake.getClientIdentityArgsForCall)] - fake.getClientIdentityArgsForCall = append(fake.getClientIdentityArgsForCall, struct { - }{}) - stub := fake.GetClientIdentityStub - fakeReturns := fake.getClientIdentityReturns - fake.recordInvocation("GetClientIdentity", []interface{}{}) - fake.getClientIdentityMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *TransactionContext) GetClientIdentityCallCount() int { - fake.getClientIdentityMutex.RLock() - defer fake.getClientIdentityMutex.RUnlock() - return len(fake.getClientIdentityArgsForCall) -} - -func (fake *TransactionContext) GetClientIdentityCalls(stub func() cid.ClientIdentity) { - fake.getClientIdentityMutex.Lock() - defer fake.getClientIdentityMutex.Unlock() - fake.GetClientIdentityStub = stub -} - -func (fake *TransactionContext) GetClientIdentityReturns(result1 cid.ClientIdentity) { - fake.getClientIdentityMutex.Lock() - defer fake.getClientIdentityMutex.Unlock() - fake.GetClientIdentityStub = nil - fake.getClientIdentityReturns = struct { - result1 cid.ClientIdentity - }{result1} -} - -func (fake *TransactionContext) GetClientIdentityReturnsOnCall(i int, result1 cid.ClientIdentity) { - fake.getClientIdentityMutex.Lock() - defer fake.getClientIdentityMutex.Unlock() - fake.GetClientIdentityStub = nil - if fake.getClientIdentityReturnsOnCall == nil { - fake.getClientIdentityReturnsOnCall = make(map[int]struct { - result1 cid.ClientIdentity - }) - } - fake.getClientIdentityReturnsOnCall[i] = struct { - result1 cid.ClientIdentity - }{result1} -} - -func (fake *TransactionContext) GetStub() shim.ChaincodeStubInterface { - fake.getStubMutex.Lock() - ret, specificReturn := fake.getStubReturnsOnCall[len(fake.getStubArgsForCall)] - fake.getStubArgsForCall = append(fake.getStubArgsForCall, struct { - }{}) - stub := fake.GetStubStub - fakeReturns := fake.getStubReturns - fake.recordInvocation("GetStub", []interface{}{}) - fake.getStubMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *TransactionContext) GetStubCallCount() int { - fake.getStubMutex.RLock() - defer fake.getStubMutex.RUnlock() - return len(fake.getStubArgsForCall) -} - -func (fake *TransactionContext) GetStubCalls(stub func() shim.ChaincodeStubInterface) { - fake.getStubMutex.Lock() - defer fake.getStubMutex.Unlock() - fake.GetStubStub = stub -} - -func (fake *TransactionContext) GetStubReturns(result1 shim.ChaincodeStubInterface) { - fake.getStubMutex.Lock() - defer fake.getStubMutex.Unlock() - fake.GetStubStub = nil - fake.getStubReturns = struct { - result1 shim.ChaincodeStubInterface - }{result1} -} - -func (fake *TransactionContext) GetStubReturnsOnCall(i int, result1 shim.ChaincodeStubInterface) { - fake.getStubMutex.Lock() - defer fake.getStubMutex.Unlock() - fake.GetStubStub = nil - if fake.getStubReturnsOnCall == nil { - fake.getStubReturnsOnCall = make(map[int]struct { - result1 shim.ChaincodeStubInterface - }) - } - fake.getStubReturnsOnCall[i] = struct { - result1 shim.ChaincodeStubInterface - }{result1} -} - -func (fake *TransactionContext) Invocations() map[string][][]interface{} { - fake.invocationsMutex.RLock() - defer fake.invocationsMutex.RUnlock() - fake.getClientIdentityMutex.RLock() - defer fake.getClientIdentityMutex.RUnlock() - fake.getStubMutex.RLock() - defer fake.getStubMutex.RUnlock() - copiedInvocations := map[string][][]interface{}{} - for key, value := range fake.invocations { - copiedInvocations[key] = value - } - return copiedInvocations -} - -func (fake *TransactionContext) recordInvocation(key string, args []interface{}) { - fake.invocationsMutex.Lock() - defer fake.invocationsMutex.Unlock() - if fake.invocations == nil { - fake.invocations = map[string][][]interface{}{} - } - if fake.invocations[key] == nil { - fake.invocations[key] = [][]interface{}{} - } - fake.invocations[key] = append(fake.invocations[key], args) -} diff --git a/asset-transfer-basic/chaincode-go/chaincode/smartcontract.go b/asset-transfer-basic/chaincode-go/chaincode/smartcontract.go deleted file mode 100644 index 567067e0..00000000 --- a/asset-transfer-basic/chaincode-go/chaincode/smartcontract.go +++ /dev/null @@ -1,194 +0,0 @@ -package chaincode - -import ( - "encoding/json" - "fmt" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -// SmartContract provides functions for managing an Asset -type SmartContract struct { - contractapi.Contract -} - -// Asset describes basic details of what makes up a simple asset -// Insert struct field in alphabetic order => to achieve determinism across languages -// golang keeps the order when marshal to json but doesn't order automatically -type Asset struct { - AppraisedValue int `json:"AppraisedValue"` - Color string `json:"Color"` - ID string `json:"ID"` - Owner string `json:"Owner"` - Size int `json:"Size"` -} - -// InitLedger adds a base set of assets to the ledger -func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error { - assets := []Asset{ - {ID: "asset1", Color: "blue", Size: 5, Owner: "Tomoko", AppraisedValue: 300}, - {ID: "asset2", Color: "red", Size: 5, Owner: "Brad", AppraisedValue: 400}, - {ID: "asset3", Color: "green", Size: 10, Owner: "Jin Soo", AppraisedValue: 500}, - {ID: "asset4", Color: "yellow", Size: 10, Owner: "Max", AppraisedValue: 600}, - {ID: "asset5", Color: "black", Size: 15, Owner: "Adriana", AppraisedValue: 700}, - {ID: "asset6", Color: "white", Size: 15, Owner: "Michel", AppraisedValue: 800}, - } - - for _, asset := range assets { - assetJSON, err := json.Marshal(asset) - if err != nil { - return err - } - - err = ctx.GetStub().PutState(asset.ID, assetJSON) - if err != nil { - return fmt.Errorf("failed to put to world state. %v", err) - } - } - - return nil -} - -// CreateAsset issues a new asset to the world state with given details. -func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, id string, color string, size int, owner string, appraisedValue int) error { - exists, err := s.AssetExists(ctx, id) - if err != nil { - return err - } - if exists { - return fmt.Errorf("the asset %s already exists", id) - } - - asset := Asset{ - ID: id, - Color: color, - Size: size, - Owner: owner, - AppraisedValue: appraisedValue, - } - assetJSON, err := json.Marshal(asset) - if err != nil { - return err - } - - return ctx.GetStub().PutState(id, assetJSON) -} - -// ReadAsset returns the asset stored in the world state with given id. -func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, id string) (*Asset, error) { - assetJSON, err := ctx.GetStub().GetState(id) - if err != nil { - return nil, fmt.Errorf("failed to read from world state: %v", err) - } - if assetJSON == nil { - return nil, fmt.Errorf("the asset %s does not exist", id) - } - - var asset Asset - err = json.Unmarshal(assetJSON, &asset) - if err != nil { - return nil, err - } - - return &asset, nil -} - -// UpdateAsset updates an existing asset in the world state with provided parameters. -func (s *SmartContract) UpdateAsset(ctx contractapi.TransactionContextInterface, id string, color string, size int, owner string, appraisedValue int) error { - exists, err := s.AssetExists(ctx, id) - if err != nil { - return err - } - if !exists { - return fmt.Errorf("the asset %s does not exist", id) - } - - // overwriting original asset with new asset - asset := Asset{ - ID: id, - Color: color, - Size: size, - Owner: owner, - AppraisedValue: appraisedValue, - } - assetJSON, err := json.Marshal(asset) - if err != nil { - return err - } - - return ctx.GetStub().PutState(id, assetJSON) -} - -// DeleteAsset deletes an given asset from the world state. -func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface, id string) error { - exists, err := s.AssetExists(ctx, id) - if err != nil { - return err - } - if !exists { - return fmt.Errorf("the asset %s does not exist", id) - } - - return ctx.GetStub().DelState(id) -} - -// AssetExists returns true when asset with given ID exists in world state -func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, id string) (bool, error) { - assetJSON, err := ctx.GetStub().GetState(id) - if err != nil { - return false, fmt.Errorf("failed to read from world state: %v", err) - } - - return assetJSON != nil, nil -} - -// TransferAsset updates the owner field of asset with given id in world state, and returns the old owner. -func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) (string, error) { - asset, err := s.ReadAsset(ctx, id) - if err != nil { - return "", err - } - - oldOwner := asset.Owner - asset.Owner = newOwner - - assetJSON, err := json.Marshal(asset) - if err != nil { - return "", err - } - - err = ctx.GetStub().PutState(id, assetJSON) - if err != nil { - return "", err - } - - return oldOwner, nil -} - -// GetAllAssets returns all assets found in world state -func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface) ([]*Asset, error) { - // range query with empty string for startKey and endKey does an - // open-ended query of all assets in the chaincode namespace. - resultsIterator, err := ctx.GetStub().GetStateByRange("", "") - if err != nil { - return nil, err - } - defer resultsIterator.Close() - - var assets []*Asset - for resultsIterator.HasNext() { - queryResponse, err := resultsIterator.Next() - if err != nil { - return nil, err - } - - var asset Asset - err = json.Unmarshal(queryResponse.Value, &asset) - if err != nil { - return nil, err - } - assets = append(assets, &asset) - } - - return assets, nil -} diff --git a/asset-transfer-basic/chaincode-go/chaincode/smartcontract_test.go b/asset-transfer-basic/chaincode-go/chaincode/smartcontract_test.go deleted file mode 100644 index 801611f4..00000000 --- a/asset-transfer-basic/chaincode-go/chaincode/smartcontract_test.go +++ /dev/null @@ -1,184 +0,0 @@ -package chaincode_test - -import ( - "encoding/json" - "fmt" - "testing" - - "github.com/hyperledger/fabric-chaincode-go/v2/shim" - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" - "github.com/hyperledger/fabric-protos-go-apiv2/ledger/queryresult" - "github.com/hyperledger/fabric-samples/asset-transfer-basic/chaincode-go/chaincode" - "github.com/hyperledger/fabric-samples/asset-transfer-basic/chaincode-go/chaincode/mocks" - "github.com/stretchr/testify/require" -) - -//go:generate counterfeiter -o mocks/transaction.go -fake-name TransactionContext . transactionContext -type transactionContext interface { - contractapi.TransactionContextInterface -} - -//go:generate counterfeiter -o mocks/chaincodestub.go -fake-name ChaincodeStub . chaincodeStub -type chaincodeStub interface { - shim.ChaincodeStubInterface -} - -//go:generate counterfeiter -o mocks/statequeryiterator.go -fake-name StateQueryIterator . stateQueryIterator -type stateQueryIterator interface { - shim.StateQueryIteratorInterface -} - -func TestInitLedger(t *testing.T) { - chaincodeStub := &mocks.ChaincodeStub{} - transactionContext := &mocks.TransactionContext{} - transactionContext.GetStubReturns(chaincodeStub) - - assetTransfer := chaincode.SmartContract{} - err := assetTransfer.InitLedger(transactionContext) - require.NoError(t, err) - - chaincodeStub.PutStateReturns(fmt.Errorf("failed inserting key")) - err = assetTransfer.InitLedger(transactionContext) - require.EqualError(t, err, "failed to put to world state. failed inserting key") -} - -func TestCreateAsset(t *testing.T) { - chaincodeStub := &mocks.ChaincodeStub{} - transactionContext := &mocks.TransactionContext{} - transactionContext.GetStubReturns(chaincodeStub) - - assetTransfer := chaincode.SmartContract{} - err := assetTransfer.CreateAsset(transactionContext, "", "", 0, "", 0) - require.NoError(t, err) - - chaincodeStub.GetStateReturns([]byte{}, nil) - err = assetTransfer.CreateAsset(transactionContext, "asset1", "", 0, "", 0) - require.EqualError(t, err, "the asset asset1 already exists") - - chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) - err = assetTransfer.CreateAsset(transactionContext, "asset1", "", 0, "", 0) - require.EqualError(t, err, "failed to read from world state: unable to retrieve asset") -} - -func TestReadAsset(t *testing.T) { - chaincodeStub := &mocks.ChaincodeStub{} - transactionContext := &mocks.TransactionContext{} - transactionContext.GetStubReturns(chaincodeStub) - - expectedAsset := &chaincode.Asset{ID: "asset1"} - bytes, err := json.Marshal(expectedAsset) - require.NoError(t, err) - - chaincodeStub.GetStateReturns(bytes, nil) - assetTransfer := chaincode.SmartContract{} - asset, err := assetTransfer.ReadAsset(transactionContext, "") - require.NoError(t, err) - require.Equal(t, expectedAsset, asset) - - chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) - _, err = assetTransfer.ReadAsset(transactionContext, "") - require.EqualError(t, err, "failed to read from world state: unable to retrieve asset") - - chaincodeStub.GetStateReturns(nil, nil) - asset, err = assetTransfer.ReadAsset(transactionContext, "asset1") - require.EqualError(t, err, "the asset asset1 does not exist") - require.Nil(t, asset) -} - -func TestUpdateAsset(t *testing.T) { - chaincodeStub := &mocks.ChaincodeStub{} - transactionContext := &mocks.TransactionContext{} - transactionContext.GetStubReturns(chaincodeStub) - - expectedAsset := &chaincode.Asset{ID: "asset1"} - bytes, err := json.Marshal(expectedAsset) - require.NoError(t, err) - - chaincodeStub.GetStateReturns(bytes, nil) - assetTransfer := chaincode.SmartContract{} - err = assetTransfer.UpdateAsset(transactionContext, "", "", 0, "", 0) - require.NoError(t, err) - - chaincodeStub.GetStateReturns(nil, nil) - err = assetTransfer.UpdateAsset(transactionContext, "asset1", "", 0, "", 0) - require.EqualError(t, err, "the asset asset1 does not exist") - - chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) - err = assetTransfer.UpdateAsset(transactionContext, "asset1", "", 0, "", 0) - require.EqualError(t, err, "failed to read from world state: unable to retrieve asset") -} - -func TestDeleteAsset(t *testing.T) { - chaincodeStub := &mocks.ChaincodeStub{} - transactionContext := &mocks.TransactionContext{} - transactionContext.GetStubReturns(chaincodeStub) - - asset := &chaincode.Asset{ID: "asset1"} - bytes, err := json.Marshal(asset) - require.NoError(t, err) - - chaincodeStub.GetStateReturns(bytes, nil) - chaincodeStub.DelStateReturns(nil) - assetTransfer := chaincode.SmartContract{} - err = assetTransfer.DeleteAsset(transactionContext, "") - require.NoError(t, err) - - chaincodeStub.GetStateReturns(nil, nil) - err = assetTransfer.DeleteAsset(transactionContext, "asset1") - require.EqualError(t, err, "the asset asset1 does not exist") - - chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) - err = assetTransfer.DeleteAsset(transactionContext, "") - require.EqualError(t, err, "failed to read from world state: unable to retrieve asset") -} - -func TestTransferAsset(t *testing.T) { - chaincodeStub := &mocks.ChaincodeStub{} - transactionContext := &mocks.TransactionContext{} - transactionContext.GetStubReturns(chaincodeStub) - - asset := &chaincode.Asset{ID: "asset1"} - bytes, err := json.Marshal(asset) - require.NoError(t, err) - - chaincodeStub.GetStateReturns(bytes, nil) - assetTransfer := chaincode.SmartContract{} - _, err = assetTransfer.TransferAsset(transactionContext, "", "") - require.NoError(t, err) - - chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) - _, err = assetTransfer.TransferAsset(transactionContext, "", "") - require.EqualError(t, err, "failed to read from world state: unable to retrieve asset") -} - -func TestGetAllAssets(t *testing.T) { - asset := &chaincode.Asset{ID: "asset1"} - bytes, err := json.Marshal(asset) - require.NoError(t, err) - - iterator := &mocks.StateQueryIterator{} - iterator.HasNextReturnsOnCall(0, true) - iterator.HasNextReturnsOnCall(1, false) - iterator.NextReturns(&queryresult.KV{Value: bytes}, nil) - - chaincodeStub := &mocks.ChaincodeStub{} - transactionContext := &mocks.TransactionContext{} - transactionContext.GetStubReturns(chaincodeStub) - - chaincodeStub.GetStateByRangeReturns(iterator, nil) - assetTransfer := &chaincode.SmartContract{} - assets, err := assetTransfer.GetAllAssets(transactionContext) - require.NoError(t, err) - require.Equal(t, []*chaincode.Asset{asset}, assets) - - iterator.HasNextReturns(true) - iterator.NextReturns(nil, fmt.Errorf("failed retrieving next item")) - assets, err = assetTransfer.GetAllAssets(transactionContext) - require.EqualError(t, err, "failed retrieving next item") - require.Nil(t, assets) - - chaincodeStub.GetStateByRangeReturns(nil, fmt.Errorf("failed retrieving all assets")) - assets, err = assetTransfer.GetAllAssets(transactionContext) - require.EqualError(t, err, "failed retrieving all assets") - require.Nil(t, assets) -} diff --git a/asset-transfer-basic/chaincode-go/go.mod b/asset-transfer-basic/chaincode-go/go.mod deleted file mode 100644 index 4eb2ca43..00000000 --- a/asset-transfer-basic/chaincode-go/go.mod +++ /dev/null @@ -1,31 +0,0 @@ -module github.com/hyperledger/fabric-samples/asset-transfer-basic/chaincode-go - -go 1.22.0 - -require ( - github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0 - github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0 - github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 - github.com/stretchr/testify v1.10.0 - google.golang.org/protobuf v1.36.1 -) - -require ( - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xeipuuv/gojsonschema v1.2.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect - google.golang.org/grpc v1.67.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/asset-transfer-basic/chaincode-go/go.sum b/asset-transfer-basic/chaincode-go/go.sum deleted file mode 100644 index 4e0be676..00000000 --- a/asset-transfer-basic/chaincode-go/go.sum +++ /dev/null @@ -1,61 +0,0 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0 h1:IhkHfrl5X/fVnmB6pWeCYCdIJRi9bxj+WTnVN8DtW3c= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0/go.mod h1:PHHaFffjw7p7n9bmCfcm7RqDqYdivNEsJdiNIKZo5Lk= -github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0 h1:rmUoBmciB0GL/miqcbJmJbgp5QTWoJUrZo+CNxrNLF4= -github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0/go.mod h1:FeWeO/jwGjiME7ak3GufqKIcwkejtzrDG4QxbfKydWs= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 h1:YJrd+gMaeY0/vsN0aS0QkEKTivGoUnSRIXxGJ7KI+Pc= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4/go.mod h1:bau/6AJhvEcu9GKKYHlDXAxXKzYNfhP6xu2GXuxEcFk= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= -google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= -google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= -google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/asset-transfer-basic/chaincode-java/.gitattributes b/asset-transfer-basic/chaincode-java/.gitattributes deleted file mode 100644 index 00a51aff..00000000 --- a/asset-transfer-basic/chaincode-java/.gitattributes +++ /dev/null @@ -1,6 +0,0 @@ -# -# https://help.github.com/articles/dealing-with-line-endings/ -# -# These are explicitly windows files and should use crlf -*.bat text eol=crlf - diff --git a/asset-transfer-basic/chaincode-java/.gitignore b/asset-transfer-basic/chaincode-java/.gitignore deleted file mode 100644 index bd6fd304..00000000 --- a/asset-transfer-basic/chaincode-java/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.idea/ -.gradle/ diff --git a/asset-transfer-basic/chaincode-java/Dockerfile b/asset-transfer-basic/chaincode-java/Dockerfile deleted file mode 100755 index c42f3051..00000000 --- a/asset-transfer-basic/chaincode-java/Dockerfile +++ /dev/null @@ -1,31 +0,0 @@ -# the first stage -FROM gradle:8.6-jdk11 AS GRADLE_BUILD - -# copy the build.gradle and src code to the container -COPY src/ src/ -COPY build.gradle ./ - -# Build and package our code -RUN gradle --no-daemon build shadowJar -x checkstyleMain -x checkstyleTest - - -# the second stage of our build just needs the compiled files -FROM openjdk:11-jre -ARG CC_SERVER_PORT=9999 - -# Setup tini to work better handle signals -ENV TINI_VERSION v0.19.0 -ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini -RUN chmod +x /tini - -RUN addgroup --system javauser && useradd -g javauser javauser - -# copy only the artifacts we need from the first stage and discard the rest -COPY --chown=javauser:javauser --from=GRADLE_BUILD /home/gradle/build/libs/chaincode.jar /chaincode.jar -COPY --chown=javauser:javauser docker/docker-entrypoint.sh /docker-entrypoint.sh - -ENV PORT $CC_SERVER_PORT -EXPOSE $CC_SERVER_PORT - -USER javauser -ENTRYPOINT [ "/tini", "--", "/docker-entrypoint.sh" ] diff --git a/asset-transfer-basic/chaincode-java/README.md b/asset-transfer-basic/chaincode-java/README.md deleted file mode 100644 index e069f568..00000000 --- a/asset-transfer-basic/chaincode-java/README.md +++ /dev/null @@ -1,10 +0,0 @@ - -## Basic Asset Transfer - -This sample implements the basic asset transfer scenario, illustrating the use of the Java Contract SDKs to provide a -smart contract as a service. - -To run this chaincode contract locally on a development network, see: - -- [Debugging chaincode as a service](../../test-network-k8s/docs/CHAINCODE_AS_A_SERVICE.md) (Kube test network) -- [End-to-end with the test-network](../../test-network/CHAINCODE_AS_A_SERVICE_TUTORIAL.md#end-to-end-with-the-the-test-network) (Docker compose) diff --git a/asset-transfer-basic/chaincode-java/build.gradle b/asset-transfer-basic/chaincode-java/build.gradle deleted file mode 100644 index d26c3b68..00000000 --- a/asset-transfer-basic/chaincode-java/build.gradle +++ /dev/null @@ -1,92 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -plugins { - id 'com.gradleup.shadow' version '8.3.5' - id 'application' - id 'checkstyle' - id 'jacoco' -} - -group 'org.hyperledger.fabric.samples' -version '1.0-SNAPSHOT' - -dependencies { - - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.+' - implementation 'org.json:json:+' - implementation 'com.owlike:genson:1.6' - testImplementation 'org.junit.jupiter:junit-jupiter:5.10.2' - testImplementation 'org.assertj:assertj-core:3.25.3' - testImplementation 'org.mockito:mockito-core:5.12.0' -} - -repositories { - mavenCentral() - maven { - url 'https://jitpack.io' - } -} - -java { - toolchain { - languageVersion = JavaLanguageVersion.of(11) - } -} - -application { - mainClass = 'org.hyperledger.fabric.contract.ContractRouter' -} - -checkstyle { - toolVersion '8.21' - configFile file("config/checkstyle/checkstyle.xml") -} - -checkstyleMain { - source ='src/main/java' -} - -checkstyleTest { - source ='src/test/java' -} - -jacocoTestReport { - dependsOn test -} - -jacocoTestCoverageVerification { - violationRules { - rule { - limit { - minimum = 0.9 - } - } - } - - finalizedBy jacocoTestReport -} - -test { - useJUnitPlatform() - testLogging { - events "passed", "skipped", "failed" - } -} - -mainClassName = 'org.hyperledger.fabric.contract.ContractRouter' - -shadowJar { - archiveBaseName = 'chaincode' - archiveVersion = '' - archiveClassifier = '' - mergeServiceFiles() - - manifest { - attributes 'Main-Class': 'org.hyperledger.fabric.contract.ContractRouter' - } -} - -check.dependsOn jacocoTestCoverageVerification -installDist.dependsOn check diff --git a/asset-transfer-basic/chaincode-java/config/checkstyle/checkstyle.xml b/asset-transfer-basic/chaincode-java/config/checkstyle/checkstyle.xml deleted file mode 100644 index acd5df44..00000000 --- a/asset-transfer-basic/chaincode-java/config/checkstyle/checkstyle.xml +++ /dev/null @@ -1,171 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/asset-transfer-basic/chaincode-java/config/checkstyle/suppressions.xml b/asset-transfer-basic/chaincode-java/config/checkstyle/suppressions.xml deleted file mode 100644 index 8c44b0a0..00000000 --- a/asset-transfer-basic/chaincode-java/config/checkstyle/suppressions.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/asset-transfer-basic/chaincode-java/docker/docker-entrypoint.sh b/asset-transfer-basic/chaincode-java/docker/docker-entrypoint.sh deleted file mode 100755 index 1ff8e07e..00000000 --- a/asset-transfer-basic/chaincode-java/docker/docker-entrypoint.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash -# -# SPDX-License-Identifier: Apache-2.0 -# -set -euo pipefail -: ${CORE_PEER_TLS_ENABLED:="false"} -: ${DEBUG:="false"} - -if [ "${DEBUG,,}" = "true" ]; then - exec java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0.0.0.0:8000 -jar /chaincode.jar -elif [ "${CORE_PEER_TLS_ENABLED,,}" = "true" ]; then - exec java -jar /chaincode.jar # todo -else - exec java -jar /chaincode.jar -fi - diff --git a/asset-transfer-basic/chaincode-java/gradle/wrapper/gradle-wrapper.jar b/asset-transfer-basic/chaincode-java/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index d64cd4917707c1f8861d8cb53dd15194d4248596..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43462 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 diff --git a/asset-transfer-basic/chaincode-java/gradle/wrapper/gradle-wrapper.properties b/asset-transfer-basic/chaincode-java/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index e2847c82..00000000 --- a/asset-transfer-basic/chaincode-java/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/asset-transfer-basic/chaincode-java/gradlew b/asset-transfer-basic/chaincode-java/gradlew deleted file mode 100755 index 1aa94a42..00000000 --- a/asset-transfer-basic/chaincode-java/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/asset-transfer-basic/chaincode-java/gradlew.bat b/asset-transfer-basic/chaincode-java/gradlew.bat deleted file mode 100644 index 25da30db..00000000 --- a/asset-transfer-basic/chaincode-java/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/asset-transfer-basic/chaincode-java/settings.gradle b/asset-transfer-basic/chaincode-java/settings.gradle deleted file mode 100644 index b8074969..00000000 --- a/asset-transfer-basic/chaincode-java/settings.gradle +++ /dev/null @@ -1,4 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ -rootProject.name = System.getenv('CHAINCODE_NAME') ?: 'basic' \ No newline at end of file diff --git a/asset-transfer-basic/chaincode-java/src/main/java/org/hyperledger/fabric/samples/assettransfer/Asset.java b/asset-transfer-basic/chaincode-java/src/main/java/org/hyperledger/fabric/samples/assettransfer/Asset.java deleted file mode 100644 index 803f22fb..00000000 --- a/asset-transfer-basic/chaincode-java/src/main/java/org/hyperledger/fabric/samples/assettransfer/Asset.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.hyperledger.fabric.samples.assettransfer; - -import java.util.Objects; - -import org.hyperledger.fabric.contract.annotation.DataType; -import org.hyperledger.fabric.contract.annotation.Property; - -import com.owlike.genson.annotation.JsonProperty; - -@DataType() -public final class Asset { - - @Property() - private final String assetID; - - @Property() - private final String color; - - @Property() - private final int size; - - @Property() - private final String owner; - - @Property() - private final int appraisedValue; - - public String getAssetID() { - return assetID; - } - - public String getColor() { - return color; - } - - public int getSize() { - return size; - } - - public String getOwner() { - return owner; - } - - public int getAppraisedValue() { - return appraisedValue; - } - - public Asset(@JsonProperty("assetID") final String assetID, @JsonProperty("color") final String color, - @JsonProperty("size") final int size, @JsonProperty("owner") final String owner, - @JsonProperty("appraisedValue") final int appraisedValue) { - this.assetID = assetID; - this.color = color; - this.size = size; - this.owner = owner; - this.appraisedValue = appraisedValue; - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - - if ((obj == null) || (getClass() != obj.getClass())) { - return false; - } - - Asset other = (Asset) obj; - - return Objects.deepEquals( - new String[] {getAssetID(), getColor(), getOwner()}, - new String[] {other.getAssetID(), other.getColor(), other.getOwner()}) - && - Objects.deepEquals( - new int[] {getSize(), getAppraisedValue()}, - new int[] {other.getSize(), other.getAppraisedValue()}); - } - - @Override - public int hashCode() { - return Objects.hash(getAssetID(), getColor(), getSize(), getOwner(), getAppraisedValue()); - } - - @Override - public String toString() { - return this.getClass().getSimpleName() + "@" + Integer.toHexString(hashCode()) + " [assetID=" + assetID + ", color=" - + color + ", size=" + size + ", owner=" + owner + ", appraisedValue=" + appraisedValue + "]"; - } -} diff --git a/asset-transfer-basic/chaincode-java/src/main/java/org/hyperledger/fabric/samples/assettransfer/AssetTransfer.java b/asset-transfer-basic/chaincode-java/src/main/java/org/hyperledger/fabric/samples/assettransfer/AssetTransfer.java deleted file mode 100644 index 68e3b139..00000000 --- a/asset-transfer-basic/chaincode-java/src/main/java/org/hyperledger/fabric/samples/assettransfer/AssetTransfer.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.hyperledger.fabric.samples.assettransfer; - -import java.util.ArrayList; -import java.util.List; - - -import org.hyperledger.fabric.contract.Context; -import org.hyperledger.fabric.contract.ContractInterface; -import org.hyperledger.fabric.contract.annotation.Contact; -import org.hyperledger.fabric.contract.annotation.Contract; -import org.hyperledger.fabric.contract.annotation.Default; -import org.hyperledger.fabric.contract.annotation.Info; -import org.hyperledger.fabric.contract.annotation.License; -import org.hyperledger.fabric.contract.annotation.Transaction; -import org.hyperledger.fabric.shim.ChaincodeException; -import org.hyperledger.fabric.shim.ChaincodeStub; -import org.hyperledger.fabric.shim.ledger.KeyValue; -import org.hyperledger.fabric.shim.ledger.QueryResultsIterator; - -import com.owlike.genson.Genson; - -@Contract( - name = "basic", - info = @Info( - title = "Asset Transfer", - description = "The hyperlegendary asset transfer", - version = "0.0.1-SNAPSHOT", - license = @License( - name = "Apache 2.0 License", - url = "http://www.apache.org/licenses/LICENSE-2.0.html"), - contact = @Contact( - email = "a.transfer@example.com", - name = "Adrian Transfer", - url = "https://hyperledger.example.com"))) -@Default -public final class AssetTransfer implements ContractInterface { - - private final Genson genson = new Genson(); - - private enum AssetTransferErrors { - ASSET_NOT_FOUND, - ASSET_ALREADY_EXISTS - } - - /** - * Creates some initial assets on the ledger. - * - * @param ctx the transaction context - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public void InitLedger(final Context ctx) { - putAsset(ctx, new Asset("asset1", "blue", 5, "Tomoko", 300)); - putAsset(ctx, new Asset("asset2", "red", 5, "Brad", 400)); - putAsset(ctx, new Asset("asset3", "green", 10, "Jin Soo", 500)); - putAsset(ctx, new Asset("asset4", "yellow", 10, "Max", 600)); - putAsset(ctx, new Asset("asset5", "black", 15, "Adrian", 700)); - putAsset(ctx, new Asset("asset6", "white", 15, "Michel", 700)); - - } - - /** - * Creates a new asset on the ledger. - * - * @param ctx the transaction context - * @param assetID the ID of the new asset - * @param color the color of the new asset - * @param size the size for the new asset - * @param owner the owner of the new asset - * @param appraisedValue the appraisedValue of the new asset - * @return the created asset - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public Asset CreateAsset(final Context ctx, final String assetID, final String color, final int size, - final String owner, final int appraisedValue) { - - if (AssetExists(ctx, assetID)) { - String errorMessage = String.format("Asset %s already exists", assetID); - System.out.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.ASSET_ALREADY_EXISTS.toString()); - } - - return putAsset(ctx, new Asset(assetID, color, size, owner, appraisedValue)); - } - - private Asset putAsset(final Context ctx, final Asset asset) { - // Use Genson to convert the Asset into string, sort it alphabetically and serialize it into a json string - String sortedJson = genson.serialize(asset); - ctx.getStub().putStringState(asset.getAssetID(), sortedJson); - - return asset; - } - - /** - * Retrieves an asset with the specified ID from the ledger. - * - * @param ctx the transaction context - * @param assetID the ID of the asset - * @return the asset found on the ledger if there was one - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public Asset ReadAsset(final Context ctx, final String assetID) { - String assetJSON = ctx.getStub().getStringState(assetID); - - if (assetJSON == null || assetJSON.isEmpty()) { - String errorMessage = String.format("Asset %s does not exist", assetID); - System.out.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.ASSET_NOT_FOUND.toString()); - } - - return genson.deserialize(assetJSON, Asset.class); - } - - /** - * Updates the properties of an asset on the ledger. - * - * @param ctx the transaction context - * @param assetID the ID of the asset being updated - * @param color the color of the asset being updated - * @param size the size of the asset being updated - * @param owner the owner of the asset being updated - * @param appraisedValue the appraisedValue of the asset being updated - * @return the transferred asset - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public Asset UpdateAsset(final Context ctx, final String assetID, final String color, final int size, - final String owner, final int appraisedValue) { - - if (!AssetExists(ctx, assetID)) { - String errorMessage = String.format("Asset %s does not exist", assetID); - System.out.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.ASSET_NOT_FOUND.toString()); - } - - return putAsset(ctx, new Asset(assetID, color, size, owner, appraisedValue)); - } - - /** - * Deletes asset on the ledger. - * - * @param ctx the transaction context - * @param assetID the ID of the asset being deleted - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public void DeleteAsset(final Context ctx, final String assetID) { - if (!AssetExists(ctx, assetID)) { - String errorMessage = String.format("Asset %s does not exist", assetID); - System.out.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.ASSET_NOT_FOUND.toString()); - } - - ctx.getStub().delState(assetID); - } - - /** - * Checks the existence of the asset on the ledger - * - * @param ctx the transaction context - * @param assetID the ID of the asset - * @return boolean indicating the existence of the asset - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public boolean AssetExists(final Context ctx, final String assetID) { - String assetJSON = ctx.getStub().getStringState(assetID); - - return (assetJSON != null && !assetJSON.isEmpty()); - } - - /** - * Changes the owner of a asset on the ledger. - * - * @param ctx the transaction context - * @param assetID the ID of the asset being transferred - * @param newOwner the new owner - * @return the old owner - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public String TransferAsset(final Context ctx, final String assetID, final String newOwner) { - String assetJSON = ctx.getStub().getStringState(assetID); - - if (assetJSON == null || assetJSON.isEmpty()) { - String errorMessage = String.format("Asset %s does not exist", assetID); - System.out.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.ASSET_NOT_FOUND.toString()); - } - - Asset asset = genson.deserialize(assetJSON, Asset.class); - - putAsset(ctx, new Asset(asset.getAssetID(), asset.getColor(), asset.getSize(), newOwner, asset.getAppraisedValue())); - - return asset.getOwner(); - } - - /** - * Retrieves all assets from the ledger. - * - * @param ctx the transaction context - * @return array of assets found on the ledger - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public String GetAllAssets(final Context ctx) { - ChaincodeStub stub = ctx.getStub(); - - List queryResults = new ArrayList<>(); - - // To retrieve all assets from the ledger use getStateByRange with empty startKey & endKey. - // Giving empty startKey & endKey is interpreted as all the keys from beginning to end. - // As another example, if you use startKey = 'asset0', endKey = 'asset9' , - // then getStateByRange will retrieve asset with keys between asset0 (inclusive) and asset9 (exclusive) in lexical order. - QueryResultsIterator results = stub.getStateByRange("", ""); - - for (KeyValue result: results) { - Asset asset = genson.deserialize(result.getStringValue(), Asset.class); - System.out.println(asset); - queryResults.add(asset); - } - - return genson.serialize(queryResults); - } -} diff --git a/asset-transfer-basic/chaincode-java/src/test/java/org/hyperledger/fabric/samples/assettransfer/AssetTest.java b/asset-transfer-basic/chaincode-java/src/test/java/org/hyperledger/fabric/samples/assettransfer/AssetTest.java deleted file mode 100644 index 7da94caa..00000000 --- a/asset-transfer-basic/chaincode-java/src/test/java/org/hyperledger/fabric/samples/assettransfer/AssetTest.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.hyperledger.fabric.samples.assettransfer; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; - -public final class AssetTest { - - @Nested - class Equality { - - @Test - public void isReflexive() { - Asset asset = new Asset("asset1", "Blue", 20, "Guy", 100); - - assertThat(asset).isEqualTo(asset); - } - - @Test - public void isSymmetric() { - Asset assetA = new Asset("asset1", "Blue", 20, "Guy", 100); - Asset assetB = new Asset("asset1", "Blue", 20, "Guy", 100); - - assertThat(assetA).isEqualTo(assetB); - assertThat(assetB).isEqualTo(assetA); - } - - @Test - public void isTransitive() { - Asset assetA = new Asset("asset1", "Blue", 20, "Guy", 100); - Asset assetB = new Asset("asset1", "Blue", 20, "Guy", 100); - Asset assetC = new Asset("asset1", "Blue", 20, "Guy", 100); - - assertThat(assetA).isEqualTo(assetB); - assertThat(assetB).isEqualTo(assetC); - assertThat(assetA).isEqualTo(assetC); - } - - @Test - public void handlesInequality() { - Asset assetA = new Asset("asset1", "Blue", 20, "Guy", 100); - Asset assetB = new Asset("asset2", "Red", 40, "Lady", 200); - - assertThat(assetA).isNotEqualTo(assetB); - } - - @Test - public void handlesOtherObjects() { - Asset assetA = new Asset("asset1", "Blue", 20, "Guy", 100); - String assetB = "not a asset"; - - assertThat(assetA).isNotEqualTo(assetB); - } - - @Test - public void handlesNull() { - Asset asset = new Asset("asset1", "Blue", 20, "Guy", 100); - - assertThat(asset).isNotEqualTo(null); - } - } - - @Test - public void toStringIdentifiesAsset() { - Asset asset = new Asset("asset1", "Blue", 20, "Guy", 100); - - assertThat(asset.toString()).isEqualTo("Asset@e04f6c53 [assetID=asset1, color=Blue, size=20, owner=Guy, appraisedValue=100]"); - } -} diff --git a/asset-transfer-basic/chaincode-java/src/test/java/org/hyperledger/fabric/samples/assettransfer/AssetTransferTest.java b/asset-transfer-basic/chaincode-java/src/test/java/org/hyperledger/fabric/samples/assettransfer/AssetTransferTest.java deleted file mode 100644 index f54f3b1d..00000000 --- a/asset-transfer-basic/chaincode-java/src/test/java/org/hyperledger/fabric/samples/assettransfer/AssetTransferTest.java +++ /dev/null @@ -1,305 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.hyperledger.fabric.samples.assettransfer; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.ThrowableAssert.catchThrowable; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verifyNoInteractions; -import static org.mockito.Mockito.when; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.hyperledger.fabric.contract.Context; -import org.hyperledger.fabric.shim.ChaincodeException; -import org.hyperledger.fabric.shim.ChaincodeStub; -import org.hyperledger.fabric.shim.ledger.KeyValue; -import org.hyperledger.fabric.shim.ledger.QueryResultsIterator; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.mockito.InOrder; - -public final class AssetTransferTest { - - private static final class MockKeyValue implements KeyValue { - - private final String key; - private final String value; - - MockKeyValue(final String key, final String value) { - super(); - this.key = key; - this.value = value; - } - - @Override - public String getKey() { - return this.key; - } - - @Override - public String getStringValue() { - return this.value; - } - - @Override - public byte[] getValue() { - return this.value.getBytes(); - } - - } - - private static final class MockAssetResultsIterator implements QueryResultsIterator { - - private final List assetList; - - MockAssetResultsIterator() { - super(); - - assetList = new ArrayList(); - - assetList.add(new MockKeyValue("asset1", - "{ \"assetID\": \"asset1\", \"color\": \"blue\", \"size\": 5, \"owner\": \"Tomoko\", \"appraisedValue\": 300 }")); - assetList.add(new MockKeyValue("asset2", - "{ \"assetID\": \"asset2\", \"color\": \"red\", \"size\": 5,\"owner\": \"Brad\", \"appraisedValue\": 400 }")); - assetList.add(new MockKeyValue("asset3", - "{ \"assetID\": \"asset3\", \"color\": \"green\", \"size\": 10,\"owner\": \"Jin Soo\", \"appraisedValue\": 500 }")); - assetList.add(new MockKeyValue("asset4", - "{ \"assetID\": \"asset4\", \"color\": \"yellow\", \"size\": 10,\"owner\": \"Max\", \"appraisedValue\": 600 }")); - assetList.add(new MockKeyValue("asset5", - "{ \"assetID\": \"asset5\", \"color\": \"black\", \"size\": 15,\"owner\": \"Adrian\", \"appraisedValue\": 700 }")); - assetList.add(new MockKeyValue("asset6", - "{ \"assetID\": \"asset6\", \"color\": \"white\", \"size\": 15,\"owner\": \"Michel\", \"appraisedValue\": 800 }")); - } - - @Override - public Iterator iterator() { - return assetList.iterator(); - } - - @Override - public void close() throws Exception { - // do nothing - } - - } - - @Test - public void invokeUnknownTransaction() { - AssetTransfer contract = new AssetTransfer(); - Context ctx = mock(Context.class); - - Throwable thrown = catchThrowable(() -> { - contract.unknownTransaction(ctx); - }); - - assertThat(thrown).isInstanceOf(ChaincodeException.class).hasNoCause() - .hasMessage("Undefined contract method called"); - assertThat(((ChaincodeException) thrown).getPayload()).isEqualTo(null); - - verifyNoInteractions(ctx); - } - - @Nested - class InvokeReadAssetTransaction { - - @Test - public void whenAssetExists() { - AssetTransfer contract = new AssetTransfer(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState("asset1")) - .thenReturn("{ \"assetID\": \"asset1\", \"color\": \"blue\", \"size\": 5, \"owner\": \"Tomoko\", \"appraisedValue\": 300 }"); - - Asset asset = contract.ReadAsset(ctx, "asset1"); - - assertThat(asset).isEqualTo(new Asset("asset1", "blue", 5, "Tomoko", 300)); - } - - @Test - public void whenAssetDoesNotExist() { - AssetTransfer contract = new AssetTransfer(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState("asset1")).thenReturn(""); - - Throwable thrown = catchThrowable(() -> { - contract.ReadAsset(ctx, "asset1"); - }); - - assertThat(thrown).isInstanceOf(ChaincodeException.class).hasNoCause() - .hasMessage("Asset asset1 does not exist"); - assertThat(((ChaincodeException) thrown).getPayload()).isEqualTo("ASSET_NOT_FOUND".getBytes()); - } - } - - @Test - void invokeInitLedgerTransaction() { - AssetTransfer contract = new AssetTransfer(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - - contract.InitLedger(ctx); - - InOrder inOrder = inOrder(stub); - inOrder.verify(stub).putStringState("asset1", "{\"appraisedValue\":300,\"assetID\":\"asset1\",\"color\":\"blue\",\"owner\":\"Tomoko\",\"size\":5}"); - inOrder.verify(stub).putStringState("asset2", "{\"appraisedValue\":400,\"assetID\":\"asset2\",\"color\":\"red\",\"owner\":\"Brad\",\"size\":5}"); - inOrder.verify(stub).putStringState("asset3", "{\"appraisedValue\":500,\"assetID\":\"asset3\",\"color\":\"green\",\"owner\":\"Jin Soo\",\"size\":10}"); - inOrder.verify(stub).putStringState("asset4", "{\"appraisedValue\":600,\"assetID\":\"asset4\",\"color\":\"yellow\",\"owner\":\"Max\",\"size\":10}"); - inOrder.verify(stub).putStringState("asset5", "{\"appraisedValue\":700,\"assetID\":\"asset5\",\"color\":\"black\",\"owner\":\"Adrian\",\"size\":15}"); - - } - - @Nested - class InvokeCreateAssetTransaction { - - @Test - public void whenAssetExists() { - AssetTransfer contract = new AssetTransfer(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState("asset1")) - .thenReturn("{ \"assetID\": \"asset1\", \"color\": \"blue\", \"size\": 5, \"owner\": \"Tomoko\", \"appraisedValue\": 300 }"); - - Throwable thrown = catchThrowable(() -> { - contract.CreateAsset(ctx, "asset1", "blue", 45, "Siobhán", 60); - }); - - assertThat(thrown).isInstanceOf(ChaincodeException.class).hasNoCause() - .hasMessage("Asset asset1 already exists"); - assertThat(((ChaincodeException) thrown).getPayload()).isEqualTo("ASSET_ALREADY_EXISTS".getBytes()); - } - - @Test - public void whenAssetDoesNotExist() { - AssetTransfer contract = new AssetTransfer(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState("asset1")).thenReturn(""); - - Asset asset = contract.CreateAsset(ctx, "asset1", "blue", 45, "Siobhán", 60); - - assertThat(asset).isEqualTo(new Asset("asset1", "blue", 45, "Siobhán", 60)); - } - } - - @Test - void invokeGetAllAssetsTransaction() { - AssetTransfer contract = new AssetTransfer(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStateByRange("", "")).thenReturn(new MockAssetResultsIterator()); - - String assets = contract.GetAllAssets(ctx); - - assertThat(assets).isEqualTo("[{\"appraisedValue\":300,\"assetID\":\"asset1\",\"color\":\"blue\",\"owner\":\"Tomoko\",\"size\":5}," - + "{\"appraisedValue\":400,\"assetID\":\"asset2\",\"color\":\"red\",\"owner\":\"Brad\",\"size\":5}," - + "{\"appraisedValue\":500,\"assetID\":\"asset3\",\"color\":\"green\",\"owner\":\"Jin Soo\",\"size\":10}," - + "{\"appraisedValue\":600,\"assetID\":\"asset4\",\"color\":\"yellow\",\"owner\":\"Max\",\"size\":10}," - + "{\"appraisedValue\":700,\"assetID\":\"asset5\",\"color\":\"black\",\"owner\":\"Adrian\",\"size\":15}," - + "{\"appraisedValue\":800,\"assetID\":\"asset6\",\"color\":\"white\",\"owner\":\"Michel\",\"size\":15}]"); - - } - - @Nested - class TransferAssetTransaction { - - @Test - public void whenAssetExists() { - AssetTransfer contract = new AssetTransfer(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState("asset1")) - .thenReturn("{ \"assetID\": \"asset1\", \"color\": \"blue\", \"size\": 5, \"owner\": \"Tomoko\", \"appraisedValue\": 300 }"); - - String oldOwner = contract.TransferAsset(ctx, "asset1", "Dr Evil"); - - assertThat(oldOwner).isEqualTo("Tomoko"); - } - - @Test - public void whenAssetDoesNotExist() { - AssetTransfer contract = new AssetTransfer(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState("asset1")).thenReturn(""); - - Throwable thrown = catchThrowable(() -> { - contract.TransferAsset(ctx, "asset1", "Dr Evil"); - }); - - assertThat(thrown).isInstanceOf(ChaincodeException.class).hasNoCause() - .hasMessage("Asset asset1 does not exist"); - assertThat(((ChaincodeException) thrown).getPayload()).isEqualTo("ASSET_NOT_FOUND".getBytes()); - } - } - - @Nested - class UpdateAssetTransaction { - - @Test - public void whenAssetExists() { - AssetTransfer contract = new AssetTransfer(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState("asset1")) - .thenReturn("{ \"assetID\": \"asset1\", \"color\": \"blue\", \"size\": 45, \"owner\": \"Arturo\", \"appraisedValue\": 60 }"); - - Asset asset = contract.UpdateAsset(ctx, "asset1", "pink", 45, "Arturo", 600); - - assertThat(asset).isEqualTo(new Asset("asset1", "pink", 45, "Arturo", 600)); - } - - @Test - public void whenAssetDoesNotExist() { - AssetTransfer contract = new AssetTransfer(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState("asset1")).thenReturn(""); - - Throwable thrown = catchThrowable(() -> { - contract.TransferAsset(ctx, "asset1", "Alex"); - }); - - assertThat(thrown).isInstanceOf(ChaincodeException.class).hasNoCause() - .hasMessage("Asset asset1 does not exist"); - assertThat(((ChaincodeException) thrown).getPayload()).isEqualTo("ASSET_NOT_FOUND".getBytes()); - } - } - - @Nested - class DeleteAssetTransaction { - - @Test - public void whenAssetDoesNotExist() { - AssetTransfer contract = new AssetTransfer(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState("asset1")).thenReturn(""); - - Throwable thrown = catchThrowable(() -> { - contract.DeleteAsset(ctx, "asset1"); - }); - - assertThat(thrown).isInstanceOf(ChaincodeException.class).hasNoCause() - .hasMessage("Asset asset1 does not exist"); - assertThat(((ChaincodeException) thrown).getPayload()).isEqualTo("ASSET_NOT_FOUND".getBytes()); - } - } -} diff --git a/asset-transfer-basic/chaincode-javascript/.eslintignore b/asset-transfer-basic/chaincode-javascript/.eslintignore deleted file mode 100644 index 15958470..00000000 --- a/asset-transfer-basic/chaincode-javascript/.eslintignore +++ /dev/null @@ -1,5 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -coverage diff --git a/asset-transfer-basic/chaincode-javascript/.eslintrc.js b/asset-transfer-basic/chaincode-javascript/.eslintrc.js deleted file mode 100644 index 555c0cf5..00000000 --- a/asset-transfer-basic/chaincode-javascript/.eslintrc.js +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -module.exports = { - env: { - node: true, - mocha: true, - es6: true - }, - parserOptions: { - ecmaVersion: 8, - sourceType: 'script' - }, - extends: "eslint:recommended", - rules: { - indent: ['error', 4], - 'linebreak-style': ['error', 'unix'], - quotes: ['error', 'single'], - semi: ['error', 'always'], - 'no-unused-vars': ['error', { args: 'none' }], - 'no-console': 'off', - curly: 'error', - eqeqeq: 'error', - 'no-throw-literal': 'error', - strict: 'error', - 'no-var': 'error', - 'dot-notation': 'error', - 'no-tabs': 'error', - 'no-trailing-spaces': 'error', - 'no-use-before-define': 'error', - 'no-useless-call': 'error', - 'no-with': 'error', - 'operator-linebreak': 'error', - yoda: 'error', - 'quote-props': ['error', 'as-needed'], - 'no-constant-condition': ["error", { "checkLoops": false }] - } -}; diff --git a/asset-transfer-basic/chaincode-javascript/.gitignore b/asset-transfer-basic/chaincode-javascript/.gitignore deleted file mode 100644 index eeace290..00000000 --- a/asset-transfer-basic/chaincode-javascript/.gitignore +++ /dev/null @@ -1,15 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -# Coverage directory used by tools like istanbul -coverage - -# Report cache used by istanbul -.nyc_output - -# Dependency directories -node_modules/ -jspm_packages/ - -package-lock.json diff --git a/asset-transfer-basic/chaincode-javascript/index.js b/asset-transfer-basic/chaincode-javascript/index.js deleted file mode 100644 index 55a0dcfb..00000000 --- a/asset-transfer-basic/chaincode-javascript/index.js +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const assetTransfer = require('./lib/assetTransfer'); - -module.exports.AssetTransfer = assetTransfer; -module.exports.contracts = [assetTransfer]; diff --git a/asset-transfer-basic/chaincode-javascript/lib/assetTransfer.js b/asset-transfer-basic/chaincode-javascript/lib/assetTransfer.js deleted file mode 100644 index a68b75c6..00000000 --- a/asset-transfer-basic/chaincode-javascript/lib/assetTransfer.js +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -// Deterministic JSON.stringify() -const stringify = require('json-stringify-deterministic'); -const sortKeysRecursive = require('sort-keys-recursive'); -const { Contract } = require('fabric-contract-api'); - -class AssetTransfer extends Contract { - - async InitLedger(ctx) { - const assets = [ - { - ID: 'asset1', - Color: 'blue', - Size: 5, - Owner: 'Tomoko', - AppraisedValue: 300, - }, - { - ID: 'asset2', - Color: 'red', - Size: 5, - Owner: 'Brad', - AppraisedValue: 400, - }, - { - ID: 'asset3', - Color: 'green', - Size: 10, - Owner: 'Jin Soo', - AppraisedValue: 500, - }, - { - ID: 'asset4', - Color: 'yellow', - Size: 10, - Owner: 'Max', - AppraisedValue: 600, - }, - { - ID: 'asset5', - Color: 'black', - Size: 15, - Owner: 'Adriana', - AppraisedValue: 700, - }, - { - ID: 'asset6', - Color: 'white', - Size: 15, - Owner: 'Michel', - AppraisedValue: 800, - }, - ]; - - for (const asset of assets) { - asset.docType = 'asset'; - // example of how to write to world state deterministically - // use convetion of alphabetic order - // we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive' - // when retrieving data, in any lang, the order of data will be the same and consequently also the corresonding hash - await ctx.stub.putState(asset.ID, Buffer.from(stringify(sortKeysRecursive(asset)))); - } - } - - // CreateAsset issues a new asset to the world state with given details. - async CreateAsset(ctx, id, color, size, owner, appraisedValue) { - const exists = await this.AssetExists(ctx, id); - if (exists) { - throw new Error(`The asset ${id} already exists`); - } - - const asset = { - ID: id, - Color: color, - Size: size, - Owner: owner, - AppraisedValue: appraisedValue, - }; - // we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive' - await ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(asset)))); - return JSON.stringify(asset); - } - - // ReadAsset returns the asset stored in the world state with given id. - async ReadAsset(ctx, id) { - const assetJSON = await ctx.stub.getState(id); // get the asset from chaincode state - if (!assetJSON || assetJSON.length === 0) { - throw new Error(`The asset ${id} does not exist`); - } - return assetJSON.toString(); - } - - // UpdateAsset updates an existing asset in the world state with provided parameters. - async UpdateAsset(ctx, id, color, size, owner, appraisedValue) { - const exists = await this.AssetExists(ctx, id); - if (!exists) { - throw new Error(`The asset ${id} does not exist`); - } - - // overwriting original asset with new asset - const updatedAsset = { - ID: id, - Color: color, - Size: size, - Owner: owner, - AppraisedValue: appraisedValue, - }; - // we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive' - return ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(updatedAsset)))); - } - - // DeleteAsset deletes an given asset from the world state. - async DeleteAsset(ctx, id) { - const exists = await this.AssetExists(ctx, id); - if (!exists) { - throw new Error(`The asset ${id} does not exist`); - } - return ctx.stub.deleteState(id); - } - - // AssetExists returns true when asset with given ID exists in world state. - async AssetExists(ctx, id) { - const assetJSON = await ctx.stub.getState(id); - return assetJSON && assetJSON.length > 0; - } - - // TransferAsset updates the owner field of asset with given id in the world state. - async TransferAsset(ctx, id, newOwner) { - const assetString = await this.ReadAsset(ctx, id); - const asset = JSON.parse(assetString); - const oldOwner = asset.Owner; - asset.Owner = newOwner; - // we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive' - await ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(asset)))); - return oldOwner; - } - - // GetAllAssets returns all assets found in the world state. - async GetAllAssets(ctx) { - const allResults = []; - // range query with empty string for startKey and endKey does an open-ended query of all assets in the chaincode namespace. - const iterator = await ctx.stub.getStateByRange('', ''); - let result = await iterator.next(); - while (!result.done) { - const strValue = Buffer.from(result.value.value.toString()).toString('utf8'); - let record; - try { - record = JSON.parse(strValue); - } catch (err) { - console.log(err); - record = strValue; - } - allResults.push(record); - result = await iterator.next(); - } - return JSON.stringify(allResults); - } -} - -module.exports = AssetTransfer; diff --git a/asset-transfer-basic/chaincode-javascript/npm-shrinkwrap.json b/asset-transfer-basic/chaincode-javascript/npm-shrinkwrap.json deleted file mode 100644 index ee1170c7..00000000 --- a/asset-transfer-basic/chaincode-javascript/npm-shrinkwrap.json +++ /dev/null @@ -1,4025 +0,0 @@ -{ - "name": "asset-transfer-basic", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "asset-transfer-basic", - "version": "1.0.0", - "license": "Apache-2.0", - "dependencies": { - "fabric-contract-api": "~2.5", - "fabric-shim": "~2.5", - "json-stringify-deterministic": "^1.0.0", - "sort-keys-recursive": "^2.1.0" - }, - "devDependencies": { - "chai": "^4.4.1", - "eslint": "^8.57.0", - "mocha": "^10.4.0", - "nyc": "^15.1.0", - "sinon": "^18.0.0", - "sinon-chai": "^3.7.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.24.7", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.7.tgz", - "integrity": "sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz", - "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helpers": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/@babel/generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", - "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz", - "integrity": "sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "browserslist": "^4.22.2", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", - "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", - "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", - "dev": true, - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", - "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz", - "integrity": "sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", - "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", - "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz", - "integrity": "sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.7.tgz", - "integrity": "sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", - "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/template": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", - "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", - "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", - "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@colors/colors": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", - "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@dabh/diagnostics": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", - "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", - "dependencies": { - "colorspace": "1.1.x", - "enabled": "2.0.x", - "kuler": "^2.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", - "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@fidm/asn1": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@fidm/asn1/-/asn1-1.0.4.tgz", - "integrity": "sha512-esd1jyNvRb2HVaQGq2Gg8Z0kbQPXzV9Tq5Z14KNIov6KfFD6PTaRIO8UpcsYiTNzOqJpmyzWgVTrUwFV3UF4TQ==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@fidm/x509": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@fidm/x509/-/x509-1.2.1.tgz", - "integrity": "sha512-nwc2iesjyc9hkuzcrMCBXQRn653XuAUKorfWM8PZyJawiy1QzLj4vahwzaI25+pfpwOLvMzbJ0uKpWLDNmo16w==", - "dependencies": { - "@fidm/asn1": "^1.0.4", - "tweetnacl": "^1.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@grpc/grpc-js": { - "version": "1.10.9", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.10.9.tgz", - "integrity": "sha512-5tcgUctCG0qoNyfChZifz2tJqbRbXVO9J7X6duFcOjY3HUNCxg5D0ZCK7EP9vIcZ0zRpLU9bWkyCqVCLZ46IbQ==", - "dependencies": { - "@grpc/proto-loader": "^0.7.13", - "@js-sdsl/ordered-map": "^4.4.2" - }, - "engines": { - "node": ">=12.10.0" - } - }, - "node_modules/@grpc/proto-loader": { - "version": "0.7.13", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", - "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", - "dependencies": { - "lodash.camelcase": "^4.3.0", - "long": "^5.0.0", - "protobufjs": "^7.2.5", - "yargs": "^17.7.2" - }, - "bin": { - "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true - }, - "node_modules/@hyperledger/fabric-protos": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@hyperledger/fabric-protos/-/fabric-protos-0.2.1.tgz", - "integrity": "sha512-qjm0vIQIfCall804tWDeA8p/mUfu14sl5Sj+PbOn2yDKJq+7ThoIhNsLAqf+BCxUfqsoqQq6AojhqQeTFyOOqg==", - "dependencies": { - "@grpc/grpc-js": "^1.9.0", - "google-protobuf": "^3.21.0" - }, - "engines": { - "node": ">=14.15.0" - } - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@js-sdsl/ordered-map": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", - "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" - }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", - "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, - "node_modules/@sinonjs/samsam": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", - "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^2.0.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" - } - }, - "node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/text-encoding": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", - "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", - "dev": true - }, - "node_modules/@types/node": { - "version": "16.18.98", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.98.tgz", - "integrity": "sha512-fpiC20NvLpTLAzo3oVBKIqBGR6Fx/8oAK/SSf7G+fydnXMY1x4x9RZ6sBXhqKlCU21g2QapUsbLlhv3+a7wS+Q==" - }, - "node_modules/@types/triple-beam": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", - "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/append-transform": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", - "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", - "dev": true, - "dependencies": { - "default-require-extensions": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", - "dev": true - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "node_modules/browserslist": { - "version": "4.23.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.1.tgz", - "integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001629", - "electron-to-chromium": "^1.4.796", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.16" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/caching-transform": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", - "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", - "dev": true, - "dependencies": { - "hasha": "^5.0.0", - "make-dir": "^3.0.0", - "package-hash": "^4.0.0", - "write-file-atomic": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001633", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001633.tgz", - "integrity": "sha512-6sT0yf/z5jqf8tISAgpJDrmwOpLsrpnyCdD/lOZKvKkkJK4Dn0X5i7KF7THEZhOq+30bmhwBlNEaqPUiHiKtZg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/chai": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", - "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", - "dev": true, - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.0.8" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/class-transformer": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.4.0.tgz", - "integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==" - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/color": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", - "dependencies": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/color/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/colorspace": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", - "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", - "dependencies": { - "color": "^3.1.3", - "text-hex": "1.0.x" - } - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/deep-eql": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", - "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", - "dev": true, - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/default-require-extensions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", - "integrity": "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==", - "dev": true, - "dependencies": { - "strip-bom": "^4.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.802", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.802.tgz", - "integrity": "sha512-TnTMUATbgNdPXVSHsxvNVSG0uEd6cSZsANjm8c9HbvflZVVn1yTRcmVXYT1Ma95/ssB/Dcd30AHweH2TE+dNpA==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/enabled": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", - "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" - }, - "node_modules/es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true - }, - "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fabric-contract-api": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/fabric-contract-api/-/fabric-contract-api-2.5.6.tgz", - "integrity": "sha512-AosGb8tA+Jgt+pqMEgYNB3/J/P5QuWOC7yhXbhDmAAwUzn4Sc7pdWDICH1YyrFGZNFxMGQmqJmLVWUX8BKHy0w==", - "dependencies": { - "class-transformer": "^0.4.0", - "fabric-shim-api": "2.5.6", - "fast-safe-stringify": "^2.1.1", - "get-params": "^0.1.2", - "reflect-metadata": "^0.1.13", - "winston": "^3.7.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/fabric-shim": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/fabric-shim/-/fabric-shim-2.5.6.tgz", - "integrity": "sha512-4Y8WNFhYuQ9QYSEgPXWdlXnrXjwOlM10sQQzE4kJ7cDh8a4LX0rn44FxtxTCB18lnzrSLMZ8/8Cr5m0c9NeXWA==", - "dependencies": { - "@fidm/x509": "^1.2.1", - "@grpc/grpc-js": "~1.10.9", - "@hyperledger/fabric-protos": "~0.2.1", - "@types/node": "^16.11.1", - "ajv": "^6.12.2", - "fabric-contract-api": "2.5.6", - "fabric-shim-api": "2.5.6", - "fast-safe-stringify": "^2.1.1", - "long": "^5.2.3", - "reflect-metadata": "^0.1.13", - "winston": "^3.7.2", - "yargs": "^17.4.0", - "yargs-parser": "^21.0.1" - }, - "bin": { - "fabric-chaincode-node": "cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/fabric-shim-api": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/fabric-shim-api/-/fabric-shim-api-2.5.6.tgz", - "integrity": "sha512-1L0nO7CJ31/gEOWKWHEeCqgB5HkqPVfRbpcS7L9eTscT7tffjg2OkZISvC+a7RiqihL0iyrXNBgBg5MwlSSN9g==", - "engines": { - "eslint": "^6.6.0", - "node": ">=18" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fecha": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "node_modules/fn.name": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", - "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" - }, - "node_modules/foreground-child": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/fromentries": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", - "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-params": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/get-params/-/get-params-0.1.2.tgz", - "integrity": "sha512-41eOxtlGgHQRbFyA8KTH+w+32Em3cRdfBud7j67ulzmIfmaHX9doq47s0fa4P5o9H64BZX9nrYI6sJvk46Op+Q==" - }, - "node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/google-protobuf": { - "version": "3.21.2", - "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz", - "integrity": "sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==" - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/hasha": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", - "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", - "dev": true, - "dependencies": { - "is-stream": "^2.0.0", - "type-fest": "^0.8.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/hasha/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/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, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "node_modules/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==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-hook": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", - "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", - "dev": true, - "dependencies": { - "append-transform": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, - "dependencies": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-processinfo": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz", - "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==", - "dev": true, - "dependencies": { - "archy": "^1.0.0", - "cross-spawn": "^7.0.3", - "istanbul-lib-coverage": "^3.2.0", - "p-map": "^3.0.0", - "rimraf": "^3.0.0", - "uuid": "^8.3.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-report/node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/istanbul-lib-report/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", - "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json-stringify-deterministic": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/json-stringify-deterministic/-/json-stringify-deterministic-1.0.12.tgz", - "integrity": "sha512-q3PN0lbUdv0pmurkBNdJH3pfFvOTL/Zp0lquqpvcjfKzt6Y0j49EPHAmVHCAS4Ceq/Y+PejWTzyiVpoY71+D6g==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/just-extend": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", - "integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==", - "dev": true - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/kuler": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" - }, - "node_modules/lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", - "dev": true - }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/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, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/logform": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", - "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", - "dependencies": { - "@colors/colors": "1.6.0", - "@types/triple-beam": "^1.3.2", - "fecha": "^4.2.0", - "ms": "^2.1.1", - "safe-stable-stringify": "^2.3.1", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/long": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" - }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.1" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mocha": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.4.0.tgz", - "integrity": "sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA==", - "dev": true, - "dependencies": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "8.1.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/mocha/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/mocha/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/mocha/node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/mocha/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/nise": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/nise/-/nise-6.0.0.tgz", - "integrity": "sha512-K8ePqo9BFvN31HXwEtTNGzgrPpmvgciDsFz8aztFjt4LqKO/JeFD8tBOeuDiCMXrIl/m1YvfH8auSpxfaD09wg==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.0", - "@sinonjs/fake-timers": "^11.2.2", - "@sinonjs/text-encoding": "^0.7.2", - "just-extend": "^6.2.0", - "path-to-regexp": "^6.2.1" - } - }, - "node_modules/node-preload": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", - "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", - "dev": true, - "dependencies": { - "process-on-spawn": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nyc": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", - "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", - "dev": true, - "dependencies": { - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "caching-transform": "^4.0.0", - "convert-source-map": "^1.7.0", - "decamelize": "^1.2.0", - "find-cache-dir": "^3.2.0", - "find-up": "^4.1.0", - "foreground-child": "^2.0.0", - "get-package-type": "^0.1.0", - "glob": "^7.1.6", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-hook": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "make-dir": "^3.0.0", - "node-preload": "^0.2.1", - "p-map": "^3.0.0", - "process-on-spawn": "^1.0.0", - "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "spawn-wrap": "^2.0.0", - "test-exclude": "^6.0.0", - "yargs": "^15.0.2" - }, - "bin": { - "nyc": "bin/nyc.js" - }, - "engines": { - "node": ">=8.9" - } - }, - "node_modules/nyc/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/nyc/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/nyc/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nyc/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "node_modules/nyc/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/one-time": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", - "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", - "dependencies": { - "fn.name": "1.x.x" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/package-hash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", - "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.15", - "hasha": "^5.0.0", - "lodash.flattendeep": "^4.4.0", - "release-zalgo": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-to-regexp": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz", - "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==", - "dev": true - }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/process-on-spawn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", - "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", - "dev": true, - "dependencies": { - "fromentries": "^1.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/protobufjs": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.2.tgz", - "integrity": "sha512-RXyHaACeqXeqAKGLDl68rQKbmObRsTIn4TYVUUug1KfS47YWCo5MacGITEryugIgZqORCvJWEk4l449POg5Txg==", - "hasInstallScript": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/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, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/reflect-metadata": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", - "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==" - }, - "node_modules/release-zalgo": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", - "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==", - "dev": true, - "dependencies": { - "es6-error": "^4.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safe-stable-stringify": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", - "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", - "engines": { - "node": ">=10" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/sinon": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-18.0.0.tgz", - "integrity": "sha512-+dXDXzD1sBO6HlmZDd7mXZCR/y5ECiEiGCBSGuFD/kZ0bDTofPYc6JaeGmPSF+1j1MejGUWkORbYOLDyvqCWpA==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.1", - "@sinonjs/fake-timers": "^11.2.2", - "@sinonjs/samsam": "^8.0.0", - "diff": "^5.2.0", - "nise": "^6.0.0", - "supports-color": "^7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/sinon" - } - }, - "node_modules/sinon-chai": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.7.0.tgz", - "integrity": "sha512-mf5NURdUaSdnatJx3uhoBOrY9dtL19fiOtAdT1Azxg3+lNJFiuN0uzaU3xX1LeAfL17kHQhTAJgpsfhbMJMY2g==", - "dev": true, - "peerDependencies": { - "chai": "^4.0.0", - "sinon": ">=4.0.0" - } - }, - "node_modules/sinon/node_modules/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/sort-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-4.2.0.tgz", - "integrity": "sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg==", - "dependencies": { - "is-plain-obj": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/sort-keys-recursive": { - "version": "2.1.10", - "resolved": "https://registry.npmjs.org/sort-keys-recursive/-/sort-keys-recursive-2.1.10.tgz", - "integrity": "sha512-yRLJbEER/PjU7hSRwXvP+NyXiORufu8rbSbp+3wFRuJZXoi/AhuKczbjuipqn7Le0SsTXK4VUeri2+Ni6WS8Hg==", - "dependencies": { - "kind-of": "~6.0.2", - "sort-keys": "~4.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/spawn-wrap": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", - "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", - "dev": true, - "dependencies": { - "foreground-child": "^2.0.0", - "is-windows": "^1.0.2", - "make-dir": "^3.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "which": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", - "engines": { - "node": "*" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/test-exclude/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/text-hex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/triple-beam": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", - "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/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, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", - "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-module": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", - "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", - "dev": true - }, - "node_modules/winston": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.13.0.tgz", - "integrity": "sha512-rwidmA1w3SE4j0E5MuIufFhyJPBDG7Nu71RkZor1p2+qHvJSZ9GYDA81AyleQcZbh/+V6HjeBdfnTZJm9rSeQQ==", - "dependencies": { - "@colors/colors": "^1.6.0", - "@dabh/diagnostics": "^2.0.2", - "async": "^3.2.3", - "is-stream": "^2.0.0", - "logform": "^2.4.0", - "one-time": "^1.0.0", - "readable-stream": "^3.4.0", - "safe-stable-stringify": "^2.3.1", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.7.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/winston-transport": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz", - "integrity": "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==", - "dependencies": { - "logform": "^2.3.2", - "readable-stream": "^3.6.0", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yargs-unparser/node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/asset-transfer-basic/chaincode-javascript/package.json b/asset-transfer-basic/chaincode-javascript/package.json deleted file mode 100644 index b4ea1317..00000000 --- a/asset-transfer-basic/chaincode-javascript/package.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "name": "asset-transfer-basic", - "version": "1.0.0", - "description": "Asset-Transfer-Basic contract implemented in JavaScript", - "main": "index.js", - "engines": { - "node": ">=18" - }, - "scripts": { - "lint": "eslint *.js */**.js", - "pretest": "npm run lint", - "test": "nyc mocha --recursive", - "start": "fabric-chaincode-node start" - }, - "engineStrict": true, - "author": "Hyperledger", - "license": "Apache-2.0", - "dependencies": { - "fabric-contract-api": "~2.5", - "fabric-shim": "~2.5", - "json-stringify-deterministic": "^1.0.0", - "sort-keys-recursive": "^2.1.0" - }, - "devDependencies": { - "chai": "^4.4.1", - "eslint": "^8.57.0", - "mocha": "^10.4.0", - "nyc": "^15.1.0", - "sinon": "^18.0.0", - "sinon-chai": "^3.7.0" - }, - "nyc": { - "exclude": [ - "coverage/**", - "test/**", - "index.js", - ".eslintrc.js" - ], - "reporter": [ - "text-summary", - "html" - ], - "all": true, - "check-coverage": true, - "statements": 100, - "branches": 100, - "functions": 100, - "lines": 100 - } -} diff --git a/asset-transfer-basic/chaincode-javascript/test/assetTransfer.test.js b/asset-transfer-basic/chaincode-javascript/test/assetTransfer.test.js deleted file mode 100644 index 906b5ff5..00000000 --- a/asset-transfer-basic/chaincode-javascript/test/assetTransfer.test.js +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 -*/ - -'use strict'; -const sinon = require('sinon'); -const chai = require('chai'); -const sinonChai = require('sinon-chai'); -const expect = chai.expect; - -const { Context } = require('fabric-contract-api'); -const { ChaincodeStub } = require('fabric-shim'); - -const AssetTransfer = require('../lib/assetTransfer.js'); - -let assert = sinon.assert; -chai.use(sinonChai); - -describe('Asset Transfer Basic Tests', () => { - let transactionContext, chaincodeStub, asset; - beforeEach(() => { - transactionContext = new Context(); - - chaincodeStub = sinon.createStubInstance(ChaincodeStub); - transactionContext.setChaincodeStub(chaincodeStub); - - chaincodeStub.putState.callsFake((key, value) => { - if (!chaincodeStub.states) { - chaincodeStub.states = {}; - } - chaincodeStub.states[key] = value; - }); - - chaincodeStub.getState.callsFake(async (key) => { - let ret; - if (chaincodeStub.states) { - ret = chaincodeStub.states[key]; - } - return Promise.resolve(ret); - }); - - chaincodeStub.deleteState.callsFake(async (key) => { - if (chaincodeStub.states) { - delete chaincodeStub.states[key]; - } - return Promise.resolve(key); - }); - - chaincodeStub.getStateByRange.callsFake(async () => { - function* internalGetStateByRange() { - if (chaincodeStub.states) { - // Shallow copy - const copied = Object.assign({}, chaincodeStub.states); - - for (let key in copied) { - yield {value: copied[key]}; - } - } - } - - return Promise.resolve(internalGetStateByRange()); - }); - - asset = { - ID: 'asset1', - Color: 'blue', - Size: 5, - Owner: 'Tomoko', - AppraisedValue: 300, - }; - }); - - describe('Test InitLedger', () => { - it('should return error on InitLedger', async () => { - chaincodeStub.putState.rejects('failed inserting key'); - let assetTransfer = new AssetTransfer(); - try { - await assetTransfer.InitLedger(transactionContext); - assert.fail('InitLedger should have failed'); - } catch (err) { - expect(err.name).to.equal('failed inserting key'); - } - }); - - it('should return success on InitLedger', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.InitLedger(transactionContext); - let ret = JSON.parse((await chaincodeStub.getState('asset1')).toString()); - expect(ret).to.eql(Object.assign({docType: 'asset'}, asset)); - }); - }); - - describe('Test CreateAsset', () => { - it('should return error on CreateAsset', async () => { - chaincodeStub.putState.rejects('failed inserting key'); - - let assetTransfer = new AssetTransfer(); - try { - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - assert.fail('CreateAsset should have failed'); - } catch(err) { - expect(err.name).to.equal('failed inserting key'); - } - }); - - it('should return success on CreateAsset', async () => { - let assetTransfer = new AssetTransfer(); - - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - let ret = JSON.parse((await chaincodeStub.getState(asset.ID)).toString()); - expect(ret).to.eql(asset); - }); - }); - - describe('Test ReadAsset', () => { - it('should return error on ReadAsset', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - try { - await assetTransfer.ReadAsset(transactionContext, 'asset2'); - assert.fail('ReadAsset should have failed'); - } catch (err) { - expect(err.message).to.equal('The asset asset2 does not exist'); - } - }); - - it('should return success on ReadAsset', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - let ret = JSON.parse(await chaincodeStub.getState(asset.ID)); - expect(ret).to.eql(asset); - }); - }); - - describe('Test UpdateAsset', () => { - it('should return error on UpdateAsset', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - try { - await assetTransfer.UpdateAsset(transactionContext, 'asset2', 'orange', 10, 'Me', 500); - assert.fail('UpdateAsset should have failed'); - } catch (err) { - expect(err.message).to.equal('The asset asset2 does not exist'); - } - }); - - it('should return success on UpdateAsset', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - await assetTransfer.UpdateAsset(transactionContext, 'asset1', 'orange', 10, 'Me', 500); - let ret = JSON.parse(await chaincodeStub.getState(asset.ID)); - let expected = { - ID: 'asset1', - Color: 'orange', - Size: 10, - Owner: 'Me', - AppraisedValue: 500 - }; - expect(ret).to.eql(expected); - }); - }); - - describe('Test DeleteAsset', () => { - it('should return error on DeleteAsset', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - try { - await assetTransfer.DeleteAsset(transactionContext, 'asset2'); - assert.fail('DeleteAsset should have failed'); - } catch (err) { - expect(err.message).to.equal('The asset asset2 does not exist'); - } - }); - - it('should return success on DeleteAsset', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - await assetTransfer.DeleteAsset(transactionContext, asset.ID); - let ret = await chaincodeStub.getState(asset.ID); - expect(ret).to.equal(undefined); - }); - }); - - describe('Test TransferAsset', () => { - it('should return error on TransferAsset', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - try { - await assetTransfer.TransferAsset(transactionContext, 'asset2', 'Me'); - assert.fail('DeleteAsset should have failed'); - } catch (err) { - expect(err.message).to.equal('The asset asset2 does not exist'); - } - }); - - it('should return success on TransferAsset', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - await assetTransfer.TransferAsset(transactionContext, asset.ID, 'Me'); - let ret = JSON.parse((await chaincodeStub.getState(asset.ID)).toString()); - expect(ret).to.eql(Object.assign({}, asset, {Owner: 'Me'})); - }); - }); - - describe('Test GetAllAssets', () => { - it('should return success on GetAllAssets', async () => { - let assetTransfer = new AssetTransfer(); - - await assetTransfer.CreateAsset(transactionContext, 'asset1', 'blue', 5, 'Robert', 100); - await assetTransfer.CreateAsset(transactionContext, 'asset2', 'orange', 10, 'Paul', 200); - await assetTransfer.CreateAsset(transactionContext, 'asset3', 'red', 15, 'Troy', 300); - await assetTransfer.CreateAsset(transactionContext, 'asset4', 'pink', 20, 'Van', 400); - - let ret = await assetTransfer.GetAllAssets(transactionContext); - ret = JSON.parse(ret); - expect(ret.length).to.equal(4); - - let expected = [ - {ID: 'asset1', Color: 'blue', Size: 5, Owner: 'Robert', AppraisedValue: 100}, - {ID: 'asset2', Color: 'orange', Size: 10, Owner: 'Paul', AppraisedValue: 200}, - {ID: 'asset3', Color: 'red', Size: 15, Owner: 'Troy', AppraisedValue: 300}, - {ID: 'asset4', Color: 'pink', Size: 20, Owner: 'Van', AppraisedValue: 400} - ]; - - expect(ret).to.eql(expected); - }); - - it('should return success on GetAllAssets for non JSON value', async () => { - let assetTransfer = new AssetTransfer(); - - chaincodeStub.putState.onFirstCall().callsFake((key, value) => { - if (!chaincodeStub.states) { - chaincodeStub.states = {}; - } - chaincodeStub.states[key] = 'non-json-value'; - }); - - await assetTransfer.CreateAsset(transactionContext, 'asset1', 'blue', 5, 'Robert', 100); - await assetTransfer.CreateAsset(transactionContext, 'asset2', 'orange', 10, 'Paul', 200); - await assetTransfer.CreateAsset(transactionContext, 'asset3', 'red', 15, 'Troy', 300); - await assetTransfer.CreateAsset(transactionContext, 'asset4', 'pink', 20, 'Van', 400); - - let ret = await assetTransfer.GetAllAssets(transactionContext); - ret = JSON.parse(ret); - expect(ret.length).to.equal(4); - - let expected = [ - 'non-json-value', - {ID: 'asset2', Color: 'orange', Size: 10, Owner: 'Paul', AppraisedValue: 200}, - {ID: 'asset3', Color: 'red', Size: 15, Owner: 'Troy', AppraisedValue: 300}, - {ID: 'asset4', Color: 'pink', Size: 20, Owner: 'Van', AppraisedValue: 400} - ]; - - expect(ret).to.eql(expected); - }); - }); -}); diff --git a/asset-transfer-basic/chaincode-typescript/src/asset.ts b/asset-transfer-basic/chaincode-typescript/src/asset.ts deleted file mode 100644 index 8845ab03..00000000 --- a/asset-transfer-basic/chaincode-typescript/src/asset.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - SPDX-License-Identifier: Apache-2.0 -*/ - -import {Object, Property} from 'fabric-contract-api'; - -@Object() -export class Asset { - @Property() - public docType?: string; - - @Property() - public ID: string = ''; - - @Property() - public Color: string = ''; - - @Property() - public Size: number = 0; - - @Property() - public Owner: string = ''; - - @Property() - public AppraisedValue: number = 0; -} diff --git a/asset-transfer-basic/chaincode-typescript/src/assetTransfer.ts b/asset-transfer-basic/chaincode-typescript/src/assetTransfer.ts deleted file mode 100644 index d3ed927a..00000000 --- a/asset-transfer-basic/chaincode-typescript/src/assetTransfer.ts +++ /dev/null @@ -1,173 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ -// Deterministic JSON.stringify() -import {Context, Contract, Info, Returns, Transaction} from 'fabric-contract-api'; -import stringify from 'json-stringify-deterministic'; -import sortKeysRecursive from 'sort-keys-recursive'; -import {Asset} from './asset'; - -@Info({title: 'AssetTransfer', description: 'Smart contract for trading assets'}) -export class AssetTransferContract extends Contract { - - @Transaction() - public async InitLedger(ctx: Context): Promise { - const assets: Asset[] = [ - { - ID: 'asset1', - Color: 'blue', - Size: 5, - Owner: 'Tomoko', - AppraisedValue: 300, - }, - { - ID: 'asset2', - Color: 'red', - Size: 5, - Owner: 'Brad', - AppraisedValue: 400, - }, - { - ID: 'asset3', - Color: 'green', - Size: 10, - Owner: 'Jin Soo', - AppraisedValue: 500, - }, - { - ID: 'asset4', - Color: 'yellow', - Size: 10, - Owner: 'Max', - AppraisedValue: 600, - }, - { - ID: 'asset5', - Color: 'black', - Size: 15, - Owner: 'Adriana', - AppraisedValue: 700, - }, - { - ID: 'asset6', - Color: 'white', - Size: 15, - Owner: 'Michel', - AppraisedValue: 800, - }, - ]; - - for (const asset of assets) { - asset.docType = 'asset'; - // example of how to write to world state deterministically - // use convetion of alphabetic order - // we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive' - // when retrieving data, in any lang, the order of data will be the same and consequently also the corresonding hash - await ctx.stub.putState(asset.ID, Buffer.from(stringify(sortKeysRecursive(asset)))); - console.info(`Asset ${asset.ID} initialized`); - } - } - - // CreateAsset issues a new asset to the world state with given details. - @Transaction() - public async CreateAsset(ctx: Context, id: string, color: string, size: number, owner: string, appraisedValue: number): Promise { - const exists = await this.AssetExists(ctx, id); - if (exists) { - throw new Error(`The asset ${id} already exists`); - } - - const asset = { - ID: id, - Color: color, - Size: size, - Owner: owner, - AppraisedValue: appraisedValue, - }; - // we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive' - await ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(asset)))); - } - - // ReadAsset returns the asset stored in the world state with given id. - @Transaction(false) - public async ReadAsset(ctx: Context, id: string): Promise { - const assetJSON = await ctx.stub.getState(id); // get the asset from chaincode state - if (assetJSON.length === 0) { - throw new Error(`The asset ${id} does not exist`); - } - return assetJSON.toString(); - } - - // UpdateAsset updates an existing asset in the world state with provided parameters. - @Transaction() - public async UpdateAsset(ctx: Context, id: string, color: string, size: number, owner: string, appraisedValue: number): Promise { - const exists = await this.AssetExists(ctx, id); - if (!exists) { - throw new Error(`The asset ${id} does not exist`); - } - - // overwriting original asset with new asset - const updatedAsset = { - ID: id, - Color: color, - Size: size, - Owner: owner, - AppraisedValue: appraisedValue, - }; - // we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive' - return ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(updatedAsset)))); - } - - // DeleteAsset deletes an given asset from the world state. - @Transaction() - public async DeleteAsset(ctx: Context, id: string): Promise { - const exists = await this.AssetExists(ctx, id); - if (!exists) { - throw new Error(`The asset ${id} does not exist`); - } - return ctx.stub.deleteState(id); - } - - // AssetExists returns true when asset with given ID exists in world state. - @Transaction(false) - @Returns('boolean') - public async AssetExists(ctx: Context, id: string): Promise { - const assetJSON = await ctx.stub.getState(id); - return assetJSON.length > 0; - } - - // TransferAsset updates the owner field of asset with given id in the world state, and returns the old owner. - @Transaction() - public async TransferAsset(ctx: Context, id: string, newOwner: string): Promise { - const assetString = await this.ReadAsset(ctx, id); - const asset = JSON.parse(assetString) as Asset; - const oldOwner = asset.Owner; - asset.Owner = newOwner; - // we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive' - await ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(asset)))); - return oldOwner; - } - - // GetAllAssets returns all assets found in the world state. - @Transaction(false) - @Returns('string') - public async GetAllAssets(ctx: Context): Promise { - const allResults = []; - // range query with empty string for startKey and endKey does an open-ended query of all assets in the chaincode namespace. - const iterator = await ctx.stub.getStateByRange('', ''); - let result = await iterator.next(); - while (!result.done) { - const strValue = Buffer.from(result.value.value.toString()).toString('utf8'); - let record; - try { - record = JSON.parse(strValue) as Asset; - } catch (err) { - console.log(err); - record = strValue; - } - allResults.push(record); - result = await iterator.next(); - } - return JSON.stringify(allResults); - } - -} diff --git a/asset-transfer-basic/chaincode-typescript/src/assetTransferCustom.ts b/asset-transfer-basic/chaincode-typescript/src/assetTransferCustom.ts new file mode 100644 index 00000000..40d8fcd9 --- /dev/null +++ b/asset-transfer-basic/chaincode-typescript/src/assetTransferCustom.ts @@ -0,0 +1,253 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ +// Deterministic JSON.stringify() +import {Context, Contract, Info, Returns, Transaction} from 'fabric-contract-api'; +import stringify from 'json-stringify-deterministic'; +import sortKeysRecursive from 'sort-keys-recursive'; +import {Asset, Student, Department, Certificate} from './customAsset'; +import { createHash } from 'node:crypto'; + +@Info({title: 'AssetTransfer', description: 'Smart contract for trading assets'}) +export class AssetTransferCustomContract extends Contract { + + @Transaction() + public async InitLedger(ctx: Context): Promise { + const assets: Student[] = []; + + for (const asset of assets) { + asset.docType = 'asset'; + // example of how to write to world state deterministically + // use convetion of alphabetic order + // we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive' + // when retrieving data, in any lang, the order of data will be the same and consequently also the corresonding hash + await ctx.stub.putState(asset.RollNo, Buffer.from(stringify(sortKeysRecursive(asset)))); + console.info(`Asset ${asset.RollNo} initialized`); + } + } + + // ReadAsset returns the asset stored in the world state with given id. + @Transaction(false) + public async ReadAsset(ctx: Context, id: string): Promise { + const assetJSON = await ctx.stub.getState(id); // get the asset from chaincode state + if (assetJSON.length === 0) { + throw new Error(`The asset ${id} does not exist`); + } + return assetJSON.toString(); + } + + + // DeleteAsset deletes an given asset from the world state. + @Transaction() + public async DeleteAsset(ctx: Context, id: string): Promise { + const exists = await this.AssetExists(ctx, id); + if (!exists) { + throw new Error(`The asset ${id} does not exist`); + } + return ctx.stub.deleteState(id); + } + + // AssetExists returns true when asset with given ID exists in world state. + @Transaction(false) + @Returns('boolean') + public async AssetExists(ctx: Context, id: string): Promise { + const assetJSON = await ctx.stub.getState(id); + return assetJSON.length > 0; + } + + // GetAllAssets returns all assets found in the world state. + @Transaction(false) + @Returns('string') + public async GetAllAssets(ctx: Context): Promise { + const allResults = []; + // range query with empty string for startKey and endKey does an open-ended query of all assets in the chaincode namespace. + const iterator = await ctx.stub.getStateByRange('', ''); + let result = await iterator.next(); + while (!result.done) { + const strValue = Buffer.from(result.value.value.toString()).toString('utf8'); + let record; + try { + record = JSON.parse(strValue) as Asset; + } catch (err) { + console.log(err); + record = strValue; + } + allResults.push(record); + result = await iterator.next(); + } + return JSON.stringify(allResults); + } + + @Transaction() + public async CreateStudentData(ctx: Context, rollNo:string, name:string): Promise { + const exists = await this.AssetExists(ctx, "Studenet"+rollNo); + if (exists) { + throw new Error(`The asset ${rollNo} already exists`); + } + + const asset: Student = { + ID: 'Student' + rollNo, + docType: 'Student', + RollNo: rollNo, + Name: name, + Marks: {}, + DepartmentID: '' + }; + + await ctx.stub.putState(asset.ID, Buffer.from(stringify(sortKeysRecursive(asset)))); + } + + @Transaction() + public async CreateDept(ctx: Context, deptName:string, year:number): Promise { + const exists = await this.AssetExists(ctx, 'Department'+deptName + year); + if (exists) { + throw new Error(`The asset ${deptName + year} already exists`); + } + + const department: Department = { + ID: 'Department' + deptName + year, + docType: 'Department', + DeptID: deptName + year, + DeptName: deptName, + Year: year, + Subject: [], + RollNos: [] + }; + + await ctx.stub.putState(department.ID, Buffer.from(stringify(sortKeysRecursive(department)))); + } + + @Transaction() + public async deptAddSubject(ctx: Context, deptID:string, subject:string): Promise { + const exists = await this.AssetExists(ctx,"Department"+ deptID); + if (!exists) { + throw new Error(`The asset ${deptID} already exists`); + } + + const dept: Department = JSON.parse(await this.ReadAsset(ctx,"Department"+ deptID)); + + const new_dept: Department = { + ID: dept.ID, + docType: dept.docType, + DeptID: dept.DeptID, + DeptName: dept.DeptName, + Subject: [...dept.Subject, subject], + RollNos: dept.RollNos, + Year: dept.Year + }; + + await ctx.stub.putState(new_dept.ID, Buffer.from(stringify(sortKeysRecursive(new_dept)))); + + } + + @Transaction() + public async deptAddStudent(ctx: Context, deptID:string, rollNo:string): Promise { + const exists = await this.AssetExists(ctx,"Department"+ deptID); + if (!exists) { + throw new Error(`The Department ${deptID} doesnt exists`); + } + + const dept: Department = JSON.parse(await this.ReadAsset(ctx,"Department"+deptID)); + const student: Student = JSON.parse(await this.ReadAsset(ctx, "Student"+rollNo)) + + const new_stud: Student = { + ID: student.ID, + docType: student.docType, + RollNo: student.RollNo, + Name: student.Name, + DepartmentID: deptID, + Marks: student.Marks + } + + const new_dept: Department = { + ID: dept.ID, + docType: dept.docType, + DeptID: dept.DeptID, + DeptName: dept.DeptName, + Subject: dept.Subject, + RollNos: [...dept.RollNos,rollNo], + Year: dept.Year + }; + + await ctx.stub.putState(new_stud.ID, Buffer.from(stringify(sortKeysRecursive(new_dept)))); + await ctx.stub.putState(new_dept.ID, Buffer.from(stringify(sortKeysRecursive(new_dept)))); + } + + @Transaction() + public async addStudentMark(ctx: Context, rollNo: string, subjectG: string, mark: number): Promise { + const exists = await this.AssetExists(ctx,"Student" + rollNo); + if (!exists) { + throw new Error(`The asset ${rollNo} already exists`); + } + + const student: Student = JSON.parse(await this.ReadAsset(ctx,"Student"+ rollNo)); + + ctx.clientIdentity.assertAttributeValue + + const newStudent: Student = { + ID: student.ID, + docType: student.docType, + RollNo: student.RollNo, + Name: student.Name, + Marks: {...student.Marks,[subjectG] : mark}, + DepartmentID: student.DepartmentID + }; + + await ctx.stub.putState(newStudent.ID, Buffer.from(stringify(sortKeysRecursive(newStudent)))); + } + + @Transaction(false) + public async getStudent(ctx: Context, rollNo: string) + { + const exists = await this.AssetExists(ctx, "Student"+rollNo); + if (!exists) { + throw new Error(`The asset doest exists`); + } + const student = await this.ReadAsset(ctx,"Student"+rollNo); + + return JSON.stringify(student) + + } + + @Transaction() + public async addCertificate(ctx: Context, name: string, event: string, links: string): Promise { + + const hash = createHash('sha256') + + hash.update(name+event+links) + + const hashStr: string = hash.copy().digest('hex'); + + const exists = await this.AssetExists(ctx,"Certificate" + hashStr); + if (exists) { + throw new Error(`The asset ${hashStr} already exists`); + } + + + const newCertificate: Certificate = { + ID: 'Certificate' + hashStr, + Name: name, + Event: event, + Links: links, + docType: 'Certificate' + } + + + await ctx.stub.putState(newCertificate.ID, Buffer.from(stringify(sortKeysRecursive(newCertificate)))); + + return hashStr; + } + + @Transaction(false) + public async validateCertificate(ctx: Context, hashStr: string): Promise { + const assetJSON = await ctx.stub.getState('Certificate'+hashStr); // get the asset from chaincode state + if (assetJSON.length === 0) { + throw new Error(`The Certificate does not exist`); + } + return assetJSON.toString(); + } + + + + +} diff --git a/asset-transfer-basic/chaincode-typescript/src/customAsset.ts b/asset-transfer-basic/chaincode-typescript/src/customAsset.ts new file mode 100644 index 00000000..cd60cae7 --- /dev/null +++ b/asset-transfer-basic/chaincode-typescript/src/customAsset.ts @@ -0,0 +1,90 @@ +/* + SPDX-License-Identifier: Apache-2.0 +*/ + +import {Object, Property} from 'fabric-contract-api'; + +@Object() +export class Asset { + @Property() + public docType?: string; + + @Property() + public ID: string = ''; + + @Property() + public Name:string = ''; + + @Property() + public DOB: string = ''; + + @Property() + public Marks: number = 0; +} + + +@Object() +export class Student{ + + @Property() + public ID: string = ''; + + @Property() + public docType:string = 'Student'; + + @Property() + public RollNo: string = ''; + + @Property() + public Name: string = ''; + + @Property() + public Marks: object = {}; + + @Property() + public DepartmentID:string = ''; +} + +@Object() +export class Department{ + + @Property() + public ID: string = ''; + + @Property() + public docType:string = 'Department'; + + @Property() + public DeptID: string = ''; + + @Property() + public DeptName: string = ''; + + @Property() + public Year: number = 0; + + @Property() + public Subject: string[] = []; + + @Property() + public RollNos: string[] = []; +} + +@Object() +export class Certificate{ + + @Property() + public ID: string = ''; + + @Property() + public docType:string = 'Certificate'; + + @Property() + public Name:string = ''; + + @Property() + public Event:string = ''; + + @Property() + public Links:string = ''; +} diff --git a/asset-transfer-basic/chaincode-typescript/src/index.ts b/asset-transfer-basic/chaincode-typescript/src/index.ts index 87166997..7d6a6914 100644 --- a/asset-transfer-basic/chaincode-typescript/src/index.ts +++ b/asset-transfer-basic/chaincode-typescript/src/index.ts @@ -3,6 +3,6 @@ */ import {type Contract} from 'fabric-contract-api'; -import {AssetTransferContract} from './assetTransfer'; +import {AssetTransferCustomContract} from './assetTransferCustom'; -export const contracts: typeof Contract[] = [AssetTransferContract]; +export const contracts: typeof Contract[] = [AssetTransferCustomContract]; diff --git a/asset-transfer-basic/rest-api-go/.gitignore b/asset-transfer-basic/rest-api-go/.gitignore deleted file mode 100644 index b264572c..00000000 --- a/asset-transfer-basic/rest-api-go/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -Requests.http -rest-api-go \ No newline at end of file diff --git a/asset-transfer-basic/rest-api-go/README.md b/asset-transfer-basic/rest-api-go/README.md deleted file mode 100644 index 331411b7..00000000 --- a/asset-transfer-basic/rest-api-go/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# Asset Transfer REST API Sample - -This is a simple REST server written in golang with endpoints for chaincode invoke and query. - - -## Usage - -- Setup fabric test network and deploy the asset transfer chaincode by [following this instructions](https://hyperledger-fabric.readthedocs.io/en/release-2.4/test_network.html). - -- cd into rest-api-go directory -- Download required dependencies using `go mod download` -- Run `go run main.go` to run the REST server - -## Sending Requests - -Invoke endpoint accepts POST requests with chaincode function and arguments. Query endpoint accepts get requests with chaincode function and arguments. - -Sample chaincode invoke for the "createAsset" function. Response will contain transaction ID for a successful invoke. - -``` sh -curl --request POST \ - --url http://localhost:3000/invoke \ - --header 'content-type: application/x-www-form-urlencoded' \ - --data = \ - --data channelid=mychannel \ - --data chaincodeid=basic \ - --data function=createAsset \ - --data args=Asset123 \ - --data args=yellow \ - --data args=54 \ - --data args=Tom \ - --data args=13005 -``` -Sample chaincode query for getting asset details. - -``` sh -curl --request GET \ - --url 'http://localhost:3000/query?channelid=mychannel&chaincodeid=basic&function=ReadAsset&args=Asset123' - ``` diff --git a/asset-transfer-basic/rest-api-go/go.mod b/asset-transfer-basic/rest-api-go/go.mod deleted file mode 100644 index 8324149c..00000000 --- a/asset-transfer-basic/rest-api-go/go.mod +++ /dev/null @@ -1,19 +0,0 @@ -module rest-api-go - -go 1.22.0 - -require ( - github.com/hyperledger/fabric-gateway v1.7.0 - google.golang.org/grpc v1.67.1 -) - -require ( - github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 // indirect - github.com/miekg/pkcs11 v1.1.1 // indirect - golang.org/x/crypto v0.28.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.26.0 // indirect - golang.org/x/text v0.19.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect - google.golang.org/protobuf v1.35.1 // indirect -) diff --git a/asset-transfer-basic/rest-api-go/go.sum b/asset-transfer-basic/rest-api-go/go.sum deleted file mode 100644 index 01eab6a8..00000000 --- a/asset-transfer-basic/rest-api-go/go.sum +++ /dev/null @@ -1,32 +0,0 @@ -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hyperledger/fabric-gateway v1.7.0 h1:bd1quU8qYPYqYO69m1tPIDSjB+D+u/rBJfE1eWFcpjY= -github.com/hyperledger/fabric-gateway v1.7.0/go.mod h1:TItDGnq71eJcgz5TW+m5Sq3kWGp0AEI1HPCNxj0Eu7k= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 h1:YJrd+gMaeY0/vsN0aS0QkEKTivGoUnSRIXxGJ7KI+Pc= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4/go.mod h1:bau/6AJhvEcu9GKKYHlDXAxXKzYNfhP6xu2GXuxEcFk= -github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= -github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= -golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= -google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= -google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/asset-transfer-basic/rest-api-go/main.go b/asset-transfer-basic/rest-api-go/main.go deleted file mode 100644 index ff349991..00000000 --- a/asset-transfer-basic/rest-api-go/main.go +++ /dev/null @@ -1,26 +0,0 @@ -package main - -import ( - "fmt" - "rest-api-go/web" -) - -func main() { - //Initialize setup for Org1 - cryptoPath := "../../test-network/organizations/peerOrganizations/org1.example.com" - orgConfig := web.OrgSetup{ - OrgName: "Org1", - MSPID: "Org1MSP", - CertPath: cryptoPath + "/users/User1@org1.example.com/msp/signcerts/cert.pem", - KeyPath: cryptoPath + "/users/User1@org1.example.com/msp/keystore/", - TLSCertPath: cryptoPath + "/peers/peer0.org1.example.com/tls/ca.crt", - PeerEndpoint: "dns:///localhost:7051", - GatewayPeer: "peer0.org1.example.com", - } - - orgSetup, err := web.Initialize(orgConfig) - if err != nil { - fmt.Println("Error initializing setup for Org1: ", err) - } - web.Serve(web.OrgSetup(*orgSetup)) -} diff --git a/asset-transfer-basic/rest-api-go/web/app.go b/asset-transfer-basic/rest-api-go/web/app.go deleted file mode 100644 index b8d8c1b3..00000000 --- a/asset-transfer-basic/rest-api-go/web/app.go +++ /dev/null @@ -1,31 +0,0 @@ -package web - -import ( - "fmt" - "net/http" - - "github.com/hyperledger/fabric-gateway/pkg/client" -) - -// OrgSetup contains organization's config to interact with the network. -type OrgSetup struct { - OrgName string - MSPID string - CryptoPath string - CertPath string - KeyPath string - TLSCertPath string - PeerEndpoint string - GatewayPeer string - Gateway client.Gateway -} - -// Serve starts http web server. -func Serve(setups OrgSetup) { - http.HandleFunc("/query", setups.Query) - http.HandleFunc("/invoke", setups.Invoke) - fmt.Println("Listening (http://localhost:3000/)...") - if err := http.ListenAndServe(":3000", nil); err != nil { - fmt.Println(err) - } -} diff --git a/asset-transfer-basic/rest-api-go/web/initialize.go b/asset-transfer-basic/rest-api-go/web/initialize.go deleted file mode 100644 index a14d1b15..00000000 --- a/asset-transfer-basic/rest-api-go/web/initialize.go +++ /dev/null @@ -1,108 +0,0 @@ -package web - -import ( - "crypto/x509" - "fmt" - "log" - "os" - "path" - "time" - - "github.com/hyperledger/fabric-gateway/pkg/client" - "github.com/hyperledger/fabric-gateway/pkg/hash" - "github.com/hyperledger/fabric-gateway/pkg/identity" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" -) - -// Initialize the setup for the organization. -func Initialize(setup OrgSetup) (*OrgSetup, error) { - log.Printf("Initializing connection for %s...\n", setup.OrgName) - clientConnection := setup.newGrpcConnection() - id := setup.newIdentity() - sign := setup.newSign() - - gateway, err := client.Connect( - id, - client.WithSign(sign), - client.WithHash(hash.SHA256), - client.WithClientConnection(clientConnection), - client.WithEvaluateTimeout(5*time.Second), - client.WithEndorseTimeout(15*time.Second), - client.WithSubmitTimeout(5*time.Second), - client.WithCommitStatusTimeout(1*time.Minute), - ) - if err != nil { - panic(err) - } - setup.Gateway = *gateway - log.Println("Initialization complete") - return &setup, nil -} - -// newGrpcConnection creates a gRPC connection to the Gateway server. -func (setup OrgSetup) newGrpcConnection() *grpc.ClientConn { - certificate, err := loadCertificate(setup.TLSCertPath) - if err != nil { - panic(err) - } - - certPool := x509.NewCertPool() - certPool.AddCert(certificate) - transportCredentials := credentials.NewClientTLSFromCert(certPool, setup.GatewayPeer) - - connection, err := grpc.NewClient(setup.PeerEndpoint, grpc.WithTransportCredentials(transportCredentials)) - if err != nil { - panic(fmt.Errorf("failed to create gRPC connection: %w", err)) - } - - return connection -} - -// newIdentity creates a client identity for this Gateway connection using an X.509 certificate. -func (setup OrgSetup) newIdentity() *identity.X509Identity { - certificate, err := loadCertificate(setup.CertPath) - if err != nil { - panic(err) - } - - id, err := identity.NewX509Identity(setup.MSPID, certificate) - if err != nil { - panic(err) - } - - return id -} - -// newSign creates a function that generates a digital signature from a message digest using a private key. -func (setup OrgSetup) newSign() identity.Sign { - files, err := os.ReadDir(setup.KeyPath) - if err != nil { - panic(fmt.Errorf("failed to read private key directory: %w", err)) - } - privateKeyPEM, err := os.ReadFile(path.Join(setup.KeyPath, files[0].Name())) - - if err != nil { - panic(fmt.Errorf("failed to read private key file: %w", err)) - } - - privateKey, err := identity.PrivateKeyFromPEM(privateKeyPEM) - if err != nil { - panic(err) - } - - sign, err := identity.NewPrivateKeySign(privateKey) - if err != nil { - panic(err) - } - - return sign -} - -func loadCertificate(filename string) (*x509.Certificate, error) { - certificatePEM, err := os.ReadFile(filename) - if err != nil { - return nil, fmt.Errorf("failed to read certificate file: %w", err) - } - return identity.CertificateFromPEM(certificatePEM) -} diff --git a/asset-transfer-basic/rest-api-go/web/invoke.go b/asset-transfer-basic/rest-api-go/web/invoke.go deleted file mode 100644 index f2907d58..00000000 --- a/asset-transfer-basic/rest-api-go/web/invoke.go +++ /dev/null @@ -1,40 +0,0 @@ -package web - -import ( - "fmt" - "net/http" - - "github.com/hyperledger/fabric-gateway/pkg/client" -) - -// Invoke handles chaincode invoke requests. -func (setup *OrgSetup) Invoke(w http.ResponseWriter, r *http.Request) { - fmt.Println("Received Invoke request") - if err := r.ParseForm(); err != nil { - fmt.Fprintf(w, "ParseForm() err: %s", err) - return - } - chainCodeName := r.FormValue("chaincodeid") - channelID := r.FormValue("channelid") - function := r.FormValue("function") - args := r.Form["args"] - fmt.Printf("channel: %s, chaincode: %s, function: %s, args: %s\n", channelID, chainCodeName, function, args) - network := setup.Gateway.GetNetwork(channelID) - contract := network.GetContract(chainCodeName) - txn_proposal, err := contract.NewProposal(function, client.WithArguments(args...)) - if err != nil { - fmt.Fprintf(w, "Error creating txn proposal: %s", err) - return - } - txn_endorsed, err := txn_proposal.Endorse() - if err != nil { - fmt.Fprintf(w, "Error endorsing txn: %s", err) - return - } - txn_committed, err := txn_endorsed.Submit() - if err != nil { - fmt.Fprintf(w, "Error submitting transaction: %s", err) - return - } - fmt.Fprintf(w, "Transaction ID : %s Response: %s", txn_committed.TransactionID(), txn_endorsed.Result()) -} diff --git a/asset-transfer-basic/rest-api-go/web/query.go b/asset-transfer-basic/rest-api-go/web/query.go deleted file mode 100644 index eff1a70a..00000000 --- a/asset-transfer-basic/rest-api-go/web/query.go +++ /dev/null @@ -1,25 +0,0 @@ -package web - -import ( - "fmt" - "net/http" -) - -// Query handles chaincode query requests. -func (setup OrgSetup) Query(w http.ResponseWriter, r *http.Request) { - fmt.Println("Received Query request") - queryParams := r.URL.Query() - chainCodeName := queryParams.Get("chaincodeid") - channelID := queryParams.Get("channelid") - function := queryParams.Get("function") - args := r.URL.Query()["args"] - fmt.Printf("channel: %s, chaincode: %s, function: %s, args: %s\n", channelID, chainCodeName, function, args) - network := setup.Gateway.GetNetwork(channelID) - contract := network.GetContract(chainCodeName) - evaluateResponse, err := contract.EvaluateTransaction(function, args...) - if err != nil { - fmt.Fprintf(w, "Error: %s", err) - return - } - fmt.Fprintf(w, "Response: %s", evaluateResponse) -} diff --git a/asset-transfer-basic/rest-api-typescript/README.md b/asset-transfer-basic/rest-api-typescript/README.md index f5e0953a..0c0a5544 100644 --- a/asset-transfer-basic/rest-api-typescript/README.md +++ b/asset-transfer-basic/rest-api-typescript/README.md @@ -113,7 +113,7 @@ npm run build Create a `.env` file to configure the server for the test network (make sure TEST_NETWORK_HOME is set to the fully qualified `test-network` directory) ```shell -TEST_NETWORK_HOME=$HOME/fabric-samples/test-network npm run generateEnv +TEST_NETWORK_HOME=/home/calvin/go/src/github.com/delete_me0/sandbx/fabric-samples/test-network npm run generateEnv ``` **Note:** see [src/config.ts](src/config.ts) for details of configuring the sample diff --git a/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh b/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh index 626f84b9..f2af8107 100755 --- a/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh +++ b/asset-transfer-basic/rest-api-typescript/scripts/generateEnv.sh @@ -8,12 +8,12 @@ ${AS_LOCAL_HOST:=true} : "${TEST_NETWORK_HOME:=../..}" : "${CONNECTION_PROFILE_FILE_ORG1:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/connection-org1.json}" -: "${CERTIFICATE_FILE_ORG1:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/signcerts/User1@org1.example.com-cert.pem}" -: "${PRIVATE_KEY_FILE_ORG1:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/keystore/priv_sk}" +: "${CERTIFICATE_FILE_ORG1:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/signcerts/*.pem}" +: "${PRIVATE_KEY_FILE_ORG1:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp/keystore/*_sk}" : "${CONNECTION_PROFILE_FILE_ORG2:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org2.example.com/connection-org2.json}" -: "${CERTIFICATE_FILE_ORG2:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org2.example.com/users/User1@org2.example.com/msp/signcerts/User1@org2.example.com-cert.pem}" -: "${PRIVATE_KEY_FILE_ORG2:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org2.example.com/users/User1@org2.example.com/msp/keystore/priv_sk}" +: "${CERTIFICATE_FILE_ORG2:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org2.example.com/users/User1@org2.example.com/msp/signcerts/*.pem}" +: "${PRIVATE_KEY_FILE_ORG2:=${TEST_NETWORK_HOME}/organizations/peerOrganizations/org2.example.com/users/User1@org2.example.com/msp/keystore/*_sk}" cat << ENV_END > .env diff --git a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts index 39cf66dd..c0714b6c 100644 --- a/asset-transfer-basic/rest-api-typescript/src/assets.router.ts +++ b/asset-transfer-basic/rest-api-typescript/src/assets.router.ts @@ -27,6 +27,7 @@ import { AssetNotFoundError } from './errors'; import { evatuateTransaction } from './fabric'; import { addSubmitTransactionJob } from './jobs'; import { logger } from './logger'; +import { createHash } from 'crypto'; const { ACCEPTED, BAD_REQUEST, INTERNAL_SERVER_ERROR, NOT_FOUND, OK } = StatusCodes; @@ -54,15 +55,11 @@ assetsRouter.get('/', async (req: Request, res: Response) => { }); } }); - assetsRouter.post( - '/', + '/student', body().isObject().withMessage('body must contain an asset object'), - body('ID', 'must be a string').notEmpty(), - body('Color', 'must be a string').notEmpty(), - body('Size', 'must be a number').isNumeric(), - body('Owner', 'must be a string').notEmpty(), - body('AppraisedValue', 'must be a number').isNumeric(), + body('RollNo', 'must be a string').notEmpty(), + body('Name', 'must be a string').notEmpty(), async (req: Request, res: Response) => { logger.debug(req.body, 'Create asset request received'); @@ -78,19 +75,16 @@ assetsRouter.post( } const mspId = req.user as string; - const assetId = req.body.ID; + const rollNo = req.body.RollNo; try { const submitQueue = req.app.locals.jobq as Queue; const jobId = await addSubmitTransactionJob( submitQueue, mspId, - 'CreateAsset', - assetId, - req.body.Color, - req.body.Size, - req.body.Owner, - req.body.AppraisedValue + 'CreateStudentData', + rollNo, + req.body.Name ); return res.status(ACCEPTED).json({ @@ -102,7 +96,7 @@ assetsRouter.post( logger.error( { err }, 'Error processing create asset request for asset ID %s', - assetId + rollNo ); return res.status(INTERNAL_SERVER_ERROR).json({ @@ -113,50 +107,6 @@ assetsRouter.post( } ); -assetsRouter.options('/:assetId', async (req: Request, res: Response) => { - const assetId = req.params.assetId; - logger.debug('Asset options request received for asset ID %s', assetId); - - try { - const mspId = req.user as string; - const contract = req.app.locals[mspId]?.assetContract as Contract; - - const data = await evatuateTransaction( - contract, - 'AssetExists', - assetId - ); - const exists = data.toString() === 'true'; - - if (exists) { - return res - .status(OK) - .set({ - Allow: 'DELETE,GET,OPTIONS,PATCH,PUT', - }) - .json({ - status: getReasonPhrase(OK), - timestamp: new Date().toISOString(), - }); - } else { - return res.status(NOT_FOUND).json({ - status: getReasonPhrase(NOT_FOUND), - timestamp: new Date().toISOString(), - }); - } - } catch (err) { - logger.error( - { err }, - 'Error processing asset options request for asset ID %s', - assetId - ); - return res.status(INTERNAL_SERVER_ERROR).json({ - status: getReasonPhrase(INTERNAL_SERVER_ERROR), - timestamp: new Date().toISOString(), - }); - } -}); - assetsRouter.get('/:assetId', async (req: Request, res: Response) => { const assetId = req.params.assetId; logger.debug('Read asset request received for asset ID %s', assetId); @@ -190,134 +140,6 @@ assetsRouter.get('/:assetId', async (req: Request, res: Response) => { } }); -assetsRouter.put( - '/:assetId', - body().isObject().withMessage('body must contain an asset object'), - body('ID', 'must be a string').notEmpty(), - body('Color', 'must be a string').notEmpty(), - body('Size', 'must be a number').isNumeric(), - body('Owner', 'must be a string').notEmpty(), - body('AppraisedValue', 'must be a number').isNumeric(), - async (req: Request, res: Response) => { - logger.debug(req.body, 'Update asset request received'); - - const errors = validationResult(req); - if (!errors.isEmpty()) { - return res.status(BAD_REQUEST).json({ - status: getReasonPhrase(BAD_REQUEST), - reason: 'VALIDATION_ERROR', - message: 'Invalid request body', - timestamp: new Date().toISOString(), - errors: errors.array(), - }); - } - - if (req.params.assetId != req.body.ID) { - return res.status(BAD_REQUEST).json({ - status: getReasonPhrase(BAD_REQUEST), - reason: 'ASSET_ID_MISMATCH', - message: 'Asset IDs must match', - timestamp: new Date().toISOString(), - }); - } - - const mspId = req.user as string; - const assetId = req.params.assetId; - - try { - const submitQueue = req.app.locals.jobq as Queue; - const jobId = await addSubmitTransactionJob( - submitQueue, - mspId, - 'UpdateAsset', - assetId, - req.body.color, - req.body.size, - req.body.owner, - req.body.appraisedValue - ); - - return res.status(ACCEPTED).json({ - status: getReasonPhrase(ACCEPTED), - jobId: jobId, - timestamp: new Date().toISOString(), - }); - } catch (err) { - logger.error( - { err }, - 'Error processing update asset request for asset ID %s', - assetId - ); - - return res.status(INTERNAL_SERVER_ERROR).json({ - status: getReasonPhrase(INTERNAL_SERVER_ERROR), - timestamp: new Date().toISOString(), - }); - } - } -); - -assetsRouter.patch( - '/:assetId', - body() - .isArray({ - min: 1, - max: 1, - }) - .withMessage( - 'body must contain an array with a single patch operation' - ), - body('*.op', "operation must be 'replace'").equals('replace'), - body('*.path', "path must be '/Owner'").equals('/Owner'), - body('*.value', 'must be a string').isString(), - async (req: Request, res: Response) => { - logger.debug(req.body, 'Transfer asset request received'); - - const errors = validationResult(req); - if (!errors.isEmpty()) { - return res.status(BAD_REQUEST).json({ - status: getReasonPhrase(BAD_REQUEST), - reason: 'VALIDATION_ERROR', - message: 'Invalid request body', - timestamp: new Date().toISOString(), - errors: errors.array(), - }); - } - - const mspId = req.user as string; - const assetId = req.params.assetId; - const newOwner = req.body[0].value; - - try { - const submitQueue = req.app.locals.jobq as Queue; - const jobId = await addSubmitTransactionJob( - submitQueue, - mspId, - 'TransferAsset', - assetId, - newOwner - ); - - return res.status(ACCEPTED).json({ - status: getReasonPhrase(ACCEPTED), - jobId: jobId, - timestamp: new Date().toISOString(), - }); - } catch (err) { - logger.error( - { err }, - 'Error processing update asset request for asset ID %s', - req.params.assetId - ); - - return res.status(INTERNAL_SERVER_ERROR).json({ - status: getReasonPhrase(INTERNAL_SERVER_ERROR), - timestamp: new Date().toISOString(), - }); - } - } -); - assetsRouter.delete('/:assetId', async (req: Request, res: Response) => { logger.debug(req.body, 'Delete asset request received'); @@ -351,3 +173,344 @@ assetsRouter.delete('/:assetId', async (req: Request, res: Response) => { }); } }); + +assetsRouter.post( + '/dept', + body().isObject().withMessage('body must contain an asset object'), + body('DeptName', 'must be a string').notEmpty(), + body('Year', 'must be a number').isNumeric(), + async (req: Request, res: Response) => { + logger.debug(req.body, 'Create asset request received'); + + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(BAD_REQUEST).json({ + status: getReasonPhrase(BAD_REQUEST), + reason: 'VALIDATION_ERROR', + message: 'Invalid request body', + timestamp: new Date().toISOString(), + errors: errors.array(), + }); + } + + const mspId = req.user as string; + const assetId = req.body.DeptName; + + try { + const submitQueue = req.app.locals.jobq as Queue; + const jobId = await addSubmitTransactionJob( + submitQueue, + mspId, + 'CreateDept', + assetId, + req.body.Year + ); + + return res.status(ACCEPTED).json({ + status: getReasonPhrase(ACCEPTED), + jobId: jobId, + timestamp: new Date().toISOString(), + }); + } catch (err) { + logger.error( + { err }, + 'Error processing create asset request for asset ID %s', + assetId + ); + + return res.status(INTERNAL_SERVER_ERROR).json({ + status: getReasonPhrase(INTERNAL_SERVER_ERROR), + timestamp: new Date().toISOString(), + }); + } + } +); + +assetsRouter.post( + '/sub', + body().isObject().withMessage('body must contain an asset object'), + body('DeptID', 'must be a string').notEmpty(), + body('Subject', 'must be a string').notEmpty(), + async (req: Request, res: Response) => { + logger.debug(req.body, 'Create asset request received'); + + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(BAD_REQUEST).json({ + status: getReasonPhrase(BAD_REQUEST), + reason: 'VALIDATION_ERROR', + message: 'Invalid request body', + timestamp: new Date().toISOString(), + errors: errors.array(), + }); + } + + const mspId = req.user as string; + const assetId = req.body.DeptID; + + try { + const submitQueue = req.app.locals.jobq as Queue; + const jobId = await addSubmitTransactionJob( + submitQueue, + mspId, + 'deptAddSubject', + assetId, + req.body.Subject + ); + + return res.status(ACCEPTED).json({ + status: getReasonPhrase(ACCEPTED), + jobId: jobId, + timestamp: new Date().toISOString(), + }); + } catch (err) { + logger.error( + { err }, + 'Error processing create asset request for asset ID %s', + assetId + ); + + return res.status(INTERNAL_SERVER_ERROR).json({ + status: getReasonPhrase(INTERNAL_SERVER_ERROR), + timestamp: new Date().toISOString(), + }); + } + } +); + +assetsRouter.post( + '/addstu', + body().isObject().withMessage('body must contain an asset object'), + body('DeptID', 'must be a string').notEmpty(), + body('RollNo', 'must be a string').notEmpty(), + async (req: Request, res: Response) => { + logger.debug(req.body, 'Create asset request received'); + + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(BAD_REQUEST).json({ + status: getReasonPhrase(BAD_REQUEST), + reason: 'VALIDATION_ERROR', + message: 'Invalid request body', + timestamp: new Date().toISOString(), + errors: errors.array(), + }); + } + + const mspId = req.user as string; + const assetId = req.body.DeptID; + + try { + const submitQueue = req.app.locals.jobq as Queue; + const jobId = await addSubmitTransactionJob( + submitQueue, + mspId, + 'deptAddStudent', + assetId, + req.body.RollNo + ); + + return res.status(ACCEPTED).json({ + status: getReasonPhrase(ACCEPTED), + jobId: jobId, + timestamp: new Date().toISOString(), + }); + } catch (err) { + logger.error( + { err }, + 'Error processing create asset request for asset ID %s', + assetId + ); + + return res.status(INTERNAL_SERVER_ERROR).json({ + status: getReasonPhrase(INTERNAL_SERVER_ERROR), + timestamp: new Date().toISOString(), + }); + } + } +); + +assetsRouter.post( + '/stuaddsub', + body().isObject().withMessage('body must contain an asset object'), + body('RollNo', 'must be a string').notEmpty(), + body('Subject', 'must be a string').notEmpty(), + body('Mark', 'must be a number').isNumeric(), + async (req: Request, res: Response) => { + logger.debug(req.body, 'Create asset request received'); + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(BAD_REQUEST).json({ + status: getReasonPhrase(BAD_REQUEST), + reason: 'VALIDATION_ERROR', + message: 'Invalid request body', + timestamp: new Date().toISOString(), + errors: errors.array(), + }); + } + + const mspId = req.user as string; + const assetId = req.body.RollNo; + + try { + const submitQueue = req.app.locals.jobq as Queue; + const jobId = await addSubmitTransactionJob( + submitQueue, + mspId, + 'addStudentMark', + assetId, + req.body.Subject, + req.body.Mark + ); + + return res.status(ACCEPTED).json({ + status: getReasonPhrase(ACCEPTED), + jobId: jobId, + timestamp: new Date().toISOString(), + }); + } catch (err) { + logger.error( + { err }, + 'Error processing create asset request for asset ID %s', + assetId + ); + + return res.status(INTERNAL_SERVER_ERROR).json({ + status: getReasonPhrase(INTERNAL_SERVER_ERROR), + timestamp: new Date().toISOString(), + }); + } + } +); + +assetsRouter.get('/student/:assetId', async (req: Request, res: Response) => { + const rollNo = req.params.assetId; + logger.debug('Read asset request received for asset ID %s', rollNo); + + try { + const mspId = req.user as string; + const contract = req.app.locals[mspId]?.assetContract as Contract; + + const data = await evatuateTransaction(contract, 'getStudent', rollNo); + const asset = JSON.parse(data.toString()); + + return res.status(OK).json(asset); + } catch (err) { + logger.error( + { err }, + 'Error processing read asset request for asset ID %s', + rollNo + ); + + if (err instanceof AssetNotFoundError) { + return res.status(NOT_FOUND).json({ + status: getReasonPhrase(NOT_FOUND), + timestamp: new Date().toISOString(), + }); + } + + return res.status(INTERNAL_SERVER_ERROR).json({ + status: getReasonPhrase(INTERNAL_SERVER_ERROR), + timestamp: new Date().toISOString(), + }); + } +}); + +assetsRouter.post( + '/certificate', + body().isObject().withMessage('body must contain an asset object'), + body('Name', 'must be a string').notEmpty(), + body('Event', 'must be a string').notEmpty(), + body('Links', 'must be a string').notEmpty(), + async (req: Request, res: Response) => { + logger.debug(req.body, 'Create asset request received'); + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(BAD_REQUEST).json({ + status: getReasonPhrase(BAD_REQUEST), + reason: 'VALIDATION_ERROR', + message: 'Invalid request body', + timestamp: new Date().toISOString(), + errors: errors.array(), + }); + } + + const mspId = req.user as string; + + try { + const submitQueue = req.app.locals.jobq as Queue; + const jobId = await addSubmitTransactionJob( + submitQueue, + mspId, + 'addCertificate', + req.body.Name, + req.body.Event, + req.body.Links + ); + + const hash = createHash('sha256'); + + hash.update(req.body.Name + req.body.Event + req.body.Links); + + const hashStr: string = hash.digest('hex'); + + return res.status(ACCEPTED).json({ + certificate_hash: hashStr, + job_id: jobId, + }); + } catch (err) { + logger.error( + { err }, + 'Error processing create asset request for asset ID %s', + req.body.Name + ); + + return res.status(INTERNAL_SERVER_ERROR).json({ + status: getReasonPhrase(INTERNAL_SERVER_ERROR), + timestamp: new Date().toISOString(), + }); + } + } +); + +assetsRouter.get( + '/certificate', + body().isObject().withMessage('body must contain an asset object'), + body('Hash', 'must be a string').notEmpty(), + async (req: Request, res: Response) => { + const hashStr = req.body.Hash; + logger.debug('Read asset request received for asset ID %s', hashStr); + + try { + const mspId = req.user as string; + const contract = req.app.locals[mspId]?.assetContract as Contract; + + const data = await evatuateTransaction( + contract, + 'validateCertificate', + hashStr + ); + const asset = JSON.parse(data.toString()); + + return res.status(OK).json(asset); + } catch (err) { + logger.error( + { err }, + 'Error processing read asset request for asset ID %s', + hashStr + ); + + if (err instanceof AssetNotFoundError) { + return res.status(NOT_FOUND).json({ + status: getReasonPhrase(NOT_FOUND), + timestamp: new Date().toISOString(), + }); + } + + return res.status(INTERNAL_SERVER_ERROR).json({ + status: getReasonPhrase(INTERNAL_SERVER_ERROR), + timestamp: new Date().toISOString(), + }); + } + } +); diff --git a/asset-transfer-basic/rest-api-typescript/src/server.ts b/asset-transfer-basic/rest-api-typescript/src/server.ts index 2d7d31bf..ae72ebe5 100644 --- a/asset-transfer-basic/rest-api-typescript/src/server.ts +++ b/asset-transfer-basic/rest-api-typescript/src/server.ts @@ -54,12 +54,15 @@ export const createServer = async (): Promise => { } if (process.env.NODE_ENV === 'test') { + app.use(cors()); // TBC } if (process.env.NODE_ENV === 'production') { + app.use(cors()); app.use(helmet()); } + app.use(cors()); app.use('/', healthRouter); app.use('/api/assets', authenticateApiKey, assetsRouter); diff --git a/asset-transfer-events/README.md b/asset-transfer-events/README.md deleted file mode 100644 index edfd1148..00000000 --- a/asset-transfer-events/README.md +++ /dev/null @@ -1,84 +0,0 @@ -# Asset transfer events sample - -The asset transfer events sample demonstrates: - -- Emitting chaincode events from smart contract transaction functions. -- Receiving chaincode events in a client application. -- Replaying previous chaincode events in a client application. - -Events are published when a block is committed to the ledger. - -For more information about event services on per-channel basis, visit the -[Channel-based event service](https://hyperledger-fabric.readthedocs.io/en/latest/peer_event_services.html) -page in the Fabric documentation. - - -## About the sample - -This sample includes smart contract and application code in multiple languages. In a use-case similar to basic asset transfer (see [asset-transfer-basic](../asset-transfer-basic) folder) this sample shows sending and receiving of events during create / update / delete of an asset, and during transfer of an asset to a new owner. - -### Application - -Follow the execution flow in the client application code, and corresponding output on running the application. Pay attention to the sequence of: - -- Transaction invocations (console output like "**--> Submit transaction**"). -- Events received by the application (console output like "**<-- Chaincode event received**"). - -Notice that events will be received by the listener after the application code submits the transaction and it is committed to the ledger, but during other application activity unrelated to the event. - -### Smart Contract - -The smart contract (in folder `chaincode-xyz`) implements the following functions to support the application: - -- CreateAsset -- ReadAsset -- UpdateAsset -- DeleteAsset -- TransferAsset - -Note that the asset transfer implemented by the smart contract is a simplified scenario, without ownership validation, meant only to demonstrate the use of sending and receiving events. - -## Running the sample - -Like other samples, the Fabric test network is used to deploy and run this sample. Follow these steps in order: - -1. Create the test network and a channel (from the `test-network` folder). - ``` - ./network.sh up createChannel -c mychannel -ca - ``` - -1. Deploy one of the smart contract implementations (from the `test-network` folder). - ``` - # To deploy the Go chaincode implementation - ./network.sh deployCC -ccn events -ccp ../asset-transfer-events/chaincode-go/ -ccl go -ccep "OR('Org1MSP.peer','Org2MSP.peer')" - - # To deploy the JavaScript chaincode implementation - ./network.sh deployCC -ccn events -ccp ../asset-transfer-events/chaincode-javascript/ -ccl javascript -ccep "OR('Org1MSP.peer','Org2MSP.peer')" - - # To deploy the Java chaincode implementation - ./network.sh deployCC -ccn events -ccp ../asset-transfer-events/chaincode-java/ -ccl java -ccep "OR('Org1MSP.peer','Org2MSP.peer')" - ``` - -1. Run the application (from the `asset-transfer-events` folder). - ``` - # To run the Go sample application - cd application-gateway-go - go run . - - # To run the TypeScript sample application - cd application-gateway-typescript - npm install - npm start - - # To run the Java sample application - cd application-gateway-java - ./gradlew run - ``` - -## Clean up - -When you are finished, you can bring down the test network (from the `test-network` folder). The command will remove all the nodes of the test network, and delete any ledger data that you created. - -``` -./network.sh down -``` \ No newline at end of file diff --git a/asset-transfer-events/application-gateway-go/app.go b/asset-transfer-events/application-gateway-go/app.go deleted file mode 100755 index f4fc7a58..00000000 --- a/asset-transfer-events/application-gateway-go/app.go +++ /dev/null @@ -1,172 +0,0 @@ -/* -Copyright 2022 IBM All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "time" - - "github.com/hyperledger/fabric-gateway/pkg/client" - "github.com/hyperledger/fabric-gateway/pkg/hash" -) - -const ( - channelName = "mychannel" - chaincodeName = "events" -) - -var now = time.Now() -var assetID = fmt.Sprintf("asset%d", now.Unix()*1e3+int64(now.Nanosecond())/1e6) - -func main() { - clientConnection := newGrpcConnection() - defer clientConnection.Close() - - id := newIdentity() - sign := newSign() - - gateway, err := client.Connect( - id, - client.WithSign(sign), - client.WithHash(hash.SHA256), - client.WithClientConnection(clientConnection), - client.WithEvaluateTimeout(5*time.Second), - client.WithEndorseTimeout(15*time.Second), - client.WithSubmitTimeout(5*time.Second), - client.WithCommitStatusTimeout(1*time.Minute), - ) - if err != nil { - panic(err) - } - defer gateway.Close() - - network := gateway.GetNetwork(channelName) - contract := network.GetContract(chaincodeName) - - // Context used for event listening - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - // Listen for events emitted by subsequent transactions - startChaincodeEventListening(ctx, network) - - firstBlockNumber := createAsset(contract) - updateAsset(contract) - transferAsset(contract) - deleteAsset(contract) - - // Replay events from the block containing the first transaction - replayChaincodeEvents(ctx, network, firstBlockNumber) -} - -func startChaincodeEventListening(ctx context.Context, network *client.Network) { - fmt.Println("\n*** Start chaincode event listening") - - events, err := network.ChaincodeEvents(ctx, chaincodeName) - if err != nil { - panic(fmt.Errorf("failed to start chaincode event listening: %w", err)) - } - - go func() { - for event := range events { - asset := formatJSON(event.Payload) - fmt.Printf("\n<-- Chaincode event received: %s - %s\n", event.EventName, asset) - } - }() -} - -func formatJSON(data []byte) string { - var result bytes.Buffer - if err := json.Indent(&result, data, "", " "); err != nil { - panic(fmt.Errorf("failed to parse JSON: %w", err)) - } - return result.String() -} - -func createAsset(contract *client.Contract) uint64 { - fmt.Printf("\n--> Submit transaction: CreateAsset, %s owned by Sam with appraised value 100\n", assetID) - - _, commit, err := contract.SubmitAsync("CreateAsset", client.WithArguments(assetID, "blue", "10", "Sam", "100")) - if err != nil { - panic(fmt.Errorf("failed to submit transaction: %w", err)) - } - - status, err := commit.Status() - if err != nil { - panic(fmt.Errorf("failed to get transaction commit status: %w", err)) - } - - if !status.Successful { - panic(fmt.Errorf("failed to commit transaction with status code %v", status.Code)) - } - - fmt.Println("\n*** CreateAsset committed successfully") - - return status.BlockNumber -} - -func updateAsset(contract *client.Contract) { - fmt.Printf("\n--> Submit transaction: UpdateAsset, %s update appraised value to 200\n", assetID) - - _, err := contract.SubmitTransaction("UpdateAsset", assetID, "blue", "10", "Sam", "200") - if err != nil { - panic(fmt.Errorf("failed to submit transaction: %w", err)) - } - - fmt.Println("\n*** UpdateAsset committed successfully") -} - -func transferAsset(contract *client.Contract) { - fmt.Printf("\n--> Submit transaction: TransferAsset, %s to Mary\n", assetID) - - _, err := contract.SubmitTransaction("TransferAsset", assetID, "Mary") - if err != nil { - panic(fmt.Errorf("failed to submit transaction: %w", err)) - } - - fmt.Println("\n*** TransferAsset committed successfully") -} - -func deleteAsset(contract *client.Contract) { - fmt.Printf("\n--> Submit transaction: DeleteAsset, %s\n", assetID) - - _, err := contract.SubmitTransaction("DeleteAsset", assetID) - if err != nil { - panic(fmt.Errorf("failed to submit transaction: %w", err)) - } - - fmt.Println("\n*** DeleteAsset committed successfully") -} - -func replayChaincodeEvents(ctx context.Context, network *client.Network, startBlock uint64) { - fmt.Println("\n*** Start chaincode event replay") - - events, err := network.ChaincodeEvents(ctx, chaincodeName, client.WithStartBlock(startBlock)) - if err != nil { - panic(fmt.Errorf("failed to start chaincode event listening: %w", err)) - } - - for { - select { - case <-time.After(10 * time.Second): - panic(errors.New("timeout waiting for event replay")) - - case event := <-events: - asset := formatJSON(event.Payload) - fmt.Printf("\n<-- Chaincode event replayed: %s - %s\n", event.EventName, asset) - - if event.EventName == "DeleteAsset" { - // Reached the last submitted transaction so return to stop listening for events - return - } - } - } -} diff --git a/asset-transfer-events/application-gateway-go/connect.go b/asset-transfer-events/application-gateway-go/connect.go deleted file mode 100755 index 7b21d8b1..00000000 --- a/asset-transfer-events/application-gateway-go/connect.go +++ /dev/null @@ -1,114 +0,0 @@ -/* -Copyright 2022 IBM All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "crypto/x509" - "fmt" - "os" - "path" - - "github.com/hyperledger/fabric-gateway/pkg/identity" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" -) - -const ( - mspID = "Org1MSP" - cryptoPath = "../../test-network/organizations/peerOrganizations/org1.example.com" - certPath = cryptoPath + "/users/User1@org1.example.com/msp/signcerts" - keyPath = cryptoPath + "/users/User1@org1.example.com/msp/keystore" - tlsCertPath = cryptoPath + "/peers/peer0.org1.example.com/tls/ca.crt" - peerEndpoint = "dns:///localhost:7051" - gatewayPeer = "peer0.org1.example.com" -) - -// newGrpcConnection creates a gRPC connection to the Gateway server. -func newGrpcConnection() *grpc.ClientConn { - certificatePEM, err := os.ReadFile(tlsCertPath) - if err != nil { - panic(fmt.Errorf("failed to read TLS certifcate file: %w", err)) - } - - certificate, err := identity.CertificateFromPEM(certificatePEM) - if err != nil { - panic(err) - } - - certPool := x509.NewCertPool() - certPool.AddCert(certificate) - transportCredentials := credentials.NewClientTLSFromCert(certPool, gatewayPeer) - - connection, err := grpc.NewClient(peerEndpoint, grpc.WithTransportCredentials(transportCredentials)) - if err != nil { - panic(fmt.Errorf("failed to create gRPC connection: %w", err)) - } - - return connection -} - -// newIdentity creates a client identity for this Gateway connection using an X.509 certificate. -func newIdentity() *identity.X509Identity { - certificatePEM, err := readFirstFile(certPath) - if err != nil { - panic(fmt.Errorf("failed to read certificate file: %w", err)) - } - - certificate, err := identity.CertificateFromPEM(certificatePEM) - if err != nil { - panic(err) - } - - id, err := identity.NewX509Identity(mspID, certificate) - if err != nil { - panic(err) - } - - return id -} - -func loadCertificate(filename string) (*x509.Certificate, error) { - certificatePEM, err := os.ReadFile(filename) - if err != nil { - return nil, fmt.Errorf("failed to read certificate file: %w", err) - } - return identity.CertificateFromPEM(certificatePEM) -} - -// newSign creates a function that generates a digital signature from a message digest using a private key. -func newSign() identity.Sign { - privateKeyPEM, err := readFirstFile(keyPath) - if err != nil { - panic(fmt.Errorf("failed to read private key file: %w", err)) - } - - privateKey, err := identity.PrivateKeyFromPEM(privateKeyPEM) - if err != nil { - panic(err) - } - - sign, err := identity.NewPrivateKeySign(privateKey) - if err != nil { - panic(err) - } - - return sign -} - -func readFirstFile(dirPath string) ([]byte, error) { - dir, err := os.Open(dirPath) - if err != nil { - return nil, err - } - - fileNames, err := dir.Readdirnames(1) - if err != nil { - return nil, err - } - - return os.ReadFile(path.Join(dirPath, fileNames[0])) -} diff --git a/asset-transfer-events/application-gateway-go/go.mod b/asset-transfer-events/application-gateway-go/go.mod deleted file mode 100644 index 65128cfd..00000000 --- a/asset-transfer-events/application-gateway-go/go.mod +++ /dev/null @@ -1,19 +0,0 @@ -module assetTransfer - -go 1.22.0 - -require ( - github.com/hyperledger/fabric-gateway v1.7.0 - google.golang.org/grpc v1.67.1 -) - -require ( - github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 // indirect - github.com/miekg/pkcs11 v1.1.1 // indirect - golang.org/x/crypto v0.28.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.26.0 // indirect - golang.org/x/text v0.19.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect - google.golang.org/protobuf v1.35.1 // indirect -) diff --git a/asset-transfer-events/application-gateway-go/go.sum b/asset-transfer-events/application-gateway-go/go.sum deleted file mode 100644 index 01eab6a8..00000000 --- a/asset-transfer-events/application-gateway-go/go.sum +++ /dev/null @@ -1,32 +0,0 @@ -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hyperledger/fabric-gateway v1.7.0 h1:bd1quU8qYPYqYO69m1tPIDSjB+D+u/rBJfE1eWFcpjY= -github.com/hyperledger/fabric-gateway v1.7.0/go.mod h1:TItDGnq71eJcgz5TW+m5Sq3kWGp0AEI1HPCNxj0Eu7k= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 h1:YJrd+gMaeY0/vsN0aS0QkEKTivGoUnSRIXxGJ7KI+Pc= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4/go.mod h1:bau/6AJhvEcu9GKKYHlDXAxXKzYNfhP6xu2GXuxEcFk= -github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= -github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= -golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= -google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= -google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/asset-transfer-events/application-gateway-java/build.gradle b/asset-transfer-events/application-gateway-java/build.gradle deleted file mode 100644 index e0743122..00000000 --- a/asset-transfer-events/application-gateway-java/build.gradle +++ /dev/null @@ -1,28 +0,0 @@ -plugins { - // Apply the application plugin to add support for building a CLI application. - id 'application' -} - -repositories { - mavenCentral() -} - -dependencies { - implementation 'org.hyperledger.fabric:fabric-gateway:1.7.0' - implementation platform('com.google.protobuf:protobuf-bom:4.28.2') - implementation platform('io.grpc:grpc-bom:1.67.1') - compileOnly 'io.grpc:grpc-api' - runtimeOnly 'io.grpc:grpc-netty-shaded' - implementation 'com.google.code.gson:gson:2.11.0' -} - -java { - toolchain { - languageVersion = JavaLanguageVersion.of(11) - } -} - -application { - // Define the main class for the application. - mainClass = 'App' -} diff --git a/asset-transfer-events/application-gateway-java/gradle/wrapper/gradle-wrapper.jar b/asset-transfer-events/application-gateway-java/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index d64cd4917707c1f8861d8cb53dd15194d4248596..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43462 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 diff --git a/asset-transfer-events/application-gateway-java/gradle/wrapper/gradle-wrapper.properties b/asset-transfer-events/application-gateway-java/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index e2847c82..00000000 --- a/asset-transfer-events/application-gateway-java/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/asset-transfer-events/application-gateway-java/gradlew b/asset-transfer-events/application-gateway-java/gradlew deleted file mode 100755 index 1aa94a42..00000000 --- a/asset-transfer-events/application-gateway-java/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/asset-transfer-events/application-gateway-java/gradlew.bat b/asset-transfer-events/application-gateway-java/gradlew.bat deleted file mode 100644 index 7101f8e4..00000000 --- a/asset-transfer-events/application-gateway-java/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/asset-transfer-events/application-gateway-java/pom.xml b/asset-transfer-events/application-gateway-java/pom.xml deleted file mode 100644 index e959e925..00000000 --- a/asset-transfer-events/application-gateway-java/pom.xml +++ /dev/null @@ -1,101 +0,0 @@ - - - 4.0.0 - - org.hyperledger.fabric.example - asset-transfer-events - 1.0-SNAPSHOT - - - UTF-8 - 11 - - - - - - com.google.protobuf - protobuf-bom - 4.28.2 - pom - import - - - io.grpc - grpc-bom - 1.67.1 - pom - import - - - - - - - org.hyperledger.fabric - fabric-gateway - 1.7.0 - - - io.grpc - grpc-api - - - io.grpc - grpc-netty-shaded - runtime - - - com.google.code.gson - gson - 2.11.0 - - - - - - - - - maven-clean-plugin - 3.4.0 - - - - maven-resources-plugin - 3.3.1 - - - maven-compiler-plugin - 3.13.0 - - - maven-surefire-plugin - 3.3.0 - - - maven-jar-plugin - 3.4.2 - - - maven-install-plugin - 3.1.2 - - - maven-deploy-plugin - 3.1.2 - - - - maven-site-plugin - 3.12.1 - - - maven-project-info-reports-plugin - 3.6.1 - - - - - diff --git a/asset-transfer-events/application-gateway-java/settings.gradle b/asset-transfer-events/application-gateway-java/settings.gradle deleted file mode 100644 index acea186a..00000000 --- a/asset-transfer-events/application-gateway-java/settings.gradle +++ /dev/null @@ -1,10 +0,0 @@ -/* - * This file was generated by the Gradle 'init' task. - * - * The settings file is used to specify which projects to include in your build. - * - * Detailed information about configuring a multi-project build in Gradle can be found - * in the user manual at https://docs.gradle.org/6.5/userguide/multi_project_builds.html - */ - -rootProject.name = 'asset-transfer-events' diff --git a/asset-transfer-events/application-gateway-java/src/main/java/App.java b/asset-transfer-events/application-gateway-java/src/main/java/App.java deleted file mode 100644 index 1bdbeba9..00000000 --- a/asset-transfer-events/application-gateway-java/src/main/java/App.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonParser; -import io.grpc.Status; -import org.hyperledger.fabric.client.ChaincodeEvent; -import org.hyperledger.fabric.client.CloseableIterator; -import org.hyperledger.fabric.client.CommitException; -import org.hyperledger.fabric.client.CommitStatusException; -import org.hyperledger.fabric.client.Contract; -import org.hyperledger.fabric.client.EndorseException; -import org.hyperledger.fabric.client.Gateway; -import org.hyperledger.fabric.client.GatewayRuntimeException; -import org.hyperledger.fabric.client.Hash; -import org.hyperledger.fabric.client.Network; -import org.hyperledger.fabric.client.SubmitException; - -import java.nio.charset.StandardCharsets; -import java.time.Instant; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - -public final class App implements AutoCloseable { - private static final String channelName = "mychannel"; - private static final String chaincodeName = "events"; - - private final Network network; - private final Contract contract; - private final String assetId = "asset" + Instant.now().toEpochMilli(); - private final Gson gson = new GsonBuilder().setPrettyPrinting().create(); - private final ExecutorService executor = Executors.newCachedThreadPool(); - - public static void main(final String[] args) throws Exception { - var grpcChannel = Connections.newGrpcConnection(); - var builder = Gateway.newInstance() - .identity(Connections.newIdentity()) - .signer(Connections.newSigner()) - .hash(Hash.SHA256) - .connection(grpcChannel) - .evaluateOptions(options -> options.withDeadlineAfter(5, TimeUnit.SECONDS)) - .endorseOptions(options -> options.withDeadlineAfter(15, TimeUnit.SECONDS)) - .submitOptions(options -> options.withDeadlineAfter(5, TimeUnit.SECONDS)) - .commitStatusOptions(options -> options.withDeadlineAfter(1, TimeUnit.MINUTES)); - - try (var gateway = builder.connect(); var app = new App(gateway)) { - app.run(); - } finally { - grpcChannel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS); - } - } - - public App(final Gateway gateway) { - network = gateway.getNetwork(channelName); - contract = network.getContract(chaincodeName); - } - - public void run() throws EndorseException, SubmitException, CommitStatusException, CommitException { - // Listen for events emitted by subsequent transactions, stopping when the try-with-resources block exits - try (var eventSession = startChaincodeEventListening()) { - var firstBlockNumber = createAsset(); - updateAsset(); - transferAsset(); - deleteAsset(); - - // Replay events from the block containing the first transaction - replayChaincodeEvents(firstBlockNumber); - } - } - - private CloseableIterator startChaincodeEventListening() { - System.out.println("\n*** Start chaincode event listening"); - - var eventIter = network.getChaincodeEvents(chaincodeName); - executor.execute(() -> readEvents(eventIter)); - - return eventIter; - } - - private void readEvents(final CloseableIterator eventIter) { - try { - eventIter.forEachRemaining(event -> { - var payload = prettyJson(event.getPayload()); - System.out.println("\n<-- Chaincode event received: " + event.getEventName() + " - " + payload); - }); - } catch (GatewayRuntimeException e) { - if (e.getStatus().getCode() != Status.Code.CANCELLED) { - throw e; - } - } - } - - private String prettyJson(final byte[] json) { - return prettyJson(new String(json, StandardCharsets.UTF_8)); - } - - private String prettyJson(final String json) { - var parsedJson = JsonParser.parseString(json); - return gson.toJson(parsedJson); - } - - private long createAsset() throws EndorseException, SubmitException, CommitStatusException { - System.out.println("\n--> Submit transaction: CreateAsset, " + assetId + " owned by Sam with appraised value 100"); - - var commit = contract.newProposal("CreateAsset") - .addArguments(assetId, "blue", "10", "Sam", "100") - .build() - .endorse() - .submitAsync(); - - var status = commit.getStatus(); - if (!status.isSuccessful()) { - throw new RuntimeException("failed to commit transaction with status code " + status.getCode()); - } - - System.out.println("\n*** CreateAsset committed successfully"); - - return status.getBlockNumber(); - } - - private void updateAsset() throws EndorseException, SubmitException, CommitStatusException, CommitException { - System.out.println("\n--> Submit transaction: UpdateAsset, " + assetId + " update appraised value to 200"); - - contract.submitTransaction("UpdateAsset", assetId, "blue", "10", "Sam", "200"); - - System.out.println("\n*** UpdateAsset committed successfully"); - } - - private void transferAsset() throws EndorseException, SubmitException, CommitStatusException, CommitException { - System.out.println("\n--> Submit transaction: TransferAsset, " + assetId + " to Mary"); - - contract.submitTransaction("TransferAsset", assetId, "Mary"); - - System.out.println("\n*** TransferAsset committed successfully"); - } - - private void deleteAsset() throws EndorseException, SubmitException, CommitStatusException, CommitException { - System.out.println("\n--> Submit transaction: DeleteAsset, " + assetId); - - contract.submitTransaction("DeleteAsset", assetId); - - System.out.println("\n*** DeleteAsset committed successfully"); - } - - private void replayChaincodeEvents(final long startBlock) { - System.out.println("\n*** Start chaincode event replay"); - - var request = network.newChaincodeEventsRequest(chaincodeName) - .startBlock(startBlock) - .build(); - - try (var eventIter = request.getEvents()) { - while (eventIter.hasNext()) { - var event = eventIter.next(); - var payload = prettyJson(event.getPayload()); - System.out.println("\n<-- Chaincode event replayed: " + event.getEventName() + " - " + payload); - - if (event.getEventName().equals("DeleteAsset")) { - // Reached the last submitted transaction so break to close the iterator and stop listening for events - break; - } - } - } - } - - @Override - public void close() throws Exception { - executor.shutdownNow(); - } -} diff --git a/asset-transfer-events/application-gateway-java/src/main/java/Connections.java b/asset-transfer-events/application-gateway-java/src/main/java/Connections.java deleted file mode 100644 index 6902fc03..00000000 --- a/asset-transfer-events/application-gateway-java/src/main/java/Connections.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -import io.grpc.Grpc; -import io.grpc.ManagedChannel; -import io.grpc.TlsChannelCredentials; -import org.hyperledger.fabric.client.identity.Identities; -import org.hyperledger.fabric.client.identity.Identity; -import org.hyperledger.fabric.client.identity.Signer; -import org.hyperledger.fabric.client.identity.Signers; -import org.hyperledger.fabric.client.identity.X509Identity; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.security.InvalidKeyException; -import java.security.cert.CertificateException; - -public final class Connections { - // Path to crypto materials. - private static final Path cryptoPath = Paths.get("..", "..", "test-network", "organizations", "peerOrganizations", "org1.example.com"); - // Path to user certificate. - private static final Path certDirPath = cryptoPath.resolve(Paths.get("users", "User1@org1.example.com", "msp", "signcerts")); - // Path to user private key directory. - private static final Path keyDirPath = cryptoPath.resolve(Paths.get("users", "User1@org1.example.com", "msp", "keystore")); - // Path to peer tls certificate. - private static final Path tlsCertPath = cryptoPath.resolve(Paths.get("peers", "peer0.org1.example.com", "tls", "ca.crt")); - - // Gateway peer end point. - private static final String peerEndpoint = "localhost:7051"; - private static final String overrideAuth = "peer0.org1.example.com"; - - private static final String mspID = "Org1MSP"; - - private Connections() { - // Private constructor to prevent instantiation - } - - public static ManagedChannel newGrpcConnection() throws IOException { - var credentials = TlsChannelCredentials.newBuilder() - .trustManager(tlsCertPath.toFile()) - .build(); - return Grpc.newChannelBuilder(peerEndpoint, credentials) - .overrideAuthority(overrideAuth) - .build(); - } - - public static Identity newIdentity() throws IOException, CertificateException { - try (var certReader = Files.newBufferedReader(getFirstFilePath(certDirPath))) { - var certificate = Identities.readX509Certificate(certReader); - return new X509Identity(mspID, certificate); - } - } - - public static Signer newSigner() throws IOException, InvalidKeyException { - try (var keyReader = Files.newBufferedReader(getFirstFilePath(keyDirPath))) { - var privateKey = Identities.readPrivateKey(keyReader); - return Signers.newPrivateKeySigner(privateKey); - } - } - - private static Path getFirstFilePath(Path dirPath) throws IOException { - try (var keyFiles = Files.list(dirPath)) { - return keyFiles.findFirst().orElseThrow(); - } - }} diff --git a/asset-transfer-events/application-gateway-typescript/.gitignore b/asset-transfer-events/application-gateway-typescript/.gitignore deleted file mode 100644 index 99e5af9f..00000000 --- a/asset-transfer-events/application-gateway-typescript/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - - -# Coverage directory used by tools like istanbul -coverage - -# Dependency directories -node_modules/ -jspm_packages/ - -# Compiled TypeScript files -dist diff --git a/asset-transfer-events/application-gateway-typescript/.npmrc b/asset-transfer-events/application-gateway-typescript/.npmrc deleted file mode 100644 index b6f27f13..00000000 --- a/asset-transfer-events/application-gateway-typescript/.npmrc +++ /dev/null @@ -1 +0,0 @@ -engine-strict=true diff --git a/asset-transfer-events/application-gateway-typescript/eslint.config.mjs b/asset-transfer-events/application-gateway-typescript/eslint.config.mjs deleted file mode 100644 index 9ef6b243..00000000 --- a/asset-transfer-events/application-gateway-typescript/eslint.config.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import js from '@eslint/js'; -import tseslint from 'typescript-eslint'; - -export default tseslint.config(js.configs.recommended, ...tseslint.configs.strictTypeChecked, { - languageOptions: { - ecmaVersion: 2023, - sourceType: 'module', - parserOptions: { - project: 'tsconfig.json', - tsconfigRootDir: import.meta.dirname, - }, - }, -}); diff --git a/asset-transfer-events/application-gateway-typescript/package.json b/asset-transfer-events/application-gateway-typescript/package.json deleted file mode 100755 index 24ca024e..00000000 --- a/asset-transfer-events/application-gateway-typescript/package.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "asset-transfer-events", - "version": "1.0.0", - "description": "Asset Transfer Events Application implemented in typeScript using fabric-gateway", - "main": "dist/index.js", - "typings": "dist/index.d.ts", - "engines": { - "node": ">=18" - }, - "scripts": { - "build": "tsc", - "build:watch": "tsc -w", - "lint": "eslint src", - "prepare": "npm run build", - "pretest": "npm run lint", - "start": "node dist/app.js" - }, - "engineStrict": true, - "author": "Hyperledger", - "license": "Apache-2.0", - "dependencies": { - "@grpc/grpc-js": "^1.12.2", - "@hyperledger/fabric-gateway": "^1.7.0" - }, - "devDependencies": { - "@eslint/js": "^9.3.0", - "@tsconfig/node18": "^18.2.2", - "@types/node": "^18.18.6", - "eslint": "^8.57.0", - "typescript": "~5.4", - "typescript-eslint": "^7.13.0" - } -} diff --git a/asset-transfer-events/application-gateway-typescript/src/app.ts b/asset-transfer-events/application-gateway-typescript/src/app.ts deleted file mode 100755 index 7db50116..00000000 --- a/asset-transfer-events/application-gateway-typescript/src/app.ts +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as grpc from '@grpc/grpc-js'; -import { ChaincodeEvent, CloseableAsyncIterable, connect, Contract, GatewayError, hash, Network } from '@hyperledger/fabric-gateway'; -import { TextDecoder } from 'util'; -import { newGrpcConnection, newIdentity, newSigner } from './connect'; - -const channelName = 'mychannel'; -const chaincodeName = 'events'; - -const utf8Decoder = new TextDecoder(); -const now = Date.now(); -const assetId = `asset${String(now)}`; - - -async function main(): Promise { - const client = await newGrpcConnection(); - const gateway = connect({ - client, - identity: await newIdentity(), - signer: await newSigner(), - hash: hash.sha256, - evaluateOptions: () => { - return { deadline: Date.now() + 5000 }; // 5 seconds - }, - endorseOptions: () => { - return { deadline: Date.now() + 15000 }; // 15 seconds - }, - submitOptions: () => { - return { deadline: Date.now() + 5000 }; // 5 seconds - }, - commitStatusOptions: () => { - return { deadline: Date.now() + 60000 }; // 1 minute - }, - }); - - let events: CloseableAsyncIterable | undefined; - - try { - const network = gateway.getNetwork(channelName); - const contract = network.getContract(chaincodeName); - - // Listen for events emitted by subsequent transactions - events = await startEventListening(network); - - const firstBlockNumber = await createAsset(contract); - await updateAsset(contract); - await transferAsset(contract); - await deleteAssetByID(contract); - - // Replay events from the block containing the first transaction - await replayChaincodeEvents(network,firstBlockNumber); - } finally { - events?.close(); - gateway.close(); - client.close(); - } -} - -main().catch((error: unknown) => { - console.error('******** FAILED to run the application:', error); - process.exitCode = 1; -}); - -async function startEventListening(network: Network): Promise> { - console.log('\n*** Start chaincode event listening'); - - const events = await network.getChaincodeEvents(chaincodeName); - - void readEvents(events); // Don't await - run asynchronously - return events; -} - -async function readEvents(events: CloseableAsyncIterable): Promise { - try { - for await (const event of events) { - const payload = parseJson(event.payload); - console.log(`\n<-- Chaincode event received: ${event.eventName} -`, payload); - } - } catch (error: unknown) { - // Ignore the read error when events.close() is called explicitly - if (!(error instanceof GatewayError) || error.code !== grpc.status.CANCELLED.valueOf()) { - throw error; - } - } -} - -function parseJson(jsonBytes: Uint8Array): unknown { - const json = utf8Decoder.decode(jsonBytes); - return JSON.parse(json); -} - -async function createAsset(contract: Contract): Promise { - console.log(`\n--> Submit Transaction: CreateAsset, ${assetId} owned by Sam with appraised value 100`); - - const result = await contract.submitAsync('CreateAsset', { - arguments: [ assetId, 'blue', '10', 'Sam', '100' ], - }); - - const status = await result.getStatus(); - if (!status.successful) { - throw new Error(`failed to commit transaction ${status.transactionId} with status code ${String(status.code)}`); - } - - console.log('\n*** CreateAsset committed successfully'); - - return status.blockNumber; -} - -async function updateAsset(contract: Contract): Promise { - console.log(`\n--> Submit transaction: UpdateAsset, ${assetId} update appraised value to 200`); - - await contract.submitTransaction('UpdateAsset', assetId, 'blue', '10', 'Sam', '200'); - - console.log('\n*** UpdateAsset committed successfully'); -} - -async function transferAsset(contract: Contract): Promise { - console.log(`\n--> Submit transaction: TransferAsset, ${assetId} to Mary`); - - await contract.submitTransaction('TransferAsset', assetId, 'Mary'); - - console.log('\n*** TransferAsset committed successfully'); -} - -async function deleteAssetByID(contract: Contract): Promise{ - console.log(`\n--> Submit transaction: DeleteAsset, ${assetId}`); - - await contract.submitTransaction('DeleteAsset', assetId); - - console.log('\n*** DeleteAsset committed successfully'); -} - -async function replayChaincodeEvents(network: Network, startBlock: bigint): Promise { - console.log('\n*** Start chaincode event replay'); - - const events = await network.getChaincodeEvents(chaincodeName, { - startBlock, - }); - - try { - for await (const event of events) { - const payload = parseJson(event.payload); - console.log(`\n<-- Chaincode event replayed: ${event.eventName} -`, payload); - - if (event.eventName === 'DeleteAsset') { - // Reached the last submitted transaction so break to stop listening for events - break; - } - } - } finally { - events.close(); - } -} diff --git a/asset-transfer-events/application-gateway-typescript/src/connect.ts b/asset-transfer-events/application-gateway-typescript/src/connect.ts deleted file mode 100644 index c72f766a..00000000 --- a/asset-transfer-events/application-gateway-typescript/src/connect.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as grpc from '@grpc/grpc-js'; -import { Identity, Signer, signers } from '@hyperledger/fabric-gateway'; -import * as crypto from 'crypto'; -import { promises as fs } from 'fs'; -import * as path from 'path'; - -const mspId = 'Org1MSP'; - -// Path to crypto materials. -const cryptoPath = path.resolve(__dirname, '..', '..', '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.example.com'); - -// Path to user private key directory. -const keyDirectoryPath = path.resolve(cryptoPath, 'users', 'User1@org1.example.com', 'msp', 'keystore'); - -// Path to user certificate. -const certDirectoryPath = path.resolve(cryptoPath, 'users', 'User1@org1.example.com', 'msp', 'signcerts'); - -// Path to peer tls certificate. -const tlsCertPath = path.resolve(cryptoPath, 'peers', 'peer0.org1.example.com', 'tls', 'ca.crt'); - -// Gateway peer endpoint. -const peerEndpoint = 'localhost:7051'; - -export async function newGrpcConnection(): Promise { - const tlsRootCert = await fs.readFile(tlsCertPath); - const tlsCredentials = grpc.credentials.createSsl(tlsRootCert); - return new grpc.Client(peerEndpoint, tlsCredentials, { - 'grpc.ssl_target_name_override': 'peer0.org1.example.com', - }); -} - -export async function newIdentity(): Promise { - const certPath = await getFirstDirFileName(certDirectoryPath); - const credentials = await fs.readFile(certPath); - return { mspId, credentials }; -} - -export async function newSigner(): Promise { - const keyPath = await getFirstDirFileName(keyDirectoryPath); - const privateKeyPem = await fs.readFile(keyPath); - const privateKey = crypto.createPrivateKey(privateKeyPem); - return signers.newPrivateKeySigner(privateKey); -} - -async function getFirstDirFileName(dirPath: string): Promise { - const files = await fs.readdir(dirPath); - const file = files[0]; - if (!file) { - throw new Error(`No files in directory: ${dirPath}`); - } - return path.join(dirPath, file); -} diff --git a/asset-transfer-events/application-gateway-typescript/tsconfig.json b/asset-transfer-events/application-gateway-typescript/tsconfig.json deleted file mode 100644 index 4c20df24..00000000 --- a/asset-transfer-events/application-gateway-typescript/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "@tsconfig/node18/tsconfig.json", - "compilerOptions": { - "outDir": "dist", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "noUnusedLocals": true, - "noImplicitReturns": true, - "noUncheckedIndexedAccess": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["./src/**/*"], - "exclude": ["./src/**/*.spec.ts"] -} diff --git a/asset-transfer-events/chaincode-go/assetTransferEvents.go b/asset-transfer-events/chaincode-go/assetTransferEvents.go deleted file mode 100644 index 4aede5c1..00000000 --- a/asset-transfer-events/chaincode-go/assetTransferEvents.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "log" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" - "github.com/hyperledger/fabric-samples/asset-transfer-events/chaincode-go/chaincode" -) - -func main() { - assetChaincode, err := contractapi.NewChaincode(&chaincode.SmartContract{}) - if err != nil { - log.Panicf("Error creating asset-transfer-events chaincode: %v", err) - } - - if err := assetChaincode.Start(); err != nil { - log.Panicf("Error starting asset-transfer-events chaincode: %v", err) - } -} diff --git a/asset-transfer-events/chaincode-go/chaincode/smartcontract.go b/asset-transfer-events/chaincode-go/chaincode/smartcontract.go deleted file mode 100644 index e9420cfa..00000000 --- a/asset-transfer-events/chaincode-go/chaincode/smartcontract.go +++ /dev/null @@ -1,134 +0,0 @@ -package chaincode - -import ( - "encoding/json" - "fmt" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -// SmartContract provides functions for managing an Asset -type SmartContract struct { - contractapi.Contract -} - -// Asset describes basic details of what makes up a simple asset -// Insert struct field in alphabetic order => to achieve determinism across languages -// golang keeps the order when marshal to json but doesn't order automatically -type Asset struct { - AppraisedValue int `json:"AppraisedValue"` - Color string `json:"Color"` - ID string `json:"ID"` - Owner string `json:"Owner"` - Size int `json:"Size"` -} - -// CreateAsset issues a new asset to the world state with given details. -func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, id string, color string, size int, owner string, appraisedValue int) error { - existing, err := s.readState(ctx, id) - if err == nil && existing != nil { - return fmt.Errorf("the asset %s already exists", id) - } - - asset := Asset{ - ID: id, - Color: color, - Size: size, - Owner: owner, - AppraisedValue: appraisedValue, - } - assetJSON, err := json.Marshal(asset) - if err != nil { - return err - } - - ctx.GetStub().SetEvent("CreateAsset", assetJSON) - return ctx.GetStub().PutState(id, assetJSON) -} - -func (s *SmartContract) readState(ctx contractapi.TransactionContextInterface, id string) ([]byte, error) { - assetJSON, err := ctx.GetStub().GetState(id) - if err != nil { - return nil, fmt.Errorf("failed to read from world state: %w", err) - } - if assetJSON == nil { - return nil, fmt.Errorf("the asset %s does not exist", id) - } - - return assetJSON, nil -} - -// ReadAsset returns the asset stored in the world state with given id. -func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, id string) (*Asset, error) { - assetJSON, err := s.readState(ctx, id) - if err != nil { - return nil, err - } - - var asset Asset - err = json.Unmarshal(assetJSON, &asset) - if err != nil { - return nil, err - } - - return &asset, nil -} - -// UpdateAsset updates an existing asset in the world state with provided parameters. -func (s *SmartContract) UpdateAsset(ctx contractapi.TransactionContextInterface, id string, color string, size int, owner string, appraisedValue int) error { - _, err := s.readState(ctx, id) - if err != nil { - return err - } - - // overwriting original asset with new asset - asset := Asset{ - ID: id, - Color: color, - Size: size, - Owner: owner, - AppraisedValue: appraisedValue, - } - assetJSON, err := json.Marshal(asset) - if err != nil { - return err - } - - ctx.GetStub().SetEvent("UpdateAsset", assetJSON) - return ctx.GetStub().PutState(id, assetJSON) -} - -// DeleteAsset deletes an given asset from the world state. -func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface, id string) error { - assetJSON, err := s.readState(ctx, id) - if err != nil { - return err - } - - ctx.GetStub().SetEvent("DeleteAsset", assetJSON) - return ctx.GetStub().DelState(id) -} - -// TransferAsset updates the owner field of asset with given id in world state, and returns the old owner. -func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) (string, error) { - asset, err := s.ReadAsset(ctx, id) - if err != nil { - return "", err - } - - oldOwner := asset.Owner - asset.Owner = newOwner - - assetJSON, err := json.Marshal(asset) - if err != nil { - return "", err - } - - ctx.GetStub().SetEvent("TransferAsset", assetJSON) - err = ctx.GetStub().PutState(id, assetJSON) - if err != nil { - return "", err - } - - return oldOwner, nil -} diff --git a/asset-transfer-events/chaincode-go/go.mod b/asset-transfer-events/chaincode-go/go.mod deleted file mode 100644 index be5bcd4b..00000000 --- a/asset-transfer-events/chaincode-go/go.mod +++ /dev/null @@ -1,26 +0,0 @@ -module github.com/hyperledger/fabric-samples/asset-transfer-events/chaincode-go - -go 1.22.0 - -require github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0 - -require ( - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0 // indirect - github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xeipuuv/gojsonschema v1.2.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect - google.golang.org/grpc v1.67.0 // indirect - google.golang.org/protobuf v1.36.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/asset-transfer-events/chaincode-go/go.sum b/asset-transfer-events/chaincode-go/go.sum deleted file mode 100644 index 1459ca55..00000000 --- a/asset-transfer-events/chaincode-go/go.sum +++ /dev/null @@ -1,61 +0,0 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0 h1:IhkHfrl5X/fVnmB6pWeCYCdIJRi9bxj+WTnVN8DtW3c= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0/go.mod h1:PHHaFffjw7p7n9bmCfcm7RqDqYdivNEsJdiNIKZo5Lk= -github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0 h1:rmUoBmciB0GL/miqcbJmJbgp5QTWoJUrZo+CNxrNLF4= -github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0/go.mod h1:FeWeO/jwGjiME7ak3GufqKIcwkejtzrDG4QxbfKydWs= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 h1:YJrd+gMaeY0/vsN0aS0QkEKTivGoUnSRIXxGJ7KI+Pc= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4/go.mod h1:bau/6AJhvEcu9GKKYHlDXAxXKzYNfhP6xu2GXuxEcFk= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= -google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= -google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/asset-transfer-events/chaincode-java/build.gradle b/asset-transfer-events/chaincode-java/build.gradle deleted file mode 100644 index b04a0bff..00000000 --- a/asset-transfer-events/chaincode-java/build.gradle +++ /dev/null @@ -1,69 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -plugins { - id 'com.gradleup.shadow' version '8.3.5' - id 'application' - id 'checkstyle' - id 'jacoco' -} - -group 'org.hyperledger.fabric.samples' -version '1.0-SNAPSHOT' - -dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.+' - implementation 'org.json:json:+' - testImplementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.+' -} - -repositories { - mavenCentral() - maven { - url 'https://jitpack.io' - } -} - -java { - toolchain { - languageVersion = JavaLanguageVersion.of(11) - } -} - -application { - mainClassName = 'org.hyperledger.fabric.contract.ContractRouter' -} - - -checkstyle { - toolVersion '8.21' - configFile file("config/checkstyle/checkstyle.xml") -} - -checkstyleMain { - source ='src/main/java' -} - -checkstyleTest { - source ='src/test/java' -} - -jacocoTestReport { - dependsOn test -} - -mainClassName = 'org.hyperledger.fabric.contract.ContractRouter' - -shadowJar { - archiveBaseName = 'chaincode' - archiveVersion = '' - archiveClassifier = '' - mergeServiceFiles() - - manifest { - attributes 'Main-Class': 'org.hyperledger.fabric.contract.ContractRouter' - } -} - -installDist.dependsOn check diff --git a/asset-transfer-events/chaincode-java/config/checkstyle/checkstyle.xml b/asset-transfer-events/chaincode-java/config/checkstyle/checkstyle.xml deleted file mode 100644 index acd5df44..00000000 --- a/asset-transfer-events/chaincode-java/config/checkstyle/checkstyle.xml +++ /dev/null @@ -1,171 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/asset-transfer-events/chaincode-java/config/checkstyle/suppressions.xml b/asset-transfer-events/chaincode-java/config/checkstyle/suppressions.xml deleted file mode 100644 index 33dda041..00000000 --- a/asset-transfer-events/chaincode-java/config/checkstyle/suppressions.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - diff --git a/asset-transfer-events/chaincode-java/gradle/wrapper/gradle-wrapper.jar b/asset-transfer-events/chaincode-java/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index d64cd4917707c1f8861d8cb53dd15194d4248596..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43462 zcma&NWl&^owk(X(xVyW%ySuwf;qI=D6|RlDJ2cR^yEKh!@I- zp9QeisK*rlxC>+~7Dk4IxIRsKBHqdR9b3+fyL=ynHmIDe&|>O*VlvO+%z5;9Z$|DJ zb4dO}-R=MKr^6EKJiOrJdLnCJn>np?~vU-1sSFgPu;pthGwf}bG z(1db%xwr#x)r+`4AGu$j7~u2MpVs3VpLp|mx&;>`0p0vH6kF+D2CY0fVdQOZ@h;A` z{infNyvmFUiu*XG}RNMNwXrbec_*a3N=2zJ|Wh5z* z5rAX$JJR{#zP>KY**>xHTuw?|-Rg|o24V)74HcfVT;WtQHXlE+_4iPE8QE#DUm%x0 zEKr75ur~W%w#-My3Tj`hH6EuEW+8K-^5P62$7Sc5OK+22qj&Pd1;)1#4tKihi=~8C zHiQSst0cpri6%OeaR`PY>HH_;CPaRNty%WTm4{wDK8V6gCZlG@U3$~JQZ;HPvDJcT1V{ z?>H@13MJcCNe#5z+MecYNi@VT5|&UiN1D4ATT+%M+h4c$t;C#UAs3O_q=GxK0}8%8 z8J(_M9bayxN}69ex4dzM_P3oh@ZGREjVvn%%r7=xjkqxJP4kj}5tlf;QosR=%4L5y zWhgejO=vao5oX%mOHbhJ8V+SG&K5dABn6!WiKl{|oPkq(9z8l&Mm%(=qGcFzI=eLu zWc_oCLyf;hVlB@dnwY98?75B20=n$>u3b|NB28H0u-6Rpl((%KWEBOfElVWJx+5yg z#SGqwza7f}$z;n~g%4HDU{;V{gXIhft*q2=4zSezGK~nBgu9-Q*rZ#2f=Q}i2|qOp z!!y4p)4o=LVUNhlkp#JL{tfkhXNbB=Ox>M=n6soptJw-IDI|_$is2w}(XY>a=H52d z3zE$tjPUhWWS+5h=KVH&uqQS=$v3nRs&p$%11b%5qtF}S2#Pc`IiyBIF4%A!;AVoI zXU8-Rpv!DQNcF~(qQnyyMy=-AN~U>#&X1j5BLDP{?K!%h!;hfJI>$mdLSvktEr*89 zdJHvby^$xEX0^l9g$xW-d?J;L0#(`UT~zpL&*cEh$L|HPAu=P8`OQZV!-}l`noSp_ zQ-1$q$R-gDL)?6YaM!=8H=QGW$NT2SeZlb8PKJdc=F-cT@j7Xags+Pr*jPtlHFnf- zh?q<6;)27IdPc^Wdy-mX%2s84C1xZq9Xms+==F4);O`VUASmu3(RlgE#0+#giLh-& zcxm3_e}n4{%|X zJp{G_j+%`j_q5}k{eW&TlP}J2wtZ2^<^E(O)4OQX8FDp6RJq!F{(6eHWSD3=f~(h} zJXCf7=r<16X{pHkm%yzYI_=VDP&9bmI1*)YXZeB}F? z(%QsB5fo*FUZxK$oX~X^69;x~j7ms8xlzpt-T15e9}$4T-pC z6PFg@;B-j|Ywajpe4~bk#S6(fO^|mm1hKOPfA%8-_iGCfICE|=P_~e;Wz6my&)h_~ zkv&_xSAw7AZ%ThYF(4jADW4vg=oEdJGVOs>FqamoL3Np8>?!W#!R-0%2Bg4h?kz5I zKV-rKN2n(vUL%D<4oj@|`eJ>0i#TmYBtYmfla;c!ATW%;xGQ0*TW@PTlGG><@dxUI zg>+3SiGdZ%?5N=8uoLA|$4isK$aJ%i{hECP$bK{J#0W2gQ3YEa zZQ50Stn6hqdfxJ*9#NuSLwKFCUGk@c=(igyVL;;2^wi4o30YXSIb2g_ud$ zgpCr@H0qWtk2hK8Q|&wx)}4+hTYlf;$a4#oUM=V@Cw#!$(nOFFpZ;0lc!qd=c$S}Z zGGI-0jg~S~cgVT=4Vo)b)|4phjStD49*EqC)IPwyeKBLcN;Wu@Aeph;emROAwJ-0< z_#>wVm$)ygH|qyxZaet&(Vf%pVdnvKWJn9`%DAxj3ot;v>S$I}jJ$FLBF*~iZ!ZXE zkvui&p}fI0Y=IDX)mm0@tAd|fEHl~J&K}ZX(Mm3cm1UAuwJ42+AO5@HwYfDH7ipIc zmI;1J;J@+aCNG1M`Btf>YT>~c&3j~Qi@Py5JT6;zjx$cvOQW@3oQ>|}GH?TW-E z1R;q^QFjm5W~7f}c3Ww|awg1BAJ^slEV~Pk`Kd`PS$7;SqJZNj->it4DW2l15}xP6 zoCl$kyEF%yJni0(L!Z&14m!1urXh6Btj_5JYt1{#+H8w?5QI%% zo-$KYWNMJVH?Hh@1n7OSu~QhSswL8x0=$<8QG_zepi_`y_79=nK=_ZP_`Em2UI*tyQoB+r{1QYZCpb?2OrgUw#oRH$?^Tj!Req>XiE#~B|~ z+%HB;=ic+R@px4Ld8mwpY;W^A%8%l8$@B@1m5n`TlKI6bz2mp*^^^1mK$COW$HOfp zUGTz-cN9?BGEp}5A!mDFjaiWa2_J2Iq8qj0mXzk; z66JBKRP{p%wN7XobR0YjhAuW9T1Gw3FDvR5dWJ8ElNYF94eF3ebu+QwKjtvVu4L zI9ip#mQ@4uqVdkl-TUQMb^XBJVLW(-$s;Nq;@5gr4`UfLgF$adIhd?rHOa%D);whv z=;krPp~@I+-Z|r#s3yCH+c1US?dnm+C*)r{m+86sTJusLdNu^sqLrfWed^ndHXH`m zd3#cOe3>w-ga(Dus_^ppG9AC>Iq{y%%CK+Cro_sqLCs{VLuK=dev>OL1dis4(PQ5R zcz)>DjEkfV+MO;~>VUlYF00SgfUo~@(&9$Iy2|G0T9BSP?&T22>K46D zL*~j#yJ?)^*%J3!16f)@Y2Z^kS*BzwfAQ7K96rFRIh>#$*$_Io;z>ux@}G98!fWR@ zGTFxv4r~v)Gsd|pF91*-eaZ3Qw1MH$K^7JhWIdX%o$2kCbvGDXy)a?@8T&1dY4`;L z4Kn+f%SSFWE_rpEpL9bnlmYq`D!6F%di<&Hh=+!VI~j)2mfil03T#jJ_s?}VV0_hp z7T9bWxc>Jm2Z0WMU?`Z$xE74Gu~%s{mW!d4uvKCx@WD+gPUQ zV0vQS(Ig++z=EHN)BR44*EDSWIyT~R4$FcF*VEY*8@l=218Q05D2$|fXKFhRgBIEE zdDFB}1dKkoO^7}{5crKX!p?dZWNz$m>1icsXG2N+((x0OIST9Zo^DW_tytvlwXGpn zs8?pJXjEG;T@qrZi%#h93?FP$!&P4JA(&H61tqQi=opRzNpm zkrG}$^t9&XduK*Qa1?355wd8G2CI6QEh@Ua>AsD;7oRUNLPb76m4HG3K?)wF~IyS3`fXuNM>${?wmB zpVz;?6_(Fiadfd{vUCBM*_kt$+F3J+IojI;9L(gc9n3{sEZyzR9o!_mOwFC#tQ{Q~ zP3-`#uK#tP3Q7~Q;4H|wjZHO8h7e4IuBxl&vz2w~D8)w=Wtg31zpZhz%+kzSzL*dV zwp@{WU4i;hJ7c2f1O;7Mz6qRKeASoIv0_bV=i@NMG*l<#+;INk-^`5w@}Dj~;k=|}qM1vq_P z|GpBGe_IKq|LNy9SJhKOQ$c=5L{Dv|Q_lZl=-ky*BFBJLW9&y_C|!vyM~rQx=!vun z?rZJQB5t}Dctmui5i31C_;_}CEn}_W%>oSXtt>@kE1=JW*4*v4tPp;O6 zmAk{)m!)}34pTWg8{i>($%NQ(Tl;QC@J@FfBoc%Gr&m560^kgSfodAFrIjF}aIw)X zoXZ`@IsMkc8_=w%-7`D6Y4e*CG8k%Ud=GXhsTR50jUnm+R*0A(O3UKFg0`K;qp1bl z7``HN=?39ic_kR|^R^~w-*pa?Vj#7|e9F1iRx{GN2?wK!xR1GW!qa=~pjJb-#u1K8 zeR?Y2i-pt}yJq;SCiVHODIvQJX|ZJaT8nO+(?HXbLefulKKgM^B(UIO1r+S=7;kLJ zcH}1J=Px2jsh3Tec&v8Jcbng8;V-`#*UHt?hB(pmOipKwf3Lz8rG$heEB30Sg*2rx zV<|KN86$soN(I!BwO`1n^^uF2*x&vJ$2d$>+`(romzHP|)K_KkO6Hc>_dwMW-M(#S zK(~SiXT1@fvc#U+?|?PniDRm01)f^#55;nhM|wi?oG>yBsa?~?^xTU|fX-R(sTA+5 zaq}-8Tx7zrOy#3*JLIIVsBmHYLdD}!0NP!+ITW+Thn0)8SS!$@)HXwB3tY!fMxc#1 zMp3H?q3eD?u&Njx4;KQ5G>32+GRp1Ee5qMO0lZjaRRu&{W<&~DoJNGkcYF<5(Ab+J zgO>VhBl{okDPn78<%&e2mR{jwVCz5Og;*Z;;3%VvoGo_;HaGLWYF7q#jDX=Z#Ml`H z858YVV$%J|e<1n`%6Vsvq7GmnAV0wW4$5qQ3uR@1i>tW{xrl|ExywIc?fNgYlA?C5 zh$ezAFb5{rQu6i7BSS5*J-|9DQ{6^BVQ{b*lq`xS@RyrsJN?-t=MTMPY;WYeKBCNg z^2|pN!Q^WPJuuO4!|P@jzt&tY1Y8d%FNK5xK(!@`jO2aEA*4 zkO6b|UVBipci?){-Ke=+1;mGlND8)6+P;8sq}UXw2hn;fc7nM>g}GSMWu&v&fqh

iViYT=fZ(|3Ox^$aWPp4a8h24tD<|8-!aK0lHgL$N7Efw}J zVIB!7=T$U`ao1?upi5V4Et*-lTG0XvExbf!ya{cua==$WJyVG(CmA6Of*8E@DSE%L z`V^$qz&RU$7G5mg;8;=#`@rRG`-uS18$0WPN@!v2d{H2sOqP|!(cQ@ zUHo!d>>yFArLPf1q`uBvY32miqShLT1B@gDL4XoVTK&@owOoD)OIHXrYK-a1d$B{v zF^}8D3Y^g%^cnvScOSJR5QNH+BI%d|;J;wWM3~l>${fb8DNPg)wrf|GBP8p%LNGN# z3EaIiItgwtGgT&iYCFy9-LG}bMI|4LdmmJt@V@% zb6B)1kc=T)(|L@0;wr<>=?r04N;E&ef+7C^`wPWtyQe(*pD1pI_&XHy|0gIGHMekd zF_*M4yi6J&Z4LQj65)S zXwdM{SwUo%3SbPwFsHgqF@V|6afT|R6?&S;lw=8% z3}@9B=#JI3@B*#4s!O))~z zc>2_4Q_#&+5V`GFd?88^;c1i7;Vv_I*qt!_Yx*n=;rj!82rrR2rQ8u5(Ejlo{15P% zs~!{%XJ>FmJ})H^I9bn^Re&38H{xA!0l3^89k(oU;bZWXM@kn$#aoS&Y4l^-WEn-fH39Jb9lA%s*WsKJQl?n9B7_~P z-XM&WL7Z!PcoF6_D>V@$CvUIEy=+Z&0kt{szMk=f1|M+r*a43^$$B^MidrT0J;RI` z(?f!O<8UZkm$_Ny$Hth1J#^4ni+im8M9mr&k|3cIgwvjAgjH z8`N&h25xV#v*d$qBX5jkI|xOhQn!>IYZK7l5#^P4M&twe9&Ey@@GxYMxBZq2e7?`q z$~Szs0!g{2fGcp9PZEt|rdQ6bhAgpcLHPz?f-vB?$dc*!9OL?Q8mn7->bFD2Si60* z!O%y)fCdMSV|lkF9w%x~J*A&srMyYY3{=&$}H zGQ4VG_?$2X(0|vT0{=;W$~icCI{b6W{B!Q8xdGhF|D{25G_5_+%s(46lhvNLkik~R z>nr(&C#5wwOzJZQo9m|U<;&Wk!_#q|V>fsmj1g<6%hB{jGoNUPjgJslld>xmODzGjYc?7JSuA?A_QzjDw5AsRgi@Y|Z0{F{!1=!NES-#*f^s4l0Hu zz468))2IY5dmD9pa*(yT5{EyP^G>@ZWumealS-*WeRcZ}B%gxq{MiJ|RyX-^C1V=0 z@iKdrGi1jTe8Ya^x7yyH$kBNvM4R~`fbPq$BzHum-3Zo8C6=KW@||>zsA8-Y9uV5V z#oq-f5L5}V<&wF4@X@<3^C%ptp6+Ce)~hGl`kwj)bsAjmo_GU^r940Z-|`<)oGnh7 zFF0Tde3>ui?8Yj{sF-Z@)yQd~CGZ*w-6p2U<8}JO-sRsVI5dBji`01W8A&3$?}lxBaC&vn0E$c5tW* zX>5(zzZ=qn&!J~KdsPl;P@bmA-Pr8T*)eh_+Dv5=Ma|XSle6t(k8qcgNyar{*ReQ8 zTXwi=8vr>!3Ywr+BhggHDw8ke==NTQVMCK`$69fhzEFB*4+H9LIvdt-#IbhZvpS}} zO3lz;P?zr0*0$%-Rq_y^k(?I{Mk}h@w}cZpMUp|ucs55bcloL2)($u%mXQw({Wzc~ z;6nu5MkjP)0C(@%6Q_I_vsWrfhl7Zpoxw#WoE~r&GOSCz;_ro6i(^hM>I$8y>`!wW z*U^@?B!MMmb89I}2(hcE4zN2G^kwyWCZp5JG>$Ez7zP~D=J^LMjSM)27_0B_X^C(M z`fFT+%DcKlu?^)FCK>QzSnV%IsXVcUFhFdBP!6~se&xxrIxsvySAWu++IrH;FbcY$ z2DWTvSBRfLwdhr0nMx+URA$j3i7_*6BWv#DXfym?ZRDcX9C?cY9sD3q)uBDR3uWg= z(lUIzB)G$Hr!){>E{s4Dew+tb9kvToZp-1&c?y2wn@Z~(VBhqz`cB;{E4(P3N2*nJ z_>~g@;UF2iG{Kt(<1PyePTKahF8<)pozZ*xH~U-kfoAayCwJViIrnqwqO}7{0pHw$ zs2Kx?s#vQr7XZ264>5RNKSL8|Ty^=PsIx^}QqOOcfpGUU4tRkUc|kc7-!Ae6!+B{o~7nFpm3|G5^=0#Bnm6`V}oSQlrX(u%OWnC zoLPy&Q;1Jui&7ST0~#+}I^&?vcE*t47~Xq#YwvA^6^} z`WkC)$AkNub|t@S!$8CBlwbV~?yp&@9h{D|3z-vJXgzRC5^nYm+PyPcgRzAnEi6Q^gslXYRv4nycsy-SJu?lMps-? zV`U*#WnFsdPLL)Q$AmD|0`UaC4ND07+&UmOu!eHruzV|OUox<+Jl|Mr@6~C`T@P%s zW7sgXLF2SSe9Fl^O(I*{9wsFSYb2l%-;&Pi^dpv!{)C3d0AlNY6!4fgmSgj_wQ*7Am7&$z;Jg&wgR-Ih;lUvWS|KTSg!&s_E9_bXBkZvGiC6bFKDWZxsD$*NZ#_8bl zG1P-#@?OQzED7@jlMJTH@V!6k;W>auvft)}g zhoV{7$q=*;=l{O>Q4a@ ziMjf_u*o^PsO)#BjC%0^h>Xp@;5$p{JSYDt)zbb}s{Kbt!T*I@Pk@X0zds6wsefuU zW$XY%yyRGC94=6mf?x+bbA5CDQ2AgW1T-jVAJbm7K(gp+;v6E0WI#kuACgV$r}6L? zd|Tj?^%^*N&b>Dd{Wr$FS2qI#Ucs1yd4N+RBUQiSZGujH`#I)mG&VKoDh=KKFl4=G z&MagXl6*<)$6P}*Tiebpz5L=oMaPrN+caUXRJ`D?=K9!e0f{@D&cZLKN?iNP@X0aF zE(^pl+;*T5qt?1jRC=5PMgV!XNITRLS_=9{CJExaQj;lt!&pdzpK?8p>%Mb+D z?yO*uSung=-`QQ@yX@Hyd4@CI^r{2oiu`%^bNkz+Nkk!IunjwNC|WcqvX~k=><-I3 zDQdbdb|!v+Iz01$w@aMl!R)koD77Xp;eZwzSl-AT zr@Vu{=xvgfq9akRrrM)}=!=xcs+U1JO}{t(avgz`6RqiiX<|hGG1pmop8k6Q+G_mv zJv|RfDheUp2L3=^C=4aCBMBn0aRCU(DQwX-W(RkRwmLeuJYF<0urcaf(=7)JPg<3P zQs!~G)9CT18o!J4{zX{_e}4eS)U-E)0FAt}wEI(c0%HkxgggW;(1E=>J17_hsH^sP z%lT0LGgbUXHx-K*CI-MCrP66UP0PvGqM$MkeLyqHdbgP|_Cm!7te~b8p+e6sQ_3k| zVcwTh6d83ltdnR>D^)BYQpDKlLk3g0Hdcgz2}%qUs9~~Rie)A-BV1mS&naYai#xcZ z(d{8=-LVpTp}2*y)|gR~;qc7fp26}lPcLZ#=JpYcn3AT9(UIdOyg+d(P5T7D&*P}# zQCYplZO5|7+r19%9e`v^vfSS1sbX1c%=w1;oyruXB%Kl$ACgKQ6=qNWLsc=28xJjg zwvsI5-%SGU|3p>&zXVl^vVtQT3o-#$UT9LI@Npz~6=4!>mc431VRNN8od&Ul^+G_kHC`G=6WVWM z%9eWNyy(FTO|A+@x}Ou3CH)oi;t#7rAxdIXfNFwOj_@Y&TGz6P_sqiB`Q6Lxy|Q{`|fgmRG(k+!#b*M+Z9zFce)f-7;?Km5O=LHV9f9_87; zF7%R2B+$?@sH&&-$@tzaPYkw0;=i|;vWdI|Wl3q_Zu>l;XdIw2FjV=;Mq5t1Q0|f< zs08j54Bp`3RzqE=2enlkZxmX6OF+@|2<)A^RNQpBd6o@OXl+i)zO%D4iGiQNuXd+zIR{_lb96{lc~bxsBveIw6umhShTX+3@ZJ=YHh@ zWY3(d0azg;7oHn>H<>?4@*RQbi>SmM=JrHvIG(~BrvI)#W(EAeO6fS+}mxxcc+X~W6&YVl86W9WFSS}Vz-f9vS?XUDBk)3TcF z8V?$4Q)`uKFq>xT=)Y9mMFVTUk*NIA!0$?RP6Ig0TBmUFrq*Q-Agq~DzxjStQyJ({ zBeZ;o5qUUKg=4Hypm|}>>L=XKsZ!F$yNTDO)jt4H0gdQ5$f|d&bnVCMMXhNh)~mN z@_UV6D7MVlsWz+zM+inZZp&P4fj=tm6fX)SG5H>OsQf_I8c~uGCig$GzuwViK54bcgL;VN|FnyQl>Ed7(@>=8$a_UKIz|V6CeVSd2(P z0Uu>A8A+muM%HLFJQ9UZ5c)BSAv_zH#1f02x?h9C}@pN@6{>UiAp>({Fn(T9Q8B z^`zB;kJ5b`>%dLm+Ol}ty!3;8f1XDSVX0AUe5P#@I+FQ-`$(a;zNgz)4x5hz$Hfbg z!Q(z26wHLXko(1`;(BAOg_wShpX0ixfWq3ponndY+u%1gyX)_h=v1zR#V}#q{au6; z!3K=7fQwnRfg6FXtNQmP>`<;!N137paFS%y?;lb1@BEdbvQHYC{976l`cLqn;b8lp zIDY>~m{gDj(wfnK!lpW6pli)HyLEiUrNc%eXTil|F2s(AY+LW5hkKb>TQ3|Q4S9rr zpDs4uK_co6XPsn_z$LeS{K4jFF`2>U`tbgKdyDne`xmR<@6AA+_hPNKCOR-Zqv;xk zu5!HsBUb^!4uJ7v0RuH-7?l?}b=w5lzzXJ~gZcxRKOovSk@|#V+MuX%Y+=;14i*%{)_gSW9(#4%)AV#3__kac1|qUy!uyP{>?U#5wYNq}y$S9pCc zFc~4mgSC*G~j0u#qqp9 z${>3HV~@->GqEhr_Xwoxq?Hjn#=s2;i~g^&Hn|aDKpA>Oc%HlW(KA1?BXqpxB;Ydx)w;2z^MpjJ(Qi(X!$5RC z*P{~%JGDQqojV>2JbEeCE*OEu!$XJ>bWA9Oa_Hd;y)F%MhBRi*LPcdqR8X`NQ&1L# z5#9L*@qxrx8n}LfeB^J{%-?SU{FCwiWyHp682F+|pa+CQa3ZLzBqN1{)h4d6+vBbV zC#NEbQLC;}me3eeYnOG*nXOJZEU$xLZ1<1Y=7r0(-U0P6-AqwMAM`a(Ed#7vJkn6plb4eI4?2y3yOTGmmDQ!z9`wzbf z_OY#0@5=bnep;MV0X_;;SJJWEf^E6Bd^tVJ9znWx&Ks8t*B>AM@?;D4oWUGc z!H*`6d7Cxo6VuyS4Eye&L1ZRhrRmN6Lr`{NL(wDbif|y&z)JN>Fl5#Wi&mMIr5i;x zBx}3YfF>>8EC(fYnmpu~)CYHuHCyr5*`ECap%t@y=jD>!_%3iiE|LN$mK9>- zHdtpy8fGZtkZF?%TW~29JIAfi2jZT8>OA7=h;8T{{k?c2`nCEx9$r zS+*&vt~2o^^J+}RDG@+9&M^K*z4p{5#IEVbz`1%`m5c2};aGt=V?~vIM}ZdPECDI)47|CWBCfDWUbxBCnmYivQ*0Nu_xb*C>~C9(VjHM zxe<*D<#dQ8TlpMX2c@M<9$w!RP$hpG4cs%AI){jp*Sj|*`m)5(Bw*A0$*i-(CA5#%>a)$+jI2C9r6|(>J8InryENI z$NohnxDUB;wAYDwrb*!N3noBTKPpPN}~09SEL18tkG zxgz(RYU_;DPT{l?Q$+eaZaxnsWCA^ds^0PVRkIM%bOd|G2IEBBiz{&^JtNsODs;5z zICt_Zj8wo^KT$7Bg4H+y!Df#3mbl%%?|EXe!&(Vmac1DJ*y~3+kRKAD=Ovde4^^%~ zw<9av18HLyrf*_>Slp;^i`Uy~`mvBjZ|?Ad63yQa#YK`4+c6;pW4?XIY9G1(Xh9WO8{F-Aju+nS9Vmv=$Ac0ienZ+p9*O%NG zMZKy5?%Z6TAJTE?o5vEr0r>f>hb#2w2U3DL64*au_@P!J!TL`oH2r*{>ffu6|A7tv zL4juf$DZ1MW5ZPsG!5)`k8d8c$J$o;%EIL0va9&GzWvkS%ZsGb#S(?{!UFOZ9<$a| zY|a+5kmD5N&{vRqkgY>aHsBT&`rg|&kezoD)gP0fsNYHsO#TRc_$n6Lf1Z{?+DLziXlHrq4sf(!>O{?Tj;Eh@%)+nRE_2VxbN&&%%caU#JDU%vL3}Cb zsb4AazPI{>8H&d=jUaZDS$-0^AxE@utGs;-Ez_F(qC9T=UZX=>ok2k2 ziTn{K?y~a5reD2A)P${NoI^>JXn>`IeArow(41c-Wm~)wiryEP(OS{YXWi7;%dG9v zI?mwu1MxD{yp_rrk!j^cKM)dc4@p4Ezyo%lRN|XyD}}>v=Xoib0gOcdXrQ^*61HNj z=NP|pd>@yfvr-=m{8$3A8TQGMTE7g=z!%yt`8`Bk-0MMwW~h^++;qyUP!J~ykh1GO z(FZ59xuFR$(WE;F@UUyE@Sp>`aVNjyj=Ty>_Vo}xf`e7`F;j-IgL5`1~-#70$9_=uBMq!2&1l zomRgpD58@)YYfvLtPW}{C5B35R;ZVvB<<#)x%srmc_S=A7F@DW8>QOEGwD6suhwCg z>Pa+YyULhmw%BA*4yjDp|2{!T98~<6Yfd(wo1mQ!KWwq0eg+6)o1>W~f~kL<-S+P@$wx*zeI|1t7z#Sxr5 zt6w+;YblPQNplq4Z#T$GLX#j6yldXAqj>4gAnnWtBICUnA&-dtnlh=t0Ho_vEKwV` z)DlJi#!@nkYV#$!)@>udAU*hF?V`2$Hf=V&6PP_|r#Iv*J$9)pF@X3`k;5})9^o4y z&)~?EjX5yX12O(BsFy-l6}nYeuKkiq`u9145&3Ssg^y{5G3Pse z9w(YVa0)N-fLaBq1`P!_#>SS(8fh_5!f{UrgZ~uEdeMJIz7DzI5!NHHqQtm~#CPij z?=N|J>nPR6_sL7!f4hD_|KH`vf8(Wpnj-(gPWH+ZvID}%?~68SwhPTC3u1_cB`otq z)U?6qo!ZLi5b>*KnYHWW=3F!p%h1;h{L&(Q&{qY6)_qxNfbP6E3yYpW!EO+IW3?@J z);4>g4gnl^8klu7uA>eGF6rIGSynacogr)KUwE_R4E5Xzi*Qir@b-jy55-JPC8c~( zo!W8y9OGZ&`xmc8;=4-U9=h{vCqfCNzYirONmGbRQlR`WWlgnY+1wCXbMz&NT~9*| z6@FrzP!LX&{no2!Ln_3|I==_4`@}V?4a;YZKTdw;vT<+K+z=uWbW(&bXEaWJ^W8Td z-3&1bY^Z*oM<=M}LVt>_j+p=2Iu7pZmbXrhQ_k)ysE9yXKygFNw$5hwDn(M>H+e1&9BM5!|81vd%r%vEm zqxY3?F@fb6O#5UunwgAHR9jp_W2zZ}NGp2%mTW@(hz7$^+a`A?mb8|_G*GNMJ) zjqegXQio=i@AINre&%ofexAr95aop5C+0MZ0m-l=MeO8m3epm7U%vZB8+I+C*iNFM z#T3l`gknX;D$-`2XT^Cg*vrv=RH+P;_dfF++cP?B_msQI4j+lt&rX2)3GaJx%W*Nn zkML%D{z5tpHH=dksQ*gzc|}gzW;lwAbxoR07VNgS*-c3d&8J|;@3t^ zVUz*J*&r7DFRuFVDCJDK8V9NN5hvpgGjwx+5n)qa;YCKe8TKtdnh{I7NU9BCN!0dq zczrBk8pE{{@vJa9ywR@mq*J=v+PG;?fwqlJVhijG!3VmIKs>9T6r7MJpC)m!Tc#>g zMtVsU>wbwFJEfwZ{vB|ZlttNe83)$iz`~#8UJ^r)lJ@HA&G#}W&ZH*;k{=TavpjWE z7hdyLZPf*X%Gm}i`Y{OGeeu^~nB8=`{r#TUrM-`;1cBvEd#d!kPqIgYySYhN-*1;L z^byj%Yi}Gx)Wnkosi337BKs}+5H5dth1JA{Ir-JKN$7zC)*}hqeoD(WfaUDPT>0`- z(6sa0AoIqASwF`>hP}^|)a_j2s^PQn*qVC{Q}htR z5-)duBFXT_V56-+UohKXlq~^6uf!6sA#ttk1o~*QEy_Y-S$gAvq47J9Vtk$5oA$Ct zYhYJ@8{hsC^98${!#Ho?4y5MCa7iGnfz}b9jE~h%EAAv~Qxu)_rAV;^cygV~5r_~?l=B`zObj7S=H=~$W zPtI_m%g$`kL_fVUk9J@>EiBH zOO&jtn~&`hIFMS5S`g8w94R4H40mdNUH4W@@XQk1sr17b{@y|JB*G9z1|CrQjd+GX z6+KyURG3;!*BQrentw{B2R&@2&`2}n(z-2&X7#r!{yg@Soy}cRD~j zj9@UBW+N|4HW4AWapy4wfUI- zZ`gSL6DUlgj*f1hSOGXG0IVH8HxK?o2|3HZ;KW{K+yPAlxtb)NV_2AwJm|E)FRs&& z=c^e7bvUsztY|+f^k7NXs$o1EUq>cR7C0$UKi6IooHWlK_#?IWDkvywnzg&ThWo^? z2O_N{5X39#?eV9l)xI(>@!vSB{DLt*oY!K1R8}_?%+0^C{d9a%N4 zoxHVT1&Lm|uDX%$QrBun5e-F`HJ^T$ zmzv)p@4ZHd_w9!%Hf9UYNvGCw2TTTbrj9pl+T9%-_-}L(tES>Or-}Z4F*{##n3~L~TuxjirGuIY#H7{%$E${?p{Q01 zi6T`n;rbK1yIB9jmQNycD~yZq&mbIsFWHo|ZAChSFPQa<(%d8mGw*V3fh|yFoxOOiWJd(qvVb!Z$b88cg->N=qO*4k~6;R==|9ihg&riu#P~s4Oap9O7f%crSr^rljeIfXDEg>wi)&v*a%7zpz<9w z*r!3q9J|390x`Zk;g$&OeN&ctp)VKRpDSV@kU2Q>jtok($Y-*x8_$2piTxun81@vt z!Vj?COa0fg2RPXMSIo26T=~0d`{oGP*eV+$!0I<(4azk&Vj3SiG=Q!6mX0p$z7I}; z9BJUFgT-K9MQQ-0@Z=^7R<{bn2Fm48endsSs`V7_@%8?Bxkqv>BDoVcj?K#dV#uUP zL1ND~?D-|VGKe3Rw_7-Idpht>H6XRLh*U7epS6byiGvJpr%d}XwfusjH9g;Z98H`x zyde%%5mhGOiL4wljCaWCk-&uE4_OOccb9c!ZaWt4B(wYl!?vyzl%7n~QepN&eFUrw zFIOl9c({``6~QD+43*_tzP{f2x41h(?b43^y6=iwyB)2os5hBE!@YUS5?N_tXd=h( z)WE286Fbd>R4M^P{!G)f;h<3Q>Fipuy+d2q-)!RyTgt;wr$(?9ox3;q+{E*ZQHhOn;lM`cjnu9 zXa48ks-v(~b*;MAI<>YZH(^NV8vjb34beE<_cwKlJoR;k6lJNSP6v}uiyRD?|0w+X@o1ONrH8a$fCxXpf? z?$DL0)7|X}Oc%h^zrMKWc-NS9I0Utu@>*j}b@tJ=ixQSJ={4@854wzW@E>VSL+Y{i z#0b=WpbCZS>kUCO_iQz)LoE>P5LIG-hv9E+oG}DtlIDF>$tJ1aw9^LuhLEHt?BCj& z(O4I8v1s#HUi5A>nIS-JK{v!7dJx)^Yg%XjNmlkWAq2*cv#tHgz`Y(bETc6CuO1VkN^L-L3j_x<4NqYb5rzrLC-7uOv z!5e`GZt%B782C5-fGnn*GhDF$%(qP<74Z}3xx+{$4cYKy2ikxI7B2N+2r07DN;|-T->nU&!=Cm#rZt%O_5c&1Z%nlWq3TKAW0w zQqemZw_ue--2uKQsx+niCUou?HjD`xhEjjQd3%rrBi82crq*~#uA4+>vR<_S{~5ce z-2EIl?~s z1=GVL{NxP1N3%=AOaC}j_Fv=ur&THz zyO!d9kHq|c73kpq`$+t+8Bw7MgeR5~`d7ChYyGCBWSteTB>8WAU(NPYt2Dk`@#+}= zI4SvLlyk#pBgVigEe`?NG*vl7V6m+<}%FwPV=~PvvA)=#ths==DRTDEYh4V5}Cf$z@#;< zyWfLY_5sP$gc3LLl2x+Ii)#b2nhNXJ{R~vk`s5U7Nyu^3yFg&D%Txwj6QezMX`V(x z=C`{76*mNb!qHHs)#GgGZ_7|vkt9izl_&PBrsu@}L`X{95-2jf99K)0=*N)VxBX2q z((vkpP2RneSIiIUEnGb?VqbMb=Zia+rF~+iqslydE34cSLJ&BJW^3knX@M;t*b=EA zNvGzv41Ld_T+WT#XjDB840vovUU^FtN_)G}7v)1lPetgpEK9YS^OWFkPoE{ovj^=@ zO9N$S=G$1ecndT_=5ehth2Lmd1II-PuT~C9`XVePw$y8J#dpZ?Tss<6wtVglm(Ok7 z3?^oi@pPio6l&!z8JY(pJvG=*pI?GIOu}e^EB6QYk$#FJQ%^AIK$I4epJ+9t?KjqA+bkj&PQ*|vLttme+`9G=L% ziadyMw_7-M)hS(3E$QGNCu|o23|%O+VN7;Qggp?PB3K-iSeBa2b}V4_wY`G1Jsfz4 z9|SdB^;|I8E8gWqHKx!vj_@SMY^hLEIbSMCuE?WKq=c2mJK z8LoG-pnY!uhqFv&L?yEuxo{dpMTsmCn)95xanqBrNPTgXP((H$9N${Ow~Is-FBg%h z53;|Y5$MUN)9W2HBe2TD`ct^LHI<(xWrw}$qSoei?}s)&w$;&!14w6B6>Yr6Y8b)S z0r71`WmAvJJ`1h&poLftLUS6Ir zC$bG9!Im_4Zjse)#K=oJM9mHW1{%l8sz$1o?ltdKlLTxWWPB>Vk22czVt|1%^wnN@*!l)}?EgtvhC>vlHm^t+ogpgHI1_$1ox9e;>0!+b(tBrmXRB`PY1vp-R**8N7 zGP|QqI$m(Rdu#=(?!(N}G9QhQ%o!aXE=aN{&wtGP8|_qh+7a_j_sU5|J^)vxq;# zjvzLn%_QPHZZIWu1&mRAj;Sa_97p_lLq_{~j!M9N^1yp3U_SxRqK&JnR%6VI#^E12 z>CdOVI^_9aPK2eZ4h&^{pQs}xsijXgFYRIxJ~N7&BB9jUR1fm!(xl)mvy|3e6-B3j zJn#ajL;bFTYJ2+Q)tDjx=3IklO@Q+FFM}6UJr6km7hj7th9n_&JR7fnqC!hTZoM~T zBeaVFp%)0cbPhejX<8pf5HyRUj2>aXnXBqDJe73~J%P(2C?-RT{c3NjE`)om! zl$uewSgWkE66$Kb34+QZZvRn`fob~Cl9=cRk@Es}KQm=?E~CE%spXaMO6YmrMl%9Q zlA3Q$3|L1QJ4?->UjT&CBd!~ru{Ih^in&JXO=|<6J!&qp zRe*OZ*cj5bHYlz!!~iEKcuE|;U4vN1rk$xq6>bUWD*u(V@8sG^7>kVuo(QL@Ki;yL zWC!FT(q{E8#on>%1iAS0HMZDJg{Z{^!De(vSIq&;1$+b)oRMwA3nc3mdTSG#3uYO_ z>+x;7p4I;uHz?ZB>dA-BKl+t-3IB!jBRgdvAbW!aJ(Q{aT>+iz?91`C-xbe)IBoND z9_Xth{6?(y3rddwY$GD65IT#f3<(0o#`di{sh2gm{dw*#-Vnc3r=4==&PU^hCv$qd zjw;>i&?L*Wq#TxG$mFIUf>eK+170KG;~+o&1;Tom9}}mKo23KwdEM6UonXgc z!6N(@k8q@HPw{O8O!lAyi{rZv|DpgfU{py+j(X_cwpKqcalcqKIr0kM^%Br3SdeD> zHSKV94Yxw;pjzDHo!Q?8^0bb%L|wC;4U^9I#pd5O&eexX+Im{ z?jKnCcsE|H?{uGMqVie_C~w7GX)kYGWAg%-?8|N_1#W-|4F)3YTDC+QSq1s!DnOML3@d`mG%o2YbYd#jww|jD$gotpa)kntakp#K;+yo-_ZF9qrNZw<%#C zuPE@#3RocLgPyiBZ+R_-FJ_$xP!RzWm|aN)S+{$LY9vvN+IW~Kf3TsEIvP+B9Mtm! zpfNNxObWQpLoaO&cJh5>%slZnHl_Q~(-Tfh!DMz(dTWld@LG1VRF`9`DYKhyNv z2pU|UZ$#_yUx_B_|MxUq^glT}O5Xt(Vm4Mr02><%C)@v;vPb@pT$*yzJ4aPc_FZ3z z3}PLoMBIM>q_9U2rl^sGhk1VUJ89=*?7|v`{!Z{6bqFMq(mYiA?%KbsI~JwuqVA9$H5vDE+VocjX+G^%bieqx->s;XWlKcuv(s%y%D5Xbc9+ zc(_2nYS1&^yL*ey664&4`IoOeDIig}y-E~_GS?m;D!xv5-xwz+G`5l6V+}CpeJDi^ z%4ed$qowm88=iYG+(`ld5Uh&>Dgs4uPHSJ^TngXP_V6fPyl~>2bhi20QB%lSd#yYn zO05?KT1z@?^-bqO8Cg`;ft>ilejsw@2%RR7;`$Vs;FmO(Yr3Fp`pHGr@P2hC%QcA|X&N2Dn zYf`MqXdHi%cGR@%y7Rg7?d3?an){s$zA{!H;Ie5exE#c~@NhQUFG8V=SQh%UxUeiV zd7#UcYqD=lk-}sEwlpu&H^T_V0{#G?lZMxL7ih_&{(g)MWBnCZxtXg znr#}>U^6!jA%e}@Gj49LWG@*&t0V>Cxc3?oO7LSG%~)Y5}f7vqUUnQ;STjdDU}P9IF9d9<$;=QaXc zL1^X7>fa^jHBu_}9}J~#-oz3Oq^JmGR#?GO7b9a(=R@fw@}Q{{@`Wy1vIQ#Bw?>@X z-_RGG@wt|%u`XUc%W{J z>iSeiz8C3H7@St3mOr_mU+&bL#Uif;+Xw-aZdNYUpdf>Rvu0i0t6k*}vwU`XNO2he z%miH|1tQ8~ZK!zmL&wa3E;l?!!XzgV#%PMVU!0xrDsNNZUWKlbiOjzH-1Uoxm8E#r`#2Sz;-o&qcqB zC-O_R{QGuynW14@)7&@yw1U}uP(1cov)twxeLus0s|7ayrtT8c#`&2~Fiu2=R;1_4bCaD=*E@cYI>7YSnt)nQc zohw5CsK%m?8Ack)qNx`W0_v$5S}nO|(V|RZKBD+btO?JXe|~^Qqur%@eO~<8-L^9d z=GA3-V14ng9L29~XJ>a5k~xT2152zLhM*@zlp2P5Eu}bywkcqR;ISbas&#T#;HZSf z2m69qTV(V@EkY(1Dk3`}j)JMo%ZVJ*5eB zYOjIisi+igK0#yW*gBGj?@I{~mUOvRFQR^pJbEbzFxTubnrw(Muk%}jI+vXmJ;{Q6 zrSobKD>T%}jV4Ub?L1+MGOD~0Ir%-`iTnWZN^~YPrcP5y3VMAzQ+&en^VzKEb$K!Q z<7Dbg&DNXuow*eD5yMr+#08nF!;%4vGrJI++5HdCFcGLfMW!KS*Oi@=7hFwDG!h2< zPunUEAF+HncQkbfFj&pbzp|MU*~60Z(|Ik%Tn{BXMN!hZOosNIseT?R;A`W?=d?5X zK(FB=9mZusYahp|K-wyb={rOpdn=@;4YI2W0EcbMKyo~-#^?h`BA9~o285%oY zfifCh5Lk$SY@|2A@a!T2V+{^!psQkx4?x0HSV`(w9{l75QxMk!)U52Lbhn{8ol?S) zCKo*7R(z!uk<6*qO=wh!Pul{(qq6g6xW;X68GI_CXp`XwO zxuSgPRAtM8K7}5E#-GM!*ydOOG_{A{)hkCII<|2=ma*71ci_-}VPARm3crFQjLYV! z9zbz82$|l01mv`$WahE2$=fAGWkd^X2kY(J7iz}WGS z@%MyBEO=A?HB9=^?nX`@nh;7;laAjs+fbo!|K^mE!tOB>$2a_O0y-*uaIn8k^6Y zSbuv;5~##*4Y~+y7Z5O*3w4qgI5V^17u*ZeupVGH^nM&$qmAk|anf*>r zWc5CV;-JY-Z@Uq1Irpb^O`L_7AGiqd*YpGUShb==os$uN3yYvb`wm6d=?T*it&pDk zo`vhw)RZX|91^^Wa_ti2zBFyWy4cJu#g)_S6~jT}CC{DJ_kKpT`$oAL%b^!2M;JgT zM3ZNbUB?}kP(*YYvXDIH8^7LUxz5oE%kMhF!rnPqv!GiY0o}NR$OD=ITDo9r%4E>E0Y^R(rS^~XjWyVI6 zMOR5rPXhTp*G*M&X#NTL`Hu*R+u*QNoiOKg4CtNPrjgH>c?Hi4MUG#I917fx**+pJfOo!zFM&*da&G_x)L(`k&TPI*t3e^{crd zX<4I$5nBQ8Ax_lmNRa~E*zS-R0sxkz`|>7q_?*e%7bxqNm3_eRG#1ae3gtV9!fQpY z+!^a38o4ZGy9!J5sylDxZTx$JmG!wg7;>&5H1)>f4dXj;B+@6tMlL=)cLl={jLMxY zbbf1ax3S4>bwB9-$;SN2?+GULu;UA-35;VY*^9Blx)Jwyb$=U!D>HhB&=jSsd^6yw zL)?a|>GxU!W}ocTC(?-%z3!IUhw^uzc`Vz_g>-tv)(XA#JK^)ZnC|l1`@CdX1@|!| z_9gQ)7uOf?cR@KDp97*>6X|;t@Y`k_N@)aH7gY27)COv^P3ya9I{4z~vUjLR9~z1Z z5=G{mVtKH*&$*t0@}-i_v|3B$AHHYale7>E+jP`ClqG%L{u;*ff_h@)al?RuL7tOO z->;I}>%WI{;vbLP3VIQ^iA$4wl6@0sDj|~112Y4OFjMs`13!$JGkp%b&E8QzJw_L5 zOnw9joc0^;O%OpF$Qp)W1HI!$4BaXX84`%@#^dk^hFp^pQ@rx4g(8Xjy#!X%+X5Jd@fs3amGT`}mhq#L97R>OwT5-m|h#yT_-v@(k$q7P*9X~T*3)LTdzP!*B} z+SldbVWrrwQo9wX*%FyK+sRXTa@O?WM^FGWOE?S`R(0P{<6p#f?0NJvnBia?k^fX2 zNQs7K-?EijgHJY}&zsr;qJ<*PCZUd*x|dD=IQPUK_nn)@X4KWtqoJNHkT?ZWL_hF? zS8lp2(q>;RXR|F;1O}EE#}gCrY~#n^O`_I&?&z5~7N;zL0)3Tup`%)oHMK-^r$NT% zbFg|o?b9w(q@)6w5V%si<$!U<#}s#x@0aX-hP>zwS#9*75VXA4K*%gUc>+yzupTDBOKH8WR4V0pM(HrfbQ&eJ79>HdCvE=F z|J>s;;iDLB^3(9}?biKbxf1$lI!*Z%*0&8UUq}wMyPs_hclyQQi4;NUY+x2qy|0J; zhn8;5)4ED1oHwg+VZF|80<4MrL97tGGXc5Sw$wAI#|2*cvQ=jB5+{AjMiDHmhUC*a zlmiZ`LAuAn_}hftXh;`Kq0zblDk8?O-`tnilIh|;3lZp@F_osJUV9`*R29M?7H{Fy z`nfVEIDIWXmU&YW;NjU8)EJpXhxe5t+scf|VXM!^bBlwNh)~7|3?fWwo_~ZFk(22% zTMesYw+LNx3J-_|DM~`v93yXe=jPD{q;li;5PD?Dyk+b? zo21|XpT@)$BM$%F=P9J19Vi&1#{jM3!^Y&fr&_`toi`XB1!n>sbL%U9I5<7!@?t)~ z;&H%z>bAaQ4f$wIzkjH70;<8tpUoxzKrPhn#IQfS%9l5=Iu))^XC<58D!-O z{B+o5R^Z21H0T9JQ5gNJnqh#qH^na|z92=hONIM~@_iuOi|F>jBh-?aA20}Qx~EpDGElELNn~|7WRXRFnw+Wdo`|# zBpU=Cz3z%cUJ0mx_1($X<40XEIYz(`noWeO+x#yb_pwj6)R(__%@_Cf>txOQ74wSJ z0#F3(zWWaR-jMEY$7C*3HJrohc79>MCUu26mfYN)f4M~4gD`}EX4e}A!U}QV8!S47 z6y-U-%+h`1n`*pQuKE%Av0@)+wBZr9mH}@vH@i{v(m-6QK7Ncf17x_D=)32`FOjjo zg|^VPf5c6-!FxN{25dvVh#fog=NNpXz zfB$o+0jbRkHH{!TKhE709f+jI^$3#v1Nmf80w`@7-5$1Iv_`)W^px8P-({xwb;D0y z7LKDAHgX<84?l!I*Dvi2#D@oAE^J|g$3!)x1Ua;_;<@#l1fD}lqU2_tS^6Ht$1Wl} zBESo7o^)9-Tjuz$8YQSGhfs{BQV6zW7dA?0b(Dbt=UnQs&4zHfe_sj{RJ4uS-vQpC zX;Bbsuju4%!o8?&m4UZU@~ZZjeFF6ex2ss5_60_JS_|iNc+R0GIjH1@Z z=rLT9%B|WWgOrR7IiIwr2=T;Ne?30M!@{%Qf8o`!>=s<2CBpCK_TWc(DX51>e^xh8 z&@$^b6CgOd7KXQV&Y4%}_#uN*mbanXq(2=Nj`L7H7*k(6F8s6{FOw@(DzU`4-*77{ zF+dxpv}%mFpYK?>N_2*#Y?oB*qEKB}VoQ@bzm>ptmVS_EC(#}Lxxx730trt0G)#$b zE=wVvtqOct1%*9}U{q<)2?{+0TzZzP0jgf9*)arV)*e!f`|jgT{7_9iS@e)recI#z zbzolURQ+TOzE!ymqvBY7+5NnAbWxvMLsLTwEbFqW=CPyCsmJ}P1^V30|D5E|p3BC5 z)3|qgw@ra7aXb-wsa|l^in~1_fm{7bS9jhVRkYVO#U{qMp z)Wce+|DJ}4<2gp8r0_xfZpMo#{Hl2MfjLcZdRB9(B(A(f;+4s*FxV{1F|4d`*sRNd zp4#@sEY|?^FIJ;tmH{@keZ$P(sLh5IdOk@k^0uB^BWr@pk6mHy$qf&~rI>P*a;h0C{%oA*i!VjWn&D~O#MxN&f@1Po# zKN+ zrGrkSjcr?^R#nGl<#Q722^wbYcgW@{+6CBS<1@%dPA8HC!~a`jTz<`g_l5N1M@9wn9GOAZ>nqNgq!yOCbZ@1z`U_N`Z>}+1HIZxk*5RDc&rd5{3qjRh8QmT$VyS;jK z;AF+r6XnnCp=wQYoG|rT2@8&IvKq*IB_WvS%nt%e{MCFm`&W*#LXc|HrD?nVBo=(8*=Aq?u$sDA_sC_RPDUiQ+wnIJET8vx$&fxkW~kP9qXKt zozR)@xGC!P)CTkjeWvXW5&@2?)qt)jiYWWBU?AUtzAN}{JE1I)dfz~7$;}~BmQF`k zpn11qmObXwRB8&rnEG*#4Xax3XBkKlw(;tb?Np^i+H8m(Wyz9k{~ogba@laiEk;2! zV*QV^6g6(QG%vX5Um#^sT&_e`B1pBW5yVth~xUs#0}nv?~C#l?W+9Lsb_5)!71rirGvY zTIJ$OPOY516Y|_014sNv+Z8cc5t_V=i>lWV=vNu#!58y9Zl&GsMEW#pPYPYGHQ|;vFvd*9eM==$_=vc7xnyz0~ zY}r??$<`wAO?JQk@?RGvkWVJlq2dk9vB(yV^vm{=NVI8dhsX<)O(#nr9YD?I?(VmQ z^r7VfUBn<~p3()8yOBjm$#KWx!5hRW)5Jl7wY@ky9lNM^jaT##8QGVsYeaVywmpv>X|Xj7gWE1Ezai&wVLt3p)k4w~yrskT-!PR!kiyQlaxl(( zXhF%Q9x}1TMt3~u@|#wWm-Vq?ZerK={8@~&@9r5JW}r#45#rWii};t`{5#&3$W)|@ zbAf2yDNe0q}NEUvq_Quq3cTjcw z@H_;$hu&xllCI9CFDLuScEMg|x{S7GdV8<&Mq=ezDnRZAyX-8gv97YTm0bg=d)(>N z+B2FcqvI9>jGtnK%eO%y zoBPkJTk%y`8TLf4)IXPBn`U|9>O~WL2C~C$z~9|0m*YH<-vg2CD^SX#&)B4ngOSG$ zV^wmy_iQk>dfN@Pv(ckfy&#ak@MLC7&Q6Ro#!ezM*VEh`+b3Jt%m(^T&p&WJ2Oqvj zs-4nq0TW6cv~(YI$n0UkfwN}kg3_fp?(ijSV#tR9L0}l2qjc7W?i*q01=St0eZ=4h zyGQbEw`9OEH>NMuIe)hVwYHsGERWOD;JxEiO7cQv%pFCeR+IyhwQ|y@&^24k+|8fD zLiOWFNJ2&vu2&`Jv96_z-Cd5RLgmeY3*4rDOQo?Jm`;I_(+ejsPM03!ly!*Cu}Cco zrQSrEDHNyzT(D5s1rZq!8#?f6@v6dB7a-aWs(Qk>N?UGAo{gytlh$%_IhyL7h?DLXDGx zgxGEBQoCAWo-$LRvM=F5MTle`M})t3vVv;2j0HZY&G z22^iGhV@uaJh(XyyY%} zd4iH_UfdV#T=3n}(Lj^|n;O4|$;xhu*8T3hR1mc_A}fK}jfZ7LX~*n5+`8N2q#rI$ z@<_2VANlYF$vIH$ zl<)+*tIWW78IIINA7Rr7i{<;#^yzxoLNkXL)eSs=%|P>$YQIh+ea_3k z_s7r4%j7%&*NHSl?R4k%1>Z=M9o#zxY!n8sL5>BO-ZP;T3Gut>iLS@U%IBrX6BA3k z)&@q}V8a{X<5B}K5s(c(LQ=%v1ocr`t$EqqY0EqVjr65usa=0bkf|O#ky{j3)WBR(((L^wmyHRzoWuL2~WTC=`yZ zn%VX`L=|Ok0v7?s>IHg?yArBcync5rG#^+u)>a%qjES%dRZoIyA8gQ;StH z1Ao7{<&}6U=5}4v<)1T7t!J_CL%U}CKNs-0xWoTTeqj{5{?Be$L0_tk>M9o8 zo371}S#30rKZFM{`H_(L`EM9DGp+Mifk&IP|C2Zu_)Ghr4Qtpmkm1osCf@%Z$%t+7 zYH$Cr)Ro@3-QDeQJ8m+x6%;?YYT;k6Z0E-?kr>x33`H%*ueBD7Zx~3&HtWn0?2Wt} zTG}*|v?{$ajzt}xPzV%lL1t-URi8*Zn)YljXNGDb>;!905Td|mpa@mHjIH%VIiGx- zd@MqhpYFu4_?y5N4xiHn3vX&|e6r~Xt> zZG`aGq|yTNjv;9E+Txuoa@A(9V7g?1_T5FzRI;!=NP1Kqou1z5?%X~Wwb{trRfd>i z8&y^H)8YnKyA_Fyx>}RNmQIczT?w2J4SNvI{5J&}Wto|8FR(W;Qw#b1G<1%#tmYzQ zQ2mZA-PAdi%RQOhkHy9Ea#TPSw?WxwL@H@cbkZwIq0B!@ns}niALidmn&W?!Vd4Gj zO7FiuV4*6Mr^2xlFSvM;Cp_#r8UaqIzHJQg_z^rEJw&OMm_8NGAY2)rKvki|o1bH~ z$2IbfVeY2L(^*rMRU1lM5Y_sgrDS`Z??nR2lX;zyR=c%UyGb*%TC-Dil?SihkjrQy~TMv6;BMs7P8il`H7DmpVm@rJ;b)hW)BL)GjS154b*xq-NXq2cwE z^;VP7ua2pxvCmxrnqUYQMH%a%nHmwmI33nJM(>4LznvY*k&C0{8f*%?zggpDgkuz&JBx{9mfb@wegEl2v!=}Sq2Gaty0<)UrOT0{MZtZ~j5y&w zXlYa_jY)I_+VA-^#mEox#+G>UgvM!Ac8zI<%JRXM_73Q!#i3O|)lOP*qBeJG#BST0 zqohi)O!|$|2SeJQo(w6w7%*92S})XfnhrH_Z8qe!G5>CglP=nI7JAOW?(Z29;pXJ9 zR9`KzQ=WEhy*)WH>$;7Cdz|>*i>=##0bB)oU0OR>>N<21e4rMCHDemNi2LD>Nc$;& zQRFthpWniC1J6@Zh~iJCoLOxN`oCKD5Q4r%ynwgUKPlIEd#?QViIqovY|czyK8>6B zSP%{2-<;%;1`#0mG^B(8KbtXF;Nf>K#Di72UWE4gQ%(_26Koiad)q$xRL~?pN71ZZ zujaaCx~jXjygw;rI!WB=xrOJO6HJ!!w}7eiivtCg5K|F6$EXa)=xUC za^JXSX98W`7g-tm@uo|BKj39Dl;sg5ta;4qjo^pCh~{-HdLl6qI9Ix6f$+qiZ$}s= zNguKrU;u+T@ko(Vr1>)Q%h$?UKXCY>3se%&;h2osl2D zE4A9bd7_|^njDd)6cI*FupHpE3){4NQ*$k*cOWZ_?CZ>Z4_fl@n(mMnYK62Q1d@+I zr&O))G4hMihgBqRIAJkLdk(p(D~X{-oBUA+If@B}j& zsHbeJ3RzTq96lB7d($h$xTeZ^gP0c{t!Y0c)aQE;$FY2!mACg!GDEMKXFOPI^)nHZ z`aSPJpvV0|bbrzhWWkuPURlDeN%VT8tndV8?d)eN*i4I@u zVKl^6{?}A?P)Fsy?3oi#clf}L18t;TjNI2>eI&(ezDK7RyqFxcv%>?oxUlonv(px) z$vnPzRH`y5A(x!yOIfL0bmgeMQB$H5wenx~!ujQK*nUBW;@Em&6Xv2%s(~H5WcU2R z;%Nw<$tI)a`Ve!>x+qegJnQsN2N7HaKzrFqM>`6R*gvh%O*-%THt zrB$Nk;lE;z{s{r^PPm5qz(&lM{sO*g+W{sK+m3M_z=4=&CC>T`{X}1Vg2PEfSj2x_ zmT*(x;ov%3F?qoEeeM>dUn$a*?SIGyO8m806J1W1o+4HRhc2`9$s6hM#qAm zChQ87b~GEw{ADfs+5}FJ8+|bIlIv(jT$Ap#hSHoXdd9#w<#cA<1Rkq^*EEkknUd4& zoIWIY)sAswy6fSERVm&!SO~#iN$OgOX*{9@_BWFyJTvC%S++ilSfCrO(?u=Dc?CXZ zzCG&0yVR{Z`|ZF0eEApWEo#s9osV>F{uK{QA@BES#&;#KsScf>y zvs?vIbI>VrT<*!;XmQS=bhq%46-aambZ(8KU-wOO2=en~D}MCToB_u;Yz{)1ySrPZ z@=$}EvjTdzTWU7c0ZI6L8=yP+YRD_eMMos}b5vY^S*~VZysrkq<`cK3>>v%uy7jgq z0ilW9KjVDHLv0b<1K_`1IkbTOINs0=m-22c%M~l=^S}%hbli-3?BnNq?b`hx^HX2J zIe6ECljRL0uBWb`%{EA=%!i^4sMcj+U_TaTZRb+~GOk z^ZW!nky0n*Wb*r+Q|9H@ml@Z5gU&W`(z4-j!OzC1wOke`TRAYGZVl$PmQ16{3196( zO*?`--I}Qf(2HIwb2&1FB^!faPA2=sLg(@6P4mN)>Dc3i(B0;@O-y2;lM4akD>@^v z=u>*|!s&9zem70g7zfw9FXl1bpJW(C#5w#uy5!V?Q(U35A~$dR%LDVnq@}kQm13{} zd53q3N(s$Eu{R}k2esbftfjfOITCL;jWa$}(mmm}d(&7JZ6d3%IABCapFFYjdEjdK z&4Edqf$G^MNAtL=uCDRs&Fu@FXRgX{*0<(@c3|PNHa>L%zvxWS={L8%qw`STm+=Rd zA}FLspESSIpE_^41~#5yI2bJ=9`oc;GIL!JuW&7YetZ?0H}$$%8rW@*J37L-~Rsx!)8($nI4 zZhcZ2^=Y+p4YPl%j!nFJA|*M^gc(0o$i3nlphe+~-_m}jVkRN{spFs(o0ajW@f3K{ zDV!#BwL322CET$}Y}^0ixYj2w>&Xh12|R8&yEw|wLDvF!lZ#dOTHM9pK6@Nm-@9Lnng4ZHBgBSrr7KI8YCC9DX5Kg|`HsiwJHg2(7#nS;A{b3tVO?Z% za{m5b3rFV6EpX;=;n#wltDv1LE*|g5pQ+OY&*6qCJZc5oDS6Z6JD#6F)bWxZSF@q% z+1WV;m!lRB!n^PC>RgQCI#D1br_o^#iPk>;K2hB~0^<~)?p}LG%kigm@moD#q3PE+ zA^Qca)(xnqw6x>XFhV6ku9r$E>bWNrVH9fum0?4s?Rn2LG{Vm_+QJHse6xa%nzQ?k zKug4PW~#Gtb;#5+9!QBgyB@q=sk9=$S{4T>wjFICStOM?__fr+Kei1 z3j~xPqW;W@YkiUM;HngG!;>@AITg}vAE`M2Pj9Irl4w1fo4w<|Bu!%rh%a(Ai^Zhi zs92>v5;@Y(Zi#RI*ua*h`d_7;byQSa*v9E{2x$<-_=5Z<7{%)}4XExANcz@rK69T0x3%H<@frW>RA8^swA+^a(FxK| zFl3LD*ImHN=XDUkrRhp6RY5$rQ{bRgSO*(vEHYV)3Mo6Jy3puiLmU&g82p{qr0F?ohmbz)f2r{X2|T2 z$4fdQ=>0BeKbiVM!e-lIIs8wVTuC_m7}y4A_%ikI;Wm5$9j(^Y z(cD%U%k)X>_>9~t8;pGzL6L-fmQO@K; zo&vQzMlgY95;1BSkngY)e{`n0!NfVgf}2mB3t}D9@*N;FQ{HZ3Pb%BK6;5#-O|WI( zb6h@qTLU~AbVW#_6?c!?Dj65Now7*pU{h!1+eCV^KCuPAGs28~3k@ueL5+u|Z-7}t z9|lskE`4B7W8wMs@xJa{#bsCGDFoRSNSnmNYB&U7 zVGKWe%+kFB6kb)e;TyHfqtU6~fRg)f|>=5(N36)0+C z`hv65J<$B}WUc!wFAb^QtY31yNleq4dzmG`1wHTj=c*=hay9iD071Hc?oYoUk|M*_ zU1GihAMBsM@5rUJ(qS?9ZYJ6@{bNqJ`2Mr+5#hKf?doa?F|+^IR!8lq9)wS3tF_9n zW_?hm)G(M+MYb?V9YoX^_mu5h-LP^TL^!Q9Z7|@sO(rg_4+@=PdI)WL(B7`!K^ND- z-uIuVDCVEdH_C@c71YGYT^_Scf_dhB8Z2Xy6vGtBSlYud9vggOqv^L~F{BraSE_t} zIkP+Hp2&nH^-MNEs}^`oMLy11`PQW$T|K(`Bu*(f@)mv1-qY(_YG&J2M2<7k;;RK~ zL{Fqj9yCz8(S{}@c)S!65aF<=&eLI{hAMErCx&>i7OeDN>okvegO87OaG{Jmi<|}D zaT@b|0X{d@OIJ7zvT>r+eTzgLq~|Dpu)Z&db-P4z*`M$UL51lf>FLlq6rfG)%doyp z)3kk_YIM!03eQ8Vu_2fg{+osaEJPtJ-s36R+5_AEG12`NG)IQ#TF9c@$99%0iye+ zUzZ57=m2)$D(5Nx!n)=5Au&O0BBgwxIBaeI(mro$#&UGCr<;C{UjJVAbVi%|+WP(a zL$U@TYCxJ=1{Z~}rnW;7UVb7+ZnzgmrogDxhjLGo>c~MiJAWs&&;AGg@%U?Y^0JhL ze(x6Z74JG6FlOFK(T}SXQfhr}RIFl@QXKnIcXYF)5|V~e-}suHILKT-k|<*~Ij|VF zC;t@=uj=hot~*!C68G8hTA%8SzOfETOXQ|3FSaIEjvBJp(A)7SWUi5!Eu#yWgY+;n zlm<$+UDou*V+246_o#V4kMdto8hF%%Lki#zPh}KYXmMf?hrN0;>Mv%`@{0Qn`Ujp) z=lZe+13>^Q!9zT);H<(#bIeRWz%#*}sgUX9P|9($kexOyKIOc`dLux}c$7It4u|Rl z6SSkY*V~g_B-hMPo_ak>>z@AVQ(_N)VY2kB3IZ0G(iDUYw+2d7W^~(Jq}KY=JnWS( z#rzEa&0uNhJ>QE8iiyz;n2H|SV#Og+wEZv=f2%1ELX!SX-(d3tEj$5$1}70Mp<&eI zCkfbByL7af=qQE@5vDVxx1}FSGt_a1DoE3SDI+G)mBAna)KBG4p8Epxl9QZ4BfdAN zFnF|Y(umr;gRgG6NLQ$?ZWgllEeeq~z^ZS7L?<(~O&$5|y)Al^iMKy}&W+eMm1W z7EMU)u^ke(A1#XCV>CZ71}P}0x)4wtHO8#JRG3MA-6g=`ZM!FcICCZ{IEw8Dm2&LQ z1|r)BUG^0GzI6f946RrBlfB1Vs)~8toZf~7)+G;pv&XiUO(%5bm)pl=p>nV^o*;&T z;}@oZSibzto$arQgfkp|z4Z($P>dTXE{4O=vY0!)kDO* zGF8a4wq#VaFpLfK!iELy@?-SeRrdz%F*}hjKcA*y@mj~VD3!it9lhRhX}5YOaR9$} z3mS%$2Be7{l(+MVx3 z(4?h;P!jnRmX9J9sYN#7i=iyj_5q7n#X(!cdqI2lnr8T$IfOW<_v`eB!d9xY1P=2q&WtOXY=D9QYteP)De?S4}FK6#6Ma z=E*V+#s8>L;8aVroK^6iKo=MH{4yEZ_>N-N z`(|;aOATba1^asjxlILk<4}f~`39dBFlxj>Dw(hMYKPO3EEt1@S`1lxFNM+J@uB7T zZ8WKjz7HF1-5&2=l=fqF-*@>n5J}jIxdDwpT?oKM3s8Nr`x8JnN-kCE?~aM1H!hAE z%%w(3kHfGwMnMmNj(SU(w42OrC-euI>Dsjk&jz3ts}WHqmMpzQ3vZrsXrZ|}+MHA7 z068obeXZTsO*6RS@o3x80E4ok``rV^Y3hr&C1;|ZZ0|*EKO`$lECUYG2gVFtUTw)R z4Um<0ZzlON`zTdvVdL#KFoMFQX*a5wM0Czp%wTtfK4Sjs)P**RW&?lP$(<}q%r68Z zS53Y!d@&~ne9O)A^tNrXHhXBkj~$8j%pT1%%mypa9AW5E&s9)rjF4@O3ytH{0z6riz|@< zB~UPh*wRFg2^7EbQrHf0y?E~dHlkOxof_a?M{LqQ^C!i2dawHTPYUE=X@2(3<=OOxs8qn_(y>pU>u^}3y&df{JarR0@VJn0f+U%UiF=$Wyq zQvnVHESil@d|8&R<%}uidGh7@u^(%?$#|&J$pvFC-n8&A>utA=n3#)yMkz+qnG3wd zP7xCnF|$9Dif@N~L)Vde3hW8W!UY0BgT2v(wzp;tlLmyk2%N|0jfG$%<;A&IVrOI< z!L)o>j>;dFaqA3pL}b-Je(bB@VJ4%!JeX@3x!i{yIeIso^=n?fDX`3bU=eG7sTc%g%ye8$v8P@yKE^XD=NYxTb zbf!Mk=h|otpqjFaA-vs5YOF-*GwWPc7VbaOW&stlANnCN8iftFMMrUdYNJ_Bnn5Vt zxfz@Ah|+4&P;reZxp;MmEI7C|FOv8NKUm8njF7Wb6Gi7DeODLl&G~}G4be&*Hi0Qw z5}77vL0P+7-B%UL@3n1&JPxW^d@vVwp?u#gVcJqY9#@-3X{ok#UfW3<1fb%FT`|)V~ggq z(3AUoUS-;7)^hCjdT0Kf{i}h)mBg4qhtHHBti=~h^n^OTH5U*XMgDLIR@sre`AaB$ zg)IGBET_4??m@cx&c~bA80O7B8CHR7(LX7%HThkeC*@vi{-pL%e)yXp!B2InafbDF zjPXf1mko3h59{lT6EEbxKO1Z5GF71)WwowO6kY|6tjSVSWdQ}NsK2x{>i|MKZK8%Q zfu&_0D;CO-Jg0#YmyfctyJ!mRJp)e#@O0mYdp|8x;G1%OZQ3Q847YWTyy|%^cpA;m zze0(5p{tMu^lDkpe?HynyO?a1$_LJl2L&mpeKu%8YvgRNr=%2z${%WThHG=vrWY@4 zsA`OP#O&)TetZ>s%h!=+CE15lOOls&nvC~$Qz0Ph7tHiP;O$i|eDwpT{cp>+)0-|; zY$|bB+Gbel>5aRN3>c0x)4U=|X+z+{ zn*_p*EQoquRL+=+p;=lm`d71&1NqBz&_ph)MXu(Nv6&XE7(RsS)^MGj5Q?Fwude-(sq zjJ>aOq!7!EN>@(fK7EE#;i_BGvli`5U;r!YA{JRodLBc6-`n8K+Fjgwb%sX;j=qHQ z7&Tr!)!{HXoO<2BQrV9Sw?JRaLXV8HrsNevvnf>Y-6|{T!pYLl7jp$-nEE z#X!4G4L#K0qG_4Z;Cj6=;b|Be$hi4JvMH!-voxqx^@8cXp`B??eFBz2lLD8RRaRGh zn7kUfy!YV~p(R|p7iC1Rdgt$_24i0cd-S8HpG|`@my70g^y`gu%#Tf_L21-k?sRRZHK&at(*ED0P8iw{7?R$9~OF$Ko;Iu5)ur5<->x!m93Eb zFYpIx60s=Wxxw=`$aS-O&dCO_9?b1yKiPCQmSQb>T)963`*U+Ydj5kI(B(B?HNP8r z*bfSBpSu)w(Z3j7HQoRjUG(+d=IaE~tv}y14zHHs|0UcN52fT8V_<@2ep_ee{QgZG zmgp8iv4V{k;~8@I%M3<#B;2R>Ef(Gg_cQM7%}0s*^)SK6!Ym+~P^58*wnwV1BW@eG z4sZLqsUvBbFsr#8u7S1r4teQ;t)Y@jnn_m5jS$CsW1um!p&PqAcc8!zyiXHVta9QC zY~wCwCF0U%xiQPD_INKtTb;A|Zf29(mu9NI;E zc-e>*1%(LSXB`g}kd`#}O;veb<(sk~RWL|f3ljxCnEZDdNSTDV6#Td({6l&y4IjKF z^}lIUq*ZUqgTPumD)RrCN{M^jhY>E~1pn|KOZ5((%F)G|*ZQ|r4zIbrEiV%42hJV8 z3xS)=!X1+=olbdGJ=yZil?oXLct8FM{(6ikLL3E%=q#O6(H$p~gQu6T8N!plf!96| z&Q3=`L~>U0zZh;z(pGR2^S^{#PrPxTRHD1RQOON&f)Siaf`GLj#UOk&(|@0?zm;Sx ztsGt8=29-MZs5CSf1l1jNFtNt5rFNZxJPvkNu~2}7*9468TWm>nN9TP&^!;J{-h)_ z7WsHH9|F%I`Pb!>KAS3jQWKfGivTVkMJLO-HUGM_a4UQ_%RgL6WZvrW+Z4ujZn;y@ zz9$=oO!7qVTaQAA^BhX&ZxS*|5dj803M=k&2%QrXda`-Q#IoZL6E(g+tN!6CA!CP* zCpWtCujIea)ENl0liwVfj)Nc<9mV%+e@=d`haoZ*`B7+PNjEbXBkv=B+Pi^~L#EO$D$ZqTiD8f<5$eyb54-(=3 zh)6i8i|jp(@OnRrY5B8t|LFXFQVQ895n*P16cEKTrT*~yLH6Z4e*bZ5otpRDri&+A zfNbK1D5@O=sm`fN=WzWyse!za5n%^+6dHPGX#8DyIK>?9qyX}2XvBWVqbP%%D)7$= z=#$WulZlZR<{m#gU7lwqK4WS1Ne$#_P{b17qe$~UOXCl>5b|6WVh;5vVnR<%d+Lnp z$uEmML38}U4vaW8>shm6CzB(Wei3s#NAWE3)a2)z@i{4jTn;;aQS)O@l{rUM`J@K& l00vQ5JBs~;vo!vr%%-k{2_Fq1Mn4QF81S)AQ99zk{{c4yR+0b! diff --git a/asset-transfer-events/chaincode-java/gradle/wrapper/gradle-wrapper.properties b/asset-transfer-events/chaincode-java/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index e2847c82..00000000 --- a/asset-transfer-events/chaincode-java/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/asset-transfer-events/chaincode-java/gradlew b/asset-transfer-events/chaincode-java/gradlew deleted file mode 100755 index 1aa94a42..00000000 --- a/asset-transfer-events/chaincode-java/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/asset-transfer-events/chaincode-java/gradlew.bat b/asset-transfer-events/chaincode-java/gradlew.bat deleted file mode 100644 index 7101f8e4..00000000 --- a/asset-transfer-events/chaincode-java/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/asset-transfer-events/chaincode-java/settings.gradle b/asset-transfer-events/chaincode-java/settings.gradle deleted file mode 100644 index 7112a47d..00000000 --- a/asset-transfer-events/chaincode-java/settings.gradle +++ /dev/null @@ -1,5 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -rootProject.name = 'events' diff --git a/asset-transfer-events/chaincode-java/src/main/java/org/hyperledger/fabric/samples/events/Asset.java b/asset-transfer-events/chaincode-java/src/main/java/org/hyperledger/fabric/samples/events/Asset.java deleted file mode 100644 index f9bdc18e..00000000 --- a/asset-transfer-events/chaincode-java/src/main/java/org/hyperledger/fabric/samples/events/Asset.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.hyperledger.fabric.samples.events; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -import static java.nio.charset.StandardCharsets.UTF_8; - -import org.hyperledger.fabric.contract.annotation.DataType; -import org.hyperledger.fabric.contract.annotation.Property; - - -import org.json.JSONObject; - -@DataType() -public final class Asset { - - @Property() - private final String assetID; - - @Property() - private String color; - - @Property() - private int size; - - @Property() - private String owner; - - @Property() - private int appraisedValue; - - public Asset(final String assetID, final String color, - final int size, final String owner, final int value) { - - this.assetID = assetID; - this.color = color; - this.size = size; - this.owner = owner; - this.appraisedValue = value; - } - - public String getAssetID() { - return assetID; - } - - public String getColor() { - return color; - } - - public int getSize() { - return size; - } - - public String getOwner() { - return owner; - } - - public int getAppraisedValue() { - return appraisedValue; - } - - public void setOwner(final String newowner) { - this.owner = newowner; - } - - public void setAppraisedValue(final int value) { - this.appraisedValue = value; - } - - public void setColor(final String c) { - this.color = c; - } - - public void setSize(final int s) { - this.size = s; - } - - // Serialize asset without private properties - public byte[] serialize() { - return serialize(null).getBytes(UTF_8); - } - - public String serialize(final String privateProps) { - Map tMap = new HashMap(); - tMap.put("ID", assetID); - tMap.put("Color", color); - tMap.put("Owner", owner); - tMap.put("Size", Integer.toString(size)); - tMap.put("AppraisedValue", Integer.toString(appraisedValue)); - if (privateProps != null && privateProps.length() > 0) { - tMap.put("asset_properties", new JSONObject(privateProps)); - } - return new JSONObject(tMap).toString(); - } - - public static Asset deserialize(final byte[] assetJSON) { - return deserialize(new String(assetJSON, UTF_8)); - } - - public static Asset deserialize(final String assetJSON) { - - JSONObject json = new JSONObject(assetJSON); - Map tMap = json.toMap(); - final String id = (String) tMap.get("ID"); - - final String color = (String) tMap.get("Color"); - final String owner = (String) tMap.get("Owner"); - int size = 0; - int appraisedValue = 0; - if (tMap.containsKey("Size")) { - size = Integer.parseInt((String) tMap.get("Size")); - } - if (tMap.containsKey("AppraisedValue")) { - appraisedValue = Integer.parseInt((String) tMap.get("AppraisedValue")); - } - return new Asset(id, color, size, owner, appraisedValue); - - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - - if ((obj == null) || (getClass() != obj.getClass())) { - return false; - } - - Asset other = (Asset) obj; - - return Objects.deepEquals( - new String[]{getAssetID(), getColor(), getOwner()}, - new String[]{other.getAssetID(), other.getColor(), other.getOwner()}) - && - Objects.deepEquals( - new int[]{getSize(), getAppraisedValue()}, - new int[]{other.getSize(), other.getAppraisedValue()}); - } - - @Override - public int hashCode() { - return Objects.hash(getAssetID(), getColor(), getSize(), getOwner(), getAppraisedValue()); - } - - @Override - public String toString() { - return this.getClass().getSimpleName() + "@" + Integer.toHexString(hashCode()) - + " [assetID=" + assetID + ", appraisedValue=" + appraisedValue + ", color=" - + color + ", size=" + size + ", owner=" + owner + "]"; - } - -} diff --git a/asset-transfer-events/chaincode-java/src/main/java/org/hyperledger/fabric/samples/events/AssetTransfer.java b/asset-transfer-events/chaincode-java/src/main/java/org/hyperledger/fabric/samples/events/AssetTransfer.java deleted file mode 100644 index a892693a..00000000 --- a/asset-transfer-events/chaincode-java/src/main/java/org/hyperledger/fabric/samples/events/AssetTransfer.java +++ /dev/null @@ -1,299 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.hyperledger.fabric.samples.events; - -import static java.nio.charset.StandardCharsets.UTF_8; - -import org.hyperledger.fabric.contract.Context; -import org.hyperledger.fabric.contract.ContractInterface; -import org.hyperledger.fabric.contract.annotation.Contact; -import org.hyperledger.fabric.contract.annotation.Contract; -import org.hyperledger.fabric.contract.annotation.Default; -import org.hyperledger.fabric.contract.annotation.Info; -import org.hyperledger.fabric.contract.annotation.License; -import org.hyperledger.fabric.contract.annotation.Transaction; -import org.hyperledger.fabric.shim.ChaincodeException; -import org.hyperledger.fabric.shim.ChaincodeStub; - -import java.util.Map; - -/** - * Main Chaincode class. - * - * @see org.hyperledger.fabric.shim.Chaincode - *

- * Each chaincode transaction function must take, Context as first parameter. - * Unless specified otherwise via annotation (@Contract or @Transaction), the contract name - * is the class name (without package) - * and the transaction name is the method name. - */ -@Contract( - name = "asset-transfer-events-java", - info = @Info( - title = "Asset Transfer Events", - description = "The hyperlegendary asset transfer events sample", - version = "0.0.1-SNAPSHOT", - license = @License( - name = "Apache 2.0 License", - url = "http://www.apache.org/licenses/LICENSE-2.0.html"), - contact = @Contact( - email = "a.transfer@example.com", - name = "Fabric Development Team", - url = "https://hyperledger.example.com"))) -@Default -public final class AssetTransfer implements ContractInterface { - - static final String IMPLICIT_COLLECTION_NAME_PREFIX = "_implicit_org_"; - static final String PRIVATE_PROPS_KEY = "asset_properties"; - - /** - * Retrieves the asset details with the specified ID - * - * @param ctx the transaction context - * @param assetID the ID of the asset - * @return the asset found on the ledger. Returns error if asset is not found - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public String ReadAsset(final Context ctx, final String assetID) { - System.out.printf("ReadAsset: ID %s\n", assetID); - - Asset asset = getState(ctx, assetID); - String privData = readPrivateData(ctx, assetID); - return asset.serialize(privData); - } - - /** - * Creates a new asset on the ledger. Saves the passed private data (asset properties) from transient map input. - * - * @param ctx the transaction context - * Transient map with asset_properties key with asset json as value - * @param assetID - * @param color - * @param size - * @param owner - * @param appraisedValue - * @return the created asset - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public Asset CreateAsset(final Context ctx, final String assetID, final String color, final int size, final String owner, final int appraisedValue) { - ChaincodeStub stub = ctx.getStub(); - // input validations - String errorMessage = null; - if (assetID == null || assetID.equals("")) { - errorMessage = String.format("Empty input: assetID"); - } - if (owner == null || owner.equals("")) { - errorMessage = String.format("Empty input: owner"); - } - - if (errorMessage != null) { - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString()); - } - // Check if asset already exists - byte[] assetJSON = ctx.getStub().getState(assetID); - if (assetJSON != null && assetJSON.length > 0) { - errorMessage = String.format("Asset %s already exists", assetID); - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.ASSET_ALREADY_EXISTS.toString()); - } - - Asset asset = new Asset(assetID, color, size, owner, appraisedValue); - - savePrivateData(ctx, assetID); - assetJSON = asset.serialize(); - System.out.printf("CreateAsset Put: ID %s Data %s\n", assetID, new String(assetJSON)); - - stub.putState(assetID, assetJSON); - // add Event data to the transaction data. Event will be published after the block containing - // this transaction is committed - stub.setEvent("CreateAsset", assetJSON); - return asset; - } - - - /** - * TransferAsset transfers the asset to the new owner - * Save any private data, if provided in transient map - * - * @param ctx the transaction context - * @param assetID asset to delete - * @param newOwner new owner for the asset - * @return none - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public void TransferAsset(final Context ctx, final String assetID, final String newOwner) { - ChaincodeStub stub = ctx.getStub(); - String errorMessage = null; - - if (assetID == null || assetID.equals("")) { - errorMessage = "Empty input: assetID"; - } - if (newOwner == null || newOwner.equals("")) { - errorMessage = "Empty input: newOwner"; - } - if (errorMessage != null) { - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString()); - } - System.out.printf("TransferAsset: verify asset %s exists\n", assetID); - Asset thisAsset = getState(ctx, assetID); - // Transfer asset to new owner - thisAsset.setOwner(newOwner); - - System.out.printf(" Transfer Asset: ID %s to owner %s\n", assetID, newOwner); - savePrivateData(ctx, assetID); // save private data if any - byte[] assetJSON = thisAsset.serialize(); - - stub.putState(assetID, assetJSON); - stub.setEvent("TransferAsset", assetJSON); //publish Event - } - - /** - * Update existing asset on the ledger with provided parameters. - * Saves the passed private data (asset properties) from transient map input. - * - * @param ctx the transaction context - * Transient map with asset_properties key with asset json as value - * @param assetID - * @param color - * @param size - * @param owner - * @param appraisedValue - * @return the created asset - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public Asset UpdateAsset(final Context ctx, final String assetID, final String color, final int size, final String owner, final int appraisedValue) { - ChaincodeStub stub = ctx.getStub(); - // input validations - String errorMessage = null; - if (assetID == null || assetID.equals("")) { - errorMessage = String.format("Empty input: assetID"); - } - - if (errorMessage != null) { - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString()); - } - // reads from the Statedb. Check if asset already exists - Asset asset = getState(ctx, assetID); - - if (owner != null) { - asset.setOwner(owner); - } - if (color != null) { - asset.setColor(color); - } - if (size > 0) { - asset.setSize(size); - } - if (appraisedValue > 0) { - asset.setAppraisedValue(appraisedValue); - } - - savePrivateData(ctx, assetID); - byte[] assetJSON = asset.serialize(); - System.out.printf("UpdateAsset Put: ID %s Data %s\n", assetID, new String(assetJSON)); - stub.putState(assetID, assetJSON); - stub.setEvent("UpdateAsset", assetJSON); //publish Event - return asset; - } - - /** - * Deletes a asset & related details from the ledger. - * - * @param ctx the transaction context - * @param assetID asset to delete - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public void DeleteAsset(final Context ctx, final String assetID) { - ChaincodeStub stub = ctx.getStub(); - System.out.printf("DeleteAsset: verify asset %s exists\n", assetID); - Asset asset = getState(ctx, assetID); - - System.out.printf(" DeleteAsset: ID %s\n", assetID); - // delete private details of asset - removePrivateData(ctx, assetID); - stub.delState(assetID); // delete the key from Statedb - stub.setEvent("DeleteAsset", asset.serialize()); // publish Event - } - - private Asset getState(final Context ctx, final String assetID) { - byte[] assetJSON = ctx.getStub().getState(assetID); - if (assetJSON == null || assetJSON.length == 0) { - String errorMessage = String.format("Asset %s does not exist", assetID); - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.ASSET_NOT_FOUND.toString()); - } - - try { - Asset asset = Asset.deserialize(assetJSON); - return asset; - } catch (Exception e) { - throw new ChaincodeException("Deserialize error: " + e.getMessage(), AssetTransferErrors.DATA_ERROR.toString()); - } - } - - private String readPrivateData(final Context ctx, final String assetKey) { - String peerMSPID = ctx.getStub().getMspId(); - String clientMSPID = ctx.getClientIdentity().getMSPID(); - String implicitCollectionName = getCollectionName(ctx); - String privData = null; - // only if ClientOrgMatchesPeerOrg - if (peerMSPID.equals(clientMSPID)) { - System.out.printf(" ReadPrivateData from collection %s, ID %s\n", implicitCollectionName, assetKey); - byte[] propJSON = ctx.getStub().getPrivateData(implicitCollectionName, assetKey); - - if (propJSON != null && propJSON.length > 0) { - privData = new String(propJSON, UTF_8); - } - } - return privData; - } - - private void savePrivateData(final Context ctx, final String assetKey) { - String peerMSPID = ctx.getStub().getMspId(); - String clientMSPID = ctx.getClientIdentity().getMSPID(); - String implicitCollectionName = getCollectionName(ctx); - - if (peerMSPID.equals(clientMSPID)) { - Map transientMap = ctx.getStub().getTransient(); - if (transientMap != null && transientMap.containsKey(PRIVATE_PROPS_KEY)) { - byte[] transientAssetJSON = transientMap.get(PRIVATE_PROPS_KEY); - - System.out.printf("Asset's PrivateData Put in collection %s, ID %s\n", implicitCollectionName, assetKey); - ctx.getStub().putPrivateData(implicitCollectionName, assetKey, transientAssetJSON); - } - } - } - - private void removePrivateData(final Context ctx, final String assetKey) { - String peerMSPID = ctx.getStub().getMspId(); - String clientMSPID = ctx.getClientIdentity().getMSPID(); - String implicitCollectionName = getCollectionName(ctx); - - if (peerMSPID.equals(clientMSPID)) { - System.out.printf("PrivateData Delete from collection %s, ID %s\n", implicitCollectionName, assetKey); - ctx.getStub().delPrivateData(implicitCollectionName, assetKey); - } - } - - // Return the implicit collection name, to use for private property persistance - private String getCollectionName(final Context ctx) { - // Get the MSP ID of submitting client identity - String clientMSPID = ctx.getClientIdentity().getMSPID(); - String collectionName = IMPLICIT_COLLECTION_NAME_PREFIX + clientMSPID; - return collectionName; - } - - private enum AssetTransferErrors { - INCOMPLETE_INPUT, - INVALID_ACCESS, - ASSET_NOT_FOUND, - ASSET_ALREADY_EXISTS, - DATA_ERROR - } - -} diff --git a/asset-transfer-events/chaincode-javascript/.eslintignore b/asset-transfer-events/chaincode-javascript/.eslintignore deleted file mode 100644 index 15958470..00000000 --- a/asset-transfer-events/chaincode-javascript/.eslintignore +++ /dev/null @@ -1,5 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -coverage diff --git a/asset-transfer-events/chaincode-javascript/.eslintrc.js b/asset-transfer-events/chaincode-javascript/.eslintrc.js deleted file mode 100644 index cb00fa96..00000000 --- a/asset-transfer-events/chaincode-javascript/.eslintrc.js +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -module.exports = { - env: { - node: true, - mocha: true, - es6: true - }, - parserOptions: { - ecmaVersion: 8, - sourceType: 'script' - }, - extends: 'eslint:recommended', - rules: { - indent: ['error', 'tab'], - 'linebreak-style': ['error', 'unix'], - quotes: ['error', 'single'], - semi: ['error', 'always'], - 'no-unused-vars': ['error', { args: 'none' }], - 'no-console': 'off', - curly: 'error', - eqeqeq: 'error', - 'no-throw-literal': 'error', - strict: 'error', - 'no-var': 'error', - 'dot-notation': 'error', - 'no-trailing-spaces': 'error', - 'no-use-before-define': 'error', - 'no-useless-call': 'error', - 'no-with': 'error', - 'operator-linebreak': 'error', - yoda: 'error', - 'quote-props': ['error', 'as-needed'], - 'no-constant-condition': ['error', { checkLoops: false }] - } -}; diff --git a/asset-transfer-events/chaincode-javascript/.gitignore b/asset-transfer-events/chaincode-javascript/.gitignore deleted file mode 100644 index eeace290..00000000 --- a/asset-transfer-events/chaincode-javascript/.gitignore +++ /dev/null @@ -1,15 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -# Coverage directory used by tools like istanbul -coverage - -# Report cache used by istanbul -.nyc_output - -# Dependency directories -node_modules/ -jspm_packages/ - -package-lock.json diff --git a/asset-transfer-events/chaincode-javascript/index.js b/asset-transfer-events/chaincode-javascript/index.js deleted file mode 100644 index 3244cedf..00000000 --- a/asset-transfer-events/chaincode-javascript/index.js +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const assetTransferEvents = require('./lib/assetTransferEvents'); - -module.exports.AssetTransferEvents = assetTransferEvents; -module.exports.contracts = [assetTransferEvents]; diff --git a/asset-transfer-events/chaincode-javascript/lib/assetTransferEvents.js b/asset-transfer-events/chaincode-javascript/lib/assetTransferEvents.js deleted file mode 100644 index 27c5acbd..00000000 --- a/asset-transfer-events/chaincode-javascript/lib/assetTransferEvents.js +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Contract } = require('fabric-contract-api'); - -async function savePrivateData(ctx, assetKey) { - const clientOrg = ctx.clientIdentity.getMSPID(); - const peerOrg = ctx.stub.getMspID(); - const collection = '_implicit_org_' + peerOrg; - - if (clientOrg === peerOrg) { - const transientMap = ctx.stub.getTransient(); - if (transientMap) { - const properties = transientMap.get('asset_properties'); - if (properties) { - await ctx.stub.putPrivateData(collection, assetKey, properties); - } - } - } -} - -async function removePrivateData(ctx, assetKey) { - const clientOrg = ctx.clientIdentity.getMSPID(); - const peerOrg = ctx.stub.getMspID(); - const collection = '_implicit_org_' + peerOrg; - - if (clientOrg === peerOrg) { - const propertiesBuffer = await ctx.stub.getPrivateData(collection, assetKey); - if (propertiesBuffer && propertiesBuffer.length > 0) { - await ctx.stub.deletePrivateData(collection, assetKey); - } - } -} - -async function addPrivateData(ctx, assetKey, asset) { - const clientOrg = ctx.clientIdentity.getMSPID(); - const peerOrg = ctx.stub.getMspID(); - const collection = '_implicit_org_' + peerOrg; - - if (clientOrg === peerOrg) { - const propertiesBuffer = await ctx.stub.getPrivateData(collection, assetKey); - if (propertiesBuffer && propertiesBuffer.length > 0) { - const properties = JSON.parse(propertiesBuffer.toString()); - asset.asset_properties = properties; - } - } -} - -async function readState(ctx, id) { - const assetBuffer = await ctx.stub.getState(id); // get the asset from chaincode state - if (!assetBuffer || assetBuffer.length === 0) { - throw new Error(`The asset ${id} does not exist`); - } - const assetString = assetBuffer.toString(); - const asset = JSON.parse(assetString); - - return asset; -} - -class AssetTransferEvents extends Contract { - - // CreateAsset issues a new asset to the world state with given details. - async CreateAsset(ctx, id, color, size, owner, appraisedValue) { - const asset = { - ID: id, - Color: color, - Size: size, - Owner: owner, - AppraisedValue: appraisedValue, - }; - await savePrivateData(ctx, id); - const assetBuffer = Buffer.from(JSON.stringify(asset)); - - ctx.stub.setEvent('CreateAsset', assetBuffer); - return ctx.stub.putState(id, assetBuffer); - } - - // TransferAsset updates the owner field of an asset with the given id in - // the world state. - async TransferAsset(ctx, id, newOwner) { - const asset = await readState(ctx, id); - asset.Owner = newOwner; - const assetBuffer = Buffer.from(JSON.stringify(asset)); - await savePrivateData(ctx, id); - - ctx.stub.setEvent('TransferAsset', assetBuffer); - return ctx.stub.putState(id, assetBuffer); - } - - // ReadAsset returns the asset stored in the world state with given id. - async ReadAsset(ctx, id) { - const asset = await readState(ctx, id); - await addPrivateData(ctx, asset.ID, asset); - - return JSON.stringify(asset); - } - - // UpdateAsset updates an existing asset in the world state with provided parameters. - async UpdateAsset(ctx, id, color, size, owner, appraisedValue) { - const asset = await readState(ctx, id); - asset.Color = color; - asset.Size = size; - asset.Owner = owner; - asset.AppraisedValue = appraisedValue; - const assetBuffer = Buffer.from(JSON.stringify(asset)); - await savePrivateData(ctx, id); - - ctx.stub.setEvent('UpdateAsset', assetBuffer); - return ctx.stub.putState(id, assetBuffer); - } - - // DeleteAsset deletes an given asset from the world state. - async DeleteAsset(ctx, id) { - const asset = await readState(ctx, id); - const assetBuffer = Buffer.from(JSON.stringify(asset)); - await removePrivateData(ctx, id); - - ctx.stub.setEvent('DeleteAsset', assetBuffer); - return ctx.stub.deleteState(id); - } -} - -module.exports = AssetTransferEvents; diff --git a/asset-transfer-events/chaincode-javascript/npm-shrinkwrap.json b/asset-transfer-events/chaincode-javascript/npm-shrinkwrap.json deleted file mode 100644 index 8f9fc8e5..00000000 --- a/asset-transfer-events/chaincode-javascript/npm-shrinkwrap.json +++ /dev/null @@ -1,3982 +0,0 @@ -{ - "name": "asset-transfer-events", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "asset-transfer-events", - "version": "1.0.0", - "license": "Apache-2.0", - "dependencies": { - "fabric-contract-api": "~2.5", - "fabric-shim": "~2.5" - }, - "devDependencies": { - "chai": "^4.4.1", - "eslint": "^8.57.0", - "mocha": "^10.4.0", - "nyc": "^15.1.0", - "sinon": "^18.0.0", - "sinon-chai": "^3.7.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.24.7", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.7.tgz", - "integrity": "sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz", - "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helpers": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/@babel/generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", - "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz", - "integrity": "sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "browserslist": "^4.22.2", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", - "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", - "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", - "dev": true, - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", - "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz", - "integrity": "sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", - "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", - "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz", - "integrity": "sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.7.tgz", - "integrity": "sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", - "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/template": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", - "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", - "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", - "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@colors/colors": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", - "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@dabh/diagnostics": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", - "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", - "dependencies": { - "colorspace": "1.1.x", - "enabled": "2.0.x", - "kuler": "^2.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", - "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@fidm/asn1": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@fidm/asn1/-/asn1-1.0.4.tgz", - "integrity": "sha512-esd1jyNvRb2HVaQGq2Gg8Z0kbQPXzV9Tq5Z14KNIov6KfFD6PTaRIO8UpcsYiTNzOqJpmyzWgVTrUwFV3UF4TQ==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@fidm/x509": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@fidm/x509/-/x509-1.2.1.tgz", - "integrity": "sha512-nwc2iesjyc9hkuzcrMCBXQRn653XuAUKorfWM8PZyJawiy1QzLj4vahwzaI25+pfpwOLvMzbJ0uKpWLDNmo16w==", - "dependencies": { - "@fidm/asn1": "^1.0.4", - "tweetnacl": "^1.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@grpc/grpc-js": { - "version": "1.10.9", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.10.9.tgz", - "integrity": "sha512-5tcgUctCG0qoNyfChZifz2tJqbRbXVO9J7X6duFcOjY3HUNCxg5D0ZCK7EP9vIcZ0zRpLU9bWkyCqVCLZ46IbQ==", - "dependencies": { - "@grpc/proto-loader": "^0.7.13", - "@js-sdsl/ordered-map": "^4.4.2" - }, - "engines": { - "node": ">=12.10.0" - } - }, - "node_modules/@grpc/proto-loader": { - "version": "0.7.13", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", - "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", - "dependencies": { - "lodash.camelcase": "^4.3.0", - "long": "^5.0.0", - "protobufjs": "^7.2.5", - "yargs": "^17.7.2" - }, - "bin": { - "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true - }, - "node_modules/@hyperledger/fabric-protos": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@hyperledger/fabric-protos/-/fabric-protos-0.2.1.tgz", - "integrity": "sha512-qjm0vIQIfCall804tWDeA8p/mUfu14sl5Sj+PbOn2yDKJq+7ThoIhNsLAqf+BCxUfqsoqQq6AojhqQeTFyOOqg==", - "dependencies": { - "@grpc/grpc-js": "^1.9.0", - "google-protobuf": "^3.21.0" - }, - "engines": { - "node": ">=14.15.0" - } - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@js-sdsl/ordered-map": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", - "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" - }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", - "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, - "node_modules/@sinonjs/samsam": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", - "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^2.0.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" - } - }, - "node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/text-encoding": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", - "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", - "dev": true - }, - "node_modules/@types/node": { - "version": "16.18.98", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.98.tgz", - "integrity": "sha512-fpiC20NvLpTLAzo3oVBKIqBGR6Fx/8oAK/SSf7G+fydnXMY1x4x9RZ6sBXhqKlCU21g2QapUsbLlhv3+a7wS+Q==" - }, - "node_modules/@types/triple-beam": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", - "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/append-transform": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", - "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", - "dev": true, - "dependencies": { - "default-require-extensions": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", - "dev": true - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "node_modules/browserslist": { - "version": "4.23.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.1.tgz", - "integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001629", - "electron-to-chromium": "^1.4.796", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.16" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/caching-transform": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", - "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", - "dev": true, - "dependencies": { - "hasha": "^5.0.0", - "make-dir": "^3.0.0", - "package-hash": "^4.0.0", - "write-file-atomic": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001633", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001633.tgz", - "integrity": "sha512-6sT0yf/z5jqf8tISAgpJDrmwOpLsrpnyCdD/lOZKvKkkJK4Dn0X5i7KF7THEZhOq+30bmhwBlNEaqPUiHiKtZg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/chai": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", - "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", - "dev": true, - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.0.8" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/class-transformer": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.4.0.tgz", - "integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==" - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/color": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", - "dependencies": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/color/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/colorspace": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", - "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", - "dependencies": { - "color": "^3.1.3", - "text-hex": "1.0.x" - } - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/deep-eql": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", - "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", - "dev": true, - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/default-require-extensions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", - "integrity": "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==", - "dev": true, - "dependencies": { - "strip-bom": "^4.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.802", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.802.tgz", - "integrity": "sha512-TnTMUATbgNdPXVSHsxvNVSG0uEd6cSZsANjm8c9HbvflZVVn1yTRcmVXYT1Ma95/ssB/Dcd30AHweH2TE+dNpA==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/enabled": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", - "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" - }, - "node_modules/es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true - }, - "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fabric-contract-api": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/fabric-contract-api/-/fabric-contract-api-2.5.6.tgz", - "integrity": "sha512-AosGb8tA+Jgt+pqMEgYNB3/J/P5QuWOC7yhXbhDmAAwUzn4Sc7pdWDICH1YyrFGZNFxMGQmqJmLVWUX8BKHy0w==", - "dependencies": { - "class-transformer": "^0.4.0", - "fabric-shim-api": "2.5.6", - "fast-safe-stringify": "^2.1.1", - "get-params": "^0.1.2", - "reflect-metadata": "^0.1.13", - "winston": "^3.7.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/fabric-shim": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/fabric-shim/-/fabric-shim-2.5.6.tgz", - "integrity": "sha512-4Y8WNFhYuQ9QYSEgPXWdlXnrXjwOlM10sQQzE4kJ7cDh8a4LX0rn44FxtxTCB18lnzrSLMZ8/8Cr5m0c9NeXWA==", - "dependencies": { - "@fidm/x509": "^1.2.1", - "@grpc/grpc-js": "~1.10.9", - "@hyperledger/fabric-protos": "~0.2.1", - "@types/node": "^16.11.1", - "ajv": "^6.12.2", - "fabric-contract-api": "2.5.6", - "fabric-shim-api": "2.5.6", - "fast-safe-stringify": "^2.1.1", - "long": "^5.2.3", - "reflect-metadata": "^0.1.13", - "winston": "^3.7.2", - "yargs": "^17.4.0", - "yargs-parser": "^21.0.1" - }, - "bin": { - "fabric-chaincode-node": "cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/fabric-shim-api": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/fabric-shim-api/-/fabric-shim-api-2.5.6.tgz", - "integrity": "sha512-1L0nO7CJ31/gEOWKWHEeCqgB5HkqPVfRbpcS7L9eTscT7tffjg2OkZISvC+a7RiqihL0iyrXNBgBg5MwlSSN9g==", - "engines": { - "eslint": "^6.6.0", - "node": ">=18" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fecha": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "node_modules/fn.name": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", - "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" - }, - "node_modules/foreground-child": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/fromentries": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", - "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-params": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/get-params/-/get-params-0.1.2.tgz", - "integrity": "sha512-41eOxtlGgHQRbFyA8KTH+w+32Em3cRdfBud7j67ulzmIfmaHX9doq47s0fa4P5o9H64BZX9nrYI6sJvk46Op+Q==" - }, - "node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/google-protobuf": { - "version": "3.21.2", - "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz", - "integrity": "sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==" - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/hasha": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", - "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", - "dev": true, - "dependencies": { - "is-stream": "^2.0.0", - "type-fest": "^0.8.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/hasha/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/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, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "node_modules/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==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-hook": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", - "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", - "dev": true, - "dependencies": { - "append-transform": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, - "dependencies": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-processinfo": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz", - "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==", - "dev": true, - "dependencies": { - "archy": "^1.0.0", - "cross-spawn": "^7.0.3", - "istanbul-lib-coverage": "^3.2.0", - "p-map": "^3.0.0", - "rimraf": "^3.0.0", - "uuid": "^8.3.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-report/node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/istanbul-lib-report/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", - "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/just-extend": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", - "integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==", - "dev": true - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kuler": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" - }, - "node_modules/lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", - "dev": true - }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/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, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/logform": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", - "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", - "dependencies": { - "@colors/colors": "1.6.0", - "@types/triple-beam": "^1.3.2", - "fecha": "^4.2.0", - "ms": "^2.1.1", - "safe-stable-stringify": "^2.3.1", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/long": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" - }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.1" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mocha": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.4.0.tgz", - "integrity": "sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA==", - "dev": true, - "dependencies": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "8.1.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/mocha/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/mocha/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/mocha/node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/mocha/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/nise": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/nise/-/nise-6.0.0.tgz", - "integrity": "sha512-K8ePqo9BFvN31HXwEtTNGzgrPpmvgciDsFz8aztFjt4LqKO/JeFD8tBOeuDiCMXrIl/m1YvfH8auSpxfaD09wg==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.0", - "@sinonjs/fake-timers": "^11.2.2", - "@sinonjs/text-encoding": "^0.7.2", - "just-extend": "^6.2.0", - "path-to-regexp": "^6.2.1" - } - }, - "node_modules/node-preload": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", - "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", - "dev": true, - "dependencies": { - "process-on-spawn": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nyc": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", - "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", - "dev": true, - "dependencies": { - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "caching-transform": "^4.0.0", - "convert-source-map": "^1.7.0", - "decamelize": "^1.2.0", - "find-cache-dir": "^3.2.0", - "find-up": "^4.1.0", - "foreground-child": "^2.0.0", - "get-package-type": "^0.1.0", - "glob": "^7.1.6", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-hook": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "make-dir": "^3.0.0", - "node-preload": "^0.2.1", - "p-map": "^3.0.0", - "process-on-spawn": "^1.0.0", - "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "spawn-wrap": "^2.0.0", - "test-exclude": "^6.0.0", - "yargs": "^15.0.2" - }, - "bin": { - "nyc": "bin/nyc.js" - }, - "engines": { - "node": ">=8.9" - } - }, - "node_modules/nyc/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/nyc/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/nyc/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nyc/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "node_modules/nyc/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/one-time": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", - "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", - "dependencies": { - "fn.name": "1.x.x" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/package-hash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", - "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.15", - "hasha": "^5.0.0", - "lodash.flattendeep": "^4.4.0", - "release-zalgo": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-to-regexp": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz", - "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==", - "dev": true - }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/process-on-spawn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", - "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", - "dev": true, - "dependencies": { - "fromentries": "^1.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/protobufjs": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.2.tgz", - "integrity": "sha512-RXyHaACeqXeqAKGLDl68rQKbmObRsTIn4TYVUUug1KfS47YWCo5MacGITEryugIgZqORCvJWEk4l449POg5Txg==", - "hasInstallScript": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/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, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/reflect-metadata": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", - "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==" - }, - "node_modules/release-zalgo": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", - "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==", - "dev": true, - "dependencies": { - "es6-error": "^4.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safe-stable-stringify": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", - "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", - "engines": { - "node": ">=10" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/sinon": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-18.0.0.tgz", - "integrity": "sha512-+dXDXzD1sBO6HlmZDd7mXZCR/y5ECiEiGCBSGuFD/kZ0bDTofPYc6JaeGmPSF+1j1MejGUWkORbYOLDyvqCWpA==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.1", - "@sinonjs/fake-timers": "^11.2.2", - "@sinonjs/samsam": "^8.0.0", - "diff": "^5.2.0", - "nise": "^6.0.0", - "supports-color": "^7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/sinon" - } - }, - "node_modules/sinon-chai": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.7.0.tgz", - "integrity": "sha512-mf5NURdUaSdnatJx3uhoBOrY9dtL19fiOtAdT1Azxg3+lNJFiuN0uzaU3xX1LeAfL17kHQhTAJgpsfhbMJMY2g==", - "dev": true, - "peerDependencies": { - "chai": "^4.0.0", - "sinon": ">=4.0.0" - } - }, - "node_modules/sinon/node_modules/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/spawn-wrap": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", - "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", - "dev": true, - "dependencies": { - "foreground-child": "^2.0.0", - "is-windows": "^1.0.2", - "make-dir": "^3.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "which": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", - "engines": { - "node": "*" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/test-exclude/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/text-hex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/triple-beam": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", - "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/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, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", - "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-module": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", - "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", - "dev": true - }, - "node_modules/winston": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.13.0.tgz", - "integrity": "sha512-rwidmA1w3SE4j0E5MuIufFhyJPBDG7Nu71RkZor1p2+qHvJSZ9GYDA81AyleQcZbh/+V6HjeBdfnTZJm9rSeQQ==", - "dependencies": { - "@colors/colors": "^1.6.0", - "@dabh/diagnostics": "^2.0.2", - "async": "^3.2.3", - "is-stream": "^2.0.0", - "logform": "^2.4.0", - "one-time": "^1.0.0", - "readable-stream": "^3.4.0", - "safe-stable-stringify": "^2.3.1", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.7.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/winston-transport": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz", - "integrity": "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==", - "dependencies": { - "logform": "^2.3.2", - "readable-stream": "^3.6.0", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yargs-unparser/node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/asset-transfer-events/chaincode-javascript/package.json b/asset-transfer-events/chaincode-javascript/package.json deleted file mode 100644 index 05587582..00000000 --- a/asset-transfer-events/chaincode-javascript/package.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "name": "asset-transfer-events", - "version": "1.0.0", - "description": "Asset-Transfer-Events contract implemented in JavaScript", - "main": "index.js", - "engines": { - "node": ">=18" - }, - "scripts": { - "lint": "eslint .", - "pretest": "npm run lint", - "test": "nyc mocha --recursive", - "start": "fabric-chaincode-node start" - }, - "engineStrict": true, - "author": "Hyperledger", - "license": "Apache-2.0", - "dependencies": { - "fabric-contract-api": "~2.5", - "fabric-shim": "~2.5" - }, - "devDependencies": { - "chai": "^4.4.1", - "eslint": "^8.57.0", - "mocha": "^10.4.0", - "nyc": "^15.1.0", - "sinon": "^18.0.0", - "sinon-chai": "^3.7.0" - }, - "nyc": { - "exclude": [ - "coverage/**", - "test/**", - "index.js", - ".eslintrc.js" - ], - "reporter": [ - "text-summary", - "html" - ], - "all": true, - "check-coverage": true, - "statements": 100, - "branches": 100, - "functions": 100, - "lines": 100 - } -} diff --git a/asset-transfer-events/chaincode-javascript/test/assetTransferEvents.test.js b/asset-transfer-events/chaincode-javascript/test/assetTransferEvents.test.js deleted file mode 100644 index 552b8ad7..00000000 --- a/asset-transfer-events/chaincode-javascript/test/assetTransferEvents.test.js +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 -*/ - -'use strict'; -const sinon = require('sinon'); -const chai = require('chai'); -const sinonChai = require('sinon-chai'); -const expect = chai.expect; - -const { Context } = require('fabric-contract-api'); -const { ChaincodeStub, ClientIdentity } = require('fabric-shim'); - -const AssetTransfer = require('../lib/assetTransferEvents.js'); - -let assert = sinon.assert; -chai.use(sinonChai); - -describe('Asset Transfer Events Tests', () => { - let transactionContext, chaincodeStub, clientIdentity, asset; - let transientMap, asset_properties; - - beforeEach(() => { - transactionContext = new Context(); - - chaincodeStub = sinon.createStubInstance(ChaincodeStub); - chaincodeStub.getMspID.returns('org1'); - transactionContext.setChaincodeStub(chaincodeStub); - - clientIdentity = sinon.createStubInstance(ClientIdentity); - clientIdentity.getMSPID.returns('org1'); - transactionContext.clientIdentity = clientIdentity; - - chaincodeStub.putState.callsFake((key, value) => { - if (!chaincodeStub.states) { - chaincodeStub.states = {}; - } - chaincodeStub.states[key] = value; - }); - - chaincodeStub.getState.callsFake(async (key) => { - let ret; - if (chaincodeStub.states) { - ret = chaincodeStub.states[key]; - } - return Promise.resolve(ret); - }); - - chaincodeStub.deleteState.callsFake(async (key) => { - if (chaincodeStub.states) { - delete chaincodeStub.states[key]; - } - return Promise.resolve(key); - }); - - chaincodeStub.getStateByRange.callsFake(async () => { - function* internalGetStateByRange() { - if (chaincodeStub.states) { - // Shallow copy - const copied = Object.assign({}, chaincodeStub.states); - - for (let key in copied) { - yield {value: copied[key]}; - } - } - } - - return Promise.resolve(internalGetStateByRange()); - }); - - asset = { - ID: 'asset1', - Color: 'blue', - Size: 5, - Owner: 'Tomoko', - AppraisedValue: 300, - }; - const randomNumber = Math.floor(Math.random() * 100) + 1; - asset_properties = { - object_type: 'asset_properties', - asset_id: 'asset1', - Price: '90', - salt: Buffer.from(randomNumber.toString()).toString('hex') - }; - transientMap = new Map(); - transientMap.set('asset_properties', Buffer.from(JSON.stringify(asset_properties))); - }); - - describe('Test CreateAsset', () => { - it('should return error on CreateAsset', async () => { - chaincodeStub.putState.rejects('failed inserting key'); - - let assetTransfer = new AssetTransfer(); - try { - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - assert.fail('CreateAsset should have failed'); - } catch(err) { - expect(err.name).to.equal('failed inserting key'); - } - }); - - it('should return success on CreateAsset', async () => { - let assetTransfer = new AssetTransfer(); - - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - let ret = JSON.parse((await chaincodeStub.getState(asset.ID)).toString()); - expect(ret).to.eql(asset); - }); - it('should return success on CreateAsset with transient data', async () => { - let assetTransfer = new AssetTransfer(); - chaincodeStub.getTransient.returns(transientMap); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - let ret = JSON.parse((await chaincodeStub.getState(asset.ID)).toString()); - expect(ret).to.eql(asset); - }); - }); - - describe('Test ReadAsset', () => { - it('should return error on ReadAsset', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - try { - await assetTransfer.ReadAsset(transactionContext, 'asset2'); - assert.fail('ReadAsset should have failed'); - } catch (err) { - expect(err.message).to.equal('The asset asset2 does not exist'); - } - }); - - it('should return success on ReadAsset', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - const assetString = await assetTransfer.ReadAsset(transactionContext, 'asset1'); - const readAsset = JSON.parse(assetString); - expect(readAsset).to.eql(asset); - }); - - it('should return success on ReadAsset with private data', async () => { - asset.asset_properties = asset_properties; - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - chaincodeStub.getPrivateData.returns(Buffer.from(JSON.stringify(asset_properties))); - const assetString = await assetTransfer.ReadAsset(transactionContext, 'asset1'); - const readAsset = JSON.parse(assetString); - expect(readAsset).to.eql(asset); - }); - }); - - describe('Test UpdateAsset', () => { - it('should return error on UpdateAsset', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - try { - await assetTransfer.UpdateAsset(transactionContext, 'asset2', 'orange', 10, 'Me', 500); - assert.fail('UpdateAsset should have failed'); - } catch (err) { - expect(err.message).to.equal('The asset asset2 does not exist'); - } - }); - - it('should return success on UpdateAsset', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - await assetTransfer.UpdateAsset(transactionContext, 'asset1', 'orange', 10, 'Me', 500); - let ret = JSON.parse(await chaincodeStub.getState(asset.ID)); - let expected = { - ID: 'asset1', - Color: 'orange', - Size: 10, - Owner: 'Me', - AppraisedValue: 500 - }; - expect(ret).to.eql(expected); - }); - }); - - describe('Test DeleteAsset', () => { - it('should return error on DeleteAsset', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - try { - await assetTransfer.DeleteAsset(transactionContext, 'asset2'); - assert.fail('DeleteAsset should have failed'); - } catch (err) { - expect(err.message).to.equal('The asset asset2 does not exist'); - } - }); - - it('should return success on DeleteAsset', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - await assetTransfer.DeleteAsset(transactionContext, asset.ID); - let ret = await chaincodeStub.getState(asset.ID); - expect(ret).to.equal(undefined); - }); - }); - - describe('Test TransferAsset', () => { - it('should return error on TransferAsset', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - try { - await assetTransfer.TransferAsset(transactionContext, 'asset2', 'Me'); - assert.fail('DeleteAsset should have failed'); - } catch (err) { - expect(err.message).to.equal('The asset asset2 does not exist'); - } - }); - - it('should return success on TransferAsset', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - await assetTransfer.TransferAsset(transactionContext, asset.ID, 'Me'); - let ret = JSON.parse((await chaincodeStub.getState(asset.ID)).toString()); - expect(ret).to.eql(Object.assign({}, asset, {Owner: 'Me'})); - }); - }); -}); diff --git a/asset-transfer-ledger-queries/application-java/.gitattributes b/asset-transfer-ledger-queries/application-java/.gitattributes deleted file mode 100644 index 00a51aff..00000000 --- a/asset-transfer-ledger-queries/application-java/.gitattributes +++ /dev/null @@ -1,6 +0,0 @@ -# -# https://help.github.com/articles/dealing-with-line-endings/ -# -# These are explicitly windows files and should use crlf -*.bat text eol=crlf - diff --git a/asset-transfer-ledger-queries/application-java/build.gradle b/asset-transfer-ledger-queries/application-java/build.gradle deleted file mode 100644 index a204249d..00000000 --- a/asset-transfer-ledger-queries/application-java/build.gradle +++ /dev/null @@ -1,42 +0,0 @@ -/* - * This file was generated by the Gradle 'init' task. - * - * This generated file contains a sample Java project to get you started. - * For more details take a look at the Java Quickstart chapter in the Gradle - * User Manual available at https://docs.gradle.org/6.5/userguide/tutorial_java_projects.html - */ - -plugins { - // Apply the java plugin to add support for Java - id 'java' - - // Apply the application plugin to add support for building a CLI application. - id 'application' -} -ext { - javaMainClass = "application.java.App" -} - -repositories { - // You can declare any Maven/Ivy/file repository here. - mavenCentral() -} - -dependencies { - // This dependency is used by the application. - implementation 'com.google.guava:guava:29.0-jre' - implementation 'org.hyperledger.fabric:fabric-gateway-java:2.1.1' -} - -application { - // Define the main class for the application. - mainClassName = 'application.java.App' -} - -// task for running the app after building dependencies -task runApp(type: Exec) { - dependsOn build - group = "Execution" - description = "Run the main class with ExecTask" - commandLine "java", "-classpath", sourceSets.main.runtimeClasspath.getAsPath(), javaMainClass -} \ No newline at end of file diff --git a/asset-transfer-ledger-queries/application-java/gradle/wrapper/gradle-wrapper.jar b/asset-transfer-ledger-queries/application-java/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index d64cd4917707c1f8861d8cb53dd15194d4248596..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43462 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 diff --git a/asset-transfer-ledger-queries/application-java/gradle/wrapper/gradle-wrapper.properties b/asset-transfer-ledger-queries/application-java/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index e2847c82..00000000 --- a/asset-transfer-ledger-queries/application-java/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/asset-transfer-ledger-queries/application-java/gradlew b/asset-transfer-ledger-queries/application-java/gradlew deleted file mode 100755 index 1aa94a42..00000000 --- a/asset-transfer-ledger-queries/application-java/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/asset-transfer-ledger-queries/application-java/gradlew.bat b/asset-transfer-ledger-queries/application-java/gradlew.bat deleted file mode 100644 index 25da30db..00000000 --- a/asset-transfer-ledger-queries/application-java/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/asset-transfer-ledger-queries/application-java/settings.gradle b/asset-transfer-ledger-queries/application-java/settings.gradle deleted file mode 100644 index 5423bc7d..00000000 --- a/asset-transfer-ledger-queries/application-java/settings.gradle +++ /dev/null @@ -1,10 +0,0 @@ -/* - * This file was generated by the Gradle 'init' task. - * - * The settings file is used to specify which projects to include in your build. - * - * Detailed information about configuring a multi-project build in Gradle can be found - * in the user manual at https://docs.gradle.org/6.5/userguide/multi_project_builds.html - */ - -rootProject.name = 'application-java' diff --git a/asset-transfer-ledger-queries/application-java/src/main/java/application/java/App.java b/asset-transfer-ledger-queries/application-java/src/main/java/application/java/App.java deleted file mode 100644 index 595d6f33..00000000 --- a/asset-transfer-ledger-queries/application-java/src/main/java/application/java/App.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -// Running TestApp: -// gradle runApp - -package application.java; - -import java.nio.file.Path; -import java.nio.file.Paths; -import org.hyperledger.fabric.gateway.Contract; -import org.hyperledger.fabric.gateway.Gateway; -import org.hyperledger.fabric.gateway.Network; -import org.hyperledger.fabric.gateway.Wallet; -import org.hyperledger.fabric.gateway.Wallets; - - -public class App { - - static { - System.setProperty("org.hyperledger.fabric.sdk.service_discovery.as_localhost", "true"); - } - - // helper function for getting connected to the gateway - public static Gateway connect() throws Exception{ - // Load a file system based wallet for managing identities. - Path walletPath = Paths.get("wallet"); - Wallet wallet = Wallets.newFileSystemWallet(walletPath); - // load a CCP - Path networkConfigPath = Paths.get("..", "..", "test-network", "organizations", "peerOrganizations", "org1.example.com", "connection-org1.yaml"); - - Gateway.Builder builder = Gateway.createBuilder(); - builder.identity(wallet, "appUser").networkConfig(networkConfigPath).discovery(true); - return builder.connect(); - } - - public static void main(String[] args) throws Exception { - // enrolls the admin and registers the user - try { - EnrollAdmin.main(null); - RegisterUser.main(null); - } catch (Exception e) { - System.err.println(e); - } - - // connect to the network and invoke the smart contract - try (Gateway gateway = connect()) { - - // get the network and contract - Network network = gateway.getNetwork("mychannel"); - Contract contract = network.getContract("ledger"); - - byte[] result; - - System.out.println("Submit Transaction: InitLedger creates the initial set of assets on the ledger."); - contract.submitTransaction("InitLedger"); - - System.out.println("\n"); - // passing in 2 empty strings will query all the assets - result = contract.evaluateTransaction("GetAssetsByRange", "", ""); - System.out.println("Evaluate Transaction: GetAssetsByRange, result: " + new String(result)); - - System.out.println("\n"); - System.out.println("Submit Transaction: CreateAsset asset13"); - // CreateAsset creates an asset with ID asset13, color yellow, owner Tom, size 5 and appraisedValue of 1300 - contract.submitTransaction("CreateAsset", "asset13", "yellow", "5", "Tom", "1300"); - - System.out.println("\n"); - System.out.println("Evaluate Transaction: ReadAsset asset13"); - // ReadAsset returns an asset with given assetID - result = contract.evaluateTransaction("ReadAsset", "asset13"); - System.out.println("result: " + new String(result)); - - System.out.println("\n"); - System.out.println("Evaluate Transaction: AssetExists asset1"); - // AssetExists returns "true" if an asset with given assetID exist - result = contract.evaluateTransaction("AssetExists", "asset1"); - System.out.println("result: " + new String(result)); - - System.out.println("\n"); - System.out.println("Submit Transaction: DeleteAsset asset1"); - contract.submitTransaction("DeleteAsset", "asset1"); - - System.out.println("\n"); - System.out.println("Evaluate Transaction: AssetExists asset1"); - // AssetExists returns "true" if an asset with given assetID exist - result = contract.evaluateTransaction("AssetExists", "asset1"); - System.out.println("result: " + new String(result)); - - System.out.println("\n"); - System.out.println("Submit Transaction: TransferAsset asset2 from owner Tomoko > owner Tom"); - // TransferAsset transfers an asset with given ID to new owner Tom - contract.submitTransaction("TransferAsset", "asset2", "Tom"); - - // Rich Query with Pagination (Only supported if CouchDB is used as state database) - System.out.println("\n"); - System.out.println("Evaluate Transaction:QueryAssetsWithPagination Tom's assets"); - result = contract.evaluateTransaction("QueryAssetsWithPagination","{\"selector\":{\"docType\":\"asset\",\"owner\":\"Tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}","3",""); - System.out.println("result: " + new String(result)); - - System.out.println("\n"); - System.out.println("Submit Transaction: TransferAssetByColor yellow assets > newOwner Michel"); - contract.submitTransaction("TransferAssetByColor", "yellow", "Michel"); - - // Rich Query (Only supported if CouchDB is used as state database): - System.out.println("\n"); - System.out.println("Evaluate Transaction:QueryAssetsByOwner Michel"); - result = contract.evaluateTransaction("QueryAssetsByOwner", "Michel"); - System.out.println("result: " + new String(result)); - - System.out.println("\n"); - System.out.println("Evaluate Transaction:GetAssetHistory asset13"); - result = contract.evaluateTransaction("GetAssetHistory", "asset13"); - System.out.println("result: " + new String(result)); - - // Rich Query (Only supported if CouchDB is used as state database): - System.out.println("\n"); - System.out.println("Evaluate Transaction:QueryAssets assets of size 15"); - result = contract.evaluateTransaction("QueryAssets", "{\"selector\":{\"size\":15}}"); - System.out.println("result: " + new String(result)); - - // Rich Query with index design doc and index name specified (Only supported if CouchDB is used as state database): - System.out.println("\n"); - System.out.println("Evaluate Transaction:QueryAssets Jin Soo's assets"); - result = contract.evaluateTransaction("QueryAssets","{\"selector\":{\"docType\":\"asset\",\"owner\":\"Jin Soo\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}"); - System.out.println("result: " + new String(result)); - - // Range Query with Pagination - System.out.println("\n"); - System.out.println("Evaluate Transaction:GetAssetsByRangeWithPagination assets 3-5"); - result = contract.evaluateTransaction("GetAssetsByRangeWithPagination", "asset3", "asset6", "3",""); - System.out.println("result: " + new String(result)); - } - catch(Exception e){ - System.err.println(e); - System.exit(1); - } - - } -} diff --git a/asset-transfer-ledger-queries/application-java/src/main/java/application/java/EnrollAdmin.java b/asset-transfer-ledger-queries/application-java/src/main/java/application/java/EnrollAdmin.java deleted file mode 100644 index 563a35f1..00000000 --- a/asset-transfer-ledger-queries/application-java/src/main/java/application/java/EnrollAdmin.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -package application.java; - -import java.nio.file.Paths; -import java.util.Properties; - -import org.hyperledger.fabric.gateway.Wallet; -import org.hyperledger.fabric.gateway.Wallets; -import org.hyperledger.fabric.gateway.Identities; -import org.hyperledger.fabric.gateway.Identity; -import org.hyperledger.fabric.sdk.Enrollment; -import org.hyperledger.fabric.sdk.security.CryptoSuite; -import org.hyperledger.fabric.sdk.security.CryptoSuiteFactory; -import org.hyperledger.fabric_ca.sdk.EnrollmentRequest; -import org.hyperledger.fabric_ca.sdk.HFCAClient; - -public class EnrollAdmin { - - public static void main(String[] args) throws Exception { - - // Create a CA client for interacting with the CA. - Properties props = new Properties(); - props.put("pemFile", - "../../test-network/organizations/peerOrganizations/org1.example.com/ca/ca.org1.example.com-cert.pem"); - props.put("allowAllHostNames", "true"); - HFCAClient caClient = HFCAClient.createNewInstance("https://localhost:7054", props); - CryptoSuite cryptoSuite = CryptoSuiteFactory.getDefault().getCryptoSuite(); - caClient.setCryptoSuite(cryptoSuite); - - // Create a wallet for managing identities - Wallet wallet = Wallets.newFileSystemWallet(Paths.get("wallet")); - - // Check to see if we've already enrolled the admin user. - if (wallet.get("admin") != null) { - System.out.println("An identity for the admin user \"admin\" already exists in the wallet"); - return; - } - - // Enroll the admin user, and import the new identity into the wallet. - final EnrollmentRequest enrollmentRequestTLS = new EnrollmentRequest(); - enrollmentRequestTLS.addHost("localhost"); - enrollmentRequestTLS.setProfile("tls"); - Enrollment enrollment = caClient.enroll("admin", "adminpw", enrollmentRequestTLS); - Identity user = Identities.newX509Identity("Org1MSP", enrollment); - wallet.put("admin", user); - System.out.println("Successfully enrolled user \"admin\" and imported it into the wallet"); - } -} diff --git a/asset-transfer-ledger-queries/application-java/src/main/java/application/java/RegisterUser.java b/asset-transfer-ledger-queries/application-java/src/main/java/application/java/RegisterUser.java deleted file mode 100644 index 367b4a39..00000000 --- a/asset-transfer-ledger-queries/application-java/src/main/java/application/java/RegisterUser.java +++ /dev/null @@ -1,107 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package application.java; - -import java.nio.file.Paths; -import java.security.PrivateKey; -import java.util.Properties; -import java.util.Set; - -import org.hyperledger.fabric.gateway.Wallet; -import org.hyperledger.fabric.gateway.Wallets; -import org.hyperledger.fabric.gateway.Identities; -import org.hyperledger.fabric.gateway.Identity; -import org.hyperledger.fabric.gateway.X509Identity; -import org.hyperledger.fabric.sdk.Enrollment; -import org.hyperledger.fabric.sdk.User; -import org.hyperledger.fabric.sdk.security.CryptoSuite; -import org.hyperledger.fabric.sdk.security.CryptoSuiteFactory; -import org.hyperledger.fabric_ca.sdk.HFCAClient; -import org.hyperledger.fabric_ca.sdk.RegistrationRequest; - -public class RegisterUser { - - public static void main(String[] args) throws Exception { - - // Create a CA client for interacting with the CA. - Properties props = new Properties(); - props.put("pemFile", - "../../test-network/organizations/peerOrganizations/org1.example.com/ca/ca.org1.example.com-cert.pem"); - props.put("allowAllHostNames", "true"); - HFCAClient caClient = HFCAClient.createNewInstance("https://localhost:7054", props); - CryptoSuite cryptoSuite = CryptoSuiteFactory.getDefault().getCryptoSuite(); - caClient.setCryptoSuite(cryptoSuite); - - // Create a wallet for managing identities - Wallet wallet = Wallets.newFileSystemWallet(Paths.get("wallet")); - - // Check to see if we've already enrolled the user. - if (wallet.get("appUser") != null) { - System.out.println("An identity for the user \"appUser\" already exists in the wallet"); - return; - } - - X509Identity adminIdentity = (X509Identity)wallet.get("admin"); - if (adminIdentity == null) { - System.out.println("\"admin\" needs to be enrolled and added to the wallet first"); - return; - } - User admin = new User() { - - @Override - public String getName() { - return "admin"; - } - - @Override - public Set getRoles() { - return null; - } - - @Override - public String getAccount() { - return null; - } - - @Override - public String getAffiliation() { - return "org1.department1"; - } - - @Override - public Enrollment getEnrollment() { - return new Enrollment() { - - @Override - public PrivateKey getKey() { - return adminIdentity.getPrivateKey(); - } - - @Override - public String getCert() { - return Identities.toPemString(adminIdentity.getCertificate()); - } - }; - } - - @Override - public String getMspId() { - return "Org1MSP"; - } - - }; - - // Register the user, enroll the user, and import the new identity into the wallet. - RegistrationRequest registrationRequest = new RegistrationRequest("appUser"); - registrationRequest.setAffiliation("org1.department1"); - registrationRequest.setEnrollmentID("appUser"); - String enrollmentSecret = caClient.register(registrationRequest, admin); - Enrollment enrollment = caClient.enroll("appUser", enrollmentSecret); - Identity user = Identities.newX509Identity("Org1MSP", enrollment); - wallet.put("appUser", user); - System.out.println("Successfully enrolled user \"appUser\" and imported it into the wallet"); - } - -} diff --git a/asset-transfer-ledger-queries/application-java/src/main/resources/log4j.properties b/asset-transfer-ledger-queries/application-java/src/main/resources/log4j.properties deleted file mode 100644 index f1f841fe..00000000 --- a/asset-transfer-ledger-queries/application-java/src/main/resources/log4j.properties +++ /dev/null @@ -1,19 +0,0 @@ -# initialize root logger with level ERROR for stdout and fout -log4j.rootLogger=ERROR,stdout,fout -# set the log level for these components -log4j.logger.com.endeca=INFO -log4j.logger.com.endeca.itl.web.metrics=INFO - -# add a ConsoleAppender to the logger stdout to write to the console -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -# use a simple message format -log4j.appender.stdout.layout.ConversionPattern=%m%n - -# add a FileAppender to the logger fout -log4j.appender.fout=org.apache.log4j.FileAppender -# create a log file -log4j.appender.fout.File=crawl.log -log4j.appender.fout.layout=org.apache.log4j.PatternLayout -# use a more detailed message pattern -log4j.appender.fout.layout.ConversionPattern=%p\t%d{ISO8601}\t%r\t%c\t[%t]\t%m%n diff --git a/asset-transfer-ledger-queries/application-javascript/.eslintignore b/asset-transfer-ledger-queries/application-javascript/.eslintignore deleted file mode 100644 index 15958470..00000000 --- a/asset-transfer-ledger-queries/application-javascript/.eslintignore +++ /dev/null @@ -1,5 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -coverage diff --git a/asset-transfer-ledger-queries/application-javascript/.eslintrc.js b/asset-transfer-ledger-queries/application-javascript/.eslintrc.js deleted file mode 100644 index 072edaf6..00000000 --- a/asset-transfer-ledger-queries/application-javascript/.eslintrc.js +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -module.exports = { - env: { - node: true, - mocha: true - }, - parserOptions: { - ecmaVersion: 8, - sourceType: 'script' - }, - extends: 'eslint:recommended', - rules: { - indent: ['error', 'tab'], - 'linebreak-style': ['error', 'unix'], - quotes: ['error', 'single'], - semi: ['error', 'always'], - 'no-unused-vars': ['error', { args: 'none' }], - 'no-console': 'off', - curly: 'error', - eqeqeq: 'error', - 'no-throw-literal': 'error', - strict: 'error', - 'no-var': 'error', - 'dot-notation': 'error', - 'no-trailing-spaces': 'error', - 'no-use-before-define': 'error', - 'no-useless-call': 'error', - 'no-with': 'error', - 'operator-linebreak': 'error', - yoda: 'error', - 'quote-props': ['error', 'as-needed'] - } -}; diff --git a/asset-transfer-ledger-queries/application-javascript/.gitignore b/asset-transfer-ledger-queries/application-javascript/.gitignore deleted file mode 100644 index 21b287f7..00000000 --- a/asset-transfer-ledger-queries/application-javascript/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -# Coverage directory used by tools like istanbul -coverage - -# Dependency directories -node_modules/ -jspm_packages/ -package-lock.json - -wallet -!wallet/.gitkeep diff --git a/asset-transfer-ledger-queries/application-javascript/app.js b/asset-transfer-ledger-queries/application-javascript/app.js deleted file mode 100644 index 0aa179a8..00000000 --- a/asset-transfer-ledger-queries/application-javascript/app.js +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const FabricCAServices = require('fabric-ca-client'); -const path = require('path'); -const { buildCAClient, registerAndEnrollUser, enrollAdmin } = require('../../test-application/javascript/CAUtil.js'); -const { buildCCPOrg1, buildWallet } = require('../../test-application/javascript/AppUtil.js'); - -const channelName = 'mychannel'; -const chaincodeName = 'ledger'; -const mspOrg1 = 'Org1MSP'; - -const walletPath = path.join(__dirname, 'wallet'); -const userId = 'appUser'; - -function prettyJSONString(inputString) { - return JSON.stringify(JSON.parse(inputString), null, 2); -} - -// pre-requisites: -// - fabric-sample two organization test-network setup with two peers, ordering service, -// and 2 certificate authorities, with the state database using couchdb -// ===> from directory /fabric-samples/test-network -// ./network.sh up createChannel -ca -s couchdb -// - Use any of the asset-transfer-ledger-queries chaincodes deployed on the channel "mychannel" -// with the chaincode name of "ledger". The following deploy command will package, -// install, approve, and commit the javascript chaincode, all the actions it takes -// to deploy a chaincode to a channel. -// ===> from directory /fabric-samples/test-network -// ./network.sh deployCC -ccn ledger -ccp ../asset-transfer-ledger-queries/chaincode-javascript/ -ccl javascript -// - Be sure that node.js is installed -// ===> from directory /fabric-samples/asset-transfer-ledger-queries/application-javascript -// node -v -// - npm installed code dependencies -// ===> from directory /fabric-samples/asset-transfer-ledger-queries/application-javascript -// npm install -// - to run this test application -// ===> from directory /fabric-samples/asset-transfer-ledger-queries/application-javascript -// node app.js - -// NOTE: If you see kind an error like these: -/* - 2020-08-07T20:23:17.590Z - error: [DiscoveryService]: send[mychannel] - Channel:mychannel received discovery error:access denied - ******** FAILED to run the application: Error: DiscoveryService: mychannel error: access denied - - OR - - Failed to register user : Error: fabric-ca request register failed with errors [[ { code: 20, message: 'Authentication failure' } ]] - ******** FAILED to run the application: Error: Identity not found in wallet: appUser -*/ -// Delete the /fabric-samples/asset-transfer-ledger-queries/application-javascript/wallet directory -// and retry this application. -// -// The certificate authority must have been restarted and the saved certificates for the -// admin and application user are not valid. Deleting the wallet store will force these to be reset -// with the new certificate authority. -// - -/** - * A test application to show ledger queries operations with any of the asset-transfer-ledger-queries chaincodes - * -- How to submit a transaction - * -- How to query and check the results - * - * To see the SDK workings, try setting the logging to show on the console before running - * export HFC_LOGGING='{"debug":"console"}' - */ -async function main() { - let skipInit = false; - if (process.argv.length > 2) { - if (process.argv[2] === 'skipInit') { - skipInit = true; - } - } - - try { - // build an in memory object with the network configuration (also known as a connection profile) - const ccp = buildCCPOrg1(); - - // build an instance of the fabric ca services client based on - // the information in the network configuration - const caClient = buildCAClient(FabricCAServices, ccp, 'ca.org1.example.com'); - - // setup the wallet to hold the credentials of the application user - const wallet = await buildWallet(Wallets, walletPath); - - // in a real application this would be done on an administrative flow, and only once - await enrollAdmin(caClient, wallet, mspOrg1); - - // in a real application this would be done only when a new user was required to be added - // and would be part of an administrative flow - await registerAndEnrollUser(caClient, wallet, mspOrg1, userId, 'org1.department1'); - - // Create a new gateway instance for interacting with the fabric network. - // In a real application this would be done as the backend server session is setup for - // a user that has been verified. - const gateway = new Gateway(); - - try { - // setup the gateway instance - // The user will now be able to create connections to the fabric network and be able to - // submit transactions and query. All transactions submitted by this gateway will be - // signed by this user using the credentials stored in the wallet. - await gateway.connect(ccp, { - wallet, - identity: userId, - discovery: { enabled: true, asLocalhost: true } // using asLocalhost as this gateway is using a fabric network deployed locally - }); - - // Build a network instance based on the channel where the smart contract is deployed - const network = await gateway.getNetwork(channelName); - - // Get the contract from the network. - const contract = network.getContract(chaincodeName); - - // Initialize a set of asset data on the channel using the chaincode 'InitLedger' function. - // This type of transaction would only be run once by an application the first time it was started after it - // deployed the first time. Any updates to the chaincode deployed later would likely not need to run - // an "init" type function. - if (!skipInit) { - try { - console.log('\n--> Submit Transaction: InitLedger, function creates the initial set of assets on the ledger'); - await contract.submitTransaction('InitLedger'); - console.log('*** Result: committed'); - } catch (initError) { - // this is error is OK if we are rerunning this app without restarting - console.log(`******** initLedger failed :: ${initError}`); - } - } else { - console.log('*** not executing "InitLedger'); - } - - let result; - - // Let's try a query operation (function). - // This will be sent to just one peer and the results will be shown. - console.log('\n--> Evaluate Transaction: GetAssetsByRange, function returns assets in a specific range from asset1 to before asset6'); - result = await contract.evaluateTransaction('GetAssetsByRange', 'asset1', 'asset6'); - console.log(`*** Result: ${prettyJSONString(result.toString())}`); - - console.log('\n--> Evaluate Transaction: GetAssetsByRange, function use an open start and open end range to return assest1 to asset6'); - result = await contract.evaluateTransaction('GetAssetsByRange', '', ''); - console.log(`*** Result: ${prettyJSONString(result.toString())}`); - - console.log('\n--> Evaluate Transaction: GetAssetsByRange, function use an fixed start (asset3) and open end range to return assest3 to asset6'); - result = await contract.evaluateTransaction('GetAssetsByRange', 'asset3', ''); - console.log(`*** Result: ${prettyJSONString(result.toString())}`); - - console.log('\n--> Evaluate Transaction: GetAssetsByRange, function use an open start and fixed end (asset3) range to return assest1 to asset2'); - result = await contract.evaluateTransaction('GetAssetsByRange', '', 'asset3'); - console.log(`*** Result: ${prettyJSONString(result.toString())}`); - - // Now let's try to submit a transaction. - // This will be sent to both peers and if both peers endorse the transaction, the endorsed proposal will be sent - // to the orderer to be committed by each of the peer's to the channel ledger. - console.log('\n--> Submit Transaction: CreateAsset, creates new asset with ID(asset7), color(yellow), size(5), owner(Tom), and appraisedValue(1300) arguments'); - await contract.submitTransaction('CreateAsset', 'asset7', 'yellow', '5', 'Tom', '1300'); - console.log('*** Result: committed'); - - console.log('\n--> Evaluate Transaction: ReadAsset, function returns information about an asset with ID(asset7)'); - result = await contract.evaluateTransaction('ReadAsset', 'asset7'); - console.log(`*** Result: ${prettyJSONString(result.toString())}`); - - console.log('\n--> Evaluate Transaction: AssetExists, function returns "true" if an asset with ID(asset7) exist'); - result = await contract.evaluateTransaction('AssetExists', 'asset7'); - console.log(`*** Result: ${prettyJSONString(result.toString())}`); - - // Now let's try to submit a transaction that deletes an asset - // This will be sent to both peers and if both peers endorse the transaction, the endorsed proposal will be sent - // to the orderer to be committed by each of the peer's to the channel ledger. - console.log('\n--> Submit Transaction: DeleteAsset with ID(asset7)'); - await contract.submitTransaction('DeleteAsset', 'asset7'); - console.log('*** Result: committed'); - - console.log('\n--> Evaluate Transaction: AssetExists, function returns "false" if an asset with ID(asset7) does not exist'); - result = await contract.evaluateTransaction('AssetExists', 'asset7'); - console.log(`*** Result: ${prettyJSONString(result.toString())}`); - - console.log('\n--> Submit Transaction: TransferAsset, transfer asset(asset2) to new owner(Max)'); - await contract.submitTransaction('TransferAsset', 'asset2', 'Max'); - console.log('*** Result: committed'); - - console.log('\n--> Evaluate Transaction: ReadAsset, function returns information about an asset with ID(asset2)'); - result = await contract.evaluateTransaction('ReadAsset', 'asset2'); - console.log(`*** Result: ${prettyJSONString(result.toString())}`); - - // Rich Query with Pagination (Only supported if CouchDB is used as state database) - console.log('\n--> Evaluate Transaction: QueryAssetsWithPagination, function returns "Max" assets'); - result = await contract.evaluateTransaction('QueryAssetsWithPagination', '{"selector":{"docType":"asset","owner":"Max"}, "use_index":["_design/indexOwnerDoc", "indexOwner"]}', '1', ''); - console.log(`*** Result: ${prettyJSONString(result.toString())}`); - - // Recover the bookmark from previous query. Normally it will be inside a variable. - const resultJson = JSON.parse(result.toString()); - - console.log('\n--> Evaluate Transaction: QueryAssetsWithPagination, function returns "Max" assets next page'); - result = await contract.evaluateTransaction('QueryAssetsWithPagination', '{"selector":{"docType":"asset","owner":"Max"}, "use_index":["_design/indexOwnerDoc", "indexOwner"]}', '1', resultJson.bookmark); - console.log(`*** Result: ${prettyJSONString(result.toString())}`); - - console.log('\n--> Submit Transaction: TransferAssetByColor, transfer all yellow assets to new owner(Michel)'); - await contract.submitTransaction('TransferAssetByColor', 'yellow', 'Michel'); - console.log('*** Result: committed'); - - // Rich Query (Only supported if CouchDB is used as state database): - console.log('\n--> Evaluate Transaction: QueryAssetsByOwner, find all assets with owner(Michel)'); - result = await contract.evaluateTransaction('QueryAssetsByOwner', 'Michel'); - console.log(`*** Result: ${prettyJSONString(result.toString())}`); - - console.log('\n--> Evaluate Transaction: GetAssetHistory, get the history of an asset(asset7)'); - result = await contract.evaluateTransaction('GetAssetHistory', 'asset7'); - console.log(`*** Result: ${prettyJSONString(result.toString())}`); - - // Rich Query (Only supported if CouchDB is used as state database): - console.log('\n--> Evaluate Transaction: QueryAssets, assets of size 15'); - result = await contract.evaluateTransaction('QueryAssets', '{"selector":{"size":15}}'); - console.log(`*** Result: ${prettyJSONString(result.toString())}`); - - // Rich Query with index design doc and index name specified (Only supported if CouchDB is used as state database): - console.log('\n--> Evaluate Transaction: QueryAssets, Jin Soo\'s assets'); - result = await contract.evaluateTransaction('QueryAssets', '{"selector":{"docType":"asset","owner":"Jin Soo"}, "use_index":["_design/indexOwnerDoc", "indexOwner"]}'); - console.log(`*** Result: ${prettyJSONString(result.toString())}`); - - // Range Query with Pagination - console.log('\n--> Evaluate Transaction: GetAssetsByRangeWithPagination - get page 1 of assets from asset2 to asset6 (asset2, asset3)'); - result = await contract.evaluateTransaction('GetAssetsByRangeWithPagination', 'asset2', 'asset6', '2', ''); - console.log(`*** Result: ${prettyJSONString(result.toString())}`); - - // Range Query with Pagination - console.log('\n--> Evaluate Transaction: GetAssetsByRangeWithPagination - get page 2 of assets from asset2 to asset6 (asset4, asset5)'); - result = await contract.evaluateTransaction('GetAssetsByRangeWithPagination', 'asset2', 'asset6', '2', 'asset4'); - console.log(`*** Result: ${prettyJSONString(result.toString())}`); - - console.log('*** all tests completed'); - } finally { - // Disconnect from the gateway when the application is closing - // This will close all connections to the network - gateway.disconnect(); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - process.exit(1); - } - - console.log('*** application ending'); - -} - -main(); diff --git a/asset-transfer-ledger-queries/application-javascript/package.json b/asset-transfer-ledger-queries/application-javascript/package.json deleted file mode 100644 index a3cafb86..00000000 --- a/asset-transfer-ledger-queries/application-javascript/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "asset-transfer-ledger-queries", - "version": "1.0.0", - "description": "Asset transfer ledger queries application implemented in JavaScript", - "engines": { - "node": ">=12", - "npm": ">=5" - }, - "engineStrict": true, - "author": "Hyperledger", - "license": "Apache-2.0", - "scripts": { - "run": "node app.js", - "lint": "eslint *.js" - }, - "dependencies": { - "fabric-ca-client": "^2.2.19", - "fabric-network": "^2.2.19" - }, - "devDependencies": { - "eslint": "^7.32.0" - } -} diff --git a/asset-transfer-ledger-queries/chaincode-go/META-INF/statedb/couchdb/indexes/indexOwner.json b/asset-transfer-ledger-queries/chaincode-go/META-INF/statedb/couchdb/indexes/indexOwner.json deleted file mode 100644 index 305f0904..00000000 --- a/asset-transfer-ledger-queries/chaincode-go/META-INF/statedb/couchdb/indexes/indexOwner.json +++ /dev/null @@ -1 +0,0 @@ -{"index":{"fields":["docType","owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"} diff --git a/asset-transfer-ledger-queries/chaincode-go/asset_transfer_ledger_chaincode.go b/asset-transfer-ledger-queries/chaincode-go/asset_transfer_ledger_chaincode.go deleted file mode 100644 index 45eb1ba0..00000000 --- a/asset-transfer-ledger-queries/chaincode-go/asset_transfer_ledger_chaincode.go +++ /dev/null @@ -1,469 +0,0 @@ -/* - SPDX-License-Identifier: Apache-2.0 -*/ - -/* -====CHAINCODE EXECUTION SAMPLES (CLI) ================== - -==== Invoke assets ==== -peer chaincode invoke -C myc1 -n asset_transfer -c '{"Args":["CreateAsset","asset1","blue","5","tom","35"]}' -peer chaincode invoke -C myc1 -n asset_transfer -c '{"Args":["CreateAsset","asset2","red","4","tom","50"]}' -peer chaincode invoke -C myc1 -n asset_transfer -c '{"Args":["CreateAsset","asset3","blue","6","tom","70"]}' -peer chaincode invoke -C myc1 -n asset_transfer -c '{"Args":["TransferAsset","asset2","jerry"]}' -peer chaincode invoke -C myc1 -n asset_transfer -c '{"Args":["TransferAssetByColor","blue","jerry"]}' -peer chaincode invoke -C myc1 -n asset_transfer -c '{"Args":["DeleteAsset","asset1"]}' - -==== Query assets ==== -peer chaincode query -C myc1 -n asset_transfer -c '{"Args":["ReadAsset","asset1"]}' -peer chaincode query -C myc1 -n asset_transfer -c '{"Args":["GetAssetsByRange","asset1","asset3"]}' -peer chaincode query -C myc1 -n asset_transfer -c '{"Args":["GetAssetHistory","asset1"]}' - -Rich Query (Only supported if CouchDB is used as state database): -peer chaincode query -C myc1 -n asset_transfer -c '{"Args":["QueryAssetsByOwner","tom"]}' -peer chaincode query -C myc1 -n asset_transfer -c '{"Args":["QueryAssets","{\"selector\":{\"owner\":\"tom\"}}"]}' - -Rich Query with Pagination (Only supported if CouchDB is used as state database): -peer chaincode query -C myc1 -n asset_transfer -c '{"Args":["QueryAssetsWithPagination","{\"selector\":{\"owner\":\"tom\"}}","3",""]}' - -INDEXES TO SUPPORT COUCHDB RICH QUERIES - -Indexes in CouchDB are required in order to make JSON queries efficient and are required for -any JSON query with a sort. Indexes may be packaged alongside -chaincode in a META-INF/statedb/couchdb/indexes directory. Each index must be defined in its own -text file with extension *.json with the index definition formatted in JSON following the -CouchDB index JSON syntax as documented at: -http://docs.couchdb.org/en/2.3.1/api/database/find.html#db-index - -This asset transfer ledger example chaincode demonstrates a packaged -index which you can find in META-INF/statedb/couchdb/indexes/indexOwner.json. - -If you have access to the your peer's CouchDB state database in a development environment, -you may want to iteratively test various indexes in support of your chaincode queries. You -can use the CouchDB Fauxton interface or a command line curl utility to create and update -indexes. Then once you finalize an index, include the index definition alongside your -chaincode in the META-INF/statedb/couchdb/indexes directory, for packaging and deployment -to managed environments. - -In the examples below you can find index definitions that support asset transfer ledger -chaincode queries, along with the syntax that you can use in development environments -to create the indexes in the CouchDB Fauxton interface or a curl command line utility. - - -Index for docType, owner. - -Example curl command line to define index in the CouchDB channel_chaincode database -curl -i -X POST -H "Content-Type: application/json" -d "{\"index\":{\"fields\":[\"docType\",\"owner\"]},\"name\":\"indexOwner\",\"ddoc\":\"indexOwnerDoc\",\"type\":\"json\"}" http://hostname:port/myc1_assets/_index - - -Index for docType, owner, size (descending order). - -Example curl command line to define index in the CouchDB channel_chaincode database: -curl -i -X POST -H "Content-Type: application/json" -d "{\"index\":{\"fields\":[{\"size\":\"desc\"},{\"docType\":\"desc\"},{\"owner\":\"desc\"}]},\"ddoc\":\"indexSizeSortDoc\", \"name\":\"indexSizeSortDesc\",\"type\":\"json\"}" http://hostname:port/myc1_assets/_index - -Rich Query with index design doc and index name specified (Only supported if CouchDB is used as state database): -peer chaincode query -C myc1 -n asset_transfer -c '{"Args":["QueryAssets","{\"selector\":{\"docType\":\"asset\",\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}"]}' - -Rich Query with index design doc specified only (Only supported if CouchDB is used as state database): -peer chaincode query -C myc1 -n asset_transfer -c '{"Args":["QueryAssets","{\"selector\":{\"docType\":{\"$eq\":\"asset\"},\"owner\":{\"$eq\":\"tom\"},\"size\":{\"$gt\":0}},\"fields\":[\"docType\",\"owner\",\"size\"],\"sort\":[{\"size\":\"desc\"}],\"use_index\":\"_design/indexSizeSortDoc\"}"]}' -*/ - -package main - -import ( - "encoding/json" - "fmt" - "log" - "time" - - "github.com/hyperledger/fabric-chaincode-go/v2/shim" - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -const index = "color~name" - -// SimpleChaincode implements the fabric-contract-api-go programming model -type SimpleChaincode struct { - contractapi.Contract -} - -type Asset struct { - DocType string `json:"docType"` //docType is used to distinguish the various types of objects in state database - ID string `json:"ID"` //the field tags are needed to keep case from bouncing around - Color string `json:"color"` - Size int `json:"size"` - Owner string `json:"owner"` - AppraisedValue int `json:"appraisedValue"` -} - -// HistoryQueryResult structure used for returning result of history query -type HistoryQueryResult struct { - Record *Asset `json:"record"` - TxId string `json:"txId"` - Timestamp time.Time `json:"timestamp"` - IsDelete bool `json:"isDelete"` -} - -// PaginatedQueryResult structure used for returning paginated query results and metadata -type PaginatedQueryResult struct { - Records []*Asset `json:"records"` - FetchedRecordsCount int32 `json:"fetchedRecordsCount"` - Bookmark string `json:"bookmark"` -} - -// CreateAsset initializes a new asset in the ledger -func (t *SimpleChaincode) CreateAsset(ctx contractapi.TransactionContextInterface, assetID, color string, size int, owner string, appraisedValue int) error { - exists, err := t.AssetExists(ctx, assetID) - if err != nil { - return fmt.Errorf("failed to get asset: %v", err) - } - if exists { - return fmt.Errorf("asset already exists: %s", assetID) - } - - asset := &Asset{ - DocType: "asset", - ID: assetID, - Color: color, - Size: size, - Owner: owner, - AppraisedValue: appraisedValue, - } - assetBytes, err := json.Marshal(asset) - if err != nil { - return err - } - - err = ctx.GetStub().PutState(assetID, assetBytes) - if err != nil { - return err - } - - // Create an index to enable color-based range queries, e.g. return all blue assets. - // An 'index' is a normal key-value entry in the ledger. - // The key is a composite key, with the elements that you want to range query on listed first. - // In our case, the composite key is based on indexName~color~name. - // This will enable very efficient state range queries based on composite keys matching indexName~color~* - colorNameIndexKey, err := ctx.GetStub().CreateCompositeKey(index, []string{asset.Color, asset.ID}) - if err != nil { - return err - } - // Save index entry to world state. Only the key name is needed, no need to store a duplicate copy of the asset. - // Note - passing a 'nil' value will effectively delete the key from state, therefore we pass null character as value - value := []byte{0x00} - return ctx.GetStub().PutState(colorNameIndexKey, value) -} - -// ReadAsset retrieves an asset from the ledger -func (t *SimpleChaincode) ReadAsset(ctx contractapi.TransactionContextInterface, assetID string) (*Asset, error) { - assetBytes, err := ctx.GetStub().GetState(assetID) - if err != nil { - return nil, fmt.Errorf("failed to get asset %s: %v", assetID, err) - } - if assetBytes == nil { - return nil, fmt.Errorf("asset %s does not exist", assetID) - } - - var asset Asset - err = json.Unmarshal(assetBytes, &asset) - if err != nil { - return nil, err - } - - return &asset, nil -} - -// DeleteAsset removes an asset key-value pair from the ledger -func (t *SimpleChaincode) DeleteAsset(ctx contractapi.TransactionContextInterface, assetID string) error { - asset, err := t.ReadAsset(ctx, assetID) - if err != nil { - return err - } - - err = ctx.GetStub().DelState(assetID) - if err != nil { - return fmt.Errorf("failed to delete asset %s: %v", assetID, err) - } - - colorNameIndexKey, err := ctx.GetStub().CreateCompositeKey(index, []string{asset.Color, asset.ID}) - if err != nil { - return err - } - - // Delete index entry - return ctx.GetStub().DelState(colorNameIndexKey) -} - -// TransferAsset transfers an asset by setting a new owner name on the asset -func (t *SimpleChaincode) TransferAsset(ctx contractapi.TransactionContextInterface, assetID, newOwner string) error { - asset, err := t.ReadAsset(ctx, assetID) - if err != nil { - return err - } - - asset.Owner = newOwner - assetBytes, err := json.Marshal(asset) - if err != nil { - return err - } - - return ctx.GetStub().PutState(assetID, assetBytes) -} - -// constructQueryResponseFromIterator constructs a slice of assets from the resultsIterator -func constructQueryResponseFromIterator(resultsIterator shim.StateQueryIteratorInterface) ([]*Asset, error) { - var assets []*Asset - for resultsIterator.HasNext() { - queryResult, err := resultsIterator.Next() - if err != nil { - return nil, err - } - var asset Asset - err = json.Unmarshal(queryResult.Value, &asset) - if err != nil { - return nil, err - } - assets = append(assets, &asset) - } - - return assets, nil -} - -// GetAssetsByRange performs a range query based on the start and end keys provided. -// Read-only function results are not typically submitted to ordering. If the read-only -// results are submitted to ordering, or if the query is used in an update transaction -// and submitted to ordering, then the committing peers will re-execute to guarantee that -// result sets are stable between endorsement time and commit time. The transaction is -// invalidated by the committing peers if the result set has changed between endorsement -// time and commit time. -// Therefore, range queries are a safe option for performing update transactions based on query results. -func (t *SimpleChaincode) GetAssetsByRange(ctx contractapi.TransactionContextInterface, startKey, endKey string) ([]*Asset, error) { - resultsIterator, err := ctx.GetStub().GetStateByRange(startKey, endKey) - if err != nil { - return nil, err - } - defer resultsIterator.Close() - - return constructQueryResponseFromIterator(resultsIterator) -} - -// TransferAssetByColor will transfer assets of a given color to a certain new owner. -// Uses GetStateByPartialCompositeKey (range query) against color~name 'index'. -// Committing peers will re-execute range queries to guarantee that result sets are stable -// between endorsement time and commit time. The transaction is invalidated by the -// committing peers if the result set has changed between endorsement time and commit time. -// Therefore, range queries are a safe option for performing update transactions based on query results. -// Example: GetStateByPartialCompositeKey/RangeQuery -func (t *SimpleChaincode) TransferAssetByColor(ctx contractapi.TransactionContextInterface, color, newOwner string) error { - // Execute a key range query on all keys starting with 'color' - coloredAssetResultsIterator, err := ctx.GetStub().GetStateByPartialCompositeKey(index, []string{color}) - if err != nil { - return err - } - defer coloredAssetResultsIterator.Close() - - for coloredAssetResultsIterator.HasNext() { - responseRange, err := coloredAssetResultsIterator.Next() - if err != nil { - return err - } - - _, compositeKeyParts, err := ctx.GetStub().SplitCompositeKey(responseRange.Key) - if err != nil { - return err - } - - if len(compositeKeyParts) > 1 { - returnedAssetID := compositeKeyParts[1] - asset, err := t.ReadAsset(ctx, returnedAssetID) - if err != nil { - return err - } - asset.Owner = newOwner - assetBytes, err := json.Marshal(asset) - if err != nil { - return err - } - err = ctx.GetStub().PutState(returnedAssetID, assetBytes) - if err != nil { - return fmt.Errorf("transfer failed for asset %s: %v", returnedAssetID, err) - } - } - } - - return nil -} - -// QueryAssetsByOwner queries for assets based on the owners name. -// This is an example of a parameterized query where the query logic is baked into the chaincode, -// and accepting a single query parameter (owner). -// Only available on state databases that support rich query (e.g. CouchDB) -// Example: Parameterized rich query -func (t *SimpleChaincode) QueryAssetsByOwner(ctx contractapi.TransactionContextInterface, owner string) ([]*Asset, error) { - queryString := fmt.Sprintf(`{"selector":{"docType":"asset","owner":"%s"}}`, owner) - return getQueryResultForQueryString(ctx, queryString) -} - -// QueryAssets uses a query string to perform a query for assets. -// Query string matching state database syntax is passed in and executed as is. -// Supports ad hoc queries that can be defined at runtime by the client. -// If this is not desired, follow the QueryAssetsForOwner example for parameterized queries. -// Only available on state databases that support rich query (e.g. CouchDB) -// Example: Ad hoc rich query -func (t *SimpleChaincode) QueryAssets(ctx contractapi.TransactionContextInterface, queryString string) ([]*Asset, error) { - return getQueryResultForQueryString(ctx, queryString) -} - -// getQueryResultForQueryString executes the passed in query string. -// The result set is built and returned as a byte array containing the JSON results. -func getQueryResultForQueryString(ctx contractapi.TransactionContextInterface, queryString string) ([]*Asset, error) { - resultsIterator, err := ctx.GetStub().GetQueryResult(queryString) - if err != nil { - return nil, err - } - defer resultsIterator.Close() - - return constructQueryResponseFromIterator(resultsIterator) -} - -// GetAssetsByRangeWithPagination performs a range query based on the start and end key, -// page size and a bookmark. -// The number of fetched records will be equal to or lesser than the page size. -// Paginated range queries are only valid for read only transactions. -// Example: Pagination with Range Query -func (t *SimpleChaincode) GetAssetsByRangeWithPagination(ctx contractapi.TransactionContextInterface, startKey string, endKey string, pageSize int, bookmark string) (*PaginatedQueryResult, error) { - - resultsIterator, responseMetadata, err := ctx.GetStub().GetStateByRangeWithPagination(startKey, endKey, int32(pageSize), bookmark) - if err != nil { - return nil, err - } - defer resultsIterator.Close() - - assets, err := constructQueryResponseFromIterator(resultsIterator) - if err != nil { - return nil, err - } - - return &PaginatedQueryResult{ - Records: assets, - FetchedRecordsCount: responseMetadata.FetchedRecordsCount, - Bookmark: responseMetadata.Bookmark, - }, nil -} - -// QueryAssetsWithPagination uses a query string, page size and a bookmark to perform a query -// for assets. Query string matching state database syntax is passed in and executed as is. -// The number of fetched records would be equal to or lesser than the specified page size. -// Supports ad hoc queries that can be defined at runtime by the client. -// If this is not desired, follow the QueryAssetsForOwner example for parameterized queries. -// Only available on state databases that support rich query (e.g. CouchDB) -// Paginated queries are only valid for read only transactions. -// Example: Pagination with Ad hoc Rich Query -func (t *SimpleChaincode) QueryAssetsWithPagination(ctx contractapi.TransactionContextInterface, queryString string, pageSize int, bookmark string) (*PaginatedQueryResult, error) { - - return getQueryResultForQueryStringWithPagination(ctx, queryString, int32(pageSize), bookmark) -} - -// getQueryResultForQueryStringWithPagination executes the passed in query string with -// pagination info. The result set is built and returned as a byte array containing the JSON results. -func getQueryResultForQueryStringWithPagination(ctx contractapi.TransactionContextInterface, queryString string, pageSize int32, bookmark string) (*PaginatedQueryResult, error) { - - resultsIterator, responseMetadata, err := ctx.GetStub().GetQueryResultWithPagination(queryString, pageSize, bookmark) - if err != nil { - return nil, err - } - defer resultsIterator.Close() - - assets, err := constructQueryResponseFromIterator(resultsIterator) - if err != nil { - return nil, err - } - - return &PaginatedQueryResult{ - Records: assets, - FetchedRecordsCount: responseMetadata.FetchedRecordsCount, - Bookmark: responseMetadata.Bookmark, - }, nil -} - -// GetAssetHistory returns the chain of custody for an asset since issuance. -func (t *SimpleChaincode) GetAssetHistory(ctx contractapi.TransactionContextInterface, assetID string) ([]HistoryQueryResult, error) { - log.Printf("GetAssetHistory: ID %v", assetID) - - resultsIterator, err := ctx.GetStub().GetHistoryForKey(assetID) - if err != nil { - return nil, err - } - defer resultsIterator.Close() - - var records []HistoryQueryResult - for resultsIterator.HasNext() { - response, err := resultsIterator.Next() - if err != nil { - return nil, err - } - - var asset Asset - if len(response.Value) > 0 { - err = json.Unmarshal(response.Value, &asset) - if err != nil { - return nil, err - } - } else { - asset = Asset{ - ID: assetID, - } - } - - record := HistoryQueryResult{ - TxId: response.TxId, - Timestamp: response.Timestamp.AsTime(), - Record: &asset, - IsDelete: response.IsDelete, - } - records = append(records, record) - } - - return records, nil -} - -// AssetExists returns true when asset with given ID exists in the ledger. -func (t *SimpleChaincode) AssetExists(ctx contractapi.TransactionContextInterface, assetID string) (bool, error) { - assetBytes, err := ctx.GetStub().GetState(assetID) - if err != nil { - return false, fmt.Errorf("failed to read asset %s from world state. %v", assetID, err) - } - - return assetBytes != nil, nil -} - -// InitLedger creates the initial set of assets in the ledger. -func (t *SimpleChaincode) InitLedger(ctx contractapi.TransactionContextInterface) error { - assets := []Asset{ - {DocType: "asset", ID: "asset1", Color: "blue", Size: 5, Owner: "Tomoko", AppraisedValue: 300}, - {DocType: "asset", ID: "asset2", Color: "red", Size: 5, Owner: "Brad", AppraisedValue: 400}, - {DocType: "asset", ID: "asset3", Color: "green", Size: 10, Owner: "Jin Soo", AppraisedValue: 500}, - {DocType: "asset", ID: "asset4", Color: "yellow", Size: 10, Owner: "Max", AppraisedValue: 600}, - {DocType: "asset", ID: "asset5", Color: "black", Size: 15, Owner: "Adriana", AppraisedValue: 700}, - {DocType: "asset", ID: "asset6", Color: "white", Size: 15, Owner: "Michel", AppraisedValue: 800}, - } - - for _, asset := range assets { - err := t.CreateAsset(ctx, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue) - if err != nil { - return err - } - } - - return nil -} - -func main() { - chaincode, err := contractapi.NewChaincode(&SimpleChaincode{}) - if err != nil { - log.Panicf("Error creating asset chaincode: %v", err) - } - - if err := chaincode.Start(); err != nil { - log.Panicf("Error starting asset chaincode: %v", err) - } -} diff --git a/asset-transfer-ledger-queries/chaincode-go/go.mod b/asset-transfer-ledger-queries/chaincode-go/go.mod deleted file mode 100644 index 000abbbd..00000000 --- a/asset-transfer-ledger-queries/chaincode-go/go.mod +++ /dev/null @@ -1,28 +0,0 @@ -module github.com/hyperledger/fabric-samples/asset-transfer-ledger-queries/chaincode-go - -go 1.22.0 - -require ( - github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0 - github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0 -) - -require ( - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xeipuuv/gojsonschema v1.2.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect - google.golang.org/grpc v1.67.0 // indirect - google.golang.org/protobuf v1.36.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/asset-transfer-ledger-queries/chaincode-go/go.sum b/asset-transfer-ledger-queries/chaincode-go/go.sum deleted file mode 100644 index fa4d3b24..00000000 --- a/asset-transfer-ledger-queries/chaincode-go/go.sum +++ /dev/null @@ -1,61 +0,0 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0 h1:IhkHfrl5X/fVnmB6pWeCYCdIJRi9bxj+WTnVN8DtW3c= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0/go.mod h1:PHHaFffjw7p7n9bmCfcm7RqDqYdivNEsJdiNIKZo5Lk= -github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0 h1:rmUoBmciB0GL/miqcbJmJbgp5QTWoJUrZo+CNxrNLF4= -github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0/go.mod h1:FeWeO/jwGjiME7ak3GufqKIcwkejtzrDG4QxbfKydWs= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 h1:YJrd+gMaeY0/vsN0aS0QkEKTivGoUnSRIXxGJ7KI+Pc= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4/go.mod h1:bau/6AJhvEcu9GKKYHlDXAxXKzYNfhP6xu2GXuxEcFk= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= -google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= -google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/asset-transfer-ledger-queries/chaincode-javascript/.eslintignore b/asset-transfer-ledger-queries/chaincode-javascript/.eslintignore deleted file mode 100644 index 15958470..00000000 --- a/asset-transfer-ledger-queries/chaincode-javascript/.eslintignore +++ /dev/null @@ -1,5 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -coverage diff --git a/asset-transfer-ledger-queries/chaincode-javascript/.eslintrc.js b/asset-transfer-ledger-queries/chaincode-javascript/.eslintrc.js deleted file mode 100644 index 072edaf6..00000000 --- a/asset-transfer-ledger-queries/chaincode-javascript/.eslintrc.js +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -module.exports = { - env: { - node: true, - mocha: true - }, - parserOptions: { - ecmaVersion: 8, - sourceType: 'script' - }, - extends: 'eslint:recommended', - rules: { - indent: ['error', 'tab'], - 'linebreak-style': ['error', 'unix'], - quotes: ['error', 'single'], - semi: ['error', 'always'], - 'no-unused-vars': ['error', { args: 'none' }], - 'no-console': 'off', - curly: 'error', - eqeqeq: 'error', - 'no-throw-literal': 'error', - strict: 'error', - 'no-var': 'error', - 'dot-notation': 'error', - 'no-trailing-spaces': 'error', - 'no-use-before-define': 'error', - 'no-useless-call': 'error', - 'no-with': 'error', - 'operator-linebreak': 'error', - yoda: 'error', - 'quote-props': ['error', 'as-needed'] - } -}; diff --git a/asset-transfer-ledger-queries/chaincode-javascript/META-INF/statedb/couchdb/indexes/indexOwner.json b/asset-transfer-ledger-queries/chaincode-javascript/META-INF/statedb/couchdb/indexes/indexOwner.json deleted file mode 100644 index 305f0904..00000000 --- a/asset-transfer-ledger-queries/chaincode-javascript/META-INF/statedb/couchdb/indexes/indexOwner.json +++ /dev/null @@ -1 +0,0 @@ -{"index":{"fields":["docType","owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"} diff --git a/asset-transfer-ledger-queries/chaincode-javascript/index.js b/asset-transfer-ledger-queries/chaincode-javascript/index.js deleted file mode 100644 index 5c7b6e0d..00000000 --- a/asset-transfer-ledger-queries/chaincode-javascript/index.js +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const CC = require('./lib/asset_transfer_ledger_chaincode.js'); - -module.exports.CC = CC; -module.exports.contracts = [ CC ]; diff --git a/asset-transfer-ledger-queries/chaincode-javascript/lib/asset_transfer_ledger_chaincode.js b/asset-transfer-ledger-queries/chaincode-javascript/lib/asset_transfer_ledger_chaincode.js deleted file mode 100644 index fbd92152..00000000 --- a/asset-transfer-ledger-queries/chaincode-javascript/lib/asset_transfer_ledger_chaincode.js +++ /dev/null @@ -1,411 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 -*/ - -// ====CHAINCODE EXECUTION SAMPLES (CLI) ================== - -// ==== Invoke assets ==== -// peer chaincode invoke -C CHANNEL_NAME -n asset_transfer -c '{"Args":["CreateAsset","asset1","blue","35","Tom","100"]}' -// peer chaincode invoke -C CHANNEL_NAME -n asset_transfer -c '{"Args":["CreateAsset","asset2","red","50","Tom","150"]}' -// peer chaincode invoke -C CHANNEL_NAME -n asset_transfer -c '{"Args":["CreateAsset","asset3","blue","70","Tom","200"]}' -// peer chaincode invoke -C CHANNEL_NAME -n asset_transfer -c '{"Args":["TransferAsset","asset2","jerry"]}' -// peer chaincode invoke -C CHANNEL_NAME -n asset_transfer -c '{"Args":["TransferAssetByColor","blue","jerry"]}' -// peer chaincode invoke -C CHANNEL_NAME -n asset_transfer -c '{"Args":["DeleteAsset","asset1"]}' - -// ==== Query assets ==== -// peer chaincode query -C CHANNEL_NAME -n asset_transfer -c '{"Args":["ReadAsset","asset1"]}' -// peer chaincode query -C CHANNEL_NAME -n asset_transfer -c '{"Args":["GetAssetsByRange","asset1","asset3"]}' -// peer chaincode query -C CHANNEL_NAME -n asset_transfer -c '{"Args":["GetAssetHistory","asset1"]}' - -// Rich Query (Only supported if CouchDB is used as state database): -// peer chaincode query -C CHANNEL_NAME -n asset_transfer -c '{"Args":["QueryAssetsByOwner","Tom"]}' output issue -// peer chaincode query -C CHANNEL_NAME -n asset_transfer -c '{"Args":["QueryAssets","{\"selector\":{\"owner\":\"Tom\"}}"]}' - -// Rich Query with Pagination (Only supported if CouchDB is used as state database): -// peer chaincode query -C CHANNEL_NAME -n asset_transfer -c '{"Args":["QueryAssetsWithPagination","{\"selector\":{\"owner\":\"Tom\"}}","3",""]}' - -// INDEXES TO SUPPORT COUCHDB RICH QUERIES -// -// Indexes in CouchDB are required in order to make JSON queries efficient and are required for -// any JSON query with a sort. Indexes may be packaged alongside -// chaincode in a META-INF/statedb/couchdb/indexes directory. Each index must be defined in its own -// text file with extension *.json with the index definition formatted in JSON following the -// CouchDB index JSON syntax as documented at: -// http://docs.couchdb.org/en/2.3.1/api/database/find.html#db-index -// -// This asset transfer ledger example chaincode demonstrates a packaged -// index which you can find in META-INF/statedb/couchdb/indexes/indexOwner.json. -// -// If you have access to the your peer's CouchDB state database in a development environment, -// you may want to iteratively test various indexes in support of your chaincode queries. You -// can use the CouchDB Fauxton interface or a command line curl utility to create and update -// indexes. Then once you finalize an index, include the index definition alongside your -// chaincode in the META-INF/statedb/couchdb/indexes directory, for packaging and deployment -// to managed environments. -// -// In the examples below you can find index definitions that support asset transfer ledger -// chaincode queries, along with the syntax that you can use in development environments -// to create the indexes in the CouchDB Fauxton interface or a curl command line utility. -// - -// Index for docType, owner. -// -// Example curl command line to define index in the CouchDB channel_chaincode database -// curl -i -X POST -H "Content-Type: application/json" -d "{\"index\":{\"fields\":[\"docType\",\"owner\"]},\"name\":\"indexOwner\",\"ddoc\":\"indexOwnerDoc\",\"type\":\"json\"}" http://hostname:port/myc1_assets/_index -// - -// Index for docType, owner, size (descending order). -// -// Example curl command line to define index in the CouchDB channel_chaincode database -// curl -i -X POST -H "Content-Type: application/json" -d "{\"index\":{\"fields\":[{\"size\":\"desc\"},{\"docType\":\"desc\"},{\"owner\":\"desc\"}]},\"ddoc\":\"indexSizeSortDoc\", \"name\":\"indexSizeSortDesc\",\"type\":\"json\"}" http://hostname:port/myc1_assets/_index - -// Rich Query with index design doc and index name specified (Only supported if CouchDB is used as state database): -// peer chaincode query -C CHANNEL_NAME -n ledger -c '{"Args":["QueryAssets","{\"selector\":{\"docType\":\"asset\",\"owner\":\"Tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}"]}' - -// Rich Query with index design doc specified only (Only supported if CouchDB is used as state database): -// peer chaincode query -C CHANNEL_NAME -n ledger -c '{"Args":["QueryAssets","{\"selector\":{\"docType\":{\"$eq\":\"asset\"},\"owner\":{\"$eq\":\"Tom\"},\"size\":{\"$gt\":0}},\"fields\":[\"docType\",\"owner\",\"size\"],\"sort\":[{\"size\":\"desc\"}],\"use_index\":\"_design/indexSizeSortDoc\"}"]}' - -'use strict'; - -const {Contract} = require('fabric-contract-api'); - -class Chaincode extends Contract { - - // CreateAsset - create a new asset, store into chaincode state - async CreateAsset(ctx, assetID, color, size, owner, appraisedValue) { - const exists = await this.AssetExists(ctx, assetID); - if (exists) { - throw new Error(`The asset ${assetID} already exists`); - } - - // ==== Create asset object and marshal to JSON ==== - let asset = { - docType: 'asset', - assetID: assetID, - color: color, - size: size, - owner: owner, - appraisedValue: appraisedValue - }; - - - // === Save asset to state === - await ctx.stub.putState(assetID, Buffer.from(JSON.stringify(asset))); - let indexName = 'color~name'; - let colorNameIndexKey = await ctx.stub.createCompositeKey(indexName, [asset.color, asset.assetID]); - - // Save index entry to state. Only the key name is needed, no need to store a duplicate copy of the marble. - // Note - passing a 'nil' value will effectively delete the key from state, therefore we pass null character as value - await ctx.stub.putState(colorNameIndexKey, Buffer.from('\u0000')); - } - - // ReadAsset returns the asset stored in the world state with given id. - async ReadAsset(ctx, id) { - const assetJSON = await ctx.stub.getState(id); // get the asset from chaincode state - if (!assetJSON || assetJSON.length === 0) { - throw new Error(`Asset ${id} does not exist`); - } - - return assetJSON.toString(); - } - - // delete - remove a asset key/value pair from state - async DeleteAsset(ctx, id) { - if (!id) { - throw new Error('Asset name must not be empty'); - } - - let exists = await this.AssetExists(ctx, id); - if (!exists) { - throw new Error(`Asset ${id} does not exist`); - } - - // to maintain the color~name index, we need to read the asset first and get its color - let valAsbytes = await ctx.stub.getState(id); // get the asset from chaincode state - let jsonResp = {}; - if (!valAsbytes) { - jsonResp.error = `Asset does not exist: ${id}`; - throw new Error(jsonResp); - } - let assetJSON; - try { - assetJSON = JSON.parse(valAsbytes.toString()); - } catch (err) { - jsonResp = {}; - jsonResp.error = `Failed to decode JSON of: ${id}`; - throw new Error(jsonResp); - } - await ctx.stub.deleteState(id); //remove the asset from chaincode state - - // delete the index - let indexName = 'color~name'; - let colorNameIndexKey = ctx.stub.createCompositeKey(indexName, [assetJSON.color, assetJSON.assetID]); - if (!colorNameIndexKey) { - throw new Error(' Failed to create the createCompositeKey'); - } - // Delete index entry to state. - await ctx.stub.deleteState(colorNameIndexKey); - } - - // TransferAsset transfers a asset by setting a new owner name on the asset - async TransferAsset(ctx, assetName, newOwner) { - - let assetAsBytes = await ctx.stub.getState(assetName); - if (!assetAsBytes || !assetAsBytes.toString()) { - throw new Error(`Asset ${assetName} does not exist`); - } - let assetToTransfer = {}; - try { - assetToTransfer = JSON.parse(assetAsBytes.toString()); //unmarshal - } catch (err) { - let jsonResp = {}; - jsonResp.error = 'Failed to decode JSON of: ' + assetName; - throw new Error(jsonResp); - } - assetToTransfer.owner = newOwner; //change the owner - - let assetJSONasBytes = Buffer.from(JSON.stringify(assetToTransfer)); - await ctx.stub.putState(assetName, assetJSONasBytes); //rewrite the asset - } - - // GetAssetsByRange performs a range query based on the start and end keys provided. - // Read-only function results are not typically submitted to ordering. If the read-only - // results are submitted to ordering, or if the query is used in an update transaction - // and submitted to ordering, then the committing peers will re-execute to guarantee that - // result sets are stable between endorsement time and commit time. The transaction is - // invalidated by the committing peers if the result set has changed between endorsement - // time and commit time. - // Therefore, range queries are a safe option for performing update transactions based on query results. - async GetAssetsByRange(ctx, startKey, endKey) { - - let resultsIterator = await ctx.stub.getStateByRange(startKey, endKey); - let results = await this._GetAllResults(resultsIterator, false); - - return JSON.stringify(results); - } - - // TransferAssetByColor will transfer assets of a given color to a certain new owner. - // Uses a GetStateByPartialCompositeKey (range query) against color~name 'index'. - // Committing peers will re-execute range queries to guarantee that result sets are stable - // between endorsement time and commit time. The transaction is invalidated by the - // committing peers if the result set has changed between endorsement time and commit time. - // Therefore, range queries are a safe option for performing update transactions based on query results. - // Example: GetStateByPartialCompositeKey/RangeQuery - async TransferAssetByColor(ctx, color, newOwner) { - // Query the color~name index by color - // This will execute a key range query on all keys starting with 'color' - let coloredAssetResultsIterator = await ctx.stub.getStateByPartialCompositeKey('color~name', [color]); - - // Iterate through result set and for each asset found, transfer to newOwner - let responseRange = await coloredAssetResultsIterator.next(); - while (!responseRange.done) { - if (!responseRange || !responseRange.value || !responseRange.value.key) { - return; - } - - let objectType; - let attributes; - ( - {objectType, attributes} = await ctx.stub.splitCompositeKey(responseRange.value.key) - ); - - console.log(objectType); - let returnedAssetName = attributes[1]; - - // Now call the transfer function for the found asset. - // Re-use the same function that is used to transfer individual assets - await this.TransferAsset(ctx, returnedAssetName, newOwner); - responseRange = await coloredAssetResultsIterator.next(); - } - } - - // QueryAssetsByOwner queries for assets based on a passed in owner. - // This is an example of a parameterized query where the query logic is baked into the chaincode, - // and accepting a single query parameter (owner). - // Only available on state databases that support rich query (e.g. CouchDB) - // Example: Parameterized rich query - async QueryAssetsByOwner(ctx, owner) { - let queryString = {}; - queryString.selector = {}; - queryString.selector.docType = 'asset'; - queryString.selector.owner = owner; - return await this.GetQueryResultForQueryString(ctx, JSON.stringify(queryString)); //shim.success(queryResults); - } - - // Example: Ad hoc rich query - // QueryAssets uses a query string to perform a query for assets. - // Query string matching state database syntax is passed in and executed as is. - // Supports ad hoc queries that can be defined at runtime by the client. - // If this is not desired, follow the QueryAssetsForOwner example for parameterized queries. - // Only available on state databases that support rich query (e.g. CouchDB) - async QueryAssets(ctx, queryString) { - return await this.GetQueryResultForQueryString(ctx, queryString); - } - - // GetQueryResultForQueryString executes the passed in query string. - // Result set is built and returned as a byte array containing the JSON results. - async GetQueryResultForQueryString(ctx, queryString) { - - let resultsIterator = await ctx.stub.getQueryResult(queryString); - let results = await this._GetAllResults(resultsIterator, false); - - return JSON.stringify(results); - } - - // Example: Pagination with Range Query - // GetAssetsByRangeWithPagination performs a range query based on the start & end key, - // page size and a bookmark. - // The number of fetched records will be equal to or lesser than the page size. - // Paginated range queries are only valid for read only transactions. - async GetAssetsByRangeWithPagination(ctx, startKey, endKey, pageSize, bookmark) { - - const {iterator, metadata} = await ctx.stub.getStateByRangeWithPagination(startKey, endKey, pageSize, bookmark); - let results = {}; - - results.results = await this._GetAllResults(iterator, false); - - results.fetchedRecordsCount = metadata.fetchedRecordsCount; - - results.bookmark = metadata.bookmark; - - return JSON.stringify(results); - } - - // Example: Pagination with Ad hoc Rich Query - // QueryAssetsWithPagination uses a query string, page size and a bookmark to perform a query - // for assets. Query string matching state database syntax is passed in and executed as is. - // The number of fetched records would be equal to or lesser than the specified page size. - // Supports ad hoc queries that can be defined at runtime by the client. - // If this is not desired, follow the QueryAssetsForOwner example for parameterized queries. - // Only available on state databases that support rich query (e.g. CouchDB) - // Paginated queries are only valid for read only transactions. - async QueryAssetsWithPagination(ctx, queryString, pageSize, bookmark) { - - const {iterator, metadata} = await ctx.stub.getQueryResultWithPagination(queryString, pageSize, bookmark); - let results = {}; - - results.results = await this._GetAllResults(iterator, false); - - results.fetchedRecordsCount = metadata.fetchedRecordsCount; - - results.bookmark = metadata.bookmark; - - return JSON.stringify(results); - } - - // GetAssetHistory returns the chain of custody for an asset since issuance. - async GetAssetHistory(ctx, assetName) { - - let resultsIterator = await ctx.stub.getHistoryForKey(assetName); - let results = await this._GetAllResults(resultsIterator, true); - - return JSON.stringify(results); - } - - // AssetExists returns true when asset with given ID exists in world state - async AssetExists(ctx, assetName) { - // ==== Check if asset already exists ==== - let assetState = await ctx.stub.getState(assetName); - return assetState && assetState.length > 0; - } - - // This is JavaScript so without Funcation Decorators, all functions are assumed - // to be transaction functions - // - // For internal functions... prefix them with _ - async _GetAllResults(iterator, isHistory) { - let allResults = []; - let res = await iterator.next(); - while (!res.done) { - if (res.value && res.value.value.toString()) { - let jsonRes = {}; - console.log(res.value.value.toString('utf8')); - if (isHistory && isHistory === true) { - jsonRes.TxId = res.value.txId; - jsonRes.Timestamp = res.value.timestamp; - try { - jsonRes.Value = JSON.parse(res.value.value.toString('utf8')); - } catch (err) { - console.log(err); - jsonRes.Value = res.value.value.toString('utf8'); - } - } else { - jsonRes.Key = res.value.key; - try { - jsonRes.Record = JSON.parse(res.value.value.toString('utf8')); - } catch (err) { - console.log(err); - jsonRes.Record = res.value.value.toString('utf8'); - } - } - allResults.push(jsonRes); - } - res = await iterator.next(); - } - iterator.close(); - return allResults; - } - - // InitLedger creates sample assets in the ledger - async InitLedger(ctx) { - const assets = [ - { - assetID: 'asset1', - color: 'blue', - size: 5, - owner: 'Tom', - appraisedValue: 100 - }, - { - assetID: 'asset2', - color: 'red', - size: 5, - owner: 'Brad', - appraisedValue: 100 - }, - { - assetID: 'asset3', - color: 'green', - size: 10, - owner: 'Jin Soo', - appraisedValue: 200 - }, - { - assetID: 'asset4', - color: 'yellow', - size: 10, - owner: 'Max', - appraisedValue: 200 - }, - { - assetID: 'asset5', - color: 'black', - size: 15, - owner: 'Adriana', - appraisedValue: 250 - }, - { - assetID: 'asset6', - color: 'white', - size: 15, - owner: 'Michel', - appraisedValue: 250 - }, - ]; - - for (const asset of assets) { - await this.CreateAsset( - ctx, - asset.assetID, - asset.color, - asset.size, - asset.owner, - asset.appraisedValue - ); - } - } -} - -module.exports = Chaincode; diff --git a/asset-transfer-ledger-queries/chaincode-javascript/npm-shrinkwrap.json b/asset-transfer-ledger-queries/chaincode-javascript/npm-shrinkwrap.json deleted file mode 100644 index 46c74951..00000000 --- a/asset-transfer-ledger-queries/chaincode-javascript/npm-shrinkwrap.json +++ /dev/null @@ -1,1733 +0,0 @@ -{ - "name": "asset-transfer-ledger-queries", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "asset-transfer-ledger-queries", - "version": "1.0.0", - "license": "Apache-2.0", - "dependencies": { - "fabric-contract-api": "~2.5", - "fabric-shim": "~2.5" - }, - "devDependencies": { - "eslint": "^8.57.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@colors/colors": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", - "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@dabh/diagnostics": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", - "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", - "dependencies": { - "colorspace": "1.1.x", - "enabled": "2.0.x", - "kuler": "^2.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", - "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@fidm/asn1": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@fidm/asn1/-/asn1-1.0.4.tgz", - "integrity": "sha512-esd1jyNvRb2HVaQGq2Gg8Z0kbQPXzV9Tq5Z14KNIov6KfFD6PTaRIO8UpcsYiTNzOqJpmyzWgVTrUwFV3UF4TQ==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@fidm/x509": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@fidm/x509/-/x509-1.2.1.tgz", - "integrity": "sha512-nwc2iesjyc9hkuzcrMCBXQRn653XuAUKorfWM8PZyJawiy1QzLj4vahwzaI25+pfpwOLvMzbJ0uKpWLDNmo16w==", - "dependencies": { - "@fidm/asn1": "^1.0.4", - "tweetnacl": "^1.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@grpc/grpc-js": { - "version": "1.10.9", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.10.9.tgz", - "integrity": "sha512-5tcgUctCG0qoNyfChZifz2tJqbRbXVO9J7X6duFcOjY3HUNCxg5D0ZCK7EP9vIcZ0zRpLU9bWkyCqVCLZ46IbQ==", - "dependencies": { - "@grpc/proto-loader": "^0.7.13", - "@js-sdsl/ordered-map": "^4.4.2" - }, - "engines": { - "node": ">=12.10.0" - } - }, - "node_modules/@grpc/proto-loader": { - "version": "0.7.13", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", - "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", - "dependencies": { - "lodash.camelcase": "^4.3.0", - "long": "^5.0.0", - "protobufjs": "^7.2.5", - "yargs": "^17.7.2" - }, - "bin": { - "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true - }, - "node_modules/@hyperledger/fabric-protos": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@hyperledger/fabric-protos/-/fabric-protos-0.2.1.tgz", - "integrity": "sha512-qjm0vIQIfCall804tWDeA8p/mUfu14sl5Sj+PbOn2yDKJq+7ThoIhNsLAqf+BCxUfqsoqQq6AojhqQeTFyOOqg==", - "dependencies": { - "@grpc/grpc-js": "^1.9.0", - "google-protobuf": "^3.21.0" - }, - "engines": { - "node": ">=14.15.0" - } - }, - "node_modules/@js-sdsl/ordered-map": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", - "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" - }, - "node_modules/@types/node": { - "version": "16.18.98", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.98.tgz", - "integrity": "sha512-fpiC20NvLpTLAzo3oVBKIqBGR6Fx/8oAK/SSf7G+fydnXMY1x4x9RZ6sBXhqKlCU21g2QapUsbLlhv3+a7wS+Q==" - }, - "node_modules/@types/triple-beam": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", - "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/class-transformer": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.4.0.tgz", - "integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==" - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/color": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", - "dependencies": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/color/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/colorspace": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", - "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", - "dependencies": { - "color": "^3.1.3", - "text-hex": "1.0.x" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/enabled": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", - "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" - }, - "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fabric-contract-api": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/fabric-contract-api/-/fabric-contract-api-2.5.6.tgz", - "integrity": "sha512-AosGb8tA+Jgt+pqMEgYNB3/J/P5QuWOC7yhXbhDmAAwUzn4Sc7pdWDICH1YyrFGZNFxMGQmqJmLVWUX8BKHy0w==", - "dependencies": { - "class-transformer": "^0.4.0", - "fabric-shim-api": "2.5.6", - "fast-safe-stringify": "^2.1.1", - "get-params": "^0.1.2", - "reflect-metadata": "^0.1.13", - "winston": "^3.7.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/fabric-shim": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/fabric-shim/-/fabric-shim-2.5.6.tgz", - "integrity": "sha512-4Y8WNFhYuQ9QYSEgPXWdlXnrXjwOlM10sQQzE4kJ7cDh8a4LX0rn44FxtxTCB18lnzrSLMZ8/8Cr5m0c9NeXWA==", - "dependencies": { - "@fidm/x509": "^1.2.1", - "@grpc/grpc-js": "~1.10.9", - "@hyperledger/fabric-protos": "~0.2.1", - "@types/node": "^16.11.1", - "ajv": "^6.12.2", - "fabric-contract-api": "2.5.6", - "fabric-shim-api": "2.5.6", - "fast-safe-stringify": "^2.1.1", - "long": "^5.2.3", - "reflect-metadata": "^0.1.13", - "winston": "^3.7.2", - "yargs": "^17.4.0", - "yargs-parser": "^21.0.1" - }, - "bin": { - "fabric-chaincode-node": "cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/fabric-shim-api": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/fabric-shim-api/-/fabric-shim-api-2.5.6.tgz", - "integrity": "sha512-1L0nO7CJ31/gEOWKWHEeCqgB5HkqPVfRbpcS7L9eTscT7tffjg2OkZISvC+a7RiqihL0iyrXNBgBg5MwlSSN9g==", - "engines": { - "eslint": "^6.6.0", - "node": ">=18" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fecha": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "node_modules/fn.name": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", - "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-params": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/get-params/-/get-params-0.1.2.tgz", - "integrity": "sha512-41eOxtlGgHQRbFyA8KTH+w+32Em3cRdfBud7j67ulzmIfmaHX9doq47s0fa4P5o9H64BZX9nrYI6sJvk46Op+Q==" - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/google-protobuf": { - "version": "3.21.2", - "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz", - "integrity": "sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==" - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kuler": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/logform": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", - "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", - "dependencies": { - "@colors/colors": "1.6.0", - "@types/triple-beam": "^1.3.2", - "fecha": "^4.2.0", - "ms": "^2.1.1", - "safe-stable-stringify": "^2.3.1", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/long": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/one-time": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", - "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", - "dependencies": { - "fn.name": "1.x.x" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/protobufjs": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.2.tgz", - "integrity": "sha512-RXyHaACeqXeqAKGLDl68rQKbmObRsTIn4TYVUUug1KfS47YWCo5MacGITEryugIgZqORCvJWEk4l449POg5Txg==", - "hasInstallScript": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/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, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/reflect-metadata": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", - "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==" - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safe-stable-stringify": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", - "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", - "engines": { - "node": "*" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-hex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/triple-beam": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", - "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/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, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/winston": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.13.0.tgz", - "integrity": "sha512-rwidmA1w3SE4j0E5MuIufFhyJPBDG7Nu71RkZor1p2+qHvJSZ9GYDA81AyleQcZbh/+V6HjeBdfnTZJm9rSeQQ==", - "dependencies": { - "@colors/colors": "^1.6.0", - "@dabh/diagnostics": "^2.0.2", - "async": "^3.2.3", - "is-stream": "^2.0.0", - "logform": "^2.4.0", - "one-time": "^1.0.0", - "readable-stream": "^3.4.0", - "safe-stable-stringify": "^2.3.1", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.7.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/winston-transport": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz", - "integrity": "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==", - "dependencies": { - "logform": "^2.3.2", - "readable-stream": "^3.6.0", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "engines": { - "node": ">=12" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/asset-transfer-ledger-queries/chaincode-javascript/package.json b/asset-transfer-ledger-queries/chaincode-javascript/package.json deleted file mode 100644 index 384069fa..00000000 --- a/asset-transfer-ledger-queries/chaincode-javascript/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "asset-transfer-ledger-queries", - "version": "1.0.0", - "description": "asset chaincode implemented in node.js", - "main": "index.js", - "engines": { - "node": ">=18" - }, - "scripts": { - "start": "fabric-chaincode-node start", - "lint": "eslint *.js */**.js", - "test": "" - }, - "engine-strict": true, - "license": "Apache-2.0", - "dependencies": { - "fabric-contract-api": "~2.5", - "fabric-shim": "~2.5" - }, - "devDependencies": { - "eslint": "^8.57.0" - } -} diff --git a/asset-transfer-private-data/README.md b/asset-transfer-private-data/README.md deleted file mode 100644 index 0df860a8..00000000 --- a/asset-transfer-private-data/README.md +++ /dev/null @@ -1,79 +0,0 @@ -# Asset transfer private data sample - -The asset transfer private data sample demonstrates: - -- Usage of organization private data collections -- Read data from the organization private data collection. -- Store data in organization private data collection. - -For more information about private data, visit the -[Private Data](https://hyperledger-fabric.readthedocs.io/en/latest/private-data-arch.html) -page in the Fabric documentation. - -## About the sample - -This sample includes smart contract and application code in multiple languages. In a use-case similar to basic asset transfer (see [asset-transfer-basic](../asset-transfer-basic) folder) this sample shows sending and receiving of asset along with its private data owned by organizations during create / delete of an asset , and during transfer of an asset to a new owner. - -### Application - -Please refer the below link to understand the application flow. -https://hyperledger-fabric.readthedocs.io/en/latest/private-data/private-data.html#example-scenario-asset-transfer-using-private-data-collections - -### Smart Contract - -The smart contract (in folder `chaincode-xyz`) implements the following functions to support the application: - -CreateAsset -AgreeToTransfer -TransferAsset -DeleteAsset -DeleteTranferAgreement - -ReadAsset -ReadAssetPrivateDetails -ReadTransferAgreement -GetAssetByRange -QueryAssetByOwner -QueryAssets -getQueryResultForQueryString - -## Running the sample - -Like other samples, the Fabric test network is used to deploy and run this sample. Follow these steps in order: - -1. Create the test network and a channel (from the `test-network` folder). - ``` - ./network.sh up createChannel -c mychannel -ca - ``` - -2. Deploy one of the smart contract implementations (from the `test-network` folder). - ``` - # To deploy the Java chaincode implementation - ./network.sh deployCC -ccn private -ccp ../asset-transfer-private-data/chaincode-java -ccl java -ccep "OR('Org1MSP.peer','Org2MSP.peer')" -cccg '../asset-transfer-private-data/chaincode-java/collections_config.json' -ccep "OR('Org1MSP.peer','Org2MSP.peer')" - - # To deploy the go chaincode implementation - ./network.sh deployCC -ccn private -ccp ../asset-transfer-private-data/chaincode-go -ccl go -ccep "OR('Org1MSP.peer','Org2MSP.peer')" -cccg '../asset-transfer-private-data/chaincode-go/collections_config.json' -ccep "OR('Org1MSP.peer','Org2MSP.peer')" - - # To deploy the typescript chaincode implementation - ./network.sh deployCC -ccn private -ccp ../asset-transfer-private-data/chaincode-typescript/ -ccl typescript -ccep "OR('Org1MSP.peer','Org2MSP.peer')" -cccg ../asset-transfer-private-data/chaincode-typescript/collections_config.json - ``` - -3. Run the application (from the `asset-transfer-private-data` folder). - ``` - # To run the Typescript sample application - cd application-gateway-typescript - npm install - npm start - - # To run the Go sample application - cd application-gateway-go - go run . - ``` - -## Clean up - -When you are finished, you can bring down the test network (from the `test-network` folder). The command will remove all the nodes of the test network, and delete any ledger data that you created. - -``` -./network.sh down -``` diff --git a/asset-transfer-private-data/application-gateway-go/app.go b/asset-transfer-private-data/application-gateway-go/app.go deleted file mode 100644 index 5274e3ab..00000000 --- a/asset-transfer-private-data/application-gateway-go/app.go +++ /dev/null @@ -1,398 +0,0 @@ -/* -Copyright 2024 IBM All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "strings" - "time" - - "github.com/hyperledger/fabric-gateway/pkg/client" - "github.com/hyperledger/fabric-gateway/pkg/hash" - "github.com/hyperledger/fabric-protos-go-apiv2/gateway" - "google.golang.org/grpc/status" -) - -type transient = map[string][]byte - -const ( - channelName = "mychannel" - chaincodeName = "private" - mspIDOrg1 = "Org1MSP" - mspIDOrg2 = "Org2MSP" - - // Collection names. - org1PrivateCollectionName = "Org1MSPPrivateCollection" - org2PrivateCollectionName = "Org2MSPPrivateCollection" - - Red = "\033[31m" - Reset = "\033[0m" -) - -// Use a unique key so that we can run multiple times. -var now = time.Now() -var assetID1 = fmt.Sprintf("asset%d", now.Unix()) -var assetID2 = fmt.Sprintf("asset%d", now.Unix()+1) - -func main() { - clientOrg1 := newGrpcConnection( - tlsCertPathOrg1, - peerEndpointOrg1, - peerNameOrg1, - ) - defer clientOrg1.Close() - - gatewayOrg1, err := client.Connect( - newIdentity(certDirectoryPathOrg1, mspIDOrg1), - client.WithSign(newSign(keyDirectoryPathOrg1)), - client.WithClientConnection(clientOrg1), - client.WithHash(hash.SHA256), - ) - if err != nil { - panic(err) - } - defer gatewayOrg1.Close() - - clientOrg2 := newGrpcConnection( - tlsCertPathOrg2, - peerEndpointOrg2, - peerNameOrg2, - ) - defer clientOrg2.Close() - - gatewayOrg2, err := client.Connect( - newIdentity(certDirectoryPathOrg2, mspIDOrg2), - client.WithSign(newSign(keyDirectoryPathOrg2)), - client.WithClientConnection(clientOrg2), - client.WithHash(hash.SHA256), - ) - if err != nil { - panic(err) - } - defer gatewayOrg2.Close() - - // Get the smart contract as an Org1 client. - contractOrg1 := gatewayOrg1.GetNetwork(channelName).GetContract(chaincodeName) - - // Get the smart contract as an Org1 client. - contractOrg2 := gatewayOrg2.GetNetwork(channelName).GetContract(chaincodeName) - - fmt.Println("~~~~~~~~~~~~~~~~ As Org1 Client ~~~~~~~~~~~~~~~~") - - // Create new assets on the ledger. - createAssets(contractOrg1) - - // Read asset from the Org1's private data collection with ID in the given range. - getAssetByRange(contractOrg1) - - // Attempt to transfer asset without prior approval from Org2, transaction expected to fail. - fmt.Println("\nAttempt TransferAsset without prior AgreeToTransfer") - err = transferAsset(contractOrg1, assetID1) - if err == nil { - doFail("TransferAsset transaction succeeded when it was expected to fail") - } - fmt.Printf("*** Received expected error: %+v\n", errorWithDetails(err)) - - fmt.Println("\n~~~~~~~~~~~~~~~~ As Org2 Client ~~~~~~~~~~~~~~~~") - - // Read the asset by ID. - readAssetByID(contractOrg2, assetID1) - - // Make agreement to transfer the asset from Org1 to Org2. - agreeToTransfer(contractOrg2, assetID1) - - fmt.Println("\n~~~~~~~~~~~~~~~~ As Org1 Client ~~~~~~~~~~~~~~~~") - - // Read transfer agreement. - readTransferAgreement(contractOrg1, assetID1) - - // Transfer asset to Org2. - if err := transferAsset(contractOrg1, assetID1); err != nil { - doFail(fmt.Sprintf("TransferAsset transaction failed when it was expected to succeed: %+v\n", errorWithDetails(err))) - } - - // Again ReadAsset: results will show that the buyer identity now owns the asset. - readAssetByID(contractOrg1, assetID1) - - // Confirm that transfer removed the private details from the Org1 collection. - org1ReadSuccess := readAssetPrivateDetails(contractOrg1, assetID1, org1PrivateCollectionName) - if org1ReadSuccess { - doFail(fmt.Sprintf("Asset private data still exists in %s", org1PrivateCollectionName)) - } - - fmt.Println("\n~~~~~~~~~~~~~~~~ As Org2 Client ~~~~~~~~~~~~~~~~") - - // Org2 can read asset private details: Org2 is owner, and private details exist in new owner's Collection. - org2ReadSuccess := readAssetPrivateDetails(contractOrg2, assetID1, org2PrivateCollectionName) - if !org2ReadSuccess { - doFail(fmt.Sprintf("Asset private data not found in %s", org2PrivateCollectionName)) - } - - fmt.Println("\nAttempt DeleteAsset using non-owner organization") - err = deleteAsset(contractOrg2, assetID2) - if err == nil { - doFail("DeleteAsset transaction succeeded when it was expected to fail") - } - fmt.Printf("*** Received expected error: %+v\n", errorWithDetails(err)) - - fmt.Println("\n~~~~~~~~~~~~~~~~ As Org1 Client ~~~~~~~~~~~~~~~~") - - // Delete AssetID2 as Org1. - if err := deleteAsset(contractOrg1, assetID2); err != nil { - doFail(fmt.Sprintf("DeleteAsset transaction failed when it was expected to succeed: %+v\n", errorWithDetails(err))) - } - - // Trigger a purge of the private data for the asset. - // The previous delete is optional if purge is used. - if err := purgeAsset(contractOrg1, assetID2); err != nil { - doFail(fmt.Sprintf("PurgeAsset transaction failed when it was expected to succeed: %+v\n", errorWithDetails(err))) - } -} - -func createAssets(contract *client.Contract) { - assetType := "ValuableAsset" - - fmt.Printf("\n--> Submit Transaction: CreateAsset, ID: %s\n", assetID1) - - type assetTransientInput struct { - ObjectType string - AssetID string - Color string - Size uint8 - AppraisedValue uint16 - } - - asset1Data := assetTransientInput{ - ObjectType: assetType, - AssetID: assetID1, - Color: "green", - Size: 20, - AppraisedValue: 100, - } - - if _, err := contract.Submit( - "CreateAsset", - client.WithTransient(transient{ - "asset_properties": marshal(asset1Data), - }), - ); err != nil { - panic(err) - } - - logTxCommitSuccess() - fmt.Printf("\n--> Submit Transaction: CreateAsset, ID: %s\n", assetID2) - - asset2Data := assetTransientInput{ - ObjectType: assetType, - AssetID: assetID2, - Color: "blue", - Size: 35, - AppraisedValue: 727, - } - - if _, err := contract.Submit( - "CreateAsset", - client.WithTransient(transient{ - "asset_properties": marshal(asset2Data), - }), - ); err != nil { - panic(err) - } - - logTxCommitSuccess() -} - -func getAssetByRange(contract *client.Contract) { - // GetAssetByRange returns assets on the ledger with ID in the range of startKey (inclusive) and endKey (exclusive). - fmt.Printf("\n--> Evaluate Transaction: GetAssetByRange from %s\n", org1PrivateCollectionName) - - resultBytes, err := contract.EvaluateTransaction("GetAssetByRange", assetID1, fmt.Sprintf("asset%d", now.Unix()+2)) - if err != nil { - panic(err) - } - - if len(resultBytes) == 0 { - doFail("Received empty query list for GetAssetByRange") - } - - fmt.Printf("*** Result: %s\n", formatJSON(resultBytes)) -} - -func readAssetByID(contract *client.Contract, assetID string) { - fmt.Printf("\n--> Evaluate Transaction: ReadAsset, ID: %s\n", assetID) - - resultBytes, err := contract.EvaluateTransaction("ReadAsset", assetID) - if err != nil { - panic(err) - } - - if len(resultBytes) == 0 { - doFail("Received empty result for ReadAsset") - } - - fmt.Printf("*** Result: %s\n", formatJSON(resultBytes)) -} - -func agreeToTransfer(contract *client.Contract, assetID string) { - // Buyer from Org2 agrees to buy the asset. - // To purchase the asset, the buyer needs to agree to the same value as the asset owner. - dataForAgreement := struct { - AssetID string `json:"assetID"` - AppraisedValue int `json:"appraisedValue"` - }{assetID, 100} - fmt.Printf("\n--> Submit Transaction: AgreeToTransfer, payload: %+v\n", dataForAgreement) - - if _, err := contract.Submit( - "AgreeToTransfer", - client.WithTransient(transient{ - "asset_value": marshal(dataForAgreement), - }), - ); err != nil { - panic(err) - } - - logTxCommitSuccess() -} - -func readTransferAgreement(contract *client.Contract, assetID string) { - fmt.Printf("\n--> Evaluate Transaction: ReadTransferAgreement, ID: %s\n", assetID) - - resultBytes, err := contract.EvaluateTransaction("ReadTransferAgreement", assetID) - if err != nil { - panic(err) - } - - if len(resultBytes) == 0 { - doFail("Received empty result for ReadTransferAgreement") - } - - fmt.Printf("*** Result: %s\n", formatJSON(resultBytes)) -} - -func transferAsset(contract *client.Contract, assetID string) (err error) { - fmt.Printf("\n--> Submit Transaction: TransferAsset, ID: %s\n", assetID) - - buyerDetails := struct { - AssetID string `json:"assetID"` - BuyerMSP string `json:"buyerMSP"` - }{assetID, mspIDOrg2} - - if _, err = contract.Submit( - "TransferAsset", - client.WithTransient(transient{ - "asset_owner": marshal(buyerDetails), - }), - ); err != nil { - return - } - - logTxCommitSuccess() - return -} - -func deleteAsset(contract *client.Contract, assetID string) (err error) { - fmt.Printf("\n--> Submit Transaction: DeleteAsset, ID: %s\n", assetID) - - dataForDelete := struct{ AssetID string }{assetID} - - if _, err = contract.Submit( - "DeleteAsset", - client.WithTransient(transient{ - "asset_delete": marshal(dataForDelete), - }), - ); err != nil { - return - } - - logTxCommitSuccess() - return -} - -func purgeAsset(contract *client.Contract, assetID string) (err error) { - fmt.Printf("\n--> Submit Transaction: PurgeAsset, ID: %s\n", assetID) - - dataForPurge := struct{ AssetID string }{assetID} - - if _, err = contract.Submit( - "PurgeAsset", - client.WithTransient(transient{ - "asset_purge": marshal(dataForPurge), - }), - ); err != nil { - return - } - - logTxCommitSuccess() - return -} - -func readAssetPrivateDetails(contract *client.Contract, assetID, collectionName string) bool { - fmt.Printf("\n--> Evaluate Transaction: ReadAssetPrivateDetails from %s, ID: %s\n", collectionName, assetID) - - resultBytes, err := contract.EvaluateTransaction("ReadAssetPrivateDetails", collectionName, assetID) - if err != nil { - panic(err) - } - - if len(resultBytes) == 0 { - fmt.Println("*** No result") - return false - } - - fmt.Printf("*** Result: %s\n", formatJSON(resultBytes)) - - return true -} - -func marshal(value any) []byte { - valueAsBytes, err := json.Marshal(&value) - if err != nil { - panic(err) - } - - return valueAsBytes -} - -func logTxCommitSuccess() { - fmt.Println("*** Transaction committed successfully") -} - -func doFail(msg string) { - fmt.Println(Red + msg + Reset) - panic(errors.New(msg)) -} - -func formatJSON(data []byte) string { - var result bytes.Buffer - if err := json.Indent(&result, data, "", " "); err != nil { - panic(fmt.Errorf("failed to parse JSON: %w", err)) - } - return result.String() -} - -func errorWithDetails(err error) error { - var buf strings.Builder - - statusErr := status.Convert(err) - errDetails := statusErr.Details() - if len(errDetails) > 0 { - buf.WriteString("\nError Details:") - - for _, errDetail := range errDetails { - if detail, ok := errDetail.(*gateway.ErrorDetail); ok { - buf.WriteString(fmt.Sprintf("\n- address: %s", detail.GetAddress())) - buf.WriteString(fmt.Sprintf("\n- mspID: %s", detail.GetMspId())) - buf.WriteString(fmt.Sprintf("\n- message: %s\n", detail.GetMessage())) - } - } - } - - return fmt.Errorf("%w%s", err, buf.String()) -} diff --git a/asset-transfer-private-data/application-gateway-go/connect.go b/asset-transfer-private-data/application-gateway-go/connect.go deleted file mode 100644 index 3bd76863..00000000 --- a/asset-transfer-private-data/application-gateway-go/connect.go +++ /dev/null @@ -1,111 +0,0 @@ -/* -Copyright 2022 IBM All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "crypto/x509" - "fmt" - "os" - "path" - - "github.com/hyperledger/fabric-gateway/pkg/identity" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" -) - -const ( - cryptoPathOrg1 = "../../test-network/organizations/peerOrganizations/org1.example.com" - keyDirectoryPathOrg1 = cryptoPathOrg1 + "/users/User1@org1.example.com/msp/keystore" - certDirectoryPathOrg1 = cryptoPathOrg1 + "/users/User1@org1.example.com/msp/signcerts" - tlsCertPathOrg1 = cryptoPathOrg1 + "/peers/peer0.org1.example.com/tls/ca.crt" - peerEndpointOrg1 = "dns:///localhost:7051" - peerNameOrg1 = "peer0.org1.example.com" - cryptoPathOrg2 = "../../test-network/organizations/peerOrganizations/org2.example.com" - keyDirectoryPathOrg2 = cryptoPathOrg2 + "/users/User1@org2.example.com/msp/keystore" - certDirectoryPathOrg2 = cryptoPathOrg2 + "/users/User1@org2.example.com/msp/signcerts" - tlsCertPathOrg2 = cryptoPathOrg2 + "/peers/peer0.org2.example.com/tls/ca.crt" - peerEndpointOrg2 = "dns:///localhost:9051" - peerNameOrg2 = "peer0.org2.example.com" -) - -// newGrpcConnection creates a gRPC connection to the Gateway server. -func newGrpcConnection(tlsCertPath, peerEndpoint, peerName string) *grpc.ClientConn { - certificatePEM, err := os.ReadFile(tlsCertPath) - if err != nil { - panic(fmt.Errorf("failed to read TLS certificate file: %w", err)) - } - - certificate, err := identity.CertificateFromPEM(certificatePEM) - if err != nil { - panic(err) - } - - certPool := x509.NewCertPool() - certPool.AddCert(certificate) - transportCredentials := credentials.NewClientTLSFromCert(certPool, peerName) - - connection, err := grpc.NewClient(peerEndpoint, grpc.WithTransportCredentials(transportCredentials)) - if err != nil { - panic(fmt.Errorf("failed to create gRPC connection: %w", err)) - } - - return connection -} - -// newIdentity creates a client identity for this Gateway connection using an X.509 certificate. -func newIdentity(certDirectoryPath, mspId string) *identity.X509Identity { - certificatePEM, err := readFirstFile(certDirectoryPath) - if err != nil { - panic(fmt.Errorf("failed to read certificate file: %w", err)) - } - - certificate, err := identity.CertificateFromPEM(certificatePEM) - if err != nil { - panic(err) - } - - id, err := identity.NewX509Identity(mspId, certificate) - if err != nil { - panic(err) - } - - return id -} - -// newSign creates a function that generates a digital signature from a message digest using a private key. -func newSign(keyDirectoryPash string) identity.Sign { - privateKeyPEM, err := readFirstFile(keyDirectoryPash) - if err != nil { - panic(fmt.Errorf("failed to read private key file: %w", err)) - } - - privateKey, err := identity.PrivateKeyFromPEM(privateKeyPEM) - if err != nil { - panic(err) - } - - sign, err := identity.NewPrivateKeySign(privateKey) - if err != nil { - panic(err) - } - - return sign -} - -func readFirstFile(dirPath string) ([]byte, error) { - dir, err := os.Open(dirPath) - if err != nil { - return nil, err - } - - fileNames, err := dir.Readdirnames(1) - if err != nil { - return nil, err - } - - return os.ReadFile(path.Join(dirPath, fileNames[0])) -} diff --git a/asset-transfer-private-data/application-gateway-go/go.mod b/asset-transfer-private-data/application-gateway-go/go.mod deleted file mode 100644 index 83a97113..00000000 --- a/asset-transfer-private-data/application-gateway-go/go.mod +++ /dev/null @@ -1,23 +0,0 @@ -module assetTransfer - -go 1.22.0 - -require ( - github.com/hyperledger/fabric-gateway v1.6.0 - google.golang.org/grpc v1.67.0 -) - -require ( - github.com/golang/protobuf v1.5.3 // indirect - github.com/hyperledger/fabric-protos-go v0.0.0-20200707132912-fee30f3ccd23 // indirect - github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3 // indirect - github.com/hyperledger/fabric-sdk-go v1.0.0 // indirect - github.com/miekg/pkcs11 v1.1.1 // indirect - github.com/pkg/errors v0.8.1 // indirect - golang.org/x/crypto v0.27.0 // indirect - golang.org/x/net v0.29.0 // indirect - golang.org/x/sys v0.25.0 // indirect - golang.org/x/text v0.18.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61 // indirect - google.golang.org/protobuf v1.34.2 // indirect -) diff --git a/asset-transfer-private-data/application-gateway-go/go.sum b/asset-transfer-private-data/application-gateway-go/go.sum deleted file mode 100644 index 5306d77e..00000000 --- a/asset-transfer-private-data/application-gateway-go/go.sum +++ /dev/null @@ -1,223 +0,0 @@ -bitbucket.org/liamstask/goose v0.0.0-20150115234039-8488cc47d90c/go.mod h1:hSVuE3qU7grINVSwrmzHfpg9k87ALBk+XaualNyUzI4= -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= -github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= -github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/backoff v0.0.0-20161212185259-647f3cdfc87a/go.mod h1:rzgs2ZOiguV6/NpiDgADjRLPNyZlApIWxKpkT+X8SdY= -github.com/cloudflare/cfssl v1.4.1/go.mod h1:KManx/OJPb5QY+y0+o/898AMcM128sF0bURvoVUSjTo= -github.com/cloudflare/go-metrics v0.0.0-20151117154305-6a9aea36fb41/go.mod h1:eaZPlJWD+G9wseg1BuRXlHnjntPMrywMsyxf+LTOdP4= -github.com/cloudflare/redoctober v0.0.0-20171127175943-746a508df14c/go.mod h1:6Se34jNoqrd8bTxrmJB2Bg2aoZ2CdSXonils9NsiNgo= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/getsentry/raven-go v0.0.0-20180121060056-563b81fc02b7/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/hyperledger/fabric-config v0.0.5/go.mod h1:YpITBI/+ZayA3XWY5lF302K7PAsFYjEEPM/zr3hegA8= -github.com/hyperledger/fabric-gateway v1.6.0 h1:mPdXFSHdEjT0cmhsqKBfFMTVyBvfJXlO3Neicp/c27E= -github.com/hyperledger/fabric-gateway v1.6.0/go.mod h1:qHdJcgC6UrTxfYH+YIyAhPUkeNri0gPpyP/6xmiYrZo= -github.com/hyperledger/fabric-lib-go v1.0.0/go.mod h1:H362nMlunurmHwkYqR5uHL2UDWbQdbfz74n8kbCFsqc= -github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= -github.com/hyperledger/fabric-protos-go v0.0.0-20200707132912-fee30f3ccd23 h1:SEbB3yH4ISTGRifDamYXAst36gO2kM855ndMJlsv+pc= -github.com/hyperledger/fabric-protos-go v0.0.0-20200707132912-fee30f3ccd23/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3 h1:Xpd6fzG/KjAOHJsq7EQXY2l+qi/y8muxBaY7R6QWABk= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3/go.mod h1:2pq0ui6ZWA0cC8J+eCErgnMDCS1kPOEYVY+06ZAK0qE= -github.com/hyperledger/fabric-sdk-go v1.0.0 h1:NRu0iNbHV6u4nd9jgYghAdA1Ll4g0Sri4hwMEGiTbyg= -github.com/hyperledger/fabric-sdk-go v1.0.0/go.mod h1:qWE9Syfg1KbwNjtILk70bJLilnmCvllIYFCSY/pa1RU= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548/go.mod h1:hGT6jSUVzF6no3QaDSMLGLEHtHSBSefs+MgcDWnmhmo= -github.com/jmoiron/sqlx v0.0.0-20180124204410-05cef0741ade/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/kisielk/sqlstruct v0.0.0-20150923205031-648daed35d49/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE= -github.com/kisom/goutils v1.1.0/go.mod h1:+UBTfd78habUYWFbNWTJNG+jNG/i/lGURakr4A/yNRw= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kylelemons/go-gypsy v0.0.0-20160905020020-08cad365cd28/go.mod h1:T/T7jsxVqf9k/zYOqbgNAsANsjxTd1Yq3htjDhQ1H0c= -github.com/lib/pq v0.0.0-20180201184707-88edab080323/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= -github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= -github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= -github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/spf13/afero v1.3.1/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.1.1/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= -github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= -github.com/weppos/publicsuffix-go v0.5.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= -github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= -github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= -github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= -github.com/zmap/zcrypto v0.0.0-20190729165852-9051775e6a2e/go.mod h1:w7kd3qXHh8FNaczNjslXqvFQiv5mMWRXlL9klTUAHc8= -github.com/zmap/zlint v0.0.0-20190806154020-fd021b4cfbeb/go.mod h1:29UiAJNsiVdvTBFCJW8e3q6dcDbOoPkhMgttOSCIMMY= -go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= -go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61 h1:N9BgCIAUvn/M+p4NJccWPWb3BWh88+zyL0ll9HgbEeM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= -google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/asset-transfer-private-data/application-gateway-typescript/.gitignore b/asset-transfer-private-data/application-gateway-typescript/.gitignore deleted file mode 100644 index 99e5af9f..00000000 --- a/asset-transfer-private-data/application-gateway-typescript/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - - -# Coverage directory used by tools like istanbul -coverage - -# Dependency directories -node_modules/ -jspm_packages/ - -# Compiled TypeScript files -dist diff --git a/asset-transfer-private-data/application-gateway-typescript/.npmrc b/asset-transfer-private-data/application-gateway-typescript/.npmrc deleted file mode 100644 index b6f27f13..00000000 --- a/asset-transfer-private-data/application-gateway-typescript/.npmrc +++ /dev/null @@ -1 +0,0 @@ -engine-strict=true diff --git a/asset-transfer-private-data/application-gateway-typescript/README.md b/asset-transfer-private-data/application-gateway-typescript/README.md deleted file mode 100644 index 94cc79c0..00000000 --- a/asset-transfer-private-data/application-gateway-typescript/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Asset Transfer Private Data Sample - -This app uses fabric-samples/test-network based setup and the companion chaincode asset-transfer-private-data/chaincode-go/ with chaincode endorsement policy as "OR('Org1MSP.peer','Org2MSP.peer')" - -For this usecase illustration, we will use both Org1 & Org2 client identity from this same app -In real world the Org1 & Org2 identity will be used in different apps to achieve asset transfer. - -For more details refer: -https://hyperledger-fabric.readthedocs.io/en/release-2.4/private_data_tutorial.html#pd-use-case - diff --git a/asset-transfer-private-data/application-gateway-typescript/eslint.config.mjs b/asset-transfer-private-data/application-gateway-typescript/eslint.config.mjs deleted file mode 100644 index 9ef6b243..00000000 --- a/asset-transfer-private-data/application-gateway-typescript/eslint.config.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import js from '@eslint/js'; -import tseslint from 'typescript-eslint'; - -export default tseslint.config(js.configs.recommended, ...tseslint.configs.strictTypeChecked, { - languageOptions: { - ecmaVersion: 2023, - sourceType: 'module', - parserOptions: { - project: 'tsconfig.json', - tsconfigRootDir: import.meta.dirname, - }, - }, -}); diff --git a/asset-transfer-private-data/application-gateway-typescript/package.json b/asset-transfer-private-data/application-gateway-typescript/package.json deleted file mode 100644 index 96d609bf..00000000 --- a/asset-transfer-private-data/application-gateway-typescript/package.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "asset-transfer-private-data", - "version": "1.0.0", - "description": "Asset transfer private data application implemented in typeScript using fabric-gateway", - "main": "dist/index.js", - "typings": "dist/index.d.ts", - "engines": { - "node": ">=18" - }, - "scripts": { - "build": "tsc", - "build:watch": "tsc -w", - "lint": "eslint src", - "prepare": "npm run build", - "pretest": "npm run lint", - "start": "node dist/app.js" - }, - "engineStrict": true, - "author": "Hyperledger", - "license": "Apache-2.0", - "dependencies": { - "@grpc/grpc-js": "^1.12.2", - "@hyperledger/fabric-gateway": "^1.7.0" - }, - "devDependencies": { - "@eslint/js": "^9.3.0", - "@tsconfig/node18": "^18.2.2", - "@types/node": "^18.18.6", - "eslint": "^8.57.0", - "typescript": "~5.4", - "typescript-eslint": "^7.13.0" - } -} diff --git a/asset-transfer-private-data/application-gateway-typescript/src/app.ts b/asset-transfer-private-data/application-gateway-typescript/src/app.ts deleted file mode 100644 index 1e190227..00000000 --- a/asset-transfer-private-data/application-gateway-typescript/src/app.ts +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -import { connect, Contract, hash } from '@hyperledger/fabric-gateway'; -import { TextDecoder } from 'util'; -import { - certDirectoryPathOrg1, certDirectoryPathOrg2, keyDirectoryPathOrg1, keyDirectoryPathOrg2, newGrpcConnection, newIdentity, - newSigner, peerEndpointOrg1, peerEndpointOrg2, peerNameOrg1, peerNameOrg2, tlsCertPathOrg1, tlsCertPathOrg2 -} from './connect'; - -const channelName = 'mychannel'; -const chaincodeName = 'private'; -const mspIdOrg1 = 'Org1MSP'; -const mspIdOrg2 = 'Org2MSP'; - -const utf8Decoder = new TextDecoder(); - -// Collection names. -const org1PrivateCollectionName = 'Org1MSPPrivateCollection'; -const org2PrivateCollectionName = 'Org2MSPPrivateCollection'; - -const RED = '\x1b[31m\n'; -const RESET = '\x1b[0m'; - -// Use a unique key so that we can run multiple times. -const now = Date.now(); -const assetID1 = `asset${String(now)}`; -const assetID2 = `asset${String(now + 1)}`; - -async function main(): Promise { - const clientOrg1 = await newGrpcConnection( - tlsCertPathOrg1, - peerEndpointOrg1, - peerNameOrg1 - ); - - const gatewayOrg1 = connect({ - client: clientOrg1, - identity: await newIdentity(certDirectoryPathOrg1, mspIdOrg1), - signer: await newSigner(keyDirectoryPathOrg1), - hash: hash.sha256, - }); - - const clientOrg2 = await newGrpcConnection( - tlsCertPathOrg2, - peerEndpointOrg2, - peerNameOrg2 - ); - - const gatewayOrg2 = connect({ - client: clientOrg2, - identity: await newIdentity(certDirectoryPathOrg2, mspIdOrg2), - signer: await newSigner(keyDirectoryPathOrg2), - hash: hash.sha256, - }); - - try { - // Get the smart contract as an Org1 client. - const contractOrg1 = gatewayOrg1 - .getNetwork(channelName) - .getContract(chaincodeName); - - // Get the smart contract as an Org2 client. - const contractOrg2 = gatewayOrg2 - .getNetwork(channelName) - .getContract(chaincodeName); - - console.log('\n~~~~~~~~~~~~~~~~ As Org1 Client ~~~~~~~~~~~~~~~~'); - - // Create new assets on the ledger. - await createAssets(contractOrg1); - - // Read asset from the Org1's private data collection with ID in the given range. - await getAssetByRange(contractOrg1); - - try { - // Attempt to transfer asset without prior approval from Org2, transaction expected to fail. - console.log('\nAttempt TransferAsset without prior AgreeToTransfer'); - await transferAsset(contractOrg1, assetID1); - doFail('TransferAsset transaction succeeded when it was expected to fail'); - } catch (e) { - console.log('*** Received expected error:', e); - } - - console.log('\n~~~~~~~~~~~~~~~~ As Org2 Client ~~~~~~~~~~~~~~~~'); - - // Read the asset by ID. - await readAssetByID(contractOrg2, assetID1); - - // Make agreement to transfer the asset from Org1 to Org2. - await agreeToTransfer(contractOrg2, assetID1); - - console.log('\n~~~~~~~~~~~~~~~~ As Org1 Client ~~~~~~~~~~~~~~~~'); - - // Read transfer agreement. - await readTransferAgreement(contractOrg1, assetID1); - - // Transfer asset to Org2. - await transferAsset(contractOrg1, assetID1); - - // Again ReadAsset: results will show that the buyer identity now owns the asset. - await readAssetByID(contractOrg1, assetID1); - - // Confirm that transfer removed the private details from the Org1 collection. - const org1ReadSuccess = await readAssetPrivateDetails(contractOrg1, assetID1, org1PrivateCollectionName); - if (org1ReadSuccess) { - doFail(`Asset private data still exists in ${org1PrivateCollectionName}`); - } - - console.log('\n~~~~~~~~~~~~~~~~ As Org2 Client ~~~~~~~~~~~~~~~~'); - - // Org2 can read asset private details: Org2 is owner, and private details exist in new owner's collection. - const org2ReadSuccess = await readAssetPrivateDetails(contractOrg2, assetID1, org2PrivateCollectionName); - if (!org2ReadSuccess) { - doFail(`Asset private data not found in ${org2PrivateCollectionName}`); - } - - try { - console.log('\nAttempt DeleteAsset using non-owner organization'); - await deleteAsset(contractOrg2, assetID2); - doFail('DeleteAsset transaction succeeded when it was expected to fail'); - } catch (e) { - console.log('*** Received expected error:', e); - } - - console.log('\n~~~~~~~~~~~~~~~~ As Org1 Client ~~~~~~~~~~~~~~~~'); - - // Delete AssetID2 as Org1. - await deleteAsset(contractOrg1, assetID2); - - // Trigger a purge of the private data for the asset. - // The previous delete is optional if purge is used. - await purgeAsset(contractOrg1, assetID2); - } finally { - gatewayOrg1.close(); - clientOrg1.close(); - - gatewayOrg2.close(); - clientOrg2.close(); - } -} - -main().catch((error: unknown) => { - console.error('******** FAILED to run the application:', error); - process.exitCode = 1; -}); - -/** - * Submit a transaction synchronously, blocking until it has been committed to the ledger. - */ -async function createAssets(contract: Contract): Promise { - const assetType = 'ValuableAsset'; - - console.log(`\n--> Submit Transaction: CreateAsset, ID: ${assetID1}`); - - const asset1Data = { - objectType: assetType, - assetID: assetID1, - color: 'green', - size: 20, - appraisedValue: 100, - }; - - await contract.submit('CreateAsset', { - transientData: { asset_properties: JSON.stringify(asset1Data) }, - }); - - console.log('*** Transaction committed successfully'); - console.log(`\n--> Submit Transaction: CreateAsset, ID: ${assetID2}`); - - const asset2Data = { - objectType: assetType, - assetID: assetID2, - color: 'blue', - size: 35, - appraisedValue: 727, - }; - - await contract.submit('CreateAsset', { - transientData: { asset_properties: JSON.stringify(asset2Data) }, - }); - - console.log('*** Transaction committed successfully'); -} - -async function getAssetByRange(contract: Contract): Promise { - // GetAssetByRange returns assets on the ledger with ID in the range of startKey (inclusive) and endKey (exclusive). - console.log(`\n--> Evaluate Transaction: GetAssetByRange from ${org1PrivateCollectionName}`); - - const resultBytes = await contract.evaluateTransaction( - 'GetAssetByRange', - assetID1, - `asset${String(now + 2)}` - ); - - const resultString = utf8Decoder.decode(resultBytes); - if (!resultString) { - doFail('Received empty query list for GetAssetByRange'); - } - const result: unknown = JSON.parse(resultString); - console.log('*** Result:', result); -} - -async function readAssetByID(contract: Contract, assetID: string): Promise { - console.log(`\n--> Evaluate Transaction: ReadAsset, ID: ${assetID}`); - const resultBytes = await contract.evaluateTransaction('ReadAsset', assetID); - - const resultString = utf8Decoder.decode(resultBytes); - if (!resultString) { - doFail('Received empty result for ReadAsset'); - } - const result: unknown = JSON.parse(resultString); - console.log('*** Result:', result); -} - -async function agreeToTransfer(contract: Contract, assetID: string): Promise { - // Buyer from Org2 agrees to buy the asset. - // To purchase the asset, the buyer needs to agree to the same value as the asset owner. - - const dataForAgreement = { assetID, appraisedValue: 100 }; - console.log('\n--> Submit Transaction: AgreeToTransfer, payload:', dataForAgreement); - - await contract.submit('AgreeToTransfer', { - transientData: { asset_value: JSON.stringify(dataForAgreement) }, - }); - - console.log('*** Transaction committed successfully'); -} - -async function readTransferAgreement(contract: Contract, assetID: string): Promise { - console.log(`\n--> Evaluate Transaction: ReadTransferAgreement, ID: ${assetID}`); - - const resultBytes = await contract.evaluateTransaction( - 'ReadTransferAgreement', - assetID - ); - - const resultString = utf8Decoder.decode(resultBytes); - if (!resultString) { - doFail('Received no result for ReadTransferAgreement'); - } - const result: unknown = JSON.parse(resultString); - console.log('*** Result:', result); -} - -async function transferAsset(contract: Contract, assetID: string): Promise { - console.log(`\n--> Submit Transaction: TransferAsset, ID: ${assetID}`); - - const buyerDetails = { assetID, buyerMSP: mspIdOrg2 }; - await contract.submit('TransferAsset', { - transientData: { asset_owner: JSON.stringify(buyerDetails) }, - }); - - console.log('*** Transaction committed successfully'); -} - -async function deleteAsset(contract: Contract, assetID: string): Promise { - console.log('\n--> Submit Transaction: DeleteAsset, ID:', assetID); - const dataForDelete = { assetID }; - await contract.submit('DeleteAsset', { - transientData: { asset_delete: JSON.stringify(dataForDelete) }, - }); - - console.log('*** Transaction committed successfully'); -} - -async function purgeAsset(contract: Contract, assetID: string): Promise { - console.log('\n--> Submit Transaction: PurgeAsset, ID:', assetID); - const dataForPurge = { assetID }; - await contract.submit('PurgeAsset', { - transientData: { asset_purge: JSON.stringify(dataForPurge) }, - }); - - console.log('*** Transaction committed successfully'); -} - -async function readAssetPrivateDetails(contract: Contract, assetID: string, collectionName: string): Promise { - console.log(`\n--> Evaluate Transaction: ReadAssetPrivateDetails from ${collectionName}, ID: ${assetID}`); - - const resultBytes = await contract.evaluateTransaction( - 'ReadAssetPrivateDetails', - collectionName, - assetID - ); - - const resultJson = utf8Decoder.decode(resultBytes); - if (!resultJson) { - console.log('*** No result'); - return false; - } - const result: unknown = JSON.parse(resultJson); - console.log('*** Result:', result); - return true; -} - -export function doFail(msgString: string): never { - console.error(`${RED}\t${msgString}${RESET}`); - throw new Error(msgString); -} diff --git a/asset-transfer-private-data/application-gateway-typescript/src/connect.ts b/asset-transfer-private-data/application-gateway-typescript/src/connect.ts deleted file mode 100644 index 0fe7f3a3..00000000 --- a/asset-transfer-private-data/application-gateway-typescript/src/connect.ts +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as grpc from '@grpc/grpc-js'; -import { Identity, Signer, signers } from '@hyperledger/fabric-gateway'; -import * as crypto from 'crypto'; -import { promises as fs } from 'fs'; -import * as path from 'path'; - -// Path to org1 crypto materials. -const cryptoPathOrg1 = path.resolve( - __dirname, - '..', - '..', - '..', - 'test-network', - 'organizations', - 'peerOrganizations', - 'org1.example.com' -); - -// Path to org1 user private key directory. -export const keyDirectoryPathOrg1 = path.resolve( - cryptoPathOrg1, - 'users', - 'User1@org1.example.com', - 'msp', - 'keystore' -); - -// Path to org1 user certificate. -export const certDirectoryPathOrg1 = path.resolve( - cryptoPathOrg1, - 'users', - 'User1@org1.example.com', - 'msp', - 'signcerts' -); - -// Path to org1 peer tls certificate. -export const tlsCertPathOrg1 = path.resolve( - cryptoPathOrg1, - 'peers', - 'peer0.org1.example.com', - 'tls', - 'ca.crt' -); - -// Path to org2 crypto materials. -export const cryptoPathOrg2 = path.resolve( - __dirname, - '..', - '..', - '..', - 'test-network', - 'organizations', - 'peerOrganizations', - 'org2.example.com' -); - -// Path to org2 user private key directory. -export const keyDirectoryPathOrg2 = path.resolve( - cryptoPathOrg2, - 'users', - 'User1@org2.example.com', - 'msp', - 'keystore' -); - -// Path to org2 user certificate. -export const certDirectoryPathOrg2 = path.resolve( - cryptoPathOrg2, - 'users', - 'User1@org2.example.com', - 'msp', - 'signcerts' -); - -// Path to org2 peer tls certificate. -export const tlsCertPathOrg2 = path.resolve( - cryptoPathOrg2, - 'peers', - 'peer0.org2.example.com', - 'tls', - 'ca.crt' -); - -// Gateway peer endpoint. -export const peerEndpointOrg1 = 'localhost:7051'; -export const peerEndpointOrg2 = 'localhost:9051'; - -// Gateway peer container name. -export const peerNameOrg1 = 'peer0.org1.example.com'; -export const peerNameOrg2 = 'peer0.org2.example.com'; - - -export async function newGrpcConnection( - tlsCertPath: string, - peerEndpoint: string, - peerName: string -): Promise { - const tlsRootCert = await fs.readFile(tlsCertPath); - const tlsCredentials = grpc.credentials.createSsl(tlsRootCert); - return new grpc.Client(peerEndpoint, tlsCredentials, { - 'grpc.ssl_target_name_override': peerName, - }); -} - -export async function newIdentity( - certDirectoryPath: string, - mspId: string -): Promise { - const certPath = await getFirstDirFileName(certDirectoryPath); - const credentials = await fs.readFile(certPath); - return { mspId, credentials }; -} - -export async function newSigner(keyDirectoryPath: string): Promise { - const keyPath = await getFirstDirFileName(keyDirectoryPath); - const privateKeyPem = await fs.readFile(keyPath); - const privateKey = crypto.createPrivateKey(privateKeyPem); - return signers.newPrivateKeySigner(privateKey); -} - -async function getFirstDirFileName(dirPath: string): Promise { - const files = await fs.readdir(dirPath); - const file = files[0]; - if (!file) { - throw new Error(`No files in directory: ${dirPath}`); - } - return path.join(dirPath, file); -} diff --git a/asset-transfer-private-data/application-gateway-typescript/tsconfig.json b/asset-transfer-private-data/application-gateway-typescript/tsconfig.json deleted file mode 100644 index 4c20df24..00000000 --- a/asset-transfer-private-data/application-gateway-typescript/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "@tsconfig/node18/tsconfig.json", - "compilerOptions": { - "outDir": "dist", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "noUnusedLocals": true, - "noImplicitReturns": true, - "noUncheckedIndexedAccess": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["./src/**/*"], - "exclude": ["./src/**/*.spec.ts"] -} diff --git a/asset-transfer-private-data/chaincode-go/META-INF/statedb/couchdb/collections/assetCollection/indexes/indexOwner.json b/asset-transfer-private-data/chaincode-go/META-INF/statedb/couchdb/collections/assetCollection/indexes/indexOwner.json deleted file mode 100644 index e2d1d087..00000000 --- a/asset-transfer-private-data/chaincode-go/META-INF/statedb/couchdb/collections/assetCollection/indexes/indexOwner.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "index": { - "fields": [ - "objectType", - "owner" - ] - }, - "ddoc": "indexOwnerDoc", - "name": "indexOwner", - "type": "json" -} - diff --git a/asset-transfer-private-data/chaincode-go/README.md b/asset-transfer-private-data/chaincode-go/README.md deleted file mode 100644 index f87a95c6..00000000 --- a/asset-transfer-private-data/chaincode-go/README.md +++ /dev/null @@ -1 +0,0 @@ -[Using Private Data tutorial](https://hyperledger-fabric.readthedocs.io/en/latest/private_data_tutorial.html) diff --git a/asset-transfer-private-data/chaincode-go/chaincode/asset_queries.go b/asset-transfer-private-data/chaincode-go/chaincode/asset_queries.go deleted file mode 100644 index 0542947a..00000000 --- a/asset-transfer-private-data/chaincode-go/chaincode/asset_queries.go +++ /dev/null @@ -1,190 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "encoding/json" - "fmt" - "log" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -// ReadAsset reads the information from collection -func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, assetID string) (*Asset, error) { - - log.Printf("ReadAsset: collection %v, ID %v", assetCollection, assetID) - assetJSON, err := ctx.GetStub().GetPrivateData(assetCollection, assetID) //get the asset from chaincode state - if err != nil { - return nil, fmt.Errorf("failed to read asset: %v", err) - } - - // No Asset found, return empty response - if assetJSON == nil { - log.Printf("%v does not exist in collection %v", assetID, assetCollection) - return nil, nil - } - - var asset *Asset - err = json.Unmarshal(assetJSON, &asset) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal JSON: %v", err) - } - - return asset, nil - -} - -// ReadAssetPrivateDetails reads the asset private details in organization specific collection -func (s *SmartContract) ReadAssetPrivateDetails(ctx contractapi.TransactionContextInterface, collection string, assetID string) (*AssetPrivateDetails, error) { - log.Printf("ReadAssetPrivateDetails: collection %v, ID %v", collection, assetID) - assetDetailsJSON, err := ctx.GetStub().GetPrivateData(collection, assetID) // Get the asset from chaincode state - if err != nil { - return nil, fmt.Errorf("failed to read asset details: %v", err) - } - if assetDetailsJSON == nil { - log.Printf("AssetPrivateDetails for %v does not exist in collection %v", assetID, collection) - return nil, nil - } - - var assetDetails *AssetPrivateDetails - err = json.Unmarshal(assetDetailsJSON, &assetDetails) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal JSON: %v", err) - } - - return assetDetails, nil -} - -// ReadTransferAgreement gets the buyer's identity from the transfer agreement from collection -func (s *SmartContract) ReadTransferAgreement(ctx contractapi.TransactionContextInterface, assetID string) (*TransferAgreement, error) { - log.Printf("ReadTransferAgreement: collection %v, ID %v", assetCollection, assetID) - // composite key for TransferAgreement of this asset - transferAgreeKey, err := ctx.GetStub().CreateCompositeKey(transferAgreementObjectType, []string{assetID}) - if err != nil { - return nil, fmt.Errorf("failed to create composite key: %v", err) - } - - buyerIdentity, err := ctx.GetStub().GetPrivateData(assetCollection, transferAgreeKey) // Get the identity from collection - if err != nil { - return nil, fmt.Errorf("failed to read TransferAgreement: %v", err) - } - if buyerIdentity == nil { - log.Printf("TransferAgreement for %v does not exist", assetID) - return nil, nil - } - agreement := &TransferAgreement{ - ID: assetID, - BuyerID: string(buyerIdentity), - } - return agreement, nil -} - -// GetAssetByRange performs a range query based on the start and end keys provided. Range -// queries can be used to read data from private data collections, but can not be used in -// a transaction that also writes to private data. -func (s *SmartContract) GetAssetByRange(ctx contractapi.TransactionContextInterface, startKey string, endKey string) ([]*Asset, error) { - - resultsIterator, err := ctx.GetStub().GetPrivateDataByRange(assetCollection, startKey, endKey) - if err != nil { - return nil, err - } - defer resultsIterator.Close() - - results := []*Asset{} - - for resultsIterator.HasNext() { - response, err := resultsIterator.Next() - if err != nil { - return nil, err - } - - var asset *Asset - err = json.Unmarshal(response.Value, &asset) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal JSON: %v", err) - } - - results = append(results, asset) - } - - return results, nil - -} - -// =======Rich queries ========================================================================= -// Two examples of rich queries are provided below (parameterized query and ad hoc query). -// Rich queries pass a query string to the state database. -// Rich queries are only supported by state database implementations -// that support rich query (e.g. CouchDB). -// The query string is in the syntax of the underlying state database. -// With rich queries there is no guarantee that the result set hasn't changed between -// endorsement time and commit time, aka 'phantom reads'. -// Therefore, rich queries should not be used in update transactions, unless the -// application handles the possibility of result set changes between endorsement and commit time. -// Rich queries can be used for point-in-time queries against a peer. -// ============================================================================================ - -// ===== Example: Parameterized rich query ================================================= - -// QueryAssetByOwner queries for assets based on assetType, owner. -// This is an example of a parameterized query where the query logic is baked into the chaincode, -// and accepting a single query parameter (owner). -// Only available on state databases that support rich query (e.g. CouchDB) -// ========================================================================================= -func (s *SmartContract) QueryAssetByOwner(ctx contractapi.TransactionContextInterface, assetType string, owner string) ([]*Asset, error) { - - queryString := fmt.Sprintf("{\"selector\":{\"objectType\":\"%v\",\"owner\":\"%v\"}}", assetType, owner) - - queryResults, err := s.getQueryResultForQueryString(ctx, queryString) - if err != nil { - return nil, err - } - return queryResults, nil -} - -// QueryAssets uses a query string to perform a query for assets. -// Query string matching state database syntax is passed in and executed as is. -// Supports ad hoc queries that can be defined at runtime by the client. -// If this is not desired, follow the QueryAssetByOwner example for parameterized queries. -// Only available on state databases that support rich query (e.g. CouchDB) -func (s *SmartContract) QueryAssets(ctx contractapi.TransactionContextInterface, queryString string) ([]*Asset, error) { - - queryResults, err := s.getQueryResultForQueryString(ctx, queryString) - if err != nil { - return nil, err - } - return queryResults, nil -} - -// getQueryResultForQueryString executes the passed in query string. -func (s *SmartContract) getQueryResultForQueryString(ctx contractapi.TransactionContextInterface, queryString string) ([]*Asset, error) { - - resultsIterator, err := ctx.GetStub().GetPrivateDataQueryResult(assetCollection, queryString) - if err != nil { - return nil, err - } - defer resultsIterator.Close() - - results := []*Asset{} - - for resultsIterator.HasNext() { - response, err := resultsIterator.Next() - if err != nil { - return nil, err - } - var asset *Asset - - err = json.Unmarshal(response.Value, &asset) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal JSON: %v", err) - } - - results = append(results, asset) - } - return results, nil -} diff --git a/asset-transfer-private-data/chaincode-go/chaincode/asset_queries_test.go b/asset-transfer-private-data/chaincode-go/chaincode/asset_queries_test.go deleted file mode 100644 index c35e9f20..00000000 --- a/asset-transfer-private-data/chaincode-go/chaincode/asset_queries_test.go +++ /dev/null @@ -1,185 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ -package chaincode_test - -import ( - "encoding/json" - "fmt" - "testing" - - "github.com/hyperledger/fabric-protos-go-apiv2/ledger/queryresult" - - "github.com/hyperledger/fabric-samples/asset-transfer-private-data/chaincode-go/chaincode" - "github.com/hyperledger/fabric-samples/asset-transfer-private-data/chaincode-go/chaincode/mocks" - "github.com/stretchr/testify/require" -) - -/* -For details on generating the mocks, see comments in the file asset_transfer_test.go -*/ -func TestReadAsset(t *testing.T) { - transactionContext, chaincodeStub := prepMocksAsOrg1() - assetTransferCC := chaincode.SmartContract{} - - assetBytes, err := assetTransferCC.ReadAsset(transactionContext, "id1") - require.NoError(t, err) - require.Nil(t, assetBytes) - - chaincodeStub.GetPrivateDataReturns(nil, fmt.Errorf("unable to retrieve asset")) - assetBytes, err = assetTransferCC.ReadAsset(transactionContext, "id1") - require.EqualError(t, err, "failed to read asset: unable to retrieve asset") - - testAsset := &chaincode.Asset{ - ID: "id1", - Type: "testfulasset", - Color: "gray", - Size: 7, - Owner: myOrg1Clientid, - } - setReturnPrivateDataInStub(t, chaincodeStub, testAsset) - assetRead, err := assetTransferCC.ReadAsset(transactionContext, "id1") - require.NoError(t, err) - require.Equal(t, testAsset, assetRead) -} - -func TestReadAssetPrivateDetails(t *testing.T) { - transactionContext, chaincodeStub := prepMocksAsOrg1() - assetTransferCC := chaincode.SmartContract{} - - assetBytes, err := assetTransferCC.ReadAssetPrivateDetails(transactionContext, myOrg1PrivCollection, "id1") - require.NoError(t, err) - require.Nil(t, assetBytes) - - // read from the collection with no access - chaincodeStub.GetPrivateDataReturns(nil, fmt.Errorf("collection not found")) - assetBytes, err = assetTransferCC.ReadAssetPrivateDetails(transactionContext, myOrg2PrivCollection, "id1") - require.EqualError(t, err, "failed to read asset details: collection not found") - - returnPrivData := &chaincode.AssetPrivateDetails{ - ID: "id1", - AppraisedValue: 5, - } - setReturnAssetPrivateDetailsInStub(t, chaincodeStub, returnPrivData) - assetRead, err := assetTransferCC.ReadAssetPrivateDetails(transactionContext, myOrg1PrivCollection, "id1") - require.NoError(t, err) - require.Equal(t, returnPrivData, assetRead) -} - -func TestReadTransferAgreement(t *testing.T) { - transactionContext, chaincodeStub := prepMocksAsOrg1() - assetTransferCC := chaincode.SmartContract{} - - // TransferAgreement does not exist - assetBytes, err := assetTransferCC.ReadTransferAgreement(transactionContext, "id1") - require.NoError(t, err) - require.Nil(t, assetBytes) - - chaincodeStub.GetPrivateDataReturns([]byte(myOrg2Clientid), nil) - expectedData := &chaincode.TransferAgreement{ - ID: "id1", - BuyerID: myOrg2Clientid, - } - dataRead, err := assetTransferCC.ReadTransferAgreement(transactionContext, "id1") - require.NoError(t, err) - require.Equal(t, expectedData, dataRead) -} - -func TestQueryAssetByOwner(t *testing.T) { - transactionContext, chaincodeStub := prepMocksAsOrg1() - - asset := &chaincode.Asset{Type: "valuableasset", ID: "asset1", Owner: "user1"} - asset1Bytes, err := json.Marshal(asset) - require.NoError(t, err) - - iterator := &mocks.StateQueryIterator{} - iterator.HasNextReturnsOnCall(0, true) - iterator.HasNextReturnsOnCall(1, false) - iterator.NextReturns(&queryresult.KV{Value: asset1Bytes}, nil) - chaincodeStub.GetPrivateDataQueryResultReturns(iterator, nil) - - assetTransferCC := &chaincode.SmartContract{} - assets, err := assetTransferCC.QueryAssetByOwner(transactionContext, "valuableasset", "user1") - require.NoError(t, err) - require.Equal(t, []*chaincode.Asset{asset}, assets) - - iterator.HasNextReturns(true) - iterator.NextReturns(nil, fmt.Errorf("failed retrieving next item")) - assets, err = assetTransferCC.QueryAssetByOwner(transactionContext, "valuableasset", "user1") - require.EqualError(t, err, "failed retrieving next item") - require.Nil(t, assets) - -} - -func TestQueryAssets(t *testing.T) { - transactionContext, chaincodeStub := prepMocksAsOrg1() - // Iterator with no records - iterator := &mocks.StateQueryIterator{} - iterator.HasNextReturns(false) - chaincodeStub.GetPrivateDataQueryResultReturns(iterator, nil) - - assetTransferCC := &chaincode.SmartContract{} - assets, err := assetTransferCC.QueryAssets(transactionContext, "querystr") - require.NoError(t, err) - require.Equal(t, []*chaincode.Asset{}, assets) - - iterator = &mocks.StateQueryIterator{} - chaincodeStub.GetPrivateDataQueryResultReturns(iterator, nil) - iterator.HasNextReturns(true) - iterator.NextReturns(nil, fmt.Errorf("failed retrieving next item")) - assets, err = assetTransferCC.QueryAssets(transactionContext, "querystr") - require.EqualError(t, err, "failed retrieving next item") - require.Nil(t, assets) - - asset := &chaincode.Asset{Type: "valuableasset", ID: "asset1", Owner: "user1"} - asset1Bytes, err := json.Marshal(asset) - require.NoError(t, err) - - iterator = &mocks.StateQueryIterator{} - chaincodeStub.GetPrivateDataQueryResultReturns(iterator, nil) - iterator.HasNextReturnsOnCall(0, true) - iterator.HasNextReturnsOnCall(1, false) - iterator.NextReturns(&queryresult.KV{Value: asset1Bytes}, nil) - - assets, err = assetTransferCC.QueryAssets(transactionContext, "querystr") - require.NoError(t, err) - require.Equal(t, []*chaincode.Asset{asset}, assets) -} - -func TestGetAssetByRange(t *testing.T) { - transactionContext, chaincodeStub := prepMocksAsOrg1() - // Iterator with no records - iterator := &mocks.StateQueryIterator{} - iterator.HasNextReturns(false) - chaincodeStub.GetPrivateDataByRangeReturns(iterator, nil) - - assetTransferCC := &chaincode.SmartContract{} - assets, err := assetTransferCC.GetAssetByRange(transactionContext, "st", "end") - require.NoError(t, err) - require.Equal(t, []*chaincode.Asset{}, assets) - - iterator = &mocks.StateQueryIterator{} - chaincodeStub.GetPrivateDataByRangeReturns(iterator, nil) - iterator.HasNextReturns(true) - iterator.NextReturns(nil, fmt.Errorf("failed retrieving next item")) - assets, err = assetTransferCC.GetAssetByRange(transactionContext, "st", "end") - require.EqualError(t, err, "failed retrieving next item") - require.Nil(t, assets) - - asset := &chaincode.Asset{Type: "valuableasset", ID: "asset1", Owner: "user1"} - asset1Bytes, err := json.Marshal(asset) - require.NoError(t, err) - - iterator = &mocks.StateQueryIterator{} - chaincodeStub.GetPrivateDataByRangeReturns(iterator, nil) - iterator.HasNextReturnsOnCall(0, true) - iterator.HasNextReturnsOnCall(1, false) - iterator.NextReturns(&queryresult.KV{Value: asset1Bytes}, nil) - - assets, err = assetTransferCC.GetAssetByRange(transactionContext, "st", "end") - require.NoError(t, err) - require.Equal(t, []*chaincode.Asset{asset}, assets) - -} diff --git a/asset-transfer-private-data/chaincode-go/chaincode/asset_transfer.go b/asset-transfer-private-data/chaincode-go/chaincode/asset_transfer.go deleted file mode 100644 index 58817a56..00000000 --- a/asset-transfer-private-data/chaincode-go/chaincode/asset_transfer.go +++ /dev/null @@ -1,652 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "bytes" - "encoding/base64" - "encoding/json" - "fmt" - "log" - - "github.com/hyperledger/fabric-chaincode-go/v2/shim" - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -const assetCollection = "assetCollection" -const transferAgreementObjectType = "transferAgreement" - -// SmartContract of this fabric sample -type SmartContract struct { - contractapi.Contract -} - -// Asset describes main asset details that are visible to all organizations -type Asset struct { - Type string `json:"objectType"` //Type is used to distinguish the various types of objects in state database - ID string `json:"assetID"` - Color string `json:"color"` - Size int `json:"size"` - Owner string `json:"owner"` -} - -// AssetPrivateDetails describes details that are private to owners -type AssetPrivateDetails struct { - ID string `json:"assetID"` - AppraisedValue int `json:"appraisedValue"` -} - -// TransferAgreement describes the buyer agreement returned by ReadTransferAgreement -type TransferAgreement struct { - ID string `json:"assetID"` - BuyerID string `json:"buyerID"` -} - -// CreateAsset creates a new asset by placing the main asset details in the assetCollection -// that can be read by both organizations. The appraisal value is stored in the owners org specific collection. -func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface) error { - - // Get new asset from transient map - transientMap, err := ctx.GetStub().GetTransient() - if err != nil { - return fmt.Errorf("error getting transient: %v", err) - } - - // Asset properties are private, therefore they get passed in transient field, instead of func args - transientAssetJSON, ok := transientMap["asset_properties"] - if !ok { - // log error to stdout - return fmt.Errorf("asset not found in the transient map input") - } - - type assetTransientInput struct { - Type string `json:"objectType"` //Type is used to distinguish the various types of objects in state database - ID string `json:"assetID"` - Color string `json:"color"` - Size int `json:"size"` - AppraisedValue int `json:"appraisedValue"` - } - - var assetInput assetTransientInput - err = json.Unmarshal(transientAssetJSON, &assetInput) - if err != nil { - return fmt.Errorf("failed to unmarshal JSON: %v", err) - } - - if len(assetInput.Type) == 0 { - return fmt.Errorf("objectType field must be a non-empty string") - } - if len(assetInput.ID) == 0 { - return fmt.Errorf("assetID field must be a non-empty string") - } - if len(assetInput.Color) == 0 { - return fmt.Errorf("color field must be a non-empty string") - } - if assetInput.Size <= 0 { - return fmt.Errorf("size field must be a positive integer") - } - if assetInput.AppraisedValue <= 0 { - return fmt.Errorf("appraisedValue field must be a positive integer") - } - - // Check if asset already exists - assetAsBytes, err := ctx.GetStub().GetPrivateData(assetCollection, assetInput.ID) - if err != nil { - return fmt.Errorf("failed to get asset: %v", err) - } else if assetAsBytes != nil { - fmt.Println("Asset already exists: " + assetInput.ID) - return fmt.Errorf("this asset already exists: " + assetInput.ID) - } - - // Get ID of submitting client identity - clientID, err := submittingClientIdentity(ctx) - if err != nil { - return err - } - - // Verify that the client is submitting request to peer in their organization - // This is to ensure that a client from another org doesn't attempt to read or - // write private data from this peer. - err = verifyClientOrgMatchesPeerOrg(ctx) - if err != nil { - return fmt.Errorf("CreateAsset cannot be performed: Error %v", err) - } - - // Make submitting client the owner - asset := Asset{ - Type: assetInput.Type, - ID: assetInput.ID, - Color: assetInput.Color, - Size: assetInput.Size, - Owner: clientID, - } - assetJSONasBytes, err := json.Marshal(asset) - if err != nil { - return fmt.Errorf("failed to marshal asset into JSON: %v", err) - } - - // Save asset to private data collection - // Typical logger, logs to stdout/file in the fabric managed docker container, running this chaincode - // Look for container name like dev-peer0.org1.example.com-{chaincodename_version}-xyz - log.Printf("CreateAsset Put: collection %v, ID %v, owner %v", assetCollection, assetInput.ID, clientID) - - err = ctx.GetStub().PutPrivateData(assetCollection, assetInput.ID, assetJSONasBytes) - if err != nil { - return fmt.Errorf("failed to put asset into private data collecton: %v", err) - } - - // Save asset details to collection visible to owning organization - assetPrivateDetails := AssetPrivateDetails{ - ID: assetInput.ID, - AppraisedValue: assetInput.AppraisedValue, - } - - assetPrivateDetailsAsBytes, err := json.Marshal(assetPrivateDetails) // marshal asset details to JSON - if err != nil { - return fmt.Errorf("failed to marshal into JSON: %v", err) - } - - // Get collection name for this organization. - orgCollection, err := getCollectionName(ctx) - if err != nil { - return fmt.Errorf("failed to infer private collection name for the org: %v", err) - } - - // Put asset appraised value into owners org specific private data collection - log.Printf("Put: collection %v, ID %v", orgCollection, assetInput.ID) - err = ctx.GetStub().PutPrivateData(orgCollection, assetInput.ID, assetPrivateDetailsAsBytes) - if err != nil { - return fmt.Errorf("failed to put asset private details: %v", err) - } - return nil -} - -// AgreeToTransfer is used by the potential buyer of the asset to agree to the -// asset value. The agreed to appraisal value is stored in the buying orgs -// org specifc collection, while the buyer client ID is stored in the asset collection -// using a composite key -func (s *SmartContract) AgreeToTransfer(ctx contractapi.TransactionContextInterface) error { - - // Get ID of submitting client identity - clientID, err := submittingClientIdentity(ctx) - if err != nil { - return err - } - - // Value is private, therefore it gets passed in transient field - transientMap, err := ctx.GetStub().GetTransient() - if err != nil { - return fmt.Errorf("error getting transient: %v", err) - } - - // Persist the JSON bytes as-is so that there is no risk of nondeterministic marshaling. - valueJSONasBytes, ok := transientMap["asset_value"] - if !ok { - return fmt.Errorf("asset_value key not found in the transient map") - } - - // Unmarshal the tranisent map to get the asset ID. - var valueJSON AssetPrivateDetails - err = json.Unmarshal(valueJSONasBytes, &valueJSON) - if err != nil { - return fmt.Errorf("failed to unmarshal JSON: %v", err) - } - - // Do some error checking since we get the chance - if len(valueJSON.ID) == 0 { - return fmt.Errorf("assetID field must be a non-empty string") - } - if valueJSON.AppraisedValue <= 0 { - return fmt.Errorf("appraisedValue field must be a positive integer") - } - - // Read asset from the private data collection - asset, err := s.ReadAsset(ctx, valueJSON.ID) - if err != nil { - return fmt.Errorf("error reading asset: %v", err) - } - if asset == nil { - return fmt.Errorf("%v does not exist", valueJSON.ID) - } - // Verify that the client is submitting request to peer in their organization - err = verifyClientOrgMatchesPeerOrg(ctx) - if err != nil { - return fmt.Errorf("AgreeToTransfer cannot be performed: Error %v", err) - } - - // Get collection name for this organization. Needs to be read by a member of the organization. - orgCollection, err := getCollectionName(ctx) - if err != nil { - return fmt.Errorf("failed to infer private collection name for the org: %v", err) - } - - log.Printf("AgreeToTransfer Put: collection %v, ID %v", orgCollection, valueJSON.ID) - // Put agreed value in the org specifc private data collection - err = ctx.GetStub().PutPrivateData(orgCollection, valueJSON.ID, valueJSONasBytes) - if err != nil { - return fmt.Errorf("failed to put asset bid: %v", err) - } - - // Create agreeement that indicates which identity has agreed to purchase - // In a more realistic transfer scenario, a transfer agreement would be secured to ensure that it cannot - // be overwritten by another channel member - transferAgreeKey, err := ctx.GetStub().CreateCompositeKey(transferAgreementObjectType, []string{valueJSON.ID}) - if err != nil { - return fmt.Errorf("failed to create composite key: %v", err) - } - - log.Printf("AgreeToTransfer Put: collection %v, ID %v, Key %v", assetCollection, valueJSON.ID, transferAgreeKey) - err = ctx.GetStub().PutPrivateData(assetCollection, transferAgreeKey, []byte(clientID)) - if err != nil { - return fmt.Errorf("failed to put asset bid: %v", err) - } - - return nil -} - -// TransferAsset transfers the asset to the new owner by setting a new owner ID -func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface) error { - - transientMap, err := ctx.GetStub().GetTransient() - if err != nil { - return fmt.Errorf("error getting transient %v", err) - } - - // Asset properties are private, therefore they get passed in transient field - transientTransferJSON, ok := transientMap["asset_owner"] - if !ok { - return fmt.Errorf("asset owner not found in the transient map") - } - - type assetTransferTransientInput struct { - ID string `json:"assetID"` - BuyerMSP string `json:"buyerMSP"` - } - - var assetTransferInput assetTransferTransientInput - err = json.Unmarshal(transientTransferJSON, &assetTransferInput) - if err != nil { - return fmt.Errorf("failed to unmarshal JSON: %v", err) - } - - if len(assetTransferInput.ID) == 0 { - return fmt.Errorf("assetID field must be a non-empty string") - } - if len(assetTransferInput.BuyerMSP) == 0 { - return fmt.Errorf("buyerMSP field must be a non-empty string") - } - log.Printf("TransferAsset: verify asset exists ID %v", assetTransferInput.ID) - // Read asset from the private data collection - asset, err := s.ReadAsset(ctx, assetTransferInput.ID) - if err != nil { - return fmt.Errorf("error reading asset: %v", err) - } - if asset == nil { - return fmt.Errorf("%v does not exist", assetTransferInput.ID) - } - // Verify that the client is submitting request to peer in their organization - err = verifyClientOrgMatchesPeerOrg(ctx) - if err != nil { - return fmt.Errorf("TransferAsset cannot be performed: Error %v", err) - } - - // Verify transfer details and transfer owner - err = s.verifyAgreement(ctx, assetTransferInput.ID, asset.Owner, assetTransferInput.BuyerMSP) - if err != nil { - return fmt.Errorf("failed transfer verification: %v", err) - } - - transferAgreement, err := s.ReadTransferAgreement(ctx, assetTransferInput.ID) - if err != nil { - return fmt.Errorf("failed ReadTransferAgreement to find buyerID: %v", err) - } - if transferAgreement.BuyerID == "" { - return fmt.Errorf("BuyerID not found in TransferAgreement for %v", assetTransferInput.ID) - } - - // Transfer asset in private data collection to new owner - asset.Owner = transferAgreement.BuyerID - - assetJSONasBytes, err := json.Marshal(asset) - if err != nil { - return fmt.Errorf("failed marshalling asset %v: %v", assetTransferInput.ID, err) - } - - log.Printf("TransferAsset Put: collection %v, ID %v", assetCollection, assetTransferInput.ID) - err = ctx.GetStub().PutPrivateData(assetCollection, assetTransferInput.ID, assetJSONasBytes) //rewrite the asset - if err != nil { - return err - } - - // Get collection name for this organization - ownersCollection, err := getCollectionName(ctx) - if err != nil { - return fmt.Errorf("failed to infer private collection name for the org: %v", err) - } - - // Delete the asset appraised value from this organization's private data collection - err = ctx.GetStub().DelPrivateData(ownersCollection, assetTransferInput.ID) - if err != nil { - return err - } - - // Delete the transfer agreement from the asset collection - transferAgreeKey, err := ctx.GetStub().CreateCompositeKey(transferAgreementObjectType, []string{assetTransferInput.ID}) - if err != nil { - return fmt.Errorf("failed to create composite key: %v", err) - } - - err = ctx.GetStub().DelPrivateData(assetCollection, transferAgreeKey) - if err != nil { - return err - } - - return nil - -} - -// verifyAgreement is an internal helper function used by TransferAsset to verify -// that the transfer is being initiated by the owner and that the buyer has agreed -// to the same appraisal value as the owner -func (s *SmartContract) verifyAgreement(ctx contractapi.TransactionContextInterface, assetID string, owner string, buyerMSP string) error { - - // Check 1: verify that the transfer is being initiatied by the owner - - // Get ID of submitting client identity - clientID, err := submittingClientIdentity(ctx) - if err != nil { - return err - } - - if clientID != owner { - return fmt.Errorf("error: submitting client identity does not own asset") - } - - // Check 2: verify that the buyer has agreed to the appraised value - - // Get collection names - collectionOwner, err := getCollectionName(ctx) // get owner collection from caller identity - if err != nil { - return fmt.Errorf("failed to infer private collection name for the org: %v", err) - } - - collectionBuyer := buyerMSP + "PrivateCollection" // get buyers collection - - // Get hash of owners agreed to value - ownerAppraisedValueHash, err := ctx.GetStub().GetPrivateDataHash(collectionOwner, assetID) - if err != nil { - return fmt.Errorf("failed to get hash of appraised value from owners collection %v: %v", collectionOwner, err) - } - if ownerAppraisedValueHash == nil { - return fmt.Errorf("hash of appraised value for %v does not exist in collection %v", assetID, collectionOwner) - } - - // Get hash of buyers agreed to value - buyerAppraisedValueHash, err := ctx.GetStub().GetPrivateDataHash(collectionBuyer, assetID) - if err != nil { - return fmt.Errorf("failed to get hash of appraised value from buyer collection %v: %v", collectionBuyer, err) - } - if buyerAppraisedValueHash == nil { - return fmt.Errorf("hash of appraised value for %v does not exist in collection %v. AgreeToTransfer must be called by the buyer first", assetID, collectionBuyer) - } - - // Verify that the two hashes match - if !bytes.Equal(ownerAppraisedValueHash, buyerAppraisedValueHash) { - return fmt.Errorf("hash for appraised value for owner %x does not value for seller %x", ownerAppraisedValueHash, buyerAppraisedValueHash) - } - - return nil -} - -// DeleteAsset can be used by the owner of the asset to delete the asset -func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface) error { - - transientMap, err := ctx.GetStub().GetTransient() - if err != nil { - return fmt.Errorf("Error getting transient: %v", err) - } - - // Asset properties are private, therefore they get passed in transient field - transientDeleteJSON, ok := transientMap["asset_delete"] - if !ok { - return fmt.Errorf("asset to delete not found in the transient map") - } - - type assetDelete struct { - ID string `json:"assetID"` - } - - var assetDeleteInput assetDelete - err = json.Unmarshal(transientDeleteJSON, &assetDeleteInput) - if err != nil { - return fmt.Errorf("failed to unmarshal JSON: %v", err) - } - - if len(assetDeleteInput.ID) == 0 { - return fmt.Errorf("assetID field must be a non-empty string") - } - - // Verify that the client is submitting request to peer in their organization - err = verifyClientOrgMatchesPeerOrg(ctx) - if err != nil { - return fmt.Errorf("DeleteAsset cannot be performed: Error %v", err) - } - - log.Printf("Deleting Asset: %v", assetDeleteInput.ID) - valAsbytes, err := ctx.GetStub().GetPrivateData(assetCollection, assetDeleteInput.ID) //get the asset from chaincode state - if err != nil { - return fmt.Errorf("failed to read asset: %v", err) - } - if valAsbytes == nil { - return fmt.Errorf("asset not found: %v", assetDeleteInput.ID) - } - - ownerCollection, err := getCollectionName(ctx) // Get owners collection - if err != nil { - return fmt.Errorf("failed to infer private collection name for the org: %v", err) - } - - // Check the asset is in the caller org's private collection - valAsbytes, err = ctx.GetStub().GetPrivateData(ownerCollection, assetDeleteInput.ID) - if err != nil { - return fmt.Errorf("failed to read asset from owner's Collection: %v", err) - } - if valAsbytes == nil { - return fmt.Errorf("asset not found in owner's private Collection %v: %v", ownerCollection, assetDeleteInput.ID) - } - - // delete the asset from state - err = ctx.GetStub().DelPrivateData(assetCollection, assetDeleteInput.ID) - if err != nil { - return fmt.Errorf("failed to delete state: %v", err) - } - - // Finally, delete private details of asset - err = ctx.GetStub().DelPrivateData(ownerCollection, assetDeleteInput.ID) - if err != nil { - return err - } - - return nil - -} - -// PurgeAsset can be used by the owner of the asset to delete the asset -// Trigger removal of the asset -func (s *SmartContract) PurgeAsset(ctx contractapi.TransactionContextInterface) error { - - transientMap, err := ctx.GetStub().GetTransient() - if err != nil { - return fmt.Errorf("Error getting transient: %v", err) - } - - // Asset properties are private, therefore they get passed in transient field - transientDeleteJSON, ok := transientMap["asset_purge"] - if !ok { - return fmt.Errorf("asset to purge not found in the transient map") - } - - type assetPurge struct { - ID string `json:"assetID"` - } - - var assetPurgeInput assetPurge - err = json.Unmarshal(transientDeleteJSON, &assetPurgeInput) - if err != nil { - return fmt.Errorf("failed to unmarshal JSON: %v", err) - } - - if len(assetPurgeInput.ID) == 0 { - return fmt.Errorf("assetID field must be a non-empty string") - } - - // Verify that the client is submitting request to peer in their organization - err = verifyClientOrgMatchesPeerOrg(ctx) - if err != nil { - return fmt.Errorf("PurgeAsset cannot be performed: Error %v", err) - } - - log.Printf("Purging Asset: %v", assetPurgeInput.ID) - - // Note that there is no check here to see if the id exist; it might have been 'deleted' already - // so a check here is pointless. We would need to call purge irrespective of the result - // A delete can be called before purge, but is not essential - - ownerCollection, err := getCollectionName(ctx) // Get owners collection - if err != nil { - return fmt.Errorf("failed to infer private collection name for the org: %v", err) - } - - // delete the asset from state - err = ctx.GetStub().PurgePrivateData(assetCollection, assetPurgeInput.ID) - if err != nil { - return fmt.Errorf("failed to purge state from asset collection: %v", err) - } - - // Finally, delete private details of asset - err = ctx.GetStub().PurgePrivateData(ownerCollection, assetPurgeInput.ID) - if err != nil { - return fmt.Errorf("failed to purge state from owner collection: %v", err) - } - - return nil - -} - -// DeleteTranferAgreement can be used by the buyer to withdraw a proposal from -// the asset collection and from his own collection. -func (s *SmartContract) DeleteTranferAgreement(ctx contractapi.TransactionContextInterface) error { - - transientMap, err := ctx.GetStub().GetTransient() - if err != nil { - return fmt.Errorf("error getting transient: %v", err) - } - - // Asset properties are private, therefore they get passed in transient field - transientDeleteJSON, ok := transientMap["agreement_delete"] - if !ok { - return fmt.Errorf("asset to delete not found in the transient map") - } - - type assetDelete struct { - ID string `json:"assetID"` - } - - var assetDeleteInput assetDelete - err = json.Unmarshal(transientDeleteJSON, &assetDeleteInput) - if err != nil { - return fmt.Errorf("failed to unmarshal JSON: %v", err) - } - - if len(assetDeleteInput.ID) == 0 { - return fmt.Errorf("transient input ID field must be a non-empty string") - } - - // Verify that the client is submitting request to peer in their organization - err = verifyClientOrgMatchesPeerOrg(ctx) - if err != nil { - return fmt.Errorf("DeleteTranferAgreement cannot be performed: Error %v", err) - } - // Delete private details of agreement - orgCollection, err := getCollectionName(ctx) // Get proposers collection. - if err != nil { - return fmt.Errorf("failed to infer private collection name for the org: %v", err) - } - tranferAgreeKey, err := ctx.GetStub().CreateCompositeKey(transferAgreementObjectType, []string{assetDeleteInput. - ID}) // Create composite key - if err != nil { - return fmt.Errorf("failed to create composite key: %v", err) - } - - valAsbytes, err := ctx.GetStub().GetPrivateData(assetCollection, tranferAgreeKey) //get the transfer_agreement - if err != nil { - return fmt.Errorf("failed to read transfer_agreement: %v", err) - } - if valAsbytes == nil { - return fmt.Errorf("asset's transfer_agreement does not exist: %v", assetDeleteInput.ID) - } - - log.Printf("Deleting TranferAgreement: %v", assetDeleteInput.ID) - err = ctx.GetStub().DelPrivateData(orgCollection, assetDeleteInput.ID) // Delete the asset - if err != nil { - return err - } - - // Delete transfer agreement record - err = ctx.GetStub().DelPrivateData(assetCollection, tranferAgreeKey) // remove agreement from state - if err != nil { - return err - } - - return nil - -} - -// getCollectionName is an internal helper function to get collection of submitting client identity. -func getCollectionName(ctx contractapi.TransactionContextInterface) (string, error) { - - // Get the MSP ID of submitting client identity - clientMSPID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return "", fmt.Errorf("failed to get verified MSPID: %v", err) - } - - // Create the collection name - orgCollection := clientMSPID + "PrivateCollection" - - return orgCollection, nil -} - -// verifyClientOrgMatchesPeerOrg is an internal function used verify client org id and matches peer org id. -func verifyClientOrgMatchesPeerOrg(ctx contractapi.TransactionContextInterface) error { - clientMSPID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed getting the client's MSPID: %v", err) - } - peerMSPID, err := shim.GetMSPID() - if err != nil { - return fmt.Errorf("failed getting the peer's MSPID: %v", err) - } - - if clientMSPID != peerMSPID { - return fmt.Errorf("client from org %v is not authorized to read or write private data from an org %v peer", clientMSPID, peerMSPID) - } - - return nil -} - -func submittingClientIdentity(ctx contractapi.TransactionContextInterface) (string, error) { - b64ID, err := ctx.GetClientIdentity().GetID() - if err != nil { - return "", fmt.Errorf("Failed to read clientID: %v", err) - } - decodeID, err := base64.StdEncoding.DecodeString(b64ID) - if err != nil { - return "", fmt.Errorf("failed to base64 decode clientID: %v", err) - } - return string(decodeID), nil -} diff --git a/asset-transfer-private-data/chaincode-go/chaincode/asset_transfer_test.go b/asset-transfer-private-data/chaincode-go/chaincode/asset_transfer_test.go deleted file mode 100644 index 6eaf338d..00000000 --- a/asset-transfer-private-data/chaincode-go/chaincode/asset_transfer_test.go +++ /dev/null @@ -1,445 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ -package chaincode_test - -import ( - "encoding/base64" - "encoding/json" - "os" - "testing" - - "github.com/hyperledger/fabric-chaincode-go/v2/pkg/cid" - "github.com/hyperledger/fabric-chaincode-go/v2/shim" - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" - - "github.com/hyperledger/fabric-samples/asset-transfer-private-data/chaincode-go/chaincode" - "github.com/hyperledger/fabric-samples/asset-transfer-private-data/chaincode-go/chaincode/mocks" - "github.com/stretchr/testify/require" -) - -/* -These unit tests use mocks to simulate chaincode-api & fabric interactions -The mocks are generated using counterfeiter directives in the comments (starting with "go:generate counterfeiter") -All files in mocks/* are generated by running following, in the directory with your directive: - `go generate` -*/ - -//go:generate counterfeiter -o mocks/transaction.go -fake-name TransactionContext . transactionContext -type transactionContext interface { - contractapi.TransactionContextInterface -} - -//go:generate counterfeiter -o mocks/chaincodestub.go -fake-name ChaincodeStub . chaincodeStub -type chaincodeStub interface { - shim.ChaincodeStubInterface -} - -//go:generate counterfeiter -o mocks/statequeryiterator.go -fake-name StateQueryIterator . stateQueryIterator -type stateQueryIterator interface { - shim.StateQueryIteratorInterface -} - -//go:generate counterfeiter -o mocks/clientIdentity.go -fake-name ClientIdentity . clientIdentity -type clientIdentity interface { - cid.ClientIdentity -} - -const assetCollectionName = "assetCollection" -const transferAgreementObjectType = "transferAgreement" -const myOrg1Msp = "Org1Testmsp" -const myOrg1Clientid = "myOrg1Userid" -const myOrg1PrivCollection = "Org1TestmspPrivateCollection" -const myOrg2Msp = "Org2Testmsp" -const myOrg2Clientid = "myOrg2Userid" -const myOrg2PrivCollection = "Org2TestmspPrivateCollection" - -type assetTransientInput struct { - Type string `json:"objectType"` - ID string `json:"assetID"` - Color string `json:"color"` - Size int `json:"size"` - AppraisedValue int `json:"appraisedValue"` -} - -type assetTransferTransientInput struct { - ID string `json:"assetID"` - BuyerMSP string `json:"buyerMSP"` -} - -func TestCreateAssetBadInput(t *testing.T) { - transactionContext, chaincodeStub := prepMocksAsOrg1() - assetTransferCC := chaincode.SmartContract{} - - // No transient map - err := assetTransferCC.CreateAsset(transactionContext) - require.EqualError(t, err, "asset not found in the transient map input") - - // transient map with incomplete asset data - assetPropMap := map[string][]byte{ - "asset_properties": []byte("ill formatted property"), - } - chaincodeStub.GetTransientReturns(assetPropMap, nil) - err = assetTransferCC.CreateAsset(transactionContext) - require.Error(t, err, "Expected error: transient map with incomplete asset data") - require.Contains(t, err.Error(), "failed to unmarshal JSON") - - testAsset := &assetTransientInput{ - Type: "testfulasset", - } - setReturnAssetPropsInTransientMap(t, chaincodeStub, testAsset) - err = assetTransferCC.CreateAsset(transactionContext) - require.EqualError(t, err, "assetID field must be a non-empty string") - - testAsset = &assetTransientInput{ - ID: "id1", - Color: "gray", - } - setReturnAssetPropsInTransientMap(t, chaincodeStub, testAsset) - err = assetTransferCC.CreateAsset(transactionContext) - require.EqualError(t, err, "objectType field must be a non-empty string") - - // case when asset exists, GetPrivateData returns a valid data from ledger - testAsset = &assetTransientInput{ - ID: "id1", - Type: "testfulasset", - Color: "gray", - Size: 7, - AppraisedValue: 500, - } - setReturnAssetPropsInTransientMap(t, chaincodeStub, testAsset) - chaincodeStub.GetPrivateDataReturns([]byte{}, nil) - err = assetTransferCC.CreateAsset(transactionContext) - require.EqualError(t, err, "this asset already exists: id1") -} - -func TestCreateAssetSuccessful(t *testing.T) { - transactionContext, chaincodeStub := prepMocksAsOrg1() - assetTransferCC := chaincode.SmartContract{} - testAsset := &assetTransientInput{ - ID: "id1", - Type: "testfulasset", - Color: "gray", - Size: 7, - AppraisedValue: 500, - } - setReturnAssetPropsInTransientMap(t, chaincodeStub, testAsset) - err := assetTransferCC.CreateAsset(transactionContext) - require.NoError(t, err) - // Validate PutPrivateData calls - calledCollection, calledId, _ := chaincodeStub.PutPrivateDataArgsForCall(0) - require.Equal(t, assetCollectionName, calledCollection) - require.Equal(t, "id1", calledId) - - expectedPrivateDetails := &chaincode.AssetPrivateDetails{ - ID: "id1", - AppraisedValue: 500, - } - assetBytes, err := json.Marshal(expectedPrivateDetails) - calledCollection, calledId, calledAssetBytes := chaincodeStub.PutPrivateDataArgsForCall(1) - require.Equal(t, myOrg1PrivCollection, calledCollection) - require.Equal(t, "id1", calledId) - require.Equal(t, assetBytes, calledAssetBytes) -} - -func TestAgreeToTransferBadInput(t *testing.T) { - transactionContext, chaincodeStub := prepMocksAsOrg1() - assetTransferCC := chaincode.SmartContract{} - - assetPrivDetail := &chaincode.AssetPrivateDetails{ - ID: "id1", - // no AppraisedValue - } - setReturnAssetPrivateDetailsInTransientMap(t, chaincodeStub, assetPrivDetail) - origAsset := chaincode.Asset{ - ID: "id1", - Type: "testfulasset", - Color: "gray", - Size: 7, - Owner: myOrg1Clientid, - } - setReturnPrivateDataInStub(t, chaincodeStub, &origAsset) - - err := assetTransferCC.AgreeToTransfer(transactionContext) - require.EqualError(t, err, "appraisedValue field must be a positive integer") - - assetPrivDetail = &chaincode.AssetPrivateDetails{ - // no ID - AppraisedValue: 500, - } - setReturnAssetPrivateDetailsInTransientMap(t, chaincodeStub, assetPrivDetail) - err = assetTransferCC.AgreeToTransfer(transactionContext) - require.EqualError(t, err, "assetID field must be a non-empty string") - - assetPrivDetail = &chaincode.AssetPrivateDetails{ - ID: "id1", - AppraisedValue: 500, - } - setReturnAssetPrivateDetailsInTransientMap(t, chaincodeStub, assetPrivDetail) - // asset does not exist - setReturnPrivateDataInStub(t, chaincodeStub, nil) - err = assetTransferCC.AgreeToTransfer(transactionContext) - require.EqualError(t, err, "id1 does not exist") -} - -func TestAgreeToTransferSuccessful(t *testing.T) { - transactionContext, chaincodeStub := prepMocksAsOrg1() - assetTransferCC := chaincode.SmartContract{} - assetPrivDetail := &chaincode.AssetPrivateDetails{ - ID: "id1", - AppraisedValue: 500, - } - setReturnAssetPrivateDetailsInTransientMap(t, chaincodeStub, assetPrivDetail) - origAsset := chaincode.Asset{ - ID: "id1", - Type: "testfulasset", - Color: "gray", - Size: 7, - Owner: myOrg1Clientid, - } - setReturnPrivateDataInStub(t, chaincodeStub, &origAsset) - chaincodeStub.CreateCompositeKeyReturns(transferAgreementObjectType+"id1", nil) - err := assetTransferCC.AgreeToTransfer(transactionContext) - require.NoError(t, err) - - expectedDataBytes, err := json.Marshal(assetPrivDetail) - calledCollection, calledId, calledWithDataBytes := chaincodeStub.PutPrivateDataArgsForCall(0) - require.Equal(t, myOrg1PrivCollection, calledCollection) - require.Equal(t, "id1", calledId) - require.Equal(t, expectedDataBytes, calledWithDataBytes) - - calledCollection, calledId, calledWithDataBytes = chaincodeStub.PutPrivateDataArgsForCall(1) - require.Equal(t, assetCollectionName, calledCollection) - require.Equal(t, transferAgreementObjectType+"id1", calledId) - require.Equal(t, []byte(myOrg1Clientid), calledWithDataBytes) -} -func TestTransferAssetBadInput(t *testing.T) { - transactionContext, chaincodeStub := prepMocksAsOrg1() - assetTransferCC := chaincode.SmartContract{} - - assetNewOwner := &assetTransferTransientInput{ - ID: "id1", - BuyerMSP: "", - } - setReturnAssetOwnerInTransientMap(t, chaincodeStub, assetNewOwner) - setReturnPrivateDataInStub(t, chaincodeStub, &chaincode.Asset{}) - err := assetTransferCC.TransferAsset(transactionContext) - require.EqualError(t, err, "buyerMSP field must be a non-empty string") - - assetNewOwner = &assetTransferTransientInput{ - ID: "id1", - BuyerMSP: myOrg2Msp, - } - setReturnAssetOwnerInTransientMap(t, chaincodeStub, assetNewOwner) - // asset does not exist - setReturnPrivateDataInStub(t, chaincodeStub, nil) - err = assetTransferCC.TransferAsset(transactionContext) - require.EqualError(t, err, "id1 does not exist") -} - -func TestTransferAssetSuccessful(t *testing.T) { - transactionContext, chaincodeStub := prepMocksAsOrg1() - assetTransferCC := chaincode.SmartContract{} - assetNewOwner := &assetTransferTransientInput{ - ID: "id1", - BuyerMSP: myOrg2Msp, - } - setReturnAssetOwnerInTransientMap(t, chaincodeStub, assetNewOwner) - origAsset := chaincode.Asset{ - ID: "id1", - Type: "testfulasset", - Color: "gray", - Size: 7, - Owner: myOrg1Clientid, - } - setReturnPrivateDataInStub(t, chaincodeStub, &origAsset) - // to ensure we pass data hash verification - chaincodeStub.GetPrivateDataHashReturns([]byte("datahash"), nil) - // to ensure that ReadTransferAgreement call returns org2 client ID - chaincodeStub.GetPrivateDataReturnsOnCall(1, []byte(myOrg2Clientid), nil) - chaincodeStub.CreateCompositeKeyReturns(transferAgreementObjectType+"id1", nil) - - err := assetTransferCC.TransferAsset(transactionContext) - require.NoError(t, err) - // Validate PutPrivateData calls - expectedNewAsset := origAsset - expectedNewAsset.Owner = myOrg2Clientid - expectedNewAssetBytes, err := json.Marshal(expectedNewAsset) - require.NoError(t, err) - calledCollection, calledId, calledWithAssetBytes := chaincodeStub.PutPrivateDataArgsForCall(0) - require.Equal(t, assetCollectionName, calledCollection) - require.Equal(t, "id1", calledId) - require.Equal(t, expectedNewAssetBytes, calledWithAssetBytes) - calledCollection, calledId = chaincodeStub.DelPrivateDataArgsForCall(0) - require.Equal(t, myOrg1PrivCollection, calledCollection) - require.Equal(t, "id1", calledId) - - calledCollection, calledId = chaincodeStub.DelPrivateDataArgsForCall(1) - require.Equal(t, assetCollectionName, calledCollection) - require.Equal(t, transferAgreementObjectType+"id1", calledId) - -} - -func TestTransferAssetByNonOwner(t *testing.T) { - transactionContext, chaincodeStub := prepMocksAsOrg1() - assetTransferCC := chaincode.SmartContract{} - assetNewOwner := &assetTransferTransientInput{ - ID: "id1", - BuyerMSP: myOrg1Msp, - } - setReturnAssetOwnerInTransientMap(t, chaincodeStub, assetNewOwner) - // Try to transfer asset owned by Org2 - org2Asset := chaincode.Asset{ - ID: "id1", - Type: "testfulasset", - Color: "gray", - Size: 7, - Owner: myOrg2Clientid, - } - setReturnPrivateDataInStub(t, chaincodeStub, &org2Asset) - err := assetTransferCC.TransferAsset(transactionContext) - require.EqualError(t, err, "failed transfer verification: error: submitting client identity does not own asset") -} - -func TestTransferAssetWithoutAnAgreement(t *testing.T) { - transactionContext, chaincodeStub := prepMocksAsOrg1() - assetTransferCC := chaincode.SmartContract{} - assetNewOwner := &assetTransferTransientInput{ - ID: "id1", - BuyerMSP: myOrg1Msp, - } - setReturnAssetOwnerInTransientMap(t, chaincodeStub, assetNewOwner) - orgAsset := chaincode.Asset{ - ID: "id1", - Type: "testfulasset", - Color: "gray", - Size: 7, - Owner: myOrg1Clientid, - } - setReturnPrivateDataInStub(t, chaincodeStub, &orgAsset) - // to ensure we pass data hash verification - chaincodeStub.GetPrivateDataHashReturns([]byte("datahash"), nil) - chaincodeStub.CreateCompositeKeyReturns(transferAgreementObjectType+"id1", nil) - // ReadTransferAgreement call returns no buyer client ID - chaincodeStub.GetPrivateDataReturnsOnCall(1, []byte{}, nil) - - err := assetTransferCC.TransferAsset(transactionContext) - require.EqualError(t, err, "BuyerID not found in TransferAgreement for id1") -} - -func TestTransferAssetNonMatchingAppraisalValue(t *testing.T) { - transactionContext, chaincodeStub := prepMocksAsOrg1() - assetTransferCC := chaincode.SmartContract{} - assetNewOwner := &assetTransferTransientInput{ - ID: "id1", - BuyerMSP: myOrg2Msp, - } - setReturnAssetOwnerInTransientMap(t, chaincodeStub, assetNewOwner) - - orgAsset := chaincode.Asset{ - ID: "id1", - Type: "testfulasset", - Color: "gray", - Size: 7, - Owner: myOrg1Clientid, - } - setReturnPrivateDataInStub(t, chaincodeStub, &orgAsset) - chaincodeStub.CreateCompositeKeyReturns(transferAgreementObjectType+"id1", nil) - // data hash different in each collection - chaincodeStub.GetPrivateDataHashReturnsOnCall(0, []byte("datahash1"), nil) - chaincodeStub.GetPrivateDataHashReturnsOnCall(1, []byte("datahash2"), nil) - - err := assetTransferCC.TransferAsset(transactionContext) - require.Error(t, err, "Expected failed hash verification") - require.Contains(t, err.Error(), "failed transfer verification: hash for appraised value") -} - -func prepMocksAsOrg1() (*mocks.TransactionContext, *mocks.ChaincodeStub) { - return prepMocks(myOrg1Msp, myOrg1Clientid) -} -func prepMocksAsOrg2() (*mocks.TransactionContext, *mocks.ChaincodeStub) { - return prepMocks(myOrg2Msp, myOrg2Clientid) -} -func prepMocks(orgMSP, clientId string) (*mocks.TransactionContext, *mocks.ChaincodeStub) { - chaincodeStub := &mocks.ChaincodeStub{} - transactionContext := &mocks.TransactionContext{} - transactionContext.GetStubReturns(chaincodeStub) - - clientIdentity := &mocks.ClientIdentity{} - clientIdentity.GetMSPIDReturns(orgMSP, nil) - clientIdentity.GetIDReturns(base64.StdEncoding.EncodeToString([]byte(clientId)), nil) - // set matching msp ID using peer shim env variable - os.Setenv("CORE_PEER_LOCALMSPID", orgMSP) - transactionContext.GetClientIdentityReturns(clientIdentity) - return transactionContext, chaincodeStub -} - -func setReturnAssetPrivateDetailsInTransientMap(t *testing.T, chaincodeStub *mocks.ChaincodeStub, assetPrivDetail *chaincode.AssetPrivateDetails) []byte { - assetOwnerBytes := []byte{} - if assetPrivDetail != nil { - var err error - assetOwnerBytes, err = json.Marshal(assetPrivDetail) - require.NoError(t, err) - } - assetPropMap := map[string][]byte{ - "asset_value": assetOwnerBytes, - } - chaincodeStub.GetTransientReturns(assetPropMap, nil) - return assetOwnerBytes -} - -func setReturnAssetOwnerInTransientMap(t *testing.T, chaincodeStub *mocks.ChaincodeStub, assetOwner *assetTransferTransientInput) []byte { - assetOwnerBytes := []byte{} - if assetOwner != nil { - var err error - assetOwnerBytes, err = json.Marshal(assetOwner) - require.NoError(t, err) - } - assetPropMap := map[string][]byte{ - "asset_owner": assetOwnerBytes, - } - chaincodeStub.GetTransientReturns(assetPropMap, nil) - return assetOwnerBytes -} - -func setReturnAssetPropsInTransientMap(t *testing.T, chaincodeStub *mocks.ChaincodeStub, testAsset *assetTransientInput) []byte { - assetBytes := []byte{} - if testAsset != nil { - var err error - assetBytes, err = json.Marshal(testAsset) - require.NoError(t, err) - } - assetPropMap := map[string][]byte{ - "asset_properties": assetBytes, - } - chaincodeStub.GetTransientReturns(assetPropMap, nil) - return assetBytes -} - -func setReturnPrivateDataInStub(t *testing.T, chaincodeStub *mocks.ChaincodeStub, testAsset *chaincode.Asset) []byte { - if testAsset == nil { - chaincodeStub.GetPrivateDataReturns(nil, nil) - return nil - } else { - var err error - assetBytes, err := json.Marshal(testAsset) - require.NoError(t, err) - chaincodeStub.GetPrivateDataReturns(assetBytes, nil) - return assetBytes - } -} - -func setReturnAssetPrivateDetailsInStub(t *testing.T, chaincodeStub *mocks.ChaincodeStub, testAsset *chaincode.AssetPrivateDetails) []byte { - if testAsset == nil { - chaincodeStub.GetPrivateDataReturns(nil, nil) - return nil - } else { - var err error - assetBytes, err := json.Marshal(testAsset) - require.NoError(t, err) - chaincodeStub.GetPrivateDataReturns(assetBytes, nil) - return assetBytes - } -} diff --git a/asset-transfer-private-data/chaincode-go/chaincode/mocks/chaincodestub.go b/asset-transfer-private-data/chaincode-go/chaincode/mocks/chaincodestub.go deleted file mode 100644 index 06248e33..00000000 --- a/asset-transfer-private-data/chaincode-go/chaincode/mocks/chaincodestub.go +++ /dev/null @@ -1,2991 +0,0 @@ -// Code generated by counterfeiter. DO NOT EDIT. -package mocks - -import ( - "sync" - - "github.com/hyperledger/fabric-chaincode-go/v2/shim" - "github.com/hyperledger/fabric-protos-go-apiv2/peer" - "google.golang.org/protobuf/types/known/timestamppb" -) - -type ChaincodeStub struct { - CreateCompositeKeyStub func(string, []string) (string, error) - createCompositeKeyMutex sync.RWMutex - createCompositeKeyArgsForCall []struct { - arg1 string - arg2 []string - } - createCompositeKeyReturns struct { - result1 string - result2 error - } - createCompositeKeyReturnsOnCall map[int]struct { - result1 string - result2 error - } - DelPrivateDataStub func(string, string) error - delPrivateDataMutex sync.RWMutex - delPrivateDataArgsForCall []struct { - arg1 string - arg2 string - } - delPrivateDataReturns struct { - result1 error - } - delPrivateDataReturnsOnCall map[int]struct { - result1 error - } - DelStateStub func(string) error - delStateMutex sync.RWMutex - delStateArgsForCall []struct { - arg1 string - } - delStateReturns struct { - result1 error - } - delStateReturnsOnCall map[int]struct { - result1 error - } - GetArgsStub func() [][]byte - getArgsMutex sync.RWMutex - getArgsArgsForCall []struct { - } - getArgsReturns struct { - result1 [][]byte - } - getArgsReturnsOnCall map[int]struct { - result1 [][]byte - } - GetArgsSliceStub func() ([]byte, error) - getArgsSliceMutex sync.RWMutex - getArgsSliceArgsForCall []struct { - } - getArgsSliceReturns struct { - result1 []byte - result2 error - } - getArgsSliceReturnsOnCall map[int]struct { - result1 []byte - result2 error - } - GetBindingStub func() ([]byte, error) - getBindingMutex sync.RWMutex - getBindingArgsForCall []struct { - } - getBindingReturns struct { - result1 []byte - result2 error - } - getBindingReturnsOnCall map[int]struct { - result1 []byte - result2 error - } - GetChannelIDStub func() string - getChannelIDMutex sync.RWMutex - getChannelIDArgsForCall []struct { - } - getChannelIDReturns struct { - result1 string - } - getChannelIDReturnsOnCall map[int]struct { - result1 string - } - GetCreatorStub func() ([]byte, error) - getCreatorMutex sync.RWMutex - getCreatorArgsForCall []struct { - } - getCreatorReturns struct { - result1 []byte - result2 error - } - getCreatorReturnsOnCall map[int]struct { - result1 []byte - result2 error - } - GetDecorationsStub func() map[string][]byte - getDecorationsMutex sync.RWMutex - getDecorationsArgsForCall []struct { - } - getDecorationsReturns struct { - result1 map[string][]byte - } - getDecorationsReturnsOnCall map[int]struct { - result1 map[string][]byte - } - GetFunctionAndParametersStub func() (string, []string) - getFunctionAndParametersMutex sync.RWMutex - getFunctionAndParametersArgsForCall []struct { - } - getFunctionAndParametersReturns struct { - result1 string - result2 []string - } - getFunctionAndParametersReturnsOnCall map[int]struct { - result1 string - result2 []string - } - GetHistoryForKeyStub func(string) (shim.HistoryQueryIteratorInterface, error) - getHistoryForKeyMutex sync.RWMutex - getHistoryForKeyArgsForCall []struct { - arg1 string - } - getHistoryForKeyReturns struct { - result1 shim.HistoryQueryIteratorInterface - result2 error - } - getHistoryForKeyReturnsOnCall map[int]struct { - result1 shim.HistoryQueryIteratorInterface - result2 error - } - GetPrivateDataStub func(string, string) ([]byte, error) - getPrivateDataMutex sync.RWMutex - getPrivateDataArgsForCall []struct { - arg1 string - arg2 string - } - getPrivateDataReturns struct { - result1 []byte - result2 error - } - getPrivateDataReturnsOnCall map[int]struct { - result1 []byte - result2 error - } - GetPrivateDataByPartialCompositeKeyStub func(string, string, []string) (shim.StateQueryIteratorInterface, error) - getPrivateDataByPartialCompositeKeyMutex sync.RWMutex - getPrivateDataByPartialCompositeKeyArgsForCall []struct { - arg1 string - arg2 string - arg3 []string - } - getPrivateDataByPartialCompositeKeyReturns struct { - result1 shim.StateQueryIteratorInterface - result2 error - } - getPrivateDataByPartialCompositeKeyReturnsOnCall map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 error - } - GetPrivateDataByRangeStub func(string, string, string) (shim.StateQueryIteratorInterface, error) - getPrivateDataByRangeMutex sync.RWMutex - getPrivateDataByRangeArgsForCall []struct { - arg1 string - arg2 string - arg3 string - } - getPrivateDataByRangeReturns struct { - result1 shim.StateQueryIteratorInterface - result2 error - } - getPrivateDataByRangeReturnsOnCall map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 error - } - GetPrivateDataHashStub func(string, string) ([]byte, error) - getPrivateDataHashMutex sync.RWMutex - getPrivateDataHashArgsForCall []struct { - arg1 string - arg2 string - } - getPrivateDataHashReturns struct { - result1 []byte - result2 error - } - getPrivateDataHashReturnsOnCall map[int]struct { - result1 []byte - result2 error - } - GetPrivateDataQueryResultStub func(string, string) (shim.StateQueryIteratorInterface, error) - getPrivateDataQueryResultMutex sync.RWMutex - getPrivateDataQueryResultArgsForCall []struct { - arg1 string - arg2 string - } - getPrivateDataQueryResultReturns struct { - result1 shim.StateQueryIteratorInterface - result2 error - } - getPrivateDataQueryResultReturnsOnCall map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 error - } - GetPrivateDataValidationParameterStub func(string, string) ([]byte, error) - getPrivateDataValidationParameterMutex sync.RWMutex - getPrivateDataValidationParameterArgsForCall []struct { - arg1 string - arg2 string - } - getPrivateDataValidationParameterReturns struct { - result1 []byte - result2 error - } - getPrivateDataValidationParameterReturnsOnCall map[int]struct { - result1 []byte - result2 error - } - GetQueryResultStub func(string) (shim.StateQueryIteratorInterface, error) - getQueryResultMutex sync.RWMutex - getQueryResultArgsForCall []struct { - arg1 string - } - getQueryResultReturns struct { - result1 shim.StateQueryIteratorInterface - result2 error - } - getQueryResultReturnsOnCall map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 error - } - GetQueryResultWithPaginationStub func(string, int32, string) (shim.StateQueryIteratorInterface, *peer.QueryResponseMetadata, error) - getQueryResultWithPaginationMutex sync.RWMutex - getQueryResultWithPaginationArgsForCall []struct { - arg1 string - arg2 int32 - arg3 string - } - getQueryResultWithPaginationReturns struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - } - getQueryResultWithPaginationReturnsOnCall map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - } - GetSignedProposalStub func() (*peer.SignedProposal, error) - getSignedProposalMutex sync.RWMutex - getSignedProposalArgsForCall []struct { - } - getSignedProposalReturns struct { - result1 *peer.SignedProposal - result2 error - } - getSignedProposalReturnsOnCall map[int]struct { - result1 *peer.SignedProposal - result2 error - } - GetStateStub func(string) ([]byte, error) - getStateMutex sync.RWMutex - getStateArgsForCall []struct { - arg1 string - } - getStateReturns struct { - result1 []byte - result2 error - } - getStateReturnsOnCall map[int]struct { - result1 []byte - result2 error - } - GetStateByPartialCompositeKeyStub func(string, []string) (shim.StateQueryIteratorInterface, error) - getStateByPartialCompositeKeyMutex sync.RWMutex - getStateByPartialCompositeKeyArgsForCall []struct { - arg1 string - arg2 []string - } - getStateByPartialCompositeKeyReturns struct { - result1 shim.StateQueryIteratorInterface - result2 error - } - getStateByPartialCompositeKeyReturnsOnCall map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 error - } - GetStateByPartialCompositeKeyWithPaginationStub func(string, []string, int32, string) (shim.StateQueryIteratorInterface, *peer.QueryResponseMetadata, error) - getStateByPartialCompositeKeyWithPaginationMutex sync.RWMutex - getStateByPartialCompositeKeyWithPaginationArgsForCall []struct { - arg1 string - arg2 []string - arg3 int32 - arg4 string - } - getStateByPartialCompositeKeyWithPaginationReturns struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - } - getStateByPartialCompositeKeyWithPaginationReturnsOnCall map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - } - GetStateByRangeStub func(string, string) (shim.StateQueryIteratorInterface, error) - getStateByRangeMutex sync.RWMutex - getStateByRangeArgsForCall []struct { - arg1 string - arg2 string - } - getStateByRangeReturns struct { - result1 shim.StateQueryIteratorInterface - result2 error - } - getStateByRangeReturnsOnCall map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 error - } - GetStateByRangeWithPaginationStub func(string, string, int32, string) (shim.StateQueryIteratorInterface, *peer.QueryResponseMetadata, error) - getStateByRangeWithPaginationMutex sync.RWMutex - getStateByRangeWithPaginationArgsForCall []struct { - arg1 string - arg2 string - arg3 int32 - arg4 string - } - getStateByRangeWithPaginationReturns struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - } - getStateByRangeWithPaginationReturnsOnCall map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - } - GetStateValidationParameterStub func(string) ([]byte, error) - getStateValidationParameterMutex sync.RWMutex - getStateValidationParameterArgsForCall []struct { - arg1 string - } - getStateValidationParameterReturns struct { - result1 []byte - result2 error - } - getStateValidationParameterReturnsOnCall map[int]struct { - result1 []byte - result2 error - } - GetStringArgsStub func() []string - getStringArgsMutex sync.RWMutex - getStringArgsArgsForCall []struct { - } - getStringArgsReturns struct { - result1 []string - } - getStringArgsReturnsOnCall map[int]struct { - result1 []string - } - GetTransientStub func() (map[string][]byte, error) - getTransientMutex sync.RWMutex - getTransientArgsForCall []struct { - } - getTransientReturns struct { - result1 map[string][]byte - result2 error - } - getTransientReturnsOnCall map[int]struct { - result1 map[string][]byte - result2 error - } - GetTxIDStub func() string - getTxIDMutex sync.RWMutex - getTxIDArgsForCall []struct { - } - getTxIDReturns struct { - result1 string - } - getTxIDReturnsOnCall map[int]struct { - result1 string - } - GetTxTimestampStub func() (*timestamppb.Timestamp, error) - getTxTimestampMutex sync.RWMutex - getTxTimestampArgsForCall []struct { - } - getTxTimestampReturns struct { - result1 *timestamppb.Timestamp - result2 error - } - getTxTimestampReturnsOnCall map[int]struct { - result1 *timestamppb.Timestamp - result2 error - } - InvokeChaincodeStub func(string, [][]byte, string) *peer.Response - invokeChaincodeMutex sync.RWMutex - invokeChaincodeArgsForCall []struct { - arg1 string - arg2 [][]byte - arg3 string - } - invokeChaincodeReturns struct { - result1 *peer.Response - } - invokeChaincodeReturnsOnCall map[int]struct { - result1 *peer.Response - } - PurgePrivateDataStub func(string, string) error - purgePrivateDataMutex sync.RWMutex - purgePrivateDataArgsForCall []struct { - arg1 string - arg2 string - } - purgePrivateDataReturns struct { - result1 error - } - purgePrivateDataReturnsOnCall map[int]struct { - result1 error - } - PutPrivateDataStub func(string, string, []byte) error - putPrivateDataMutex sync.RWMutex - putPrivateDataArgsForCall []struct { - arg1 string - arg2 string - arg3 []byte - } - putPrivateDataReturns struct { - result1 error - } - putPrivateDataReturnsOnCall map[int]struct { - result1 error - } - PutStateStub func(string, []byte) error - putStateMutex sync.RWMutex - putStateArgsForCall []struct { - arg1 string - arg2 []byte - } - putStateReturns struct { - result1 error - } - putStateReturnsOnCall map[int]struct { - result1 error - } - SetEventStub func(string, []byte) error - setEventMutex sync.RWMutex - setEventArgsForCall []struct { - arg1 string - arg2 []byte - } - setEventReturns struct { - result1 error - } - setEventReturnsOnCall map[int]struct { - result1 error - } - SetPrivateDataValidationParameterStub func(string, string, []byte) error - setPrivateDataValidationParameterMutex sync.RWMutex - setPrivateDataValidationParameterArgsForCall []struct { - arg1 string - arg2 string - arg3 []byte - } - setPrivateDataValidationParameterReturns struct { - result1 error - } - setPrivateDataValidationParameterReturnsOnCall map[int]struct { - result1 error - } - SetStateValidationParameterStub func(string, []byte) error - setStateValidationParameterMutex sync.RWMutex - setStateValidationParameterArgsForCall []struct { - arg1 string - arg2 []byte - } - setStateValidationParameterReturns struct { - result1 error - } - setStateValidationParameterReturnsOnCall map[int]struct { - result1 error - } - SplitCompositeKeyStub func(string) (string, []string, error) - splitCompositeKeyMutex sync.RWMutex - splitCompositeKeyArgsForCall []struct { - arg1 string - } - splitCompositeKeyReturns struct { - result1 string - result2 []string - result3 error - } - splitCompositeKeyReturnsOnCall map[int]struct { - result1 string - result2 []string - result3 error - } - invocations map[string][][]interface{} - invocationsMutex sync.RWMutex -} - -func (fake *ChaincodeStub) CreateCompositeKey(arg1 string, arg2 []string) (string, error) { - var arg2Copy []string - if arg2 != nil { - arg2Copy = make([]string, len(arg2)) - copy(arg2Copy, arg2) - } - fake.createCompositeKeyMutex.Lock() - ret, specificReturn := fake.createCompositeKeyReturnsOnCall[len(fake.createCompositeKeyArgsForCall)] - fake.createCompositeKeyArgsForCall = append(fake.createCompositeKeyArgsForCall, struct { - arg1 string - arg2 []string - }{arg1, arg2Copy}) - stub := fake.CreateCompositeKeyStub - fakeReturns := fake.createCompositeKeyReturns - fake.recordInvocation("CreateCompositeKey", []interface{}{arg1, arg2Copy}) - fake.createCompositeKeyMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) CreateCompositeKeyCallCount() int { - fake.createCompositeKeyMutex.RLock() - defer fake.createCompositeKeyMutex.RUnlock() - return len(fake.createCompositeKeyArgsForCall) -} - -func (fake *ChaincodeStub) CreateCompositeKeyCalls(stub func(string, []string) (string, error)) { - fake.createCompositeKeyMutex.Lock() - defer fake.createCompositeKeyMutex.Unlock() - fake.CreateCompositeKeyStub = stub -} - -func (fake *ChaincodeStub) CreateCompositeKeyArgsForCall(i int) (string, []string) { - fake.createCompositeKeyMutex.RLock() - defer fake.createCompositeKeyMutex.RUnlock() - argsForCall := fake.createCompositeKeyArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ChaincodeStub) CreateCompositeKeyReturns(result1 string, result2 error) { - fake.createCompositeKeyMutex.Lock() - defer fake.createCompositeKeyMutex.Unlock() - fake.CreateCompositeKeyStub = nil - fake.createCompositeKeyReturns = struct { - result1 string - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) CreateCompositeKeyReturnsOnCall(i int, result1 string, result2 error) { - fake.createCompositeKeyMutex.Lock() - defer fake.createCompositeKeyMutex.Unlock() - fake.CreateCompositeKeyStub = nil - if fake.createCompositeKeyReturnsOnCall == nil { - fake.createCompositeKeyReturnsOnCall = make(map[int]struct { - result1 string - result2 error - }) - } - fake.createCompositeKeyReturnsOnCall[i] = struct { - result1 string - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) DelPrivateData(arg1 string, arg2 string) error { - fake.delPrivateDataMutex.Lock() - ret, specificReturn := fake.delPrivateDataReturnsOnCall[len(fake.delPrivateDataArgsForCall)] - fake.delPrivateDataArgsForCall = append(fake.delPrivateDataArgsForCall, struct { - arg1 string - arg2 string - }{arg1, arg2}) - stub := fake.DelPrivateDataStub - fakeReturns := fake.delPrivateDataReturns - fake.recordInvocation("DelPrivateData", []interface{}{arg1, arg2}) - fake.delPrivateDataMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) DelPrivateDataCallCount() int { - fake.delPrivateDataMutex.RLock() - defer fake.delPrivateDataMutex.RUnlock() - return len(fake.delPrivateDataArgsForCall) -} - -func (fake *ChaincodeStub) DelPrivateDataCalls(stub func(string, string) error) { - fake.delPrivateDataMutex.Lock() - defer fake.delPrivateDataMutex.Unlock() - fake.DelPrivateDataStub = stub -} - -func (fake *ChaincodeStub) DelPrivateDataArgsForCall(i int) (string, string) { - fake.delPrivateDataMutex.RLock() - defer fake.delPrivateDataMutex.RUnlock() - argsForCall := fake.delPrivateDataArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ChaincodeStub) DelPrivateDataReturns(result1 error) { - fake.delPrivateDataMutex.Lock() - defer fake.delPrivateDataMutex.Unlock() - fake.DelPrivateDataStub = nil - fake.delPrivateDataReturns = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) DelPrivateDataReturnsOnCall(i int, result1 error) { - fake.delPrivateDataMutex.Lock() - defer fake.delPrivateDataMutex.Unlock() - fake.DelPrivateDataStub = nil - if fake.delPrivateDataReturnsOnCall == nil { - fake.delPrivateDataReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.delPrivateDataReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) DelState(arg1 string) error { - fake.delStateMutex.Lock() - ret, specificReturn := fake.delStateReturnsOnCall[len(fake.delStateArgsForCall)] - fake.delStateArgsForCall = append(fake.delStateArgsForCall, struct { - arg1 string - }{arg1}) - stub := fake.DelStateStub - fakeReturns := fake.delStateReturns - fake.recordInvocation("DelState", []interface{}{arg1}) - fake.delStateMutex.Unlock() - if stub != nil { - return stub(arg1) - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) DelStateCallCount() int { - fake.delStateMutex.RLock() - defer fake.delStateMutex.RUnlock() - return len(fake.delStateArgsForCall) -} - -func (fake *ChaincodeStub) DelStateCalls(stub func(string) error) { - fake.delStateMutex.Lock() - defer fake.delStateMutex.Unlock() - fake.DelStateStub = stub -} - -func (fake *ChaincodeStub) DelStateArgsForCall(i int) string { - fake.delStateMutex.RLock() - defer fake.delStateMutex.RUnlock() - argsForCall := fake.delStateArgsForCall[i] - return argsForCall.arg1 -} - -func (fake *ChaincodeStub) DelStateReturns(result1 error) { - fake.delStateMutex.Lock() - defer fake.delStateMutex.Unlock() - fake.DelStateStub = nil - fake.delStateReturns = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) DelStateReturnsOnCall(i int, result1 error) { - fake.delStateMutex.Lock() - defer fake.delStateMutex.Unlock() - fake.DelStateStub = nil - if fake.delStateReturnsOnCall == nil { - fake.delStateReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.delStateReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) GetArgs() [][]byte { - fake.getArgsMutex.Lock() - ret, specificReturn := fake.getArgsReturnsOnCall[len(fake.getArgsArgsForCall)] - fake.getArgsArgsForCall = append(fake.getArgsArgsForCall, struct { - }{}) - stub := fake.GetArgsStub - fakeReturns := fake.getArgsReturns - fake.recordInvocation("GetArgs", []interface{}{}) - fake.getArgsMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) GetArgsCallCount() int { - fake.getArgsMutex.RLock() - defer fake.getArgsMutex.RUnlock() - return len(fake.getArgsArgsForCall) -} - -func (fake *ChaincodeStub) GetArgsCalls(stub func() [][]byte) { - fake.getArgsMutex.Lock() - defer fake.getArgsMutex.Unlock() - fake.GetArgsStub = stub -} - -func (fake *ChaincodeStub) GetArgsReturns(result1 [][]byte) { - fake.getArgsMutex.Lock() - defer fake.getArgsMutex.Unlock() - fake.GetArgsStub = nil - fake.getArgsReturns = struct { - result1 [][]byte - }{result1} -} - -func (fake *ChaincodeStub) GetArgsReturnsOnCall(i int, result1 [][]byte) { - fake.getArgsMutex.Lock() - defer fake.getArgsMutex.Unlock() - fake.GetArgsStub = nil - if fake.getArgsReturnsOnCall == nil { - fake.getArgsReturnsOnCall = make(map[int]struct { - result1 [][]byte - }) - } - fake.getArgsReturnsOnCall[i] = struct { - result1 [][]byte - }{result1} -} - -func (fake *ChaincodeStub) GetArgsSlice() ([]byte, error) { - fake.getArgsSliceMutex.Lock() - ret, specificReturn := fake.getArgsSliceReturnsOnCall[len(fake.getArgsSliceArgsForCall)] - fake.getArgsSliceArgsForCall = append(fake.getArgsSliceArgsForCall, struct { - }{}) - stub := fake.GetArgsSliceStub - fakeReturns := fake.getArgsSliceReturns - fake.recordInvocation("GetArgsSlice", []interface{}{}) - fake.getArgsSliceMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetArgsSliceCallCount() int { - fake.getArgsSliceMutex.RLock() - defer fake.getArgsSliceMutex.RUnlock() - return len(fake.getArgsSliceArgsForCall) -} - -func (fake *ChaincodeStub) GetArgsSliceCalls(stub func() ([]byte, error)) { - fake.getArgsSliceMutex.Lock() - defer fake.getArgsSliceMutex.Unlock() - fake.GetArgsSliceStub = stub -} - -func (fake *ChaincodeStub) GetArgsSliceReturns(result1 []byte, result2 error) { - fake.getArgsSliceMutex.Lock() - defer fake.getArgsSliceMutex.Unlock() - fake.GetArgsSliceStub = nil - fake.getArgsSliceReturns = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetArgsSliceReturnsOnCall(i int, result1 []byte, result2 error) { - fake.getArgsSliceMutex.Lock() - defer fake.getArgsSliceMutex.Unlock() - fake.GetArgsSliceStub = nil - if fake.getArgsSliceReturnsOnCall == nil { - fake.getArgsSliceReturnsOnCall = make(map[int]struct { - result1 []byte - result2 error - }) - } - fake.getArgsSliceReturnsOnCall[i] = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetBinding() ([]byte, error) { - fake.getBindingMutex.Lock() - ret, specificReturn := fake.getBindingReturnsOnCall[len(fake.getBindingArgsForCall)] - fake.getBindingArgsForCall = append(fake.getBindingArgsForCall, struct { - }{}) - stub := fake.GetBindingStub - fakeReturns := fake.getBindingReturns - fake.recordInvocation("GetBinding", []interface{}{}) - fake.getBindingMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetBindingCallCount() int { - fake.getBindingMutex.RLock() - defer fake.getBindingMutex.RUnlock() - return len(fake.getBindingArgsForCall) -} - -func (fake *ChaincodeStub) GetBindingCalls(stub func() ([]byte, error)) { - fake.getBindingMutex.Lock() - defer fake.getBindingMutex.Unlock() - fake.GetBindingStub = stub -} - -func (fake *ChaincodeStub) GetBindingReturns(result1 []byte, result2 error) { - fake.getBindingMutex.Lock() - defer fake.getBindingMutex.Unlock() - fake.GetBindingStub = nil - fake.getBindingReturns = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetBindingReturnsOnCall(i int, result1 []byte, result2 error) { - fake.getBindingMutex.Lock() - defer fake.getBindingMutex.Unlock() - fake.GetBindingStub = nil - if fake.getBindingReturnsOnCall == nil { - fake.getBindingReturnsOnCall = make(map[int]struct { - result1 []byte - result2 error - }) - } - fake.getBindingReturnsOnCall[i] = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetChannelID() string { - fake.getChannelIDMutex.Lock() - ret, specificReturn := fake.getChannelIDReturnsOnCall[len(fake.getChannelIDArgsForCall)] - fake.getChannelIDArgsForCall = append(fake.getChannelIDArgsForCall, struct { - }{}) - stub := fake.GetChannelIDStub - fakeReturns := fake.getChannelIDReturns - fake.recordInvocation("GetChannelID", []interface{}{}) - fake.getChannelIDMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) GetChannelIDCallCount() int { - fake.getChannelIDMutex.RLock() - defer fake.getChannelIDMutex.RUnlock() - return len(fake.getChannelIDArgsForCall) -} - -func (fake *ChaincodeStub) GetChannelIDCalls(stub func() string) { - fake.getChannelIDMutex.Lock() - defer fake.getChannelIDMutex.Unlock() - fake.GetChannelIDStub = stub -} - -func (fake *ChaincodeStub) GetChannelIDReturns(result1 string) { - fake.getChannelIDMutex.Lock() - defer fake.getChannelIDMutex.Unlock() - fake.GetChannelIDStub = nil - fake.getChannelIDReturns = struct { - result1 string - }{result1} -} - -func (fake *ChaincodeStub) GetChannelIDReturnsOnCall(i int, result1 string) { - fake.getChannelIDMutex.Lock() - defer fake.getChannelIDMutex.Unlock() - fake.GetChannelIDStub = nil - if fake.getChannelIDReturnsOnCall == nil { - fake.getChannelIDReturnsOnCall = make(map[int]struct { - result1 string - }) - } - fake.getChannelIDReturnsOnCall[i] = struct { - result1 string - }{result1} -} - -func (fake *ChaincodeStub) GetCreator() ([]byte, error) { - fake.getCreatorMutex.Lock() - ret, specificReturn := fake.getCreatorReturnsOnCall[len(fake.getCreatorArgsForCall)] - fake.getCreatorArgsForCall = append(fake.getCreatorArgsForCall, struct { - }{}) - stub := fake.GetCreatorStub - fakeReturns := fake.getCreatorReturns - fake.recordInvocation("GetCreator", []interface{}{}) - fake.getCreatorMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetCreatorCallCount() int { - fake.getCreatorMutex.RLock() - defer fake.getCreatorMutex.RUnlock() - return len(fake.getCreatorArgsForCall) -} - -func (fake *ChaincodeStub) GetCreatorCalls(stub func() ([]byte, error)) { - fake.getCreatorMutex.Lock() - defer fake.getCreatorMutex.Unlock() - fake.GetCreatorStub = stub -} - -func (fake *ChaincodeStub) GetCreatorReturns(result1 []byte, result2 error) { - fake.getCreatorMutex.Lock() - defer fake.getCreatorMutex.Unlock() - fake.GetCreatorStub = nil - fake.getCreatorReturns = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetCreatorReturnsOnCall(i int, result1 []byte, result2 error) { - fake.getCreatorMutex.Lock() - defer fake.getCreatorMutex.Unlock() - fake.GetCreatorStub = nil - if fake.getCreatorReturnsOnCall == nil { - fake.getCreatorReturnsOnCall = make(map[int]struct { - result1 []byte - result2 error - }) - } - fake.getCreatorReturnsOnCall[i] = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetDecorations() map[string][]byte { - fake.getDecorationsMutex.Lock() - ret, specificReturn := fake.getDecorationsReturnsOnCall[len(fake.getDecorationsArgsForCall)] - fake.getDecorationsArgsForCall = append(fake.getDecorationsArgsForCall, struct { - }{}) - stub := fake.GetDecorationsStub - fakeReturns := fake.getDecorationsReturns - fake.recordInvocation("GetDecorations", []interface{}{}) - fake.getDecorationsMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) GetDecorationsCallCount() int { - fake.getDecorationsMutex.RLock() - defer fake.getDecorationsMutex.RUnlock() - return len(fake.getDecorationsArgsForCall) -} - -func (fake *ChaincodeStub) GetDecorationsCalls(stub func() map[string][]byte) { - fake.getDecorationsMutex.Lock() - defer fake.getDecorationsMutex.Unlock() - fake.GetDecorationsStub = stub -} - -func (fake *ChaincodeStub) GetDecorationsReturns(result1 map[string][]byte) { - fake.getDecorationsMutex.Lock() - defer fake.getDecorationsMutex.Unlock() - fake.GetDecorationsStub = nil - fake.getDecorationsReturns = struct { - result1 map[string][]byte - }{result1} -} - -func (fake *ChaincodeStub) GetDecorationsReturnsOnCall(i int, result1 map[string][]byte) { - fake.getDecorationsMutex.Lock() - defer fake.getDecorationsMutex.Unlock() - fake.GetDecorationsStub = nil - if fake.getDecorationsReturnsOnCall == nil { - fake.getDecorationsReturnsOnCall = make(map[int]struct { - result1 map[string][]byte - }) - } - fake.getDecorationsReturnsOnCall[i] = struct { - result1 map[string][]byte - }{result1} -} - -func (fake *ChaincodeStub) GetFunctionAndParameters() (string, []string) { - fake.getFunctionAndParametersMutex.Lock() - ret, specificReturn := fake.getFunctionAndParametersReturnsOnCall[len(fake.getFunctionAndParametersArgsForCall)] - fake.getFunctionAndParametersArgsForCall = append(fake.getFunctionAndParametersArgsForCall, struct { - }{}) - stub := fake.GetFunctionAndParametersStub - fakeReturns := fake.getFunctionAndParametersReturns - fake.recordInvocation("GetFunctionAndParameters", []interface{}{}) - fake.getFunctionAndParametersMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetFunctionAndParametersCallCount() int { - fake.getFunctionAndParametersMutex.RLock() - defer fake.getFunctionAndParametersMutex.RUnlock() - return len(fake.getFunctionAndParametersArgsForCall) -} - -func (fake *ChaincodeStub) GetFunctionAndParametersCalls(stub func() (string, []string)) { - fake.getFunctionAndParametersMutex.Lock() - defer fake.getFunctionAndParametersMutex.Unlock() - fake.GetFunctionAndParametersStub = stub -} - -func (fake *ChaincodeStub) GetFunctionAndParametersReturns(result1 string, result2 []string) { - fake.getFunctionAndParametersMutex.Lock() - defer fake.getFunctionAndParametersMutex.Unlock() - fake.GetFunctionAndParametersStub = nil - fake.getFunctionAndParametersReturns = struct { - result1 string - result2 []string - }{result1, result2} -} - -func (fake *ChaincodeStub) GetFunctionAndParametersReturnsOnCall(i int, result1 string, result2 []string) { - fake.getFunctionAndParametersMutex.Lock() - defer fake.getFunctionAndParametersMutex.Unlock() - fake.GetFunctionAndParametersStub = nil - if fake.getFunctionAndParametersReturnsOnCall == nil { - fake.getFunctionAndParametersReturnsOnCall = make(map[int]struct { - result1 string - result2 []string - }) - } - fake.getFunctionAndParametersReturnsOnCall[i] = struct { - result1 string - result2 []string - }{result1, result2} -} - -func (fake *ChaincodeStub) GetHistoryForKey(arg1 string) (shim.HistoryQueryIteratorInterface, error) { - fake.getHistoryForKeyMutex.Lock() - ret, specificReturn := fake.getHistoryForKeyReturnsOnCall[len(fake.getHistoryForKeyArgsForCall)] - fake.getHistoryForKeyArgsForCall = append(fake.getHistoryForKeyArgsForCall, struct { - arg1 string - }{arg1}) - stub := fake.GetHistoryForKeyStub - fakeReturns := fake.getHistoryForKeyReturns - fake.recordInvocation("GetHistoryForKey", []interface{}{arg1}) - fake.getHistoryForKeyMutex.Unlock() - if stub != nil { - return stub(arg1) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetHistoryForKeyCallCount() int { - fake.getHistoryForKeyMutex.RLock() - defer fake.getHistoryForKeyMutex.RUnlock() - return len(fake.getHistoryForKeyArgsForCall) -} - -func (fake *ChaincodeStub) GetHistoryForKeyCalls(stub func(string) (shim.HistoryQueryIteratorInterface, error)) { - fake.getHistoryForKeyMutex.Lock() - defer fake.getHistoryForKeyMutex.Unlock() - fake.GetHistoryForKeyStub = stub -} - -func (fake *ChaincodeStub) GetHistoryForKeyArgsForCall(i int) string { - fake.getHistoryForKeyMutex.RLock() - defer fake.getHistoryForKeyMutex.RUnlock() - argsForCall := fake.getHistoryForKeyArgsForCall[i] - return argsForCall.arg1 -} - -func (fake *ChaincodeStub) GetHistoryForKeyReturns(result1 shim.HistoryQueryIteratorInterface, result2 error) { - fake.getHistoryForKeyMutex.Lock() - defer fake.getHistoryForKeyMutex.Unlock() - fake.GetHistoryForKeyStub = nil - fake.getHistoryForKeyReturns = struct { - result1 shim.HistoryQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetHistoryForKeyReturnsOnCall(i int, result1 shim.HistoryQueryIteratorInterface, result2 error) { - fake.getHistoryForKeyMutex.Lock() - defer fake.getHistoryForKeyMutex.Unlock() - fake.GetHistoryForKeyStub = nil - if fake.getHistoryForKeyReturnsOnCall == nil { - fake.getHistoryForKeyReturnsOnCall = make(map[int]struct { - result1 shim.HistoryQueryIteratorInterface - result2 error - }) - } - fake.getHistoryForKeyReturnsOnCall[i] = struct { - result1 shim.HistoryQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetPrivateData(arg1 string, arg2 string) ([]byte, error) { - fake.getPrivateDataMutex.Lock() - ret, specificReturn := fake.getPrivateDataReturnsOnCall[len(fake.getPrivateDataArgsForCall)] - fake.getPrivateDataArgsForCall = append(fake.getPrivateDataArgsForCall, struct { - arg1 string - arg2 string - }{arg1, arg2}) - stub := fake.GetPrivateDataStub - fakeReturns := fake.getPrivateDataReturns - fake.recordInvocation("GetPrivateData", []interface{}{arg1, arg2}) - fake.getPrivateDataMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetPrivateDataCallCount() int { - fake.getPrivateDataMutex.RLock() - defer fake.getPrivateDataMutex.RUnlock() - return len(fake.getPrivateDataArgsForCall) -} - -func (fake *ChaincodeStub) GetPrivateDataCalls(stub func(string, string) ([]byte, error)) { - fake.getPrivateDataMutex.Lock() - defer fake.getPrivateDataMutex.Unlock() - fake.GetPrivateDataStub = stub -} - -func (fake *ChaincodeStub) GetPrivateDataArgsForCall(i int) (string, string) { - fake.getPrivateDataMutex.RLock() - defer fake.getPrivateDataMutex.RUnlock() - argsForCall := fake.getPrivateDataArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ChaincodeStub) GetPrivateDataReturns(result1 []byte, result2 error) { - fake.getPrivateDataMutex.Lock() - defer fake.getPrivateDataMutex.Unlock() - fake.GetPrivateDataStub = nil - fake.getPrivateDataReturns = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetPrivateDataReturnsOnCall(i int, result1 []byte, result2 error) { - fake.getPrivateDataMutex.Lock() - defer fake.getPrivateDataMutex.Unlock() - fake.GetPrivateDataStub = nil - if fake.getPrivateDataReturnsOnCall == nil { - fake.getPrivateDataReturnsOnCall = make(map[int]struct { - result1 []byte - result2 error - }) - } - fake.getPrivateDataReturnsOnCall[i] = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetPrivateDataByPartialCompositeKey(arg1 string, arg2 string, arg3 []string) (shim.StateQueryIteratorInterface, error) { - var arg3Copy []string - if arg3 != nil { - arg3Copy = make([]string, len(arg3)) - copy(arg3Copy, arg3) - } - fake.getPrivateDataByPartialCompositeKeyMutex.Lock() - ret, specificReturn := fake.getPrivateDataByPartialCompositeKeyReturnsOnCall[len(fake.getPrivateDataByPartialCompositeKeyArgsForCall)] - fake.getPrivateDataByPartialCompositeKeyArgsForCall = append(fake.getPrivateDataByPartialCompositeKeyArgsForCall, struct { - arg1 string - arg2 string - arg3 []string - }{arg1, arg2, arg3Copy}) - stub := fake.GetPrivateDataByPartialCompositeKeyStub - fakeReturns := fake.getPrivateDataByPartialCompositeKeyReturns - fake.recordInvocation("GetPrivateDataByPartialCompositeKey", []interface{}{arg1, arg2, arg3Copy}) - fake.getPrivateDataByPartialCompositeKeyMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetPrivateDataByPartialCompositeKeyCallCount() int { - fake.getPrivateDataByPartialCompositeKeyMutex.RLock() - defer fake.getPrivateDataByPartialCompositeKeyMutex.RUnlock() - return len(fake.getPrivateDataByPartialCompositeKeyArgsForCall) -} - -func (fake *ChaincodeStub) GetPrivateDataByPartialCompositeKeyCalls(stub func(string, string, []string) (shim.StateQueryIteratorInterface, error)) { - fake.getPrivateDataByPartialCompositeKeyMutex.Lock() - defer fake.getPrivateDataByPartialCompositeKeyMutex.Unlock() - fake.GetPrivateDataByPartialCompositeKeyStub = stub -} - -func (fake *ChaincodeStub) GetPrivateDataByPartialCompositeKeyArgsForCall(i int) (string, string, []string) { - fake.getPrivateDataByPartialCompositeKeyMutex.RLock() - defer fake.getPrivateDataByPartialCompositeKeyMutex.RUnlock() - argsForCall := fake.getPrivateDataByPartialCompositeKeyArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 -} - -func (fake *ChaincodeStub) GetPrivateDataByPartialCompositeKeyReturns(result1 shim.StateQueryIteratorInterface, result2 error) { - fake.getPrivateDataByPartialCompositeKeyMutex.Lock() - defer fake.getPrivateDataByPartialCompositeKeyMutex.Unlock() - fake.GetPrivateDataByPartialCompositeKeyStub = nil - fake.getPrivateDataByPartialCompositeKeyReturns = struct { - result1 shim.StateQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetPrivateDataByPartialCompositeKeyReturnsOnCall(i int, result1 shim.StateQueryIteratorInterface, result2 error) { - fake.getPrivateDataByPartialCompositeKeyMutex.Lock() - defer fake.getPrivateDataByPartialCompositeKeyMutex.Unlock() - fake.GetPrivateDataByPartialCompositeKeyStub = nil - if fake.getPrivateDataByPartialCompositeKeyReturnsOnCall == nil { - fake.getPrivateDataByPartialCompositeKeyReturnsOnCall = make(map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 error - }) - } - fake.getPrivateDataByPartialCompositeKeyReturnsOnCall[i] = struct { - result1 shim.StateQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetPrivateDataByRange(arg1 string, arg2 string, arg3 string) (shim.StateQueryIteratorInterface, error) { - fake.getPrivateDataByRangeMutex.Lock() - ret, specificReturn := fake.getPrivateDataByRangeReturnsOnCall[len(fake.getPrivateDataByRangeArgsForCall)] - fake.getPrivateDataByRangeArgsForCall = append(fake.getPrivateDataByRangeArgsForCall, struct { - arg1 string - arg2 string - arg3 string - }{arg1, arg2, arg3}) - stub := fake.GetPrivateDataByRangeStub - fakeReturns := fake.getPrivateDataByRangeReturns - fake.recordInvocation("GetPrivateDataByRange", []interface{}{arg1, arg2, arg3}) - fake.getPrivateDataByRangeMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetPrivateDataByRangeCallCount() int { - fake.getPrivateDataByRangeMutex.RLock() - defer fake.getPrivateDataByRangeMutex.RUnlock() - return len(fake.getPrivateDataByRangeArgsForCall) -} - -func (fake *ChaincodeStub) GetPrivateDataByRangeCalls(stub func(string, string, string) (shim.StateQueryIteratorInterface, error)) { - fake.getPrivateDataByRangeMutex.Lock() - defer fake.getPrivateDataByRangeMutex.Unlock() - fake.GetPrivateDataByRangeStub = stub -} - -func (fake *ChaincodeStub) GetPrivateDataByRangeArgsForCall(i int) (string, string, string) { - fake.getPrivateDataByRangeMutex.RLock() - defer fake.getPrivateDataByRangeMutex.RUnlock() - argsForCall := fake.getPrivateDataByRangeArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 -} - -func (fake *ChaincodeStub) GetPrivateDataByRangeReturns(result1 shim.StateQueryIteratorInterface, result2 error) { - fake.getPrivateDataByRangeMutex.Lock() - defer fake.getPrivateDataByRangeMutex.Unlock() - fake.GetPrivateDataByRangeStub = nil - fake.getPrivateDataByRangeReturns = struct { - result1 shim.StateQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetPrivateDataByRangeReturnsOnCall(i int, result1 shim.StateQueryIteratorInterface, result2 error) { - fake.getPrivateDataByRangeMutex.Lock() - defer fake.getPrivateDataByRangeMutex.Unlock() - fake.GetPrivateDataByRangeStub = nil - if fake.getPrivateDataByRangeReturnsOnCall == nil { - fake.getPrivateDataByRangeReturnsOnCall = make(map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 error - }) - } - fake.getPrivateDataByRangeReturnsOnCall[i] = struct { - result1 shim.StateQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetPrivateDataHash(arg1 string, arg2 string) ([]byte, error) { - fake.getPrivateDataHashMutex.Lock() - ret, specificReturn := fake.getPrivateDataHashReturnsOnCall[len(fake.getPrivateDataHashArgsForCall)] - fake.getPrivateDataHashArgsForCall = append(fake.getPrivateDataHashArgsForCall, struct { - arg1 string - arg2 string - }{arg1, arg2}) - stub := fake.GetPrivateDataHashStub - fakeReturns := fake.getPrivateDataHashReturns - fake.recordInvocation("GetPrivateDataHash", []interface{}{arg1, arg2}) - fake.getPrivateDataHashMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetPrivateDataHashCallCount() int { - fake.getPrivateDataHashMutex.RLock() - defer fake.getPrivateDataHashMutex.RUnlock() - return len(fake.getPrivateDataHashArgsForCall) -} - -func (fake *ChaincodeStub) GetPrivateDataHashCalls(stub func(string, string) ([]byte, error)) { - fake.getPrivateDataHashMutex.Lock() - defer fake.getPrivateDataHashMutex.Unlock() - fake.GetPrivateDataHashStub = stub -} - -func (fake *ChaincodeStub) GetPrivateDataHashArgsForCall(i int) (string, string) { - fake.getPrivateDataHashMutex.RLock() - defer fake.getPrivateDataHashMutex.RUnlock() - argsForCall := fake.getPrivateDataHashArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ChaincodeStub) GetPrivateDataHashReturns(result1 []byte, result2 error) { - fake.getPrivateDataHashMutex.Lock() - defer fake.getPrivateDataHashMutex.Unlock() - fake.GetPrivateDataHashStub = nil - fake.getPrivateDataHashReturns = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetPrivateDataHashReturnsOnCall(i int, result1 []byte, result2 error) { - fake.getPrivateDataHashMutex.Lock() - defer fake.getPrivateDataHashMutex.Unlock() - fake.GetPrivateDataHashStub = nil - if fake.getPrivateDataHashReturnsOnCall == nil { - fake.getPrivateDataHashReturnsOnCall = make(map[int]struct { - result1 []byte - result2 error - }) - } - fake.getPrivateDataHashReturnsOnCall[i] = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetPrivateDataQueryResult(arg1 string, arg2 string) (shim.StateQueryIteratorInterface, error) { - fake.getPrivateDataQueryResultMutex.Lock() - ret, specificReturn := fake.getPrivateDataQueryResultReturnsOnCall[len(fake.getPrivateDataQueryResultArgsForCall)] - fake.getPrivateDataQueryResultArgsForCall = append(fake.getPrivateDataQueryResultArgsForCall, struct { - arg1 string - arg2 string - }{arg1, arg2}) - stub := fake.GetPrivateDataQueryResultStub - fakeReturns := fake.getPrivateDataQueryResultReturns - fake.recordInvocation("GetPrivateDataQueryResult", []interface{}{arg1, arg2}) - fake.getPrivateDataQueryResultMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetPrivateDataQueryResultCallCount() int { - fake.getPrivateDataQueryResultMutex.RLock() - defer fake.getPrivateDataQueryResultMutex.RUnlock() - return len(fake.getPrivateDataQueryResultArgsForCall) -} - -func (fake *ChaincodeStub) GetPrivateDataQueryResultCalls(stub func(string, string) (shim.StateQueryIteratorInterface, error)) { - fake.getPrivateDataQueryResultMutex.Lock() - defer fake.getPrivateDataQueryResultMutex.Unlock() - fake.GetPrivateDataQueryResultStub = stub -} - -func (fake *ChaincodeStub) GetPrivateDataQueryResultArgsForCall(i int) (string, string) { - fake.getPrivateDataQueryResultMutex.RLock() - defer fake.getPrivateDataQueryResultMutex.RUnlock() - argsForCall := fake.getPrivateDataQueryResultArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ChaincodeStub) GetPrivateDataQueryResultReturns(result1 shim.StateQueryIteratorInterface, result2 error) { - fake.getPrivateDataQueryResultMutex.Lock() - defer fake.getPrivateDataQueryResultMutex.Unlock() - fake.GetPrivateDataQueryResultStub = nil - fake.getPrivateDataQueryResultReturns = struct { - result1 shim.StateQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetPrivateDataQueryResultReturnsOnCall(i int, result1 shim.StateQueryIteratorInterface, result2 error) { - fake.getPrivateDataQueryResultMutex.Lock() - defer fake.getPrivateDataQueryResultMutex.Unlock() - fake.GetPrivateDataQueryResultStub = nil - if fake.getPrivateDataQueryResultReturnsOnCall == nil { - fake.getPrivateDataQueryResultReturnsOnCall = make(map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 error - }) - } - fake.getPrivateDataQueryResultReturnsOnCall[i] = struct { - result1 shim.StateQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetPrivateDataValidationParameter(arg1 string, arg2 string) ([]byte, error) { - fake.getPrivateDataValidationParameterMutex.Lock() - ret, specificReturn := fake.getPrivateDataValidationParameterReturnsOnCall[len(fake.getPrivateDataValidationParameterArgsForCall)] - fake.getPrivateDataValidationParameterArgsForCall = append(fake.getPrivateDataValidationParameterArgsForCall, struct { - arg1 string - arg2 string - }{arg1, arg2}) - stub := fake.GetPrivateDataValidationParameterStub - fakeReturns := fake.getPrivateDataValidationParameterReturns - fake.recordInvocation("GetPrivateDataValidationParameter", []interface{}{arg1, arg2}) - fake.getPrivateDataValidationParameterMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetPrivateDataValidationParameterCallCount() int { - fake.getPrivateDataValidationParameterMutex.RLock() - defer fake.getPrivateDataValidationParameterMutex.RUnlock() - return len(fake.getPrivateDataValidationParameterArgsForCall) -} - -func (fake *ChaincodeStub) GetPrivateDataValidationParameterCalls(stub func(string, string) ([]byte, error)) { - fake.getPrivateDataValidationParameterMutex.Lock() - defer fake.getPrivateDataValidationParameterMutex.Unlock() - fake.GetPrivateDataValidationParameterStub = stub -} - -func (fake *ChaincodeStub) GetPrivateDataValidationParameterArgsForCall(i int) (string, string) { - fake.getPrivateDataValidationParameterMutex.RLock() - defer fake.getPrivateDataValidationParameterMutex.RUnlock() - argsForCall := fake.getPrivateDataValidationParameterArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ChaincodeStub) GetPrivateDataValidationParameterReturns(result1 []byte, result2 error) { - fake.getPrivateDataValidationParameterMutex.Lock() - defer fake.getPrivateDataValidationParameterMutex.Unlock() - fake.GetPrivateDataValidationParameterStub = nil - fake.getPrivateDataValidationParameterReturns = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetPrivateDataValidationParameterReturnsOnCall(i int, result1 []byte, result2 error) { - fake.getPrivateDataValidationParameterMutex.Lock() - defer fake.getPrivateDataValidationParameterMutex.Unlock() - fake.GetPrivateDataValidationParameterStub = nil - if fake.getPrivateDataValidationParameterReturnsOnCall == nil { - fake.getPrivateDataValidationParameterReturnsOnCall = make(map[int]struct { - result1 []byte - result2 error - }) - } - fake.getPrivateDataValidationParameterReturnsOnCall[i] = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetQueryResult(arg1 string) (shim.StateQueryIteratorInterface, error) { - fake.getQueryResultMutex.Lock() - ret, specificReturn := fake.getQueryResultReturnsOnCall[len(fake.getQueryResultArgsForCall)] - fake.getQueryResultArgsForCall = append(fake.getQueryResultArgsForCall, struct { - arg1 string - }{arg1}) - stub := fake.GetQueryResultStub - fakeReturns := fake.getQueryResultReturns - fake.recordInvocation("GetQueryResult", []interface{}{arg1}) - fake.getQueryResultMutex.Unlock() - if stub != nil { - return stub(arg1) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetQueryResultCallCount() int { - fake.getQueryResultMutex.RLock() - defer fake.getQueryResultMutex.RUnlock() - return len(fake.getQueryResultArgsForCall) -} - -func (fake *ChaincodeStub) GetQueryResultCalls(stub func(string) (shim.StateQueryIteratorInterface, error)) { - fake.getQueryResultMutex.Lock() - defer fake.getQueryResultMutex.Unlock() - fake.GetQueryResultStub = stub -} - -func (fake *ChaincodeStub) GetQueryResultArgsForCall(i int) string { - fake.getQueryResultMutex.RLock() - defer fake.getQueryResultMutex.RUnlock() - argsForCall := fake.getQueryResultArgsForCall[i] - return argsForCall.arg1 -} - -func (fake *ChaincodeStub) GetQueryResultReturns(result1 shim.StateQueryIteratorInterface, result2 error) { - fake.getQueryResultMutex.Lock() - defer fake.getQueryResultMutex.Unlock() - fake.GetQueryResultStub = nil - fake.getQueryResultReturns = struct { - result1 shim.StateQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetQueryResultReturnsOnCall(i int, result1 shim.StateQueryIteratorInterface, result2 error) { - fake.getQueryResultMutex.Lock() - defer fake.getQueryResultMutex.Unlock() - fake.GetQueryResultStub = nil - if fake.getQueryResultReturnsOnCall == nil { - fake.getQueryResultReturnsOnCall = make(map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 error - }) - } - fake.getQueryResultReturnsOnCall[i] = struct { - result1 shim.StateQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetQueryResultWithPagination(arg1 string, arg2 int32, arg3 string) (shim.StateQueryIteratorInterface, *peer.QueryResponseMetadata, error) { - fake.getQueryResultWithPaginationMutex.Lock() - ret, specificReturn := fake.getQueryResultWithPaginationReturnsOnCall[len(fake.getQueryResultWithPaginationArgsForCall)] - fake.getQueryResultWithPaginationArgsForCall = append(fake.getQueryResultWithPaginationArgsForCall, struct { - arg1 string - arg2 int32 - arg3 string - }{arg1, arg2, arg3}) - stub := fake.GetQueryResultWithPaginationStub - fakeReturns := fake.getQueryResultWithPaginationReturns - fake.recordInvocation("GetQueryResultWithPagination", []interface{}{arg1, arg2, arg3}) - fake.getQueryResultWithPaginationMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3) - } - if specificReturn { - return ret.result1, ret.result2, ret.result3 - } - return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3 -} - -func (fake *ChaincodeStub) GetQueryResultWithPaginationCallCount() int { - fake.getQueryResultWithPaginationMutex.RLock() - defer fake.getQueryResultWithPaginationMutex.RUnlock() - return len(fake.getQueryResultWithPaginationArgsForCall) -} - -func (fake *ChaincodeStub) GetQueryResultWithPaginationCalls(stub func(string, int32, string) (shim.StateQueryIteratorInterface, *peer.QueryResponseMetadata, error)) { - fake.getQueryResultWithPaginationMutex.Lock() - defer fake.getQueryResultWithPaginationMutex.Unlock() - fake.GetQueryResultWithPaginationStub = stub -} - -func (fake *ChaincodeStub) GetQueryResultWithPaginationArgsForCall(i int) (string, int32, string) { - fake.getQueryResultWithPaginationMutex.RLock() - defer fake.getQueryResultWithPaginationMutex.RUnlock() - argsForCall := fake.getQueryResultWithPaginationArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 -} - -func (fake *ChaincodeStub) GetQueryResultWithPaginationReturns(result1 shim.StateQueryIteratorInterface, result2 *peer.QueryResponseMetadata, result3 error) { - fake.getQueryResultWithPaginationMutex.Lock() - defer fake.getQueryResultWithPaginationMutex.Unlock() - fake.GetQueryResultWithPaginationStub = nil - fake.getQueryResultWithPaginationReturns = struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - }{result1, result2, result3} -} - -func (fake *ChaincodeStub) GetQueryResultWithPaginationReturnsOnCall(i int, result1 shim.StateQueryIteratorInterface, result2 *peer.QueryResponseMetadata, result3 error) { - fake.getQueryResultWithPaginationMutex.Lock() - defer fake.getQueryResultWithPaginationMutex.Unlock() - fake.GetQueryResultWithPaginationStub = nil - if fake.getQueryResultWithPaginationReturnsOnCall == nil { - fake.getQueryResultWithPaginationReturnsOnCall = make(map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - }) - } - fake.getQueryResultWithPaginationReturnsOnCall[i] = struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - }{result1, result2, result3} -} - -func (fake *ChaincodeStub) GetSignedProposal() (*peer.SignedProposal, error) { - fake.getSignedProposalMutex.Lock() - ret, specificReturn := fake.getSignedProposalReturnsOnCall[len(fake.getSignedProposalArgsForCall)] - fake.getSignedProposalArgsForCall = append(fake.getSignedProposalArgsForCall, struct { - }{}) - stub := fake.GetSignedProposalStub - fakeReturns := fake.getSignedProposalReturns - fake.recordInvocation("GetSignedProposal", []interface{}{}) - fake.getSignedProposalMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetSignedProposalCallCount() int { - fake.getSignedProposalMutex.RLock() - defer fake.getSignedProposalMutex.RUnlock() - return len(fake.getSignedProposalArgsForCall) -} - -func (fake *ChaincodeStub) GetSignedProposalCalls(stub func() (*peer.SignedProposal, error)) { - fake.getSignedProposalMutex.Lock() - defer fake.getSignedProposalMutex.Unlock() - fake.GetSignedProposalStub = stub -} - -func (fake *ChaincodeStub) GetSignedProposalReturns(result1 *peer.SignedProposal, result2 error) { - fake.getSignedProposalMutex.Lock() - defer fake.getSignedProposalMutex.Unlock() - fake.GetSignedProposalStub = nil - fake.getSignedProposalReturns = struct { - result1 *peer.SignedProposal - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetSignedProposalReturnsOnCall(i int, result1 *peer.SignedProposal, result2 error) { - fake.getSignedProposalMutex.Lock() - defer fake.getSignedProposalMutex.Unlock() - fake.GetSignedProposalStub = nil - if fake.getSignedProposalReturnsOnCall == nil { - fake.getSignedProposalReturnsOnCall = make(map[int]struct { - result1 *peer.SignedProposal - result2 error - }) - } - fake.getSignedProposalReturnsOnCall[i] = struct { - result1 *peer.SignedProposal - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetState(arg1 string) ([]byte, error) { - fake.getStateMutex.Lock() - ret, specificReturn := fake.getStateReturnsOnCall[len(fake.getStateArgsForCall)] - fake.getStateArgsForCall = append(fake.getStateArgsForCall, struct { - arg1 string - }{arg1}) - stub := fake.GetStateStub - fakeReturns := fake.getStateReturns - fake.recordInvocation("GetState", []interface{}{arg1}) - fake.getStateMutex.Unlock() - if stub != nil { - return stub(arg1) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetStateCallCount() int { - fake.getStateMutex.RLock() - defer fake.getStateMutex.RUnlock() - return len(fake.getStateArgsForCall) -} - -func (fake *ChaincodeStub) GetStateCalls(stub func(string) ([]byte, error)) { - fake.getStateMutex.Lock() - defer fake.getStateMutex.Unlock() - fake.GetStateStub = stub -} - -func (fake *ChaincodeStub) GetStateArgsForCall(i int) string { - fake.getStateMutex.RLock() - defer fake.getStateMutex.RUnlock() - argsForCall := fake.getStateArgsForCall[i] - return argsForCall.arg1 -} - -func (fake *ChaincodeStub) GetStateReturns(result1 []byte, result2 error) { - fake.getStateMutex.Lock() - defer fake.getStateMutex.Unlock() - fake.GetStateStub = nil - fake.getStateReturns = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetStateReturnsOnCall(i int, result1 []byte, result2 error) { - fake.getStateMutex.Lock() - defer fake.getStateMutex.Unlock() - fake.GetStateStub = nil - if fake.getStateReturnsOnCall == nil { - fake.getStateReturnsOnCall = make(map[int]struct { - result1 []byte - result2 error - }) - } - fake.getStateReturnsOnCall[i] = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetStateByPartialCompositeKey(arg1 string, arg2 []string) (shim.StateQueryIteratorInterface, error) { - var arg2Copy []string - if arg2 != nil { - arg2Copy = make([]string, len(arg2)) - copy(arg2Copy, arg2) - } - fake.getStateByPartialCompositeKeyMutex.Lock() - ret, specificReturn := fake.getStateByPartialCompositeKeyReturnsOnCall[len(fake.getStateByPartialCompositeKeyArgsForCall)] - fake.getStateByPartialCompositeKeyArgsForCall = append(fake.getStateByPartialCompositeKeyArgsForCall, struct { - arg1 string - arg2 []string - }{arg1, arg2Copy}) - stub := fake.GetStateByPartialCompositeKeyStub - fakeReturns := fake.getStateByPartialCompositeKeyReturns - fake.recordInvocation("GetStateByPartialCompositeKey", []interface{}{arg1, arg2Copy}) - fake.getStateByPartialCompositeKeyMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetStateByPartialCompositeKeyCallCount() int { - fake.getStateByPartialCompositeKeyMutex.RLock() - defer fake.getStateByPartialCompositeKeyMutex.RUnlock() - return len(fake.getStateByPartialCompositeKeyArgsForCall) -} - -func (fake *ChaincodeStub) GetStateByPartialCompositeKeyCalls(stub func(string, []string) (shim.StateQueryIteratorInterface, error)) { - fake.getStateByPartialCompositeKeyMutex.Lock() - defer fake.getStateByPartialCompositeKeyMutex.Unlock() - fake.GetStateByPartialCompositeKeyStub = stub -} - -func (fake *ChaincodeStub) GetStateByPartialCompositeKeyArgsForCall(i int) (string, []string) { - fake.getStateByPartialCompositeKeyMutex.RLock() - defer fake.getStateByPartialCompositeKeyMutex.RUnlock() - argsForCall := fake.getStateByPartialCompositeKeyArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ChaincodeStub) GetStateByPartialCompositeKeyReturns(result1 shim.StateQueryIteratorInterface, result2 error) { - fake.getStateByPartialCompositeKeyMutex.Lock() - defer fake.getStateByPartialCompositeKeyMutex.Unlock() - fake.GetStateByPartialCompositeKeyStub = nil - fake.getStateByPartialCompositeKeyReturns = struct { - result1 shim.StateQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetStateByPartialCompositeKeyReturnsOnCall(i int, result1 shim.StateQueryIteratorInterface, result2 error) { - fake.getStateByPartialCompositeKeyMutex.Lock() - defer fake.getStateByPartialCompositeKeyMutex.Unlock() - fake.GetStateByPartialCompositeKeyStub = nil - if fake.getStateByPartialCompositeKeyReturnsOnCall == nil { - fake.getStateByPartialCompositeKeyReturnsOnCall = make(map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 error - }) - } - fake.getStateByPartialCompositeKeyReturnsOnCall[i] = struct { - result1 shim.StateQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetStateByPartialCompositeKeyWithPagination(arg1 string, arg2 []string, arg3 int32, arg4 string) (shim.StateQueryIteratorInterface, *peer.QueryResponseMetadata, error) { - var arg2Copy []string - if arg2 != nil { - arg2Copy = make([]string, len(arg2)) - copy(arg2Copy, arg2) - } - fake.getStateByPartialCompositeKeyWithPaginationMutex.Lock() - ret, specificReturn := fake.getStateByPartialCompositeKeyWithPaginationReturnsOnCall[len(fake.getStateByPartialCompositeKeyWithPaginationArgsForCall)] - fake.getStateByPartialCompositeKeyWithPaginationArgsForCall = append(fake.getStateByPartialCompositeKeyWithPaginationArgsForCall, struct { - arg1 string - arg2 []string - arg3 int32 - arg4 string - }{arg1, arg2Copy, arg3, arg4}) - stub := fake.GetStateByPartialCompositeKeyWithPaginationStub - fakeReturns := fake.getStateByPartialCompositeKeyWithPaginationReturns - fake.recordInvocation("GetStateByPartialCompositeKeyWithPagination", []interface{}{arg1, arg2Copy, arg3, arg4}) - fake.getStateByPartialCompositeKeyWithPaginationMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3, arg4) - } - if specificReturn { - return ret.result1, ret.result2, ret.result3 - } - return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3 -} - -func (fake *ChaincodeStub) GetStateByPartialCompositeKeyWithPaginationCallCount() int { - fake.getStateByPartialCompositeKeyWithPaginationMutex.RLock() - defer fake.getStateByPartialCompositeKeyWithPaginationMutex.RUnlock() - return len(fake.getStateByPartialCompositeKeyWithPaginationArgsForCall) -} - -func (fake *ChaincodeStub) GetStateByPartialCompositeKeyWithPaginationCalls(stub func(string, []string, int32, string) (shim.StateQueryIteratorInterface, *peer.QueryResponseMetadata, error)) { - fake.getStateByPartialCompositeKeyWithPaginationMutex.Lock() - defer fake.getStateByPartialCompositeKeyWithPaginationMutex.Unlock() - fake.GetStateByPartialCompositeKeyWithPaginationStub = stub -} - -func (fake *ChaincodeStub) GetStateByPartialCompositeKeyWithPaginationArgsForCall(i int) (string, []string, int32, string) { - fake.getStateByPartialCompositeKeyWithPaginationMutex.RLock() - defer fake.getStateByPartialCompositeKeyWithPaginationMutex.RUnlock() - argsForCall := fake.getStateByPartialCompositeKeyWithPaginationArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 -} - -func (fake *ChaincodeStub) GetStateByPartialCompositeKeyWithPaginationReturns(result1 shim.StateQueryIteratorInterface, result2 *peer.QueryResponseMetadata, result3 error) { - fake.getStateByPartialCompositeKeyWithPaginationMutex.Lock() - defer fake.getStateByPartialCompositeKeyWithPaginationMutex.Unlock() - fake.GetStateByPartialCompositeKeyWithPaginationStub = nil - fake.getStateByPartialCompositeKeyWithPaginationReturns = struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - }{result1, result2, result3} -} - -func (fake *ChaincodeStub) GetStateByPartialCompositeKeyWithPaginationReturnsOnCall(i int, result1 shim.StateQueryIteratorInterface, result2 *peer.QueryResponseMetadata, result3 error) { - fake.getStateByPartialCompositeKeyWithPaginationMutex.Lock() - defer fake.getStateByPartialCompositeKeyWithPaginationMutex.Unlock() - fake.GetStateByPartialCompositeKeyWithPaginationStub = nil - if fake.getStateByPartialCompositeKeyWithPaginationReturnsOnCall == nil { - fake.getStateByPartialCompositeKeyWithPaginationReturnsOnCall = make(map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - }) - } - fake.getStateByPartialCompositeKeyWithPaginationReturnsOnCall[i] = struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - }{result1, result2, result3} -} - -func (fake *ChaincodeStub) GetStateByRange(arg1 string, arg2 string) (shim.StateQueryIteratorInterface, error) { - fake.getStateByRangeMutex.Lock() - ret, specificReturn := fake.getStateByRangeReturnsOnCall[len(fake.getStateByRangeArgsForCall)] - fake.getStateByRangeArgsForCall = append(fake.getStateByRangeArgsForCall, struct { - arg1 string - arg2 string - }{arg1, arg2}) - stub := fake.GetStateByRangeStub - fakeReturns := fake.getStateByRangeReturns - fake.recordInvocation("GetStateByRange", []interface{}{arg1, arg2}) - fake.getStateByRangeMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetStateByRangeCallCount() int { - fake.getStateByRangeMutex.RLock() - defer fake.getStateByRangeMutex.RUnlock() - return len(fake.getStateByRangeArgsForCall) -} - -func (fake *ChaincodeStub) GetStateByRangeCalls(stub func(string, string) (shim.StateQueryIteratorInterface, error)) { - fake.getStateByRangeMutex.Lock() - defer fake.getStateByRangeMutex.Unlock() - fake.GetStateByRangeStub = stub -} - -func (fake *ChaincodeStub) GetStateByRangeArgsForCall(i int) (string, string) { - fake.getStateByRangeMutex.RLock() - defer fake.getStateByRangeMutex.RUnlock() - argsForCall := fake.getStateByRangeArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ChaincodeStub) GetStateByRangeReturns(result1 shim.StateQueryIteratorInterface, result2 error) { - fake.getStateByRangeMutex.Lock() - defer fake.getStateByRangeMutex.Unlock() - fake.GetStateByRangeStub = nil - fake.getStateByRangeReturns = struct { - result1 shim.StateQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetStateByRangeReturnsOnCall(i int, result1 shim.StateQueryIteratorInterface, result2 error) { - fake.getStateByRangeMutex.Lock() - defer fake.getStateByRangeMutex.Unlock() - fake.GetStateByRangeStub = nil - if fake.getStateByRangeReturnsOnCall == nil { - fake.getStateByRangeReturnsOnCall = make(map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 error - }) - } - fake.getStateByRangeReturnsOnCall[i] = struct { - result1 shim.StateQueryIteratorInterface - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetStateByRangeWithPagination(arg1 string, arg2 string, arg3 int32, arg4 string) (shim.StateQueryIteratorInterface, *peer.QueryResponseMetadata, error) { - fake.getStateByRangeWithPaginationMutex.Lock() - ret, specificReturn := fake.getStateByRangeWithPaginationReturnsOnCall[len(fake.getStateByRangeWithPaginationArgsForCall)] - fake.getStateByRangeWithPaginationArgsForCall = append(fake.getStateByRangeWithPaginationArgsForCall, struct { - arg1 string - arg2 string - arg3 int32 - arg4 string - }{arg1, arg2, arg3, arg4}) - stub := fake.GetStateByRangeWithPaginationStub - fakeReturns := fake.getStateByRangeWithPaginationReturns - fake.recordInvocation("GetStateByRangeWithPagination", []interface{}{arg1, arg2, arg3, arg4}) - fake.getStateByRangeWithPaginationMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3, arg4) - } - if specificReturn { - return ret.result1, ret.result2, ret.result3 - } - return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3 -} - -func (fake *ChaincodeStub) GetStateByRangeWithPaginationCallCount() int { - fake.getStateByRangeWithPaginationMutex.RLock() - defer fake.getStateByRangeWithPaginationMutex.RUnlock() - return len(fake.getStateByRangeWithPaginationArgsForCall) -} - -func (fake *ChaincodeStub) GetStateByRangeWithPaginationCalls(stub func(string, string, int32, string) (shim.StateQueryIteratorInterface, *peer.QueryResponseMetadata, error)) { - fake.getStateByRangeWithPaginationMutex.Lock() - defer fake.getStateByRangeWithPaginationMutex.Unlock() - fake.GetStateByRangeWithPaginationStub = stub -} - -func (fake *ChaincodeStub) GetStateByRangeWithPaginationArgsForCall(i int) (string, string, int32, string) { - fake.getStateByRangeWithPaginationMutex.RLock() - defer fake.getStateByRangeWithPaginationMutex.RUnlock() - argsForCall := fake.getStateByRangeWithPaginationArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 -} - -func (fake *ChaincodeStub) GetStateByRangeWithPaginationReturns(result1 shim.StateQueryIteratorInterface, result2 *peer.QueryResponseMetadata, result3 error) { - fake.getStateByRangeWithPaginationMutex.Lock() - defer fake.getStateByRangeWithPaginationMutex.Unlock() - fake.GetStateByRangeWithPaginationStub = nil - fake.getStateByRangeWithPaginationReturns = struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - }{result1, result2, result3} -} - -func (fake *ChaincodeStub) GetStateByRangeWithPaginationReturnsOnCall(i int, result1 shim.StateQueryIteratorInterface, result2 *peer.QueryResponseMetadata, result3 error) { - fake.getStateByRangeWithPaginationMutex.Lock() - defer fake.getStateByRangeWithPaginationMutex.Unlock() - fake.GetStateByRangeWithPaginationStub = nil - if fake.getStateByRangeWithPaginationReturnsOnCall == nil { - fake.getStateByRangeWithPaginationReturnsOnCall = make(map[int]struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - }) - } - fake.getStateByRangeWithPaginationReturnsOnCall[i] = struct { - result1 shim.StateQueryIteratorInterface - result2 *peer.QueryResponseMetadata - result3 error - }{result1, result2, result3} -} - -func (fake *ChaincodeStub) GetStateValidationParameter(arg1 string) ([]byte, error) { - fake.getStateValidationParameterMutex.Lock() - ret, specificReturn := fake.getStateValidationParameterReturnsOnCall[len(fake.getStateValidationParameterArgsForCall)] - fake.getStateValidationParameterArgsForCall = append(fake.getStateValidationParameterArgsForCall, struct { - arg1 string - }{arg1}) - stub := fake.GetStateValidationParameterStub - fakeReturns := fake.getStateValidationParameterReturns - fake.recordInvocation("GetStateValidationParameter", []interface{}{arg1}) - fake.getStateValidationParameterMutex.Unlock() - if stub != nil { - return stub(arg1) - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetStateValidationParameterCallCount() int { - fake.getStateValidationParameterMutex.RLock() - defer fake.getStateValidationParameterMutex.RUnlock() - return len(fake.getStateValidationParameterArgsForCall) -} - -func (fake *ChaincodeStub) GetStateValidationParameterCalls(stub func(string) ([]byte, error)) { - fake.getStateValidationParameterMutex.Lock() - defer fake.getStateValidationParameterMutex.Unlock() - fake.GetStateValidationParameterStub = stub -} - -func (fake *ChaincodeStub) GetStateValidationParameterArgsForCall(i int) string { - fake.getStateValidationParameterMutex.RLock() - defer fake.getStateValidationParameterMutex.RUnlock() - argsForCall := fake.getStateValidationParameterArgsForCall[i] - return argsForCall.arg1 -} - -func (fake *ChaincodeStub) GetStateValidationParameterReturns(result1 []byte, result2 error) { - fake.getStateValidationParameterMutex.Lock() - defer fake.getStateValidationParameterMutex.Unlock() - fake.GetStateValidationParameterStub = nil - fake.getStateValidationParameterReturns = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetStateValidationParameterReturnsOnCall(i int, result1 []byte, result2 error) { - fake.getStateValidationParameterMutex.Lock() - defer fake.getStateValidationParameterMutex.Unlock() - fake.GetStateValidationParameterStub = nil - if fake.getStateValidationParameterReturnsOnCall == nil { - fake.getStateValidationParameterReturnsOnCall = make(map[int]struct { - result1 []byte - result2 error - }) - } - fake.getStateValidationParameterReturnsOnCall[i] = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetStringArgs() []string { - fake.getStringArgsMutex.Lock() - ret, specificReturn := fake.getStringArgsReturnsOnCall[len(fake.getStringArgsArgsForCall)] - fake.getStringArgsArgsForCall = append(fake.getStringArgsArgsForCall, struct { - }{}) - stub := fake.GetStringArgsStub - fakeReturns := fake.getStringArgsReturns - fake.recordInvocation("GetStringArgs", []interface{}{}) - fake.getStringArgsMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) GetStringArgsCallCount() int { - fake.getStringArgsMutex.RLock() - defer fake.getStringArgsMutex.RUnlock() - return len(fake.getStringArgsArgsForCall) -} - -func (fake *ChaincodeStub) GetStringArgsCalls(stub func() []string) { - fake.getStringArgsMutex.Lock() - defer fake.getStringArgsMutex.Unlock() - fake.GetStringArgsStub = stub -} - -func (fake *ChaincodeStub) GetStringArgsReturns(result1 []string) { - fake.getStringArgsMutex.Lock() - defer fake.getStringArgsMutex.Unlock() - fake.GetStringArgsStub = nil - fake.getStringArgsReturns = struct { - result1 []string - }{result1} -} - -func (fake *ChaincodeStub) GetStringArgsReturnsOnCall(i int, result1 []string) { - fake.getStringArgsMutex.Lock() - defer fake.getStringArgsMutex.Unlock() - fake.GetStringArgsStub = nil - if fake.getStringArgsReturnsOnCall == nil { - fake.getStringArgsReturnsOnCall = make(map[int]struct { - result1 []string - }) - } - fake.getStringArgsReturnsOnCall[i] = struct { - result1 []string - }{result1} -} - -func (fake *ChaincodeStub) GetTransient() (map[string][]byte, error) { - fake.getTransientMutex.Lock() - ret, specificReturn := fake.getTransientReturnsOnCall[len(fake.getTransientArgsForCall)] - fake.getTransientArgsForCall = append(fake.getTransientArgsForCall, struct { - }{}) - stub := fake.GetTransientStub - fakeReturns := fake.getTransientReturns - fake.recordInvocation("GetTransient", []interface{}{}) - fake.getTransientMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetTransientCallCount() int { - fake.getTransientMutex.RLock() - defer fake.getTransientMutex.RUnlock() - return len(fake.getTransientArgsForCall) -} - -func (fake *ChaincodeStub) GetTransientCalls(stub func() (map[string][]byte, error)) { - fake.getTransientMutex.Lock() - defer fake.getTransientMutex.Unlock() - fake.GetTransientStub = stub -} - -func (fake *ChaincodeStub) GetTransientReturns(result1 map[string][]byte, result2 error) { - fake.getTransientMutex.Lock() - defer fake.getTransientMutex.Unlock() - fake.GetTransientStub = nil - fake.getTransientReturns = struct { - result1 map[string][]byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetTransientReturnsOnCall(i int, result1 map[string][]byte, result2 error) { - fake.getTransientMutex.Lock() - defer fake.getTransientMutex.Unlock() - fake.GetTransientStub = nil - if fake.getTransientReturnsOnCall == nil { - fake.getTransientReturnsOnCall = make(map[int]struct { - result1 map[string][]byte - result2 error - }) - } - fake.getTransientReturnsOnCall[i] = struct { - result1 map[string][]byte - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetTxID() string { - fake.getTxIDMutex.Lock() - ret, specificReturn := fake.getTxIDReturnsOnCall[len(fake.getTxIDArgsForCall)] - fake.getTxIDArgsForCall = append(fake.getTxIDArgsForCall, struct { - }{}) - stub := fake.GetTxIDStub - fakeReturns := fake.getTxIDReturns - fake.recordInvocation("GetTxID", []interface{}{}) - fake.getTxIDMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) GetTxIDCallCount() int { - fake.getTxIDMutex.RLock() - defer fake.getTxIDMutex.RUnlock() - return len(fake.getTxIDArgsForCall) -} - -func (fake *ChaincodeStub) GetTxIDCalls(stub func() string) { - fake.getTxIDMutex.Lock() - defer fake.getTxIDMutex.Unlock() - fake.GetTxIDStub = stub -} - -func (fake *ChaincodeStub) GetTxIDReturns(result1 string) { - fake.getTxIDMutex.Lock() - defer fake.getTxIDMutex.Unlock() - fake.GetTxIDStub = nil - fake.getTxIDReturns = struct { - result1 string - }{result1} -} - -func (fake *ChaincodeStub) GetTxIDReturnsOnCall(i int, result1 string) { - fake.getTxIDMutex.Lock() - defer fake.getTxIDMutex.Unlock() - fake.GetTxIDStub = nil - if fake.getTxIDReturnsOnCall == nil { - fake.getTxIDReturnsOnCall = make(map[int]struct { - result1 string - }) - } - fake.getTxIDReturnsOnCall[i] = struct { - result1 string - }{result1} -} - -func (fake *ChaincodeStub) GetTxTimestamp() (*timestamppb.Timestamp, error) { - fake.getTxTimestampMutex.Lock() - ret, specificReturn := fake.getTxTimestampReturnsOnCall[len(fake.getTxTimestampArgsForCall)] - fake.getTxTimestampArgsForCall = append(fake.getTxTimestampArgsForCall, struct { - }{}) - stub := fake.GetTxTimestampStub - fakeReturns := fake.getTxTimestampReturns - fake.recordInvocation("GetTxTimestamp", []interface{}{}) - fake.getTxTimestampMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ChaincodeStub) GetTxTimestampCallCount() int { - fake.getTxTimestampMutex.RLock() - defer fake.getTxTimestampMutex.RUnlock() - return len(fake.getTxTimestampArgsForCall) -} - -func (fake *ChaincodeStub) GetTxTimestampCalls(stub func() (*timestamppb.Timestamp, error)) { - fake.getTxTimestampMutex.Lock() - defer fake.getTxTimestampMutex.Unlock() - fake.GetTxTimestampStub = stub -} - -func (fake *ChaincodeStub) GetTxTimestampReturns(result1 *timestamppb.Timestamp, result2 error) { - fake.getTxTimestampMutex.Lock() - defer fake.getTxTimestampMutex.Unlock() - fake.GetTxTimestampStub = nil - fake.getTxTimestampReturns = struct { - result1 *timestamppb.Timestamp - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) GetTxTimestampReturnsOnCall(i int, result1 *timestamppb.Timestamp, result2 error) { - fake.getTxTimestampMutex.Lock() - defer fake.getTxTimestampMutex.Unlock() - fake.GetTxTimestampStub = nil - if fake.getTxTimestampReturnsOnCall == nil { - fake.getTxTimestampReturnsOnCall = make(map[int]struct { - result1 *timestamppb.Timestamp - result2 error - }) - } - fake.getTxTimestampReturnsOnCall[i] = struct { - result1 *timestamppb.Timestamp - result2 error - }{result1, result2} -} - -func (fake *ChaincodeStub) InvokeChaincode(arg1 string, arg2 [][]byte, arg3 string) *peer.Response { - var arg2Copy [][]byte - if arg2 != nil { - arg2Copy = make([][]byte, len(arg2)) - copy(arg2Copy, arg2) - } - fake.invokeChaincodeMutex.Lock() - ret, specificReturn := fake.invokeChaincodeReturnsOnCall[len(fake.invokeChaincodeArgsForCall)] - fake.invokeChaincodeArgsForCall = append(fake.invokeChaincodeArgsForCall, struct { - arg1 string - arg2 [][]byte - arg3 string - }{arg1, arg2Copy, arg3}) - stub := fake.InvokeChaincodeStub - fakeReturns := fake.invokeChaincodeReturns - fake.recordInvocation("InvokeChaincode", []interface{}{arg1, arg2Copy, arg3}) - fake.invokeChaincodeMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3) - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) InvokeChaincodeCallCount() int { - fake.invokeChaincodeMutex.RLock() - defer fake.invokeChaincodeMutex.RUnlock() - return len(fake.invokeChaincodeArgsForCall) -} - -func (fake *ChaincodeStub) InvokeChaincodeCalls(stub func(string, [][]byte, string) *peer.Response) { - fake.invokeChaincodeMutex.Lock() - defer fake.invokeChaincodeMutex.Unlock() - fake.InvokeChaincodeStub = stub -} - -func (fake *ChaincodeStub) InvokeChaincodeArgsForCall(i int) (string, [][]byte, string) { - fake.invokeChaincodeMutex.RLock() - defer fake.invokeChaincodeMutex.RUnlock() - argsForCall := fake.invokeChaincodeArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 -} - -func (fake *ChaincodeStub) InvokeChaincodeReturns(result1 *peer.Response) { - fake.invokeChaincodeMutex.Lock() - defer fake.invokeChaincodeMutex.Unlock() - fake.InvokeChaincodeStub = nil - fake.invokeChaincodeReturns = struct { - result1 *peer.Response - }{result1} -} - -func (fake *ChaincodeStub) InvokeChaincodeReturnsOnCall(i int, result1 *peer.Response) { - fake.invokeChaincodeMutex.Lock() - defer fake.invokeChaincodeMutex.Unlock() - fake.InvokeChaincodeStub = nil - if fake.invokeChaincodeReturnsOnCall == nil { - fake.invokeChaincodeReturnsOnCall = make(map[int]struct { - result1 *peer.Response - }) - } - fake.invokeChaincodeReturnsOnCall[i] = struct { - result1 *peer.Response - }{result1} -} - -func (fake *ChaincodeStub) PurgePrivateData(arg1 string, arg2 string) error { - fake.purgePrivateDataMutex.Lock() - ret, specificReturn := fake.purgePrivateDataReturnsOnCall[len(fake.purgePrivateDataArgsForCall)] - fake.purgePrivateDataArgsForCall = append(fake.purgePrivateDataArgsForCall, struct { - arg1 string - arg2 string - }{arg1, arg2}) - stub := fake.PurgePrivateDataStub - fakeReturns := fake.purgePrivateDataReturns - fake.recordInvocation("PurgePrivateData", []interface{}{arg1, arg2}) - fake.purgePrivateDataMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) PurgePrivateDataCallCount() int { - fake.purgePrivateDataMutex.RLock() - defer fake.purgePrivateDataMutex.RUnlock() - return len(fake.purgePrivateDataArgsForCall) -} - -func (fake *ChaincodeStub) PurgePrivateDataCalls(stub func(string, string) error) { - fake.purgePrivateDataMutex.Lock() - defer fake.purgePrivateDataMutex.Unlock() - fake.PurgePrivateDataStub = stub -} - -func (fake *ChaincodeStub) PurgePrivateDataArgsForCall(i int) (string, string) { - fake.purgePrivateDataMutex.RLock() - defer fake.purgePrivateDataMutex.RUnlock() - argsForCall := fake.purgePrivateDataArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ChaincodeStub) PurgePrivateDataReturns(result1 error) { - fake.purgePrivateDataMutex.Lock() - defer fake.purgePrivateDataMutex.Unlock() - fake.PurgePrivateDataStub = nil - fake.purgePrivateDataReturns = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) PurgePrivateDataReturnsOnCall(i int, result1 error) { - fake.purgePrivateDataMutex.Lock() - defer fake.purgePrivateDataMutex.Unlock() - fake.PurgePrivateDataStub = nil - if fake.purgePrivateDataReturnsOnCall == nil { - fake.purgePrivateDataReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.purgePrivateDataReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) PutPrivateData(arg1 string, arg2 string, arg3 []byte) error { - var arg3Copy []byte - if arg3 != nil { - arg3Copy = make([]byte, len(arg3)) - copy(arg3Copy, arg3) - } - fake.putPrivateDataMutex.Lock() - ret, specificReturn := fake.putPrivateDataReturnsOnCall[len(fake.putPrivateDataArgsForCall)] - fake.putPrivateDataArgsForCall = append(fake.putPrivateDataArgsForCall, struct { - arg1 string - arg2 string - arg3 []byte - }{arg1, arg2, arg3Copy}) - stub := fake.PutPrivateDataStub - fakeReturns := fake.putPrivateDataReturns - fake.recordInvocation("PutPrivateData", []interface{}{arg1, arg2, arg3Copy}) - fake.putPrivateDataMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3) - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) PutPrivateDataCallCount() int { - fake.putPrivateDataMutex.RLock() - defer fake.putPrivateDataMutex.RUnlock() - return len(fake.putPrivateDataArgsForCall) -} - -func (fake *ChaincodeStub) PutPrivateDataCalls(stub func(string, string, []byte) error) { - fake.putPrivateDataMutex.Lock() - defer fake.putPrivateDataMutex.Unlock() - fake.PutPrivateDataStub = stub -} - -func (fake *ChaincodeStub) PutPrivateDataArgsForCall(i int) (string, string, []byte) { - fake.putPrivateDataMutex.RLock() - defer fake.putPrivateDataMutex.RUnlock() - argsForCall := fake.putPrivateDataArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 -} - -func (fake *ChaincodeStub) PutPrivateDataReturns(result1 error) { - fake.putPrivateDataMutex.Lock() - defer fake.putPrivateDataMutex.Unlock() - fake.PutPrivateDataStub = nil - fake.putPrivateDataReturns = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) PutPrivateDataReturnsOnCall(i int, result1 error) { - fake.putPrivateDataMutex.Lock() - defer fake.putPrivateDataMutex.Unlock() - fake.PutPrivateDataStub = nil - if fake.putPrivateDataReturnsOnCall == nil { - fake.putPrivateDataReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.putPrivateDataReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) PutState(arg1 string, arg2 []byte) error { - var arg2Copy []byte - if arg2 != nil { - arg2Copy = make([]byte, len(arg2)) - copy(arg2Copy, arg2) - } - fake.putStateMutex.Lock() - ret, specificReturn := fake.putStateReturnsOnCall[len(fake.putStateArgsForCall)] - fake.putStateArgsForCall = append(fake.putStateArgsForCall, struct { - arg1 string - arg2 []byte - }{arg1, arg2Copy}) - stub := fake.PutStateStub - fakeReturns := fake.putStateReturns - fake.recordInvocation("PutState", []interface{}{arg1, arg2Copy}) - fake.putStateMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) PutStateCallCount() int { - fake.putStateMutex.RLock() - defer fake.putStateMutex.RUnlock() - return len(fake.putStateArgsForCall) -} - -func (fake *ChaincodeStub) PutStateCalls(stub func(string, []byte) error) { - fake.putStateMutex.Lock() - defer fake.putStateMutex.Unlock() - fake.PutStateStub = stub -} - -func (fake *ChaincodeStub) PutStateArgsForCall(i int) (string, []byte) { - fake.putStateMutex.RLock() - defer fake.putStateMutex.RUnlock() - argsForCall := fake.putStateArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ChaincodeStub) PutStateReturns(result1 error) { - fake.putStateMutex.Lock() - defer fake.putStateMutex.Unlock() - fake.PutStateStub = nil - fake.putStateReturns = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) PutStateReturnsOnCall(i int, result1 error) { - fake.putStateMutex.Lock() - defer fake.putStateMutex.Unlock() - fake.PutStateStub = nil - if fake.putStateReturnsOnCall == nil { - fake.putStateReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.putStateReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) SetEvent(arg1 string, arg2 []byte) error { - var arg2Copy []byte - if arg2 != nil { - arg2Copy = make([]byte, len(arg2)) - copy(arg2Copy, arg2) - } - fake.setEventMutex.Lock() - ret, specificReturn := fake.setEventReturnsOnCall[len(fake.setEventArgsForCall)] - fake.setEventArgsForCall = append(fake.setEventArgsForCall, struct { - arg1 string - arg2 []byte - }{arg1, arg2Copy}) - stub := fake.SetEventStub - fakeReturns := fake.setEventReturns - fake.recordInvocation("SetEvent", []interface{}{arg1, arg2Copy}) - fake.setEventMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) SetEventCallCount() int { - fake.setEventMutex.RLock() - defer fake.setEventMutex.RUnlock() - return len(fake.setEventArgsForCall) -} - -func (fake *ChaincodeStub) SetEventCalls(stub func(string, []byte) error) { - fake.setEventMutex.Lock() - defer fake.setEventMutex.Unlock() - fake.SetEventStub = stub -} - -func (fake *ChaincodeStub) SetEventArgsForCall(i int) (string, []byte) { - fake.setEventMutex.RLock() - defer fake.setEventMutex.RUnlock() - argsForCall := fake.setEventArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ChaincodeStub) SetEventReturns(result1 error) { - fake.setEventMutex.Lock() - defer fake.setEventMutex.Unlock() - fake.SetEventStub = nil - fake.setEventReturns = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) SetEventReturnsOnCall(i int, result1 error) { - fake.setEventMutex.Lock() - defer fake.setEventMutex.Unlock() - fake.SetEventStub = nil - if fake.setEventReturnsOnCall == nil { - fake.setEventReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.setEventReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) SetPrivateDataValidationParameter(arg1 string, arg2 string, arg3 []byte) error { - var arg3Copy []byte - if arg3 != nil { - arg3Copy = make([]byte, len(arg3)) - copy(arg3Copy, arg3) - } - fake.setPrivateDataValidationParameterMutex.Lock() - ret, specificReturn := fake.setPrivateDataValidationParameterReturnsOnCall[len(fake.setPrivateDataValidationParameterArgsForCall)] - fake.setPrivateDataValidationParameterArgsForCall = append(fake.setPrivateDataValidationParameterArgsForCall, struct { - arg1 string - arg2 string - arg3 []byte - }{arg1, arg2, arg3Copy}) - stub := fake.SetPrivateDataValidationParameterStub - fakeReturns := fake.setPrivateDataValidationParameterReturns - fake.recordInvocation("SetPrivateDataValidationParameter", []interface{}{arg1, arg2, arg3Copy}) - fake.setPrivateDataValidationParameterMutex.Unlock() - if stub != nil { - return stub(arg1, arg2, arg3) - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) SetPrivateDataValidationParameterCallCount() int { - fake.setPrivateDataValidationParameterMutex.RLock() - defer fake.setPrivateDataValidationParameterMutex.RUnlock() - return len(fake.setPrivateDataValidationParameterArgsForCall) -} - -func (fake *ChaincodeStub) SetPrivateDataValidationParameterCalls(stub func(string, string, []byte) error) { - fake.setPrivateDataValidationParameterMutex.Lock() - defer fake.setPrivateDataValidationParameterMutex.Unlock() - fake.SetPrivateDataValidationParameterStub = stub -} - -func (fake *ChaincodeStub) SetPrivateDataValidationParameterArgsForCall(i int) (string, string, []byte) { - fake.setPrivateDataValidationParameterMutex.RLock() - defer fake.setPrivateDataValidationParameterMutex.RUnlock() - argsForCall := fake.setPrivateDataValidationParameterArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 -} - -func (fake *ChaincodeStub) SetPrivateDataValidationParameterReturns(result1 error) { - fake.setPrivateDataValidationParameterMutex.Lock() - defer fake.setPrivateDataValidationParameterMutex.Unlock() - fake.SetPrivateDataValidationParameterStub = nil - fake.setPrivateDataValidationParameterReturns = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) SetPrivateDataValidationParameterReturnsOnCall(i int, result1 error) { - fake.setPrivateDataValidationParameterMutex.Lock() - defer fake.setPrivateDataValidationParameterMutex.Unlock() - fake.SetPrivateDataValidationParameterStub = nil - if fake.setPrivateDataValidationParameterReturnsOnCall == nil { - fake.setPrivateDataValidationParameterReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.setPrivateDataValidationParameterReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) SetStateValidationParameter(arg1 string, arg2 []byte) error { - var arg2Copy []byte - if arg2 != nil { - arg2Copy = make([]byte, len(arg2)) - copy(arg2Copy, arg2) - } - fake.setStateValidationParameterMutex.Lock() - ret, specificReturn := fake.setStateValidationParameterReturnsOnCall[len(fake.setStateValidationParameterArgsForCall)] - fake.setStateValidationParameterArgsForCall = append(fake.setStateValidationParameterArgsForCall, struct { - arg1 string - arg2 []byte - }{arg1, arg2Copy}) - stub := fake.SetStateValidationParameterStub - fakeReturns := fake.setStateValidationParameterReturns - fake.recordInvocation("SetStateValidationParameter", []interface{}{arg1, arg2Copy}) - fake.setStateValidationParameterMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ChaincodeStub) SetStateValidationParameterCallCount() int { - fake.setStateValidationParameterMutex.RLock() - defer fake.setStateValidationParameterMutex.RUnlock() - return len(fake.setStateValidationParameterArgsForCall) -} - -func (fake *ChaincodeStub) SetStateValidationParameterCalls(stub func(string, []byte) error) { - fake.setStateValidationParameterMutex.Lock() - defer fake.setStateValidationParameterMutex.Unlock() - fake.SetStateValidationParameterStub = stub -} - -func (fake *ChaincodeStub) SetStateValidationParameterArgsForCall(i int) (string, []byte) { - fake.setStateValidationParameterMutex.RLock() - defer fake.setStateValidationParameterMutex.RUnlock() - argsForCall := fake.setStateValidationParameterArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ChaincodeStub) SetStateValidationParameterReturns(result1 error) { - fake.setStateValidationParameterMutex.Lock() - defer fake.setStateValidationParameterMutex.Unlock() - fake.SetStateValidationParameterStub = nil - fake.setStateValidationParameterReturns = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) SetStateValidationParameterReturnsOnCall(i int, result1 error) { - fake.setStateValidationParameterMutex.Lock() - defer fake.setStateValidationParameterMutex.Unlock() - fake.SetStateValidationParameterStub = nil - if fake.setStateValidationParameterReturnsOnCall == nil { - fake.setStateValidationParameterReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.setStateValidationParameterReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *ChaincodeStub) SplitCompositeKey(arg1 string) (string, []string, error) { - fake.splitCompositeKeyMutex.Lock() - ret, specificReturn := fake.splitCompositeKeyReturnsOnCall[len(fake.splitCompositeKeyArgsForCall)] - fake.splitCompositeKeyArgsForCall = append(fake.splitCompositeKeyArgsForCall, struct { - arg1 string - }{arg1}) - stub := fake.SplitCompositeKeyStub - fakeReturns := fake.splitCompositeKeyReturns - fake.recordInvocation("SplitCompositeKey", []interface{}{arg1}) - fake.splitCompositeKeyMutex.Unlock() - if stub != nil { - return stub(arg1) - } - if specificReturn { - return ret.result1, ret.result2, ret.result3 - } - return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3 -} - -func (fake *ChaincodeStub) SplitCompositeKeyCallCount() int { - fake.splitCompositeKeyMutex.RLock() - defer fake.splitCompositeKeyMutex.RUnlock() - return len(fake.splitCompositeKeyArgsForCall) -} - -func (fake *ChaincodeStub) SplitCompositeKeyCalls(stub func(string) (string, []string, error)) { - fake.splitCompositeKeyMutex.Lock() - defer fake.splitCompositeKeyMutex.Unlock() - fake.SplitCompositeKeyStub = stub -} - -func (fake *ChaincodeStub) SplitCompositeKeyArgsForCall(i int) string { - fake.splitCompositeKeyMutex.RLock() - defer fake.splitCompositeKeyMutex.RUnlock() - argsForCall := fake.splitCompositeKeyArgsForCall[i] - return argsForCall.arg1 -} - -func (fake *ChaincodeStub) SplitCompositeKeyReturns(result1 string, result2 []string, result3 error) { - fake.splitCompositeKeyMutex.Lock() - defer fake.splitCompositeKeyMutex.Unlock() - fake.SplitCompositeKeyStub = nil - fake.splitCompositeKeyReturns = struct { - result1 string - result2 []string - result3 error - }{result1, result2, result3} -} - -func (fake *ChaincodeStub) SplitCompositeKeyReturnsOnCall(i int, result1 string, result2 []string, result3 error) { - fake.splitCompositeKeyMutex.Lock() - defer fake.splitCompositeKeyMutex.Unlock() - fake.SplitCompositeKeyStub = nil - if fake.splitCompositeKeyReturnsOnCall == nil { - fake.splitCompositeKeyReturnsOnCall = make(map[int]struct { - result1 string - result2 []string - result3 error - }) - } - fake.splitCompositeKeyReturnsOnCall[i] = struct { - result1 string - result2 []string - result3 error - }{result1, result2, result3} -} - -func (fake *ChaincodeStub) Invocations() map[string][][]interface{} { - fake.invocationsMutex.RLock() - defer fake.invocationsMutex.RUnlock() - fake.createCompositeKeyMutex.RLock() - defer fake.createCompositeKeyMutex.RUnlock() - fake.delPrivateDataMutex.RLock() - defer fake.delPrivateDataMutex.RUnlock() - fake.delStateMutex.RLock() - defer fake.delStateMutex.RUnlock() - fake.getArgsMutex.RLock() - defer fake.getArgsMutex.RUnlock() - fake.getArgsSliceMutex.RLock() - defer fake.getArgsSliceMutex.RUnlock() - fake.getBindingMutex.RLock() - defer fake.getBindingMutex.RUnlock() - fake.getChannelIDMutex.RLock() - defer fake.getChannelIDMutex.RUnlock() - fake.getCreatorMutex.RLock() - defer fake.getCreatorMutex.RUnlock() - fake.getDecorationsMutex.RLock() - defer fake.getDecorationsMutex.RUnlock() - fake.getFunctionAndParametersMutex.RLock() - defer fake.getFunctionAndParametersMutex.RUnlock() - fake.getHistoryForKeyMutex.RLock() - defer fake.getHistoryForKeyMutex.RUnlock() - fake.getPrivateDataMutex.RLock() - defer fake.getPrivateDataMutex.RUnlock() - fake.getPrivateDataByPartialCompositeKeyMutex.RLock() - defer fake.getPrivateDataByPartialCompositeKeyMutex.RUnlock() - fake.getPrivateDataByRangeMutex.RLock() - defer fake.getPrivateDataByRangeMutex.RUnlock() - fake.getPrivateDataHashMutex.RLock() - defer fake.getPrivateDataHashMutex.RUnlock() - fake.getPrivateDataQueryResultMutex.RLock() - defer fake.getPrivateDataQueryResultMutex.RUnlock() - fake.getPrivateDataValidationParameterMutex.RLock() - defer fake.getPrivateDataValidationParameterMutex.RUnlock() - fake.getQueryResultMutex.RLock() - defer fake.getQueryResultMutex.RUnlock() - fake.getQueryResultWithPaginationMutex.RLock() - defer fake.getQueryResultWithPaginationMutex.RUnlock() - fake.getSignedProposalMutex.RLock() - defer fake.getSignedProposalMutex.RUnlock() - fake.getStateMutex.RLock() - defer fake.getStateMutex.RUnlock() - fake.getStateByPartialCompositeKeyMutex.RLock() - defer fake.getStateByPartialCompositeKeyMutex.RUnlock() - fake.getStateByPartialCompositeKeyWithPaginationMutex.RLock() - defer fake.getStateByPartialCompositeKeyWithPaginationMutex.RUnlock() - fake.getStateByRangeMutex.RLock() - defer fake.getStateByRangeMutex.RUnlock() - fake.getStateByRangeWithPaginationMutex.RLock() - defer fake.getStateByRangeWithPaginationMutex.RUnlock() - fake.getStateValidationParameterMutex.RLock() - defer fake.getStateValidationParameterMutex.RUnlock() - fake.getStringArgsMutex.RLock() - defer fake.getStringArgsMutex.RUnlock() - fake.getTransientMutex.RLock() - defer fake.getTransientMutex.RUnlock() - fake.getTxIDMutex.RLock() - defer fake.getTxIDMutex.RUnlock() - fake.getTxTimestampMutex.RLock() - defer fake.getTxTimestampMutex.RUnlock() - fake.invokeChaincodeMutex.RLock() - defer fake.invokeChaincodeMutex.RUnlock() - fake.purgePrivateDataMutex.RLock() - defer fake.purgePrivateDataMutex.RUnlock() - fake.putPrivateDataMutex.RLock() - defer fake.putPrivateDataMutex.RUnlock() - fake.putStateMutex.RLock() - defer fake.putStateMutex.RUnlock() - fake.setEventMutex.RLock() - defer fake.setEventMutex.RUnlock() - fake.setPrivateDataValidationParameterMutex.RLock() - defer fake.setPrivateDataValidationParameterMutex.RUnlock() - fake.setStateValidationParameterMutex.RLock() - defer fake.setStateValidationParameterMutex.RUnlock() - fake.splitCompositeKeyMutex.RLock() - defer fake.splitCompositeKeyMutex.RUnlock() - copiedInvocations := map[string][][]interface{}{} - for key, value := range fake.invocations { - copiedInvocations[key] = value - } - return copiedInvocations -} - -func (fake *ChaincodeStub) recordInvocation(key string, args []interface{}) { - fake.invocationsMutex.Lock() - defer fake.invocationsMutex.Unlock() - if fake.invocations == nil { - fake.invocations = map[string][][]interface{}{} - } - if fake.invocations[key] == nil { - fake.invocations[key] = [][]interface{}{} - } - fake.invocations[key] = append(fake.invocations[key], args) -} diff --git a/asset-transfer-private-data/chaincode-go/chaincode/mocks/clientIdentity.go b/asset-transfer-private-data/chaincode-go/chaincode/mocks/clientIdentity.go deleted file mode 100644 index 79bf75dd..00000000 --- a/asset-transfer-private-data/chaincode-go/chaincode/mocks/clientIdentity.go +++ /dev/null @@ -1,404 +0,0 @@ -// Code generated by counterfeiter. DO NOT EDIT. -package mocks - -import ( - "crypto/x509" - "sync" -) - -type ClientIdentity struct { - AssertAttributeValueStub func(string, string) error - assertAttributeValueMutex sync.RWMutex - assertAttributeValueArgsForCall []struct { - arg1 string - arg2 string - } - assertAttributeValueReturns struct { - result1 error - } - assertAttributeValueReturnsOnCall map[int]struct { - result1 error - } - GetAttributeValueStub func(string) (string, bool, error) - getAttributeValueMutex sync.RWMutex - getAttributeValueArgsForCall []struct { - arg1 string - } - getAttributeValueReturns struct { - result1 string - result2 bool - result3 error - } - getAttributeValueReturnsOnCall map[int]struct { - result1 string - result2 bool - result3 error - } - GetIDStub func() (string, error) - getIDMutex sync.RWMutex - getIDArgsForCall []struct { - } - getIDReturns struct { - result1 string - result2 error - } - getIDReturnsOnCall map[int]struct { - result1 string - result2 error - } - GetMSPIDStub func() (string, error) - getMSPIDMutex sync.RWMutex - getMSPIDArgsForCall []struct { - } - getMSPIDReturns struct { - result1 string - result2 error - } - getMSPIDReturnsOnCall map[int]struct { - result1 string - result2 error - } - GetX509CertificateStub func() (*x509.Certificate, error) - getX509CertificateMutex sync.RWMutex - getX509CertificateArgsForCall []struct { - } - getX509CertificateReturns struct { - result1 *x509.Certificate - result2 error - } - getX509CertificateReturnsOnCall map[int]struct { - result1 *x509.Certificate - result2 error - } - invocations map[string][][]interface{} - invocationsMutex sync.RWMutex -} - -func (fake *ClientIdentity) AssertAttributeValue(arg1 string, arg2 string) error { - fake.assertAttributeValueMutex.Lock() - ret, specificReturn := fake.assertAttributeValueReturnsOnCall[len(fake.assertAttributeValueArgsForCall)] - fake.assertAttributeValueArgsForCall = append(fake.assertAttributeValueArgsForCall, struct { - arg1 string - arg2 string - }{arg1, arg2}) - stub := fake.AssertAttributeValueStub - fakeReturns := fake.assertAttributeValueReturns - fake.recordInvocation("AssertAttributeValue", []interface{}{arg1, arg2}) - fake.assertAttributeValueMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *ClientIdentity) AssertAttributeValueCallCount() int { - fake.assertAttributeValueMutex.RLock() - defer fake.assertAttributeValueMutex.RUnlock() - return len(fake.assertAttributeValueArgsForCall) -} - -func (fake *ClientIdentity) AssertAttributeValueCalls(stub func(string, string) error) { - fake.assertAttributeValueMutex.Lock() - defer fake.assertAttributeValueMutex.Unlock() - fake.AssertAttributeValueStub = stub -} - -func (fake *ClientIdentity) AssertAttributeValueArgsForCall(i int) (string, string) { - fake.assertAttributeValueMutex.RLock() - defer fake.assertAttributeValueMutex.RUnlock() - argsForCall := fake.assertAttributeValueArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *ClientIdentity) AssertAttributeValueReturns(result1 error) { - fake.assertAttributeValueMutex.Lock() - defer fake.assertAttributeValueMutex.Unlock() - fake.AssertAttributeValueStub = nil - fake.assertAttributeValueReturns = struct { - result1 error - }{result1} -} - -func (fake *ClientIdentity) AssertAttributeValueReturnsOnCall(i int, result1 error) { - fake.assertAttributeValueMutex.Lock() - defer fake.assertAttributeValueMutex.Unlock() - fake.AssertAttributeValueStub = nil - if fake.assertAttributeValueReturnsOnCall == nil { - fake.assertAttributeValueReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.assertAttributeValueReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *ClientIdentity) GetAttributeValue(arg1 string) (string, bool, error) { - fake.getAttributeValueMutex.Lock() - ret, specificReturn := fake.getAttributeValueReturnsOnCall[len(fake.getAttributeValueArgsForCall)] - fake.getAttributeValueArgsForCall = append(fake.getAttributeValueArgsForCall, struct { - arg1 string - }{arg1}) - stub := fake.GetAttributeValueStub - fakeReturns := fake.getAttributeValueReturns - fake.recordInvocation("GetAttributeValue", []interface{}{arg1}) - fake.getAttributeValueMutex.Unlock() - if stub != nil { - return stub(arg1) - } - if specificReturn { - return ret.result1, ret.result2, ret.result3 - } - return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3 -} - -func (fake *ClientIdentity) GetAttributeValueCallCount() int { - fake.getAttributeValueMutex.RLock() - defer fake.getAttributeValueMutex.RUnlock() - return len(fake.getAttributeValueArgsForCall) -} - -func (fake *ClientIdentity) GetAttributeValueCalls(stub func(string) (string, bool, error)) { - fake.getAttributeValueMutex.Lock() - defer fake.getAttributeValueMutex.Unlock() - fake.GetAttributeValueStub = stub -} - -func (fake *ClientIdentity) GetAttributeValueArgsForCall(i int) string { - fake.getAttributeValueMutex.RLock() - defer fake.getAttributeValueMutex.RUnlock() - argsForCall := fake.getAttributeValueArgsForCall[i] - return argsForCall.arg1 -} - -func (fake *ClientIdentity) GetAttributeValueReturns(result1 string, result2 bool, result3 error) { - fake.getAttributeValueMutex.Lock() - defer fake.getAttributeValueMutex.Unlock() - fake.GetAttributeValueStub = nil - fake.getAttributeValueReturns = struct { - result1 string - result2 bool - result3 error - }{result1, result2, result3} -} - -func (fake *ClientIdentity) GetAttributeValueReturnsOnCall(i int, result1 string, result2 bool, result3 error) { - fake.getAttributeValueMutex.Lock() - defer fake.getAttributeValueMutex.Unlock() - fake.GetAttributeValueStub = nil - if fake.getAttributeValueReturnsOnCall == nil { - fake.getAttributeValueReturnsOnCall = make(map[int]struct { - result1 string - result2 bool - result3 error - }) - } - fake.getAttributeValueReturnsOnCall[i] = struct { - result1 string - result2 bool - result3 error - }{result1, result2, result3} -} - -func (fake *ClientIdentity) GetID() (string, error) { - fake.getIDMutex.Lock() - ret, specificReturn := fake.getIDReturnsOnCall[len(fake.getIDArgsForCall)] - fake.getIDArgsForCall = append(fake.getIDArgsForCall, struct { - }{}) - stub := fake.GetIDStub - fakeReturns := fake.getIDReturns - fake.recordInvocation("GetID", []interface{}{}) - fake.getIDMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ClientIdentity) GetIDCallCount() int { - fake.getIDMutex.RLock() - defer fake.getIDMutex.RUnlock() - return len(fake.getIDArgsForCall) -} - -func (fake *ClientIdentity) GetIDCalls(stub func() (string, error)) { - fake.getIDMutex.Lock() - defer fake.getIDMutex.Unlock() - fake.GetIDStub = stub -} - -func (fake *ClientIdentity) GetIDReturns(result1 string, result2 error) { - fake.getIDMutex.Lock() - defer fake.getIDMutex.Unlock() - fake.GetIDStub = nil - fake.getIDReturns = struct { - result1 string - result2 error - }{result1, result2} -} - -func (fake *ClientIdentity) GetIDReturnsOnCall(i int, result1 string, result2 error) { - fake.getIDMutex.Lock() - defer fake.getIDMutex.Unlock() - fake.GetIDStub = nil - if fake.getIDReturnsOnCall == nil { - fake.getIDReturnsOnCall = make(map[int]struct { - result1 string - result2 error - }) - } - fake.getIDReturnsOnCall[i] = struct { - result1 string - result2 error - }{result1, result2} -} - -func (fake *ClientIdentity) GetMSPID() (string, error) { - fake.getMSPIDMutex.Lock() - ret, specificReturn := fake.getMSPIDReturnsOnCall[len(fake.getMSPIDArgsForCall)] - fake.getMSPIDArgsForCall = append(fake.getMSPIDArgsForCall, struct { - }{}) - stub := fake.GetMSPIDStub - fakeReturns := fake.getMSPIDReturns - fake.recordInvocation("GetMSPID", []interface{}{}) - fake.getMSPIDMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ClientIdentity) GetMSPIDCallCount() int { - fake.getMSPIDMutex.RLock() - defer fake.getMSPIDMutex.RUnlock() - return len(fake.getMSPIDArgsForCall) -} - -func (fake *ClientIdentity) GetMSPIDCalls(stub func() (string, error)) { - fake.getMSPIDMutex.Lock() - defer fake.getMSPIDMutex.Unlock() - fake.GetMSPIDStub = stub -} - -func (fake *ClientIdentity) GetMSPIDReturns(result1 string, result2 error) { - fake.getMSPIDMutex.Lock() - defer fake.getMSPIDMutex.Unlock() - fake.GetMSPIDStub = nil - fake.getMSPIDReturns = struct { - result1 string - result2 error - }{result1, result2} -} - -func (fake *ClientIdentity) GetMSPIDReturnsOnCall(i int, result1 string, result2 error) { - fake.getMSPIDMutex.Lock() - defer fake.getMSPIDMutex.Unlock() - fake.GetMSPIDStub = nil - if fake.getMSPIDReturnsOnCall == nil { - fake.getMSPIDReturnsOnCall = make(map[int]struct { - result1 string - result2 error - }) - } - fake.getMSPIDReturnsOnCall[i] = struct { - result1 string - result2 error - }{result1, result2} -} - -func (fake *ClientIdentity) GetX509Certificate() (*x509.Certificate, error) { - fake.getX509CertificateMutex.Lock() - ret, specificReturn := fake.getX509CertificateReturnsOnCall[len(fake.getX509CertificateArgsForCall)] - fake.getX509CertificateArgsForCall = append(fake.getX509CertificateArgsForCall, struct { - }{}) - stub := fake.GetX509CertificateStub - fakeReturns := fake.getX509CertificateReturns - fake.recordInvocation("GetX509Certificate", []interface{}{}) - fake.getX509CertificateMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *ClientIdentity) GetX509CertificateCallCount() int { - fake.getX509CertificateMutex.RLock() - defer fake.getX509CertificateMutex.RUnlock() - return len(fake.getX509CertificateArgsForCall) -} - -func (fake *ClientIdentity) GetX509CertificateCalls(stub func() (*x509.Certificate, error)) { - fake.getX509CertificateMutex.Lock() - defer fake.getX509CertificateMutex.Unlock() - fake.GetX509CertificateStub = stub -} - -func (fake *ClientIdentity) GetX509CertificateReturns(result1 *x509.Certificate, result2 error) { - fake.getX509CertificateMutex.Lock() - defer fake.getX509CertificateMutex.Unlock() - fake.GetX509CertificateStub = nil - fake.getX509CertificateReturns = struct { - result1 *x509.Certificate - result2 error - }{result1, result2} -} - -func (fake *ClientIdentity) GetX509CertificateReturnsOnCall(i int, result1 *x509.Certificate, result2 error) { - fake.getX509CertificateMutex.Lock() - defer fake.getX509CertificateMutex.Unlock() - fake.GetX509CertificateStub = nil - if fake.getX509CertificateReturnsOnCall == nil { - fake.getX509CertificateReturnsOnCall = make(map[int]struct { - result1 *x509.Certificate - result2 error - }) - } - fake.getX509CertificateReturnsOnCall[i] = struct { - result1 *x509.Certificate - result2 error - }{result1, result2} -} - -func (fake *ClientIdentity) Invocations() map[string][][]interface{} { - fake.invocationsMutex.RLock() - defer fake.invocationsMutex.RUnlock() - fake.assertAttributeValueMutex.RLock() - defer fake.assertAttributeValueMutex.RUnlock() - fake.getAttributeValueMutex.RLock() - defer fake.getAttributeValueMutex.RUnlock() - fake.getIDMutex.RLock() - defer fake.getIDMutex.RUnlock() - fake.getMSPIDMutex.RLock() - defer fake.getMSPIDMutex.RUnlock() - fake.getX509CertificateMutex.RLock() - defer fake.getX509CertificateMutex.RUnlock() - copiedInvocations := map[string][][]interface{}{} - for key, value := range fake.invocations { - copiedInvocations[key] = value - } - return copiedInvocations -} - -func (fake *ClientIdentity) recordInvocation(key string, args []interface{}) { - fake.invocationsMutex.Lock() - defer fake.invocationsMutex.Unlock() - if fake.invocations == nil { - fake.invocations = map[string][][]interface{}{} - } - if fake.invocations[key] == nil { - fake.invocations[key] = [][]interface{}{} - } - fake.invocations[key] = append(fake.invocations[key], args) -} diff --git a/asset-transfer-private-data/chaincode-go/chaincode/mocks/statequeryiterator.go b/asset-transfer-private-data/chaincode-go/chaincode/mocks/statequeryiterator.go deleted file mode 100644 index 76cdcaa1..00000000 --- a/asset-transfer-private-data/chaincode-go/chaincode/mocks/statequeryiterator.go +++ /dev/null @@ -1,235 +0,0 @@ -// Code generated by counterfeiter. DO NOT EDIT. -package mocks - -import ( - "sync" - - "github.com/hyperledger/fabric-protos-go-apiv2/ledger/queryresult" -) - -type StateQueryIterator struct { - CloseStub func() error - closeMutex sync.RWMutex - closeArgsForCall []struct { - } - closeReturns struct { - result1 error - } - closeReturnsOnCall map[int]struct { - result1 error - } - HasNextStub func() bool - hasNextMutex sync.RWMutex - hasNextArgsForCall []struct { - } - hasNextReturns struct { - result1 bool - } - hasNextReturnsOnCall map[int]struct { - result1 bool - } - NextStub func() (*queryresult.KV, error) - nextMutex sync.RWMutex - nextArgsForCall []struct { - } - nextReturns struct { - result1 *queryresult.KV - result2 error - } - nextReturnsOnCall map[int]struct { - result1 *queryresult.KV - result2 error - } - invocations map[string][][]interface{} - invocationsMutex sync.RWMutex -} - -func (fake *StateQueryIterator) Close() error { - fake.closeMutex.Lock() - ret, specificReturn := fake.closeReturnsOnCall[len(fake.closeArgsForCall)] - fake.closeArgsForCall = append(fake.closeArgsForCall, struct { - }{}) - stub := fake.CloseStub - fakeReturns := fake.closeReturns - fake.recordInvocation("Close", []interface{}{}) - fake.closeMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *StateQueryIterator) CloseCallCount() int { - fake.closeMutex.RLock() - defer fake.closeMutex.RUnlock() - return len(fake.closeArgsForCall) -} - -func (fake *StateQueryIterator) CloseCalls(stub func() error) { - fake.closeMutex.Lock() - defer fake.closeMutex.Unlock() - fake.CloseStub = stub -} - -func (fake *StateQueryIterator) CloseReturns(result1 error) { - fake.closeMutex.Lock() - defer fake.closeMutex.Unlock() - fake.CloseStub = nil - fake.closeReturns = struct { - result1 error - }{result1} -} - -func (fake *StateQueryIterator) CloseReturnsOnCall(i int, result1 error) { - fake.closeMutex.Lock() - defer fake.closeMutex.Unlock() - fake.CloseStub = nil - if fake.closeReturnsOnCall == nil { - fake.closeReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.closeReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *StateQueryIterator) HasNext() bool { - fake.hasNextMutex.Lock() - ret, specificReturn := fake.hasNextReturnsOnCall[len(fake.hasNextArgsForCall)] - fake.hasNextArgsForCall = append(fake.hasNextArgsForCall, struct { - }{}) - stub := fake.HasNextStub - fakeReturns := fake.hasNextReturns - fake.recordInvocation("HasNext", []interface{}{}) - fake.hasNextMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *StateQueryIterator) HasNextCallCount() int { - fake.hasNextMutex.RLock() - defer fake.hasNextMutex.RUnlock() - return len(fake.hasNextArgsForCall) -} - -func (fake *StateQueryIterator) HasNextCalls(stub func() bool) { - fake.hasNextMutex.Lock() - defer fake.hasNextMutex.Unlock() - fake.HasNextStub = stub -} - -func (fake *StateQueryIterator) HasNextReturns(result1 bool) { - fake.hasNextMutex.Lock() - defer fake.hasNextMutex.Unlock() - fake.HasNextStub = nil - fake.hasNextReturns = struct { - result1 bool - }{result1} -} - -func (fake *StateQueryIterator) HasNextReturnsOnCall(i int, result1 bool) { - fake.hasNextMutex.Lock() - defer fake.hasNextMutex.Unlock() - fake.HasNextStub = nil - if fake.hasNextReturnsOnCall == nil { - fake.hasNextReturnsOnCall = make(map[int]struct { - result1 bool - }) - } - fake.hasNextReturnsOnCall[i] = struct { - result1 bool - }{result1} -} - -func (fake *StateQueryIterator) Next() (*queryresult.KV, error) { - fake.nextMutex.Lock() - ret, specificReturn := fake.nextReturnsOnCall[len(fake.nextArgsForCall)] - fake.nextArgsForCall = append(fake.nextArgsForCall, struct { - }{}) - stub := fake.NextStub - fakeReturns := fake.nextReturns - fake.recordInvocation("Next", []interface{}{}) - fake.nextMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1, ret.result2 - } - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *StateQueryIterator) NextCallCount() int { - fake.nextMutex.RLock() - defer fake.nextMutex.RUnlock() - return len(fake.nextArgsForCall) -} - -func (fake *StateQueryIterator) NextCalls(stub func() (*queryresult.KV, error)) { - fake.nextMutex.Lock() - defer fake.nextMutex.Unlock() - fake.NextStub = stub -} - -func (fake *StateQueryIterator) NextReturns(result1 *queryresult.KV, result2 error) { - fake.nextMutex.Lock() - defer fake.nextMutex.Unlock() - fake.NextStub = nil - fake.nextReturns = struct { - result1 *queryresult.KV - result2 error - }{result1, result2} -} - -func (fake *StateQueryIterator) NextReturnsOnCall(i int, result1 *queryresult.KV, result2 error) { - fake.nextMutex.Lock() - defer fake.nextMutex.Unlock() - fake.NextStub = nil - if fake.nextReturnsOnCall == nil { - fake.nextReturnsOnCall = make(map[int]struct { - result1 *queryresult.KV - result2 error - }) - } - fake.nextReturnsOnCall[i] = struct { - result1 *queryresult.KV - result2 error - }{result1, result2} -} - -func (fake *StateQueryIterator) Invocations() map[string][][]interface{} { - fake.invocationsMutex.RLock() - defer fake.invocationsMutex.RUnlock() - fake.closeMutex.RLock() - defer fake.closeMutex.RUnlock() - fake.hasNextMutex.RLock() - defer fake.hasNextMutex.RUnlock() - fake.nextMutex.RLock() - defer fake.nextMutex.RUnlock() - copiedInvocations := map[string][][]interface{}{} - for key, value := range fake.invocations { - copiedInvocations[key] = value - } - return copiedInvocations -} - -func (fake *StateQueryIterator) recordInvocation(key string, args []interface{}) { - fake.invocationsMutex.Lock() - defer fake.invocationsMutex.Unlock() - if fake.invocations == nil { - fake.invocations = map[string][][]interface{}{} - } - if fake.invocations[key] == nil { - fake.invocations[key] = [][]interface{}{} - } - fake.invocations[key] = append(fake.invocations[key], args) -} diff --git a/asset-transfer-private-data/chaincode-go/chaincode/mocks/transaction.go b/asset-transfer-private-data/chaincode-go/chaincode/mocks/transaction.go deleted file mode 100644 index 5e98d069..00000000 --- a/asset-transfer-private-data/chaincode-go/chaincode/mocks/transaction.go +++ /dev/null @@ -1,166 +0,0 @@ -// Code generated by counterfeiter. DO NOT EDIT. -package mocks - -import ( - "sync" - - "github.com/hyperledger/fabric-chaincode-go/v2/pkg/cid" - "github.com/hyperledger/fabric-chaincode-go/v2/shim" -) - -type TransactionContext struct { - GetClientIdentityStub func() cid.ClientIdentity - getClientIdentityMutex sync.RWMutex - getClientIdentityArgsForCall []struct { - } - getClientIdentityReturns struct { - result1 cid.ClientIdentity - } - getClientIdentityReturnsOnCall map[int]struct { - result1 cid.ClientIdentity - } - GetStubStub func() shim.ChaincodeStubInterface - getStubMutex sync.RWMutex - getStubArgsForCall []struct { - } - getStubReturns struct { - result1 shim.ChaincodeStubInterface - } - getStubReturnsOnCall map[int]struct { - result1 shim.ChaincodeStubInterface - } - invocations map[string][][]interface{} - invocationsMutex sync.RWMutex -} - -func (fake *TransactionContext) GetClientIdentity() cid.ClientIdentity { - fake.getClientIdentityMutex.Lock() - ret, specificReturn := fake.getClientIdentityReturnsOnCall[len(fake.getClientIdentityArgsForCall)] - fake.getClientIdentityArgsForCall = append(fake.getClientIdentityArgsForCall, struct { - }{}) - stub := fake.GetClientIdentityStub - fakeReturns := fake.getClientIdentityReturns - fake.recordInvocation("GetClientIdentity", []interface{}{}) - fake.getClientIdentityMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *TransactionContext) GetClientIdentityCallCount() int { - fake.getClientIdentityMutex.RLock() - defer fake.getClientIdentityMutex.RUnlock() - return len(fake.getClientIdentityArgsForCall) -} - -func (fake *TransactionContext) GetClientIdentityCalls(stub func() cid.ClientIdentity) { - fake.getClientIdentityMutex.Lock() - defer fake.getClientIdentityMutex.Unlock() - fake.GetClientIdentityStub = stub -} - -func (fake *TransactionContext) GetClientIdentityReturns(result1 cid.ClientIdentity) { - fake.getClientIdentityMutex.Lock() - defer fake.getClientIdentityMutex.Unlock() - fake.GetClientIdentityStub = nil - fake.getClientIdentityReturns = struct { - result1 cid.ClientIdentity - }{result1} -} - -func (fake *TransactionContext) GetClientIdentityReturnsOnCall(i int, result1 cid.ClientIdentity) { - fake.getClientIdentityMutex.Lock() - defer fake.getClientIdentityMutex.Unlock() - fake.GetClientIdentityStub = nil - if fake.getClientIdentityReturnsOnCall == nil { - fake.getClientIdentityReturnsOnCall = make(map[int]struct { - result1 cid.ClientIdentity - }) - } - fake.getClientIdentityReturnsOnCall[i] = struct { - result1 cid.ClientIdentity - }{result1} -} - -func (fake *TransactionContext) GetStub() shim.ChaincodeStubInterface { - fake.getStubMutex.Lock() - ret, specificReturn := fake.getStubReturnsOnCall[len(fake.getStubArgsForCall)] - fake.getStubArgsForCall = append(fake.getStubArgsForCall, struct { - }{}) - stub := fake.GetStubStub - fakeReturns := fake.getStubReturns - fake.recordInvocation("GetStub", []interface{}{}) - fake.getStubMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *TransactionContext) GetStubCallCount() int { - fake.getStubMutex.RLock() - defer fake.getStubMutex.RUnlock() - return len(fake.getStubArgsForCall) -} - -func (fake *TransactionContext) GetStubCalls(stub func() shim.ChaincodeStubInterface) { - fake.getStubMutex.Lock() - defer fake.getStubMutex.Unlock() - fake.GetStubStub = stub -} - -func (fake *TransactionContext) GetStubReturns(result1 shim.ChaincodeStubInterface) { - fake.getStubMutex.Lock() - defer fake.getStubMutex.Unlock() - fake.GetStubStub = nil - fake.getStubReturns = struct { - result1 shim.ChaincodeStubInterface - }{result1} -} - -func (fake *TransactionContext) GetStubReturnsOnCall(i int, result1 shim.ChaincodeStubInterface) { - fake.getStubMutex.Lock() - defer fake.getStubMutex.Unlock() - fake.GetStubStub = nil - if fake.getStubReturnsOnCall == nil { - fake.getStubReturnsOnCall = make(map[int]struct { - result1 shim.ChaincodeStubInterface - }) - } - fake.getStubReturnsOnCall[i] = struct { - result1 shim.ChaincodeStubInterface - }{result1} -} - -func (fake *TransactionContext) Invocations() map[string][][]interface{} { - fake.invocationsMutex.RLock() - defer fake.invocationsMutex.RUnlock() - fake.getClientIdentityMutex.RLock() - defer fake.getClientIdentityMutex.RUnlock() - fake.getStubMutex.RLock() - defer fake.getStubMutex.RUnlock() - copiedInvocations := map[string][][]interface{}{} - for key, value := range fake.invocations { - copiedInvocations[key] = value - } - return copiedInvocations -} - -func (fake *TransactionContext) recordInvocation(key string, args []interface{}) { - fake.invocationsMutex.Lock() - defer fake.invocationsMutex.Unlock() - if fake.invocations == nil { - fake.invocations = map[string][][]interface{}{} - } - if fake.invocations[key] == nil { - fake.invocations[key] = [][]interface{}{} - } - fake.invocations[key] = append(fake.invocations[key], args) -} diff --git a/asset-transfer-private-data/chaincode-go/collections_config.json b/asset-transfer-private-data/chaincode-go/collections_config.json deleted file mode 100644 index 993bbd31..00000000 --- a/asset-transfer-private-data/chaincode-go/collections_config.json +++ /dev/null @@ -1,38 +0,0 @@ -[ - { - "name": "assetCollection", - "policy": "OR('Org1MSP.member', 'Org2MSP.member')", - "requiredPeerCount": 1, - "maxPeerCount": 1, - "blockToLive":1000000, - "memberOnlyRead": true, - "memberOnlyWrite": true, - "endorsementPolicy": { - "signaturePolicy":"OR('Org1MSP.member','Org2MSP.member')" - } -}, - { - "name": "Org1MSPPrivateCollection", - "policy": "OR('Org1MSP.member')", - "requiredPeerCount": 0, - "maxPeerCount": 1, - "blockToLive":3, - "memberOnlyRead": true, - "memberOnlyWrite": false, - "endorsementPolicy": { - "signaturePolicy": "OR('Org1MSP.member')" - } - }, - { - "name": "Org2MSPPrivateCollection", - "policy": "OR('Org2MSP.member')", - "requiredPeerCount": 0, - "maxPeerCount": 1, - "blockToLive":3, - "memberOnlyRead": true, - "memberOnlyWrite": false, - "endorsementPolicy": { - "signaturePolicy": "OR('Org2MSP.member')" - } - } -] diff --git a/asset-transfer-private-data/chaincode-go/go.mod b/asset-transfer-private-data/chaincode-go/go.mod deleted file mode 100644 index 15836147..00000000 --- a/asset-transfer-private-data/chaincode-go/go.mod +++ /dev/null @@ -1,31 +0,0 @@ -module github.com/hyperledger/fabric-samples/asset-transfer-private-data/chaincode-go - -go 1.22.0 - -require ( - github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0 - github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0 - github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 - github.com/stretchr/testify v1.10.0 - google.golang.org/protobuf v1.36.1 -) - -require ( - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xeipuuv/gojsonschema v1.2.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect - google.golang.org/grpc v1.67.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/asset-transfer-private-data/chaincode-go/go.sum b/asset-transfer-private-data/chaincode-go/go.sum deleted file mode 100644 index fa4d3b24..00000000 --- a/asset-transfer-private-data/chaincode-go/go.sum +++ /dev/null @@ -1,61 +0,0 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0 h1:IhkHfrl5X/fVnmB6pWeCYCdIJRi9bxj+WTnVN8DtW3c= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0/go.mod h1:PHHaFffjw7p7n9bmCfcm7RqDqYdivNEsJdiNIKZo5Lk= -github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0 h1:rmUoBmciB0GL/miqcbJmJbgp5QTWoJUrZo+CNxrNLF4= -github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0/go.mod h1:FeWeO/jwGjiME7ak3GufqKIcwkejtzrDG4QxbfKydWs= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 h1:YJrd+gMaeY0/vsN0aS0QkEKTivGoUnSRIXxGJ7KI+Pc= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4/go.mod h1:bau/6AJhvEcu9GKKYHlDXAxXKzYNfhP6xu2GXuxEcFk= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= -google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= -google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/asset-transfer-private-data/chaincode-go/main.go b/asset-transfer-private-data/chaincode-go/main.go deleted file mode 100644 index 8f4032c7..00000000 --- a/asset-transfer-private-data/chaincode-go/main.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "log" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" - "github.com/hyperledger/fabric-samples/asset-transfer-private-data/chaincode-go/chaincode" -) - -func main() { - assetChaincode, err := contractapi.NewChaincode(&chaincode.SmartContract{}) - if err != nil { - log.Panicf("Error creating asset-transfer-private-data chaincode: %v", err) - } - - if err := assetChaincode.Start(); err != nil { - log.Panicf("Error starting asset-transfer-private-data chaincode: %v", err) - } -} diff --git a/asset-transfer-private-data/chaincode-java/.gitattributes b/asset-transfer-private-data/chaincode-java/.gitattributes deleted file mode 100644 index 00a51aff..00000000 --- a/asset-transfer-private-data/chaincode-java/.gitattributes +++ /dev/null @@ -1,6 +0,0 @@ -# -# https://help.github.com/articles/dealing-with-line-endings/ -# -# These are explicitly windows files and should use crlf -*.bat text eol=crlf - diff --git a/asset-transfer-private-data/chaincode-java/META-INF/statedb/couchdb/collections/assetCollection/indexes/indexOwner.json b/asset-transfer-private-data/chaincode-java/META-INF/statedb/couchdb/collections/assetCollection/indexes/indexOwner.json deleted file mode 100644 index 2e2a5c6d..00000000 --- a/asset-transfer-private-data/chaincode-java/META-INF/statedb/couchdb/collections/assetCollection/indexes/indexOwner.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "index": { - "fields": [ - "objectType", - "owner" - ] - }, - "ddoc": "indexOwnerDoc", - "name": "indexOwner", - "type": "json" -} diff --git a/asset-transfer-private-data/chaincode-java/build.gradle b/asset-transfer-private-data/chaincode-java/build.gradle deleted file mode 100644 index ec6a602c..00000000 --- a/asset-transfer-private-data/chaincode-java/build.gradle +++ /dev/null @@ -1,79 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -plugins { - id 'com.gradleup.shadow' version '8.3.5' - id 'application' - id 'checkstyle' - id 'jacoco' -} - -group 'org.hyperledger.fabric.samples' -version '1.0-SNAPSHOT' - -dependencies { - - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.+' - implementation 'org.json:json:+' - - testImplementation 'org.junit.jupiter:junit-jupiter:5.10.2' - testImplementation 'org.assertj:assertj-core:3.25.3' - testImplementation 'org.mockito:mockito-core:5.12.0' -} - -repositories { - mavenCentral() - maven { - url 'https://jitpack.io' - } -} - -java { - toolchain { - languageVersion = JavaLanguageVersion.of(11) - } -} - -application { - mainClass = 'org.hyperledger.fabric.contract.ContractRouter' -} - -checkstyle { - toolVersion '8.21' - configFile file("config/checkstyle/checkstyle.xml") -} - -checkstyleMain { - source ='src/main/java' -} - -checkstyleTest { - source ='src/test/java' -} - -jacocoTestReport { - dependsOn test -} - -test { - useJUnitPlatform() - testLogging { - events "passed", "skipped", "failed" - } -} - -mainClassName = 'org.hyperledger.fabric.contract.ContractRouter' - -shadowJar { - archiveBaseName = 'chaincode' - archiveVersion = '' - archiveClassifier = '' - mergeServiceFiles() - - manifest { - attributes 'Main-Class': 'org.hyperledger.fabric.contract.ContractRouter' - } -} - -installDist.dependsOn check diff --git a/asset-transfer-private-data/chaincode-java/collections_config.json b/asset-transfer-private-data/chaincode-java/collections_config.json deleted file mode 100644 index 6d67f3c3..00000000 --- a/asset-transfer-private-data/chaincode-java/collections_config.json +++ /dev/null @@ -1,38 +0,0 @@ -[ - { - "name": "assetCollection", - "policy": "OR('Org1MSP.member', 'Org2MSP.member')", - "requiredPeerCount": 1, - "maxPeerCount": 1, - "blockToLive":1000000, - "memberOnlyRead": true, - "memberOnlyWrite": true, - "endorsementPolicy": { - "signaturePolicy":"OR('Org1MSP.member','Org2MSP.member')" - } -}, - { - "name": "Org1MSPPrivateCollection", - "policy": "OR('Org1MSP.member')", - "requiredPeerCount": 0, - "maxPeerCount": 1, - "blockToLive":3, - "memberOnlyRead": true, - "memberOnlyWrite": false, - "endorsementPolicy": { - "signaturePolicy": "OR('Org1MSP.member')" - } - }, - { - "name": "Org2MSPPrivateCollection", - "policy": "OR('Org2MSP.member')", - "requiredPeerCount": 0, - "maxPeerCount": 1, - "blockToLive":3, - "memberOnlyRead": true, - "memberOnlyWrite": false, - "endorsementPolicy": { - "signaturePolicy": "OR('Org2MSP.member')" - } - } -] diff --git a/asset-transfer-private-data/chaincode-java/config/checkstyle/checkstyle.xml b/asset-transfer-private-data/chaincode-java/config/checkstyle/checkstyle.xml deleted file mode 100644 index acd5df44..00000000 --- a/asset-transfer-private-data/chaincode-java/config/checkstyle/checkstyle.xml +++ /dev/null @@ -1,171 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/asset-transfer-private-data/chaincode-java/config/checkstyle/suppressions.xml b/asset-transfer-private-data/chaincode-java/config/checkstyle/suppressions.xml deleted file mode 100644 index 33dda041..00000000 --- a/asset-transfer-private-data/chaincode-java/config/checkstyle/suppressions.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - diff --git a/asset-transfer-private-data/chaincode-java/gradle/wrapper/gradle-wrapper.jar b/asset-transfer-private-data/chaincode-java/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index d64cd4917707c1f8861d8cb53dd15194d4248596..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43462 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 diff --git a/asset-transfer-private-data/chaincode-java/gradle/wrapper/gradle-wrapper.properties b/asset-transfer-private-data/chaincode-java/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index e2847c82..00000000 --- a/asset-transfer-private-data/chaincode-java/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/asset-transfer-private-data/chaincode-java/gradlew b/asset-transfer-private-data/chaincode-java/gradlew deleted file mode 100755 index 1aa94a42..00000000 --- a/asset-transfer-private-data/chaincode-java/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/asset-transfer-private-data/chaincode-java/gradlew.bat b/asset-transfer-private-data/chaincode-java/gradlew.bat deleted file mode 100644 index 25da30db..00000000 --- a/asset-transfer-private-data/chaincode-java/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/asset-transfer-private-data/chaincode-java/settings.gradle b/asset-transfer-private-data/chaincode-java/settings.gradle deleted file mode 100644 index 59cbbbca..00000000 --- a/asset-transfer-private-data/chaincode-java/settings.gradle +++ /dev/null @@ -1,5 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -rootProject.name = 'private' diff --git a/asset-transfer-private-data/chaincode-java/src/main/java/org/hyperledger/fabric/samples/privatedata/Asset.java b/asset-transfer-private-data/chaincode-java/src/main/java/org/hyperledger/fabric/samples/privatedata/Asset.java deleted file mode 100644 index 11b29101..00000000 --- a/asset-transfer-private-data/chaincode-java/src/main/java/org/hyperledger/fabric/samples/privatedata/Asset.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.hyperledger.fabric.samples.privatedata; - -import java.util.Objects; - -import static java.nio.charset.StandardCharsets.UTF_8; - -import org.hyperledger.fabric.contract.annotation.DataType; -import org.hyperledger.fabric.contract.annotation.Property; - -import org.hyperledger.fabric.shim.ChaincodeException; -import org.json.JSONObject; - -@DataType() -public final class Asset { - - @Property() - private final String assetID; - - @Property() - private final String objectType; - - @Property() - private final String color; - - @Property() - private final int size; - - @Property() - private String owner; - - public String getAssetID() { - return assetID; - } - - public String getColor() { - return color; - } - - public int getSize() { - return size; - } - - public String getOwner() { - return owner; - } - - public String getObjectType() { - return objectType; - } - - public void setOwner(final String newowner) { - owner = newowner; - } - - public Asset(final String type, - final String assetID, final String color, - final int size, final String owner) { - this.objectType = type; - this.assetID = assetID; - this.color = color; - this.size = size; - this.owner = owner; - } - - public byte[] serialize() { - String jsonStr = new JSONObject(this).toString(); - return jsonStr.getBytes(UTF_8); - } - - public static Asset deserialize(final byte[] assetJSON) { - return deserialize(new String(assetJSON, UTF_8)); - } - - public static Asset deserialize(final String assetJSON) { - try { - JSONObject json = new JSONObject(assetJSON); - final String id = json.getString("assetID"); - final String type = json.getString("objectType"); - final String color = json.getString("color"); - final String owner = json.getString("owner"); - final int size = json.getInt("size"); - return new Asset(type, id, color, size, owner); - } catch (Exception e) { - throw new ChaincodeException("Deserialize error: " + e.getMessage(), "DATA_ERROR"); - } - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - - if ((obj == null) || (getClass() != obj.getClass())) { - return false; - } - - Asset other = (Asset) obj; - - return Objects.deepEquals( - new String[]{getAssetID(), getColor(), getOwner()}, - new String[]{other.getAssetID(), other.getColor(), other.getOwner()}) - && - Objects.deepEquals( - new int[]{getSize()}, - new int[]{other.getSize()}); - } - - @Override - public int hashCode() { - return Objects.hash(getObjectType(), getAssetID(), getColor(), getSize(), getOwner()); - } - - @Override - public String toString() { - return this.getClass().getSimpleName() + "@" + Integer.toHexString(hashCode()) - + " [assetID=" + assetID + ", type=" + objectType + ", color=" - + color + ", size=" + size + ", owner=" + owner + "]"; - } - - -} diff --git a/asset-transfer-private-data/chaincode-java/src/main/java/org/hyperledger/fabric/samples/privatedata/AssetPrivateDetails.java b/asset-transfer-private-data/chaincode-java/src/main/java/org/hyperledger/fabric/samples/privatedata/AssetPrivateDetails.java deleted file mode 100644 index da1c6e24..00000000 --- a/asset-transfer-private-data/chaincode-java/src/main/java/org/hyperledger/fabric/samples/privatedata/AssetPrivateDetails.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.hyperledger.fabric.samples.privatedata; - -import org.hyperledger.fabric.contract.annotation.DataType; -import org.hyperledger.fabric.contract.annotation.Property; - -import org.hyperledger.fabric.shim.ChaincodeException; -import org.json.JSONObject; - -import static java.nio.charset.StandardCharsets.UTF_8; - -@DataType() -public final class AssetPrivateDetails { - - @Property() - private final String assetID; - - @Property() - private int appraisedValue; - - public String getAssetID() { - return assetID; - } - - public int getAppraisedValue() { - return appraisedValue; - } - - public AssetPrivateDetails(final String assetID, - final int appraisedValue) { - this.assetID = assetID; - this.appraisedValue = appraisedValue; - } - - public byte[] serialize() { - String jsonStr = new JSONObject(this).toString(); - return jsonStr.getBytes(UTF_8); - } - - public static AssetPrivateDetails deserialize(final byte[] assetJSON) { - try { - JSONObject json = new JSONObject(new String(assetJSON, UTF_8)); - final String id = json.getString("assetID"); - final int appraisedValue = json.getInt("appraisedValue"); - return new AssetPrivateDetails(id, appraisedValue); - } catch (Exception e) { - throw new ChaincodeException("Deserialize error: " + e.getMessage(), "DATA_ERROR"); - } - } - - -} diff --git a/asset-transfer-private-data/chaincode-java/src/main/java/org/hyperledger/fabric/samples/privatedata/AssetTransfer.java b/asset-transfer-private-data/chaincode-java/src/main/java/org/hyperledger/fabric/samples/privatedata/AssetTransfer.java deleted file mode 100644 index 3bc17862..00000000 --- a/asset-transfer-private-data/chaincode-java/src/main/java/org/hyperledger/fabric/samples/privatedata/AssetTransfer.java +++ /dev/null @@ -1,643 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.hyperledger.fabric.samples.privatedata; - -import static java.nio.charset.StandardCharsets.UTF_8; - -import org.hyperledger.fabric.contract.Context; -import org.hyperledger.fabric.contract.ContractInterface; -import org.hyperledger.fabric.contract.annotation.Contact; -import org.hyperledger.fabric.contract.annotation.Contract; -import org.hyperledger.fabric.contract.annotation.Default; -import org.hyperledger.fabric.contract.annotation.Info; -import org.hyperledger.fabric.contract.annotation.License; -import org.hyperledger.fabric.contract.annotation.Transaction; -import org.hyperledger.fabric.shim.ChaincodeException; -import org.hyperledger.fabric.shim.ChaincodeStub; -import org.hyperledger.fabric.shim.ledger.CompositeKey; - -import org.hyperledger.fabric.shim.ledger.KeyValue; -import org.hyperledger.fabric.shim.ledger.QueryResultsIterator; -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -/** - * Main Chaincode class. A ContractInterface gets converted to Chaincode internally. - * @see org.hyperledger.fabric.shim.Chaincode - * - * Each chaincode transaction function must take, Context as first parameter. - * Unless specified otherwise via annotation (@Contract or @Transaction), the contract name - * is the class name (without package) - * and the transaction name is the method name. - * - * To create fabric test-network - * cd fabric-samples/test-network - * ./network.sh up createChannel -ca -s couchdb - * To deploy this chaincode to test-network, use the collection config as described in - * See - * Change both -ccs sequence & -ccv version args for iterative deployment - * ./network.sh deployCC -ccn private -ccp ../asset-transfer-private-data/chaincode-java/ -ccl java -ccep "OR('Org1MSP.peer','Org2MSP.peer')" -cccg ../asset-transfer-private-data/chaincode-go/collections_config.json -ccs 1 -ccv 1 - */ -@Contract( - name = "private", - info = @Info( - title = "Asset Transfer Private Data", - description = "The hyperlegendary asset transfer private data", - version = "0.0.1-SNAPSHOT", - license = @License( - name = "Apache 2.0 License", - url = "http://www.apache.org/licenses/LICENSE-2.0.html"), - contact = @Contact( - email = "a.transfer@example.com", - name = "Private Transfer", - url = "https://hyperledger.example.com"))) -@Default -public final class AssetTransfer implements ContractInterface { - - static final String ASSET_COLLECTION_NAME = "assetCollection"; - static final String AGREEMENT_KEYPREFIX = "transferAgreement"; - - private enum AssetTransferErrors { - INCOMPLETE_INPUT, - INVALID_ACCESS, - ASSET_NOT_FOUND, - ASSET_ALREADY_EXISTS - } - - /** - * Retrieves the asset public details with the specified ID from the AssetCollection. - * - * @param ctx the transaction context - * @param assetID the ID of the asset - * @return the asset found on the ledger if there was one - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public Asset ReadAsset(final Context ctx, final String assetID) { - ChaincodeStub stub = ctx.getStub(); - System.out.printf("ReadAsset: collection %s, ID %s\n", ASSET_COLLECTION_NAME, assetID); - byte[] assetJSON = stub.getPrivateData(ASSET_COLLECTION_NAME, assetID); - - if (assetJSON == null || assetJSON.length == 0) { - System.out.printf("Asset not found: ID %s\n", assetID); - return null; - } - - Asset asset = Asset.deserialize(assetJSON); - return asset; - } - - /** - * Retrieves the asset's AssetPrivateDetails details with the specified ID from the Collection. - * - * @param ctx the transaction context - * @param collection the org's collection containing asset private details - * @param assetID the ID of the asset - * @return the AssetPrivateDetails from the collection, if there was one - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public AssetPrivateDetails ReadAssetPrivateDetails(final Context ctx, final String collection, final String assetID) { - ChaincodeStub stub = ctx.getStub(); - System.out.printf("ReadAssetPrivateDetails: collection %s, ID %s\n", collection, assetID); - byte[] assetPrvJSON = stub.getPrivateData(collection, assetID); - - if (assetPrvJSON == null || assetPrvJSON.length == 0) { - String errorMessage = String.format("AssetPrivateDetails %s does not exist in collection %s", assetID, collection); - System.out.println(errorMessage); - return null; - } - - AssetPrivateDetails assetpd = AssetPrivateDetails.deserialize(assetPrvJSON); - return assetpd; - } - - /** - * ReadTransferAgreement gets the buyer's identity from the transfer agreement from collection - * - * @param ctx the transaction context - * @param assetID the ID of the asset - * @return the AssetPrivateDetails from the collection, if there was one - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public TransferAgreement ReadTransferAgreement(final Context ctx, final String assetID) { - ChaincodeStub stub = ctx.getStub(); - - CompositeKey aggKey = stub.createCompositeKey(AGREEMENT_KEYPREFIX, assetID); - System.out.printf("ReadTransferAgreement Get: collection %s, ID %s, Key %s\n", ASSET_COLLECTION_NAME, assetID, aggKey); - byte[] buyerIdentity = stub.getPrivateData(ASSET_COLLECTION_NAME, aggKey.toString()); - - if (buyerIdentity == null || buyerIdentity.length == 0) { - String errorMessage = String.format("BuyerIdentity for asset %s does not exist in TransferAgreement ", assetID); - System.out.println(errorMessage); - return null; - } - - return new TransferAgreement(assetID, new String(buyerIdentity, UTF_8)); - } - - /** - * GetAssetByRange performs a range query based on the start and end keys provided. Range - * queries can be used to read data from private data collections, but can not be used in - * a transaction that also writes to private collection, since transaction may not get endorsed - * on some peers that do not have the collection. - * - * @param ctx the transaction context - * @param startKey for ID range of the asset - * @param endKey for ID range of the asset - * @return the asset found on the ledger if there was one - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public Asset[] GetAssetByRange(final Context ctx, final String startKey, final String endKey) throws Exception { - ChaincodeStub stub = ctx.getStub(); - System.out.printf("GetAssetByRange: start %s, end %s\n", startKey, endKey); - - List queryResults = new ArrayList<>(); - // retrieve asset with keys between startKey (inclusive) and endKey(exclusive) in lexical order. - try (QueryResultsIterator results = stub.getPrivateDataByRange(ASSET_COLLECTION_NAME, startKey, endKey)) { - for (KeyValue result : results) { - if (result.getStringValue() == null || result.getStringValue().length() == 0) { - System.err.printf("Invalid Asset json: %s\n", result.getStringValue()); - continue; - } - Asset asset = Asset.deserialize(result.getStringValue()); - queryResults.add(asset); - System.out.println("QueryResult: " + asset.toString()); - } - } - return queryResults.toArray(new Asset[0]); - } - - // =======Rich queries ========================================================================= - // Two examples of rich queries are provided below (parameterized query and ad hoc query). - // Rich queries pass a query string to the state database. - // Rich queries are only supported by state database implementations - // that support rich query (e.g. CouchDB). - // The query string is in the syntax of the underlying state database. - // With rich queries there is no guarantee that the result set hasn't changed between - // endorsement time and commit time, aka 'phantom reads'. - // Therefore, rich queries should not be used in update transactions, unless the - // application handles the possibility of result set changes between endorsement and commit time. - // Rich queries can be used for point-in-time queries against a peer. - // ============================================================================================ - - /** - * QueryAssetByOwner queries for assets based on assetType, owner. - * This is an example of a parameterized query where the query logic is baked into the chaincode, - * and accepting a single query parameter (owner). - * - * @param ctx the transaction context - * @param assetType type to query for - * @param owner asset owner to query for - * @return the asset found on the ledger if there was one - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public Asset[] QueryAssetByOwner(final Context ctx, final String assetType, final String owner) throws Exception { - String queryString = String.format("{\"selector\":{\"objectType\":\"%s\",\"owner\":\"%s\"}}", assetType, owner); - return getQueryResult(ctx, queryString); - } - - /** - * QueryAssets uses a query string to perform a query for assets. - * Query string matching state database syntax is passed in and executed as is. - * Supports ad hoc queries that can be defined at runtime by the client. - * - * @param ctx the transaction context - * @param queryString query string matching state database syntax - * @return the asset found on the ledger if there was one - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public Asset[] QueryAssets(final Context ctx, final String queryString) throws Exception { - return getQueryResult(ctx, queryString); - } - - private Asset[] getQueryResult(final Context ctx, final String queryString) throws Exception { - ChaincodeStub stub = ctx.getStub(); - System.out.printf("QueryAssets: %s\n", queryString); - - List queryResults = new ArrayList(); - // retrieve asset with keys between startKey (inclusive) and endKey(exclusive) in lexical order. - try (QueryResultsIterator results = stub.getPrivateDataQueryResult(ASSET_COLLECTION_NAME, queryString)) { - for (KeyValue result : results) { - if (result.getStringValue() == null || result.getStringValue().length() == 0) { - System.err.printf("Invalid Asset json: %s\n", result.getStringValue()); - continue; - } - Asset asset = Asset.deserialize(result.getStringValue()); - queryResults.add(asset); - System.out.println("QueryResult: " + asset.toString()); - } - } - return queryResults.toArray(new Asset[0]); - } - - - /** - * Creates a new asset on the ledger from asset properties passed in as transient map. - * Asset owner will be inferred from the ClientId via stub api - * - * @param ctx the transaction context - * Transient map with asset_properties key with asset json as value - * @return the created asset - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public Asset CreateAsset(final Context ctx) { - ChaincodeStub stub = ctx.getStub(); - Map transientMap = ctx.getStub().getTransient(); - if (!transientMap.containsKey("asset_properties")) { - String errorMessage = String.format("CreateAsset call must specify asset_properties in Transient map input"); - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString()); - } - - byte[] transientAssetJSON = transientMap.get("asset_properties"); - final String assetID; - final String type; - final String color; - int appraisedValue = 0; - int size = 0; - try { - JSONObject json = new JSONObject(new String(transientAssetJSON, UTF_8)); - Map tMap = json.toMap(); - - type = (String) tMap.get("objectType"); - assetID = (String) tMap.get("assetID"); - color = (String) tMap.get("color"); - if (tMap.containsKey("size")) { - size = (Integer) tMap.get("size"); - } - if (tMap.containsKey("appraisedValue")) { - appraisedValue = (Integer) tMap.get("appraisedValue"); - } - } catch (Exception err) { - String errorMessage = String.format("TransientMap deserialized error: %s ", err); - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString()); - } - - //input validations - String errorMessage = null; - if (assetID.equals("")) { - errorMessage = String.format("Empty input in Transient map: assetID"); - } - if (type.equals("")) { - errorMessage = String.format("Empty input in Transient map: objectType"); - } - if (color.equals("")) { - errorMessage = String.format("Empty input in Transient map: color"); - } - if (size <= 0) { - errorMessage = String.format("Empty input in Transient map: size"); - } - if (appraisedValue <= 0) { - errorMessage = String.format("Empty input in Transient map: appraisedValue"); - } - - if (errorMessage != null) { - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString()); - } - - Asset asset = new Asset(type, assetID, color, size, ""); - // Check if asset already exists - byte[] assetJSON = ctx.getStub().getPrivateData(ASSET_COLLECTION_NAME, assetID); - if (assetJSON != null && assetJSON.length > 0) { - errorMessage = String.format("Asset %s already exists", assetID); - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.ASSET_ALREADY_EXISTS.toString()); - } - - // Get ID of submitting client identity - String clientID = ctx.getClientIdentity().getId(); - - // Verify that the client is submitting request to peer in their organization - // This is to ensure that a client from another org doesn't attempt to read or - // write private data from this peer. - verifyClientOrgMatchesPeerOrg(ctx); - - // Make submitting client the owner - asset.setOwner(clientID); - System.out.printf("CreateAsset Put: collection %s, ID %s\n", ASSET_COLLECTION_NAME, assetID); - System.out.printf("Put: collection %s, ID %s\n", ASSET_COLLECTION_NAME, new String(asset.serialize())); - stub.putPrivateData(ASSET_COLLECTION_NAME, assetID, asset.serialize()); - - // Get collection name for this organization. - String orgCollectionName = getCollectionName(ctx); - - // Save AssetPrivateDetails to org collection - AssetPrivateDetails assetPriv = new AssetPrivateDetails(assetID, appraisedValue); - System.out.printf("Put AssetPrivateDetails: collection %s, ID %s\n", orgCollectionName, assetID); - stub.putPrivateData(orgCollectionName, assetID, assetPriv.serialize()); - - return asset; - } - - /** - * AgreeToTransfer is used by the potential buyer of the asset to agree to the - * asset value. The agreed to appraisal value is stored in the buying orgs - * org specifc collection, while the buyer client ID is stored in the asset collection - * using a composite key - * Uses transient map with key asset_value - * - * @param ctx the transaction context - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public void AgreeToTransfer(final Context ctx) { - ChaincodeStub stub = ctx.getStub(); - Map transientMap = ctx.getStub().getTransient(); - if (!transientMap.containsKey("asset_value")) { - String errorMessage = String.format("AgreeToTransfer call must specify \"asset_value\" in Transient map input"); - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString()); - } - - byte[] transientAssetJSON = transientMap.get("asset_value"); - AssetPrivateDetails assetPriv; - String assetID; - try { - JSONObject json = new JSONObject(new String(transientAssetJSON, UTF_8)); - assetID = json.getString("assetID"); - final int appraisedValue = json.getInt("appraisedValue"); - - assetPriv = new AssetPrivateDetails(assetID, appraisedValue); - } catch (Exception err) { - String errorMessage = String.format("TransientMap deserialized error %s ", err); - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString()); - } - - if (assetID.equals("")) { - String errorMessage = String.format("Invalid input in Transient map: assetID"); - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString()); - } - if (assetPriv.getAppraisedValue() <= 0) { // appraisedValue field must be a positive integer - String errorMessage = String.format("Input must be positive integer: appraisedValue"); - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString()); - } - System.out.printf("AgreeToTransfer: verify asset %s exists\n", assetID); - Asset existing = ReadAsset(ctx, assetID); - if (existing == null) { - String errorMessage = String.format("Asset does not exist in the collection: ", assetID); - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString()); - } - // Get collection name for this organization. - String orgCollectionName = getCollectionName(ctx); - - verifyClientOrgMatchesPeerOrg(ctx); - - // Save AssetPrivateDetails to org collection - System.out.printf("Put AssetPrivateDetails: collection %s, ID %s\n", orgCollectionName, assetID); - stub.putPrivateData(orgCollectionName, assetID, assetPriv.serialize()); - - String clientID = ctx.getClientIdentity().getId(); - // Write the AgreeToTransfer key in assetCollection - CompositeKey aggKey = stub.createCompositeKey(AGREEMENT_KEYPREFIX, assetID); - System.out.printf("AgreeToTransfer Put: collection %s, ID %s, Key %s\n", ASSET_COLLECTION_NAME, assetID, aggKey); - stub.putPrivateData(ASSET_COLLECTION_NAME, aggKey.toString(), clientID); - } - - /** - * TransferAsset transfers the asset to the new owner by setting a new owner ID based on - * AgreeToTransfer data - * - * @param ctx the transaction context - * @return none - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public void TransferAsset(final Context ctx) { - ChaincodeStub stub = ctx.getStub(); - Map transientMap = ctx.getStub().getTransient(); - if (!transientMap.containsKey("asset_owner")) { - String errorMessage = "TransferAsset call must specify \"asset_owner\" in Transient map input"; - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString()); - } - - byte[] transientAssetJSON = transientMap.get("asset_owner"); - final String assetID; - final String buyerMSP; - try { - JSONObject json = new JSONObject(new String(transientAssetJSON, UTF_8)); - assetID = json.getString("assetID"); - buyerMSP = json.getString("buyerMSP"); - - } catch (Exception err) { - String errorMessage = String.format("TransientMap deserialized error %s ", err); - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString()); - } - - if (assetID.equals("")) { - String errorMessage = String.format("Invalid input in Transient map: " + "assetID"); - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString()); - } - if (buyerMSP.equals("")) { - String errorMessage = String.format("Invalid input in Transient map: " + "buyerMSP"); - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString()); - } - - System.out.printf("TransferAsset: verify asset %s exists\n", assetID); - byte[] assetJSON = stub.getPrivateData(ASSET_COLLECTION_NAME, assetID); - - if (assetJSON == null || assetJSON.length == 0) { - String errorMessage = String.format("Asset %s does not exist in the collection", assetID); - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString()); - } - - verifyClientOrgMatchesPeerOrg(ctx); - Asset thisAsset = Asset.deserialize(assetJSON); - // Verify transfer details and transfer owner - verifyAgreement(ctx, assetID, thisAsset.getOwner(), buyerMSP); - - TransferAgreement transferAgreement = ReadTransferAgreement(ctx, assetID); - if (transferAgreement == null) { - String errorMessage = String.format("TransferAgreement does not exist for asset: %s", assetID); - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString()); - } - - // Transfer asset in private data collection to new owner - String newOwner = transferAgreement.getBuyerID(); - thisAsset.setOwner(newOwner); - - // Save updated Asset to collection - System.out.printf("Transfer Asset: collection %s, ID %s to owner %s\n", ASSET_COLLECTION_NAME, assetID, newOwner); - stub.putPrivateData(ASSET_COLLECTION_NAME, assetID, thisAsset.serialize()); - - // Delete the key from owners collection - String ownersCollectionName = getCollectionName(ctx); - stub.delPrivateData(ownersCollectionName, assetID); - - // Delete the transfer agreement from the asset collection - CompositeKey aggKey = stub.createCompositeKey(AGREEMENT_KEYPREFIX, assetID); - System.out.printf("AgreeToTransfer deleteKey: collection %s, ID %s, Key %s\n", ASSET_COLLECTION_NAME, assetID, aggKey); - stub.delPrivateData(ASSET_COLLECTION_NAME, aggKey.toString()); - } - - /** - * Deletes a asset & related details from the ledger. - * Input in transient map: asset_delete - * - * This deletes the private data, but does not trigger an immediate cleanup - * of the history. To specifically force removal right now use purge - * - * @param ctx the transaction context - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public void DeleteAsset(final Context ctx) { - ChaincodeStub stub = ctx.getStub(); - Map transientMap = ctx.getStub().getTransient(); - if (!transientMap.containsKey("asset_delete")) { - String errorMessage = String.format("DeleteAsset call must specify 'asset_delete' in Transient map input"); - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString()); - } - - byte[] transientAssetJSON = transientMap.get("asset_delete"); - final String assetID; - - try { - JSONObject json = new JSONObject(new String(transientAssetJSON, UTF_8)); - assetID = json.getString("assetID"); - - } catch (Exception err) { - String errorMessage = String.format("TransientMap deserialized error: %s ", err); - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString()); - } - - System.out.printf("DeleteAsset: verify asset %s exists\n", assetID); - byte[] assetJSON = stub.getPrivateData(ASSET_COLLECTION_NAME, assetID); - - if (assetJSON == null || assetJSON.length == 0) { - String errorMessage = String.format("Asset %s does not exist", assetID); - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.ASSET_NOT_FOUND.toString()); - } - String ownersCollectionName = getCollectionName(ctx); - byte[] apdJSON = stub.getPrivateData(ownersCollectionName, assetID); - - if (apdJSON == null || apdJSON.length == 0) { - String errorMessage = String.format("Failed to read asset from owner's Collection %s", ownersCollectionName); - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.ASSET_NOT_FOUND.toString()); - } - verifyClientOrgMatchesPeerOrg(ctx); - - // delete the key from asset collection - System.out.printf("DeleteAsset: collection %s, ID %s\n", ASSET_COLLECTION_NAME, assetID); - stub.delPrivateData(ASSET_COLLECTION_NAME, assetID); - - // Finally, delete private details of asset - stub.delPrivateData(ownersCollectionName, assetID); - } - - /** - * Purges the history of the asset from Private Data - * (delete does not need to be called as well) - * Input in transient map: asset_delete - * - * @param ctx the transaction context - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public void PurgeAsset(final Context ctx) { - ChaincodeStub stub = ctx.getStub(); - Map transientMap = ctx.getStub().getTransient(); - if (!transientMap.containsKey("asset_purge")) { - String errorMessage = String.format("PurgeAsset call must specify 'asset_purge' in Transient map input"); - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString()); - } - - byte[] transientAssetJSON = transientMap.get("asset_purge"); - final String assetID; - - try { - JSONObject json = new JSONObject(new String(transientAssetJSON, UTF_8)); - assetID = json.getString("assetID"); - - } catch (Exception err) { - String errorMessage = String.format("TransientMap deserialized error: %s ", err); - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString()); - } - - // Note that there is no check here to see if the id exist; it might have been 'deleted' already - // so a check here is pointless. We would need to call purge irrespective of the result - // A delete can be called before purge, but is not essential - - String ownersCollectionName = getCollectionName(ctx); - verifyClientOrgMatchesPeerOrg(ctx); - - // delete the key from asset collection - System.out.printf("PurgeAsset: collection %s, ID %s\n", ASSET_COLLECTION_NAME, assetID); - stub.purgePrivateData(ASSET_COLLECTION_NAME, assetID); - - // Finally, delete private details of asset - System.out.printf("PurgeAsset: collection %s, ID %s\n", ownersCollectionName, assetID); - stub.purgePrivateData(ownersCollectionName, assetID); - } - - - // Used by TransferAsset to verify that the transfer is being initiated by the owner and that - // the buyer has agreed to the same appraisal value as the owner - private void verifyAgreement(final Context ctx, final String assetID, final String owner, final String buyerMSP) { - String clienID = ctx.getClientIdentity().getId(); - - // Check 1: verify that the transfer is being initiatied by the owner - if (!clienID.equals(owner)) { - throw new ChaincodeException("Submitting client identity does not own the asset", AssetTransferErrors.INVALID_ACCESS.toString()); - } - - // Check 2: verify that the buyer has agreed to the appraised value - String collectionOwner = getCollectionName(ctx); // get owner collection from caller identity - String collectionBuyer = buyerMSP + "PrivateCollection"; - - // Get hash of owners agreed to value - byte[] ownerAppraisedValueHash = ctx.getStub().getPrivateDataHash(collectionOwner, assetID); - if (ownerAppraisedValueHash == null) { - throw new ChaincodeException(String.format("Hash of appraised value for %s does not exist in collection %s", assetID, collectionOwner)); - } - - // Get hash of buyers agreed to value - byte[] buyerAppraisedValueHash = ctx.getStub().getPrivateDataHash(collectionBuyer, assetID); - if (buyerAppraisedValueHash == null) { - throw new ChaincodeException(String.format("Hash of appraised value for %s does not exist in collection %s. AgreeToTransfer must be called by the buyer first.", assetID, collectionBuyer)); - } - - // Verify that the two hashes match - if (!Arrays.equals(ownerAppraisedValueHash, buyerAppraisedValueHash)) { - throw new ChaincodeException(String.format("Hash for appraised value for owner %x does not match value for seller %x", ownerAppraisedValueHash, buyerAppraisedValueHash)); - } - } - - private void verifyClientOrgMatchesPeerOrg(final Context ctx) { - String clientMSPID = ctx.getClientIdentity().getMSPID(); - String peerMSPID = ctx.getStub().getMspId(); - - if (!peerMSPID.equals(clientMSPID)) { - String errorMessage = String.format("Client from org %s is not authorized to read or write private data from an org %s peer", clientMSPID, peerMSPID); - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INVALID_ACCESS.toString()); - } - } - - private String getCollectionName(final Context ctx) { - - // Get the MSP ID of submitting client identity - String clientMSPID = ctx.getClientIdentity().getMSPID(); - // Create the collection name - return clientMSPID + "PrivateCollection"; - } - -} diff --git a/asset-transfer-private-data/chaincode-java/src/main/java/org/hyperledger/fabric/samples/privatedata/TransferAgreement.java b/asset-transfer-private-data/chaincode-java/src/main/java/org/hyperledger/fabric/samples/privatedata/TransferAgreement.java deleted file mode 100644 index 2082d978..00000000 --- a/asset-transfer-private-data/chaincode-java/src/main/java/org/hyperledger/fabric/samples/privatedata/TransferAgreement.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.hyperledger.fabric.samples.privatedata; - -import org.hyperledger.fabric.contract.annotation.DataType; -import org.hyperledger.fabric.contract.annotation.Property; -import org.hyperledger.fabric.shim.ChaincodeException; -import org.json.JSONObject; - -import static java.nio.charset.StandardCharsets.UTF_8; - -@DataType() -public final class TransferAgreement { - - @Property() - private final String assetID; - - - @Property() - private String buyerID; - - public String getAssetID() { - return assetID; - } - - public String getBuyerID() { - return buyerID; - } - - public TransferAgreement(final String assetID, - final String buyer) { - this.assetID = assetID; - this.buyerID = buyer; - } - - public byte[] serialize() { - String jsonStr = new JSONObject(this).toString(); - return jsonStr.getBytes(UTF_8); - } - - public static TransferAgreement deserialize(final byte[] assetJSON) { - try { - JSONObject json = new JSONObject(new String(assetJSON, UTF_8)); - final String id = json.getString("assetID"); - final String buyerID = json.getString("buyerID"); - return new TransferAgreement(id, buyerID); - } catch (Exception e) { - throw new ChaincodeException("Deserialize error: " + e.getMessage(), "DATA_ERROR"); - } - } - - -} diff --git a/asset-transfer-private-data/chaincode-java/src/test/java/org/hyperledger/fabric/samples/privatedata/AssetTransferTest.java b/asset-transfer-private-data/chaincode-java/src/test/java/org/hyperledger/fabric/samples/privatedata/AssetTransferTest.java deleted file mode 100644 index 171efe68..00000000 --- a/asset-transfer-private-data/chaincode-java/src/test/java/org/hyperledger/fabric/samples/privatedata/AssetTransferTest.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.hyperledger.fabric.samples.privatedata; - -import org.hyperledger.fabric.contract.ClientIdentity; -import org.hyperledger.fabric.contract.Context; -import org.hyperledger.fabric.shim.ChaincodeException; -import org.hyperledger.fabric.shim.ChaincodeStub; -import org.hyperledger.fabric.shim.ledger.CompositeKey; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; - -import java.util.HashMap; -import java.util.Map; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.ThrowableAssert.catchThrowable; -import static org.hyperledger.fabric.samples.privatedata.AssetTransfer.AGREEMENT_KEYPREFIX; -import static org.hyperledger.fabric.samples.privatedata.AssetTransfer.ASSET_COLLECTION_NAME; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoInteractions; -import static org.mockito.Mockito.when; - -public final class AssetTransferTest { - - @Nested - class InvokeWriteTransaction { - - @Test - public void createAssetWhenAssetExists() { - AssetTransfer contract = new AssetTransfer(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - Map m = new HashMap<>(); - m.put("asset_properties", DATA_ASSET_1_BYTES); - when(ctx.getStub().getTransient()).thenReturn(m); - when(stub.getPrivateData(ASSET_COLLECTION_NAME, TEST_ASSET_1_ID)) - .thenReturn(DATA_ASSET_1_BYTES); - - Throwable thrown = catchThrowable(() -> { - contract.CreateAsset(ctx); - }); - - assertThat(thrown).isInstanceOf(ChaincodeException.class).hasNoCause() - .hasMessage("Asset asset1 already exists"); - assertThat(((ChaincodeException) thrown).getPayload()).isEqualTo("ASSET_ALREADY_EXISTS".getBytes()); - } - - @Test - public void createAssetWhenNewAssetIsCreated() { - AssetTransfer contract = new AssetTransfer(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getMspId()).thenReturn(TEST_ORG_1_MSP); - ClientIdentity ci = mock(ClientIdentity.class); - when(ci.getId()).thenReturn(TEST_ORG_1_USER); - when(ci.getMSPID()).thenReturn(TEST_ORG_1_MSP); - when(ctx.getClientIdentity()).thenReturn(ci); - - Map m = new HashMap<>(); - m.put("asset_properties", DATA_ASSET_1_BYTES); - when(ctx.getStub().getTransient()).thenReturn(m); - - when(stub.getPrivateData(ASSET_COLLECTION_NAME, TEST_ASSET_1_ID)) - .thenReturn(new byte[0]); - - Asset created = contract.CreateAsset(ctx); - assertThat(created).isEqualTo(TEST_ASSET_1); - - verify(stub).putPrivateData(ASSET_COLLECTION_NAME, TEST_ASSET_1_ID, created.serialize()); - } - - @Test - public void transferAssetWhenExistingAssetIsTransferred() { - AssetTransfer contract = new AssetTransfer(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getMspId()).thenReturn(TEST_ORG_1_MSP); - ClientIdentity ci = mock(ClientIdentity.class); - when(ci.getId()).thenReturn(TEST_ORG_1_USER); - when(ctx.getClientIdentity()).thenReturn(ci); - when(ci.getMSPID()).thenReturn(TEST_ORG_1_MSP); - final String recipientOrgMsp = "TestOrg2"; - final String buyerIdentity = "TestOrg2User"; - Map m = new HashMap<>(); - m.put("asset_owner", ("{ \"buyerMSP\": \"" + recipientOrgMsp + "\", \"assetID\": \"" + TEST_ASSET_1_ID + "\" }").getBytes()); - when(ctx.getStub().getTransient()).thenReturn(m); - - when(stub.getPrivateDataHash(anyString(), anyString())).thenReturn("TestHashValue".getBytes()); - when(stub.getPrivateData(ASSET_COLLECTION_NAME, TEST_ASSET_1_ID)) - .thenReturn(DATA_ASSET_1_BYTES); - CompositeKey ck = mock(CompositeKey.class); - when(ck.toString()).thenReturn(AGREEMENT_KEYPREFIX + TEST_ASSET_1_ID); - when(stub.createCompositeKey(AGREEMENT_KEYPREFIX, TEST_ASSET_1_ID)).thenReturn(ck); - when(stub.getPrivateData(ASSET_COLLECTION_NAME, AGREEMENT_KEYPREFIX + TEST_ASSET_1_ID)).thenReturn(buyerIdentity.getBytes(UTF_8)); - contract.TransferAsset(ctx); - - Asset exptectedAfterTransfer = Asset.deserialize("{ \"objectType\": \"testasset\", \"assetID\": \"asset1\", \"color\": \"blue\", \"size\": 5, \"owner\": \"" + buyerIdentity + "\", \"appraisedValue\": 300 }"); - - verify(stub).putPrivateData(ASSET_COLLECTION_NAME, TEST_ASSET_1_ID, exptectedAfterTransfer.serialize()); - String collectionOwner = TEST_ORG_1_MSP + "PrivateCollection"; - verify(stub).delPrivateData(collectionOwner, TEST_ASSET_1_ID); - verify(stub).delPrivateData(ASSET_COLLECTION_NAME, AGREEMENT_KEYPREFIX + TEST_ASSET_1_ID); - } - } - - @Nested - class QueryReadAssetTransaction { - - @Test - public void whenAssetExists() { - AssetTransfer contract = new AssetTransfer(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getPrivateData(ASSET_COLLECTION_NAME, TEST_ASSET_1_ID)) - .thenReturn(DATA_ASSET_1_BYTES); - - Asset asset = contract.ReadAsset(ctx, TEST_ASSET_1_ID); - - assertThat(asset).isEqualTo(TEST_ASSET_1); - } - - @Test - public void whenAssetDoesNotExist() { - AssetTransfer contract = new AssetTransfer(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(TEST_ASSET_1_ID)).thenReturn(null); - - Asset asset = contract.ReadAsset(ctx, TEST_ASSET_1_ID); - assertThat(asset).isNull(); - } - - @Test - public void invokeUnknownTransaction() { - AssetTransfer contract = new AssetTransfer(); - Context ctx = mock(Context.class); - - Throwable thrown = catchThrowable(() -> { - contract.unknownTransaction(ctx); - }); - - assertThat(thrown).isInstanceOf(ChaincodeException.class).hasNoCause() - .hasMessage("Undefined contract method called"); - assertThat(((ChaincodeException) thrown).getPayload()).isEqualTo(null); - - verifyNoInteractions(ctx); - } - - } - - private static final String TEST_ORG_1_MSP = "TestOrg1"; - private static final String TEST_ORG_1_USER = "testOrg1User"; - - private static final String TEST_ASSET_1_ID = "asset1"; - private static final Asset TEST_ASSET_1 = new Asset("testasset", "asset1", "blue", 5, TEST_ORG_1_USER); - private static final byte[] DATA_ASSET_1_BYTES = "{ \"objectType\": \"testasset\", \"assetID\": \"asset1\", \"color\": \"blue\", \"size\": 5, \"owner\": \"testOrg1User\", \"appraisedValue\": 300 }".getBytes(); -} diff --git a/asset-transfer-private-data/chaincode-java/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/asset-transfer-private-data/chaincode-java/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker deleted file mode 100644 index 1f0955d4..00000000 --- a/asset-transfer-private-data/chaincode-java/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker +++ /dev/null @@ -1 +0,0 @@ -mock-maker-inline diff --git a/asset-transfer-private-data/chaincode-typescript/.dockerignore b/asset-transfer-private-data/chaincode-typescript/.dockerignore deleted file mode 100644 index b512c09d..00000000 --- a/asset-transfer-private-data/chaincode-typescript/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -node_modules \ No newline at end of file diff --git a/asset-transfer-private-data/chaincode-typescript/.gitignore b/asset-transfer-private-data/chaincode-typescript/.gitignore deleted file mode 100644 index 79bfe1a3..00000000 --- a/asset-transfer-private-data/chaincode-typescript/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - - -# Coverage directory used by tools like istanbul -coverage - -# Dependency directories -node_modules/ -jspm_packages/ -package-lock.json - -# Compiled TypeScript files -dist - diff --git a/asset-transfer-private-data/chaincode-typescript/Dockerfile b/asset-transfer-private-data/chaincode-typescript/Dockerfile deleted file mode 100644 index 98c90e77..00000000 --- a/asset-transfer-private-data/chaincode-typescript/Dockerfile +++ /dev/null @@ -1,36 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# -FROM node:16 AS builder - -WORKDIR /usr/src/app - -# Copy node.js source and build, changing owner as well -COPY --chown=node:node . /usr/src/app -ENV npm_config_cache=/usr/src/app -RUN npm ci && npm run package - - -FROM node:16 AS production -ARG CC_SERVER_PORT - -# Setup tini to work better handle signals -ENV TINI_VERSION v0.19.0 -ENV PLATFORM=amd64 -ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-${PLATFORM} /tini -RUN chmod +x /tini - -WORKDIR /usr/src/app -COPY --chown=node:node --from=builder /usr/src/app/dist ./dist -COPY --chown=node:node --from=builder /usr/src/app/package.json ./ -COPY --chown=node:node --from=builder /usr/src/app/npm-shrinkwrap.json ./ -COPY --chown=node:node docker/docker-entrypoint.sh /usr/src/app/docker-entrypoint.sh - -RUN npm ci --omit=dev && npm cache clean --force - -ENV PORT $CC_SERVER_PORT -EXPOSE $CC_SERVER_PORT -ENV NODE_ENV=production - -USER node -ENTRYPOINT [ "/tini", "--", "/usr/src/app/docker-entrypoint.sh" ] diff --git a/asset-transfer-private-data/chaincode-typescript/Readme.md b/asset-transfer-private-data/chaincode-typescript/Readme.md deleted file mode 100644 index 3a81fe77..00000000 --- a/asset-transfer-private-data/chaincode-typescript/Readme.md +++ /dev/null @@ -1,9 +0,0 @@ -## Usage -This chaincode written for Hyperledger Fabric private data tutorial(https://hyperledger-fabric.readthedocs.io/en/latest/private_data_tutorial.html). - -### Deploy chaincode with: -1. ``` cd fabric-samples/asset-transfer-private-data/chaincode-typescript/ ``` -2. ``` npm install ``` -3. ``` npm run build ``` -4. ``` cd fabric-samples/test-network/ ``` -5. ``` ./network.sh deployCC -ccn private -ccp ../asset-transfer-private-data/chaincode-typescript/ -ccl typescript -ccep "OR('Org1MSP.peer','Org2MSP.peer')" -cccg ../asset-transfer-private-data/chaincode-typescript/collections_config.json ``` \ No newline at end of file diff --git a/asset-transfer-private-data/chaincode-typescript/collections_config.json b/asset-transfer-private-data/chaincode-typescript/collections_config.json deleted file mode 100644 index 993bbd31..00000000 --- a/asset-transfer-private-data/chaincode-typescript/collections_config.json +++ /dev/null @@ -1,38 +0,0 @@ -[ - { - "name": "assetCollection", - "policy": "OR('Org1MSP.member', 'Org2MSP.member')", - "requiredPeerCount": 1, - "maxPeerCount": 1, - "blockToLive":1000000, - "memberOnlyRead": true, - "memberOnlyWrite": true, - "endorsementPolicy": { - "signaturePolicy":"OR('Org1MSP.member','Org2MSP.member')" - } -}, - { - "name": "Org1MSPPrivateCollection", - "policy": "OR('Org1MSP.member')", - "requiredPeerCount": 0, - "maxPeerCount": 1, - "blockToLive":3, - "memberOnlyRead": true, - "memberOnlyWrite": false, - "endorsementPolicy": { - "signaturePolicy": "OR('Org1MSP.member')" - } - }, - { - "name": "Org2MSPPrivateCollection", - "policy": "OR('Org2MSP.member')", - "requiredPeerCount": 0, - "maxPeerCount": 1, - "blockToLive":3, - "memberOnlyRead": true, - "memberOnlyWrite": false, - "endorsementPolicy": { - "signaturePolicy": "OR('Org2MSP.member')" - } - } -] diff --git a/asset-transfer-private-data/chaincode-typescript/docker/docker-entrypoint.sh b/asset-transfer-private-data/chaincode-typescript/docker/docker-entrypoint.sh deleted file mode 100644 index 2fd8fcf6..00000000 --- a/asset-transfer-private-data/chaincode-typescript/docker/docker-entrypoint.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash -# -# SPDX-License-Identifier: Apache-2.0 -# -set -euo pipefail -: ${CORE_PEER_TLS_ENABLED:="false"} -: ${DEBUG:="false"} - -if [ "${DEBUG,,}" = "true" ]; then - npm run start:server-debug -elif [ "${CORE_PEER_TLS_ENABLED,,}" = "true" ]; then - npm run start:server -else - npm run start:server-nontls -fi - diff --git a/asset-transfer-private-data/chaincode-typescript/eslint.config.mjs b/asset-transfer-private-data/chaincode-typescript/eslint.config.mjs deleted file mode 100644 index 9ef6b243..00000000 --- a/asset-transfer-private-data/chaincode-typescript/eslint.config.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import js from '@eslint/js'; -import tseslint from 'typescript-eslint'; - -export default tseslint.config(js.configs.recommended, ...tseslint.configs.strictTypeChecked, { - languageOptions: { - ecmaVersion: 2023, - sourceType: 'module', - parserOptions: { - project: 'tsconfig.json', - tsconfigRootDir: import.meta.dirname, - }, - }, -}); diff --git a/asset-transfer-private-data/chaincode-typescript/npm-shrinkwrap.json b/asset-transfer-private-data/chaincode-typescript/npm-shrinkwrap.json deleted file mode 100644 index 940936a8..00000000 --- a/asset-transfer-private-data/chaincode-typescript/npm-shrinkwrap.json +++ /dev/null @@ -1,2256 +0,0 @@ -{ - "name": "asset-transfer-private-data", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "asset-transfer-private-data", - "version": "1.0.0", - "license": "Apache-2.0", - "dependencies": { - "fabric-contract-api": "~2.5", - "fabric-shim": "~2.5", - "json-stringify-deterministic": "^1.0.0", - "sort-keys-recursive": "^2.1.0" - }, - "devDependencies": { - "@eslint/js": "^9.3.0", - "@tsconfig/node18": "^18.2.4", - "@types/node": "^18.19.33", - "eslint": "^8.57.0", - "typescript": "~5.4.5", - "typescript-eslint": "^7.11.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@colors/colors": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", - "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@dabh/diagnostics": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", - "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", - "dependencies": { - "colorspace": "1.1.x", - "enabled": "2.0.x", - "kuler": "^2.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", - "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/js": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.4.0.tgz", - "integrity": "sha512-fdI7VJjP3Rvc70lC4xkFXHB0fiPeojiL1PxVG6t1ZvXQrarj893PweuBTujxDUFk0Fxj4R7PIIAZ/aiiyZPZcg==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@fidm/asn1": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@fidm/asn1/-/asn1-1.0.4.tgz", - "integrity": "sha512-esd1jyNvRb2HVaQGq2Gg8Z0kbQPXzV9Tq5Z14KNIov6KfFD6PTaRIO8UpcsYiTNzOqJpmyzWgVTrUwFV3UF4TQ==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@fidm/x509": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@fidm/x509/-/x509-1.2.1.tgz", - "integrity": "sha512-nwc2iesjyc9hkuzcrMCBXQRn653XuAUKorfWM8PZyJawiy1QzLj4vahwzaI25+pfpwOLvMzbJ0uKpWLDNmo16w==", - "dependencies": { - "@fidm/asn1": "^1.0.4", - "tweetnacl": "^1.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@grpc/grpc-js": { - "version": "1.10.9", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.10.9.tgz", - "integrity": "sha512-5tcgUctCG0qoNyfChZifz2tJqbRbXVO9J7X6duFcOjY3HUNCxg5D0ZCK7EP9vIcZ0zRpLU9bWkyCqVCLZ46IbQ==", - "dependencies": { - "@grpc/proto-loader": "^0.7.13", - "@js-sdsl/ordered-map": "^4.4.2" - }, - "engines": { - "node": ">=12.10.0" - } - }, - "node_modules/@grpc/proto-loader": { - "version": "0.7.13", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", - "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", - "dependencies": { - "lodash.camelcase": "^4.3.0", - "long": "^5.0.0", - "protobufjs": "^7.2.5", - "yargs": "^17.7.2" - }, - "bin": { - "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true - }, - "node_modules/@hyperledger/fabric-protos": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@hyperledger/fabric-protos/-/fabric-protos-0.2.1.tgz", - "integrity": "sha512-qjm0vIQIfCall804tWDeA8p/mUfu14sl5Sj+PbOn2yDKJq+7ThoIhNsLAqf+BCxUfqsoqQq6AojhqQeTFyOOqg==", - "dependencies": { - "@grpc/grpc-js": "^1.9.0", - "google-protobuf": "^3.21.0" - }, - "engines": { - "node": ">=14.15.0" - } - }, - "node_modules/@js-sdsl/ordered-map": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", - "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" - }, - "node_modules/@tsconfig/node18": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node18/-/node18-18.2.4.tgz", - "integrity": "sha512-5xxU8vVs9/FNcvm3gE07fPbn9tl6tqGGWA9tSlwsUEkBxtRnTsNmwrV8gasZ9F/EobaSv9+nu8AxUKccw77JpQ==", - "dev": true - }, - "node_modules/@types/node": { - "version": "18.19.34", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.34.tgz", - "integrity": "sha512-eXF4pfBNV5DAMKGbI02NnDtWrQ40hAN558/2vvS4gMpMIxaf6JmD7YjnZbq0Q9TDSSkKBamime8ewRoomHdt4g==", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/triple-beam": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", - "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.0.tgz", - "integrity": "sha512-FX1X6AF0w8MdVFLSdqwqN/me2hyhuQg4ykN6ZpVhh1ij/80pTvDKclX1sZB9iqex8SjQfVhwMKs3JtnnMLzG9w==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.13.0", - "@typescript-eslint/type-utils": "7.13.0", - "@typescript-eslint/utils": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^7.0.0", - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.0.tgz", - "integrity": "sha512-EjMfl69KOS9awXXe83iRN7oIEXy9yYdqWfqdrFAYAAr6syP8eLEFI7ZE4939antx2mNgPRW/o1ybm2SFYkbTVA==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "7.13.0", - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/typescript-estree": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.0.tgz", - "integrity": "sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.0.tgz", - "integrity": "sha512-xMEtMzxq9eRkZy48XuxlBFzpVMDurUAfDu5Rz16GouAtXm0TaAoTFzqWUFPPuQYXI/CDaH/Bgx/fk/84t/Bc9A==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "7.13.0", - "@typescript-eslint/utils": "7.13.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.0.tgz", - "integrity": "sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==", - "dev": true, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.0.tgz", - "integrity": "sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.0.tgz", - "integrity": "sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.13.0", - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/typescript-estree": "7.13.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.0.tgz", - "integrity": "sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.13.0", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/class-transformer": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.4.0.tgz", - "integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==" - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/color": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", - "dependencies": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/color/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/colorspace": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", - "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", - "dependencies": { - "color": "^3.1.3", - "text-hex": "1.0.x" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/enabled": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", - "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" - }, - "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fabric-contract-api": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/fabric-contract-api/-/fabric-contract-api-2.5.6.tgz", - "integrity": "sha512-AosGb8tA+Jgt+pqMEgYNB3/J/P5QuWOC7yhXbhDmAAwUzn4Sc7pdWDICH1YyrFGZNFxMGQmqJmLVWUX8BKHy0w==", - "dependencies": { - "class-transformer": "^0.4.0", - "fabric-shim-api": "2.5.6", - "fast-safe-stringify": "^2.1.1", - "get-params": "^0.1.2", - "reflect-metadata": "^0.1.13", - "winston": "^3.7.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/fabric-shim": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/fabric-shim/-/fabric-shim-2.5.6.tgz", - "integrity": "sha512-4Y8WNFhYuQ9QYSEgPXWdlXnrXjwOlM10sQQzE4kJ7cDh8a4LX0rn44FxtxTCB18lnzrSLMZ8/8Cr5m0c9NeXWA==", - "dependencies": { - "@fidm/x509": "^1.2.1", - "@grpc/grpc-js": "~1.10.9", - "@hyperledger/fabric-protos": "~0.2.1", - "@types/node": "^16.11.1", - "ajv": "^6.12.2", - "fabric-contract-api": "2.5.6", - "fabric-shim-api": "2.5.6", - "fast-safe-stringify": "^2.1.1", - "long": "^5.2.3", - "reflect-metadata": "^0.1.13", - "winston": "^3.7.2", - "yargs": "^17.4.0", - "yargs-parser": "^21.0.1" - }, - "bin": { - "fabric-chaincode-node": "cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/fabric-shim-api": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/fabric-shim-api/-/fabric-shim-api-2.5.6.tgz", - "integrity": "sha512-1L0nO7CJ31/gEOWKWHEeCqgB5HkqPVfRbpcS7L9eTscT7tffjg2OkZISvC+a7RiqihL0iyrXNBgBg5MwlSSN9g==", - "engines": { - "eslint": "^6.6.0", - "node": ">=18" - } - }, - "node_modules/fabric-shim/node_modules/@types/node": { - "version": "16.18.98", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.98.tgz", - "integrity": "sha512-fpiC20NvLpTLAzo3oVBKIqBGR6Fx/8oAK/SSf7G+fydnXMY1x4x9RZ6sBXhqKlCU21g2QapUsbLlhv3+a7wS+Q==" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fecha": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "node_modules/fn.name": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", - "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-params": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/get-params/-/get-params-0.1.2.tgz", - "integrity": "sha512-41eOxtlGgHQRbFyA8KTH+w+32Em3cRdfBud7j67ulzmIfmaHX9doq47s0fa4P5o9H64BZX9nrYI6sJvk46Op+Q==" - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "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" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/google-protobuf": { - "version": "3.21.2", - "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz", - "integrity": "sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==" - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/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, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json-stringify-deterministic": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/json-stringify-deterministic/-/json-stringify-deterministic-1.0.12.tgz", - "integrity": "sha512-q3PN0lbUdv0pmurkBNdJH3pfFvOTL/Zp0lquqpvcjfKzt6Y0j49EPHAmVHCAS4Ceq/Y+PejWTzyiVpoY71+D6g==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/kuler": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/logform": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", - "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", - "dependencies": { - "@colors/colors": "1.6.0", - "@types/triple-beam": "^1.3.2", - "fecha": "^4.2.0", - "ms": "^2.1.1", - "safe-stable-stringify": "^2.3.1", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/long": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", - "dev": true, - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/one-time": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", - "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", - "dependencies": { - "fn.name": "1.x.x" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/protobufjs": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.2.tgz", - "integrity": "sha512-RXyHaACeqXeqAKGLDl68rQKbmObRsTIn4TYVUUug1KfS47YWCo5MacGITEryugIgZqORCvJWEk4l449POg5Txg==", - "hasInstallScript": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/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, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/reflect-metadata": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", - "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==" - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safe-stable-stringify": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", - "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", - "engines": { - "node": ">=10" - } - }, - "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/sort-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-4.2.0.tgz", - "integrity": "sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg==", - "dependencies": { - "is-plain-obj": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/sort-keys-recursive": { - "version": "2.1.10", - "resolved": "https://registry.npmjs.org/sort-keys-recursive/-/sort-keys-recursive-2.1.10.tgz", - "integrity": "sha512-yRLJbEER/PjU7hSRwXvP+NyXiORufu8rbSbp+3wFRuJZXoi/AhuKczbjuipqn7Le0SsTXK4VUeri2+Ni6WS8Hg==", - "dependencies": { - "kind-of": "~6.0.2", - "sort-keys": "~4.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", - "engines": { - "node": "*" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-hex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/triple-beam": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", - "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", - "dev": true, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/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, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.13.0.tgz", - "integrity": "sha512-upO0AXxyBwJ4BbiC6CRgAJKtGYha2zw4m1g7TIVPSonwYEuf7vCicw3syjS1OxdDMTz96sZIXl3Jx3vWJLLKFw==", - "dev": true, - "dependencies": { - "@typescript-eslint/eslint-plugin": "7.13.0", - "@typescript-eslint/parser": "7.13.0", - "@typescript-eslint/utils": "7.13.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/winston": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.13.0.tgz", - "integrity": "sha512-rwidmA1w3SE4j0E5MuIufFhyJPBDG7Nu71RkZor1p2+qHvJSZ9GYDA81AyleQcZbh/+V6HjeBdfnTZJm9rSeQQ==", - "dependencies": { - "@colors/colors": "^1.6.0", - "@dabh/diagnostics": "^2.0.2", - "async": "^3.2.3", - "is-stream": "^2.0.0", - "logform": "^2.4.0", - "one-time": "^1.0.0", - "readable-stream": "^3.4.0", - "safe-stable-stringify": "^2.3.1", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.7.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/winston-transport": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz", - "integrity": "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==", - "dependencies": { - "logform": "^2.3.2", - "readable-stream": "^3.6.0", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "engines": { - "node": ">=12" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/asset-transfer-private-data/chaincode-typescript/package.json b/asset-transfer-private-data/chaincode-typescript/package.json deleted file mode 100755 index 204a1e84..00000000 --- a/asset-transfer-private-data/chaincode-typescript/package.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "asset-transfer-private-data", - "version": "1.0.0", - "description": "Asset Transfer(Private Data Tutorial) contract implemented in TypeScript.", - "main": "dist/index.js", - "typings": "dist/index.d.ts", - "engines": { - "node": ">=18" - }, - "scripts": { - "lint": "eslint src", - "pretest": "npm run lint", - "test": "", - "start": "set -x && fabric-chaincode-node start", - "build": "tsc", - "build:watch": "tsc -w", - "prepublishOnly": "npm run build", - "docker": "docker build -f ./Dockerfile -t asset-transfer-private-data .", - "package": "npm run build && npm shrinkwrap", - "start:server-nontls": "set -x && fabric-chaincode-node server --chaincode-address=$CHAINCODE_SERVER_ADDRESS --chaincode-id=$CHAINCODE_ID", - "start:server-debug": "set -x && NODE_OPTIONS='--inspect=0.0.0.0:9229' fabric-chaincode-node server --chaincode-address=$CHAINCODE_SERVER_ADDRESS --chaincode-id=$CHAINCODE_ID", - "start:server": "set -x && fabric-chaincode-node server --chaincode-address=$CHAINCODE_SERVER_ADDRESS --chaincode-id=$CHAINCODE_ID --chaincode-tls-key-file=/hyperledger/privatekey.pem --chaincode-tls-client-cacert-file=/hyperledger/rootcert.pem --chaincode-tls-cert-file=/hyperledger/cert.pem" - }, - "engineStrict": true, - "author": "Hyperledger", - "license": "Apache-2.0", - "dependencies": { - "fabric-contract-api": "~2.5", - "fabric-shim": "~2.5", - "json-stringify-deterministic": "^1.0.0", - "sort-keys-recursive": "^2.1.0" - }, - "devDependencies": { - "@types/node": "^18.19.33", - "@eslint/js": "^9.3.0", - "@tsconfig/node18": "^18.2.4", - "eslint": "^8.57.0", - "typescript": "~5.4.5", - "typescript-eslint": "^7.11.0" - } -} diff --git a/asset-transfer-private-data/chaincode-typescript/src/asset.ts b/asset-transfer-private-data/chaincode-typescript/src/asset.ts deleted file mode 100644 index 02c1347d..00000000 --- a/asset-transfer-private-data/chaincode-typescript/src/asset.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - SPDX-License-Identifier: Apache-2.0 -*/ - -import { Object, Property } from "fabric-contract-api"; -import { nonEmptyString, positiveNumber } from "./utils"; - -@Object() -// Asset describes main asset details that are visible to all organizations -export class Asset { - @Property() - docType?: string; - - @Property() - ID: string = ""; - - @Property() - Color: string = ""; - - @Property() - Size: number = 0; - - @Property() - Owner: string = ""; - - static fromBytes(bytes: Uint8Array): Asset { - if (bytes.length === 0) { - throw new Error("no asset data"); - } - const json = Buffer.from(bytes).toString(); - const properties = JSON.parse(json) as Partial; - - const result = new Asset(); - result.docType = properties.docType; - result.ID = nonEmptyString(properties.ID, "ID field must be a non-empty string"); - result.Color = nonEmptyString(properties.Color, "Color field must be a non-empty string"); - result.Size = positiveNumber(properties.Size, "Size field must be a positive integer"); - result.Owner = nonEmptyString(properties.Owner, "appraiseOwner field must be a non-empty string"); - - return result; - } -} diff --git a/asset-transfer-private-data/chaincode-typescript/src/assetTransfer.ts b/asset-transfer-private-data/chaincode-typescript/src/assetTransfer.ts deleted file mode 100644 index fab116bd..00000000 --- a/asset-transfer-private-data/chaincode-typescript/src/assetTransfer.ts +++ /dev/null @@ -1,374 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ -import { Context, Contract, Info, Transaction } from 'fabric-contract-api'; -import stringify from 'json-stringify-deterministic'; -import sortKeysRecursive from 'sort-keys-recursive'; -import { Asset } from './asset'; -import { AssetPrivateDetails } from './assetTransferDetails'; -import { TransientAssetDelete, TransientAssetOwner, TransientAssetProperties, TransientAssetPurge, TransientAssetValue } from './assetTransferTransientInput'; -import { TransferAgreement } from './transferAgreement'; - -const assetCollection = 'assetCollection'; -const transferAgreementObjectType = 'transferAgreement'; - -@Info({ title: 'AssetTransfer', description: 'Smart contract for trading assets' }) -export class AssetTransfer extends Contract { - - // CreateAsset issues a new asset to the world state with given details. - @Transaction() - public async CreateAsset(ctx: Context): Promise { - const transientMap = ctx.stub.getTransient(); - const assetProperties = new TransientAssetProperties(transientMap); - - // Check if asset already exists - const assetAsBytes = await ctx.stub.getPrivateData(assetCollection, assetProperties.assetID); - if (assetAsBytes.length !== 0) { - throw new Error('this asset already exists: ' + assetProperties.assetID); - } - - // Get ID of submitting client identity - const clientID = ctx.clientIdentity.getID(); - - // Verify that the client is submitting request to peer in their organization - // This is to ensure that a client from another org doesn't attempt to read or - // write private data from this peer. - this.verifyClientOrgMatchesPeerOrg(ctx); - - const asset: Asset = { - ID: assetProperties.assetID, - Color: assetProperties.color, - Size: assetProperties.size, - Owner: clientID, - }; - - // Save asset to private data collection - // Typical logger, logs to stdout/file in the fabric managed docker container, running this chaincode - // Look for container name like dev-peer0.org1.example.com-{chaincodename_version}-xyz - await ctx.stub.putPrivateData(assetCollection, asset.ID, Buffer.from(stringify(sortKeysRecursive(asset)))); - - // Save asset details to collection visible to owning organization - const assetPrivateDetails: AssetPrivateDetails = { - ID: assetProperties.assetID, - AppraisedValue: assetProperties.appraisedValue, - }; - // Get collection name for this organization. - const orgCollection = this.getCollectionName(ctx); - // Put asset appraised value into owners org specific private data collection - console.log('Put: collection %v, ID %v', orgCollection, assetProperties.assetID); - await ctx.stub.putPrivateData(orgCollection, asset.ID, Buffer.from(stringify(sortKeysRecursive(assetPrivateDetails)))); - } - - // AgreeToTransfer is used by the potential buyer of the asset to agree to the - // asset value. The agreed to appraisal value is stored in the buying orgs - // org specifc collection, while the buyer client ID is stored in the asset collection - // using a composite key - @Transaction() - public async AgreeToTransfer(ctx: Context): Promise { - // Get ID of submitting client identity - const clientID = ctx.clientIdentity.getID(); - // Value is private, therefore it gets passed in transient field - const transientMap = ctx.stub.getTransient(); - const assetValue = new TransientAssetValue(transientMap); - - const valueJSON: AssetPrivateDetails = { - ID: assetValue.assetID, - AppraisedValue: assetValue.appraisedValue, - }; - // Read asset from the private data collection - const asset = await this.ReadAsset(ctx, valueJSON.ID); - // Verify that the client is submitting request to peer in their organization - this.verifyClientOrgMatchesPeerOrg(ctx); - - // Get collection name for this organization. Needs to be read by a member of the organization. - const orgCollection = this.getCollectionName(ctx); - console.log(`AgreeToTransfer Put: collection ${orgCollection}, ID ${valueJSON.ID}`); - // Put agreed value in the org specifc private data collection - await ctx.stub.putPrivateData(orgCollection, asset.ID, Buffer.from(stringify(sortKeysRecursive(valueJSON)))); - // Create agreeement that indicates which identity has agreed to purchase - // In a more realistic transfer scenario, a transfer agreement would be secured to ensure that it cannot - // be overwritten by another channel member - const transferAgreeKey = ctx.stub.createCompositeKey(transferAgreementObjectType, [valueJSON.ID]); - console.log(`AgreeToTransfer Put: collection ${assetCollection}, ID ${valueJSON.ID}, Key ${transferAgreeKey}`); - await ctx.stub.putPrivateData(assetCollection, transferAgreeKey, new Uint8Array(Buffer.from(clientID))); - } - - @Transaction() - // TransferAsset transfers the asset to the new owner by setting a new owner ID - public async TransferAsset(ctx: Context): Promise { - // Asset properties are private, therefore they get passed in transient field - const transientMap = ctx.stub.getTransient(); - const assetOwner = new TransientAssetOwner(transientMap); - - console.log('TransferAsset: verify asset exists ID ' + assetOwner.assetID); - // Read asset from the private data collection - const asset = await this.ReadAsset(ctx, assetOwner.assetID); - // Verify that the client is submitting request to peer in their organization - this.verifyClientOrgMatchesPeerOrg(ctx); - // Verify transfer details and transfer owner - await this.verifyAgreement(ctx, assetOwner.assetID, asset.Owner, assetOwner.buyerMSP); - - const transferAgreement = await this.ReadTransferAgreement(ctx, assetOwner.assetID); - if (transferAgreement.BuyerID === '') { - throw new Error('BuyerID not found in TransferAgreement for ' + assetOwner.assetID); - } - // Transfer asset in private data collection to new owner - asset.Owner = transferAgreement.BuyerID; - console.log(`TransferAsset Put: collection ${assetCollection}, ID ${assetOwner.assetID}`); - await ctx.stub.putPrivateData(assetCollection, assetOwner.assetID, Buffer.from(stringify(sortKeysRecursive(asset)))); // rewrite the asset - - // Get collection name for this organization - const ownersCollection = this.getCollectionName(ctx); - // Delete the asset appraised value from this organization's private data collection - await ctx.stub.deletePrivateData(ownersCollection, assetOwner.assetID); - // Delete the transfer agreement from the asset collection - const transferAgreeKey = ctx.stub.createCompositeKey(transferAgreementObjectType, [assetOwner.assetID]); - await ctx.stub.deletePrivateData(assetCollection, transferAgreeKey); - } - - @Transaction() - // DeleteAsset can be used by the owner of the asset to delete the asset - public async DeleteAsset(ctx: Context): Promise { - // Value is private, therefore it gets passed in transient field - const transientMap = ctx.stub.getTransient(); - const assetDelete = new TransientAssetDelete(transientMap); - - // Verify that the client is submitting request to peer in their organization - this.verifyClientOrgMatchesPeerOrg(ctx); - - console.log('Deleting Asset: ' + assetDelete.assetID); - // get the asset from chaincode state - const valAsbytes = await ctx.stub.getPrivateData(assetCollection, assetDelete.assetID); - if (valAsbytes.length === 0) { - throw new Error('asset not found: ' + assetDelete.assetID); - } - const ownerCollection = this.getCollectionName(ctx); - // Check the asset is in the caller org's private collection - const valAsbytesPrivate = await ctx.stub.getPrivateData(ownerCollection, assetDelete.assetID); - if (valAsbytesPrivate.length === 0) { - throw new Error(`asset not found in owner's private Collection: ${ownerCollection} : ${assetDelete.assetID}`); - } - // delete the asset from state - await ctx.stub.deletePrivateData(assetCollection, assetDelete.assetID); - // Finally, delete private details of asset - await ctx.stub.deletePrivateData(ownerCollection, assetDelete.assetID); - } - - @Transaction() - // PurgeAsset can be used by the owner of the asset to delete the asset - // Trigger removal of the asset - public async PurgeAsset(ctx: Context): Promise { - // Value is private, therefore it gets passed in transient field - const transientMap = ctx.stub.getTransient(); - const assetPurge = new TransientAssetPurge(transientMap); - - // Verify that the client is submitting request to peer in their organization - this.verifyClientOrgMatchesPeerOrg(ctx); - - console.log('Purging Asset: ' + assetPurge.assetID); - // Note that there is no check here to see if the id exist; it might have been 'deleted' already - // so a check here is pointless. We would need to call purge irrespective of the result - // A delete can be called before purge, but is not essential - const ownerCollection = this.getCollectionName(ctx); - // delete the asset from state - await ctx.stub.purgePrivateData(assetCollection, assetPurge.assetID); - // Finally, delete private details of asset - await ctx.stub.purgePrivateData(ownerCollection, assetPurge.assetID); - } - - @Transaction() - // DeleteTranferAgreement can be used by the buyer to withdraw a proposal from - // the asset collection and from his own collection. - public async DeleteTransferAgreement(ctx: Context): Promise { - // Value is private, therefore it gets passed in transient field - const transientMap = ctx.stub.getTransient(); - const agreementDelete = new TransientAssetDelete(transientMap); - - // Verify that the client is submitting request to peer in their organization - this.verifyClientOrgMatchesPeerOrg(ctx); - - // Delete private details of agreement - // Get proposers collection. - const orgCollection = this.getCollectionName(ctx); - // Delete the transfer agreement from the asset collection - const transferAgreeKey = ctx.stub.createCompositeKey(transferAgreementObjectType, [agreementDelete.assetID]); - // get the transfer_agreement - const valAsbytes = await ctx.stub.getPrivateData(assetCollection, transferAgreeKey); - - if (valAsbytes.length === 0) { - throw new Error(`asset's transfer_agreement does not exist: ${agreementDelete.assetID}`); - } - // Delete the asset - await ctx.stub.deletePrivateData(orgCollection, agreementDelete.assetID); - // Delete transfer agreement record, remove agreement from state - await ctx.stub.deletePrivateData(assetCollection, transferAgreeKey); - } - - /* - GETTERS - */ - - // ReadAsset reads the information from collection - @Transaction() - public async ReadAsset(ctx: Context, id: string): Promise { - // Check if asset already exists - const assetAsBytes = await ctx.stub.getPrivateData(assetCollection, id); - // No Asset found, return empty response - if (assetAsBytes.length === 0) { - throw new Error(id + ' does not exist in collection ' + assetCollection); - } - return Asset.fromBytes(assetAsBytes); - } - - // ReadAssetPrivateDetails reads the asset private details in organization specific collection - @Transaction() - public async ReadAssetPrivateDetails(ctx: Context, collection: string, id: string): Promise { - // Check if asset already exists - const detailBytes = await ctx.stub.getPrivateData(collection, id); - // No Asset found, return empty response - if (detailBytes.length === 0) { - throw new Error(id + ' does not exist in collection ' + collection); - } - return AssetPrivateDetails.fromBytes(detailBytes); - } - - // ReadTransferAgreement gets the buyer's identity from the transfer agreement from collection - @Transaction() - public async ReadTransferAgreement(ctx: Context, assetID: string): Promise { - // composite key for TransferAgreement of this asset - const transferAgreeKey = ctx.stub.createCompositeKey(transferAgreementObjectType, [assetID]); - // Get the identity from collection - const buyerIdentity = await ctx.stub.getPrivateData(assetCollection, transferAgreeKey); - - if (buyerIdentity.length === 0) { - throw new Error(`TransferAgreement for ${assetID} does not exist `); - } - - return { - ID: assetID, - BuyerID: String(buyerIdentity), - }; - } - - // GetAssetByRange performs a range query based on the start and end keys provided. Range - // queries can be used to read data from private data collections, but can not be used in - // a transaction that also writes to private data. - @Transaction() - public async GetAssetByRange(ctx: Context, startKey: string, endKey: string): Promise { - const resultsIterator = ctx.stub.getPrivateDataByRange(assetCollection, startKey, endKey); - const results: Asset[] = []; - for await (const res of resultsIterator) { - const asset = Asset.fromBytes(res.value); - results.push(asset); - } - return results; - } - /* - HELPERS - */ - // verifyAgreement is an internal helper function used by TransferAsset to verify - // that the transfer is being initiated by the owner and that the buyer has agreed - // to the same appraisal value as the owner - public async verifyAgreement(ctx: Context, assetID: string, owner: string, buyerMSP: string): Promise { - // Check 1: verify that the transfer is being initiatied by the owner - // Get ID of submitting client identity - const clientID = ctx.clientIdentity.getID(); - if (clientID !== owner) { - throw new Error(`error: submitting client(${clientID}) identity does not own asset ${assetID}.Owner is ${owner}`); - } - // Check 2: verify that the buyer has agreed to the appraised value - // Get collection names - const collectionOwner = this.getCollectionName(ctx); // get owner collection from caller identity - - const collectionBuyer = buyerMSP + 'PrivateCollection'; // get buyers collection - // Get hash of owners agreed to value - const ownerAppraisedValueHash = await ctx.stub.getPrivateDataHash(collectionOwner, assetID); - - if (ownerAppraisedValueHash.length === 0) { - throw new Error(`hash of appraised value for ${assetID} does not exist in collection ${collectionOwner}`); - } - // Get hash of buyers agreed to value - const buyerAppraisedValueHash = await ctx.stub.getPrivateDataHash(collectionBuyer, assetID); - if (buyerAppraisedValueHash.length === 0) { - throw new Error(`hash of appraised value for ${assetID} does not exist in collection ${collectionBuyer}. AgreeToTransfer must be called by the buyer first`); - } - // Verify that the two hashes match - if (ownerAppraisedValueHash.toString() !== buyerAppraisedValueHash.toString()) { - throw new Error(`hash for appraised value for owner ${Buffer.from(ownerAppraisedValueHash).toString('hex')} does not match value for seller ${Buffer.from(buyerAppraisedValueHash).toString('hex')}`); - } - } - // getCollectionName is an internal helper function to get collection of submitting client identity. - public getCollectionName(ctx: Context): string { - // Get the MSP ID of submitting client identity - const clientMSPID = ctx.clientIdentity.getMSPID(); - // Create the collection name - const orgCollection = clientMSPID + 'PrivateCollection'; - - return orgCollection; - } - // Get ID of submitting client identity - public submittingClientIdentity(ctx: Context): string { - - const b64ID = ctx.clientIdentity.getID(); - - // base64.StdEncoding.DecodeString(b64ID); - const decodeID = Buffer.from(b64ID, 'base64').toString('binary'); - - return String(decodeID); - } - // verifyClientOrgMatchesPeerOrg is an internal function used verify client org id and matches peer org id. - public verifyClientOrgMatchesPeerOrg(ctx: Context): void { - - const clientMSPID = ctx.clientIdentity.getMSPID(); - - const peerMSPID = ctx.stub.getMspID(); - - if (clientMSPID !== peerMSPID) { - throw new Error('client from org %v is not authorized to read or write private data from an org ' + clientMSPID + ' peer ' + peerMSPID); - } - } - // =======Rich queries ========================================================================= - // Two examples of rich queries are provided below (parameterized query and ad hoc query). - // Rich queries pass a query string to the state database. - // Rich queries are only supported by state database implementations - // that support rich query (e.g. CouchDB). - // The query string is in the syntax of the underlying state database. - // With rich queries there is no guarantee that the result set hasn't changed between - // endorsement time and commit time, aka 'phantom reads'. - // Therefore, rich queries should not be used in update transactions, unless the - // application handles the possibility of result set changes between endorsement and commit time. - // Rich queries can be used for point-in-time queries against a peer. - // ============================================================================================ - - // ===== Example: Parameterized rich query ================================================= - - // QueryAssetByOwner queries for assets based on assetType, owner. - // This is an example of a parameterized query where the query logic is baked into the chaincode, - // and accepting a single query parameter (owner). - // Only available on state databases that support rich query (e.g. CouchDB) - // ========================================================================================= - public async QueryAssetByOwner(ctx: Context, assetType: string, owner: string): Promise { - - const queryString = `{'selector':{'objectType':'${assetType}','owner':'${owner}'}}`; - - return await this.getQueryResultForQueryString(ctx, queryString); - } - - public QueryAssets(ctx: Context, queryString: string): Promise { - return this.getQueryResultForQueryString(ctx, queryString); - } - - public async getQueryResultForQueryString(ctx: Context, queryString: string): Promise { - - const resultsIterator = ctx.stub.getPrivateDataQueryResult(assetCollection, queryString); - - const results: Asset[] = []; - - for await (const res of resultsIterator) { - const asset = Asset.fromBytes(res.value); - results.push(asset); - } - - return results; - } -} diff --git a/asset-transfer-private-data/chaincode-typescript/src/assetTransferDetails.ts b/asset-transfer-private-data/chaincode-typescript/src/assetTransferDetails.ts deleted file mode 100644 index 7a63e8c7..00000000 --- a/asset-transfer-private-data/chaincode-typescript/src/assetTransferDetails.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - SPDX-License-Identifier: Apache-2.0 -*/ - -import { Object, Property } from "fabric-contract-api"; -import { nonEmptyString, positiveNumber } from "./utils"; - -@Object() -// AssetPrivateDetails describes details that are private to owners -export class AssetPrivateDetails { - @Property() - ID: string = ""; - @Property() - AppraisedValue: number = 0; - - static fromBytes(bytes: Uint8Array): AssetPrivateDetails { - if (bytes.length === 0) { - throw new Error("no asset private details"); - } - const json = Buffer.from(bytes).toString(); - const properties = JSON.parse(json) as Partial; - - const result = new AssetPrivateDetails(); - result.ID = nonEmptyString(properties.ID, "ID field must be a non-empty string"); - result.AppraisedValue = positiveNumber( - properties.AppraisedValue, - "AppraisedValue field must be a positive integer" - ); - - return result; - } -} diff --git a/asset-transfer-private-data/chaincode-typescript/src/assetTransferTransientInput.ts b/asset-transfer-private-data/chaincode-typescript/src/assetTransferTransientInput.ts deleted file mode 100644 index 66ed44d2..00000000 --- a/asset-transfer-private-data/chaincode-typescript/src/assetTransferTransientInput.ts +++ /dev/null @@ -1,115 +0,0 @@ -/* - SPDX-License-Identifier: Apache-2.0 -*/ - -import { nonEmptyString, positiveNumber } from "./utils"; - -export class TransientAssetProperties { - objectType: string; - assetID: string; - color: string; - size: number; - appraisedValue: number; - - constructor(transientMap: Map) { - const transient = transientMap.get("asset_properties"); - if (!transient?.length) { - throw new Error("no asset properties"); - } - const json = Buffer.from(transient).toString(); - const properties = JSON.parse(json) as Partial; - - this.objectType = nonEmptyString(properties.objectType, "objectType field must be a non-empty string"); - this.assetID = nonEmptyString(properties.assetID, "assetID field must be a non-empty string"); - this.color = nonEmptyString(properties.color, "color field must be a non-empty string"); - this.size = positiveNumber(properties.size, "size field must be a positive integer"); - this.appraisedValue = positiveNumber( - properties.appraisedValue, - "appraisedValue field must be a positive integer" - ); - } -} - -export class TransientAssetValue { - assetID: string; - appraisedValue: number; - - constructor(transientMap: Map) { - const transient = transientMap.get("asset_value"); - if (!transient?.length) { - throw new Error("no asset value"); - } - const json = Buffer.from(transient).toString(); - const properties = JSON.parse(json) as Partial; - - this.assetID = nonEmptyString(properties.assetID, "assetID field must be a non-empty string"); - this.appraisedValue = positiveNumber( - properties.appraisedValue, - "appraisedValue field must be a positive integer" - ); - } -} - -export class TransientAssetOwner { - assetID: string; - buyerMSP: string; - - constructor(transientMap: Map) { - const transient = transientMap.get("asset_owner"); - if (!transient?.length) { - throw new Error("no asset owner"); - } - const json = Buffer.from(transient).toString(); - const properties = JSON.parse(json) as Partial; - - this.assetID = nonEmptyString(properties.assetID, "assetID field must be a non-empty string"); - this.buyerMSP = nonEmptyString(properties.buyerMSP, "buyerMSP field must be a non-empty string"); - } -} - -export class TransientAssetDelete { - assetID: string; - - constructor(transientMap: Map) { - const transient = transientMap.get("asset_delete"); - if (!transient?.length) { - throw new Error("no asset delete"); - } - const json = Buffer.from(transient).toString(); - const properties = JSON.parse(json) as Partial; - - this.assetID = nonEmptyString(properties.assetID, "assetID field must be a non-empty string"); - } -} - -export class TransientAssetPurge { - assetID: string; - - constructor(transientMap: Map) { - const transient = transientMap.get("asset_purge"); - if (!transient?.length) { - throw new Error("no asset purge"); - } - - const json = Buffer.from(transient).toString(); - const properties = JSON.parse(json) as Partial; - - this.assetID = nonEmptyString(properties.assetID, "assetID field must be a non-empty string"); - } -} - -export class TransientAgreementDelete { - assetID: string; - - constructor(transientMap: Map) { - const transient = transientMap.get("agreement_delete"); - if (!transient?.length) { - throw new Error("no agreement delete"); - } - - const json = Buffer.from(transient).toString(); - const properties = JSON.parse(json) as Partial; - - this.assetID = nonEmptyString(properties.assetID, "assetID field must be a non-empty string"); - } -} diff --git a/asset-transfer-private-data/chaincode-typescript/src/index.ts b/asset-transfer-private-data/chaincode-typescript/src/index.ts deleted file mode 100644 index d5c4cc01..00000000 --- a/asset-transfer-private-data/chaincode-typescript/src/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -import { type Contract } from 'fabric-contract-api'; -import {AssetTransfer} from './assetTransfer'; - -export {AssetTransfer} from './assetTransfer'; - -export const contracts: typeof Contract[] = [AssetTransfer]; diff --git a/asset-transfer-private-data/chaincode-typescript/src/transferAgreement.ts b/asset-transfer-private-data/chaincode-typescript/src/transferAgreement.ts deleted file mode 100644 index fd780746..00000000 --- a/asset-transfer-private-data/chaincode-typescript/src/transferAgreement.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - SPDX-License-Identifier: Apache-2.0 -*/ - -import { Object, Property } from "fabric-contract-api"; - -@Object() -// TransferAgreement describes the buyer agreement returned by ReadTransferAgreement -export class TransferAgreement { - @Property() - ID: string = ""; - @Property() - BuyerID: string = ""; -} diff --git a/asset-transfer-private-data/chaincode-typescript/src/utils.ts b/asset-transfer-private-data/chaincode-typescript/src/utils.ts deleted file mode 100644 index 1763f0a9..00000000 --- a/asset-transfer-private-data/chaincode-typescript/src/utils.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - SPDX-License-Identifier: Apache-2.0 -*/ - -export function nonEmptyString(arg: unknown, errorMessage: string): string { - if (typeof arg !== "string" || arg.length === 0) { - throw new Error(errorMessage); - } - - return arg; -} - -export function positiveNumber(arg: unknown, errorMessage: string): number { - if (typeof arg !== "number" || arg < 1) { - throw new Error(errorMessage); - } - - return arg; -} diff --git a/asset-transfer-private-data/chaincode-typescript/tsconfig.json b/asset-transfer-private-data/chaincode-typescript/tsconfig.json deleted file mode 100644 index 031d7de7..00000000 --- a/asset-transfer-private-data/chaincode-typescript/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "extends": "@tsconfig/node18/tsconfig.json", - "compilerOptions": { - "experimentalDecorators": true, - "emitDecoratorMetadata": true, - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "outDir": "dist", - "strict": true, - "noUnusedLocals": true, - "noImplicitReturns": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["src/"] -} diff --git a/asset-transfer-sbe/README.md b/asset-transfer-sbe/README.md deleted file mode 100644 index 87bb99aa..00000000 --- a/asset-transfer-sbe/README.md +++ /dev/null @@ -1,169 +0,0 @@ -# State-based endorsement asset transfer sample - -Transactions that are submitted to Hyperledger Fabric networks need to be endorsed -by peers that are joined to a channel before the transaction can be added to the -ledger. Fabric peers endorse transactions by executing a smart contract using the -inputs of the transaction proposal. The peers then sign the input and output -generated by the smart contract execution. The endorsement policy specifies the -set of organizations whose peers need to endorse a transaction before it can be -added to the ledger. - -Each chaincode that is deployed to a channel has an endorsement policy that governs -the assets managed by the chaincode smart contracts. However, you can override the -chaincode level endorsement policy to create an endorsement policy for a specific key, -either on the public channel ledger or in a private collection. -State-based endorsement policies, also known as key-level endorsement policies, allow -channel members to use different endorsement policies for assets that are managed by -the same smart contract. For more information about endorsement policies and -state-based endorsement, visit the -[Endorsement Policies](https://hyperledger-fabric.readthedocs.io/en/release-2.2/endorsement-policies.html) -topic in the Fabric documentation. - -The implementation provided by State Based interface creates a policy which requires signatures from all the Org principals added, and hence is equivalent to an AND policy. For other advanced State Based policy implementations which are not supported by State Based interface directly like OR or NOutOf policies, please refer to method implementations setStateBasedEndorsementNOutOf(), which can be used as an alternative for setStateBasedEndorsement() inside asset-transfer-sbe smart contracts. - -## About the Sample - -The state-based endorsement (SBE) asset transfer sample demonstrates how to use -key-level endorsement policies to ensure that an asset only is endorsed by an -asset owner. In the course of the tutorial, you will use the smart contract -to complete the following transfer scenario: - -- Deploy the SBE smart contract to a channel that was created using the Fabric -test network. The channel will have two members, Org1 and Org2, that will -participate in the asset transfer. Each organization operates one peer that -is joined to the channel. -- Create an asset using the chaincode endorsement policy. The chaincode level -endorsement policy requires that a majority of organizations on the channel -endorse a transaction. This means that a transaction that creates an asset -needs to be endorsed by peers that belong to Org1 and Org2. When the asset is -created, the smart contract creates a state-based endorsement policy that -specifies that only the organization that owns that asset may endorse update -transactions. Because the asset is owned by Org1, any future updates to the asset -need to be endorsed by the Org1 peer. -- Update the asset by only endorsing with Org1, this will use the state-based -endorsement policy applied to the asset when it was created by the chaincode. -- Transfer the asset to Org2. During the execution of the transfer transaction, -the chaincode will create a new state-based endorsement policy that reflects -the new asset owner for the asset. -- Update the asset once more, this time with Org2 as the owner. Because the -state-based endorsement policy has been updated, this transaction only needs -to be endorsed by Org2. - -## Deploy the smart contract - -We are going to run the SBE smart contract using the Fabric test network. Open a command terminal and navigate to test network directory in your local clone of the `fabric-samples`. We will operate from the `test-network` directory for the remainder of the tutorial. -``` -cd fabric-samples/test-network -``` - -Run the following command to deploy the test network and create a channel named `mychannel`: - -``` -./network.sh up createChannel -``` - -You can use the test network script to deploy the smart contract to the channel that was just created. The script uses the Fabric chaincode lifecycle to deploy the smart contract to the channel. We will use the default chaincode level endorsement policy used by the Fabric chaincode lifecycle, which requires an endorsement from a majority of channel members. In our case, this will require that both Org1 and Org2 endorse a transaction (2 of 2). Deploy the smart contract to `mychannel` using the following command: -``` -./network.sh deployCC -ccn sbe -ccp ../asset-transfer-sbe/chaincode-typescript/ -ccl typescript -``` - -Set the following environment variables to interact with the network as a user from Org1: - -``` -export PATH=${PWD}/../bin:${PWD}:$PATH -export FABRIC_CFG_PATH=$PWD/../config/ -export CORE_PEER_TLS_ENABLED=true -export CORE_PEER_LOCALMSPID=Org1MSP -export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp -export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt -export CORE_PEER_ADDRESS=localhost:7051 -``` - -## Run the transfer scenario - -We can now invoke the SBE smart contract to create a new asset: -``` -peer chaincode invoke -o localhost:7050 --waitForEvent --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n sbe --peerAddresses localhost:7051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt" -c '{"function":"CreateAsset","Args":["asset1","100","Org1User1"]}' -``` -The create transaction needs to target both peers from Org1 and Org2 to meet the chaincode endorsement policy. The chaincode will read the MSP ID of the client user submitting the transaction and assign that organization as the asset owner. As a result, the asset will initially be owned by Org1. - -You can query the asset using with the following command: -``` -peer chaincode query -C mychannel -n sbe -c '{"Args":["ReadAsset","asset1"]}' -``` -The result is a new asset owned by Org1, identified using the Org1 MSP ID `Org1MSP`: -`{"ID":"asset1","Value":100,"Owner":"Org1User1","OwnerOrg":"Org1MSP"}` - -In addition to creating the asset, the `CreateAsset` function also sets a state-based endorsement policy for the asset. Only a peer of the asset owner, can successfully endorse an asset update. To demonstrate the key-level endorsement policy, lets try to update the asset while targeting the Org2 peer: -``` -peer chaincode invoke -o localhost:7050 --waitForEvent --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n sbe --peerAddresses localhost:9051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt" -c '{"function":"UpdateAsset","Args":["asset1","200"]}' -``` -The result is an endorsement policy failure: -``` -Error: transaction invalidated with status (ENDORSEMENT_POLICY_FAILURE) - proposal response: -``` - -If we attempt to update the asset with an endorsement from the Org1 peer, the update succeeds: -``` -peer chaincode invoke -o localhost:7050 --waitForEvent --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n sbe --peerAddresses localhost:7051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" -c '{"function":"UpdateAsset","Args":["asset1","200"]}' -``` -You can query the asset one more time to verify that the update was successful: -``` -peer chaincode query -C mychannel -n sbe -c '{"Args":["ReadAsset","asset1"]}' -``` - -The asset value is now 200: -``` -{"ID":"asset1","Value":200,"Owner":"Org1User1","OwnerOrg":"Org1MSP"} -``` - -Now that we have tested the asset key-level endorsement policy, we can transfer the asset to Org2. Run the following command to transfer the asset from Org1 to Org2. This time the Org2 MSP ID is provided as a transaction input. The `TransferAsset` function will update the endorsement policy to specify that only a peer of the new owner can update the asset. Note that this command targets the Org1 peer. - -``` -peer chaincode invoke -o localhost:7050 --waitForEvent --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n sbe --peerAddresses localhost:7051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" -c '{"function":"TransferAsset","Args":["asset1","Org2User1","Org2MSP"]}' -``` - -We can query the asset to see that the owner has been updated from Org1 to Org2: -``` -peer chaincode query -C mychannel -n sbe -c '{"Args":["ReadAsset","asset1"]}' -``` - -The owning organization is now Org2: -``` -{"ID":"asset1","Value":200,"Owner":"Org2User1","OwnerOrg":"Org2MSP"} -``` - -Org2 now needs to endorse any asset updates. Run the following command to try to update the asset with an endorsement from the Org1 peer: -``` -peer chaincode invoke -o localhost:7050 --waitForEvent --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n sbe --peerAddresses localhost:7051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" -c '{"function":"UpdateAsset","Args":["asset1","300"]}' -``` - -The response will be an endorsement policy failure: -``` -Error: transaction invalidated with status (ENDORSEMENT_POLICY_FAILURE) - proposal response: -``` - -Now try to update the asset with an endorsement from the Org2 peer: -``` -peer chaincode invoke -o localhost:7050 --waitForEvent --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n sbe --peerAddresses localhost:9051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt" -c '{"function":"UpdateAsset","Args":["asset1","300"]}' -``` - -You can query the asset again to verify that the transaction update succeeded: -``` -peer chaincode query -C mychannel -n sbe -c '{"Args":["ReadAsset","asset1"]}' -``` - -The asset value is now 300: -``` -{"ID":"asset1","Value":300,"Owner":"Org2User1","OwnerOrg":"Org2MSP"} -``` - -Note that the transaction to update the asset was submitted by a user from Org1, even though the asset was owned by Org2. The transfer enabled by the SBE smart contract is a simple scenario meant only to demonstrate the use of state-based endorsement policies. The smart contract can use access control to specify that an asset can only be updated by its owner. Private data collections can also be used to ensure that transfers need to be endorsed by the owner and recipient of the transfer, instead of just the asset owner. For a more realistic example of an asset transfer scenario, see the [Secured asset transfer in Fabric](https://hyperledger-fabric.readthedocs.io/en/master/secured_asset_transfer/secured_private_asset_transfer_tutorial.html) tutorial. - -## Clean up - -When you are finished, you can bring down the test network. The command will remove all the nodes of the test network, and delete any ledger data that you created: - -``` -./network.sh down -``` diff --git a/asset-transfer-sbe/application-javascript/.eslintignore b/asset-transfer-sbe/application-javascript/.eslintignore deleted file mode 100644 index 15958470..00000000 --- a/asset-transfer-sbe/application-javascript/.eslintignore +++ /dev/null @@ -1,5 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -coverage diff --git a/asset-transfer-sbe/application-javascript/.eslintrc.js b/asset-transfer-sbe/application-javascript/.eslintrc.js deleted file mode 100644 index 072edaf6..00000000 --- a/asset-transfer-sbe/application-javascript/.eslintrc.js +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -module.exports = { - env: { - node: true, - mocha: true - }, - parserOptions: { - ecmaVersion: 8, - sourceType: 'script' - }, - extends: 'eslint:recommended', - rules: { - indent: ['error', 'tab'], - 'linebreak-style': ['error', 'unix'], - quotes: ['error', 'single'], - semi: ['error', 'always'], - 'no-unused-vars': ['error', { args: 'none' }], - 'no-console': 'off', - curly: 'error', - eqeqeq: 'error', - 'no-throw-literal': 'error', - strict: 'error', - 'no-var': 'error', - 'dot-notation': 'error', - 'no-trailing-spaces': 'error', - 'no-use-before-define': 'error', - 'no-useless-call': 'error', - 'no-with': 'error', - 'operator-linebreak': 'error', - yoda: 'error', - 'quote-props': ['error', 'as-needed'] - } -}; diff --git a/asset-transfer-sbe/application-javascript/.gitignore b/asset-transfer-sbe/application-javascript/.gitignore deleted file mode 100644 index 21b287f7..00000000 --- a/asset-transfer-sbe/application-javascript/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -# Coverage directory used by tools like istanbul -coverage - -# Dependency directories -node_modules/ -jspm_packages/ -package-lock.json - -wallet -!wallet/.gitkeep diff --git a/asset-transfer-sbe/application-javascript/app.js b/asset-transfer-sbe/application-javascript/app.js deleted file mode 100644 index 134f4443..00000000 --- a/asset-transfer-sbe/application-javascript/app.js +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -/** - * A test application to show state based endorsements operations with a running - * asset-transfer-sbe chaincode with discovery. - * -- How to submit a transaction - * -- How to query - * -- How to limit the organizations involved in a transaction - * - * To see the SDK workings, try setting the logging to show on the console before running - * export HFC_LOGGING='{"debug":"console"}' - */ - -// pre-requisites: -// - fabric-sample two organization test-network setup with two peers, ordering service, -// and 2 certificate authorities -// ===> from directory /fabric-samples/test-network -// ./network.sh up createChannel -ca -// - Use any of the asset-transfer-sbe chaincodes deployed on the channel "mychannel" -// with the chaincode name of "sbe". The following deploy command will package, -// install, approve, and commit the javascript chaincode, all the actions it takes -// to deploy a chaincode to a channel. -// ===> from directory /fabric-samples/test-network -// ./network.sh deployCC -ccn sbe -ccp ../asset-transfer-sbe/chaincode-typescript/ -ccl typescript -// - Be sure that node.js is installed -// ===> from directory /fabric-samples/asset-transfer-sbe/application-javascript -// node -v -// - npm installed code dependencies -// ===> from directory /fabric-samples/asset-transfer-sbe/application-javascript -// npm install -// - to run this test application -// ===> from directory /fabric-samples/asset-transfer-sbe/application-javascript -// node app.js - -// NOTE: If you see an error like these: -/* - - Error in setup: Error: DiscoveryService: mychannel error: access denied - - OR - - Failed to register user : Error: fabric-ca request register failed with errors [[ { code: 20, message: 'Authentication failure' } ]] - - */ -// Delete the /fabric-samples/asset-transfer-sbe/application-javascript/wallet directory -// and retry this application. -// -// The certificate authority must have been restarted and the saved certificates for the -// admin and application user are not valid. Deleting the wallet store will force these to be reset -// with the new certificate authority. -// - -const { Gateway, Wallets } = require('fabric-network'); -const FabricCAServices = require('fabric-ca-client'); -const path = require('path'); -const { buildCAClient, registerAndEnrollUser, enrollAdmin } = require('../../test-application/javascript/CAUtil.js'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet } = require('../../test-application/javascript/AppUtil.js'); - -const channelName = 'mychannel'; -const chaincodeName = 'sbe'; - -const org1 = 'Org1MSP'; -const org2 = 'Org2MSP'; -const Org1UserId = 'appUser1'; -const Org2UserId = 'appUser2'; - -async function initGatewayForOrg1() { - console.log('\n--> Fabric client user & Gateway init: Using Org1 identity to Org1 Peer'); - // build an in memory object with the network configuration (also known as a connection profile) - const ccpOrg1 = buildCCPOrg1(); - - // build an instance of the fabric ca services client based on - // the information in the network configuration - const caOrg1Client = buildCAClient(FabricCAServices, ccpOrg1, 'ca.org1.example.com'); - - // setup the wallet to cache the credentials of the application user, on the app server locally - const walletPathOrg1 = path.join(__dirname, 'wallet', 'org1'); - const walletOrg1 = await buildWallet(Wallets, walletPathOrg1); - - // in a real application this would be done on an administrative flow, and only once - // stores admin identity in local wallet, if needed - await enrollAdmin(caOrg1Client, walletOrg1, org1); - // register & enroll application user with CA, which is used as client identify to make chaincode calls - // and stores app user identity in local wallet - // In a real application this would be done only when a new user was required to be added - // and would be part of an administrative flow - await registerAndEnrollUser(caOrg1Client, walletOrg1, org1, Org1UserId, 'org1.department1'); - - try { - // Create a new gateway for connecting to Org's peer node. - const gatewayOrg1 = new Gateway(); - //connect using Discovery enabled - await gatewayOrg1.connect(ccpOrg1, - { wallet: walletOrg1, identity: Org1UserId, discovery: { enabled: true, asLocalhost: true } }); - - return gatewayOrg1; - } catch (error) { - console.error(`Error in connecting to gateway for Org1: ${error}`); - process.exit(1); - } -} - -async function initGatewayForOrg2() { - console.log('\n--> Fabric client user & Gateway init: Using Org2 identity to Org2 Peer'); - const ccpOrg2 = buildCCPOrg2(); - const caOrg2Client = buildCAClient(FabricCAServices, ccpOrg2, 'ca.org2.example.com'); - - const walletPathOrg2 = path.join(__dirname, 'wallet', 'org2'); - const walletOrg2 = await buildWallet(Wallets, walletPathOrg2); - - await enrollAdmin(caOrg2Client, walletOrg2, org2); - await registerAndEnrollUser(caOrg2Client, walletOrg2, org2, Org2UserId, 'org2.department1'); - - try { - // Create a new gateway for connecting to Org's peer node. - const gatewayOrg2 = new Gateway(); - await gatewayOrg2.connect(ccpOrg2, - { wallet: walletOrg2, identity: Org2UserId, discovery: { enabled: true, asLocalhost: true } }); - - return gatewayOrg2; - } catch (error) { - console.error(`Error in connecting to gateway for Org2: ${error}`); - process.exit(1); - } -} - -function checkAsset(org, assetKey, resultBuffer, value, ownerOrg) { - let asset; - if (resultBuffer) { - asset = JSON.parse(resultBuffer.toString('utf8')); - } - - if (asset && value) { - if (asset.Value === value && asset.OwnerOrg === ownerOrg) { - console.log(`*** Result from ${org} - asset ${asset.ID} has value of ${asset.Value} and owned by ${asset.OwnerOrg}`); - } else { - console.log(`*** Failed from ${org} - asset ${asset.ID} has value of ${asset.Value} and owned by ${asset.OwnerOrg}`); - } - } else if (!asset && value === 0 ) { - console.log(`*** Success from ${org} - asset ${assetKey} does not exist`); - } else { - console.log('*** Failed - asset read failed'); - } -} - -async function readAssetByBothOrgs(assetKey, value, ownerOrg, contractOrg1, contractOrg2) { - if (value) { - console.log(`\n--> Evaluate Transaction: ReadAsset, - ${assetKey} should have a value of ${value} and owned by ${ownerOrg}`); - } else { - console.log(`\n--> Evaluate Transaction: ReadAsset, - ${assetKey} should not exist`); - } - let resultBuffer; - resultBuffer = await contractOrg1.evaluateTransaction('ReadAsset', assetKey); - checkAsset('Org1', assetKey, resultBuffer, value, ownerOrg); - resultBuffer = await contractOrg2.evaluateTransaction('ReadAsset', assetKey); - checkAsset('Org2', assetKey, resultBuffer, value, ownerOrg); -} - -// This application uses fabric-samples/test-network based setup and the companion chaincode -// For this illustration, both Org1 & Org2 client identities will be used, however -// notice they are used by two different "gateway"s to simulate two different running -// applications from two different organizations. -async function main() { - try { - // use a random key so that we can run multiple times - const assetKey = `asset-${Math.floor(Math.random() * 100) + 1}`; - - /** ******* Fabric client init: Using Org1 identity to Org1 Peer ******* */ - const gatewayOrg1 = await initGatewayForOrg1(); - const networkOrg1 = await gatewayOrg1.getNetwork(channelName); - const contractOrg1 = networkOrg1.getContract(chaincodeName); - - /** ******* Fabric client init: Using Org2 identity to Org2 Peer ******* */ - const gatewayOrg2 = await initGatewayForOrg2(); - const networkOrg2 = await gatewayOrg2.getNetwork(channelName); - const contractOrg2 = networkOrg2.getContract(chaincodeName); - - try { - let transaction; - - try { - // Create an asset by organization Org1, this will require that both organization endorse. - // The endorsement will be handled by Discovery, since the gateway was connected with discovery enabled. - console.log(`\n--> Submit Transaction: CreateAsset, ${assetKey} as Org1 - endorsed by Org1 and Org2`); - await contractOrg1.submitTransaction('CreateAsset', assetKey, '100', 'Tom'); - console.log('*** Result: committed, now asset will only require Org1 to endorse'); - } catch (createError) { - console.log(`*** Failed: create - ${createError}`); - process.exit(1); - } - - await readAssetByBothOrgs(assetKey, 100, org1, contractOrg1, contractOrg2); - - try { - // Since the gateway is using discovery we should limit the organizations used by - // discovery to endorse. This way we only have to know the organization and not - // the actual peers that may be active at any given time. - console.log(`\n--> Submit Transaction: UpdateAsset ${assetKey}, as Org1 - endorse by Org1`); - transaction = contractOrg1.createTransaction('UpdateAsset'); - transaction.setEndorsingOrganizations(org1); - await transaction.submit(assetKey, '200'); - console.log('*** Result: committed'); - } catch (updateError) { - console.log(`*** Failed: update - ${updateError}`); - process.exit(1); - } - - await readAssetByBothOrgs(assetKey, 200, org1, contractOrg1, contractOrg2); - - try { - // Submit a transaction to make an update to the asset that has a key-level endorsement policy - // set to only allow Org1 to make updates. The following example will not use the "setEndorsingOrganizations" - // to limit the organizations that will do the endorsement, this means that it will be sent to all - // organizations in the chaincode endorsement policy. When Org1 endorses, the transaction will be committed - // if Org2 endorses or not. - console.log(`\n--> Submit Transaction: UpdateAsset ${assetKey}, as Org1 - endorse by Org1 and Org2`); - transaction = contractOrg1.createTransaction('UpdateAsset'); - await transaction.submit(assetKey, '300'); - console.log('*** Result: committed - because Org1 and Org2 both endorsed, while only the Org1 endorsement was required and checked'); - } catch (updateError) { - console.log(`*** Failed: update - ${updateError}`); - process.exit(1); - } - - await readAssetByBothOrgs(assetKey, 300, org1, contractOrg1, contractOrg2); - - try { - // Again submit the change to both Organizations by not using "setEndorsingOrganizations". Since only - // Org1 is required to approve, the transaction will be committed. - console.log(`\n--> Submit Transaction: UpdateAsset ${assetKey}, as Org2 - endorse by Org1 and Org2`); - transaction = contractOrg2.createTransaction('UpdateAsset'); - await transaction.submit(assetKey, '400'); - console.log('*** Result: committed - because Org1 was on the discovery list, Org2 did not endorse'); - } catch (updateError) { - console.log(`*** Failed: update - ${updateError}`); - process.exit(1); - } - - await readAssetByBothOrgs(assetKey, 400, org1, contractOrg1, contractOrg2); - - try { - // Try to update by sending only to Org2, since the state-based-endorsement says that - // Org1 is the only organization allowed to update, the transaction will fail. - console.log(`\n--> Submit Transaction: UpdateAsset ${assetKey}, as Org2 - endorse by Org2`); - transaction = contractOrg2.createTransaction('UpdateAsset'); - transaction.setEndorsingOrganizations(org2); - await transaction.submit(assetKey, '500'); - console.log('*** Failed: committed - this should have failed to endorse and commit'); - } catch (updateError) { - console.log(`*** Successfully caught the error: \n ${updateError}`); - } - - await readAssetByBothOrgs(assetKey, 400, org1, contractOrg1, contractOrg2); - - try { - // Make a change to the state-based-endorsement policy making Org2 the owner. - console.log(`\n--> Submit Transaction: TransferAsset ${assetKey}, as Org1 - endorse by Org1`); - transaction = contractOrg1.createTransaction('TransferAsset'); - transaction.setEndorsingOrganizations(org1); - await transaction.submit(assetKey, 'Henry', org2); - console.log('*** Result: committed'); - } catch (transferError) { - console.log(`*** Failed: transfer - ${transferError}`); - process.exit(1); - } - - await readAssetByBothOrgs(assetKey, 400, org2, contractOrg1, contractOrg2); - - try { - // Make sure that Org2 can now make updates, notice how the transaction has limited the - // endorsement to only Org2. - console.log(`\n--> Submit Transaction: UpdateAsset ${assetKey}, as Org2 - endorse by Org2`); - transaction = contractOrg2.createTransaction('UpdateAsset'); - transaction.setEndorsingOrganizations(org2); - await transaction.submit(assetKey, '600'); - console.log('*** Result: committed'); - } catch (updateError) { - console.log(`*** Failed: update - ${updateError}`); - process.exit(1); - } - - await readAssetByBothOrgs(assetKey, 600, org2, contractOrg1, contractOrg2); - - try { - // With Org2 now the owner and the state-based-endorsement policy only allowing organization Org2 - // to make updates, a transaction only to Org1 will fail. - console.log(`\n--> Submit Transaction: UpdateAsset ${assetKey}, as Org1 - endorse by Org1`); - transaction = contractOrg1.createTransaction('UpdateAsset'); - transaction.setEndorsingOrganizations(org1); - await transaction.submit(assetKey, '700'); - console.log('*** Failed: committed - this should have failed to endorse and commit'); - } catch (updateError) { - console.log(`*** Successfully caught the error: \n ${updateError}`); - } - - await readAssetByBothOrgs(assetKey, 600, org2, contractOrg1, contractOrg2); - - try { - // With Org2 the owner and the state-based-endorsement policy only allowing organization Org2 - // to make updates, a transaction to delete by Org1 will fail. - console.log(`\n--> Submit Transaction: DeleteAsset ${assetKey}, as Org1 - endorse by Org1`); - transaction = contractOrg1.createTransaction('DeleteAsset'); - transaction.setEndorsingOrganizations(org1); - await transaction.submit(assetKey); - console.log('*** Failed: committed - this should have failed to endorse and commit'); - } catch (updateError) { - console.log(`*** Successfully caught the error: \n ${updateError}`); - } - - try { - // With Org2 the owner and the state-based-endorsement policy only allowing organization Org2 - // to make updates, a transaction to delete by Org2 will succeed. - console.log(`\n--> Submit Transaction: DeleteAsset ${assetKey}, as Org2 - endorse by Org2`); - transaction = contractOrg2.createTransaction('DeleteAsset'); - transaction.setEndorsingOrganizations(org2); - await transaction.submit(assetKey); - console.log('*** Result: committed'); - } catch (deleteError) { - console.log(`*** Failed: delete - ${deleteError}`); - process.exit(1); - } - - // The asset should now be deleted, both orgs should not be able to read it - try { - await readAssetByBothOrgs(assetKey, 0, org2, contractOrg1, contractOrg2); - } catch (readDeleteError) { - console.log(`*** Successfully caught the error: ${readDeleteError}`); - } - - } catch (runError) { - console.error(`Error in transaction: ${runError}`); - if (runError.stack) { - console.error(runError.stack); - } - process.exit(1); - } finally { - // Disconnect from the gateway peer when all work for this client identity is complete - gatewayOrg1.disconnect(); - gatewayOrg2.disconnect(); - } - } catch (error) { - console.error(`Error in setup: ${error}`); - if (error.stack) { - console.error(error.stack); - } - process.exit(1); - } -} - -main(); diff --git a/asset-transfer-sbe/application-javascript/package.json b/asset-transfer-sbe/application-javascript/package.json deleted file mode 100644 index 09ed4f1d..00000000 --- a/asset-transfer-sbe/application-javascript/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "asset-transfer-sbe", - "version": "1.0.0", - "description": "Asset transfer state based endorsement application implemented in JavaScript", - "engines": { - "node": ">=12", - "npm": ">=5" - }, - "engineStrict": true, - "author": "Hyperledger", - "license": "Apache-2.0", - "scripts": { - "lint": "eslint *.js" - }, - "dependencies": { - "fabric-ca-client": "^2.2.19", - "fabric-network": "^2.2.19" - }, - "devDependencies": { - "eslint": "^7.32.0" - } -} diff --git a/asset-transfer-sbe/chaincode-java/.gitattributes b/asset-transfer-sbe/chaincode-java/.gitattributes deleted file mode 100644 index 00a51aff..00000000 --- a/asset-transfer-sbe/chaincode-java/.gitattributes +++ /dev/null @@ -1,6 +0,0 @@ -# -# https://help.github.com/articles/dealing-with-line-endings/ -# -# These are explicitly windows files and should use crlf -*.bat text eol=crlf - diff --git a/asset-transfer-sbe/chaincode-java/.gitignore b/asset-transfer-sbe/chaincode-java/.gitignore deleted file mode 100644 index ae1478ca..00000000 --- a/asset-transfer-sbe/chaincode-java/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -/.classpath -/.gradle/ -/.project -/.settings/ -/bin/ -/build/ diff --git a/asset-transfer-sbe/chaincode-java/build.gradle b/asset-transfer-sbe/chaincode-java/build.gradle deleted file mode 100644 index a788dfc4..00000000 --- a/asset-transfer-sbe/chaincode-java/build.gradle +++ /dev/null @@ -1,86 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -plugins { - id 'com.gradleup.shadow' version '8.3.5' - id 'application' - id 'checkstyle' - id 'jacoco' -} - -group 'org.hyperledger.fabric.samples' -version '1.0-SNAPSHOT' - -dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.+' - implementation 'org.hyperledger.fabric:fabric-protos:0.3.3' - implementation 'com.owlike:genson:1.6' -} - -repositories { - mavenCentral() - maven { - url 'https://jitpack.io' - } -} - -java { - toolchain { - languageVersion = JavaLanguageVersion.of(11) - } -} - -application { - mainClass = 'org.hyperledger.fabric.contract.ContractRouter' -} - -checkstyle { - toolVersion '8.21' - configFile file("config/checkstyle/checkstyle.xml") -} - -checkstyleMain { - source ='src/main/java' -} - -checkstyleTest { - source ='src/test/java' -} - -jacocoTestReport { - dependsOn test -} - -jacocoTestCoverageVerification { - violationRules { - rule { - limit { - minimum = 0.9 - } - } - } - - finalizedBy jacocoTestReport -} - -test { - useJUnitPlatform() - testLogging { - events "passed", "skipped", "failed" - } -} - -shadowJar { - archiveBaseName = 'chaincode' - archiveVersion = '' - archiveClassifier = '' - mergeServiceFiles() - - manifest { - attributes 'Main-Class': 'org.hyperledger.fabric.contract.ContractRouter' - } -} - -check.dependsOn jacocoTestCoverageVerification -installDist.dependsOn check diff --git a/asset-transfer-sbe/chaincode-java/config/checkstyle/checkstyle.xml b/asset-transfer-sbe/chaincode-java/config/checkstyle/checkstyle.xml deleted file mode 100644 index 797da97b..00000000 --- a/asset-transfer-sbe/chaincode-java/config/checkstyle/checkstyle.xml +++ /dev/null @@ -1,172 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/asset-transfer-sbe/chaincode-java/config/checkstyle/suppressions.xml b/asset-transfer-sbe/chaincode-java/config/checkstyle/suppressions.xml deleted file mode 100644 index 8c44b0a0..00000000 --- a/asset-transfer-sbe/chaincode-java/config/checkstyle/suppressions.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/asset-transfer-sbe/chaincode-java/gradle/wrapper/gradle-wrapper.jar b/asset-transfer-sbe/chaincode-java/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index d64cd4917707c1f8861d8cb53dd15194d4248596..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43462 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 diff --git a/asset-transfer-sbe/chaincode-java/gradle/wrapper/gradle-wrapper.properties b/asset-transfer-sbe/chaincode-java/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index e2847c82..00000000 --- a/asset-transfer-sbe/chaincode-java/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/asset-transfer-sbe/chaincode-java/gradlew b/asset-transfer-sbe/chaincode-java/gradlew deleted file mode 100755 index 1aa94a42..00000000 --- a/asset-transfer-sbe/chaincode-java/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/asset-transfer-sbe/chaincode-java/gradlew.bat b/asset-transfer-sbe/chaincode-java/gradlew.bat deleted file mode 100644 index 25da30db..00000000 --- a/asset-transfer-sbe/chaincode-java/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/asset-transfer-sbe/chaincode-java/settings.gradle b/asset-transfer-sbe/chaincode-java/settings.gradle deleted file mode 100644 index e435c090..00000000 --- a/asset-transfer-sbe/chaincode-java/settings.gradle +++ /dev/null @@ -1,5 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -rootProject.name = 'sbe' diff --git a/asset-transfer-sbe/chaincode-java/src/main/java/org/hyperledger/fabric/samples/sbe/Asset.java b/asset-transfer-sbe/chaincode-java/src/main/java/org/hyperledger/fabric/samples/sbe/Asset.java deleted file mode 100644 index ca14959d..00000000 --- a/asset-transfer-sbe/chaincode-java/src/main/java/org/hyperledger/fabric/samples/sbe/Asset.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.hyperledger.fabric.samples.sbe; - -import com.owlike.genson.annotation.JsonProperty; -import org.hyperledger.fabric.contract.annotation.DataType; -import org.hyperledger.fabric.contract.annotation.Property; - -import java.util.Objects; - -@DataType() -public final class Asset { - - @Property() - private final String ID; - - @Property() - private int Value; - - @Property() - private String Owner; - - @Property() - private String OwnerOrg; - - @JsonProperty("ID") - public String getID() { - return ID; - } - - @JsonProperty("Value") - public int getValue() { - return Value; - } - - public void setValue(final int Value) { - this.Value = Value; - } - - @JsonProperty("Owner") - public String getOwner() { - return Owner; - } - - public void setOwner(final String Owner) { - this.Owner = Owner; - } - - @JsonProperty("OwnerOrg") - public String getOwnerOrg() { - return OwnerOrg; - } - - public void setOwnerOrg(final String OwnerOrg) { - this.OwnerOrg = OwnerOrg; - } - - public Asset(@JsonProperty("ID") final String ID, @JsonProperty("Value") final int Value, - @JsonProperty("Owner") final String Owner, @JsonProperty("OwnerOrg") final String OwnerOrg) { - this.ID = ID; - this.Value = Value; - this.Owner = Owner; - this.OwnerOrg = OwnerOrg; - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Asset asset = (Asset) o; - return getValue() == asset.getValue() - && - getID().equals(asset.getID()) - && - getOwner().equals(asset.getOwner()) - && - getOwnerOrg().equals(asset.getOwnerOrg()); - } - - @Override - public int hashCode() { - return Objects.hash(getID(), getValue(), getOwner(), getOwnerOrg()); - } - - @Override - public String toString() { - return "Asset{" + "ID='" + ID + '\'' + ", Value=" + Value + ", Owner='" - + Owner + '\'' + ", OwnerOrg='" + OwnerOrg + '\'' + '}'; - } -} diff --git a/asset-transfer-sbe/chaincode-java/src/main/java/org/hyperledger/fabric/samples/sbe/AssetContract.java b/asset-transfer-sbe/chaincode-java/src/main/java/org/hyperledger/fabric/samples/sbe/AssetContract.java deleted file mode 100644 index 62b286b0..00000000 --- a/asset-transfer-sbe/chaincode-java/src/main/java/org/hyperledger/fabric/samples/sbe/AssetContract.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.hyperledger.fabric.samples.sbe; - -import com.owlike.genson.Genson; -import org.hyperledger.fabric.contract.Context; -import org.hyperledger.fabric.contract.ContractInterface; -import org.hyperledger.fabric.contract.annotation.Contract; -import org.hyperledger.fabric.contract.annotation.Default; -import org.hyperledger.fabric.contract.annotation.Info; -import org.hyperledger.fabric.contract.annotation.License; -import org.hyperledger.fabric.contract.annotation.Transaction; -import org.hyperledger.fabric.protos.common.MSPPrincipal; -import org.hyperledger.fabric.protos.common.MSPRole; -import org.hyperledger.fabric.protos.common.SignaturePolicy; -import org.hyperledger.fabric.protos.common.SignaturePolicyEnvelope; -import org.hyperledger.fabric.shim.ChaincodeException; -import org.hyperledger.fabric.shim.ChaincodeStub; -import org.hyperledger.fabric.shim.ext.sbe.StateBasedEndorsement; -import org.hyperledger.fabric.shim.ext.sbe.impl.StateBasedEndorsementFactory; - -import java.util.Comparator; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -@Contract( - name = "sbe", - info = @Info( - title = "Asset Contract", - description = "Asset Transfer Smart Contract, using State Based Endorsement(SBE), implemented in Java", - version = "0.0.1-SNAPSHOT", - license = @License( - name = "Apache 2.0 License", - url = "http://www.apache.org/licenses/LICENSE-2.0.html"))) -@Default -public final class AssetContract implements ContractInterface { - private final Genson genson = new Genson(); - - private enum AssetTransferErrors { - ASSET_NOT_FOUND, - ASSET_ALREADY_EXISTS - } - - /** - * Creates a new asset. - * Sets the endorsement policy of the assetId Key, such that current owner Org Peer is required to endorse future updates. - * Optionally, set the endorsement policy of the assetId Key, such that any 1(N) out of the Org's specified can endorse future updates. - * - * @param ctx the transaction context - * @param assetId the id of the new asset - * @param value the value of the new asset - * @param owner the owner of the new asset - * @return the created asset - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public Asset CreateAsset(final Context ctx, final String assetId, final int value, final String owner) { - ChaincodeStub stub = ctx.getStub(); - - if (AssetExists(ctx, assetId)) { - String errorMessage = String.format("Asset %s already exists", assetId); - System.out.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.ASSET_ALREADY_EXISTS.toString()); - } - - final String ownerOrg = getClientOrgId(ctx); - Asset asset = new Asset(assetId, value, owner, ownerOrg); - String assetJSON = genson.serialize(asset); - stub.putStringState(assetId, assetJSON); - - // Set the endorsement policy of the assetId Key, such that current owner Org is required to endorse future updates - setStateBasedEndorsement(ctx, assetId, List.of(ownerOrg)); - - // Optionally, set the endorsement policy of the assetId Key, such that any 1 Org (N) out of the specified Orgs can endorse future updates - // setStateBasedEndorsementNOutOf(ctx, assetId, 1, new String[]{"Org1MSP", "Org2MSP"}); - - return asset; - } - - /** - * Retrieves an asset with the given assetId. - * - * @param ctx the transaction context - * @param assetId the id of the asset - * @return the asset found on the ledger if there was one - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public String ReadAsset(final Context ctx, final String assetId) { - ChaincodeStub stub = ctx.getStub(); - String assetJSON = stub.getStringState(assetId); - - if (assetJSON == null || assetJSON.isEmpty()) { - String errorMessage = String.format("Asset %s does not exist", assetId); - System.out.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.ASSET_NOT_FOUND.toString()); - } - - return assetJSON; - } - - /** - * Updates the properties of an existing asset. - * Needs an endorsement of current owner Org Peer. - * - * @param ctx the transaction context - * @param assetId the id of the asset being updated - * @param newValue the value of the asset being updated - * @return the updated asset - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public Asset UpdateAsset(final Context ctx, final String assetId, final int newValue) { - ChaincodeStub stub = ctx.getStub(); - - String assetString = ReadAsset(ctx, assetId); - Asset asset = genson.deserialize(assetString, Asset.class); - asset.setValue(newValue); - String updatedAssetJSON = genson.serialize(asset); - stub.putStringState(assetId, updatedAssetJSON); - - return asset; - } - - /** - * Deletes the given asset. - * Needs an endorsement of current owner Org Peer. - * - * @param ctx the transaction context - * @param assetId the id of the asset being deleted - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public void DeleteAsset(final Context ctx, final String assetId) { - ChaincodeStub stub = ctx.getStub(); - - if (!AssetExists(ctx, assetId)) { - String errorMessage = String.format("Asset %s does not exist", assetId); - System.out.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.ASSET_NOT_FOUND.toString()); - } - - stub.delState(assetId); - } - - /** - * Updates the owner & ownerOrg field of asset with given assetId, ownerOrg must be a valid Org MSP Id. - * Needs an endorsement of current owner Org Peer. - * Re-sets the endorsement policy of the assetId Key, such that new owner Org Peer is required to endorse future updates. - * - * @param ctx the transaction context - * @param assetId the id of the asset being transferred - * @param newOwner the new owner - * @param newOwnerOrg the new owner Org MSPID - * @return the updated asset - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public Asset TransferAsset(final Context ctx, final String assetId, final String newOwner, final String newOwnerOrg) { - ChaincodeStub stub = ctx.getStub(); - - String assetString = ReadAsset(ctx, assetId); - Asset asset = genson.deserialize(assetString, Asset.class); - asset.setOwner(newOwner); - asset.setOwnerOrg(newOwnerOrg); - String updatedAssetJSON = genson.serialize(asset); - stub.putStringState(assetId, updatedAssetJSON); - - // Re-Set the endorsement policy of the assetId Key, such that a new owner Org Peer is required to endorse future updates - setStateBasedEndorsement(ctx, assetId, List.of(newOwnerOrg)); - - // Optionally, set the endorsement policy of the assetId Key, such that any 1 Org (N) out of the specified Orgs can endorse future updates - // setStateBasedEndorsementNOutOf(ctx, assetId, 1, List.of("Org1MSP", "Org2MSP")); - - return asset; - } - - /** - * Checks the existence of the asset. - * - * @param ctx the transaction context - * @param assetId the id of the asset - * @return boolean indicating the existence of the asset - */ - private boolean AssetExists(final Context ctx, final String assetId) { - ChaincodeStub stub = ctx.getStub(); - String assetJSON = stub.getStringState(assetId); - - return (assetJSON != null && !assetJSON.isEmpty()); - } - - /** - * Retrieves the client's OrgId (MSPID) - * - * @param ctx the transaction context - * @return String value of the Org MSPID - */ - private static String getClientOrgId(final Context ctx) { - return ctx.getClientIdentity().getMSPID(); - } - - /** - * Sets an endorsement policy to the assetId Key. - * Enforces that the owner Org must endorse future update transactions for the specified assetId Key. - * - * @param ctx the transaction context - * @param assetId the id of the asset - * @param ownerOrgs the list of Owner Org MSPID's - */ - private static void setStateBasedEndorsement(final Context ctx, final String assetId, final List ownerOrgs) { - StateBasedEndorsement stateBasedEndorsement = StateBasedEndorsementFactory.getInstance().newStateBasedEndorsement(null); - stateBasedEndorsement.addOrgs(StateBasedEndorsement.RoleType.RoleTypeMember, ownerOrgs.toArray(new String[0])); - ctx.getStub().setStateValidationParameter(assetId, stateBasedEndorsement.policy()); - } - - /** - * Sets an endorsement policy to the assetId Key. - * Enforces that a given number of Orgs (N) out of the specified Orgs must endorse future update transactions for the specified assetId Key. - * - * @param ctx the transaction context - * @param assetId the id of the asset - * @param nOrgs the number of N Orgs to endorse out of the list of Orgs provided - * @param ownerOrgs the list of Owner Org MSPID's - */ - private static void setStateBasedEndorsementNOutOf(final Context ctx, final String assetId, final int nOrgs, final List ownerOrgs) { - ctx.getStub().setStateValidationParameter(assetId, policy(nOrgs, ownerOrgs)); - } - - /** - * Create a policy that requires a given number (N) of Org principals signatures out of the provided list of Orgs - * - * @param nOrgs the number of Org principals signatures required to endorse (out of the provided list of Orgs) - * @param mspIds the list of Owner Org MSPID's - */ - private static byte[] policy(final int nOrgs, final List mspIds) { - mspIds.sort(Comparator.naturalOrder()); - - var principals = mspIds.stream() - .map(mspId -> MSPRole.newBuilder() - .setMspIdentifier(mspId) - .setRole(MSPRole.MSPRoleType.MEMBER) - .build()) - .map(role -> MSPPrincipal.newBuilder() - .setPrincipalClassification(MSPPrincipal.Classification.ROLE) - .setPrincipal(role.toByteString()) - .build()) - .collect(Collectors.toList()); - - var signPolicy = IntStream.range(0, mspIds.size()) - .mapToObj(AssetContract::signedBy) - .collect(Collectors.toList()); - - // Create the policy such that it requires any N signature's from all the principals provided - return SignaturePolicyEnvelope.newBuilder() - .setVersion(0) - .setRule(nOutOf(nOrgs, signPolicy)) - .addAllIdentities(principals) - .build() - .toByteArray(); - } - - private static SignaturePolicy signedBy(final int index) { - return SignaturePolicy.newBuilder().setSignedBy(index).build(); - } - - private static SignaturePolicy nOutOf(final int n, final List policies) { - return SignaturePolicy.newBuilder().setNOutOf( - SignaturePolicy.NOutOf.newBuilder().setN(n).addAllRules(policies).build() - ).build(); - } -} diff --git a/asset-transfer-sbe/chaincode-typescript/.gitignore b/asset-transfer-sbe/chaincode-typescript/.gitignore deleted file mode 100644 index 2a76b3d8..00000000 --- a/asset-transfer-sbe/chaincode-typescript/.gitignore +++ /dev/null @@ -1,20 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -# Coverage directory used by tools like istanbul -coverage - -# Dependency directories -node_modules/ -jspm_packages/ -package-lock.json - -# Compiled TypeScript files -dist - -# Editor Config -.editorconfig - -# npm ignore -.npmignore diff --git a/asset-transfer-sbe/chaincode-typescript/eslint.config.mjs b/asset-transfer-sbe/chaincode-typescript/eslint.config.mjs deleted file mode 100644 index 9ef6b243..00000000 --- a/asset-transfer-sbe/chaincode-typescript/eslint.config.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import js from '@eslint/js'; -import tseslint from 'typescript-eslint'; - -export default tseslint.config(js.configs.recommended, ...tseslint.configs.strictTypeChecked, { - languageOptions: { - ecmaVersion: 2023, - sourceType: 'module', - parserOptions: { - project: 'tsconfig.json', - tsconfigRootDir: import.meta.dirname, - }, - }, -}); diff --git a/asset-transfer-sbe/chaincode-typescript/npm-shrinkwrap.json b/asset-transfer-sbe/chaincode-typescript/npm-shrinkwrap.json deleted file mode 100644 index 8ddcd6ac..00000000 --- a/asset-transfer-sbe/chaincode-typescript/npm-shrinkwrap.json +++ /dev/null @@ -1,2205 +0,0 @@ -{ - "name": "asset-transfer-sbe", - "version": "0.0.1", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "asset-transfer-sbe", - "version": "0.0.1", - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "fabric-contract-api": "~2.5", - "fabric-shim": "~2.5" - }, - "devDependencies": { - "@eslint/js": "^9.3.0", - "@tsconfig/node18": "^18.2.4", - "@types/node": "^18.19.33", - "eslint": "^8.57.0", - "typescript": "~5.4.5", - "typescript-eslint": "^7.11.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@colors/colors": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", - "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@dabh/diagnostics": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", - "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", - "dependencies": { - "colorspace": "1.1.x", - "enabled": "2.0.x", - "kuler": "^2.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", - "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/js": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.5.0.tgz", - "integrity": "sha512-A7+AOT2ICkodvtsWnxZP4Xxk3NbZ3VMHd8oihydLRGrJgqqdEz1qSeEgXYyT/Cu8h1TWWsQRejIx48mtjZ5y1w==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@fidm/asn1": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@fidm/asn1/-/asn1-1.0.4.tgz", - "integrity": "sha512-esd1jyNvRb2HVaQGq2Gg8Z0kbQPXzV9Tq5Z14KNIov6KfFD6PTaRIO8UpcsYiTNzOqJpmyzWgVTrUwFV3UF4TQ==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@fidm/x509": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@fidm/x509/-/x509-1.2.1.tgz", - "integrity": "sha512-nwc2iesjyc9hkuzcrMCBXQRn653XuAUKorfWM8PZyJawiy1QzLj4vahwzaI25+pfpwOLvMzbJ0uKpWLDNmo16w==", - "dependencies": { - "@fidm/asn1": "^1.0.4", - "tweetnacl": "^1.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@grpc/grpc-js": { - "version": "1.10.9", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.10.9.tgz", - "integrity": "sha512-5tcgUctCG0qoNyfChZifz2tJqbRbXVO9J7X6duFcOjY3HUNCxg5D0ZCK7EP9vIcZ0zRpLU9bWkyCqVCLZ46IbQ==", - "dependencies": { - "@grpc/proto-loader": "^0.7.13", - "@js-sdsl/ordered-map": "^4.4.2" - }, - "engines": { - "node": ">=12.10.0" - } - }, - "node_modules/@grpc/proto-loader": { - "version": "0.7.13", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", - "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", - "dependencies": { - "lodash.camelcase": "^4.3.0", - "long": "^5.0.0", - "protobufjs": "^7.2.5", - "yargs": "^17.7.2" - }, - "bin": { - "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true - }, - "node_modules/@hyperledger/fabric-protos": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@hyperledger/fabric-protos/-/fabric-protos-0.2.1.tgz", - "integrity": "sha512-qjm0vIQIfCall804tWDeA8p/mUfu14sl5Sj+PbOn2yDKJq+7ThoIhNsLAqf+BCxUfqsoqQq6AojhqQeTFyOOqg==", - "dependencies": { - "@grpc/grpc-js": "^1.9.0", - "google-protobuf": "^3.21.0" - }, - "engines": { - "node": ">=14.15.0" - } - }, - "node_modules/@js-sdsl/ordered-map": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", - "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" - }, - "node_modules/@tsconfig/node18": { - "version": "18.2.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node18/-/node18-18.2.4.tgz", - "integrity": "sha512-5xxU8vVs9/FNcvm3gE07fPbn9tl6tqGGWA9tSlwsUEkBxtRnTsNmwrV8gasZ9F/EobaSv9+nu8AxUKccw77JpQ==", - "dev": true - }, - "node_modules/@types/node": { - "version": "18.19.34", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.34.tgz", - "integrity": "sha512-eXF4pfBNV5DAMKGbI02NnDtWrQ40hAN558/2vvS4gMpMIxaf6JmD7YjnZbq0Q9TDSSkKBamime8ewRoomHdt4g==", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/triple-beam": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", - "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.0.tgz", - "integrity": "sha512-FX1X6AF0w8MdVFLSdqwqN/me2hyhuQg4ykN6ZpVhh1ij/80pTvDKclX1sZB9iqex8SjQfVhwMKs3JtnnMLzG9w==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.13.0", - "@typescript-eslint/type-utils": "7.13.0", - "@typescript-eslint/utils": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^7.0.0", - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.0.tgz", - "integrity": "sha512-EjMfl69KOS9awXXe83iRN7oIEXy9yYdqWfqdrFAYAAr6syP8eLEFI7ZE4939antx2mNgPRW/o1ybm2SFYkbTVA==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "7.13.0", - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/typescript-estree": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.0.tgz", - "integrity": "sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.0.tgz", - "integrity": "sha512-xMEtMzxq9eRkZy48XuxlBFzpVMDurUAfDu5Rz16GouAtXm0TaAoTFzqWUFPPuQYXI/CDaH/Bgx/fk/84t/Bc9A==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "7.13.0", - "@typescript-eslint/utils": "7.13.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.0.tgz", - "integrity": "sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==", - "dev": true, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.0.tgz", - "integrity": "sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.0.tgz", - "integrity": "sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.13.0", - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/typescript-estree": "7.13.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.0.tgz", - "integrity": "sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.13.0", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/class-transformer": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.4.0.tgz", - "integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==" - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/color": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", - "dependencies": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/color/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/colorspace": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", - "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", - "dependencies": { - "color": "^3.1.3", - "text-hex": "1.0.x" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/enabled": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", - "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" - }, - "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fabric-contract-api": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/fabric-contract-api/-/fabric-contract-api-2.5.6.tgz", - "integrity": "sha512-AosGb8tA+Jgt+pqMEgYNB3/J/P5QuWOC7yhXbhDmAAwUzn4Sc7pdWDICH1YyrFGZNFxMGQmqJmLVWUX8BKHy0w==", - "dependencies": { - "class-transformer": "^0.4.0", - "fabric-shim-api": "2.5.6", - "fast-safe-stringify": "^2.1.1", - "get-params": "^0.1.2", - "reflect-metadata": "^0.1.13", - "winston": "^3.7.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/fabric-shim": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/fabric-shim/-/fabric-shim-2.5.6.tgz", - "integrity": "sha512-4Y8WNFhYuQ9QYSEgPXWdlXnrXjwOlM10sQQzE4kJ7cDh8a4LX0rn44FxtxTCB18lnzrSLMZ8/8Cr5m0c9NeXWA==", - "dependencies": { - "@fidm/x509": "^1.2.1", - "@grpc/grpc-js": "~1.10.9", - "@hyperledger/fabric-protos": "~0.2.1", - "@types/node": "^16.11.1", - "ajv": "^6.12.2", - "fabric-contract-api": "2.5.6", - "fabric-shim-api": "2.5.6", - "fast-safe-stringify": "^2.1.1", - "long": "^5.2.3", - "reflect-metadata": "^0.1.13", - "winston": "^3.7.2", - "yargs": "^17.4.0", - "yargs-parser": "^21.0.1" - }, - "bin": { - "fabric-chaincode-node": "cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/fabric-shim-api": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/fabric-shim-api/-/fabric-shim-api-2.5.6.tgz", - "integrity": "sha512-1L0nO7CJ31/gEOWKWHEeCqgB5HkqPVfRbpcS7L9eTscT7tffjg2OkZISvC+a7RiqihL0iyrXNBgBg5MwlSSN9g==", - "engines": { - "eslint": "^6.6.0", - "node": ">=18" - } - }, - "node_modules/fabric-shim/node_modules/@types/node": { - "version": "16.18.98", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.98.tgz", - "integrity": "sha512-fpiC20NvLpTLAzo3oVBKIqBGR6Fx/8oAK/SSf7G+fydnXMY1x4x9RZ6sBXhqKlCU21g2QapUsbLlhv3+a7wS+Q==" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fecha": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "node_modules/fn.name": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", - "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-params": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/get-params/-/get-params-0.1.2.tgz", - "integrity": "sha512-41eOxtlGgHQRbFyA8KTH+w+32Em3cRdfBud7j67ulzmIfmaHX9doq47s0fa4P5o9H64BZX9nrYI6sJvk46Op+Q==" - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "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" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/google-protobuf": { - "version": "3.21.2", - "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz", - "integrity": "sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==" - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/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, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kuler": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/logform": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", - "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", - "dependencies": { - "@colors/colors": "1.6.0", - "@types/triple-beam": "^1.3.2", - "fecha": "^4.2.0", - "ms": "^2.1.1", - "safe-stable-stringify": "^2.3.1", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/long": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", - "dev": true, - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/one-time": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", - "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", - "dependencies": { - "fn.name": "1.x.x" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/protobufjs": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.2.tgz", - "integrity": "sha512-RXyHaACeqXeqAKGLDl68rQKbmObRsTIn4TYVUUug1KfS47YWCo5MacGITEryugIgZqORCvJWEk4l449POg5Txg==", - "hasInstallScript": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/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, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/reflect-metadata": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", - "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==" - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safe-stable-stringify": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", - "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", - "engines": { - "node": ">=10" - } - }, - "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", - "engines": { - "node": "*" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-hex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/triple-beam": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", - "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", - "dev": true, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/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, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.13.0.tgz", - "integrity": "sha512-upO0AXxyBwJ4BbiC6CRgAJKtGYha2zw4m1g7TIVPSonwYEuf7vCicw3syjS1OxdDMTz96sZIXl3Jx3vWJLLKFw==", - "dev": true, - "dependencies": { - "@typescript-eslint/eslint-plugin": "7.13.0", - "@typescript-eslint/parser": "7.13.0", - "@typescript-eslint/utils": "7.13.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/winston": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.13.0.tgz", - "integrity": "sha512-rwidmA1w3SE4j0E5MuIufFhyJPBDG7Nu71RkZor1p2+qHvJSZ9GYDA81AyleQcZbh/+V6HjeBdfnTZJm9rSeQQ==", - "dependencies": { - "@colors/colors": "^1.6.0", - "@dabh/diagnostics": "^2.0.2", - "async": "^3.2.3", - "is-stream": "^2.0.0", - "logform": "^2.4.0", - "one-time": "^1.0.0", - "readable-stream": "^3.4.0", - "safe-stable-stringify": "^2.3.1", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.7.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/winston-transport": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz", - "integrity": "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==", - "dependencies": { - "logform": "^2.3.2", - "readable-stream": "^3.6.0", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "engines": { - "node": ">=12" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/asset-transfer-sbe/chaincode-typescript/package.json b/asset-transfer-sbe/chaincode-typescript/package.json deleted file mode 100644 index 4ce6b7c3..00000000 --- a/asset-transfer-sbe/chaincode-typescript/package.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "asset-transfer-sbe", - "version": "0.0.1", - "description": "Asset Transfer contract, using State Based Endorsement(SBE), implemented in TypeScript", - "main": "dist/index.js", - "typings": "dist/index.d.ts", - "engines": { - "node": ">=18" - }, - "scripts": { - "lint": "eslint src", - "pretest": "npm run lint", - "test": "echo 'No tests implemented'", - "start": "fabric-chaincode-node start", - "build": "tsc", - "build:watch": "tsc -w", - "prepublishOnly": "npm run build", - "postinstall": "npm dedupe" - }, - "engineStrict": true, - "author": "Hyperledger", - "license": "Apache-2.0", - "dependencies": { - "fabric-contract-api": "~2.5", - "fabric-shim": "~2.5" - }, - "devDependencies": { - "@types/node": "^18.19.33", - "@eslint/js": "^9.3.0", - "@tsconfig/node18": "^18.2.4", - "eslint": "^8.57.0", - "typescript": "~5.4.5", - "typescript-eslint": "^7.11.0" -} -} diff --git a/asset-transfer-sbe/chaincode-typescript/src/asset.ts b/asset-transfer-sbe/chaincode-typescript/src/asset.ts deleted file mode 100644 index 272d6baf..00000000 --- a/asset-transfer-sbe/chaincode-typescript/src/asset.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -import { Object, Property } from 'fabric-contract-api'; - -@Object() -export class Asset { - @Property() - public ID: string = ''; - - @Property() - public Value: number = 0; - - @Property() - public Owner: string = ''; - - @Property() - public OwnerOrg: string = ''; -} diff --git a/asset-transfer-sbe/chaincode-typescript/src/assetContract.ts b/asset-transfer-sbe/chaincode-typescript/src/assetContract.ts deleted file mode 100644 index 019b9b19..00000000 --- a/asset-transfer-sbe/chaincode-typescript/src/assetContract.ts +++ /dev/null @@ -1,121 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -import { Context, Contract, Info, Transaction } from 'fabric-contract-api'; -import { Asset } from './asset'; -import { KeyEndorsementPolicy } from 'fabric-shim'; - -@Info({title: 'AssetContract', description: 'Asset Transfer Smart Contract, using State Based Endorsement(SBE), implemented in TypeScript' }) -export class AssetContract extends Contract { - // CreateAsset creates a new asset - // CreateAsset sets the endorsement policy of the assetId Key, such that current owner Org Peer is required to endorse future updates - @Transaction() - public async CreateAsset(ctx: Context, assetId: string, value: number, owner: string): Promise { - const exists = await this.AssetExists(ctx, assetId); - if (exists) { - throw new Error(`The asset ${assetId} already exists`); - } - const ownerOrg = AssetContract.getClientOrgId(ctx); - const asset = new Asset(); - asset.ID = assetId; - asset.Value = value; - asset.Owner = owner; - asset.OwnerOrg = ownerOrg; - const buffer = Buffer.from(JSON.stringify(asset)); - // Create the asset - await ctx.stub.putState(assetId, buffer); - - // Set the endorsement policy of the assetId Key, such that current owner Org is required to endorse future updates - await AssetContract.setStateBasedEndorsement(ctx, assetId, [ownerOrg]); - - // Optionally, set the endorsement policy of the assetId Key, such that any 1 Org (N) out of the specified Orgs can endorse future updates - // await AssetContract.setStateBasedEndorsementNOutOf(ctx, assetId, 1, ["Org1MSP", "Org2MSP"]); - } - - // ReadAsset returns asset with given assetId - @Transaction(false) - public async ReadAsset(ctx: Context, assetId: string): Promise { - const exists = await this.AssetExists(ctx, assetId); - if (!exists) { - throw new Error(`The asset ${assetId} does not exist`); - } - // Read the asset - const assetJSON = await ctx.stub.getState(assetId); - return assetJSON.toString(); - } - - // UpdateAsset updates an existing asset - // UpdateAsset needs an endorsement of current owner Org Peer - @Transaction() - public async UpdateAsset(ctx: Context, assetId: string, newValue: number): Promise { - const assetString = await this.ReadAsset(ctx, assetId); - const asset = JSON.parse(assetString) as Asset; - asset.Value = newValue; - const buffer = Buffer.from(JSON.stringify(asset)); - // Update the asset - await ctx.stub.putState(assetId, buffer); - } - - // DeleteAsset deletes an given asset - // DeleteAsset needs an endorsement of current owner Org Peer - @Transaction() - public async DeleteAsset(ctx: Context, assetId: string): Promise { - const exists = await this.AssetExists(ctx, assetId); - if (!exists) { - throw new Error(`The asset ${assetId} does not exist`); - } - // Delete the asset - await ctx.stub.deleteState(assetId); - } - - // TransferAsset updates the Owner & OwnerOrg field of asset with given assetId, OwnerOrg must be a valid Org MSP Id - // TransferAsset needs an endorsement of current owner Org Peer - // TransferAsset re-sets the endorsement policy of the assetId Key, such that new owner Org Peer is required to endorse future updates - @Transaction() - public async TransferAsset(ctx: Context, assetId: string, newOwner: string, newOwnerOrg: string): Promise { - const assetString = await this.ReadAsset(ctx, assetId); - const asset = JSON.parse(assetString) as Asset; - asset.Owner = newOwner; - asset.OwnerOrg = newOwnerOrg; - // Update the asset - await ctx.stub.putState(assetId, Buffer.from(JSON.stringify(asset))); - // Re-Set the endorsement policy of the assetId Key, such that a new owner Org Peer is required to endorse future updates - await AssetContract.setStateBasedEndorsement(ctx, asset.ID, [newOwnerOrg]); - - // Optionally, set the endorsement policy of the assetId Key, such that any 1 Org (N) out of the specified Orgs can endorse future updates - // await AssetContract.setStateBasedEndorsementNOutOf(ctx, assetId, 1, ["Org1MSP", "Org2MSP"]); - } - - // AssetExists returns true when asset with given ID exists - public async AssetExists(ctx: Context, assetId: string): Promise { - const buffer = await ctx.stub.getState(assetId); - return buffer.length > 0; - } - - // getClientOrgId gets the client's OrgId (MSPID) - private static getClientOrgId(ctx: Context): string { - return ctx.clientIdentity.getMSPID(); - } - - // setStateBasedEndorsement sets an endorsement policy to the assetId Key - // setStateBasedEndorsement enforces that the owner Org must endorse future update transactions for the specified assetId Key - private static async setStateBasedEndorsement(ctx: Context, assetId: string, ownerOrgs: string[]): Promise { - const ep = new KeyEndorsementPolicy(); - ep.addOrgs('MEMBER', ...ownerOrgs); - await ctx.stub.setStateValidationParameter(assetId, ep.getPolicy()); - } - - // setStateBasedEndorsementNOutOf sets an endorsement policy to the assetId Key - // setStateBasedEndorsementNOutOf enforces that a given number of Orgs (N) out of the specified Orgs must endorse future update transactions for the specified assetId Key. - private static async setStateBasedEndorsementNOutOf(ctx: Context, assetId: string, nOrgs: number, ownerOrgs: string[]): Promise { - const ROLE_TYPE_MEMBER = 'MEMBER'; - - // Use the KeyEndorsementPolicy helper form the chaincode libarries - // If you need more advanced policies, please use that helper as a reference point. - const keyEndorsementPolicy = new KeyEndorsementPolicy(); - keyEndorsementPolicy.addOrgs(ROLE_TYPE_MEMBER, ...ownerOrgs); - - await ctx.stub.setStateValidationParameter(assetId, keyEndorsementPolicy.getPolicy()); - } -} diff --git a/asset-transfer-sbe/chaincode-typescript/src/index.ts b/asset-transfer-sbe/chaincode-typescript/src/index.ts deleted file mode 100644 index 412fda46..00000000 --- a/asset-transfer-sbe/chaincode-typescript/src/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -import { AssetContract } from './assetContract'; -export { AssetContract } from './assetContract'; - -export const contracts: unknown[] = [ AssetContract ]; diff --git a/asset-transfer-sbe/chaincode-typescript/tsconfig.json b/asset-transfer-sbe/chaincode-typescript/tsconfig.json deleted file mode 100644 index 031d7de7..00000000 --- a/asset-transfer-sbe/chaincode-typescript/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "extends": "@tsconfig/node18/tsconfig.json", - "compilerOptions": { - "experimentalDecorators": true, - "emitDecoratorMetadata": true, - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "outDir": "dist", - "strict": true, - "noUnusedLocals": true, - "noImplicitReturns": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["src/"] -} diff --git a/asset-transfer-secured-agreement/README.md b/asset-transfer-secured-agreement/README.md deleted file mode 100644 index 83e4c2fc..00000000 --- a/asset-transfer-secured-agreement/README.md +++ /dev/null @@ -1,61 +0,0 @@ -# Asset transfer secured agreement sample - -The asset transfer events sample demonstrates how to transfer a private asset between two organizations without publicly sharing data . - -## About the sample - -This sample includes smart contract and application code in multiple languages. This sample shows how Fabric features state based endorsement, private data, and access control to provide secured transactions. - -### Application - -Refer [Secured asset transfer in Fabric](https://hyperledger-fabric.readthedocs.io/en/latest/secured_asset_transfer/secured_private_asset_transfer_tutorial.html) for application details . - -### Smart Contract - -The smart contract (in folder `chaincode-go`) implements the following functions to support the application: - -- CreateAsset -- ChangePublicDescription -- AgreeToSell -- AgreeToBuy -- VerifyAssetProperties -- TransferAsset -- ReadAsset -- GetAssetPrivateProperties -- GetAssetSalesPrice -- GetAssetBidPrice -- GetAssetHashId -- QueryAssetSaleAgreements -- QueryAssetBuyAgreements -- QueryAssetHistory - -## Running the sample - -Like other samples, the Fabric test network is used to deploy and run this sample. Follow these steps in order: - -1. Create the test network and a channel (from the `test-network` folder). - ``` - ./network.sh up createChannel -c mychannel -ca - ``` - -1. Deploy the smart contract implementations. - ``` - # To deploy the go chaincode implementation - ./network.sh deployCC -ccn secured -ccp ../asset-transfer-secured-agreement/chaincode-go/ -ccl go -ccep "OR('Org1MSP.peer','Org2MSP.peer')" - ``` - -1. Run the application (from the `asset-transfer-secured-agreement` folder). - ``` - # To run the Typescript sample application - cd application-gateway-typescript - npm install - npm start - ``` - -## Clean up - -When you are finished, you can bring down the test network (from the `test-network` folder). The command will remove all the nodes of the test network, and delete any ledger data that you created. - -``` -./network.sh down -``` \ No newline at end of file diff --git a/asset-transfer-secured-agreement/application-gateway-typescript/.gitignore b/asset-transfer-secured-agreement/application-gateway-typescript/.gitignore deleted file mode 100644 index 99e5af9f..00000000 --- a/asset-transfer-secured-agreement/application-gateway-typescript/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - - -# Coverage directory used by tools like istanbul -coverage - -# Dependency directories -node_modules/ -jspm_packages/ - -# Compiled TypeScript files -dist diff --git a/asset-transfer-secured-agreement/application-gateway-typescript/eslint.config.mjs b/asset-transfer-secured-agreement/application-gateway-typescript/eslint.config.mjs deleted file mode 100644 index 9ef6b243..00000000 --- a/asset-transfer-secured-agreement/application-gateway-typescript/eslint.config.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import js from '@eslint/js'; -import tseslint from 'typescript-eslint'; - -export default tseslint.config(js.configs.recommended, ...tseslint.configs.strictTypeChecked, { - languageOptions: { - ecmaVersion: 2023, - sourceType: 'module', - parserOptions: { - project: 'tsconfig.json', - tsconfigRootDir: import.meta.dirname, - }, - }, -}); diff --git a/asset-transfer-secured-agreement/application-gateway-typescript/package.json b/asset-transfer-secured-agreement/application-gateway-typescript/package.json deleted file mode 100644 index adcec840..00000000 --- a/asset-transfer-secured-agreement/application-gateway-typescript/package.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "asset-transfer-basic", - "version": "1.0.0", - "description": "Asset Transfer Secured Agreement Application implemented in typeScript using fabric-gateway", - "main": "dist/index.js", - "typings": "dist/index.d.ts", - "engines": { - "node": ">=18" - }, - "scripts": { - "build": "tsc", - "build:watch": "tsc -w", - "lint": "eslint src", - "prepare": "npm run build", - "pretest": "npm run lint", - "start": "node dist/app.js" - }, - "engineStrict": true, - "author": "Hyperledger", - "license": "Apache-2.0", - "dependencies": { - "@grpc/grpc-js": "^1.12.2", - "@hyperledger/fabric-gateway": "^1.7.0" - }, - "devDependencies": { - "@eslint/js": "^9.3.0", - "@tsconfig/node18": "^18.2.2", - "@types/node": "^18.18.6", - "eslint": "^8.57.0", - "typescript": "~5.4", - "typescript-eslint": "^7.13.0" - } -} diff --git a/asset-transfer-secured-agreement/application-gateway-typescript/src/app.ts b/asset-transfer-secured-agreement/application-gateway-typescript/src/app.ts deleted file mode 100644 index 14aa27ca..00000000 --- a/asset-transfer-secured-agreement/application-gateway-typescript/src/app.ts +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -import { connect, hash } from '@hyperledger/fabric-gateway'; - -import { newGrpcConnection, newIdentity, newSigner, tlsCertPathOrg1, peerEndpointOrg1, peerNameOrg1, certDirectoryPathOrg1, mspIdOrg1, keyDirectoryPathOrg1, tlsCertPathOrg2, peerEndpointOrg2, peerNameOrg2, certDirectoryPathOrg2, mspIdOrg2, keyDirectoryPathOrg2 } from './connect'; -import { ContractWrapper } from './contractWrapper'; -import { RED, RESET } from './utils'; - -const channelName = 'mychannel'; -const chaincodeName = 'secured'; - -// Use a random key so that we can run multiple times -const now = Date.now().toString(); -let assetKey: string; - -async function main(): Promise { - - // The gRPC client connection from org1 should be shared by all Gateway connections to this endpoint. - const clientOrg1 = await newGrpcConnection( - tlsCertPathOrg1, - peerEndpointOrg1, - peerNameOrg1 - ); - - const gatewayOrg1 = connect({ - client: clientOrg1, - identity: await newIdentity(certDirectoryPathOrg1, mspIdOrg1), - signer: await newSigner(keyDirectoryPathOrg1), - hash: hash.sha256, - }); - - // The gRPC client connection from org2 should be shared by all Gateway connections to this endpoint. - const clientOrg2 = await newGrpcConnection( - tlsCertPathOrg2, - peerEndpointOrg2, - peerNameOrg2 - ); - - const gatewayOrg2 = connect({ - client: clientOrg2, - identity: await newIdentity(certDirectoryPathOrg2, mspIdOrg2), - signer: await newSigner(keyDirectoryPathOrg2), - hash: hash.sha256, - }); - - - try { - - // Get the smart contract from the network for Org1. - const contractOrg1 = gatewayOrg1.getNetwork(channelName).getContract(chaincodeName); - const contractWrapperOrg1 = new ContractWrapper(contractOrg1, mspIdOrg1); - - // Get the smart contract from the network for Org2. - const contractOrg2 = gatewayOrg2.getNetwork(channelName).getContract(chaincodeName); - const contractWrapperOrg2 = new ContractWrapper(contractOrg2, mspIdOrg2); - - // Create an asset by organization Org1, this only requires the owning organization to endorse. - assetKey = await contractWrapperOrg1.createAsset(mspIdOrg1, - `Asset owned by ${mspIdOrg1} is not for sale`, { ObjectType: 'asset_properties', Color: 'blue', Size: 35 }); - - // Read the public details by org1. - await contractWrapperOrg1.readAsset(assetKey, mspIdOrg1); - - // Read the public details by org2. - await contractWrapperOrg2.readAsset(assetKey, mspIdOrg1); - - // Org1 should be able to read the private data details of the asset. - await contractWrapperOrg1.getAssetPrivateProperties(assetKey, mspIdOrg1); - - // Org2 is not the owner and does not have the private details, read expected to fail. - try { - await contractWrapperOrg2.getAssetPrivateProperties(assetKey, mspIdOrg1); - } catch (e) { - console.log(`${RED}*** Successfully caught the failure: getAssetPrivateProperties - ${String(e)}${RESET}`); - } - - // Org1 updates the assets public description. - await contractWrapperOrg1.changePublicDescription({assetId: assetKey, - ownerOrg: mspIdOrg1, - publicDescription: `Asset ${assetKey} owned by ${mspIdOrg1} is for sale`}); - - // Read the public details by org1. - await contractWrapperOrg1.readAsset(assetKey, mspIdOrg1); - - // Read the public details by org2. - await contractWrapperOrg2.readAsset(assetKey, mspIdOrg1); - - // This is an update to the public state and requires the owner(Org1) to endorse and sent by the owner org client (Org1). - // Since the client is from Org2, which is not the owner, this will fail. - try{ - await contractWrapperOrg2.changePublicDescription({assetId: assetKey, - ownerOrg: mspIdOrg1, - publicDescription: `Asset ${assetKey} owned by ${mspIdOrg2} is NOT for sale`}); - } catch(e) { - console.log(`${RED}*** Successfully caught the failure: changePublicDescription - ${String(e)}${RESET}`); - } - - // Read the public details by org1. - await contractWrapperOrg1.readAsset(assetKey, mspIdOrg1); - - // Read the public details by org2. - await contractWrapperOrg2.readAsset(assetKey, mspIdOrg1); - - // Agree to a sell by org1. - await contractWrapperOrg1.agreeToSell({ - assetId: assetKey, - price: 110, - tradeId: now, - }); - - // Check the private information about the asset from Org2. Org1 would have to send Org2 asset details, - // so the hash of the details may be checked by the chaincode. - await contractWrapperOrg2.verifyAssetProperties(assetKey, {color:'blue', size:35}); - - // Agree to a buy by org2. - await contractWrapperOrg2.agreeToBuy( {assetId: assetKey, - price: 100, - tradeId: now}, { ObjectType: 'asset_properties', Color: 'blue', Size: 35 }); - - // Org1 should be able to read the sale price of this asset. - await contractWrapperOrg1.getAssetSalesPrice(assetKey, mspIdOrg1); - - // Org2 has not set a sale price and this should fail. - try{ - await contractWrapperOrg2.getAssetSalesPrice(assetKey, mspIdOrg1); - } catch(e) { - console.log(`${RED}*** Successfully caught the failure: getAssetSalesPrice - ${String(e)}${RESET}`); - } - - // Org1 has not agreed to buy so this should fail. - try{ - await contractWrapperOrg1.getAssetBidPrice(assetKey, mspIdOrg2); - } catch(e) { - console.log(`${RED}*** Successfully caught the failure: getAssetBidPrice - ${String(e)}${RESET}`); - } - // Org2 should be able to see the price it has agreed. - await contractWrapperOrg2.getAssetBidPrice(assetKey, mspIdOrg2); - - // Org1 will try to transfer the asset to Org2 - // This will fail due to the sell price and the bid price are not the same. - try{ - await contractWrapperOrg1.transferAsset({ assetId: assetKey, price: 110, tradeId: now}, [ mspIdOrg1, mspIdOrg2 ], mspIdOrg1, mspIdOrg2); - } catch(e) { - console.log(`${RED}*** Successfully caught the failure: transferAsset - ${String(e)}${RESET}`); - } - // Agree to a sell by Org1, the seller will agree to the bid price of Org2. - await contractWrapperOrg1.agreeToSell({assetId:assetKey, price:100, tradeId:now}); - - // Read the public details by org1. - await contractWrapperOrg1.readAsset(assetKey, mspIdOrg1); - - // Read the public details by org2. - await contractWrapperOrg2.readAsset(assetKey, mspIdOrg1); - - // Org1 should be able to read the private data details of the asset. - await contractWrapperOrg1.getAssetPrivateProperties(assetKey, mspIdOrg1); - - // Org1 should be able to read the sale price of this asset. - await contractWrapperOrg1.getAssetSalesPrice(assetKey, mspIdOrg1); - - // Org2 should be able to see the price it has agreed. - await contractWrapperOrg2.getAssetBidPrice(assetKey, mspIdOrg2); - - // Org2 user will try to transfer the asset to Org1. - // This will fail as the owner is Org1. - try{ - await contractWrapperOrg2.transferAsset({ assetId: assetKey, price: 100, tradeId: now}, [ mspIdOrg1, mspIdOrg2 ], mspIdOrg1, mspIdOrg2); - } catch(e) { - console.log(`${RED}*** Successfully caught the failure: transferAsset - ${String(e)}${RESET}`); - } - - // Org1 will transfer the asset to Org2. - // This will now complete as the sell price and the bid price are the same. - await contractWrapperOrg1.transferAsset({ assetId: assetKey, price: 100, tradeId: now}, [ mspIdOrg1, mspIdOrg2 ], mspIdOrg1, mspIdOrg2); - - // Read the public details by org1. - await contractWrapperOrg1.readAsset(assetKey, mspIdOrg2); - - // Read the public details by org2. - await contractWrapperOrg2.readAsset(assetKey, mspIdOrg2); - - // Org2 should be able to read the private data details of this asset. - await contractWrapperOrg2.getAssetPrivateProperties(assetKey, mspIdOrg2); - - // Org1 should not be able to read the private data details of this asset, expected to fail. - try{ - await contractWrapperOrg1.getAssetPrivateProperties(assetKey, mspIdOrg2); - } catch(e) { - console.log(`${RED}*** Successfully caught the failure: getAssetPrivateProperties - ${String(e)}${RESET}`); - } - - // This is an update to the public state and requires only the owner to endorse. - // Org2 wants to indicate that the items is no longer for sale. - await contractWrapperOrg2.changePublicDescription( {assetId: assetKey, ownerOrg: mspIdOrg2, publicDescription: `Asset ${assetKey} owned by ${mspIdOrg2} is NOT for sale`}); - - // Read the public details by org1. - await contractWrapperOrg1.readAsset(assetKey, mspIdOrg2); - - // Read the public details by org2. - await contractWrapperOrg2.readAsset(assetKey, mspIdOrg2); - - } finally { - gatewayOrg1.close(); - gatewayOrg2.close(); - clientOrg1.close(); - clientOrg2.close(); - } -} - -main().catch((error: unknown) => { - console.error('******** FAILED to run the application:', error); - process.exitCode = 1; -}); diff --git a/asset-transfer-secured-agreement/application-gateway-typescript/src/connect.ts b/asset-transfer-secured-agreement/application-gateway-typescript/src/connect.ts deleted file mode 100644 index b6afd2e8..00000000 --- a/asset-transfer-secured-agreement/application-gateway-typescript/src/connect.ts +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as grpc from '@grpc/grpc-js'; -import { Identity, Signer, signers } from '@hyperledger/fabric-gateway'; -import * as crypto from 'crypto'; -import { promises as fs } from 'fs'; -import * as path from 'path'; - -// MSP Id's of Organizations -export const mspIdOrg1 = 'Org1MSP'; -export const mspIdOrg2 = 'Org2MSP'; - -// Path to org1 crypto materials. -export const cryptoPathOrg1 = path.resolve(__dirname, '..', '..', '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.example.com'); - -// Path to user private key directory. -export const keyDirectoryPathOrg1 = path.resolve(cryptoPathOrg1, 'users', 'User1@org1.example.com', 'msp', 'keystore'); - -// Path to user certificate. -export const certDirectoryPathOrg1 = path.resolve(cryptoPathOrg1, 'users', 'User1@org1.example.com', 'msp', 'signcerts'); - -// Path to peer tls certificate. -export const tlsCertPathOrg1 = path.resolve(cryptoPathOrg1, 'peers', 'peer0.org1.example.com', 'tls', 'ca.crt'); - -// Path to org2 crypto materials. -export const cryptoPathOrg2 = path.resolve( - __dirname, - '..', - '..', - '..', - 'test-network', - 'organizations', - 'peerOrganizations', - 'org2.example.com' -); - -// Path to org2 user private key directory. -export const keyDirectoryPathOrg2 = path.resolve( - cryptoPathOrg2, - 'users', - 'User1@org2.example.com', - 'msp', - 'keystore' -); - -// Path to org2 user certificate. -export const certDirectoryPathOrg2 = path.resolve( - cryptoPathOrg2, - 'users', - 'User1@org2.example.com', - 'msp', - 'signcerts' -); - -// Path to org2 peer tls certificate. -export const tlsCertPathOrg2 = path.resolve( - cryptoPathOrg2, - 'peers', - 'peer0.org2.example.com', - 'tls', - 'ca.crt' -); -// Gateway peer endpoint. -export const peerEndpointOrg1 = 'localhost:7051'; -export const peerEndpointOrg2 = 'localhost:9051'; - -// Gateway peer container name. -export const peerNameOrg1 = 'peer0.org1.example.com'; -export const peerNameOrg2 = 'peer0.org2.example.com'; - -// Collection Names -export const org1PrivateCollectionName = 'Org1MSPPrivateCollection'; -export const org2PrivateCollectionName = 'Org2MSPPrivateCollection'; - -export async function newGrpcConnection( - tlsCertPath: string, - peerEndpoint: string, - peerName: string -): Promise { - const tlsRootCert = await fs.readFile(tlsCertPath); - const tlsCredentials = grpc.credentials.createSsl(tlsRootCert); - return new grpc.Client(peerEndpoint, tlsCredentials, { - 'grpc.ssl_target_name_override': peerName, - }); -} - -export async function newIdentity(certDirectoryPath: string, mspId: string): Promise { - const certPath = await getFirstDirFileName(certDirectoryPath); - const credentials = await fs.readFile(certPath); - return { mspId, credentials }; -} - -export async function newSigner(keyDirectoryPath: string): Promise { - const keyPath = await getFirstDirFileName(keyDirectoryPath); - const privateKeyPem = await fs.readFile(keyPath); - const privateKey = crypto.createPrivateKey(privateKeyPem); - return signers.newPrivateKeySigner(privateKey); -} - -async function getFirstDirFileName(dirPath: string): Promise { - const files = await fs.readdir(dirPath); - const file = files[0]; - if (!file) { - throw new Error(`No files in directory: ${dirPath}`); - } - return path.join(dirPath, file); -} diff --git a/asset-transfer-secured-agreement/application-gateway-typescript/src/contractWrapper.ts b/asset-transfer-secured-agreement/application-gateway-typescript/src/contractWrapper.ts deleted file mode 100644 index 44c5f7d2..00000000 --- a/asset-transfer-secured-agreement/application-gateway-typescript/src/contractWrapper.ts +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ -import { Contract } from '@hyperledger/fabric-gateway'; -import { TextDecoder } from 'util'; -import { GREEN, parse, RED, RESET } from './utils'; -import crypto from 'crypto'; -import { mspIdOrg2 } from './connect'; - -const randomBytes = crypto.randomBytes(256).toString('hex'); - -interface AssetJSON { - objectType: string; - assetID: string; - ownerOrg: string; - publicDescription: string; -} - -interface AssetPropertiesJSON { - objectType: string; - color: string; - size: number; - salt: string; -} - -interface AssetPriceJSON { - assetID: string; - price: number; - tradeID: string; -} - -export interface AssetPrivateData { - ObjectType: string; - Color: string; - Size: number; -} - -export interface Asset { - assetId: string; - ownerOrg: string; - publicDescription: string; -} - -export interface AssetProperties { - color: string; - size: number; -} - -export interface AssetPrice { - assetId: string; - price: number; - tradeId: string; -} - -export class ContractWrapper { - - readonly #contract: Contract; - readonly #org: string; - readonly #utf8Decoder = new TextDecoder(); - readonly #randomBytes: string = randomBytes; - #endorsingOrgs: { [id: string]: string[] }; - - public constructor(contract: Contract, org: string) { - this.#contract = contract; - this.#org = org; - this.#endorsingOrgs = {}; - } - - public async createAsset(ownerOrg: string, publicDescription: string, privateData: AssetPrivateData): Promise { - console.log(`${GREEN}--> Submit Transaction: CreateAsset as ${ownerOrg} - endorsed by Org1.${RESET}`); - const assetPropertiesJSON: AssetPropertiesJSON = { - objectType: 'asset_properties', - color: privateData.Color, - size: privateData.Size, - salt: this.#randomBytes }; - - const resultBytes = await this.#contract.submit('CreateAsset', { - arguments: [publicDescription], - transientData: { asset_properties: JSON.stringify(assetPropertiesJSON)}, - }); - const assetID = this.#utf8Decoder.decode(resultBytes); - this.#endorsingOrgs[assetID] = [ownerOrg]; - console.log(`*** Result: committed, asset ${assetID} is owned by ${ownerOrg}`); - return assetID; - } - - public async readAsset(assetKey: string, ownerOrg: string): Promise { - console.log(`${GREEN}--> Evaluate Transactions: ReadAsset as ${this.#org}, - ${assetKey} should be owned by ${ownerOrg}.${RESET}`); - - const resultBytes = await this.#contract.evaluateTransaction('ReadAsset', assetKey); - - const result = this.#utf8Decoder.decode(resultBytes); - if (result.length !== 0) { - const json = parse(result); - if (json.ownerOrg === ownerOrg) { - console.log(`*** Result from ${this.#org} - asset ${json.assetID} owned by ${json.ownerOrg} DESC: ${json.publicDescription}`); - } else { - console.log(`${RED}*** Failed owner check from ${this.#org} - asset ${json.assetID} owned by ${json.ownerOrg} DESC:${json.publicDescription}.${RESET}`); - } - } else { - throw new Error('No Asset Found'); - } - } - - public async getAssetPrivateProperties(assetKey: string, ownerOrg: string): Promise { - console.log(`${GREEN}--> Evaluate Transaction: GetAssetPrivateProperties, - ${assetKey} from organization ${this.#org}.${RESET}`); - if(this.#org !== ownerOrg) { - console.log(`${GREEN}* Expected to fail as ${this.#org} is not the owner and does not have the private details.${RESET}`); - } - - const resultBytes = await this.#contract.evaluateTransaction('GetAssetPrivateProperties', assetKey); - - const resultString = this.#utf8Decoder.decode(resultBytes); - const json = parse(resultString); - const result: AssetProperties = { - color: json.color, - size: json.size, - }; - console.log('*** Result:', result); - } - - - public async changePublicDescription(asset: Asset): Promise { - console.log(`${GREEN}--> Submit Transaction: ChangePublicDescription ${asset.assetId}, as ${this.#org} - endorse by ${this.#org}.${RESET}`); - if (asset.ownerOrg !== this.#org) { - console.log(`${GREEN}* Expected to fail as ${this.#org} is not the owner.${RESET}`); - } - - await this.#contract.submit('ChangePublicDescription', { - arguments:[asset.assetId, asset.publicDescription], - endorsingOrganizations: this.#endorsingOrgs[asset.assetId] - }); - - console.log(`*** Result: committed, Desc: ${asset.publicDescription}`); - } - - public async agreeToSell(assetPrice: AssetPrice): Promise { - - console.log(`${GREEN}--> Submit Transaction: AgreeToSell, ${assetPrice.assetId} as ${this.#org} - endorsed by ${this.#org}.${RESET}`); - const assetPriceJSON: AssetPriceJSON = { - assetID:assetPrice.assetId, - price:assetPrice.price, - tradeID:assetPrice.tradeId - }; - - await this.#contract.submit('AgreeToSell', { - arguments:[assetPrice.assetId], - transientData: {asset_price: JSON.stringify(assetPriceJSON)}, - endorsingOrganizations: this.#endorsingOrgs[assetPrice.assetId] - }); - - console.log(`*** Result: committed, ${this.#org} has agreed to sell asset ${assetPrice.assetId} for ${String(assetPrice.price)}`); - } - - public async verifyAssetProperties(assetId: string, assetProperties: AssetProperties): Promise { - console.log(`${GREEN}--> Evalute: VerifyAssetProperties, ${assetId} as ${this.#org} - endorsed by ${this.#org} and ${mspIdOrg2}.${RESET}`); - const assetPropertiesJSON: AssetPropertiesJSON = {objectType: 'asset_properties', - color: assetProperties.color, - size: assetProperties.size, - salt: this.#randomBytes }; - - const resultBytes = await this.#contract.evaluate('VerifyAssetProperties', { - arguments:[assetId], - transientData: {asset_properties: JSON.stringify(assetPropertiesJSON)}, - }); - - const resultString = this.#utf8Decoder.decode(resultBytes); - if (resultString.length !== 0) { - const json = parse(resultString); - if (typeof json === 'object') { - console.log(`*** Success VerifyAssetProperties, private information about asset ${assetId} has been verified by ${this.#org}`); - } else { - console.log(`*** Failed: VerifyAssetProperties, private information about asset ${assetId} has not been verified by ${this.#org}`); - } - } else { - throw new Error(`Private information about asset ${assetId} has not been verified by ${this.#org}`); - } - } - - public async agreeToBuy(assetPrice: AssetPrice, privateData: AssetPrivateData): Promise { - - console.log(`${GREEN}--> Submit Transaction: AgreeToBuy, ${assetPrice.assetId} as ${this.#org} - endorsed by ${this.#org} and ${mspIdOrg2}.${RESET}`); - const assetPropertiesJSON: AssetPropertiesJSON = { - objectType: 'asset_properties', - color: privateData.Color, - size: privateData.Size, - salt: this.#randomBytes }; - - const assetPriceJSON: AssetPriceJSON = { - assetID: assetPrice.assetId, - price: assetPrice.price, - tradeID: assetPrice.tradeId - }; - - await this.#contract.submit('AgreeToBuy', { - arguments:[assetPrice.assetId], - transientData: { - asset_price: JSON.stringify(assetPriceJSON), - asset_properties: JSON.stringify(assetPropertiesJSON) - }, - endorsingOrganizations: this.#endorsingOrgs[assetPrice.assetId] - }); - - console.log(`*** Result: committed, ${this.#org} has agreed to buy asset ${assetPrice.assetId} for 100`); - - } - - public async getAssetSalesPrice(assetKey: string, ownerOrg: string): Promise { - - console.log(`${GREEN}--> Evaluate Transaction: GetAssetSalesPrice, - ${assetKey} from organization ${this.#org}.${RESET}`); - if(this.#org !== ownerOrg) { - console.log(`${GREEN}* Expected to fail as ${this.#org} has not set a sale price.${RESET}`); - } - - const resultBytes = await this.#contract.evaluateTransaction('GetAssetSalesPrice', assetKey); - - const resultString = this.#utf8Decoder.decode(resultBytes); - const json = parse(resultString); - - const result: AssetPrice = { - assetId: json.assetID, - price: json.price, - tradeId: json.tradeID - }; - - console.log('*** Result: GetAssetSalesPrice', result); - } - - public async getAssetBidPrice(assetKey: string, buyerOrgID: string): Promise { - - console.log(`${GREEN}--> Evaluate Transaction: GetAssetBidPrice, - ${assetKey} from organization ${this.#org}.${RESET}`); - if(this.#org !== buyerOrgID){ - console.log(`${GREEN}* Expected to fail as ${this.#org} has not agreed to buy.${RESET}`); - } - - const resultBytes = await this.#contract.evaluateTransaction('GetAssetBidPrice', assetKey); - - const resultString = this.#utf8Decoder.decode(resultBytes); - const json = parse(resultString); - const result: AssetPrice = { - assetId: json.assetID, - price: json.price, - tradeId: json.tradeID, - }; - - console.log('*** Result: GetAssetBidPrice', result); - } - - public async transferAsset(assetPrice: AssetPrice, endorsingOrganizations: string[], ownerOrgID: string, buyerOrgID: string): Promise { - - console.log(`${GREEN}--> Submit Transaction: TransferAsset, ${assetPrice.assetId} as ${this.#org } - endorsed by ${this.#org} and ${buyerOrgID}.${RESET}`); - - if (this.#org !== ownerOrgID) { - console.log(`${GREEN}* Expected to fail as the owner is ${ownerOrgID}.${RESET}`); - } else if (assetPrice.price === 110) { - console.log(`${GREEN}* Expected to fail as sell price and the bid price are not the same.${RESET}`); - } - - const assetPriceJSON: AssetPriceJSON = { assetID: assetPrice.assetId, price:assetPrice.price, tradeID:assetPrice.tradeId}; - - await this.#contract.submit('TransferAsset', { - arguments:[assetPrice.assetId, buyerOrgID], - transientData: { asset_price: JSON.stringify(assetPriceJSON) }, - endorsingOrganizations: endorsingOrganizations - }); - - console.log(`${GREEN}*** Result: committed, ${this.#org} has transfered the asset ${assetPrice.assetId} to ${buyerOrgID}.${RESET}`); - } -} diff --git a/asset-transfer-secured-agreement/application-gateway-typescript/src/utils.ts b/asset-transfer-secured-agreement/application-gateway-typescript/src/utils.ts deleted file mode 100644 index 0442ff02..00000000 --- a/asset-transfer-secured-agreement/application-gateway-typescript/src/utils.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -export const RED = '\x1b[31m\n'; -export const GREEN = '\x1b[32m\n'; -export const RESET = '\x1b[0m'; - -export function parse(data: string): T { - return JSON.parse(data) as T; -} diff --git a/asset-transfer-secured-agreement/application-gateway-typescript/tsconfig.json b/asset-transfer-secured-agreement/application-gateway-typescript/tsconfig.json deleted file mode 100644 index 4c20df24..00000000 --- a/asset-transfer-secured-agreement/application-gateway-typescript/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "@tsconfig/node18/tsconfig.json", - "compilerOptions": { - "outDir": "dist", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "noUnusedLocals": true, - "noImplicitReturns": true, - "noUncheckedIndexedAccess": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["./src/**/*"], - "exclude": ["./src/**/*.spec.ts"] -} diff --git a/asset-transfer-secured-agreement/chaincode-go/README.md b/asset-transfer-secured-agreement/chaincode-go/README.md deleted file mode 100644 index f65f09b6..00000000 --- a/asset-transfer-secured-agreement/chaincode-go/README.md +++ /dev/null @@ -1 +0,0 @@ -[Secured asset transfer in Fabric Tutorial](https://hyperledger-fabric.readthedocs.io/en/latest/secured_asset_transfer/secured_private_asset_transfer_tutorial.html) diff --git a/asset-transfer-secured-agreement/chaincode-go/asset_transfer.go b/asset-transfer-secured-agreement/chaincode-go/asset_transfer.go deleted file mode 100644 index d7228406..00000000 --- a/asset-transfer-secured-agreement/chaincode-go/asset_transfer.go +++ /dev/null @@ -1,619 +0,0 @@ -/* - SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "bytes" - "crypto/sha256" - "encoding/hex" - "encoding/json" - "fmt" - "log" - "time" - - "github.com/hyperledger/fabric-chaincode-go/v2/pkg/statebased" - "github.com/hyperledger/fabric-chaincode-go/v2/shim" - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -const ( - typeAssetForSale = "S" - typeAssetBid = "B" - typeAssetSaleReceipt = "SR" - typeAssetBuyReceipt = "BR" -) - -type SmartContract struct { - contractapi.Contract -} - -// Asset struct and properties must be exported (start with capitals) to work with contract api metadata -type Asset struct { - ObjectType string `json:"objectType"` // ObjectType is used to distinguish different object types in the same chaincode namespace - ID string `json:"assetID"` - OwnerOrg string `json:"ownerOrg"` - PublicDescription string `json:"publicDescription"` -} - -type receipt struct { - price int - timestamp time.Time -} - -// CreateAsset creates an asset, sets it as owned by the client's org and returns its id -// the id of the asset corresponds to the hash of the properties of the asset that are passed by transiet field -func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, publicDescription string) (string, error) { - transientMap, err := ctx.GetStub().GetTransient() - if err != nil { - return "", fmt.Errorf("error getting transient: %v", err) - } - - // Asset properties must be retrieved from the transient field as they are private - immutablePropertiesJSON, ok := transientMap["asset_properties"] - if !ok { - return "", fmt.Errorf("asset_properties key not found in the transient map") - } - - // AssetID will be the hash of the asset's properties - hash := sha256.New() - hash.Write(immutablePropertiesJSON) - assetID := hex.EncodeToString(hash.Sum(nil)) - - // Get the clientOrgId from the input, will be used for implicit collection, owner, and state-based endorsement policy - clientOrgID, err := getClientOrgID(ctx) - if err != nil { - return "", err - } - - // In this scenario, client is only authorized to read/write private data from its own peer, therefore verify client org id matches peer org id. - err = verifyClientOrgMatchesPeerOrg(clientOrgID) - if err != nil { - return "", err - } - - asset := Asset{ - ObjectType: "asset", - ID: assetID, - OwnerOrg: clientOrgID, - PublicDescription: publicDescription, - } - assetBytes, err := json.Marshal(asset) - if err != nil { - return "", fmt.Errorf("failed to create asset JSON: %v", err) - } - - err = ctx.GetStub().PutState(assetID, assetBytes) - if err != nil { - return "", fmt.Errorf("failed to put asset in public data: %v", err) - } - - // Set the endorsement policy such that an owner org peer is required to endorse future updates. - // In practice, consider additional endorsers such as a trusted third party to further secure transfers. - endorsingOrgs := []string{clientOrgID} - err = setAssetStateBasedEndorsement(ctx, asset.ID, endorsingOrgs) - if err != nil { - return "", fmt.Errorf("failed setting state based endorsement for buyer and seller: %v", err) - } - - // Persist private immutable asset properties to owner's private data collection - collection := buildCollectionName(clientOrgID) - err = ctx.GetStub().PutPrivateData(collection, assetID, immutablePropertiesJSON) - if err != nil { - return "", fmt.Errorf("failed to put Asset private details: %v", err) - } - - return assetID, nil -} - -// ChangePublicDescription updates the assets public description. Only the current owner can update the public description -func (s *SmartContract) ChangePublicDescription(ctx contractapi.TransactionContextInterface, assetID string, newDescription string) error { - - clientOrgID, err := getClientOrgID(ctx) - if err != nil { - return err - } - - asset, err := s.ReadAsset(ctx, assetID) - if err != nil { - return fmt.Errorf("failed to get asset: %v", err) - } - - // Auth check to ensure that client's org actually owns the asset - if clientOrgID != asset.OwnerOrg { - return fmt.Errorf("a client from %s cannot update the description of a asset owned by %s", clientOrgID, asset.OwnerOrg) - } - - asset.PublicDescription = newDescription - updatedAssetJSON, err := json.Marshal(asset) - if err != nil { - return fmt.Errorf("failed to marshal asset: %v", err) - } - - return ctx.GetStub().PutState(assetID, updatedAssetJSON) -} - -// AgreeToSell adds seller's asking price to seller's implicit private data collection. -func (s *SmartContract) AgreeToSell(ctx contractapi.TransactionContextInterface, assetID string) error { - asset, err := s.ReadAsset(ctx, assetID) - if err != nil { - return err - } - - clientOrgID, err := getClientOrgID(ctx) - if err != nil { - return err - } - - // Verify that this client belongs to the peer's org - err = verifyClientOrgMatchesPeerOrg(clientOrgID) - if err != nil { - return err - } - - // Verify that this clientOrgId actually owns the asset. - if clientOrgID != asset.OwnerOrg { - return fmt.Errorf("a client from %s cannot sell an asset owned by %s", clientOrgID, asset.OwnerOrg) - } - - return agreeToPrice(ctx, assetID, typeAssetForSale) -} - -// AgreeToBuy adds buyer's bid price and asset properties to buyer's implicit private data collection -func (s *SmartContract) AgreeToBuy(ctx contractapi.TransactionContextInterface, assetID string) error { - transientMap, err := ctx.GetStub().GetTransient() - if err != nil { - return fmt.Errorf("error getting transient: %v", err) - } - - clientOrgID, err := getClientOrgID(ctx) - if err != nil { - return err - } - - // Verify that this client belongs to the peer's org - err = verifyClientOrgMatchesPeerOrg(clientOrgID) - if err != nil { - return err - } - - // Asset properties must be retrieved from the transient field as they are private - immutablePropertiesJSON, ok := transientMap["asset_properties"] - if !ok { - return fmt.Errorf("asset_properties key not found in the transient map") - } - - // Persist private immutable asset properties to seller's private data collection - collection := buildCollectionName(clientOrgID) - err = ctx.GetStub().PutPrivateData(collection, assetID, immutablePropertiesJSON) - if err != nil { - return fmt.Errorf("failed to put Asset private details: %v", err) - } - - return agreeToPrice(ctx, assetID, typeAssetBid) -} - -// agreeToPrice adds a bid or ask price to caller's implicit private data collection -func agreeToPrice(ctx contractapi.TransactionContextInterface, assetID string, priceType string) error { - // In this scenario, both buyer and seller are authoried to read/write private about transfer after seller agrees to sell. - clientOrgID, err := getClientOrgID(ctx) - if err != nil { - return err - } - - transMap, err := ctx.GetStub().GetTransient() - if err != nil { - return fmt.Errorf("error getting transient: %v", err) - } - - // Asset price must be retrieved from the transient field as they are private - price, ok := transMap["asset_price"] - if !ok { - return fmt.Errorf("asset_price key not found in the transient map") - } - - collection := buildCollectionName(clientOrgID) - - // Persist the agreed to price in a collection sub-namespace based on priceType key prefix, - // to avoid collisions between private asset properties, sell price, and buy price - assetPriceKey, err := ctx.GetStub().CreateCompositeKey(priceType, []string{assetID}) - if err != nil { - return fmt.Errorf("failed to create composite key: %v", err) - } - - // The Price hash will be verified later, therefore always pass and persist price bytes as is, - // so that there is no risk of nondeterministic marshaling. - err = ctx.GetStub().PutPrivateData(collection, assetPriceKey, price) - if err != nil { - return fmt.Errorf("failed to put asset bid: %v", err) - } - - return nil -} - -// VerifyAssetProperties allows a buyer to validate the properties of -// an asset they intend to buy against the owner's implicit private data collection -// and verifies that the asset properties never changed from the origin of the asset by checking their hash against the assetID -func (s *SmartContract) VerifyAssetProperties(ctx contractapi.TransactionContextInterface, assetID string) (bool, error) { - transMap, err := ctx.GetStub().GetTransient() - if err != nil { - return false, fmt.Errorf("error getting transient: %v", err) - } - - // Asset properties must be retrieved from the transient field as they are private - immutablePropertiesJSON, ok := transMap["asset_properties"] - if !ok { - return false, fmt.Errorf("asset_properties key not found in the transient map") - } - - asset, err := s.ReadAsset(ctx, assetID) - if err != nil { - return false, fmt.Errorf("failed to get asset: %v", err) - } - - collectionOwner := buildCollectionName(asset.OwnerOrg) - immutablePropertiesOnChainHash, err := ctx.GetStub().GetPrivateDataHash(collectionOwner, assetID) - if err != nil { - return false, fmt.Errorf("failed to read asset private properties hash from seller's collection: %v", err) - } - if immutablePropertiesOnChainHash == nil { - return false, fmt.Errorf("asset private properties hash does not exist: %s", assetID) - } - - hash := sha256.New() - hash.Write(immutablePropertiesJSON) - calculatedPropertiesHash := hash.Sum(nil) - - // verify that the hash of the passed immutable properties matches the on-chain hash - if !bytes.Equal(immutablePropertiesOnChainHash, calculatedPropertiesHash) { - return false, fmt.Errorf("hash %x for passed immutable properties %s does not match on-chain hash %x", - calculatedPropertiesHash, - immutablePropertiesJSON, - immutablePropertiesOnChainHash, - ) - } - - // verify that the hash of the passed immutable properties and on chain hash matches the assetID - if !(hex.EncodeToString(immutablePropertiesOnChainHash) == assetID) { - return false, fmt.Errorf("hash %x for passed immutable properties %s does match on-chain hash %x but do not match assetID %s: asset was altered from its initial form", - calculatedPropertiesHash, - immutablePropertiesJSON, - immutablePropertiesOnChainHash, - assetID) - } - - return true, nil -} - -// TransferAsset checks transfer conditions and then transfers asset state to buyer. -// TransferAsset can only be called by current owner -func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, assetID string, buyerOrgID string) error { - clientOrgID, err := getClientOrgID(ctx) - if err != nil { - return err - } - - transMap, err := ctx.GetStub().GetTransient() - if err != nil { - return fmt.Errorf("error getting transient data: %v", err) - } - - priceJSON, ok := transMap["asset_price"] - if !ok { - return fmt.Errorf("asset_price key not found in the transient map") - } - - var agreement Agreement - err = json.Unmarshal(priceJSON, &agreement) - if err != nil { - return fmt.Errorf("failed to unmarshal price JSON: %v", err) - } - - asset, err := s.ReadAsset(ctx, assetID) - if err != nil { - return fmt.Errorf("failed to get asset: %v", err) - } - - err = verifyTransferConditions(ctx, asset, clientOrgID, buyerOrgID, priceJSON) - if err != nil { - return fmt.Errorf("failed transfer verification: %v", err) - } - - err = transferAssetState(ctx, asset, clientOrgID, buyerOrgID, agreement.Price) - if err != nil { - return fmt.Errorf("failed asset transfer: %v", err) - } - - return nil - -} - -// verifyTransferConditions checks that client org currently owns asset and that both parties have agreed on price -func verifyTransferConditions(ctx contractapi.TransactionContextInterface, - asset *Asset, - clientOrgID string, - buyerOrgID string, - priceJSON []byte) error { - - // CHECK1: Auth check to ensure that client's org actually owns the asset - - if clientOrgID != asset.OwnerOrg { - return fmt.Errorf("a client from %s cannot transfer a asset owned by %s", clientOrgID, asset.OwnerOrg) - } - - // CHECK2: Verify that buyer and seller on-chain asset defintion hash matches - - collectionSeller := buildCollectionName(clientOrgID) - collectionBuyer := buildCollectionName(buyerOrgID) - sellerPropertiesOnChainHash, err := ctx.GetStub().GetPrivateDataHash(collectionSeller, asset.ID) - if err != nil { - return fmt.Errorf("failed to read asset private properties hash from seller's collection: %v", err) - } - if sellerPropertiesOnChainHash == nil { - return fmt.Errorf("asset private properties hash does not exist: %s", asset.ID) - } - buyerPropertiesOnChainHash, err := ctx.GetStub().GetPrivateDataHash(collectionBuyer, asset.ID) - if err != nil { - return fmt.Errorf("failed to read asset private properties hash from seller's collection: %v", err) - } - if buyerPropertiesOnChainHash == nil { - return fmt.Errorf("asset private properties hash does not exist: %s", asset.ID) - } - - // verify that buyer and seller on-chain asset defintion hash matches - if !bytes.Equal(sellerPropertiesOnChainHash, buyerPropertiesOnChainHash) { - return fmt.Errorf("on chain hash of seller %x does not match on-chain hash of buyer %x", - sellerPropertiesOnChainHash, - buyerPropertiesOnChainHash, - ) - } - - // CHECK3: Verify that seller and buyer agreed on the same price - - // Get sellers asking price - assetForSaleKey, err := ctx.GetStub().CreateCompositeKey(typeAssetForSale, []string{asset.ID}) - if err != nil { - return fmt.Errorf("failed to create composite key: %v", err) - } - sellerPriceHash, err := ctx.GetStub().GetPrivateDataHash(collectionSeller, assetForSaleKey) - if err != nil { - return fmt.Errorf("failed to get seller price hash: %v", err) - } - if sellerPriceHash == nil { - return fmt.Errorf("seller price for %s does not exist", asset.ID) - } - - // Get buyers bid price - assetBidKey, err := ctx.GetStub().CreateCompositeKey(typeAssetBid, []string{asset.ID}) - if err != nil { - return fmt.Errorf("failed to create composite key: %v", err) - } - buyerPriceHash, err := ctx.GetStub().GetPrivateDataHash(collectionBuyer, assetBidKey) - if err != nil { - return fmt.Errorf("failed to get buyer price hash: %v", err) - } - if buyerPriceHash == nil { - return fmt.Errorf("buyer price for %s does not exist", asset.ID) - } - - hash := sha256.New() - hash.Write(priceJSON) - calculatedPriceHash := hash.Sum(nil) - - // Verify that the hash of the passed price matches the on-chain sellers price hash - if !bytes.Equal(calculatedPriceHash, sellerPriceHash) { - return fmt.Errorf("hash %x for passed price JSON %s does not match on-chain hash %x, seller hasn't agreed to the passed trade id and price", - calculatedPriceHash, - priceJSON, - sellerPriceHash, - ) - } - - // Verify that the hash of the passed price matches the on-chain buyer price hash - if !bytes.Equal(calculatedPriceHash, buyerPriceHash) { - return fmt.Errorf("hash %x for passed price JSON %s does not match on-chain hash %x, buyer hasn't agreed to the passed trade id and price", - calculatedPriceHash, - priceJSON, - buyerPriceHash, - ) - } - - return nil -} - -// transferAssetState performs the public and private state updates for the transferred asset -// changes the endorsement for the transferred asset sbe to the new owner org -func transferAssetState(ctx contractapi.TransactionContextInterface, asset *Asset, clientOrgID string, buyerOrgID string, price int) error { - - // Update ownership in public state - asset.OwnerOrg = buyerOrgID - updatedAsset, err := json.Marshal(asset) - if err != nil { - return err - } - err = ctx.GetStub().PutState(asset.ID, updatedAsset) - if err != nil { - return fmt.Errorf("failed to write asset for buyer: %v", err) - } - - // Changes the endorsement policy to the new owner org - endorsingOrgs := []string{buyerOrgID} - err = setAssetStateBasedEndorsement(ctx, asset.ID, endorsingOrgs) - if err != nil { - return fmt.Errorf("failed setting state based endorsement for new owner: %v", err) - } - - // Delete asset description from seller collection - collectionSeller := buildCollectionName(clientOrgID) - err = ctx.GetStub().DelPrivateData(collectionSeller, asset.ID) - if err != nil { - return fmt.Errorf("failed to delete Asset private details from seller: %v", err) - } - - // Delete the price records for seller - assetPriceKey, err := ctx.GetStub().CreateCompositeKey(typeAssetForSale, []string{asset.ID}) - if err != nil { - return fmt.Errorf("failed to create composite key for seller: %v", err) - } - err = ctx.GetStub().DelPrivateData(collectionSeller, assetPriceKey) - if err != nil { - return fmt.Errorf("failed to delete asset price from implicit private data collection for seller: %v", err) - } - - // Delete the price records for buyer - collectionBuyer := buildCollectionName(buyerOrgID) - assetPriceKey, err = ctx.GetStub().CreateCompositeKey(typeAssetBid, []string{asset.ID}) - if err != nil { - return fmt.Errorf("failed to create composite key for buyer: %v", err) - } - err = ctx.GetStub().DelPrivateData(collectionBuyer, assetPriceKey) - if err != nil { - return fmt.Errorf("failed to delete asset price from implicit private data collection for buyer: %v", err) - } - - // Keep record for a 'receipt' in both buyers and sellers private data collection to record the sale price and date. - // Persist the agreed to price in a collection sub-namespace based on receipt key prefix. - receiptBuyKey, err := ctx.GetStub().CreateCompositeKey(typeAssetBuyReceipt, []string{asset.ID, ctx.GetStub().GetTxID()}) - if err != nil { - return fmt.Errorf("failed to create composite key for receipt: %v", err) - } - - txTimestamp, err := ctx.GetStub().GetTxTimestamp() - if err != nil { - return fmt.Errorf("failed to create timestamp for receipt: %v", err) - } - - assetReceipt := receipt{ - price: price, - timestamp: txTimestamp.AsTime(), - } - receipt, err := json.Marshal(assetReceipt) - if err != nil { - return fmt.Errorf("failed to marshal receipt: %v", err) - } - - err = ctx.GetStub().PutPrivateData(collectionBuyer, receiptBuyKey, receipt) - if err != nil { - return fmt.Errorf("failed to put private asset receipt for buyer: %v", err) - } - - receiptSaleKey, err := ctx.GetStub().CreateCompositeKey(typeAssetSaleReceipt, []string{ctx.GetStub().GetTxID(), asset.ID}) - if err != nil { - return fmt.Errorf("failed to create composite key for receipt: %v", err) - } - - err = ctx.GetStub().PutPrivateData(collectionSeller, receiptSaleKey, receipt) - if err != nil { - return fmt.Errorf("failed to put private asset receipt for seller: %v", err) - } - - return nil -} - -// getClientOrgID gets the client org ID. -func getClientOrgID(ctx contractapi.TransactionContextInterface) (string, error) { - clientOrgID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return "", fmt.Errorf("failed getting client's orgID: %v", err) - } - - return clientOrgID, nil -} - -// getClientImplicitCollectionNameAndVerifyClientOrg gets the implicit collection for the client and checks that the client is from the same org as the peer -func getClientImplicitCollectionNameAndVerifyClientOrg(ctx contractapi.TransactionContextInterface) (string, error) { - clientOrgID, err := getClientOrgID(ctx) - if err != nil { - return "", err - } - - err = verifyClientOrgMatchesPeerOrg(clientOrgID) - if err != nil { - return "", err - } - - return buildCollectionName(clientOrgID), nil -} - -// verifyClientOrgMatchesPeerOrg checks that the client is from the same org as the peer -func verifyClientOrgMatchesPeerOrg(clientOrgID string) error { - peerOrgID, err := shim.GetMSPID() - if err != nil { - return fmt.Errorf("failed getting peer's orgID: %v", err) - } - - if clientOrgID != peerOrgID { - return fmt.Errorf("client from org %s is not authorized to read or write private data from an org %s peer", - clientOrgID, - peerOrgID, - ) - } - - return nil -} - -// buildCollectionName returns the implicit collection name for an org -func buildCollectionName(clientOrgID string) string { - return fmt.Sprintf("_implicit_org_%s", clientOrgID) -} - -// setAssetStateBasedEndorsement adds an endorsement policy to an asset so that the passed orgs need to agree upon transfer -func setAssetStateBasedEndorsement(ctx contractapi.TransactionContextInterface, assetID string, orgsToEndorse []string) error { - endorsementPolicy, err := statebased.NewStateEP(nil) - if err != nil { - return err - } - err = endorsementPolicy.AddOrgs(statebased.RoleTypePeer, orgsToEndorse...) - if err != nil { - return fmt.Errorf("failed to add org to endorsement policy: %v", err) - } - policy, err := endorsementPolicy.Policy() - if err != nil { - return fmt.Errorf("failed to create endorsement policy bytes from org: %v", err) - } - err = ctx.GetStub().SetStateValidationParameter(assetID, policy) - if err != nil { - return fmt.Errorf("failed to set validation parameter on asset: %v", err) - } - - return nil -} - -// GetAssetHashId allows a potential buyer to validate the properties of an asset against the asset Id hash on chain and returns the hash -func (s *SmartContract) GetAssetHashId(ctx contractapi.TransactionContextInterface) (string, error) { - transientMap, err := ctx.GetStub().GetTransient() - if err != nil { - return "", fmt.Errorf("error getting transient: %v", err) - } - - // Asset properties must be retrieved from the transient field as they are private - propertiesJSON, ok := transientMap["asset_properties"] - if !ok { - return "", fmt.Errorf("asset_properties key not found in the transient map") - } - - hash := sha256.New() - hash.Write(propertiesJSON) - assetID := hex.EncodeToString(hash.Sum(nil)) - - asset, err := s.ReadAsset(ctx, assetID) - if err != nil { - return "", fmt.Errorf("failed to get asset: %v, asset properies provided do not represent any on chain asset", err) - } - if asset.ID != assetID { - return "", fmt.Errorf("Asset properies provided do not correpond to any on chain asset") - } - return asset.ID, nil -} - -func main() { - chaincode, err := contractapi.NewChaincode(new(SmartContract)) - if err != nil { - log.Panicf("Error create transfer asset chaincode: %v", err) - } - - if err := chaincode.Start(); err != nil { - log.Panicf("Error starting asset chaincode: %v", err) - } -} diff --git a/asset-transfer-secured-agreement/chaincode-go/asset_transfer_queries.go b/asset-transfer-secured-agreement/chaincode-go/asset_transfer_queries.go deleted file mode 100644 index 4dc569d8..00000000 --- a/asset-transfer-secured-agreement/chaincode-go/asset_transfer_queries.go +++ /dev/null @@ -1,172 +0,0 @@ -/* - SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "encoding/json" - "fmt" - "time" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -// QueryResult structure used for handling result of query -type QueryResult struct { - Record *Asset - TxId string `json:"txId"` - Timestamp time.Time `json:"timestamp"` -} - -type Agreement struct { - ID string `json:"asset_id"` - Price int `json:"price"` - TradeID string `json:"trade_id"` -} - -// ReadAsset returns the public asset data -func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, assetID string) (*Asset, error) { - // Since only public data is accessed in this function, no access control is required - assetJSON, err := ctx.GetStub().GetState(assetID) - if err != nil { - return nil, fmt.Errorf("failed to read from world state: %v", err) - } - if assetJSON == nil { - return nil, fmt.Errorf("%s does not exist", assetID) - } - - var asset *Asset - err = json.Unmarshal(assetJSON, &asset) - if err != nil { - return nil, err - } - return asset, nil -} - -// GetAssetPrivateProperties returns the immutable asset properties from owner's private data collection -func (s *SmartContract) GetAssetPrivateProperties(ctx contractapi.TransactionContextInterface, assetID string) (string, error) { - - collection, err := getClientImplicitCollectionNameAndVerifyClientOrg(ctx) - if err != nil { - return "", err - } - - immutableProperties, err := ctx.GetStub().GetPrivateData(collection, assetID) - if err != nil { - return "", fmt.Errorf("failed to read asset private properties from client org's collection: %v", err) - } - if immutableProperties == nil { - return "", fmt.Errorf("asset private details does not exist in client org's collection: %s", assetID) - } - - return string(immutableProperties), nil -} - -// GetAssetSalesPrice returns the sales price -func (s *SmartContract) GetAssetSalesPrice(ctx contractapi.TransactionContextInterface, assetID string) (string, error) { - return getAssetPrice(ctx, assetID, typeAssetForSale) -} - -// GetAssetBidPrice returns the bid price -func (s *SmartContract) GetAssetBidPrice(ctx contractapi.TransactionContextInterface, assetID string) (string, error) { - return getAssetPrice(ctx, assetID, typeAssetBid) -} - -// getAssetPrice gets the bid or ask price from caller's implicit private data collection -func getAssetPrice(ctx contractapi.TransactionContextInterface, assetID string, priceType string) (string, error) { - - collection, err := getClientImplicitCollectionNameAndVerifyClientOrg(ctx) - if err != nil { - return "", err - } - - assetPriceKey, err := ctx.GetStub().CreateCompositeKey(priceType, []string{assetID}) - if err != nil { - return "", fmt.Errorf("failed to create composite key: %v", err) - } - - price, err := ctx.GetStub().GetPrivateData(collection, assetPriceKey) - if err != nil { - return "", fmt.Errorf("failed to read asset price from implicit private data collection: %v", err) - } - if price == nil { - return "", fmt.Errorf("asset price does not exist: %s", assetID) - } - - return string(price), nil -} - -// QueryAssetSaleAgreements returns all of an organization's proposed sales -func (s *SmartContract) QueryAssetSaleAgreements(ctx contractapi.TransactionContextInterface) ([]Agreement, error) { - return queryAgreementsByType(ctx, typeAssetForSale) -} - -// QueryAssetBuyAgreements returns all of an organization's proposed bids -func (s *SmartContract) QueryAssetBuyAgreements(ctx contractapi.TransactionContextInterface) ([]Agreement, error) { - return queryAgreementsByType(ctx, typeAssetBid) -} - -func queryAgreementsByType(ctx contractapi.TransactionContextInterface, agreeType string) ([]Agreement, error) { - collection, err := getClientImplicitCollectionNameAndVerifyClientOrg(ctx) - if err != nil { - return nil, err - } - - // Query for any object type starting with `agreeType` - agreementsIterator, err := ctx.GetStub().GetPrivateDataByPartialCompositeKey(collection, agreeType, []string{}) - if err != nil { - return nil, fmt.Errorf("failed to read from private data collection: %v", err) - } - defer agreementsIterator.Close() - - var agreements []Agreement - for agreementsIterator.HasNext() { - resp, err := agreementsIterator.Next() - if err != nil { - return nil, err - } - - var agreement Agreement - err = json.Unmarshal(resp.Value, &agreement) - if err != nil { - return nil, err - } - - agreements = append(agreements, agreement) - } - - return agreements, nil -} - -// QueryAssetHistory returns the chain of custody for a asset since issuance -func (s *SmartContract) QueryAssetHistory(ctx contractapi.TransactionContextInterface, assetID string) ([]QueryResult, error) { - resultsIterator, err := ctx.GetStub().GetHistoryForKey(assetID) - if err != nil { - return nil, err - } - defer resultsIterator.Close() - - var results []QueryResult - for resultsIterator.HasNext() { - response, err := resultsIterator.Next() - if err != nil { - return nil, err - } - - var asset *Asset - err = json.Unmarshal(response.Value, &asset) - if err != nil { - return nil, err - } - - record := QueryResult{ - TxId: response.TxId, - Timestamp: response.Timestamp.AsTime(), - Record: asset, - } - results = append(results, record) - } - - return results, nil -} diff --git a/asset-transfer-secured-agreement/chaincode-go/go.mod b/asset-transfer-secured-agreement/chaincode-go/go.mod deleted file mode 100644 index 8599ebee..00000000 --- a/asset-transfer-secured-agreement/chaincode-go/go.mod +++ /dev/null @@ -1,28 +0,0 @@ -module github.com/hyperledger/fabric-samples/chaincode/tradingMarbles - -go 1.22.0 - -require ( - github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0 - github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0 -) - -require ( - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xeipuuv/gojsonschema v1.2.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect - google.golang.org/grpc v1.67.0 // indirect - google.golang.org/protobuf v1.36.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/asset-transfer-secured-agreement/chaincode-go/go.sum b/asset-transfer-secured-agreement/chaincode-go/go.sum deleted file mode 100644 index fa4d3b24..00000000 --- a/asset-transfer-secured-agreement/chaincode-go/go.sum +++ /dev/null @@ -1,61 +0,0 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0 h1:IhkHfrl5X/fVnmB6pWeCYCdIJRi9bxj+WTnVN8DtW3c= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0/go.mod h1:PHHaFffjw7p7n9bmCfcm7RqDqYdivNEsJdiNIKZo5Lk= -github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0 h1:rmUoBmciB0GL/miqcbJmJbgp5QTWoJUrZo+CNxrNLF4= -github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0/go.mod h1:FeWeO/jwGjiME7ak3GufqKIcwkejtzrDG4QxbfKydWs= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 h1:YJrd+gMaeY0/vsN0aS0QkEKTivGoUnSRIXxGJ7KI+Pc= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4/go.mod h1:bau/6AJhvEcu9GKKYHlDXAxXKzYNfhP6xu2GXuxEcFk= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= -google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= -google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/auction-dutch/README.md b/auction-dutch/README.md deleted file mode 100644 index 12d79b1a..00000000 --- a/auction-dutch/README.md +++ /dev/null @@ -1,615 +0,0 @@ -## Dutch auction - -This example allows you to run a [Dutch auction](https://en.wikipedia.org/wiki/Dutch_auction) that sells multiple items of the same good. All items are sold at the price that clears the auction. You also have the option of adding an auditor organization to the auction. If the organizations running the auction cannot agree, or encounter a technical error that prevents them from updating the auction, one of the auction participants can appeal to an auditor organization. The dutch auction smart contract provides an example of how create a complex signature policy by creating a protobuf and then using the policy for state based endorsement. - -This tutorial uses the example smart contract to run an auction in which a single seller wants to sell 100 tickets to multiple bidders. If you chose to add an auditor to the auction, you can appeal to the auditor to end the auction by overriding the standard auction endorsement policy. - -## Deploy the chaincode - -Change into the test network directory. -``` -cd fabric-samples/test-network -``` - -If the test network is already running, run the following command to bring the network down and start from a clean initial state. -``` -./network.sh down -``` - -You can then run the following command to deploy a new network. -``` -./network.sh up createChannel -ca -``` - -Run the following command to deploy the dutch auction smart contract. -``` -./network.sh deployCC -ccn auction -ccp ../auction-dutch/chaincode-go/ -ccep "OR('Org1MSP.peer','Org2MSP.peer')" -ccl go -``` - -Note that we deploy the smart contract with an endorsement policy of `"OR('Org1MSP.peer','Org2MSP.peer')" ` instead of using the default endorsement policy of the majority of orgs on the channel. Either Org1 or Org2 can create an auction without the endorsement of the other organization. - -## Add an auditor (optional) - -The smart contract allows you to add an auditor organization to the auction. The auditor can add bids, close the auction, or end the auction if participants cannot cooperate. In this tutorial, we will add the Org3 organization to the test network channel and install an auditor specific version of the dutch auction smart contract. This allows you to use Org3 as the auditor organization. - -From the `test-network` directory, issue the following commands to add Org3 to the channel: - -``` -cd addOrg3 -./addOrg3.sh up -``` - -Navigate back to the test network directory: -``` -cd .. -``` - -Set the following environment to interact with the test network as Org3. -``` -export PATH=${PWD}/../bin:$PATH -export FABRIC_CFG_PATH=${PWD}/../config/ -export CORE_PEER_TLS_ENABLED=true -export CORE_PEER_LOCALMSPID=Org3MSP -export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt -export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org3.example.com/users/Admin@org3.example.com/msp -export CORE_PEER_ADDRESS=localhost:11051 -``` - -To deploy the smart contract on the Org3 peer, we need to use the peer lifecycle chaincode commands to install the chaincode package and approve the chaincode definition as Org3. Run the following command to package the auditor version of the dutch auction smart contract: -``` -peer lifecycle chaincode package auction.tar.gz --path ../auction-dutch/chaincode-go-auditor/ --lang golang --label auction_1 -``` -Install the chaincode package on the Org3 peer: -``` -peer lifecycle chaincode install auction.tar.gz -``` - -The next step is to approve the chaincode as the Org3 admin. This requires getting the package ID of the chaincode that we just installed. -``` -peer lifecycle chaincode queryinstalled -``` - -The command should return a response similar to the following: -``` -Installed chaincodes on peer: -Package ID: auction_1:8f0d6b6b5a616a1c2b6a9268418f2ee65718acc3c07ea12e123b189b3fb4fb14, Label: auction_1 -``` - -Save the package ID returned by the command above as an environment variable. The package ID will not be the same for all users, so you need to complete this step using the package ID returned from your console. -``` -export CC_PACKAGE_ID=auction_1:8f0d6b6b5a616a1c2b6a9268418f2ee65718acc3c07ea12e123b189b3fb4fb14 -``` - -You can now approve the auction chaincode for Org3: -``` -peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --channelID mychannel --name auction --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --signature-policy "OR('Org1MSP.peer','Org2MSP.peer')" -``` - -The command will start the dutch auction chaincode on the Org3 peer. Note that we did not update the endorsement policy before we added the auditor organization. Only Org1 and Org2 will be able create an auction. The auditor is added the endorsement policy after the auction is created. Because the auditor does not need to create an auction or create new bids, the auditor can run a different version of the smart contract than the auction participants. The auditor version of the smart contract also adds logic to check that the request is submitted by one of the auction participants before the auditor can intervene. - -## Install the application dependencies - -We will run the dutch auction using a series of Node.js applications. Change into the `application-javascript` directory: -``` -cd fabric-samples/auction-dutch/application-javascript -``` - -From this directory, run the following command to download the application dependencies if you have not done so already: -``` -npm install -``` - -## Register and enroll the application identities - -To interact with the network, you will need to enroll the Certificate Authority administrators of Org1 and Org2. You can use the `enrollAdmin.js` program for this task. Run the following command to enroll the Org1 admin: -``` -node enrollAdmin.js org1 -``` -You should see the logs of the admin wallet being created on your local file system. Now run the command to enroll the CA admin of Org2: -``` -node enrollAdmin.js org2 -``` - -We can use the CA admins of both organizations to register and enroll the identities of the seller that will create the auction and the bidders who will try to purchase the tickets. Run the following command to register and enroll the seller identity that will create the auction. The seller will belong to Org1. -``` -node registerEnrollUser.js org1 seller -``` - -You should see the logs of the seller wallet being created as well. Run the following commands to register and enroll two bidders from Org1 and another three bidders from Org2: -``` -node registerEnrollUser.js org1 bidder1 -node registerEnrollUser.js org1 bidder2 -node registerEnrollUser.js org2 bidder3 -node registerEnrollUser.js org2 bidder4 -node registerEnrollUser.js org2 bidder5 -``` - -## Create the auction - -The seller from Org1 would like to create an auction to sell 100 tickets. Run the following command to use the seller wallet to run the `createAuction.js` application. The seller needs to provide an auction ID, the item to be sold, and the quantity to be sold to create the auction. The seller uses `withAuditor` to indicate that Org3 will be added as the auditor organization. If you do not want to add an auditor, you can provide a value of `noAuditor`. You will see the application query the auction after it is created. -``` -node createAuction.js org1 seller auction1 tickets 100 withAuditor -``` - -Adding an auditor to the auction creates an endorsement policy with the auditor included. Without the auditor, each organization with sellers or bidders participating in the auction is added to the auction endorsement policy. For example, if the auction had two organizations participating in the auction, the auction endorsement policy would be `AND(Org1, Org2)`. However, if the selling organization decides to add an auditor, the auditor organization would be added to the endorsement policy. If the participating organizations disagree, or if a participant has a technical problem, the auditor can join any one of the participating organizations and agree to update the auction. Extending the example above, if the auction with two organizations added an auditor, the auction endorsement policy would be `OR(AND(Org1, Org2), AND(auditor, OR(Org1, Org2)))`. - -## Bid on the auction - -We can now use the bidder wallets to submit bids to the auction: - -### Bid as bidder1 - -Bidder1 will create a bid to purchase 50 tickets for 80 dollars. -``` -node bid.js org1 bidder1 auction1 50 80 -``` - -The application will query the bid after it is created: -``` -*** Result: Bid: { - "objectType": "bid", - "quantity": 50, - "price": 80, - "org": "Org1MSP", - "buyer": "x509::CN=bidder1,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US" -} -``` - -The `bid.js` application also prints the bidID: -``` -*** Result ***SAVE THIS VALUE*** BidID: 6630e1bb06e827a2b77023f63677fae8a0ad43126730e450d3252fa58eeb85b1 -``` - -The BidID acts as the unique identifier for the bid. This ID allows you to query the bid using the `queryBid.js` program and add the bid to the auction. Save the bidID returned by the application as an environment variable in your terminal: -``` -export BIDDER1_BID_ID=6630e1bb06e827a2b77023f63677fae8a0ad43126730e450d3252fa58eeb85b1 -``` -This value will be different for each transaction, so you will need to use the value returned in your terminal. - -Now that the bid has been created, you can submit the bid to the auction. Run the following command to submit the bid that was just created: -``` -node submitBid.js org1 bidder1 auction1 $BIDDER1_BID_ID -``` - -The hash of bid is added to the list of private bids in that have been submitted to `auction1`. Storing the hash on the public auction ledger allows users to prove the accuracy of the bids they reveal once bidding is closed. The application queries the auction to verify that the bid was added: -``` -*** Result: Auction: { - "objectType": "auction", - "item": "tickets", - "seller": "x509::CN=seller,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "quantity": 100, - "organizations": [ - "Org1MSP" - ], - "privateBids": { - "\u0000bid\u0000auction1\u00006630e1bb06e827a2b77023f63677fae8a0ad43126730e450d3252fa58eeb85b1\u0000": { - "org": "Org1MSP", - "hash": "2f7a62152627d69d73e31b62cd4731d32ecc277de0eef4d30b1235891298abf7" - } - }, - "revealedBids": {}, - "winners": [], - "price": 0, - "status": "open", - "auditor": true -} -``` - -### Bid as bidder2 - -Let's submit another bid. Bidder2 would like to purchase 40 tickets for 50 dollars. -``` -node bid.js org1 bidder2 auction1 40 50 -``` - -Save the Bid ID returned by the application: -``` -export BIDDER2_BID_ID=5796569dae2e95242eadc5cf1cf8aa24f5ae072d801e7decb2547530de5a65e8 -``` - -Submit bidder2's bid to the auction: -``` -node submitBid.js org1 bidder2 auction1 $BIDDER2_BID_ID -``` - -### Bid as bidder3 from Org2 - -Bidder3 will bid for 30 tickets at 70 dollars: -``` -node bid.js org2 bidder3 auction1 30 70 -``` - -Save the Bid ID returned by the application: -``` -export BIDDER3_BID_ID=d52ea4d9b4bc428d395db2d68323bc12cc9b5c1f8617900f459ccd41c38d3c0a -``` - -Add bidder3's bid to the auction: -``` -node submitBid.js org2 bidder3 auction1 $BIDDER3_BID_ID -``` - -Because bidder3 belongs to Org2, submitting the bid will add Org2 to the list of participating organizations. You can see the Org2 MSP ID has been added to the list of `"organizations"` in the updated auction returned by the application: -``` -*** Result: Auction: { - "objectType": "auction", - "item": "tickets", - "seller": "x509::CN=seller,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "quantity": 100, - "organizations": [ - "Org1MSP", - "Org2MSP" - ], - "privateBids": { - "\u0000bid\u0000auction1\u00005796569dae2e95242eadc5cf1cf8aa24f5ae072d801e7decb2547530de5a65e8\u0000": { - "org": "Org1MSP", - "hash": "598749480aa3af816a829455e1fdac25a44f31c2ae81f911f85d004f44dbbe6c" - }, - "\u0000bid\u0000auction1\u00006630e1bb06e827a2b77023f63677fae8a0ad43126730e450d3252fa58eeb85b1\u0000": { - "org": "Org1MSP", - "hash": "2f7a62152627d69d73e31b62cd4731d32ecc277de0eef4d30b1235891298abf7" - }, - "\u0000bid\u0000auction1\u0000d52ea4d9b4bc428d395db2d68323bc12cc9b5c1f8617900f459ccd41c38d3c0a\u0000": { - "org": "Org2MSP", - "hash": "bf1e9fb80ea3e29780fe13b4781b6dad28fa83b4b5db68bd7e90252875d152fb" - } - }, - "revealedBids": {}, - "winners": [], - "price": 0, - "status": "open", - "auditor": true -} -``` - -Now that a bid from Org2 has been added to the auction, any updates to the auction need to be endorsed by the Org2 peer. The applications will use the `"organizations"` field to specify which organizations need to endorse submitting a new bid, revealing a bid, or updating the auction status. - -### Bid as bidder4 - -Bidder4 from Org2 would like to purchase 15 tickets for 60 dollars: -``` -node bid.js org2 bidder4 auction1 15 60 -``` - -Save the Bid ID returned by the application: -``` -export BIDDER4_BID_ID=c6464f984bb01e639a46e58b94c496e8bbd829b5e4fa7ffcc150d9a565d45684 -``` - -Add bidder4's bid to the auction: -``` -node submitBid.js org2 bidder4 auction1 $BIDDER4_BID_ID -``` - -### Bid as bidder5 - -Bidder5 from Org2 will bid for 20 tickets at 60 dollars: -``` -node bid.js org2 bidder5 auction1 20 60 -``` - -Save the Bid ID returned by the application: -``` -export BIDDER5_BID_ID=f4024ab09b4dacf0a636927414850dde2a2a5e8ec4601e2a0071f5c233248207 -``` - -Add bidder5's bid to the auction: -``` -node submitBid.js org2 bidder5 auction1 $BIDDER5_BID_ID -``` - - -## Close the auction - -Now that all five bidders have joined the auction, the seller would like to close the auction and allow buyers to reveal their bids. The seller identity that created the auction needs to submit the transaction: -``` -node closeAuction.js org1 seller auction1 -``` - -The application will query the auction to allow you to verify that the auction status has changed to closed. - -## Reveal bids - -After the auction is closed, bidders can try to win the auction by revealing their bids. The transaction to reveal a bid needs to pass four checks: -1. The auction is closed. -2. The transaction was submitted by the identity that created the bid. -3. The hash of the revealed bid matches the hash of the bid on the channel ledger. This confirms that the bid is the same as the bid that is stored in the private data collection. -4. The hash of the revealed bid matches the hash that was submitted to the auction. This confirms that the bid was not altered after the auction was closed. - -Use the `revealBid.js` application to reveal the bid of Bidder1: -``` -node revealBid.js org1 bidder1 auction1 $BIDDER1_BID_ID -``` - -The full bid details, including the quantity and price, are now visible: -``` -*** Result: Auction: { - "objectType": "auction", - "item": "tickets", - "seller": "x509::CN=seller,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "quantity": 100, - "organizations": [ - "Org1MSP", - "Org2MSP" - ], - "privateBids": { - "\u0000bid\u0000auction1\u00005796569dae2e95242eadc5cf1cf8aa24f5ae072d801e7decb2547530de5a65e8\u0000": { - "org": "Org1MSP", - "hash": "598749480aa3af816a829455e1fdac25a44f31c2ae81f911f85d004f44dbbe6c" - }, - "\u0000bid\u0000auction1\u00006630e1bb06e827a2b77023f63677fae8a0ad43126730e450d3252fa58eeb85b1\u0000": { - "org": "Org1MSP", - "hash": "2f7a62152627d69d73e31b62cd4731d32ecc277de0eef4d30b1235891298abf7" - }, - "\u0000bid\u0000auction1\u0000c6464f984bb01e639a46e58b94c496e8bbd829b5e4fa7ffcc150d9a565d45684\u0000": { - "org": "Org2MSP", - "hash": "eefcadf8e9e5cb8322a6e642ab6d5512d62e6d68f37a72b00f5b0d9e580eddb9" - }, - "\u0000bid\u0000auction1\u0000d52ea4d9b4bc428d395db2d68323bc12cc9b5c1f8617900f459ccd41c38d3c0a\u0000": { - "org": "Org2MSP", - "hash": "bf1e9fb80ea3e29780fe13b4781b6dad28fa83b4b5db68bd7e90252875d152fb" - }, - "\u0000bid\u0000auction1\u0000f4024ab09b4dacf0a636927414850dde2a2a5e8ec4601e2a0071f5c233248207\u0000": { - "org": "Org2MSP", - "hash": "de82232141bac06ea3818146fb650dc9930d45b9ceab506ac66942b119eec094" - } - }, - "revealedBids": { - "\u0000bid\u0000auction1\u00006630e1bb06e827a2b77023f63677fae8a0ad43126730e450d3252fa58eeb85b1\u0000": { - "objectType": "bid", - "quantity": 50, - "price": 80, - "org": "Org1MSP", - "buyer": "x509::CN=bidder1,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US" - } - }, - "winners": [], - "price": 0, - "status": "closed", - "auditor": true -} -``` -We will add three more bidders, the second bidder from Org1 and two bidders from Org2. Run the following commands to reveal the bidders: -``` -node revealBid.js org1 bidder2 auction1 $BIDDER2_BID_ID -node revealBid.js org2 bidder4 auction1 $BIDDER4_BID_ID -node revealBid.js org2 bidder5 auction1 $BIDDER5_BID_ID -``` - -Let's try to end the auction using the seller identity and see what happens. - -``` -node endAuction.js org1 seller auction1 -``` - -The output should look something like the following: - -``` ---> Submit the transaction to end the auction -2021-01-28T16:47:27.501Z - error: [DiscoveryHandler]: compareProposalResponseResults[undefined] - read/writes result sets do not match index=1 -2021-01-28T16:47:27.503Z - error: [Transaction]: Error: No valid responses from any peers. Errors: - peer=undefined, status=grpc, message=Peer endorsements do not match -******** FAILED to submit bid: Error: No valid responses from any peers. Errors: - peer=undefined, status=grpc, message=Peer endorsements do not match -``` - -Instead of ending the auction, the transaction results in an endorsement policy failure. The end of the auction needs to be endorsed by Org2. Before endorsing the transaction, the Org2 peer queries its private data collection for any winning bids that have not yet been revealed. Because the price that would clear the auction with the currently revealed bids is lower than the bid of Bidder3, the Org2 peer refuses to endorse the transaction that would end the auction. - -In order to end the auction, Org1 would either need to wait for Org2 to reveal the final bid or appeal to the auditor. Depending on if you created the organization with an auditor, you can end the auction with either set of steps. - -## End the auction using an auditor - -If Org2 is unable to endorse the transaction to end the auction, Org1 can ask the auditor to intervene. The following program gets an endorsement from the Org3 auditor and Org1 to end the auction. As a result, the transaction would meet the auditor component of the state based endorsement policy. -``` -node endAuctionwithAuditor org1 seller auction1 -``` - -Even though Org2 has not agreed to the end of the auction, the endorsement Org1 is sufficient to end the auction if the auditor agrees. As part of ending the auction, both Org1 and the auditor need to calculate the same price and the same set of winners. Each winning bidder is listed next to the quantity that was allocated to them. -``` -*** Result: Auction: { - "objectType": "auction", - "item": "tickets", - "seller": "x509::CN=seller,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "quantity": 100, - "organizations": [ - "Org1MSP", - "Org2MSP" - ], - "privateBids": { - "\u0000bid\u0000auction1\u00005796569dae2e95242eadc5cf1cf8aa24f5ae072d801e7decb2547530de5a65e8\u0000": { - "org": "Org1MSP", - "hash": "598749480aa3af816a829455e1fdac25a44f31c2ae81f911f85d004f44dbbe6c" - }, - "\u0000bid\u0000auction1\u00006630e1bb06e827a2b77023f63677fae8a0ad43126730e450d3252fa58eeb85b1\u0000": { - "org": "Org1MSP", - "hash": "2f7a62152627d69d73e31b62cd4731d32ecc277de0eef4d30b1235891298abf7" - }, - "\u0000bid\u0000auction1\u0000c6464f984bb01e639a46e58b94c496e8bbd829b5e4fa7ffcc150d9a565d45684\u0000": { - "org": "Org2MSP", - "hash": "eefcadf8e9e5cb8322a6e642ab6d5512d62e6d68f37a72b00f5b0d9e580eddb9" - }, - "\u0000bid\u0000auction1\u0000d52ea4d9b4bc428d395db2d68323bc12cc9b5c1f8617900f459ccd41c38d3c0a\u0000": { - "org": "Org2MSP", - "hash": "bf1e9fb80ea3e29780fe13b4781b6dad28fa83b4b5db68bd7e90252875d152fb" - }, - "\u0000bid\u0000auction1\u0000f4024ab09b4dacf0a636927414850dde2a2a5e8ec4601e2a0071f5c233248207\u0000": { - "org": "Org2MSP", - "hash": "de82232141bac06ea3818146fb650dc9930d45b9ceab506ac66942b119eec094" - } - }, - "revealedBids": { - "\u0000bid\u0000auction1\u00005796569dae2e95242eadc5cf1cf8aa24f5ae072d801e7decb2547530de5a65e8\u0000": { - "objectType": "bid", - "quantity": 40, - "price": 50, - "org": "Org1MSP", - "buyer": "x509::CN=bidder2,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US" - }, - "\u0000bid\u0000auction1\u00006630e1bb06e827a2b77023f63677fae8a0ad43126730e450d3252fa58eeb85b1\u0000": { - "objectType": "bid", - "quantity": 50, - "price": 80, - "org": "Org1MSP", - "buyer": "x509::CN=bidder1,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US" - }, - "\u0000bid\u0000auction1\u0000c6464f984bb01e639a46e58b94c496e8bbd829b5e4fa7ffcc150d9a565d45684\u0000": { - "objectType": "bid", - "quantity": 15, - "price": 60, - "org": "Org2MSP", - "buyer": "x509::CN=bidder4,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK" - }, - "\u0000bid\u0000auction1\u0000f4024ab09b4dacf0a636927414850dde2a2a5e8ec4601e2a0071f5c233248207\u0000": { - "objectType": "bid", - "quantity": 20, - "price": 60, - "org": "Org2MSP", - "buyer": "x509::CN=bidder5,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK" - } - }, - "winners": [ - { - "buyer": "x509::CN=bidder1,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "quantity": 50 - }, - { - "buyer": "x509::CN=bidder4,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK", - "quantity": 15 - }, - { - "buyer": "x509::CN=bidder5,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK", - "quantity": 20 - }, - { - "buyer": "x509::CN=bidder2,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "quantity": 15 - } - ], - "price": 50, - "status": "ended", - "auditor": true -} -``` - -The auction allocates tickets to the highest bids first. Because all 100 tickets are sold after allocating tickets to the bid that was submitted at 50, 50 is the `"price"` that clears the auction. - -## End the auction without an auditor - -If we did not add an auditor to the auction, we need to add the remaining bid so that Org2 will endorse ending the auction. -``` -node revealBid.js org2 bidder3 auction1 $BIDDER3_BID_ID -``` - -Now that all the winning bids have been revealed, we can submit the transaction to end the auction once more. -``` -node endAuction org1 seller auction1 -``` - -The transaction was successfully endorsed by both Org1 and Org2, who both calculated the same price and winners of the auction. Each winning bidder is listed next to the quantity that was allocated to them. -``` -*** Result: Auction: { - "objectType": "auction", - "item": "tickets", - "seller": "x509::CN=seller,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "quantity": 100, - "organizations": [ - "Org1MSP", - "Org2MSP" - ], - "privateBids": { - "\u0000bid\u0000auction1\u0000482b2a68fbbfae329b0b4bc9d70b90f3a55fdcbae5f5274dec34d438efb6847e\u0000": { - "org": "Org1MSP", - "hash": "2f7a62152627d69d73e31b62cd4731d32ecc277de0eef4d30b1235891298abf7" - }, - "\u0000bid\u0000auction1\u000048d93017ac65cff0dd23406cc29918724fd84c8e7014eee30fd492fef760e6a4\u0000": { - "org": "Org2MSP", - "hash": "bf1e9fb80ea3e29780fe13b4781b6dad28fa83b4b5db68bd7e90252875d152fb" - }, - "\u0000bid\u0000auction1\u00005ba4c856224cdc8209b0e42f30a757331e3fb8a8b660b64a55e1bcf688b745ad\u0000": { - "org": "Org1MSP", - "hash": "598749480aa3af816a829455e1fdac25a44f31c2ae81f911f85d004f44dbbe6c" - }, - "\u0000bid\u0000auction1\u000063c8a192dae1332ae42af890f8a966fea2ae8365ca9746447e014a7c0494d64e\u0000": { - "org": "Org2MSP", - "hash": "de82232141bac06ea3818146fb650dc9930d45b9ceab506ac66942b119eec094" - }, - "\u0000bid\u0000auction1\u000066ff6d8bbe81e98654fc417915808031d49e93cd8d7475f15317d801317254fa\u0000": { - "org": "Org2MSP", - "hash": "eefcadf8e9e5cb8322a6e642ab6d5512d62e6d68f37a72b00f5b0d9e580eddb9" - } - }, - "revealedBids": { - "\u0000bid\u0000auction1\u0000482b2a68fbbfae329b0b4bc9d70b90f3a55fdcbae5f5274dec34d438efb6847e\u0000": { - "objectType": "bid", - "quantity": 50, - "price": 80, - "org": "Org1MSP", - "buyer": "x509::CN=bidder1,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US" - }, - "\u0000bid\u0000auction1\u000048d93017ac65cff0dd23406cc29918724fd84c8e7014eee30fd492fef760e6a4\u0000": { - "objectType": "bid", - "quantity": 30, - "price": 70, - "org": "Org2MSP", - "buyer": "x509::CN=bidder3,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK" - }, - "\u0000bid\u0000auction1\u00005ba4c856224cdc8209b0e42f30a757331e3fb8a8b660b64a55e1bcf688b745ad\u0000": { - "objectType": "bid", - "quantity": 40, - "price": 50, - "org": "Org1MSP", - "buyer": "x509::CN=bidder2,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US" - }, - "\u0000bid\u0000auction1\u000063c8a192dae1332ae42af890f8a966fea2ae8365ca9746447e014a7c0494d64e\u0000": { - "objectType": "bid", - "quantity": 20, - "price": 60, - "org": "Org2MSP", - "buyer": "x509::CN=bidder5,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK" - }, - "\u0000bid\u0000auction1\u000066ff6d8bbe81e98654fc417915808031d49e93cd8d7475f15317d801317254fa\u0000": { - "objectType": "bid", - "quantity": 15, - "price": 60, - "org": "Org2MSP", - "buyer": "x509::CN=bidder4,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK" - } - }, - "winners": [ - { - "buyer": "x509::CN=bidder1,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "quantity": 50 - }, - { - "buyer": "x509::CN=bidder3,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK", - "quantity": 30 - }, - { - "buyer": "x509::CN=bidder4,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK", - "quantity": 15 - }, - { - "buyer": "x509::CN=bidder5,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK", - "quantity": 5 - } - ], - "price": 60, - "status": "ended", - "auditor": false -} -``` - -The auction allocates tickets to the highest bids first. Because all 100 tickets are sold after allocating tickets to the bids that were submitted at 60, 60 is the `"price"` that clears the auction. The first 80 tickets are allocated to Bidder1 and Bidder3. The remaining 20 tickers are allocated to Bidder4 and Bidder5. When bids are tied, the auction smart contract fills the smaller bids first. As a result, Bidder4 is awarded their full bid of 15 tickets, while Bidder5 is allocated the remaining 5 tickets. - -## Clean up - -When your are done using the auction smart contract, you can bring down the network and clean up the environment. In the `auction-dutch/application-javascript` directory, run the following command to remove the wallets used to run the applications: -``` -rm -rf wallet -``` - -You can then navigate to the test network directory and bring down the network: -```` -cd ../../test-network/ -./network.sh down -```` diff --git a/auction-dutch/application-javascript/.eslintignore b/auction-dutch/application-javascript/.eslintignore deleted file mode 100644 index 15958470..00000000 --- a/auction-dutch/application-javascript/.eslintignore +++ /dev/null @@ -1,5 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -coverage diff --git a/auction-dutch/application-javascript/.eslintrc.js b/auction-dutch/application-javascript/.eslintrc.js deleted file mode 100644 index 20d4fcbd..00000000 --- a/auction-dutch/application-javascript/.eslintrc.js +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -module.exports = { - env: { - node: true, - mocha: true - }, - parserOptions: { - ecmaVersion: 8, - sourceType: 'script' - }, - extends: 'eslint:recommended', - rules: { - indent: ['error', 'tab'], - 'linebreak-style': ['error', 'unix'], - quotes: ['error', 'single'], - semi: ['error', 'always'], - 'no-unused-vars': ['error', { args: 'none' }], - 'no-console': 'off', - curly: 'error', - eqeqeq: 'error', - 'no-throw-literal': 'error', - strict: 'error', - 'no-var': 'error', - 'dot-notation': 'error', - 'no-trailing-spaces': 'error', - 'no-use-before-define': 'error', - 'no-useless-call': 'error', - 'no-with': 'error', - 'operator-linebreak': 'error', - yoda: 'error', - 'quote-props': ['error', 'as-needed'] - } -}; diff --git a/auction-dutch/application-javascript/bid.js b/auction-dutch/application-javascript/bid.js deleted file mode 100644 index aff30d65..00000000 --- a/auction-dutch/application-javascript/bid.js +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString } = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function bid (ccp, wallet, user, orgMSP, auctionID, quantity, price) { - try { - const gateway = new Gateway(); - // connect using Discovery enabled - - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - console.log('\n--> Evaluate Transaction: get your client ID'); - const buyer = await contract.evaluateTransaction('GetSubmittingClientIdentity'); - console.log('*** Result: Buyer ID is ' + buyer.toString()); - - const bidData = { objectType: 'bid', quantity: parseInt(quantity), price: parseInt(price), org: orgMSP, buyer: buyer.toString() }; - - const statefulTxn = contract.createTransaction('Bid'); - statefulTxn.setEndorsingOrganizations(orgMSP); - const tmapData = Buffer.from(JSON.stringify(bidData)); - statefulTxn.setTransient({ - bid: tmapData - }); - - const bidID = statefulTxn.getTransactionId(); - - console.log('\n--> Submit Transaction: Create the bid that is stored in your private data collection of your organization'); - await statefulTxn.submit(auctionID); - console.log('*** Result: committed'); - console.log('*** Result ***SAVE THIS VALUE*** BidID: ' + bidID.toString()); - - console.log('\n--> Evaluate Transaction: read the bid that was just created'); - const result = await contract.evaluateTransaction('QueryBid', auctionID, bidID); - console.log('*** Result: Bid: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - if (error.stack) { - console.error(error.stack); - } - process.exit(1); - } -} - -async function main () { - try { - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined || process.argv[5] === undefined || - process.argv[6] === undefined) { - console.log('Usage: node bid.js org userID auctionID quantity price'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - const quantity = process.argv[5]; - const price = process.argv[6]; - - if (org === 'Org1' || org === 'org1') { - const orgMSP = 'Org1MSP'; - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await bid(ccp, wallet, user, orgMSP, auctionID, quantity, price); - } else if (org === 'Org2' || org === 'org2') { - const orgMSP = 'Org2MSP'; - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await bid(ccp, wallet, user, orgMSP, auctionID, quantity, price); - } else { - console.log('Usage: node bid.js org userID auctionID quantity price'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - process.exit(1); - } -} - -main(); diff --git a/auction-dutch/application-javascript/closeAuction.js b/auction-dutch/application-javascript/closeAuction.js deleted file mode 100644 index 55410fb5..00000000 --- a/auction-dutch/application-javascript/closeAuction.js +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString } = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function closeAuction (ccp, wallet, user, auctionID) { - try { - const gateway = new Gateway(); - // connect using Discovery enabled - - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - // Query the auction to get the list of endorsing orgs. - // console.log('\n--> Evaluate Transaction: query the auction you want to close'); - const auctionString = await contract.evaluateTransaction('QueryAuction', auctionID); - // console.log('*** Result: Bid: ' + prettyJSONString(auctionString.toString())); - const auctionJSON = JSON.parse(auctionString); - - const statefulTxn = contract.createTransaction('CloseAuction'); - - if (auctionJSON.organizations.length === 2) { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0], auctionJSON.organizations[1]); - } else { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0]); - } - - console.log('\n--> Submit Transaction: close auction'); - await statefulTxn.submit(auctionID); - console.log('*** Result: committed'); - - console.log('\n--> Evaluate Transaction: query the updated auction'); - const result = await contract.evaluateTransaction('QueryAuction', auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - process.exit(1); - } -} - -async function main () { - try { - if (process.argv[2] === undefined || process.argv[3] === undefined || process.argv[4] === undefined) { - console.log('Usage: node closeAuction.js org userID auctionID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await closeAuction(ccp, wallet, user, auctionID); - } else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await closeAuction(ccp, wallet, user, auctionID); - } else { - console.log('Usage: node closeAuction.js org userID auctionID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - if (error.stack) { - console.error(error.stack); - } - process.exit(1); - } -} - -main(); diff --git a/auction-dutch/application-javascript/createAuction.js b/auction-dutch/application-javascript/createAuction.js deleted file mode 100644 index 2f46a248..00000000 --- a/auction-dutch/application-javascript/createAuction.js +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString } = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function createAuction (ccp, wallet, user, auctionID, item, quantity, auditor) { - try { - const gateway = new Gateway(); - // connect using Discovery enabled - - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - const statefulTxn = contract.createTransaction('CreateAuction'); - - console.log('\n--> Submit Transaction: Propose a new auction'); - await statefulTxn.submit(auctionID, item, parseInt(quantity), auditor); - console.log('*** Result: committed'); - - console.log('\n--> Evaluate Transaction: query the auction that was just created'); - const result = await contract.evaluateTransaction('QueryAuction', auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - } -} - -async function main () { - try { - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined || process.argv[5] === undefined || - process.argv[6] === undefined) { - console.log('Usage: node createAuction.js org userID auctionID item quantity'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - const item = process.argv[5]; - const quantity = process.argv[6]; - const auditor = process.argv[7]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await createAuction(ccp, wallet, user, auctionID, item, quantity, auditor); - } else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await createAuction(ccp, wallet, user, auctionID, item, quantity, auditor); - } else { - console.log('Usage: node createAuction.js org userID auctionID item quantity'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - } -} - -main(); diff --git a/auction-dutch/application-javascript/endAuction.js b/auction-dutch/application-javascript/endAuction.js deleted file mode 100644 index daec75d2..00000000 --- a/auction-dutch/application-javascript/endAuction.js +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString } = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function endAuction (ccp, wallet, user, auctionID) { - try { - const gateway = new Gateway(); - // connect using Discovery enabled - - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - // Query the auction to get the list of endorsing orgs. - // console.log('\n--> Evaluate Transaction: query the auction you want to end'); - const auctionString = await contract.evaluateTransaction('QueryAuction', auctionID); - // console.log('*** Result: Bid: ' + prettyJSONString(auctionString.toString())); - const auctionJSON = JSON.parse(auctionString); - - const statefulTxn = contract.createTransaction('EndAuction'); - - if (auctionJSON.organizations.length === 2) { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0], auctionJSON.organizations[1]); - } else { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0]); - } - - console.log('\n--> Submit the transaction to end the auction'); - await statefulTxn.submit(auctionID); - console.log('*** Result: committed'); - - console.log('\n--> Evaluate Transaction: query the updated auction'); - const result = await contract.evaluateTransaction('QueryAuction', auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - process.exit(1); - } -} - -async function main () { - try { - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined) { - console.log('Usage: node endAuction.js org userID auctionID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await endAuction(ccp, wallet, user, auctionID); - } else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await endAuction(ccp, wallet, user, auctionID); - } else { - console.log('Usage: node endAuction.js org userID auctionID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - if (error.stack) { - console.error(error.stack); - } - process.exit(1); - } -} - -main(); diff --git a/auction-dutch/application-javascript/endAuctionwithAuditor.js b/auction-dutch/application-javascript/endAuctionwithAuditor.js deleted file mode 100644 index 5e085258..00000000 --- a/auction-dutch/application-javascript/endAuctionwithAuditor.js +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString } = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function endAuction (ccp, wallet, org, user, auctionID) { - try { - const gateway = new Gateway(); - // connect using Discovery enabled - - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - const statefulTxn = contract.createTransaction('EndAuction'); - - statefulTxn.setEndorsingOrganizations(org, 'Org3MSP'); - - console.log('\n--> Submit the transaction to end the auction'); - await statefulTxn.submit(auctionID); - console.log('*** Result: committed'); - - console.log('\n--> Evaluate Transaction: query the updated auction'); - const result = await contract.evaluateTransaction('QueryAuction', auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - process.exit(1); - } -} - -async function main () { - try { - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined) { - console.log('Usage: node endAuction.js org userID auctionID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - - if (org === 'Org1' || org === 'org1') { - const orgMSP = 'Org1MSP'; - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await endAuction(ccp, wallet, orgMSP, user, auctionID); - } else if (org === 'Org2' || org === 'org2') { - const orgMSP = 'Org2MSP'; - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await endAuction(ccp, wallet, orgMSP, user, auctionID); - } else { - console.log('Usage: node endAuction.js org userID auctionID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - if (error.stack) { - console.error(error.stack); - } - process.exit(1); - } -} - -main(); diff --git a/auction-dutch/application-javascript/enrollAdmin.js b/auction-dutch/application-javascript/enrollAdmin.js deleted file mode 100644 index 90998fd8..00000000 --- a/auction-dutch/application-javascript/enrollAdmin.js +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Wallets } = require('fabric-network'); -const FabricCAServices = require('fabric-ca-client'); -const path = require('path'); -const { buildCAClient, enrollAdmin } = require('../../test-application/javascript/CAUtil.js'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet } = require('../../test-application/javascript/AppUtil.js'); - -const mspOrg1 = 'Org1MSP'; -const mspOrg2 = 'Org2MSP'; - -async function connectToOrg1CA () { - console.log('\n--> Enrolling the Org1 CA admin'); - const ccpOrg1 = buildCCPOrg1(); - const caOrg1Client = buildCAClient(FabricCAServices, ccpOrg1, 'ca.org1.example.com'); - - const walletPathOrg1 = path.join(__dirname, 'wallet/org1'); - const walletOrg1 = await buildWallet(Wallets, walletPathOrg1); - - await enrollAdmin(caOrg1Client, walletOrg1, mspOrg1); -} - -async function connectToOrg2CA () { - console.log('\n--> Enrolling the Org2 CA admin'); - const ccpOrg2 = buildCCPOrg2(); - const caOrg2Client = buildCAClient(FabricCAServices, ccpOrg2, 'ca.org2.example.com'); - - const walletPathOrg2 = path.join(__dirname, 'wallet/org2'); - const walletOrg2 = await buildWallet(Wallets, walletPathOrg2); - - await enrollAdmin(caOrg2Client, walletOrg2, mspOrg2); -} -async function main () { - if (process.argv[2] === undefined) { - console.log('Usage: node enrollAdmin.js Org'); - process.exit(1); - } - - const org = process.argv[2]; - - try { - if (org === 'Org1' || org === 'org1') { - await connectToOrg1CA(); - } else if (org === 'Org2' || org === 'org2') { - await connectToOrg2CA(); - } else { - console.log('Usage: node registerUser.js org userID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`Error in enrolling admin: ${error}`); - process.exit(1); - } -} - -main(); diff --git a/auction-dutch/application-javascript/package.json b/auction-dutch/application-javascript/package.json deleted file mode 100644 index 33954681..00000000 --- a/auction-dutch/application-javascript/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "auction", - "version": "1.0.0", - "description": "auction application implemented in JavaScript", - "engines": { - "node": ">=12", - "npm": ">=5" - }, - "engineStrict": true, - "author": "Hyperledger", - "license": "Apache-2.0", - "scripts": { - "lint": "eslint *.js" - }, - "dependencies": { - "fabric-ca-client": "^2.2.19", - "fabric-network": "^2.2.19" - }, - "devDependencies": { - "eslint": "^7.20.0", - "eslint-config-standard": "^16.0.2", - "eslint-plugin-import": "^2.22.1", - "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^4.3.1" - } -} diff --git a/auction-dutch/application-javascript/queryAuction.js b/auction-dutch/application-javascript/queryAuction.js deleted file mode 100644 index 06471d5e..00000000 --- a/auction-dutch/application-javascript/queryAuction.js +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString } = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function queryAuction (ccp, wallet, user, auctionID) { - try { - const gateway = new Gateway(); - // connect using Discovery enabled - - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - console.log('\n--> Evaluate Transaction: query the auction'); - const result = await contract.evaluateTransaction('QueryAuction', auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - } -} - -async function main () { - try { - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined) { - console.log('Usage: node queryAuction.js org userID auctionID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await queryAuction(ccp, wallet, user, auctionID); - } else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await queryAuction(ccp, wallet, user, auctionID); - } else { - console.log('Usage: node queryAuction.js org userID auctionID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - } -} - -main(); diff --git a/auction-dutch/application-javascript/queryBid.js b/auction-dutch/application-javascript/queryBid.js deleted file mode 100644 index 1bb17e7d..00000000 --- a/auction-dutch/application-javascript/queryBid.js +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString } = require('../../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function queryBid (ccp, wallet, user, auctionID, bidID) { - try { - const gateway = new Gateway(); - // connect using Discovery enabled - - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - console.log('\n--> Evaluate Transaction: read bid from private data store'); - const result = await contract.evaluateTransaction('QueryBid', auctionID, bidID); - console.log('*** Result: Bid: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - } -} - -async function main () { - try { - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined || process.argv[5] === undefined) { - console.log('Usage: node bid.js org userID auctionID bidID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - const bidID = process.argv[5]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await queryBid(ccp, wallet, user, auctionID, bidID); - } else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await queryBid(ccp, wallet, user, auctionID, bidID); - } else { - console.log('Usage: node bid.js org userID auctionID bidID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - } -} - -main(); diff --git a/auction-dutch/application-javascript/registerEnrollUser.js b/auction-dutch/application-javascript/registerEnrollUser.js deleted file mode 100644 index 9b7abc32..00000000 --- a/auction-dutch/application-javascript/registerEnrollUser.js +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Wallets } = require('fabric-network'); -const FabricCAServices = require('fabric-ca-client'); -const path = require('path'); -const { buildCAClient, registerAndEnrollUser } = require('../../test-application/javascript/CAUtil.js'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet } = require('../../test-application/javascript/AppUtil.js'); - -const mspOrg1 = 'Org1MSP'; -const mspOrg2 = 'Org2MSP'; - -async function connectToOrg1CA (UserID) { - console.log('\n--> Register and enrolling new user'); - const ccpOrg1 = buildCCPOrg1(); - const caOrg1Client = buildCAClient(FabricCAServices, ccpOrg1, 'ca.org1.example.com'); - - const walletPathOrg1 = path.join(__dirname, 'wallet/org1'); - const walletOrg1 = await buildWallet(Wallets, walletPathOrg1); - - await registerAndEnrollUser(caOrg1Client, walletOrg1, mspOrg1, UserID, 'org1.department1'); -} - -async function connectToOrg2CA (UserID) { - console.log('\n--> Register and enrolling new user'); - const ccpOrg2 = buildCCPOrg2(); - const caOrg2Client = buildCAClient(FabricCAServices, ccpOrg2, 'ca.org2.example.com'); - - const walletPathOrg2 = path.join(__dirname, 'wallet/org2'); - const walletOrg2 = await buildWallet(Wallets, walletPathOrg2); - - await registerAndEnrollUser(caOrg2Client, walletOrg2, mspOrg2, UserID, 'org2.department1'); -} -async function main () { - if (process.argv[2] === undefined && process.argv[3] === undefined) { - console.log('Usage: node registerEnrollUser.js org userID'); - process.exit(1); - } - - const org = process.argv[2]; - const userId = process.argv[3]; - - try { - if (org === 'Org1' || org === 'org1') { - await connectToOrg1CA(userId); - } else if (org === 'Org2' || org === 'org2') { - await connectToOrg2CA(userId); - } else { - console.log('Usage: node registerEnrollUser.js org userID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`Error in enrolling admin: ${error}`); - process.exit(1); - } -} - -main(); diff --git a/auction-dutch/application-javascript/revealBid.js b/auction-dutch/application-javascript/revealBid.js deleted file mode 100644 index b1fc8dc9..00000000 --- a/auction-dutch/application-javascript/revealBid.js +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString } = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function addBid (ccp, wallet, user, auctionID, bidID) { - try { - const gateway = new Gateway(); - // connect using Discovery enabled - - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - console.log('\n--> Evaluate Transaction: read your bid'); - const bidString = await contract.evaluateTransaction('QueryBid', auctionID, bidID); - const bidJSON = JSON.parse(bidString); - - // console.log('\n--> Evaluate Transaction: query the auction you want to join'); - const auctionString = await contract.evaluateTransaction('QueryAuction', auctionID); - // console.log('*** Result: Bid: ' + prettyJSONString(auctionString.toString())); - const auctionJSON = JSON.parse(auctionString); - - const bidData = { objectType: 'bid', quantity: parseInt(bidJSON.quantity), price: parseInt(bidJSON.price), org: bidJSON.org, buyer: bidJSON.buyer }; - console.log('*** Result: Bid: ' + JSON.stringify(bidData, null, 2)); - - const statefulTxn = contract.createTransaction('RevealBid'); - const tmapData = Buffer.from(JSON.stringify(bidData)); - statefulTxn.setTransient({ - bid: tmapData - }); - - if (auctionJSON.organizations.length === 2) { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0], auctionJSON.organizations[1]); - } else { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0]); - } - - await statefulTxn.submit(auctionID, bidID); - - console.log('\n--> Evaluate Transaction: query the auction to see that our bid was added'); - const result = await contract.evaluateTransaction('QueryAuction', auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - process.exit(1); - } -} - -async function main () { - try { - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined || process.argv[5] === undefined) { - console.log('Usage: node revealBid.js org userID auctionID bidID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - const bidID = process.argv[5]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await addBid(ccp, wallet, user, auctionID, bidID); - } else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await addBid(ccp, wallet, user, auctionID, bidID); - } else { - console.log('Usage: node revealBid.js org userID auctionID bidID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - if (error.stack) { - console.error(error.stack); - } - process.exit(1); - } -} - -main(); diff --git a/auction-dutch/application-javascript/submitBid.js b/auction-dutch/application-javascript/submitBid.js deleted file mode 100644 index adb3070f..00000000 --- a/auction-dutch/application-javascript/submitBid.js +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString } = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function submitBid (ccp, wallet, user, auctionID, bidID) { - try { - const gateway = new Gateway(); - // connect using Discovery enabled - - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - console.log('\n--> Evaluate Transaction: query the auction you want to join'); - const auctionString = await contract.evaluateTransaction('QueryAuction', auctionID); - const auctionJSON = JSON.parse(auctionString); - - const statefulTxn = contract.createTransaction('SubmitBid'); - - if (auctionJSON.organizations.length === 2) { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0], auctionJSON.organizations[1]); - } else { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0]); - } - - console.log('\n--> Submit Transaction: add bid to the auction'); - await statefulTxn.submit(auctionID, bidID); - - console.log('\n--> Evaluate Transaction: query the auction to see that our bid was added'); - const result = await contract.evaluateTransaction('QueryAuction', auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - process.exit(1); - } -} - -async function main () { - try { - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined || process.argv[5] === undefined) { - console.log('Usage: node submitBid.js org userID auctionID bidID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - const bidID = process.argv[5]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await submitBid(ccp, wallet, user, auctionID, bidID); - } else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await submitBid(ccp, wallet, user, auctionID, bidID); - } else { - console.log('Usage: node submitBid.js org userID auctionID bidID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - if (error.stack) { - console.error(error.stack); - } - process.exit(1); - } -} - -main(); diff --git a/auction-dutch/chaincode-go-auditor/go.mod b/auction-dutch/chaincode-go-auditor/go.mod deleted file mode 100644 index efdae2fc..00000000 --- a/auction-dutch/chaincode-go-auditor/go.mod +++ /dev/null @@ -1,28 +0,0 @@ -module github.com/hyperledger/fabric-samples/auction/dutch-auction/chaincode-go-auditor - -go 1.22.0 - -require ( - github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0 - github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0 - github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 - google.golang.org/protobuf v1.36.1 -) - -require ( - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xeipuuv/gojsonschema v1.2.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect - google.golang.org/grpc v1.67.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/auction-dutch/chaincode-go-auditor/go.sum b/auction-dutch/chaincode-go-auditor/go.sum deleted file mode 100644 index fa4d3b24..00000000 --- a/auction-dutch/chaincode-go-auditor/go.sum +++ /dev/null @@ -1,61 +0,0 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0 h1:IhkHfrl5X/fVnmB6pWeCYCdIJRi9bxj+WTnVN8DtW3c= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0/go.mod h1:PHHaFffjw7p7n9bmCfcm7RqDqYdivNEsJdiNIKZo5Lk= -github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0 h1:rmUoBmciB0GL/miqcbJmJbgp5QTWoJUrZo+CNxrNLF4= -github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0/go.mod h1:FeWeO/jwGjiME7ak3GufqKIcwkejtzrDG4QxbfKydWs= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 h1:YJrd+gMaeY0/vsN0aS0QkEKTivGoUnSRIXxGJ7KI+Pc= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4/go.mod h1:bau/6AJhvEcu9GKKYHlDXAxXKzYNfhP6xu2GXuxEcFk= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= -google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= -google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/auction-dutch/chaincode-go-auditor/smart-contract/auction.go b/auction-dutch/chaincode-go-auditor/smart-contract/auction.go deleted file mode 100644 index c56daedd..00000000 --- a/auction-dutch/chaincode-go-auditor/smart-contract/auction.go +++ /dev/null @@ -1,440 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package auction - -import ( - "bytes" - "crypto/sha256" - "encoding/json" - "errors" - "fmt" - "sort" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -type SmartContract struct { - contractapi.Contract -} - -// Auction data -type Auction struct { - Type string `json:"objectType"` - ItemSold string `json:"item"` - Seller string `json:"seller"` - Quantity int `json:"quantity"` - Orgs []string `json:"organizations"` - PrivateBids map[string]BidHash `json:"privateBids"` - RevealedBids map[string]FullBid `json:"revealedBids"` - Winners []Winners `json:"winners"` - Price int `json:"price"` - Status string `json:"status"` - Auditor bool `json:"auditor"` -} - -// FullBid is the structure of a revealed bid -type FullBid struct { - Type string `json:"objectType"` - Quantity int `json:"quantity"` - Price int `json:"price"` - Org string `json:"org"` - Buyer string `json:"buyer"` -} - -// BidHash is the structure of a private bid -type BidHash struct { - Org string `json:"org"` - Hash string `json:"hash"` -} - -// Winners stores the winners of the auction -type Winners struct { - Buyer string `json:"buyer"` - Quantity int `json:"quantity"` -} - -const bidKeyType = "bid" - -// SubmitBid is used by the bidder to add the hash of that bid stored in private data to the -// auction. Note that this function alters the auction in private state, and needs -// to meet the auction endorsement policy. Transaction ID is used identify the bid -func (s *SmartContract) SubmitBid(ctx contractapi.TransactionContextInterface, auctionID string, txID string) error { - - // get the MSP ID of the bidder's org - clientOrgID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed to get client MSP ID: %v", err) - } - - // get the auction from public state - auction, err := s.QueryAuction(ctx, auctionID) - if err != nil { - return fmt.Errorf("failed to get auction from public state %v", err) - } - - // the auction needs to be open for users to add their bid - status := auction.Status - if status != "open" { - return fmt.Errorf("cannot join closed or ended auction") - } - - // get the inplicit collection name of bidder's org - collection, err := getCollectionName(ctx) - if err != nil { - return fmt.Errorf("failed to get implicit collection name: %v", err) - } - - // use the transaction ID passed as a parameter to create composite bid key - bidKey, err := ctx.GetStub().CreateCompositeKey(bidKeyType, []string{auctionID, txID}) - if err != nil { - return fmt.Errorf("failed to create composite key: %v", err) - } - - // get the hash of the bid if found in private collection - bidHash, err := ctx.GetStub().GetPrivateDataHash(collection, bidKey) - if err != nil { - return fmt.Errorf("failed to read bid bash from collection: %v", err) - } - if bidHash == nil { - return fmt.Errorf("bid hash does not exist: %s", bidKey) - } - - // store the hash along with the bidder's organization - newHash := BidHash{ - Org: clientOrgID, - Hash: fmt.Sprintf("%x", bidHash), - } - - auction.PrivateBids[bidKey] = newHash - - // Add the bidding organization to the list of participating organization's if it is not already - orgs := auction.Orgs - if !(contains(orgs, clientOrgID)) { - newOrgs := append(orgs, clientOrgID) - auction.Orgs = newOrgs - - err = setAssetStateBasedEndorsement(ctx, auctionID, newOrgs, auction.Auditor) - if err != nil { - return fmt.Errorf("failed setting state based endorsement for new organization: %v", err) - } - } - - newAuctionJSON, _ := json.Marshal(auction) - - err = ctx.GetStub().PutState(auctionID, newAuctionJSON) - if err != nil { - return fmt.Errorf("failed to update auction: %v", err) - } - - return nil -} - -// RevealBid is used by a bidder to reveal their bid after the auction is closed -func (s *SmartContract) RevealBid(ctx contractapi.TransactionContextInterface, auctionID string, txID string) error { - - // get the MSP ID of the bidder's org - clientOrgID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed to get client MSP ID: %v", err) - } - - // get bid from transient map - transientMap, err := ctx.GetStub().GetTransient() - if err != nil { - return fmt.Errorf("error getting transient: %v", err) - } - - transientBidJSON, ok := transientMap["bid"] - if !ok { - return errors.New("bid key not found in the transient map") - } - - // get implicit collection name of organization ID - collection, err := getCollectionName(ctx) - if err != nil { - return fmt.Errorf("failed to get implicit collection name: %v", err) - } - - // use transaction ID to create composit bid key - bidKey, err := ctx.GetStub().CreateCompositeKey(bidKeyType, []string{auctionID, txID}) - if err != nil { - return fmt.Errorf("failed to create composite key: %v", err) - } - - // get bid hash of bid if private bid on the public ledger - bidHash, err := ctx.GetStub().GetPrivateDataHash(collection, bidKey) - if err != nil { - return fmt.Errorf("failed to read bid bash from collection: %v", err) - } - if bidHash == nil { - return fmt.Errorf("bid hash does not exist: %s", bidKey) - } - - // get auction from public state - auction, err := s.QueryAuction(ctx, auctionID) - if err != nil { - return fmt.Errorf("failed to get auction from public state %v", err) - } - - // check that the bidders org is a participant in the auction - orgs := auction.Orgs - if !(contains(orgs, clientOrgID)) { - return fmt.Errorf("particiant %s is not a member of the auction", clientOrgID) - } - - // Complete a series of three checks before we add the bid to the auction - - // check 1: check that the auction is closed. We cannot reveal an - // bid to an open auction - status := auction.Status - if status != "closed" { - return errors.New("cannot reveal bid for open or ended auction") - } - - // check 2: check that hash of revealed bid matches hash of private bid - // on the public ledger. This checks that the bidder is telling the truth - // about the value of their bid - - hash := sha256.New() - hash.Write(transientBidJSON) - calculatedBidJSONHash := hash.Sum(nil) - - // verify that the hash of the passed immutable properties matches the on-chain hash - if !bytes.Equal(calculatedBidJSONHash, bidHash) { - return fmt.Errorf("hash %x for bid JSON %s does not match hash in auction: %x", - calculatedBidJSONHash, - transientBidJSON, - bidHash, - ) - } - - // check 3; check hash of relealed bid matches hash of private bid that was - // added earlier. This ensures that the bid has not changed since it - // was added to the auction - - privateBidHashString := auction.PrivateBids[bidKey].Hash - - onChainBidHashString := fmt.Sprintf("%x", bidHash) - if privateBidHashString != onChainBidHashString { - return fmt.Errorf("hash %s for bid JSON %s does not match hash in auction: %s, bidder must have changed bid", - privateBidHashString, - transientBidJSON, - onChainBidHashString, - ) - } - - // we can add the bid to the auction if all checks have passed - type transientBidInput struct { - Quantity int `json:"quantity"` - Price int `json:"price"` - Org string `json:"org"` - Buyer string `json:"buyer"` - } - - // unmarshal bid imput - var bidInput transientBidInput - err = json.Unmarshal(transientBidJSON, &bidInput) - if err != nil { - return fmt.Errorf("failed to unmarshal JSON: %v", err) - } - - // get ID of submitting client - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - // marshal transient parameters and ID and MSPID into bid object - newBid := FullBid{ - Type: bidKeyType, - Quantity: bidInput.Quantity, - Price: bidInput.Price, - Org: bidInput.Org, - Buyer: bidInput.Buyer, - } - - // check 4: make sure that the transaction is being submitted is the bidder - if bidInput.Buyer != clientID { - return fmt.Errorf("permission denied, client id %v is not the owner of the bid", clientID) - } - - auction.RevealedBids[bidKey] = newBid - - auctionJSON, _ := json.Marshal(auction) - - // put auction with bid added back into state - err = ctx.GetStub().PutState(auctionID, auctionJSON) - if err != nil { - return fmt.Errorf("failed to update auction: %v", err) - } - - return nil -} - -// CloseAuction can be used by the seller to close the auction. This prevents -// bids from being added to the auction, and allows users to reveal their bid -func (s *SmartContract) CloseAuction(ctx contractapi.TransactionContextInterface, auctionID string) error { - - // get the MSP ID of the bidder's org - clientOrgID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed to get client MSP ID: %v", err) - } - - // get auction from public state - auction, err := s.QueryAuction(ctx, auctionID) - if err != nil { - return fmt.Errorf("failed to get auction from public state %v", err) - } - - // check that the bidders org is a participant in the auction - orgs := auction.Orgs - if !(contains(orgs, clientOrgID)) { - return fmt.Errorf("particiant %s is not a member of the auction", clientOrgID) - } - - // the auction can only be closed by the seller - - // get ID of submitting client - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - seller := auction.Seller - if seller != clientID { - return fmt.Errorf("auction can only be closed by seller: %v", err) - } - - status := auction.Status - if status != "open" { - return errors.New("cannot close auction that is not open") - } - - auction.Status = string("closed") - - closedAuctionJSON, _ := json.Marshal(auction) - - err = ctx.GetStub().PutState(auctionID, closedAuctionJSON) - if err != nil { - return fmt.Errorf("failed to close auction: %v", err) - } - - return nil -} - -// EndAuction both changes the auction status to closed and calculates the winners -// of the auction -func (s *SmartContract) EndAuction(ctx contractapi.TransactionContextInterface, auctionID string) error { - - // get the MSP ID of the bidder's org - clientOrgID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed to get client MSP ID: %v", err) - } - - // get auction from public state - auction, err := s.QueryAuction(ctx, auctionID) - if err != nil { - return fmt.Errorf("failed to get auction from public state %v", err) - } - - // check that the bidders org is a participant in the auction - orgs := auction.Orgs - if !(contains(orgs, clientOrgID)) { - return fmt.Errorf("particiant %s is not a member of the auction", clientOrgID) - } - - // Check that the auction is being ended by the seller - - // get ID of submitting client - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - seller := auction.Seller - if seller != clientID { - return fmt.Errorf("auction can only be ended by seller: %v", err) - } - - status := auction.Status - if status != "closed" { - return errors.New("can only end a closed auction") - } - - // get the list of revealed bids - - revealedBidMap := auction.RevealedBids - if len(auction.RevealedBids) == 0 { - return fmt.Errorf("no bids have been revealed, cannot end auction: %v", err) - } - - // sort the map of revealed bids to make it easier to calculate winners - // if bids are tied, fill smaller bids first - var bidders []FullBid - - for _, bid := range revealedBidMap { - bidders = append(bidders, bid) - } - - sort.Slice(bidders, func(p, q int) bool { - if bidders[p].Price > bidders[q].Price { - return true - } - if bidders[p].Price < bidders[q].Price { - return false - } - return bidders[p].Quantity < bidders[q].Quantity - }) - - i := 0 - remainingQuantity := auction.Quantity - - // calculate the winners - for remainingQuantity > 0 { - - // create the next winning bid - winner := Winners{ - Buyer: bidders[i].Buyer, - Quantity: bidders[i].Quantity, - } - - // add them to the list of winners and change the winning price - auction.Winners = append(auction.Winners, winner) - auction.Price = bidders[i].Price - - // Calculate the quantity that goes to the winner - // if there is sufficient quantity to give them the full bid - if remainingQuantity > bidders[i].Quantity { - remainingQuantity = remainingQuantity - bidders[i].Quantity - - // if there is not, give the remainder - } else { - auction.Winners[i].Quantity = remainingQuantity - remainingQuantity = 0 - } - i++ - if i == len(bidders) { - remainingQuantity = 0 - } - } - - // check if there is a winning bid that has yet to be revealed - err = checkForHigherBid(ctx, auction.Price, auction.RevealedBids, auction.PrivateBids) - if err != nil { - return fmt.Errorf("cannot end auction: %v", err) - } - - auction.Status = "ended" - - endedAuctionJSON, _ := json.Marshal(auction) - - err = ctx.GetStub().PutState(auctionID, endedAuctionJSON) - if err != nil { - return fmt.Errorf("failed to end auction: %v", err) - } - return nil -} diff --git a/auction-dutch/chaincode-go-auditor/smart-contract/auctionQueries.go b/auction-dutch/chaincode-go-auditor/smart-contract/auctionQueries.go deleted file mode 100644 index 45b84762..00000000 --- a/auction-dutch/chaincode-go-auditor/smart-contract/auctionQueries.go +++ /dev/null @@ -1,92 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package auction - -import ( - "encoding/json" - "errors" - "fmt" - - "github.com/hyperledger/fabric-chaincode-go/v2/shim" - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -// QueryAuction allows all members of the channel to read a public auction -func (s *SmartContract) QueryAuction(ctx contractapi.TransactionContextInterface, auctionID string) (*Auction, error) { - - auctionJSON, err := ctx.GetStub().GetState(auctionID) - if err != nil { - return nil, fmt.Errorf("failed to get auction object %v: %v", auctionID, err) - } - if auctionJSON == nil { - return nil, errors.New("auction does not exist") - } - - var auction *Auction - err = json.Unmarshal(auctionJSON, &auction) - if err != nil { - return nil, err - } - - return auction, nil -} - -// checkForHigherBid is an internal function that is used to determine if a winning bid has yet to be revealed -func checkForHigherBid(ctx contractapi.TransactionContextInterface, auctionPrice int, revealedBidders map[string]FullBid, bidders map[string]BidHash) error { - - // Get MSP ID of peer org - peerMSPID, err := shim.GetMSPID() - if err != nil { - return fmt.Errorf("failed getting the peer's MSPID: %v", err) - } - - var error error - error = nil - - for bidKey, privateBid := range bidders { - - if _, bidInAuction := revealedBidders[bidKey]; bidInAuction { - - // bid is already revealed, no action to take - - } else { - - collection := "_implicit_org_" + privateBid.Org - - if privateBid.Org == peerMSPID { - - bidJSON, err := ctx.GetStub().GetPrivateData(collection, bidKey) - if err != nil { - return fmt.Errorf("failed to get bid %v: %v", bidKey, err) - } - if bidJSON == nil { - return fmt.Errorf("bid %v does not exist", bidKey) - } - - var bid *FullBid - err = json.Unmarshal(bidJSON, &bid) - if err != nil { - return err - } - - if bid.Price > auctionPrice { - error = fmt.Errorf("Cannot close auction, bidder has a higher price: %v", err) - } - - } else { - - hash, err := ctx.GetStub().GetPrivateDataHash(collection, bidKey) - if err != nil { - return fmt.Errorf("failed to read bid hash from collection: %v", err) - } - if hash == nil { - return fmt.Errorf("bid hash does not exist: %s", bidKey) - } - } - } - } - - return error -} diff --git a/auction-dutch/chaincode-go-auditor/smart-contract/utils.go b/auction-dutch/chaincode-go-auditor/smart-contract/utils.go deleted file mode 100644 index 4b73a7f3..00000000 --- a/auction-dutch/chaincode-go-auditor/smart-contract/utils.go +++ /dev/null @@ -1,203 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package auction - -import ( - "encoding/base64" - "fmt" - - "github.com/hyperledger/fabric-chaincode-go/v2/shim" - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" - "github.com/hyperledger/fabric-protos-go-apiv2/common" - "github.com/hyperledger/fabric-protos-go-apiv2/msp" - "google.golang.org/protobuf/proto" -) - -func (s *SmartContract) GetSubmittingClientIdentity(ctx contractapi.TransactionContextInterface) (string, error) { - - b64ID, err := ctx.GetClientIdentity().GetID() - if err != nil { - return "", fmt.Errorf("Failed to read clientID: %v", err) - } - decodeID, err := base64.StdEncoding.DecodeString(b64ID) - if err != nil { - return "", fmt.Errorf("failed to base64 decode clientID: %v", err) - } - return string(decodeID), nil -} - -// getCollectionName is an internal helper function to get collection of submitting client identity. -func getCollectionName(ctx contractapi.TransactionContextInterface) (string, error) { - - // Get the MSP ID of submitting client identity - clientMSPID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return "", fmt.Errorf("failed to get verified MSPID: %v", err) - } - - // Create the collection name - orgCollection := "_implicit_org_" + clientMSPID - - return orgCollection, nil -} - -// verifyClientOrgMatchesPeerOrg is an internal function used to verify that client org id matches peer org id. -func verifyClientOrgMatchesPeerOrg(ctx contractapi.TransactionContextInterface) error { - - clientMSPID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed getting the client's MSPID: %v", err) - } - peerMSPID, err := shim.GetMSPID() - if err != nil { - return fmt.Errorf("failed getting the peer's MSPID: %v", err) - } - - if clientMSPID != peerMSPID { - return fmt.Errorf("client from org %v is not authorized to read or write private data from an org %v peer", clientMSPID, peerMSPID) - } - - return nil -} - -func contains(sli []string, str string) bool { - for _, a := range sli { - if a == str { - return true - } - } - return false -} - -func setAssetStateBasedEndorsement(ctx contractapi.TransactionContextInterface, assetId string, mspids []string, auditor bool) error { - - principals := make([]*msp.MSPPrincipal, len(mspids)) - participantSigsPolicy := make([]*common.SignaturePolicy, len(mspids)) - - for i, id := range mspids { - principal, err := proto.Marshal( - &msp.MSPRole{ - Role: msp.MSPRole_PEER, - MspIdentifier: id, - }, - ) - if err != nil { - return err - } - principals[i] = &msp.MSPPrincipal{ - PrincipalClassification: msp.MSPPrincipal_ROLE, - Principal: principal, - } - participantSigsPolicy[i] = &common.SignaturePolicy{ - Type: &common.SignaturePolicy_SignedBy{ - SignedBy: int32(i), - }, - } - } - - if auditor == false { - // create the defalt policy for an auction without an auditor - - policy := &common.SignaturePolicyEnvelope{ - Version: 0, - Rule: &common.SignaturePolicy{ - Type: &common.SignaturePolicy_NOutOf_{ - NOutOf: &common.SignaturePolicy_NOutOf{ - N: int32(len(mspids)), - Rules: participantSigsPolicy, - }, - }, - }, - Identities: principals, - } - - spBytes, err := proto.Marshal(policy) - if err != nil { - return err - } - err = ctx.GetStub().SetStateValidationParameter(assetId, spBytes) - if err != nil { - return fmt.Errorf("failed to set validation parameter on auction: %v", err) - } - } else { - - // create the defalt policy for an auction with an auditor - - // create the auditor identity and signature policy - auditorMSP, err := proto.Marshal( - &msp.MSPRole{ - Role: msp.MSPRole_PEER, - MspIdentifier: "Org3MSP", - }, - ) - if err != nil { - return err - } - principals = append(principals, &msp.MSPPrincipal{ - PrincipalClassification: msp.MSPPrincipal_ROLE, - Principal: auditorMSP, - }, - ) - // Create the policies in case the auditor is needed. In this case, an - // auditor and 1 participant can update the auction. - auditorPolicies := make([]*common.SignaturePolicy, 2) - auditorPolicies[0] = &common.SignaturePolicy{ - Type: &common.SignaturePolicy_SignedBy{ - SignedBy: int32(len(principals) - 1), - }, - } - auditorPolicies[1] = &common.SignaturePolicy{ - Type: &common.SignaturePolicy_NOutOf_{ - NOutOf: &common.SignaturePolicy_NOutOf{ - N: 1, - Rules: participantSigsPolicy, - }, - }, - } - - // The auditor policy below is equivilent to AND(auditor, OR(participants)) - policies := make([]*common.SignaturePolicy, 2) - policies[0] = &common.SignaturePolicy{ - Type: &common.SignaturePolicy_NOutOf_{ - NOutOf: &common.SignaturePolicy_NOutOf{ - N: 2, - Rules: auditorPolicies, - }, - }, - } - // Participants can also update the auction without an auditor - policies[1] = &common.SignaturePolicy{ - Type: &common.SignaturePolicy_NOutOf_{ - NOutOf: &common.SignaturePolicy_NOutOf{ - N: int32(len(mspids)), - Rules: participantSigsPolicy, - }, - }, - } - // Either the auditor policy or the participant policy can update - // the auction - policy := &common.SignaturePolicyEnvelope{ - Version: 0, - Rule: &common.SignaturePolicy{ - Type: &common.SignaturePolicy_NOutOf_{ - NOutOf: &common.SignaturePolicy_NOutOf{ - N: 1, - Rules: policies, - }, - }, - }, - Identities: principals, - } - spBytes, err := proto.Marshal(policy) - if err != nil { - return err - } - err = ctx.GetStub().SetStateValidationParameter(assetId, spBytes) - if err != nil { - return fmt.Errorf("failed to set validation parameter on auction: %v", err) - } - } - return nil -} diff --git a/auction-dutch/chaincode-go-auditor/smartContract.go b/auction-dutch/chaincode-go-auditor/smartContract.go deleted file mode 100644 index f5feca58..00000000 --- a/auction-dutch/chaincode-go-auditor/smartContract.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "log" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" - auction "github.com/hyperledger/fabric-samples/auction/dutch-auction/chaincode-go-auditor/smart-contract" -) - -func main() { - auctionSmartContract, err := contractapi.NewChaincode(&auction.SmartContract{}) - if err != nil { - log.Panicf("Error creating auction chaincode: %v", err) - } - - if err := auctionSmartContract.Start(); err != nil { - log.Panicf("Error starting auction chaincode: %v", err) - } -} diff --git a/auction-dutch/chaincode-go/go.mod b/auction-dutch/chaincode-go/go.mod deleted file mode 100644 index 24f1f572..00000000 --- a/auction-dutch/chaincode-go/go.mod +++ /dev/null @@ -1,28 +0,0 @@ -module github.com/hyperledger/fabric-samples/auction/dutch-auction/chaincode-go - -go 1.22.0 - -require ( - github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0 - github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0 - github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 - google.golang.org/protobuf v1.36.1 -) - -require ( - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xeipuuv/gojsonschema v1.2.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect - google.golang.org/grpc v1.67.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/auction-dutch/chaincode-go/go.sum b/auction-dutch/chaincode-go/go.sum deleted file mode 100644 index fa4d3b24..00000000 --- a/auction-dutch/chaincode-go/go.sum +++ /dev/null @@ -1,61 +0,0 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0 h1:IhkHfrl5X/fVnmB6pWeCYCdIJRi9bxj+WTnVN8DtW3c= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0/go.mod h1:PHHaFffjw7p7n9bmCfcm7RqDqYdivNEsJdiNIKZo5Lk= -github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0 h1:rmUoBmciB0GL/miqcbJmJbgp5QTWoJUrZo+CNxrNLF4= -github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0/go.mod h1:FeWeO/jwGjiME7ak3GufqKIcwkejtzrDG4QxbfKydWs= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 h1:YJrd+gMaeY0/vsN0aS0QkEKTivGoUnSRIXxGJ7KI+Pc= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4/go.mod h1:bau/6AJhvEcu9GKKYHlDXAxXKzYNfhP6xu2GXuxEcFk= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= -google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= -google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/auction-dutch/chaincode-go/smart-contract/auction.go b/auction-dutch/chaincode-go/smart-contract/auction.go deleted file mode 100644 index 90a9097b..00000000 --- a/auction-dutch/chaincode-go/smart-contract/auction.go +++ /dev/null @@ -1,513 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package auction - -import ( - "bytes" - "crypto/sha256" - "encoding/json" - "errors" - "fmt" - "sort" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -type SmartContract struct { - contractapi.Contract -} - -// Auction data -type Auction struct { - Type string `json:"objectType"` - ItemSold string `json:"item"` - Seller string `json:"seller"` - Quantity int `json:"quantity"` - Orgs []string `json:"organizations"` - PrivateBids map[string]BidHash `json:"privateBids"` - RevealedBids map[string]FullBid `json:"revealedBids"` - Winners []Winners `json:"winners"` - Price int `json:"price"` - Status string `json:"status"` - Auditor bool `json:"auditor"` -} - -// FullBid is the structure of a revealed bid -type FullBid struct { - Type string `json:"objectType"` - Quantity int `json:"quantity"` - Price int `json:"price"` - Org string `json:"org"` - Buyer string `json:"buyer"` -} - -// BidHash is the structure of a private bid -type BidHash struct { - Org string `json:"org"` - Hash string `json:"hash"` -} - -// Winners stores the winners of the auction -type Winners struct { - Buyer string `json:"buyer"` - Quantity int `json:"quantity"` -} - -const bidKeyType = "bid" - -// CreateAuction creates on auction on the public channel. The identity that -// submits the transacion becomes the seller of the auction -func (s *SmartContract) CreateAuction(ctx contractapi.TransactionContextInterface, auctionID string, itemsold string, quantity int, withAuditor string) error { - - // get ID of submitting client - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - // get org of submitting client - clientOrgID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - auditor := false - - if withAuditor == "withAuditor" { - auditor = true - } - - // Create auction - bidders := make(map[string]BidHash) - revealedBids := make(map[string]FullBid) - - auction := Auction{ - Type: "auction", - ItemSold: itemsold, - Quantity: quantity, - Price: 0, - Seller: clientID, - Orgs: []string{clientOrgID}, - PrivateBids: bidders, - RevealedBids: revealedBids, - Winners: []Winners{}, - Status: "open", - Auditor: auditor, - } - - auctionJSON, err := json.Marshal(auction) - if err != nil { - return err - } - - // put auction into state - err = ctx.GetStub().PutState(auctionID, auctionJSON) - if err != nil { - return fmt.Errorf("failed to put auction in public data: %v", err) - } - - // set the seller of the auction as an endorser - err = setAssetStateBasedEndorsement(ctx, auctionID, []string{clientOrgID}, auditor) - if err != nil { - return fmt.Errorf("failed setting state based endorsement for new organization: %v", err) - } - - return nil -} - -// Bid is used to add a users bid to the auction. The bid is stored in the private -// data collection on the peer of the bidder's organization. The function returns -// the transaction ID so that users can identify and query their bid -func (s *SmartContract) Bid(ctx contractapi.TransactionContextInterface, auctionID string) (string, error) { - - // get bid from transient map - transientMap, err := ctx.GetStub().GetTransient() - if err != nil { - return "", fmt.Errorf("error getting transient: %v", err) - } - - bidJSON, ok := transientMap["bid"] - if !ok { - return "", errors.New("bid key not found in the transient map") - } - - // get the implicit collection name using the bidder's organization ID - collection, err := getCollectionName(ctx) - if err != nil { - return "", fmt.Errorf("failed to get implicit collection name: %v", err) - } - - // the bidder has to target their peer to store the bid - err = verifyClientOrgMatchesPeerOrg(ctx) - if err != nil { - return "", fmt.Errorf("cannot store bid on this peer, not a member of this org: %v", err) - } - - // the transaction ID is used as a unique index for the bid - txID := ctx.GetStub().GetTxID() - - // create a composite key using the transaction ID - bidKey, err := ctx.GetStub().CreateCompositeKey(bidKeyType, []string{auctionID, txID}) - if err != nil { - return "", fmt.Errorf("failed to create composite key: %v", err) - } - - // put the bid into the organization's implicit data collection - err = ctx.GetStub().PutPrivateData(collection, bidKey, bidJSON) - if err != nil { - return "", fmt.Errorf("failed to input price into collection: %v", err) - } - - // return the trannsaction ID so that the uset can identify their bid - return txID, nil -} - -// SubmitBid is used by the bidder to add the hash of that bid stored in private data to the -// auction. Note that this function alters the auction in private state, and needs -// to meet the auction endorsement policy. Transaction ID is used identify the bid -func (s *SmartContract) SubmitBid(ctx contractapi.TransactionContextInterface, auctionID string, txID string) error { - - // get the MSP ID of the bidder's org - clientOrgID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed to get client MSP ID: %v", err) - } - - // get the auction from public state - auction, err := s.QueryAuction(ctx, auctionID) - if err != nil { - return fmt.Errorf("failed to get auction from public state %v", err) - } - - // the auction needs to be open for users to add their bid - status := auction.Status - if status != "open" { - return fmt.Errorf("cannot join closed or ended auction") - } - - // get the inplicit collection name of bidder's org - collection, err := getCollectionName(ctx) - if err != nil { - return fmt.Errorf("failed to get implicit collection name: %v", err) - } - - // use the transaction ID passed as a parameter to create composite bid key - bidKey, err := ctx.GetStub().CreateCompositeKey(bidKeyType, []string{auctionID, txID}) - if err != nil { - return fmt.Errorf("failed to create composite key: %v", err) - } - - // get the hash of the bid if found in private collection - bidHash, err := ctx.GetStub().GetPrivateDataHash(collection, bidKey) - if err != nil { - return fmt.Errorf("failed to read bid bash from collection: %v", err) - } - if bidHash == nil { - return fmt.Errorf("bid hash does not exist: %s", bidKey) - } - - // store the hash along with the bidder's organization - newHash := BidHash{ - Org: clientOrgID, - Hash: fmt.Sprintf("%x", bidHash), - } - - auction.PrivateBids[bidKey] = newHash - - // Add the bidding organization to the list of participating organization's if it is not already - orgs := auction.Orgs - if !(contains(orgs, clientOrgID)) { - newOrgs := append(orgs, clientOrgID) - auction.Orgs = newOrgs - - err = setAssetStateBasedEndorsement(ctx, auctionID, newOrgs, auction.Auditor) - if err != nil { - return fmt.Errorf("failed setting state based endorsement for new organization: %v", err) - } - } - - newAuctionJSON, _ := json.Marshal(auction) - - err = ctx.GetStub().PutState(auctionID, newAuctionJSON) - if err != nil { - return fmt.Errorf("failed to update auction: %v", err) - } - - return nil -} - -// RevealBid is used by a bidder to reveal their bid after the auction is closed -func (s *SmartContract) RevealBid(ctx contractapi.TransactionContextInterface, auctionID string, txID string) error { - - // get bid from transient map - transientMap, err := ctx.GetStub().GetTransient() - if err != nil { - return fmt.Errorf("error getting transient: %v", err) - } - - transientBidJSON, ok := transientMap["bid"] - if !ok { - return fmt.Errorf("bid key not found in the transient map") - } - - // get implicit collection name of organization ID - collection, err := getCollectionName(ctx) - if err != nil { - return fmt.Errorf("failed to get implicit collection name: %v", err) - } - - // use transaction ID to create composit bid key - bidKey, err := ctx.GetStub().CreateCompositeKey(bidKeyType, []string{auctionID, txID}) - if err != nil { - return fmt.Errorf("failed to create composite key: %v", err) - } - - // get bid hash of bid if private bid on the public ledger - bidHash, err := ctx.GetStub().GetPrivateDataHash(collection, bidKey) - if err != nil { - return fmt.Errorf("failed to read bid bash from collection: %v", err) - } - if bidHash == nil { - return fmt.Errorf("bid hash does not exist: %s", bidKey) - } - - // get auction from public state - auction, err := s.QueryAuction(ctx, auctionID) - if err != nil { - return fmt.Errorf("failed to get auction from public state %v", err) - } - - // Complete a series of three checks before we add the bid to the auction - - // check 1: check that the auction is closed. We cannot reveal an - // bid to an open auction - status := auction.Status - if status != "closed" { - return fmt.Errorf("cannot reveal bid for open or ended auction") - } - - // check 2: check that hash of revealed bid matches hash of private bid - // on the public ledger. This checks that the bidder is telling the truth - // about the value of their bid - - hash := sha256.New() - hash.Write(transientBidJSON) - calculatedBidJSONHash := hash.Sum(nil) - - // verify that the hash of the passed immutable properties matches the on-chain hash - if !bytes.Equal(calculatedBidJSONHash, bidHash) { - return fmt.Errorf("hash %x for bid JSON %s does not match hash in auction: %x", - calculatedBidJSONHash, - transientBidJSON, - bidHash, - ) - } - - // check 3; check hash of relealed bid matches hash of private bid that was - // added earlier. This ensures that the bid has not changed since it - // was added to the auction - - privateBidHashString := auction.PrivateBids[bidKey].Hash - - onChainBidHashString := fmt.Sprintf("%x", bidHash) - if privateBidHashString != onChainBidHashString { - return fmt.Errorf("hash %s for bid JSON %s does not match hash in auction: %s, bidder must have changed bid", - privateBidHashString, - transientBidJSON, - onChainBidHashString, - ) - } - - // we can add the bid to the auction if all checks have passed - type transientBidInput struct { - Quantity int `json:"quantity"` - Price int `json:"price"` - Org string `json:"org"` - Buyer string `json:"buyer"` - } - - // unmarshal bid imput - var bidInput transientBidInput - err = json.Unmarshal(transientBidJSON, &bidInput) - if err != nil { - return fmt.Errorf("failed to unmarshal JSON: %v", err) - } - - // get ID of submitting client - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - // marshal transient parameters and ID and MSPID into bid object - newBid := FullBid{ - Type: bidKeyType, - Quantity: bidInput.Quantity, - Price: bidInput.Price, - Org: bidInput.Org, - Buyer: bidInput.Buyer, - } - - // check 4: make sure that the transaction is being submitted is the bidder - if bidInput.Buyer != clientID { - return fmt.Errorf("permission denied, client id %v is not the owner of the bid", clientID) - } - - revealedBids := auction.RevealedBids - revealedBids[bidKey] = newBid - auction.RevealedBids = revealedBids - - auctionJSON, _ := json.Marshal(auction) - - // put auction with bid added back into state - err = ctx.GetStub().PutState(auctionID, auctionJSON) - if err != nil { - return fmt.Errorf("failed to update auction: %v", err) - } - - return nil -} - -// CloseAuction can be used by the seller to close the auction. This prevents -// bids from being added to the auction, and allows users to reveal their bid -func (s *SmartContract) CloseAuction(ctx contractapi.TransactionContextInterface, auctionID string) error { - - // get auction from public state - auction, err := s.QueryAuction(ctx, auctionID) - if err != nil { - return fmt.Errorf("failed to get auction from public state %v", err) - } - - // the auction can only be closed by the seller - - // get ID of submitting client - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - seller := auction.Seller - if seller != clientID { - return fmt.Errorf("auction can only be closed by seller: %v", err) - } - - status := auction.Status - if status != "open" { - return fmt.Errorf("cannot close auction that is not open") - } - - auction.Status = string("closed") - - closedAuctionJSON, _ := json.Marshal(auction) - - err = ctx.GetStub().PutState(auctionID, closedAuctionJSON) - if err != nil { - return fmt.Errorf("failed to close auction: %v", err) - } - - return nil -} - -// EndAuction both changes the auction status to closed and calculates the winners -// of the auction -func (s *SmartContract) EndAuction(ctx contractapi.TransactionContextInterface, auctionID string) error { - - // get auction from public state - auction, err := s.QueryAuction(ctx, auctionID) - if err != nil { - return fmt.Errorf("failed to get auction from public state %v", err) - } - - // Check that the auction is being ended by the seller - - // get ID of submitting client - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - seller := auction.Seller - if seller != clientID { - return fmt.Errorf("auction can only be ended by seller: %v", err) - } - - status := auction.Status - if status != "closed" { - return fmt.Errorf("can only end a closed auction") - } - - // get the list of revealed bids - - revealedBidMap := auction.RevealedBids - if len(auction.RevealedBids) == 0 { - return fmt.Errorf("no bids have been revealed, cannot end auction: %v", err) - } - - // sort the map of revealed bids to make it easier to calculate winners - // if bids are tied, fill smaller bids first - var bidders []FullBid - - for _, bid := range revealedBidMap { - bidders = append(bidders, bid) - } - - sort.Slice(bidders, func(p, q int) bool { - if bidders[p].Price > bidders[q].Price { - return true - } - if bidders[p].Price < bidders[q].Price { - return false - } - return bidders[p].Quantity < bidders[q].Quantity - }) - - i := 0 - remainingQuantity := auction.Quantity - - // calculate the winners - for remainingQuantity > 0 { - - // create the next winning bid - winner := Winners{ - Buyer: bidders[i].Buyer, - Quantity: bidders[i].Quantity, - } - - // add them to the list of winners and change the winning price - auction.Winners = append(auction.Winners, winner) - auction.Price = bidders[i].Price - - // Calculate the quantity that goes to the winner - // if there is sufficient quantity to give them the full bid - if remainingQuantity > bidders[i].Quantity { - remainingQuantity = remainingQuantity - bidders[i].Quantity - - // if there is not, give the remainder - } else { - auction.Winners[i].Quantity = remainingQuantity - remainingQuantity = 0 - } - i++ - if i == len(bidders) { - remainingQuantity = 0 - } - } - - // check if there is a winning bid that has yet to be revealed - err = checkForHigherBid(ctx, auction.Price, auction.RevealedBids, auction.PrivateBids) - if err != nil { - return fmt.Errorf("cannot end auction: %v", err) - } - - auction.Status = "ended" - - endedAuctionJSON, _ := json.Marshal(auction) - - err = ctx.GetStub().PutState(auctionID, endedAuctionJSON) - if err != nil { - return fmt.Errorf("failed to end auction: %v", err) - } - return nil -} diff --git a/auction-dutch/chaincode-go/smart-contract/auctionQueries.go b/auction-dutch/chaincode-go/smart-contract/auctionQueries.go deleted file mode 100644 index d5024fb4..00000000 --- a/auction-dutch/chaincode-go/smart-contract/auctionQueries.go +++ /dev/null @@ -1,137 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package auction - -import ( - "encoding/json" - "errors" - "fmt" - - "github.com/hyperledger/fabric-chaincode-go/v2/shim" - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -// QueryAuction allows all members of the channel to read a public auction -func (s *SmartContract) QueryAuction(ctx contractapi.TransactionContextInterface, auctionID string) (*Auction, error) { - - auctionJSON, err := ctx.GetStub().GetState(auctionID) - if err != nil { - return nil, fmt.Errorf("failed to get auction object %v: %v", auctionID, err) - } - if auctionJSON == nil { - return nil, errors.New("auction does not exist") - } - - var auction *Auction - err = json.Unmarshal(auctionJSON, &auction) - if err != nil { - return nil, err - } - - return auction, nil -} - -// QueryBid allows the submitter of the bid to read their bid from public state -func (s *SmartContract) QueryBid(ctx contractapi.TransactionContextInterface, auctionID string, txID string) (*FullBid, error) { - - err := verifyClientOrgMatchesPeerOrg(ctx) - if err != nil { - return nil, fmt.Errorf("failed to get implicit collection name: %v", err) - } - - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return nil, fmt.Errorf("failed to get client identity %v", err) - } - - collection, err := getCollectionName(ctx) - if err != nil { - return nil, fmt.Errorf("failed to get implicit collection name: %v", err) - } - - bidKey, err := ctx.GetStub().CreateCompositeKey(bidKeyType, []string{auctionID, txID}) - if err != nil { - return nil, fmt.Errorf("failed to create composite key: %v", err) - } - - bidJSON, err := ctx.GetStub().GetPrivateData(collection, bidKey) - if err != nil { - return nil, fmt.Errorf("failed to get bid %v: %v", bidKey, err) - } - if bidJSON == nil { - return nil, fmt.Errorf("bid %v does not exist", bidKey) - } - - var bid *FullBid - err = json.Unmarshal(bidJSON, &bid) - if err != nil { - return nil, err - } - - // check that the client querying the bid is the bid owner - if bid.Buyer != clientID { - return nil, fmt.Errorf("permission denied, client id %v is not the owner of the bid", clientID) - } - - return bid, nil -} - -// checkForHigherBid is an internal function that is used to determine if a winning bid has yet to be revealed -func checkForHigherBid(ctx contractapi.TransactionContextInterface, auctionPrice int, revealedBidders map[string]FullBid, bidders map[string]BidHash) error { - - // Get MSP ID of peer org - peerMSPID, err := shim.GetMSPID() - if err != nil { - return fmt.Errorf("failed getting the peer's MSPID: %v", err) - } - - var error error - error = nil - - for bidKey, privateBid := range bidders { - - if _, bidInAuction := revealedBidders[bidKey]; bidInAuction { - - // bid is already revealed, no action to take - - } else { - - collection := "_implicit_org_" + privateBid.Org - - if privateBid.Org == peerMSPID { - - bidJSON, err := ctx.GetStub().GetPrivateData(collection, bidKey) - if err != nil { - return fmt.Errorf("failed to get bid %v: %v", bidKey, err) - } - if bidJSON == nil { - return fmt.Errorf("bid %v does not exist", bidKey) - } - - var bid *FullBid - err = json.Unmarshal(bidJSON, &bid) - if err != nil { - return err - } - - if bid.Price > auctionPrice { - error = fmt.Errorf("cannot close auction, bidder has a higher price: %v", err) - } - - } else { - - hash, err := ctx.GetStub().GetPrivateDataHash(collection, bidKey) - if err != nil { - return fmt.Errorf("failed to read bid hash from collection: %v", err) - } - if hash == nil { - return fmt.Errorf("bid hash does not exist: %s", bidKey) - } - } - } - } - - return error -} diff --git a/auction-dutch/chaincode-go/smart-contract/utils.go b/auction-dutch/chaincode-go/smart-contract/utils.go deleted file mode 100644 index 351826fb..00000000 --- a/auction-dutch/chaincode-go/smart-contract/utils.go +++ /dev/null @@ -1,205 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package auction - -import ( - "encoding/base64" - "fmt" - - "github.com/hyperledger/fabric-chaincode-go/v2/shim" - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" - "github.com/hyperledger/fabric-protos-go-apiv2/common" - "github.com/hyperledger/fabric-protos-go-apiv2/msp" - "google.golang.org/protobuf/proto" -) - -func (s *SmartContract) GetSubmittingClientIdentity(ctx contractapi.TransactionContextInterface) (string, error) { - - b64ID, err := ctx.GetClientIdentity().GetID() - if err != nil { - return "", fmt.Errorf("failed to read clientID: %v", err) - } - decodeID, err := base64.StdEncoding.DecodeString(b64ID) - if err != nil { - return "", fmt.Errorf("failed to base64 decode clientID: %v", err) - } - return string(decodeID), nil -} - -// getCollectionName is an internal helper function to get collection of submitting client identity. -func getCollectionName(ctx contractapi.TransactionContextInterface) (string, error) { - - // Get the MSP ID of submitting client identity - clientMSPID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return "", fmt.Errorf("failed to get verified MSPID: %v", err) - } - - // Create the collection name - orgCollection := "_implicit_org_" + clientMSPID - - return orgCollection, nil -} - -// verifyClientOrgMatchesPeerOrg is an internal function used to verify that client org id matches peer org id. -func verifyClientOrgMatchesPeerOrg(ctx contractapi.TransactionContextInterface) error { - - clientMSPID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed getting the client's MSPID: %v", err) - } - peerMSPID, err := shim.GetMSPID() - if err != nil { - return fmt.Errorf("failed getting the peer's MSPID: %v", err) - } - - if clientMSPID != peerMSPID { - return fmt.Errorf("client from org %v is not authorized to read or write private data from an org %v peer", clientMSPID, peerMSPID) - } - - return nil -} - -func contains(sli []string, str string) bool { - for _, a := range sli { - if a == str { - return true - } - } - return false -} - -func setAssetStateBasedEndorsement(ctx contractapi.TransactionContextInterface, assetId string, mspids []string, auditor bool) error { - - principals := make([]*msp.MSPPrincipal, len(mspids)) - participantSigsPolicy := make([]*common.SignaturePolicy, len(mspids)) - - for i, id := range mspids { - principal, err := proto.Marshal( - &msp.MSPRole{ - Role: msp.MSPRole_PEER, - MspIdentifier: id, - }, - ) - if err != nil { - return err - } - principals[i] = &msp.MSPPrincipal{ - PrincipalClassification: msp.MSPPrincipal_ROLE, - Principal: principal, - } - participantSigsPolicy[i] = &common.SignaturePolicy{ - Type: &common.SignaturePolicy_SignedBy{ - SignedBy: int32(i), - }, - } - } - - if !auditor { - // create the defalt policy for an auction without an auditor - - policy := &common.SignaturePolicyEnvelope{ - Version: 0, - Rule: &common.SignaturePolicy{ - Type: &common.SignaturePolicy_NOutOf_{ - NOutOf: &common.SignaturePolicy_NOutOf{ - N: int32(len(mspids)), - Rules: participantSigsPolicy, - }, - }, - }, - Identities: principals, - } - - spBytes, err := proto.Marshal(policy) - if err != nil { - return err - } - err = ctx.GetStub().SetStateValidationParameter(assetId, spBytes) - if err != nil { - return fmt.Errorf("failed to set validation parameter on auction: %v", err) - } - } else { - - // create the defalt policy for an auction with an auditor - - // create the auditor identity and signature policy - auditorMSP, err := proto.Marshal( - &msp.MSPRole{ - Role: msp.MSPRole_PEER, - MspIdentifier: "Org3MSP", - }, - ) - if err != nil { - return err - } - principals = append(principals, &msp.MSPPrincipal{ - PrincipalClassification: msp.MSPPrincipal_ROLE, - Principal: auditorMSP, - }, - ) - // Create the policies in case the auditor is needed. In this case, an - // auditor and 1 participant can update the auction. - auditorPolicies := make([]*common.SignaturePolicy, 2) - auditorPolicies[0] = &common.SignaturePolicy{ - Type: &common.SignaturePolicy_SignedBy{ - SignedBy: int32(len(principals) - 1), - }, - } - auditorPolicies[1] = &common.SignaturePolicy{ - Type: &common.SignaturePolicy_NOutOf_{ - NOutOf: &common.SignaturePolicy_NOutOf{ - N: 1, - Rules: participantSigsPolicy, - }, - }, - } - - // For two organizations, the auditor policy below is equivilent to - // AND(auditor, OR(Org1, Org2)) - policies := make([]*common.SignaturePolicy, 2) - policies[0] = &common.SignaturePolicy{ - Type: &common.SignaturePolicy_NOutOf_{ - NOutOf: &common.SignaturePolicy_NOutOf{ - N: 2, - Rules: auditorPolicies, - }, - }, - } - // Participants can also update the auction without an auditor - policies[1] = &common.SignaturePolicy{ - Type: &common.SignaturePolicy_NOutOf_{ - NOutOf: &common.SignaturePolicy_NOutOf{ - N: int32(len(mspids)), - Rules: participantSigsPolicy, - }, - }, - } - // Either the auditor policy or the participant policy can update - // the auction. For example, for two organizations, the full policy would be - // equivilent to OR(AND(Org1, Org2),AND(auditor, OR(Org1, Org2))) - policy := &common.SignaturePolicyEnvelope{ - Version: 0, - Rule: &common.SignaturePolicy{ - Type: &common.SignaturePolicy_NOutOf_{ - NOutOf: &common.SignaturePolicy_NOutOf{ - N: 1, - Rules: policies, - }, - }, - }, - Identities: principals, - } - spBytes, err := proto.Marshal(policy) - if err != nil { - return err - } - err = ctx.GetStub().SetStateValidationParameter(assetId, spBytes) - if err != nil { - return fmt.Errorf("failed to set validation parameter on auction: %v", err) - } - } - return nil -} diff --git a/auction-dutch/chaincode-go/smartContract.go b/auction-dutch/chaincode-go/smartContract.go deleted file mode 100644 index 939a519c..00000000 --- a/auction-dutch/chaincode-go/smartContract.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "log" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" - auction "github.com/hyperledger/fabric-samples/auction/dutch-auction/chaincode-go/smart-contract" -) - -func main() { - auctionSmartContract, err := contractapi.NewChaincode(&auction.SmartContract{}) - if err != nil { - log.Panicf("Error creating auction chaincode: %v", err) - } - - if err := auctionSmartContract.Start(); err != nil { - log.Panicf("Error starting auction chaincode: %v", err) - } -} diff --git a/auction-simple/README.md b/auction-simple/README.md deleted file mode 100644 index e6bb6308..00000000 --- a/auction-simple/README.md +++ /dev/null @@ -1,410 +0,0 @@ -## Simple blind auction sample - -The simple blind auction sample uses Hyperledger Fabric to run an auction where bids are kept private until the auction period is over. Instead of displaying the full bid on the public ledger, buyers can only see hashes of other bids while bidding is underway. This prevents buyers from changing their bids in response to bids submitted by others. After the bidding period ends, participants reveal their bid to try to win the auction. The organizations participating in the auction verify that a revealed bid matches the hash on the public ledger. Whichever has the highest bid wins. - -A user that wants to sell one item can use the smart contract to create an auction. The auction is stored on the channel ledger and can be read by all channel members. The auctions created by the smart contract are run in three steps: -1. Each auction is created with the status **open**. While the auction is open, buyers can add new bids to the auction. The full bids of each buyer are stored in the implicit private data collections of their organization. After the bid is created, the bidder can submit the hash of the bid to the auction. A bid is added to the auction in two steps because the transaction that creates the bid only needs to be endorsed by a peer of the bidders organization, while a transaction that updates the auction may need to be endorsed by multiple organizations. When the bid is added to the auction, the bidder's organization is added to the list of organizations that need to endorse any updates to the auction. -2. The auction is **closed** to prevent additional bids from being added to the auction. After the auction is closed, bidders that submitted bids to the auction can reveal their full bid. Only revealed bids can win the auction. -3. The auction is **ended** to calculate the winner from the set of revealed bids. All organizations participating in the auction calculate the price that clears the auction and the winning bid. The seller can end the auction only if all bidding organizations endorse the same winner and price. - -Before endorsing the transaction that ends the auction, each organization queries the implicit private data collection on their peers to check if any organization member has a winning bid that has not yet been revealed. If a winning bid is found, the organization will withhold their endorsement and prevent the auction from being closed. This prevents the seller from ending the auction prematurely, or colluding with buyers to end the auction at an artificially low price. - -The sample uses several Fabric features to make the auction private and secure. Bids are stored in private data collections to prevent bids from being distributed to other peers in the channel. When bidding is closed, the auction smart contract uses the `GetPrivateDataHash()` API to verify that the bid stored in private data is the same bid that is being revealed. State based endorsement is used to add the organization of each bidder to the auction endorsement policy. The smart contract uses the `GetClientIdentity.GetID()` API to ensure that only the potential buyer can read their bid from private state and only the seller can close or end the auction. - -This tutorial uses the auction smart contract in a scenario where one seller wants to auction a painting. Four potential buyers from two different organizations will submit bids to the auction and try to win the auction. - -## Deploy the chaincode - -We will run the auction smart contract using the Fabric test network. Open a command terminal and navigate to the test network directory: -``` -cd fabric-samples/test-network -``` - -You can then run the following command to deploy the test network. -``` -./network.sh up createChannel -ca -``` - -Note that we use the `-ca` flag to deploy the network using certificate authorities. We will use the CA to register and enroll our sellers and buyers. - -Run the following command to deploy the auction smart contract. We will override the default endorsement policy to allow any channel member to create an auction without requiring an endorsement from another organization. -``` -./network.sh deployCC -ccn auction -ccp ../auction-simple/chaincode-go/ -ccl go -ccep "OR('Org1MSP.peer','Org2MSP.peer')" -``` - -## Install the application dependencies - -We will interact with the auction smart contract through a set of Node.js applications. Change into the `application-javascript` directory: -``` -cd fabric-samples/auction-simple/application-javascript -``` - -From this directory, run the following command to download the application dependencies: -``` -npm install -``` - -## Register and enroll the application identities - -To interact with the network, you will need to enroll the Certificate Authority administrators of Org1 and Org2. You can use the `enrollAdmin.js` program for this task. Run the following command to enroll the Org1 admin: -``` -node enrollAdmin.js org1 -``` -You should see the logs of the admin wallet being created on your local file system. Now run the command to enroll the CA admin of Org2: -``` -node enrollAdmin.js org2 -``` - -We can use the CA admins of both organizations to register and enroll the identities of the seller that will create the auction and the bidders who will try to purchase the painting. - -Run the following command to register and enroll the seller identity that will create the auction. The seller will belong to Org1. -``` -node registerEnrollUser.js org1 seller -``` - -You should see the logs of the seller wallet being created as well. Run the following commands to register and enroll 2 bidders from Org1 and another 2 bidders from Org2: -``` -node registerEnrollUser.js org1 bidder1 -node registerEnrollUser.js org1 bidder2 -node registerEnrollUser.js org2 bidder3 -node registerEnrollUser.js org2 bidder4 -``` - -## Create the auction - -The seller from Org1 would like to create an auction to sell a vintage Matchbox painting. Run the following command to use the seller wallet to run the `createAuction.js` application. The program will submit a transaction to the network that creates the auction on the channel ledger. The organization and identity name are passed to the application to use the wallet that was created by the `registerEnrollUser.js` application. The seller needs to provide an ID for the auction and the item to be sold to create the auction: -``` -node createAuction.js org1 seller PaintingAuction painting -``` - -After the transaction is complete, the `createAuction.js` application will query the auction stored in the public channel ledger: -``` -*** Result: Auction: { - "objectType": "auction", - "item": "painting", - "seller": "x509::CN=seller,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "organizations": [ - "Org1MSP" - ], - "privateBids": {}, - "revealedBids": {}, - "winner": "", - "price": 0, - "status": "open" -} -``` -The smart contract uses the `GetClientIdentity().GetID()` API to read the identity that creates the auction and defines that identity as the auction `"seller"`. The seller is identified by the name and issuer of the seller's certificate. - -## Bid on the auction - -We can now use the bidder wallets to submit bids to the auction: - -### Bid as bidder1 - -Bidder1 will create a bid to purchase the painting for 800 dollars. -``` -node bid.js org1 bidder1 PaintingAuction 800 -``` - -The application will query the bid after it is created: -``` -*** Result: Bid: { - "objectType": "bid", - "price": 800, - "org": "Org1MSP", - "bidder": "x509::CN=bidder1,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US" -} -``` - -The bid is stored in the Org1 implicit data collection. The `"bidder"` parameter is the information from the certificate of the user that created the bid. Only this identity will be able can query the bid from private state or reveal the bid during the auction. - -The `bid.js` application also prints the bidID: -``` -*** Result ***SAVE THIS VALUE*** BidID: 67d85ef08e32de20994c816362d0952fe5c2ae3f2d1083600c3ac61f65a89f60 -``` - -The BidID acts as the unique identifier for the bid. This ID allows you to query the bid using the `queryBid.js` program and add the bid to the auction. Save the bidID returned by the application as an environment variable in your terminal: -``` -export BIDDER1_BID_ID=67d85ef08e32de20994c816362d0952fe5c2ae3f2d1083600c3ac61f65a89f60 -``` -This value will be different for each transaction, so you will need to use the value returned in your terminal. - -Now that the bid has been created, you can submit the bid to the auction. Run the following command to submit the bid that was just created: -``` -node submitBid.js org1 bidder1 PaintingAuction $BIDDER1_BID_ID -``` - -The hash of bid will be added to the list private bids in that have been submitted to `PaintingAuction`. Storing the hash in the public auction allows users to accurately reveal the bid after bidding is closed. The application will query the auction to verify that the bid was added: -``` -*** Result: Auction: { - "objectType": "auction", - "item": "painting", - "seller": "x509::CN=seller,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "organizations": [ - "Org1MSP" - ], - "privateBids": { - "\u0000bid\u0000PaintingAuction\u00005c049b0b4552d34c88e0f8fb5abca31fa04472b7e1336a16650ac8cfb0b16472\u0000": { - "org": "Org1MSP", - "hash": "0b8bbdb96b1d252e71ac1ed71df3580f7a0e31a743a4a09bbf5196dffef426b2" - } - }, - "revealedBids": {}, - "winner": "", - "price": 0, - "status": "open" -} -``` - -### Bid as bidder2 - -Let's submit another bid. Bidder2 would like to purchase the painting for 500 dollars. -``` -node bid.js org1 bidder2 PaintingAuction 500 -``` - -Save the Bid ID returned by the application: -``` -export BIDDER2_BID_ID=0fa8b3b15923966f205a1f5ebd163d2707d069ffa055105114fc654d225f511d -``` - -Submit bidder2's bid to the auction: -``` -node submitBid.js org1 bidder2 PaintingAuction $BIDDER2_BID_ID -``` - -### Bid as bidder3 from Org2 - -Bidder3 will bid 700 dollars for the painting: -``` -node bid.js org2 bidder3 PaintingAuction 700 -``` - -Save the Bid ID returned by the application: -``` -export BIDDER3_BID_ID=cda8bb2849fc0553efb036c56ea86d82791a695b5641941dac797dc6e2d75768 -``` - -Add bidder3's bid to the auction: -``` -node submitBid.js org2 bidder3 PaintingAuction $BIDDER3_BID_ID -``` - -Because bidder3 belongs to Org2, submitting the bid will add Org2 to the list of participating organizations. You can see the Org2 MSP ID has been added to the list of `"organizations"` in the updated auction returned by the application: -``` -*** Result: Auction: { - "objectType": "auction", - "item": "painting", - "seller": "x509::CN=seller,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "organizations": [ - "Org1MSP", - "Org2MSP" - ], - "privateBids": { - "\u0000bid\u0000PaintingAuction\u00001b9dc0006fef10413df5cca927cabdf73ab854fe92b7a7b2eebfa00961fdac67\u0000": { - "org": "Org1MSP", - "hash": "15cd9a3e12825017f3e758499ac6138ebbe1adec4c49cc6ea6a0973fc6514666" - }, - "\u0000bid\u0000PaintingAuction\u00005c049b0b4552d34c88e0f8fb5abca31fa04472b7e1336a16650ac8cfb0b16472\u0000": { - "org": "Org1MSP", - "hash": "0b8bbdb96b1d252e71ac1ed71df3580f7a0e31a743a4a09bbf5196dffef426b2" - }, - "\u0000bid\u0000PaintingAuction\u00005ee4fa53b54ea0821e57a6884a1ada5eb04f136ee222e92d7399bcdf47556ea1\u0000": { - "org": "Org2MSP", - "hash": "14d47d17acceceb483e87c14a4349844874fce549d71c6a23457d953ed8ffbd3" - } - }, - "revealedBids": {}, - "winner": "", - "price": 0, - "status": "open" -} -``` - -Now that a bid from Org2 has been added to the auction, any updates to the auction need to be endorsed by the Org2 peer. The applications will use `"organizations"` field to specify which organizations need to endorse submitting a new bid, revealing a bid, or updating the auction status. - -### Bid as bidder4 - -Bidder4 from Org2 would like to purchase the painting for 900 dollars: -``` -node bid.js org2 bidder4 PaintingAuction 900 -``` - -Save the Bid ID returned by the application: -``` -export BIDDER4_BID_ID=83861eb17715ff537a1e73cd2d08509dc7199572806a5368706516759af1a257 -``` - -Add bidder4's bid to the auction: -``` -node submitBid.js org2 bidder4 PaintingAuction $BIDDER4_BID_ID -``` - -## Close the auction - -Now that all four bidders have joined the auction, the seller would like to close the auction and allow buyers to reveal their bids. The seller identity that created the auction needs to submit the transaction: -``` -node closeAuction.js org1 seller PaintingAuction -``` - -The application will query the auction to allow you to verify that the auction status has changed to closed. As a test, you can try to create and submit a new bid to verify that no new bids can be added to the auction. - -## Reveal bids - -After the auction is closed, bidders can try to win the auction by revealing their bids. The transaction to reveal a bid needs to pass four checks: -1. The auction is closed. -2. The transaction was submitted by the identity that created the bid. -3. The hash of the revealed bid matches the hash of the bid on the channel ledger. This confirms that the bid is the same as the bid that is stored in the private data collection. -4. The hash of the revealed bid matches the hash that was submitted to the auction. This confirms that the bid was not altered after the auction was closed. - -Use the `revealBid.js` application to reveal the bid of Bidder1: -``` -node revealBid.js org1 bidder1 PaintingAuction $BIDDER1_BID_ID -``` - -The full bid details, including the price, are now visible: -``` -*** Result: Auction: { - "objectType": "auction", - "item": "painting", - "seller": "x509::CN=seller,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "organizations": [ - "Org1MSP", - "Org2MSP" - ], - "privateBids": { - "\u0000bid\u0000PaintingAuction\u000019a7a0dd2c5456a3f79c2f9ccb09dddd0f1c9ece514dfea7cbea06e7cbc79855\u0000": { - "org": "Org2MSP", - "hash": "08db66c6cc226577a3153dadeb0b77d3834162fcf5f008b344058a1bc5c1b3a4" - }, - "\u0000bid\u0000PaintingAuction\u00001b9dc0006fef10413df5cca927cabdf73ab854fe92b7a7b2eebfa00961fdac67\u0000": { - "org": "Org1MSP", - "hash": "15cd9a3e12825017f3e758499ac6138ebbe1adec4c49cc6ea6a0973fc6514666" - }, - "\u0000bid\u0000PaintingAuction\u00005c049b0b4552d34c88e0f8fb5abca31fa04472b7e1336a16650ac8cfb0b16472\u0000": { - "org": "Org1MSP", - "hash": "0b8bbdb96b1d252e71ac1ed71df3580f7a0e31a743a4a09bbf5196dffef426b2" - }, - "\u0000bid\u0000PaintingAuction\u00005ee4fa53b54ea0821e57a6884a1ada5eb04f136ee222e92d7399bcdf47556ea1\u0000": { - "org": "Org2MSP", - "hash": "14d47d17acceceb483e87c14a4349844874fce549d71c6a23457d953ed8ffbd3" - } - }, - "revealedBids": { - "\u0000bid\u0000PaintingAuction\u00005c049b0b4552d34c88e0f8fb5abca31fa04472b7e1336a16650ac8cfb0b16472\u0000": { - "objectType": "bid", - "price": 800, - "org": "Org1MSP", - "bidder": "x509::CN=bidder1,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US" - } - }, - "winner": "", - "price": 0, - "status": "closed" -} -``` - -Bidder3 from Org2 will also reveal their bid: -``` -node revealBid.js org2 bidder3 PaintingAuction $BIDDER3_BID_ID -``` - -If the auction ended now, Bidder1 would win. Let's try to end the auction using the seller identity and see what happens. - -``` -node endAuction.js org1 seller PaintingAuction -``` - -The output should look something like the following: - -``` ---> Submit the transaction to end the auction -2021-01-28T16:47:27.501Z - error: [DiscoveryHandler]: compareProposalResponseResults[undefined] - read/writes result sets do not match index=1 -2021-01-28T16:47:27.503Z - error: [Transaction]: Error: No valid responses from any peers. Errors: - peer=undefined, status=grpc, message=Peer endorsements do not match -******** FAILED to submit bid: Error: No valid responses from any peers. Errors: - peer=undefined, status=grpc, message=Peer endorsements do not match -``` - -Instead of ending the auction, the transaction results in an endorsement policy failure. The end of the auction needs to be endorsed by Org2. Before endorsing the transaction, the Org2 peer queries its private data collection for any winning bids that have not yet been revealed. Because Bidder4 created a bid that is above the winning price, the Org2 peer refuses to endorse the transaction that would end the auction. - -Before we can end the auction, we need to reveal the bid from bidder4. -``` -node revealBid.js org2 bidder4 PaintingAuction $BIDDER4_BID_ID -``` - -Bidder2 from Org1 would not win the auction in either case. As a result, Bidder2 decides not to reveal their bid. - -## End the auction - -Now that the winning bids have been revealed, we can end the auction: -``` -node endAuction org1 seller PaintingAuction -``` - -The transaction was successfully endorsed by both Org1 and Org2, who both calculated the same price and winner. The winning bidder is listed along with the price: -``` -*** Result: Auction: { - "objectType": "auction", - "item": "painting", - "seller": "x509::CN=seller,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "organizations": [ - "Org1MSP", - "Org2MSP" - ], - "privateBids": { - "\u0000bid\u0000PaintingAuction\u000019a7a0dd2c5456a3f79c2f9ccb09dddd0f1c9ece514dfea7cbea06e7cbc79855\u0000": { - "org": "Org2MSP", - "hash": "08db66c6cc226577a3153dadeb0b77d3834162fcf5f008b344058a1bc5c1b3a4" - }, - "\u0000bid\u0000PaintingAuction\u00001b9dc0006fef10413df5cca927cabdf73ab854fe92b7a7b2eebfa00961fdac67\u0000": { - "org": "Org1MSP", - "hash": "15cd9a3e12825017f3e758499ac6138ebbe1adec4c49cc6ea6a0973fc6514666" - }, - "\u0000bid\u0000PaintingAuction\u00005c049b0b4552d34c88e0f8fb5abca31fa04472b7e1336a16650ac8cfb0b16472\u0000": { - "org": "Org1MSP", - "hash": "0b8bbdb96b1d252e71ac1ed71df3580f7a0e31a743a4a09bbf5196dffef426b2" - }, - "\u0000bid\u0000PaintingAuction\u00005ee4fa53b54ea0821e57a6884a1ada5eb04f136ee222e92d7399bcdf47556ea1\u0000": { - "org": "Org2MSP", - "hash": "14d47d17acceceb483e87c14a4349844874fce549d71c6a23457d953ed8ffbd3" - } - }, - "revealedBids": { - "\u0000bid\u0000PaintingAuction\u000019a7a0dd2c5456a3f79c2f9ccb09dddd0f1c9ece514dfea7cbea06e7cbc79855\u0000": { - "objectType": "bid", - "price": 900, - "org": "Org2MSP", - "bidder": "x509::CN=bidder4,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK" - }, - "\u0000bid\u0000PaintingAuction\u00005c049b0b4552d34c88e0f8fb5abca31fa04472b7e1336a16650ac8cfb0b16472\u0000": { - "objectType": "bid", - "price": 800, - "org": "Org1MSP", - "bidder": "x509::CN=bidder1,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US" - }, - "\u0000bid\u0000PaintingAuction\u00005ee4fa53b54ea0821e57a6884a1ada5eb04f136ee222e92d7399bcdf47556ea1\u0000": { - "objectType": "bid", - "price": 700, - "org": "Org2MSP", - "bidder": "x509::CN=bidder3,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK" - } - }, - "winner": "x509::CN=bidder4,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK", - "price": 900, - "status": "ended" -} -``` - -## Clean up - -When your are done using the auction smart contract, you can bring down the network and clean up the environment. In the `auction-simple/application-javascript` directory, run the following command to remove the wallets used to run the applications: -``` -rm -rf wallet -``` - -You can then navigate to the test network directory and bring down the network: -```` -cd ../../test-network/ -./network.sh down -```` diff --git a/auction-simple/application-javascript/.eslintignore b/auction-simple/application-javascript/.eslintignore deleted file mode 100644 index 15958470..00000000 --- a/auction-simple/application-javascript/.eslintignore +++ /dev/null @@ -1,5 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -coverage diff --git a/auction-simple/application-javascript/.eslintrc.js b/auction-simple/application-javascript/.eslintrc.js deleted file mode 100644 index 20d4fcbd..00000000 --- a/auction-simple/application-javascript/.eslintrc.js +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -module.exports = { - env: { - node: true, - mocha: true - }, - parserOptions: { - ecmaVersion: 8, - sourceType: 'script' - }, - extends: 'eslint:recommended', - rules: { - indent: ['error', 'tab'], - 'linebreak-style': ['error', 'unix'], - quotes: ['error', 'single'], - semi: ['error', 'always'], - 'no-unused-vars': ['error', { args: 'none' }], - 'no-console': 'off', - curly: 'error', - eqeqeq: 'error', - 'no-throw-literal': 'error', - strict: 'error', - 'no-var': 'error', - 'dot-notation': 'error', - 'no-trailing-spaces': 'error', - 'no-use-before-define': 'error', - 'no-useless-call': 'error', - 'no-with': 'error', - 'operator-linebreak': 'error', - yoda: 'error', - 'quote-props': ['error', 'as-needed'] - } -}; diff --git a/auction-simple/application-javascript/bid.js b/auction-simple/application-javascript/bid.js deleted file mode 100644 index d4b4de56..00000000 --- a/auction-simple/application-javascript/bid.js +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString} = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function bid(ccp,wallet,user,orgMSP,auctionID,price) { - try { - - const gateway = new Gateway(); - // Connect using Discovery enabled - - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - console.log('\n--> Evaluate Transaction: get your client ID'); - let bidder = await contract.evaluateTransaction('GetSubmittingClientIdentity'); - console.log('*** Result: Bidder ID is ' + bidder.toString()); - - let bidData = { objectType: 'bid', price: parseInt(price), org: orgMSP, bidder: bidder.toString()}; - - let statefulTxn = contract.createTransaction('Bid'); - statefulTxn.setEndorsingOrganizations(orgMSP); - let tmapData = Buffer.from(JSON.stringify(bidData)); - statefulTxn.setTransient({ - bid: tmapData - }); - - let bidID = statefulTxn.getTransactionId(); - - console.log('\n--> Submit Transaction: Create the bid that is stored in your organization\'s private data collection'); - await statefulTxn.submit(auctionID); - console.log('*** Result: committed'); - console.log('*** Result ***SAVE THIS VALUE*** BidID: ' + bidID.toString()); - - console.log('\n--> Evaluate Transaction: read the bid that was just created'); - let result = await contract.evaluateTransaction('QueryBid',auctionID,bidID); - console.log('*** Result: Bid: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - if (error.stack) { - console.error(error.stack); - } - process.exit(1); - } -} - -async function main() { - try { - - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined || process.argv[5] === undefined) { - console.log('Usage: node bid.js org userID auctionID price'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - const price = process.argv[5]; - - if (org === 'Org1' || org === 'org1') { - - const orgMSP = 'Org1MSP'; - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await bid(ccp,wallet,user,orgMSP,auctionID,price); - } - else if (org === 'Org2' || org === 'org2') { - - const orgMSP = 'Org2MSP'; - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await bid(ccp,wallet,user,orgMSP,auctionID,price); - } else { - console.log('Usage: node bid.js org userID auctionID price'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - process.exit(1); - } -} - -main(); diff --git a/auction-simple/application-javascript/closeAuction.js b/auction-simple/application-javascript/closeAuction.js deleted file mode 100644 index b637e761..00000000 --- a/auction-simple/application-javascript/closeAuction.js +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString} = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function closeAuction(ccp,wallet,user,auctionID) { - try { - - const gateway = new Gateway(); - - // Connect using Discovery enabled - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - // Query the auction to get the list of endorsing orgs. - let auctionString = await contract.evaluateTransaction('QueryAuction',auctionID); - let auctionJSON = JSON.parse(auctionString); - - let statefulTxn = contract.createTransaction('CloseAuction'); - - if (auctionJSON.organizations.length === 2) { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0],auctionJSON.organizations[1]); - } else { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0]); - } - - console.log('\n--> Submit Transaction: close auction'); - await statefulTxn.submit(auctionID); - console.log('*** Result: committed'); - - console.log('\n--> Evaluate Transaction: query the updated auction'); - let result = await contract.evaluateTransaction('QueryAuction',auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - process.exit(1); - } -} - -async function main() { - try { - - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined) { - console.log('Usage: node closeAuction.js org userID auctionID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await closeAuction(ccp,wallet,user,auctionID); - } - else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await closeAuction(ccp,wallet,user,auctionID); - } else { - console.log('Usage: node closeAuction.js org userID auctionID '); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - if (error.stack) { - console.error(error.stack); - } - process.exit(1); - } -} - - -main(); diff --git a/auction-simple/application-javascript/createAuction.js b/auction-simple/application-javascript/createAuction.js deleted file mode 100644 index a05d4f96..00000000 --- a/auction-simple/application-javascript/createAuction.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString} = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function createAuction(ccp,wallet,user,auctionID,item) { - try { - - const gateway = new Gateway(); - - // Connect using Discovery enabled - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - let statefulTxn = contract.createTransaction('CreateAuction'); - - console.log('\n--> Submit Transaction: Propose a new auction'); - await statefulTxn.submit(auctionID,item); - console.log('*** Result: committed'); - - console.log('\n--> Evaluate Transaction: query the auction that was just created'); - let result = await contract.evaluateTransaction('QueryAuction',auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - } -} - -async function main() { - try { - - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined || process.argv[5] === undefined) { - console.log('Usage: node createAuction.js org userID auctionID item'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - const item = process.argv[5]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await createAuction(ccp,wallet,user,auctionID,item); - } - else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await createAuction(ccp,wallet,user,auctionID,item); - } else { - console.log('Usage: node createAuction.js org userID auctionID item'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - } -} - - -main(); diff --git a/auction-simple/application-javascript/endAuction.js b/auction-simple/application-javascript/endAuction.js deleted file mode 100644 index 27ea5983..00000000 --- a/auction-simple/application-javascript/endAuction.js +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString} = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function endAuction(ccp,wallet,user,auctionID) { - try { - - const gateway = new Gateway(); - - // Connect using Discovery enabled - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - // Query the auction to get the list of endorsing orgs. - let auctionString = await contract.evaluateTransaction('QueryAuction',auctionID); - let auctionJSON = JSON.parse(auctionString); - - let statefulTxn = contract.createTransaction('EndAuction'); - - if (auctionJSON.organizations.length === 2) { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0],auctionJSON.organizations[1]); - } else { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0]); - } - - console.log('\n--> Submit the transaction to end the auction'); - await statefulTxn.submit(auctionID); - console.log('*** Result: committed'); - - console.log('\n--> Evaluate Transaction: query the updated auction'); - let result = await contract.evaluateTransaction('QueryAuction',auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - process.exit(1); - } -} - -async function main() { - try { - - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined) { - console.log('Usage: node endAuction.js org userID auctionID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await endAuction(ccp,wallet,user,auctionID); - } - else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await endAuction(ccp,wallet,user,auctionID); - } else { - console.log('Usage: node endAuction.js org userID auctionID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - if (error.stack) { - console.error(error.stack); - } - process.exit(1); - } -} - - -main(); diff --git a/auction-simple/application-javascript/enrollAdmin.js b/auction-simple/application-javascript/enrollAdmin.js deleted file mode 100644 index 1c87cad5..00000000 --- a/auction-simple/application-javascript/enrollAdmin.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Wallets } = require('fabric-network'); -const FabricCAServices = require('fabric-ca-client'); -const path = require('path'); -const { buildCAClient, enrollAdmin } = require('../../test-application/javascript/CAUtil.js'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet } = require('../../test-application/javascript/AppUtil.js'); - -const mspOrg1 = 'Org1MSP'; -const mspOrg2 = 'Org2MSP'; - -async function connectToOrg1CA() { - console.log('\n--> Enrolling the Org1 CA admin'); - const ccpOrg1 = buildCCPOrg1(); - const caOrg1Client = buildCAClient(FabricCAServices, ccpOrg1, 'ca.org1.example.com'); - - const walletPathOrg1 = path.join(__dirname, 'wallet/org1'); - const walletOrg1 = await buildWallet(Wallets, walletPathOrg1); - - await enrollAdmin(caOrg1Client, walletOrg1, mspOrg1); - -} - -async function connectToOrg2CA() { - console.log('\n--> Enrolling the Org2 CA admin'); - const ccpOrg2 = buildCCPOrg2(); - const caOrg2Client = buildCAClient(FabricCAServices, ccpOrg2, 'ca.org2.example.com'); - - const walletPathOrg2 = path.join(__dirname, 'wallet/org2'); - const walletOrg2 = await buildWallet(Wallets, walletPathOrg2); - - await enrollAdmin(caOrg2Client, walletOrg2, mspOrg2); - -} -async function main() { - - if (process.argv[2] === undefined) { - console.log('Usage: node enrollAdmin.js Org'); - process.exit(1); - } - - const org = process.argv[2]; - - try { - - if (org === 'Org1' || org === 'org1') { - await connectToOrg1CA(); - } - else if (org === 'Org2' || org === 'org2') { - await connectToOrg2CA(); - } else { - console.log('Usage: node registerUser.js org userID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`Error in enrolling admin: ${error}`); - process.exit(1); - } -} - -main(); diff --git a/auction-simple/application-javascript/package.json b/auction-simple/application-javascript/package.json deleted file mode 100644 index 49bf01e8..00000000 --- a/auction-simple/application-javascript/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "auction", - "version": "1.0.0", - "description": "auction application implemented in JavaScript", - "engines": { - "node": ">=12", - "npm": ">=5" - }, - "engineStrict": true, - "author": "Hyperledger", - "license": "Apache-2.0", - "scripts": { - "lint": "eslint *.js" - }, - "dependencies": { - "fabric-ca-client": "^2.2.19", - "fabric-network": "^2.2.19" - }, - "devDependencies": { - "eslint": "^7.32.0" - } -} diff --git a/auction-simple/application-javascript/queryAuction.js b/auction-simple/application-javascript/queryAuction.js deleted file mode 100644 index 046267af..00000000 --- a/auction-simple/application-javascript/queryAuction.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString} = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function queryAuction(ccp,wallet,user,auctionID) { - try { - - const gateway = new Gateway(); - - // Connect using Discovery enabled - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - console.log('\n--> Evaluate Transaction: query the auction'); - let result = await contract.evaluateTransaction('QueryAuction',auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - } -} - -async function main() { - try { - - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined) { - console.log('Usage: node queryAuction.js org userID auctionID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await queryAuction(ccp,wallet,user,auctionID); - } - else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await queryAuction(ccp,wallet,user,auctionID); - } else { - console.log('Usage: node queryAuction.js org userID auctionID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - } -} - - -main(); diff --git a/auction-simple/application-javascript/queryBid.js b/auction-simple/application-javascript/queryBid.js deleted file mode 100644 index 57ce37ba..00000000 --- a/auction-simple/application-javascript/queryBid.js +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString} = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function queryBid(ccp,wallet,user,auctionID,bidID) { - try { - - const gateway = new Gateway(); - - // Connect using Discovery enabled - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - console.log('\n--> Evaluate Transaction: read bid from private data store'); - let result = await contract.evaluateTransaction('QueryBid',auctionID,bidID); - console.log('*** Result: Bid: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - } -} - -async function main() { - try { - - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined || process.argv[5] === undefined) { - console.log('Usage: node bid.js org userID auctionID bidID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - const bidID = process.argv[5]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await queryBid(ccp,wallet,user,auctionID,bidID); - } - else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await queryBid(ccp,wallet,user,auctionID,bidID); - } else { - console.log('Usage: node bid.js org userID auctionID bidID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - } -} - - -main(); diff --git a/auction-simple/application-javascript/registerEnrollUser.js b/auction-simple/application-javascript/registerEnrollUser.js deleted file mode 100644 index d6cb9a66..00000000 --- a/auction-simple/application-javascript/registerEnrollUser.js +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Wallets } = require('fabric-network'); -const FabricCAServices = require('fabric-ca-client'); -const path = require('path'); -const { buildCAClient, registerAndEnrollUser } = require('../../test-application/javascript/CAUtil.js'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet } = require('../../test-application/javascript/AppUtil.js'); - -const mspOrg1 = 'Org1MSP'; -const mspOrg2 = 'Org2MSP'; - -async function connectToOrg1CA(UserID) { - console.log('\n--> Register and enrolling new user'); - const ccpOrg1 = buildCCPOrg1(); - const caOrg1Client = buildCAClient(FabricCAServices, ccpOrg1, 'ca.org1.example.com'); - - const walletPathOrg1 = path.join(__dirname, 'wallet/org1'); - const walletOrg1 = await buildWallet(Wallets, walletPathOrg1); - - await registerAndEnrollUser(caOrg1Client, walletOrg1, mspOrg1, UserID, 'org1.department1'); - -} - -async function connectToOrg2CA(UserID) { - console.log('\n--> Register and enrolling new user'); - const ccpOrg2 = buildCCPOrg2(); - const caOrg2Client = buildCAClient(FabricCAServices, ccpOrg2, 'ca.org2.example.com'); - - const walletPathOrg2 = path.join(__dirname, 'wallet/org2'); - const walletOrg2 = await buildWallet(Wallets, walletPathOrg2); - - await registerAndEnrollUser(caOrg2Client, walletOrg2, mspOrg2, UserID, 'org2.department1'); - -} -async function main() { - - if (process.argv[2] === undefined && process.argv[3] === undefined) { - console.log('Usage: node registerEnrollUser.js org userID'); - process.exit(1); - } - - const org = process.argv[2]; - const userId = process.argv[3]; - - try { - - if (org === 'Org1' || org === 'org1') { - await connectToOrg1CA(userId); - } - else if (org === 'Org2' || org === 'org2') { - await connectToOrg2CA(userId); - } else { - console.log('Usage: node registerEnrollUser.js org userID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`Error in enrolling admin: ${error}`); - process.exit(1); - } -} - -main(); diff --git a/auction-simple/application-javascript/revealBid.js b/auction-simple/application-javascript/revealBid.js deleted file mode 100644 index bb0b1a7f..00000000 --- a/auction-simple/application-javascript/revealBid.js +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString} = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function addBid(ccp,wallet,user,auctionID,bidID) { - try { - - const gateway = new Gateway(); - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - console.log('\n--> Evaluate Transaction: read your bid'); - let bidString = await contract.evaluateTransaction('QueryBid',auctionID,bidID); - let bidJSON = JSON.parse(bidString); - - // console.log('\n--> Evaluate Transaction: query the auction you want to join'); - let auctionString = await contract.evaluateTransaction('QueryAuction',auctionID); - // console.log('*** Result: Bid: ' + prettyJSONString(auctionString.toString())); - let auctionJSON = JSON.parse(auctionString); - - let bidData = { objectType: 'bid', price: parseInt(bidJSON.price), org: bidJSON.org, bidder: bidJSON.bidder}; - console.log('*** Result: Bid: ' + JSON.stringify(bidData,null,2)); - - let statefulTxn = contract.createTransaction('RevealBid'); - let tmapData = Buffer.from(JSON.stringify(bidData)); - statefulTxn.setTransient({ - bid: tmapData - }); - - if (auctionJSON.organizations.length === 2) { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0],auctionJSON.organizations[1]); - } else { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0]); - } - - await statefulTxn.submit(auctionID,bidID); - - console.log('\n--> Evaluate Transaction: query the auction to see that our bid was added'); - let result = await contract.evaluateTransaction('QueryAuction',auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - process.exit(1); - } -} - -async function main() { - try { - - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined || process.argv[5] === undefined) { - console.log('Usage: node revealBid.js org userID auctionID bidID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - const bidID = process.argv[5]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await addBid(ccp,wallet,user,auctionID,bidID); - } - else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await addBid(ccp,wallet,user,auctionID,bidID); - } - else { - console.log('Usage: node revealBid.js org userID auctionID bidID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - if (error.stack) { - console.error(error.stack); - } - process.exit(1); - } -} - - -main(); diff --git a/auction-simple/application-javascript/submitBid.js b/auction-simple/application-javascript/submitBid.js deleted file mode 100644 index 6c2e0669..00000000 --- a/auction-simple/application-javascript/submitBid.js +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet } = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - - -function prettyJSONString(inputString) { - if (inputString) { - return JSON.stringify(JSON.parse(inputString), null, 2); - } - else { - return inputString; - } -} - -async function submitBid(ccp,wallet,user,auctionID,bidID) { - try { - - const gateway = new Gateway(); - - // Connect using Discovery enabled - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - console.log('\n--> Evaluate Transaction: query the auction you want to join'); - let auctionString = await contract.evaluateTransaction('QueryAuction',auctionID); - let auctionJSON = JSON.parse(auctionString); - - let statefulTxn = contract.createTransaction('SubmitBid'); - - if (auctionJSON.organizations.length === 2) { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0],auctionJSON.organizations[1]); - } else { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0]); - } - - console.log('\n--> Submit Transaction: add bid to the auction'); - await statefulTxn.submit(auctionID,bidID); - - console.log('\n--> Evaluate Transaction: query the auction to see that our bid was added'); - let result = await contract.evaluateTransaction('QueryAuction',auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - process.exit(1); - } -} - -async function main() { - try { - - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined || process.argv[5] === undefined) { - console.log('Usage: node submitBid.js org userID auctionID bidID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - const bidID = process.argv[5]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await submitBid(ccp,wallet,user,auctionID,bidID); - } - else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await submitBid(ccp,wallet,user,auctionID,bidID); - } - else { - console.log('Usage: node submitBid.js org userID auctionID bidID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - if (error.stack) { - console.error(error.stack); - } - process.exit(1); - } -} - - -main(); diff --git a/auction-simple/chaincode-go/go.mod b/auction-simple/chaincode-go/go.mod deleted file mode 100644 index 3d087a3c..00000000 --- a/auction-simple/chaincode-go/go.mod +++ /dev/null @@ -1,28 +0,0 @@ -module github.com/hyperledger/fabric-samples/auction/chaincode-go - -go 1.22.0 - -require ( - github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0 - github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0 -) - -require ( - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xeipuuv/gojsonschema v1.2.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect - google.golang.org/grpc v1.67.0 // indirect - google.golang.org/protobuf v1.36.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/auction-simple/chaincode-go/go.sum b/auction-simple/chaincode-go/go.sum deleted file mode 100644 index fa4d3b24..00000000 --- a/auction-simple/chaincode-go/go.sum +++ /dev/null @@ -1,61 +0,0 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0 h1:IhkHfrl5X/fVnmB6pWeCYCdIJRi9bxj+WTnVN8DtW3c= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0/go.mod h1:PHHaFffjw7p7n9bmCfcm7RqDqYdivNEsJdiNIKZo5Lk= -github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0 h1:rmUoBmciB0GL/miqcbJmJbgp5QTWoJUrZo+CNxrNLF4= -github.com/hyperledger/fabric-contract-api-go/v2 v2.2.0/go.mod h1:FeWeO/jwGjiME7ak3GufqKIcwkejtzrDG4QxbfKydWs= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4 h1:YJrd+gMaeY0/vsN0aS0QkEKTivGoUnSRIXxGJ7KI+Pc= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.4/go.mod h1:bau/6AJhvEcu9GKKYHlDXAxXKzYNfhP6xu2GXuxEcFk= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= -google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= -google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/auction-simple/chaincode-go/smart-contract/auction.go b/auction-simple/chaincode-go/smart-contract/auction.go deleted file mode 100644 index f0f5e14d..00000000 --- a/auction-simple/chaincode-go/smart-contract/auction.go +++ /dev/null @@ -1,448 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package auction - -import ( - "bytes" - "crypto/sha256" - "encoding/json" - "errors" - "fmt" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -type SmartContract struct { - contractapi.Contract -} - -// Auction data -type Auction struct { - Type string `json:"objectType"` - ItemSold string `json:"item"` - Seller string `json:"seller"` - Orgs []string `json:"organizations"` - PrivateBids map[string]BidHash `json:"privateBids"` - RevealedBids map[string]FullBid `json:"revealedBids"` - Winner string `json:"winner"` - Price int `json:"price"` - Status string `json:"status"` -} - -// FullBid is the structure of a revealed bid -type FullBid struct { - Type string `json:"objectType"` - Price int `json:"price"` - Org string `json:"org"` - Bidder string `json:"bidder"` -} - -// BidHash is the structure of a private bid -type BidHash struct { - Org string `json:"org"` - Hash string `json:"hash"` -} - -const bidKeyType = "bid" - -// CreateAuction creates on auction on the public channel. The identity that -// submits the transacion becomes the seller of the auction -func (s *SmartContract) CreateAuction(ctx contractapi.TransactionContextInterface, auctionID string, itemsold string) error { - - // get ID of submitting client - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - // get org of submitting client - clientOrgID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - // Create auction - bidders := make(map[string]BidHash) - revealedBids := make(map[string]FullBid) - - auction := Auction{ - Type: "auction", - ItemSold: itemsold, - Price: 0, - Seller: clientID, - Orgs: []string{clientOrgID}, - PrivateBids: bidders, - RevealedBids: revealedBids, - Winner: "", - Status: "open", - } - - auctionJSON, err := json.Marshal(auction) - if err != nil { - return err - } - - // put auction into state - err = ctx.GetStub().PutState(auctionID, auctionJSON) - if err != nil { - return fmt.Errorf("failed to put auction in public data: %v", err) - } - - // set the seller of the auction as an endorser - err = setAssetStateBasedEndorsement(ctx, auctionID, clientOrgID) - if err != nil { - return fmt.Errorf("failed setting state based endorsement for new organization: %v", err) - } - - return nil -} - -// Bid is used to add a user's bid to the auction. The bid is stored in the private -// data collection on the peer of the bidder's organization. The function returns -// the transaction ID so that users can identify and query their bid -func (s *SmartContract) Bid(ctx contractapi.TransactionContextInterface, auctionID string) (string, error) { - - // get bid from transient map - transientMap, err := ctx.GetStub().GetTransient() - if err != nil { - return "", fmt.Errorf("error getting transient: %v", err) - } - - BidJSON, ok := transientMap["bid"] - if !ok { - return "", errors.New("bid key not found in the transient map") - } - - // get the implicit collection name using the bidder's organization ID - collection, err := getCollectionName(ctx) - if err != nil { - return "", fmt.Errorf("failed to get implicit collection name: %v", err) - } - - // the bidder has to target their peer to store the bid - err = verifyClientOrgMatchesPeerOrg(ctx) - if err != nil { - return "", fmt.Errorf("cannot store bid on this peer, not a member of this org: Error %v", err) - } - - // the transaction ID is used as a unique index for the bid - txID := ctx.GetStub().GetTxID() - - // create a composite key using the transaction ID - bidKey, err := ctx.GetStub().CreateCompositeKey(bidKeyType, []string{auctionID, txID}) - if err != nil { - return "", fmt.Errorf("failed to create composite key: %v", err) - } - - // put the bid into the organization's implicit data collection - err = ctx.GetStub().PutPrivateData(collection, bidKey, BidJSON) - if err != nil { - return "", fmt.Errorf("failed to input price into collection: %v", err) - } - - // return the trannsaction ID so that the uset can identify their bid - return txID, nil -} - -// SubmitBid is used by the bidder to add the hash of that bid stored in private data to the -// auction. Note that this function alters the auction in private state, and needs -// to meet the auction endorsement policy. Transaction ID is used identify the bid -func (s *SmartContract) SubmitBid(ctx contractapi.TransactionContextInterface, auctionID string, txID string) error { - - // get the MSP ID of the bidder's org - clientOrgID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed to get client MSP ID: %v", err) - } - - // get the auction from public state - auction, err := s.QueryAuction(ctx, auctionID) - if err != nil { - return fmt.Errorf("failed to get auction from public state %v", err) - } - - // the auction needs to be open for users to add their bid - Status := auction.Status - if Status != "open" { - return errors.New("cannot join closed or ended auction") - } - - // get the inplicit collection name of bidder's org - collection, err := getCollectionName(ctx) - if err != nil { - return fmt.Errorf("failed to get implicit collection name: %v", err) - } - - // use the transaction ID passed as a parameter to create composite bid key - bidKey, err := ctx.GetStub().CreateCompositeKey(bidKeyType, []string{auctionID, txID}) - if err != nil { - return fmt.Errorf("failed to create composite key: %v", err) - } - - // get the hash of the bid stored in private data collection - bidHash, err := ctx.GetStub().GetPrivateDataHash(collection, bidKey) - if err != nil { - return fmt.Errorf("failed to read bid bash from collection: %v", err) - } - if bidHash == nil { - return fmt.Errorf("bid hash does not exist: %s", bidKey) - } - - // store the hash along with the bidder's organization - NewHash := BidHash{ - Org: clientOrgID, - Hash: fmt.Sprintf("%x", bidHash), - } - - auction.PrivateBids[bidKey] = NewHash - - // Add the bidding organization to the list of participating organizations if it is not already - Orgs := auction.Orgs - if !(contains(Orgs, clientOrgID)) { - newOrgs := append(Orgs, clientOrgID) - auction.Orgs = newOrgs - - err = addAssetStateBasedEndorsement(ctx, auctionID, clientOrgID) - if err != nil { - return fmt.Errorf("failed setting state based endorsement for new organization: %v", err) - } - } - - newAuctionJSON, _ := json.Marshal(auction) - - err = ctx.GetStub().PutState(auctionID, newAuctionJSON) - if err != nil { - return fmt.Errorf("failed to update auction: %v", err) - } - - return nil -} - -// RevealBid is used by a bidder to reveal their bid after the auction is closed -func (s *SmartContract) RevealBid(ctx contractapi.TransactionContextInterface, auctionID string, txID string) error { - - // get bid from transient map - transientMap, err := ctx.GetStub().GetTransient() - if err != nil { - return fmt.Errorf("error getting transient: %v", err) - } - - transientBidJSON, ok := transientMap["bid"] - if !ok { - return errors.New("bid key not found in the transient map") - } - - // get implicit collection name of organization ID - collection, err := getCollectionName(ctx) - if err != nil { - return fmt.Errorf("failed to get implicit collection name: %v", err) - } - - // use transaction ID to create composit bid key - bidKey, err := ctx.GetStub().CreateCompositeKey(bidKeyType, []string{auctionID, txID}) - if err != nil { - return fmt.Errorf("failed to create composite key: %v", err) - } - - // get bid hash of bid if private bid on the public ledger - bidHash, err := ctx.GetStub().GetPrivateDataHash(collection, bidKey) - if err != nil { - return fmt.Errorf("failed to read bid bash from collection: %v", err) - } - if bidHash == nil { - return fmt.Errorf("bid hash does not exist: %s", bidKey) - } - - // get auction from public state - auction, err := s.QueryAuction(ctx, auctionID) - if err != nil { - return fmt.Errorf("failed to get auction from public state %v", err) - } - - // Complete a series of three checks before we add the bid to the auction - - // check 1: check that the auction is closed. We cannot reveal a - // bid to an open auction - Status := auction.Status - if Status != "closed" { - return errors.New("cannot reveal bid for open or ended auction") - } - - // check 2: check that hash of revealed bid matches hash of private bid - // on the public ledger. This checks that the bidder is telling the truth - // about the value of their bid - - hash := sha256.New() - hash.Write(transientBidJSON) - calculatedBidJSONHash := hash.Sum(nil) - - // verify that the hash of the passed immutable properties matches the on-chain hash - if !bytes.Equal(calculatedBidJSONHash, bidHash) { - return fmt.Errorf("hash %x for bid JSON %s does not match hash in auction: %x", - calculatedBidJSONHash, - transientBidJSON, - bidHash, - ) - } - - // check 3; check hash of relealed bid matches hash of private bid that was - // added earlier. This ensures that the bid has not changed since it - // was added to the auction - - privateBidHashString := auction.PrivateBids[bidKey].Hash - - onChainBidHashString := fmt.Sprintf("%x", bidHash) - if privateBidHashString != onChainBidHashString { - return fmt.Errorf("hash %s for bid JSON %s does not match hash in auction: %s, bidder must have changed bid", - privateBidHashString, - transientBidJSON, - onChainBidHashString, - ) - } - - // we can add the bid to the auction if all checks have passed - type transientBidInput struct { - Price int `json:"price"` - Org string `json:"org"` - Bidder string `json:"bidder"` - } - - // unmarshal bid input - var bidInput transientBidInput - err = json.Unmarshal(transientBidJSON, &bidInput) - if err != nil { - return fmt.Errorf("failed to unmarshal JSON: %v", err) - } - - // Get ID of submitting client identity - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - // marshal transient parameters and ID and MSPID into bid object - NewBid := FullBid{ - Type: bidKeyType, - Price: bidInput.Price, - Org: bidInput.Org, - Bidder: bidInput.Bidder, - } - - // check 4: make sure that the transaction is being submitted is the bidder - if bidInput.Bidder != clientID { - return fmt.Errorf("permission denied, client id %v is not the owner of the bid", clientID) - } - - auction.RevealedBids[bidKey] = NewBid - - newAuctionJSON, _ := json.Marshal(auction) - - // put auction with bid added back into state - err = ctx.GetStub().PutState(auctionID, newAuctionJSON) - if err != nil { - return fmt.Errorf("failed to update auction: %v", err) - } - - return nil -} - -// CloseAuction can be used by the seller to close the auction. This prevents -// bids from being added to the auction, and allows users to reveal their bid -func (s *SmartContract) CloseAuction(ctx contractapi.TransactionContextInterface, auctionID string) error { - - // get auction from public state - auction, err := s.QueryAuction(ctx, auctionID) - if err != nil { - return fmt.Errorf("failed to get auction from public state %v", err) - } - - // the auction can only be closed by the seller - - // get ID of submitting client - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - Seller := auction.Seller - if Seller != clientID { - return fmt.Errorf("auction can only be closed by seller: %v", err) - } - - Status := auction.Status - if Status != "open" { - return errors.New("cannot close auction that is not open") - } - - auction.Status = string("closed") - - closedAuctionJSON, _ := json.Marshal(auction) - - err = ctx.GetStub().PutState(auctionID, closedAuctionJSON) - if err != nil { - return fmt.Errorf("failed to close auction: %v", err) - } - - return nil -} - -// EndAuction both changes the auction status to closed and calculates the winners -// of the auction -func (s *SmartContract) EndAuction(ctx contractapi.TransactionContextInterface, auctionID string) error { - - // get auction from public state - auction, err := s.QueryAuction(ctx, auctionID) - if err != nil { - return fmt.Errorf("failed to get auction from public state %v", err) - } - - // Check that the auction is being ended by the seller - - // get ID of submitting client - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - Seller := auction.Seller - if Seller != clientID { - return fmt.Errorf("auction can only be ended by seller: %v", err) - } - - Status := auction.Status - if Status != "closed" { - return errors.New("can only end a closed auction") - } - - // get the list of revealed bids - revealedBidMap := auction.RevealedBids - if len(auction.RevealedBids) == 0 { - return fmt.Errorf("no bids have been revealed, cannot end auction: %v", err) - } - - // determine the highest bid - for _, bid := range revealedBidMap { - if bid.Price > auction.Price { - auction.Winner = bid.Bidder - auction.Price = bid.Price - } - } - - // check if there is a winning bid that has yet to be revealed - err = checkForHigherBid(ctx, auction.Price, auction.RevealedBids, auction.PrivateBids) - if err != nil { - return fmt.Errorf("cannot end auction: %v", err) - } - - auction.Status = "ended" - - endedAuctionJSON, _ := json.Marshal(auction) - - err = ctx.GetStub().PutState(auctionID, endedAuctionJSON) - if err != nil { - return fmt.Errorf("failed to end auction: %v", err) - } - return nil -} diff --git a/auction-simple/chaincode-go/smart-contract/auctionQueries.go b/auction-simple/chaincode-go/smart-contract/auctionQueries.go deleted file mode 100644 index cd99558b..00000000 --- a/auction-simple/chaincode-go/smart-contract/auctionQueries.go +++ /dev/null @@ -1,137 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package auction - -import ( - "encoding/json" - "errors" - "fmt" - - "github.com/hyperledger/fabric-chaincode-go/v2/shim" - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -// QueryAuction allows all members of the channel to read a public auction -func (s *SmartContract) QueryAuction(ctx contractapi.TransactionContextInterface, auctionID string) (*Auction, error) { - - auctionJSON, err := ctx.GetStub().GetState(auctionID) - if err != nil { - return nil, fmt.Errorf("failed to get auction object %v: %v", auctionID, err) - } - if auctionJSON == nil { - return nil, errors.New("auction does not exist") - } - - var auction *Auction - err = json.Unmarshal(auctionJSON, &auction) - if err != nil { - return nil, err - } - - return auction, nil -} - -// QueryBid allows the submitter of the bid to read their bid from public state -func (s *SmartContract) QueryBid(ctx contractapi.TransactionContextInterface, auctionID string, txID string) (*FullBid, error) { - - err := verifyClientOrgMatchesPeerOrg(ctx) - if err != nil { - return nil, fmt.Errorf("failed to get implicit collection name: %v", err) - } - - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return nil, fmt.Errorf("failed to get client identity %v", err) - } - - collection, err := getCollectionName(ctx) - if err != nil { - return nil, fmt.Errorf("failed to get implicit collection name: %v", err) - } - - bidKey, err := ctx.GetStub().CreateCompositeKey(bidKeyType, []string{auctionID, txID}) - if err != nil { - return nil, fmt.Errorf("failed to create composite key: %v", err) - } - - bidJSON, err := ctx.GetStub().GetPrivateData(collection, bidKey) - if err != nil { - return nil, fmt.Errorf("failed to get bid %v: %v", bidKey, err) - } - if bidJSON == nil { - return nil, fmt.Errorf("bid %v does not exist", bidKey) - } - - var bid *FullBid - err = json.Unmarshal(bidJSON, &bid) - if err != nil { - return nil, err - } - - // check that the client querying the bid is the bid owner - if bid.Bidder != clientID { - return nil, fmt.Errorf("permission denied, client id %v is not the owner of the bid", clientID) - } - - return bid, nil -} - -// checkForHigherBid is an internal function that is used to determine if a winning bid has yet to be revealed -func checkForHigherBid(ctx contractapi.TransactionContextInterface, auctionPrice int, revealedBidders map[string]FullBid, bidders map[string]BidHash) error { - - // Get MSP ID of peer org - peerMSPID, err := shim.GetMSPID() - if err != nil { - return fmt.Errorf("failed getting the peer's MSPID: %v", err) - } - - var error error - error = nil - - for bidKey, privateBid := range bidders { - - if _, bidInAuction := revealedBidders[bidKey]; bidInAuction { - - // bid is already revealed, no action to take - - } else { - - collection := "_implicit_org_" + privateBid.Org - - if privateBid.Org == peerMSPID { - - bidJSON, err := ctx.GetStub().GetPrivateData(collection, bidKey) - if err != nil { - return fmt.Errorf("failed to get bid %v: %v", bidKey, err) - } - if bidJSON == nil { - return fmt.Errorf("bid %v does not exist", bidKey) - } - - var bid *FullBid - err = json.Unmarshal(bidJSON, &bid) - if err != nil { - return err - } - - if bid.Price > auctionPrice { - error = fmt.Errorf("cannot close auction, bidder has a higher price: %v", err) - } - - } else { - - Hash, err := ctx.GetStub().GetPrivateDataHash(collection, bidKey) - if err != nil { - return fmt.Errorf("failed to read bid hash from collection: %v", err) - } - if Hash == nil { - return fmt.Errorf("bid hash does not exist: %s", bidKey) - } - } - } - } - - return error -} diff --git a/auction-simple/chaincode-go/smart-contract/utils.go b/auction-simple/chaincode-go/smart-contract/utils.go deleted file mode 100644 index b663e608..00000000 --- a/auction-simple/chaincode-go/smart-contract/utils.go +++ /dev/null @@ -1,121 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package auction - -import ( - "encoding/base64" - "fmt" - - "github.com/hyperledger/fabric-chaincode-go/v2/pkg/statebased" - "github.com/hyperledger/fabric-chaincode-go/v2/shim" - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -func (s *SmartContract) GetSubmittingClientIdentity(ctx contractapi.TransactionContextInterface) (string, error) { - - b64ID, err := ctx.GetClientIdentity().GetID() - if err != nil { - return "", fmt.Errorf("failed to read clientID: %v", err) - } - decodeID, err := base64.StdEncoding.DecodeString(b64ID) - if err != nil { - return "", fmt.Errorf("failed to base64 decode clientID: %v", err) - } - return string(decodeID), nil -} - -// setAssetStateBasedEndorsement sets the endorsement policy of a new auction -func setAssetStateBasedEndorsement(ctx contractapi.TransactionContextInterface, auctionID string, orgToEndorse string) error { - - endorsementPolicy, err := statebased.NewStateEP(nil) - if err != nil { - return err - } - err = endorsementPolicy.AddOrgs(statebased.RoleTypePeer, orgToEndorse) - if err != nil { - return fmt.Errorf("failed to add org to endorsement policy: %v", err) - } - policy, err := endorsementPolicy.Policy() - if err != nil { - return fmt.Errorf("failed to create endorsement policy bytes from org: %v", err) - } - err = ctx.GetStub().SetStateValidationParameter(auctionID, policy) - if err != nil { - return fmt.Errorf("failed to set validation parameter on auction: %v", err) - } - - return nil -} - -// addAssetStateBasedEndorsement adds a new organization as an endorser of the auction -func addAssetStateBasedEndorsement(ctx contractapi.TransactionContextInterface, auctionID string, orgToEndorse string) error { - - endorsementPolicy, err := ctx.GetStub().GetStateValidationParameter(auctionID) - if err != nil { - return err - } - - newEndorsementPolicy, err := statebased.NewStateEP(endorsementPolicy) - if err != nil { - return err - } - - err = newEndorsementPolicy.AddOrgs(statebased.RoleTypePeer, orgToEndorse) - if err != nil { - return fmt.Errorf("failed to add org to endorsement policy: %v", err) - } - policy, err := newEndorsementPolicy.Policy() - if err != nil { - return fmt.Errorf("failed to create endorsement policy bytes from org: %v", err) - } - err = ctx.GetStub().SetStateValidationParameter(auctionID, policy) - if err != nil { - return fmt.Errorf("failed to set validation parameter on auction: %v", err) - } - - return nil -} - -// getCollectionName is an internal helper function to get collection of submitting client identity. -func getCollectionName(ctx contractapi.TransactionContextInterface) (string, error) { - - // Get the MSP ID of submitting client identity - clientMSPID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return "", fmt.Errorf("failed to get verified MSPID: %v", err) - } - - // Create the collection name - orgCollection := "_implicit_org_" + clientMSPID - - return orgCollection, nil -} - -// verifyClientOrgMatchesPeerOrg is an internal function used to verify that client org id matches peer org id. -func verifyClientOrgMatchesPeerOrg(ctx contractapi.TransactionContextInterface) error { - clientMSPID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed getting the client's MSPID: %v", err) - } - peerMSPID, err := shim.GetMSPID() - if err != nil { - return fmt.Errorf("failed getting the peer's MSPID: %v", err) - } - - if clientMSPID != peerMSPID { - return fmt.Errorf("client from org %v is not authorized to read or write private data from an org %v peer", clientMSPID, peerMSPID) - } - - return nil -} - -func contains(sli []string, str string) bool { - for _, a := range sli { - if a == str { - return true - } - } - return false -} diff --git a/auction-simple/chaincode-go/smartContract.go b/auction-simple/chaincode-go/smartContract.go deleted file mode 100644 index c165075d..00000000 --- a/auction-simple/chaincode-go/smartContract.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "log" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" - "github.com/hyperledger/fabric-samples/auction/chaincode-go/smart-contract" -) - -func main() { - auctionSmartContract, err := contractapi.NewChaincode(&auction.SmartContract{}) - if err != nil { - log.Panicf("Error creating auction chaincode: %v", err) - } - - if err := auctionSmartContract.Start(); err != nil { - log.Panicf("Error starting auction chaincode: %v", err) - } -} diff --git a/full-stack-asset-transfer-guide/.gitignore b/full-stack-asset-transfer-guide/.gitignore deleted file mode 100644 index a7148016..00000000 --- a/full-stack-asset-transfer-guide/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -fabric -_cfg -node_modules -*.bin -.idea/ -_* -*tgz -*.tar.gz -~*.pptx - -bin -config/ - -.DS_Store -.idea/ - -rook \ No newline at end of file diff --git a/full-stack-asset-transfer-guide/LICENSE b/full-stack-asset-transfer-guide/LICENSE deleted file mode 100644 index 261eeb9e..00000000 --- a/full-stack-asset-transfer-guide/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/full-stack-asset-transfer-guide/README.md b/full-stack-asset-transfer-guide/README.md deleted file mode 100644 index 2d886005..00000000 --- a/full-stack-asset-transfer-guide/README.md +++ /dev/null @@ -1,108 +0,0 @@ -![Conga](https://avatars.githubusercontent.com/u/49026922?s=200&v=4) - -# Fabric Full Stack Development Workshop - -![Hyperledger](https://img.shields.io/badge/hyperledger-2F3134?style=for-the-badge&logo=hyperledger&logoColor=white) - -Hyperledger Fabric can be used to represent assets of any kind on a permissioned decentralized ledger, from fungible tokens to non-fungible tokens, including monetary products, marbles, pineapples, classic cars, fine art, and anything else you can imagine. -Fabric can be used to track and update anything about these assets, common examples include asset ownership, exchange, provenance, and lifecycle. - -This workshop will demonstrate how a generic asset transfer solution can be modeled and deployed to take advantage of a blockchains qualitites of service. - -The workshop will be split into three sections: -- Smart Contract Development -- Client Application Development -- Cloud Native Fabric Deployment - -![Intro diagram](./docs/images/readme_diagram.png) - -**OBJECTIVES:** - -- Show how an Asset Transfer smart contract can be written to encapsulate business logic - - Show how the smart contract can be developed iteratively to get correct function in a development context -- Show how client applications can be written using the Gateway functionality - - Show how the simplification of the Gateway programming model makes connecting applications more streamlined - - Show how this streamlined approach improves resilience and availability -- Show how the solution can then be deployed to a production-class environment - - Show how a Hyperledger Fabric network can be created and managed in Kubernetes (K8S) using automation - - Show how the Fabric Operator and Console can be installed via Ansible playbooks - - Show how a multi-organization configuration of Fabric can be created - ---- - -**Please ensure you've got the [required tools](./SETUP.md) on your local machine or in a virtual machine -- To check, run `./check.sh`** - ---- - - -## Before you begin.... - -Fabric is a multi-server decentralized system with orderer and peer nodes, so it can be quite complex to configure. Even the simplest smart contract needs a running Fabric Infrastructure and one size does not fit all. - -There are configurations that can run Fabric either as local binaries, in a single docker container, in multiple containers, or in K8S. -This workshop will show some of the approaches that can be used for developing applications and contracts with a minimal Fabric environment (Microfab), and how a production deployment can be achieved. -There are other ways of deploying Fabric produced by the community - these are equally valid and useful. Feel free to try the others, once you understand the basic concepts to find what works best for you. - -At a high-level remember that a solution using Fabric has (a) client application to send in transaction requests (b) Fabric infrastructure to service those requests (c) Smart Contract to action the transactions. -The nature of (b) the fabric infrastructure will change depending on your scenario; start simple and build up. The smart contracts and client application's code will remain the same no matter the way Fabric is provisioned. -There will be minor variations in deployment (eg local docker container vs remote K8S cluster) but fundamentally the process is the same. - -## Running the workshop - -![Windows](https://img.shields.io/badge/Windows-0078D6?style=for-the-badge&logo=windows&logoColor=white) If you're running on Windows, please check the [hints and tips](./docs/tips-for-windows-dev.md) - -- Ensure you've got the tools you may need, either installed locally or in a multipass virtual machine. See the [setup page](./SETUP.md) for details. -- Clone this repository to a convient location -- We suggest that you open 3 or 4 terminal windows - - One for running chaincode in dev mode - - One for running the fabric infrastructure and optionally one for monitoring it - - One for client applications - -- Work through the sections below in order, although you don't necessarily need to complete all the Exercises before moving to the next section. - ---- -## Scenario - -Lets assume the assets you are tracking on the blockchain ledger are trading cards. Each trading card represents a comic book character and has an id, size, favorite color, and owner. -These trading cards can be passed between people, with some cards having more 'value' due to rarity or having notable attributes. - -In token terms, think of these cards as non-fungible tokens. Each card has different attributes and individual cards can't be subdivided. - -We'll create a digital representation of these cards on the blockchain ledger. There are a few important aspects of this solution to consider: - -- Ledger - The blockchain ledger on each peer maintains the current state of each card (asset), as well as the history of transactions that led to the current state, so that there is no doubt about the assets issuance, provenance, attributes, and ownership. -- Asset transfer smart contract - manage changes to asset state such as the transfer of cards between people -- Organizations - Since this is a permissioned blockchain we'll model the participants as organizations that are authorized to run nodes or transact on the Fabric network. Our simple network will consist of an ordering service organization and two transacting organizations. - - Ordering service organization - runs the ordering service to ensure transactions get ordered into blocks fairly, this may be a consortium leader or regulator in the industry. Note that ordering service nodes could also be contributed from multiple organizations, this becomes especially important when running a Byzantine Fault Tolerant (BFT) ordering service. - - Owner Organizations - Each owner organization is authorized to run peers and submit transfer transactions for the cards (assets) that they own. - - -## Smart Contract Development - -- [Introduction](./docs/SmartContractDev/00-Introduction.md) [Español](./docs/SmartContractDev/00-Introduction-ES.md) -- **Exercise**: [Getting Started with a Smart Contract](./docs/SmartContractDev/01-Exercise-Getting-Started.md) [Español](./docs/SmartContractDev/01-Exercise-Getting-Started-ES.md) -- **Exercise**: [Adding a new transaction function](./docs/SmartContractDev/02-Exercise-Adding-tx-function.md) [Español](./docs/SmartContractDev/02-Exercise-Adding-tx-function-ES.md) -- Reference: - - [Detailed Test and Debug](./docs/SmartContractDev/03-Test-And-Debug-Reference.md) [Español](./docs/SmartContractDev/03-Test-And-Debug-Reference-ES.md) - -## Client Application Development - -- [Fabric Gateway](docs/ApplicationDev/01-FabricGateway.md) -- **Exercise:** [Run the client application](docs/ApplicationDev/02-Exercise-RunApplication.md) -- [Application overview](docs/ApplicationDev/03-ApplicationOverview.md) -- **Exercise:** [Implement asset transfer](docs/ApplicationDev/04-Exercise-AssetTransfer.md) -- [Chaincode events](docs/ApplicationDev/05-ChaincodeEvents.md) -- **Exercise:** [Use chaincode events](docs/ApplicationDev/06-Exercise-ChaincodeEvents.md) - -## Cloud Native Fabric - -- [Cloud Ready!](docs/CloudReady/00-setup.md) [中文](docs/CloudReady/00-setup-zh.md) -- **Exercise:** [Deploy a Kubernetes Cluster](docs/CloudReady/10-kube.md) [中文](docs/CloudReady/10-kube-zh.md) -- **Exercise:** [Deploy a Fabric Network](docs/CloudReady/20-fabric.md) [中文](docs/CloudReady/20-fabric-zh.md) -- **Exercise:** [Deploy a Smart Contract](docs/CloudReady/30-chaincode.md)[中文](docs/CloudReady/30-chaincode-zh.md) -- **Exercise:** [Deploy a Client Application](docs/CloudReady/40-bananas.md)[中文](docs/CloudReady/40-bananas-zh.md) - -## Epilogue - -- [Go Bananas](docs/CloudReady/40-bananas.md) -- [Bring it Home](docs/CloudReady/90-teardown.md) diff --git a/full-stack-asset-transfer-guide/SETUP.md b/full-stack-asset-transfer-guide/SETUP.md deleted file mode 100644 index 4f8f0d2d..00000000 --- a/full-stack-asset-transfer-guide/SETUP.md +++ /dev/null @@ -1,138 +0,0 @@ -# Essential Setup - -Remember to clone this repository! - -```shell -git clone https://github.com/hyperledger/fabric-samples.git fabric-samples -cd fabric-samples/full-stack-asset-transfer-guide -export WORKSHOP_PATH=$(pwd) -``` - -> to check the tools you already have `./check.sh` - -## Option 1: Use local environment - -Do you want to configure your local environment with the workshop dependencies? - -- To develop an application and/or contract (first two parts of workshop) follow the *DEV* setup below - -- To deploy a chaincode to kubernetes in a production manner (third part of workshop) follow the *PROD* setup below - -## Option 2: Use a Multipass Ubuntu image - -If you do not want to install dependencies on your local environment, you can use a Multipass Ubuntu image instead. - -Tip - You may need to stop any VPN client for the Multipass networking to work. - -- [Install multipass](https://multipass.run/install) - -- Launch the virtual machine and automatically install the workshop dependencies: - -```shell -multipass launch \ - --name fabric-dev \ - --disk 80G \ - --cpus 8 \ - --mem 8G \ - --cloud-init infrastructure/multipass-cloud-config.yaml -``` - -- Mount the local workshop to your multipass vm: - -```shell -multipass mount $PWD fabric-dev:/home/ubuntu/full-stack-asset-transfer-guide -``` - -- Open a shell on the virtual machine: - -```shell -multipass shell fabric-dev -``` - -Tip - The vm creation log can be seen at /var/log/cloud-init-output.log if you need to troubleshoot anything. - -- You are now inside the virtual machine. cd to the workshop directory: - -```shell -cd full-stack-asset-transfer-guide -``` - -- Install Fabric peer CLI and set environment variables -```shell -curl -sSLO https://raw.githubusercontent.com/hyperledger/fabric/main/scripts/install-fabric.sh && chmod +x install-fabric.sh -./install-fabric.sh binary -export WORKSHOP_PATH=$(pwd) -export PATH=${WORKSHOP_PATH}/bin:$PATH -export FABRIC_CFG_PATH=${WORKSHOP_PATH}/config -``` - -Note - You'll probably want three terminal windows for running the workshop, go ahead and open the shells now: - -```shell -multipass shell fabric-dev -``` - -- Eventual cleanup - To remove the multipass image when you are done with it after the workshop: -```shell -multipass delete fabric-dev -multipass purge -multipass list -``` - -## DEV - Required Tools - -You will need a set of tools to assist with chaincode and application development. -We'll assume you are developing in Node for this workshop, but you could also develop in Java or Go by installing the respective compilers. - -- [docker engine](https://docs.docker.com/engine/install/) - -- [just](https://github.com/casey/just#installation) to run all the commands here directly - -- [nvm](https://github.com/nvm-sh/nvm#installing-and-updating) to install node and npm -```shell -curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash -``` - -- [node v16 and npm](https://github.com/nvm-sh/nvm#usage) to run node chaincode and applications -```shell -nvm install 16 -``` - -- [typescript](https://www.typescriptlang.org/download) to compile typescript chaincode and applications to node -```shell -npm install -g typescript -``` - -- [weft ](https://www.npmjs.com/package/@hyperledger-labs/weft) Hyperledger-Labs cli to work with identities and chaincode packages -```shell -npm install -g @hyperledger-labs/weft -``` - -- [jq](https://stedolan.github.io/jq/) jq JSON command-line processor -```shell -sudo apt-get update && sudo apt-get install -y jq -``` - -- Fabric peer CLI -```shell -curl -sSL https://raw.githubusercontent.com/hyperledger/fabric/main/scripts/install-fabric.sh | bash -s -- binary -export WORKSHOP_PATH=$(pwd) -export PATH=${WORKSHOP_PATH}/bin:$PATH -export FABRIC_CFG_PATH=${WORKSHOP_PATH}/config -``` - -## PROD - Required Tools for Kubernetes Deployment - -- [kubectl](https://kubernetes.io/docs/tasks/tools/) -- [jq](https://stedolan.github.io/jq/) -- [just](https://github.com/casey/just#installation) to run all the comamnds here directly -- [kind](https://kind.sigs.k8s.io/) if you want to create a cluster locally, see below for other options -- [k9s](https://k9scli.io) (recommended, but not essential) - -### Beta Ansible Playbooks - -The v2.0.0-beta Ansible Collection for Hyperledger Fabric is required for Kubernetes deployment. This isn't yet being published to DockerHub but is being published to Github Packages. - -For reference check the latest version of [ofs-ansible](https://github.com/IBM-Blockchain/ansible-collection/pkgs/container/ofs-ansibe) - -The Ansible scripts in the workshop are set to use the latest image here by default. diff --git a/full-stack-asset-transfer-guide/applications/conga-cards/.eslintrc.js b/full-stack-asset-transfer-guide/applications/conga-cards/.eslintrc.js deleted file mode 100644 index ad992fae..00000000 --- a/full-stack-asset-transfer-guide/applications/conga-cards/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - root: true, - parser: '@typescript-eslint/parser', - plugins: [ - '@typescript-eslint', - ], - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'prettier', - ], -}; \ No newline at end of file diff --git a/full-stack-asset-transfer-guide/applications/conga-cards/.gitignore b/full-stack-asset-transfer-guide/applications/conga-cards/.gitignore deleted file mode 100644 index 1276eb3b..00000000 --- a/full-stack-asset-transfer-guide/applications/conga-cards/.gitignore +++ /dev/null @@ -1,18 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -# Coverage directory used by tools like istanbul -coverage - -# Dependencies -node_modules/ -jspm_packages/ -package-lock.json - -# Compiled TypeScript files -dist - -# Files generated by the application at runtime -checkpoint.json -store.log diff --git a/full-stack-asset-transfer-guide/applications/conga-cards/.npmrc b/full-stack-asset-transfer-guide/applications/conga-cards/.npmrc deleted file mode 100644 index b6f27f13..00000000 --- a/full-stack-asset-transfer-guide/applications/conga-cards/.npmrc +++ /dev/null @@ -1 +0,0 @@ -engine-strict=true diff --git a/full-stack-asset-transfer-guide/applications/conga-cards/README.md b/full-stack-asset-transfer-guide/applications/conga-cards/README.md deleted file mode 100644 index e99b1bcc..00000000 --- a/full-stack-asset-transfer-guide/applications/conga-cards/README.md +++ /dev/null @@ -1,73 +0,0 @@ -# Conga Cards - -This Gateway Client application will listen for chaincode events, invoking a [#discord webhook](https://discord.com/developers/docs/resources/webhook) -to post a channel message when [Conga Cards](assets/) are created, deleted, and exchanged on a channel. - -> [Conga Comics](https://congacomic.github.io) | Life on the chain, one block at a time by Ed Moffatt & some friends - -This project is based on the [trader-typescript](../trader-typescript) sample Gateway Client application. - - -## Prerequisites - -The client application requires Node.js 16 or later. - -## Set up - -The following steps prepare the client application for execution: - -1. Ensure the [asset-transfer](../../contracts/asset-transfer-typescript/) smart contract is deployed to a running Fabric network. -1. Run `npm install` to download dependencies and compile the application code. - -> **Note:** After making any code changes to the application, be sure to recompile the application code. This can be done by explicitly running `npm install` again, or you can leave `npm run build:watch` running in a terminal window to automatically rebuild the application on any code change. - - -The client application uses environment variables to supply configuration options. You must set the following environment variables when running the application: - -- `ENDPOINT` - endpoint address for the Gateway service to which the client will connect in the form **hostname:port**. Depending on your environment, this can be the address of a specific peer within the user's organization, or an ingress endpoint that dispatches to any available peer in the user's organization. -- `MSP_ID` - member service provider ID for the user's organization. -- `CERTIFICATE` - PEM file containing the user's X.509 certificate. -- `PRIVATE_KEY` - PEM file containing the user's private key. - -The following environment variables are optional and can be set if required by your environment: - -- `CHANNEL_NAME` - Channel to which the chaincode is deployed. (Default: `mychannel`) -- `CHAINCODE_NAME` - Channel to which the chaincode is deployed. (Default: `asset-transfer`) -- `TLS_CERT` - PEM file containing the CA certificate used to authenticate the TLS connection to the Gateway peer. *Only required if using a TLS connection and a private CA.* -- `HOST_ALIAS` - the name of the Gateway peer as it appears in its TLS certificate. *Only required if the endpoint address used by the client does not match the address in the Gateway peer's TLS certificate.* - -- `WEBHOOK_URL` - the [#discord webhook](https://discord.com/developers/docs/resources/webhook) to which the channel - events will be relayed. - - -# Run - -The sample application is run as a command-line application, and is lauched using `npm start [ ...]`. The following commands are available: - -- `npm start create ` to create a new asset. -- `npm start delete ` to delete an existing asset. -- `npm start getAllAssets` to list all assets. -- `npm start read ` to view an existing asset. -- `npm start transfer ` to transfer an asset to a new owner within an organization MSP ID. -- `npm start discord` starts an event loop, relaying channel events to `${WEBHOOK_URL}` - - -## Sample Interaction: - -- Submit some transactions to a ledger: -```shell -npm start create blockbert SeanB orange - -npm start create count-blockula jkneubuhl Org1MSP purple - -npm start transfer count-blockula davidboswell Org1MSP -``` - -- Run the discord event listener: -```shell -export WEBHOOK_URL="https://discord.com/api/webhooks/123456789/xyzzy-abcdef-12345" - -npm start discord -``` - -![Sample Interaction](images/interaction.png) \ No newline at end of file diff --git a/full-stack-asset-transfer-guide/applications/conga-cards/assets/appleplectic.png b/full-stack-asset-transfer-guide/applications/conga-cards/assets/appleplectic.png deleted file mode 100644 index 7a8da445a68fce3e4a0e26c912f3010a76d2ede7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 64230 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 kZ@S?fi~^EV&<7wUK9!~g&Q diff --git a/full-stack-asset-transfer-guide/applications/conga-cards/assets/bananomatopoeia.png b/full-stack-asset-transfer-guide/applications/conga-cards/assets/bananomatopoeia.png deleted file mode 100644 index 40fcba2587f2fd54c706ca8a8a391fcc99a30ea3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 113103 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≠49QfulGh_r&zo(mAxxZ9LCD1Yi!FT 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