From 0617217435268481f67dff37e770f82e060e6c05 Mon Sep 17 00:00:00 2001 From: Michal Bajer Date: Mon, 23 Oct 2023 10:35:46 +0000 Subject: [PATCH] feat(cactus-example-discounted-asset-trade): use openapi sawtooth connector - Refactor discounted asset trade sample to use openapi sawtooth connector instead of sawtooth-socketio. - Remove sawtooth-socketio connector since it's not used any more. Depends on: #2825 Signed-off-by: Michal Bajer --- .cspell.json | 1 - .eslintignore | 1 - .github/workflows/ci.yaml | 26 -- .../BusinessLogicElectricityTrade.ts | 251 ++++-------------- .../README.md | 11 - .../config/usersetting.yaml | 5 +- .../config/validator-registry-config.yaml | 15 -- .../docker-compose.yml | 20 -- .../package.json | 1 + .../sawtooth-connector.ts | 123 +++++++++ .../script-dockerless-config-patch.sh | 4 - .../script-start-ledgers.sh | 20 -- .../tsconfig.json | 3 + .../cactus-example-electricity-trade/www.ts | 2 + .../.gitignore | 1 - .../CHANGELOG.md | 90 ------- .../Dockerfile | 15 -- .../README.md | 86 ------ .../package.json | 81 ------ .../sample-config/default.yaml | 13 - .../src/main/typescript/common/core/app.ts | 53 ---- .../main/typescript/common/core/bin/www.ts | 161 ----------- .../main/typescript/connector/PluginUtil.ts | 84 ------ .../connector/ServerMonitorPlugin.ts | 185 ------------- .../src/main/typescript/index.ts | 1 - .../src/main/typescript/public-api.ts | 1 - .../sawtooth-socketio-connector.test.ts | 244 ----------------- .../tsconfig.json | 34 --- tsconfig.json | 3 - yarn.lock | 31 +-- 30 files changed, 186 insertions(+), 1380 deletions(-) delete mode 100644 examples/cactus-example-electricity-trade/config/validator-registry-config.yaml create mode 100644 examples/cactus-example-electricity-trade/sawtooth-connector.ts delete mode 100644 packages/cactus-plugin-ledger-connector-sawtooth-socketio/.gitignore delete mode 100644 packages/cactus-plugin-ledger-connector-sawtooth-socketio/CHANGELOG.md delete mode 100644 packages/cactus-plugin-ledger-connector-sawtooth-socketio/Dockerfile delete mode 100644 packages/cactus-plugin-ledger-connector-sawtooth-socketio/README.md delete mode 100644 packages/cactus-plugin-ledger-connector-sawtooth-socketio/package.json delete mode 100644 packages/cactus-plugin-ledger-connector-sawtooth-socketio/sample-config/default.yaml delete mode 100644 packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/common/core/app.ts delete mode 100755 packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/common/core/bin/www.ts delete mode 100644 packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/connector/PluginUtil.ts delete mode 100644 packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/connector/ServerMonitorPlugin.ts delete mode 100644 packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/index.ts delete mode 100644 packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/public-api.ts delete mode 100644 packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/test/typescript/integration/sawtooth-socketio-connector.test.ts delete mode 100644 packages/cactus-plugin-ledger-connector-sawtooth-socketio/tsconfig.json diff --git a/.cspell.json b/.cspell.json index 8d17edfe2f..7893e92eb4 100644 --- a/.cspell.json +++ b/.cspell.json @@ -162,7 +162,6 @@ "**/src/main/typescript/generated/**", "packages/cactus-plugin-verifier-cc/**", "packages/cactus-cmd-socketio-server/**", - "packages/cactus-plugin-ledger-connector-sawtooth-socketio/**", "packages/cactus-plugin-ledger-connector-go-ethereum-socketio/**", "packages/cactus-plugin-ledger-connector-*-socketio/**" ] diff --git a/.eslintignore b/.eslintignore index 2057b28377..138020cb96 100644 --- a/.eslintignore +++ b/.eslintignore @@ -5,7 +5,6 @@ packages/cactus-verifier/src/main/typescript/ packages/cactus-cmd-socketio-server/** -packages/cactus-plugin-ledger-connector-sawtooth-socketio/** packages/cactus-plugin-ledger-connector-go-ethereum-socketio/** packages/cactus-plugin-ledger-connector-*-socketio/** diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index cbe152149f..908ddcba9f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1359,32 +1359,6 @@ jobs: 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: ./tools/ci.sh - cactus-plugin-ledger-connector-sawtooth-socketio: - continue-on-error: false - env: - DEV_BUILD_DISABLED: false - FULL_BUILD_DISABLED: true - JEST_TEST_PATTERN: packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/test/typescript/(unit|integration|benchmark)/.*/*.test.ts - JEST_TEST_RUNNER_DISABLED: true - 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 diff --git a/examples/cactus-example-electricity-trade/BusinessLogicElectricityTrade.ts b/examples/cactus-example-electricity-trade/BusinessLogicElectricityTrade.ts index 84f693aca2..ae54bf5694 100644 --- a/examples/cactus-example-electricity-trade/BusinessLogicElectricityTrade.ts +++ b/examples/cactus-example-electricity-trade/BusinessLogicElectricityTrade.ts @@ -10,42 +10,25 @@ import { RequestInfo } from "./RequestInfo"; import { MeterManagement } from "./MeterManagement"; import { MeterInfo } from "./MeterInfo"; import { - TradeInfo, - routesTransactionManagement, BusinessLogicBase, LedgerEvent, json2str, ConfigUtil, - LPInfoHolder, } from "@hyperledger/cactus-cmd-socketio-server"; import { sendEthereumTransaction } from "./TransactionEthereum"; const config: any = ConfigUtil.getConfig() as any; import { getLogger } from "log4js"; +import { getSawtoothApiClient } from "./sawtooth-connector"; import { - VerifierFactory, - VerifierFactoryConfig, -} from "@hyperledger/cactus-verifier-client"; + isWatchBlocksV1CactiTransactionsResponse, + WatchBlocksV1ListenerType, + WatchBlocksV1Progress, +} from "@hyperledger/cactus-plugin-ledger-connector-sawtooth"; const moduleName = "BusinessLogicElectricityTrade"; const logger = getLogger(`${moduleName}`); logger.level = config.logLevel; -const connectInfo = new LPInfoHolder(); -const routesVerifierFactory = new VerifierFactory( - connectInfo.ledgerPluginInfo as VerifierFactoryConfig, - config.logLevel, -); - -interface SawtoothEventData { - status: number | string; - blockData: []; -} - -interface SawtoothBlockDataData { - header_signature: string; - hash: string; - payload_decoded: { Verb: string; Name: string; Value: string }[]; -} export class BusinessLogicElectricityTrade extends BusinessLogicBase { businessLogicID: string; @@ -71,39 +54,54 @@ export class BusinessLogicElectricityTrade extends BusinessLogicBase { // set TradeID requestInfo.setTradeID(tradeID); - // Create trade information - const tradeInfo: TradeInfo = new TradeInfo( - requestInfo.businessLogicID, - requestInfo.tradeID, - ); - - this.startMonitor(tradeInfo); + this.startSawtoothMonitor(); } - startMonitor(tradeInfo: TradeInfo): void { - // Get Verifier Instance - logger.debug( - `##startMonitor(): businessLogicID: ${tradeInfo.businessLogicID}`, - ); - const useValidator = JSON.parse( - routesTransactionManagement.getValidatorToUse(tradeInfo.businessLogicID), - ); - logger.debug( - `filterKey: ${config.electricityTradeInfo.sawtooth.filterKey}`, - ); - const options = { - filterKey: config.electricityTradeInfo.sawtooth.filterKey, - }; - // const verifierSawtooth = transactionManagement.getVerifier(useValidator['validatorID'][0], options); - const verifierSawtooth = routesVerifierFactory.getVerifier( - useValidator["validatorID"][0], - ); - verifierSawtooth.startMonitor( - "BusinessLogicElectricityTrade", - options, - routesTransactionManagement, - ); - logger.debug("getVerifierSawtooth"); + startSawtoothMonitor(): void { + // Start monitoring + const sawtoothApiClient = getSawtoothApiClient(); + const watchObservable = sawtoothApiClient.watchBlocksV1({ + type: WatchBlocksV1ListenerType.CactiTransactions, + txFilterBy: { + family_name: config.electricityTradeInfo.sawtooth.filterKey, + }, + }); + watchObservable.subscribe({ + next: (event: WatchBlocksV1Progress) => { + logger.debug(`##in onEventSawtooth()`); + + if (!isWatchBlocksV1CactiTransactionsResponse(event)) { + logger.error("Wrong input block format!", event); + return; + } + + for (const tx of event.cactiTransactionsEvents) { + try { + const txId = tx.header_signature; + logger.debug(`##txId = ${txId}`); + + const txPayload = tx.payload_decoded[0]; + if (txPayload && txPayload.Verb !== "set") { + this.remittanceTransaction({ + Name: txPayload.Name, + Value: txPayload.Value, + Verb: txPayload.Verb, + }); + } + } catch (err) { + logger.error( + `##onEventSawtooth(): onEvent, err: ${err}, event: ${JSON.stringify( + tx, + )}`, + tx, + ); + } + } + }, + error(err: unknown) { + logger.error("Sawtooth watchBlocksV1() error:", err); + }, + }); } remittanceTransaction(transactionSubset: Record): void { @@ -144,68 +142,10 @@ export class BusinessLogicElectricityTrade extends BusinessLogicBase { } onEvent(ledgerEvent: LedgerEvent, targetIndex: number): void { - logger.debug(`##in BLP:onEvent()`); - logger.debug( - `##onEvent(): ${json2str(ledgerEvent["data"]["blockData"][targetIndex])}`, + logger.error( + "onEvent() ERROR - No monitors are running, should not be called!", ); - - switch (ledgerEvent.verifierId) { - case config.electricityTradeInfo.sawtooth.validatorID: - this.onEventSawtooth(ledgerEvent.data, targetIndex); - break; - default: - logger.error( - `##onEvent(), invalid verifierId: ${ledgerEvent.verifierId}`, - ); - return; - } - } - - onEventSawtooth(event: SawtoothEventData, targetIndex: number): void { - logger.debug(`##in onEventSawtooth()`); - const tx = this.getTransactionFromSawtoothEvent(event, targetIndex); - if (tx == null) { - logger.error(`##onEventSawtooth(): invalid event: ${json2str(event)}`); - return; - } - - try { - const txId = tx["header_signature"]; - logger.debug(`##txId = ${txId}`); - - if (tx["payload_decoded"][0].Verb !== "set") { - const transactionSubset = { - Name: tx["payload_decoded"][0].Name, - Value: tx["payload_decoded"][0].Value, - Verb: tx["payload_decoded"][0].Verb, - }; - this.remittanceTransaction(transactionSubset); - } - } catch (err) { - logger.error( - `##onEventSawtooth(): err: ${err}, event: ${json2str(event)}`, - ); - } - } - - getTransactionFromSawtoothEvent( - event: SawtoothEventData, - targetIndex: number | string, - ): SawtoothBlockDataData | undefined { - try { - if (typeof targetIndex === "number") { - const retTransaction = event["blockData"][targetIndex]; - - logger.debug( - `##getTransactionFromSawtoothEvent(), retTransaction: ${retTransaction}`, - ); - return retTransaction; - } - } catch (err) { - logger.error( - `##getTransactionFromSawtoothEvent(): invalid even, err:${err}, event:${event}`, - ); - } + return; } getOperationStatus(): Record { @@ -213,89 +153,6 @@ export class BusinessLogicElectricityTrade extends BusinessLogicBase { return {}; } - getTxIDFromEvent( - ledgerEvent: LedgerEvent, - targetIndex: number, - ): string | null { - logger.debug(`##in getTxIDFromEvent`); - // logger.debug(`##event: ${json2str(ledgerEvent)}`); - - switch (ledgerEvent.verifierId) { - case config.electricityTradeInfo.sawtooth.validatorID: - return this.getTxIDFromEventSawtooth(ledgerEvent.data, targetIndex); - default: - logger.error( - `##getTxIDFromEvent(): invalid verifierId: ${ledgerEvent.verifierId}`, - ); - } - return null; - } - - getTxIDFromEventSawtooth( - event: SawtoothEventData, - targetIndex: number | string, - ): string | null { - logger.debug(`##in getTxIDFromEventSawtooth()`); - const tx = this.getTransactionFromSawtoothEvent(event, targetIndex); - if (tx == null) { - logger.warn(`#getTxIDFromEventSawtooth(): skip(not found tx)`); - return null; - } - - try { - const txId = tx["header_signature"]; - - if (typeof txId !== "string") { - logger.warn( - `#getTxIDFromEventSawtooth(): skip(invalid block, not found txId.), event: ${json2str( - event, - )}`, - ); - return null; - } - - logger.debug(`###getTxIDFromEventSawtooth(): txId: ${txId}`); - return txId; - } catch (err) { - logger.error( - `##getTxIDFromEventSawtooth(): err: ${err}, event: ${json2str(event)}`, - ); - return null; - } - } - - getEventDataNum(ledgerEvent: LedgerEvent): number { - logger.debug( - `##in BLP:getEventDataNum(), ledgerEvent.verifierId: ${ledgerEvent.verifierId}`, - ); - const event = ledgerEvent.data; - let retEventNum = 0; - - try { - logger.error(ledgerEvent.data); - - switch (ledgerEvent.verifierId) { - case config.electricityTradeInfo.sawtooth.validatorID: - retEventNum = event["blockData"].length; - break; - default: - logger.error( - `##getEventDataNum(): invalid verifierId: ${ledgerEvent.verifierId}`, - ); - break; - } - logger.debug( - `##getEventDataNum(): retEventNum: ${retEventNum}, verifierId: ${ledgerEvent.verifierId}`, - ); - return retEventNum; - } catch (err) { - logger.error( - `##getEventDataNum(): invalid even, err: ${err}, event: ${event}`, - ); - return 0; - } - } - getAccountInfo( transactionSubset: Record, ): Record { diff --git a/examples/cactus-example-electricity-trade/README.md b/examples/cactus-example-electricity-trade/README.md index 81ed13fdc3..037145f146 100644 --- a/examples/cactus-example-electricity-trade/README.md +++ b/examples/cactus-example-electricity-trade/README.md @@ -16,10 +16,6 @@ In this example, we use the Sawtooth intkey transaction processor as an applicat ## Prerequisites -- Available ports: - - `5034`: the port of `cactus-cmd-socketio-server` - - `5140`: the port of `cactus-plugin-ledger-connector-sawtooth-socketio` - - You can modify port exported to the host in `./docker-compose.yml` - Available directory (This directory must be empty): - `./etc/cactus`: the directory for storing the config files of `cactus-cmd-socketio-server`, will be mounted by the containers. @@ -59,11 +55,6 @@ In this example, we use the Sawtooth intkey transaction processor as an applicat ``` cmd-socketio-base-dummy | OK - Exit cmd-socketio-base-dummy exited with code 0 - cactus-example-electricity-trade-sawtooth-validator | - cactus-example-electricity-trade-sawtooth-validator | > @hyperledger/cactus-plugin-ledger-connector-sawtooth-socketio@1.0.0-rc.3 start /root/cactus - cactus-example-electricity-trade-sawtooth-validator | > cd ./dist && node common/core/bin/www.js - cactus-example-electricity-trade-sawtooth-validator | - cactus-example-electricity-trade-sawtooth-validator | listening on *:5140 cactus-example-electricity-trade-blp | [2022-02-14T15:47:47.312] [INFO] www - Using BLP with id = h40Q9eMD cactus-example-electricity-trade-blp | start Dynamic loading. cactus-example-electricity-trade-blp | path: /api/v1/bl/cactus-example-electricity-trade/, routerJs: /root/cactus/dist/cactus-example-electricity-trade.js @@ -77,8 +68,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-electricity-trade/` directory. This will patch the configs and copy it to global location. -1. Start sawtooth validators (in separate cmd window, ethereum connector started as part of BLP). - 1. `cd packages/cactus-plugin-ledger-connector-sawtooth-socketio/ && npm run start` 1. Start electricity-trade: `npm run start-dockerless` ## How to use this application diff --git a/examples/cactus-example-electricity-trade/config/usersetting.yaml b/examples/cactus-example-electricity-trade/config/usersetting.yaml index 13604fb7b9..2f10609451 100644 --- a/examples/cactus-example-electricity-trade/config/usersetting.yaml +++ b/examples/cactus-example-electricity-trade/config/usersetting.yaml @@ -2,7 +2,7 @@ blpRegistry: - businessLogicID: h40Q9eMD - validatorID: [sUr7d10R] + validatorID: [] logLevel: debug @@ -24,10 +24,9 @@ appRouters: # BLP Config electricityTradeInfo: sawtooth: - validatorID: sUr7d10R filterKey: intkey + restApiURL: http://localhost:8008 ethereum: - validatorID: 84jUisrs gethURL: ws://localhost:8546 chainName: geth1 networkID: 10 diff --git a/examples/cactus-example-electricity-trade/config/validator-registry-config.yaml b/examples/cactus-example-electricity-trade/config/validator-registry-config.yaml deleted file mode 100644 index 6f2f49a879..0000000000 --- a/examples/cactus-example-electricity-trade/config/validator-registry-config.yaml +++ /dev/null @@ -1,15 +0,0 @@ -ledgerPluginInfo: - - - validatorID: sUr7d10R - validatorType: legacy-socketio - validatorURL: https://sawtooth-validator:5140 - validatorKeyPath: /etc/cactus/connector-sawtooth-socketio/CA/connector.crt - maxCounterRequestID: 100 - syncFunctionTimeoutMillisecond: 5000 - socketOptions: - rejectUnauthorized: false - reconnection: false - timeout: 20000 - ledgerInfo: - ledgerAbstract: Sawtooth Ledger - apiInfo: [] diff --git a/examples/cactus-example-electricity-trade/docker-compose.yml b/examples/cactus-example-electricity-trade/docker-compose.yml index 12c195cc61..32637c75af 100644 --- a/examples/cactus-example-electricity-trade/docker-compose.yml +++ b/examples/cactus-example-electricity-trade/docker-compose.yml @@ -12,23 +12,6 @@ services: context: ../../packages/cactus-cmd-socketio-server/ command: ["echo", "OK - Exit"] - sawtooth-validator: - container_name: cactus-example-electricity-trade-sawtooth-validator - image: cactus-plugin-ledger-connector-sawtooth-socketio - build: - context: ../../packages/cactus-plugin-ledger-connector-sawtooth-socketio/ - ports: - - "5140:5140" - networks: - - sawtooth_aio_testnet_1x - - cactus-example-electricity-trade-net - depends_on: - - cmd-socketio-base-image - volumes: - - type: bind - source: ./etc/cactus - target: /etc/cactus - cactus-example-electricity-trade-blp: container_name: cactus-example-electricity-trade-blp image: cactus-example-electricity-trade-blp @@ -39,7 +22,6 @@ services: networks: - cactus-example-electricity-trade-net depends_on: - - sawtooth-validator - cmd-socketio-base-image volumes: - type: bind @@ -47,7 +29,5 @@ services: target: /etc/cactus networks: - sawtooth_aio_testnet_1x: - external: true cactus-example-electricity-trade-net: driver: bridge diff --git a/examples/cactus-example-electricity-trade/package.json b/examples/cactus-example-electricity-trade/package.json index a1a15ae7df..db8db2174a 100644 --- a/examples/cactus-example-electricity-trade/package.json +++ b/examples/cactus-example-electricity-trade/package.json @@ -20,6 +20,7 @@ "@hyperledger/cactus-core-api": "2.0.0-alpha.2", "@hyperledger/cactus-plugin-keychain-memory": "2.0.0-alpha.2", "@hyperledger/cactus-plugin-ledger-connector-ethereum": "2.0.0-alpha.2", + "@hyperledger/cactus-plugin-ledger-connector-sawtooth": "2.0.0-alpha.2", "@hyperledger/cactus-verifier-client": "2.0.0-alpha.2", "@types/node": "14.18.54", "body-parser": "1.20.2", diff --git a/examples/cactus-example-electricity-trade/sawtooth-connector.ts b/examples/cactus-example-electricity-trade/sawtooth-connector.ts new file mode 100644 index 0000000000..be3b3c0f65 --- /dev/null +++ b/examples/cactus-example-electricity-trade/sawtooth-connector.ts @@ -0,0 +1,123 @@ +import { IListenOptions, Servers } from "@hyperledger/cactus-common"; +import { Constants, Configuration } from "@hyperledger/cactus-core-api"; +import { ConfigUtil } from "@hyperledger/cactus-cmd-socketio-server"; +import { + PluginLedgerConnectorSawtooth, + SawtoothApiClient, + StatusResponseV1, +} from "@hyperledger/cactus-plugin-ledger-connector-sawtooth"; + +import http from "http"; +import express from "express"; +import bodyParser from "body-parser"; +import { AddressInfo } from "net"; +import { v4 as uuidv4 } from "uuid"; +import { getLogger } from "log4js"; +import { Server as SocketIoServer } from "socket.io"; + +const config: any = ConfigUtil.getConfig(); +const moduleName = "sawtooth-connector"; +const logger = getLogger(`${moduleName}`); +logger.level = config.logLevel; + +// Single Sawtooth connector instance +let sawtoothConnectorPlugin: PluginLedgerConnectorSawtooth | undefined = + undefined; +let sawtoothApiClient: SawtoothApiClient | undefined = undefined; + +async function createSawtoothConnector() { + if (sawtoothConnectorPlugin) { + sawtoothConnectorPlugin.shutdown(); + sawtoothConnectorPlugin = undefined; + } + + sawtoothConnectorPlugin = new PluginLedgerConnectorSawtooth({ + instanceId: `ethElectricityTrade-${uuidv4()}`, + sawtoothRestApiEndpoint: config.electricityTradeInfo.sawtooth.restApiURL, + logLevel: config.logLevel, + }); + + await sawtoothConnectorPlugin.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 sawtoothConnectorPlugin.getOrCreateWebServices(); + await sawtoothConnectorPlugin.registerWebServices(expressApp, socketioServer); + + // Create ApiClient + const apiConfig = new Configuration({ basePath: apiHost }); + sawtoothApiClient = new SawtoothApiClient(apiConfig); +} + +/** + * Get latest block data. Can be used to test sawtooth connection. + */ +async function getStatus(): Promise { + if (!sawtoothConnectorPlugin) { + throw new Error("getLatestBlock() called before initSawtoothConnector()!"); + } + + return sawtoothConnectorPlugin.getStatus(); +} + +/** + * Create sawtooth connector and check if connection can be established + */ +export async function initSawtoothConnector(): Promise { + if (!sawtoothConnectorPlugin) { + await createSawtoothConnector(); + + const connectorStatus = await getStatus(); + if (!connectorStatus.initialized) { + throw new Error(`Invalid getLatestBlock response: ${connectorStatus}`); + } + + logger.info("initSawtoothConnector() done."); + } else { + logger.info( + "initSawtoothConnector() Sawtooth connector already initialized", + ); + } +} + +/** + * Get instance of sawtooth connector, initialize it if not done yet. + */ +export async function getSawtoothConnector(): Promise { + if (!sawtoothConnectorPlugin) { + await initSawtoothConnector(); + } + + if (sawtoothConnectorPlugin) { + return sawtoothConnectorPlugin; + } else { + throw new Error("Could not initialize new sawtooth connector!"); + } +} + +/** + * Get instance of sawtooth api client. + */ +export function getSawtoothApiClient(): SawtoothApiClient { + if (sawtoothApiClient) { + return sawtoothApiClient; + } else { + throw new Error("Sawtooth connector not initialized yet!"); + } +} diff --git a/examples/cactus-example-electricity-trade/script-dockerless-config-patch.sh b/examples/cactus-example-electricity-trade/script-dockerless-config-patch.sh index d3ced99573..8ee2d281e8 100755 --- a/examples/cactus-example-electricity-trade/script-dockerless-config-patch.sh +++ b/examples/cactus-example-electricity-trade/script-dockerless-config-patch.sh @@ -11,10 +11,6 @@ sudo rm -rf "$COMMON_CACTUS_CONFIG" sudo cp -ar "./etc/cactus" "/etc" sudo chown -hR $(whoami) "$COMMON_CACTUS_CONFIG" -echo "Patch validators..." -sed -i 's/geth1/localhost/g' "${COMMON_CACTUS_CONFIG}/connector-go-ethereum-socketio/default.yaml" -sed -i 's/sawtooth_all_in_one_ledger_1x/localhost/g' "${COMMON_CACTUS_CONFIG}/connector-sawtooth-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/sawtooth-validator/localhost/g' "${COMMON_CACTUS_CONFIG}/validator-registry-config.yaml" diff --git a/examples/cactus-example-electricity-trade/script-start-ledgers.sh b/examples/cactus-example-electricity-trade/script-start-ledgers.sh index 1c9e864779..2db6dd4290 100755 --- a/examples/cactus-example-electricity-trade/script-start-ledgers.sh +++ b/examples/cactus-example-electricity-trade/script-start-ledgers.sh @@ -60,14 +60,6 @@ function start_ethereum_testnet() { popd } -function copy_ethereum_validator_config() { - echo ">> copy_ethereum_validator_config()" - cp -fr ${ROOT_DIR}/packages/cactus-plugin-ledger-connector-go-ethereum-socketio/sample-config/* \ - "${CONFIG_VOLUME_PATH}/connector-go-ethereum-socketio/" - generate_certificate "GoEthereumCactusValidator" "${CONFIG_VOLUME_PATH}/connector-go-ethereum-socketio/CA/" - echo ">> copy_ethereum_validator_config() done." -} - function start_sawtooth_testnet() { pushd "${ROOT_DIR}/tools/docker/sawtooth-all-in-one" ./script-start-docker.sh @@ -84,14 +76,6 @@ function start_sawtooth_testnet() { echo ">> Sawtooth ${CACTUS_FABRIC_ALL_IN_ONE_VERSION} started." } -function copy_sawtooth_validator_config() { - echo ">> copy_sawtooth_validator_config()" - cp -fr ${ROOT_DIR}/packages/cactus-plugin-ledger-connector-sawtooth-socketio/sample-config/* \ - "${CONFIG_VOLUME_PATH}/connector-sawtooth-socketio/" - generate_certificate "SawtoothCactusValidator" "${CONFIG_VOLUME_PATH}/connector-sawtooth-socketio/CA/" - echo ">> copy_sawtooth_validator_config() done." -} - function start_ledgers() { # Clear ./etc/cactus mkdir -p "${CONFIG_VOLUME_PATH}/" @@ -101,14 +85,10 @@ function start_ledgers() { cp -f ./config/*.yaml "${CONFIG_VOLUME_PATH}/" # Start Ethereum - mkdir -p "${CONFIG_VOLUME_PATH}/connector-go-ethereum-socketio" start_ethereum_testnet - copy_ethereum_validator_config # Start Sawtooth - mkdir -p "${CONFIG_VOLUME_PATH}/connector-sawtooth-socketio" start_sawtooth_testnet - copy_sawtooth_validator_config } start_ledgers diff --git a/examples/cactus-example-electricity-trade/tsconfig.json b/examples/cactus-example-electricity-trade/tsconfig.json index dd1b41c4f8..265207f66a 100644 --- a/examples/cactus-example-electricity-trade/tsconfig.json +++ b/examples/cactus-example-electricity-trade/tsconfig.json @@ -26,6 +26,9 @@ { "path": "../../packages/cactus-plugin-ledger-connector-ethereum/tsconfig.json" }, + { + "path": "../../packages/cactus-plugin-ledger-connector-sawtooth/tsconfig.json" + }, { "path": "../../packages/cactus-verifier-client/tsconfig.json" } diff --git a/examples/cactus-example-electricity-trade/www.ts b/examples/cactus-example-electricity-trade/www.ts index 6925059e3a..def3aa49a5 100644 --- a/examples/cactus-example-electricity-trade/www.ts +++ b/examples/cactus-example-electricity-trade/www.ts @@ -1,10 +1,12 @@ import { BusinessLogicElectricityTrade } from "./BusinessLogicElectricityTrade"; import { startCactusSocketIOServer } from "@hyperledger/cactus-cmd-socketio-server"; import { initEthereumConnector } from "./ethereum-connector"; +import { initSawtoothConnector } from "./sawtooth-connector"; async function startBLP() { try { await initEthereumConnector(); + await initSawtoothConnector(); startCactusSocketIOServer({ id: "h40Q9eMD", diff --git a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/.gitignore b/packages/cactus-plugin-ledger-connector-sawtooth-socketio/.gitignore deleted file mode 100644 index 849ddff3b7..0000000000 --- a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/.gitignore +++ /dev/null @@ -1 +0,0 @@ -dist/ diff --git a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/CHANGELOG.md b/packages/cactus-plugin-ledger-connector-sawtooth-socketio/CHANGELOG.md deleted file mode 100644 index be209898ea..0000000000 --- a/packages/cactus-plugin-ledger-connector-sawtooth-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 - -* **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) -* use common conventions: tsconfig.json, package.json ([50f5c02](https://github.com/hyperledger/cacti/commit/50f5c02190ba28b77492c09e81f5d5ba6578e862)), closes [#2216](https://github.com/hyperledger/cacti/issues/2216) - -# [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-sawtooth-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-sawtooth-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-sawtooth-socketio - -## [1.1.3](https://github.com/hyperledger/cactus/compare/v1.1.2...v1.1.3) (2022-12-08) - -**Note:** Version bump only for package @hyperledger/cactus-plugin-ledger-connector-sawtooth-socketio - -## [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-sawtooth-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-sawtooth-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 - -* **sawtooth-ledger:** add single sawtooth test ledger image ([cd4c746](https://github.com/hyperledger/cactus/commit/cd4c7460f6e005ce56a0d79edea6f609756bf9d5)), closes [#2108](https://github.com/hyperledger/cactus/issues/2108) [#2030](https://github.com/hyperledger/cactus/issues/2030) -* **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) -* **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) - -**Note:** Version bump only for package @hyperledger/cactus-plugin-ledger-connector-sawtooth-socketio - -# [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-sawtooth-socketio - -# [1.0.0-rc.1](https://github.com/hyperledger/cactus/compare/v0.10.0...v1.0.0-rc.1) (2021-10-11) - -### Bug Fixes - -* **cmd-socker-server:** delete unnecessary files on cmd-socker-server ([20e15cd](https://github.com/hyperledger/cactus/commit/20e15cd257628fe392818e14728851304a76c7cb)) - -### Features - -* **connector-sawtooth:** add the docker environment of Validator on connector-sawtooth-socketio ([7a57ea4](https://github.com/hyperledger/cactus/commit/7a57ea4adeb84bdf00bf32472ceac68fd43dc52d)) - -# [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-sawtooth-socketio/Dockerfile b/packages/cactus-plugin-ledger-connector-sawtooth-socketio/Dockerfile deleted file mode 100644 index 75c03ba5a9..0000000000 --- a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM cactus-cmd-socketio-server:latest - -ENV CACTUS_CONNECTOR_SAWTOOTH_PATH=/opt/cactus-plugin-ledger-connector-sawtooth-socketio - -WORKDIR ${CACTUS_CONNECTOR_SAWTOOTH_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 5140 -VOLUME ["/etc/cactus/"] -CMD [ "npm", "run", "start" ] diff --git a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/README.md b/packages/cactus-plugin-ledger-connector-sawtooth-socketio/README.md deleted file mode 100644 index 7e1426505e..0000000000 --- a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/README.md +++ /dev/null @@ -1,86 +0,0 @@ - -# `@hyperledger/cactus-plugin-ledger-connector-sawtooth-socketio` - -This plugin provides `Cactus` a way to interact with Hyperledger Sawtooth networks. Using this we can perform: -- `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: Linux (recommended Ubuntu20.04,18.04 or 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: [sawtooth-all-in-one](../../tools/docker/sawtooth-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!** - ``` - mkdir -p /etc/cactus/connector-sawtooth-socketio/ - rm -r /etc/cactus/connector-sawtooth-socketio/* - cp -rf ./sample-config/* /etc/cactus/connector-sawtooth-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-sawtooth-socketio - -# Run -docker run -v/etc/cactus/:/etc/cactus -p 5140:5140 cactus-plugin-ledger-connector-sawtooth-socketio -``` - -### Manual -- Ensure ledger ports are exposed to the host first. - -``` -npm run start -``` - -## Configuration -- Validator can be configured in `/etc/cactus/connector-sawtooth-socketio/default.yaml` (see [sample-config](./sample-config/default.yaml) for details). -- This configuration can be overwriten in `NODE_CONFIG` environment variable (JSON format). - -## Usage samples -- To confirm the operation of this package, please refer to the following business-logic sample application: - - [cactus-example-electricity-trade](../../examples/cactus-example-electricity-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-sawtooth-socketio/package.json b/packages/cactus-plugin-ledger-connector-sawtooth-socketio/package.json deleted file mode 100644 index 38ada91c64..0000000000 --- a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/package.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "name": "@hyperledger/cactus-plugin-ledger-connector-sawtooth-socketio", - "version": "2.0.0-alpha.2", - "description": "Allows Cactus nodes to connect to a Sawtooth ledger", - "keywords": [ - "Hyperledger", - "Cactus", - "Integration", - "Blockchain", - "Distributed Ledger Technology" - ], - "homepage": "https://github.com/hyperledger/cacti#readme", - "bugs": { - "url": "https://github.com/hyperledger/cacti/issues" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/hyperledger/cacti.git" - }, - "license": "Apache-2.0", - "author": { - "name": "Hyperledger Cactus Contributors", - "email": "cactus@lists.hyperledger.org", - "url": "https://www.hyperledger.org/use/cacti" - }, - "contributors": [ - { - "name": "Please add yourself to the list of contributors", - "email": "your.name@example.com", - "url": "https://example.com" - } - ], - "main": "dist/lib/main/typescript/index.js", - "module": "dist/lib/main/typescript/index.js", - "types": "dist/lib/main/typescript/index.d.ts", - "files": [ - "dist/*" - ], - "scripts": { - "build": "npm run build-ts && npm run build:dev:backend:postbuild", - "build-ts": "tsc", - "build:dev:backend:postbuild": "npm run init-sawtooth", - "debug": "nodemon --inspect ./dist/common/core/bin/www.js", - "init-sawtooth": "cp -af ../../yarn.lock ./dist/lib/yarn.lock", - "start": "cd ./dist && node common/core/bin/www.js" - }, - "dependencies": { - "@hyperledger/cactus-cmd-socketio-server": "2.0.0-alpha.2", - "@types/node": "14.18.54", - "body-parser": "1.20.2", - "cbor": "6.0.1", - "cookie-parser": "1.4.6", - "debug": "3.1.0", - "express": "4.18.2", - "js-yaml": "3.14.1", - "jsonwebtoken": "9.0.0", - "log4js": "6.4.1", - "morgan": "1.10.0", - "serve-favicon": "2.4.5", - "shelljs": "0.8.5", - "socket.io": "4.5.4", - "xmlhttprequest": "1.8.0" - }, - "devDependencies": { - "@hyperledger/cactus-api-client": "2.0.0-alpha.2", - "@hyperledger/cactus-common": "2.0.0-alpha.2", - "@hyperledger/cactus-test-tooling": "2.0.0-alpha.2", - "@types/body-parser": "1.19.3", - "@types/config": "0.0.41", - "@types/cookie-parser": "1.4.3", - "@types/express": "4.17.19", - "@types/http-errors": "2.0.1" - }, - "engines": { - "node": ">=10", - "npm": ">=6" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/sample-config/default.yaml b/packages/cactus-plugin-ledger-connector-sawtooth-socketio/sample-config/default.yaml deleted file mode 100644 index 07b508c496..0000000000 --- a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/sample-config/default.yaml +++ /dev/null @@ -1,13 +0,0 @@ -sslParam: - port: 5140 - key: "/etc/cactus/connector-sawtooth-socketio/CA/connector.priv" - cert: "/etc/cactus/connector-sawtooth-socketio/CA/connector.crt" -blockMonitor: - request: - method: "GET" - host: "http://sawtooth_all_in_one_ledger_1x:8008/" - getLatestBlockNumberCommand: "blocks?limit=1" - periodicMonitoringCommand1: "blocks?start=" - periodicMonitoringCommand2: "&reverse" - pollingInterval: 5000 -logLevel: "debug" \ No newline at end of file diff --git a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/common/core/app.ts b/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/common/core/app.ts deleted file mode 100644 index b86a7e295f..0000000000 --- a/packages/cactus-plugin-ledger-connector-sawtooth-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, RequestHandler } 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() as RequestHandler); - -// catch 404 and forward to error handler -app.use((req: Request, res: Response, next: NextFunction) => { - 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(errorResponse); - } -); - -export default app; diff --git a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/common/core/bin/www.ts b/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/common/core/bin/www.ts deleted file mode 100755 index 785f23e9ca..0000000000 --- a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/common/core/bin/www.ts +++ /dev/null @@ -1,161 +0,0 @@ -#!/usr/bin/env node - -/* - * Copyright 2022 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * www.js - */ - -/* Summary: - * Connector: a part independent of end-chains - */ - -/** - * Module dependencies. - */ - -import app from "../app"; -import https = require("https"); - -// Overwrite config read path -export const DEFAULT_NODE_CONFIG_DIR = - "/etc/cactus/connector-sawtooth-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'); - -// destination dependency (MONITOR) implementation class -import { ServerMonitorPlugin } from "../../../connector/ServerMonitorPlugin"; - -// 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; -} - -export async function startSawtoothSocketIOConnector() { - 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": - console.error(bind + " requires elevated privileges"); - process.exit(1); - case "EADDRINUSE": - console.error(bind + " is already in use"); - process.exit(1); - default: - throw error; - } - }); - - io.on("connection", function (client) { - logger.info("Client " + client.id + " connected."); - - // startMonitor: starting block generation event monitoring - client.on("startMonitor", function (data) { - - if (!data || !data.filterKey) { - client.emit("error", { - status: 400, - errorDetail: "filterKey is required for startMonitor on sawtooth ledger", - }); - } - - Smonitor.startMonitor(client.id, data.filterKey, (callbackData) => { - let emitType = ""; - if (callbackData.status == 200) { - emitType = "eventReceived"; - logger.info("event data callbacked."); - } else { - emitType = "monitor_error"; - } - client.emit(emitType, callbackData); - }); - }); - - - client.on("stopMonitor", function () { - Smonitor.stopMonitor(client.id); - }); - - client.on("disconnect", function (reason) { - 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))); -} - -if (require.main === module) { - // When this file executed as a script, not loaded as module - run the connector - startSawtoothSocketIOConnector().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 sawtooth-socketio connector:", err); - }); -} diff --git a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/connector/PluginUtil.ts b/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/connector/PluginUtil.ts deleted file mode 100644 index 8b607e56d4..0000000000 --- a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/connector/PluginUtil.ts +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * PluginUtil.js - */ - -const cbor = require("cbor"); - -/* - * Summary: - * Cooperation server: utility library dependent on endchains - * For example, implementing internal functions that should not be exposed as functions of server plugins. - */ - -/* - * convNum - * - * @param {String/Number} value: The scientific string or numeric value to be converted. For numbers, it is returned as is. - * @param {String/Number} defaultValue: The value to use if conversion was not possible. Text or number in scientific notation. Optional. - * - * @return {Number} The value converted to a number, or the defaultValue if the conversion failed. - * - * @desc exponentiation is also supported. The following formats are supported:. (value, defaultValue) - * 3.78*10^14 - * 3.78e14 - */ -exports.convNum = function convNum(value: number | string, defaultValue: number | string) { - let retValue = 0; - let defValue = 0; - - switch (typeof defaultValue) { - case "number": - defValue = defaultValue; - break; - case "string": - const defValueStr = defaultValue.replace(/\*10\^/g, "e"); - defValue = parseFloat(defValueStr); - break; - default: - // undefined should also be included here. - // Fixed value because of cumbersome handling. - defValue = 0; - break; - } // switch(typeof(defaultValue)) - - if (Number.isNaN(defValue)) { - // number is guaranteed. - defValue = 0; - } - - switch (typeof value) { - case "number": - retValue = value; - break; - case "string": - const valueStr = value.replace(/\*10\^/g, "e"); - retValue = parseFloat(valueStr); - break; - default: - // Set default value. - retValue = defValue; - break; - } // switch(typeof(value)) - - if (Number.isNaN(retValue)) { - // number is guaranteed. - retValue = defValue; - } - - return retValue; -}; - -exports.convertBlockNumber = function (value: number) { - return "0x" + ("0000000000000000" + value.toString(16)).substr(-16); -}; - -exports.decodeBase64 = function (encoded: string): Buffer { - return Buffer.from(encoded, "base64"); -}; - -exports.deccodeCbor = function (encoded: any): Array { - return cbor.decodeAllSync(encoded); -}; diff --git a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/connector/ServerMonitorPlugin.ts b/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/connector/ServerMonitorPlugin.ts deleted file mode 100644 index 242fee0ec7..0000000000 --- a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/connector/ServerMonitorPlugin.ts +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2021 Hyperledger Cactus Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * ServerMonitorPlugin.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 SplugUtil = require("./PluginUtil"); -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"); -const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest; - -export type MonitorCallback = (callback: { - status: number; - blockData: string; -}) => void; - -/* - * ServerMonitorPlugin - * Class definitions of server monitoring - */ -export class ServerMonitorPlugin { - currentBlockNumber = -1; - runningMonitors = new Map>(); - - /* - * startMonitor - * Start Monitoring - * @param {string} clientId: Client ID from which monitoring start request was made - * @param {string} filterKey: Key to filter blocks - * @param {function} cb: A callback function that receives monitoring results at any time. - */ - startMonitor(clientId: string, filterKey: string, cb: MonitorCallback) { - logger.info("*** START MONITOR ***"); - logger.info("Client ID :" + clientId); - logger.debug(`filterKey = ${filterKey}`); - - const that = this; - const httpReq = new XMLHttpRequest(); - httpReq.onload = function () { - const responseObj = JSON.parse(httpReq.responseText); - that.currentBlockNumber = parseInt(responseObj.data[0].header.block_num); - logger.debug(`responseObj = ${JSON.stringify(responseObj)}`); - logger.debug(`currentBlockNumber = ${that.currentBlockNumber}`); - that.periodicMonitoring(clientId, filterKey, cb); - } - - const method = configRead("blockMonitor.request.method"); - const latestBlockURL = new URL( - configRead("blockMonitor.request.getLatestBlockNumberCommand"), - configRead("blockMonitor.request.host")) - .toString(); - logger.debug("latestBlockURL:", latestBlockURL); - - httpReq.open( - method, - latestBlockURL, - ); - - httpReq.send(); - } - - /* - * periodicMonitoring - * Periodic monitoring - * @param {string} clientId: Client ID from which monitoring start request was made - * @param {string} filterKey: Key to filter blocks - * @param {function} cb: A callback function that receives monitoring results at any time. - */ - periodicMonitoring(clientId: string, filterKey: string, cb: MonitorCallback) { - logger.info("*** START PERIODIC MONITORING ***"); - - const that = this; - - const httpReq = new XMLHttpRequest(); - httpReq.onload = function () { - const responseObj = JSON.parse(httpReq.responseText); - logger.debug(`responseObj = ${JSON.stringify(responseObj)}`); - - let newBlockNumber = -1; - for (const blockData of responseObj.data) { - const targetBlockNumber = parseInt(blockData.header.block_num); - if (targetBlockNumber === that.currentBlockNumber) { - continue; - } - const transactionDataArray = []; - for (const batchData of blockData.batches) { - logger.debug( - `transaction_ids.length = ${batchData.header.transaction_ids.length}`, - ); - if (batchData.header.transaction_ids.length < 1) { - logger.debug(`skip block (No transactions) = ${targetBlockNumber}`); - continue; - } - for (const transactionData of batchData.transactions) { - if (transactionData.header.family_name !== filterKey) { - logger.debug( - `skip transaction (Not target) = ${transactionData.header_signature}`, - ); - continue; - } - const transactionDataPlus = Object.assign({}, transactionData); - transactionDataPlus["payload_decoded"] = SplugUtil.deccodeCbor( - SplugUtil.decodeBase64(transactionData.payload), - ); - transactionDataArray.push(transactionDataPlus); - } - } - if (newBlockNumber < targetBlockNumber) { - newBlockNumber = targetBlockNumber; - } - if (transactionDataArray.length > 0) { - logger.info("*** SEND TRANSACTION DATA ***"); - logger.debug( - `transactionDataArray = ${JSON.stringify(transactionDataArray)}`, - ); - const signedTransactionDataArray = signMessageJwt({ - blockData: transactionDataArray, - }); - logger.debug( - `signedTransactionDataArray = ${signedTransactionDataArray}`, - ); - const retObj = { - status: 200, - blockData: signedTransactionDataArray, - }; - - if (that.runningMonitors.has(clientId)) { - cb(retObj); - } else { - logger.info("Monitoring seems to be stopped - don't send the response! ClientID:", clientId); - } - } - } - - if (that.currentBlockNumber < newBlockNumber) { - that.currentBlockNumber = newBlockNumber; - } - logger.debug(`currentBlockNumber = ${that.currentBlockNumber}`); - }; - - const timerBlockMonitoring = setInterval(function () { - const newBlocksPath = - configRead("blockMonitor.request.periodicMonitoringCommand1") + - SplugUtil.convertBlockNumber(that.currentBlockNumber) + - configRead("blockMonitor.request.periodicMonitoringCommand2"); - const newBlocksUrl = new URL( - newBlocksPath, - configRead("blockMonitor.request.host")) - .toString(); - logger.debug(`newBlocksUrl = ${newBlocksUrl}`); - - httpReq.open(configRead("blockMonitor.request.method"), newBlocksUrl); - httpReq.send(); - }, configRead("blockMonitor.pollingInterval")); - - this.runningMonitors.set(clientId, timerBlockMonitoring); - } - - /** - * Stop monitor for given client. - * - * @param {string} clientId: Client ID from which monitoring stop request was made - */ - stopMonitor(clientId: string) { - let monitorInterval = this.runningMonitors.get(clientId); - if (monitorInterval) { - logger.info("stop watching and remove interval."); - clearInterval(monitorInterval); - this.runningMonitors.delete(clientId); - } - } -} diff --git a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/index.ts b/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/index.ts deleted file mode 100644 index 87cb558397..0000000000 --- a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./public-api"; diff --git a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/public-api.ts b/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/public-api.ts deleted file mode 100644 index 089662c6b7..0000000000 --- a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/main/typescript/public-api.ts +++ /dev/null @@ -1 +0,0 @@ -export { startSawtoothSocketIOConnector } from "./common/core/bin/www" diff --git a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/test/typescript/integration/sawtooth-socketio-connector.test.ts b/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/test/typescript/integration/sawtooth-socketio-connector.test.ts deleted file mode 100644 index a0b2ed893e..0000000000 --- a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/src/test/typescript/integration/sawtooth-socketio-connector.test.ts +++ /dev/null @@ -1,244 +0,0 @@ -/** - * Functional test of basic operations on sawtooth connector (packages/cactus-plugin-ledger-connector-sawtooth-socketio). - */ - -////////////////////////////////// -// Constants -////////////////////////////////// - -const testLogLevel: LogLevelDesc = "info"; -const sutLogLevel: LogLevelDesc = "info"; -const testTimeout = 1000 * 2 * 60; // 2 minutes timeout for some tests -const setupTimeout = 1000 * 3 * 60; // 3 minutes timeout for setup - -// Ledger settings -const containerImageName = "ghcr.io/hyperledger/cactus-sawtooth-all-in-one"; -const containerImageVersion = "2022-11-21-9da24a0"; -const useRunningLedger = false; - -// Use for development on local sawtooth network -// const containerImageName = "sawtooth_aio_1x"; -// const containerImageVersion = "1.0.0"; -// const useRunningLedger = true; - -// ApiClient settings -const syncReqTimeout = 1000 * 10; // 10 seconds - -import { - SawtoothTestLedger, - SelfSignedPkiGenerator, - pruneDockerAllIfGithubAction, -} from "@hyperledger/cactus-test-tooling"; - -import { - LogLevelDesc, - LoggerProvider, - Logger, -} from "@hyperledger/cactus-common"; - -import { SocketIOApiClient } from "@hyperledger/cactus-api-client"; - -import "jest-extended"; -import { Server as HttpsServer } from "https"; - -// Logger setup -const log: Logger = LoggerProvider.getOrCreate({ - label: "sawtooth-socketio-connector.test", - level: testLogLevel, -}); - -describe("Sawtooth-SocketIO connector tests", () => { - let ledger: SawtoothTestLedger; - let connectorPrivKeyValue: string; - let connectorCertValue: string; - let connectorServer: HttpsServer; - let apiClient: SocketIOApiClient; - - ////////////////////////////////// - // Environment Setup - ////////////////////////////////// - - beforeAll(async () => { - log.info("Prune Docker..."); - await pruneDockerAllIfGithubAction({ logLevel: testLogLevel }); - - log.info(`Start Ledger ${containerImageName}:${containerImageVersion}...`); - ledger = new SawtoothTestLedger({ - containerImageName, - containerImageVersion, - emitContainerLogs: false, - logLevel: sutLogLevel, - useRunningLedger, - }); - await ledger.start(); - const ledgerRestApi = await ledger.getRestApiHost(); - log.info(`Ledger started, API: ${ledgerRestApi}`); - - // Generate connector private key and certificate - const pkiGenerator = new SelfSignedPkiGenerator(); - const pki = pkiGenerator.create("localhost"); - connectorPrivKeyValue = pki.privateKeyPem; - connectorCertValue = pki.certificatePem; - const jwtAlgo = "RS512"; - - const connectorConfig: any = { - sslParam: { - port: 0, // random port - keyValue: connectorPrivKeyValue, - certValue: connectorCertValue, - jwtAlgo: jwtAlgo, - }, - blockMonitor: { - request: { - method: "GET", - host: ledgerRestApi, - getLatestBlockNumberCommand: "blocks?limit=1", - periodicMonitoringCommand1: "blocks?start=", - periodicMonitoringCommand2: "&reverse", - }, - pollingInterval: 5000 - }, - logLevel: sutLogLevel, - }; - const configJson = JSON.stringify(connectorConfig); - log.debug("Connector Config:", configJson); - - log.info("Export connector config before loading the module..."); - process.env["NODE_CONFIG"] = configJson; - - // Load connector module - const connectorModule = await import("../../../main/typescript/index"); - - // Run the connector - connectorServer = await connectorModule.startSawtoothSocketIOConnector(); - expect(connectorServer).toBeTruthy(); - const connectorAddress = connectorServer.address(); - if (!connectorAddress || typeof connectorAddress === "string") { - throw new Error("Unexpected sawtooth connector AddressInfo type"); - } - log.info( - "Sawtooth-SocketIO Connector started on:", - `${connectorAddress.address}:${connectorAddress.port}`, - ); - - // Create ApiClient instance - const apiConfigOptions = { - validatorID: "sawtooth-socketio-test", - validatorURL: `https://localhost:${connectorAddress.port}`, - validatorKeyValue: connectorCertValue, - logLevel: sutLogLevel, - maxCounterRequestID: 1000, - syncFunctionTimeoutMillisecond: syncReqTimeout, - socketOptions: { - rejectUnauthorized: false, - reconnection: false, - timeout: syncReqTimeout * 2, - }, - }; - log.debug("ApiClient config:", apiConfigOptions); - apiClient = new SocketIOApiClient(apiConfigOptions); - }, setupTimeout); - - afterAll(async () => { - log.info("FINISHING THE TESTS"); - - if (apiClient) { - log.info("Close ApiClient connection..."); - apiClient.close(); - } - - if (connectorServer) { - log.info("Stop the sawtooth connector..."); - await new Promise((resolve) => - connectorServer.close(() => resolve()), - ); - } - - if (ledger) { - log.info("Stop the sawtooth ledger..."); - await ledger.stop(); - await ledger.destroy(); - } - - // SocketIOApiClient has timeout running for each request which is not cancellable at the moment. - // Wait timeout amount of seconds to make sure all handles are closed. - await new Promise((resolve) => setTimeout(resolve, syncReqTimeout)) - - log.info("Prune Docker..."); - await pruneDockerAllIfGithubAction({ logLevel: testLogLevel }); - }, setupTimeout); - - ////////////////////////////////// - // Tests - ////////////////////////////////// - - /** - * Simple test to see if test sawtooth ledger is running correctly and required API is available. - * Will set and retrieve intkey value. - * Doesn't use apiClient or validator. - */ - test("Sanity check ledger connection", async () => { - const keyName = "sanityCheck"; - const keyValue = "42"; - - // Set key - const setResponse = JSON.parse(await ledger.runSawtoothShell(["intkey", "set", keyName, keyValue])); - log.debug("setResponse:", setResponse); - const setStatus = await ledger.waitOnTransaction(setResponse.link); - log.info("setStatus:", setStatus); - expect(setStatus).not.toEqual("PENDING"); // TX should be commited - - // Show key - const showResponse = await ledger.runSawtoothShell(["intkey", "show", keyName]); - log.info("showResponse:", showResponse); - expect(showResponse).toContain(keyName); - expect(showResponse).toContain(keyValue); - }); - - /** - * Test ServerMonitorPlugin startMonitor/stopMonitor functions. - */ - test("Monitoring returns new block", async () => { - // Create monitoring promise and subscription - let monitorSub: any; - const newBlockPromise = new Promise((resolve, reject) => { - monitorSub = apiClient.watchBlocksV1({ - filterKey: "intkey" - }).subscribe({ - next: block => resolve(block), - error: err => reject(err), - complete: () => reject("Unexpected watchBlocksV1 completion - reject."), - }); - }); - - // Keep adding new keys until block was received - try { - let keyId = 1; - while (keyId++) { // infinite loop - // Set new key - const keyName = "monitorTest" + keyId; - await ledger.runSawtoothShell(["intkey", "set", keyName, "42"]); - await ledger.runSawtoothShell(["intkey", "inc", keyName, "11"]); - const sleepPromise: Promise = new Promise((resolve) => setTimeout(resolve, 2000)) - - // Wait for 2 seconds or for new block to arrive - const resolvedValue = await Promise.race([newBlockPromise, sleepPromise]); - log.debug("Monitor: resolvedValue", resolvedValue); - if (resolvedValue && resolvedValue!.blockData) { - log.info("Resolved watchBlock promise"); - expect(resolvedValue.status).toEqual(200); - expect(resolvedValue.blockData).toBeTruthy(); - break; - } - } - } catch (error) { - throw error; - } finally { - if (monitorSub) { - monitorSub.unsubscribe(); - } else { - log.warn("monitorSub was not valid, could not unsubscribe"); - } - } - }, testTimeout); -}); diff --git a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/tsconfig.json b/packages/cactus-plugin-ledger-connector-sawtooth-socketio/tsconfig.json deleted file mode 100644 index b223436d86..0000000000 --- a/packages/cactus-plugin-ledger-connector-sawtooth-socketio/tsconfig.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "rootDir": "./src", - "composite": true, - "outDir": "./dist/lib", - "sourceMap": false, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "tsBuildInfoFile": "../../.build-cache/cactus-plugin-ledger-connector-sawtooth-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", - "./src/test/typescript/integration/*.ts" - ], - "references": [ - { - "path": "../cactus-cmd-socketio-server/tsconfig.json" - }, - { - "path": "../cactus-test-tooling/tsconfig.json" - }, - { - "path": "../cactus-common/tsconfig.json" - }, - { - "path": "../cactus-api-client/tsconfig.json" - } - ] -} diff --git a/tsconfig.json b/tsconfig.json index 6098243927..318ab009df 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -115,9 +115,6 @@ { "path": "./packages/cactus-plugin-ledger-connector-sawtooth/tsconfig.json" }, - { - "path": "./packages/cactus-plugin-ledger-connector-sawtooth-socketio/tsconfig.json" - }, { "path": "./packages/cactus-test-tooling/tsconfig.json" }, diff --git a/yarn.lock b/yarn.lock index 996aac2907..4507415d30 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7229,6 +7229,7 @@ __metadata: "@hyperledger/cactus-core-api": 2.0.0-alpha.2 "@hyperledger/cactus-plugin-keychain-memory": 2.0.0-alpha.2 "@hyperledger/cactus-plugin-ledger-connector-ethereum": 2.0.0-alpha.2 + "@hyperledger/cactus-plugin-ledger-connector-sawtooth": 2.0.0-alpha.2 "@hyperledger/cactus-verifier-client": 2.0.0-alpha.2 "@types/escape-html": 1.0.1 "@types/express": 4.17.19 @@ -7924,36 +7925,6 @@ __metadata: languageName: unknown linkType: soft -"@hyperledger/cactus-plugin-ledger-connector-sawtooth-socketio@workspace:packages/cactus-plugin-ledger-connector-sawtooth-socketio": - version: 0.0.0-use.local - resolution: "@hyperledger/cactus-plugin-ledger-connector-sawtooth-socketio@workspace:packages/cactus-plugin-ledger-connector-sawtooth-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/body-parser": 1.19.3 - "@types/config": 0.0.41 - "@types/cookie-parser": 1.4.3 - "@types/express": 4.17.19 - "@types/http-errors": 2.0.1 - "@types/node": 14.18.54 - body-parser: 1.20.2 - cbor: 6.0.1 - cookie-parser: 1.4.6 - debug: 3.1.0 - express: 4.18.2 - js-yaml: 3.14.1 - jsonwebtoken: 9.0.0 - log4js: 6.4.1 - morgan: 1.10.0 - serve-favicon: 2.4.5 - shelljs: 0.8.5 - socket.io: 4.5.4 - xmlhttprequest: 1.8.0 - languageName: unknown - linkType: soft - "@hyperledger/cactus-plugin-ledger-connector-sawtooth@2.0.0-alpha.2, @hyperledger/cactus-plugin-ledger-connector-sawtooth@workspace:packages/cactus-plugin-ledger-connector-sawtooth": version: 0.0.0-use.local resolution: "@hyperledger/cactus-plugin-ledger-connector-sawtooth@workspace:packages/cactus-plugin-ledger-connector-sawtooth"