From d9b57e08ca1abe766d63d74c74a40d15679ba9b3 Mon Sep 17 00:00:00 2001 From: Michal Bajer Date: Mon, 10 Jul 2023 11:06:30 +0000 Subject: [PATCH 1/3] build: add geth-all-in-one image Signed-off-by: Michal Bajer --- .../workflows/geth-all-in-one-publish.yaml | 60 +++++++++++++++++ tools/docker/geth-all-in-one/Dockerfile | 43 +++++++++++++ tools/docker/geth-all-in-one/README.md | 64 +++++++++++++++++++ .../docker/geth-all-in-one/docker-compose.yml | 22 +++++++ .../geth-all-in-one/script-start-docker.sh | 2 + tools/docker/geth-all-in-one/src/genesis.json | 27 ++++++++ .../docker/geth-all-in-one/src/healthcheck.sh | 14 ++++ ...--6a2ec8c50ba1a9ce47c52d1cb5b7136ee9d0ccc0 | 1 + 8 files changed, 233 insertions(+) create mode 100644 .github/workflows/geth-all-in-one-publish.yaml create mode 100644 tools/docker/geth-all-in-one/Dockerfile create mode 100644 tools/docker/geth-all-in-one/README.md create mode 100644 tools/docker/geth-all-in-one/docker-compose.yml create mode 100755 tools/docker/geth-all-in-one/script-start-docker.sh create mode 100644 tools/docker/geth-all-in-one/src/genesis.json create mode 100644 tools/docker/geth-all-in-one/src/healthcheck.sh create mode 100644 tools/docker/geth-all-in-one/src/keystore/UTC--2023-07-03T14-42-00.153791517Z--6a2ec8c50ba1a9ce47c52d1cb5b7136ee9d0ccc0 diff --git a/.github/workflows/geth-all-in-one-publish.yaml b/.github/workflows/geth-all-in-one-publish.yaml new file mode 100644 index 0000000000..73d5cabc63 --- /dev/null +++ b/.github/workflows/geth-all-in-one-publish.yaml @@ -0,0 +1,60 @@ +name: geth-all-in-one-publish + +on: + push: + # Publish `main` as Docker `latest` image. + branches: + - main + + # Publish `v1.2.3` tags as releases. + tags: + - v* + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + IMAGE_NAME: cactus-geth-all-in-one + +jobs: + # Push image to GitHub Packages. + # See also https://docs.docker.com/docker-hub/builds/ + build-tag-push-container: + runs-on: ubuntu-20.04 + env: + DOCKER_BUILDKIT: 1 + DOCKERFILE_PATH: ./tools/docker/geth-all-in-one/Dockerfile + DOCKER_BUILD_DIR: ./tools/docker/geth-all-in-one/ + permissions: + packages: write + contents: read + + steps: + - uses: actions/checkout@v3.5.2 + + - name: Build image + run: docker build $DOCKER_BUILD_DIR --file $DOCKERFILE_PATH --tag $IMAGE_NAME --label "runnumber=${GITHUB_RUN_ID}" + + - name: Log in to registry + # This is where you will update the PAT to GITHUB_TOKEN + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin + + - name: Push image + run: | + SHORTHASH=$(git rev-parse --short "$GITHUB_SHA") + TODAYS_DATE="$(date +%F)" + DOCKER_TAG="$TODAYS_DATE-$SHORTHASH" + IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME + # Change all uppercase to lowercase + IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') + # Strip git ref prefix from version + VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,') + # Strip "v" prefix from tag name + [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//') + # Do not use the `latest` tag at all, tag with date + git short hash if there is no git tag + [ "$VERSION" == "main" ] && VERSION=$DOCKER_TAG + echo IMAGE_ID=$IMAGE_ID + echo VERSION=$VERSION + docker tag $IMAGE_NAME $IMAGE_ID:$VERSION + docker push $IMAGE_ID:$VERSION diff --git a/tools/docker/geth-all-in-one/Dockerfile b/tools/docker/geth-all-in-one/Dockerfile new file mode 100644 index 0000000000..5615348cc7 --- /dev/null +++ b/tools/docker/geth-all-in-one/Dockerfile @@ -0,0 +1,43 @@ +FROM ethereum/client-go:v1.12.0 + +# Init +COPY ./src/genesis.json /root/data/ +COPY ./src/keystore/ /root/data/keystore/ +RUN geth --datadir "/root/data" init "/root/data/genesis.json" + +# Setup healtcheck +COPY ./src/healthcheck.sh /bin/healthcheck +RUN chmod +x /bin/healthcheck +HEALTHCHECK --interval=5s --timeout=10s --start-period=10s --retries=30 CMD /bin/healthcheck + +# RPC - HTTP +EXPOSE 8545 +# RPC - WS +EXPOSE 8546 + +VOLUME [ "/root/data" ] + +ENTRYPOINT [ \ + "geth", \ + "--datadir", "/root/data", \ + "--nodiscover", \ + "--http", \ + "--http.addr", "0.0.0.0", \ + "--http.port", "8545", \ + "--http.corsdomain", "*", \ + "--http.vhosts", "*", \ + "--ws", \ + "--ws.addr", "0.0.0.0", \ + "--ws.port", "8546", \ + "--ws.origins", "*", \ + "--unlock", "0x6A2EC8c50BA1a9cE47c52d1cb5B7136Ee9d0cCC0", \ + "--mine", \ + "--password", "/dev/null", \ + "--allow-insecure-unlock", \ + "--miner.etherbase", "0x6A2EC8c50BA1a9cE47c52d1cb5B7136Ee9d0cCC0" \ + ] +CMD [ \ + "--networkid", "10", \ + "--http.api", "eth,personal,web3,net,admin,debug", \ + "--ws.api", "eth,personal,web3,net,admin,debug" \ + ] \ No newline at end of file diff --git a/tools/docker/geth-all-in-one/README.md b/tools/docker/geth-all-in-one/README.md new file mode 100644 index 0000000000..318e4aa61c --- /dev/null +++ b/tools/docker/geth-all-in-one/README.md @@ -0,0 +1,64 @@ +# geth-all-in-one + +An all in one ethereum/client-go (geth) docker image as described in [go-ethereum documentation](https://geth.ethereum.org/docs/fundamentals/private-network). + +- Clique (PoS) is used to mimic mainnet node. +- This docker image is for `testing` and `development` only. +- **Do NOT use in production!** + +## Usage + +### Docker Compose + +```bash +./script-start-docker.sh +``` + +or manually: + +```bash +docker-compose build && docker-compose up -d +``` + +### Docker + +```bash +# Build +DOCKER_BUILDKIT=1 docker build ./tools/docker/geth-all-in-one/ -t cactus_geth_all_in_one + +# Run +docker run --rm --name geth_aio_testnet --detach -p 8545:8545 -p 8546:8546 cactus_geth_all_in_one +``` + +### Examples + +#### Attach geth CLI + +```bash +docker exec -ti geth_aio_testnet geth --datadir "/root/data" attach + +> eth.blockNumber +24 +``` + +### Configure with Hardhat + +```javascript +module.exports = { + // ... + networks: { + geth: { + url: "http://127.0.0.1:8545", + chainId: 10, + }, + }, +}; +``` + +## Test Setup + +- TODO + +## Possible improvements + +- Replace (deprecated) `eth.personal` with `Clef` - https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-personal diff --git a/tools/docker/geth-all-in-one/docker-compose.yml b/tools/docker/geth-all-in-one/docker-compose.yml new file mode 100644 index 0000000000..288b0ed149 --- /dev/null +++ b/tools/docker/geth-all-in-one/docker-compose.yml @@ -0,0 +1,22 @@ +version: "3.5" + +services: + geth-aio-testnet: + container_name: ${CACTUS_GETH_LEDGER_CONTAINER_NAME:-geth_aio_testnet} + image: ${CACTUS_GETH_LEDGER_IMAGE_NAME:-cactus_geth_all_in_one:1.0.0} + build: + context: ./ + dockerfile: Dockerfile + ports: + - 8545:8545/tcp # RPC - HTTP + - 8546:8546/tcp # RPC - WS + expose: + - 8545/tcp # RPC - HTTP + - 8546/tcp # RPC - WS + networks: + - geth-network + +networks: + geth-network: + name: geth_aio_network + driver: bridge diff --git a/tools/docker/geth-all-in-one/script-start-docker.sh b/tools/docker/geth-all-in-one/script-start-docker.sh new file mode 100755 index 0000000000..83156688d0 --- /dev/null +++ b/tools/docker/geth-all-in-one/script-start-docker.sh @@ -0,0 +1,2 @@ +echo "[process] start docker environment for Geth testnet" +docker-compose build && docker-compose up -d diff --git a/tools/docker/geth-all-in-one/src/genesis.json b/tools/docker/geth-all-in-one/src/genesis.json new file mode 100644 index 0000000000..6066c68e57 --- /dev/null +++ b/tools/docker/geth-all-in-one/src/genesis.json @@ -0,0 +1,27 @@ +{ + "config": { + "chainId": 10, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "clique": { + "period": 5, + "epoch": 30000 + } + }, + "difficulty": "1", + "gasLimit": "800000000", + "extradata": "0x00000000000000000000000000000000000000000000000000000000000000006a2ec8c50ba1a9ce47c52d1cb5b7136ee9d0ccc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "alloc": { + "6a2ec8c50ba1a9ce47c52d1cb5b7136ee9d0ccc0": { + "balance": "100000000000000000000000000" + } + } +} diff --git a/tools/docker/geth-all-in-one/src/healthcheck.sh b/tools/docker/geth-all-in-one/src/healthcheck.sh new file mode 100644 index 0000000000..1a5b51c260 --- /dev/null +++ b/tools/docker/geth-all-in-one/src/healthcheck.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +function is_valid_block_returned() { + local rpc_endpoint="$1" + local block_number=$(geth attach --exec "eth.blockNumber" "$rpc_endpoint") + if ! echo "$block_number" | grep -Eq '^[0-9]+$'; then + echo "Invalid eth.blockNumber '${block_number}' -> UNHEALTHY" + exit 1 + fi +} + +# Check both HTTP and WS endpoints +is_valid_block_returned "http://localhost:8545" +is_valid_block_returned "ws://localhost:8546" diff --git a/tools/docker/geth-all-in-one/src/keystore/UTC--2023-07-03T14-42-00.153791517Z--6a2ec8c50ba1a9ce47c52d1cb5b7136ee9d0ccc0 b/tools/docker/geth-all-in-one/src/keystore/UTC--2023-07-03T14-42-00.153791517Z--6a2ec8c50ba1a9ce47c52d1cb5b7136ee9d0ccc0 new file mode 100644 index 0000000000..2d6576bd78 --- /dev/null +++ b/tools/docker/geth-all-in-one/src/keystore/UTC--2023-07-03T14-42-00.153791517Z--6a2ec8c50ba1a9ce47c52d1cb5b7136ee9d0ccc0 @@ -0,0 +1 @@ +{"address":"6a2ec8c50ba1a9ce47c52d1cb5b7136ee9d0ccc0","crypto":{"cipher":"aes-128-ctr","ciphertext":"2b0ea1bbdd3aa8ae3205de9428a2327e73a3fb301ea7eb36cc3b588879e15983","cipherparams":{"iv":"fbcaccd21ec623ab283aa2506055cff2"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"a686699704e7f43cf2ca2421dc026a03e6532d97ab129d66f20faf1439456097"},"mac":"186797fe2b904d2d0ed9f2d839af14785326ef31c4277d6c668c7a4d3431be60"},"id":"a2cd2edd-813d-49e5-b84d-3c18b6e2524f","version":3} \ No newline at end of file From bce6623860a2a32272b1289b13661867ec404ea0 Mon Sep 17 00:00:00 2001 From: Michal Bajer Date: Tue, 11 Jul 2023 08:33:42 +0000 Subject: [PATCH 2/3] build: add geth ledger class and basic tests Signed-off-by: Michal Bajer --- packages/cactus-test-geth-ledger/README.md | 3 + packages/cactus-test-geth-ledger/package.json | 71 +++ .../src/main/typescript/geth-test-ledger.ts | 413 ++++++++++++++++++ .../src/main/typescript/index.ts | 1 + .../src/main/typescript/index.web.ts | 1 + .../src/main/typescript/public-api.ts | 7 + .../integration/api-surface.test.ts | 5 + .../integration/geth-test-ledger.test.ts | 115 +++++ .../cactus-test-geth-ledger/tsconfig.json | 21 + tools/docker/geth-all-in-one/README.md | 2 +- tsconfig.json | 3 + 11 files changed, 641 insertions(+), 1 deletion(-) create mode 100644 packages/cactus-test-geth-ledger/README.md create mode 100644 packages/cactus-test-geth-ledger/package.json create mode 100644 packages/cactus-test-geth-ledger/src/main/typescript/geth-test-ledger.ts create mode 100755 packages/cactus-test-geth-ledger/src/main/typescript/index.ts create mode 100755 packages/cactus-test-geth-ledger/src/main/typescript/index.web.ts create mode 100755 packages/cactus-test-geth-ledger/src/main/typescript/public-api.ts create mode 100644 packages/cactus-test-geth-ledger/src/test/typescript/integration/api-surface.test.ts create mode 100644 packages/cactus-test-geth-ledger/src/test/typescript/integration/geth-test-ledger.test.ts create mode 100644 packages/cactus-test-geth-ledger/tsconfig.json diff --git a/packages/cactus-test-geth-ledger/README.md b/packages/cactus-test-geth-ledger/README.md new file mode 100644 index 0000000000..d0980e32ad --- /dev/null +++ b/packages/cactus-test-geth-ledger/README.md @@ -0,0 +1,3 @@ +# `@hyperledger/cactus-test-geth-ledger` + +- Helpers for running test go-ethereum ledger in test scripts. diff --git a/packages/cactus-test-geth-ledger/package.json b/packages/cactus-test-geth-ledger/package.json new file mode 100644 index 0000000000..04ab51f20f --- /dev/null +++ b/packages/cactus-test-geth-ledger/package.json @@ -0,0 +1,71 @@ +{ + "name": "@hyperledger/cactus-test-geth-ledger", + "version": "2.0.0-alpha.1", + "description": "Helpers for running test go-ethereum ledger in test scripts.", + "keywords": [ + "Hyperledger", + "Cactus", + "Integration", + "Blockchain", + "Distributed Ledger Technology" + ], + "homepage": "https://github.com/hyperledger/cactus#readme", + "bugs": { + "url": "https://github.com/hyperledger/cactus/issues" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/hyperledger/cactus.git" + }, + "license": "Apache-2.0", + "author": { + "name": "Hyperledger Cactus Contributors", + "email": "cactus@lists.hyperledger.org", + "url": "https://www.hyperledger.org/use/cactus" + }, + "contributors": [ + { + "name": "Please add yourself to the list of contributors", + "email": "your.name@example.com", + "url": "https://example.com" + }, + { + "name": "Michal Bajer", + "email": "michal.bajer@fujitsu.com", + "url": "https://www.fujitsu.com/global/" + } + ], + "main": "dist/lib/main/typescript/index.js", + "module": "dist/lib/main/typescript/index.js", + "browser": "dist/cactus-test-geth-ledger.web.umd.js", + "types": "dist/lib/main/typescript/index.d.ts", + "files": [ + "dist/*" + ], + "scripts": { + "watch": "npm-watch", + "webpack": "npm-run-all webpack:dev", + "webpack:dev": "npm-run-all webpack:dev:node webpack:dev:web", + "webpack:dev:node": "webpack --env=dev --target=node --config ../../webpack.config.js", + "webpack:dev:web": "webpack --env=dev --target=web --config ../../webpack.config.js" + }, + "dependencies": { + "@hyperledger/cactus-common": "2.0.0-alpha.1", + "@hyperledger/cactus-test-tooling": "2.0.0-alpha.1", + "dockerode": "3.3.0", + "internal-ip": "6.2.0", + "web3": "dev", + "web3-eth-accounts": "dev", + "run-time-error": "1.4.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + }, + "publishConfig": { + "access": "public" + }, + "browserMinified": "dist/cactus-test-geth-ledger.web.umd.min.js", + "mainMinified": "dist/cactus-test-geth-ledger.node.umd.min.js", + "watch": {} +} diff --git a/packages/cactus-test-geth-ledger/src/main/typescript/geth-test-ledger.ts b/packages/cactus-test-geth-ledger/src/main/typescript/geth-test-ledger.ts new file mode 100644 index 0000000000..4f2e6e9e56 --- /dev/null +++ b/packages/cactus-test-geth-ledger/src/main/typescript/geth-test-ledger.ts @@ -0,0 +1,413 @@ +import { EventEmitter } from "events"; +import Docker, { Container } from "dockerode"; // TODO - import dockerode from test-tooling? +import { v4 as internalIpV4 } from "internal-ip"; +import Web3, { ContractAbi, TransactionReceipt } from "web3"; +import type { Web3Account } from "web3-eth-accounts"; +import { RuntimeError } from "run-time-error"; + +import { + Logger, + Checks, + LogLevelDesc, + LoggerProvider, +} from "@hyperledger/cactus-common"; +import { Containers } from "@hyperledger/cactus-test-tooling"; + +export interface IGethTestLedgerOptions { + readonly containerImageName?: string; + readonly containerImageVersion?: string; + readonly logLevel?: LogLevelDesc; + readonly emitContainerLogs?: boolean; + readonly envVars?: string[]; + // For test development, attach to ledger that is already running, don't spin up new one + readonly useRunningLedger?: boolean; +} + +/** + * Default values used by GethTestLedger constructor. + */ +export const GETH_TEST_LEDGER_DEFAULT_OPTIONS = Object.freeze({ + containerImageName: "cactus_geth_all_in_one", + containerImageVersion: "latest", + logLevel: "info" as LogLevelDesc, + emitContainerLogs: false, + envVars: [], + useRunningLedger: false, +}); + +export const WHALE_ACCOUNT_PRIVATE_KEY = + "86bbf98cf5e5b1c43d2c8701764897357e0fa24982c0137efabf6dc3a6e7b69e"; +export const WHALE_ACCOUNT_PUBLIC_KEY = + "6a2ec8c50ba1a9ce47c52d1cb5b7136ee9d0ccc0"; + +export class GethTestLedger { + public static readonly CLASS_NAME = "GethTestLedger"; + private readonly log: Logger; + private readonly logLevel: LogLevelDesc; + private readonly containerImageName: string; + private readonly containerImageVersion: string; + private readonly envVars: string[]; + private readonly emitContainerLogs: boolean; + public readonly useRunningLedger: boolean; + private _container: Container | undefined; + private _containerId: string | undefined; + private _web3: Web3 | undefined; + + public get fullContainerImageName(): string { + return [this.containerImageName, this.containerImageVersion].join(":"); + } + + public get className(): string { + return GethTestLedger.CLASS_NAME; + } + + public get container(): Container { + if (this._container) { + return this._container; + } else { + throw new Error(`Invalid state: _container is not set. Called start()?`); + } + } + + private get web3(): Web3 { + if (this._web3) { + return this._web3; + } else { + throw new Error( + "Invalid state: web3 client is missing, start the ledger container first.", + ); + } + } + + constructor(public readonly options: IGethTestLedgerOptions) { + const fnTag = `${this.className}#constructor()`; + Checks.truthy(options, `${fnTag} arg options`); + + this.logLevel = + this.options.logLevel || GETH_TEST_LEDGER_DEFAULT_OPTIONS.logLevel; + const label = this.className; + this.log = LoggerProvider.getOrCreate({ level: this.logLevel, label }); + + this.emitContainerLogs = + options?.emitContainerLogs ?? + GETH_TEST_LEDGER_DEFAULT_OPTIONS.emitContainerLogs; + this.useRunningLedger = + options?.useRunningLedger ?? + GETH_TEST_LEDGER_DEFAULT_OPTIONS.useRunningLedger; + this.containerImageName = + this.options.containerImageName || + GETH_TEST_LEDGER_DEFAULT_OPTIONS.containerImageName; + this.containerImageVersion = + this.options.containerImageVersion || + GETH_TEST_LEDGER_DEFAULT_OPTIONS.containerImageVersion; + this.envVars = + this.options.envVars || GETH_TEST_LEDGER_DEFAULT_OPTIONS.envVars; + + this.log.info( + `Created ${this.className} OK. Image FQN: ${this.fullContainerImageName}`, + ); + } + + /** + * Get container status. + * + * @returns status string + */ + public async getContainerStatus(): Promise { + if (!this.container) { + throw new Error( + "GethTestLedger#getContainerStatus(): Container not started yet!", + ); + } + + const { Status } = await Containers.getById(this.container.id); + return Status; + } + + /** + * Start a test Geth ledger. + * + * @param omitPull Don't pull docker image from upstream if true. + * @returns Promise + */ + public async start(omitPull = false): Promise { + if (this.useRunningLedger) { + this.log.info( + "Search for already running Geth Test Ledger because 'useRunningLedger' flag is enabled.", + ); + this.log.info( + "Search criteria - image name: ", + this.fullContainerImageName, + ", state: running", + ); + const containerInfo = await Containers.getByPredicate( + (ci) => + ci.Image === this.fullContainerImageName && ci.State === "healthy", + ); + const docker = new Docker(); + this._container = docker.getContainer(containerInfo.Id); + return this._container; + } + + if (this._container) { + this.log.warn("Container was already running - restarting it..."); + await this.container.stop(); + await this.container.remove(); + this._container = undefined; + } + + if (!omitPull) { + await Containers.pullImage( + this.fullContainerImageName, + {}, + this.logLevel, + ); + } + + return new Promise((resolve, reject) => { + const docker = new Docker(); + const eventEmitter: EventEmitter = docker.run( + this.fullContainerImageName, + [], + [], + { + ExposedPorts: { + ["8545/tcp"]: {}, + ["8546/tcp"]: {}, + }, + Env: this.envVars, + HostConfig: { + PublishAllPorts: true, + }, + }, + {}, + (err?: Error) => { + if (err) { + this.log.error( + `Failed to start ${this.fullContainerImageName} container; `, + err, + ); + reject(err); + } + }, + ); + + eventEmitter.once("start", async (container: Container) => { + this._container = container; + this._containerId = container.id; + + if (this.emitContainerLogs) { + const fnTag = `[${this.fullContainerImageName}]`; + await Containers.streamLogs({ + container: this.container, + tag: fnTag, + log: this.log, + }); + } + + try { + await Containers.waitForHealthCheck(this._containerId); + this._web3 = new Web3(await this.getRpcApiHttpHost()); + resolve(container); + } catch (ex) { + reject(ex); + } + }); + }); + } + + /** + * Stop a test Geth ledger. + * + * @returns Stop operation results. + */ + public async stop(): Promise { + if (this.useRunningLedger) { + this.log.info("Ignore stop request because useRunningLedger is enabled."); + return; + } else if (this.container) { + this._web3 = undefined; + return Containers.stop(this.container); + } else { + throw new Error( + `GethTestLedger#stop() Container was never created, nothing to stop.`, + ); + } + } + + /** + * Destroy a test Geth ledger. + * + * @returns Destroy operation results. + */ + public async destroy(): Promise { + if (this.useRunningLedger) { + this.log.info( + "Ignore destroy request because useRunningLedger is enabled.", + ); + return; + } else if (this.container) { + this._web3 = undefined; + return this.container.remove(); + } else { + throw new Error( + `GethTestLedger#destroy() Container was never created, nothing to destroy.`, + ); + } + } + + /** + * Creates a new ETH account from scratch on the ledger and then sends it a + * little seed money to get things started. + * + * Uses `web3.eth.accounts.create` + * + * @param [seedMoney=10e8] The amount of money to seed the new test account with. + */ + public async createEthTestAccount(seedMoney = 10e8): Promise { + const ethTestAccount = this.web3.eth.accounts.create(); + + const receipt = await this.transferAssetFromCoinbase( + ethTestAccount.address, + seedMoney, + ); + + if (receipt instanceof Error) { + throw new RuntimeError("Error in createEthTestAccount", receipt); + } else { + return ethTestAccount; + } + } + + /** + * Creates a new personal ethereum account with specified initial money and password. + * + * Uses `web3.eth.personal.newAccount` + * + * @param seedMoney Initial money to transfer to this account + * @param password Personal account password + * @returns New account address + */ + public async newEthPersonalAccount( + seedMoney = 10e8, + password = "test", + ): Promise { + const account = await this.web3.eth.personal.newAccount(password); + + const receipt = await this.transferAssetFromCoinbase(account, seedMoney); + + if (receipt instanceof Error) { + throw new RuntimeError("Error in newEthPersonalAccount", receipt); + } else { + return account; + } + } + + /** + * Seed `targetAccount` with money from coin base account. + * + * @param targetAccount Ethereum account to send money to. + * @param value Amount of money. + * @returns Transfer `TransactionReceipt` + */ + public async transferAssetFromCoinbase( + targetAccount: string, + value: number, + ): Promise { + const fnTag = `${this.className}#transferAssetFromCoinbase()`; + + const tx = await this.web3.eth.accounts.signTransaction( + { + from: WHALE_ACCOUNT_PUBLIC_KEY, + to: targetAccount, + value: value, + gas: 1000000, + }, + WHALE_ACCOUNT_PRIVATE_KEY, + ); + + if (!tx.rawTransaction) { + throw new Error(`${fnTag} Signing transaction failed, reason unknown.`); + } + + return await this.web3.eth.sendSignedTransaction(tx.rawTransaction); + } + + /** + * Deploy contract from coin base account to the ledger. + * + * @param abi - JSON interface of the contract. + * @param bytecode - Compiled code of the contract. + * @param args - Contract arguments. + * @returns Contract deployment `TransactionReceipt` + */ + public async deployContract( + abi: ContractAbi, + bytecode: string, + args?: any[], + ): Promise { + // Encode ABI + const contractProxy = new this.web3.eth.Contract(abi); + const contractTx = contractProxy.deploy({ + data: bytecode, + arguments: args as any, + }); + + // Send TX + const signedTx = await this.web3.eth.accounts.signTransaction( + { + from: WHALE_ACCOUNT_PUBLIC_KEY, + data: contractTx.encodeABI(), + gas: 8000000, // Max possible gas + nonce: await this.web3.eth.getTransactionCount( + WHALE_ACCOUNT_PUBLIC_KEY, + ), + }, + WHALE_ACCOUNT_PRIVATE_KEY, + ); + + if (!signedTx.rawTransaction) { + throw new Error(`Signing transaction failed, reason unknown.`); + } + + return await this.web3.eth.sendSignedTransaction(signedTx.rawTransaction); + } + + public async getRpcApiHttpHost( + host?: string, + port?: number, + ): Promise { + const thePort = port || (await this.getHostPortHttp()); + const lanIpV4OrUndefined = await internalIpV4(); + const lanAddress = host || lanIpV4OrUndefined || "127.0.0.1"; // best effort... + return `http://${lanAddress}:${thePort}`; + } + + public async getRpcApiWebSocketHost( + host?: string, + port?: number, + ): Promise { + const thePort = port || (await this.getHostPortWs()); + const lanIpV4OrUndefined = await internalIpV4(); + const lanAddress = host || lanIpV4OrUndefined || "127.0.0.1"; // best effort... + return `ws://${lanAddress}:${thePort}`; + } + + private async getHostPort(port: number): Promise { + const fnTag = `${this.className}#getHostPort()`; + if (this._containerId) { + const cInfo = await Containers.getById(this._containerId); + return Containers.getPublicPort(port, cInfo); + } else { + throw new Error(`${fnTag} Container ID not set. Did you call start()?`); + } + } + + public async getHostPortHttp(): Promise { + return this.getHostPort(8545); + } + + public async getHostPortWs(): Promise { + return this.getHostPort(8546); + } +} diff --git a/packages/cactus-test-geth-ledger/src/main/typescript/index.ts b/packages/cactus-test-geth-ledger/src/main/typescript/index.ts new file mode 100755 index 0000000000..87cb558397 --- /dev/null +++ b/packages/cactus-test-geth-ledger/src/main/typescript/index.ts @@ -0,0 +1 @@ +export * from "./public-api"; diff --git a/packages/cactus-test-geth-ledger/src/main/typescript/index.web.ts b/packages/cactus-test-geth-ledger/src/main/typescript/index.web.ts new file mode 100755 index 0000000000..cb0ff5c3b5 --- /dev/null +++ b/packages/cactus-test-geth-ledger/src/main/typescript/index.web.ts @@ -0,0 +1 @@ +export {}; diff --git a/packages/cactus-test-geth-ledger/src/main/typescript/public-api.ts b/packages/cactus-test-geth-ledger/src/main/typescript/public-api.ts new file mode 100755 index 0000000000..bcc4746567 --- /dev/null +++ b/packages/cactus-test-geth-ledger/src/main/typescript/public-api.ts @@ -0,0 +1,7 @@ +export { + IGethTestLedgerOptions, + GETH_TEST_LEDGER_DEFAULT_OPTIONS, + WHALE_ACCOUNT_PRIVATE_KEY, + WHALE_ACCOUNT_PUBLIC_KEY, + GethTestLedger, +} from "./geth-test-ledger"; diff --git a/packages/cactus-test-geth-ledger/src/test/typescript/integration/api-surface.test.ts b/packages/cactus-test-geth-ledger/src/test/typescript/integration/api-surface.test.ts new file mode 100644 index 0000000000..a65ea58247 --- /dev/null +++ b/packages/cactus-test-geth-ledger/src/test/typescript/integration/api-surface.test.ts @@ -0,0 +1,5 @@ +import * as apiSurface from "../../../main/typescript/public-api"; + +test("Library can be loaded", async () => { + expect(apiSurface).toBeTruthy(); +}); diff --git a/packages/cactus-test-geth-ledger/src/test/typescript/integration/geth-test-ledger.test.ts b/packages/cactus-test-geth-ledger/src/test/typescript/integration/geth-test-ledger.test.ts new file mode 100644 index 0000000000..03b2c7fefb --- /dev/null +++ b/packages/cactus-test-geth-ledger/src/test/typescript/integration/geth-test-ledger.test.ts @@ -0,0 +1,115 @@ +/** + * Tests of Geth helper typescript setup class. + * + * TODO: + * - `fullContainerImageName` test + * - `className` test + * - `container`/`web3` throws when not started, works after + * - `getContainerStatus` (check if healthy after test start) + * - dont test `useRunningLedger` or `omitPull` options + * - `createEthTestAccount` test + * - `newEthPersonalAccount` test + * - Refactor to use `Clef` instead of `eth.personal` + * - `transferAssetFromCoinbase` test + * - `deployContract` test + * - `getRpcApiHttpHost` / `getRpcApiWebSocketHost` - valid URL returned + */ + +////////////////////////////////// +// Constants +////////////////////////////////// + +// Ledger settings +// const containerImageName = "ghcr.io/hyperledger/cactus-geth-all-in-one"; +// const containerImageVersion = "2022-10-18-06770b6c"; +// const useRunningLedger = false; + +// Log settings +const testLogLevel: LogLevelDesc = "info"; + +import { GethTestLedger } from "../../../main/typescript/index"; + +import { + LogLevelDesc, + LoggerProvider, + Logger, +} from "@hyperledger/cactus-common"; +import { pruneDockerAllIfGithubAction } from "@hyperledger/cactus-test-tooling"; + +import "jest-extended"; +import { Web3 } from "web3"; + +// Logger setup +const log: Logger = LoggerProvider.getOrCreate({ + label: "geth-test-ledger.test", + level: testLogLevel, +}); + +/** + * Main test suite + */ +describe("Geth Test Ledger checks", () => { + let ledger: GethTestLedger; + + ////////////////////////////////// + // Environment Setup + ////////////////////////////////// + + beforeAll(async () => { + log.info("Prune Docker..."); + await pruneDockerAllIfGithubAction({ logLevel: testLogLevel }); + + log.info("Start GethTestLedger..."); + ledger = new GethTestLedger({ + emitContainerLogs: true, + logLevel: testLogLevel, + }); + log.debug("Geth image:", ledger.fullContainerImageName); + expect(ledger).toBeTruthy(); + + await ledger.start(true); + }); + + afterAll(async () => { + log.info("FINISHING THE TESTS"); + + if (ledger) { + log.info("Stop the fabric ledger..."); + await ledger.stop(); + await ledger.destroy(); + } + + log.info("Prune Docker..."); + await pruneDockerAllIfGithubAction({ logLevel: testLogLevel }); + }); + + ////////////////////////////////// + // Tests + ////////////////////////////////// + + /** + * Check if started container is still healthy. + */ + test("Started container is healthy", async () => { + const status = await ledger.getContainerStatus(); + expect(status).toEndWith("(healthy)"); + }); + + test("web3 can be attached through HTTP endpoint", async () => { + const httpRpcHost = await ledger.getRpcApiHttpHost(); + const httpWeb3 = new Web3(httpRpcHost); + const blockNumber = await httpWeb3.eth.getBlockNumber(); + expect(blockNumber.toString()).toBeTruthy(); + }); + + test("web3 can be attached through WS endpoint", async () => { + const wsRpcHost = await ledger.getRpcApiWebSocketHost(); + const wsWeb3 = new Web3(wsRpcHost); + try { + const blockNumber = await wsWeb3.eth.getBlockNumber(); + expect(blockNumber.toString()).toBeTruthy(); + } finally { + wsWeb3.provider?.disconnect(); + } + }); +}); diff --git a/packages/cactus-test-geth-ledger/tsconfig.json b/packages/cactus-test-geth-ledger/tsconfig.json new file mode 100644 index 0000000000..95cf4429f7 --- /dev/null +++ b/packages/cactus-test-geth-ledger/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "composite": true, + "outDir": "./dist/lib/", + "declarationDir": "./dist/lib/", + "rootDir": "./src", + "tsBuildInfoFile": "../../.build-cache/cactus-test-geth-ledger.tsbuildinfo" + }, + "include": [ + "./src" + ], + "references": [ + { + "path": "../cactus-common/tsconfig.json" + }, + { + "path": "../cactus-test-tooling/tsconfig.json" + } + ] +} \ No newline at end of file diff --git a/tools/docker/geth-all-in-one/README.md b/tools/docker/geth-all-in-one/README.md index 318e4aa61c..21f20eefc6 100644 --- a/tools/docker/geth-all-in-one/README.md +++ b/tools/docker/geth-all-in-one/README.md @@ -57,7 +57,7 @@ module.exports = { ## Test Setup -- TODO +- Use typescript [GethTestLedger helper class](../../../packages/cactus-test-geth-ledger) to start this ledger and use it from inside of automatic test. ## Possible improvements diff --git a/tsconfig.json b/tsconfig.json index a7a3723df1..0e0afcf5e8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -91,6 +91,9 @@ { "path": "./packages/cactus-test-cmd-api-server/tsconfig.json" }, + { + "path": "./packages/cactus-test-geth-ledger/tsconfig.json" + }, { "path": "./packages/cactus-test-plugin-consortium-manual/tsconfig.json" }, From e1b93b369df5250ee5299a2eb7deda39a53504b7 Mon Sep 17 00:00:00 2001 From: Tomasz Awramski Date: Fri, 28 Jul 2023 17:32:26 +0200 Subject: [PATCH 3/3] test: add test for geth-test-ledger -add tests for geth-test-ledger -fix small errors in GethTestLedger class Closes: #2579 Depends on: #2577 Signed-off-by: Tomasz Awramski cacti-test-geth-ledger}/README.md (60%) rename packages/{cactus-test-geth-ledger => cacti-test-geth-ledger}/package.json (70%) rename packages/{cactus-test-geth-ledger => cacti-test-geth-ledger}/src/main/typescript/geth-test-ledger.ts (91%) rename packages/{cactus-test-geth-ledger => cacti-test-geth-ledger}/src/main/typescript/index.ts (100%) rename packages/{cactus-test-geth-ledger => cacti-test-geth-ledger}/src/main/typescript/index.web.ts (100%) rename packages/{cactus-test-geth-ledger => cacti-test-geth-ledger}/src/main/typescript/public-api.ts (100%) rename packages/{cactus-test-geth-ledger => cacti-test-geth-ledger}/src/test/typescript/integration/api-surface.test.ts (100%) create mode 100644 packages/cacti-test-geth-ledger/src/test/typescript/integration/geth-test-ledger.test.ts create mode 100644 packages/cacti-test-geth-ledger/src/test/typescript/solidity/hello-world-contract/HelloWorld.json create mode 100644 packages/cacti-test-geth-ledger/src/test/typescript/solidity/hello-world-contract/HelloWorld.sol rename packages/{cactus-test-geth-ledger => cacti-test-geth-ledger}/tsconfig.json (72%) delete mode 100644 packages/cactus-test-geth-ledger/src/test/typescript/integration/geth-test-ledger.test.ts diff --git a/jest.config.js b/jest.config.js index f495cb2302..a0056f7d97 100644 --- a/jest.config.js +++ b/jest.config.js @@ -8,6 +8,7 @@ module.exports = { testTimeout: 60 * 60 * 1000, testMatch: [ `**/cactus-*/src/test/typescript/{unit,integration,benchmark}/**/*.test.ts`, + `**/cacti-*/src/test/typescript/{unit,integration,benchmark}/**/*.test.ts`, ], // Ignore the tests that are still using tap/tape for as their test runner testPathIgnorePatterns: [ diff --git a/packages/cactus-test-geth-ledger/README.md b/packages/cacti-test-geth-ledger/README.md similarity index 60% rename from packages/cactus-test-geth-ledger/README.md rename to packages/cacti-test-geth-ledger/README.md index d0980e32ad..fd903d2234 100644 --- a/packages/cactus-test-geth-ledger/README.md +++ b/packages/cacti-test-geth-ledger/README.md @@ -1,3 +1,3 @@ -# `@hyperledger/cactus-test-geth-ledger` +# `@hyperledger/cacti-test-geth-ledger` - Helpers for running test go-ethereum ledger in test scripts. diff --git a/packages/cactus-test-geth-ledger/package.json b/packages/cacti-test-geth-ledger/package.json similarity index 70% rename from packages/cactus-test-geth-ledger/package.json rename to packages/cacti-test-geth-ledger/package.json index 04ab51f20f..51c4fc0bf1 100644 --- a/packages/cactus-test-geth-ledger/package.json +++ b/packages/cacti-test-geth-ledger/package.json @@ -1,27 +1,27 @@ { - "name": "@hyperledger/cactus-test-geth-ledger", + "name": "@hyperledger/cacti-test-geth-ledger", "version": "2.0.0-alpha.1", "description": "Helpers for running test go-ethereum ledger in test scripts.", "keywords": [ "Hyperledger", - "Cactus", + "Cacti", "Integration", "Blockchain", "Distributed Ledger Technology" ], - "homepage": "https://github.com/hyperledger/cactus#readme", + "homepage": "https://github.com/hyperledger/cacti#readme", "bugs": { - "url": "https://github.com/hyperledger/cactus/issues" + "url": "https://github.com/hyperledger/cacti/issues" }, "repository": { "type": "git", - "url": "git+https://github.com/hyperledger/cactus.git" + "url": "git+https://github.com/hyperledger/cacti.git" }, "license": "Apache-2.0", "author": { - "name": "Hyperledger Cactus Contributors", + "name": "Hyperledger Cacti Contributors", "email": "cactus@lists.hyperledger.org", - "url": "https://www.hyperledger.org/use/cactus" + "url": "https://www.hyperledger.org/use/cacti" }, "contributors": [ { @@ -37,7 +37,7 @@ ], "main": "dist/lib/main/typescript/index.js", "module": "dist/lib/main/typescript/index.js", - "browser": "dist/cactus-test-geth-ledger.web.umd.js", + "browser": "dist/cacti-test-geth-ledger.web.umd.js", "types": "dist/lib/main/typescript/index.d.ts", "files": [ "dist/*" @@ -54,9 +54,12 @@ "@hyperledger/cactus-test-tooling": "2.0.0-alpha.1", "dockerode": "3.3.0", "internal-ip": "6.2.0", + "run-time-error": "1.4.0", "web3": "dev", - "web3-eth-accounts": "dev", - "run-time-error": "1.4.0" + "web3-eth-accounts": "dev" + }, + "devDependencies": { + "@types/dockerode": "3.2.7" }, "engines": { "node": ">=10", @@ -65,7 +68,7 @@ "publishConfig": { "access": "public" }, - "browserMinified": "dist/cactus-test-geth-ledger.web.umd.min.js", - "mainMinified": "dist/cactus-test-geth-ledger.node.umd.min.js", + "browserMinified": "dist/cacti-test-geth-ledger.web.umd.min.js", + "mainMinified": "dist/cacti-test-geth-ledger.node.umd.min.js", "watch": {} } diff --git a/packages/cactus-test-geth-ledger/src/main/typescript/geth-test-ledger.ts b/packages/cacti-test-geth-ledger/src/main/typescript/geth-test-ledger.ts similarity index 91% rename from packages/cactus-test-geth-ledger/src/main/typescript/geth-test-ledger.ts rename to packages/cacti-test-geth-ledger/src/main/typescript/geth-test-ledger.ts index 4f2e6e9e56..63aefda897 100644 --- a/packages/cactus-test-geth-ledger/src/main/typescript/geth-test-ledger.ts +++ b/packages/cacti-test-geth-ledger/src/main/typescript/geth-test-ledger.ts @@ -27,8 +27,8 @@ export interface IGethTestLedgerOptions { * Default values used by GethTestLedger constructor. */ export const GETH_TEST_LEDGER_DEFAULT_OPTIONS = Object.freeze({ - containerImageName: "cactus_geth_all_in_one", - containerImageVersion: "latest", + containerImageName: "ghcr.io/hyperledger/cacti-geth-all-in-one", + containerImageVersion: "2023-07-27-2a8c48ed6", logLevel: "info" as LogLevelDesc, emitContainerLogs: false, envVars: [], @@ -36,9 +36,9 @@ export const GETH_TEST_LEDGER_DEFAULT_OPTIONS = Object.freeze({ }); export const WHALE_ACCOUNT_PRIVATE_KEY = - "86bbf98cf5e5b1c43d2c8701764897357e0fa24982c0137efabf6dc3a6e7b69e"; + "0x86bbf98cf5e5b1c43d2c8701764897357e0fa24982c0137efabf6dc3a6e7b69e"; export const WHALE_ACCOUNT_PUBLIC_KEY = - "6a2ec8c50ba1a9ce47c52d1cb5b7136ee9d0ccc0"; + "0x6a2ec8c50ba1a9ce47c52d1cb5b7136ee9d0ccc0"; export class GethTestLedger { public static readonly CLASS_NAME = "GethTestLedger"; @@ -205,13 +205,20 @@ export class GethTestLedger { }); } - try { - await Containers.waitForHealthCheck(this._containerId); - this._web3 = new Web3(await this.getRpcApiHttpHost()); - resolve(container); - } catch (ex) { - reject(ex); + if (!this._containerId) { + const eMsg = + "InvalidState: this._container is falsy. " + + "Cannot attempt to wait for a passing healthcheck without it."; + throw new RuntimeError(eMsg); } + + // If this (the promise factory function) throws, the parent promise + // will re-throw it for us by default so we don't need to wrap it in a + // try-catch block of it's own just to make sure it gets rejected. + await Containers.waitForHealthCheck(this._containerId); + const rpcApiHttpHost = await this.getRpcApiHttpHost(); + this._web3 = new Web3(rpcApiHttpHost); + resolve(container); }); }); } @@ -289,11 +296,10 @@ export class GethTestLedger { * @returns New account address */ public async newEthPersonalAccount( - seedMoney = 10e8, + seedMoney = 0x10e8, password = "test", ): Promise { const account = await this.web3.eth.personal.newAccount(password); - const receipt = await this.transferAssetFromCoinbase(account, seedMoney); if (receipt instanceof Error) { @@ -321,6 +327,7 @@ export class GethTestLedger { from: WHALE_ACCOUNT_PUBLIC_KEY, to: targetAccount, value: value, + gasPrice: await this.web3.eth.getGasPrice(), gas: 1000000, }, WHALE_ACCOUNT_PRIVATE_KEY, @@ -358,7 +365,8 @@ export class GethTestLedger { { from: WHALE_ACCOUNT_PUBLIC_KEY, data: contractTx.encodeABI(), - gas: 8000000, // Max possible gas + gasPrice: await this.web3.eth.getGasPrice(), + gas: 1000000, nonce: await this.web3.eth.getTransactionCount( WHALE_ACCOUNT_PUBLIC_KEY, ), diff --git a/packages/cactus-test-geth-ledger/src/main/typescript/index.ts b/packages/cacti-test-geth-ledger/src/main/typescript/index.ts similarity index 100% rename from packages/cactus-test-geth-ledger/src/main/typescript/index.ts rename to packages/cacti-test-geth-ledger/src/main/typescript/index.ts diff --git a/packages/cactus-test-geth-ledger/src/main/typescript/index.web.ts b/packages/cacti-test-geth-ledger/src/main/typescript/index.web.ts similarity index 100% rename from packages/cactus-test-geth-ledger/src/main/typescript/index.web.ts rename to packages/cacti-test-geth-ledger/src/main/typescript/index.web.ts diff --git a/packages/cactus-test-geth-ledger/src/main/typescript/public-api.ts b/packages/cacti-test-geth-ledger/src/main/typescript/public-api.ts similarity index 100% rename from packages/cactus-test-geth-ledger/src/main/typescript/public-api.ts rename to packages/cacti-test-geth-ledger/src/main/typescript/public-api.ts diff --git a/packages/cactus-test-geth-ledger/src/test/typescript/integration/api-surface.test.ts b/packages/cacti-test-geth-ledger/src/test/typescript/integration/api-surface.test.ts similarity index 100% rename from packages/cactus-test-geth-ledger/src/test/typescript/integration/api-surface.test.ts rename to packages/cacti-test-geth-ledger/src/test/typescript/integration/api-surface.test.ts diff --git a/packages/cacti-test-geth-ledger/src/test/typescript/integration/geth-test-ledger.test.ts b/packages/cacti-test-geth-ledger/src/test/typescript/integration/geth-test-ledger.test.ts new file mode 100644 index 0000000000..5008ec00c5 --- /dev/null +++ b/packages/cacti-test-geth-ledger/src/test/typescript/integration/geth-test-ledger.test.ts @@ -0,0 +1,184 @@ +/** + * Tests of Geth helper typescript setup class. + * + * TODO: + * - Refactor to use `Clef` instead of `eth.personal` + */ + +////////////////////////////////// +// Constants +////////////////////////////////// + +// Ledger settings +// const containerImageName = "ghcr.io/hyperledger/cactus-geth-all-in-one"; +// const containerImageVersion = "2022-10-18-06770b6c"; +// const useRunningLedger = false; + +// Log settings +const testLogLevel: LogLevelDesc = "debug"; + +import { GethTestLedger } from "../../../main/typescript/index"; +import contractData from "../solidity/hello-world-contract/HelloWorld.json"; + +import { + LogLevelDesc, + LoggerProvider, + Logger, +} from "@hyperledger/cactus-common"; +import { pruneDockerAllIfGithubAction } from "@hyperledger/cactus-test-tooling"; + +import "jest-extended"; +import { Web3 } from "web3"; + +// Logger setup +const log: Logger = LoggerProvider.getOrCreate({ + label: "geth-test-ledger.test", + level: testLogLevel, +}); + +/** + * Main test suite + */ + +describe("Geth Test Ledger checks", () => { + let ledger: GethTestLedger; + let testEthAcc: any; + let web3Instance: Web3; + ////////////////////////////////// + // Environment Setup + ////////////////////////////////// + + beforeAll(async () => { + log.info("Prune Docker..."); + await pruneDockerAllIfGithubAction({ logLevel: testLogLevel }); + + log.info("Start GethTestLedger..."); + ledger = new GethTestLedger({ + emitContainerLogs: true, + logLevel: testLogLevel, + }); + expect(ledger).toBeTruthy(); + log.debug("Geth image:", ledger.fullContainerImageName); + + await ledger.start(false); + web3Instance = new Web3(await ledger.getRpcApiHttpHost()); + expect(web3Instance).toBeTruthy; + }); + + afterAll(async () => { + log.info("FINISHING THE TESTS"); + + if (ledger) { + log.info("Stop the fabric ledger..."); + await ledger.stop(); + await ledger.destroy(); + } + + log.info("Prune Docker..."); + await pruneDockerAllIfGithubAction({ logLevel: testLogLevel }); + }); + + ////////////////////////////////// + // Tests + ////////////////////////////////// + + /** + * Check if started container is still healthy. + */ + test("Started container is healthy", async () => { + const status = await ledger.getContainerStatus(); + expect(status).toEndWith("(healthy)"); + }); + + test("web3 can be attached through HTTP endpoint", async () => { + const httpRpcHost = await ledger.getRpcApiHttpHost(); + const httpWeb3 = new Web3(httpRpcHost); + const blockNumber = await httpWeb3.eth.getBlockNumber(); + expect(blockNumber.toString()).toBeTruthy(); + }); + + test("web3 can be attached through WS endpoint", async () => { + const wsRpcHost = await ledger.getRpcApiWebSocketHost(); + const wsWeb3 = new Web3(wsRpcHost); + try { + const blockNumber = await wsWeb3.eth.getBlockNumber(); + expect(blockNumber.toString()).toBeTruthy(); + } finally { + wsWeb3.provider?.disconnect(); + } + }); + + test("Class name is correct", async () => { + const className = ledger.className; + expect(className).toEqual("GethTestLedger"); + }); + + test("Method createEthTestAccount works", async () => { + testEthAcc = await ledger.createEthTestAccount(); + + expect(testEthAcc).toBeTruthy(); + expect(testEthAcc.address).toHaveLength(42); + expect(testEthAcc.address).toStartWith("0x"); + }); + + test("Method newEthPersonalAccount works", async () => { + const testEthAccount = await ledger.newEthPersonalAccount(); + + expect(testEthAccount).toBeTruthy(); + expect(testEthAccount).toHaveLength(42); + expect(testEthAccount).toStartWith("0x"); + }); + + test("Method transferAssetFromCoinbase works", async () => { + const txReceipt = await ledger.transferAssetFromCoinbase( + testEthAcc.address, + 1000, + ); + + expect(txReceipt).toBeTruthy(); + expect(web3Instance.utils.toChecksumAddress(txReceipt.to)).toEqual( + testEthAcc.address, + ); + expect(await web3Instance.eth.getBalance(testEthAcc.address)).toEqual( + BigInt(1000001000), + ); + }); + + test("Method deployContract works and returns contract address", async () => { + const deployedData = await ledger.deployContract( + contractData.abi, + contractData.bytecode, + [], + ); + + const contract = new web3Instance.eth.Contract( + contractData.abi, + deployedData.contractAddress, + ); + + const contractCallResult = await contract.methods.sayHello().call(); + + expect(deployedData).toBeTruthy(); + expect(deployedData.contractAddress).toStartWith("0x"); + expect(deployedData.contractAddress).toHaveLength(42); + expect(contractCallResult).toEqual("Hello World!"); + }); + + test("Method getRpcApiHttpHost works and overlaps with actual open ports", async () => { + const httpHostAddress = await ledger.getRpcApiHttpHost(); + const httpPort = await ledger.getHostPortHttp(); + + expect(httpHostAddress).toBeTruthy(); + expect(httpHostAddress).toStartWith("http://"); + expect(httpHostAddress).toContain(`${httpPort}`); + }); + + test("Method getRpcApiWebSocketHost works and overlaps with actual open ports", async () => { + const wsHostAddress = await ledger.getRpcApiWebSocketHost(); + const wsPort = await ledger.getHostPortWs(); + + expect(wsHostAddress).toBeTruthy(); + expect(wsHostAddress).toStartWith("ws://"); + expect(wsHostAddress).toContain(`${wsPort}`); + }); +}); diff --git a/packages/cacti-test-geth-ledger/src/test/typescript/solidity/hello-world-contract/HelloWorld.json b/packages/cacti-test-geth-ledger/src/test/typescript/solidity/hello-world-contract/HelloWorld.json new file mode 100644 index 0000000000..29f7eb9fc7 --- /dev/null +++ b/packages/cacti-test-geth-ledger/src/test/typescript/solidity/hello-world-contract/HelloWorld.json @@ -0,0 +1,418 @@ +{ + "contractName": "HelloWorld", + "abi": [ + { + "inputs": [], + "name": "getName", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "sayHello", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "newName", + "type": "string" + } + ], + "name": "setName", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "metadata": "{\"compiler\":{\"version\":\"0.7.2+commit.51b20bc0\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"getName\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sayHello\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"newName\",\"type\":\"string\"}],\"name\":\"setName\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"/home/peter/a/blockchain/blockchain-integration-framework/packages/cactus-test-plugin-ledger-connector-quorum/src/test/solidity/hello-world-contract/HelloWorld.sol\":\"HelloWorld\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"/home/peter/a/blockchain/blockchain-integration-framework/packages/cactus-test-plugin-ledger-connector-quorum/src/test/solidity/hello-world-contract/HelloWorld.sol\":{\"keccak256\":\"0x0b78fa11f33f7936a80da194c49f04198e38947e3f98f3a7b765b4adb4c455c1\",\"urls\":[\"bzz-raw://12697aa12341c70ed7a411a27a17398dcb2d4336a14dac51845e2123acf174c7\",\"dweb:/ipfs/QmPhH1UbHtUeeen9W2qMDwEVVWAtVJSMN29Nch5q8Gax1D\"]}},\"version\":1}", + "bytecode": "60c0604052600d60808190526c4361707461696e43616374757360981b60a090815261002e9160009190610041565b5034801561003b57600080fd5b506100d4565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061008257805160ff19168380011785556100af565b828001600101855582156100af579182015b828111156100af578251825591602001919060010190610094565b506100bb9291506100bf565b5090565b5b808211156100bb57600081556001016100c0565b61030f806100e36000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806317d7de7c14610046578063c47f0027146100c3578063ef5fb05b1461016b575b600080fd5b61004e610173565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610088578181015183820152602001610070565b50505050905090810190601f1680156100b55780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610169600480360360208110156100d957600080fd5b8101906020810181356401000000008111156100f457600080fd5b82018360208201111561010657600080fd5b8035906020019184600183028401116401000000008311171561012857600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610209945050505050565b005b61004e610220565b60008054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156101ff5780601f106101d4576101008083540402835291602001916101ff565b820191906000526020600020905b8154815290600101906020018083116101e257829003601f168201915b5050505050905090565b805161021c906000906020840190610246565b5050565b60408051808201909152600c81526b48656c6c6f20576f726c642160a01b602082015290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061028757805160ff19168380011785556102b4565b828001600101855582156102b4579182015b828111156102b4578251825591602001919060010190610299565b506102c09291506102c4565b5090565b5b808211156102c057600081556001016102c556fea2646970667358221220b72c0e77fdf429e47051940ba62646ae01296865473f15795ffca6619fe80f9964736f6c63430007020033", + "deployedBytecode": "608060405234801561001057600080fd5b50600436106100415760003560e01c806317d7de7c14610046578063c47f0027146100c3578063ef5fb05b1461016b575b600080fd5b61004e610173565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610088578181015183820152602001610070565b50505050905090810190601f1680156100b55780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610169600480360360208110156100d957600080fd5b8101906020810181356401000000008111156100f457600080fd5b82018360208201111561010657600080fd5b8035906020019184600183028401116401000000008311171561012857600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610209945050505050565b005b61004e610220565b60008054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156101ff5780601f106101d4576101008083540402835291602001916101ff565b820191906000526020600020905b8154815290600101906020018083116101e257829003601f168201915b5050505050905090565b805161021c906000906020840190610246565b5050565b60408051808201909152600c81526b48656c6c6f20576f726c642160a01b602082015290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061028757805160ff19168380011785556102b4565b828001600101855582156102b4579182015b828111156102b4578251825591602001919060010190610299565b506102c09291506102c4565b5090565b5b808211156102c057600081556001016102c556fea2646970667358221220b72c0e77fdf429e47051940ba62646ae01296865473f15795ffca6619fe80f9964736f6c63430007020033", + "sourceMap": "463:37:0:-:0;439:322;463:37;;439:322;463:37;;;-1:-1:-1;;;463:37:0;;;;;;-1:-1:-1;;463:37:0;;:::i;:::-;;439:322;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;439:322:0;;;-1:-1:-1;439:322:0;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;", + "deployedSourceMap": "439:322:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;598:81;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;683:76;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;683:76:0;;-1:-1:-1;683:76:0;;-1:-1:-1;;;;;683:76:0:i;:::-;;505:89;;;:::i;598:81::-;670:4;663:11;;;;;;;;-1:-1:-1;;663:11:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;638:13;;663:11;;670:4;;663:11;;670:4;663:11;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;598:81;:::o;683:76::-;740:14;;;;:4;;:14;;;;;:::i;:::-;;683:76;:::o;505:89::-;568:21;;;;;;;;;;;;-1:-1:-1;;;568:21:0;;;;505:89;:::o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;", + "sourcePath": "/home/peter/a/blockchain/blockchain-integration-framework/packages/cactus-test-plugin-ledger-connector-quorum/src/test/solidity/hello-world-contract/HelloWorld.sol", + "compiler": { + "name": "solc", + "version": "0.7.2+commit.51b20bc0" + }, + "networks":{}, + "ast": { + "absolutePath": "/home/peter/a/blockchain/blockchain-integration-framework/packages/cactus-test-plugin-ledger-connector-quorum/src/test/solidity/hello-world-contract/HelloWorld.sol", + "exportedSymbols": { + "HelloWorld": [ + 31 + ] + }, + "id": 32, + "nodeType": "SourceUnit", + "nodes": [ + { + "id": 1, + "literals": [ + "solidity", + ">=", + "0.7", + ".0" + ], + "nodeType": "PragmaDirective", + "src": "413:24:0" + }, + { + "abstract": false, + "baseContracts": [], + "contractDependencies": [], + "contractKind": "contract", + "fullyImplemented": true, + "id": 31, + "linearizedBaseContracts": [ + 31 + ], + "name": "HelloWorld", + "nodeType": "ContractDefinition", + "nodes": [ + { + "constant": false, + "id": 4, + "mutability": "mutable", + "name": "name", + "nodeType": "VariableDeclaration", + "scope": 31, + "src": "463:37:0", + "stateVariable": true, + "storageLocation": "default", + "typeDescriptions": { + "typeIdentifier": "t_string_storage", + "typeString": "string" + }, + "typeName": { + "id": 2, + "name": "string", + "nodeType": "ElementaryTypeName", + "src": "463:6:0", + "typeDescriptions": { + "typeIdentifier": "t_string_storage_ptr", + "typeString": "string" + } + }, + "value": { + "hexValue": "4361707461696e436163747573", + "id": 3, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "string", + "lValueRequested": false, + "nodeType": "Literal", + "src": "485:15:0", + "typeDescriptions": { + "typeIdentifier": "t_stringliteral_bdd2f21877c99489ddcc32737686677f40d460368c7982ce22ce4f72b41b0312", + "typeString": "literal_string \"CaptainCactus\"" + }, + "value": "CaptainCactus" + }, + "visibility": "private" + }, + { + "body": { + "id": 11, + "nodeType": "Block", + "src": "562:32:0", + "statements": [ + { + "expression": { + "hexValue": "48656c6c6f20576f726c6421", + "id": 9, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "string", + "lValueRequested": false, + "nodeType": "Literal", + "src": "575:14:0", + "typeDescriptions": { + "typeIdentifier": "t_stringliteral_3ea2f1d0abf3fc66cf29eebb70cbd4e7fe762ef8a09bcc06c8edf641230afec0", + "typeString": "literal_string \"Hello World!\"" + }, + "value": "Hello World!" + }, + "functionReturnParameters": 8, + "id": 10, + "nodeType": "Return", + "src": "568:21:0" + } + ] + }, + "functionSelector": "ef5fb05b", + "id": 12, + "implemented": true, + "kind": "function", + "modifiers": [], + "name": "sayHello", + "nodeType": "FunctionDefinition", + "parameters": { + "id": 5, + "nodeType": "ParameterList", + "parameters": [], + "src": "523:2:0" + }, + "returnParameters": { + "id": 8, + "nodeType": "ParameterList", + "parameters": [ + { + "constant": false, + "id": 7, + "mutability": "mutable", + "name": "", + "nodeType": "VariableDeclaration", + "scope": 12, + "src": "547:13:0", + "stateVariable": false, + "storageLocation": "memory", + "typeDescriptions": { + "typeIdentifier": "t_string_memory_ptr", + "typeString": "string" + }, + "typeName": { + "id": 6, + "name": "string", + "nodeType": "ElementaryTypeName", + "src": "547:6:0", + "typeDescriptions": { + "typeIdentifier": "t_string_storage_ptr", + "typeString": "string" + } + }, + "visibility": "internal" + } + ], + "src": "546:15:0" + }, + "scope": 31, + "src": "505:89:0", + "stateMutability": "pure", + "virtual": false, + "visibility": "public" + }, + { + "body": { + "id": 19, + "nodeType": "Block", + "src": "655:24:0", + "statements": [ + { + "expression": { + "id": 17, + "name": "name", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 4, + "src": "670:4:0", + "typeDescriptions": { + "typeIdentifier": "t_string_storage", + "typeString": "string storage ref" + } + }, + "functionReturnParameters": 16, + "id": 18, + "nodeType": "Return", + "src": "663:11:0" + } + ] + }, + "functionSelector": "17d7de7c", + "id": 20, + "implemented": true, + "kind": "function", + "modifiers": [], + "name": "getName", + "nodeType": "FunctionDefinition", + "parameters": { + "id": 13, + "nodeType": "ParameterList", + "parameters": [], + "src": "614:2:0" + }, + "returnParameters": { + "id": 16, + "nodeType": "ParameterList", + "parameters": [ + { + "constant": false, + "id": 15, + "mutability": "mutable", + "name": "", + "nodeType": "VariableDeclaration", + "scope": 20, + "src": "638:13:0", + "stateVariable": false, + "storageLocation": "memory", + "typeDescriptions": { + "typeIdentifier": "t_string_memory_ptr", + "typeString": "string" + }, + "typeName": { + "id": 14, + "name": "string", + "nodeType": "ElementaryTypeName", + "src": "638:6:0", + "typeDescriptions": { + "typeIdentifier": "t_string_storage_ptr", + "typeString": "string" + } + }, + "visibility": "internal" + } + ], + "src": "637:15:0" + }, + "scope": 31, + "src": "598:81:0", + "stateMutability": "view", + "virtual": false, + "visibility": "public" + }, + { + "body": { + "id": 29, + "nodeType": "Block", + "src": "732:27:0", + "statements": [ + { + "expression": { + "id": 27, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "leftHandSide": { + "id": 25, + "name": "name", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 4, + "src": "740:4:0", + "typeDescriptions": { + "typeIdentifier": "t_string_storage", + "typeString": "string storage ref" + } + }, + "nodeType": "Assignment", + "operator": "=", + "rightHandSide": { + "id": 26, + "name": "newName", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 22, + "src": "747:7:0", + "typeDescriptions": { + "typeIdentifier": "t_string_memory_ptr", + "typeString": "string memory" + } + }, + "src": "740:14:0", + "typeDescriptions": { + "typeIdentifier": "t_string_storage", + "typeString": "string storage ref" + } + }, + "id": 28, + "nodeType": "ExpressionStatement", + "src": "740:14:0" + } + ] + }, + "functionSelector": "c47f0027", + "id": 30, + "implemented": true, + "kind": "function", + "modifiers": [], + "name": "setName", + "nodeType": "FunctionDefinition", + "parameters": { + "id": 23, + "nodeType": "ParameterList", + "parameters": [ + { + "constant": false, + "id": 22, + "mutability": "mutable", + "name": "newName", + "nodeType": "VariableDeclaration", + "scope": 30, + "src": "700:21:0", + "stateVariable": false, + "storageLocation": "memory", + "typeDescriptions": { + "typeIdentifier": "t_string_memory_ptr", + "typeString": "string" + }, + "typeName": { + "id": 21, + "name": "string", + "nodeType": "ElementaryTypeName", + "src": "700:6:0", + "typeDescriptions": { + "typeIdentifier": "t_string_storage_ptr", + "typeString": "string" + } + }, + "visibility": "internal" + } + ], + "src": "699:23:0" + }, + "returnParameters": { + "id": 24, + "nodeType": "ParameterList", + "parameters": [], + "src": "732:0:0" + }, + "scope": 31, + "src": "683:76:0", + "stateMutability": "nonpayable", + "virtual": false, + "visibility": "public" + } + ], + "scope": 32, + "src": "439:322:0" + } + ], + "src": "413:349:0" + }, + "functionHashes": { + "getName()": "17d7de7c", + "sayHello()": "ef5fb05b", + "setName(string)": "c47f0027" + }, + "gasEstimates": { + "creation": { + "codeDepositCost": "156600", + "executionCost": "infinite", + "totalCost": "infinite" + }, + "external": { + "getName()": "infinite", + "sayHello()": "infinite", + "setName(string)": "infinite" + } + } +} \ No newline at end of file diff --git a/packages/cacti-test-geth-ledger/src/test/typescript/solidity/hello-world-contract/HelloWorld.sol b/packages/cacti-test-geth-ledger/src/test/typescript/solidity/hello-world-contract/HelloWorld.sol new file mode 100644 index 0000000000..3384d9077c --- /dev/null +++ b/packages/cacti-test-geth-ledger/src/test/typescript/solidity/hello-world-contract/HelloWorld.sol @@ -0,0 +1,26 @@ +// ***************************************************************************** +// IMPORTANT: If you update this code then make sure to recompile +// it and update the .json file as well so that they +// remain in sync for consistent test executions. +// With that said, there shouldn't be any reason to recompile this, like ever... +// ***************************************************************************** + +pragma solidity >=0.7.0; + +contract HelloWorld { + string private name = "gethLedger"; + + function sayHello () public pure returns (string memory) { + return 'Hello World!'; + } + + function getName() public view returns (string memory) + { + return name; + } + + function setName(string memory newName) public + { + name = newName; + } +} diff --git a/packages/cactus-test-geth-ledger/tsconfig.json b/packages/cacti-test-geth-ledger/tsconfig.json similarity index 72% rename from packages/cactus-test-geth-ledger/tsconfig.json rename to packages/cacti-test-geth-ledger/tsconfig.json index 95cf4429f7..07847c71db 100644 --- a/packages/cactus-test-geth-ledger/tsconfig.json +++ b/packages/cacti-test-geth-ledger/tsconfig.json @@ -5,11 +5,9 @@ "outDir": "./dist/lib/", "declarationDir": "./dist/lib/", "rootDir": "./src", - "tsBuildInfoFile": "../../.build-cache/cactus-test-geth-ledger.tsbuildinfo" + "tsBuildInfoFile": "../../.build-cache/cacti-test-geth-ledger.tsbuildinfo" }, - "include": [ - "./src" - ], + "include": ["./src", "./src/**/*.json"], "references": [ { "path": "../cactus-common/tsconfig.json" @@ -18,4 +16,4 @@ "path": "../cactus-test-tooling/tsconfig.json" } ] -} \ No newline at end of file +} diff --git a/packages/cactus-test-geth-ledger/src/test/typescript/integration/geth-test-ledger.test.ts b/packages/cactus-test-geth-ledger/src/test/typescript/integration/geth-test-ledger.test.ts deleted file mode 100644 index 03b2c7fefb..0000000000 --- a/packages/cactus-test-geth-ledger/src/test/typescript/integration/geth-test-ledger.test.ts +++ /dev/null @@ -1,115 +0,0 @@ -/** - * Tests of Geth helper typescript setup class. - * - * TODO: - * - `fullContainerImageName` test - * - `className` test - * - `container`/`web3` throws when not started, works after - * - `getContainerStatus` (check if healthy after test start) - * - dont test `useRunningLedger` or `omitPull` options - * - `createEthTestAccount` test - * - `newEthPersonalAccount` test - * - Refactor to use `Clef` instead of `eth.personal` - * - `transferAssetFromCoinbase` test - * - `deployContract` test - * - `getRpcApiHttpHost` / `getRpcApiWebSocketHost` - valid URL returned - */ - -////////////////////////////////// -// Constants -////////////////////////////////// - -// Ledger settings -// const containerImageName = "ghcr.io/hyperledger/cactus-geth-all-in-one"; -// const containerImageVersion = "2022-10-18-06770b6c"; -// const useRunningLedger = false; - -// Log settings -const testLogLevel: LogLevelDesc = "info"; - -import { GethTestLedger } from "../../../main/typescript/index"; - -import { - LogLevelDesc, - LoggerProvider, - Logger, -} from "@hyperledger/cactus-common"; -import { pruneDockerAllIfGithubAction } from "@hyperledger/cactus-test-tooling"; - -import "jest-extended"; -import { Web3 } from "web3"; - -// Logger setup -const log: Logger = LoggerProvider.getOrCreate({ - label: "geth-test-ledger.test", - level: testLogLevel, -}); - -/** - * Main test suite - */ -describe("Geth Test Ledger checks", () => { - let ledger: GethTestLedger; - - ////////////////////////////////// - // Environment Setup - ////////////////////////////////// - - beforeAll(async () => { - log.info("Prune Docker..."); - await pruneDockerAllIfGithubAction({ logLevel: testLogLevel }); - - log.info("Start GethTestLedger..."); - ledger = new GethTestLedger({ - emitContainerLogs: true, - logLevel: testLogLevel, - }); - log.debug("Geth image:", ledger.fullContainerImageName); - expect(ledger).toBeTruthy(); - - await ledger.start(true); - }); - - afterAll(async () => { - log.info("FINISHING THE TESTS"); - - if (ledger) { - log.info("Stop the fabric ledger..."); - await ledger.stop(); - await ledger.destroy(); - } - - log.info("Prune Docker..."); - await pruneDockerAllIfGithubAction({ logLevel: testLogLevel }); - }); - - ////////////////////////////////// - // Tests - ////////////////////////////////// - - /** - * Check if started container is still healthy. - */ - test("Started container is healthy", async () => { - const status = await ledger.getContainerStatus(); - expect(status).toEndWith("(healthy)"); - }); - - test("web3 can be attached through HTTP endpoint", async () => { - const httpRpcHost = await ledger.getRpcApiHttpHost(); - const httpWeb3 = new Web3(httpRpcHost); - const blockNumber = await httpWeb3.eth.getBlockNumber(); - expect(blockNumber.toString()).toBeTruthy(); - }); - - test("web3 can be attached through WS endpoint", async () => { - const wsRpcHost = await ledger.getRpcApiWebSocketHost(); - const wsWeb3 = new Web3(wsRpcHost); - try { - const blockNumber = await wsWeb3.eth.getBlockNumber(); - expect(blockNumber.toString()).toBeTruthy(); - } finally { - wsWeb3.provider?.disconnect(); - } - }); -}); diff --git a/tools/docker/geth-all-in-one/README.md b/tools/docker/geth-all-in-one/README.md index 21f20eefc6..fd5dee4c92 100644 --- a/tools/docker/geth-all-in-one/README.md +++ b/tools/docker/geth-all-in-one/README.md @@ -57,7 +57,7 @@ module.exports = { ## Test Setup -- Use typescript [GethTestLedger helper class](../../../packages/cactus-test-geth-ledger) to start this ledger and use it from inside of automatic test. +- Use typescript [GethTestLedger helper class](../../../packages/cacti-test-geth-ledger) to start this ledger and use it from inside of automatic test. ## Possible improvements diff --git a/tsconfig.json b/tsconfig.json index 0e0afcf5e8..287d5b5c42 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -92,7 +92,7 @@ "path": "./packages/cactus-test-cmd-api-server/tsconfig.json" }, { - "path": "./packages/cactus-test-geth-ledger/tsconfig.json" + "path": "./packages/cacti-test-geth-ledger/tsconfig.json" }, { "path": "./packages/cactus-test-plugin-consortium-manual/tsconfig.json" diff --git a/yarn.lock b/yarn.lock index 8330088f08..2775d34a03 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19,6 +19,13 @@ __metadata: languageName: node linkType: hard +"@adraffy/ens-normalize@npm:^1.8.8": + version: 1.9.4 + resolution: "@adraffy/ens-normalize@npm:1.9.4" + checksum: 7d7fff58ebe2c4961f7e5e61dad123aa6a63fec0df5c84af1fa41079dc05d398599690be4427b3a94d2baa94084544bcfdf2d51cbed7504b9b0583b0960ad550 + languageName: node + linkType: hard + "@ampproject/remapping@npm:2.2.0": version: 2.2.0 resolution: "@ampproject/remapping@npm:2.2.0" @@ -5068,6 +5075,15 @@ __metadata: languageName: node linkType: hard +"@ethereumjs/rlp@npm:^4.0.1": + version: 4.0.1 + resolution: "@ethereumjs/rlp@npm:4.0.1" + bin: + rlp: bin/rlp + checksum: 30db19c78faa2b6ff27275ab767646929207bb207f903f09eb3e4c273ce2738b45f3c82169ddacd67468b4f063d8d96035f2bf36f02b6b7e4d928eefe2e3ecbc + languageName: node + linkType: hard + "@ethereumjs/tx@npm:3.3.2": version: 3.3.2 resolution: "@ethereumjs/tx@npm:3.3.2" @@ -6080,6 +6096,21 @@ __metadata: languageName: unknown linkType: soft +"@hyperledger/cacti-test-geth-ledger@workspace:packages/cacti-test-geth-ledger": + version: 0.0.0-use.local + resolution: "@hyperledger/cacti-test-geth-ledger@workspace:packages/cacti-test-geth-ledger" + dependencies: + "@hyperledger/cactus-common": 2.0.0-alpha.1 + "@hyperledger/cactus-test-tooling": 2.0.0-alpha.1 + "@types/dockerode": 3.2.7 + dockerode: 3.3.0 + internal-ip: 6.2.0 + run-time-error: 1.4.0 + web3: dev + web3-eth-accounts: dev + languageName: unknown + linkType: soft + "@hyperledger/cacti-weaver-besu-cli@workspace:weaver/samples/besu/besu-cli": version: 0.0.0-use.local resolution: "@hyperledger/cacti-weaver-besu-cli@workspace:weaver/samples/besu/besu-cli" @@ -13107,7 +13138,7 @@ __metadata: languageName: node linkType: hard -"@types/ws@npm:^8.2.2": +"@types/ws@npm:8.5.3, @types/ws@npm:^8.2.2": version: 8.5.3 resolution: "@types/ws@npm:8.5.3" dependencies: @@ -19317,6 +19348,15 @@ __metadata: languageName: node linkType: hard +"crc-32@npm:^1.2.2": + version: 1.2.2 + resolution: "crc-32@npm:1.2.2" + bin: + crc32: bin/crc32.njs + checksum: ad2d0ad0cbd465b75dcaeeff0600f8195b686816ab5f3ba4c6e052a07f728c3e70df2e3ca9fd3d4484dc4ba70586e161ca5a2334ec8bf5a41bf022a6103ff243 + languageName: node + linkType: hard + "crc32-stream@npm:^4.0.2": version: 4.0.2 resolution: "crc32-stream@npm:4.0.2" @@ -29217,6 +29257,15 @@ __metadata: languageName: node linkType: hard +"isomorphic-ws@npm:^5.0.0": + version: 5.0.0 + resolution: "isomorphic-ws@npm:5.0.0" + peerDependencies: + ws: "*" + checksum: e20eb2aee09ba96247465fda40c6d22c1153394c0144fa34fe6609f341af4c8c564f60ea3ba762335a7a9c306809349f9b863c8beedf2beea09b299834ad5398 + languageName: node + linkType: hard + "isstream@npm:0.1.x, isstream@npm:~0.1.2": version: 0.1.2 resolution: "isstream@npm:0.1.2" @@ -47596,6 +47645,34 @@ __metadata: languageName: node linkType: hard +"web3-core@npm:4.1.1-dev.622174c.0+622174c": + version: 4.1.1-dev.622174c.0 + resolution: "web3-core@npm:4.1.1-dev.622174c.0" + dependencies: + web3-errors: 1.1.1-dev.622174c.0+622174c + web3-eth-iban: 4.0.5-dev.622174c.0+622174c + web3-providers-http: 4.0.5-dev.622174c.0+622174c + web3-providers-ipc: 4.0.5-dev.622174c.0+622174c + web3-providers-ws: 4.0.5-dev.622174c.0+622174c + web3-types: 1.1.1-dev.622174c.0+622174c + web3-utils: 4.0.5-dev.622174c.0+622174c + web3-validator: 2.0.1-dev.622174c.0+622174c + dependenciesMeta: + web3-providers-ipc: + optional: true + checksum: 9ebe6d610a4ce4b687937ab5a9d80e78cc87234e8e03f48740f8a4fa80e76166f2e17045648978fce1406c2e961477cbe56195eaca45f5e96d9f8b1bd9a6b479 + languageName: node + linkType: hard + +"web3-errors@npm:1.1.1-dev.622174c.0+622174c": + version: 1.1.1-dev.622174c.0 + resolution: "web3-errors@npm:1.1.1-dev.622174c.0" + dependencies: + web3-types: 1.1.1-dev.622174c.0+622174c + checksum: 28c71b6c185fdc5172c62ca29dd838dd5c8e92cbb02e51fc947471e7f35f786c23a8965e8fc60cdc6cae4466dc94e91a9a279ba9f7237d1ff803a6cc35366592 + languageName: node + linkType: hard + "web3-errors@npm:^1.0.2": version: 1.0.2 resolution: "web3-errors@npm:1.0.2" @@ -47688,6 +47765,19 @@ __metadata: languageName: node linkType: hard +"web3-eth-abi@npm:4.1.1-dev.622174c.0+622174c": + version: 4.1.1-dev.622174c.0 + resolution: "web3-eth-abi@npm:4.1.1-dev.622174c.0" + dependencies: + "@ethersproject/abi": ^5.7.0 + "@ethersproject/bignumber": ^5.7.0 + web3-errors: 1.1.1-dev.622174c.0+622174c + web3-types: 1.1.1-dev.622174c.0+622174c + web3-utils: 4.0.5-dev.622174c.0+622174c + checksum: d85fc4c1c58ac89dcd983af3c2d43fcccb56ca03401d25550034fe666cc9f0d83c561509ba06f1ef4e592302787a0054e136e01309c46f6c8d3b26771d262d07 + languageName: node + linkType: hard + "web3-eth-accounts@npm:1.10.0": version: 1.10.0 resolution: "web3-eth-accounts@npm:1.10.0" @@ -47819,6 +47909,21 @@ __metadata: languageName: node linkType: hard +"web3-eth-accounts@npm:4.0.5-dev.622174c.0+622174c, web3-eth-accounts@npm:dev": + version: 4.0.5-dev.622174c.0 + resolution: "web3-eth-accounts@npm:4.0.5-dev.622174c.0" + dependencies: + "@ethereumjs/rlp": ^4.0.1 + crc-32: ^1.2.2 + ethereum-cryptography: ^2.0.0 + web3-errors: 1.1.1-dev.622174c.0+622174c + web3-types: 1.1.1-dev.622174c.0+622174c + web3-utils: 4.0.5-dev.622174c.0+622174c + web3-validator: 2.0.1-dev.622174c.0+622174c + checksum: 1e5df3ee2f93cbcf065a3b4de4a819c51470209bfb6e0097413593694926dd256debcc6e68abe10dfc141824b6addc11ef5e9a7d6739e1669e762ff5f7fac8a8 + languageName: node + linkType: hard + "web3-eth-contract@npm:1.10.0": version: 1.10.0 resolution: "web3-eth-contract@npm:1.10.0" @@ -47931,6 +48036,21 @@ __metadata: languageName: node linkType: hard +"web3-eth-contract@npm:4.0.5-dev.622174c.0+622174c": + version: 4.0.5-dev.622174c.0 + resolution: "web3-eth-contract@npm:4.0.5-dev.622174c.0" + dependencies: + web3-core: 4.1.1-dev.622174c.0+622174c + web3-errors: 1.1.1-dev.622174c.0+622174c + web3-eth: 4.1.1-dev.622174c.0+622174c + web3-eth-abi: 4.1.1-dev.622174c.0+622174c + web3-types: 1.1.1-dev.622174c.0+622174c + web3-utils: 4.0.5-dev.622174c.0+622174c + web3-validator: 2.0.1-dev.622174c.0+622174c + checksum: 3dd00aa7433230c851a3ca3e40b64d6fddc2cee84519031e7c747f6eccf27a1d39c40280855ca9ea213dff50a8405a1da9800326b0b5ee2ada04845b376e7368 + languageName: node + linkType: hard + "web3-eth-ens@npm:1.10.0": version: 1.10.0 resolution: "web3-eth-ens@npm:1.10.0" @@ -48043,6 +48163,23 @@ __metadata: languageName: node linkType: hard +"web3-eth-ens@npm:4.0.5-dev.622174c.0+622174c": + version: 4.0.5-dev.622174c.0 + resolution: "web3-eth-ens@npm:4.0.5-dev.622174c.0" + dependencies: + "@adraffy/ens-normalize": ^1.8.8 + web3-core: 4.1.1-dev.622174c.0+622174c + web3-errors: 1.1.1-dev.622174c.0+622174c + web3-eth: 4.1.1-dev.622174c.0+622174c + web3-eth-contract: 4.0.5-dev.622174c.0+622174c + web3-net: 4.0.5-dev.622174c.0+622174c + web3-types: 1.1.1-dev.622174c.0+622174c + web3-utils: 4.0.5-dev.622174c.0+622174c + web3-validator: 2.0.1-dev.622174c.0+622174c + checksum: 9ea8376b984daa13d1c5a43e43419255491bf66355b01e36b424f0c061baa64dc1dc10a1fc7a6e58d864b026e7dd0c2fb61730a59b40049260cbcf736d2451f8 + languageName: node + linkType: hard + "web3-eth-iban@npm:1.10.0": version: 1.10.0 resolution: "web3-eth-iban@npm:1.10.0" @@ -48113,6 +48250,18 @@ __metadata: languageName: node linkType: hard +"web3-eth-iban@npm:4.0.5-dev.622174c.0+622174c": + version: 4.0.5-dev.622174c.0 + resolution: "web3-eth-iban@npm:4.0.5-dev.622174c.0" + dependencies: + web3-errors: 1.1.1-dev.622174c.0+622174c + web3-types: 1.1.1-dev.622174c.0+622174c + web3-utils: 4.0.5-dev.622174c.0+622174c + web3-validator: 2.0.1-dev.622174c.0+622174c + checksum: 8f7ba51bd00e2e48f722e8e187d5b0ffd4da37003403b9664e792dcd71762b232d4c50e4fe7ec14cf5172eeff4d423d9f73c0eae77ece77493f182e019c3cdec + languageName: node + linkType: hard + "web3-eth-personal@npm:1.10.0": version: 1.10.0 resolution: "web3-eth-personal@npm:1.10.0" @@ -48211,6 +48360,20 @@ __metadata: languageName: node linkType: hard +"web3-eth-personal@npm:4.0.5-dev.622174c.0+622174c": + version: 4.0.5-dev.622174c.0 + resolution: "web3-eth-personal@npm:4.0.5-dev.622174c.0" + dependencies: + web3-core: 4.1.1-dev.622174c.0+622174c + web3-eth: 4.1.1-dev.622174c.0+622174c + web3-rpc-methods: 1.1.1-dev.622174c.0+622174c + web3-types: 1.1.1-dev.622174c.0+622174c + web3-utils: 4.0.5-dev.622174c.0+622174c + web3-validator: 2.0.1-dev.622174c.0+622174c + checksum: 85731affff9b817e55641d0593af444858ef7f756843d8b7071626bec0cc60dda20fb61c09a697ca1314aa4d7420a116946604c7b06889a13eb1deabefb23b5c + languageName: node + linkType: hard + "web3-eth@npm:1.10.0": version: 1.10.0 resolution: "web3-eth@npm:1.10.0" @@ -48351,6 +48514,25 @@ __metadata: languageName: node linkType: hard +"web3-eth@npm:4.1.1-dev.622174c.0+622174c": + version: 4.1.1-dev.622174c.0 + resolution: "web3-eth@npm:4.1.1-dev.622174c.0" + dependencies: + setimmediate: ^1.0.5 + web3-core: 4.1.1-dev.622174c.0+622174c + web3-errors: 1.1.1-dev.622174c.0+622174c + web3-eth-abi: 4.1.1-dev.622174c.0+622174c + web3-eth-accounts: 4.0.5-dev.622174c.0+622174c + web3-net: 4.0.5-dev.622174c.0+622174c + web3-providers-ws: 4.0.5-dev.622174c.0+622174c + web3-rpc-methods: 1.1.1-dev.622174c.0+622174c + web3-types: 1.1.1-dev.622174c.0+622174c + web3-utils: 4.0.5-dev.622174c.0+622174c + web3-validator: 2.0.1-dev.622174c.0+622174c + checksum: 700e1f807e7a134e6692cc17cc0cf38041b5b4744b8284d56b9ad2fe5df248dbf1a34472f31fb44f2a86e71ea6f35cfd1d960f898581e684557dbe7d3985bf26 + languageName: node + linkType: hard + "web3-net@npm:1.10.0": version: 1.10.0 resolution: "web3-net@npm:1.10.0" @@ -48428,6 +48610,18 @@ __metadata: languageName: node linkType: hard +"web3-net@npm:4.0.5-dev.622174c.0+622174c": + version: 4.0.5-dev.622174c.0 + resolution: "web3-net@npm:4.0.5-dev.622174c.0" + dependencies: + web3-core: 4.1.1-dev.622174c.0+622174c + web3-rpc-methods: 1.1.1-dev.622174c.0+622174c + web3-types: 1.1.1-dev.622174c.0+622174c + web3-utils: 4.0.5-dev.622174c.0+622174c + checksum: d3ed183563c1de181220e2c5af4ee0106c5ca62289f47aceeb9a8ffc7b414d90b6b35f333e172b225325eb96e79409fed3a54ba669eab0208dc74d502a4f94b8 + languageName: node + linkType: hard + "web3-providers-http@npm:1.10.0": version: 1.10.0 resolution: "web3-providers-http@npm:1.10.0" @@ -48504,6 +48698,18 @@ __metadata: languageName: node linkType: hard +"web3-providers-http@npm:4.0.5-dev.622174c.0+622174c": + version: 4.0.5-dev.622174c.0 + resolution: "web3-providers-http@npm:4.0.5-dev.622174c.0" + dependencies: + cross-fetch: ^3.1.5 + web3-errors: 1.1.1-dev.622174c.0+622174c + web3-types: 1.1.1-dev.622174c.0+622174c + web3-utils: 4.0.5-dev.622174c.0+622174c + checksum: aca49d97ce9464676a1349162f3f1478fd716d1f354232da65755f72094e095d7a70921f5c89f137b3293984699c8b0cfdca328770e28095eb2d40cc6f5681d3 + languageName: node + linkType: hard + "web3-providers-ipc@npm:1.10.0": version: 1.10.0 resolution: "web3-providers-ipc@npm:1.10.0" @@ -48574,6 +48780,17 @@ __metadata: languageName: node linkType: hard +"web3-providers-ipc@npm:4.0.5-dev.622174c.0+622174c": + version: 4.0.5-dev.622174c.0 + resolution: "web3-providers-ipc@npm:4.0.5-dev.622174c.0" + dependencies: + web3-errors: 1.1.1-dev.622174c.0+622174c + web3-types: 1.1.1-dev.622174c.0+622174c + web3-utils: 4.0.5-dev.622174c.0+622174c + checksum: e772cb2569480480a9dd04b347ca36f69070392ce250636975f05f86a6eb043ee7d2d6402d3a8c4a090c6a7caaceb7c52f64eeafaf0149e5432586b3f29ba5a6 + languageName: node + linkType: hard + "web3-providers-ws@npm:1.10.0": version: 1.10.0 resolution: "web3-providers-ws@npm:1.10.0" @@ -48651,6 +48868,31 @@ __metadata: languageName: node linkType: hard +"web3-providers-ws@npm:4.0.5-dev.622174c.0+622174c": + version: 4.0.5-dev.622174c.0 + resolution: "web3-providers-ws@npm:4.0.5-dev.622174c.0" + dependencies: + "@types/ws": 8.5.3 + isomorphic-ws: ^5.0.0 + web3-errors: 1.1.1-dev.622174c.0+622174c + web3-types: 1.1.1-dev.622174c.0+622174c + web3-utils: 4.0.5-dev.622174c.0+622174c + ws: ^8.8.1 + checksum: c96e2e4dc596e884181345734f2fb39e5ae6058822fe195d199fcbaad2d34b9338d6416ffdf6c20da7cdb00606563e1d243b8e7baa4c32ff6092c1912f93d535 + languageName: node + linkType: hard + +"web3-rpc-methods@npm:1.1.1-dev.622174c.0+622174c": + version: 1.1.1-dev.622174c.0 + resolution: "web3-rpc-methods@npm:1.1.1-dev.622174c.0" + dependencies: + web3-core: 4.1.1-dev.622174c.0+622174c + web3-types: 1.1.1-dev.622174c.0+622174c + web3-validator: 2.0.1-dev.622174c.0+622174c + checksum: 0d363fd04f9c208732302a8afd71966a07f39978aff0b809eef74ece828aa363fc1d34a1ae923cd11752f4dab16048381d682a66b92e7cd8e7c503f2b33382c4 + languageName: node + linkType: hard + "web3-shh@npm:1.10.0": version: 1.10.0 resolution: "web3-shh@npm:1.10.0" @@ -48735,6 +48977,13 @@ __metadata: languageName: node linkType: hard +"web3-types@npm:1.1.1-dev.622174c.0+622174c": + version: 1.1.1-dev.622174c.0 + resolution: "web3-types@npm:1.1.1-dev.622174c.0" + checksum: d72cac8c651cf5133253cc550cb8f5a5cb410489e17da9f8132c0a786c7f8aaa69ab4084501b0431e07d57b5932927a9dcb8e30d2b788eb61c1ddd067d7655e4 + languageName: node + linkType: hard + "web3-types@npm:^1.0.2": version: 1.0.2 resolution: "web3-types@npm:1.0.2" @@ -48860,6 +49109,31 @@ __metadata: languageName: node linkType: hard +"web3-utils@npm:4.0.5-dev.622174c.0+622174c": + version: 4.0.5-dev.622174c.0 + resolution: "web3-utils@npm:4.0.5-dev.622174c.0" + dependencies: + ethereum-cryptography: ^2.0.0 + web3-errors: 1.1.1-dev.622174c.0+622174c + web3-types: 1.1.1-dev.622174c.0+622174c + web3-validator: 2.0.1-dev.622174c.0+622174c + checksum: 39e5e5cc63310eca908b6ad52efdd6aec50ebca531903591d8851afbe1c2fc933159edae3b72f4e478ff63bc1f159834f062a5fda2dc3cff053756c15b97a86e + languageName: node + linkType: hard + +"web3-validator@npm:2.0.1-dev.622174c.0+622174c": + version: 2.0.1-dev.622174c.0 + resolution: "web3-validator@npm:2.0.1-dev.622174c.0" + dependencies: + ethereum-cryptography: ^2.0.0 + util: ^0.12.5 + web3-errors: 1.1.1-dev.622174c.0+622174c + web3-types: 1.1.1-dev.622174c.0+622174c + zod: ^3.21.4 + checksum: fd469628af05ca801815b42d754c047d947e3e15505bc78cdf90a4ac1fe57542608eb2f5f4d0605dff6a9b2896349a9a2ec2c789f6d5504882145496a103b898 + languageName: node + linkType: hard + "web3-validator@npm:^1.0.2": version: 1.0.2 resolution: "web3-validator@npm:1.0.2" @@ -48978,6 +49252,30 @@ __metadata: languageName: node linkType: hard +"web3@npm:dev": + version: 4.1.1-dev.622174c.0 + resolution: "web3@npm:4.1.1-dev.622174c.0" + dependencies: + web3-core: 4.1.1-dev.622174c.0+622174c + web3-errors: 1.1.1-dev.622174c.0+622174c + web3-eth: 4.1.1-dev.622174c.0+622174c + web3-eth-abi: 4.1.1-dev.622174c.0+622174c + web3-eth-accounts: 4.0.5-dev.622174c.0+622174c + web3-eth-contract: 4.0.5-dev.622174c.0+622174c + web3-eth-ens: 4.0.5-dev.622174c.0+622174c + web3-eth-iban: 4.0.5-dev.622174c.0+622174c + web3-eth-personal: 4.0.5-dev.622174c.0+622174c + web3-net: 4.0.5-dev.622174c.0+622174c + web3-providers-http: 4.0.5-dev.622174c.0+622174c + web3-providers-ws: 4.0.5-dev.622174c.0+622174c + web3-rpc-methods: 1.1.1-dev.622174c.0+622174c + web3-types: 1.1.1-dev.622174c.0+622174c + web3-utils: 4.0.5-dev.622174c.0+622174c + web3-validator: 2.0.1-dev.622174c.0+622174c + checksum: 8558f129ddb9881b2a3ed9e832bd4bc10f11fbff78955090d120606bd6e8b5bd5be8aa0eba0d4a5dde23487b33f3cec528ac249d132ac2db9eaf6e7c0c6b2f32 + languageName: node + linkType: hard + "web3js-quorum@npm:21.7.0-rc1": version: 21.7.0-rc1 resolution: "web3js-quorum@npm:21.7.0-rc1" @@ -49947,7 +50245,7 @@ __metadata: languageName: node linkType: hard -"ws@npm:^8.4.2": +"ws@npm:^8.4.2, ws@npm:^8.8.1": version: 8.13.0 resolution: "ws@npm:8.13.0" peerDependencies: @@ -50645,6 +50943,13 @@ __metadata: languageName: node linkType: hard +"zod@npm:^3.21.4": + version: 3.22.1 + resolution: "zod@npm:3.22.1" + checksum: 05b62cc1069da6e6349ad2325ec6b7d0c00699f0796e0fd071bcc2b44ac711679e52ad00bc563019504c7e64bbf0bf73737f31366d882a856962cd6e2882cf0e + languageName: node + linkType: hard + "zone.js@npm:0.11.4": version: 0.11.4 resolution: "zone.js@npm:0.11.4"