diff --git a/apps/whale-api/src/e2e.defid.module.ts b/apps/whale-api/src/e2e.defid.module.ts index fc7c7b6628..c353c0ff09 100644 --- a/apps/whale-api/src/e2e.defid.module.ts +++ b/apps/whale-api/src/e2e.defid.module.ts @@ -7,7 +7,6 @@ import { v4 as uuidv4 } from 'uuid' import fs from 'fs' import { ChildProcess, spawn } from 'child_process' import { RegTestFoundationKeys } from '@defichain/jellyfish-network' -import { MasterNodeRegTestContainer } from '@defichain/testcontainers/dist/index' import { ApiPagedResponse } from './module.api/_core/api.paged.response' import { AddressToken, AddressHistory } from '@defichain/whale-api-client/dist/api/address' @@ -39,10 +38,9 @@ import { TokenData } from '@defichain/whale-api-client/dist/api/tokens' import { Transaction } from './module.model/transaction' import { TransactionVin } from './module.model/transaction.vin' import { TransactionVout } from './module.model/transaction.vout' +import { DeFiDRpcError, waitForCondition } from '@defichain/testcontainers' -const PORT = 3002 -const ENDPOINT = `http://127.0.0.1:${PORT}` -const SPAWNING_TIME = 120_000 +const SPAWNING_TIME = 180_000 export interface OceanListQuery { size: number @@ -61,15 +59,17 @@ export interface OceanProposalQuery { } class DefidOceanApi { + endpoint = 'http://127.0.0.1:3002' + async get (path: string): Promise { - const res = await fetch(`${ENDPOINT}${path}`, { + const res = await fetch(`${this.endpoint}${path}`, { method: 'GET' }) return await res.json() } async post (path: string, data?: any): Promise { - const res = await fetch(`${ENDPOINT}${path}`, { + const res = await fetch(`${this.endpoint}${path}`, { method: 'POST', body: JSON.stringify(data) }) @@ -344,12 +344,8 @@ export class DTransactionController extends DefidOceanController { } } -export class DefidBin { - tmpDir: string = `/tmp/${uuidv4()}` - binary: ChildProcess | null = null - - public constructor ( - readonly container: MasterNodeRegTestContainer, +export class DefidOcean { + constructor ( readonly addressController: DAddressController, readonly blockController: DBlockController, readonly feeController: DFeeController, @@ -364,6 +360,98 @@ export class DefidBin { readonly tokenController: DTokenController ) { } +} + +export class DefidRpc { + rpcUrl = 'http://test:test@127.0.0.1:19554' + + getCachedRpcUrl (): string { + return this.rpcUrl + } + + async call (method: string, params: any = []): Promise { + const body = JSON.stringify({ + jsonrpc: '1.0', + id: Math.floor(Math.random() * 100000000000000), + method: method, + params: params + }) + + const text = await this.post(body) + const { + result, + error + } = JSON.parse(text) + + if (error !== undefined && error !== null) { + throw new DeFiDRpcError(error) + } + + return result + } + + async post (body: string): Promise { + const response = await fetch(this.rpcUrl, { + method: 'POST', + body: body + }) + return await response.text() + } + + async generate ( + nblocks: number, + address?: string | undefined, + maxTries: number = 1000000 + ): Promise { + if (address === undefined) { + address = await this.call('getnewaddress') + } + for (let minted = 0, tries = 0; minted < nblocks && tries < maxTries; tries++) { + const result = await this.call('generatetoaddress', [1, address, 1]) + if (result === 1) { + minted += 1 + } + } + } + + async waitForBlockHeight (height: number, timeout = 590000): Promise { + return await waitForCondition(async () => { + const count = await this.getBlockCount() + if (count > height) { + return true + } + await this.generate(1) + return false + }, timeout, 100, 'waitForBlockHeight') + } + + async getNewAddress (label: string = '', addressType: 'legacy' | 'p2sh-segwit' | 'bech32' | 'eth' | string = 'bech32'): Promise { + return await this.call('getnewaddress', [label, addressType]) + } + + async getBlockCount (): Promise { + return await this.call('getblockcount', []) + } +} + +export class DefidBin { + tmpDir: string = `/tmp/${uuidv4()}` + binary: ChildProcess | null = null + rpc = new DefidRpc() + ocean = new DefidOcean( + new DAddressController(), + new DBlockController(), + new DFeeController(), + new DGovernanceController(), + new DMasternodeController(), + new DOracleController(), + new DPoolPairController(), + new DPriceController(), + new DRawTxController(), + new DStatsController(), + new DTransactionController(), + new DTokenController() + ) async start (): Promise { fs.mkdirSync(this.tmpDir) @@ -375,7 +463,6 @@ export class DefidBin { const args = [ `-datadir=${this.tmpDir}`, '-regtest', - '-oceanarchive', '-printtoconsole', '-gen=0', '-rpcuser=test', @@ -389,7 +476,8 @@ export class DefidBin { '-txnotokens=0', '-logtimemicros', '-txindex=1', - '-acindex=1' + '-acindex=1', + '-oceanarchive' ] const extraArgs = [ @@ -443,8 +531,9 @@ export class DefidBin { await new Promise((resolve) => setTimeout(resolve, 1000)) try { - const res = await this.blockController.get('0') - console.log('[DefidBin.start()] blockController.get res: ', res) + // TODO(canonbrother): blockController.get(0) + const res = await this.ocean.blockController.list({ size: 1 }) + console.log('[DefidBin.start()] blockController.list res: ', res) } catch (err) { console.log('[DefidBin.start()] blockController.get err: ', err) } @@ -454,7 +543,9 @@ export class DefidBin { binary.stderr.off('data', onData) binary.stdout.off('data', onData) - // import privkey + await this.rpc.call('importprivkey', [RegTestFoundationKeys[1].owner.privKey]) + await this.rpc.call('importprivkey', [RegTestFoundationKeys[1].operator.privKey]) + // setgov // generate(2) @@ -468,4 +559,22 @@ export class DefidBin { this.binary = binary } + + async stop (): Promise { + const interval = setInterval(() => { + if (this.binary?.pid !== undefined && !this.isRunning(this.binary?.pid)) { + clearInterval(interval) + fs.rmdirSync(this.tmpDir, { recursive: true }) + } + }, 500) + this.binary?.kill() + } + + private isRunning (pid: number): boolean { + try { + return process.kill(pid, 0) + } catch (err: any) { + return err.code === 'EPERM' + } + } } diff --git a/apps/whale-api/src/e2e.module.ts b/apps/whale-api/src/e2e.module.ts index 94275c004c..ed3db5edf3 100644 --- a/apps/whale-api/src/e2e.module.ts +++ b/apps/whale-api/src/e2e.module.ts @@ -1,4 +1,3 @@ -import fs from 'fs' import { Test, TestingModule } from '@nestjs/testing' import { AppModule } from './app.module' import { ConfigService } from '@nestjs/config' @@ -11,21 +10,7 @@ import waitForExpect from 'wait-for-expect' import { addressToHid } from './module.api/address.controller' import { ScriptAggregationMapper } from './module.model/script.aggregation' import { TestingGroup } from '@defichain/jellyfish-testing' -import { - DefidBin, - DAddressController, - DBlockController, - DFeeController, - DGovernanceController, - DMasternodeController, - DOracleController, - DPoolPairController, - DPriceController, - DStatsController, - DTransactionController, - DTokenController, - DRawTxController -} from './e2e.defid.module' +import { DefidBin } from './e2e.defid.module' /** * Configures an end-to-end testing app integrated with all modules. @@ -35,29 +20,7 @@ import { * @param {MasterNodeRegTestContainer} container to provide defid client * @return Promise with initialization */ -export async function createTestingApp (container: MasterNodeRegTestContainer): Promise -export async function createTestingApp (container: MasterNodeRegTestContainer): Promise -export async function createTestingApp (container: MasterNodeRegTestContainer): Promise { - if (process.env.DEFID !== undefined) { - const defid = new DefidBin( - container, - new DAddressController(), - new DBlockController(), - new DFeeController(), - new DGovernanceController(), - new DMasternodeController(), - new DOracleController(), - new DPoolPairController(), - new DPriceController(), - new DRawTxController(), - new DStatsController(), - new DTransactionController(), - new DTokenController() - ) - await defid.start() - return defid - } - +export async function createTestingApp (container: MasterNodeRegTestContainer): Promise { const url = await container.getCachedRpcUrl() const module = await createTestingModule(url) @@ -76,21 +39,11 @@ export async function createTestingApp (container: MasterNodeRegTestContainer): * @param {MasterNodeRegTestContainer | TestingGroup} container to provide defid client * @param {NestFastifyApplication} app to close */ -export async function stopTestingApp (container: MasterNodeRegTestContainer | TestingGroup, app: NestFastifyApplication | DefidBin): Promise { +export async function stopTestingApp (container: MasterNodeRegTestContainer | TestingGroup, app: NestFastifyApplication): Promise { try { - if (app instanceof DefidBin) { - const interval = setInterval(() => { - if (app.binary?.pid !== undefined && !isRunning(app.binary?.pid)) { - clearInterval(interval) - fs.rmdirSync(app.tmpDir, { recursive: true }) - } - }, 500) - app.binary?.kill() - } else { - const indexer = app.get(RPCBlockProvider) - await indexer.stop() - await app.close() - } + const indexer = app.get(RPCBlockProvider) + await indexer.stop() + await app.close() } finally { await new Promise((resolve) => { // Wait 2000ms between indexer cycle time to prevent database error @@ -105,14 +58,6 @@ export async function stopTestingApp (container: MasterNodeRegTestContainer | Te } } -function isRunning (pid: number): boolean { - try { - return process.kill(pid, 0) - } catch (err: any) { - return err.code === 'EPERM' - } -} - async function createTestingModule (url: string): Promise { return await Test.createTestingModule({ imports: [AppModule.forRoot('memory')] @@ -141,16 +86,16 @@ export async function waitForIndexedHeightLatest (app: NestFastifyApplication, c export async function waitForIndexedHeight (app: NestFastifyApplication | DefidBin, height: number, timeout: number = 30000): Promise { if (app instanceof DefidBin) { await waitForExpect(async () => { - // TODO(): maybe get index from DefidBin - const count = await app.container.getBlockCount() - await expect(count).toBeGreaterThan(height) - await await app.container.generate(1) + // TODO(canonbrother): ocean getblockcount + // const count = await app.ocean.getBlockCount() + // expect(count).toBeGreaterThan(height) + // await app.rpc.generate(1) }, timeout) } else { const blockMapper = app.get(BlockMapper) await waitForExpect(async () => { const block = await blockMapper.getHighest() - await expect(block?.height).toBeGreaterThan(height) + expect(block?.height).toBeGreaterThan(height) }, timeout) } await new Promise((resolve) => setTimeout(resolve, 1000)) diff --git a/apps/whale-api/src/module.api/block.controller.e2e.ts b/apps/whale-api/src/module.api/block.controller.e2e.ts index 6dd8187920..3d6ea5916f 100644 --- a/apps/whale-api/src/module.api/block.controller.e2e.ts +++ b/apps/whale-api/src/module.api/block.controller.e2e.ts @@ -3,26 +3,33 @@ import { MasterNodeRegTestContainer } from '@defichain/testcontainers' import { NestFastifyApplication } from '@nestjs/platform-fastify' import { createTestingApp, stopTestingApp, waitForIndexedHeight } from '../e2e.module' import { JsonRpcClient } from '@defichain/jellyfish-api-jsonrpc' -import { DBlockController, DefidBin } from '../e2e.defid.module' +import { DBlockController, DefidBin, DefidRpc } from '../e2e.defid.module' -const container = new MasterNodeRegTestContainer() let app: NestFastifyApplication | DefidBin +let container: MasterNodeRegTestContainer | DefidRpc let controller: BlockController | DBlockController let client: JsonRpcClient beforeAll(async () => { - await container.start() - await container.waitForBlockHeight(101) + if (process.env.DEFID !== undefined) { + app = new DefidBin() + await app.start() + container = app.rpc + controller = app.ocean.blockController + await container.waitForBlockHeight(101) + // await waitForIndexedHeight(app, 100) + client = new JsonRpcClient(container.getCachedRpcUrl()) + } else { + container = new MasterNodeRegTestContainer() + await container.start() + await container.waitForBlockHeight(101) - app = await createTestingApp(container) + app = await createTestingApp(container) - await waitForIndexedHeight(app, 100) - if (app instanceof DefidBin) { - controller = app.blockController - } else { + await waitForIndexedHeight(app, 100) controller = app.get(BlockController) + client = new JsonRpcClient(await container.getCachedRpcUrl()) } - client = new JsonRpcClient(await container.getCachedRpcUrl()) const address = await container.getNewAddress() for (let i = 0; i < 4; i += 1) { @@ -34,7 +41,11 @@ beforeAll(async () => { }) afterAll(async () => { - await stopTestingApp(container, app) + if (process.env.DEFID !== undefined) { + await (app as DefidBin).stop() + return + } + await stopTestingApp(container as MasterNodeRegTestContainer, app as NestFastifyApplication) }) describe('get', () => {