Merge pull request #693 from cosmos/support-different-generated-types

Bring back support for pbjs generated types
This commit is contained in:
mergify[bot] 2021-02-24 13:24:51 +00:00 committed by GitHub
commit f4d313b56a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 108 additions and 35 deletions

View File

@ -1,4 +1,12 @@
export { EncodeObject, GeneratedType, Registry } from "./registry";
export {
isPbjsGeneratedType,
isTsProtoGeneratedType,
EncodeObject,
GeneratedType,
Registry,
TsProtoGeneratedType,
PbjsGeneratedType,
} from "./registry";
export { DirectSecp256k1HdWallet } from "./directsecp256k1hdwallet";
export { DirectSecp256k1Wallet } from "./directsecp256k1wallet";
export { makeCosmoshubPath } from "./paths";

View File

@ -1,17 +1,23 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { fromHex } from "@cosmjs/encoding";
import { assert } from "@cosmjs/utils";
import Long from "long";
import { Field, Type } from "protobufjs";
import { MsgSend as IMsgSend } from "./codec/cosmos/bank/v1beta1/tx";
import { TxBody } from "./codec/cosmos/tx/v1beta1/tx";
import { Any } from "./codec/google/protobuf/any";
import { Registry } from "./registry";
import { isPbjsGeneratedType, isTsProtoGeneratedType, Registry } from "./registry";
describe("registry demo", () => {
it("works with a default msg", () => {
const registry = new Registry();
const Coin = registry.lookupType("/cosmos.base.v1beta1.Coin")!;
const MsgSend = registry.lookupType("/cosmos.bank.v1beta1.MsgSend")!;
const Coin = registry.lookupType("/cosmos.base.v1beta1.Coin");
const MsgSend = registry.lookupType("/cosmos.bank.v1beta1.MsgSend");
assert(Coin);
assert(MsgSend);
assert(isTsProtoGeneratedType(Coin));
assert(isTsProtoGeneratedType(MsgSend));
const coin = Coin.fromPartial({
denom: "ucosm",
@ -49,35 +55,53 @@ describe("registry demo", () => {
expect(msgSendDecoded.amount).toEqual(msgSend.amount);
});
// TODO: Can't autogenerate types from TS code using ts-proto
// it("works with a custom msg", () => {
// const typeUrl = "/demo.MsgDemo";
// const registry = new Registry([[typeUrl, MsgDemoType]]);
// const MsgDemo = registry.lookupType(typeUrl)!;
it("works with a custom msg", () => {
// From https://gist.github.com/fadeev/a4981eff1cf3a805ef10e25313d5f2b7
const typeUrl = "/blog.MsgCreatePost";
const MsgCreatePostOriginal = new Type("MsgCreatePost")
.add(new Field("creator", 1, "string"))
.add(new Field("title", 2, "string"))
.add(new Field("body", 3, "string"))
.add(new Field("attachment", 4, "bytes"));
// const msgDemo = MsgDemo.fromPartial({
// example: "Some example text",
// });
// const msgDemoBytes = MsgDemo.encode(msgDemo).finish();
// const msgDemoWrapped = Any.create({
// type_url: typeUrl,
// value: msgDemoBytes,
// });
// const txBody = TxBody.create({
// messages: [msgDemoWrapped],
// memo: "Some memo",
// timeoutHeight: Long.fromNumber(9999),
// extensionOptions: [],
// });
// const txBodyBytes = TxBody.encode(txBody).finish();
const registry = new Registry([[typeUrl, MsgCreatePostOriginal]]);
const MsgCreatePost = registry.lookupType(typeUrl);
assert(MsgCreatePost);
assert(isPbjsGeneratedType(MsgCreatePost));
// const txBodyDecoded = TxBody.decode(txBodyBytes);
// const msg = txBodyDecoded.messages[0];
// assert(msg.type_url);
// assert(msg.value);
const msgDemo = MsgCreatePost.create({
creator: "Me",
title: "Something with stars",
body: "la la la",
attachment: fromHex("AABBAABB66FE"),
});
const msgDemoBytes = MsgCreatePost.encode(msgDemo).finish();
const msgDemoWrapped = Any.fromPartial({
typeUrl: typeUrl,
value: msgDemoBytes,
});
const txBody = TxBody.fromPartial({
messages: [msgDemoWrapped],
memo: "Some memo",
timeoutHeight: Long.fromNumber(9999),
extensionOptions: [],
});
const txBodyBytes = TxBody.encode(txBody).finish();
// const decoder = registry.lookupType(msg.type_url)!;
// const msgDemoDecoded = decoder.decode(msg.value);
// expect(msgDemoDecoded.example).toEqual(msgDemo.example);
// });
const txBodyDecoded = TxBody.decode(txBodyBytes);
const msg = txBodyDecoded.messages[0];
assert(msg.typeUrl);
assert(msg.value);
const decoder = registry.lookupType(msg.typeUrl)!;
const msgDemoDecoded = decoder.decode(msg.value);
expect(msgDemoDecoded).toEqual(
jasmine.objectContaining({
creator: "Me",
title: "Something with stars",
body: "la la la",
}),
);
expect(Uint8Array.from(msgDemoDecoded.attachment)).toEqual(fromHex("AABBAABB66FE"));
});
});

View File

@ -7,7 +7,10 @@ import { Coin } from "./codec/cosmos/base/v1beta1/coin";
import { TxBody } from "./codec/cosmos/tx/v1beta1/tx";
import { Any } from "./codec/google/protobuf/any";
export interface GeneratedType {
/**
* A type generated by [ts-proto](https://github.com/stephenh/ts-proto).
*/
export interface TsProtoGeneratedType {
readonly encode: (message: any | { [k: string]: any }, writer?: protobuf.Writer) => protobuf.Writer;
readonly decode: (input: Uint8Array | protobuf.Reader, length?: number) => any;
readonly fromJSON: (object: { [k: string]: any }) => any;
@ -15,6 +18,28 @@ export interface GeneratedType {
readonly toJSON: (message: any | { [k: string]: any }) => unknown;
}
/**
* A type generated by [protobufjs](https://github.com/protobufjs/protobuf.js).
*
* This can be used if you want to create types at runtime using pure JavaScript.
* See https://gist.github.com/fadeev/a4981eff1cf3a805ef10e25313d5f2b7
*/
export interface PbjsGeneratedType {
readonly create: (properties?: { [k: string]: any }) => any;
readonly encode: (message: any | { [k: string]: any }, writer?: protobuf.Writer) => protobuf.Writer;
readonly decode: (reader: protobuf.Reader | Uint8Array, length?: number) => any;
}
export type GeneratedType = TsProtoGeneratedType | PbjsGeneratedType;
export function isTsProtoGeneratedType(type: GeneratedType): type is TsProtoGeneratedType {
return typeof (type as TsProtoGeneratedType).fromPartial === "function";
}
export function isPbjsGeneratedType(type: GeneratedType): type is PbjsGeneratedType {
return !isTsProtoGeneratedType(type);
}
export interface EncodeObject {
readonly typeUrl: string;
readonly value: any;
@ -56,6 +81,22 @@ export class Registry {
this.types.set(typeUrl, type);
}
/**
* Looks up a type that was previously added to the registry.
*
* The generator information (ts-proto or pbjs) gets lost along the way.
* If you need to work with the result type in TypeScript, you can use:
*
* ```
* import { assert } from "@cosmjs/utils";
*
* const Coin = registry.lookupType("/cosmos.base.v1beta1.Coin");
* assert(Coin); // Ensures not unset
* assert(isTsProtoGeneratedType(Coin)); // Ensures this is the type we expect
*
* // Coin is typed TsProtoGeneratedType now.
* ```
*/
public lookupType(typeUrl: string): GeneratedType | undefined {
return this.types.get(typeUrl);
}
@ -73,8 +114,8 @@ export class Registry {
return this.encodeTxBody(value);
}
const type = this.lookupTypeWithError(typeUrl);
const created = type.fromPartial(value);
return Uint8Array.from(type.encode(created).finish());
const instance = isTsProtoGeneratedType(type) ? type.fromPartial(value) : type.create(value);
return Uint8Array.from(type.encode(instance).finish());
}
public encodeTxBody(txBodyFields: TxBodyValue): Uint8Array {