From 961b46d36ef81eb5590b20fce5dd0de20a2a8a66 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Tue, 25 May 2021 12:20:51 +0200 Subject: [PATCH] Added the support for block_search RPC endpoint --- .../src/tendermint34/adaptor.ts | 2 + .../tendermint34/adaptors/v0-34/requests.ts | 19 +++++++++ .../tendermint34/adaptors/v0-34/responses.ts | 16 ++++++++ .../src/tendermint34/requests.ts | 17 ++++++++ .../src/tendermint34/responses.ts | 5 +++ .../src/tendermint34/tendermint34client.ts | 41 +++++++++++++++++++ 6 files changed, 100 insertions(+) diff --git a/packages/tendermint-rpc/src/tendermint34/adaptor.ts b/packages/tendermint-rpc/src/tendermint34/adaptor.ts index 7248942d..44c06917 100644 --- a/packages/tendermint-rpc/src/tendermint34/adaptor.ts +++ b/packages/tendermint-rpc/src/tendermint34/adaptor.ts @@ -23,6 +23,7 @@ export interface Params { readonly encodeBlock: (req: requests.BlockRequest) => JsonRpcRequest; readonly encodeBlockchain: (req: requests.BlockchainRequest) => JsonRpcRequest; readonly encodeBlockResults: (req: requests.BlockResultsRequest) => JsonRpcRequest; + readonly encodeBlockSearch: (req: requests.BlockSearchRequest) => JsonRpcRequest; readonly encodeBroadcastTx: (req: requests.BroadcastTxRequest) => JsonRpcRequest; readonly encodeCommit: (req: requests.CommitRequest) => JsonRpcRequest; readonly encodeGenesis: (req: requests.GenesisRequest) => JsonRpcRequest; @@ -39,6 +40,7 @@ export interface Responses { readonly decodeAbciQuery: (response: JsonRpcSuccessResponse) => responses.AbciQueryResponse; readonly decodeBlock: (response: JsonRpcSuccessResponse) => responses.BlockResponse; readonly decodeBlockResults: (response: JsonRpcSuccessResponse) => responses.BlockResultsResponse; + readonly decodeBlockSearch: (response: JsonRpcSuccessResponse) => responses.BlockSearchResponse; readonly decodeBlockchain: (response: JsonRpcSuccessResponse) => responses.BlockchainResponse; readonly decodeBroadcastTxSync: (response: JsonRpcSuccessResponse) => responses.BroadcastTxSyncResponse; readonly decodeBroadcastTxAsync: (response: JsonRpcSuccessResponse) => responses.BroadcastTxAsyncResponse; diff --git a/packages/tendermint-rpc/src/tendermint34/adaptors/v0-34/requests.ts b/packages/tendermint-rpc/src/tendermint34/adaptors/v0-34/requests.ts index 54436f7a..1dc11c4c 100644 --- a/packages/tendermint-rpc/src/tendermint34/adaptors/v0-34/requests.ts +++ b/packages/tendermint-rpc/src/tendermint34/adaptors/v0-34/requests.ts @@ -30,6 +30,21 @@ function encodeBlockchainRequestParams(param: requests.BlockchainRequestParams): }; } +interface RpcBlockSearchParams { + readonly query: string; + readonly page?: string; + readonly per_page?: string; + readonly order_by?: string; +} +function encodeBlockSearchParams(params: requests.BlockSearchParams): RpcBlockSearchParams { + return { + query: params.query, + page: may(Integer.encode, params.page), + per_page: may(Integer.encode, params.per_page), + order_by: params.order_by, + }; +} + interface RpcAbciQueryParams { readonly path: string; /** hex encoded */ @@ -118,6 +133,10 @@ export class Params { return createJsonRpcRequest(req.method, encodeHeightParam(req.params)); } + public static encodeBlockSearch(req: requests.BlockSearchRequest): JsonRpcRequest { + return createJsonRpcRequest(req.method, encodeBlockSearchParams(req.params)); + } + public static encodeBroadcastTx(req: requests.BroadcastTxRequest): JsonRpcRequest { return createJsonRpcRequest(req.method, encodeBroadcastTxParams(req.params)); } diff --git a/packages/tendermint-rpc/src/tendermint34/adaptors/v0-34/responses.ts b/packages/tendermint-rpc/src/tendermint34/adaptors/v0-34/responses.ts index 5386c7e1..7f5ffa0e 100644 --- a/packages/tendermint-rpc/src/tendermint34/adaptors/v0-34/responses.ts +++ b/packages/tendermint-rpc/src/tendermint34/adaptors/v0-34/responses.ts @@ -783,6 +783,18 @@ function decodeBlockResponse(data: RpcBlockResponse): responses.BlockResponse { }; } +interface RpcBlockSearchResponse { + readonly blocks: readonly RpcBlockResponse[]; + readonly total_count: string; +} + +function decodeBlockSearch(data: RpcBlockSearchResponse): responses.BlockSearchResponse { + return { + totalCount: Integer.parse(assertNotEmpty(data.total_count)), + blocks: assertArray(data.blocks).map(decodeBlockResponse), + }; +} + export class Responses { public static decodeAbciInfo(response: JsonRpcSuccessResponse): responses.AbciInfoResponse { return decodeAbciInfo(assertObject((response.result as AbciInfoResult).response)); @@ -800,6 +812,10 @@ export class Responses { return decodeBlockResults(response.result as RpcBlockResultsResponse); } + public static decodeBlockSearch(response: JsonRpcSuccessResponse): responses.BlockSearchResponse { + return decodeBlockSearch(response.result as RpcBlockSearchResponse); + } + public static decodeBlockchain(response: JsonRpcSuccessResponse): responses.BlockchainResponse { return decodeBlockchain(response.result as RpcBlockchainResponse); } diff --git a/packages/tendermint-rpc/src/tendermint34/requests.ts b/packages/tendermint-rpc/src/tendermint34/requests.ts index d985b8e6..75690766 100644 --- a/packages/tendermint-rpc/src/tendermint34/requests.ts +++ b/packages/tendermint-rpc/src/tendermint34/requests.ts @@ -12,6 +12,7 @@ export enum Method { /** Get block headers for minHeight <= height <= maxHeight. */ Blockchain = "blockchain", BlockResults = "block_results", + BlockSearch = "block_search", BroadcastTxAsync = "broadcast_tx_async", BroadcastTxSync = "broadcast_tx_sync", BroadcastTxCommit = "broadcast_tx_commit", @@ -30,6 +31,7 @@ export type Request = | AbciInfoRequest | AbciQueryRequest | BlockRequest + | BlockSearchRequest | BlockchainRequest | BlockResultsRequest | BroadcastTxRequest @@ -60,6 +62,7 @@ export interface AbciQueryRequest { readonly method: Method.AbciQuery; readonly params: AbciQueryParams; } + export interface AbciQueryParams { readonly path: string; readonly data: Uint8Array; @@ -97,10 +100,23 @@ export interface BlockResultsRequest { }; } +export interface BlockSearchRequest { + readonly method: Method.BlockSearch; + readonly params: BlockSearchParams; +} + +export interface BlockSearchParams { + readonly query: string; + readonly page?: number; + readonly per_page?: number; + readonly order_by?: string; +} + export interface BroadcastTxRequest { readonly method: Method.BroadcastTxAsync | Method.BroadcastTxSync | Method.BroadcastTxCommit; readonly params: BroadcastTxParams; } + export interface BroadcastTxParams { readonly tx: Uint8Array; } @@ -141,6 +157,7 @@ export interface TxRequest { readonly method: Method.Tx; readonly params: TxParams; } + export interface TxParams { readonly hash: Uint8Array; readonly prove?: boolean; diff --git a/packages/tendermint-rpc/src/tendermint34/responses.ts b/packages/tendermint-rpc/src/tendermint34/responses.ts index ba7d3970..b71c4826 100644 --- a/packages/tendermint-rpc/src/tendermint34/responses.ts +++ b/packages/tendermint-rpc/src/tendermint34/responses.ts @@ -60,6 +60,11 @@ export interface BlockResultsResponse { readonly endBlockEvents: readonly Event[]; } +export interface BlockSearchResponse { + readonly blocks: readonly BlockResponse[]; + readonly totalCount: number; +} + export interface BlockchainResponse { readonly lastHeight: number; readonly blockMetas: readonly BlockMeta[]; diff --git a/packages/tendermint-rpc/src/tendermint34/tendermint34client.ts b/packages/tendermint-rpc/src/tendermint34/tendermint34client.ts index 42d20c4a..3b5335e7 100644 --- a/packages/tendermint-rpc/src/tendermint34/tendermint34client.ts +++ b/packages/tendermint-rpc/src/tendermint34/tendermint34client.ts @@ -98,6 +98,47 @@ export class Tendermint34Client { return this.doCall(query, this.p.encodeBlockResults, this.r.decodeBlockResults); } + /** + * Search for events that are in a block + * + * @see https://docs.tendermint.com/master/rpc/#/Info/block_search + */ + public async blockSearch(params: requests.BlockSearchParams): Promise { + const query: requests.BlockSearchRequest = { params: params, method: requests.Method.BlockSearch }; + const resp = await this.doCall(query, this.p.encodeBlockSearch, this.r.decodeBlockSearch); + return { + ...resp, + // make sure we sort by height, as tendermint may be sorting by string value of the height + blocks: [...resp.blocks].sort((a, b) => a.block.header.height - b.block.header.height), + }; + } + + // this should paginate through all blockSearch options to ensure it returns all results. + // starts with page 1 or whatever was provided (eg. to start on page 7) + public async blockSearchAll(params: requests.BlockSearchParams): Promise { + let page = params.page || 1; + const blocks: responses.BlockResponse[] = []; + let done = false; + + while (!done) { + const resp = await this.blockSearch({ ...params, page: page }); + blocks.push(...resp.blocks); + if (blocks.length < resp.totalCount) { + page++; + } else { + done = true; + } + } + // make sure we sort by height, as tendermint may be sorting by string value of the height + // and the earlier items may be in a higher page than the later items + blocks.sort((a, b) => a.block.header.height - b.block.header.height); + + return { + totalCount: blocks.length, + blocks: blocks, + }; + } + /** * Queries block headers filtered by minHeight <= height <= maxHeight. *