diff --git a/multichain-testing/config.yaml b/multichain-testing/config.yaml index e73005c4cb7..5fce1d31e7f 100644 --- a/multichain-testing/config.yaml +++ b/multichain-testing/config.yaml @@ -118,9 +118,6 @@ relayers: chains: - osmosislocal - cosmoshublocal - config: - global: - log_level: 'debug' - name: agoric-osmosis type: hermes image: ghcr.io/cosmology-tech/starship/hermes:1.10.5 @@ -128,9 +125,6 @@ relayers: chains: - agoriclocal - osmosislocal - config: - global: - log_level: 'debug' - name: agoric-cosmoshub type: hermes image: ghcr.io/cosmology-tech/starship/hermes:1.10.5 @@ -138,9 +132,6 @@ relayers: chains: - agoriclocal - cosmoshublocal - config: - global: - log_level: 'debug' explorer: enabled: true diff --git a/multichain-testing/test/ibc-transfers.ts b/multichain-testing/test/ibc-transfers.ts index a1530be4c33..77400556d82 100644 --- a/multichain-testing/test/ibc-transfers.ts +++ b/multichain-testing/test/ibc-transfers.ts @@ -4,9 +4,11 @@ import type { TestFn, ExecutionContext } from 'ava'; import { commonSetup, type SetupContext } from './support.js'; import { createWallet, generateMnemonic } from '../tools/wallet.js'; import { makeQueryClient } from '../tools/query.js'; -import { makeAgd } from '../tools/agd-lib.js'; +import { makeAgd, type Agd } from '../tools/agd-lib.js'; import starshipChainInfo from '../starship-chain-info.js'; import type { ForwardInfo } from '@agoric/orchestration'; +import { sleep } from '../tools/sleep.js'; +import { objectMap } from '@endo/patterns'; const test = anyTest as TestFn; @@ -14,6 +16,23 @@ test.before(async t => { t.context = await commonSetup(t); }); +const queryStrings = { + msgReceivePacket: { + agoric: ['--events', 'message.action=/ibc.core.channel.v1.MsgRecvPacket'], + cosmos: ['--query', "message.action='/ibc.core.channel.v1.MsgRecvPacket'"], + }, + msgAcknowledgement: { + agoric: [ + '--events', + 'message.action=/ibc.core.channel.v1.MsgAcknowledgement', + ], + cosmos: [ + '--query', + "message.action='/ibc.core.channel.v1.MsgAcknowledgement'", + ], + }, +}; + // use this on osmosis, cosmoshub as our account name in the keyring const keyName = 'testuser'; @@ -112,15 +131,80 @@ const setupSourceWallet = async ( }; }; -test('pfm: osmosis -> agoric -> gaia', async t => { - const { retryUntilCondition, useChain } = t.context; +type QueryRes = { total_count: string; txs: object[] }; +const queryPackets = async (binaries: Record) => { + const results: Record = {}; + for (const [name, chaind] of Object.entries(binaries)) { + // perhaps the different is pre/post v0.50 queries? + const queryType = name === 'agd' ? 'agoric' : 'cosmos'; + const recvs = await chaind.query([ + 'txs', + ...queryStrings.msgReceivePacket[queryType], + ]); + const acks = await chaind.query([ + 'txs', + ...queryStrings.msgAcknowledgement[queryType], + ]); + results[name] = { + recvs, + acks, + }; + } + return results; +}; +type ChainPacketCounts = Record< + string, + { + recvs: number; + acks: number; + } +>; + +const recordPackets = async ( + binaries: Record, + iteration: `q${number}`, +): Promise => { + const q = await queryPackets(binaries); + const counts = objectMap(q, val => ({ + recvs: Number(val.recvs.total_count), + acks: Number(val.acks.total_count), + })); + console.log(`${iteration} counts`, counts); + return counts; +}; + +const diffPacketCounts = ( + current: ChainPacketCounts, + previous: ChainPacketCounts, +): ChainPacketCounts => { + return objectMap(current, (val, key) => ({ + recvs: val.recvs - previous[key].recvs, + acks: val.acks - previous[key].acks, + })); +}; + +test('pfm: osmosis -> agoric -> cosmoshub', async t => { + const { agd, retryUntilCondition, useChain } = t.context; const { acctAddr: osmosisAddr, chaind: osmosisd } = await setupSourceWallet( t, { chainName: 'osmosis', }, ); + + const gaiad = makeAgd({ execFileSync }).withOpts({ + chainName: 'cosmoshub', + }); + const binaries = { + osmosisd, + agd, + gaiad, + }; + + await sleep(10_000); // wait for acks + const q0 = await recordPackets(binaries, 'q0'); + const { denom: denomOnOsmosis } = await fundRemote(t, { acctAddr: osmosisAddr, destChainName: 'osmosis', @@ -129,6 +213,19 @@ test('pfm: osmosis -> agoric -> gaia', async t => { denom: 'ubld', }); + await sleep(10_000); // wait for acks + const q1 = await recordPackets(binaries, 'q1'); + const p1Diff = diffPacketCounts(q1, q0); + t.like( + p1Diff, + { + osmosisd: { recvs: 1, acks: 0 }, + agd: { recvs: 0, acks: 1 }, + gaiad: { recvs: 0, acks: 0 }, + }, + 'Initial transfer packet counts incorrect', + ); + const cosmosChainId = useChain('cosmoshub').chain.chain_id; const agoricChainId = useChain('agoric').chain.chain_id; const osmosisChainId = useChain('osmosis').chain.chain_id; @@ -151,6 +248,10 @@ test('pfm: osmosis -> agoric -> gaia', async t => { }, }; + // intermediary receiver for PFM transfer + const agoricAddr = (await (await createWallet('agoric')).getAccounts())[0] + .address; + // agd tx ibc-transfer transfer [src-port] [src-channel] [receiver] [amount] [flags] const pfmThroughAgoric = await osmosisd.tx( [ @@ -158,10 +259,10 @@ test('pfm: osmosis -> agoric -> gaia', async t => { 'transfer', 'transfer', osmosisToAgoric.channelId, - 'agoric1ujmk0492mauq2f2vrcn7ylq3w3x55k0ap9mt2p', // consider using an agoric intermediary address + agoricAddr, `50${denomOnOsmosis}`, '--memo', - `'${JSON.stringify(forwardInfo)}'`, + `${JSON.stringify(forwardInfo)}`, // consider --packet-timeout-timestamp. default is 10mins ], { @@ -177,11 +278,28 @@ test('pfm: osmosis -> agoric -> gaia', async t => { const cosmosQueryClient = makeQueryClient( await useChain('cosmoshub').getRestEndpoint(), ); + + // TODO, wait until these events are observed instead of sleeping + await sleep(18_000); // wait for acks + const q2 = await recordPackets(binaries, 'q2'); + + const p2Diff = diffPacketCounts(q2, q1); + t.deepEqual( + p2Diff, + { + osmosisd: { recvs: 0, acks: 1 }, // Should receive ack from Agoric + agd: { recvs: 1, acks: 1 }, // Receives from Osmosis, gets ack from Cosmos + gaiad: { recvs: 1, acks: 0 }, // Receives forwarded packet + }, + 'PFM transfer packet counts incorrect', + ); + const { balances: cosmosBalances } = await retryUntilCondition( () => cosmosQueryClient.queryBalances(cosmosAddr), ({ balances }) => !!balances.length, `${cosmosAddr} received bld from osmosis`, ); t.log('cosmosBalances', cosmosBalances); - // osmosisd.keys.delete(keyName); + + osmosisd.keys.delete(keyName); }); diff --git a/multichain-testing/tools/agd-lib.js b/multichain-testing/tools/agd-lib.js index 54b51bf7c5d..190e701019f 100644 --- a/multichain-testing/tools/agd-lib.js +++ b/multichain-testing/tools/agd-lib.js @@ -96,10 +96,13 @@ export const makeAgd = ({ execFileSync }) => { * @param {| [kind: 'gov', domain: string, ...rest: any] * | [kind: 'tx', txhash: string] * | [mod: 'vstorage', kind: 'data' | 'children', path: string] + * | [kind: 'txs', ...rest: any] * } qArgs */ query: async qArgs => { - const out = exec(['query', ...qArgs, ...nodeArgs, ...outJson], { + const args = ['query', ...qArgs, ...nodeArgs, ...outJson]; + console.log(`$$$ ${chainToBinary[chainName]}`, ...args); + const out = exec(args, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'], });