From 798854b002828fdc59319a0f49c01f42a1244ccf Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Fri, 21 Feb 2020 13:01:35 +0100 Subject: [PATCH] Rename to txsQuery and test --- packages/sdk/src/cosmwasmclient.ts | 9 +- packages/sdk/src/restclient.spec.ts | 179 +++++++++++++++++++++++++++- packages/sdk/src/restclient.ts | 20 ++-- packages/sdk/types/restclient.d.ts | 4 +- 4 files changed, 194 insertions(+), 18 deletions(-) diff --git a/packages/sdk/src/cosmwasmclient.ts b/packages/sdk/src/cosmwasmclient.ts index 7a305740..5542eaf8 100644 --- a/packages/sdk/src/cosmwasmclient.ts +++ b/packages/sdk/src/cosmwasmclient.ts @@ -111,13 +111,14 @@ export class CosmWasmClient { } if (isSearchByIdQuery(query)) { - return (await this.restClient.txs(`tx.hash=${query.id}`)).txs; + return (await this.restClient.txsQuery(`tx.hash=${query.id}`)).txs; } else if (isSearchByHeightQuery(query)) { - return (await this.restClient.txs(`tx.height=${query.height}`)).txs; + return (await this.restClient.txsQuery(`tx.height=${query.height}`)).txs; } else if (isSearchBySentFromOrToQuery(query)) { // We cannot get both in one request (see https://github.com/cosmos/gaia/issues/75) - const sent = (await this.restClient.txs(limited(`message.sender=${query.sentFromOrTo}`))).txs; - const received = (await this.restClient.txs(limited(`transfer.recipient=${query.sentFromOrTo}`))).txs; + const sent = (await this.restClient.txsQuery(limited(`message.sender=${query.sentFromOrTo}`))).txs; + const received = (await this.restClient.txsQuery(limited(`transfer.recipient=${query.sentFromOrTo}`))) + .txs; const sentHashes = sent.map(t => t.txhash); return [...sent, ...received.filter(t => !sentHashes.includes(t.txhash))]; } else { diff --git a/packages/sdk/src/restclient.spec.ts b/packages/sdk/src/restclient.spec.ts index b381023f..27171dbf 100644 --- a/packages/sdk/src/restclient.spec.ts +++ b/packages/sdk/src/restclient.spec.ts @@ -1,14 +1,15 @@ /* eslint-disable @typescript-eslint/camelcase */ import { Sha256 } from "@iov/crypto"; import { Encoding } from "@iov/encoding"; -import { assert } from "@iov/utils"; +import { assert, sleep } from "@iov/utils"; import { ReadonlyDate } from "readonly-date"; import { makeSignBytes } from "./encoding"; import { findAttribute, parseLogs } from "./logs"; import { Pen, Secp256k1Pen } from "./pen"; import { encodeBech32Pubkey } from "./pubkey"; -import { PostTxsResponse, RestClient } from "./restclient"; +import { PostTxsResponse, RestClient, TxsResponse } from "./restclient"; +import { SigningCosmWasmClient } from "./signingcosmwasmclient"; import cosmoshub from "./testdata/cosmoshub.json"; import { getRandomizedHackatom, @@ -304,6 +305,180 @@ describe("RestClient", () => { // The /txs endpoints + describe("txsQuery", () => { + let posted: + | { + readonly sender: string; + readonly recipient: string; + readonly hash: string; + readonly height: number; + readonly tx: TxsResponse; + } + | undefined; + + beforeAll(async () => { + if (wasmdEnabled()) { + const pen = await Secp256k1Pen.fromMnemonic(faucet.mnemonic); + const client = new SigningCosmWasmClient(httpUrl, faucet.address, signBytes => pen.sign(signBytes)); + + const recipient = makeRandomAddress(); + const transferAmount = [ + { + denom: "ucosm", + amount: "1234567", + }, + ]; + const result = await client.sendTokens(recipient, transferAmount); + + await sleep(50); // wait until tx is indexed + const txDetails = await new RestClient(httpUrl).txsById(result.transactionHash); + posted = { + sender: faucet.address, + recipient: recipient, + hash: result.transactionHash, + height: Number.parseInt(txDetails.height, 10), + tx: txDetails, + }; + } + }); + + it("can query transactions by height", async () => { + pendingWithoutWasmd(); + assert(posted); + const client = new RestClient(httpUrl); + const result = await client.txsQuery(`tx.height=${posted.height}&limit=26`); + expect(parseInt(result.count, 10)).toEqual(1); + expect(parseInt(result.limit, 10)).toEqual(26); + expect(parseInt(result.page_number, 10)).toEqual(1); + expect(parseInt(result.page_total, 10)).toEqual(1); + expect(parseInt(result.total_count, 10)).toEqual(1); + expect(result.txs).toEqual([posted.tx]); + }); + + it("can query transactions by ID", async () => { + pendingWithoutWasmd(); + assert(posted); + const client = new RestClient(httpUrl); + const result = await client.txsQuery(`tx.hash=${posted.hash}&limit=26`); + expect(parseInt(result.count, 10)).toEqual(1); + expect(parseInt(result.limit, 10)).toEqual(26); + expect(parseInt(result.page_number, 10)).toEqual(1); + expect(parseInt(result.page_total, 10)).toEqual(1); + expect(parseInt(result.total_count, 10)).toEqual(1); + expect(result.txs).toEqual([posted.tx]); + }); + + it("can query transactions by sender", async () => { + pendingWithoutWasmd(); + assert(posted); + const client = new RestClient(httpUrl); + const result = await client.txsQuery(`message.sender=${posted.sender}&limit=200`); + expect(parseInt(result.count, 10)).toBeGreaterThanOrEqual(1); + expect(parseInt(result.limit, 10)).toEqual(200); + expect(parseInt(result.page_number, 10)).toEqual(1); + expect(parseInt(result.page_total, 10)).toEqual(1); + expect(parseInt(result.total_count, 10)).toBeGreaterThanOrEqual(1); + expect(result.txs.length).toBeGreaterThanOrEqual(1); + expect(result.txs[result.txs.length - 1]).toEqual(posted.tx); + }); + + it("can query transactions by recipient", async () => { + pendingWithoutWasmd(); + assert(posted); + const client = new RestClient(httpUrl); + const result = await client.txsQuery(`transfer.recipient=${posted.recipient}&limit=200`); + expect(parseInt(result.count, 10)).toEqual(1); + expect(parseInt(result.limit, 10)).toEqual(200); + expect(parseInt(result.page_number, 10)).toEqual(1); + expect(parseInt(result.page_total, 10)).toEqual(1); + expect(parseInt(result.total_count, 10)).toEqual(1); + expect(result.txs.length).toBeGreaterThanOrEqual(1); + expect(result.txs[result.txs.length - 1]).toEqual(posted.tx); + }); + + it("can filter by tx.hash and tx.minheight", async () => { + pending("This combination is broken 🤷‍♂️. Handle client-side at higher level."); + pendingWithoutWasmd(); + assert(posted); + const client = new RestClient(httpUrl); + const hashQuery = `tx.hash=${posted.hash}`; + + { + const { count } = await client.txsQuery(`${hashQuery}&tx.minheight=0`); + expect(count).toEqual("1"); + } + + { + const { count } = await client.txsQuery(`${hashQuery}&tx.minheight=${posted.height - 1}`); + expect(count).toEqual("1"); + } + + { + const { count } = await client.txsQuery(`${hashQuery}&tx.minheight=${posted.height}`); + expect(count).toEqual("1"); + } + + { + const { count } = await client.txsQuery(`${hashQuery}&tx.minheight=${posted.height + 1}`); + expect(count).toEqual("0"); + } + }); + + it("can filter by recipient and tx.minheight", async () => { + pendingWithoutWasmd(); + assert(posted); + const client = new RestClient(httpUrl); + const recipientQuery = `transfer.recipient=${posted.recipient}`; + + { + const { count } = await client.txsQuery(`${recipientQuery}&tx.minheight=0`); + expect(count).toEqual("1"); + } + + { + const { count } = await client.txsQuery(`${recipientQuery}&tx.minheight=${posted.height - 1}`); + expect(count).toEqual("1"); + } + + { + const { count } = await client.txsQuery(`${recipientQuery}&tx.minheight=${posted.height}`); + expect(count).toEqual("1"); + } + + { + const { count } = await client.txsQuery(`${recipientQuery}&tx.minheight=${posted.height + 1}`); + expect(count).toEqual("0"); + } + }); + + it("can filter by recipient and tx.maxheight", async () => { + pendingWithoutWasmd(); + assert(posted); + const client = new RestClient(httpUrl); + const recipientQuery = `transfer.recipient=${posted.recipient}`; + + { + const { count } = await client.txsQuery(`${recipientQuery}&tx.maxheight=9999999999999`); + expect(count).toEqual("1"); + } + + { + const { count } = await client.txsQuery(`${recipientQuery}&tx.maxheight=${posted.height + 1}`); + expect(count).toEqual("1"); + } + + { + const { count } = await client.txsQuery(`${recipientQuery}&tx.maxheight=${posted.height}`); + expect(count).toEqual("1"); + } + + { + const { count } = await client.txsQuery(`${recipientQuery}&tx.maxheight=${posted.height - 1}`); + expect(count).toEqual("0"); + } + }); + }); + describe("encodeTx", () => { it("works for cosmoshub example", async () => { pendingWithoutWasmd(); diff --git a/packages/sdk/src/restclient.ts b/packages/sdk/src/restclient.ts index 89bbac09..2387692f 100644 --- a/packages/sdk/src/restclient.ts +++ b/packages/sdk/src/restclient.ts @@ -276,16 +276,7 @@ export class RestClient { // The /txs endpoints - /** returns the amino-encoding of the transaction performed by the server */ - public async encodeTx(tx: CosmosSdkTx): Promise { - const responseData = await this.post("/txs/encode", tx); - if (!(responseData as any).tx) { - throw new Error("Unexpected response data format"); - } - return Encoding.fromBase64((responseData as EncodeTxResponse).tx); - } - - public async txs(query: string): Promise { + public async txsQuery(query: string): Promise { const responseData = await this.get(`/txs?${query}`); if (!(responseData as any).txs) { throw new Error("Unexpected response data format"); @@ -301,6 +292,15 @@ export class RestClient { return responseData as TxsResponse; } + /** returns the amino-encoding of the transaction performed by the server */ + public async encodeTx(tx: CosmosSdkTx): Promise { + const responseData = await this.post("/txs/encode", tx); + if (!(responseData as any).tx) { + throw new Error("Unexpected response data format"); + } + return Encoding.fromBase64((responseData as EncodeTxResponse).tx); + } + /** * Broadcasts a signed transaction to into the transaction pool. * Depending on the RestClient's broadcast mode, this might or might diff --git a/packages/sdk/types/restclient.d.ts b/packages/sdk/types/restclient.d.ts index 5823fef1..e5f96309 100644 --- a/packages/sdk/types/restclient.d.ts +++ b/packages/sdk/types/restclient.d.ts @@ -128,10 +128,10 @@ export declare class RestClient { blocksLatest(): Promise; blocks(height: number): Promise; nodeInfo(): Promise; + txsQuery(query: string): Promise; + txsById(id: string): Promise; /** returns the amino-encoding of the transaction performed by the server */ encodeTx(tx: CosmosSdkTx): Promise; - txs(query: string): Promise; - txsById(id: string): Promise; /** * Broadcasts a signed transaction to into the transaction pool. * Depending on the RestClient's broadcast mode, this might or might