From aff82e1f40fc26d6a6602804dd37b5ae58df54ce Mon Sep 17 00:00:00 2001 From: willclarktech Date: Wed, 10 Jun 2020 12:45:34 +0100 Subject: [PATCH 1/3] Improve cosmwasm searchTx by sentFromOrTo --- packages/cosmwasm/src/cosmwasmclient.ts | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/packages/cosmwasm/src/cosmwasmclient.ts b/packages/cosmwasm/src/cosmwasmclient.ts index 45f88de7..e6cac469 100644 --- a/packages/cosmwasm/src/cosmwasmclient.ts +++ b/packages/cosmwasm/src/cosmwasmclient.ts @@ -286,11 +286,26 @@ export class CosmWasmClient { // We cannot get both in one request (see https://github.com/cosmos/gaia/issues/75) const sentQuery = withFilters(`message.module=bank&message.sender=${query.sentFromOrTo}`); const receivedQuery = withFilters(`message.module=bank&transfer.recipient=${query.sentFromOrTo}`); - const sent = await this.txsQuery(sentQuery); - const received = await this.txsQuery(receivedQuery); + const [sent, received] = (await Promise.all([ + this.txsQuery(sentQuery), + this.txsQuery(receivedQuery), + ])) as [IndexedTx[], IndexedTx[]]; - const sentHashes = sent.map((t) => t.hash); - txs = [...sent, ...received.filter((t) => !sentHashes.includes(t.hash))]; + txs = []; + /* eslint-disable @typescript-eslint/no-non-null-assertion */ + // sent/received are presorted + while (sent.length && received.length) { + const next = + sent[0].hash === received[0].hash + ? sent.shift()! && received.shift()! + : sent[0].height <= received[0].height + ? sent.shift()! + : received.shift()!; + txs = [...txs, next]; + } + /* eslint-enable @typescript-eslint/no-non-null-assertion */ + // At least one of sent/received is empty by now + txs = [...txs, ...sent, ...received]; } else if (isSearchByTagsQuery(query)) { const rawQuery = withFilters(query.tags.map((t) => `${t.key}=${t.value}`).join("&")); txs = await this.txsQuery(rawQuery); From 16cb27bf46db6bdbaaf560391995b3bd0bce6771 Mon Sep 17 00:00:00 2001 From: willclarktech Date: Wed, 10 Jun 2020 12:46:18 +0100 Subject: [PATCH 2/3] Add sorting/dedup test for cosmwasm searchTx by sentFromOrTo --- .../src/cosmwasmclient.searchtx.spec.ts | 64 +++++++++++++------ 1 file changed, 44 insertions(+), 20 deletions(-) diff --git a/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts b/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts index 9ed9a979..e0c8f909 100644 --- a/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts +++ b/packages/cosmwasm/src/cosmwasmclient.searchtx.spec.ts @@ -16,25 +16,20 @@ import { wasmdEnabled, } from "./testutils.spec"; +type TestSendTx = + | { + readonly sender: string; + readonly recipient: string; + readonly hash: string; + readonly height: number; + readonly tx: CosmosSdkTx; + } + | undefined; + describe("CosmWasmClient.searchTx", () => { - let sendSuccessful: - | { - readonly sender: string; - readonly recipient: string; - readonly hash: string; - readonly height: number; - readonly tx: CosmosSdkTx; - } - | undefined; - let sendUnsuccessful: - | { - readonly sender: string; - readonly recipient: string; - readonly hash: string; - readonly height: number; - readonly tx: CosmosSdkTx; - } - | undefined; + let sendSuccessful: TestSendTx; + let sendSelfSuccessful: TestSendTx; + let sendUnsuccessful: TestSendTx; let postedExecute: | { readonly sender: string; @@ -70,6 +65,24 @@ describe("CosmWasmClient.searchTx", () => { }; } + { + const recipient = alice.address0; + const transferAmount: Coin = { + denom: "ucosm", + amount: "2345678", + }; + const result = await client.sendTokens(recipient, [transferAmount]); + await sleep(75); // wait until tx is indexed + const txDetails = await new RestClient(wasmd.endpoint).txById(result.transactionHash); + sendSelfSuccessful = { + sender: alice.address0, + recipient: recipient, + hash: result.transactionHash, + height: Number.parseInt(txDetails.height, 10), + tx: txDetails.tx, + }; + } + { const memo = "Sending more than I can afford"; const recipient = makeRandomAddress(); @@ -268,8 +281,8 @@ describe("CosmWasmClient.searchTx", () => { expect(containsMsgWithSender || containsMsgWithRecipient).toEqual(true); } - // Check details of most recent result - expect(results[results.length - 1]).toEqual( + // Check details of most recent result (not sent to self) + expect(results[results.length - 2]).toEqual( jasmine.objectContaining({ height: sendSuccessful.height, hash: sendSuccessful.hash, @@ -305,6 +318,17 @@ describe("CosmWasmClient.searchTx", () => { ); }); + it("can search by sender or recipient (sorted and deduplicated)", async () => { + pendingWithoutWasmd(); + assert(sendSelfSuccessful, "value must be set in beforeAll()"); + const txhash = sendSelfSuccessful.hash; + const client = new CosmWasmClient(wasmd.endpoint); + const results = await client.searchTx({ sentFromOrTo: sendSelfSuccessful.recipient }); + + expect(Array.from(results).sort((tx1, tx2) => tx1.height - tx2.height)).toEqual(results); + expect(results.filter((result) => result.hash === txhash).length).toEqual(1); + }); + it("can search by recipient and filter by minHeight", async () => { pendingWithoutWasmd(); assert(sendSuccessful); From f816c961b49195959961946e88979cf8c25279f0 Mon Sep 17 00:00:00 2001 From: willclarktech Date: Wed, 10 Jun 2020 13:47:32 +0100 Subject: [PATCH 3/3] Improve readability of cosmwasm searchTx by sentFromOrTo --- packages/cosmwasm/src/cosmwasmclient.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/cosmwasm/src/cosmwasmclient.ts b/packages/cosmwasm/src/cosmwasmclient.ts index e6cac469..e8a17b4d 100644 --- a/packages/cosmwasm/src/cosmwasmclient.ts +++ b/packages/cosmwasm/src/cosmwasmclient.ts @@ -291,7 +291,7 @@ export class CosmWasmClient { this.txsQuery(receivedQuery), ])) as [IndexedTx[], IndexedTx[]]; - txs = []; + let mergedTxs: readonly IndexedTx[] = []; /* eslint-disable @typescript-eslint/no-non-null-assertion */ // sent/received are presorted while (sent.length && received.length) { @@ -301,11 +301,11 @@ export class CosmWasmClient { : sent[0].height <= received[0].height ? sent.shift()! : received.shift()!; - txs = [...txs, next]; + mergedTxs = [...mergedTxs, next]; } /* eslint-enable @typescript-eslint/no-non-null-assertion */ // At least one of sent/received is empty by now - txs = [...txs, ...sent, ...received]; + txs = [...mergedTxs, ...sent, ...received]; } else if (isSearchByTagsQuery(query)) { const rawQuery = withFilters(query.tags.map((t) => `${t.key}=${t.value}`).join("&")); txs = await this.txsQuery(rawQuery);