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"