Reorganise error handling in sdk38

This commit is contained in:
willclarktech 2020-06-09 16:46:10 +01:00
parent 16eb718b45
commit 34d19e4d7e
No known key found for this signature in database
GPG Key ID: 551A86E2E398ADF7
6 changed files with 61 additions and 37 deletions

View File

@ -3,7 +3,7 @@ import { Uint53 } from "@cosmjs/math";
import { assert, sleep } from "@cosmjs/utils";
import { Coin } from "./coins";
import { CosmosClient } from "./cosmosclient";
import { CosmosClient, isPostTxFailureResult } from "./cosmosclient";
import { makeSignBytes } from "./encoding";
import { Secp256k1Pen } from "./pen";
import { RestClient } from "./restclient";
@ -105,19 +105,13 @@ describe("CosmosClient.searchTx", () => {
},
};
const transactionId = await client.getIdentifier(tx);
try {
await client.postTx(tx.value);
} catch (error) {
// postTx() throws on execution failures, which is a questionable design. Ignore for now.
// console.log(error);
const errorMessage: string = error.toString();
const [_, heightMatch] = errorMessage.match(/at height ([0-9]+)/) || ["", ""];
const result = await client.postTx(tx.value);
if (isPostTxFailureResult(result)) {
sendUnsuccessful = {
sender: faucet.address,
recipient: recipient,
hash: transactionId,
height: Uint53.fromString(heightMatch).toNumber(),
height: Uint53.fromString(result.height).toNumber(),
tx: tx,
};
}

View File

@ -2,7 +2,7 @@
import { sleep } from "@cosmjs/utils";
import { ReadonlyDate } from "readonly-date";
import { CosmosClient, PrivateCosmWasmClient } from "./cosmosclient";
import { CosmosClient, isPostTxFailureResult, PrivateCosmWasmClient } from "./cosmosclient";
import { makeSignBytes } from "./encoding";
import { findAttribute } from "./logs";
import { Secp256k1Pen } from "./pen";
@ -230,7 +230,11 @@ describe("CosmosClient", () => {
memo: memo,
signatures: [signature],
};
const { logs, transactionHash } = await client.postTx(signedTx);
const txResult = await client.postTx(signedTx);
if (isPostTxFailureResult(txResult)) {
throw new Error("Post tx failed");
}
const { logs, transactionHash } = txResult;
const amountAttr = findAttribute(logs, "transfer", "amount");
expect(amountAttr.value).toEqual("1234567ucosm");
expect(transactionHash).toMatch(/^[0-9A-F]{64}$/);

View File

@ -1,5 +1,5 @@
import { Sha256 } from "@cosmjs/crypto";
import { fromBase64, toHex } from "@cosmjs/encoding";
import { fromBase64, fromHex, toHex } from "@cosmjs/encoding";
import { Coin } from "./coins";
import { Log, parseLogs } from "./logs";
@ -21,11 +21,26 @@ export interface Account {
readonly sequence: number;
}
export interface PostTxResult {
export interface PostTxFailureResult {
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
readonly transactionHash: string;
readonly height: string;
readonly code: number;
readonly rawLog: string;
}
export interface PostTxSuccessResult {
readonly logs: readonly Log[];
readonly rawLog: string;
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
readonly transactionHash: string;
readonly data?: Uint8Array;
}
export type PostTxResult = PostTxSuccessResult | PostTxFailureResult;
export function isPostTxFailureResult(postTxResult: PostTxResult): postTxResult is PostTxFailureResult {
return (postTxResult as PostTxFailureResult).code !== undefined;
}
export interface SearchByIdQuery {
@ -276,17 +291,19 @@ export class CosmosClient {
throw new Error("Received ill-formatted txhash. Must be non-empty upper-case hex");
}
if (result.code) {
throw new Error(
`Error when posting tx ${result.txhash} at height ${result.height}. Code: ${result.code}; Raw log: ${result.raw_log}`,
);
}
return {
logs: result.logs ? parseLogs(result.logs) : [],
rawLog: result.raw_log || "",
transactionHash: result.txhash,
};
return result.code !== undefined
? {
height: result.height,
transactionHash: result.txhash,
code: result.code,
rawLog: result.raw_log || "",
}
: {
logs: result.logs ? parseLogs(result.logs) : [],
rawLog: result.raw_log || "",
transactionHash: result.txhash,
data: result.data ? fromHex(result.data) : undefined,
};
}
private async txsQuery(query: string): Promise<readonly IndexedTx[]> {

View File

@ -4,6 +4,7 @@ import { assert, sleep } from "@cosmjs/utils";
import { ReadonlyDate } from "readonly-date";
import { rawSecp256k1PubkeyToAddress } from "./address";
import { isPostTxFailureResult } from "./cosmosclient";
import { makeSignBytes } from "./encoding";
import { parseLogs } from "./logs";
import { makeCosmoshubPath, Secp256k1Pen } from "./pen";
@ -275,11 +276,9 @@ describe("RestClient", () => {
signatures: [signature],
};
const transactionId = await client.getIdentifier({ type: "cosmos-sdk/StdTx", value: signedTx });
try {
await client.postTx(signedTx);
} catch (error) {
// postTx() throws on execution failures, which is a questionable design. Ignore for now.
// console.log(error);
const result = await client.postTx(signedTx);
if (!isPostTxFailureResult(result)) {
throw new Error("Post tx succeeded unexpectedly");
}
unsuccessful = {
sender: faucet.address,
@ -631,7 +630,6 @@ describe("RestClient", () => {
signatures: [signature1, signature2, signature3],
};
const postResult = await client.postTx(signedTx);
// console.log(postResult.raw_log);
expect(postResult.code).toEqual(4);
expect(postResult.raw_log).toContain("wrong number of signers");
});
@ -691,7 +689,6 @@ describe("RestClient", () => {
signatures: [signature1],
};
const postResult = await client.postTx(signedTx);
// console.log(postResult.raw_log);
expect(postResult.code).toBeUndefined();
});
@ -755,7 +752,6 @@ describe("RestClient", () => {
signatures: [signature2, signature1],
};
const postResult = await client.postTx(signedTx);
// console.log(postResult.raw_log);
expect(postResult.code).toBeUndefined();
await sleep(500);
@ -824,7 +820,6 @@ describe("RestClient", () => {
signatures: [signature2, signature1],
};
const postResult = await client.postTx(signedTx);
// console.log(postResult.raw_log);
expect(postResult.code).toEqual(8);
});
@ -888,7 +883,6 @@ describe("RestClient", () => {
signatures: [signature1, signature2],
};
const postResult = await client.postTx(signedTx);
// console.log(postResult.raw_log);
expect(postResult.code).toEqual(8);
});
});

View File

@ -1,7 +1,7 @@
import { assert } from "@cosmjs/utils";
import { Coin } from "./coins";
import { PrivateCosmWasmClient } from "./cosmosclient";
import { isPostTxFailureResult, PrivateCosmWasmClient } from "./cosmosclient";
import { Secp256k1Pen } from "./pen";
import { SigningCosmosClient } from "./signingcosmosclient";
import { makeRandomAddress, pendingWithoutWasmd } from "./testutils.spec";
@ -66,6 +66,9 @@ describe("SigningCosmosClient", () => {
// send
const result = await client.sendTokens(beneficiaryAddress, transferAmount, "for dinner");
if (isPostTxFailureResult(result)) {
throw new Error("Send tokens failed");
}
const [firstLog] = result.logs;
expect(firstLog).toBeTruthy();

View File

@ -14,12 +14,24 @@ export interface Account {
readonly accountNumber: number;
readonly sequence: number;
}
export interface PostTxResult {
export interface PostTxFailureResult {
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
readonly transactionHash: string;
readonly height: string;
readonly code: number;
readonly rawLog: string;
}
export interface PostTxSuccessResult {
readonly logs: readonly Log[];
readonly rawLog: string;
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
readonly transactionHash: string;
readonly data?: Uint8Array;
}
export declare type PostTxResult = PostTxSuccessResult | PostTxFailureResult;
export declare function isPostTxFailureResult(
postTxResult: PostTxResult,
): postTxResult is PostTxFailureResult;
export interface SearchByIdQuery {
readonly id: string;
}