Skip to content

Commit

Permalink
Merge pull request #1302 from cosmos/stargate-events
Browse files Browse the repository at this point in the history
Improve event propagation
  • Loading branch information
webmaster128 committed Oct 24, 2022
2 parents 55ca044 + c51fb21 commit d953ede
Show file tree
Hide file tree
Showing 11 changed files with 112 additions and 11 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Expand Up @@ -10,6 +10,12 @@ and this project adheres to

- @cosmjs/tendermint-rpc: Add `HttpBatchClient`, which implements `RpcClient`,
supporting batch RPC requests ([#1300]).
- @cosmjs/encoding: Add `lossy` parameter to `fromUtf8` allowing the use of a
replacement charater instead of throwing.
- @cosmjs/stargate: Add structured `Events`s to `IndexTx.events` and
`DeliverTxResponse.events`.
- @cosmjs/cosmwasm-stargate: Add structured `Events`s field to
`SigningCosmWasmClient`s transaction execution methods.

## [0.29.2] - 2022-10-13

Expand Down
3 changes: 3 additions & 0 deletions packages/cosmwasm-stargate/src/cosmwasmclient.ts
Expand Up @@ -10,6 +10,7 @@ import {
BroadcastTxError,
Coin,
DeliverTxResponse,
fromTendermint34Event,
IndexedTx,
isSearchByHeightQuery,
isSearchBySentFromOrToQuery,
Expand Down Expand Up @@ -283,6 +284,7 @@ export class CosmWasmClient {
height: result.height,
rawLog: result.rawLog,
transactionHash: txId,
events: result.events,
gasUsed: result.gasUsed,
gasWanted: result.gasWanted,
}
Expand Down Expand Up @@ -462,6 +464,7 @@ export class CosmWasmClient {
height: tx.height,
hash: toHex(tx.hash).toUpperCase(),
code: tx.result.code,
events: tx.result.events.map(fromTendermint34Event),
rawLog: tx.result.log || "",
tx: tx.tx,
gasUsed: tx.result.gasUsed,
Expand Down
1 change: 1 addition & 0 deletions packages/cosmwasm-stargate/src/index.ts
Expand Up @@ -32,4 +32,5 @@ export {
} from "./signingcosmwasmclient";

// Re-exported because this is part of the CosmWasmClient/SigningCosmWasmClient APIs
export { Attribute, DeliverTxResponse, Event, IndexedTx } from "@cosmjs/stargate";
export { HttpEndpoint } from "@cosmjs/tendermint-rpc";
12 changes: 12 additions & 0 deletions packages/cosmwasm-stargate/src/signingcosmwasmclient.ts
Expand Up @@ -20,6 +20,7 @@ import {
createBankAminoConverters,
defaultRegistryTypes as defaultStargateTypes,
DeliverTxResponse,
Event,
GasPrice,
isDeliverTxFailure,
logs,
Expand Down Expand Up @@ -76,6 +77,7 @@ export interface UploadResult {
readonly height: number;
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
readonly transactionHash: string;
readonly events: readonly Event[];
readonly gasWanted: number;
readonly gasUsed: number;
}
Expand Down Expand Up @@ -109,6 +111,7 @@ export interface InstantiateResult {
readonly height: number;
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
readonly transactionHash: string;
readonly events: readonly Event[];
readonly gasWanted: number;
readonly gasUsed: number;
}
Expand All @@ -122,6 +125,7 @@ export interface ChangeAdminResult {
readonly height: number;
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
readonly transactionHash: string;
readonly events: readonly Event[];
readonly gasWanted: number;
readonly gasUsed: number;
}
Expand All @@ -132,6 +136,7 @@ export interface MigrateResult {
readonly height: number;
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
readonly transactionHash: string;
readonly events: readonly Event[];
readonly gasWanted: number;
readonly gasUsed: number;
}
Expand All @@ -148,6 +153,7 @@ export interface ExecuteResult {
readonly height: number;
/** Transaction hash (might be used as transaction ID). Guaranteed to be non-empty upper-case hex */
readonly transactionHash: string;
readonly events: readonly Event[];
readonly gasWanted: number;
readonly gasUsed: number;
}
Expand Down Expand Up @@ -271,6 +277,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
logs: parsedLogs,
height: result.height,
transactionHash: result.transactionHash,
events: result.events,
gasWanted: result.gasWanted,
gasUsed: result.gasUsed,
};
Expand Down Expand Up @@ -306,6 +313,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
logs: parsedLogs,
height: result.height,
transactionHash: result.transactionHash,
events: result.events,
gasWanted: result.gasWanted,
gasUsed: result.gasUsed,
};
Expand Down Expand Up @@ -334,6 +342,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
logs: logs.parseRawLog(result.rawLog),
height: result.height,
transactionHash: result.transactionHash,
events: result.events,
gasWanted: result.gasWanted,
gasUsed: result.gasUsed,
};
Expand All @@ -360,6 +369,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
logs: logs.parseRawLog(result.rawLog),
height: result.height,
transactionHash: result.transactionHash,
events: result.events,
gasWanted: result.gasWanted,
gasUsed: result.gasUsed,
};
Expand Down Expand Up @@ -390,6 +400,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
logs: logs.parseRawLog(result.rawLog),
height: result.height,
transactionHash: result.transactionHash,
events: result.events,
gasWanted: result.gasWanted,
gasUsed: result.gasUsed,
};
Expand Down Expand Up @@ -437,6 +448,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
logs: logs.parseRawLog(result.rawLog),
height: result.height,
transactionHash: result.transactionHash,
events: result.events,
gasWanted: result.gasWanted,
gasUsed: result.gasUsed,
};
Expand Down
12 changes: 12 additions & 0 deletions packages/encoding/src/utf8.spec.ts
@@ -1,3 +1,4 @@
import { toAscii } from "./ascii";
import { fromUtf8, toUtf8 } from "./utf8";

