From 6a607d22e3742eb0b02eb829941c952f3003091d Mon Sep 17 00:00:00 2001 From: willclarktech Date: Thu, 13 Aug 2020 12:27:49 +0200 Subject: [PATCH] stargate: Add searchTx method to client --- packages/stargate/src/stargateclient.ts | 85 +++++++++++++++++++-- packages/stargate/types/stargateclient.d.ts | 14 +++- 2 files changed, 90 insertions(+), 9 deletions(-) diff --git a/packages/stargate/src/stargateclient.ts b/packages/stargate/src/stargateclient.ts index cda62e28..85280403 100644 --- a/packages/stargate/src/stargateclient.ts +++ b/packages/stargate/src/stargateclient.ts @@ -1,14 +1,35 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { Bech32, toAscii, toHex } from "@cosmjs/encoding"; -import { Block, Coin, decodeAminoPubkey, PubKey } from "@cosmjs/launchpad"; +import { + Block, + Coin, + decodeAminoPubkey, + isSearchByHeightQuery, + isSearchByIdQuery, + PubKey, + SearchTxFilter, + SearchTxQuery, +} from "@cosmjs/launchpad"; import { Uint53, Uint64 } from "@cosmjs/math"; import { decodeAny } from "@cosmjs/proto-signing"; import { broadcastTxCommitSuccess, Client as TendermintClient } from "@cosmjs/tendermint-rpc"; +import { QueryString } from "@cosmjs/tendermint-rpc/types/requests"; import { arrayContentEquals, assert, assertDefined } from "@cosmjs/utils"; import Long from "long"; import { cosmos } from "./generated/codecimpl"; +/** A transaction that is indexed as part of the transaction history */ +export interface IndexedTx { + readonly height: number; + /** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */ + readonly hash: string; + /** Transaction execution error code. 0 on success. */ + readonly code: number; + readonly rawLog: string; + readonly tx: Uint8Array; +} + export interface Account { /** Bech32 account address */ readonly address: string; @@ -206,25 +227,57 @@ export class StargateClient { return response.balances.map(coinFromProto); } + 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 + + let txs: readonly IndexedTx[]; + + if (isSearchByIdQuery(query)) { + txs = await this.txsQuery(`tx.hash='${query.id}'`); + } else if (isSearchByHeightQuery(query)) { + txs = + query.height >= minHeight && query.height <= maxHeight + ? await this.txsQuery(`tx.height=${query.height}`) + : []; + } else { + throw new Error("Unknown query type"); + } + + const filtered = txs.filter((tx) => tx.height >= minHeight && tx.height <= maxHeight); + return filtered; + } + public disconnect(): void { this.tmClient.disconnect(); } public async broadcastTx(tx: Uint8Array): Promise { const response = await this.tmClient.broadcastTxCommit({ tx }); - return broadcastTxCommitSuccess(response) + if (broadcastTxCommitSuccess(response)) { + return { + height: response.height, + transactionHash: toHex(response.hash).toUpperCase(), + rawLog: response.deliverTx?.log, + data: response.deliverTx?.data, + }; + } + return response.checkTx.code !== 0 ? { - height: response.height, - transactionHash: toHex(response.hash).toUpperCase(), - rawLog: response.deliverTx?.log, - data: response.deliverTx?.data, - } - : { height: response.height, code: response.checkTx.code, transactionHash: toHex(response.hash).toUpperCase(), rawLog: response.checkTx.log, data: response.checkTx.data, + } + : { + height: response.height, + code: response.deliverTx?.code, + transactionHash: toHex(response.hash).toUpperCase(), + rawLog: response.deliverTx?.log, + data: response.deliverTx?.data, }; } @@ -264,4 +317,20 @@ export class StargateClient { return response.value; } + + private async txsQuery(query: string): Promise { + const params = { + query: query as QueryString, + }; + const results = await this.tmClient.txSearchAll(params); + return results.txs.map((tx) => { + return { + height: tx.height, + hash: toHex(tx.hash).toUpperCase(), + code: tx.result.code, + rawLog: tx.result.log || "", + tx: tx.tx, + }; + }); + } } diff --git a/packages/stargate/types/stargateclient.d.ts b/packages/stargate/types/stargateclient.d.ts index e3c01a43..d641352f 100644 --- a/packages/stargate/types/stargateclient.d.ts +++ b/packages/stargate/types/stargateclient.d.ts @@ -1,5 +1,15 @@ -import { Block, Coin, PubKey } from "@cosmjs/launchpad"; +import { Block, Coin, PubKey, SearchTxFilter, SearchTxQuery } from "@cosmjs/launchpad"; import { Client as TendermintClient } from "@cosmjs/tendermint-rpc"; +/** A transaction that is indexed as part of the transaction history */ +export interface IndexedTx { + readonly height: number; + /** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */ + readonly hash: string; + /** Transaction execution error code. 0 on success. */ + readonly code: number; + readonly rawLog: string; + readonly tx: Uint8Array; +} export interface Account { /** Bech32 account address */ readonly address: string; @@ -55,8 +65,10 @@ export declare class StargateClient { * proofs from such a method. */ getAllBalancesUnverified(address: string): Promise; + searchTx(query: SearchTxQuery, filter?: SearchTxFilter): Promise; disconnect(): void; broadcastTx(tx: Uint8Array): Promise; private queryVerified; private queryUnverified; + private txsQuery; }