From 2280bafac7bfb414f6077853789024a6a94b6251 Mon Sep 17 00:00:00 2001 From: willclarktech Date: Mon, 15 Jun 2020 18:45:15 +0100 Subject: [PATCH] demo-protobuf: Add basic registry example --- packages/demo-protobuf/src/demo.ts | 2 +- packages/demo-protobuf/src/registry.spec.ts | 88 +++++++++++++++++++++ packages/demo-protobuf/src/registry.ts | 21 +++++ packages/demo-protobuf/types/demo.d.ts | 2 + packages/demo-protobuf/types/registry.d.ts | 6 ++ 5 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 packages/demo-protobuf/src/registry.spec.ts create mode 100644 packages/demo-protobuf/src/registry.ts create mode 100644 packages/demo-protobuf/types/registry.d.ts diff --git a/packages/demo-protobuf/src/demo.ts b/packages/demo-protobuf/src/demo.ts index 6f7e31d7..09baa378 100644 --- a/packages/demo-protobuf/src/demo.ts +++ b/packages/demo-protobuf/src/demo.ts @@ -1,6 +1,6 @@ import { Field, Root, Type } from "protobufjs"; -const MsgDemo = new Type("MsgDemo").add(new Field("example", 1, "string")); +export const MsgDemo = new Type("MsgDemo").add(new Field("example", 1, "string")); const root = new Root().define("demo").add(MsgDemo); diff --git a/packages/demo-protobuf/src/registry.spec.ts b/packages/demo-protobuf/src/registry.spec.ts new file mode 100644 index 00000000..bc11581f --- /dev/null +++ b/packages/demo-protobuf/src/registry.spec.ts @@ -0,0 +1,88 @@ +/* eslint-disable @typescript-eslint/camelcase */ +import { assert } from "@cosmjs/utils"; + +import { MsgDemo as MsgDemoType } from "./demo"; +import { cosmos_sdk as cosmosSdk } from "./generated/codecimpl"; +import { Registry } from "./registry"; + +type MsgDemo = { + readonly example: string; +}; + +describe("registry demo", () => { + it("works with a default msg", () => { + const registry = new Registry(); + const Coin = registry.lookupType("/cosmos.Coin")!; + const MsgSend = registry.lookupType("/cosmos.bank.MsgSend")!; + const TxBody = registry.lookupType("/cosmos.tx.TxBody")!; + const Any = registry.lookupType("/google.protobuf.Any")!; + + const coin = Coin.create({ + denom: "ucosm", + amount: "1234567890", + }); + const msgSend = (MsgSend.create({ + fromAddress: Uint8Array.from(Array.from({ length: 20 }, () => 1)), + toAddress: Uint8Array.from(Array.from({ length: 20 }, () => 2)), + amount: [coin], + }) as unknown) as cosmosSdk.x.bank.v1.MsgSend; + const msgSendBytes = MsgSend.encode(msgSend).finish(); + const msgSendWrapped = Any.create({ + type_url: "/cosmos.bank.MsgSend", + value: msgSendBytes, + }); + const txBody = TxBody.create({ + messages: [msgSendWrapped], + memo: "Some memo", + timeoutHeight: 9999, + extensionOptions: [], + }); + const txBodyBytes = TxBody.encode(txBody).finish(); + + const txBodyDecoded = (TxBody.decode(txBodyBytes) as unknown) as cosmosSdk.tx.v1.TxBody; + const msg = txBodyDecoded.messages[0]; + assert(msg.type_url); + assert(msg.value); + + const decoder = registry.lookupType(msg.type_url)!; + const msgSendDecoded = (decoder.decode(msg.value) as unknown) as cosmosSdk.x.bank.v1.MsgSend; + + // fromAddress and toAddress are now Buffers + expect(Uint8Array.from(msgSendDecoded.fromAddress)).toEqual(msgSend.fromAddress); + expect(Uint8Array.from(msgSendDecoded.toAddress)).toEqual(msgSend.toAddress); + expect(msgSendDecoded.amount).toEqual(msgSend.amount); + }); + + it("works with a custom msg", () => { + const typeUrl = "/demo.MsgDemo"; + const registry = new Registry([[typeUrl, MsgDemoType]]); + const MsgDemo = registry.lookupType(typeUrl)!; + const TxBody = registry.lookupType("/cosmos.tx.TxBody")!; + const Any = registry.lookupType("/google.protobuf.Any")!; + + const msgDemo = (MsgDemo.create({ + example: "Some example text", + }) as unknown) as MsgDemo; + const msgDemoBytes = MsgDemo.encode(msgDemo).finish(); + const msgDemoWrapped = Any.create({ + type_url: "/demo.MsgDemo", + value: msgDemoBytes, + }); + const txBody = TxBody.create({ + messages: [msgDemoWrapped], + memo: "Some memo", + timeoutHeight: 9999, + extensionOptions: [], + }); + const txBodyBytes = TxBody.encode(txBody).finish(); + + const txBodyDecoded = (TxBody.decode(txBodyBytes) as unknown) as cosmosSdk.tx.v1.TxBody; + const msg = txBodyDecoded.messages[0]; + assert(msg.type_url); + assert(msg.value); + + const decoder = registry.lookupType(msg.type_url)!; + const msgDemoDecoded = (decoder.decode(msg.value) as unknown) as MsgDemo; + expect(msgDemoDecoded.example).toEqual(msgDemo.example); + }); +}); diff --git a/packages/demo-protobuf/src/registry.ts b/packages/demo-protobuf/src/registry.ts new file mode 100644 index 00000000..302f67ef --- /dev/null +++ b/packages/demo-protobuf/src/registry.ts @@ -0,0 +1,21 @@ +import protobuf from "protobufjs"; + +import { cosmos_sdk as cosmosSdk, google } from "./generated/codecimpl"; + +export class Registry { + private readonly types: Map; + + constructor(customTypes: readonly [string, protobuf.Type][] = []) { + this.types = new Map([ + ["/cosmos.Coin", (cosmosSdk.v1.Coin as unknown) as protobuf.Type], + ["/cosmos.bank.MsgSend", (cosmosSdk.x.bank.v1.MsgSend as unknown) as protobuf.Type], + ["/cosmos.tx.TxBody", (cosmosSdk.tx.v1.TxBody as unknown) as protobuf.Type], + ["/google.protobuf.Any", (google.protobuf.Any as unknown) as protobuf.Type], + ...customTypes, + ]); + } + + public lookupType(name: string): protobuf.Type | undefined { + return this.types.get(name); + } +} diff --git a/packages/demo-protobuf/types/demo.d.ts b/packages/demo-protobuf/types/demo.d.ts index 0b1d1914..3cacd8ff 100644 --- a/packages/demo-protobuf/types/demo.d.ts +++ b/packages/demo-protobuf/types/demo.d.ts @@ -1,2 +1,4 @@ +import { Type } from "protobufjs"; +export declare const MsgDemo: Type; declare const root: import("protobufjs").Namespace; export default root; diff --git a/packages/demo-protobuf/types/registry.d.ts b/packages/demo-protobuf/types/registry.d.ts new file mode 100644 index 00000000..9b011609 --- /dev/null +++ b/packages/demo-protobuf/types/registry.d.ts @@ -0,0 +1,6 @@ +import protobuf from "protobufjs"; +export declare class Registry { + private readonly types; + constructor(customTypes?: readonly [string, protobuf.Type][]); + lookupType(name: string): protobuf.Type | undefined; +}