From 9955ec0dbece6105286fed4661bce64672c7cb51 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 17 Aug 2020 13:44:16 +0200 Subject: [PATCH] Add better docs and test for Client.blockchain --- packages/tendermint-rpc/src/client.spec.ts | 80 ++++++++++++++++++- packages/tendermint-rpc/src/client.ts | 3 + packages/tendermint-rpc/src/requests.ts | 2 + packages/tendermint-rpc/src/responses.ts | 2 + packages/tendermint-rpc/src/testutil.spec.ts | 1 + packages/tendermint-rpc/src/v0-33/requests.ts | 1 + packages/tendermint-rpc/types/client.d.ts | 3 + packages/tendermint-rpc/types/requests.d.ts | 1 + 8 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 packages/tendermint-rpc/src/testutil.spec.ts diff --git a/packages/tendermint-rpc/src/client.spec.ts b/packages/tendermint-rpc/src/client.spec.ts index da9eff42..8aa7d510 100644 --- a/packages/tendermint-rpc/src/client.spec.ts +++ b/packages/tendermint-rpc/src/client.spec.ts @@ -12,6 +12,7 @@ import { tendermintInstances } from "./config.spec"; import { buildQuery } from "./requests"; import * as responses from "./responses"; import { HttpClient, RpcClient, WebsocketClient } from "./rpcclients"; +import { chainIdMatcher } from "./testutil.spec"; import { TxBytes } from "./types"; function tendermintEnabled(): boolean { @@ -145,6 +146,81 @@ function defaultTestSuite(rpcFactory: () => RpcClient, adaptor: Adaptor): void { }); }); + describe("blockchain", () => { + it("returns latest in descending order by default", async () => { + pendingWithoutTendermint(); + const client = new Client(rpcFactory(), adaptor); + + // Run in parallel to increase chance there is no block between the calls + const [status, blockchain] = await Promise.all([client.status(), client.blockchain()]); + const height = status.syncInfo.latestBlockHeight; + + expect(blockchain.lastHeight).toEqual(height); + expect(blockchain.blockMetas.length).toBeGreaterThanOrEqual(3); + expect(blockchain.blockMetas[0].header.height).toEqual(height); + expect(blockchain.blockMetas[1].header.height).toEqual(height - 1); + expect(blockchain.blockMetas[2].header.height).toEqual(height - 2); + + client.disconnect(); + }); + + it("can limit by maxHeight", async () => { + pendingWithoutTendermint(); + const client = new Client(rpcFactory(), adaptor); + + const height = (await client.status()).syncInfo.latestBlockHeight; + const blockchain = await client.blockchain(undefined, height - 1); + expect(blockchain.lastHeight).toEqual(height); + expect(blockchain.blockMetas.length).toBeGreaterThanOrEqual(2); + expect(blockchain.blockMetas[0].header.height).toEqual(height - 1); // upper limit included + expect(blockchain.blockMetas[1].header.height).toEqual(height - 2); + + client.disconnect(); + }); + + it("can limit by minHeight and maxHeight", async () => { + pendingWithoutTendermint(); + const client = new Client(rpcFactory(), adaptor); + + const height = (await client.status()).syncInfo.latestBlockHeight; + const blockchain = await client.blockchain(height - 2, height - 1); + expect(blockchain.lastHeight).toEqual(height); + expect(blockchain.blockMetas.length).toEqual(2); + expect(blockchain.blockMetas[0].header.height).toEqual(height - 1); // upper limit included + expect(blockchain.blockMetas[1].header.height).toEqual(height - 2); // lower limit included + + client.disconnect(); + }); + + it("contains all the info", async () => { + pendingWithoutTendermint(); + const client = new Client(rpcFactory(), adaptor); + + const height = (await client.status()).syncInfo.latestBlockHeight; + const blockchain = await client.blockchain(height - 1, height - 1); + + expect(blockchain.lastHeight).toEqual(height); + expect(blockchain.blockMetas.length).toBeGreaterThanOrEqual(1); + const meta = blockchain.blockMetas[0]; + + // TODO: check all the fields + expect(meta).toEqual({ + blockId: jasmine.objectContaining({}), + // block_size: jasmine.stringMatching(nonNegativeIntegerMatcher), + // num_txs: jasmine.stringMatching(nonNegativeIntegerMatcher), + header: jasmine.objectContaining({ + version: { + block: 10, + app: 1, + }, + chainId: jasmine.stringMatching(chainIdMatcher), + }), + }); + + client.disconnect(); + }); + }); + describe("tx", () => { it("can query a tx properly", async () => { pendingWithoutTendermint(); @@ -280,7 +356,7 @@ function websocketTestSuite(rpcFactory: () => RpcClient, adaptor: Adaptor, appCr expect(stream).toBeTruthy(); const subscription = stream.subscribe({ next: (event) => { - expect(event.chainId).toMatch(/^[-a-zA-Z0-9]{3,30}$/); + expect(event.chainId).toMatch(chainIdMatcher); expect(event.height).toBeGreaterThan(0); // seems that tendermint just guarantees within the last second for timestamp expect(event.time.getTime()).toBeGreaterThan(testStart - 1000); @@ -337,7 +413,7 @@ function websocketTestSuite(rpcFactory: () => RpcClient, adaptor: Adaptor, appCr const stream = client.subscribeNewBlock(); const subscription = stream.subscribe({ next: (event) => { - expect(event.header.chainId).toMatch(/^[-a-zA-Z0-9]{3,30}$/); + expect(event.header.chainId).toMatch(chainIdMatcher); expect(event.header.height).toBeGreaterThan(0); // seems that tendermint just guarantees within the last second for timestamp expect(event.header.time.getTime()).toBeGreaterThan(testStart - 1000); diff --git a/packages/tendermint-rpc/src/client.ts b/packages/tendermint-rpc/src/client.ts index 23fd42ec..9bda89ea 100644 --- a/packages/tendermint-rpc/src/client.ts +++ b/packages/tendermint-rpc/src/client.ts @@ -74,6 +74,9 @@ export class Client { return this.doCall(query, this.p.encodeBlockResults, this.r.decodeBlockResults); } + /** + * Get block headers for minHeight <= height <= maxHeight. + */ public async blockchain(minHeight?: number, maxHeight?: number): Promise { const query: requests.BlockchainRequest = { method: requests.Method.Blockchain, diff --git a/packages/tendermint-rpc/src/requests.ts b/packages/tendermint-rpc/src/requests.ts index 21ba5648..bb6b1b83 100644 --- a/packages/tendermint-rpc/src/requests.ts +++ b/packages/tendermint-rpc/src/requests.ts @@ -10,6 +10,7 @@ export enum Method { AbciInfo = "abci_info", AbciQuery = "abci_query", Block = "block", + /** Get block headers for minHeight <= height <= maxHeight. */ Blockchain = "blockchain", BlockResults = "block_results", BroadcastTxAsync = "broadcast_tx_async", @@ -84,6 +85,7 @@ export interface BlockchainRequest { readonly method: Method.Blockchain; readonly params: BlockchainRequestParams; } + export interface BlockchainRequestParams { readonly minHeight?: number; readonly maxHeight?: number; diff --git a/packages/tendermint-rpc/src/responses.ts b/packages/tendermint-rpc/src/responses.ts index 1eb25b6f..bfbde872 100644 --- a/packages/tendermint-rpc/src/responses.ts +++ b/packages/tendermint-rpc/src/responses.ts @@ -186,6 +186,8 @@ export interface TxProof { export interface BlockMeta { readonly blockId: BlockId; readonly header: Header; + // TODO: Add blockSize (e.g "block_size": "471") + // TODO: Add numTxs (e.g "num_txs": "0") } export interface BlockId { diff --git a/packages/tendermint-rpc/src/testutil.spec.ts b/packages/tendermint-rpc/src/testutil.spec.ts new file mode 100644 index 00000000..de7ecb19 --- /dev/null +++ b/packages/tendermint-rpc/src/testutil.spec.ts @@ -0,0 +1 @@ +export const chainIdMatcher = /^[-a-zA-Z0-9]{3,30}$/; diff --git a/packages/tendermint-rpc/src/v0-33/requests.ts b/packages/tendermint-rpc/src/v0-33/requests.ts index f3c1dc7a..0e6b71c3 100644 --- a/packages/tendermint-rpc/src/v0-33/requests.ts +++ b/packages/tendermint-rpc/src/v0-33/requests.ts @@ -22,6 +22,7 @@ interface RpcBlockchainRequestParams { readonly minHeight?: IntegerString; readonly maxHeight?: IntegerString; } + function encodeBlockchainRequestParams(param: requests.BlockchainRequestParams): RpcBlockchainRequestParams { return { minHeight: may(Integer.encode, param.minHeight), diff --git a/packages/tendermint-rpc/types/client.d.ts b/packages/tendermint-rpc/types/client.d.ts index 550db050..5844ad64 100644 --- a/packages/tendermint-rpc/types/client.d.ts +++ b/packages/tendermint-rpc/types/client.d.ts @@ -15,6 +15,9 @@ export declare class Client { abciQuery(params: requests.AbciQueryParams): Promise; block(height?: number): Promise; blockResults(height?: number): Promise; + /** + * Get block headers for minHeight <= height <= maxHeight. + */ blockchain(minHeight?: number, maxHeight?: number): Promise; /** * Broadcast transaction to mempool and wait for response diff --git a/packages/tendermint-rpc/types/requests.d.ts b/packages/tendermint-rpc/types/requests.d.ts index f17fa18d..c8c8f312 100644 --- a/packages/tendermint-rpc/types/requests.d.ts +++ b/packages/tendermint-rpc/types/requests.d.ts @@ -8,6 +8,7 @@ export declare enum Method { AbciInfo = "abci_info", AbciQuery = "abci_query", Block = "block", + /** Get block headers for minHeight <= height <= maxHeight. */ Blockchain = "blockchain", BlockResults = "block_results", BroadcastTxAsync = "broadcast_tx_async",