diff --git a/packages/cactus-plugin-ledger-connector-quorum/package.json b/packages/cactus-plugin-ledger-connector-quorum/package.json index e2ae8b9e4d..e62e8f0d5c 100644 --- a/packages/cactus-plugin-ledger-connector-quorum/package.json +++ b/packages/cactus-plugin-ledger-connector-quorum/package.json @@ -70,6 +70,7 @@ "socket.io-client": "4.5.4", "typescript-optional": "2.0.1", "web3": "1.6.1", + "web3-core-helpers": "1.6.1", "web3-eth-contract": "1.6.1", "web3-utils": "1.6.1", "web3js-quorum": "22.4.0" diff --git a/packages/cactus-plugin-ledger-connector-quorum/src/main/typescript/plugin-ledger-connector-quorum.ts b/packages/cactus-plugin-ledger-connector-quorum/src/main/typescript/plugin-ledger-connector-quorum.ts index 5884e95770..8ee1bec286 100644 --- a/packages/cactus-plugin-ledger-connector-quorum/src/main/typescript/plugin-ledger-connector-quorum.ts +++ b/packages/cactus-plugin-ledger-connector-quorum/src/main/typescript/plugin-ledger-connector-quorum.ts @@ -12,6 +12,10 @@ import Web3JsQuorum, { ISendRawTransaction, IPrivateTransactionReceipt, } from "web3js-quorum"; +import { + WebsocketProviderOptions, + HttpProviderOptions, +} from "web3-core-helpers"; import { AbiItem } from "web3-utils"; import { Contract } from "web3-eth-contract"; import { ContractSendMethod } from "web3-eth-contract"; @@ -84,6 +88,8 @@ export interface IPluginLedgerConnectorQuorumOptions prometheusExporter?: PrometheusExporter; pluginRegistry: PluginRegistry; privateUrl?: string; + wsProviderOptions?: WebsocketProviderOptions; + httpProviderOptions?: HttpProviderOptions; } export class PluginLedgerConnectorQuorum @@ -113,9 +119,20 @@ export class PluginLedgerConnectorQuorum private getWeb3Provider() { if (!this.options.rpcApiWsHost) { - return new Web3.providers.HttpProvider(this.options.rpcApiHttpHost); - } - return new Web3.providers.WebsocketProvider(this.options.rpcApiWsHost); + return this.options.httpProviderOptions + ? new Web3.providers.HttpProvider( + this.options.rpcApiHttpHost, + this.options.httpProviderOptions, + ) + : new Web3.providers.HttpProvider(this.options.rpcApiHttpHost); + } + + return this.options.wsProviderOptions + ? new Web3.providers.WebsocketProvider( + this.options.rpcApiWsHost, + this.options.wsProviderOptions, + ) + : new Web3.providers.WebsocketProvider(this.options.rpcApiWsHost); } constructor(public readonly options: IPluginLedgerConnectorQuorumOptions) { diff --git a/packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/v21.4.1-invoke-web3-method-v1.test.ts b/packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/v21.4.1-invoke-web3-method-v1.test.ts index 5b897746fa..6ff2ee0cbb 100644 --- a/packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/v21.4.1-invoke-web3-method-v1.test.ts +++ b/packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/v21.4.1-invoke-web3-method-v1.test.ts @@ -51,7 +51,9 @@ describe("invokeRawWeb3EthMethod Tests", () => { await quorumTestLedger.start(); const rpcApiHttpHost = await quorumTestLedger.getRpcApiHttpHost(); - log.debug("rpcApiHttpHost:", rpcApiHttpHost); + const getRpcApiWsHost = await quorumTestLedger.getRpcApiWsHost(); + log.warn("rpcApiHttpHost:", rpcApiHttpHost); + log.warn("getRpcApiWsHost:", getRpcApiWsHost); log.info("Create PluginLedgerConnectorQuorum..."); connector = new PluginLedgerConnectorQuorum({ diff --git a/packages/cactus-test-plugin-ledger-connector-quorum/src/test/typescript/integration/api-client/verifier-integration-with-quorum-connector.test.ts b/packages/cactus-test-plugin-ledger-connector-quorum/src/test/typescript/integration/api-client/verifier-integration-with-quorum-connector.test.ts index d0fae5441a..1e86af0deb 100644 --- a/packages/cactus-test-plugin-ledger-connector-quorum/src/test/typescript/integration/api-client/verifier-integration-with-quorum-connector.test.ts +++ b/packages/cactus-test-plugin-ledger-connector-quorum/src/test/typescript/integration/api-client/verifier-integration-with-quorum-connector.test.ts @@ -18,6 +18,7 @@ import "jest-extended"; import lodash from "lodash"; import { v4 as uuidv4 } from "uuid"; import Web3 from "web3"; +import { WebsocketProviderOptions } from "web3-core-helpers"; import { AbiItem } from "web3-utils"; import { PluginRegistry } from "@hyperledger/cactus-core"; import { @@ -112,9 +113,19 @@ describe("Verifier integration with quorum connector tests", () => { plugins.push(keychainPlugin); log.info("Create PluginLedgerConnectorQuorum..."); + + const wsProviderOptions: WebsocketProviderOptions = { + clientConfig: { + // Useful if requests are large + maxReceivedFrameSize: 100000000, + maxReceivedMessageSize: 100000000, + }, + }; + connector = new PluginLedgerConnectorQuorum({ rpcApiHttpHost: connectionProfile.quorum.member1.url, rpcApiWsHost: connectionProfile.quorum.member1.wsUrl, + wsProviderOptions: wsProviderOptions, logLevel: sutLogLevel, instanceId: uuidv4(), pluginRegistry: new PluginRegistry({ plugins: [keychainPlugin] }), @@ -270,6 +281,26 @@ describe("Verifier integration with quorum connector tests", () => { }; }); + test("Using verifier for calling getBlock method works", async () => { + const correctContract = {}; + const correctMethod = { + type: "web3Eth", + command: "getBlock", + }; + + const correctArgs: any = { args: ["latest"] }; + + const resultCorrect = await verifier.sendSyncRequest( + correctContract, + correctMethod, + correctArgs, + ); + + log.warn("verifier", verifier); + log.warn("###Results", resultCorrect); + // expect(resultCorrect.status).toEqual(200); + }); + test("Invalid web3EthContract calls are rejected by QuorumApiClient", async () => { // Define correct input parameters const correctContract: Record = lodash.clone( @@ -500,6 +531,7 @@ describe("Verifier integration with quorum connector tests", () => { methodCall, argsCall, ); + log.error(resultsCall); expect(resultsCall.status).toEqual(200); expect(resultsCall.data).toEqual(newName); }); diff --git a/packages/cactus-test-tooling/src/main/typescript/quorum/quorum-test-ledger.ts b/packages/cactus-test-tooling/src/main/typescript/quorum/quorum-test-ledger.ts index eb28870515..d89e7dfebe 100644 --- a/packages/cactus-test-tooling/src/main/typescript/quorum/quorum-test-ledger.ts +++ b/packages/cactus-test-tooling/src/main/typescript/quorum/quorum-test-ledger.ts @@ -23,6 +23,7 @@ export interface IQuorumTestLedgerConstructorOptions { containerImageVersion?: string; containerImageName?: string; rpcApiHttpPort?: number; + rpcApiWsPort?: number; logLevel?: LogLevelDesc; emitContainerLogs?: boolean; readonly envVars?: string[]; @@ -32,6 +33,7 @@ export const QUORUM_TEST_LEDGER_DEFAULT_OPTIONS = Object.freeze({ containerImageVersion: "2021-01-08-7a055c3", containerImageName: "ghcr.io/hyperledger/cactus-quorum-all-in-one", rpcApiHttpPort: 8545, + rpcApiWsPort: 8546, }); export const QUORUM_TEST_LEDGER_OPTIONS_JOI_SCHEMA: Joi.Schema = Joi.object().keys( @@ -51,6 +53,7 @@ export class QuorumTestLedger implements ITestLedger { public readonly containerImageVersion: string; public readonly containerImageName: string; public readonly rpcApiHttpPort: number; + public readonly rpcApiWsPort: number; public readonly emitContainerLogs: boolean; private readonly log: Logger; @@ -73,6 +76,8 @@ export class QuorumTestLedger implements ITestLedger { this.rpcApiHttpPort = options.rpcApiHttpPort || QUORUM_TEST_LEDGER_DEFAULT_OPTIONS.rpcApiHttpPort; + this.rpcApiWsPort = + options.rpcApiWsPort || QUORUM_TEST_LEDGER_DEFAULT_OPTIONS.rpcApiWsPort; this.envVars = options.envVars || []; @@ -102,9 +107,14 @@ export class QuorumTestLedger implements ITestLedger { public async getRpcApiHttpHost(): Promise { const ipAddress = "127.0.0.1"; - const hostPort = await this.getRpcApiPublicPort(); + const hostPort = await this.getRpcHttpApiPublicPort(); return `http://${ipAddress}:${hostPort}`; } + public async getRpcApiWsHost(): Promise { + const ipAddress = "127.0.0.1"; + const hostPort = await this.getRpcWsApiPublicPort(); + return `ws://${ipAddress}:${hostPort}`; + } public async getFileContents(filePath: string): Promise { const response: NodeJS.ReadableStream = await this.getContainer().getArchive( @@ -221,7 +231,7 @@ export class QuorumTestLedger implements ITestLedger { Env: this.envVars, ExposedPorts: { [`${this.rpcApiHttpPort}/tcp`]: {}, // quorum RPC - HTTP - "8546/tcp": {}, // quorum RPC - WebSocket + [`${this.rpcApiWsPort}/tcp`]: {}, // quorum RPC - WebSocket "8888/tcp": {}, // orion Client Port - HTTP "8080/tcp": {}, // orion Node Port - HTTP "9001/tcp": {}, // supervisord - HTTP @@ -339,7 +349,7 @@ export class QuorumTestLedger implements ITestLedger { } } - public async getRpcApiPublicPort(): Promise { + public async getRpcHttpApiPublicPort(): Promise { const fnTag = "QuorumTestLedger#getRpcApiPublicPort()"; const aContainerInfo = await this.getContainerInfo(); const { rpcApiHttpPort: thePort } = this; @@ -362,6 +372,29 @@ export class QuorumTestLedger implements ITestLedger { } } + public async getRpcWsApiPublicPort(): Promise { + const fnTag = "QuorumTestLedger#getRpcWsApiPublicPort()"; + const aContainerInfo = await this.getContainerInfo(); + const { rpcApiWsPort: thePort } = this; + const { Ports: ports } = aContainerInfo; + + if (ports.length < 1) { + throw new Error(`${fnTag} no ports exposed or mapped at all`); + } + const mapping = ports.find((x) => x.PrivatePort === thePort); + if (mapping) { + if (!mapping.PublicPort) { + throw new Error(`${fnTag} port ${thePort} mapped but not public`); + } else if (mapping.IP !== "0.0.0.0") { + throw new Error(`${fnTag} port ${thePort} mapped to localhost`); + } else { + return mapping.PublicPort; + } + } else { + throw new Error(`${fnTag} no mapping found for ${thePort}`); + } + } + public async getContainerIpAddress(): Promise { const fnTag = "QuorumTestLedger#getContainerIpAddress()"; const aContainerInfo = await this.getContainerInfo(); diff --git a/packages/cactus-test-tooling/src/test/typescript/integration/quorum/quorum-test-ledger/constructor-validates-options.test.ts b/packages/cactus-test-tooling/src/test/typescript/integration/quorum/quorum-test-ledger/constructor-validates-options.test.ts index 42cb3d4110..0668843b1c 100644 --- a/packages/cactus-test-tooling/src/test/typescript/integration/quorum/quorum-test-ledger/constructor-validates-options.test.ts +++ b/packages/cactus-test-tooling/src/test/typescript/integration/quorum/quorum-test-ledger/constructor-validates-options.test.ts @@ -35,7 +35,7 @@ tap.test("starts/stops/destroys a docker container", async (assert: any) => { assert.ok(ipAddress); assert.ok(ipAddress.length); - const hostPort: number = await ledger.getRpcApiPublicPort(); + const hostPort: number = await ledger.getRpcHttpApiPublicPort(); assert.ok(hostPort, "getRpcApiPublicPort() returns truthy OK"); assert.ok(isFinite(hostPort), "getRpcApiPublicPort() returns finite OK"); diff --git a/tools/docker/quorum-all-in-one/start-quorum.sh b/tools/docker/quorum-all-in-one/start-quorum.sh index 86e593616c..8ada58b928 100755 --- a/tools/docker/quorum-all-in-one/start-quorum.sh +++ b/tools/docker/quorum-all-in-one/start-quorum.sh @@ -43,6 +43,11 @@ geth \ --http.vhosts "*" \ --http.addr 0.0.0.0 \ --http.port 8545 \ + --ws \ + --wsaddr "0.0.0.0" \ + --wsport "8546" \ + --wsapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum,${QUORUM_CONSENSUS:-raft} \ + --wsorigins "*" \ --http.api admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum,${QUORUM_CONSENSUS:-raft} \ --port 21000 \ --allow-insecure-unlock \ diff --git a/yarn.lock b/yarn.lock index e0106dfccd..2ed4c756cb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6702,6 +6702,7 @@ __metadata: socket.io-client: 4.5.4 typescript-optional: 2.0.1 web3: 1.6.1 + web3-core-helpers: 1.6.1 web3-eth: 1.6.1 web3-eth-contract: 1.6.1 web3-utils: 1.6.1