stargate: Improve StargateClient.broadcastTx

This commit is contained in:
willclarktech 2021-04-07 17:25:53 +02:00
parent fcdab9d6d5
commit 46a45f0e8f
No known key found for this signature in database
GPG Key ID: 551A86E2E398ADF7

View File

@ -1,4 +1,5 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { sha256 } from "@cosmjs/crypto";
import { toHex } from "@cosmjs/encoding";
import { Uint53 } from "@cosmjs/math";
import {
@ -6,6 +7,7 @@ import {
Tendermint34Client,
toRfc3339WithNanoseconds,
} from "@cosmjs/tendermint-rpc";
import { sleep } from "@cosmjs/utils";
import { Account, accountFromAny } from "./accounts";
import { MsgData, TxMsgData } from "./codec/cosmos/base/abci/v1beta1/abci";
@ -19,6 +21,15 @@ import {
SearchTxQuery,
} from "./search";
class TimeoutError extends Error {
public readonly txId: string;
public constructor(message: string, txId: string) {
super(message);
this.txId = txId;
}
}
/**
* This is the same as BlockHeader from @cosmjs/launchpad but those might diverge in the future.
*/
@ -268,7 +279,61 @@ export class StargateClient {
if (this.tmClient) this.tmClient.disconnect();
}
public async broadcastTx(tx: Uint8Array): Promise<BroadcastTxResponse> {
public async broadcastTx(
tx: Uint8Array,
timeoutMs = 60_000,
pollIntervalMs = 3_000,
): Promise<BroadcastTxResponse> {
const txId = toHex(sha256(tx));
let timedOut = false;
const timeoutTimeout = setTimeout(() => {
timedOut = true;
}, timeoutMs);
const handlePrematureTimeout = (): Promise<BroadcastTxResponse> => {
if (timedOut) {
throw new TimeoutError(
`Transaction with ID ${txId} was submitted but was not yet found on the chain. You might want to check later.`,
txId,
);
}
return sleep(pollIntervalMs)
.then(() => this.getTx(txId))
.then((result) =>
result
? {
code: result.code,
height: result.height,
rawLog: result.rawLog,
transactionHash: txId,
}
: handlePrematureTimeout(),
);
};
return new Promise((resolve, reject) =>
this.broadcastTxCommit(tx)
.catch((error) => {
try {
const errorJson = JSON.parse(error.message);
if (errorJson.code !== -32603) {
// irrelevant error
throw error;
}
} catch {
// invalid JSON
throw error;
}
// timed out waiting for tx to be included in a block
// now we poll to artificially extend the timeout
return handlePrematureTimeout();
})
.then(resolve, reject)
.finally(() => clearTimeout(timeoutTimeout)),
);
}
private async broadcastTxCommit(tx: Uint8Array): Promise<BroadcastTxResponse> {
const response = await this.forceGetTmClient().broadcastTxCommit({ tx });
if (broadcastTxCommitSuccess(response)) {
return {