From 04d719358ddd404588aac1cbe8b37d79923caed1 Mon Sep 17 00:00:00 2001 From: Peter Somogyvari Date: Wed, 26 May 2021 15:50:20 -0700 Subject: [PATCH] feat(connector-quorum): support v21.4.1 and Tessera 21.1.1 #901 Refactored how tests are named so that we can start having a support matrix backed by tests for each permutation needed. The used Quorum version is encoded in the beginning of the test case file name to make them easy to tell apart in logs. Fixes https://github.com/hyperledger/cactus/issues/901 Signed-off-by: Peter Somogyvari --- .../v2.3.0-deploy-contract-from-json.test.ts | 479 ++++++++++++++++++ .../v2.3.0-invoke-contract.test.ts | 397 +++++++++++++++ ...v21.4.1-deploy-contract-from-json.test.ts} | 5 +- ...est.ts => v21.4.1-invoke-contract.test.ts} | 5 +- 4 files changed, 884 insertions(+), 2 deletions(-) create mode 100644 packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/v2.3.0-deploy-contract-from-json.test.ts create mode 100644 packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/v2.3.0-invoke-contract.test.ts rename packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/{deploy-contract-from-json.test.ts => v21.4.1-deploy-contract-from-json.test.ts} (98%) rename packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/{invoke-contract.test.ts => v21.4.1-invoke-contract.test.ts} (97%) diff --git a/packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/v2.3.0-deploy-contract-from-json.test.ts b/packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/v2.3.0-deploy-contract-from-json.test.ts new file mode 100644 index 0000000000..942691d1e8 --- /dev/null +++ b/packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/v2.3.0-deploy-contract-from-json.test.ts @@ -0,0 +1,479 @@ +import test, { Test } from "tape-promise/tape"; +import Web3 from "web3"; +import { v4 as uuidV4 } from "uuid"; + +import { + LogLevelDesc, + IListenOptions, + Servers, +} from "@hyperledger/cactus-common"; + +import { PluginKeychainMemory } from "@hyperledger/cactus-plugin-keychain-memory"; + +import HelloWorldContractJson from "../../../../solidity/hello-world-contract/HelloWorld.json"; + +import { K_CACTUS_QUORUM_TOTAL_TX_COUNT } from "../../../../../main/typescript/prometheus-exporter/metrics"; + +import { + EthContractInvocationType, + PluginLedgerConnectorQuorum, + Web3SigningCredentialCactusKeychainRef, + Web3SigningCredentialType, + DefaultApi as QuorumApi, +} from "../../../../../main/typescript/public-api"; + +import { + QuorumTestLedger, + IQuorumGenesisOptions, + IAccount, + pruneDockerAllIfGithubAction, +} from "@hyperledger/cactus-test-tooling"; +import { PluginRegistry } from "@hyperledger/cactus-core"; + +const testCase = "Quorum Ledger Connector Plugin"; +import express from "express"; +import bodyParser from "body-parser"; +import http from "http"; +import { AddressInfo } from "net"; + +const logLevel: LogLevelDesc = "INFO"; +const contractName = "HelloWorld"; + +test("BEFORE " + testCase, async (t: Test) => { + const pruning = pruneDockerAllIfGithubAction({ logLevel }); + await t.doesNotReject(pruning, "Pruning didn't throw OK"); + t.end(); +}); + +test(testCase, async (t: Test) => { + const containerImageVersion = "2021-01-08-7a055c3"; // Quorum v2.3.0, Tessera v0.10.0 + const containerImageName = "hyperledger/cactus-quorum-all-in-one"; + const ledgerOptions = { containerImageName, containerImageVersion }; + const ledger = new QuorumTestLedger(ledgerOptions); + await ledger.start(); + + test.onFinish(async () => { + await ledger.stop(); + await ledger.destroy(); + }); + + const rpcApiHttpHost = await ledger.getRpcApiHttpHost(); + const quorumGenesisOptions: IQuorumGenesisOptions = await ledger.getGenesisJsObject(); + t.ok(quorumGenesisOptions); + t.ok(quorumGenesisOptions.alloc); + + const highNetWorthAccounts: string[] = Object.keys( + quorumGenesisOptions.alloc, + ).filter((address: string) => { + const anAccount: IAccount = quorumGenesisOptions.alloc[address]; + const theBalance = parseInt(anAccount.balance, 10); + return theBalance > 10e7; + }); + const [firstHighNetWorthAccount] = highNetWorthAccounts; + + const web3 = new Web3(rpcApiHttpHost); + const testEthAccount = web3.eth.accounts.create(uuidV4()); + + const keychainEntryKey = uuidV4(); + const keychainEntryValue = testEthAccount.privateKey; + const keychainPlugin = new PluginKeychainMemory({ + instanceId: uuidV4(), + keychainId: uuidV4(), + // pre-provision keychain with mock backend holding the private key of the + // test account that we'll reference while sending requests with the + // signing credential pointing to this keychain entry. + backend: new Map([[keychainEntryKey, keychainEntryValue]]), + logLevel, + }); + keychainPlugin.set( + HelloWorldContractJson.contractName, + HelloWorldContractJson, + ); + // Instantiate connector with the keychain plugin that already has the + // private key we want to use for one of our tests + const connector: PluginLedgerConnectorQuorum = new PluginLedgerConnectorQuorum( + { + instanceId: uuidV4(), + rpcApiHttpHost, + logLevel, + pluginRegistry: new PluginRegistry({ plugins: [keychainPlugin] }), + }, + ); + + const expressApp = express(); + expressApp.use(bodyParser.json({ limit: "250mb" })); + const server = http.createServer(expressApp); + const listenOptions: IListenOptions = { + hostname: "0.0.0.0", + port: 0, + server, + }; + const addressInfo = (await Servers.listen(listenOptions)) as AddressInfo; + test.onFinish(async () => await Servers.shutdown(server)); + const { address, port } = addressInfo; + const apiHost = `http://${address}:${port}`; + t.comment( + `Metrics URL: ${apiHost}/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-quorum/get-prometheus-exporter-metrics`, + ); + const apiClient = new QuorumApi({ basePath: apiHost }); + + await connector.getOrCreateWebServices(); + await connector.registerWebServices(expressApp); + + await connector.transact({ + web3SigningCredential: { + ethAccount: firstHighNetWorthAccount, + secret: "", + type: Web3SigningCredentialType.GETHKEYCHAINPASSWORD, + }, + transactionConfig: { + from: firstHighNetWorthAccount, + to: testEthAccount.address, + value: 10e9, + }, + }); + + const balance = await web3.eth.getBalance(testEthAccount.address); + t.ok(balance, "Retrieved balance of test account OK"); + t.equals(parseInt(balance, 10), 10e9, "Balance of test account is OK"); + + let contractAddress: string; + + test("deploys contract via .json file", async (t2: Test) => { + const deployOut = await connector.deployContract({ + contractName: HelloWorldContractJson.contractName, + keychainId: keychainPlugin.getKeychainId(), + web3SigningCredential: { + ethAccount: firstHighNetWorthAccount, + secret: "", + type: Web3SigningCredentialType.GETHKEYCHAINPASSWORD, + }, + bytecode: HelloWorldContractJson.bytecode, + gas: 1000000, + }); + t2.ok(deployOut, "deployContract() output is truthy OK"); + t2.ok( + deployOut.transactionReceipt, + "deployContract() output.transactionReceipt is truthy OK", + ); + t2.ok( + deployOut.transactionReceipt.contractAddress, + "deployContract() output.transactionReceipt.contractAddress is truthy OK", + ); + + contractAddress = deployOut.transactionReceipt.contractAddress as string; + t2.ok( + typeof contractAddress === "string", + "contractAddress typeof string OK", + ); + + const { callOutput: helloMsg } = await connector.invokeContract({ + contractName, + contractAbi: HelloWorldContractJson.abi, + contractAddress, + invocationType: EthContractInvocationType.CALL, + methodName: "sayHello", + params: [], + signingCredential: { + ethAccount: firstHighNetWorthAccount, + secret: "", + type: Web3SigningCredentialType.GETHKEYCHAINPASSWORD, + }, + }); + t2.ok(helloMsg, "sayHello() output is truthy"); + t2.true( + typeof helloMsg === "string", + "sayHello() output is type of string", + ); + }); + + test("invoke Web3SigningCredentialType.GETHKEYCHAINPASSWORD", async (t2: Test) => { + const newName = `DrCactus${uuidV4()}`; + const setNameOut = await connector.invokeContract({ + contractName, + contractAbi: HelloWorldContractJson.abi, + contractAddress, + invocationType: EthContractInvocationType.SEND, + methodName: "setName", + params: [newName], + signingCredential: { + ethAccount: firstHighNetWorthAccount, + secret: "", + type: Web3SigningCredentialType.GETHKEYCHAINPASSWORD, + }, + nonce: 2, + }); + t2.ok(setNameOut, "setName() invocation #1 output is truthy OK"); + + try { + const setNameOutInvalid = await connector.invokeContract({ + contractName, + contractAbi: HelloWorldContractJson.abi, + contractAddress, + invocationType: EthContractInvocationType.SEND, + methodName: "setName", + params: [newName], + gas: 1000000, + signingCredential: { + ethAccount: firstHighNetWorthAccount, + secret: "", + type: Web3SigningCredentialType.GETHKEYCHAINPASSWORD, + }, + nonce: 2, + }); + t2.ifError(setNameOutInvalid.transactionReceipt); + } catch (error) { + t2.notStrictEqual( + error, + "Nonce too low", + "setName() invocation with invalid nonce", + ); + } + + const getNameOut = await connector.invokeContract({ + contractName, + contractAbi: HelloWorldContractJson.abi, + contractAddress, + invocationType: EthContractInvocationType.SEND, + methodName: "getName", + params: [], + signingCredential: { + ethAccount: firstHighNetWorthAccount, + secret: "", + type: Web3SigningCredentialType.GETHKEYCHAINPASSWORD, + }, + }); + t2.ok(getNameOut.success, `getName() SEND invocation produced receipt OK`); + + const { callOutput: getNameOut2 } = await connector.invokeContract({ + contractName, + contractAbi: HelloWorldContractJson.abi, + contractAddress, + invocationType: EthContractInvocationType.CALL, + methodName: "getName", + params: [], + signingCredential: { + ethAccount: firstHighNetWorthAccount, + secret: "", + type: Web3SigningCredentialType.GETHKEYCHAINPASSWORD, + }, + }); + t2.equal( + getNameOut2, + newName, + "setName() invocation #2 output is truthy OK", + ); + + t2.end(); + }); + + test("invoke Web3SigningCredentialType.NONE", async (t2: Test) => { + const testEthAccount2 = web3.eth.accounts.create(uuidV4()); + + const { rawTransaction } = await web3.eth.accounts.signTransaction( + { + from: testEthAccount.address, + to: testEthAccount2.address, + value: 10e6, + gas: 1000000, + }, + testEthAccount.privateKey, + ); + + await connector.transact({ + web3SigningCredential: { + type: Web3SigningCredentialType.NONE, + }, + transactionConfig: { + rawTransaction, + }, + }); + + const balance2 = await web3.eth.getBalance(testEthAccount2.address); + t2.ok(balance2, "Retrieved balance of test account 2 OK"); + t2.equals(parseInt(balance2, 10), 10e6, "Balance of test account2 is OK"); + t2.end(); + }); + + test("invoke Web3SigningCredentialType.PRIVATEKEYHEX", async (t2: Test) => { + const newName = `DrCactus${uuidV4()}`; + const setNameOut = await connector.invokeContract({ + contractName, + contractAbi: HelloWorldContractJson.abi, + contractAddress, + invocationType: EthContractInvocationType.SEND, + methodName: "setName", + params: [newName], + signingCredential: { + ethAccount: testEthAccount.address, + secret: testEthAccount.privateKey, + type: Web3SigningCredentialType.PRIVATEKEYHEX, + }, + nonce: 1, + }); + t2.ok(setNameOut, "setName() invocation #1 output is truthy OK"); + + try { + const setNameOutInvalid = await connector.invokeContract({ + contractName, + contractAbi: HelloWorldContractJson.abi, + contractAddress, + invocationType: EthContractInvocationType.SEND, + methodName: "setName", + params: [newName], + gas: 1000000, + signingCredential: { + ethAccount: testEthAccount.address, + secret: testEthAccount.privateKey, + type: Web3SigningCredentialType.PRIVATEKEYHEX, + }, + nonce: 1, + }); + t2.ifError(setNameOutInvalid.transactionReceipt); + } catch (error) { + t2.notStrictEqual( + error, + "Nonce too low", + "setName() invocation with invalid nonce", + ); + } + const { callOutput: getNameOut } = await connector.invokeContract({ + contractName, + contractAbi: HelloWorldContractJson.abi, + contractAddress, + invocationType: EthContractInvocationType.CALL, + methodName: "getName", + params: [], + gas: 1000000, + signingCredential: { + ethAccount: testEthAccount.address, + secret: testEthAccount.privateKey, + type: Web3SigningCredentialType.PRIVATEKEYHEX, + }, + }); + t2.equal(getNameOut, newName, `getName() output reflects the update OK`); + + const getNameOut2 = await connector.invokeContract({ + contractName, + contractAbi: HelloWorldContractJson.abi, + contractAddress, + invocationType: EthContractInvocationType.SEND, + methodName: "getName", + params: [], + gas: 1000000, + signingCredential: { + ethAccount: testEthAccount.address, + secret: testEthAccount.privateKey, + type: Web3SigningCredentialType.PRIVATEKEYHEX, + }, + }); + t2.ok(getNameOut2, "getName() invocation #2 output is truthy OK"); + + t2.end(); + }); + + test("invoke Web3SigningCredentialType.CACTUSKEYCHAINREF", async (t2: Test) => { + const newName = `DrCactus${uuidV4()}`; + + const signingCredential: Web3SigningCredentialCactusKeychainRef = { + ethAccount: testEthAccount.address, + keychainEntryKey, + keychainId: keychainPlugin.getKeychainId(), + type: Web3SigningCredentialType.CACTUSKEYCHAINREF, + }; + + const setNameOut = await connector.invokeContract({ + contractName, + contractAbi: HelloWorldContractJson.abi, + contractAddress, + invocationType: EthContractInvocationType.SEND, + methodName: "setName", + params: [newName], + gas: 1000000, + signingCredential, + nonce: 3, + }); + t2.ok(setNameOut, "setName() invocation #1 output is truthy OK"); + + try { + const setNameOutInvalid = await connector.invokeContract({ + contractName, + contractAbi: HelloWorldContractJson.abi, + contractAddress, + invocationType: EthContractInvocationType.SEND, + methodName: "setName", + params: [newName], + gas: 1000000, + signingCredential: { + ethAccount: firstHighNetWorthAccount, + secret: "", + type: Web3SigningCredentialType.GETHKEYCHAINPASSWORD, + }, + nonce: 3, + }); + t2.ifError(setNameOutInvalid.transactionReceipt); + } catch (error) { + t2.notStrictEqual( + error, + "Nonce too low", + "setName() invocation with invalid nonce", + ); + } + const { callOutput: getNameOut } = await connector.invokeContract({ + contractName, + contractAbi: HelloWorldContractJson.abi, + contractAddress, + invocationType: EthContractInvocationType.CALL, + methodName: "getName", + params: [], + gas: 1000000, + signingCredential, + }); + t2.equal(getNameOut, newName, `getName() output reflects the update OK`); + + const getNameOut2 = await connector.invokeContract({ + contractName, + contractAbi: HelloWorldContractJson.abi, + contractAddress, + invocationType: EthContractInvocationType.SEND, + methodName: "getName", + params: [], + gas: 1000000, + signingCredential, + }); + t2.ok(getNameOut2, "getName() invocation #2 output is truthy OK"); + + t2.end(); + }); + + test("get prometheus exporter metrics", async (t2: Test) => { + const res = await apiClient.getPrometheusExporterMetricsV1(); + const promMetricsOutput = + "# HELP " + + K_CACTUS_QUORUM_TOTAL_TX_COUNT + + " Total transactions executed\n" + + "# TYPE " + + K_CACTUS_QUORUM_TOTAL_TX_COUNT + + " gauge\n" + + K_CACTUS_QUORUM_TOTAL_TX_COUNT + + '{type="' + + K_CACTUS_QUORUM_TOTAL_TX_COUNT + + '"} 5'; + t2.ok(res); + t2.ok(res.data); + t2.equal(res.status, 200); + t2.true( + res.data.includes(promMetricsOutput), + "Total Transaction Count of 5 recorded as expected. RESULT OK.", + ); + t2.end(); + }); + + t.end(); +}); + +test("AFTER " + testCase, async (t: Test) => { + const pruning = pruneDockerAllIfGithubAction({ logLevel }); + await t.doesNotReject(pruning, "Pruning didn't throw OK"); + t.end(); +}); diff --git a/packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/v2.3.0-invoke-contract.test.ts b/packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/v2.3.0-invoke-contract.test.ts new file mode 100644 index 0000000000..f4b06a2f33 --- /dev/null +++ b/packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/v2.3.0-invoke-contract.test.ts @@ -0,0 +1,397 @@ +import test, { Test } from "tape"; +import Web3 from "web3"; +import { v4 as uuidV4 } from "uuid"; + +import { LogLevelDesc } from "@hyperledger/cactus-common"; + +import { PluginKeychainMemory } from "@hyperledger/cactus-plugin-keychain-memory"; + +import HelloWorldContractJson from "../../../../solidity/hello-world-contract/HelloWorld.json"; + +import { + EthContractInvocationType, + PluginLedgerConnectorQuorum, + Web3SigningCredentialCactusKeychainRef, + Web3SigningCredentialType, +} from "../../../../../main/typescript/public-api"; + +import { + QuorumTestLedger, + IQuorumGenesisOptions, + IAccount, +} from "@hyperledger/cactus-test-tooling"; +import { PluginRegistry } from "@hyperledger/cactus-core"; + +const logLevel: LogLevelDesc = "INFO"; +const contractName = "HelloWorld"; + +test("Quorum Ledger Connector Plugin", async (t: Test) => { + const containerImageVersion = "2021-01-08-7a055c3"; // Quorum v2.3.0, Tessera v0.10.0 + const containerImageName = "hyperledger/cactus-quorum-all-in-one"; + const ledgerOptions = { containerImageName, containerImageVersion }; + const ledger = new QuorumTestLedger(ledgerOptions); + await ledger.start(); + + test.onFinish(async () => { + await ledger.stop(); + await ledger.destroy(); + }); + + const rpcApiHttpHost = await ledger.getRpcApiHttpHost(); + const quorumGenesisOptions: IQuorumGenesisOptions = await ledger.getGenesisJsObject(); + t.ok(quorumGenesisOptions); + t.ok(quorumGenesisOptions.alloc); + + const highNetWorthAccounts: string[] = Object.keys( + quorumGenesisOptions.alloc, + ).filter((address: string) => { + const anAccount: IAccount = quorumGenesisOptions.alloc[address]; + const theBalance = parseInt(anAccount.balance, 10); + return theBalance > 10e7; + }); + const [firstHighNetWorthAccount] = highNetWorthAccounts; + + const web3 = new Web3(rpcApiHttpHost); + const testEthAccount = web3.eth.accounts.create(uuidV4()); + + const keychainEntryKey = uuidV4(); + const keychainEntryValue = testEthAccount.privateKey; + const keychainPlugin = new PluginKeychainMemory({ + instanceId: uuidV4(), + keychainId: uuidV4(), + // pre-provision keychain with mock backend holding the private key of the + // test account that we'll reference while sending requests with the + // signing credential pointing to this keychain entry. + backend: new Map([[keychainEntryKey, keychainEntryValue]]), + logLevel, + }); + keychainPlugin.set( + HelloWorldContractJson.contractName, + HelloWorldContractJson, + ); + // Instantiate connector with the keychain plugin that already has the + // private key we want to use for one of our tests + const connector: PluginLedgerConnectorQuorum = new PluginLedgerConnectorQuorum( + { + instanceId: uuidV4(), + rpcApiHttpHost, + logLevel, + pluginRegistry: new PluginRegistry({ plugins: [keychainPlugin] }), + }, + ); + + await connector.transact({ + web3SigningCredential: { + ethAccount: firstHighNetWorthAccount, + secret: "", + type: Web3SigningCredentialType.GETHKEYCHAINPASSWORD, + }, + transactionConfig: { + from: firstHighNetWorthAccount, + to: testEthAccount.address, + value: 10e9, + }, + }); + + const balance = await web3.eth.getBalance(testEthAccount.address); + t.ok(balance, "Retrieved balance of test account OK"); + t.equals(parseInt(balance, 10), 10e9, "Balance of test account is OK"); + + let contractAddress: string; + + test("deploys contract via .json file", async (t2: Test) => { + const deployOut = await connector.deployContract({ + keychainId: keychainPlugin.getKeychainId(), + contractName: HelloWorldContractJson.contractName, + web3SigningCredential: { + ethAccount: firstHighNetWorthAccount, + secret: "", + type: Web3SigningCredentialType.GETHKEYCHAINPASSWORD, + }, + bytecode: HelloWorldContractJson.bytecode, + gas: 1000000, + }); + t2.ok(deployOut, "deployContract() output is truthy OK"); + t2.ok( + deployOut.transactionReceipt, + "deployContract() output.transactionReceipt is truthy OK", + ); + t2.ok( + deployOut.transactionReceipt.contractAddress, + "deployContract() output.transactionReceipt.contractAddress is truthy OK", + ); + + contractAddress = deployOut.transactionReceipt.contractAddress as string; + t2.ok( + typeof contractAddress === "string", + "contractAddress typeof string OK", + ); + + const { callOutput: helloMsg } = await connector.invokeContract({ + contractName, + keychainId: keychainPlugin.getKeychainId(), + invocationType: EthContractInvocationType.CALL, + methodName: "sayHello", + params: [], + signingCredential: { + ethAccount: firstHighNetWorthAccount, + secret: "", + type: Web3SigningCredentialType.GETHKEYCHAINPASSWORD, + }, + }); + t2.ok(helloMsg, "sayHello() output is truthy"); + t2.true( + typeof helloMsg === "string", + "sayHello() output is type of string", + ); + }); + + test("invoke Web3SigningCredentialType.GETHKEYCHAINPASSWORD", async (t2: Test) => { + const newName = `DrCactus${uuidV4()}`; + const setNameOut = await connector.invokeContract({ + contractName, + keychainId: keychainPlugin.getKeychainId(), + invocationType: EthContractInvocationType.SEND, + methodName: "setName", + params: [newName], + signingCredential: { + ethAccount: firstHighNetWorthAccount, + secret: "", + type: Web3SigningCredentialType.GETHKEYCHAINPASSWORD, + }, + nonce: 2, + }); + t2.ok(setNameOut, "setName() invocation #1 output is truthy OK"); + + try { + const setNameOutInvalid = await connector.invokeContract({ + contractName, + keychainId: keychainPlugin.getKeychainId(), + invocationType: EthContractInvocationType.SEND, + methodName: "setName", + params: [newName], + gas: 1000000, + signingCredential: { + ethAccount: firstHighNetWorthAccount, + secret: "", + type: Web3SigningCredentialType.GETHKEYCHAINPASSWORD, + }, + nonce: 2, + }); + t2.ifError(setNameOutInvalid.transactionReceipt); + } catch (error) { + t2.notStrictEqual( + error, + "Nonce too low", + "setName() invocation with invalid nonce", + ); + } + + const getNameOut = await connector.invokeContract({ + contractName, + keychainId: keychainPlugin.getKeychainId(), + invocationType: EthContractInvocationType.SEND, + methodName: "getName", + params: [], + signingCredential: { + ethAccount: firstHighNetWorthAccount, + secret: "", + type: Web3SigningCredentialType.GETHKEYCHAINPASSWORD, + }, + }); + t2.ok(getNameOut.success, `getName() SEND invocation produced receipt OK`); + + const { callOutput: getNameOut2 } = await connector.invokeContract({ + contractName, + keychainId: keychainPlugin.getKeychainId(), + invocationType: EthContractInvocationType.CALL, + methodName: "getName", + params: [], + signingCredential: { + ethAccount: firstHighNetWorthAccount, + secret: "", + type: Web3SigningCredentialType.GETHKEYCHAINPASSWORD, + }, + }); + t2.equal( + getNameOut2, + newName, + "setName() invocation #2 output is truthy OK", + ); + + t2.end(); + }); + + test("invoke Web3SigningCredentialType.NONE", async (t2: Test) => { + const testEthAccount2 = web3.eth.accounts.create(uuidV4()); + + const { rawTransaction } = await web3.eth.accounts.signTransaction( + { + from: testEthAccount.address, + to: testEthAccount2.address, + value: 10e6, + gas: 1000000, + }, + testEthAccount.privateKey, + ); + + await connector.transact({ + web3SigningCredential: { + type: Web3SigningCredentialType.NONE, + }, + transactionConfig: { + rawTransaction, + }, + }); + + const balance2 = await web3.eth.getBalance(testEthAccount2.address); + t2.ok(balance2, "Retrieved balance of test account 2 OK"); + t2.equals(parseInt(balance2, 10), 10e6, "Balance of test account2 is OK"); + t2.end(); + }); + + test("invoke Web3SigningCredentialType.PRIVATEKEYHEX", async (t2: Test) => { + const newName = `DrCactus${uuidV4()}`; + const setNameOut = await connector.invokeContract({ + contractName, + keychainId: keychainPlugin.getKeychainId(), + invocationType: EthContractInvocationType.SEND, + methodName: "setName", + params: [newName], + signingCredential: { + ethAccount: testEthAccount.address, + secret: testEthAccount.privateKey, + type: Web3SigningCredentialType.PRIVATEKEYHEX, + }, + nonce: 1, + }); + t2.ok(setNameOut, "setName() invocation #1 output is truthy OK"); + + try { + const setNameOutInvalid = await connector.invokeContract({ + contractName, + keychainId: keychainPlugin.getKeychainId(), + invocationType: EthContractInvocationType.SEND, + methodName: "setName", + params: [newName], + gas: 1000000, + signingCredential: { + ethAccount: testEthAccount.address, + secret: testEthAccount.privateKey, + type: Web3SigningCredentialType.PRIVATEKEYHEX, + }, + nonce: 1, + }); + t2.ifError(setNameOutInvalid.transactionReceipt); + } catch (error) { + t2.notStrictEqual( + error, + "Nonce too low", + "setName() invocation with invalid nonce", + ); + } + const { callOutput: getNameOut } = await connector.invokeContract({ + contractName, + keychainId: keychainPlugin.getKeychainId(), + invocationType: EthContractInvocationType.CALL, + methodName: "getName", + params: [], + gas: 1000000, + signingCredential: { + ethAccount: testEthAccount.address, + secret: testEthAccount.privateKey, + type: Web3SigningCredentialType.PRIVATEKEYHEX, + }, + }); + t2.equal(getNameOut, newName, `getName() output reflects the update OK`); + + const getNameOut2 = await connector.invokeContract({ + contractName, + keychainId: keychainPlugin.getKeychainId(), + invocationType: EthContractInvocationType.SEND, + methodName: "getName", + params: [], + gas: 1000000, + signingCredential: { + ethAccount: testEthAccount.address, + secret: testEthAccount.privateKey, + type: Web3SigningCredentialType.PRIVATEKEYHEX, + }, + }); + t2.ok(getNameOut2, "getName() invocation #2 output is truthy OK"); + + t2.end(); + }); + + test("invoke Web3SigningCredentialType.CACTUSKEYCHAINREF", async (t2: Test) => { + const newName = `DrCactus${uuidV4()}`; + + const signingCredential: Web3SigningCredentialCactusKeychainRef = { + ethAccount: testEthAccount.address, + keychainEntryKey, + keychainId: keychainPlugin.getKeychainId(), + type: Web3SigningCredentialType.CACTUSKEYCHAINREF, + }; + + const setNameOut = await connector.invokeContract({ + contractName, + keychainId: keychainPlugin.getKeychainId(), + invocationType: EthContractInvocationType.SEND, + methodName: "setName", + params: [newName], + gas: 1000000, + signingCredential, + nonce: 3, + }); + t2.ok(setNameOut, "setName() invocation #1 output is truthy OK"); + + try { + const setNameOutInvalid = await connector.invokeContract({ + contractName, + keychainId: keychainPlugin.getKeychainId(), + invocationType: EthContractInvocationType.SEND, + methodName: "setName", + params: [newName], + gas: 1000000, + signingCredential: { + ethAccount: firstHighNetWorthAccount, + secret: "", + type: Web3SigningCredentialType.GETHKEYCHAINPASSWORD, + }, + nonce: 3, + }); + t2.ifError(setNameOutInvalid.transactionReceipt); + } catch (error) { + t2.notStrictEqual( + error, + "Nonce too low", + "setName() invocation with invalid nonce", + ); + } + const { callOutput: getNameOut } = await connector.invokeContract({ + contractName, + keychainId: keychainPlugin.getKeychainId(), + invocationType: EthContractInvocationType.CALL, + methodName: "getName", + params: [], + gas: 1000000, + signingCredential, + }); + t2.equal(getNameOut, newName, `getName() output reflects the update OK`); + + const getNameOut2 = await connector.invokeContract({ + contractName, + keychainId: keychainPlugin.getKeychainId(), + invocationType: EthContractInvocationType.SEND, + methodName: "getName", + params: [], + gas: 1000000, + signingCredential, + }); + t2.ok(getNameOut2, "getName() invocation #2 output is truthy OK"); + + t2.end(); + }); + + t.end(); +}); diff --git a/packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/deploy-contract-from-json.test.ts b/packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/v21.4.1-deploy-contract-from-json.test.ts similarity index 98% rename from packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/deploy-contract-from-json.test.ts rename to packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/v21.4.1-deploy-contract-from-json.test.ts index 19cddc2a23..9dd989ad06 100644 --- a/packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/deploy-contract-from-json.test.ts +++ b/packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/v21.4.1-deploy-contract-from-json.test.ts @@ -46,7 +46,10 @@ test("BEFORE " + testCase, async (t: Test) => { }); test(testCase, async (t: Test) => { - const ledger = new QuorumTestLedger(); + const containerImageName = "hyperledger/cactus-quorum-all-in-one"; + const containerImageVersion = "2021-05-03-quorum-v21.4.1"; + const ledgerOptions = { containerImageName, containerImageVersion }; + const ledger = new QuorumTestLedger(ledgerOptions); await ledger.start(); test.onFinish(async () => { diff --git a/packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/invoke-contract.test.ts b/packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/v21.4.1-invoke-contract.test.ts similarity index 97% rename from packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/invoke-contract.test.ts rename to packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/v21.4.1-invoke-contract.test.ts index 8d8a98a726..32d23a2ca9 100644 --- a/packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/invoke-contract.test.ts +++ b/packages/cactus-plugin-ledger-connector-quorum/src/test/typescript/integration/plugin-ledger-connector-quorum/deploy-contract/v21.4.1-invoke-contract.test.ts @@ -26,7 +26,10 @@ const logLevel: LogLevelDesc = "INFO"; const contractName = "HelloWorld"; test("Quorum Ledger Connector Plugin", async (t: Test) => { - const ledger = new QuorumTestLedger(); + const containerImageName = "hyperledger/cactus-quorum-all-in-one"; + const containerImageVersion = "2021-05-03-quorum-v21.4.1"; + const ledgerOptions = { containerImageName, containerImageVersion }; + const ledger = new QuorumTestLedger(ledgerOptions); await ledger.start(); test.onFinish(async () => {