From dd2d28bf39eb6c0a37e0f8d525529be83fa5585a Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Tue, 21 Jan 2025 14:28:51 -0600 Subject: [PATCH] fixup! feat(multichain/tools): executeOfferTx does not wait for completion --- multichain-testing/tools/block-iter.js | 59 ++++++++++++++++++++++++++ multichain-testing/tools/query.ts | 11 +++++ 2 files changed, 70 insertions(+) create mode 100644 multichain-testing/tools/block-iter.js diff --git a/multichain-testing/tools/block-iter.js b/multichain-testing/tools/block-iter.js new file mode 100644 index 00000000000..191baac7bdc --- /dev/null +++ b/multichain-testing/tools/block-iter.js @@ -0,0 +1,59 @@ +import { makeIntervalIterable } from '@agoric/client-utils/src/clock-timer.js'; + +const { freeze } = Object; + +/** + * @import {IntervalIO} from '@agoric/client-utils/src/clock-timer.js'; + * @import {makeQueryClient} from './query.js'; + */ + +/** + * @param {ReturnType} api + * @param {number} [delta] + */ +const recentBlockRate = async (api, delta = 2) => { + /** @param {{ height: number, time: string }} header */ + const relevant = ({ height, time }) => ({ height, time }); + const { block: latest } = await api.queryBlock(); + const heightRecent = Number(latest.header.height) - delta; + const { block: recent } = await api.queryBlock(heightRecent); + const t0 = Date.parse(recent.header.time); + const t1 = Date.parse(latest.header.time); + return { + delta, + latest: { ...relevant(latest.header) }, + recent: { ...relevant(recent.header) }, + elapsed: t1 - t0, + period: (t1 - t0) / delta, + }; +}; + +/** + * Make an iterator for observing each block. + * + * We measure the block rate by observing the latest block + * and one earlier (by `delta`) block. + * + * Then we poll at 2x that rate (Nyquist frequency) and + * fire the iterator when the height changes. + * + * @param {IntervalIO & { api: ReturnType, delta?: number }} io + */ +export const makeBlocksIterable = ({ api, delta = 2, ...io }) => { + return freeze({ + async *[Symbol.asyncIterator]() { + const { period } = await recentBlockRate(api, delta); + const nyquist = period / 2; + let prev; + const ticks = makeIntervalIterable(nyquist, io); + for await (const tick of ticks) { + const { block } = await api.queryBlock(); + const current = Number(block.header.height); + if (current === prev) continue; + prev = current; + const { time } = block.header; + yield freeze({ tick, height: current, time }); + } + }, + }); +}; diff --git a/multichain-testing/tools/query.ts b/multichain-testing/tools/query.ts index 1e4c10b13f4..b8633825ba4 100644 --- a/multichain-testing/tools/query.ts +++ b/multichain-testing/tools/query.ts @@ -10,8 +10,15 @@ import type { QueryDenomHashResponseSDKType } from '@agoric/cosmic-proto/ibc/app import type { QueryChannelResponseSDKType } from '@agoric/cosmic-proto/ibc/core/channel/v1/query.js'; import type { QueryChannelsResponseSDKType } from '@agoric/cosmic-proto/ibc/core/channel/v1/query.js'; +// TODO: export tendermint Block from @agoric/cosmic-proto +type BlockHeaderPartial = { + height: number; + time: string; +}; + // TODO use telescope generated query client from @agoric/cosmic-proto // https://github.com/Agoric/agoric-sdk/issues/9200 +// TODO: inject fetch export function makeQueryClient(apiUrl: string) { const query = async (path: string): Promise => { try { @@ -26,6 +33,10 @@ export function makeQueryClient(apiUrl: string) { return { query, + queryBlock: (height?: number) => + query<{ block: { header: BlockHeaderPartial } }>( + `/cosmos/base/tendermint/v1beta1/blocks/${height || 'latest'}`, + ), queryBalances: (address: string) => query( `/cosmos/bank/v1beta1/balances/${address}`,