From eb52e93fd4bf8027167f4ef02f62dd0a6f942c43 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 4 May 2023 18:25:11 +0200 Subject: [PATCH] Simplify searchTx --- .../src/cosmwasmclient.searchtx.spec.ts | 78 +++---------------- .../cosmwasm-stargate/src/cosmwasmclient.ts | 48 +++--------- packages/stargate/src/index.ts | 11 +-- packages/stargate/src/search.ts | 31 ++------ .../src/stargateclient.searchtx.spec.ts | 78 +++---------------- packages/stargate/src/stargateclient.ts | 52 +++---------- 6 files changed, 49 insertions(+), 249 deletions(-) diff --git a/packages/cosmwasm-stargate/src/cosmwasmclient.searchtx.spec.ts b/packages/cosmwasm-stargate/src/cosmwasmclient.searchtx.spec.ts index af79e7f4..5fde52e1 100644 --- a/packages/cosmwasm-stargate/src/cosmwasmclient.searchtx.spec.ts +++ b/packages/cosmwasm-stargate/src/cosmwasmclient.searchtx.spec.ts @@ -196,12 +196,12 @@ describe("CosmWasmClient.getTx and .searchTx", () => { }); }); - describe("with SearchByHeightQuery", () => { + describe("searchTx", () => { it("can search successful tx by height", async () => { pendingWithoutWasmd(); assert(sendSuccessful, "value must be set in beforeAll()"); const client = await CosmWasmClient.connect(wasmd.endpoint); - const result = await client.searchTx({ height: sendSuccessful.height }); + const result = await client.searchTx(`tx.height=${sendSuccessful.height}`); expect(result.length).toBeGreaterThanOrEqual(1); expect(result).toContain( jasmine.objectContaining({ @@ -218,7 +218,7 @@ describe("CosmWasmClient.getTx and .searchTx", () => { pendingWithoutWasmd(); assert(sendUnsuccessful, "value must be set in beforeAll()"); const client = await CosmWasmClient.connect(wasmd.endpoint); - const result = await client.searchTx({ height: sendUnsuccessful.height }); + const result = await client.searchTx(`tx.height=${sendUnsuccessful.height}`); expect(result.length).toBeGreaterThanOrEqual(1); expect(result).toContain( jasmine.objectContaining({ @@ -230,14 +230,14 @@ describe("CosmWasmClient.getTx and .searchTx", () => { }), ); }); - }); - describe("with SearchBySentFromOrToQuery", () => { it("can search by sender", async () => { pendingWithoutWasmd(); assert(sendSuccessful, "value must be set in beforeAll()"); const client = await CosmWasmClient.connect(wasmd.endpoint); - const results = await client.searchTx({ sentFromOrTo: sendSuccessful.sender }); + const results = await client.searchTx( + `message.module='bank' AND transfer.sender='${sendSuccessful.sender}'`, + ); expect(results.length).toBeGreaterThanOrEqual(1); // Check basic structure of all results @@ -266,7 +266,9 @@ describe("CosmWasmClient.getTx and .searchTx", () => { pendingWithoutWasmd(); assert(sendSuccessful, "value must be set in beforeAll()"); const client = await CosmWasmClient.connect(wasmd.endpoint); - const results = await client.searchTx({ sentFromOrTo: sendSuccessful.recipient }); + const results = await client.searchTx( + `message.module='bank' AND transfer.recipient='${sendSuccessful.recipient}'`, + ); expect(results.length).toBeGreaterThanOrEqual(1); // Check basic structure of all results @@ -290,69 +292,11 @@ describe("CosmWasmClient.getTx and .searchTx", () => { ); }); - it("can search by recipient and filter by minHeight", async () => { - pendingWithoutWasmd(); - assert(sendSuccessful); - const client = await CosmWasmClient.connect(wasmd.endpoint); - const query = { sentFromOrTo: sendSuccessful.recipient }; - - { - const result = await client.searchTx(query, { minHeight: 0 }); - expect(result.length).toEqual(1); - } - - { - const result = await client.searchTx(query, { minHeight: sendSuccessful.height - 1 }); - expect(result.length).toEqual(1); - } - - { - const result = await client.searchTx(query, { minHeight: sendSuccessful.height }); - expect(result.length).toEqual(1); - } - - { - const result = await client.searchTx(query, { minHeight: sendSuccessful.height + 1 }); - expect(result.length).toEqual(0); - } - }); - - it("can search by recipient and filter by maxHeight", async () => { - pendingWithoutWasmd(); - assert(sendSuccessful); - const client = await CosmWasmClient.connect(wasmd.endpoint); - const query = { sentFromOrTo: sendSuccessful.recipient }; - - { - const result = await client.searchTx(query, { maxHeight: 9999999999999 }); - expect(result.length).toEqual(1); - } - - { - const result = await client.searchTx(query, { maxHeight: sendSuccessful.height + 1 }); - expect(result.length).toEqual(1); - } - - { - const result = await client.searchTx(query, { maxHeight: sendSuccessful.height }); - expect(result.length).toEqual(1); - } - - { - const result = await client.searchTx(query, { maxHeight: sendSuccessful.height - 1 }); - expect(result.length).toEqual(0); - } - }); - }); - - describe("with SearchByTagsQuery", () => { - it("can search by transfer.recipient", async () => { + it("works with tags", async () => { pendingWithoutWasmd(); assert(sendSuccessful, "value must be set in beforeAll()"); const client = await CosmWasmClient.connect(wasmd.endpoint); - const results = await client.searchTx({ - tags: [{ key: "transfer.recipient", value: sendSuccessful.recipient }], - }); + const results = await client.searchTx([{ key: "transfer.recipient", value: sendSuccessful.recipient }]); expect(results.length).toBeGreaterThanOrEqual(1); // Check basic structure of all results diff --git a/packages/cosmwasm-stargate/src/cosmwasmclient.ts b/packages/cosmwasm-stargate/src/cosmwasmclient.ts index b52d54e9..aebe895c 100644 --- a/packages/cosmwasm-stargate/src/cosmwasmclient.ts +++ b/packages/cosmwasm-stargate/src/cosmwasmclient.ts @@ -12,11 +12,7 @@ import { DeliverTxResponse, fromTendermintEvent, IndexedTx, - isSearchByHeightQuery, - isSearchBySentFromOrToQuery, - isSearchByTagsQuery, QueryClient, - SearchTxFilter, SearchTxQuery, SequenceResponse, setupAuthExtension, @@ -221,42 +217,16 @@ export class CosmWasmClient { return results[0] ?? null; } - public async searchTx(query: SearchTxQuery, filter: SearchTxFilter = {}): Promise { - const minHeight = filter.minHeight || 0; - const maxHeight = filter.maxHeight || Number.MAX_SAFE_INTEGER; - - if (maxHeight < minHeight) return []; // optional optimization - - function withFilters(originalQuery: string): string { - return `${originalQuery} AND tx.height>=${minHeight} AND tx.height<=${maxHeight}`; - } - - let txs: readonly IndexedTx[]; - - if (isSearchByHeightQuery(query)) { - txs = - query.height >= minHeight && query.height <= maxHeight - ? await this.txsQuery(`tx.height=${query.height}`) - : []; - } else if (isSearchBySentFromOrToQuery(query)) { - const sentQuery = withFilters(`message.module='bank' AND transfer.sender='${query.sentFromOrTo}'`); - const receivedQuery = withFilters( - `message.module='bank' AND transfer.recipient='${query.sentFromOrTo}'`, - ); - const [sent, received] = await Promise.all( - [sentQuery, receivedQuery].map((rawQuery) => this.txsQuery(rawQuery)), - ); - const sentHashes = sent.map((t) => t.hash); - txs = [...sent, ...received.filter((t) => !sentHashes.includes(t.hash))]; - } else if (isSearchByTagsQuery(query)) { - const rawQuery = withFilters(query.tags.map((t) => `${t.key}='${t.value}'`).join(" AND ")); - txs = await this.txsQuery(rawQuery); + public async searchTx(query: SearchTxQuery): Promise { + let rawQuery: string; + if (typeof query === "string") { + rawQuery = query; + } else if (Array.isArray(query)) { + rawQuery = query.map((t) => `${t.key}='${t.value}'`).join(" AND "); } else { - throw new Error("Unknown query type"); + throw new Error("Got unsupported query type. See CosmJS 0.31 CHANGELOG for API breaking changes here."); } - - const filtered = txs.filter((tx) => tx.height >= minHeight && tx.height <= maxHeight); - return filtered; + return this.txsQuery(rawQuery); } public disconnect(): void { @@ -477,7 +447,7 @@ export class CosmWasmClient { } } - private async txsQuery(query: string): Promise { + private async txsQuery(query: string): Promise { const results = await this.forceGetTmClient().txSearchAll({ query: query }); return results.txs.map((tx) => { return { diff --git a/packages/stargate/src/index.ts b/packages/stargate/src/index.ts index 23720d37..5a41e4df 100644 --- a/packages/stargate/src/index.ts +++ b/packages/stargate/src/index.ts @@ -112,16 +112,7 @@ export { QueryClient, QueryStoreResponse, } from "./queryclient"; -export { - isSearchByHeightQuery, - isSearchBySentFromOrToQuery, - isSearchByTagsQuery, - SearchByHeightQuery, - SearchBySentFromOrToQuery, - SearchByTagsQuery, - SearchTxFilter, - SearchTxQuery, -} from "./search"; +export { SearchByHeightQuery, SearchBySentFromOrToQuery, SearchTxQuery } from "./search"; export { createDefaultAminoConverters, defaultRegistryTypes, diff --git a/packages/stargate/src/search.ts b/packages/stargate/src/search.ts index aae61508..3261ca24 100644 --- a/packages/stargate/src/search.ts +++ b/packages/stargate/src/search.ts @@ -7,28 +7,11 @@ export interface SearchBySentFromOrToQuery { } /** - * This query type allows you to pass arbitrary key/value pairs to the backend. It is - * more powerful and slightly lower level than the other search options. + * This query type allows you to pass arbitrary key/value pairs to the backend. */ -export interface SearchByTagsQuery { - readonly tags: ReadonlyArray<{ readonly key: string; readonly value: string }>; -} - -export type SearchTxQuery = SearchByHeightQuery | SearchBySentFromOrToQuery | SearchByTagsQuery; - -export function isSearchByHeightQuery(query: SearchTxQuery): query is SearchByHeightQuery { - return (query as SearchByHeightQuery).height !== undefined; -} - -export function isSearchBySentFromOrToQuery(query: SearchTxQuery): query is SearchBySentFromOrToQuery { - return (query as SearchBySentFromOrToQuery).sentFromOrTo !== undefined; -} - -export function isSearchByTagsQuery(query: SearchTxQuery): query is SearchByTagsQuery { - return (query as SearchByTagsQuery).tags !== undefined; -} - -export interface SearchTxFilter { - readonly minHeight?: number; - readonly maxHeight?: number; -} +export type SearchTxQuery = + | string + | ReadonlyArray<{ + readonly key: string; + readonly value: string; + }>; diff --git a/packages/stargate/src/stargateclient.searchtx.spec.ts b/packages/stargate/src/stargateclient.searchtx.spec.ts index 01d0e27a..30c6c539 100644 --- a/packages/stargate/src/stargateclient.searchtx.spec.ts +++ b/packages/stargate/src/stargateclient.searchtx.spec.ts @@ -190,12 +190,12 @@ describe("StargateClient.getTx and .searchTx", () => { }); }); - describe("with SearchByHeightQuery", () => { + describe("searchTx", () => { it("can search successful tx by height", async () => { pendingWithoutSimapp(); assert(sendSuccessful, "value must be set in beforeAll()"); const client = await StargateClient.connect(simapp.tendermintUrl); - const result = await client.searchTx({ height: sendSuccessful.height }); + const result = await client.searchTx(`tx.height=${sendSuccessful.height}`); expect(result.length).toBeGreaterThanOrEqual(1); expect(result).toContain( jasmine.objectContaining({ @@ -211,7 +211,7 @@ describe("StargateClient.getTx and .searchTx", () => { pendingWithoutSimapp(); assert(sendUnsuccessful, "value must be set in beforeAll()"); const client = await StargateClient.connect(simapp.tendermintUrl); - const result = await client.searchTx({ height: sendUnsuccessful.height }); + const result = await client.searchTx(`tx.height=${sendUnsuccessful.height}`); expect(result.length).toBeGreaterThanOrEqual(1); expect(result).toContain( jasmine.objectContaining({ @@ -222,14 +222,14 @@ describe("StargateClient.getTx and .searchTx", () => { }), ); }); - }); - describe("with SearchBySentFromOrToQuery", () => { it("can search by sender", async () => { pendingWithoutSimapp(); assert(sendSuccessful, "value must be set in beforeAll()"); const client = await StargateClient.connect(simapp.tendermintUrl); - const results = await client.searchTx({ sentFromOrTo: sendSuccessful.sender }); + const results = await client.searchTx( + `message.module='bank' AND transfer.sender='${sendSuccessful.sender}'`, + ); expect(results.length).toBeGreaterThanOrEqual(1); // Check basic structure of all results @@ -257,7 +257,9 @@ describe("StargateClient.getTx and .searchTx", () => { pendingWithoutSimapp(); assert(sendSuccessful, "value must be set in beforeAll()"); const client = await StargateClient.connect(simapp.tendermintUrl); - const results = await client.searchTx({ sentFromOrTo: sendSuccessful.recipient }); + const results = await client.searchTx( + `message.module='bank' AND transfer.recipient='${sendSuccessful.recipient}'`, + ); expect(results.length).toBeGreaterThanOrEqual(1); // Check basic structure of all results @@ -281,69 +283,11 @@ describe("StargateClient.getTx and .searchTx", () => { ); }); - it("can search by recipient and filter by minHeight", async () => { - pendingWithoutSimapp(); - assert(sendSuccessful); - const client = await StargateClient.connect(simapp.tendermintUrl); - const query = { sentFromOrTo: sendSuccessful.recipient }; - - { - const result = await client.searchTx(query, { minHeight: 0 }); - expect(result.length).toEqual(1); - } - - { - const result = await client.searchTx(query, { minHeight: sendSuccessful.height - 1 }); - expect(result.length).toEqual(1); - } - - { - const result = await client.searchTx(query, { minHeight: sendSuccessful.height }); - expect(result.length).toEqual(1); - } - - { - const result = await client.searchTx(query, { minHeight: sendSuccessful.height + 1 }); - expect(result.length).toEqual(0); - } - }); - - it("can search by recipient and filter by maxHeight", async () => { - pendingWithoutSimapp(); - assert(sendSuccessful); - const client = await StargateClient.connect(simapp.tendermintUrl); - const query = { sentFromOrTo: sendSuccessful.recipient }; - - { - const result = await client.searchTx(query, { maxHeight: 9999999999999 }); - expect(result.length).toEqual(1); - } - - { - const result = await client.searchTx(query, { maxHeight: sendSuccessful.height + 1 }); - expect(result.length).toEqual(1); - } - - { - const result = await client.searchTx(query, { maxHeight: sendSuccessful.height }); - expect(result.length).toEqual(1); - } - - { - const result = await client.searchTx(query, { maxHeight: sendSuccessful.height - 1 }); - expect(result.length).toEqual(0); - } - }); - }); - - describe("with SearchByTagsQuery", () => { - it("can search by transfer.recipient", async () => { + it("works with tags", async () => { pendingWithoutSimapp(); assert(sendSuccessful, "value must be set in beforeAll()"); const client = await StargateClient.connect(simapp.tendermintUrl); - const results = await client.searchTx({ - tags: [{ key: "transfer.recipient", value: sendSuccessful.recipient }], - }); + const results = await client.searchTx([{ key: "transfer.recipient", value: sendSuccessful.recipient }]); expect(results.length).toBeGreaterThanOrEqual(1); // Check basic structure of all results diff --git a/packages/stargate/src/stargateclient.ts b/packages/stargate/src/stargateclient.ts index c412f262..43d92a25 100644 --- a/packages/stargate/src/stargateclient.ts +++ b/packages/stargate/src/stargateclient.ts @@ -28,13 +28,7 @@ import { TxExtension, } from "./modules"; import { QueryClient } from "./queryclient"; -import { - isSearchByHeightQuery, - isSearchBySentFromOrToQuery, - isSearchByTagsQuery, - SearchTxFilter, - SearchTxQuery, -} from "./search"; +import { SearchTxQuery } from "./search"; export class TimeoutError extends Error { public readonly txId: string; @@ -394,42 +388,16 @@ export class StargateClient { return results[0] ?? null; } - public async searchTx(query: SearchTxQuery, filter: SearchTxFilter = {}): Promise { - const minHeight = filter.minHeight || 0; - const maxHeight = filter.maxHeight || Number.MAX_SAFE_INTEGER; - - if (maxHeight < minHeight) return []; // optional optimization - - function withFilters(originalQuery: string): string { - return `${originalQuery} AND tx.height>=${minHeight} AND tx.height<=${maxHeight}`; - } - - let txs: readonly IndexedTx[]; - - if (isSearchByHeightQuery(query)) { - txs = - query.height >= minHeight && query.height <= maxHeight - ? await this.txsQuery(`tx.height=${query.height}`) - : []; - } else if (isSearchBySentFromOrToQuery(query)) { - const sentQuery = withFilters(`message.module='bank' AND transfer.sender='${query.sentFromOrTo}'`); - const receivedQuery = withFilters( - `message.module='bank' AND transfer.recipient='${query.sentFromOrTo}'`, - ); - const [sent, received] = await Promise.all( - [sentQuery, receivedQuery].map((rawQuery) => this.txsQuery(rawQuery)), - ); - const sentHashes = sent.map((t) => t.hash); - txs = [...sent, ...received.filter((t) => !sentHashes.includes(t.hash))]; - } else if (isSearchByTagsQuery(query)) { - const rawQuery = withFilters(query.tags.map((t) => `${t.key}='${t.value}'`).join(" AND ")); - txs = await this.txsQuery(rawQuery); + public async searchTx(query: SearchTxQuery): Promise { + let rawQuery: string; + if (typeof query === "string") { + rawQuery = query; + } else if (Array.isArray(query)) { + rawQuery = query.map((t) => `${t.key}='${t.value}'`).join(" AND "); } else { - throw new Error("Unknown query type"); + throw new Error("Got unsupported query type. See CosmJS 0.31 CHANGELOG for API breaking changes here."); } - - const filtered = txs.filter((tx) => tx.height >= minHeight && tx.height <= maxHeight); - return filtered; + return this.txsQuery(rawQuery); } public disconnect(): void { @@ -503,7 +471,7 @@ export class StargateClient { ); } - private async txsQuery(query: string): Promise { + private async txsQuery(query: string): Promise { const results = await this.forceGetTmClient().txSearchAll({ query: query }); return results.txs.map((tx) => { return {