Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve event propagation #1302

Merged
merged 5 commits into from Oct 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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