From 50f6ce5dc35f640cbf0b22f6c7ac357e299586a5 Mon Sep 17 00:00:00 2001 From: Michal Bajer Date: Thu, 12 Oct 2023 10:21:19 +0000 Subject: [PATCH] feat(cactus-plugin-ledger-connector-fabric-socketio): remove fabric-socketio connector - Remove cactus-plugin-ledger-connector-fabric-socketio connector. - Refactor discounted cartrade sample to use openapi fabric connector instead of fabric-socketio. Sample app will use delegated signing, similar to offline signing in old connector. - Remove dead code from cmd-socketio-server - Update fabric SDK to 2.X in all cacti projects, refactor code that use it where necessary. Only exception is fabric persistence plugin which uses fabric SDK as dev dependency (for tests). It can be updated in separate PR later on. Depends on: #2644 Signed-off-by: Michal Bajer --- .github/workflows/ci.yaml | 27 - .../README.md | 25 +- .../business-logic-asset-trade.ts | 282 ++--- .../config/usersetting.yaml | 22 +- .../config/validator-registry-config.yaml | 48 +- .../docker-compose.yml | 56 +- .../fabric-asset-management.ts | 70 -- .../fabric-asset.ts | 9 +- .../fabric-connector.ts | 322 +++++ .../package.json | 10 +- .../read-ledger-state.js | 2 +- .../script-dockerless-config-patch.sh | 2 - .../script-post-trade-request.sh | 5 + .../script-start-ledgers.sh | 12 +- .../sign-utils.ts | 105 -- .../template-trade-management.ts | 105 -- .../template-trade.ts | 117 -- .../transaction-fabric.ts | 227 +--- .../tsconfig.json | 23 +- .../www.ts | 19 +- .../cactus-cmd-socketio-server/package.json | 4 +- .../main/typescript/util/TransactionSigner.ts | 295 +---- .../CHANGELOG.md | 90 -- .../Dockerfile | 15 - .../README.md | 89 -- .../package.json | 51 - .../sample-config/default.yaml | 37 - .../sample-config/wallet/.gitkeep | 0 .../src/.gitignore | 9 - .../src/main/typescript/common/core/app.ts | 53 - .../main/typescript/common/core/bin/www.ts | 302 ----- .../connector/ServerMonitorPlugin.ts | 188 --- .../main/typescript/connector/ServerPlugin.ts | 1066 ----------------- .../connector/fabric-proto-serializers.ts | 162 --- .../main/typescript/connector/fabricaccess.ts | 176 --- .../main/typescript/connector/sign-utils.ts | 105 -- .../template/PluginConfig_template.ts | 16 - .../connector/template/PluginUtil_template.ts | 14 - .../template/ServerMonitorPlugin_template.ts | 59 - .../template/ServerPlugin_template.ts | 59 - .../connector/template/package_template.json | 7 - .../src/main/typescript/index.ts | 1 - .../src/main/typescript/public-api.ts | 1 - .../integration/fabric-setup-helpers.ts | 165 --- .../fabric-socketio-connector.test.ts | 794 ------------ .../src/test/typescript/unit-test/.gitignore | 4 - .../test/typescript/unit-test/PluginConfig.ts | 42 - .../unit-test/config/connection.json | 52 - .../typescript/unit-test/config/default.js | 41 - .../typescript/unit-test/copyStaticAssets.ts | 8 - .../test/typescript/unit-test/createCar.ts | 90 -- .../unit-test/fabric-docker/.gitignore | 4 - .../unit-test/fabric-docker/README.md | 79 -- .../test/typescript/unit-test/package.json | 24 - .../src/test/typescript/unit-test/queryCar.ts | 86 -- .../test/typescript/unit-test/tsconfig.json | 21 - .../validatorDriver_changeCarOwner.ts | 112 -- .../unit-test/validatorDriver_queryAllCars.ts | 104 -- .../unit-test/validatorDriver_queryCar.ts | 105 -- .../validatorDriver_signTransactionOffline.ts | 407 ------- .../tsconfig.json | 30 - .../fabric-watch-blocks-v1-endpoint.test.ts | 1 - packages/cactus-verifier-client/README.md | 2 +- .../asset-transfer-basic-utils/README.md | 2 +- .../asset-transfer-basic-utils/enrollAdmin.js | 26 +- .../asset-transfer-basic-utils/package.json | 4 +- .../asset-transfer-basic-utils/query.js | 22 +- .../registerUser.js | 60 +- tsconfig.json | 3 - yarn.lock | 97 +- 70 files changed, 672 insertions(+), 6000 deletions(-) delete mode 100644 examples/cactus-example-discounted-asset-trade/fabric-asset-management.ts create mode 100644 examples/cactus-example-discounted-asset-trade/fabric-connector.ts delete mode 100644 examples/cactus-example-discounted-asset-trade/sign-utils.ts delete mode 100644 examples/cactus-example-discounted-asset-trade/template-trade-management.ts delete mode 100644 examples/cactus-example-discounted-asset-trade/template-trade.ts delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/CHANGELOG.md delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/Dockerfile delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/README.md delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/package.json delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/sample-config/default.yaml delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/sample-config/wallet/.gitkeep delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/.gitignore delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/common/core/app.ts delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/common/core/bin/www.ts delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/ServerMonitorPlugin.ts delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/ServerPlugin.ts delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/fabric-proto-serializers.ts delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/fabricaccess.ts delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/sign-utils.ts delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/template/PluginConfig_template.ts delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/template/PluginUtil_template.ts delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/template/ServerMonitorPlugin_template.ts delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/template/ServerPlugin_template.ts delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/template/package_template.json delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/index.ts delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/public-api.ts delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/integration/fabric-setup-helpers.ts delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/integration/fabric-socketio-connector.test.ts delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/.gitignore delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/PluginConfig.ts delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/config/connection.json delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/config/default.js delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/copyStaticAssets.ts delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/createCar.ts delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/fabric-docker/.gitignore delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/fabric-docker/README.md delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/package.json delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/queryCar.ts delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/tsconfig.json delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/validatorDriver_changeCarOwner.ts delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/validatorDriver_queryAllCars.ts delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/validatorDriver_queryCar.ts delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/validatorDriver_signTransactionOffline.ts delete mode 100644 packages/cactus-plugin-ledger-connector-fabric-socketio/tsconfig.json diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 13dc53ff7a..5f385de063 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1215,33 +1215,6 @@ jobs: - run: npm run configure - run: yarn ts-node ./packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/run-transaction-with-ws-ids.test.ts - cactus-plugin-ledger-connector-fabric-socketio: - continue-on-error: false - env: - FULL_BUILD_DISABLED: true - JEST_TEST_PATTERN: packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/(unit|integration|benchmark)/.*/*.test.ts - JEST_TEST_RUNNER_DISABLED: false - TAPE_TEST_RUNNER_DISABLED: true - needs: build-dev - runs-on: ubuntu-20.04 - steps: - - name: Use Node.js v16.14.2 - uses: actions/setup-node@v3.6.0 - with: - node-version: v16.14.2 - - uses: actions/checkout@v3.5.2 - - - id: yarn-cache - name: Restore Yarn Cache - uses: actions/cache@v3.3.1 - with: - key: ${{ runner.os }}-yarn-${{ hashFiles('./yarn.lock') }} - path: ./.yarn/ - restore-keys: | - ${{ runner.os }}-yarn-${{ hashFiles('./yarn.lock') }} - - run: yarn --version - - run: yarn install - - run: ./tools/ci.sh cactus-plugin-ledger-connector-go-ethereum-socketio: continue-on-error: false env: diff --git a/examples/cactus-example-discounted-asset-trade/README.md b/examples/cactus-example-discounted-asset-trade/README.md index 10dd5033db..afcd48ecb3 100644 --- a/examples/cactus-example-discounted-asset-trade/README.md +++ b/examples/cactus-example-discounted-asset-trade/README.md @@ -26,10 +26,10 @@ Alice will use credentials and other Indy formats such as schema and definition ## Setup Overview -### fabric-socketio-validator +### fabric-connector - Validator for fabric ledger. -- Docker networks: `fabric-all-in-one_testnet-2x`, `cactus-example-discounted-asset-trade-net` +- Started as part of discounted asset trade BLP. ### ethereum-validator @@ -114,8 +114,6 @@ Alice will use credentials and other Indy formats such as schema and definition ``` cactus-example-discounted-asset-trade-ethereum-validator | listening on *:5050 ... - cactus-example-discounted-asset-trade-fabric-socketio-validator | listening on *:5040 - ... cactus-example-discounted-asset-trade-indy-validator | 2022-01-31 16:00:49,552 INFO success: validator entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) ... cactus-example-discounted-asset-trade-indy-validator-nginx | 2022/01/31 16:00:49 [notice] 1#1: start worker process 35 @@ -154,9 +152,6 @@ For development purposes, it might be useful to run the sample application outsi 1. Configure cactus and start the ledgers as described above. 1. Run `./script-dockerless-config-patch.sh` from `cactus-example-discounted-asset-trade/` directory. This will patch the configs and copy it to global location. 1. Start validators (each in separate cmd window). - 1. ```bash - cd packages/cactus-plugin-ledger-connector-fabric-socketio/ && npm run start - ``` 1. ```bash cd packages/cactus-plugin-ledger-connector-go-ethereum-socketio/ && npm run start ``` @@ -207,8 +202,6 @@ For development purposes, it might be useful to run the sample application outsi 1. Run the transaction execution: - **For docker-compose environment, run:** - ``` ./script-post-trade-request.sh ``` @@ -219,17 +212,10 @@ For development purposes, it might be useful to run the sample application outsi docker run --rm -ti -v "$(pwd)/etc/cactus/":"/etc/cactus/" --net="host" register-indy-data ``` - **For dockerless environment, run:** - - ```bash - pushd ../register-indy-data && sh ./script-build-docker.sh && popd && - docker run --rm -ti -v/etc/cactus/:/etc/cactus/ --net="host" register-indy-data --force - ``` - **After sending the requests** - The transactions are executed by order. - - When the following log appears on the BLP console, the transactions are completed. + - When the following log appears on the BLP console, the transactions are completed (you may need to scroll a bit to find it). ``` [INFO] BusinessLogicAssetTrade - ##INFO: completed asset-trade, businessLogicID: guks32pf, tradeID: *******-001 @@ -295,3 +281,8 @@ For development purposes, it might be useful to run the sample application outsi ./script-cleanup.sh popd ``` + +#### Possible improvements +- Ethereum events are duplicated, causing trade to proceed even if previous step was not successfull. + - Handle this case properly - ignore duplciated events, move forward only if current step was completed. + - Investigate and fix duplicated events in Verifier / Ethereum connector (or use openapi ethereum connector). diff --git a/examples/cactus-example-discounted-asset-trade/business-logic-asset-trade.ts b/examples/cactus-example-discounted-asset-trade/business-logic-asset-trade.ts index 7f636de727..24cd7b3bc2 100644 --- a/examples/cactus-example-discounted-asset-trade/business-logic-asset-trade.ts +++ b/examples/cactus-example-discounted-asset-trade/business-logic-asset-trade.ts @@ -17,7 +17,7 @@ import { routesTransactionManagement } from "@hyperledger/cactus-cmd-socketio-se import { BusinessLogicBase } from "@hyperledger/cactus-cmd-socketio-server"; import { LPInfoHolder } from "@hyperledger/cactus-cmd-socketio-server"; import { makeRawTransaction } from "./transaction-ethereum"; -import { makeSignedProposal } from "./transaction-fabric"; +import { transferOwnership } from "./transaction-fabric"; import { getDataFromIndy } from "./transaction-indy"; import { LedgerEvent, @@ -29,10 +29,20 @@ import { VerifierFactory, VerifierFactoryConfig, } from "@hyperledger/cactus-verifier-client"; +import { + WatchBlocksCactusTransactionsEventV1, + WatchBlocksListenerTypeV1, + WatchBlocksResponseV1, +} from "@hyperledger/cactus-plugin-ledger-connector-fabric"; const config: any = ConfigUtil.getConfig(); import { getLogger } from "log4js"; +import { + createSigningToken, + getFabricApiClient, + getSignerIdentity, +} from "./fabric-connector"; const moduleName = "BusinessLogicAssetTrade"; const logger = getLogger(`${moduleName}`); logger.level = config.logLevel; @@ -220,15 +230,8 @@ export class BusinessLogicAssetTrade extends BusinessLogicBase { // get schema & credential definition from indy // now verifierGetEntitiesFromLedger don't get revRegDefs & revRegs // did is null. If it is null, indy.buidlGetSchemaRequest API get data by default param. - const [ - schemasJson, - credDefsJson, - revRegDefsJson, - revRegsJson, - ] = await this.verifierGetEntitiesFromLedger( - null, - proofJson["identifiers"], - ); + const [schemasJson, credDefsJson, revRegDefsJson, revRegsJson] = + await this.verifierGetEntitiesFromLedger(null, proofJson["identifiers"]); assert( "Permanent" === @@ -412,70 +415,62 @@ export class BusinessLogicAssetTrade extends BusinessLogicBase { ): void { logger.debug("called secondTransaction"); - ///// Fab Transfer - - // Get Verifier Instance - logger.debug( - `##secondTransaction(): businessLogicID: ${tradeInfo.businessLogicID}`, - ); - const useValidator = JSON.parse( - routesTransactionManagement.getValidatorToUse(tradeInfo.businessLogicID), - ); - const verifierFabric = routesVerifierFactory.getVerifier( - useValidator["validatorID"][1], - ); - verifierFabric.startMonitor( - "BusinessLogicAssetTrade", - {}, - routesTransactionManagement, - ); - logger.debug("getVerifierFabric"); - - // Generate parameters for sendSignedProposal(TransferAsset) - const ccFncName = "TransferAsset"; - - const ccArgs: string[] = [ - assetID, // assetID - fabricAccountTo, // Owner - ]; - makeSignedProposal(ccFncName, ccArgs, verifierFabric) - .then((result) => { - logger.info("secondTransaction txId : " + result.txId); - - // Register transaction data in DB - const transactionData: TransactionData = new TransactionData( - "transfer", - "ledger002", - result.txId, - ); - this.transactionInfoManagement.setTransactionData( - tradeInfo, - transactionData, - ); + // Start monitoring + const fabricApiClient = getFabricApiClient(); + const watchObservable = fabricApiClient.watchBlocksDelegatedSignV1({ + channelName: config.assetTradeInfo.fabric.channelName, + type: WatchBlocksListenerTypeV1.CactusTransactions, + signerCertificate: getSignerIdentity().credentials.certificate, + signerMspID: getSignerIdentity().mspId, + uniqueTransactionData: createSigningToken("watchBlock"), + }); + const watchSub = watchObservable.subscribe({ + next: (event: WatchBlocksResponseV1) => { + if (!("cactusTransactionsEvents" in event)) { + logger.error("Wrong input block format!", event); + return; + } - // Call sendSignedTransactionV2 - const contract = { - channelName: config.assetTradeInfo.fabric.channelName, - }; - const method = { type: "function", command: "sendSignedTransactionV2" }; - const args = { - args: result.signedTxArgs, - }; - - // Run Verifier (Fabric) - logger.debug("Sending fabric.sendSignedTransactionV2"); - verifierFabric - .sendAsyncRequest(contract, method, args) - .then(() => { - logger.debug(`##secondTransaction sendAsyncRequest finish`); - }) - .catch((err) => { - logger.error(err); - }); - }) - .catch((err) => { - logger.error(err); - }); + for (const ev of event.cactusTransactionsEvents) { + logger.debug(`##in onEventFabric()`); + + try { + const txId = ev.transactionId; + logger.debug(`##txId = ${txId}`); + if (this.hasTxIDInTransactions(txId)) { + watchSub.unsubscribe(); + this.executeNextTransaction(ev, txId); + break; + } + } catch (err) { + logger.error( + `##onEventFabric(): onEvent, err: ${err}, event: ${JSON.stringify( + ev, + )}`, + ev, + ); + } + } + }, + error(err: unknown) { + logger.error("Fabric watchBlocksV1() error:", err); + }, + }); + + transferOwnership(assetID, fabricAccountTo).then((result) => { + logger.info("secondTransaction txId : " + result.transactionId); + + // Register transaction data in DB + const transactionData: TransactionData = new TransactionData( + "transfer", + "ledger002", + result.transactionId, + ); + this.transactionInfoManagement.setTransactionData( + tradeInfo, + transactionData, + ); + }); } thirdTransaction( @@ -578,9 +573,6 @@ export class BusinessLogicAssetTrade extends BusinessLogicBase { case config.assetTradeInfo.ethereum.validatorID: this.onEvenEtherem(ledgerEvent.data, targetIndex); break; - case config.assetTradeInfo.fabric.validatorID: - this.onEvenFabric(ledgerEvent.data, targetIndex); - break; default: logger.error( `##onEvent(), invalid verifierId: ${ledgerEvent.verifierId}`, @@ -634,67 +626,15 @@ export class BusinessLogicAssetTrade extends BusinessLogicBase { } } - onEvenFabric(event: FabricEvent, targetIndex: number): void { - logger.debug(`##in onEvenFabric()`); - const tx: - | { - txId: string; - } - | undefined = this.getTransactionFromFabricEvent(event, targetIndex); - if (tx == null) { - logger.warn(`##onEvenFabric(): invalid event: ${json2str(event)}`); - return; - } - - try { - const txId = tx["txId"]; - const status = event["status"]; - logger.debug(`##txId = ${txId}`); - logger.debug(`##status =${status}`); - - if (status !== 200) { - logger.error( - `##onEvenFabric(): error event, status: ${status}, txId: ${txId}`, - ); - return; - } - - // Perform the following transaction actions - this.executeNextTransaction(tx, txId); - } catch (err) { - logger.error( - `##onEvenFabric(): onEvent, err: ${err}, event: ${json2str(event)}`, - ); - } - } - - getTransactionFromFabricEvent( - event: FabricEvent, - targetIndex: number, - ): FabricEvent | undefined { - try { - const retTransaction = event["blockData"][targetIndex]; - logger.debug( - `##getTransactionFromFabricEvent(): retTransaction: ${retTransaction}`, - ); - return retTransaction; - } catch (err) { - logger.error( - `##getTransactionFromFabricEvent(): invalid even, err:${err}, event:${event}`, - ); - } - } - executeNextTransaction( - txInfo: Record | EthData, + txInfo: WatchBlocksCactusTransactionsEventV1 | EthData, txId: string, ): void { let transactionInfo: TransactionInfo | null = null; try { // Retrieve DB transaction information - transactionInfo = this.transactionInfoManagement.getTransactionInfoByTxId( - txId, - ); + transactionInfo = + this.transactionInfoManagement.getTransactionInfoByTxId(txId); if (transactionInfo != null) { logger.debug( `##onEvent(A), transactionInfo: ${json2str(transactionInfo)}`, @@ -704,9 +644,8 @@ export class BusinessLogicAssetTrade extends BusinessLogicBase { return; } const txStatus = transactionInfo.status; - const tradeInfo = this.createTradeInfoFromTransactionInfo( - transactionInfo, - ); + const tradeInfo = + this.createTradeInfoFromTransactionInfo(transactionInfo); let txInfoData: TxInfoData; switch (txStatus) { @@ -792,10 +731,12 @@ export class BusinessLogicAssetTrade extends BusinessLogicBase { getOperationStatus(tradeID: string): TransactionStatusData { logger.debug(`##in getOperationStatus()`); - const businessLogicInquireAssetTradeStatus: BusinessLogicInquireAssetTradeStatus = new BusinessLogicInquireAssetTradeStatus(); - const transactionStatusData = businessLogicInquireAssetTradeStatus.getAssetTradeOperationStatus( - tradeID, - ); + const businessLogicInquireAssetTradeStatus: BusinessLogicInquireAssetTradeStatus = + new BusinessLogicInquireAssetTradeStatus(); + const transactionStatusData = + businessLogicInquireAssetTradeStatus.getAssetTradeOperationStatus( + tradeID, + ); return transactionStatusData; } @@ -807,22 +748,17 @@ export class BusinessLogicAssetTrade extends BusinessLogicBase { logger.debug(`##in getTxIDFromEvent`); logger.debug(`##event: ${json2str(ledgerEvent)}`); - switch (ledgerEvent.verifierId) { - case config.assetTradeInfo.ethereum.validatorID: - return this.getTxIDFromEventEtherem(ledgerEvent.data, targetIndex); - case config.assetTradeInfo.fabric.validatorID: - return this.getTxIDFromEventFabric(ledgerEvent.data, targetIndex); - default: - logger.error( - `##getTxIDFromEvent(): invalid verifierId: ${ledgerEvent.verifierId}`, - ); + if (ledgerEvent.verifierId !== config.assetTradeInfo.ethereum.validatorID) { + logger.error( + `##getTxIDFromEvent(): invalid verifierId: ${ledgerEvent.verifierId}`, + ); } - return null; - } - getTxIDFromEventEtherem(event: EthEvent, targetIndex: number): string | null { logger.debug(`##in getTxIDFromEventEtherem()`); - const tx = this.getTransactionFromEthereumEvent(event, targetIndex); + const tx = this.getTransactionFromEthereumEvent( + ledgerEvent.data, + targetIndex, + ); if (tx == null) { logger.warn(`#getTxIDFromEventEtherem(): skip(not found tx)`); return null; @@ -834,7 +770,7 @@ export class BusinessLogicAssetTrade extends BusinessLogicBase { if (typeof txId !== "string") { logger.warn( `#getTxIDFromEventEtherem(): skip(invalid block, not found txId.), event: ${json2str( - event, + ledgerEvent.data, )}`, ); return null; @@ -844,40 +780,9 @@ export class BusinessLogicAssetTrade extends BusinessLogicBase { return txId; } catch (err) { logger.error( - `##getTxIDFromEventEtherem(): err: ${err}, event: ${json2str(event)}`, - ); - return null; - } - } - - getTxIDFromEventFabric( - event: FabricEvent, - targetIndex: number, - ): string | null { - logger.debug(`##in getTxIDFromEventFabric()`); - const tx = this.getTransactionFromFabricEvent(event, targetIndex); - if (tx == null) { - logger.warn(`#getTxIDFromEventFabric(): skip(not found tx)`); - return null; - } - - try { - const txId = tx["txId"]; - - if (typeof txId !== "string") { - logger.warn( - `#getTxIDFromEventFabric(): skip(invalid block, not found txId.), event: ${json2str( - event, - )}`, - ); - return null; - } - - logger.debug(`###getTxIDFromEventFabric(): txId: ${txId}`); - return txId; - } catch (err) { - logger.error( - `##getTxIDFromEventFabric(): err: ${err}, event: ${json2str(event)}`, + `##getTxIDFromEventEtherem(): err: ${err}, event: ${json2str( + ledgerEvent.data, + )}`, ); return null; } @@ -885,9 +790,8 @@ export class BusinessLogicAssetTrade extends BusinessLogicBase { hasTxIDInTransactions(txID: string): boolean { logger.debug(`##in hasTxIDInTransactions(), txID: ${txID}`); - const transactionInfo = this.transactionInfoManagement.getTransactionInfoByTxId( - txID, - ); + const transactionInfo = + this.transactionInfoManagement.getTransactionInfoByTxId(txID); logger.debug(`##hasTxIDInTransactions(), ret: ${transactionInfo !== null}`); return transactionInfo !== null; } diff --git a/examples/cactus-example-discounted-asset-trade/config/usersetting.yaml b/examples/cactus-example-discounted-asset-trade/config/usersetting.yaml index 870baf0994..d5c4d2983b 100644 --- a/examples/cactus-example-discounted-asset-trade/config/usersetting.yaml +++ b/examples/cactus-example-discounted-asset-trade/config/usersetting.yaml @@ -1,33 +1,29 @@ # Overwrite defaults blpRegistry: - - - businessLogicID: guks32pf - validatorID: [84jUisrs, r9IS4dDf] + - businessLogicID: guks32pf + validatorID: [84jUisrs] logLevel: debug appRouters: - - - path: /api/v1/bl/trades/ + - path: /api/v1/bl/trades/ routerJs: /root/cactus/dist/trades.js - - - path: /api/v1/bl/balance/ + - path: /api/v1/bl/balance/ routerJs: /root/cactus/dist/balance.js - - - path: /api/v1/bl/fabric-asset/ + - path: /api/v1/bl/fabric-asset/ routerJs: /root/cactus/dist/fabric-asset.js # BLP Config assetTradeInfo: fabric: - validatorID: r9IS4dDf mspID: Org1MSP - keystore: "/etc/cactus/connector-fabric-socketio/wallet" + keystore: "/etc/cactus/connector-fabric/wallet" + hostname: localhost connUserName: appUser contractName: basic + tokenSecret: secret123 peers: - - - name: peer0.org1.example.com + - name: peer0.org1.example.com requests: grpc://localhost:7051 orderer: name: orderer.example.com diff --git a/examples/cactus-example-discounted-asset-trade/config/validator-registry-config.yaml b/examples/cactus-example-discounted-asset-trade/config/validator-registry-config.yaml index f8ba020811..6268597870 100644 --- a/examples/cactus-example-discounted-asset-trade/config/validator-registry-config.yaml +++ b/examples/cactus-example-discounted-asset-trade/config/validator-registry-config.yaml @@ -1,6 +1,5 @@ ledgerPluginInfo: - - - validatorID: 84jUisrs + - validatorID: 84jUisrs validatorType: legacy-socketio validatorURL: https://ethereum-validator:5050 validatorKeyPath: /etc/cactus/connector-go-ethereum-socketio/CA/connector.crt @@ -13,48 +12,24 @@ ledgerPluginInfo: ledgerInfo: ledgerAbstract: Go-Ethereum Ledger apiInfo: - - - apiType: getNumericBalance + - apiType: getNumericBalance requestedData: - - - dataName: referedAddress + - dataName: referedAddress dataType: string - - - apiType: transferNumericAsset + - apiType: transferNumericAsset requestedData: - - - dataName: fromAddress + - dataName: fromAddress dataType: string - - - dataName: toAddress + - dataName: toAddress dataType: string - - - dataName: amount + - dataName: amount dataType: number - - - apiType: sendRawTransaction + - apiType: sendRawTransaction requestedData: - - - dataName: serializedTx + - dataName: serializedTx dataType: string - - - validatorID: r9IS4dDf - validatorType: legacy-socketio - validatorURL: https://fabric-socketio-validator:5040 - validatorKeyPath: /etc/cactus/connector-fabric-socketio/CA/connector.crt - maxCounterRequestID: 100 - syncFunctionTimeoutMillisecond: 5000 - socketOptions: - rejectUnauthorized: false - reconnection: false - timeout: 20000 - ledgerInfo: - ledgerAbstract: Fabric Ledger - apiInfo: [] - - - - validatorID: 3PfTJw8g + - validatorID: 3PfTJw8g validatorType: legacy-socketio validatorURL: http://indy-validator-nginx:10080 validatorKeyPath: /etc/cactus/validator_socketio_indy/CA/connector.crt @@ -79,8 +54,7 @@ signTxInfo: fabric: mspID: Org1MSP peers: - - - name: peer0.org1.example.com + - name: peer0.org1.example.com requests: grpc://localhost:7051 orderer: URL: grpc://localhost:7050 diff --git a/examples/cactus-example-discounted-asset-trade/docker-compose.yml b/examples/cactus-example-discounted-asset-trade/docker-compose.yml index 81d1260375..b813f0c6aa 100644 --- a/examples/cactus-example-discounted-asset-trade/docker-compose.yml +++ b/examples/cactus-example-discounted-asset-trade/docker-compose.yml @@ -12,23 +12,6 @@ services: context: ../../packages/cactus-cmd-socketio-server/ command: ["echo", "OK - Exit"] - fabric-socketio-validator: - container_name: cactus-example-discounted-asset-trade-fabric-socketio-validator - image: cactus-plugin-ledger-connector-fabric-socketio - build: - context: ../../packages/cactus-plugin-ledger-connector-fabric-socketio/ - ports: - - "5040:5040" - depends_on: - - cmd-socketio-base-image - volumes: - - type: bind - source: ./etc/cactus - target: /etc/cactus - networks: - - fabric-all-in-one_testnet-2x - - cactus-example-discounted-asset-trade-net - ethereum-validator: container_name: cactus-example-discounted-asset-trade-ethereum-validator image: cactus-plugin-ledger-connector-go-ethereum-socketio @@ -39,12 +22,12 @@ services: depends_on: - cmd-socketio-base-image volumes: - - type: bind - source: ./etc/cactus - target: /etc/cactus + - type: bind + source: ./etc/cactus + target: /etc/cactus networks: - - geth1net - - cactus-example-discounted-asset-trade-net + - geth1net + - cactus-example-discounted-asset-trade-net indy-sdk-cli-base-image: # Build base image and immediately exit @@ -55,10 +38,10 @@ services: command: ["echo", "OK - Exit"] indy-validator: - container_name: cactus-example-discounted-asset-trade-indy-validator + container_name: cactus-example-discounted-asset-trade-indy-validator image: cactus_validator_socketio_indy environment: - - TEST_POOL_IP=172.16.0.2 + - TEST_POOL_IP=172.16.0.2 depends_on: - indy-sdk-cli-base-image build: @@ -67,9 +50,9 @@ services: ports: - "8000:8000" volumes: - - type: bind - source: ./etc/cactus - target: /etc/cactus + - type: bind + source: ./etc/cactus + target: /etc/cactus networks: - indy-testnet_indy_net @@ -96,23 +79,22 @@ services: ports: - "5034:5034" networks: - - cactus-example-discounted-asset-trade-net + - cactus-example-discounted-asset-trade-net depends_on: - - fabric-socketio-validator - ethereum-validator - indy-validator-nginx - cmd-socketio-base-image - indy-sdk-cli-base-image volumes: - - type: bind - source: ./etc/cactus - target: /etc/cactus + - type: bind + source: ./etc/cactus + target: /etc/cactus register-indy-data: container_name: register-indy-data image: register-indy-data environment: - - TEST_POOL_IP=172.16.0.2 + - TEST_POOL_IP=172.16.0.2 build: context: ../register-indy-data networks: @@ -120,11 +102,11 @@ services: depends_on: - cactus-example-discounted-asset-trade-blp volumes: - - type: bind - source: ./etc/cactus - target: /etc/cactus + - type: bind + source: ./etc/cactus + target: /etc/cactus # One-off command executed in container that will store a proof in /etc/cactus - command: [ "--proof_only" ] + command: ["--proof_only"] networks: fabric-all-in-one_testnet-2x: diff --git a/examples/cactus-example-discounted-asset-trade/fabric-asset-management.ts b/examples/cactus-example-discounted-asset-trade/fabric-asset-management.ts deleted file mode 100644 index ce0094c419..0000000000 --- a/examples/cactus-example-discounted-asset-trade/fabric-asset-management.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2020-2022 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * fabric-asset-management.ts - */ - -import { LPInfoHolder } from "@hyperledger/cactus-cmd-socketio-server"; -import { ConfigUtil } from "@hyperledger/cactus-cmd-socketio-server"; -import { - VerifierFactory, - VerifierFactoryConfig, -} from "@hyperledger/cactus-verifier-client"; - -const config: any = ConfigUtil.getConfig(); -import { getLogger } from "log4js"; -const moduleName = "FabricAssetManagement"; -const logger = getLogger(`${moduleName}`); -logger.level = config.logLevel; - -export class FabricAssetManagement { - private connectInfo: LPInfoHolder | null = null; // connection information - private readonly verifierFactory: VerifierFactory; - - constructor() { - this.connectInfo = new LPInfoHolder(); - this.verifierFactory = new VerifierFactory( - this.connectInfo.ledgerPluginInfo as VerifierFactoryConfig, - config.logLevel, - ); - } - - queryAsset(assetID: string): Promise { - return new Promise((resolve, reject) => { - const contract = { channelName: "mychannel", contractName: "basic" }; - const method = { type: "evaluateTransaction", command: "ReadAsset" }; - const args = { args: [assetID] }; - - this.verifierFactory - .getVerifier("r9IS4dDf") - .sendSyncRequest(contract, method, args) - .then((result) => { - resolve(result); - }) - .catch((err) => { - logger.error(err); - reject(err); - }); - }); - } - - queryAllAssets(): Promise { - return new Promise((resolve, reject) => { - const contract = { channelName: "mychannel", contractName: "basic" }; - const method = { type: "evaluateTransaction", command: "GetAllAssets" }; - const args = { args: [] }; - - this.verifierFactory - .getVerifier("r9IS4dDf") - .sendSyncRequest(contract, method, args) - .then((result) => { - resolve(result); - }) - .catch((err) => { - logger.error(err); - reject(err); - }); - }); - } -} diff --git a/examples/cactus-example-discounted-asset-trade/fabric-asset.ts b/examples/cactus-example-discounted-asset-trade/fabric-asset.ts index b5bf81001a..97360d4f70 100644 --- a/examples/cactus-example-discounted-asset-trade/fabric-asset.ts +++ b/examples/cactus-example-discounted-asset-trade/fabric-asset.ts @@ -8,7 +8,7 @@ import { Router, NextFunction, Request, Response } from "express"; import { ConfigUtil } from "@hyperledger/cactus-cmd-socketio-server"; import { RIFError } from "@hyperledger/cactus-cmd-socketio-server"; -import { FabricAssetManagement } from "./fabric-asset-management"; +import { queryAsset, queryAllAssets } from "./transaction-fabric"; const config: any = ConfigUtil.getConfig(); import { getLogger } from "log4js"; @@ -17,15 +17,13 @@ const logger = getLogger(`${moduleName}`); logger.level = config.logLevel; const router: Router = Router(); -const fabricAssetManagement: FabricAssetManagement = new FabricAssetManagement(); /* GET query asset. */ router.get("/:assetID", (req: Request, res: Response, next: NextFunction) => { try { logger.debug(`start queryAsset`); - fabricAssetManagement - .queryAsset(req.params.assetID) + queryAsset(req.params.assetID) .then((result) => { logger.debug("result(queryAsset) = " + JSON.stringify(result)); res.status(200).json(result); @@ -55,8 +53,7 @@ router.get("/", (req: Request, res: Response, next: NextFunction) => { try { logger.debug(`start queryAllAssets`); - fabricAssetManagement - .queryAllAssets() + queryAllAssets() .then((result) => { logger.debug("result(queryAllAssets) = " + JSON.stringify(result)); res.status(200).json(result); diff --git a/examples/cactus-example-discounted-asset-trade/fabric-connector.ts b/examples/cactus-example-discounted-asset-trade/fabric-connector.ts new file mode 100644 index 0000000000..53d0c9590b --- /dev/null +++ b/examples/cactus-example-discounted-asset-trade/fabric-connector.ts @@ -0,0 +1,322 @@ +import { PluginRegistry } from "@hyperledger/cactus-core"; +import { IListenOptions, Servers } from "@hyperledger/cactus-common"; +import { Constants, Configuration } from "@hyperledger/cactus-core-api"; +import { ConfigUtil } from "@hyperledger/cactus-cmd-socketio-server"; +import { + PluginLedgerConnectorFabric, + FabricApiClient, + signProposal, + FabricContractInvocationType, + RunTransactionResponse, +} from "@hyperledger/cactus-plugin-ledger-connector-fabric"; +import { PluginKeychainMemory } from "@hyperledger/cactus-plugin-keychain-memory"; + +import fs from "fs"; +import http from "http"; +import express from "express"; +import bodyParser from "body-parser"; +import jwt from "jsonwebtoken"; +import { AddressInfo } from "net"; +import { v4 as uuidv4 } from "uuid"; +import { Identity, Wallets } from "fabric-network"; +import { getLogger } from "log4js"; +import { Server as SocketIoServer } from "socket.io"; + +const config: any = ConfigUtil.getConfig(); +const moduleName = "fabric-connector"; +const logger = getLogger(`${moduleName}`); +logger.level = config.logLevel; + +const keychainId = uuidv4(); + +// Single Fabric connector instance +let fabricConnectorPlugin: PluginLedgerConnectorFabric | undefined = undefined; +let signerIdentity: FabricIdentity | undefined = undefined; +let fabricApiClient: FabricApiClient | undefined = undefined; + +export type FabricIdentity = Identity & { + credentials: { + certificate: string; + privateKey: string; + }; +}; + +// Prepare connection profile +// Fabric ledger should be running and it's config available in /etc/cactus/connector-fabric +const connectionProfile = { + name: "test-network-org1", + version: "1.0.0", + client: { + organization: "Org1", + connection: { timeout: { peer: { endorser: "300" } } }, + }, + organizations: { + Org1: { + mspid: "Org1MSP", + peers: ["peer0.org1.example.com"], + certificateAuthorities: ["ca.org1.example.com"], + }, + }, + peers: { + "peer0.org1.example.com": { + url: `grpcs://${config.assetTradeInfo.fabric.hostname}:7051`, + tlsCACerts: { + pem: fs.readFileSync( + "/etc/cactus/connector-fabric/crypto-config/peerOrganizations/org1.example.com/tlsca/tlsca.org1.example.com-cert.pem", + "ascii", + ), + }, + grpcOptions: { + "ssl-target-name-override": "peer0.org1.example.com", + hostnameOverride: "peer0.org1.example.com", + }, + }, + }, + certificateAuthorities: { + "ca.org1.example.com": { + url: `https://${config.assetTradeInfo.fabric.hostname}:7054`, + caName: "ca-org1", + tlsCACerts: { + pem: fs.readFileSync( + "/etc/cactus/connector-fabric/crypto-config/fabric-ca/org1/tls-cert.pem", + "ascii", + ), + }, + httpOptions: { verify: false }, + }, + }, + orderers: { + "orderer.example.com": { + url: `grpcs://${config.assetTradeInfo.fabric.hostname}:7050`, + grpcOptions: { "ssl-target-name-override": "orderer.example.com" }, + tlsCACerts: { + pem: fs.readFileSync( + "/etc/cactus/connector-fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem", + "ascii", + ), + }, + }, + }, + channels: { + mychannel: { + orderers: ["orderer.example.com"], + peers: { + "peer0.org1.example.com": { + endorsingPeer: true, + chaincodeQuery: true, + ledgerQuery: true, + eventSource: true, + discover: true, + }, + }, + }, + }, +}; +logger.debug("Use connection profile:", connectionProfile); + +/** + * Create signign token that will be verified in sign callback on connector side. + * @param txId unique transaction data + * @returns jwt token (string) + */ +export function createSigningToken(txId: string) { + return jwt.sign( + { + data: txId, + }, + config.assetTradeInfo.fabric.tokenSecret, + { expiresIn: "1h" }, + ); +} + +/** + * Verify if siging token is correct (i.e. was issued by this BLP). + * To be used in fabric connector sign callback. + * + * @param token jwt signing token + * @returns txId if correct, undefined otherwise. + */ +export function isValidSigningToken(token: string) { + try { + return jwt.verify(token, config.assetTradeInfo.fabric.tokenSecret); + } catch (err) { + logger.error("Invalid signing JWT token:", err); + return undefined; + } +} + +/** + * Read fabric Identity from wallet for specified user. + * + * @param user fabric user name + * @returns `Identity` + */ +export async function getUserIdentity(user: string): Promise { + const wallet = await Wallets.newFileSystemWallet( + config.assetTradeInfo.fabric.keystore, + ); + + const walletEntry = await wallet.get(user); + if (walletEntry && walletEntry.type === "X.509") { + return walletEntry as FabricIdentity; + } else { + throw new Error( + `Could not add identiy for user ${user}. Wallet identity: ${walletEntry}`, + ); + } +} + +/** + * Create new fabric connector instance + */ +async function createFabricConnector(signerIdentity: FabricIdentity) { + if (fabricConnectorPlugin) { + fabricConnectorPlugin.shutdown(); + fabricConnectorPlugin = undefined; + } + + // Create empty Keychain Plugin + const keychainPlugin = new PluginKeychainMemory({ + instanceId: uuidv4(), + keychainId, + logLevel: config.logLevel, + backend: new Map(), + }); + + fabricConnectorPlugin = new PluginLedgerConnectorFabric({ + instanceId: "cactus-example-discounted-asset-trade", + pluginRegistry: new PluginRegistry({ plugins: [keychainPlugin] }), + sshConfig: {}, // Provide SSH config to deploy contracts through connector + cliContainerEnv: {}, + peerBinary: "/fabric-samples/bin/peer", + logLevel: config.logLevel, + connectionProfile, + discoveryOptions: { + enabled: true, + asLocalhost: true, + }, + signCallback: async (payload, txData) => { + // Will be called for each delegated sign endpoints to sign a request payload. + const tokenData = isValidSigningToken(txData as string); + if (tokenData) { + logger.info("OK signing request for", tokenData); + return signProposal(signerIdentity.credentials.privateKey, payload); + } else { + throw new Error("Invalid TX token!"); + } + }, + }); + + await fabricConnectorPlugin.onPluginInit(); + + // Run http server + const expressApp = express(); + expressApp.use(bodyParser.json({ limit: "250mb" })); + const connectorServer = http.createServer(expressApp); + const listenOptions: IListenOptions = { + hostname: "127.0.0.1", + port: 0, + server: connectorServer, + }; + const addressInfo = (await Servers.listen(listenOptions)) as AddressInfo; + const apiHost = `http://${addressInfo.address}:${addressInfo.port}`; + + // Run socketio server + const socketioServer = new SocketIoServer(connectorServer, { + path: Constants.SocketIoConnectionPathV1, + }); + + // Register services + await fabricConnectorPlugin.getOrCreateWebServices(); + await fabricConnectorPlugin.registerWebServices(expressApp, socketioServer); + + // Create ApiClient + const apiConfig = new Configuration({ basePath: apiHost }); + fabricApiClient = new FabricApiClient(apiConfig); +} + +/** + * Get first block data (number 0). Can be used to test fabric connection. + */ +async function getFirstBlock(): Promise { + if (!fabricConnectorPlugin) { + throw new Error("getFirstBlock() called before initFabricConnector()!"); + } + + const queryResponse = await fabricConnectorPlugin.transactDelegatedSign({ + signerCertificate: getSignerIdentity().credentials.certificate, + signerMspID: getSignerIdentity().mspId, + channelName: config.assetTradeInfo.fabric.channelName, + invocationType: FabricContractInvocationType.Call, + contractName: "qscc", + methodName: "GetBlockByNumber", + params: [config.assetTradeInfo.fabric.channelName, "1"], + uniqueTransactionData: createSigningToken("getFirstBlock"), + endorsingPeers: ["peer0.org1.example.com"], + }); + + return queryResponse; +} + +/** + * Create fabric connector and check if connection can be established + */ +export async function initFabricConnector(): Promise { + if (!fabricConnectorPlugin) { + const user = config.assetTradeInfo.fabric.submitter.name; + signerIdentity = await getUserIdentity(user); + logger.info( + "Using signing identity for", + user, + "MspID", + signerIdentity.mspId, + ); + await createFabricConnector(signerIdentity); + + const firstBlockResponse = await getFirstBlock(); + if (!firstBlockResponse.functionOutput) { + throw new Error(`Invalid getFirstBlock response: ${firstBlockResponse}`); + } + + logger.info("initFabricConnector() done."); + } else { + logger.info("initFabricConnector() Fabric connector already initialized"); + } +} + +/** + * Get instance of fabric connector, initialize it if not done yet. + */ +export async function getFabricConnector(): Promise { + if (!fabricConnectorPlugin) { + await initFabricConnector(); + } + + if (fabricConnectorPlugin) { + return fabricConnectorPlugin; + } else { + throw new Error("Could not initialize new fabric connector!"); + } +} + +/** + * Get instance of fabric api client. + */ +export function getFabricApiClient(): FabricApiClient { + if (fabricApiClient) { + return fabricApiClient; + } else { + throw new Error("Fabric connector not initialized yet!"); + } +} + +/** + * Get signer identity + */ +export function getSignerIdentity(): FabricIdentity { + if (signerIdentity) { + return signerIdentity; + } else { + throw new Error("Fabric connector not initialized yet!"); + } +} diff --git a/examples/cactus-example-discounted-asset-trade/package.json b/examples/cactus-example-discounted-asset-trade/package.json index 708548c833..dc678379ca 100644 --- a/examples/cactus-example-discounted-asset-trade/package.json +++ b/examples/cactus-example-discounted-asset-trade/package.json @@ -16,7 +16,11 @@ }, "dependencies": { "@hyperledger/cactus-cmd-socketio-server": "2.0.0-alpha.2", + "@hyperledger/cactus-common": "2.0.0-alpha.2", + "@hyperledger/cactus-core": "2.0.0-alpha.2", "@hyperledger/cactus-core-api": "2.0.0-alpha.2", + "@hyperledger/cactus-plugin-keychain-memory": "2.0.0-alpha.2", + "@hyperledger/cactus-plugin-ledger-connector-fabric": "2.0.0-alpha.2", "@hyperledger/cactus-verifier-client": "2.0.0-alpha.2", "@types/node": "14.18.54", "axios": "0.24.0", @@ -28,9 +32,8 @@ "ethereumjs-common": "1.5.2", "ethereumjs-tx": "2.1.2", "express": "4.16.4", - "fabric-ca-client": "1.4.19", - "fabric-client": "1.4.19", - "fabric-network": "1.4.19", + "fabric-ca-client": "2.2.18", + "fabric-network": "2.2.18", "http-errors": "1.6.3", "jsonwebtoken": "9.0.0", "jsrsasign": "10.5.25", @@ -46,6 +49,7 @@ "@types/elliptic": "6.4.14", "@types/escape-html": "1.0.1", "@types/express": "4.17.13", + "@types/jsonwebtoken": "9.0.2", "@types/jsrsasign": "10.5.8" } } diff --git a/examples/cactus-example-discounted-asset-trade/read-ledger-state.js b/examples/cactus-example-discounted-asset-trade/read-ledger-state.js index 4fcacf692e..e35c097c1a 100644 --- a/examples/cactus-example-discounted-asset-trade/read-ledger-state.js +++ b/examples/cactus-example-discounted-asset-trade/read-ledger-state.js @@ -25,7 +25,7 @@ async function main() { "http://localhost:5034/api/v1/bl/fabric-asset/", ); console.log("\n# Fabric:"); - console.log(fabricResponse.data.data); + console.log(fabricResponse.data); } main(); diff --git a/examples/cactus-example-discounted-asset-trade/script-dockerless-config-patch.sh b/examples/cactus-example-discounted-asset-trade/script-dockerless-config-patch.sh index 4445214e1c..9e4d125b9c 100755 --- a/examples/cactus-example-discounted-asset-trade/script-dockerless-config-patch.sh +++ b/examples/cactus-example-discounted-asset-trade/script-dockerless-config-patch.sh @@ -12,12 +12,10 @@ sudo cp -ar "./etc/cactus" "/etc" sudo chown -hR $(whoami) "$COMMON_CACTUS_CONFIG" echo "Patch validators..." -sed -i 's/asset_trade_faio2x_testnet/localhost/g' "${COMMON_CACTUS_CONFIG}/connector-fabric-socketio/default.yaml" sed -i 's/geth1/localhost/g' "${COMMON_CACTUS_CONFIG}/connector-go-ethereum-socketio/default.yaml" echo "Patch validator-registry-config.yaml..." sed -i 's/ethereum-validator/localhost/g' "${COMMON_CACTUS_CONFIG}/validator-registry-config.yaml" -sed -i 's/fabric-socketio-validator/localhost/g' "${COMMON_CACTUS_CONFIG}/validator-registry-config.yaml" sed -i 's/indy-validator-nginx/localhost/g' "${COMMON_CACTUS_CONFIG}/validator-registry-config.yaml" echo "Patch path to asset-trade modules." diff --git a/examples/cactus-example-discounted-asset-trade/script-post-trade-request.sh b/examples/cactus-example-discounted-asset-trade/script-post-trade-request.sh index 08c56e455b..f5e1618f08 100755 --- a/examples/cactus-example-discounted-asset-trade/script-post-trade-request.sh +++ b/examples/cactus-example-discounted-asset-trade/script-post-trade-request.sh @@ -2,6 +2,11 @@ # Copyright 2020-2022 Hyperledger Cactus Contributors # SPDX-License-Identifier: Apache-2.0 +echo "Build register-indy-data container" +pushd ../register-indy-data +sh ./script-build-docker.sh +popd + echo "Run register-indy-data " docker run --rm \ -ti \ diff --git a/examples/cactus-example-discounted-asset-trade/script-start-ledgers.sh b/examples/cactus-example-discounted-asset-trade/script-start-ledgers.sh index 444f194b2e..6f6e1daecd 100755 --- a/examples/cactus-example-discounted-asset-trade/script-start-ledgers.sh +++ b/examples/cactus-example-discounted-asset-trade/script-start-ledgers.sh @@ -94,19 +94,13 @@ function start_fabric_testnet() { function copy_fabric_tlsca() { echo ">> copy_fabric_tlsca()" docker cp "${CACTUS_FABRIC_ALL_IN_ONE_CONTAINER_NAME}:/fabric-samples/test-network/organizations/" \ - "${CONFIG_VOLUME_PATH}/connector-fabric-socketio/crypto-config/" + "${CONFIG_VOLUME_PATH}/connector-fabric/crypto-config/" echo ">> copy_fabric_tlsca() done." } function copy_fabric_validator_config() { - echo ">> copy_fabric_validator_config()" - cp -fr ${ROOT_DIR}/packages/cactus-plugin-ledger-connector-fabric-socketio/sample-config/* \ - "${CONFIG_VOLUME_PATH}/connector-fabric-socketio/" - generate_certificate "FabricSocketIOCactusValidator" "${CONFIG_VOLUME_PATH}/connector-fabric-socketio/CA/" - echo ">> copy_fabric_validator_config() done." - echo ">> copy_fabric_wallet()" - cp -fr "${ROOT_DIR}/tools/docker/fabric-all-in-one/asset-transfer-basic-utils/wallet" "${CONFIG_VOLUME_PATH}/connector-fabric-socketio/" + cp -fr "${ROOT_DIR}/tools/docker/fabric-all-in-one/asset-transfer-basic-utils/wallet" "${CONFIG_VOLUME_PATH}/connector-fabric/" echo ">> copy_fabric_wallet() done." } @@ -155,7 +149,7 @@ function start_ledgers() { # Start Fabric start_fabric_testnet - mkdir -p "${CONFIG_VOLUME_PATH}/connector-fabric-socketio" + mkdir -p "${CONFIG_VOLUME_PATH}/connector-fabric" copy_fabric_tlsca copy_fabric_validator_config diff --git a/examples/cactus-example-discounted-asset-trade/sign-utils.ts b/examples/cactus-example-discounted-asset-trade/sign-utils.ts deleted file mode 100644 index 699884393f..0000000000 --- a/examples/cactus-example-discounted-asset-trade/sign-utils.ts +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2022 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * Util tools used for cryptography related to hyperledger fabric (e.g. signing proposals) - */ - -const hash = require("fabric-client/lib/hash"); -import jsrsa from "jsrsasign"; -import elliptic from "elliptic"; - -const ellipticCurves = elliptic.curves as any; - -/** - * This function comes from `CryptoSuite_ECDSA_AES.js` and will be part of the - * stand alone fabric-sig package in future. - * - */ -const ordersForCurve: Record = { - secp256r1: { - halfOrder: ellipticCurves.p256.n.shrn(1), - order: ellipticCurves.p256.n, - }, - secp384r1: { - halfOrder: ellipticCurves.p384.n.shrn(1), - order: ellipticCurves.p384.n, - }, -}; - -/** - * This function comes from `CryptoSuite_ECDSA_AES.js` and will be part of the - * stand alone fabric-sig package in future. - * - * @param sig EC signature - * @param curveParams EC key params. - * @returns Signature - */ -function preventMalleability(sig: any, curveParams: { name: string }) { - const halfOrder = ordersForCurve[curveParams.name].halfOrder; - if (!halfOrder) { - throw new Error( - 'Can not find the half order needed to calculate "s" value for immalleable signatures. Unsupported curve name: ' + - curveParams.name, - ); - } - - // in order to guarantee 's' falls in the lower range of the order, as explained in the above link, - // first see if 's' is larger than half of the order, if so, it needs to be specially treated - if (sig.s.cmp(halfOrder) === 1) { - // module 'bn.js', file lib/bn.js, method cmp() - // convert from BigInteger used by jsrsasign Key objects and bn.js used by elliptic Signature objects - const bigNum = ordersForCurve[curveParams.name].order; - sig.s = bigNum.sub(sig.s); - } - - return sig; -} - -/** - * Internal function to sign input buffer with private key. - * - * @param privateKey private key in PEM format. - * @param proposalBytes Buffer of the proposal to sign. - * @param algorithm Hash function algorithm - * @param keySize Key length - * @returns - */ -function sign( - privateKey: string, - proposalBytes: Buffer, - algorithm: string, - keySize: number, -) { - const hashAlgorithm = algorithm.toUpperCase(); - const hashFunction = hash[`${hashAlgorithm}_${keySize}`]; - const ecdsaCurve = ellipticCurves[`p${keySize}`]; - const ecdsa = new elliptic.ec(ecdsaCurve); - const key = jsrsa.KEYUTIL.getKey(privateKey) as any; - - const signKey = ecdsa.keyFromPrivate(key.prvKeyHex, "hex"); - const digest = hashFunction(proposalBytes); - - let sig = ecdsa.sign(Buffer.from(digest, "hex"), signKey); - sig = preventMalleability(sig, key.ecparams); - - return Buffer.from(sig.toDER()); -} - -/** - * Sign proposal of endorsment / transaction with private key. - * Can be used to call low-level fabric sdk functions. - * - * @param proposalBytes Buffer of the proposal to sign. - * @param paramPrivateKeyPem Private key in PEM format. - * @returns Signed proposal. - */ -export function signProposal( - proposalBytes: Buffer, - paramPrivateKeyPem: string, -) { - return { - signature: sign(paramPrivateKeyPem, proposalBytes, "sha2", 256), - proposal_bytes: proposalBytes, - }; -} diff --git a/examples/cactus-example-discounted-asset-trade/template-trade-management.ts b/examples/cactus-example-discounted-asset-trade/template-trade-management.ts deleted file mode 100644 index 87e7a1f8ea..0000000000 --- a/examples/cactus-example-discounted-asset-trade/template-trade-management.ts +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2022 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * template-trade-management.ts - */ - -import { Request } from "express"; -import { LPInfoHolder } from "@hyperledger/cactus-cmd-socketio-server"; -import { ConfigUtil } from "@hyperledger/cactus-cmd-socketio-server"; -import { - VerifierFactory, - VerifierFactoryConfig, -} from "@hyperledger/cactus-verifier-client"; - -const config: any = ConfigUtil.getConfig(); -import { getLogger } from "log4js"; -const moduleName = "TemplateTradeManagement"; -const logger = getLogger(`${moduleName}`); -logger.level = config.logLevel; - -export class TemplateTradeManagement { - private connectInfo: LPInfoHolder | null = null; // connection information - private readonly verifierFactory: VerifierFactory; - - constructor() { - this.connectInfo = new LPInfoHolder(); - this.verifierFactory = new VerifierFactory( - this.connectInfo.ledgerPluginInfo as VerifierFactoryConfig, - config.logLevel, - ); - } - - execTemplateTrade( - functionName: string, - req: Request, - ): Promise { - return new Promise((resolve, reject) => { - const contract = {}; // NOTE: Since contract does not need to be specified, specify an empty object. - const method = {}; - const template = req.body.template; - const args = req.body.args; - logger.debug( - `##contract: ${contract}, method: ${JSON.stringify( - method, - )}, template: ${template}, args: ${JSON.stringify(args)}`, - ); - - this.verifierFactory - .getVerifier("84jUisrs") - .sendSyncRequest(contract, method, args) - .then((result) => { - resolve(result as VerifierFactory); - }) - .catch((err) => { - logger.error(err); - reject(err); - }); - }); - } - - execTemplateTradeAsync(functionName: string, req: Request): string { - // TODO - const tradeID = this.createTradeID(); - - const contract = {}; // NOTE: Since contract does not need to be specified, specify an empty object. - const method = {}; - const args = req.body.args; - logger.debug( - `##contract: ${contract}, method: ${method}, args: ${JSON.stringify( - args, - )}`, - ); - - this.verifierFactory - .getVerifier("84jUisrs") - .sendAsyncRequest(contract, method, args) - .then(() => { - logger.debug(`##thirdTransaction sendAsyncRequest finish`); - }) - .catch((err) => { - logger.error(err); - }); - - return tradeID; - } - - createTradeID(): string { - // NOTE: tradeID is "(GMT date when the API was accepted) - (serial number)" - - // TODO: Trailing number-generating part not implemented - // NOTE: The last serial number is fixed "001" for 2020/9 months. - const currentTime: Date = new Date(); - const tradeID: string = - currentTime.getFullYear() + - ("0" + (currentTime.getMonth() + 1)).slice(-2) + - ("0" + currentTime.getDate()).slice(-2) + - ("0" + currentTime.getHours()).slice(-2) + - ("0" + currentTime.getMinutes()).slice(-2) + - ("0" + currentTime.getSeconds()).slice(-2) + - ("00" + currentTime.getMilliseconds()).slice(-3) + - "-001"; // NOTE: Serial number for the same time. Since the priority is low, it is fixed at "001" at this time. - return tradeID; - } -} diff --git a/examples/cactus-example-discounted-asset-trade/template-trade.ts b/examples/cactus-example-discounted-asset-trade/template-trade.ts deleted file mode 100644 index 1187eb4346..0000000000 --- a/examples/cactus-example-discounted-asset-trade/template-trade.ts +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2022 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * template-trade.ts - */ - -import { Router, NextFunction, Request, Response } from "express"; -import { ConfigUtil } from "@hyperledger/cactus-cmd-socketio-server"; -import { RIFError } from "@hyperledger/cactus-cmd-socketio-server"; -import { TemplateTradeManagement } from "./template-trade-management"; - -const config: any = ConfigUtil.getConfig(); -import { getLogger } from "log4js"; -const moduleName = "template-trade"; -const logger = getLogger(`${moduleName}`); -logger.level = config.logLevel; - -const router: Router = Router(); -const templateTradeManagement: TemplateTradeManagement = new TemplateTradeManagement(); - -/* POST template-trade. */ -// router.post('/:functionName', (req: Request, res: Response, next: NextFunction) => { -// try { -// -// logger.info(`#####[${moduleName}], functionName: ${req.param.functionName}`); -// -// templateTradeManagement.execTemplateTrade(req.param.functionName, req).then(result => { -// logger.debug(`#####[moduleName]`); -// logger.debug("result(execTemplateTrade) = " + JSON.stringify(result)); -// res.status(200).json(result); -// }).catch((err) => { -// logger.error(err); -// }); -// -// } catch (err) { -// logger.error(`##err name: ${err.constructor.name}`); -// -// if (err instanceof RIFError) { -// logger.debug(`##catch RIFError, ${err.statusCode}, ${err.message}`); -// res.status(err.statusCode); -// res.send(err.message); -// return; -// } -// -// logger.error(`##err in balance: ${err}`); -// next(err); -// } -// }); - -router.post( - "/execSyncFunction", - (req: Request, res: Response, next: NextFunction) => { - try { - const functionName = "execSyncFunction"; - logger.info(`#####[${moduleName}], functionName: ${functionName}`); - - templateTradeManagement - .execTemplateTrade(functionName, req) - .then((result) => { - logger.debug(`#####[moduleName]`); - logger.debug("result(execTemplateTrade) = " + JSON.stringify(result)); - res.status(200).json(result); - }) - .catch((err) => { - logger.error(err); - }); - } catch (err) { - if (err instanceof Error) { - logger.error(`##err name: ${err.constructor.name}`); - } - - if (err instanceof RIFError) { - logger.debug(`##catch RIFError, ${err.statusCode}, ${err.message}`); - res.status(err.statusCode); - res.send(err.message); - return; - } - - logger.error(`##err in balance: ${err}`); - next(err); - } - }, -); - -router.post( - "/sendSignedTransaction", - (req: Request, res: Response, next: NextFunction) => { - try { - const functionName = "sendSignedTransaction"; - logger.info(`#####[${moduleName}], functionName: ${functionName}`); - - const tradeID: string = templateTradeManagement.execTemplateTradeAsync( - functionName, - req, - ); - const result = { tradeID: tradeID }; - res.status(201).json(result); - } catch (err) { - if (err instanceof Error) { - logger.error(`##err name: ${err.constructor.name}`); - } - - if (err instanceof RIFError) { - logger.debug(`##catch RIFError, ${err.statusCode}, ${err.message}`); - res.status(err.statusCode); - res.send(err.message); - return; - } - - logger.error(`##err in balance: ${err}`); - next(err); - } - }, -); - -export default router; diff --git a/examples/cactus-example-discounted-asset-trade/transaction-fabric.ts b/examples/cactus-example-discounted-asset-trade/transaction-fabric.ts index 2ff96d0699..582d6626ca 100644 --- a/examples/cactus-example-discounted-asset-trade/transaction-fabric.ts +++ b/examples/cactus-example-discounted-asset-trade/transaction-fabric.ts @@ -5,187 +5,74 @@ * transaction-fabric.ts */ -//////// -// Usage -// -//////// - -/* Summary: - * Request library for fabric v1.4.0 (for offline signature) Processing library Testing library - * In this case, it is used only when transferring assets. - */ - import { ConfigUtil } from "@hyperledger/cactus-cmd-socketio-server"; -import { - ISendRequestResultV1, - ISocketApiClient, -} from "@hyperledger/cactus-core-api"; -import { Verifier } from "@hyperledger/cactus-verifier-client"; -import { signProposal } from "./sign-utils"; - -import { FileSystemWallet } from "fabric-network"; const config: any = ConfigUtil.getConfig(); import { getLogger } from "log4js"; +import { + createSigningToken, + getFabricConnector, + getSignerIdentity, +} from "./fabric-connector"; +import { FabricContractInvocationType } from "@hyperledger/cactus-plugin-ledger-connector-fabric"; + const moduleName = "TransactionFabric"; const logger = getLogger(`${moduleName}`); logger.level = config.logLevel; -export function makeSignedProposal>( - ccFncName: string, - ccArgs: string[], - verifierFabric: Verifier, -): Promise<{ signedTxArgs: unknown; txId: string }> { - return new Promise(async (resolve, reject) => { - try { - /* - * Endorse step - */ - const transactionProposalReq = { - fcn: ccFncName, // Chaincode function name - args: ccArgs, // Chaincode argument - chaincodeId: config.assetTradeInfo.fabric.chaincodeID, - channelId: config.assetTradeInfo.fabric.channelName, - }; - logger.debug(transactionProposalReq); - - // Get certificate and key acquisition - let certPem = undefined; - let privateKeyPem = undefined; - const submitter = config.assetTradeInfo.fabric.submitter.name; - const wallet = new FileSystemWallet( - config.assetTradeInfo.fabric.keystore, - ); - logger.debug(`Wallet path: ${config.assetTradeInfo.fabric.keystore}`); - - const submitterExists = await wallet.exists(submitter); - if (submitterExists) { - const submitterIdentity = (await wallet.export( - submitter, - )) as unknown as { - readonly certificate: string; - readonly privateKey: string; - }; - certPem = submitterIdentity.certificate; - privateKeyPem = submitterIdentity.privateKey; - } - - if (!certPem || !privateKeyPem) { - throw new Error( - "Could not read certPem or privateKeyPem from BLP fabric wallet.", - ); - } - - // Get unsigned proposal - const contractUnsignedProp = { - channelName: config.assetTradeInfo.fabric.channelName, - }; - const methodUnsignedProp = { - type: "function", - command: "generateUnsignedProposal", - }; - const argsUnsignedProp = { - args: { - transactionProposalReq, - certPem, - }, - }; - - logger.debug("Sending fabric.generateUnsignedProposal"); - const responseUnsignedProp = (await verifierFabric.sendSyncRequest( - contractUnsignedProp, - methodUnsignedProp, - argsUnsignedProp, - )) as ISendRequestResultV1<{ - readonly proposalBuffer: Buffer; - readonly proposal: unknown; - readonly txId: string; - }>; - const proposalBuffer = Buffer.from( - responseUnsignedProp.data.proposalBuffer, - ); - const proposal = responseUnsignedProp.data.proposal; - const txId = responseUnsignedProp.data.txId; - - // Prepare signed proposal - const signedProposal = signProposal(proposalBuffer, privateKeyPem); - - // Call sendSignedProposalV2 - const contractSignedProposal = { - channelName: config.assetTradeInfo.fabric.channelName, - }; - const methodSignedProposal = { - type: "function", - command: "sendSignedProposalV2", - }; - const argsSignedProposal = { - args: { - signedProposal, - }, - }; - - logger.debug("Sending fabric.sendSignedProposalV2"); - const responseSignedEndorse = (await verifierFabric.sendSyncRequest( - contractSignedProposal, - methodSignedProposal, - argsSignedProposal, - )) as ISendRequestResultV1<{ - readonly endorsmentStatus: string; - readonly proposalResponses: unknown; - }>; - - if (!responseSignedEndorse.data.endorsmentStatus) { - throw new Error("Fabric TX endorsment was not OK."); - } - const proposalResponses = responseSignedEndorse.data.proposalResponses; - - // Get unsigned commit (transaction) proposal - const contractUnsignedTx = { - channelName: config.assetTradeInfo.fabric.channelName, - }; - const methodUnsignedTx = { - type: "function", - command: "generateUnsignedTransaction", - }; - const argsUnsignedTx = { - args: { - proposal: proposal, - proposalResponses: proposalResponses, - }, - }; - - logger.debug("Sending fabric.generateUnsignedTransaction"); - const responseUnsignedTx = (await verifierFabric.sendSyncRequest( - contractUnsignedTx, - methodUnsignedTx, - argsUnsignedTx, - )) as ISendRequestResultV1<{ - readonly txProposalBuffer: Buffer; - }>; +export async function transferOwnership( + assetID: string, + fabricAccountTo: string, +) { + const connector = await getFabricConnector(); + + const transferResponse = await connector.transactDelegatedSign({ + signerCertificate: getSignerIdentity().credentials.certificate, + signerMspID: getSignerIdentity().mspId, + channelName: config.assetTradeInfo.fabric.channelName, + invocationType: FabricContractInvocationType.Send, + contractName: config.assetTradeInfo.fabric.chaincodeID, + methodName: "TransferAsset", + params: [assetID, fabricAccountTo], + uniqueTransactionData: createSigningToken("transferOwnership"), + }); + logger.debug("transferResponse:", transferResponse); - const commitProposalBuffer = Buffer.from( - responseUnsignedTx.data.txProposalBuffer, - ); + return transferResponse; +} - // Prepare signed commit proposal - const signedCommitProposal = signProposal( - commitProposalBuffer, - privateKeyPem, - ); +export async function queryAsset(assetID: string): Promise { + const connector = await getFabricConnector(); + + const queryResponse = await connector.transactDelegatedSign({ + signerCertificate: getSignerIdentity().credentials.certificate, + signerMspID: getSignerIdentity().mspId, + channelName: config.assetTradeInfo.fabric.channelName, + invocationType: FabricContractInvocationType.Call, + contractName: config.assetTradeInfo.fabric.chaincodeID, + methodName: "ReadAsset", + params: [assetID], + uniqueTransactionData: createSigningToken("queryAsset"), + }); + logger.debug("queryResponse:", queryResponse); - const signedTxArgs = { - signedCommitProposal, - proposal, - proposalResponses, - }; + return JSON.parse(queryResponse.functionOutput); +} - return resolve({ - txId, - signedTxArgs, - }); - } catch (e) { - logger.error(`error at Invoke: err=${e}`); - return reject(e); - } +export async function queryAllAssets(): Promise { + const connector = await getFabricConnector(); + + const queryResponse = await connector.transactDelegatedSign({ + signerCertificate: getSignerIdentity().credentials.certificate, + signerMspID: getSignerIdentity().mspId, + channelName: config.assetTradeInfo.fabric.channelName, + invocationType: FabricContractInvocationType.Call, + contractName: config.assetTradeInfo.fabric.chaincodeID, + methodName: "GetAllAssets", + params: [], + uniqueTransactionData: createSigningToken("queryAllAssets"), }); + logger.debug("queryResponse:", queryResponse); + + return JSON.parse(queryResponse.functionOutput); } diff --git a/examples/cactus-example-discounted-asset-trade/tsconfig.json b/examples/cactus-example-discounted-asset-trade/tsconfig.json index 8e96f61c09..a036fd9592 100644 --- a/examples/cactus-example-discounted-asset-trade/tsconfig.json +++ b/examples/cactus-example-discounted-asset-trade/tsconfig.json @@ -4,17 +4,30 @@ "composite": true, "outDir": "./dist/", "rootDir": "./", - "tsBuildInfoFile": "../../.build-cache/cactus-example-discounted-asset-trade.tsbuildinfo", + "tsBuildInfoFile": "../../.build-cache/cactus-example-discounted-asset-trade.tsbuildinfo" }, - "include": [ - "./*.ts", - ], + "include": ["./*.ts"], "references": [ + { + "path": "../../packages/cactus-common/tsconfig.json" + }, + { + "path": "../../packages/cactus-core/tsconfig.json" + }, + { + "path": "../../packages/cactus-core-api/tsconfig.json" + }, { "path": "../../packages/cactus-cmd-socketio-server/tsconfig.json" }, + { + "path": "../../packages/cactus-plugin-keychain-memory/tsconfig.json" + }, + { + "path": "../../packages/cactus-plugin-ledger-connector-fabric/tsconfig.json" + }, { "path": "../../packages/cactus-verifier-client/tsconfig.json" } ] -} \ No newline at end of file +} diff --git a/examples/cactus-example-discounted-asset-trade/www.ts b/examples/cactus-example-discounted-asset-trade/www.ts index 879d17008f..4d204ed4a2 100644 --- a/examples/cactus-example-discounted-asset-trade/www.ts +++ b/examples/cactus-example-discounted-asset-trade/www.ts @@ -1,7 +1,18 @@ import { BusinessLogicAssetTrade } from "./business-logic-asset-trade"; import { startCactusSocketIOServer } from "@hyperledger/cactus-cmd-socketio-server"; +import { initFabricConnector } from "./fabric-connector"; -startCactusSocketIOServer({ - id: "guks32pf", - plugin: new BusinessLogicAssetTrade(), -}); +async function startBLP() { + try { + await initFabricConnector(); + + startCactusSocketIOServer({ + id: "guks32pf", + plugin: new BusinessLogicAssetTrade(), + }); + } catch (error) { + console.error("Could not start discounted-asset-trade BLP:", error); + } +} + +startBLP(); diff --git a/packages/cactus-cmd-socketio-server/package.json b/packages/cactus-cmd-socketio-server/package.json index 108143ddf2..68bb11752f 100644 --- a/packages/cactus-cmd-socketio-server/package.json +++ b/packages/cactus-cmd-socketio-server/package.json @@ -53,12 +53,9 @@ "ethereumjs-common": "1.5.2", "ethereumjs-tx": "2.1.2", "express": "4.16.4", - "fabric-ca-client": "1.4.19", - "fabric-network": "1.4.19", "http-errors": "1.6.3", "js-yaml": "3.14.1", "jsonwebtoken": "9.0.0", - "jsrsasign": "10.5.25", "log4js": "6.4.1", "morgan": "1.10.0", "shelljs": "0.8.5", @@ -78,6 +75,7 @@ "@types/jsonwebtoken": "9.0.0", "@types/lodash": "4.14.195", "@types/morgan": "1.9.1", + "@types/node": "14.18.54", "@types/shelljs": "0.8.11", "http-terminator": "3.2.0", "lodash": "4.17.21", diff --git a/packages/cactus-cmd-socketio-server/src/main/typescript/util/TransactionSigner.ts b/packages/cactus-cmd-socketio-server/src/main/typescript/util/TransactionSigner.ts index edfffe3df4..15d2a1dfa1 100644 --- a/packages/cactus-cmd-socketio-server/src/main/typescript/util/TransactionSigner.ts +++ b/packages/cactus-cmd-socketio-server/src/main/typescript/util/TransactionSigner.ts @@ -4,39 +4,23 @@ * * TransactionSigner.ts */ + +import path from "path"; +import ethJsCommon from "ethereumjs-common"; +import { Transaction as EthTransaction } from "ethereumjs-tx"; +import { getLogger } from "log4js"; import { ConfigUtil } from "../routing-interface/util/ConfigUtil"; import { ValidatorRegistry } from "../verifier/validator-registry"; -const ethJsCommon = require("ethereumjs-common").default; -const ethJsTx = require("ethereumjs-tx").Transaction; -const libWeb3 = require("web3"); - -const fs = require("fs"); -const path = require("path"); -const yaml = require("js-yaml"); const config: any = ConfigUtil.getConfig(); -// const configVerifier: any = yaml.safeLoad(fs.readFileSync("", 'utf8')); const configVerifier: ValidatorRegistry = new ValidatorRegistry( path.resolve(__dirname, "/etc/cactus/validator-registry-config.yaml"), ); -import { getLogger } from "log4js"; + const moduleName = "TransactionEthereum"; const logger = getLogger(`${moduleName}`); logger.level = config.logLevel; -// Fabric node-sdk -const classFabricCAService = require("fabric-ca-client"); -const classClient = require("fabric-client"); - -// Cryptographic -const hash = require("fabric-client/lib/hash"); -const jsrsa = require("jsrsasign"); -const { KEYUTIL } = jsrsa; -const elliptic = require("elliptic"); -const EC = elliptic.ec; - -let fabricChannel: any = undefined; - export class TransactionSigner { static signTxEthereum(rawTx: object, signPkey: string) { logger.debug(`####in signTxEthereum()`); @@ -50,14 +34,14 @@ export class TransactionSigner { configVerifier.signTxInfo.ethereum.network, { name: configVerifier.signTxInfo.ethereum.chainName, - networkId: configVerifier.signTxInfo.ethereum.networkID, - chainId: configVerifier.signTxInfo.ethereum.chainID, + networkId: parseInt(configVerifier.signTxInfo.ethereum.networkID, 10), + chainId: parseInt(configVerifier.signTxInfo.ethereum.chainID, 10), }, configVerifier.signTxInfo.ethereum.hardfork, ); const privKey: Buffer = Buffer.from(signPkey, "hex"); - const tx = new ethJsTx(rawTx, { common: customCommon }); + const tx = new EthTransaction(rawTx, { common: customCommon }); tx.sign(privKey); // Get Transaction ID @@ -76,265 +60,4 @@ export class TransactionSigner { return signedTx; } - - static async signTxFabric( - transactionProposalReq: object, - certPem: string, - privateKeyPem: string, - ) { - logger.debug(`######call signTxFabric()`); - let invokeResponse; // Return value from chain code - - if (!configVerifier.signTxInfo) { - throw new Error("Missing configVerifier.signTxInfo"); - } - - // channel object generation - if (fabricChannel === undefined) { - fabricChannel = await TransactionSigner.setupChannel( - configVerifier.signTxInfo.fabric.channelName, - ); - } - - const { proposal, txId } = fabricChannel.generateUnsignedProposal( - transactionProposalReq, - configVerifier.signTxInfo.fabric.mspID, - certPem, - ); - logger.debug("proposal end"); - logger.debug(`##txId: ${txId.getTransactionID()}`); - const signedProposal = TransactionSigner.signProposal( - proposal.toBuffer(), - privateKeyPem, - ); - - const targets = []; - for (const peerInfo of configVerifier.signTxInfo.fabric.peers) { - const peer = fabricChannel.getPeer(peerInfo.requests.split("//")[1]); - targets.push(peer); - } - const sendSignedProposalReq = { signedProposal, targets }; - const proposalResponses = await fabricChannel.sendSignedProposal( - sendSignedProposalReq, - ); - logger.debug("successfully send signedProposal"); - let allGood = true; - for (const proposalResponse of proposalResponses) { - let oneGood = false; - if ( - proposalResponses && - proposalResponse.response && - proposalResponse.response.status === 200 - ) { - if (proposalResponse.response.payload) { - invokeResponse = proposalResponse.response.payload; - } - oneGood = true; - } else { - logger.debug("transaction proposal was bad"); - const resStr = proposalResponse.toString(); - const errMsg = resStr.replace("Error: ", ""); - // return reject(errMsg); - throw new Error(errMsg); - } - allGood = allGood && oneGood; - } - // If the return value of invoke is an empty string, store txID - if (invokeResponse === "") { - invokeResponse = txId.getTransactionID(); - } - // Error if all peers do not return status 200 - if (!allGood) { - throw new Error( - "Failed to send Proposal or receive valid response. Response null or status is not 200. exiting...", - ); - } - - /** - * End the endorse step. - * Start to commit the tx. - */ - const commitReq = { - proposalResponses, - proposal, - }; - const commitProposal = fabricChannel.generateUnsignedTransaction(commitReq); - logger.debug("Successfully build commit transaction proposal"); - - // sign this commit proposal at local - const signedCommitProposal = TransactionSigner.signProposal( - commitProposal.toBuffer(), - privateKeyPem, - ); - - const signedTx = { - signedCommitProposal: signedCommitProposal, - commitReq: commitReq, - txId: txId.getTransactionID(), - }; - - return signedTx; - } - - // BEGIN Signature process===================================================================================== - // this ordersForCurve comes from CryptoSuite_ECDSA_AES.js and will be part of the - // stand alone fabric-sig package in future. - static ordersForCurve = { - secp256r1: { - halfOrder: elliptic.curves.p256.n.shrn(1), - order: elliptic.curves.p256.n, - }, - secp384r1: { - halfOrder: elliptic.curves.p384.n.shrn(1), - order: elliptic.curves.p384.n, - }, - }; - - // this function comes from CryptoSuite_ECDSA_AES.js and will be part of the - // stand alone fabric-sig package in future. - static _preventMalleability( - sig: any, - curveParams: { name: keyof typeof TransactionSigner.ordersForCurve }, - ) { - const halfOrder: any = - TransactionSigner.ordersForCurve[curveParams.name].halfOrder; - if (!halfOrder) { - throw new Error( - 'Can not find the half order needed to calculate "s" value for immalleable signatures. Unsupported curve name: ' + - curveParams.name, - ); - } - - // in order to guarantee 's' falls in the lower range of the order, as explained in the above link, - // first see if 's' is larger than half of the order, if so, it needs to be specially treated - if (sig.s.cmp(halfOrder) === 1) { - // module 'bn.js', file lib/bn.js, method cmp() - // convert from BigInteger used by jsrsasign Key objects and bn.js used by elliptic Signature objects - const bigNum = TransactionSigner.ordersForCurve[curveParams.name].order; - sig.s = bigNum.sub(sig.s); - } - - return sig; - } - - /** - * this method is used for test at this moment. In future this - * would be a stand alone package that running at the browser/cellphone/PAD - * - * @param {string} privateKey PEM encoded private key - * @param {Buffer} proposalBytes proposal bytes - */ - static sign( - privateKey: any, - proposalBytes: any, - algorithm: any, - keySize: any, - ) { - const hashAlgorithm = algorithm.toUpperCase(); - const hashFunction = hash[`${hashAlgorithm}_${keySize}`]; - const ecdsaCurve = elliptic.curves[`p${keySize}`]; - const ecdsa = new EC(ecdsaCurve); - const key = KEYUTIL.getKey(privateKey); - - const signKey = ecdsa.keyFromPrivate(key.prvKeyHex, "hex"); - const digest = hashFunction(proposalBytes); - - let sig = ecdsa.sign(Buffer.from(digest, "hex"), signKey); - sig = TransactionSigner._preventMalleability(sig, key.ecparams); - - return Buffer.from(sig.toDER()); - } - - static signProposal(proposalBytes: any, paramPrivateKeyPem: any) { - logger.debug("signProposal start"); - - const signature = TransactionSigner.sign( - paramPrivateKeyPem, - proposalBytes, - "sha2", - 256, - ); - const signedProposal = { signature, proposal_bytes: proposalBytes }; - return signedProposal; - } - // END Signature process========================================================================================= - - // setup TLS for this client - static async TLSSetup(client: any, enrollmentID: any, secret: any) { - const tlsOptions = { - trustedRoots: [], - verify: false, - }; - logger.debug("tlssetup start"); - - if (!configVerifier.signTxInfo) { - throw new Error("Missing configVerifier.signTxInfo"); - } - - const caService = new classFabricCAService( - configVerifier.signTxInfo.fabric.ca.URL, - tlsOptions, - configVerifier.signTxInfo.fabric.ca.name, - ); - const req = { - enrollmentID: enrollmentID, - enrollmentSecret: secret, - profile: "tls", - }; - const enrollment = await caService.enroll(req); - client.setTlsClientCertAndKey( - enrollment.certificate, - enrollment.key.toBytes(), - ); - } - - // Creating a channel object - static async setupChannel(channelName: any) { - logger.debug("setupChannel start"); - - if (!configVerifier.signTxInfo) { - throw new Error("Missing configVerifier.signTxInfo"); - } - - const client = new classClient(); - await TransactionSigner.TLSSetup( - client, - configVerifier.signTxInfo.fabric.submitter.name, - configVerifier.signTxInfo.fabric.submitter.secret, - ); - const channel = client.newChannel(channelName); - - // add peer to channel - // const peerTLSCertPath = path.resolve(__dirname, './crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tlscacerts/org1.example.com-cert.pem'); - // const peerPEMCert = fs.readFileSync(peerTLSCertPath, 'utf8'); - for (const peerInfo of configVerifier.signTxInfo.fabric.peers) { - const peer = client.newPeer( - peerInfo.requests, - /*{ - pem: peerPEMCert, - 'ssl-target-name-override': 'peer0.org1.example.com', - } - */ - ); - channel.addPeer(peer); - } - - // add orderer to channel - /* - const ordererTLSCertPath = path.resolve(__dirname, './crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tlscacerts/example.com-cert.pem'); - const ordererPEMCert = fs.readFileSync(ordererTLSCertPath, 'utf8'); - */ - const orderer = client.newOrderer( - configVerifier.signTxInfo.fabric.orderer.URL, - /*{ - pem: ordererPEMCert, - 'ssl-target-name-override': 'orderer.example.com', - } - */ - ); - channel.addOrderer(orderer); - // TODO: channel.initialize() should not require an signning identity - // await channel.initialize(); - return channel; - } } diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/CHANGELOG.md b/packages/cactus-plugin-ledger-connector-fabric-socketio/CHANGELOG.md deleted file mode 100644 index 15808a5db6..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/CHANGELOG.md +++ /dev/null @@ -1,90 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -# [2.0.0-alpha.2](https://github.com/hyperledger/cacti/compare/v2.0.0-alpha.1...v2.0.0-alpha.2) (2023-09-27) - -### Bug Fixes - -* **cmd-api-server:** fix CVE-2023-36665 protobufjs Prototype Pollution vuln ([7bb3957](https://github.com/hyperledger/cacti/commit/7bb39576080592919bea0ac89646b32105e1748e)), closes [#2682](https://github.com/hyperledger/cacti/issues/2682) -* **security:** the CVE-2022-2421 - upgrade socket.io-parser to >=4.2.1 ([9172172](https://github.com/hyperledger/cacti/commit/917217227a3fa53a00429f047cd6318862e6ab8d)), closes [#2229](https://github.com/hyperledger/cacti/issues/2229) [#2228](https://github.com/hyperledger/cacti/issues/2228) -* **security:** upgrade fabric 2.x deps to 2.2.18 ([36988a5](https://github.com/hyperledger/cacti/commit/36988a5edbf9856a1bcc960a3b9afe443536733e)), closes [#2610](https://github.com/hyperledger/cacti/issues/2610) - -# [2.0.0-alpha.1](https://github.com/hyperledger/cacti/compare/v2.0.0-alpha-prerelease...v2.0.0-alpha.1) (2023-05-19) - -**Note:** Version bump only for package @hyperledger/cactus-plugin-ledger-connector-fabric-socketio - -# [2.0.0-alpha-prerelease](https://github.com/hyperledger/cacti/compare/v1.2.0...v2.0.0-alpha-prerelease) (2023-05-11) - -**Note:** Version bump only for package @hyperledger/cactus-plugin-ledger-connector-fabric-socketio - -# [1.2.0](https://github.com/hyperledger/cacti/compare/v1.1.3...v1.2.0) (2023-03-28) - -**Note:** Version bump only for package @hyperledger/cactus-plugin-ledger-connector-fabric-socketio - -## [1.1.3](https://github.com/hyperledger/cactus/compare/v1.1.2...v1.1.3) (2022-12-08) - -### Features - -* **fabric-socketio-connector:** sending transactions signed on the client-side ([0b34ca3](https://github.com/hyperledger/cactus/commit/0b34ca3d35a39826c05cc047e480d377c1c52bef)) - -## [1.1.2](https://github.com/hyperledger/cactus/compare/v1.1.1...v1.1.2) (2022-11-11) - -**Note:** Version bump only for package @hyperledger/cactus-plugin-ledger-connector-fabric-socketio - -## [1.1.1](https://github.com/hyperledger/cactus/compare/v1.1.0...v1.1.1) (2022-11-03) - -**Note:** Version bump only for package @hyperledger/cactus-plugin-ledger-connector-fabric-socketio - -# [1.1.0](https://github.com/hyperledger/cactus/compare/v1.0.0...v1.1.0) (2022-10-17) - -### Bug Fixes - -* **security:** address CVE-2017-16138 Fixes: [#1776](https://github.com/hyperledger/cactus/issues/1776) ([9f1d013](https://github.com/hyperledger/cactus/commit/9f1d01320cacf859bfd2e03426f85fb234f52dd8)) - -### Code Refactoring - -* **examples:** include sample apps in monorepo build ([51ac163](https://github.com/hyperledger/cactus/commit/51ac1630f53ca3ac881341c7f8847b6ae581b220)) - -### Features - -* **connector-fabric:** add GetBlock operation to fabric connectors ([00572ed](https://github.com/hyperledger/cactus/commit/00572edfafb82420f93570129e7e233a521f82e7)), closes [#2124](https://github.com/hyperledger/cactus/issues/2124) -* **secret:** remove Validator/Verifier secret keys from repository ([59b4af4](https://github.com/hyperledger/cactus/commit/59b4af44835e2babafe398040a280ed23e9b490e)) - -### BREAKING CHANGES - -* **examples:** building discounted-asset-trade app (or any future app that use indy validator) - requires Indy SDK to be installed on the build machine. - -Closes: 2029 - -Signed-off-by: Michal Bajer - -# [1.0.0](https://github.com/hyperledger/cactus/compare/v1.0.0-rc.3...v1.0.0) (2022-03-16) - -### Bug Fixes - -* **cmd-api-server:** upgrade socket.io - CVE-2022-21676 ([8e1c69e](https://github.com/hyperledger/cactus/commit/8e1c69e7b8ab5e4ccc31a0ec183a9777ccc22cdc)), closes [#1914](https://github.com/hyperledger/cactus/issues/1914) -* **plugin-ledger-connector-fabric-socketio:** upgrade Fabric due to jsrsasign ([a9ecb19](https://github.com/hyperledger/cactus/commit/a9ecb192cb32661c5bdd9ea684f35a90c7948f6a)), closes [#1754](https://github.com/hyperledger/cactus/issues/1754) [#1799](https://github.com/hyperledger/cactus/issues/1799) -* **security:** address CVE-2019-5413 ([212b770](https://github.com/hyperledger/cactus/commit/212b770c705c279dcc766b7230d7519ed9a98748)), closes [#1777](https://github.com/hyperledger/cactus/issues/1777) - -# [1.0.0-rc.3](https://github.com/hyperledger/cactus/compare/v1.0.0-rc.2...v1.0.0-rc.3) (2021-12-07) - -### Bug Fixes - -* **security:** upgrade fabric-common to 2.2.10 or later ([45c4a69](https://github.com/hyperledger/cactus/commit/45c4a69fb86964bc4e7018c31c5914a0063c7638)), closes [#1600](https://github.com/hyperledger/cactus/issues/1600) - -# [1.0.0-rc.2](https://github.com/hyperledger/cactus/compare/v1.0.0-rc.1...v1.0.0-rc.2) (2021-11-01) - -**Note:** Version bump only for package @hyperledger/cactus-plugin-ledger-connector-fabric-socketio - -# [1.0.0-rc.1](https://github.com/hyperledger/cactus/compare/v0.10.0...v1.0.0-rc.1) (2021-10-11) - -**Note:** Version bump only for package @hyperledger/cactus-plugin-ledger-connector-fabric-socketio - -# [0.10.0](https://github.com/hyperledger/cactus/compare/v0.9.0...v0.10.0) (2021-09-28) - -### Bug Fixes - -* **validators:** add some missing parts ([9a8f7db](https://github.com/hyperledger/cactus/commit/9a8f7db746e2a41708e2fe9d5277561d6abac3d4)) diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/Dockerfile b/packages/cactus-plugin-ledger-connector-fabric-socketio/Dockerfile deleted file mode 100644 index aa2ca1db68..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM cactus-cmd-socketio-server:latest - -ENV CACTUS_CONNECTOR_FABRIC_PATH=/opt/cactus-plugin-ledger-connector-fabric-socketio - -WORKDIR ${CACTUS_CONNECTOR_FABRIC_PATH} - -COPY ./dist ./dist/ -COPY ./dist/yarn.lock ./package.json ./ -RUN yarn add "${CACTUS_CMD_SOCKETIO_PATH}" \ - --production --frozen-lockfile --ignore-engines --non-interactive --cache-folder ./.yarnCache && \ - rm -rf ./.yarnCache - -EXPOSE 5040 -VOLUME ["/etc/cactus/"] -CMD [ "npm", "run", "start" ] diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/README.md b/packages/cactus-plugin-ledger-connector-fabric-socketio/README.md deleted file mode 100644 index 81cde7af8e..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/README.md +++ /dev/null @@ -1,89 +0,0 @@ - -# `@hyperledger/cactus-plugin-ledger-connector-fabric-socketio` - -This plugin provides `Cactus` a way to interact with Hyperledger Fabric networks. Using this we can perform: -- `sendSyncRequest`: Send sync-typed requests to the ledgers (e.g. getBalance) -- `sendAsyncRequest`: Send async-typed requests to the ledgers (e.g. sendTransaction) -- `startMonitor`: Start monitoring blocks on the ledgers -- `stopMonitor`: Stop the block monitoring - -## Summary -- [Getting started](#getting-started) -- [Usage samples](#usage-samples) -- [Contributing](#contributing) -- [License](#license) -- [Acknowledgments](#acknowledgments) - -## Getting started - -### Required software components -- OS: CentOS7 -- Docker (recommend: v17.06.2-ce or greater) -- node.js v12 (recommend: v12.20.2 or greater) - -### Prerequisites -- Please ensure that the destination ledger (default for samples: [fabric-all-in-one](../../tools/docker/fabric-all-in-one/)) is already launched. - -## Boot methods - -### Common setup -1. Always run configure command first, from the project root directory: - ``` - pushd ../.. - npm run configure - popd - ``` - -1. Copy default configuration -- **Remember to replace default CA and to adjust the `default.yaml` configuration on production deployments!** -- You can copy your wallet to `/etc/cactus/connector-fabric-socketio/wallet/` - ``` - mkdir -p /etc/cactus/connector-fabric-socketio/ - rm -r /etc/cactus/connector-fabric-socketio/* - cp -rf ./sample-config/* /etc/cactus/connector-fabric-socketio/ - ``` - -### Docker -- This image depends on `cactus-cmd-socketio-server:latest` to be present in local store. **Make sure to follow docker build instructions in [cactus-cmd-socketio-server README](../../packages/cactus-cmd-socketio-server/README.md)) before bulding this image!** -- Docker build process will use artifacts from the latest build. Make sure `./dist` contains the version you want to dockerize. - -``` -# Build -pushd ../../packages/cactus-cmd-socketio-server/ && docker build . -t cactus-cmd-socketio-server && popd -docker build . -t cactus-plugin-ledger-connector-fabric-socketio - -# Run -docker run -v/etc/cactus/:/etc/cactus -p 5040:5040 cactus-plugin-ledger-connector-fabric-socketio -``` - -### Manual -- Ensure ledger ports are exposed to the host first. - -``` -npm run start -``` - -## Configuration -- Validator can be configured in `/etc/cactus/connector-fabric-socketio/default.yaml` (see [sample-config](./sample-config/default.yaml) for details). -- This configuration can be overwriten in `NODE_CONFIG` environment variable (JSON format). See functional tests for example of that. - -## Usage samples -- To confirm the operation of this package, please refer to the following business-logic sample application: - - [cactus-example-discounted-asset-trade](../../examples/cactus-example-discounted-asset-trade) - -## Contributing - -We welcome contributions to Hyperledger Cactus in many forms, and there's always plenty to do! - -Please review [CONTIRBUTING.md](../../CONTRIBUTING.md) to get started. - -## License - -This distribution is published under the Apache License Version 2.0 found in the [LICENSE](../../LICENSE) file. - -## Acknowledgments diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/package.json b/packages/cactus-plugin-ledger-connector-fabric-socketio/package.json deleted file mode 100644 index 7e2a19a10f..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/package.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "name": "@hyperledger/cactus-plugin-ledger-connector-fabric-socketio", - "version": "2.0.0-alpha.2", - "license": "Apache-2.0", - "main": "dist/index.js", - "module": "dist/index.js", - "types": "dist/index.d.ts", - "scripts": { - "build": "npm run build-ts && npm run build:dev:backend:postbuild", - "build-ts": "tsc", - "build:dev:backend:postbuild": "npm run prepare-docker-build", - "debug": "nodemon --inspect ./dist/common/core/bin/www.js", - "prepare-docker-build": "cp -af ../../yarn.lock ./dist/yarn.lock", - "start": "cd ./dist && node common/core/bin/www.js" - }, - "dependencies": { - "@hyperledger/cactus-cmd-socketio-server": "2.0.0-alpha.2", - "@hyperledger/cactus-common": "2.0.0-alpha.2", - "@types/node": "14.18.54", - "body-parser": "1.17.2", - "cookie-parser": "1.4.6", - "debug": "3.1.0", - "express": "4.17.3", - "fabric-ca-client": "1.4.19", - "fabric-client": "1.4.19", - "fabric-network": "1.4.19", - "fs-extra": "10.1.0", - "grpc": "1.24.11", - "js-yaml": "3.14.1", - "jsonwebtoken": "9.0.0", - "lodash": "4.17.21", - "log4js": "6.4.1", - "morgan": "1.10.0", - "protobufjs": "7.2.5", - "serve-favicon": "2.4.5", - "shelljs": "0.8.5", - "socket.io": "4.5.4" - }, - "devDependencies": { - "@hyperledger/cactus-api-client": "2.0.0-alpha.2", - "@hyperledger/cactus-test-tooling": "2.0.0-alpha.2", - "@types/config": "0.0.41", - "@types/cookie-parser": "1.4.3", - "@types/elliptic": "6.4.14", - "@types/express": "4.17.13", - "@types/http-errors": "2.0.1", - "@types/jsrsasign": "10.5.8", - "@types/lodash": "4.14.195", - "ts-node": "9.1.1" - } -} diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/sample-config/default.yaml b/packages/cactus-plugin-ledger-connector-fabric-socketio/sample-config/default.yaml deleted file mode 100644 index e1c0a24e0a..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/sample-config/default.yaml +++ /dev/null @@ -1,37 +0,0 @@ -sslParam: - # Port on which the validator will listen for requests. - port: 5040 - # Private and public keys used by HTTPS server and to sign JWT messages. - # Must be either RSA or ECDSA. - key: "/etc/cactus/connector-fabric-socketio/CA/connector.priv" - cert: "/etc/cactus/connector-fabric-socketio/CA/connector.crt" - # JWT signing algorithm, must correspond to the private keys specified above. - # See more: https://www.rfc-editor.org/rfc/rfc7518#section-3.1 - # Default: ES256 (key must be ECDSA using P-256 and SHA-256) - # jwtAlgo: "ES256" -# log4js log level -logLevel: "debug" -# Fabric ledger configuration -fabric: - mspid: "Org1MSP" - keystore: "/etc/cactus/connector-fabric-socketio/wallet" - connUserName: "appUser" - contractName: "basic" - peers: - - name: "peer0.org1.example.com" - requests: "grpcs://asset_trade_faio2x_testnet:7051" - tlsca: - "/etc/cactus/connector-fabric-socketio/crypto-config/peerOrganizations/org1.example.com/tlsca/tlsca.org1.example.com-cert.pem" - orderer: - name: "orderer.example.com" - url: "grpcs://asset_trade_faio2x_testnet:7050" - tlsca: - "/etc/cactus/connector-fabric-socketio/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" - ca: - name: "ca-org1" - url: "https://asset_trade_faio2x_testnet:7054" - submitter: - name: "admin" - secret: "adminpw" - channelName: "mychannel" - chaincodeId: "basic" diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/sample-config/wallet/.gitkeep b/packages/cactus-plugin-ledger-connector-fabric-socketio/sample-config/wallet/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/.gitignore b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/.gitignore deleted file mode 100644 index 0cc590dba6..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -core/node_modules/ -core/package-lock.json -dependent/node_modules/ -dependent/package-lock.json -core/npm-debug.log -dependent/wallet/ -core/wallet/ -wallet/ -dependent/ValidatorAuthentication.ts diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/common/core/app.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/common/core/app.ts deleted file mode 100644 index c708c37861..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/common/core/app.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * app.js - */ - -/* Summary: - * - */ - -import type { NextFunction, Request, Response } from "express"; -import createError = require("http-errors"); -import express = require("express"); -import cookieParser = require("cookie-parser"); -import bodyParser = require("body-parser"); - -const app: express.Express = express(); - -app.use(bodyParser.json()); -app.use(bodyParser.urlencoded({ extended: false })); -app.use(cookieParser()); - -// catch 404 and forward to error handler -app.use(function (req, res, next) { - next(createError(404)); -}); - -// error handler -app.use( - ( - err: { message: string; status?: number }, - req: Request, - res: Response, - next: NextFunction, - ) => { - // set locals, only providing error in development - res.locals.message = err.message; - res.locals.error = req.app.get("env") === "development" ? err : {}; - - // set erreor response - const errorResponse: {} = { - statusCode: err.status || 500, - message: err.message, - }; - - // render the error page - res.status(err.status || 500); - res.send(err); - }, -); - -export default app; diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/common/core/bin/www.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/common/core/bin/www.ts deleted file mode 100644 index 0193c687ac..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/common/core/bin/www.ts +++ /dev/null @@ -1,302 +0,0 @@ -#!/usr/bin/env node - -/* - * Copyright 2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * www.js - */ - -/* Summary: - * Connector: a part independent of end-chains - */ - -import app from "../app"; -import https = require("https"); - -// Overwrite config read path -export const DEFAULT_NODE_CONFIG_DIR = "/etc/cactus/connector-fabric-socketio/"; -if (!process.env["NODE_CONFIG_DIR"]) { - // Must be set before import config - process.env["NODE_CONFIG_DIR"] = DEFAULT_NODE_CONFIG_DIR; -} -import { configRead } from "@hyperledger/cactus-cmd-socketio-server"; - -import fs = require("fs"); -import { Server } from "socket.io" -// Log settings -import { getLogger } from "log4js"; -const logger = getLogger("connector_main[" + process.pid + "]"); -logger.level = configRead('logLevel', 'info'); - -// implementation class of a part dependent of end-chains (server plugin) -import { ServerPlugin } from "../../../connector/ServerPlugin"; - -// destination dependency (MONITOR) implementation class -import { ServerMonitorPlugin } from "../../../connector/ServerMonitorPlugin"; - -export async function startFabricSocketIOConnector() { - const Splug = new ServerPlugin(); - const Smonitor = new ServerMonitorPlugin(); - - // Get port from environment and store in Express. - const sslport = normalizePort(process.env.PORT || configRead('sslParam.port')); - app.set("port", sslport); - - // Specify private key and certificate - let keyString: string; - let certString: string; - try { - keyString = configRead('sslParam.keyValue'); - certString = configRead('sslParam.certValue'); - } catch { - keyString = fs.readFileSync(configRead('sslParam.key'), "ascii"); - certString = fs.readFileSync(configRead('sslParam.cert'), "ascii"); - } - - // Create HTTPS server. - const server = https.createServer({ - key: keyString, - cert: certString, - }, app); // Start as an https server. - const io = new Server(server); - - // Event listener for HTTPS server "error" event. - server.on("error", (error: any) => { - if (error.syscall !== "listen") { - throw error; - } - - const bind = - typeof sslport === "string" ? "Pipe " + sslport : "Port " + sslport; - - // handle specific listen errors with friendly messages - switch (error.code) { - case "EACCES": - logger.error(bind + " requires elevated privileges"); - process.exit(1); - break; - case "EADDRINUSE": - logger.error(bind + " is already in use"); - process.exit(1); - break; - default: - throw error; - } - }); - - io.on("connection", function (client) { - logger.info("Client " + client.id + " connected."); - - /** - * request: The server plugin's request to execute a function - * @param {JSON} data: Request Body (following format) - * JSON: { - * "func": (string) Function name ,// For example : "transferNumericAsset" - * "args": (Object) argument// for example , {"from" : "xxx" , "to" : "yyy" , "value" : "10,000"} - * } - **/ - client.on("request", function (data) { - const func = data.func; - const args = data.args; - if (data.reqID !== undefined) { - logger.info(`##add reqID: ${data.reqID}`); - args["reqID"] = data.reqID; - } - logger.info("##[HL-BC] Invoke smart contract to transfer asset(D1)"); - logger.info("*** REQUEST ***"); - logger.info("Client ID :" + client.id); - logger.info("Data :" + JSON.stringify(data)); - - // Check for the existence of the specified function and call it if it exists. - if (Splug.isExistFunction(func)) { - // Can be called with Server plugin function name. - (Splug as any)[func](args) - .then((respObj: unknown) => { - logger.info("*** RESPONSE ***"); - logger.info("Client ID :" + client.id); - logger.info("Response :" + JSON.stringify(respObj)); - client.emit("response", respObj); - }) - .catch((errObj: unknown) => { - logger.error("*** ERROR ***"); - logger.error("Client ID :" + client.id); - logger.error("Detail :" + JSON.stringify(errObj)); - client.emit("connector_error", errObj); - }); - } else { - // No such function - const emsg = "Function " + func + " not found!"; - logger.error(emsg); - const retObj = { - status: 504, - errorDetail: emsg, - }; - client.emit("connector_error", retObj); - } - }); - - client.on("request2", function (data) { - const func = data.method.method; - let args: Record = { - contract: data.contract, - method: data.method, - args: data.args, - }; - - if (data.reqID !== undefined) { - logger.info(`##add reqID: ${data.reqID}`); - args["reqID"] = data.reqID; - } - logger.info("##[HL-BC] Invoke smart contract to transfer asset(D1)"); - logger.info("*** REQUEST ***"); - logger.info("Client ID :" + client.id); - logger.info("Data :" + JSON.stringify(data)); - - // Check for the presence of a request ID. - if ( - data.method.type === "evaluateTransaction" || - data.method.type === "submitTransaction" - ) { - // Call a synchronous method. - Splug.contractTransaction(args) - .then((respObj) => { - logger.info("*** RESPONSE ***"); - logger.info("Client ID :" + client.id); - logger.info("Response :" + JSON.stringify(respObj)); - client.emit("response", respObj); - }) - .catch((errObj) => { - logger.error("*** ERROR ***"); - logger.error("Client ID :" + client.id); - logger.error("Detail :" + JSON.stringify(errObj)); - client.emit("connector_error", errObj); - }); - } else if (data.method.type === "sendSignedTransaction") { - // Call an asynchronous method. - Splug.sendSignedTransaction(args) - .then((respObj) => { - logger.info("*** RESPONSE ***"); - logger.info("Client ID :" + client.id); - logger.info("Response :" + JSON.stringify(respObj)); - client.emit("response", respObj); - }) - .catch((errObj) => { - logger.error("*** ERROR ***"); - logger.error("Client ID :" + client.id); - logger.error("Detail :" + JSON.stringify(errObj)); - client.emit("connector_error", errObj); - }); - } else if (data.method.type === "function") { - const func = args["method"].command; - logger.info(`##method.type: function, function: ${func}`); - // logger.info(`##args: ${JSON.stringify(args)}`); - if (Splug.isExistFunction(func)) { - // Can be called with Server plugin function name. - (Splug as any)[func](args) - .then((respObj: unknown) => { - logger.info("*** RESPONSE ***"); - logger.info("Client ID :" + client.id); - logger.info("Response :" + JSON.stringify(respObj)); - client.emit("response", respObj); - }) - .catch((errObj: unknown) => { - logger.error("*** ERROR ***"); - logger.error("Client ID :" + client.id); - logger.error("Detail :" + JSON.stringify(errObj)); - client.emit("connector_error", errObj); - }); - } else { - // No such function - const emsg = "Function " + func + " not found!"; - logger.error(emsg); - const retObj = { - status: 504, - errorDetail: emsg, - }; - client.emit("connector_error", retObj); - } - } else { - // No such function - const emsg = "Function " + func + " not found!"; - logger.error(emsg); - const retObj = { - status: 504, - errorDetail: emsg, - }; - client.emit("connector_error", retObj); - } - }); - - /** - * startMonitor: starting block generation event monitoring - **/ - client.on("startMonitor", function () { - Smonitor.startMonitor(client.id, (event) => { - let emitType = ""; - - if (event.status == 200) { - emitType = "eventReceived"; - logger.info("event data callbacked."); - } else { - emitType = "monitor_error"; - } - - client.emit(emitType, event); - }); - }); - - /** - * stopMonitor: block generation events monitoring stopping - **/ - // I think it is more common to stop from the disconnect described later, but I will prepare for it. - client.on("stopMonitor", function (reason) { - Smonitor.stopMonitor(client.id); - }); - - client.on("disconnect", function (reason) { - // Unexpected disconnect as well as explicit disconnect request can be received here - logger.info("Client " + client.id + " disconnected."); - logger.info("Reason :" + reason); - // Stop monitoring if disconnected client is for event monitoring - Smonitor.stopMonitor(client.id); - }); - }); - - // Listen on provided port, on all network interfaces. - return new Promise((resolve) => server.listen(sslport, () => resolve(server))); -}; - -// Normalize a port into a number, string, or false. -function normalizePort(val: string) { - const port = parseInt(val, 10); - - if (isNaN(port)) { - // named pipe - return val; - } - - if (port >= 0) { - // port number - return port; - } - - return false; -} - -if (require.main === module) { - // When this file executed as a script, not loaded as module - run the connector - startFabricSocketIOConnector().then((server) => { - const addr = server.address(); - - if (!addr) { - logger.error("Could not get running server address - exit."); - process.exit(1); - } - - const bind = typeof addr === "string" ? "pipe " + addr : "port " + addr.port; - logger.debug("Listening on " + bind); - }).catch((err) => { - logger.error("Could not start fabric-socketio connector:", err); - }); -} diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/ServerMonitorPlugin.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/ServerMonitorPlugin.ts deleted file mode 100644 index be757d199b..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/ServerMonitorPlugin.ts +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright 2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * ServerMonitorPlugin.js - */ - -/* - * Summary: - * Monitoring class of connection destination dependent part of linkage server - * Used when performing continuous monitoring. - * Processing that ends with reception of a single event is supported by implementing a unique function in ServerPlugin. - * Unlike ServerPlugin, it does not basically handle its own functions. - */ - -// Basic package dependency declaration -const process = require("process"); -import FabricClient from "fabric-client"; -// IF declaration for fabric -import { getClientAndChannel, getSubmitterAndEnroll } from "./fabricaccess"; -// config file -import { - configRead, - signMessageJwt, -} from "@hyperledger/cactus-cmd-socketio-server"; -// Log settings -import { getLogger } from "log4js"; -const logger = getLogger("ServerMonitorPlugin[" + process.pid + "]"); -logger.level = configRead("logLevel", "info"); -// utility -import { safeStringifyException } from "@hyperledger/cactus-common"; - -export type MonitorCallback = (callback: { - status: number; - blockData?: string; - errorDetail?: string; -}) => void; - -/* - * ServerMonitorPlugin - * Server monitoring class definition - */ -export class ServerMonitorPlugin { - _filterTable = new Map(); - _eh?: FabricClient.ChannelEventHub; - - /* - * startMonitor - * Start monitoring - * @param {string} clientId : Client ID of the monitoring start request source - * @param {function} cb : Callback function that receives the monitoring result at any time - * @note Always listens on the first peer from config. - */ - startMonitor(clientId: string, cb: MonitorCallback) { - logger.info("*** START MONITOR ***"); - logger.info("Client ID :" + clientId); - const filter = this._filterTable.get(clientId); - let channel: FabricClient.Channel; - - if (!filter) { - getClientAndChannel() - .then((retobj) => { - channel = retobj.channel; //Set the returned channel - this._filterTable.set(clientId, retobj.client); - return getSubmitterAndEnroll(retobj.client); - }) - .then(() => { - this._eh = channel.newChannelEventHub( - channel.getPeers()[0].getPeer(), - ); - logger.info("Connecting the event hub"); - this._eh.registerBlockEvent( - (block) => { - const txlist = []; - logger.info("*** Block Event ***"); - - if (!("header" in block && "data" in block)) { - logger.warn( - "Invalid block type fromregisterBlockEvent - expected FabricClient.Block", - ); - return; - } - - console.log("##[HL-BC] Notify new block data(D2)"); - logger.info( - "chain id :" + configRead("fabric.channelName"), - ); - logger.info("blocknumber : " + block.header.number); - const len = block.data.data.length; - logger.info("data.data.length :" + len); - console.log("##[HL-BC] Validate transactions(D3)"); - console.log("##[HL-BC] digital sign on valid transaction(D4)"); - for (let i = 0; i < len; i++) { - const payload = block.data.data[i].payload; - const channel_header = payload.header.channel_header; - if (channel_header.type == 3) { - //'ENDORSER_TRANSACTION' - const txid = channel_header.tx_id; - logger.info("transaction id :" + txid); - const transaction = payload.data; - const actionPayload = transaction.actions[0].payload; - const proposalPayload = - actionPayload.chaincode_proposal_payload; - const invocationSpec = proposalPayload.input; - // Can obtain chaincode name and argument list (function name at the beginning) from invocationSpec - const ccid = invocationSpec.chaincode_spec.chaincode_id.name; - logger.info("chaincode id :" + ccid); - // Only notify transactions from the chaincode used in ServerPlugin - if (ccid == configRead("fabric.chaincodeId")) { - const args = invocationSpec.chaincode_spec.input.args; - logger.info("args.length :" + args.length); - for (let j = 0; j < args.length; j++) { - // code must be specified for toString - args[j] = args[j].toString("utf8"); - logger.info("args[" + j + "] :" + args[j]); - } - const func = args[0]; - args.shift(); - - // Interpretation of response - const resp = - actionPayload.action.proposal_response_payload.extension - .response.payload; - logger.info("resp :" + resp); - - //The transaction data should include the following. - txlist.push({ - chaincodeId: ccid, - txId: txid, - func: func, - args: args, - }); - } - } - } - logger.info("*** SEND BLOCK DATA ***"); - logger.debug(`txlist = ${JSON.stringify(txlist)}`); - const signedTxlist = signMessageJwt({ - blockData: txlist, - }); - logger.debug(`signedTxlist = ${signedTxlist}`); - const retObj = { - status: 200, - blockData: signedTxlist, - }; - cb(retObj); - }, - (err) => { - logger.warn(`Monitor error for client ${clientId} - `, err); - }, - ); - this._eh.connect(true); //fullBlock=true - }) - .catch((err) => { - logger.error(err); - const errObj = { - status: 504, - errorDetail: safeStringifyException(err), - }; - cb(errObj); - }); - } else { - logger.info("target filter has already start watching."); - } - } - - /* - * stopMonitor - * Stop monitoring - * @param {string} clientId : Client ID of the monitoring stop request source - */ - stopMonitor(clientId: string) { - const filter = this._filterTable.get(clientId); - - if (filter) { - // Stop filter & remove from table - if (this._eh == null) { - logger.error("EventHub does not exist"); - return; - } - if (this._eh.isconnected()) { - logger.info("Disconnecting the event hub"); - this._eh.disconnect(); - } - this._filterTable.delete(clientId); - } - } -} diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/ServerPlugin.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/ServerPlugin.ts deleted file mode 100644 index 6dab5b45e3..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/ServerPlugin.ts +++ /dev/null @@ -1,1066 +0,0 @@ -/* - * Copyright 2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * ServerPlugin.js - */ - -/* - * Summary: - * Dependent part of the connection destination of the connector - * Define and implement the function independently according to the connection destination dependent part (adapter) on the core side. - */ - -import path from "path"; -import Client, { - Proposal, - ProposalRequest, - ProposalResponse, - Block, -} from "fabric-client"; -import { FileSystemWallet, Gateway } from "fabric-network"; - -import { getClientAndChannel, getSubmitterAndEnroll } from "./fabricaccess"; -import { signProposal } from "./sign-utils"; -import { - ProposalSerializer, - ProposalResponseSerializer, -} from "./fabric-proto-serializers"; - -// Config reading -import { - configRead, - signMessageJwt, -} from "@hyperledger/cactus-cmd-socketio-server"; -const connUserName = configRead("fabric.connUserName"); - -// Log settings -import { getLogger } from "log4js"; -import { safeStringifyException } from "@hyperledger/cactus-common"; -const logger = getLogger("ServerPlugin[" + process.pid + "]"); -logger.level = configRead("logLevel", "info"); - -///////////////////////////// -// API call signatures -///////////////////////////// - -/** - * `generateUnsignedProposal()` input argument type. - */ -type GenerateUnsignedProposalArgs = { - contract: { - channelName: string; - }; - args: { - args: { - transactionProposalReq: Client.ProposalRequest; - certPem: string; - }; - }; - reqID?: string; -}; - -/** - * `generateUnsignedTransaction()` input argument type. - */ -type GenerateUnsignedTransactionArgs = { - contract: { - channelName: string; - }; - args: { - args: { - proposal: string; - proposalResponses: string[]; - }; - }; - reqID?: string; -}; - -/** - * `sendSignedProposal()` input argument type. - */ -type SendSignedProposalArgs = { - contract: { - channelName: string; - }; - args: { - args: { - transactionProposalReq: Client.ProposalRequest; - certPem?: string; - privateKeyPem?: string; - }; - }; - reqID?: string; -}; - -/** - * `sendSignedProposalV2()` input argument type. - */ -type SendSignedProposalV2Args = { - contract: { - channelName: string; - }; - args: { - args: { - signedProposal: Buffer; - }; - }; - reqID?: string; -}; - -/** - * `sendSignedTransactionV2()` input argument type. - */ -type SendSignedTransactionV2Args = { - contract: { - channelName: string; - }; - args: { - args: { - signedCommitProposal: Buffer; - proposal: string; - proposalResponses: string[]; - }; - }; - reqID?: string; -}; - -///////////////////////////// -// ServerPlugin Class -///////////////////////////// - -export class ServerPlugin { - /* - * isExistFunction - * - * @param {String} funcName : The function name you want to determine. - * - * @return {Boolean} true : exist / false : not exist - * - * @desc Determines if the specified function exists in its class. - * Make sure that the support status of your class can be determined by your class. - * Functions that you do not want to call directly need to be devised such as implemented outside of this class like utilities. - */ - isExistFunction(funcName: string) { - if ((this as any)[funcName]) { - return true; - } else { - return false; - } - } - - /* - * contractTransaction(Sync) - * - * @param {Object} args : JSON Object - * { - * "contract": { - * "channelName": , - * "contractName": - * }, - * "args": { - * "args":[ - * , - * < : >, - * < : > - * ] - * }, - * "method": { - * "method": - * ] - * }, - * "reqID": // option - * } - * @return {Object} JSON object - */ - contractTransaction(args: any) { - return new Promise((resolve, reject) => { - logger.info("evaluateTransaction start"); - // logger.debug(`##evaluateTransaction(A)`); - let retObj: Record; - let reqID = args["reqID"]; - if (reqID === undefined) { - reqID = null; - } - // logger.debug(`##evaluateTransaction(Aa): args: ${JSON.stringify(args.args.args)}, reqID: ${reqID}`); - const reqparam = { - method: args.method, - args: args.args.args, - channelName: args.contract.channelName, - contractName: args.contract.contractName, - }; - // Block generation event monitoring target because it is performed from the operation request by the CC chain code - InvokeSync(reqparam) - .then((returnvalue: any) => { - // logger.debug(`##evaluateTransaction(B)`); - // logger.debug(`##evaluateTransaction(B1), returnvalue: ${returnvalue}`); - if (returnvalue == null) { - logger.debug(`##evaluateTransaction(B2), returnvalue: null`); - } else if (returnvalue == undefined) { - logger.debug(`##evaluateTransaction(B3), returnvalue: undefined`); - } else if (returnvalue == "") { - logger.debug( - `##evaluateTransaction(B4), returnvalue: empty string`, - ); - } - if (returnvalue != null) { - // logger.debug(`##evaluateTransaction(B5)`); - let objRetValue = {}; - if (returnvalue != "") { - // logger.debug(`##evaluateTransaction(B6)`); - objRetValue = JSON.parse(returnvalue); - } - const signedResults = signMessageJwt({ - result: objRetValue, - }); - retObj = { - resObj: { - status: 200, - data: signedResults, - }, - }; - if (reqID !== null) { - retObj["id"] = reqID; - } - logger.debug(`##evaluateTransaction(C1c) retObj: ${retObj}`); - return resolve(retObj); - } - }) - .catch((err) => { - logger.debug(`##evaluateTransaction(D)`); - retObj = { - resObj: { - status: 504, - errorDetail: safeStringifyException(err), - }, - }; - logger.error(err); - return reject(retObj); - }); - }); - } - - /** - * Offline trading - * @param {object} args : JSON Object - * { - * "args": { - * "contract": {"channelName": channelName}, - * "args":[ - * { - * "signedCommitProposal":, - * "commitReq": - * } - * ] - * }, - * "reqID": // option - * } - * @return {Object} JSON object - */ - sendSignedTransaction(args: any) { - return new Promise((resolve, reject) => { - logger.info("sendSignedTransaction start"); - let retObj: Record; - - // parameter check - logger.info("sendSignedTransaction parameter check"); - const channelName = args.contract.channelName; - const signedCommitProposal = args.args.args[0].signedCommitProposal; - const commitReq = args.args.args[0].commitReq; - // logger.debug(`##sendSignedTransaction: channelName = ${channelName}`); - // logger.debug(`##sendSignedTransaction: signedCommitProposal = ${JSON.stringify(signedCommitProposal)}`); - // logger.debug(`##sendSignedTransaction: commitReq = ${JSON.stringify(commitReq)}`); - if (signedCommitProposal == undefined || commitReq == undefined) { - const emsg = "Insufficient parameters."; - logger.info(emsg); - retObj = { - status: 504, - errorDetail: emsg, - }; - return reject(retObj); - } - const reqparam = { - signedCommitProposal: signedCommitProposal, - commitReq: commitReq, - channelName: channelName, - }; - // call chainncode - InvokeSendSignedTransaction(reqparam) - .then((returnvalue) => { - if (returnvalue != null) { - retObj = { - resObj: { - status: 200, - data: returnvalue, - }, - }; - - if (args.reqID) { - retObj["id"] = args.reqID; - } - return resolve(retObj); - } - }) - .catch((err) => { - retObj = { - status: 504, - errorDetail: safeStringifyException(err), - }; - logger.error(err); - return reject(retObj); - }); - }); - } - - /** - * API request to send commit transaction signed on the client side. - * No user cryptographic data is handled by this function. - * Uses Fabric-SDK `channel.sendSignedTransaction` call. - * - * @param args.signedCommitProposal Signed commit proposal buffer. - * @param args.proposal Encoded proposal from `generateUnsignedProposal` API call. - * @param args.proposalResponses Encoded endorsing responses from `sendSignedProposalV2` API call. - * @returns Send status. - */ - async sendSignedTransactionV2(args: SendSignedTransactionV2Args) { - logger.info("sendSignedTransactionV2 start"); - - // Parse arguments - const channelName = args.contract.channelName; - const signedCommitProposal = args.args.args.signedCommitProposal; - const proposal = ProposalSerializer.decode(args.args.args.proposal); - let proposalResponses: any[] = args.args.args.proposalResponses.map((val) => - ProposalResponseSerializer.decode(val), - ); - let reqID = args.reqID; - logger.info(`##sendSignedTransactionV2: reqID: ${reqID}`); - - if ( - !channelName || - !signedCommitProposal || - !proposal || - proposalResponses.length === 0 - ) { - throw { - resObj: { - status: 504, - errorDetail: "sendSignedTransactionV2: Invalid input parameters", - }, - }; - } - - // Logic - try { - const invokeResponse = await InvokeSendSignedTransaction({ - signedCommitProposal, - commitReq: { - proposal, - proposalResponses, - }, - channelName: channelName, - }); - logger.info("sendSignedTransactionV2: done."); - - return { - id: reqID, - resObj: { - status: 200, - data: invokeResponse, - }, - }; - } catch (error) { - logger.error("sendSignedTransactionV2() error:", error); - throw { - resObj: { - status: 504, - errorDetail: safeStringifyException(error), - }, - }; - } - } - - /** - * API request to send transaction endorsment. - * Uses cryptographic data either from input arguments, or from local (connectors) wallet. - * - * @param args.transactionProposalReq Raw transaction that will be turned into proposal. - * @param args.certPem Client public key in PEM format. - * @param args.privateKeyPem Client private key in PEM format. - * @returns signedCommitProposal Signed transaction proposal. - * @returns commitReq Unsigned commit request. - * @returns txId Transaction ID. - */ - async sendSignedProposal(args: SendSignedProposalArgs) { - logger.info("sendSignedProposal start"); - - // Parse arguments - const channelName = args.contract.channelName; - const transactionProposalReq = args.args.args.transactionProposalReq; - let certPem = args.args.args.certPem; - let privateKeyPem = args.args.args.privateKeyPem; - let reqID = args.reqID; - logger.info(`##sendSignedProposal: reqID: ${reqID}`); - - // Logic - try { - let { client, channel } = await getClientAndChannel(channelName); - - if (!certPem || !privateKeyPem) { - // Get identity from connector wallet - const submiterId = await getSubmiterIdentityCrypto(client); - certPem = submiterId.certPem; - privateKeyPem = submiterId.privateKeyPem; - } - - if (!certPem || !privateKeyPem) { - throw Error( - "Could not read certificate and private key of the submitter.", - ); - } - - // Generate endorsement proposal - const { proposal, txId } = InvokeGenerateUnsignedProposal( - channel, - transactionProposalReq, - certPem, - ); - const signedProposal = signProposal(proposal.toBuffer(), privateKeyPem); - - // Send proposal, get endorsment responses - const { - endorsmentStatus, - proposalResponses, - } = await InvokeSendSignedProposalV2(channel, signedProposal as any); - logger.info("sendSignedProposal: done."); - - if (!endorsmentStatus) { - throw new Error( - "Failed to send Proposal or receive valid response. Response null or status is not 200. exiting...", - ); - } - - // Generate commit proposal - const commitProposal = await InvokeGenerateUnsignedTransaction( - channel, - proposalResponses as any, - proposal, - ); - const signedCommitProposal = signProposal( - commitProposal.toBuffer(), - privateKeyPem, - ); - - // Send the response - const signedResults = signMessageJwt({ - result: { - signedCommitProposal, - commitReq: { proposalResponses, proposal }, - txId: txId.getTransactionID(), - }, - }); - - return { - id: reqID, - resObj: { - status: 200, - data: signedResults, - }, - }; - } catch (error) { - logger.error("sendSignedProposal() error:", error); - throw { - resObj: { - status: 504, - errorDetail: safeStringifyException(error), - }, - }; - } - } - - /** - * Get fabric block specified in args. - * - * @param args - * ``` javascript - * { - * "args": { - * "contract": {"channelName": string}, // Fabric channel to execute the request on - * "args": { - * // OneOf following fields is required. First one found will be used. - * "blockNumber"?: number, - * "blockHash"?: Array, - * "txId"?: string, - * // Optional. If true, this function returns an encoded block. - * "skipDecode"?: boolean, - * } - * }, - * "reqID": string // optional requestID from verifier - * } - * ``` - */ - async getBlock(args: any) { - logger.info("getBlock start"); - - const channelName = args.contract.channelName; - const blockNumber = args.args.blockNumber; - const blockHash = args.args.blockHash; - const txId = args.args.txId; - const skipDecode = args.args.skipDecode ?? false; - - const reqID = args.reqID ?? null; - logger.info(`##getBlock: reqID: ${reqID}`); - - let { client, channel } = await getClientAndChannel(channelName); - await getSubmitterAndEnroll(client); - - let block: Block; - if (typeof blockNumber === "number") { - block = await channel.queryBlock( - blockNumber, - undefined, - undefined, - skipDecode, - ); - } else if (blockHash) { - block = await channel.queryBlockByHash( - blockHash, - undefined, - undefined, - skipDecode, - ); - } else if (txId) { - block = await channel.queryBlockByTxID( - txId, - undefined, - undefined, - skipDecode, - ); - } else { - const errObj = { - resObj: { - status: 400, - errorDetail: - "getBlock: Provide either blockNumber, blockHash, or txId", - }, - id: reqID, - }; - logger.error(errObj); - throw errObj; - } - - if (!block) { - const errObj = { - resObj: { - status: 504, - errorDetail: "getBlock: Could not retrieve block", - }, - id: reqID, - }; - logger.error(errObj); - throw errObj; - } - - const signedBlock = signMessageJwt({ - result: block, - }); - - const retObj = { - resObj: { - status: 200, - data: signedBlock, - }, - id: reqID, - }; - logger.debug("##getBlock: response:", retObj); - - return retObj; - } - - /** - * API request to send endorsement proposal signed on the client side. - * No user cryptographic data is handled by this function. - * Uses Fabric-SDK `channel.sendSignedProposal` call. - * - * @param args.signedProposal Signed proposal buffer from `generateUnsignedProposal` API call. - * @returns endorsmentStatus Bool whether endorsment was OK or not. - * @returns proposalResponses Encoded responses to be used to generate commit proposal. - */ - async sendSignedProposalV2(args: SendSignedProposalV2Args) { - logger.info("sendSignedProposalV2 start"); - - // Parse arguments - const channelName = args.contract.channelName; - const signedProposal = args.args.args.signedProposal; - let reqID = args.reqID; - logger.info(`##sendSignedProposalV2: reqID: ${reqID}`); - - // Logic - try { - let { channel } = await getClientAndChannel(channelName); - - const invokeResponse = await InvokeSendSignedProposalV2( - channel, - signedProposal, - ); - logger.info("sendSignedProposalV2: done."); - - let proposalResponses = invokeResponse.proposalResponses.map((val: any) => - ProposalResponseSerializer.encode(val), - ); - logger.debug( - `sendSignedProposalV2: encoded ${proposalResponses.length} proposalResponses.`, - ); - - const signedResults = signMessageJwt({ - result: { - endorsmentStatus: invokeResponse.endorsmentStatus, - proposalResponses, - }, - }); - - return { - id: reqID, - resObj: { - status: 200, - data: signedResults, - }, - }; - } catch (error) { - logger.error("sendSignedProposalV2() error:", error); - throw { - resObj: { - status: 504, - errorDetail: safeStringifyException(error), - }, - }; - } - } - - /** - * API request to generate unsigned endorse proposal. - * Proposal must be signed on the client side. - * Uses Fabric-SDK `channel.generateUnsignedProposal` call. - * - * @param args.transactionProposalReq Raw transaction that will be turned into proposal. - * @param args.certPem Client public key in PEM format. - * @returns proposalBuffer Generated unsigned endorse proposal buffer. - * @returns proposal Encoded proposal to be used in follow-up calls to the connector. - * @returns txId Transaction ID. - */ - async generateUnsignedProposal(args: GenerateUnsignedProposalArgs) { - logger.info("generateUnsignedProposal: start"); - - // Parse arguments - const channelName = args.contract.channelName; - const transactionProposalReq = args.args.args.transactionProposalReq; - const certPem = args.args.args.certPem; - let reqID = args.reqID; - logger.info(`##generateUnsignedProposal: reqID: ${reqID}`); - - // Logic - try { - let { channel } = await getClientAndChannel(channelName); - - let invokeResponse = InvokeGenerateUnsignedProposal( - channel, - transactionProposalReq, - certPem, - ); - if (!invokeResponse.proposal || !invokeResponse.txId) { - throw new Error( - "generateUnsignedProposal: empty proposal or transaction id.", - ); - } - logger.info(`generateUnsignedProposal: done.`); - - const signedResults = signMessageJwt({ - result: { - proposalBuffer: invokeResponse.proposal.toBuffer(), - proposal: ProposalSerializer.encode(invokeResponse.proposal), - txId: invokeResponse.txId.getTransactionID(), - }, - }); - - return { - id: reqID, - resObj: { - status: 200, - data: signedResults, - }, - }; - } catch (error) { - logger.error("generateUnsignedProposal() error:", error); - throw { - resObj: { - status: 504, - errorDetail: safeStringifyException(error), - }, - }; - } - } - - /** - * API request to generate unsigned commit (transaction) proposal. - * Proposal must be signed on the client side. - * Uses Fabric-SDK `channel.generateUnsignedTransaction` call. - * - * @param args.proposal Encoded proposal from `generateUnsignedProposal` API call. - * @param args.proposalResponses Encoded proposal responses from `sendSignedProposalV2` API call. - * @returns txProposalBuffer Unsigned proposal buffer. - */ - async generateUnsignedTransaction(args: GenerateUnsignedTransactionArgs) { - logger.info("generateUnsignedTransaction: start"); - - // Parse arguments - const channelName = args.contract.channelName; - const proposal = ProposalSerializer.decode(args.args.args.proposal); - let proposalResponses: any[] = args.args.args.proposalResponses.map((val) => - ProposalResponseSerializer.decode(val), - ); - logger.debug( - `##generateUnsignedTransaction Received ${proposalResponses.length} proposal responses`, - ); - let reqID = args.reqID; - logger.info(`##generateUnsignedTransaction: reqID: ${reqID}`); - - // Logic - try { - let { channel } = await getClientAndChannel(channelName); - - const txProposal = await InvokeGenerateUnsignedTransaction( - channel, - proposalResponses, - proposal, - ); - logger.info(`generateUnsignedTransaction: done.`); - - const signedResults = signMessageJwt({ - result: { - txProposalBuffer: txProposal.toBuffer(), - }, - }); - - return { - id: reqID, - resObj: { - status: 200, - data: signedResults, - }, - }; - } catch (error) { - logger.error("generateUnsignedTransaction() error:", error); - throw { - resObj: { - status: 504, - errorDetail: safeStringifyException(error), - }, - }; - } - } -} /* class */ - -///////////////////////////// -// Invoke (logic) functions -///////////////////////////// - -/** - * Read public and private keys of the submitter from connector wallet. - * Throws `Error()` when submiters identity is missing. - * - * @param client Fabric-SDK channel client object. - * @returns `certPem`, `privateKeyPem` - */ -async function getSubmiterIdentityCrypto(client: Client) { - const wallet = new FileSystemWallet(configRead("fabric.keystore")); - logger.debug( - `Wallet path: ${path.resolve(configRead("fabric.keystore"))}`, - ); - - let user = await getSubmitterAndEnroll(client); - const submitterName = user.getName(); - const submitterExists = await wallet.exists(submitterName); - if (submitterExists) { - const submitterIdentity = await wallet.export(submitterName); - const certPem = (submitterIdentity as any).certificate as string; - const privateKeyPem = (submitterIdentity as any).privateKey as string; - return { certPem, privateKeyPem }; - } else { - throw new Error( - `No cert/key provided and submitter ${submitterName} is missing in validator wallet!`, - ); - } -} - -/* - * Invoke Sync function - * @param reqBody [json object] {fcn:, args:[arg1>,,,,], channelName:, contractName:} - * @return [string] Success: Chain code execution result - * Failure: Chain code error or internal error - */ -async function InvokeSync(reqBody: any) { - return new Promise(async function (resolve, reject) { - try { - logger.info("##fablicaccess: InvokeSync start"); - // logger.debug(`##InvokeSync(A)`); - - const type = reqBody.method.type; - const fcn = reqBody.method.command; - const args = reqBody.args; - - // Create a new file system based wallet for managing identities. - // logger.debug(`##InvokeSync(B)`); - const wallet = new FileSystemWallet( - configRead("fabric.keystore"), - ); - console.log(`Wallet path: ${configRead("fabric.keystore")}`); - - // Check to see if we've already enrolled the user. - // logger.debug(`##InvokeSync(C)`); - const userExists = await wallet.exists(connUserName); - if (!userExists) { - logger.debug(`##InvokeSync(C1)`); - //logger.error(`An identity for the user ${connUserName} does not exist in the wallet`); - const errMsg = `An identity for the user ${connUserName} does not exist in the wallet`; - logger.error(errMsg); - logger.error("Run the registerUser.js application before retrying"); - return reject(errMsg); - } - - // Create a new gateway for connecting to our peer node. - let { client } = await getClientAndChannel(reqBody.channelName); - await getSubmitterAndEnroll(client); - - const gateway = new Gateway(); - await gateway.connect(client, { - wallet, - identity: connUserName, - discovery: { enabled: false }, - }); - - // Get the network (channel) our contract is deployed to. - // logger.debug(`##InvokeSync(E)`); - const network = await gateway.getNetwork(reqBody.channelName); - - // Get the contract from the network. - // logger.debug(`##InvokeSync(F)`); - const contract = network.getContract(reqBody.contractName); - - // Submit the specified transaction. - // logger.debug(`##InvokeSync(G)`); - logger.info( - `##fablicaccess: InvokeSync Params: type=${type}, fcn=${fcn}, args0=${args[0]}, args1=${args[1]}, args2=${args[2]}`, - ); - // const transaction = contract.createTransaction(fcn); - let result: any = null; - switch (args.length) { - case 0: - // logger.debug(`##InvokeSync(G1): No args.`); - if (type === "evaluateTransaction") { - logger.debug(`##InvokeSync(G1): call evaluateTransaction`); - result = await contract.evaluateTransaction(fcn); - } else { - logger.debug(`##InvokeSync(G1): call submitTransaction`); - result = await contract.submitTransaction(fcn); - } - break; - case 1: - // logger.debug(`##InvokeSync(G2): One arg.`); - if (type === "evaluateTransaction") { - logger.debug(`##InvokeSync(G1): call evaluateTransaction`); - result = await contract.evaluateTransaction(fcn, args[0]); - } else { - logger.debug(`##InvokeSync(G1): call submitTransaction`); - result = await contract.submitTransaction(fcn, args[0]); - } - break; - case 2: - // logger.debug(`##InvokeSync(G3): Two args.`); - if (type === "evaluateTransaction") { - logger.debug(`##InvokeSync(G1): call evaluateTransaction`); - result = await contract.evaluateTransaction(fcn, args[0], args[1]); - } else { - logger.debug(`##InvokeSync(G1): call submitTransaction`); - result = await contract.submitTransaction(fcn, args[0], args[1]); - } - break; - case 3: - // logger.debug(`##InvokeSync(G4): Three args.`); - if (type === "evaluateTransaction") { - logger.debug(`##InvokeSync(G1): call evaluateTransaction`); - result = await contract.evaluateTransaction( - fcn, - args[0], - args[1], - args[2], - ); - } else { - logger.debug(`##InvokeSync(G1): call submitTransaction`); - result = await contract.submitTransaction( - fcn, - args[0], - args[1], - args[2], - ); - } - break; - } - logger.info(`##fablicaccess: InvokeSync result: ${result}`); - console.log(`##fablicaccess: InvokeSync result: ${result}`); - - logger.debug(`##InvokeSync(I)`); - return resolve(result); - } catch (error) { - // logger.debug(`##InvokeSync(Z)`); - const errMsg = `Failed to submit transaction: ${error}`; - logger.error(errMsg); - return reject(errMsg); - } - }); -} - -/** - * Function for InvokeSendSignedTransaction - * @param reqBody [json object] {signedCommitProposal:, commitReq:, channelName:} - * @return [string] Success: Chain code execution result - * Failure: Chain code error or internal error - */ -async function InvokeSendSignedTransaction(reqBody: any) { - return new Promise(async function (resolve, reject) { - logger.info("InvokeSendSignedTransaction start"); - - let invokeResponse1; // Return value from chain code - - try { - //channel object generation - let { client, channel } = await getClientAndChannel(reqBody.channelName); - await getSubmitterAndEnroll(client); - - // logger.debug(`##InvokeSendSignedTransaction: reqBody.signedCommitProposal: ${JSON.stringify(reqBody.signedCommitProposal)}`); - // logger.debug(`##InvokeSendSignedTransaction: reqBody.commitReq: ${JSON.stringify(reqBody.commitReq)}`); - // logger.debug(`##InvokeSendSignedTransaction: (A)`); - const response = await channel.sendSignedTransaction({ - signedProposal: reqBody.signedCommitProposal, - request: reqBody.commitReq, - } as any); - - // logger.debug(`##InvokeSendSignedTransaction: (B)`); - logger.info("successfully send signedCommitProposal"); - // logger.info("response : " + JSON.stringify(response)); - if (response.status === "SUCCESS") { - // logger.debug(`##InvokeSendSignedTransaction: (C)`); - invokeResponse1 = response; - return resolve(invokeResponse1); - } else { - logger.debug(`##InvokeSendSignedTransaction: (D)`); - throw new Error( - "Failed to order the transaction. Error code: " + response.status, - ); - } - } catch (e) { - logger.debug(`##InvokeSendSignedTransaction: (E)`); - return reject(e); - } - }); -} - -/** - * Call `channel.generateUnsignedProposal` to generate unsigned endorse proposal. - * - * @param channel Fabric-SDK channel object. - * @param txProposal Raw transaction. - * @param certPem Sender public key in PEM format. - * @returns `proposal` - Proposal, `txId` - Transaction object - */ -function InvokeGenerateUnsignedProposal( - channel: Client.Channel, - txProposal: ProposalRequest, - certPem: string, -) { - if (!txProposal || !certPem) { - throw new Error( - "InvokeGenerateUnsignedProposal: Invalid input parameters.", - ); - } - - logger.debug("Call channel.generateUnsignedProposal()"); - - return (channel.generateUnsignedProposal( - txProposal, - configRead("fabric.mspid"), - certPem, - false, - ) as any) as { proposal: any; txId: any }; -} - -/** - * Call `channel.generateUnsignedTransaction` to generate unsigned commit proposal. - * - * @param channel Fabric-SDK channel object. - * @param proposalResponses Proposal responses from endorse step. - * @param proposal Unsigned proposal from `generateUnsignedProposal` - * @returns Unsigned commit proposal. - */ -async function InvokeGenerateUnsignedTransaction( - channel: Client.Channel, - proposalResponses: ProposalResponse[], - proposal: Proposal, -) { - if (!proposal || !proposalResponses || proposalResponses.length === 0) { - throw new Error( - "InvokeGenerateUnsignedTransaction: Invalid input parameters.", - ); - } - - logger.debug("Call channel.generateUnsignedTransaction()"); - - return await channel.generateUnsignedTransaction({ - proposalResponses, - proposal, - }); -} - -/** - * Call `channel.sendSignedProposal`, gather and check the responses. - * - * @param channel Fabric-SDK channel object. - * @param signedProposal Proposal from `generateUnsignedProposal` signed with sender private key. - * @returns `endorsmentStatus`, `proposalResponses` - */ -async function InvokeSendSignedProposalV2( - channel: Client.Channel, - signedProposal: Buffer, -) { - logger.debug(`InvokeSendSignedProposalV2: start`); - - const targets = []; - for (const peerInfo of configRead("fabric.peers")) { - const peer = channel.getPeer(peerInfo.requests.split("//")[1]); - targets.push(peer); - } - const sendSignedProposalReq = { signedProposal, targets } as any; - - const proposalResponses = await channel.sendSignedProposal( - sendSignedProposalReq, - ); - logger.debug( - "##InvokeSendSignedProposalV2: successfully sent signedProposal", - ); - - // Determine endorsment status - let endorsmentStatus = true; - for (const proposalResponse of proposalResponses) { - const propResponse = (proposalResponse as unknown) as Client.ProposalResponse; - if ( - !propResponse || - !propResponse.response || - propResponse.response.status !== 200 - ) { - endorsmentStatus = false; - } - } - - return { - endorsmentStatus, - proposalResponses, - }; -} diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/fabric-proto-serializers.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/fabric-proto-serializers.ts deleted file mode 100644 index bb9e1ae286..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/fabric-proto-serializers.ts +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2022 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * fabric-proto-serializers.js - * - * Helper utils that are used to serialize and deserialize hyperledger fabric structures - * so they can be safely sent through the wire. Depends heavily on protobuf specifications from - * fabric packages. - */ - -import Client from "fabric-client"; -import { cloneDeep } from "lodash"; - -// TS import is using newer protobufjs version typings, use nodejs import for now. -const protobuf = require("protobufjs"); - -////////////////////////////////// -// Helper Functions -////////////////////////////////// - -/** - * Load protobuf definition from fabric module - * @param protoFilePath module name and relative path to protofile to open - * @returns protofile builder object (response of `protobuf.loadProtoFile()`) - */ -function loadFabricProto(protoFilePath: string) { - const fabricModuleProtoPath = require.resolve(protoFilePath); - return protobuf.loadProtoFile(fabricModuleProtoPath).build(); -} - -/** - * Some Fabric SDK functions does not work well with protobuf decoded object type (Message). - * Also, nested `ByteBuffer` are not unwrapped by top-level decode call, this function will do it manually. - * - * @param messageObject - Message produced by protobuf decode call - * @returns Parsed `messageObject` without any nested `ByteBuffer`, that can be safely used by fabric-sdk methods. - */ -function convertToPlainObject(messageObject: Record) { - let plainObject: Record = {}; - - for (let i in messageObject) { - if (messageObject.hasOwnProperty(i)) { - const currentElem = messageObject[i]; - - if (currentElem instanceof protobuf.ByteBuffer) { - // Convert ByteBuffer fields to nodejs Buffer type. - plainObject[i] = currentElem.toBuffer(); - } else if ( - typeof currentElem === "object" && - !Array.isArray(currentElem) && - currentElem !== null - ) { - // Convert each other nested objects as well. - plainObject[i] = convertToPlainObject(currentElem); - } else { - // Copy scalar fields as is - plainObject[i] = currentElem; - } - } - } - - return plainObject; -} - -/** - * Encode some metadata to the message that will be sent to client app. - * - * @param typeName Name of the type we serialied. - * @param encodedData Serialized object representation. - * @returns JSON with metadata included. - */ -function encodeMetdata(typeName: string, encodedData: string): string { - return JSON.stringify({ - metadata: { - typeName, - }, - encodedData: encodedData, - }); -} - -/** - * Decode the message, read and validate metadata attached to this message. - * - * @param typeName Name of the type wa want to deserialize. - * @param encodedMessage Message received from the client. - * @returns Encoded object without metadata. - */ -function decodeMetdata(typeName: string, encodedMessage: string): string { - const { metadata, encodedData } = JSON.parse(encodedMessage); - - // Check metadata - if (metadata.typeName !== typeName) { - throw new Error( - `decodeMetdata(): requested type mismatch. Wanted to decode: ${typeName}, received: ${metadata.typeName}`, - ); - } - - return encodedData; -} - -////////////////////////////////// -// Serializers -////////////////////////////////// - -// Protobuf builders -const proposalBuilder = loadFabricProto( - "fabric-client/lib/protos/peer/proposal.proto", -); -const proposalResponseBuilder = loadFabricProto( - "fabric-client/lib/protos/peer/proposal_response.proto", -); - -/** - * Client.Proposal serializers - */ -export namespace ProposalSerializer { - export const ProposalType = proposalBuilder.protos.Proposal; - const proposalTypeName = ProposalType["$type"].name; - - export function encode(proposal: Client.Proposal): string { - return encodeMetdata(proposalTypeName, (proposal as any).encodeJSON()); - } - - export function decode(encodedProposal: string): Client.Proposal { - return ProposalType.decodeJSON( - decodeMetdata(proposalTypeName, encodedProposal), - ); - } -} - -/** - * Client.ProposalResponse serializers - */ -export namespace ProposalResponseSerializer { - export const ProposalResponseType = - proposalResponseBuilder.protos.ProposalResponse; - const proposalResponseTypeName = ProposalResponseType["$type"].name; - - export function encode(proposalResponse: Client.ProposalResponse): string { - let proposalResponseCopy = cloneDeep(proposalResponse) as Record< - string, - any - >; - - // Peer is not part of protobuf definition, remove it. - delete proposalResponseCopy.peer; - - let proposalResponseMessage = new ProposalResponseType( - proposalResponseCopy, - ); - const encodedProposalResponse = proposalResponseMessage.encodeJSON(); - return encodeMetdata(proposalResponseTypeName, encodedProposalResponse); - } - - export function decode(encodedProposalResponse: string) { - let decodedProposalResponse = ProposalResponseType.decodeJSON( - decodeMetdata(proposalResponseTypeName, encodedProposalResponse), - ); - return convertToPlainObject(decodedProposalResponse); - } -} diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/fabricaccess.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/fabricaccess.ts deleted file mode 100644 index 5da5ad4f8d..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/fabricaccess.ts +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright 2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * fabricaccess.js - */ - -/* - * Summary: - * Request processing library for fabric v1.4.0 - */ - -//Dependent library -import { configRead } from "@hyperledger/cactus-cmd-socketio-server"; -const path = require("path"); -import fs from "fs"; - -//fabric client dependent library -import FabricClient, { User } from "fabric-client"; -import copService, { TLSOptions } from "fabric-ca-client"; - -// list of fabric-client objects -const clients = new Map(); - -// Log settings -import { getLogger } from "log4js"; -const logger = getLogger("fabricaccess[" + process.pid + "]"); -logger.level = configRead("logLevel", "info"); - -// Get user object to send Proposal to EP -export function getSubmitterAndEnroll(cli: FabricClient): Promise { - logger.info("##fabricaccess_getSubmitter"); - const caUrl = configRead("fabric.ca.url"); - const caName = configRead("fabric.ca.name"); - // Returns Promise when checkPersistence is true (poor typing) - return (cli.getUserContext( - configRead("fabric.submitter.name"), - true, - ) as Promise).then((user) => { - return new Promise((resolve, reject) => { - if (user && user.isEnrolled()) { - return resolve(user); - } - const member = new User(configRead("fabric.submitter.name")); - let cryptoSuite = cli.getCryptoSuite(); - if (!cryptoSuite) { - const storePath = path.join( - configRead("fabric.keystore"), - configRead("fabric.submitter.name"), - ); - cryptoSuite = FabricClient.newCryptoSuite(); - cryptoSuite.setCryptoKeyStore( - FabricClient.newCryptoKeyStore({ - path: storePath, - }), - ); - cli.setCryptoSuite(cryptoSuite); - } - member.setCryptoSuite(cryptoSuite); - - const tlsOptions: TLSOptions = { - trustedRoots: Buffer.from([]), - verify: false, - }; - const cop = new copService(caUrl, tlsOptions, caName, cryptoSuite); - return cop - .enroll({ - enrollmentID: configRead("fabric.submitter.name"), - enrollmentSecret: configRead("fabric.submitter.secret"), - }) - .then((enrollment) => { - return member.setEnrollment( - enrollment.key, - enrollment.certificate, - configRead("fabric.mspid"), - ); - }) - .then(() => { - return cli.setUserContext(member, false); - }) - .then(() => { - return resolve(member); - }) - .catch((err) => { - return reject(err); - }); - }); - }); -} - -// fabric-client and Channel object generation -export async function getClientAndChannel( - channelName = configRead("fabric.channelName"), -) { - logger.info("##fabricaccess_getClientAndChannel"); - // Since only one KVS can be set in the client, management in CA units as well as KVS path - let isNewClient = false; - let client = clients.get(configRead("fabric.ca.name")); - if (!client) { - logger.info("create new fabric-client"); - client = new FabricClient(); - clients.set(configRead("fabric.ca.name"), client); - isNewClient = true; - } - - let channel = null; - - // * If getChannel of v1.0 SDK does not exist, an exception is returned instead of null, so try ~ catch - // Therefore, the error from Client.js will always be output in the log for the first time, but it is not harmful - try { - channel = client.getChannel(channelName); - } catch (e) { - if (channel == null) { - logger.info("create new channel, name=" + channelName); - channel = client.newChannel(channelName); - - let ordererCA: string; - try { - ordererCA = configRead('fabric.orderer.tlscaValue'); - } catch { - ordererCA = fs.readFileSync(configRead('fabric.orderer.tlsca'), 'ascii'); - } - - const orderer = client.newOrderer( - configRead("fabric.orderer.url"), - { - pem: ordererCA, - "ssl-target-name-override": configRead( - "fabric.orderer.name", - ), - }, - ); - channel.addOrderer(orderer); - // EP settings - const peersConfig = configRead("fabric.peers"); - for (let i = 0; i < peersConfig.length; i++) { - let peerCA: string; - if ("tlscaValue" in peersConfig[i]) { - peerCA = peersConfig[i].tlscaValue; - } else { - peerCA = fs.readFileSync(peersConfig[i].tlsca, 'ascii'); - } - - const peer = client.newPeer(peersConfig[i].requests, { - pem: peerCA, - "ssl-target-name-override": peersConfig[i].name, - }); - - channel.addPeer(peer, configRead("fabric.mspid")); - } - - const storePath = path.join( - configRead("fabric.keystore"), - configRead("fabric.submitter.name"), - ); - const cryptoSuite = FabricClient.newCryptoSuite(); - cryptoSuite.setCryptoKeyStore( - FabricClient.newCryptoKeyStore({ - path: storePath, - }), - ); - client.setCryptoSuite(cryptoSuite); - - // Generate enrollment information storage location - let store = await FabricClient.newDefaultKeyValueStore({ - path: storePath, - }); - client.setStateStore(store); - } else { - // Exception when reflecting connection destination information difference - logger.error(e); - } - } - - return { client, channel }; -} diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/sign-utils.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/sign-utils.ts deleted file mode 100644 index 699884393f..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/sign-utils.ts +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2022 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * Util tools used for cryptography related to hyperledger fabric (e.g. signing proposals) - */ - -const hash = require("fabric-client/lib/hash"); -import jsrsa from "jsrsasign"; -import elliptic from "elliptic"; - -const ellipticCurves = elliptic.curves as any; - -/** - * This function comes from `CryptoSuite_ECDSA_AES.js` and will be part of the - * stand alone fabric-sig package in future. - * - */ -const ordersForCurve: Record = { - secp256r1: { - halfOrder: ellipticCurves.p256.n.shrn(1), - order: ellipticCurves.p256.n, - }, - secp384r1: { - halfOrder: ellipticCurves.p384.n.shrn(1), - order: ellipticCurves.p384.n, - }, -}; - -/** - * This function comes from `CryptoSuite_ECDSA_AES.js` and will be part of the - * stand alone fabric-sig package in future. - * - * @param sig EC signature - * @param curveParams EC key params. - * @returns Signature - */ -function preventMalleability(sig: any, curveParams: { name: string }) { - const halfOrder = ordersForCurve[curveParams.name].halfOrder; - if (!halfOrder) { - throw new Error( - 'Can not find the half order needed to calculate "s" value for immalleable signatures. Unsupported curve name: ' + - curveParams.name, - ); - } - - // in order to guarantee 's' falls in the lower range of the order, as explained in the above link, - // first see if 's' is larger than half of the order, if so, it needs to be specially treated - if (sig.s.cmp(halfOrder) === 1) { - // module 'bn.js', file lib/bn.js, method cmp() - // convert from BigInteger used by jsrsasign Key objects and bn.js used by elliptic Signature objects - const bigNum = ordersForCurve[curveParams.name].order; - sig.s = bigNum.sub(sig.s); - } - - return sig; -} - -/** - * Internal function to sign input buffer with private key. - * - * @param privateKey private key in PEM format. - * @param proposalBytes Buffer of the proposal to sign. - * @param algorithm Hash function algorithm - * @param keySize Key length - * @returns - */ -function sign( - privateKey: string, - proposalBytes: Buffer, - algorithm: string, - keySize: number, -) { - const hashAlgorithm = algorithm.toUpperCase(); - const hashFunction = hash[`${hashAlgorithm}_${keySize}`]; - const ecdsaCurve = ellipticCurves[`p${keySize}`]; - const ecdsa = new elliptic.ec(ecdsaCurve); - const key = jsrsa.KEYUTIL.getKey(privateKey) as any; - - const signKey = ecdsa.keyFromPrivate(key.prvKeyHex, "hex"); - const digest = hashFunction(proposalBytes); - - let sig = ecdsa.sign(Buffer.from(digest, "hex"), signKey); - sig = preventMalleability(sig, key.ecparams); - - return Buffer.from(sig.toDER()); -} - -/** - * Sign proposal of endorsment / transaction with private key. - * Can be used to call low-level fabric sdk functions. - * - * @param proposalBytes Buffer of the proposal to sign. - * @param paramPrivateKeyPem Private key in PEM format. - * @returns Signed proposal. - */ -export function signProposal( - proposalBytes: Buffer, - paramPrivateKeyPem: string, -) { - return { - signature: sign(paramPrivateKeyPem, proposalBytes, "sha2", 256), - proposal_bytes: proposalBytes, - }; -} diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/template/PluginConfig_template.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/template/PluginConfig_template.ts deleted file mode 100644 index e3a1458792..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/template/PluginConfig_template.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * PluginConfig_template.js - */ - -/* - * Summary: - * Configuration file of cooperation server: a part dependent on end-chains - * Definition values specific to the connection dependent part, etc. - */ - -module.exports = { - // Nothing special -}; diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/template/PluginUtil_template.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/template/PluginUtil_template.ts deleted file mode 100644 index df535f2278..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/template/PluginUtil_template.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright 2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * PluginUtil_template.js - */ - -/* - * Summary: - * Cooperation server: utility libraries of a part dependent on end-chains - * For example, implementing internal functions that should not be exposed as functions of ServerPlugin. - */ - -// Nothing special diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/template/ServerMonitorPlugin_template.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/template/ServerMonitorPlugin_template.ts deleted file mode 100644 index 790ed8cdbd..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/template/ServerMonitorPlugin_template.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * ServerMonitorPlugin_template.js - */ - -/* - * Summary: - * Connector: monitoring class of a part dependent on end-chains - * Used in the case of monitoring continuously. - * Processing that ends with the acceptance of a single event is handled by a custom function implementation in server plugins. - * Unlike server plugins, it basically does not handle its own functions. - */ - -// configuration file -const SplugConfig = require("./PluginConfig.js"); -const config = require("config"); -// Log settings -const log4js = require("log4js"); -const logger = log4js.getLogger("ServerMonitorPlugin[" + process.pid + "]"); -logger.level = config.logLevel; -// Load libraries, SDKs, etc. according to specifications of endchains as needed - -/* - * ServerMonitorPlugin - * Class definitions of server monitoring - */ -const ServerMonitorPlugin = class { - /* - * constructors - */ - constructor() { - // Define dependent specific settings - } - - /* - * startMonitor - * Start Monitoring - * @param {string} clientId: Client ID from which monitoring start request was made - * @param {function} cb: A callback function that receives monitoring results at any time. - */ - startMonitor(clientId, cb) { - logger.info("*** START MONITOR ***"); - logger.info("Client ID :" + clientId); - // Implement handling to receive events from an endchain and return them in a callback function - } - - /* - * stopMonitor - * monitoring stop - * @param {string} clientId: Client ID from which monitoring stop request was made - */ - stopMonitor(clientId) { - // Implement a process to end EC monitoring - } -}; /* class */ - -module.exports = ServerMonitorPlugin; diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/template/ServerPlugin_template.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/template/ServerPlugin_template.ts deleted file mode 100644 index 44e5fca5d2..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/template/ServerPlugin_template.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * ServerPlugin_template.js - */ - -/* - * Summary: - * Connector: a part dependent on endchains - * Define and implement the function according to the connection destination dependent part (ADAPTER) on the core side. - */ - -// configuration file -const SplugConfig = require("./PluginConfig.js"); -const config = require("config"); -// Log settings -const log4js = require("log4js"); -const logger = log4js.getLogger("ServerPlugin[" + process.pid + "]"); -logger.level = config.logLevel; -// utility -const SplugUtil = require("./PluginUtil.js"); -// Load libraries, SDKs, etc. according to specifications of endchains as needed - -/* - * ServerPlugin - * Class definition for server plugins - */ -const ServerPlugin = class { - /* - * constructors - */ - constructor() { - // Define dependent specific settings - } - - /* - * isExistFunction - * - * @param {String} funcName: The function name to check. - * - * @return {Boolean} true: Yes./false: does not exist. - * - * @desc Return if end-chain specific funtion is implemented - * Scope of this function is in this class - * Functions that should not be called directly should be implemented outside this class like utilities. - */ - isExistFunction(funcName) { - if (this[funcName] != undefined) { - return true; - } else { - return false; - } - } - - // Define an arbitrary function and implement it according to specifications of end-chains -}; /* class */ - -module.exports = ServerPlugin; diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/template/package_template.json b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/template/package_template.json deleted file mode 100644 index 289b20b1f1..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/connector/template/package_template.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "dependent", - "version": "0.0.0", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - } -} diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/index.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/index.ts deleted file mode 100644 index 87cb558397..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./public-api"; diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/public-api.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/public-api.ts deleted file mode 100644 index 291cedabcf..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/main/typescript/public-api.ts +++ /dev/null @@ -1 +0,0 @@ -export { startFabricSocketIOConnector } from "./common/core/bin/www"; diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/integration/fabric-setup-helpers.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/integration/fabric-setup-helpers.ts deleted file mode 100644 index e580767a4e..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/integration/fabric-setup-helpers.ts +++ /dev/null @@ -1,165 +0,0 @@ -/** - * Fabric helpers to be used by functional tests. - * Works with Fabric SDK 1.4 - that's why it's not included in fabric ledger test class. - * Most functions are based on fabric-samples and utils scripts from tools/docker/fabric-all-in-one/asset-transfer-basic-utils - */ - -import { LoggerProvider, Logger } from "@hyperledger/cactus-common"; -import { FileSystemWallet, Gateway, X509WalletMixin } from "fabric-network"; -import FabricCAServices from "fabric-ca-client"; - -// Unit Test logger setup -const log: Logger = LoggerProvider.getOrCreate({ - label: "fabric-setup-helpers", - level: "info", -}); - -/** - * Enroll admin user on fabric and store it's credential in local filesystem wallet. - * - * @param connectionProfile - Fabric connection profile JSON. - * @param walletPath - Local filesystem wallet path. - * @param enrollmentID - admin username. - * @param enrollmentSecret - admin secret. - */ -export async function enrollAdmin( - connectionProfile: any, - walletPath: string, - enrollmentID: string, - enrollmentSecret: string, -) { - log.info( - `Enroll admin user with enrollmentID='${enrollmentID}' and enrollmentSecret='${enrollmentSecret}'`, - ); - - // Create a new CA client for interacting with the CA. - const caName = connectionProfile.organizations.Org1.certificateAuthorities[0]; - const caInfo = connectionProfile.certificateAuthorities[caName]; - const caTLSCACerts = caInfo.tlsCACerts.pem; - const ca = new FabricCAServices( - caInfo.url, - { trustedRoots: caTLSCACerts, verify: false }, - caInfo.caName, - ); - - // Create a new file system based wallet for managing identities. - const wallet = new FileSystemWallet(walletPath); - - // Enroll admin user if not exist yet - const adminExists = await wallet.exists(enrollmentID); - if (!adminExists) { - const enrollment = await ca.enroll({ - enrollmentID, - enrollmentSecret, - }); - const identity = X509WalletMixin.createIdentity( - connectionProfile.organizations.Org1.mspid, - enrollment.certificate, - enrollment.key.toBytes(), - ); - await wallet.import(enrollmentID, identity); - log.info( - `Successfully enrolled admin user ${enrollmentID} and imported it into the wallet. Current state:`, - await wallet.list(), - ); - } -} - -/** - * Enroll a user on fabric and store it's credential in local filesystem wallet. - * Must be called after `enrollAdmin()` - * - * @param connectionProfile - Fabric connection profile JSON. - * @param walletPath - Local filesystem wallet path. - * @param userName - regular username to enroll. - * @param adminUserName - admin username (must be already enrolled) - */ -export async function enrollUser( - connectionProfile: any, - walletPath: string, - userName: string, - adminUserName: string, -) { - log.info(`Enroll user with userName='${userName}'`); - - // Create a new file system based wallet for managing identities. - const wallet = new FileSystemWallet(walletPath); - - // Check to see if we've already enrolled the user. - const userExists = await wallet.exists(userName); - if (userExists) { - console.log( - "An identity for the user userName already exists in the wallet", - ); - return; - } - - // Check to see if we've already enrolled the admin user. - const adminExists = await wallet.exists(adminUserName); - if (!adminExists) { - throw new Error( - "An identity for the admin user adminUserName does not exist in the wallet", - ); - } - - // Create a new gateway for connecting to our peer node. - const gateway = new Gateway(); - await gateway.connect(connectionProfile, { - wallet, - identity: adminUserName, - discovery: { enabled: true, asLocalhost: true }, - }); - - // Get the CA client object from the gateway for interacting with the CA. - const ca = gateway.getClient().getCertificateAuthority(); - const adminIdentity = gateway.getCurrentIdentity(); - - // Register the user, enroll the user, and import the new identity into the wallet. - const secret = await ca.register( - { - affiliation: "org1.department1", - enrollmentID: userName, - role: "client", - }, - adminIdentity, - ); - const enrollment = await ca.enroll({ - enrollmentID: userName, - enrollmentSecret: secret, - }); - const userIdentity = X509WalletMixin.createIdentity( - connectionProfile.organizations.Org1.mspid, - enrollment.certificate, - enrollment.key.toBytes(), - ); - await wallet.import(userName, userIdentity); - log.info( - `Successfully enrolled user ${userName} and imported it into the wallet. Current state:`, - await wallet.list(), - ); -} - -/** - * Get cryptographic data for specified user from local filesystem wallet. - * Can be used to sign transactions as specified user. - * - * @param name - Username enrolled in wallet. - * @param walletPath - Local filesystem wallet path. - * @returns A tuple [certificatePem, privateKeyPem] - */ -export async function getUserCryptoFromWallet( - name: string, - walletPath: string, -): Promise<[string, string]> { - const wallet = new FileSystemWallet(walletPath); - - const submitterExists = await wallet.exists(name); - if (!submitterExists) { - throw new Error(`User ${name} does not exist in wallet ${walletPath}`); - } - - const submitterIdentity = await wallet.export(name); - const certPem = (submitterIdentity as any).certificate; - const privateKeyPem = (submitterIdentity as any).privateKey; - return [certPem, privateKeyPem]; -} diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/integration/fabric-socketio-connector.test.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/integration/fabric-socketio-connector.test.ts deleted file mode 100644 index 1a70a724e6..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/integration/fabric-socketio-connector.test.ts +++ /dev/null @@ -1,794 +0,0 @@ -/** - * Functional test of basic operations on connector-fabric-socketio (packages/cactus-plugin-ledger-connector-fabric-socketio) - * Assumes sample CC was is deployed on the test ledger. - * Tests include sending and evaluation transactions, and monitoring for events. - * - * You can speed up development or troubleshooting by using same ledger repeatadely. - * 1. Remove fabric wallets from previous runs - `rm -rf /tmp/fabric-test-wallet*`. Repeat this everytime you restart ledger. - * 2. Change variable `leaveLedgerRunning` to true. - * 3. Run this functional test. It will leave the ledger running, and will enroll the users to common wallet location. - * 4. Change `useRunningLedger` to true. The following test runs will not setup the ledger again. - * Note: - * You may get a warning about open SIGNREQUEST handles after the test finishes. - * These are false-positives, and should be fixed in jest v28.1.0 - * More details: https://github.com/facebook/jest/pull/12789 - */ - -import { - DEFAULT_FABRIC_2_AIO_FABRIC_VERSION, - DEFAULT_FABRIC_2_AIO_IMAGE_NAME, - DEFAULT_FABRIC_2_AIO_IMAGE_VERSION, - FabricTestLedgerV1, - pruneDockerAllIfGithubAction, - SelfSignedPkiGenerator, -} from "@hyperledger/cactus-test-tooling"; - -import { - LogLevelDesc, - LoggerProvider, - Logger, -} from "@hyperledger/cactus-common"; - -import { SocketIOApiClient } from "@hyperledger/cactus-api-client"; - -import { signProposal } from "../../../main/typescript/connector/sign-utils"; - -import { - enrollAdmin, - enrollUser, - getUserCryptoFromWallet, -} from "./fabric-setup-helpers"; - -import fs from "fs"; -import path from "path"; -import os from "os"; -import "jest-extended"; -import { Server as HttpsServer } from "https"; - -////////////////////////////////// -// Constants -////////////////////////////////// - -// Ledger settings -const imageName = DEFAULT_FABRIC_2_AIO_IMAGE_NAME; -const imageVersion = DEFAULT_FABRIC_2_AIO_IMAGE_VERSION; -const fabricEnvVersion = DEFAULT_FABRIC_2_AIO_FABRIC_VERSION; -const fabricEnvCAVersion = "1.4.9"; -const ledgerUserName = "appUser"; -const ledgerChannelName = "mychannel"; -const ledgerContractName = "basic"; -const leaveLedgerRunning = false; // default: false -const useRunningLedger = false; // default: false - -// Log settings -const testLogLevel: LogLevelDesc = "debug"; // default: info -const sutLogLevel: LogLevelDesc = "debug"; // default: info - -// Logger setup -const log: Logger = LoggerProvider.getOrCreate({ - label: "fabric-socketio-connector.test", - level: testLogLevel, -}); - -/** - * Main test suite - */ -describe("Fabric-SocketIO connector tests", () => { - let ledger: FabricTestLedgerV1; - let connectorCertValue: string; - let connectorPrivKeyValue: string; - let tmpWalletDir: string; - let connectorModule: typeof import("../../../main/typescript/index"); - let connectorServer: HttpsServer; - let apiClient: SocketIOApiClient; - - ////////////////////////////////// - // Environment Setup - ////////////////////////////////// - - /** - * @param connectionProfile - Fabric connection profile JSON - * @param connectorCert - connector-fabric-socketio server certificate - * @param connectorPrivKey - connector-fabric-socketio server private key - * @param walletDir - connector-fabric-socketio internal wallet path - * @param adminName - ledger admin username - * @param adminSecret - ledger admin secret - * @returns fabric-socketio conenctor config JSON - */ - function createFabricConnectorConfig( - connectionProfile: Record, - connectorCert: string, - connectorPrivKey: string, - jwtAlgo: string, - walletDir: string, - adminName: string, - adminSecret: string, - ) { - // Get Org CA - const caId = connectionProfile.organizations.Org1.certificateAuthorities[0]; - log.debug("Use CA:", caId); - - // Get Orderer ID - const ordererId = connectionProfile.channels[ledgerChannelName].orderers[0]; - log.debug("Use Orderer:", ordererId); - - const connectorConfig: any = { - sslParam: { - port: 0, // random port - keyValue: connectorPrivKey, - certValue: connectorCert, - jwtAlgo: jwtAlgo, - }, - logLevel: sutLogLevel, - fabric: { - mspid: connectionProfile.organizations.Org1.mspid, - keystore: walletDir, - connUserName: ledgerUserName, - contractName: ledgerContractName, - peers: [], // will be filled below - orderer: { - name: - connectionProfile.orderers[ordererId].grpcOptions[ - "ssl-target-name-override" - ], - url: connectionProfile.orderers[ordererId].url, - tlscaValue: connectionProfile.orderers[ordererId].tlsCACerts.pem, - }, - ca: { - name: connectionProfile.certificateAuthorities[caId].caName, - url: connectionProfile.certificateAuthorities[caId].url, - }, - submitter: { - name: adminName, - secret: adminSecret, - }, - channelName: ledgerChannelName, - chaincodeId: ledgerContractName, - }, - }; - - // Add peers - connectionProfile.organizations.Org1.peers.forEach((peerName: string) => { - log.debug("Add Peer:", peerName); - const peer = connectionProfile.peers[peerName]; - connectorConfig.fabric.peers.push({ - name: peer.grpcOptions["ssl-target-name-override"], - requests: peer.url, - tlscaValue: peer.tlsCACerts.pem, - }); - }); - - const configJson = JSON.stringify(connectorConfig); - log.debug("Connector Config:", configJson); - return configJson; - } - - beforeAll(async () => { - log.info("Prune Docker..."); - await pruneDockerAllIfGithubAction({ logLevel: testLogLevel }); - - // Prepare local filesystem wallet path - if (leaveLedgerRunning || useRunningLedger) { - tmpWalletDir = path.join(os.tmpdir(), "fabric-test-wallet-common"); - log.warn("Using common wallet path when re-using the same ledger."); - try { - fs.mkdirSync(tmpWalletDir); - } catch (err) { - if (!err.message.includes("EEXIST")) { - log.error( - "Unexpected exception when creating common wallet dir:", - err, - ); - throw err; - } - } - } else { - log.info("Create temp dir for wallet - will be removed later..."); - tmpWalletDir = fs.mkdtempSync( - path.join(os.tmpdir(), "fabric-test-wallet"), - ); - } - log.info("Wallet path:", tmpWalletDir); - expect(tmpWalletDir).toBeTruthy(); - - log.info("Start FabricTestLedgerV1..."); - log.debug("Version:", fabricEnvVersion, "CA Version:", fabricEnvCAVersion); - ledger = new FabricTestLedgerV1({ - emitContainerLogs: false, - publishAllPorts: true, - logLevel: testLogLevel, - imageName, - imageVersion, - envVars: new Map([ - ["FABRIC_VERSION", fabricEnvVersion], - ["CA_VERSION", fabricEnvCAVersion], - ]), - useRunningLedger, - }); - log.debug("Fabric image:", ledger.getContainerImageName()); - await ledger.start({ omitPull: false }); - - // Get connection profile - log.info("Get fabric connection profile for Org1..."); - const connectionProfile = await ledger.getConnectionProfileOrg1(); - expect(connectionProfile).toBeTruthy(); - - // Get admin credentials - const [adminName, adminSecret] = ledger.adminCredentials; - - // Enroll admin and user - await enrollAdmin(connectionProfile, tmpWalletDir, adminName, adminSecret); - await enrollUser( - connectionProfile, - tmpWalletDir, - ledgerUserName, - adminName, - ); - - // Generate connector private key and certificate - const pkiGenerator = new SelfSignedPkiGenerator(); - const pki = pkiGenerator.create("localhost"); - connectorCertValue = pki.certificatePem; - connectorPrivKeyValue = pki.privateKeyPem; - const jwtAlgo = "RS512"; - - // Get connector config - log.info("Export connector config before loading the module..."); - process.env["NODE_CONFIG"] = createFabricConnectorConfig( - connectionProfile, - connectorCertValue, - connectorPrivKeyValue, - jwtAlgo, - tmpWalletDir, - adminName, - adminSecret, - ); - - // Load connector module - connectorModule = await import("../../../main/typescript/index"); - - // Run the connector - connectorServer = await connectorModule.startFabricSocketIOConnector(); - expect(connectorServer).toBeTruthy(); - const connectorAddress = connectorServer.address(); - if (!connectorAddress || typeof connectorAddress === "string") { - throw new Error("Unexpected fabric connector AddressInfo type"); - } - log.info( - "Fabric-SocketIO Connector started on:", - `${connectorAddress.address}:${connectorAddress.port}`, - ); - - // Create ApiClient instance - const apiConfigOptions = { - validatorID: "fabric-socketio-test", - validatorURL: `https://localhost:${connectorAddress.port}`, - validatorKeyValue: connectorCertValue, - logLevel: sutLogLevel, - maxCounterRequestID: 1000, - syncFunctionTimeoutMillisecond: 10000, - socketOptions: { - rejectUnauthorized: false, - reconnection: false, - timeout: 60000, - }, - }; - log.debug("ApiClient config:", apiConfigOptions); - apiClient = new SocketIOApiClient(apiConfigOptions); - }); - - afterAll(async () => { - log.info("FINISHING THE TESTS"); - - if (ledger && !leaveLedgerRunning && !useRunningLedger) { - log.info("Stop the fabric ledger..."); - await ledger.stop(); - await ledger.destroy(); - } - - if (apiClient) { - log.info("Close ApiClient connection..."); - apiClient.close(); - } - - if (connectorServer) { - log.info("Stop the fabric connector..."); - await new Promise((resolve) => - connectorServer.close(() => resolve()), - ); - } - - if (tmpWalletDir && !leaveLedgerRunning && !useRunningLedger) { - log.info("Remove tmp wallet dir", tmpWalletDir); - fs.rmSync(tmpWalletDir, { recursive: true }); - } - - log.info("Prune Docker..."); - await pruneDockerAllIfGithubAction({ logLevel: testLogLevel }); - }); - - ////////////////////////////////// - // Test Helpers - ////////////////////////////////// - - /** - * Calls `GetAllAssets` from `basic` CC on the ledger using apiClient.sendSyncRequest - * @returns List of assets - */ - async function getAllAssets() { - const contract = { - channelName: ledgerChannelName, - contractName: ledgerContractName, - }; - const method = { - type: "evaluateTransaction", - command: "GetAllAssets", - }; - const args = { args: [] }; - - const results = await apiClient.sendSyncRequest(contract, method, args); - - expect(results).toBeTruthy(); - expect(results.status).toBe(200); - expect(results.data).toBeTruthy(); - expect(results.data.length).toBeGreaterThanOrEqual(5); // we assume at least 5 assets in future tests - return results.data as { ID: string }[]; - } - - /** - * Calls `GetAllAssets` from `basic` CC on the ledger using apiClient.sendSyncRequest - * - * @param assetID - Asset to read from the ledger. - * @returns asset object - */ - async function readAsset(assetID: string) { - const contract = { - channelName: ledgerChannelName, - contractName: ledgerContractName, - }; - const method = { - type: "evaluateTransaction", - command: "ReadAsset", - }; - const args = { args: [assetID] }; - - const results = await apiClient.sendSyncRequest(contract, method, args); - - expect(results).toBeTruthy(); - expect(results.status).toBe(200); - expect(results.data).toBeTruthy(); - return results.data; - } - - /** - * Calls connector function `sendSignedProposal`, assert correct response, and returns signed proposal. - * @param txProposal - Transaction data we want to send (CC function name, arguments, chancode ID, channel ID) - * @returns Signed proposal that can be feed into `sendSignedProposal` - */ - async function getSignedProposal(txProposal: { - fcn: string; - args: string[]; - chaincodeId: string; - channelId: string; - }) { - const [certPem, privateKeyPem] = await getUserCryptoFromWallet( - ledgerUserName, - tmpWalletDir, - ); - const contract = { channelName: ledgerChannelName }; - const method = { type: "function", command: "sendSignedProposal" }; - const argsParam = { - args: { - transactionProposalReq: txProposal, - certPem, - privateKeyPem, - }, - }; - - const response = await apiClient.sendSyncRequest( - contract, - method, - argsParam, - ); - expect(response).toBeTruthy(); - expect(response.status).toBe(200); - expect(response.data).toBeTruthy(); - expect(response.data.signedCommitProposal).toBeTruthy(); - expect(response.data.commitReq).toBeTruthy(); - expect(response.data.txId).toBeTruthy(); - - const { signedCommitProposal, commitReq } = response.data; - - // signedCommitProposal must be Buffer - signedCommitProposal.signature = Buffer.from( - signedCommitProposal.signature, - ); - signedCommitProposal.proposal_bytes = Buffer.from( - signedCommitProposal.proposal_bytes, - ); - - return { signedCommitProposal, commitReq }; - } - - /** - * Calls connector function `generateUnsignedProposal`, assert correct response, and returns unsigned proposal. - * @param txProposal - Transaction data we want to send (CC function name, arguments, chancode ID, channel ID) - * @returns Unsigned proposal that can be signed locally and feed into `sendSignedProposalV2` - */ - async function getUnsignedProposal(txProposal: unknown, certPem: string) { - const contract = { channelName: ledgerChannelName }; - const method = { type: "function", command: "generateUnsignedProposal" }; - const argsParam = { - args: { - transactionProposalReq: txProposal, - certPem, - }, - }; - - log.info("Sending generateUnsignedProposal"); - - const response = await apiClient.sendSyncRequest( - contract, - method, - argsParam, - ); - expect(response).toBeTruthy(); - expect(response.status).toBe(200); - expect(response.data).toBeTruthy(); - expect(response.data.proposal).toBeTruthy(); - expect(response.data.proposalBuffer).toBeTruthy(); - expect(response.data.proposalBuffer.type).toEqual("Buffer"); - expect(response.data.proposalBuffer.data).toBeTruthy(); - expect(response.data.txId).toBeTruthy(); - - const proposalBuffer = Buffer.from(response.data.proposalBuffer); - expect(proposalBuffer).toBeTruthy(); - - log.info("Received correct response from generateUnsignedProposal"); - - return { - proposal: response.data.proposal, - proposalBuffer, - txId: response.data.txId, - }; - } - - /** - * Calls connector function `generateUnsignedTransaction`, assert correct response, and returns unsigned transaction (commit) proposal. - * @param txProposal - Transaction data we want to send (CC function name, arguments, chancode ID, channel ID) - * @param proposalResponses - Proposal resonses of endorsment step from `sendSignedProposalV2` call. - * @returns Unsigned commit proposal that can be signed locally and feed into `sendSignedTransactionV2` - */ - async function getUnsignedCommitProposal( - txProposal: unknown, - proposalResponses: unknown, - ) { - const contract = { channelName: ledgerChannelName }; - const method = { type: "function", command: "generateUnsignedTransaction" }; - const argsParam = { - args: { - proposal: txProposal, - proposalResponses: proposalResponses, - }, - }; - - log.info("Sending generateUnsignedTransaction"); - - const response = await apiClient.sendSyncRequest( - contract, - method, - argsParam, - ); - - expect(response).toBeTruthy(); - expect(response.status).toBe(200); - expect(response.data).toBeTruthy(); - expect(response.data.txProposalBuffer).toBeTruthy(); - expect(response.data.txProposalBuffer.type).toEqual("Buffer"); - expect(response.data.txProposalBuffer.data).toBeTruthy(); - - const commitProposalBuffer = Buffer.from(response.data.txProposalBuffer); - expect(commitProposalBuffer).toBeTruthy(); - - log.info("Received correct response from generateUnsignedTransaction"); - - return commitProposalBuffer; - } - - ////////////////////////////////// - // Tests - ////////////////////////////////// - - /** - * Test signProposal helper function from fabric-socketio connector module. - */ - test("Signing proposal creates a signature", async () => { - const [, privateKeyPem] = await getUserCryptoFromWallet( - ledgerUserName, - tmpWalletDir, - ); - - const proposal = Buffer.from("test test test test"); - const signedProposal = signProposal(proposal, privateKeyPem); - - expect(signedProposal).toBeTruthy(); - expect(signedProposal.proposal_bytes).toBeTruthy(); - expect(signedProposal.signature).toBeTruthy(); - }); - - /** - * Read all assets, get single asset, comapre that they return the same asset value without any errors. - */ - test("Evaluate transaction returns correct data (GetAllAssets and ReadAsset)", async () => { - const allAssets = await getAllAssets(); - const firstAsset = allAssets.pop(); - if (!firstAsset) { - throw new Error("Unexpected missing firstAsset"); - } - const readSingleAsset = await readAsset(firstAsset.ID); - expect(readSingleAsset).toEqual(firstAsset); - }); - - /** - * Get block by number. - */ - test("Get block by it's number works (both decoded and encoded)", async () => { - const contract = { channelName: ledgerChannelName }; - const method = { type: "function", command: "getBlock" }; - const argsParam = { - blockNumber: 0, - }; - - // Get decoded block - const response = await apiClient.sendSyncRequest( - contract, - method, - argsParam, - ); - expect(response).toBeTruthy(); - expect(response.status).toEqual(200); - expect(response.data).toBeTruthy(); - expect(response.data.header).toBeTruthy(); - expect(response.data.data).toBeTruthy(); - expect(response.data.metadata).toBeTruthy(); - - // Get encoded block - const argsParamEncoded = { - ...argsParam, - skipDecode: true, - }; - - const responseEncoded = await apiClient.sendSyncRequest( - contract, - method, - argsParamEncoded, - ); - expect(responseEncoded).toBeTruthy(); - expect(responseEncoded.status).toEqual(200); - expect(responseEncoded.data).toBeTruthy(); - expect(responseEncoded.data.type).toEqual("Buffer"); - expect(responseEncoded.data.data).toBeTruthy(); - }); - - /** - * Test entire process of sending transaction to the ledger without sharing the key with the connector. - * All proposals are signed on BLP (in this case, jest test) side. - * This test prepares proposal, signs it, sends for endorsment, prepares and sign commit proposal, sends commit transaction. - */ - test("Sending transaction signed on BLP side (without sharing the private key) works", async () => { - const [certPem, privateKeyPem] = await getUserCryptoFromWallet( - ledgerUserName, - tmpWalletDir, - ); - - // Prepare raw transaction proposal - const allAssets = await getAllAssets(); - const assetId = allAssets[1].ID; - const newOwnerName = "UnsignedSendTestXXX"; - const txProposal = { - fcn: "TransferAsset", - args: [assetId, newOwnerName], - chaincodeId: ledgerContractName, - channelId: ledgerChannelName, - }; - log.debug("Raw transaction proposal:", txProposal); - - // Get unsigned proposal - const { proposal, proposalBuffer } = await getUnsignedProposal( - txProposal, - certPem, - ); - - // Prepare signed proposal - const signedProposal = signProposal(proposalBuffer, privateKeyPem); - - // Call sendSignedProposalV2 - const contractSignedProposal = { channelName: ledgerChannelName }; - const methodSignedProposal = { - type: "function", - command: "sendSignedProposalV2", - }; - const argsSignedProposal = { - args: { - signedProposal, - }, - }; - - log.info("Sending sendSignedProposalV2"); - const responseSignedProposal = await apiClient.sendSyncRequest( - contractSignedProposal, - methodSignedProposal, - argsSignedProposal, - ); - - expect(responseSignedProposal).toBeTruthy(); - expect(responseSignedProposal.status).toBe(200); - expect(responseSignedProposal.data).toBeTruthy(); - expect(responseSignedProposal.data.endorsmentStatus).toBeTrue(); - expect(responseSignedProposal.data.proposalResponses).toBeTruthy(); - log.info("Received correct response from sendSignedProposalV2"); - const proposalResponses = responseSignedProposal.data.proposalResponses; - - // Get unsigned commit (transaction) proposal - const commitProposalBuffer = await getUnsignedCommitProposal( - proposal, - proposalResponses, - ); - - // Prepare signed commit proposal - const signedCommitProposal = signProposal( - commitProposalBuffer, - privateKeyPem, - ); - - // Call sendSignedTransactionV2 - const contractSignedTransaction = { channelName: ledgerChannelName }; - const methodSignedTransaction = { - type: "function", - command: "sendSignedTransactionV2", - }; - const argsSignedTransaction = { - args: { - signedCommitProposal: signedCommitProposal, - proposal: proposal, - proposalResponses: proposalResponses, - }, - }; - - log.info("Sending sendSignedTransactionV2"); - const responseSignedTransaction = await apiClient.sendSyncRequest( - contractSignedTransaction, - methodSignedTransaction, - argsSignedTransaction, - ); - - expect(responseSignedTransaction).toBeTruthy(); - expect(responseSignedTransaction.status).toBe(200); - expect(responseSignedTransaction.data).toBeTruthy(); - expect(responseSignedTransaction.data.status).toEqual("SUCCESS"); - log.info("Received correct response from sendSignedTransactionV2"); - }); - - /** - * Send transaction proposal to be signed with keys attached to the request (managed by BLP), - * and then send signed transaction to the ledger. - */ - test("Signining proposal and sending it to the ledger works", async () => { - // Get asset data to be transfered - const allAssets = await getAllAssets(); - const assetId = allAssets[1].ID; - const newOwnerName = "SignAndSendXXX"; - - // Prepare signed proposal - const txProposal = { - fcn: "TransferAsset", - args: [assetId, newOwnerName], - chaincodeId: ledgerContractName, - channelId: ledgerChannelName, - }; - const signedProposal = await getSignedProposal(txProposal); - - // Send transaction - const contract = { channelName: ledgerChannelName }; - const method = { type: "sendSignedTransaction" }; - const args = { args: [signedProposal] }; - - const response = await apiClient.sendSyncRequest(contract, method, args); - expect(response).toBeTruthy(); - expect(response.status).toBe(200); - expect(response.data).toBeTruthy(); - expect(response.data.status).toEqual("SUCCESS"); - }); - - /** - * Send transaction proposal to be signed with keys from connector wallet (managed by the connector). - * Verify correct response from the call. - */ - test("Signining proposal with connector wallet keys work", async () => { - // Get asset data to be transfered - const allAssets = await getAllAssets(); - const assetId = allAssets[2].ID; - const newOwnerName = "SignWithConnectorXXX"; - - // Prepare signed proposal - const contract = { channelName: ledgerChannelName }; - const method = { type: "function", command: "sendSignedProposal" }; - const argsParam = { - args: { - transactionProposalReq: { - fcn: "TransferAsset", - args: [assetId, newOwnerName], - chaincodeId: ledgerContractName, - channelId: ledgerChannelName, - }, - }, - }; - - const response = await apiClient.sendSyncRequest( - contract, - method, - argsParam, - ); - expect(response).toBeTruthy(); - expect(response.status).toBe(200); - expect(response.data).toBeTruthy(); - expect(response.data.signedCommitProposal).toBeTruthy(); - expect(response.data.commitReq).toBeTruthy(); - expect(response.data.txId).toBeTruthy(); - }); - - /** - * Start monitoring for fabric events. - * Send new transaction to the ledger (async) - * Finish after receiving event for matching transaction function. - * This function needs separate timeout, in case of error (no event was received). - */ - test( - "Monitoring for transaction sending works", - async () => { - // Get asset data to be transfered - const allAssets = await getAllAssets(); - const assetId = allAssets[3].ID; - const newOwnerName = "MonitorChangedXXX"; - const txFunctionName = "TransferAsset"; - - // Start monitoring - const monitorPromise = new Promise((resolve, reject) => { - apiClient.watchBlocksV1().subscribe({ - next(event) { - expect(event.status).toBe(200); - - const matchingEvents = event.blockData.filter( - (e) => e.func === txFunctionName, - ); - - if (matchingEvents.length > 0) { - resolve(); - } - }, - error(err) { - log.error("watchBlocksV1() error:", err); - reject(err); - }, - }); - }); - - // Get signed proposal - const signedProposal = await getSignedProposal({ - fcn: txFunctionName, - args: [assetId, newOwnerName], - chaincodeId: ledgerContractName, - channelId: ledgerChannelName, - }); - - // Send transaction (async) - const contract = { channelName: ledgerChannelName }; - const method = { type: "sendSignedTransaction" }; - const args = { args: [signedProposal] }; - apiClient.sendAsyncRequest(contract, method, args); - - expect(monitorPromise).toResolve(); - }, - 60 * 1000, - ); -}); diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/.gitignore b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/.gitignore deleted file mode 100644 index 583c44c7ef..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules/ -package-lock.json -wallet/ - diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/PluginConfig.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/PluginConfig.ts deleted file mode 100644 index d85cf5306f..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/PluginConfig.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * PluginConfig.js - */ - -/* - * Summary: - * Coordination server connection destination dependent part setting file - * Definition value specific to the connection destination dependent part - */ - -module.exports = { - fabric: { - mspid: "Org1MSP", - keystore: "./wallet/admin", // TODO: - connUserName: "user1", // TODO: - contractName: "fabcar", // TODO: - peers: [ - { - name: "peer0.org1.example.com", - requests: "grpc://localhost:7051", - }, - ], - - orderer: { - name: "orderer.example.com", - url: "grpc://localhost:7050", - }, - ca: { - name: "ca.example.com", - url: "http://localhost:7054", - }, - submitter: { - name: "admin", - secret: "adminpw", - }, - channelName: "mychannel", - chaincodeId: "easy_sample_ec1", - }, -}; diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/config/connection.json b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/config/connection.json deleted file mode 100644 index 54cfca3276..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/config/connection.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "name": "basic-network", - "version": "1.0.0", - "client": { - "organization": "Org1", - "connection": { - "timeout": { - "peer": { - "endorser": "300" - }, - "orderer": "300" - } - } - }, - "channels": { - "mychannel": { - "orderers": [ - "orderer.example.com" - ], - "peers": { - "peer0.org1.example.com": {} - } - } - }, - "organizations": { - "Org1": { - "mspid": "Org1MSP", - "peers": [ - "peer0.org1.example.com" - ], - "certificateAuthorities": [ - "ca.example.com" - ] - } - }, - "orderers": { - "orderer.example.com": { - "url": "grpc://localhost:7050" - } - }, - "peers": { - "peer0.org1.example.com": { - "url": "grpc://localhost:7051" - } - }, - "certificateAuthorities": { - "ca.example.com": { - "url": "http://localhost:7054", - "caName": "ca.example.com" - } - } -} diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/config/default.js b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/config/default.js deleted file mode 100644 index 30033bfbf3..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/config/default.js +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * default.js - */ - -module.exports = { - // URL to validator - validatorUrl: "https://localhost:5040", - //"validatorUrl" : 'https://localhost:5041', - - // for fabric - fabric: { - mspid: "Org1MSP", - keystore: "./wallet/admin", // TODO: - connUserName: "user1", // TODO: - contractName: "fabcar", // TODO: - peers: [ - { - name: "peer0.org1.example.com", - requests: "grpc://localhost:7051", - }, - ], - - orderer: { - name: "orderer.example.com", - url: "grpc://localhost:7050", - }, - ca: { - name: "ca.example.com", - url: "http://localhost:7054", - }, - submitter: { - name: "admin", - secret: "adminpw", - }, - channelName: "mychannel", - chaincodeId: "easy_sample_ec1", - }, -}; diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/copyStaticAssets.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/copyStaticAssets.ts deleted file mode 100644 index 96adc442c3..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/copyStaticAssets.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright 2020-2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * copyStaticAssets.ts - */ -import * as shell from "shelljs"; -shell.cp("-R", "config/", "./dist"); diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/createCar.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/createCar.ts deleted file mode 100644 index 8d2e27a338..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/createCar.ts +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * createCar.js - */ - -//////// -// Usage -// TODO: -// -//////// - -{ - ("use strict"); - - const { FileSystemWallet, Gateway } = require("fabric-network"); - //import { FileSystemWallet, Gateway } from 'fabric-network'; - const fs = require("fs"); - const path = require("path"); - - const ccpPath = path.resolve(__dirname, "config", "connection.json"); - const ccpJSON = fs.readFileSync(ccpPath, "utf8"); - const ccp = JSON.parse(ccpJSON); - - // TODO: - const walletPath = path.resolve(__dirname, "wallet"); - - // ## Request for "createCar" - const key = "CAR102"; - const make = "Toyota"; - const model = "Harrier"; - const colour = "Black"; - const owner = "Dave"; - - const userName = "user1"; - const channelName = "mychannel"; - - async function createCars() { - try { - // Create a new file system based wallet for managing identities. - const wallet = new FileSystemWallet(walletPath); - console.log(`Wallet path: ${walletPath}`); - - // Check to see if we've already enrolled the user. - const userExists = await wallet.exists(userName); - if (!userExists) { - console.log( - `An identity for the user "${userName}" does not exist in the wallet`, - ); - console.log("Run the registerUser.js application before retrying"); - return; - } - - // Create a new gateway for connecting to our peer node. - const gateway = new Gateway(); - await gateway.connect(ccp, { - wallet, - identity: userName, - discovery: { enabled: false }, - }); - - // Get the network (channel) our contract is deployed to. - const network = await gateway.getNetwork(channelName); - - // Get the contract from the network. - const contract = network.getContract("fabcar"); - - // Submit the specified transaction. - console.log(`##createCar Params: ${key}, ${make}, ${colour}, ${owner}`); - await contract.submitTransaction( - "createCar", - key, - make, - model, - colour, - owner, - ); - console.log("Transaction has been submitted"); - - // Disconnect from the gateway. - await gateway.disconnect(); - } catch (error) { - console.error(`Failed to submit transaction: ${error}`); - process.exit(1); - } - } - - createCars(); -} diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/fabric-docker/.gitignore b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/fabric-docker/.gitignore deleted file mode 100644 index af7d30cd7d..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/fabric-docker/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -chaincode/hyperledger -fabcar/javascript/wallet -fabcar/javascript/node_modules - diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/fabric-docker/README.md b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/fabric-docker/README.md deleted file mode 100644 index 5769fffe15..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/fabric-docker/README.md +++ /dev/null @@ -1,79 +0,0 @@ - -# Fabric-docker of validator for Hyperledger fabric - -## Abstract -- Modules for the unit-test of validator for Hyperledger fabric - -## a) clone the directories - curl -sSL https://bit.ly/2ysbOFE | bash -s -- 1.4.0 1.4.0 -Then, `fabric-samples` directory is made in the current directory, including `basic-network`, `bin`, `chaincode/fabcar`, and `fabcar`. - -- c.f.: https://hyperledger-fabric.readthedocs.io/en/latest/install.html#install-samples-binaries-and-docker-images -- If you are behind an proxy environment, use the command that `curl -x http://yourProxyURL:yourProxyPortNumber` instead of `curl` - -## b) Initialization -### 1) Start - - cd fabcar - ./startFabric.sh - -Ensure that the next containers are started. - - $ docker ps - CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES - ec8289e32f06 dev-peer0.org1.example.com-fabcar-1.0-5c906e402ed29f20260ae42283216aa75549c571e2e380f3615826365d8269ba "chaincode -peer.add..." 2 hours ago Up 2 hours dev-peer0.org1.example.com-fabcar-1.0 - a468d622234a hyperledger/fabric-tools "/bin/bash" 2 hours ago Up 2 hours cli - 80e28ca9fbcf hyperledger/fabric-peer "peer node start" 2 hours ago Up 2 hours 0.0.0.0:7051->7051/tcp, 0.0.0.0:7053->7053/tcp peer0.org1.example.com - 8391db445423 hyperledger/fabric-ca "sh -c 'fabric-ca-se..." 2 hours ago Up 2 hours 0.0.0.0:7054->7054/tcp ca.example.com - 3a06daddc298 hyperledger/fabric-orderer "orderer" 2 hours ago Up 2 hours 0.0.0.0:7050->7050/tcp orderer.example.com - b722f3d14f6e hyperledger/fabric-couchdb "tini -- /docker-ent..." 2 hours ago Up 2 hours 4369/tcp, 9100/tcp, 0.0.0.0:5984->5984/tcp couchdb - -### 2) Registering an administrator user and general users - -Change to the following directory: - - $ cd (installation path)/fabcar/javascript - -Install the modules - - $ npm install - -Execute the following script to register the administrator user and general users - - $ node enrollAdmin.js - $ node registerUser.js - -Verify that the user's private key information (i.e. `wallet`) has been generated. - - $ cd (installation path)/fabcar/javascript/wallet - - $ ls -la - Total 0 - drwxrwxr-x. 4 XXXX XXXX 48 X X XX:XX . - drwxrwxr-x. 4 XXXX XXXX 243 X X XX:XX .. - drwxrwxr-x. 2 XXXX XXXX 249 X X XX:XX admin - drwxrwxr-x. 2 XXXX XXXX 172 X X XX:XX user1 - -### 3) Creating and unpacking `wallet.tar`, which is required by Validator and Driver - -Copy user's private key information (`wallet`) for use with Validator and Driver. - - $ cd (installation path)/fabcar/javascript/ - $ tar cvf wallet.tar wallet - -Copy and extract wallet.tar to the following target directory: - -[Target Directory] - -- /packages/ledger-plugin/fabric/validator/src/dependent/ -- /packages/ledger-plugin/fabric/validator/unit-test/ - -[Deployment Method] - - $ tar xvf wallet.tar - diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/package.json b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/package.json deleted file mode 100644 index 8523041d5a..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "validatorDriver", - "version": "0.0.0", - "license": "Apache-2.0", - "private": true, - "scripts": { - "build": "npm run build-ts && npm run copy-static-assets", - "build-ts": "tsc", - "tslint": "tslint -c tslint.json -p tsconfig.json", - "copy-static-assets": "ts-node copyStaticAssets.ts" - }, - "dependencies": { - "@types/node": "14.18.54", - "config": "1.31.0", - "socket.io-client": "4.5.4", - "ts-node": "9.1.1", - "fabric-ca-client": "2.2.18", - "fabric-network": "2.2.18", - "shelljs": "0.8.5" - }, - "devDependencies": { - "typescript": "4.9.5" - } -} \ No newline at end of file diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/queryCar.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/queryCar.ts deleted file mode 100644 index 1185423b6a..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/queryCar.ts +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * queryCar.js - */ - -//////// -// Usage -// TODO: -// -//////// - -{ - ("use strict"); - - const { FileSystemWallet, Gateway } = require("fabric-network"); - const fs = require("fs"); - const path = require("path"); - - const ccpPath = path.resolve(__dirname, "config", "connection.json"); - const ccpJSON = fs.readFileSync(ccpPath, "utf8"); - const ccp = JSON.parse(ccpJSON); - - // TODO: - const walletPath = path.resolve(__dirname, "wallet"); - - const userName = "user1"; - const channelName = "mychannel"; - - async function queryCars() { - try { - // Create a new file system based wallet for managing identities. - const wallet = new FileSystemWallet(walletPath); - console.log(`Wallet path: ${walletPath}`); - - // Check to see if we've already enrolled the user. - const userExists = await wallet.exists(userName); - if (!userExists) { - console.log( - 'An identity for the user "' + - userName + - '" does not exist in the wallet', - ); - console.log("Run the registerUser.js application before retrying"); - return; - } - - // Create a new gateway for connecting to our peer node. - const gateway = new Gateway(); - await gateway.connect(ccp, { - wallet, - identity: userName, - discovery: { enabled: false }, - }); - - // Get the network (channel) our contract is deployed to. - const network = await gateway.getNetwork("mychannel"); - - // Get the contract from the network. - const contract = network.getContract("fabcar"); - - // Evaluate the specified transaction. - if (process.argv.length > 2) { - const key = process.argv[2]; - //console.log('##queryCar Params: ' + key); - console.log(`##queryCar Params: ${key}`); - const result = await contract.evaluateTransaction("queryCar", key); - console.log( - `Transaction has been evaluated, result is: ${result.toString()}`, - ); - } else { - console.log("##queryAllCars: "); - const result = await contract.evaluateTransaction("queryAllCars"); - console.log( - `Transaction has been evaluated, result is: ${result.toString()}`, - ); - } - } catch (error) { - console.error(`Failed to evaluate transaction: ${error}`); - process.exit(1); - } - } - - queryCars(); -} diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/tsconfig.json b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/tsconfig.json deleted file mode 100644 index 928b357062..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compileOnSave": false, - "compilerOptions": { - "outDir": "./dist", - "sourceMap": false, - "declaration": false, - "moduleResolution": "node", - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "target": "ES2017", - "module": "CommonJS", - "typeRoots": [ - "node_modules/@types", - "./typings" - ], - "lib": [ - "es2017", - "dom" - ] - }, -} diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/validatorDriver_changeCarOwner.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/validatorDriver_changeCarOwner.ts deleted file mode 100644 index 68a9305b98..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/validatorDriver_changeCarOwner.ts +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * validatorDriver_changeCarOwner.js - */ - -//////// -// Usage -// TODO: -// -//////// - -import { io } from "socket.io-client"; - -{ - // Validator test program.(socket.io client) - const config = require("config"); - - // Specify the server (Validator) of the communication destination - const validatorUrl = config.validatorUrl; - console.log("validatorUrl: " + validatorUrl); - const options = { - rejectUnauthorized: false, // temporary avoidance since self-signed certificates are used - reconnection: false, - timeout: 20000, - }; - const socket = io(validatorUrl, options); - - // ## Request for "changeCarOwner" - const carID = "CAR11"; - const newOwner = "Robert"; - const reqID = "req12345"; - - //var func = "changeCarOwner"; - //var args = { - // carId : carId, - // newOwner : newOwner - //}; - - const contract = { channelName: "mychannel", contractName: "fabcar" }; - const method = { type: "submitTransaction", command: "changeCarOwner" }; - const args = { args: [carID, newOwner] }; - - // function param - const requestData = { - contract: contract, - method: method, - args: args, - reqID: reqID, - }; - - const json2str = (jsonObj) => { - try { - return JSON.stringify(jsonObj); - } catch (error) { - return null; - } - }; - - socket.on("connect_error", (err) => { - console.log("####connect_error:", err); - // end communication - socket.disconnect(); - process.exit(0); - }); - - socket.on("connect_timeout", (err) => { - console.log("####Error:", err); - // end communication - socket.disconnect(); - process.exit(0); - }); - - socket.on("error", (err) => { - console.log("####Error:", err); - }); - - socket.on("eventReceived", function (res) { - // output the data received from the client - console.log("#[recv]eventReceived, res: " + json2str(res)); - }); - - const requestStopMonitor = () => { - console.log("##exec requestStopMonitor()"); - socket.emit("stopMonitor"); - - setTimeout(function () { - // end communication - socket.disconnect(); - process.exit(0); - }, 5000); - }; - - // request StartMonitor - const requestStartMonitor = () => { - console.log("##exec requestStartMonitor()"); - socket.emit("startMonitor"); - - setTimeout(requestStopMonitor, 15000); - }; - - const sendRequest = () => { - // - console.log("exec sendRequest()"); - console.log("#[send]requestData: " + json2str(requestData)); - socket.emit("request2", requestData); - }; - - setTimeout(requestStartMonitor, 2000); // TODO: - setTimeout(sendRequest, 4000); -} diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/validatorDriver_queryAllCars.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/validatorDriver_queryAllCars.ts deleted file mode 100644 index 9c1331f36e..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/validatorDriver_queryAllCars.ts +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * validatorDriver_queryCar.js - */ - -//////// -// Usage -// TODO: -// -//////// - -import { io } from "socket.io-client"; - -{ - // Validator test program.(socket.io client) - const config = require("config"); - - // Specify the server (Validator) of the communication destination - const validatorUrl = config.validatorUrl; - console.log("validatorUrl: " + validatorUrl); - const options = { - rejectUnauthorized: false, // temporary avoidance since self-signed certificates are used - reconnection: false, - timeout: 20000, - }; - const socket = io(validatorUrl, options); - - // ## Request for "changeCarOwner" - const reqID = "req12345"; - - const contract = { channelName: "mychannel", contractName: "fabcar" }; - const method = { type: "evaluateTransaction", command: "queryAllCars" }; - const args = { args: [] }; - - // function param - const requestData = { - contract: contract, - method: method, - args: args, - reqID: reqID, - }; - - const json2str = (jsonObj) => { - try { - return JSON.stringify(jsonObj); - } catch (error) { - return null; - } - }; - - socket.on("connect_error", (err) => { - console.log("####connect_error:", err); - // end communication - socket.disconnect(); - process.exit(0); - }); - - socket.on("connect_timeout", (err) => { - console.log("####Error:", err); - // end communication - socket.disconnect(); - process.exit(0); - }); - - socket.on("error", (err) => { - console.log("####Error:", err); - }); - - socket.on("eventReceived", function (res) { - // output the data received from the client - console.log("#[recv]eventReceived, res: " + json2str(res)); - }); - - const requestStopMonitor = () => { - console.log("##exec requestStopMonitor()"); - socket.emit("stopMonitor"); - - setTimeout(function () { - // end communication - socket.disconnect(); - process.exit(0); - }, 5000); - }; - - // request StartMonitor - const requestStartMonitor = () => { - console.log("##exec requestStartMonitor()"); - socket.emit("startMonitor"); - - setTimeout(requestStopMonitor, 15000); - }; - - const sendRequest = () => { - // - console.log("exec sendRequest()"); - console.log("#[send]requestData: " + json2str(requestData)); - socket.emit("request2", requestData); - }; - - setTimeout(requestStartMonitor, 2000); // TODO: - setTimeout(sendRequest, 4000); -} diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/validatorDriver_queryCar.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/validatorDriver_queryCar.ts deleted file mode 100644 index 9b025cca66..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/validatorDriver_queryCar.ts +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * validatorDriver_queryCar.js - */ - -//////// -// Usage -// TODO: -// -//////// - -import { io } from "socket.io-client"; - -{ - // Validator test program.(socket.io client) - const config = require("config"); - - // Specify the server (Validator) of the communication destination - const validatorUrl = config.validatorUrl; - console.log("validatorUrl: " + validatorUrl); - const options = { - rejectUnauthorized: false, // temporary avoidance since self-signed certificates are used - reconnection: false, - timeout: 20000, - }; - const socket = io(validatorUrl, options); - - // ## Request for "changeCarOwner" - const carID = "CAR11"; - const reqID = "req12345"; - - const contract = { channelName: "mychannel", contractName: "fabcar" }; - const method = { type: "evaluateTransaction", command: "queryCar" }; - const args = { args: [carID] }; - - // function param - const requestData = { - contract: contract, - method: method, - args: args, - reqID: reqID, - }; - - const json2str = (jsonObj) => { - try { - return JSON.stringify(jsonObj); - } catch (error) { - return null; - } - }; - - socket.on("connect_error", (err) => { - console.log("####connect_error:", err); - // end communication - socket.disconnect(); - process.exit(0); - }); - - socket.on("connect_timeout", (err) => { - console.log("####Error:", err); - // end communication - socket.disconnect(); - process.exit(0); - }); - - socket.on("error", (err) => { - console.log("####Error:", err); - }); - - socket.on("eventReceived", function (res) { - // output the data received from the client - console.log("#[recv]eventReceived, res: " + json2str(res)); - }); - - const requestStopMonitor = () => { - console.log("##exec requestStopMonitor()"); - socket.emit("stopMonitor"); - - setTimeout(function () { - // end communication - socket.disconnect(); - process.exit(0); - }, 5000); - }; - - // request StartMonitor - const requestStartMonitor = () => { - console.log("##exec requestStartMonitor()"); - socket.emit("startMonitor"); - - setTimeout(requestStopMonitor, 15000); - }; - - const sendRequest = () => { - // - console.log("exec sendRequest()"); - console.log("#[send]requestData: " + json2str(requestData)); - socket.emit("request2", requestData); - }; - - setTimeout(requestStartMonitor, 2000); // TODO: - setTimeout(sendRequest, 4000); -} diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/validatorDriver_signTransactionOffline.ts b/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/validatorDriver_signTransactionOffline.ts deleted file mode 100644 index 9e9416b1a2..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/src/test/typescript/unit-test/validatorDriver_signTransactionOffline.ts +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Copyright 2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * validatorDriver_signTransactionOffline.js - */ - -//////// -// Usage -// TODO:XX -// -//////// - -/* Summary: - * Request library for fabric v1.4.0 (for offline signature) Processing library Testing library - * In this case, it is used only when transferring assets. - */ - -import { io } from "socket.io-client"; - -{ - // Validator test program.(socket.io client) - const config = require("config"); - - // Specify the server (Validator) of the communication destination - const validatorUrl = config.validatorUrl; - console.log("validatorUrl: " + validatorUrl); - const options = { - rejectUnauthorized: false, // temporary avoidance since self-signed certificates are used - reconnection: false, - timeout: 20000, - }; - const socket = io(validatorUrl, options); - - // For reading keys and certificates - const fs = require("fs"); - const path = require("path"); - - //Constant definition - - //Fabric node-sdk - const FabricCAService = require("fabric-ca-client"); - const Client = require("fabric-client"); - - //Cryptographic - const hash = require("fabric-client/lib/hash"); - const jsrsa = require("jsrsasign"); - const { KEYUTIL } = jsrsa; - const elliptic = require("elliptic"); - const EC = elliptic.ec; - - // Keys and certificates issued by Fabric-CA (STM administrator, general user) - const privateKeyPem = - "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgQ3pbxM94ZzHPEHW7\n5TQ1N/WfCLSgqY97dfyF34WiJz2hRANCAATROM5gNB8NsA5TfBg2/GB5pMT+vzwG\nJ47lXjK7/oQmTjIEexzJpEKestn16rIVrn7cblXSYDuFtPDjyZ14wCuw\n-----END PRIVATE KEY-----\n"; - - const certPem = - "-----BEGIN CERTIFICATE-----\nMIICAjCCAaigAwIBAgIUYcAcX63XaN2Omym6hEXF+Kxzx2QwCgYIKoZIzj0EAwIw\nczELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh\nbiBGcmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMT\nE2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMjAwNzI3MTAzNDAwWhcNMjEwNzI3MTAz\nOTAwWjAhMQ8wDQYDVQQLEwZjbGllbnQxDjAMBgNVBAMTBWFkbWluMFkwEwYHKoZI\nzj0CAQYIKoZIzj0DAQcDQgAE0TjOYDQfDbAOU3wYNvxgeaTE/r88BieO5V4yu/6E\nJk4yBHscyaRCnrLZ9eqyFa5+3G5V0mA7hbTw48mdeMArsKNsMGowDgYDVR0PAQH/\nBAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFBMOvw1wPpaBeZIpqc3AFbGs\nY0KMMCsGA1UdIwQkMCKAIEI5qg3NdtruuLoM2nAYUdFFBNMarRst3dusalc2Xkl8\nMAoGCCqGSM49BAMCA0gAMEUCIQDXvckX5bZ5mGPHpQ49aKSFsGJkwrX1BnW7DwA+\n4suQPQIgVGKIiQBQDGlOQHkt9lqno/yFiFZSjzZSS24LFIJNKU4=\n-----END CERTIFICATE-----\n"; - - const mspId = config.fabric.mspid; - - // ## Request for "changeCarOwner" - const carId = "CAR11"; - const newOwner = "Charlie"; - - const contract = { channelName: "mychannel" }; - const method = { type: "sendSignedTransaction" }; - //const args = {"args": [carID]}; - - const func = "changeCarOwner"; - const args = { - carId: carId, - newOwner: newOwner, - }; - - // function param - const requestData = { - func: func, - args: args, - }; - - const json2str = (jsonObj) => { - try { - return JSON.stringify(jsonObj); - } catch (error) { - return null; - } - }; - - // BEGIN Signature process===================================================================================== - - // this ordersForCurve comes from CryptoSuite_ECDSA_AES.js and will be part of the - // stand alone fabric-sig package in future. - const ordersForCurve = { - secp256r1: { - halfOrder: elliptic.curves.p256.n.shrn(1), - order: elliptic.curves.p256.n, - }, - secp384r1: { - halfOrder: elliptic.curves.p384.n.shrn(1), - order: elliptic.curves.p384.n, - }, - }; - - // this function comes from CryptoSuite_ECDSA_AES.js and will be part of the - // stand alone fabric-sig package in future. - const _preventMalleability = (sig, curveParams) => { - const halfOrder = ordersForCurve[curveParams.name].halfOrder; - if (!halfOrder) { - throw new Error( - 'Can not find the half order needed to calculate "s" value for immalleable signatures. Unsupported curve name: ' + - curveParams.name, - ); - } - - // in order to guarantee 's' falls in the lower range of the order, as explained in the above link, - // first see if 's' is larger than half of the order, if so, it needs to be specially treated - if (sig.s.cmp(halfOrder) === 1) { - // module 'bn.js', file lib/bn.js, method cmp() - // convert from BigInteger used by jsrsasign Key objects and bn.js used by elliptic Signature objects - const bigNum = ordersForCurve[curveParams.name].order; - sig.s = bigNum.sub(sig.s); - } - - return sig; - }; - - /** - * this method is used for test at this moment. In future this - * would be a stand alone package that running at the browser/cellphone/PAD - * - * @param {string} privateKey PEM encoded private key - * @param {Buffer} proposalBytes proposal bytes - */ - const sign = (privateKey, proposalBytes, algorithm, keySize) => { - const hashAlgorithm = algorithm.toUpperCase(); - const hashFunction = hash[`${hashAlgorithm}_${keySize}`]; - const ecdsaCurve = elliptic.curves[`p${keySize}`]; - const ecdsa = new EC(ecdsaCurve); - const key = KEYUTIL.getKey(privateKey); - - const signKey = ecdsa.keyFromPrivate(key.prvKeyHex, "hex"); - const digest = hashFunction(proposalBytes); - - let sig = ecdsa.sign(Buffer.from(digest, "hex"), signKey); - sig = _preventMalleability(sig, key.ecparams); - - return Buffer.from(sig.toDER()); - }; - - const signProposal = (proposalBytes, paramPrivateKeyPem) => { - console.log("signProposal start"); - - const signature = sign(paramPrivateKeyPem, proposalBytes, "sha2", 256); - const signedProposal = { signature, proposal_bytes: proposalBytes }; - return signedProposal; - }; - - // END Signature process========================================================================================= - - // setup TLS for this client - const TLSSetup = async (client, enrollmentID, secret) => { - const tlsOptions = { - trustedRoots: [], - verify: false, - }; - console.log("tlssetup start"); - const caService = new FabricCAService( - config.fabric.ca.url, - tlsOptions, - config.fabric.ca.name, - ); - const req = { - enrollmentID: enrollmentID, - enrollmentSecret: secret, - profile: "tls", - }; - const enrollment = await caService.enroll(req); - client.setTlsClientCertAndKey( - enrollment.certificate, - enrollment.key.toBytes(), - ); - }; - - //Creating a channel object - const setupChannel = async (channelName) => { - console.log("setupChannel start"); - const client = new Client(); - await TLSSetup( - client, - config.fabric.submitter.name, - config.fabric.submitter.secret, - ); - const channel = client.newChannel(channelName); - - //add peer to channel - //const peerTLSCertPath = path.resolve(__dirname, './crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tlscacerts/org1.example.com-cert.pem'); - //const peerPEMCert = fs.readFileSync(peerTLSCertPath, 'utf8'); - for (let i = 0; i < config.fabric.peers.length; i++) { - const peer = client.newPeer( - config.fabric.peers[i].requests, - /*{ - pem: peerPEMCert, - 'ssl-target-name-override': 'peer0.org1.example.com', - } - */ - ); - channel.addPeer(peer); - } - - //add orderer to channel - /* - const ordererTLSCertPath = path.resolve(__dirname, './crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tlscacerts/example.com-cert.pem'); - const ordererPEMCert = fs.readFileSync(ordererTLSCertPath, 'utf8'); - */ - const orderer = client.newOrderer( - config.fabric.orderer.url, - /*{ - pem: ordererPEMCert, - 'ssl-target-name-override': 'orderer.example.com', - } - */ - ); - channel.addOrderer(orderer); - // TODO: channel.initialize() should not require an signning identity - // await channel.initialize(); - return channel; - }; - - // The following three signatures are required when sending transactions and monitoring block commits. - // Endorsement, Commit -> Signed by STM user. Request a signature from the authorization/signature server. - // RegisterChannelEventHub -> Signed by msp user (User1@example.com) - const Invoke = async (reqBody, isWait) => { - // exports.Invoke = async function(reqBody, isWait){ - //var eventhubs = []; //For the time being, give up the eventhub connection of multiple peers. - let invokeResponse; //Return value from chain code - let channel; - let eh; //EventHub - - return new Promise(async function (resolve, reject) { - try { - //channel object generation - if (channel == undefined) { - channel = await setupChannel(config.fabric.channelName); - } - - /* - * Endorse step - */ - const transactionProposalReq = { - fcn: reqBody.func, //Chain code function name - args: [reqBody.args.carId, reqBody.args.newOwner], //Chaincode argument - chaincodeId: "fabcar", - channelId: config.fabric.channelName, - }; - console.log(transactionProposalReq); - const { proposal, txId } = channel.generateUnsignedProposal( - transactionProposalReq, - config.fabric.mspid, - certPem, - ); - console.log("proposal end"); - console.log(`##txId: ${txId.getTransactionID()}`); - const signedProposal = signProposal(proposal.toBuffer(), privateKeyPem); - - const targets = []; - for (let i = 0; i < config.fabric.peers.length; i++) { - const peer = channel.getPeer( - config.fabric.peers[i].requests.split("//")[1], - ); - targets.push(peer); - } - const sendSignedProposalReq = { signedProposal, targets }; - const proposalResponses = await channel.sendSignedProposal( - sendSignedProposalReq, - ); - console.log("successfully send signedProposal"); - let allGood = true; - for (const i in proposalResponses) { - let oneGood = false; - if ( - proposalResponses && - proposalResponses[i].response && - proposalResponses[i].response.status === 200 - ) { - if (proposalResponses[i].response.payload) { - invokeResponse = new String( - proposalResponses[i].response.payload, - ); - } - oneGood = true; - } else { - console.log("transaction proposal was bad"); - const resStr = proposalResponses[0].toString(); - const errMsg = resStr.replace("Error: ", ""); - return reject(errMsg); - } - allGood = allGood && oneGood; - } - //If the return value of invoke is an empty string, store txID - if (invokeResponse == "") { - invokeResponse = txId.getTransactionID(); - } - //Error if all peers do not return status 200 - if (!allGood) { - throw new Error( - "Failed to send Proposal or receive valid response. Response null or status is not 200. exiting...", - ); - } - - /** - * End the endorse step. - * Start to commit the tx. - */ - const commitReq = { - proposalResponses, - proposal, - }; - const commitProposal = channel.generateUnsignedTransaction(commitReq); - console.log("Successfully build commit transaction proposal"); - - // sign this commit proposal at local - const signedCommitProposal = signProposal( - commitProposal.toBuffer(), - privateKeyPem, - ); - - console.log("Successfully build endorse transaction proposal"); - const retRequestData = { - contract: contract, - method: method, - args: { - args: [ - { - signedCommitProposal: signedCommitProposal, - commitReq: commitReq, - }, - ], - }, - }; - return resolve(retRequestData); - } catch (e) { - console.log(`error at Invoke: err=${e}`); - return reject(e); - } - }); - }; - - socket.on("connect_error", (err) => { - console.log("####connect_error:", err); - // end communication - socket.disconnect(); - process.exit(0); - }); - - socket.on("connect_timeout", (err) => { - console.log("####Error:", err); - // end communication - socket.disconnect(); - process.exit(0); - }); - - socket.on("error", (err) => { - console.log("####Error:", err); - }); - - socket.on("eventReceived", function (res) { - // output the data received from the client - console.log("#[recv]eventReceived, res: " + json2str(res)); - }); - - const requestStopMonitor = () => { - console.log("##exec requestStopMonitor()"); - socket.emit("stopMonitor"); - - setTimeout(function () { - // end communication - socket.disconnect(); - process.exit(0); - }, 5000); - }; - - // request StartMonitor - const requestStartMonitor = () => { - console.log("##exec requestStartMonitor()"); - socket.emit("startMonitor"); - - setTimeout(requestStopMonitor, 15000); - }; - - const sendRequest = () => { - // - console.log("exec sendRequest()"); - console.log("#[send]requestData: " + json2str(requestData)); - Invoke(requestData, true) - .then((returnvalue) => { - //console.log('success : ' + json2str(returnvalue)); - console.log(`emit request2`); - socket.emit("request2", returnvalue); - }) - .catch((err) => { - console.log("failed : " + err); - }); - }; - - setTimeout(requestStartMonitor, 2000); // TODO: - setTimeout(sendRequest, 4000); -} diff --git a/packages/cactus-plugin-ledger-connector-fabric-socketio/tsconfig.json b/packages/cactus-plugin-ledger-connector-fabric-socketio/tsconfig.json deleted file mode 100644 index cc620be6a3..0000000000 --- a/packages/cactus-plugin-ledger-connector-fabric-socketio/tsconfig.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "rootDir": "./src/main/typescript", - "composite": true, - "outDir": "./dist", - "tsBuildInfoFile": "../../.build-cache/cactus-plugin-ledger-connector-fabric-socketio.tsbuildinfo" - }, - "include": [ - "./src/main/typescript/common/core/*.ts", - "./src/main/typescript/common/core/bin/*.ts", - "./src/main/typescript/common/core/config/*.ts", - "./src/main/typescript/connector/*.ts", - "./src/main/typescript/*.ts" - ], - "references": [ - { - "path": "../cactus-api-client/tsconfig.json" - }, - { - "path": "../cactus-test-tooling/tsconfig.json" - }, - { - "path": "../cactus-cmd-socketio-server/tsconfig.json" - }, - { - "path": "../cactus-cmd-api-server/tsconfig.json" - } - ] -} diff --git a/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/fabric-watch-blocks-v1-endpoint.test.ts b/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/fabric-watch-blocks-v1-endpoint.test.ts index 54ee885d54..3f8bc088db 100644 --- a/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/fabric-watch-blocks-v1-endpoint.test.ts +++ b/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/fabric-watch-blocks-v1-endpoint.test.ts @@ -385,7 +385,6 @@ describe("watchBlocksV1 of fabric connector tests", () => { /** * Check Cactus custom transactions summary block monitoring. - * This format is compatible with legacy fabric-socketio output. */ test("Monitoring with type CactusTransactions returns transactions summary", async () => { const monitorPromise = testWatchBlock( diff --git a/packages/cactus-verifier-client/README.md b/packages/cactus-verifier-client/README.md index 856bc7e52b..8131d0fc45 100644 --- a/packages/cactus-verifier-client/README.md +++ b/packages/cactus-verifier-client/README.md @@ -14,7 +14,7 @@ This package provides `Verifier` and `VerifierFactory` components that can be us | IROHA_1X | cactus-plugin-ledger-connector-iroha | | IROHA_2X | cactus-plugin-ledger-connector-iroha2 | | FABRIC_2X | cactus-plugin-ledger-connector-fabric | -| legacy-socketio | cactus-plugin-ledger-connector-fabric-socketio
cactus-plugin-ledger-connector-go-ethereum-socketio
cactus-plugin-ledger-connector-sawtooth-socketio | +| legacy-socketio | cactus-plugin-ledger-connector-go-ethereum-socketio
cactus-plugin-ledger-connector-sawtooth-socketio | ## VerifierFactory - Used to create single verifier per ledger based on pre-defined configuration. diff --git a/tools/docker/fabric-all-in-one/asset-transfer-basic-utils/README.md b/tools/docker/fabric-all-in-one/asset-transfer-basic-utils/README.md index 349624163c..ce6f81e215 100644 --- a/tools/docker/fabric-all-in-one/asset-transfer-basic-utils/README.md +++ b/tools/docker/fabric-all-in-one/asset-transfer-basic-utils/README.md @@ -1,7 +1,7 @@ # fabric-cli-.14 Helper CLI tools for interacting with `asset-transfer-basic` CC deployed in `fabric-all-in-one` image. -Sources are based on official fabric-samples 1.4.8 - https://github.com/hyperledger/fabric-samples/releases/tag/v1.4.8. +Sources are based on official fabric-samples - https://github.com/hyperledger/fabric-samples/ ## Usage diff --git a/tools/docker/fabric-all-in-one/asset-transfer-basic-utils/enrollAdmin.js b/tools/docker/fabric-all-in-one/asset-transfer-basic-utils/enrollAdmin.js index ad207d2750..1145bc8a70 100644 --- a/tools/docker/fabric-all-in-one/asset-transfer-basic-utils/enrollAdmin.js +++ b/tools/docker/fabric-all-in-one/asset-transfer-basic-utils/enrollAdmin.js @@ -1,19 +1,18 @@ /* * SPDX-License-Identifier: Apache-2.0 - * Source: https://github.com/hyperledger/fabric-samples/releases/tag/v1.4.8 + * Source: https://github.com/hyperledger/fabric-samples */ "use strict"; const FabricCAServices = require("fabric-ca-client"); -const { FileSystemWallet, X509WalletMixin } = require("fabric-network"); +const { Wallets } = require("fabric-network"); const fs = require("fs"); const path = require("path"); const ccpPath = "./connection.json"; const ccpJSON = fs.readFileSync(ccpPath, "utf8"); const ccp = JSON.parse(ccpJSON); - async function main() { try { // Create a new CA client for interacting with the CA. @@ -27,12 +26,12 @@ async function main() { // Create a new file system based wallet for managing identities. const walletPath = path.join(process.cwd(), "wallet"); - const wallet = new FileSystemWallet(walletPath); + const wallet = await Wallets.newFileSystemWallet(walletPath); console.log(`Wallet path: ${walletPath}`); // Check to see if we've already enrolled the admin user. - const adminExists = await wallet.exists("admin"); - if (adminExists) { + const identity = await wallet.get("admin"); + if (identity) { console.log( 'An identity for the admin user "admin" already exists in the wallet', ); @@ -44,12 +43,15 @@ async function main() { enrollmentID: "admin", enrollmentSecret: "adminpw", }); - const identity = X509WalletMixin.createIdentity( - "Org1MSP", - enrollment.certificate, - enrollment.key.toBytes(), - ); - await wallet.import("admin", identity); + const x509Identity = { + credentials: { + certificate: enrollment.certificate, + privateKey: enrollment.key.toBytes(), + }, + mspId: "Org1MSP", + type: "X.509", + }; + await wallet.put("admin", x509Identity); console.log( 'Successfully enrolled admin user "admin" and imported it into the wallet', ); diff --git a/tools/docker/fabric-all-in-one/asset-transfer-basic-utils/package.json b/tools/docker/fabric-all-in-one/asset-transfer-basic-utils/package.json index b897d38a6b..4194587372 100644 --- a/tools/docker/fabric-all-in-one/asset-transfer-basic-utils/package.json +++ b/tools/docker/fabric-all-in-one/asset-transfer-basic-utils/package.json @@ -10,7 +10,7 @@ "author": "Hyperledger", "license": "Apache-2.0", "dependencies": { - "fabric-ca-client": "1.4.19", - "fabric-network": "1.4.19" + "fabric-ca-client": "2.2.18", + "fabric-network": "2.2.18" } } diff --git a/tools/docker/fabric-all-in-one/asset-transfer-basic-utils/query.js b/tools/docker/fabric-all-in-one/asset-transfer-basic-utils/query.js index ec4acc05ce..5e288a63ed 100644 --- a/tools/docker/fabric-all-in-one/asset-transfer-basic-utils/query.js +++ b/tools/docker/fabric-all-in-one/asset-transfer-basic-utils/query.js @@ -1,25 +1,29 @@ /* * SPDX-License-Identifier: Apache-2.0 - * Source: https://github.com/hyperledger/fabric-samples/releases/tag/v1.4.8 + * Source: https://github.com/hyperledger/fabric-samples */ "use strict"; -const { FileSystemWallet, Gateway } = require("fabric-network"); +const { Gateway, Wallets } = require("fabric-network"); const path = require("path"); +const fs = require("fs"); const ccpPath = "./connection.json"; async function main() { try { + // load the network configuration + const ccp = JSON.parse(fs.readFileSync(ccpPath, "utf8")); + // Create a new file system based wallet for managing identities. const walletPath = path.join(process.cwd(), "wallet"); - const wallet = new FileSystemWallet(walletPath); + const wallet = await Wallets.newFileSystemWallet(walletPath); console.log(`Wallet path: ${walletPath}`); // Check to see if we've already enrolled the user. - const userExists = await wallet.exists("appUser"); - if (!userExists) { + const identity = await wallet.get("appUser"); + if (!identity) { console.log( 'An identity for the user "appUser" does not exist in the wallet', ); @@ -29,7 +33,7 @@ async function main() { // Create a new gateway for connecting to our peer node. const gateway = new Gateway(); - await gateway.connect(ccpPath, { + await gateway.connect(ccp, { wallet, identity: "appUser", discovery: { enabled: true, asLocalhost: true }, @@ -46,9 +50,11 @@ async function main() { // GetAllAssets transaction - requires no arguments, ex: ('GetAllAssets') const result = await contract.evaluateTransaction("GetAllAssets"); console.log( - "Transaction has been evaluated, result is:", - JSON.parse(result.toString()), + `Transaction has been evaluated, result is: ${result.toString()}`, ); + + // Disconnect from the gateway. + await gateway.disconnect(); } catch (error) { console.error(`Failed to evaluate transaction: ${error}`); process.exit(1); diff --git a/tools/docker/fabric-all-in-one/asset-transfer-basic-utils/registerUser.js b/tools/docker/fabric-all-in-one/asset-transfer-basic-utils/registerUser.js index 9e79c4e08d..640ba0870b 100644 --- a/tools/docker/fabric-all-in-one/asset-transfer-basic-utils/registerUser.js +++ b/tools/docker/fabric-all-in-one/asset-transfer-basic-utils/registerUser.js @@ -1,29 +1,34 @@ /* * SPDX-License-Identifier: Apache-2.0 - * Source: https://github.com/hyperledger/fabric-samples/releases/tag/v1.4.8 + * Source: https://github.com/hyperledger/fabric-samples */ "use strict"; -const { - FileSystemWallet, - Gateway, - X509WalletMixin, -} = require("fabric-network"); +const { Wallets } = require("fabric-network"); +const FabricCAServices = require("fabric-ca-client"); +const fs = require("fs"); const path = require("path"); const ccpPath = "./connection.json"; async function main() { try { + // load the network configuration + const ccp = JSON.parse(fs.readFileSync(ccpPath, "utf8")); + + // Create a new CA client for interacting with the CA. + const caURL = ccp.certificateAuthorities["ca.org1.example.com"].url; + const ca = new FabricCAServices(caURL); + // Create a new file system based wallet for managing identities. const walletPath = path.join(process.cwd(), "wallet"); - const wallet = new FileSystemWallet(walletPath); + const wallet = await Wallets.newFileSystemWallet(walletPath); console.log(`Wallet path: ${walletPath}`); // Check to see if we've already enrolled the user. - const userExists = await wallet.exists("appUser"); - if (userExists) { + const userIdentity = await wallet.get("appUser"); + if (userIdentity) { console.log( 'An identity for the user "appUser" already exists in the wallet', ); @@ -31,8 +36,8 @@ async function main() { } // Check to see if we've already enrolled the admin user. - const adminExists = await wallet.exists("admin"); - if (!adminExists) { + const adminIdentity = await wallet.get("admin"); + if (!adminIdentity) { console.log( 'An identity for the admin user "admin" does not exist in the wallet', ); @@ -40,17 +45,11 @@ async function main() { return; } - // Create a new gateway for connecting to our peer node. - const gateway = new Gateway(); - await gateway.connect(ccpPath, { - wallet, - identity: "admin", - discovery: { enabled: true, asLocalhost: true }, - }); - - // Get the CA client object from the gateway for interacting with the CA. - const ca = gateway.getClient().getCertificateAuthority(); - const adminIdentity = gateway.getCurrentIdentity(); + // build a user object for authenticating with the CA + const provider = wallet + .getProviderRegistry() + .getProvider(adminIdentity.type); + const adminUser = await provider.getUserContext(adminIdentity, "admin"); // Register the user, enroll the user, and import the new identity into the wallet. const secret = await ca.register( @@ -59,18 +58,21 @@ async function main() { enrollmentID: "appUser", role: "client", }, - adminIdentity, + adminUser, ); const enrollment = await ca.enroll({ enrollmentID: "appUser", enrollmentSecret: secret, }); - const userIdentity = X509WalletMixin.createIdentity( - "Org1MSP", - enrollment.certificate, - enrollment.key.toBytes(), - ); - await wallet.import("appUser", userIdentity); + const x509Identity = { + credentials: { + certificate: enrollment.certificate, + privateKey: enrollment.key.toBytes(), + }, + mspId: "Org1MSP", + type: "X.509", + }; + await wallet.put("appUser", x509Identity); console.log( 'Successfully registered and enrolled admin user "appUser" and imported it into the wallet', ); diff --git a/tsconfig.json b/tsconfig.json index cdd362b869..5f2373c806 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -64,9 +64,6 @@ { "path": "./packages/cactus-plugin-ledger-connector-fabric/tsconfig.json" }, - { - "path": "./packages/cactus-plugin-ledger-connector-fabric-socketio/tsconfig.json" - }, { "path": "./packages/cactus-plugin-ledger-connector-go-ethereum-socketio/tsconfig.json" }, diff --git a/yarn.lock b/yarn.lock index 6c06558ad7..3fda3e52c4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5705,13 +5705,10 @@ __metadata: ethereumjs-common: 1.5.2 ethereumjs-tx: 2.1.2 express: 4.16.4 - fabric-ca-client: 1.4.19 - fabric-network: 1.4.19 http-errors: 1.6.3 http-terminator: 3.2.0 js-yaml: 3.14.1 jsonwebtoken: 9.0.0 - jsrsasign: 10.5.25 lodash: 4.17.21 log4js: 6.4.1 morgan: 1.10.0 @@ -5950,11 +5947,16 @@ __metadata: resolution: "@hyperledger/cactus-example-discounted-asset-trade@workspace:examples/cactus-example-discounted-asset-trade" dependencies: "@hyperledger/cactus-cmd-socketio-server": 2.0.0-alpha.2 + "@hyperledger/cactus-common": 2.0.0-alpha.2 + "@hyperledger/cactus-core": 2.0.0-alpha.2 "@hyperledger/cactus-core-api": 2.0.0-alpha.2 + "@hyperledger/cactus-plugin-keychain-memory": 2.0.0-alpha.2 + "@hyperledger/cactus-plugin-ledger-connector-fabric": 2.0.0-alpha.2 "@hyperledger/cactus-verifier-client": 2.0.0-alpha.2 "@types/elliptic": 6.4.14 "@types/escape-html": 1.0.1 "@types/express": 4.17.13 + "@types/jsonwebtoken": 9.0.2 "@types/jsrsasign": 10.5.8 "@types/node": 14.18.54 axios: 0.24.0 @@ -5966,9 +5968,8 @@ __metadata: ethereumjs-common: 1.5.2 ethereumjs-tx: 2.1.2 express: 4.16.4 - fabric-ca-client: 1.4.19 - fabric-client: 1.4.19 - fabric-network: 1.4.19 + fabric-ca-client: 2.2.18 + fabric-network: 2.2.18 http-errors: 1.6.3 jsonwebtoken: 9.0.0 jsrsasign: 10.5.25 @@ -6502,44 +6503,6 @@ __metadata: languageName: unknown linkType: soft -"@hyperledger/cactus-plugin-ledger-connector-fabric-socketio@workspace:packages/cactus-plugin-ledger-connector-fabric-socketio": - version: 0.0.0-use.local - resolution: "@hyperledger/cactus-plugin-ledger-connector-fabric-socketio@workspace:packages/cactus-plugin-ledger-connector-fabric-socketio" - dependencies: - "@hyperledger/cactus-api-client": 2.0.0-alpha.2 - "@hyperledger/cactus-cmd-socketio-server": 2.0.0-alpha.2 - "@hyperledger/cactus-common": 2.0.0-alpha.2 - "@hyperledger/cactus-test-tooling": 2.0.0-alpha.2 - "@types/config": 0.0.41 - "@types/cookie-parser": 1.4.3 - "@types/elliptic": 6.4.14 - "@types/express": 4.17.13 - "@types/http-errors": 2.0.1 - "@types/jsrsasign": 10.5.8 - "@types/lodash": 4.14.195 - "@types/node": 14.18.54 - body-parser: 1.17.2 - cookie-parser: 1.4.6 - debug: 3.1.0 - express: 4.17.3 - fabric-ca-client: 1.4.19 - fabric-client: 1.4.19 - fabric-network: 1.4.19 - fs-extra: 10.1.0 - grpc: 1.24.11 - js-yaml: 3.14.1 - jsonwebtoken: 9.0.0 - lodash: 4.17.21 - log4js: 6.4.1 - morgan: 1.10.0 - protobufjs: 7.2.5 - serve-favicon: 2.4.5 - shelljs: 0.8.5 - socket.io: 4.5.4 - ts-node: 9.1.1 - languageName: unknown - linkType: soft - "@hyperledger/cactus-plugin-ledger-connector-fabric@2.0.0-alpha.2, @hyperledger/cactus-plugin-ledger-connector-fabric@workspace:packages/cactus-plugin-ledger-connector-fabric": version: 0.0.0-use.local resolution: "@hyperledger/cactus-plugin-ledger-connector-fabric@workspace:packages/cactus-plugin-ledger-connector-fabric" @@ -10380,7 +10343,17 @@ __metadata: languageName: node linkType: hard -"@types/bytebuffer@npm:^5.0.34, @types/bytebuffer@npm:^5.0.40": +"@types/bytebuffer@npm:^5.0.34": + version: 5.0.44 + resolution: "@types/bytebuffer@npm:5.0.44" + dependencies: + "@types/long": ^3.0.0 + "@types/node": "*" + checksum: 86a58be037037b039a645da89b4319f5923b7d506fa770312e8f5f37d251a70cc4f34e59d7d392651a9223d85ca1d072e9ae8126eb874ab0302b91dc40cf352c + languageName: node + linkType: hard + +"@types/bytebuffer@npm:^5.0.40": version: 5.0.43 resolution: "@types/bytebuffer@npm:5.0.43" dependencies: @@ -10985,6 +10958,13 @@ __metadata: languageName: node linkType: hard +"@types/long@npm:^3.0.0": + version: 3.0.32 + resolution: "@types/long@npm:3.0.32" + checksum: 7c64c64b4a8bf38d9a6690f725ed5e92383905b22c1320493749729c4f476a74fa2507cc9364268ecdfdba1cf11573a46648157f3e34cb0c39f51b05d13c37eb + languageName: node + linkType: hard + "@types/lru-cache@npm:5.1.1, @types/lru-cache@npm:^5.1.0": version: 5.1.1 resolution: "@types/lru-cache@npm:5.1.1" @@ -28240,9 +28220,9 @@ __metadata: linkType: hard "klaw@npm:^4.0.1": - version: 4.0.1 - resolution: "klaw@npm:4.0.1" - checksum: 7835649ef632f96099d500f94b38c032acf1432ad5e87da596a2509c2f6a63a7fc346fb357e2227091cc433af5c1378ed448e1c0522ed028981dcd446152291e + version: 4.1.0 + resolution: "klaw@npm:4.1.0" + checksum: 23fcdd8b837f7d51f0a62bebc4e5f83ee8338083597f33f97ae6aed3305c53220c8bf9f1a81024c11658b2e71022868f3b2ba4c39298af4eaacd38ef1e3a878e languageName: node linkType: hard @@ -40655,27 +40635,6 @@ __metadata: languageName: node linkType: hard -"ts-node@npm:9.1.1": - version: 9.1.1 - resolution: "ts-node@npm:9.1.1" - dependencies: - arg: ^4.1.0 - create-require: ^1.1.0 - diff: ^4.0.1 - make-error: ^1.1.1 - source-map-support: ^0.5.17 - yn: 3.1.1 - peerDependencies: - typescript: ">=2.7" - bin: - ts-node: dist/bin.js - ts-node-script: dist/bin-script.js - ts-node-transpile-only: dist/bin-transpile.js - ts-script: dist/bin-script-deprecated.js - checksum: 356e2647b8b1e6ab00380c0537fa569b63bd9b6f006cc40fd650f81fae1817bd8fecc075300036950d8f45c1d85b95be33cd1e48a1a424a7d86c3dbb42bf60e5 - languageName: node - linkType: hard - "ts-node@npm:^10.0.0": version: 10.5.0 resolution: "ts-node@npm:10.5.0"