Merge pull request #1302 from cosmos/stargate-events
Improve event propagation
This commit is contained in:
commit
d953edef0f
@ -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
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@ import {
|
||||
BroadcastTxError,
|
||||
Coin,
|
||||
DeliverTxResponse,
|
||||
fromTendermint34Event,
|
||||
IndexedTx,
|
||||
isSearchByHeightQuery,
|
||||
isSearchBySentFromOrToQuery,
|
||||
@ -283,6 +284,7 @@ export class CosmWasmClient {
|
||||
height: result.height,
|
||||
rawLog: result.rawLog,
|
||||
transactionHash: txId,
|
||||
events: result.events,
|
||||
gasUsed: result.gasUsed,
|
||||
gasWanted: result.gasWanted,
|
||||
}
|
||||
@ -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,
|
||||
|
||||
@ -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";
|
||||
|
||||
@ -20,6 +20,7 @@ import {
|
||||
createBankAminoConverters,
|
||||
defaultRegistryTypes as defaultStargateTypes,
|
||||
DeliverTxResponse,
|
||||
Event,
|
||||
GasPrice,
|
||||
isDeliverTxFailure,
|
||||
logs,
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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,
|
||||
};
|
||||
@ -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,
|
||||
};
|
||||
@ -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,
|
||||
};
|
||||
@ -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,
|
||||
};
|
||||
@ -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,
|
||||
};
|
||||
@ -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,
|
||||
};
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { toAscii } from "./ascii";
|
||||
import { fromUtf8, toUtf8 } from "./utf8";
|
||||
|
||||
describe("utf8", () => {
|
||||
@ -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 <20>World");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -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 <EFBFBD> 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
packages/stargate/src/events.ts
Normal file
46
packages/stargate/src/events.ts
Normal file
@ -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,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 {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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,
|
||||
};
|
||||
@ -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,
|
||||
};
|
||||
|
||||
@ -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,
|
||||
@ -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.
|
||||
@ -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;
|
||||
@ -417,6 +434,7 @@ export class StargateClient {
|
||||
? {
|
||||
code: result.code,
|
||||
height: result.height,
|
||||
events: result.events,
|
||||
rawLog: result.rawLog,
|
||||
transactionHash: txId,
|
||||
gasUsed: result.gasUsed,
|
||||
@ -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,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user