diff --git a/CHANGELOG.md b/CHANGELOG.md index e9d3a9145d..890154ba71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -81,6 +81,9 @@ - @cosmjs/tendermint-rpc: Remove trivial helpers `getTxEventHeight`, `getHeaderEventHeight` and `getBlockEventHeight` because they don't do anything else than accessing an object member. +- @cosmjs/tendermint-rpc: Add support for connecting to Tendermint RPC 0.34. +- @cosmjs/tendermint-rpc: Make `TxEvent.index` optional and deprecate it because + it is not set anymore in Tendermint 0.34. - @cosmjs/utils: Add `assertDefined`. - @cosmjs/faucet: Rename binary from `cosmwasm-faucet` to `cosmos-faucet`. diff --git a/packages/tendermint-rpc/src/adaptorforversion.ts b/packages/tendermint-rpc/src/adaptorforversion.ts index eaecf1a81a..1fe1dde02d 100644 --- a/packages/tendermint-rpc/src/adaptorforversion.ts +++ b/packages/tendermint-rpc/src/adaptorforversion.ts @@ -11,7 +11,7 @@ import { v0_33 } from "./v0-33"; * @param version full Tendermint version string, e.g. "0.20.1" */ export function adaptorForVersion(version: string): Adaptor { - if (version.startsWith("0.33.")) { + if (version.startsWith("0.33.") || version.startsWith("0.34.")) { return v0_33; } else { throw new Error(`Unsupported tendermint version: ${version}`); diff --git a/packages/tendermint-rpc/src/client.spec.ts b/packages/tendermint-rpc/src/client.spec.ts index 13bb567df5..8c1c1a37b6 100644 --- a/packages/tendermint-rpc/src/client.spec.ts +++ b/packages/tendermint-rpc/src/client.spec.ts @@ -8,7 +8,7 @@ import { Stream } from "xstream"; import { Adaptor } from "./adaptor"; import { adaptorForVersion } from "./adaptorforversion"; import { Client } from "./client"; -import { tendermintInstances } from "./config.spec"; +import { ExpectedValues, tendermintInstances } from "./config.spec"; import { buildQuery } from "./requests"; import * as responses from "./responses"; import { HttpClient, RpcClient, WebsocketClient } from "./rpcclients"; @@ -41,7 +41,7 @@ function randomString(): string { .join(""); } -function defaultTestSuite(rpcFactory: () => RpcClient, adaptor: Adaptor): void { +function defaultTestSuite(rpcFactory: () => RpcClient, adaptor: Adaptor, expected: ExpectedValues): void { it("can connect to tendermint with known version", async () => { pendingWithoutTendermint(); const client = new Client(rpcFactory(), adaptor); @@ -133,13 +133,25 @@ function defaultTestSuite(rpcFactory: () => RpcClient, adaptor: Adaptor): void { const client = new Client(rpcFactory(), adaptor); const status = await client.status(); + + // node info + expect(status.nodeInfo.protocolVersion).toEqual({ + p2p: expected.p2pVersion, + block: expected.blockVersion, + app: expected.appVersion, + }); + expect(status.nodeInfo.network).toMatch(chainIdMatcher); expect(status.nodeInfo.other.size).toBeGreaterThanOrEqual(2); expect(status.nodeInfo.other.get("tx_index")).toEqual("on"); - expect(status.validatorInfo.pubkey).toBeTruthy(); - expect(status.validatorInfo.votingPower).toBeGreaterThan(0); + + // sync info expect(status.syncInfo.catchingUp).toEqual(false); expect(status.syncInfo.latestBlockHeight).toBeGreaterThanOrEqual(1); + // validator info + expect(status.validatorInfo.pubkey).toBeTruthy(); + expect(status.validatorInfo.votingPower).toBeGreaterThan(0); + client.disconnect(); }); }); @@ -238,8 +250,8 @@ function defaultTestSuite(rpcFactory: () => RpcClient, adaptor: Adaptor): void { // num_txs: jasmine.stringMatching(nonNegativeIntegerMatcher), header: jasmine.objectContaining({ version: { - block: 10, - app: 1, + block: expected.blockVersion, + app: expected.appVersion, }, chainId: jasmine.stringMatching(chainIdMatcher), }), @@ -371,7 +383,7 @@ function defaultTestSuite(rpcFactory: () => RpcClient, adaptor: Adaptor): void { }); } -function websocketTestSuite(rpcFactory: () => RpcClient, adaptor: Adaptor, appCreator: string): void { +function websocketTestSuite(rpcFactory: () => RpcClient, adaptor: Adaptor, expected: ExpectedValues): void { it("can subscribe to block header events", (done) => { pendingWithoutTendermint(); @@ -498,7 +510,6 @@ function websocketTestSuite(rpcFactory: () => RpcClient, adaptor: Adaptor, appCr const subscription = stream.subscribe({ next: (event) => { expect(event.height).toBeGreaterThan(0); - expect(event.index).toEqual(0); expect(event.result).toBeTruthy(); expect(event.result.events.length).toBeGreaterThanOrEqual(1); @@ -539,13 +550,12 @@ function websocketTestSuite(rpcFactory: () => RpcClient, adaptor: Adaptor, appCr const events: responses.TxEvent[] = []; const client = new Client(rpcFactory(), adaptor); - const query = buildQuery({ tags: [{ key: "app.creator", value: appCreator }] }); + const query = buildQuery({ tags: [{ key: "app.creator", value: expected.appCreator }] }); const stream = client.subscribeTx(query); expect(stream).toBeTruthy(); const subscription = stream.subscribe({ next: (event) => { expect(event.height).toBeGreaterThan(0); - expect(event.index).toEqual(0); expect(event.result).toBeTruthy(); expect(event.result.events.length).toBeGreaterThanOrEqual(1); events.push(event); @@ -622,7 +632,7 @@ function websocketTestSuite(rpcFactory: () => RpcClient, adaptor: Adaptor, appCr }); } -for (const { url, version, appCreator } of tendermintInstances) { +for (const { url, version, expected } of tendermintInstances) { describe(`Client ${version}`, () => { it("can connect to a given url", async () => { pendingWithoutTendermint(); @@ -654,7 +664,7 @@ for (const { url, version, appCreator } of tendermintInstances) { describe("With HttpClient", () => { const adaptor = adaptorForVersion(version); - defaultTestSuite(() => new HttpClient(url), adaptor); + defaultTestSuite(() => new HttpClient(url), adaptor, expected); }); describe("With WebsocketClient", () => { @@ -662,8 +672,8 @@ for (const { url, version, appCreator } of tendermintInstances) { const onError = process.env.TENDERMINT_ENABLED ? console.error : () => 0; const factory = (): WebsocketClient => new WebsocketClient(url, onError); const adaptor = adaptorForVersion(version); - defaultTestSuite(factory, adaptor); - websocketTestSuite(factory, adaptor, appCreator); + defaultTestSuite(factory, adaptor, expected); + websocketTestSuite(factory, adaptor, expected); }); }); } diff --git a/packages/tendermint-rpc/src/config.spec.ts b/packages/tendermint-rpc/src/config.spec.ts index ba8c4bbf3e..2810d856ba 100644 --- a/packages/tendermint-rpc/src/config.spec.ts +++ b/packages/tendermint-rpc/src/config.spec.ts @@ -1,7 +1,17 @@ +export interface ExpectedValues { + readonly appCreator: string; + readonly p2pVersion: number; + readonly blockVersion: number; + readonly appVersion: number; +} + export interface TendermintInstance { readonly url: string; readonly version: string; - readonly appCreator: string; + /** rough block time in ms */ + readonly blockTime: number; + /** Values we expect in the backend */ + readonly expected: ExpectedValues; } /** @@ -20,7 +30,24 @@ export const tendermintInstances: readonly TendermintInstance[] = [ { url: "localhost:11133", version: "0.33.x", - appCreator: "Cosmoshi Netowoko", + blockTime: 1000, + expected: { + appCreator: "Cosmoshi Netowoko", + p2pVersion: 7, + blockVersion: 10, + appVersion: 1, + }, + }, + { + url: "localhost:11134", + version: "0.34.x", + blockTime: 500, + expected: { + appCreator: "Cosmoshi Netowoko", + p2pVersion: 8, + blockVersion: 11, + appVersion: 1, + }, }, ]; diff --git a/packages/tendermint-rpc/src/responses.ts b/packages/tendermint-rpc/src/responses.ts index 92fadb4a78..c3f78a8f82 100644 --- a/packages/tendermint-rpc/src/responses.ts +++ b/packages/tendermint-rpc/src/responses.ts @@ -153,7 +153,8 @@ export interface TxEvent { readonly tx: TxBytes; readonly hash: TxHash; readonly height: number; - readonly index: number; + /** @deprecated this value is not set in Tendermint 0.34+ */ + readonly index?: number; readonly result: TxData; } diff --git a/packages/tendermint-rpc/src/rpcclients/websocketclient.spec.ts b/packages/tendermint-rpc/src/rpcclients/websocketclient.spec.ts index 0f15cb7904..2b3f366ab5 100644 --- a/packages/tendermint-rpc/src/rpcclients/websocketclient.spec.ts +++ b/packages/tendermint-rpc/src/rpcclients/websocketclient.spec.ts @@ -15,7 +15,7 @@ function pendingWithoutTendermint(): void { } describe("WebsocketClient", () => { - const tendermintUrl = defaultInstance.url; + const { blockTime, url: tendermintUrl } = defaultInstance; it("can make a simple call", async () => { pendingWithoutTendermint(); @@ -48,27 +48,27 @@ describe("WebsocketClient", () => { const events: SubscriptionEvent[] = []; - const sub = headers.subscribe({ + const subscription = headers.subscribe({ error: done.fail, complete: () => done.fail("subscription should not complete"), - next: (evt: SubscriptionEvent) => { - events.push(evt); - expect(evt.query).toEqual(query); + next: (event: SubscriptionEvent) => { + events.push(event); + expect(event.query).toEqual(query); if (events.length === 2) { // make sure they are consequtive heights const height = (i: number): number => Integer.parse(events[i].data.value.header.height); expect(height(1)).toEqual(height(0) + 1); - sub.unsubscribe(); + subscription.unsubscribe(); - // wait 1.5s and check we did not get more events + // wait 1.5 * blockTime and check we did not get more events setTimeout(() => { expect(events.length).toEqual(2); client.disconnect(); done(); - }, 1500); + }, 1.5 * blockTime); } }, }); @@ -110,23 +110,23 @@ describe("WebsocketClient", () => { const events: SubscriptionEvent[] = []; - const sub = headers.subscribe({ + const subscription = headers.subscribe({ error: done.fail, complete: () => done.fail("subscription should not complete"), - next: (evt: SubscriptionEvent) => { - events.push(evt); - expect(evt.query).toEqual(query); + next: (event: SubscriptionEvent) => { + events.push(event); + expect(event.query).toEqual(query); if (events.length === 2) { - sub.unsubscribe(); + subscription.unsubscribe(); - // wait 1.5s and check we did not get more events + // wait 1.5 * blockTime and check we did not get more events setTimeout(() => { expect(events.length).toEqual(2); client.disconnect(); done(); - }, 1500); + }, 1.5 * blockTime); } }, }); @@ -148,7 +148,7 @@ describe("WebsocketClient", () => { const receivedEvents: SubscriptionEvent[] = []; - setTimeout(() => client.disconnect(), 1500); + setTimeout(() => client.disconnect(), blockTime); headers.subscribe({ error: done.fail, diff --git a/packages/tendermint-rpc/src/v0-33/responses.ts b/packages/tendermint-rpc/src/v0-33/responses.ts index 3b17a02e99..b21960a89b 100644 --- a/packages/tendermint-rpc/src/v0-33/responses.ts +++ b/packages/tendermint-rpc/src/v0-33/responses.ts @@ -619,7 +619,8 @@ interface RpcTxEvent { readonly tx: Base64String; readonly result: RpcTxData; readonly height: IntegerString; - readonly index: number; + /** Not set since Tendermint 0.34 */ + readonly index?: number; } function decodeTxEvent(data: RpcTxEvent): responses.TxEvent { @@ -629,7 +630,7 @@ function decodeTxEvent(data: RpcTxEvent): responses.TxEvent { hash: hashTx(tx), result: decodeTxData(data.result), height: Integer.parse(assertNotEmpty(data.height)), - index: Integer.parse(assertNumber(data.index)), + index: may(Integer.parse, data.index), }; } diff --git a/packages/tendermint-rpc/types/responses.d.ts b/packages/tendermint-rpc/types/responses.d.ts index b73f6ebc37..09221e606d 100644 --- a/packages/tendermint-rpc/types/responses.d.ts +++ b/packages/tendermint-rpc/types/responses.d.ts @@ -120,7 +120,8 @@ export interface TxEvent { readonly tx: TxBytes; readonly hash: TxHash; readonly height: number; - readonly index: number; + /** @deprecated this value is not set in Tendermint 0.34+ */ + readonly index?: number; readonly result: TxData; } /** An event attribute */ diff --git a/scripts/tendermint/all_start.sh b/scripts/tendermint/all_start.sh index cfb3e4072d..05edb2c206 100755 --- a/scripts/tendermint/all_start.sh +++ b/scripts/tendermint/all_start.sh @@ -4,7 +4,8 @@ command -v shellcheck > /dev/null && shellcheck "$0" # Find latest patch releases at https://hub.docker.com/r/tendermint/tendermint/tags/ declare -a TM_VERSIONS -TM_VERSIONS[33]=v0.33.5 +TM_VERSIONS[33]=v0.33.8 +TM_VERSIONS[34]=latest SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" diff --git a/scripts/tendermint/all_stop.sh b/scripts/tendermint/all_stop.sh index c6e735f4df..4f044db815 100755 --- a/scripts/tendermint/all_stop.sh +++ b/scripts/tendermint/all_stop.sh @@ -3,7 +3,8 @@ set -o errexit -o nounset -o pipefail command -v shellcheck > /dev/null && shellcheck "$0" declare -a TM_VERSIONS -TM_VERSIONS[33]=v0.33.5 +TM_VERSIONS[33]=v0.33.8 +TM_VERSIONS[34]=latest SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" diff --git a/scripts/tendermint/start.sh b/scripts/tendermint/start.sh index a1952697cb..c863f92a12 100755 --- a/scripts/tendermint/start.sh +++ b/scripts/tendermint/start.sh @@ -46,6 +46,7 @@ if [ -n "${CI:-}" ]; then # Give process some time to come alive. No idea why this helps. Needed for CI. sleep 0.5 - # Follow the logs in CI's background job - tail -f "$LOGFILE" + # Debug start + sleep 3 + cat "$LOGFILE" fi