Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: NTRN-288: use websocket to wait for new block #50

Merged
merged 4 commits into from
Jan 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ CONTRACTS_PATH - path to contracts that will be used in tests
NEUTRON_ADDRESS_PREFIX - address prefix for neutron controller network
COSMOS_ADDRESS_PREFIX - address prefix for gaia (cosmoshub) host network
NODE1_URL - url to the first node
NODE1_WS_URL - url to websocket of the first node
NODE2_URL - url to the second node
NODE2_WS_URL - url to websocket of the second node
BLOCKS_COUNT_BEFORE_START - how many blocks we wait before start first test
NO_DOCKER - do not start cosmopark for tests
NO_REBUILD - skip containers rebuilding
Expand Down
21 changes: 14 additions & 7 deletions src/helpers/cosmos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import axios from 'axios';
import { CodeId, Wallet } from '../types';
import Long from 'long';
import path from 'path';
import { waitBlocks, getWithAttempts } from './wait';
import { BlockWaiter, getWithAttempts } from './wait';
import {
CosmosTxV1beta1GetTxResponse,
InlineResponse20075TxResponse,
Expand All @@ -17,14 +17,14 @@ import { cosmos, google } from '@cosmos-client/core/cjs/proto';
import { CosmosSDK } from '@cosmos-client/core/cjs/sdk';
import { ibc } from '@cosmos-client/ibc/cjs/proto';
import crypto from 'crypto';
import ICoin = cosmos.base.v1beta1.ICoin;
import IHeight = ibc.core.client.v1.IHeight;
import {
paramChangeProposal,
ParamChangeProposalInfo,
sendProposal,
SendProposalInfo,
} from './proposal';
import ICoin = cosmos.base.v1beta1.ICoin;
import IHeight = ibc.core.client.v1.IHeight;

export const NEUTRON_DENOM = process.env.NEUTRON_DENOM || 'stake';
export const COSMOS_DENOM = process.env.COSMOS_DENOM || 'uatom';
Expand Down Expand Up @@ -191,12 +191,19 @@ cosmosclient.codec.register(

export class CosmosWrapper {
sdk: cosmosclient.CosmosSDK;
blockWaiter: BlockWaiter;
wallet: Wallet;
denom: string;

constructor(sdk: cosmosclient.CosmosSDK, wallet: Wallet, denom: string) {
constructor(
sdk: cosmosclient.CosmosSDK,
blockWaiter: BlockWaiter,
wallet: Wallet,
denom: string,
) {
this.denom = denom;
this.sdk = sdk;
this.blockWaiter = blockWaiter;
this.wallet = wallet;
}

Expand Down Expand Up @@ -250,7 +257,7 @@ export class CosmosWrapper {
const txhash = res.data?.tx_response.txhash;
let error = null;
while (numAttempts > 0) {
await waitBlocks(this.sdk, 1);
await this.blockWaiter.waitBlocks(1);
numAttempts--;
const data = await rest.tx
.getTx(this.sdk as CosmosSDK, txhash)
Expand Down Expand Up @@ -365,7 +372,7 @@ export class CosmosWrapper {
}

numAttempts--;
await waitBlocks(this.sdk, 1);
await this.blockWaiter.waitBlocks(1);
}

throw new Error('failed to query contract');
Expand Down Expand Up @@ -480,7 +487,7 @@ export class CosmosWrapper {
expect(pauseInfo.paused.until_height).toBeGreaterThan(0);

// wait and check contract's pause info after unpausing
await waitBlocks(this.sdk, short_pause_duration);
await this.blockWaiter.waitBlocks(short_pause_duration);
pauseInfo = await this.queryPausedInfo(testingContract);
expect(pauseInfo).toEqual({ unpaused: {} });
expect(pauseInfo.paused).toEqual(undefined);
Expand Down
14 changes: 9 additions & 5 deletions src/helpers/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const BLOCKS_COUNT_BEFORE_START = process.env.BLOCKS_COUNT_BEFORE_START

let alreadySetUp = false;

export const setup = async (host: string) => {
export const setup = async (host1: string, host2: string) => {
if (alreadySetUp) {
console.log('already set up');
return;
Expand All @@ -32,8 +32,12 @@ export const setup = async (host: string) => {
showVersions();
await showContractsHashes();

await waitForHTTP(host);
await waitForChannel(host);
await waitForHTTP(host1);
await waitForChannel(host1);
await waitForHTTP(host2);
await waitForChannel(host2);
await wait(20); // FIXME: this hardcoded sleep is here to wait until hermes is fully initialized.
// proper fix would be to monitor hermes status events.
alreadySetUp = true;
};

Expand All @@ -53,7 +57,7 @@ export const waitForHTTP = async (
}
// eslint-disable-next-line no-empty
} catch (e) {}
await wait(10);
await wait(1);
}
throw new Error('No port opened');
};
Expand All @@ -80,7 +84,7 @@ export const waitForChannel = async (
}
// eslint-disable-next-line no-empty
} catch (e) {}
await wait(10);
await wait(1);
}

throw new Error('No channel opened');
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/ica.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const getIca = (
numAttempts = 20,
) =>
getWithAttempts(
cm.sdk,
cm,
() =>
cm.queryContract<{
interchain_account_address: string;
Expand Down
4 changes: 2 additions & 2 deletions src/helpers/icq.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const waitForICQResultWithRemoteHeight = (
numAttempts = 20,
) =>
getWithAttempts(
cm.sdk,
cm,
() => getRegisteredQuery(cm, contractAddress, queryId),
async (query) =>
query.registered_query.last_submitted_result_remote_height >=
Expand Down Expand Up @@ -80,7 +80,7 @@ export const waitForTransfersAmount = (
numAttempts = 50,
) =>
getWithAttempts(
cm.sdk,
cm,
async () =>
(await queryTransfersNumber(cm, contractAddress)).transfers_number,
async (amount) => amount == expectedTransfersAmount,
Expand Down
52 changes: 40 additions & 12 deletions src/helpers/wait.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { rest } from '@cosmos-client/core';
import { rest, websocket } from '@cosmos-client/core';

(global as any).WebSocket = require('ws');

export const wait = async (seconds: number) =>
new Promise((r) => {
Expand All @@ -16,23 +18,49 @@ export const getRemoteHeight = async (sdk: any) => {
return +block.data.block.header.height;
};

export const waitBlocks = async (sdk: any, n: number) => {
const targetHeight = (await getRemoteHeight(sdk)) + n;
for (;;) {
await wait(1);
const currentHeight = await getRemoteHeight(sdk);
if (currentHeight >= targetHeight) {
break;
}
export class BlockWaiter {
url;

constructor(url: string) {
this.url = url;
}
};

waitBlocks(n: number, timeout = 120000): Promise<void> {
return new Promise((resolve, reject) => {
let ws = null;
const x = setTimeout(() => {
if (ws != null) {
ws.unsubscribe();
}
reject(new Error('waitBlocks: timeout'));
}, timeout);
ws = websocket.connect(this.url);
ws.next({
id: '1',
jsonrpc: '2.0',
method: 'subscribe',
params: ["tm.event='NewBlock'"],
});
ws.subscribe((res) => {
if (Object.entries((res as any).result).length !== 0) {
n--;
if (n == 0) {
ws.unsubscribe();
clearTimeout(x);
resolve();
}
}
});
});
}
}

/**
* getWithAttempts waits until readyFunc(getFunc()) returns true
* and only then returns result of getFunc()
*/
export const getWithAttempts = async <T>(
sdk: any,
cm: any,
sotnikov-s marked this conversation as resolved.
Show resolved Hide resolved
getFunc: () => Promise<T>,
readyFunc: (t: T) => Promise<boolean>,
numAttempts = 20,
Expand All @@ -48,7 +76,7 @@ export const getWithAttempts = async <T>(
} catch (e) {
error = e;
}
await waitBlocks(sdk, 1);
await cm.blockWaiter.waitBlocks(1);
}
throw error != null ? error : new Error('getWithAttempts: no attempts left');
};
12 changes: 11 additions & 1 deletion src/testcases/common_localcosmosnet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { cosmosclient } from '@cosmos-client/core';
import { Wallet } from '../types';
import { mnemonicToWallet } from '../helpers/cosmos';
import { setup } from '../helpers/env';
import { BlockWaiter } from '../helpers/wait';

const config = require('../config.json');

Expand Down Expand Up @@ -56,6 +57,8 @@ const walletSet = async (
export class TestStateLocalCosmosTestNet {
sdk1: cosmosclient.CosmosSDK;
sdk2: cosmosclient.CosmosSDK;
blockWaiter1: BlockWaiter;
blockWaiter2: BlockWaiter;
wallets: Record<string, Record<string, Wallet>>;
icq_web_host: string;
init = async () => {
Expand All @@ -70,7 +73,14 @@ export class TestStateLocalCosmosTestNet {

this.icq_web_host = 'http://localhost:9999';

await setup(host1);
this.blockWaiter1 = new BlockWaiter(
process.env.NODE1_WS_URL || 'ws://localhost:26657',
);
this.blockWaiter2 = new BlockWaiter(
process.env.NODE2_WS_URL || 'ws://localhost:16657',
);

await setup(host1, host2);

this.wallets = {};
this.wallets.neutron = await walletSet(this.sdk1, neutron_prefix);
Expand Down
15 changes: 9 additions & 6 deletions src/testcases/governance.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,19 @@ describe('Neutron / Governance', () => {
await testState.init();
cm = new CosmosWrapper(
testState.sdk1,
testState.blockWaiter1,
testState.wallets.neutron.demo1,
NEUTRON_DENOM,
);
cm2 = new CosmosWrapper(
testState.sdk1,
testState.blockWaiter1,
testState.wallets.neutron.demo2,
NEUTRON_DENOM,
);
cm3 = new CosmosWrapper(
testState.sdk1,
testState.blockWaiter1,
testState.wallets.neutron.rly1,
NEUTRON_DENOM,
);
Expand All @@ -44,7 +47,7 @@ describe('Neutron / Governance', () => {
cm.wallet.address.toString(),
);
await getWithAttempts(
cm.sdk,
cm,
async () =>
await cm.queryVotingPower(
CORE_CONTRACT_ADDRESS,
Expand All @@ -61,7 +64,7 @@ describe('Neutron / Governance', () => {
cm2.wallet.address.toString(),
);
await getWithAttempts(
cm2.sdk,
cm2,
async () =>
await cm2.queryVotingPower(
CORE_CONTRACT_ADDRESS,
Expand All @@ -78,7 +81,7 @@ describe('Neutron / Governance', () => {
cm3.wallet.address.toString(),
);
await getWithAttempts(
cm3.sdk,
cm3,
async () =>
await cm3.queryVotingPower(
CORE_CONTRACT_ADDRESS,
Expand All @@ -90,7 +93,7 @@ describe('Neutron / Governance', () => {
});
test('check voting power', async () => {
await getWithAttempts(
cm.sdk,
cm,
async () => await cm.queryTotalVotingPower(CORE_CONTRACT_ADDRESS),
async (response) => response.power == '3000',
20,
Expand All @@ -102,7 +105,7 @@ describe('Neutron / Governance', () => {
test('send funds from wallet 1', async () => {
await cm.msgSend(CORE_CONTRACT_ADDRESS, '1000');
await getWithAttempts(
cm.sdk,
cm,
async () => await cm.queryBalances(CORE_CONTRACT_ADDRESS),
async (response) => response.balances[0].amount == '1000',
20,
Expand Down Expand Up @@ -291,7 +294,7 @@ describe('Neutron / Governance', () => {
}
expect(rawLog.includes("proposal is not in 'passed' state"));
await getWithAttempts(
cm.sdk,
cm,
async () =>
await cm.queryProposal(PROPOSE_CONTRACT_ADDRESS, proposalId),
async (response) => response.proposal.status === 'rejected',
Expand Down
Loading