From e6b82ed2508b4bb2f99e2f70f1acaf8c2bc27846 Mon Sep 17 00:00:00 2001 From: Albert Andrejev Date: Thu, 11 Jan 2024 18:19:36 +0200 Subject: [PATCH 1/5] Add sigining info tests --- README.md | 4 +- .../run_in_band/interchain_kv_query.test.ts | 101 ++++++++++++++++++ 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index df5a5875..1c047575 100644 --- a/README.md +++ b/README.md @@ -14,11 +14,11 @@ git clone git@github.com:neutron-org/neutron.git git clone git@github.com:neutron-org/neutron-query-relayer.git ``` -We use the Gaia network as a host network, so you need to clone it next to the neutron repos. We use v9.0.3 for the tests. +We use the Gaia network as a host network, so you need to clone it next to the neutron repos. We use v13.0.0 for the tests. ```shell git clone git@github.com:cosmos/gaia.git -git checkout v9.0.3 +git checkout v13.0.0 ``` ### 2. Prepare docker environment diff --git a/src/testcases/run_in_band/interchain_kv_query.test.ts b/src/testcases/run_in_band/interchain_kv_query.test.ts index ff4ecd78..78027c5d 100644 --- a/src/testcases/run_in_band/interchain_kv_query.test.ts +++ b/src/testcases/run_in_band/interchain_kv_query.test.ts @@ -88,6 +88,25 @@ const getQueryBalanceResult = ( }, }); +const getValidatorsSigningInfosResult = ( + cm: CosmosWrapper, + contractAddress: string, + queryId: number, +) => + cm.queryContract<{ + balances: { + coins: { + denom: string; + amount: string; + }[]; + }; + last_submitted_local_height: number; + }>(contractAddress, { + validators_signing_infos: { + query_id: queryId, + }, + }); + const getQueryDelegatorDelegationsResult = ( cm: CosmosWrapper, contractAddress: string, @@ -141,6 +160,36 @@ const registerBalanceQuery = async ( return queryId; }; +const registerSigningInfoQuery = async ( + cm: WalletWrapper, + contractAddress: string, + connectionId: string, + updatePeriod: number, + valcons: string, +) => { + const txResult = await cm.executeContract( + contractAddress, + JSON.stringify({ + register_validators_signing_info_query: { + connection_id: connectionId, + validators: [valcons], + update_period: updatePeriod, + }, + }), + ); + + const attribute = getEventAttribute( + (txResult as any).events, + 'neutron', + 'query_id', + ); + + const queryId = parseInt(attribute); + expect(queryId).toBeGreaterThanOrEqual(0); + + return queryId; +}; + const acceptInterchainqueriesParamsChangeProposal = async ( cm: WalletWrapper, title: string, @@ -841,4 +890,56 @@ describe('Neutron / Interchain KV Query', () => { }); }); }); + + describe('Signing info query', () => { + let queryId: number; + beforeEach(async () => { + // Top up contract address before running query + await neutronAccount.msgSend(contractAddress, '1000000'); + + queryId = await registerSigningInfoQuery( + neutronAccount, + contractAddress, + connectionId, + updatePeriods[2], + 'cosmosvalcons1gspwywrjyjkng4x3eccm6es7ukm4j8xsfyfdpt', + ); + }); + + test('signing info registered query data', async () => { + const queryResult = await getRegisteredQuery( + neutronChain, + contractAddress, + queryId, + ); + expect(queryResult.registered_query.id).toEqual(queryId); + expect(queryResult.registered_query.owner).toEqual(contractAddress); + // XXX: I could actually check that "key" is correctly derived from contractAddress, + // but this requires bech32 decoding/encoding shenanigans + expect(queryResult.registered_query.keys.length).toEqual(1); + expect(queryResult.registered_query.keys[0].path).toEqual('slashing'); + expect(queryResult.registered_query.keys[0].key.length).toBeGreaterThan( + 0, + ); + expect(queryResult.registered_query.query_type).toEqual('kv'); + expect(queryResult.registered_query.transactions_filter).toEqual(''); + expect(queryResult.registered_query.connection_id).toEqual(connectionId); + }); + + test('signing info data', async () => { + await waitForICQResultWithRemoteHeight( + neutronChain, + contractAddress, + queryId, + await getHeight(gaiaChain.sdk), + ); + + const interchainQueryResult = await getValidatorsSigningInfosResult( + neutronChain, + contractAddress, + queryId, + ); + console.log(interchainQueryResult); + }); + }); }); From f96ecbc6e4083ea7f87c23f44cfb95132f511edd Mon Sep 17 00:00:00 2001 From: Albert Andrejev Date: Mon, 15 Jan 2024 14:43:10 +0200 Subject: [PATCH 2/5] test fixes --- .../run_in_band/interchain_kv_query.test.ts | 43 ++++++++++++++++--- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/src/testcases/run_in_band/interchain_kv_query.test.ts b/src/testcases/run_in_band/interchain_kv_query.test.ts index 78027c5d..ac64df43 100644 --- a/src/testcases/run_in_band/interchain_kv_query.test.ts +++ b/src/testcases/run_in_band/interchain_kv_query.test.ts @@ -23,6 +23,7 @@ import { import { CodeId, NeutronContract } from '@neutron-org/neutronjsplus/dist/types'; import { paramChangeProposal } from '@neutron-org/neutronjsplus/dist/proposal'; import { COSMOS_DENOM } from '@neutron-org/neutronjsplus'; +import axios from 'axios'; const config = require('../../config.json'); @@ -94,10 +95,14 @@ const getValidatorsSigningInfosResult = ( queryId: number, ) => cm.queryContract<{ - balances: { - coins: { - denom: string; - amount: string; + signing_infos: { + signing_infos: { + address: string; + start_height: string; + index_offset: string; + jailed_until: string; + tombstoned: boolean; + missed_blocks_counter: number; }[]; }; last_submitted_local_height: number; @@ -107,6 +112,15 @@ const getValidatorsSigningInfosResult = ( }, }); +const getCosmosSigningInfosResult = async (sdkUrl: string) => { + try { + return (await axios.get(`${sdkUrl}/cosmos/slashing/v1beta1/signing_infos`)) + .data; + } catch (e) { + return null; + } +}; + const getQueryDelegatorDelegationsResult = ( cm: CosmosWrapper, contractAddress: string, @@ -893,16 +907,24 @@ describe('Neutron / Interchain KV Query', () => { describe('Signing info query', () => { let queryId: number; + let indexOffset: number; + let cosmosvalconspub: string; beforeEach(async () => { // Top up contract address before running query await neutronAccount.msgSend(contractAddress, '1000000'); + const infos = await getCosmosSigningInfosResult(gaiaChain.sdk.url); + expect(infos).not.toBeNull(); + const firstValidator = infos.info[0]; + indexOffset = parseInt(firstValidator.index_offset); + cosmosvalconspub = firstValidator.address; + queryId = await registerSigningInfoQuery( neutronAccount, contractAddress, connectionId, updatePeriods[2], - 'cosmosvalcons1gspwywrjyjkng4x3eccm6es7ukm4j8xsfyfdpt', + cosmosvalconspub, ); }); @@ -939,7 +961,16 @@ describe('Neutron / Interchain KV Query', () => { contractAddress, queryId, ); - console.log(interchainQueryResult); + + expect( + interchainQueryResult.signing_infos.signing_infos[0].address, + ).toEqual(cosmosvalconspub); + + expect( + parseInt( + interchainQueryResult.signing_infos.signing_infos[0].index_offset, + ), + ).toBeGreaterThan(indexOffset); }); }); }); From 6ae6f2f01415d368127b881173270f4967c66293 Mon Sep 17 00:00:00 2001 From: Murad Karammaev Date: Mon, 5 Feb 2024 23:50:31 +0200 Subject: [PATCH 3/5] unbonding query test --- src/helpers/gaia.ts | 52 ++++++ .../run_in_band/interchain_kv_query.test.ts | 165 +++++++++++++++++- 2 files changed, 210 insertions(+), 7 deletions(-) create mode 100644 src/helpers/gaia.ts diff --git a/src/helpers/gaia.ts b/src/helpers/gaia.ts new file mode 100644 index 00000000..66736123 --- /dev/null +++ b/src/helpers/gaia.ts @@ -0,0 +1,52 @@ +import { BroadcastTx200ResponseTxResponse } from '@cosmos-client/core/cjs/openapi/api'; +import { + MsgDelegate, + MsgUndelegate, +} from '@neutron-org/neutronjsplus/dist/proto/cosmos_sdk/cosmos/staking/v1beta1/tx_pb'; +import { + packAnyMsg, + WalletWrapper, +} from '@neutron-org/neutronjsplus/dist/cosmos'; +import Long from 'long'; + +export const msgDelegate = async ( + wallet: WalletWrapper, + delegatorAddress: string, + validatorAddress: string, + amount: string, +): Promise => { + const msgDelegate = new MsgDelegate({ + delegatorAddress, + validatorAddress, + amount: { denom: wallet.chain.denom, amount: amount }, + }); + const res = await wallet.execTx( + { + gas_limit: Long.fromString('200000'), + amount: [{ denom: wallet.chain.denom, amount: '1000' }], + }, + [packAnyMsg('/cosmos.staking.v1beta1.MsgDelegate', msgDelegate)], + ); + return res?.tx_response; +}; + +export const msgUndelegate = async ( + wallet: WalletWrapper, + delegatorAddress: string, + validatorAddress: string, + amount: string, +): Promise => { + const msgUndelegate = new MsgUndelegate({ + delegatorAddress, + validatorAddress, + amount: { denom: wallet.chain.denom, amount: amount }, + }); + const res = await wallet.execTx( + { + gas_limit: Long.fromString('200000'), + amount: [{ denom: wallet.chain.denom, amount: '1000' }], + }, + [packAnyMsg('/cosmos.staking.v1beta1.MsgUndelegate', msgUndelegate)], + ); + return res?.tx_response; +}; diff --git a/src/testcases/run_in_band/interchain_kv_query.test.ts b/src/testcases/run_in_band/interchain_kv_query.test.ts index ac64df43..2c8cf544 100644 --- a/src/testcases/run_in_band/interchain_kv_query.test.ts +++ b/src/testcases/run_in_band/interchain_kv_query.test.ts @@ -1,12 +1,15 @@ import '@neutron-org/neutronjsplus'; import { - WalletWrapper, CosmosWrapper, - NEUTRON_DENOM, filterIBCDenoms, getEventAttribute, + NEUTRON_DENOM, + WalletWrapper, } from '@neutron-org/neutronjsplus/dist/cosmos'; -import { TestStateLocalCosmosTestNet } from '@neutron-org/neutronjsplus'; +import { + COSMOS_DENOM, + TestStateLocalCosmosTestNet, +} from '@neutron-org/neutronjsplus'; import { getWithAttempts } from '@neutron-org/neutronjsplus/dist/wait'; import { Dao, @@ -14,7 +17,6 @@ import { getDaoContracts, } from '@neutron-org/neutronjsplus/dist/dao'; import cosmosclient from '@cosmos-client/core'; -import ICoin = cosmosclient.proto.cosmos.base.v1beta1.ICoin; import { getHeight } from '@neutron-org/neutronjsplus/dist/env'; import { getRegisteredQuery, @@ -22,8 +24,9 @@ import { } from '@neutron-org/neutronjsplus/dist/icq'; import { CodeId, NeutronContract } from '@neutron-org/neutronjsplus/dist/types'; import { paramChangeProposal } from '@neutron-org/neutronjsplus/dist/proposal'; -import { COSMOS_DENOM } from '@neutron-org/neutronjsplus'; import axios from 'axios'; +import { msgDelegate, msgUndelegate } from '../../helpers/gaia'; +import ICoin = cosmosclient.proto.cosmos.base.v1beta1.ICoin; const config = require('../../config.json'); @@ -112,6 +115,31 @@ const getValidatorsSigningInfosResult = ( }, }); +const getDelegatorUnbondingDelegationsResult = ( + cm: CosmosWrapper, + contractAddress: string, + queryId: number, +) => + cm.queryContract<{ + unbonding_delegations: { + unbonding_responses: { + delegator_address: string; + validator_address: string; + entries: { + balance: string; + completion_time: string | null; + creation_height: number; + initial_balance: string; + }[]; + }[]; + }; + last_submitted_local_height: number; + }>(contractAddress, { + get_unbonding_delegations: { + query_id: queryId, + }, + }); + const getCosmosSigningInfosResult = async (sdkUrl: string) => { try { return (await axios.get(`${sdkUrl}/cosmos/slashing/v1beta1/signing_infos`)) @@ -204,6 +232,38 @@ const registerSigningInfoQuery = async ( return queryId; }; +const registerUnbondingDelegationsQuery = async ( + cm: WalletWrapper, + contractAddress: string, + connectionId: string, + updatePeriod: number, + delegator: string, + validator: string, +) => { + const txResult = await cm.executeContract( + contractAddress, + JSON.stringify({ + register_delegator_unbonding_delegations_query: { + connection_id: connectionId, + delegator, + validators: [validator], + update_period: updatePeriod, + }, + }), + ); + + const attribute = getEventAttribute( + (txResult as any).events, + 'neutron', + 'query_id', + ); + + const queryId = parseInt(attribute); + expect(queryId).toBeGreaterThanOrEqual(0); + + return queryId; +}; + const acceptInterchainqueriesParamsChangeProposal = async ( cm: WalletWrapper, title: string, @@ -598,7 +658,8 @@ describe('Neutron / Interchain KV Query', () => { // because we only have one node per network in cosmopark test('perform icq #4: delegator delegations', async () => { const queryId = 4; - await gaiaAccount.msgDelegate( + await msgDelegate( + gaiaAccount, testState.wallets.cosmos.demo2.address.toString(), testState.wallets.cosmos.val1.address.toString(), '3000', @@ -858,7 +919,7 @@ describe('Neutron / Interchain KV Query', () => { balancesAfterRegistration.balances as ICoin[], ); - await removeQueryViaTx(neutronAccount, queryId); + await removeQueryViaTx(neutronAccount, BigInt(queryId)); await getWithAttempts( neutronChain.blockWaiter, @@ -973,4 +1034,94 @@ describe('Neutron / Interchain KV Query', () => { ).toBeGreaterThan(indexOffset); }); }); + + describe('Unbonding delegations query', () => { + let queryId: number; + let validatorAddress: string; + let delegatorAddress: string; + + beforeAll(async () => { + validatorAddress = testState.wallets.cosmos.val1.address.toString(); + delegatorAddress = testState.wallets.cosmos.demo2.address.toString(); + + await msgDelegate( + gaiaAccount, + delegatorAddress, + validatorAddress, + '3000', + ); + await msgUndelegate( + gaiaAccount, + delegatorAddress, + validatorAddress, + '2000', + ); + + // Top up contract address before running query + await neutronAccount.msgSend(contractAddress, '1000000'); + + queryId = await registerUnbondingDelegationsQuery( + neutronAccount, + contractAddress, + connectionId, + updatePeriods[2], + delegatorAddress, + validatorAddress, + ); + }); + + test('registered query data', async () => { + const queryResult = await getRegisteredQuery( + neutronChain, + contractAddress, + queryId, + ); + expect(queryResult.registered_query.id).toEqual(queryId); + expect(queryResult.registered_query.owner).toEqual(contractAddress); + expect(queryResult.registered_query.keys.length).toEqual(1); + expect(queryResult.registered_query.keys[0].path).toEqual('staking'); + expect(queryResult.registered_query.keys[0].key.length).toBeGreaterThan( + 0, + ); + expect(queryResult.registered_query.query_type).toEqual('kv'); + expect(queryResult.registered_query.transactions_filter).toEqual(''); + expect(queryResult.registered_query.connection_id).toEqual(connectionId); + }); + + test('query result', async () => { + await waitForICQResultWithRemoteHeight( + neutronChain, + contractAddress, + queryId, + await getHeight(gaiaChain.sdk), + ); + + const interchainQueryResult = + await getDelegatorUnbondingDelegationsResult( + neutronChain, + contractAddress, + queryId, + ); + expect(interchainQueryResult.last_submitted_local_height).toBeGreaterThan( + 0, + ); + expect( + interchainQueryResult.unbonding_delegations.unbonding_responses, + ).toEqual([ + { + delegator_address: 'cosmos10h9stc5v6ntgeygf5xf945njqq5h32r53uquvw', + validator_address: + 'cosmosvaloper18hl5c9xn5dze2g50uaw0l2mr02ew57zk0auktn', + entries: [ + { + balance: '2000', + completion_time: expect.any(String), + creation_height: expect.any(Number), + initial_balance: '2000', + }, + ], + }, + ]); + }); + }); }); From 687394905a427327b3c90cd299ace8c86a0642fa Mon Sep 17 00:00:00 2001 From: Murad Karammaev Date: Tue, 6 Feb 2024 15:53:16 +0200 Subject: [PATCH 4/5] fix: raise gas for msg (un)delegate --- src/helpers/gaia.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/helpers/gaia.ts b/src/helpers/gaia.ts index 66736123..1dc317c5 100644 --- a/src/helpers/gaia.ts +++ b/src/helpers/gaia.ts @@ -22,8 +22,8 @@ export const msgDelegate = async ( }); const res = await wallet.execTx( { - gas_limit: Long.fromString('200000'), - amount: [{ denom: wallet.chain.denom, amount: '1000' }], + gas_limit: Long.fromString('500000'), + amount: [{ denom: wallet.chain.denom, amount: '5000' }], }, [packAnyMsg('/cosmos.staking.v1beta1.MsgDelegate', msgDelegate)], ); @@ -43,8 +43,8 @@ export const msgUndelegate = async ( }); const res = await wallet.execTx( { - gas_limit: Long.fromString('200000'), - amount: [{ denom: wallet.chain.denom, amount: '1000' }], + gas_limit: Long.fromString('500000'), + amount: [{ denom: wallet.chain.denom, amount: '5000' }], }, [packAnyMsg('/cosmos.staking.v1beta1.MsgUndelegate', msgUndelegate)], ); From a1e464c71ed67a7ac42c0d6716d6d0500d06d790 Mon Sep 17 00:00:00 2001 From: Murad Karammaev Date: Mon, 12 Feb 2024 17:04:07 +0200 Subject: [PATCH 5/5] chore: delete useless XXX comment --- src/testcases/run_in_band/interchain_kv_query.test.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/testcases/run_in_band/interchain_kv_query.test.ts b/src/testcases/run_in_band/interchain_kv_query.test.ts index 2c8cf544..719cbba7 100644 --- a/src/testcases/run_in_band/interchain_kv_query.test.ts +++ b/src/testcases/run_in_band/interchain_kv_query.test.ts @@ -550,8 +550,6 @@ describe('Neutron / Interchain KV Query', () => { ); expect(queryResult.registered_query.id).toEqual(queryId); expect(queryResult.registered_query.owner).toEqual(contractAddress); - // XXX: I could actually check that "key" is correctly derived from contractAddress, - // but this requires bech32 decoding/encoding shenanigans expect(queryResult.registered_query.keys.length).toEqual(1); expect(queryResult.registered_query.keys[0].path).toEqual('bank'); expect(queryResult.registered_query.keys[0].key.length).toBeGreaterThan( @@ -997,8 +995,6 @@ describe('Neutron / Interchain KV Query', () => { ); expect(queryResult.registered_query.id).toEqual(queryId); expect(queryResult.registered_query.owner).toEqual(contractAddress); - // XXX: I could actually check that "key" is correctly derived from contractAddress, - // but this requires bech32 decoding/encoding shenanigans expect(queryResult.registered_query.keys.length).toEqual(1); expect(queryResult.registered_query.keys[0].path).toEqual('slashing'); expect(queryResult.registered_query.keys[0].key.length).toBeGreaterThan(