describe("utf8", () => {
Expand Down Expand Up @@ -59,4 +60,15 @@ describe("utf8", () => {
// Broken UTF8 example from https://github.com/nodejs/node/issues/16894
expect(() => fromUtf8(new Uint8Array([0xf0, 0x80, 0x80]))).toThrow();
});

describe("fromUtf8", () => {
it("replaces characters in lossy mode", () => {
expect(fromUtf8(new Uint8Array([]), true)).toEqual("");
expect(fromUtf8(new Uint8Array([0x61, 0x62, 0x63]), true)).toEqual("abc");
// Example from https://doc.rust-lang.org/stable/std/string/struct.String.html#method.from_utf8_lossy
expect(
fromUtf8(new Uint8Array([...toAscii("Hello "), 0xf0, 0x90, 0x80, ...toAscii("World")]), true),
).toEqual("Hello �World");
});
});
});
11 changes: 9 additions & 2 deletions packages/encoding/src/utf8.ts
Expand Up @@ -12,6 +12,13 @@ export function toUtf8(str: string): Uint8Array {
return new TextEncoder().encode(str);
}

export function fromUtf8(data: Uint8Array): string {
return new TextDecoder("utf-8", { fatal: true }).decode(data);
/**
* Takes UTF-8 data and decodes it to a string.
*
* In lossy mode, the replacement character � is used to substitude invalid
* encodings. By default lossy mode is off and invalid data will lead to exceptions.
*/
export function fromUtf8(data: Uint8Array, lossy = false): string {
const fatal = !lossy;
return new TextDecoder("utf-8", { fatal }).decode(data);
}
46 changes: 46 additions & 0 deletions packages/stargate/src/events.ts
@@ -0,0 +1,46 @@
import { fromUtf8 } from "@cosmjs/encoding";
import { tendermint34 } from "@cosmjs/tendermint-rpc";

/**
* An event attribute.
*
* This is the same attribute type as tendermint34.Attribute and tendermint35.EventAttribute
* but `key` and `value` are unified to strings. The conversion
* from bytes to string in the Tendermint 0.34 case should be done by performing
* [lossy] UTF-8 decoding.
*
* [lossy]: https://doc.rust-lang.org/stable/std/string/struct.String.html#method.from_utf8_lossy
*/
export interface Attribute {
readonly key: string;
readonly value: string;
}

/**
* The same event type as tendermint34.Event and tendermint35.Event
* but attribute keys and values are unified to strings. The conversion
* from bytes to string in the Tendermint 0.34 case should be done by performing
* [lossy] UTF-8 decoding.
*
* [lossy]: https://doc.rust-lang.org/stable/std/string/struct.String.html#method.from_utf8_lossy
*/
export interface Event {
readonly type: string;
readonly attributes: readonly Attribute[];
}

/**
* Takes a Tendemrint 0.34 event with binary encoded key and value
* and converts it into an `Event` with string attributes.
*/
export function fromTendermint34Event(event: tendermint34.Event): Event {
return {
type: event.type,
attributes: event.attributes.map(
(attr): Attribute => ({
key: fromUtf8(attr.key, true),
value: fromUtf8(attr.value, true),
}),
),
};
}
1 change: 1 addition & 0 deletions packages/stargate/src/index.ts
@@ -1,5 +1,6 @@
export { Account, accountFromAny, AccountParser } from "./accounts";
export { AminoConverter, AminoConverters, AminoTypes } from "./aminotypes";
export { Attribute, Event, fromTendermint34Event } from "./events";
export { calculateFee, GasPrice } from "./fee";
export * as logs from "./logs";
export {
Expand Down
10 changes: 1 addition & 9 deletions packages/stargate/src/logs.ts
@@ -1,15 +1,7 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { isNonNullObject } from "@cosmjs/utils";

export interface Attribute {
readonly key: string;
readonly value: string;
}

export interface Event {
readonly type: string;
readonly attributes: readonly Attribute[];
}
import { Attribute, Event } from "./events";

export interface Log {
readonly msg_index: number;
Expand Down
2 changes: 2 additions & 0 deletions packages/stargate/src/stargateclient.spec.ts
Expand Up @@ -42,6 +42,7 @@ const resultFailure = {
rawLog:
"failed to execute message; message index: 0: 1855527000ufct is smaller than 20000000000000000000000ufct: insufficient funds",
transactionHash: "FDC4FB701AABD465935F7D04AE490D1EF5F2BD4B227601C4E98B57EB077D9B7D",
events: [],
gasUsed: 54396,
gasWanted: 200000,
};
Expand All @@ -51,6 +52,7 @@ const resultSuccess = {
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",
events: [],
gasUsed: 61556,
gasWanted: 200000,
};
Expand Down
19 changes: 19 additions & 0 deletions packages/stargate/src/stargateclient.ts
Expand Up @@ -10,6 +10,7 @@ import { QueryDelegatorDelegationsResponse } from "cosmjs-types/cosmos/staking/v
import { DelegationResponse } from "cosmjs-types/cosmos/staking/v1beta1/staking";

import { Account, accountFromAny, AccountParser } from "./accounts";
import { Event, fromTendermint34Event } from "./events";
import {
AuthExtension,
BankExtension,
Expand Down Expand Up @@ -64,6 +65,14 @@ export interface IndexedTx {
readonly hash: string;
/** Transaction execution error code. 0 on success. */
readonly code: number;
readonly events: readonly Event[];
/**
* A string-based log document.
*
* This currently seems to merge attributes of multiple events into one event per type
* (https://github.com/tendermint/tendermint/issues/9595). You might want to use the `events`
* field instead.
*/
readonly rawLog: string;
/**
* Raw transaction bytes stored in Tendermint.
Expand Down Expand Up @@ -98,6 +107,14 @@ export interface DeliverTxResponse {
/** Error code. The transaction suceeded iff code is 0. */
readonly code: number;
readonly transactionHash: string;
readonly events: readonly Event[];
/**
* A string-based log document.
*
* This currently seems to merge attributes of multiple events into one event per type
* (https://github.com/tendermint/tendermint/issues/9595). You might want to use the `events`
* field instead.
*/
readonly rawLog?: string;
readonly data?: readonly MsgData[];
readonly gasUsed: number;
Expand Down Expand Up @@ -417,6 +434,7 @@ export class StargateClient {
? {
code: result.code,
height: result.height,
events: result.events,
rawLog: result.rawLog,
transactionHash: txId,
gasUsed: result.gasUsed,
Expand Down Expand Up @@ -453,6 +471,7 @@ export class StargateClient {
height: tx.height,
hash: toHex(tx.hash).toUpperCase(),
code: tx.result.code,
events: tx.result.events.map(fromTendermint34Event),
rawLog: tx.result.log || "",
tx: tx.tx,
gasUsed: tx.result.gasUsed,
Expand Down

0 comments on commit d953ede

Please sign in to comment.