Added the support for block_search RPC endpoint

This commit is contained in:
Riccardo Montagnin 2021-05-25 12:20:51 +02:00 committed by Simon Warta
parent 02f5439ceb
commit 961b46d36e
6 changed files with 100 additions and 0 deletions

View File

@ -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;

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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[];

View File

@ -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<responses.BlockSearchResponse> {
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<responses.BlockSearchResponse> {
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.
*