From 6bb2f5a454a02ee5992b997906b047d52af4a6b1 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Tue, 27 Sep 2022 11:52:15 +0800 Subject: [PATCH 1/4] replace metadcontainer with metachaincontainer --- pnpm-lock.yaml | 80 +--------- ts-tests/package.json | 1 + .../src/containers/MetaDContainer.test.ts | 28 ---- ts-tests/src/containers/MetaDContainer.ts | 148 ------------------ ts-tests/src/containers/index.ts | 1 - ts-tests/tests-e2e/Balances.e2e.ts | 18 ++- ts-tests/tests-e2e/Blocks.e2e.ts | 18 ++- ts-tests/tests-e2e/Contract.e2e.ts | 16 +- 8 files changed, 37 insertions(+), 273 deletions(-) delete mode 100644 ts-tests/src/containers/MetaDContainer.test.ts delete mode 100644 ts-tests/src/containers/MetaDContainer.ts delete mode 100644 ts-tests/src/containers/index.ts diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 30e48ae4..97d89aee 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -38,7 +38,7 @@ importers: ethers: 5.7.0 testcontainers: 8.13.2 devDependencies: - '@birthdayresearch/sticky-turbo-jest': 0.2.0 + '@birthdayresearch/sticky-turbo-jest': 0.2.0_ozbmybfpzvaxm2rsnksj7ojkam '@defimetachain/typescript': link:../typescript packages/typescript: @@ -50,17 +50,19 @@ importers: ts-tests: specifiers: '@birthdayresearch/sticky-turbo-jest': 0.2.0 + '@defimetachain/testcontainers': workspace:* '@defimetachain/typescript': workspace:* '@polkadot/api': ^8.8.2 ethers: ^5.4.6 hardhat: ^2.11.1 testcontainers: ^8.12.0 devDependencies: - '@birthdayresearch/sticky-turbo-jest': 0.2.0 + '@birthdayresearch/sticky-turbo-jest': 0.2.0_ozbmybfpzvaxm2rsnksj7ojkam + '@defimetachain/testcontainers': link:../packages/testcontainers '@defimetachain/typescript': link:../packages/typescript '@polkadot/api': 8.14.1 ethers: 5.7.0 - hardhat: 2.11.1 + hardhat: 2.11.1_typescript@4.8.2 testcontainers: 8.13.2 packages: @@ -498,26 +500,6 @@ packages: - typescript dev: true - /@birthdayresearch/sticky-jest/0.2.0: - resolution: {integrity: sha512-GT41i90yxh1BhcBmdsSP7eeFQ0K2trIfvwosqRHIlfgv9QpLfmlAOcHWliE78z8rKmLIWRyJK+Vy6GCLRR7wQA==} - dependencies: - '@types/jest': 28.1.8 - jest: 28.1.3 - jest-extended: 3.0.2_jest@28.1.3 - ts-jest: 28.0.8_jest@28.1.3 - wait-for-expect: 3.0.2 - transitivePeerDependencies: - - '@babel/core' - - '@jest/types' - - '@types/node' - - babel-jest - - esbuild - - node-notifier - - supports-color - - ts-node - - typescript - dev: true - /@birthdayresearch/sticky-jest/0.2.0_ozbmybfpzvaxm2rsnksj7ojkam: resolution: {integrity: sha512-GT41i90yxh1BhcBmdsSP7eeFQ0K2trIfvwosqRHIlfgv9QpLfmlAOcHWliE78z8rKmLIWRyJK+Vy6GCLRR7wQA==} dependencies: @@ -550,23 +532,6 @@ packages: - supports-color dev: true - /@birthdayresearch/sticky-turbo-jest/0.2.0: - resolution: {integrity: sha512-34ObdLp0AFH2sPIpKhuFwg1elP8lvzBgHLb92eX1sdBY2OcgfVxxMgJ4oJG0M+kYA42/ambhjKBVK0Dr9Q8ruQ==} - dependencies: - '@birthdayresearch/sticky-jest': 0.2.0 - '@birthdayresearch/sticky-turbo': 0.2.0 - transitivePeerDependencies: - - '@babel/core' - - '@jest/types' - - '@types/node' - - babel-jest - - esbuild - - node-notifier - - supports-color - - ts-node - - typescript - dev: true - /@birthdayresearch/sticky-turbo-jest/0.2.0_ozbmybfpzvaxm2rsnksj7ojkam: resolution: {integrity: sha512-34ObdLp0AFH2sPIpKhuFwg1elP8lvzBgHLb92eX1sdBY2OcgfVxxMgJ4oJG0M+kYA42/ambhjKBVK0Dr9Q8ruQ==} dependencies: @@ -4204,7 +4169,7 @@ packages: resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} dev: true - /hardhat/2.11.1: + /hardhat/2.11.1_typescript@4.8.2: resolution: {integrity: sha512-7FoyfKjBs97GHNpQejHecJBBcRPOEhAE3VkjSWXB3GeeiXefWbw+zhRVOjI4eCsUUt7PyNFAdWje/lhnBT9fig==} engines: {node: ^14.0.0 || ^16.0.0 || ^18.0.0} hasBin: true @@ -4264,6 +4229,7 @@ packages: source-map-support: 0.5.21 stacktrace-parser: 0.1.10 tsort: 0.0.1 + typescript: 4.8.2 undici: 5.10.0 uuid: 8.3.2 ws: 7.5.9 @@ -7289,38 +7255,6 @@ packages: resolution: {integrity: sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==} dev: true - /ts-jest/28.0.8_jest@28.1.3: - resolution: {integrity: sha512-5FaG0lXmRPzApix8oFG8RKjAz4ehtm8yMKOTy5HX3fY6W8kmvOrmcY0hKDElW52FJov+clhUbrKAqofnj4mXTg==} - engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} - hasBin: true - peerDependencies: - '@babel/core': '>=7.0.0-beta.0 <8' - '@jest/types': ^28.0.0 - babel-jest: ^28.0.0 - esbuild: '*' - jest: ^28.0.0 - typescript: '>=4.3' - peerDependenciesMeta: - '@babel/core': - optional: true - '@jest/types': - optional: true - babel-jest: - optional: true - esbuild: - optional: true - dependencies: - bs-logger: 0.2.6 - fast-json-stable-stringify: 2.1.0 - jest: 28.1.3 - jest-util: 28.1.3 - json5: 2.2.1 - lodash.memoize: 4.1.2 - make-error: 1.3.6 - semver: 7.3.7 - yargs-parser: 21.1.1 - dev: true - /ts-jest/28.0.8_yenyaz7zwbhjjdwalfbna3bemq: resolution: {integrity: sha512-5FaG0lXmRPzApix8oFG8RKjAz4ehtm8yMKOTy5HX3fY6W8kmvOrmcY0hKDElW52FJov+clhUbrKAqofnj4mXTg==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} diff --git a/ts-tests/package.json b/ts-tests/package.json index 9d5fd907..27f7f056 100644 --- a/ts-tests/package.json +++ b/ts-tests/package.json @@ -12,6 +12,7 @@ "devDependencies": { "@birthdayresearch/sticky-turbo-jest": "0.2.0", "@defimetachain/typescript": "workspace:*", + "@defimetachain/testcontainers": "workspace:*", "@polkadot/api": "^8.8.2", "ethers": "^5.4.6", "hardhat": "^2.11.1", diff --git a/ts-tests/src/containers/MetaDContainer.test.ts b/ts-tests/src/containers/MetaDContainer.test.ts deleted file mode 100644 index e5d9e598..00000000 --- a/ts-tests/src/containers/MetaDContainer.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { MetaDContainer } from './index'; -import { CHAIN_ID } from '../utils/constant'; - -const container = new MetaDContainer(); - -beforeAll(async () => { - await container.start(); -}); - -afterAll(async () => { - await container.stop(); -}); - -it('should have 0 hashrate', async function () { - expect(await container.call('eth_hashrate', [])).toStrictEqual('0x0'); -}); - -it('should have chainId', async function () { - expect(Number(await container.call('net_version', []))).toStrictEqual(CHAIN_ID); -}); - -it('should have no account', async function () { - expect(await container.call('eth_accounts', [])).toStrictEqual([]); -}); - -it('block author should be 0x0000000000000000000000000000000000000000', async function () { - expect(await container.call('eth_coinbase', [])).toStrictEqual('0x0000000000000000000000000000000000000000'); -}); diff --git a/ts-tests/src/containers/MetaDContainer.ts b/ts-tests/src/containers/MetaDContainer.ts deleted file mode 100644 index b9ef398f..00000000 --- a/ts-tests/src/containers/MetaDContainer.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { ethers } from 'ethers'; -import { GenericContainer, StartedTestContainer, Network, StartedNetwork } from 'testcontainers'; -import { CHAIN_ID } from '../utils/constant'; -import { META_LOG } from '../utils/constant'; - -type MetaDNetwork = 'mainnet' | 'testnet'; - -export interface StartOptions { - port?: number; - rpcPort?: number; - wsPort?: number; - timeout?: number; - spec?: number; -} - -export class MetaDContainer { - static readonly PREFIX = 'metachain-testcontainers-'; - - static get image(): string { - if (process?.env?.METACHAIN_DOCKER_IMAGE !== undefined) { - return process.env.METACHAIN_DOCKER_IMAGE; - } - return 'ghcr.io/defich/metachain:af2e7d03b061352491d550c8923d1dfac4f65095'; - } - - static readonly MetaDPorts = { - mainnet: { - port: 30333, - rpcPort: 9933, - wsPort: 9944, - }, - testnet: { - port: 39333, - rpcPort: 19933, - wsPort: 19944, - }, - }; - - genericContainer: GenericContainer; - startedContainer?: StartedTestContainer; - startOptions?: StartOptions; - protected network?: StartedNetwork; - - ethers!: ethers.providers.JsonRpcProvider; - - constructor( - readonly metaDNetwork: MetaDNetwork = 'testnet', - readonly image: string = MetaDContainer.image, - readonly provider: string = 'http', - ) { - this.genericContainer = new GenericContainer(image); - } - - protected getCmd(opts: StartOptions): string[] { - return [ - '--execution=Native', // Faster execution compare to `Wasm` - '--no-telemetry', // disable connecting to substrate telemtry server - '--no-prometheus', // do not expose a Prometheus exporter endpoint - '--no-grandpa', - `-l${META_LOG}`, - `--port=${opts.port}`, - `--rpc-port=${opts.rpcPort}`, - `--ws-port=${opts.wsPort}`, - '--rpc-external', - '--ws-external', - '--sealing=manual', - '--force-authoring', // enable authoring even when offline - '--rpc-cors=all', - '--alice', // shortcut for `--name Alice --validator` with session keys for `Alice` added to keystore, required by manual sealing to author the blocks - '--tmp', // run a temporary node - ]; - } - - async start(startOptions: StartOptions = {}): Promise { - this.network = await new Network().start(); - - this.startOptions = Object.assign(MetaDContainer.MetaDPorts[this.metaDNetwork], startOptions); - const timeout = this.startOptions.timeout ?? 100_000; - - this.startedContainer = await this.genericContainer - .withName(this.generateName()) - .withNetworkMode(this.network.getName()) - .withCmd(this.getCmd(this.startOptions)) - .withExposedPorts(...Object.values(MetaDContainer.MetaDPorts[this.metaDNetwork])) - .withStartupTimeout(timeout) - .start(); - - this.ethers = - this.provider !== 'http' - ? new ethers.providers.JsonRpcProvider( - `ws://127.0.0.1:${this.startedContainer.getMappedPort( - MetaDContainer.MetaDPorts[this.metaDNetwork].wsPort, - )}`, - { - chainId: CHAIN_ID, - name: 'meta', - }, - ) - : new ethers.providers.JsonRpcProvider( - `http://127.0.0.1:${this.startedContainer.getMappedPort( - MetaDContainer.MetaDPorts[this.metaDNetwork].rpcPort, - )}`, - { - chainId: CHAIN_ID, - name: 'meta', - }, - ); - } - - async stop(): Promise { - await this.startedContainer?.stop(); - await this.network?.stop(); - } - - async call(method: string, params: any[]): Promise { - try { - return this.ethers.send(method, params); - } catch (err: any) { - const { error } = JSON.parse(err.body); - throw new MetaDRpcError(error); - } - } - - // Create a block and finalize it. - // It will include all previously executed transactions since the last finalized block. - async generate(): Promise { - const result = await this.call('engine_createBlock', [true, true, null]); - if (!result) { - throw new Error(`Unexpected result: ${JSON.stringify(result)}`); - } - await new Promise((resolve) => setTimeout(() => resolve(0), 500)); - return result.hash; - } - - private generateName(): string { - const rand = Math.floor(Math.random() * 10000000); - return `${MetaDContainer.PREFIX}-${this.metaDNetwork}-${rand}`; - } -} - -/** - * RPC error from container - */ -export class MetaDRpcError extends Error { - constructor(error: { code: number; message: string }) { - super(`MetaDRpcError: ' ${error.message}', code: ${error.code}`); - } -} diff --git a/ts-tests/src/containers/index.ts b/ts-tests/src/containers/index.ts deleted file mode 100644 index 29b703e6..00000000 --- a/ts-tests/src/containers/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './MetaDContainer'; diff --git a/ts-tests/tests-e2e/Balances.e2e.ts b/ts-tests/tests-e2e/Balances.e2e.ts index 87662646..b235c236 100644 --- a/ts-tests/tests-e2e/Balances.e2e.ts +++ b/ts-tests/tests-e2e/Balances.e2e.ts @@ -1,5 +1,5 @@ import { ethers, BigNumber } from 'ethers'; -import { MetaDContainer } from '../src/containers'; +import { MetaChainContainer, StartedMetaChainContainer } from '@defimetachain/testcontainers'; import { GENESIS_ACCOUNT, GENESIS_ACCOUNT_BALANCE, @@ -7,7 +7,8 @@ import { EXISTENTIAL_DEPOSIT, } from '../src/utils/constant'; -const container = new MetaDContainer(); +let container: StartedMetaChainContainer; +let rpc: ethers.providers.JsonRpcProvider; const TEST_ACCOUNT = '0x1111111111111111111111111111111111111111'; const value = BigNumber.from(512); // 512, must be higher than ExistentialDeposit @@ -18,7 +19,8 @@ const expectedGenesisBalance = BigNumber.from(GENESIS_ACCOUNT_BALANCE).sub(gasPr const expectedTestBalance = value.sub(EXISTENTIAL_DEPOSIT); beforeAll(async () => { - await container.start(); + container = await new MetaChainContainer().start(); + rpc = container.getEthersHttpProvider(); }); afterAll(async () => { @@ -26,12 +28,12 @@ afterAll(async () => { }); it('should genesis balance setup correctly', async () => { - const bal = await container.ethers.getBalance(GENESIS_ACCOUNT); + const bal = await rpc.getBalance(GENESIS_ACCOUNT); expect(bal.toString()).toStrictEqual(GENESIS_ACCOUNT_BALANCE); }); it('should transfer balance', async () => { - const wallet = new ethers.Wallet(GENESIS_ACCOUNT_PRIVATE_KEY, container.ethers); + const wallet = new ethers.Wallet(GENESIS_ACCOUNT_PRIVATE_KEY, rpc); await wallet.sendTransaction({ to: TEST_ACCOUNT, @@ -40,11 +42,11 @@ it('should transfer balance', async () => { gasLimit: 0x100000, }); - await container.generate(); + await container.createBlock(); - const gBal = await container.ethers.getBalance(GENESIS_ACCOUNT); + const gBal = await rpc.getBalance(GENESIS_ACCOUNT); expect(gBal).toStrictEqual(expectedGenesisBalance); - const tBal = await container.ethers.getBalance(TEST_ACCOUNT); + const tBal = await rpc.getBalance(TEST_ACCOUNT); expect(tBal).toStrictEqual(expectedTestBalance); }); diff --git a/ts-tests/tests-e2e/Blocks.e2e.ts b/ts-tests/tests-e2e/Blocks.e2e.ts index dbda9487..b899440a 100644 --- a/ts-tests/tests-e2e/Blocks.e2e.ts +++ b/ts-tests/tests-e2e/Blocks.e2e.ts @@ -1,10 +1,12 @@ -import { BigNumber } from 'ethers'; -import { MetaDContainer } from '../src/containers'; +import { ethers, BigNumber } from 'ethers'; +import { MetaChainContainer, StartedMetaChainContainer } from '@defimetachain/testcontainers'; -const container = new MetaDContainer(); +let container: StartedMetaChainContainer; +let rpc: ethers.providers.JsonRpcProvider; beforeAll(async () => { - await container.start(); + container = await new MetaChainContainer().start(); + rpc = container.getEthersHttpProvider(); }); afterAll(async () => { @@ -12,10 +14,10 @@ afterAll(async () => { }); it('should generate', async () => { - const b0 = await container.ethers.getBlockNumber(); + const b0 = await rpc.getBlockNumber(); expect(b0).toStrictEqual(0); - const block = await container.ethers.getBlock(0); + const block = await rpc.getBlock(0); expect(block).toStrictEqual({ hash: expect.any(String), miner: '0x0000000000000000000000000000000000000000', @@ -32,8 +34,8 @@ it('should generate', async () => { _difficulty: BigNumber.from(0), }); - await container.generate(); + await container.createBlock(); - const b1 = await container.ethers.getBlockNumber(); + const b1 = await rpc.getBlockNumber(); expect(b1).toStrictEqual(1); }); diff --git a/ts-tests/tests-e2e/Contract.e2e.ts b/ts-tests/tests-e2e/Contract.e2e.ts index 62ccdac8..fa502773 100644 --- a/ts-tests/tests-e2e/Contract.e2e.ts +++ b/ts-tests/tests-e2e/Contract.e2e.ts @@ -1,12 +1,14 @@ -import { MetaDContainer } from '../src/containers'; +import { MetaChainContainer, StartedMetaChainContainer } from '@defimetachain/testcontainers'; import { GENESIS_ACCOUNT, GENESIS_ACCOUNT_PRIVATE_KEY, CONTRACT_ADDRESS } from '../src/utils/constant'; import Test from '../artifacts/contracts/Test.sol/Test.json'; import { ethers } from 'ethers'; -const container = new MetaDContainer(); +let container: StartedMetaChainContainer; +let rpc: ethers.providers.JsonRpcProvider; beforeAll(async () => { - await container.start(); + container = await new MetaChainContainer().start(); + rpc = container.getEthersHttpProvider(); }); afterAll(async () => { @@ -15,14 +17,14 @@ afterAll(async () => { it('should create and call contract', async () => { // create contract - const wallet = new ethers.Wallet(GENESIS_ACCOUNT_PRIVATE_KEY, container.ethers); + const wallet = new ethers.Wallet(GENESIS_ACCOUNT_PRIVATE_KEY, rpc); const factory = new ethers.ContractFactory(Test.abi, Test.bytecode, wallet); const contract = await factory.deploy(); expect(contract.address).toStrictEqual(CONTRACT_ADDRESS); - await container.generate(); + await container.createBlock(); // call contract expect(await contract.name()).toStrictEqual('Meta'); @@ -46,13 +48,13 @@ it('should create and call contract', async () => { expect(c0).toStrictEqual(0); await contract.incr(); - await container.generate(); + await container.createBlock(); const c1 = (await contract.getCount()).toNumber(); expect(c1).toStrictEqual(1); await contract.setCount(25); - await container.generate(); + await container.createBlock(); const c25 = (await contract.getCount()).toNumber(); expect(c25).toStrictEqual(25); From ad28ba1282c1bce48655d81496cca88468e96533 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Tue, 27 Sep 2022 13:18:12 +0800 Subject: [PATCH 2/4] isolate network --- packages/testcontainers/src/MetaChainContainer.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/testcontainers/src/MetaChainContainer.ts b/packages/testcontainers/src/MetaChainContainer.ts index 7efe6996..e8b4daaf 100644 --- a/packages/testcontainers/src/MetaChainContainer.ts +++ b/packages/testcontainers/src/MetaChainContainer.ts @@ -1,6 +1,6 @@ import { NetworkConfig, TestNet } from '@defimetachain/network'; import { ethers } from 'ethers'; -import { GenericContainer, StartedTestContainer } from 'testcontainers'; +import { GenericContainer, StartedTestContainer, Network } from 'testcontainers'; import { AbstractStartedContainer } from 'testcontainers/dist/modules/abstract-started-container'; export class MetaChainContainer extends GenericContainer { @@ -36,9 +36,12 @@ export class MetaChainContainer extends GenericContainer { } public async start(): Promise { + const network = await new Network().start(); + this.withExposedPorts(...Object.values(this.config.ports)) + .withNetworkMode(network.getName()) .withCmd(this.getCmd()) - .withStartupTimeout(120_000); + .withStartupTimeout(180_000); return new StartedMetaChainContainer(await super.start(), this.config); } From e01c067b33b328dca6c1a5a6ce95497e35c8157a Mon Sep 17 00:00:00 2001 From: canonbrother Date: Tue, 27 Sep 2022 13:19:05 +0800 Subject: [PATCH 3/4] revert tm to 120_000 --- packages/testcontainers/src/MetaChainContainer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/testcontainers/src/MetaChainContainer.ts b/packages/testcontainers/src/MetaChainContainer.ts index e8b4daaf..e8b50f3c 100644 --- a/packages/testcontainers/src/MetaChainContainer.ts +++ b/packages/testcontainers/src/MetaChainContainer.ts @@ -41,7 +41,7 @@ export class MetaChainContainer extends GenericContainer { this.withExposedPorts(...Object.values(this.config.ports)) .withNetworkMode(network.getName()) .withCmd(this.getCmd()) - .withStartupTimeout(180_000); + .withStartupTimeout(120_000); return new StartedMetaChainContainer(await super.start(), this.config); } From 2ecc16d2568abdee3bb1034fcc093c609bce309e Mon Sep 17 00:00:00 2001 From: canonbrother Date: Tue, 27 Sep 2022 13:26:25 +0800 Subject: [PATCH 4/4] lint --- packages/testcontainers/src/MetaChainContainer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/testcontainers/src/MetaChainContainer.ts b/packages/testcontainers/src/MetaChainContainer.ts index e8b50f3c..4c8f2408 100644 --- a/packages/testcontainers/src/MetaChainContainer.ts +++ b/packages/testcontainers/src/MetaChainContainer.ts @@ -1,6 +1,6 @@ import { NetworkConfig, TestNet } from '@defimetachain/network'; import { ethers } from 'ethers'; -import { GenericContainer, StartedTestContainer, Network } from 'testcontainers'; +import { GenericContainer, Network, StartedTestContainer } from 'testcontainers'; import { AbstractStartedContainer } from 'testcontainers/dist/modules/abstract-started-container'; export class MetaChainContainer extends GenericContainer {