Merge DeliverTxFailure/DeliverTxSuccess into DeliverTxResponse

This commit is contained in:
Simon Warta 2021-11-24 13:05:15 +01:00
parent 197d87fbb3
commit b56200d2e5
6 changed files with 103 additions and 29 deletions

View File

@ -12,9 +12,13 @@ and this project adheres to
([#938]).
- @cosmjs/stargate: Add `denomMetadata` and `denomsMetadata` to `BankExtension`
([#932]).
- @cosmjs/stargate: Merge `DeliverTxFailure` and `DeliverTxSuccess` into a
single `DeliverTxResponse` ([#878], [#949]). Add `assertIsDeliverTxFailure`.
[#938]: https://github.com/cosmos/cosmjs/issues/938
[#932]: https://github.com/cosmos/cosmjs/issues/932
[#878]: https://github.com/cosmos/cosmjs/issues/878
[#949]: https://github.com/cosmos/cosmjs/issues/949
### Fixed

View File

@ -18,7 +18,6 @@ import {
calculateFee,
Coin,
defaultRegistryTypes,
DeliverTxFailure,
DeliverTxResponse,
GasPrice,
isDeliverTxFailure,
@ -124,7 +123,7 @@ export interface ExecuteResult {
readonly transactionHash: string;
}
function createBroadcastTxErrorMessage(result: DeliverTxFailure): string {
function createDeliverTxResponseErrorMessage(result: DeliverTxResponse): string {
return `Error when broadcasting tx ${result.transactionHash} at height ${result.height}. Code: ${result.code}; Raw log: ${result.rawLog}`;
}
@ -238,7 +237,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
const result = await this.signAndBroadcast(senderAddress, [storeCodeMsg], fee, memo);
if (isDeliverTxFailure(result)) {
throw new Error(createBroadcastTxErrorMessage(result));
throw new Error(createDeliverTxResponseErrorMessage(result));
}
const parsedLogs = logs.parseRawLog(result.rawLog);
const codeIdAttr = logs.findAttribute(parsedLogs, "store_code", "code_id");
@ -274,7 +273,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
};
const result = await this.signAndBroadcast(senderAddress, [instantiateContractMsg], fee, options.memo);
if (isDeliverTxFailure(result)) {
throw new Error(createBroadcastTxErrorMessage(result));
throw new Error(createDeliverTxResponseErrorMessage(result));
}
const parsedLogs = logs.parseRawLog(result.rawLog);
const contractAddressAttr = logs.findAttribute(parsedLogs, "instantiate", "_contract_address");
@ -302,7 +301,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
};
const result = await this.signAndBroadcast(senderAddress, [updateAdminMsg], fee, memo);
if (isDeliverTxFailure(result)) {
throw new Error(createBroadcastTxErrorMessage(result));
throw new Error(createDeliverTxResponseErrorMessage(result));
}
return {
logs: logs.parseRawLog(result.rawLog),
@ -325,7 +324,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
};
const result = await this.signAndBroadcast(senderAddress, [clearAdminMsg], fee, memo);
if (isDeliverTxFailure(result)) {
throw new Error(createBroadcastTxErrorMessage(result));
throw new Error(createDeliverTxResponseErrorMessage(result));
}
return {
logs: logs.parseRawLog(result.rawLog),
@ -352,7 +351,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
};
const result = await this.signAndBroadcast(senderAddress, [migrateContractMsg], fee, memo);
if (isDeliverTxFailure(result)) {
throw new Error(createBroadcastTxErrorMessage(result));
throw new Error(createDeliverTxResponseErrorMessage(result));
}
return {
logs: logs.parseRawLog(result.rawLog),
@ -379,7 +378,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
};
const result = await this.signAndBroadcast(senderAddress, [executeContractMsg], fee, memo);
if (isDeliverTxFailure(result)) {
throw new Error(createBroadcastTxErrorMessage(result));
throw new Error(createDeliverTxResponseErrorMessage(result));
}
return {
logs: logs.parseRawLog(result.rawLog),

View File

@ -94,11 +94,10 @@ export {
} from "./search";
export {
assertIsDeliverTxSuccess,
assertIsDeliverTxFailure,
Block,
BlockHeader,
DeliverTxFailure,
DeliverTxResponse,
DeliverTxSuccess,
IndexedTx,
isDeliverTxFailure,
isDeliverTxSuccess,

View File

@ -13,7 +13,7 @@ import { AminoMsgDelegate } from "./aminomsgs";
import { AminoTypes } from "./aminotypes";
import { MsgDelegateEncodeObject, MsgSendEncodeObject } from "./encodeobjects";
import { PrivateSigningStargateClient, SigningStargateClient } from "./signingstargateclient";
import { assertIsDeliverTxSuccess, isDeliverTxFailure } from "./stargateclient";
import { assertIsDeliverTxFailure, assertIsDeliverTxSuccess, isDeliverTxFailure } from "./stargateclient";
import {
defaultGasPrice,
defaultSendFee,
@ -271,6 +271,40 @@ describe("SigningStargateClient", () => {
const memo = "Use your power wisely";
const result = await client.signAndBroadcast(faucet.address0, [msgAny], fee, memo);
assertIsDeliverTxSuccess(result);
expect(result.code).toEqual(0);
expect(result.gasWanted).toEqual(180_000);
expect(result.gasUsed).toBeLessThanOrEqual(180_000);
expect(result.gasUsed).toBeGreaterThan(100_000);
});
it("returns DeliverTxFailure on DeliverTx failure", async () => {
pendingWithoutSimapp();
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic);
const client = await SigningStargateClient.connectWithSigner(
simapp.tendermintUrl,
wallet,
defaultSigningClientOptions,
);
const msg = MsgSend.fromPartial({
fromAddress: faucet.address0,
toAddress: makeRandomAddress(),
amount: coins(Number.MAX_SAFE_INTEGER, "ustake"),
});
const msgAny: MsgSendEncodeObject = {
typeUrl: "/cosmos.bank.v1beta1.MsgSend",
value: msg,
};
const fee = {
amount: coins(2000, "ucosm"),
gas: "99000",
};
const result = await client.signAndBroadcast(faucet.address0, [msgAny], fee);
assertIsDeliverTxFailure(result);
expect(result.code).toBeGreaterThan(0);
expect(result.gasWanted).toEqual(99_000);
expect(result.gasUsed).toBeLessThanOrEqual(99_000);
expect(result.gasUsed).toBeGreaterThan(40_000);
});
it("works with auto gas", async () => {

View File

@ -15,6 +15,8 @@ import { ReadonlyDate } from "readonly-date";
import {
assertIsDeliverTxSuccess,
isDeliverTxFailure,
isDeliverTxSuccess,
PrivateStargateClient,
StargateClient,
TimeoutError,
@ -32,6 +34,39 @@ import {
validator,
} from "./testutils.spec";
const resultFailure = {
code: 5,
height: 219901,
rawLog:
"failed to execute message; message index: 0: 1855527000ufct is smaller than 20000000000000000000000ufct: insufficient funds",
transactionHash: "FDC4FB701AABD465935F7D04AE490D1EF5F2BD4B227601C4E98B57EB077D9B7D",
gasUsed: 54396,
gasWanted: 200000,
};
const resultSuccess = {
code: 0,
height: 219894,
rawLog:
'[{"events":[{"type":"message","attributes":[{"key":"action","value":"send"},{"key":"sender","value":"firma1trqyle9m2nvyafc2n25frkpwed2504y6avgfzr"},{"key":"module","value":"bank"}]},{"type":"transfer","attributes":[{"key":"recipient","value":"firma12er8ls2sf5zess3jgjxz59xat9xtf8hz0hk6n4"},{"key":"sender","value":"firma1trqyle9m2nvyafc2n25frkpwed2504y6avgfzr"},{"key":"amount","value":"2000000ufct"}]}]}]',
transactionHash: "C0B416CA868C55C2B8C1BBB8F3CFA233854F13A5CB15D3E9599F50CAF7B3D161",
gasUsed: 61556,
gasWanted: 200000,
};
describe("isDeliverTxFailure", () => {
it("works", () => {
expect(isDeliverTxFailure(resultFailure)).toEqual(true);
expect(isDeliverTxFailure(resultSuccess)).toEqual(false);
});
});
describe("isDeliverTxSuccess", () => {
it("works", () => {
expect(isDeliverTxSuccess(resultFailure)).toEqual(false);
expect(isDeliverTxSuccess(resultSuccess)).toEqual(true);
});
});
describe("StargateClient", () => {
describe("connect", () => {
it("works", async () => {

View File

@ -92,41 +92,33 @@ export interface SequenceResponse {
readonly sequence: number;
}
export interface DeliverTxFailure {
/**
* The response after successfully broadcasting a transaction.
* Success or failure refer to the execution result.
*/
export interface DeliverTxResponse {
readonly height: number;
/** Error code. The transaction suceeded iff code is 0. */
readonly code: number;
readonly transactionHash: string;
readonly rawLog?: string;
readonly data?: readonly MsgData[];
}
export interface DeliverTxSuccess {
readonly height: number;
readonly transactionHash: string;
readonly rawLog?: string;
readonly data?: readonly MsgData[];
readonly gasUsed: number;
readonly gasWanted: number;
}
/**
* The response after successfully broadcasting a transaction.
* Success or failure refer to the execution result.
*/
export type DeliverTxResponse = DeliverTxSuccess | DeliverTxFailure;
export function isDeliverTxFailure(result: DeliverTxResponse): result is DeliverTxFailure {
return !!(result as DeliverTxFailure).code;
export function isDeliverTxFailure(result: DeliverTxResponse): boolean {
return !!result.code;
}
export function isDeliverTxSuccess(result: DeliverTxResponse): result is DeliverTxSuccess {
export function isDeliverTxSuccess(result: DeliverTxResponse): boolean {
return !isDeliverTxFailure(result);
}
/**
* Ensures the given result is a success. Throws a detailed error message otherwise.
*/
export function assertIsDeliverTxSuccess(result: DeliverTxResponse): asserts result is DeliverTxSuccess {
export function assertIsDeliverTxSuccess(result: DeliverTxResponse): void {
if (isDeliverTxFailure(result)) {
throw new Error(
`Error when broadcasting tx ${result.transactionHash} at height ${result.height}. Code: ${result.code}; Raw log: ${result.rawLog}`,
@ -134,6 +126,17 @@ export function assertIsDeliverTxSuccess(result: DeliverTxResponse): asserts res
}
}
/**
* Ensures the given result is a failure. Throws a detailed error message otherwise.
*/
export function assertIsDeliverTxFailure(result: DeliverTxResponse): void {
if (isDeliverTxSuccess(result)) {
throw new Error(
`Transaction ${result.transactionHash} did not fail at height ${result.height}. Code: ${result.code}; Raw log: ${result.rawLog}`,
);
}
}
/** Use for testing only */
export interface PrivateStargateClient {
readonly tmClient: Tendermint34Client | undefined;