From b56200d2e515d9a491cc5476737d31c7adbc999b Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 24 Nov 2021 13:05:15 +0100 Subject: [PATCH] Merge DeliverTxFailure/DeliverTxSuccess into DeliverTxResponse --- CHANGELOG.md | 4 ++ .../src/signingcosmwasmclient.ts | 15 ++++--- packages/stargate/src/index.ts | 3 +- .../src/signingstargateclient.spec.ts | 36 ++++++++++++++++- packages/stargate/src/stargateclient.spec.ts | 35 +++++++++++++++++ packages/stargate/src/stargateclient.ts | 39 ++++++++++--------- 6 files changed, 103 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ddbe274..aa57b47b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/packages/cosmwasm-stargate/src/signingcosmwasmclient.ts b/packages/cosmwasm-stargate/src/signingcosmwasmclient.ts index 4323f353..afc9cefc 100644 --- a/packages/cosmwasm-stargate/src/signingcosmwasmclient.ts +++ b/packages/cosmwasm-stargate/src/signingcosmwasmclient.ts @@ -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), diff --git a/packages/stargate/src/index.ts b/packages/stargate/src/index.ts index f483866a..dcc6804a 100644 --- a/packages/stargate/src/index.ts +++ b/packages/stargate/src/index.ts @@ -94,11 +94,10 @@ export { } from "./search"; export { assertIsDeliverTxSuccess, + assertIsDeliverTxFailure, Block, BlockHeader, - DeliverTxFailure, DeliverTxResponse, - DeliverTxSuccess, IndexedTx, isDeliverTxFailure, isDeliverTxSuccess, diff --git a/packages/stargate/src/signingstargateclient.spec.ts b/packages/stargate/src/signingstargateclient.spec.ts index b6dc726f..67c0c973 100644 --- a/packages/stargate/src/signingstargateclient.spec.ts +++ b/packages/stargate/src/signingstargateclient.spec.ts @@ -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 () => { diff --git a/packages/stargate/src/stargateclient.spec.ts b/packages/stargate/src/stargateclient.spec.ts index b40aaec1..593a4afa 100644 --- a/packages/stargate/src/stargateclient.spec.ts +++ b/packages/stargate/src/stargateclient.spec.ts @@ -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 () => { diff --git a/packages/stargate/src/stargateclient.ts b/packages/stargate/src/stargateclient.ts index 3d441537..3fc9ef79 100644 --- a/packages/stargate/src/stargateclient.ts +++ b/packages/stargate/src/stargateclient.ts @@ -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;