Merge pull request #221 from CosmWasm/211-protobuf-demo
Add protobuf TxBody demo
This commit is contained in:
commit
30857b4723
@ -6,4 +6,5 @@ dist/
|
||||
docs/
|
||||
examples/
|
||||
generated/
|
||||
proto/
|
||||
types/
|
||||
|
||||
1
packages/demo-protobuf/.eslintignore
Symbolic link
1
packages/demo-protobuf/.eslintignore
Symbolic link
@ -0,0 +1 @@
|
||||
../../.eslintignore
|
||||
4
packages/demo-protobuf/.gitignore
vendored
Normal file
4
packages/demo-protobuf/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
build/
|
||||
dist/
|
||||
docs/
|
||||
proto/
|
||||
10
packages/demo-protobuf/README.md
Normal file
10
packages/demo-protobuf/README.md
Normal file
@ -0,0 +1,10 @@
|
||||
# @cosmjs/demo-protobuf
|
||||
|
||||
Demo package for protobufs with Cosmos SDK.
|
||||
|
||||
## License
|
||||
|
||||
This package is part of the cosmjs repository, licensed under the Apache
|
||||
License 2.0 (see
|
||||
[NOTICE](https://github.com/CosmWasm/cosmjs/blob/master/NOTICE) and
|
||||
[LICENSE](https://github.com/CosmWasm/cosmjs/blob/master/LICENSE)).
|
||||
26
packages/demo-protobuf/jasmine-testrunner.js
Executable file
26
packages/demo-protobuf/jasmine-testrunner.js
Executable file
@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
require("source-map-support").install();
|
||||
const defaultSpecReporterConfig = require("../../jasmine-spec-reporter.config.json");
|
||||
|
||||
// setup Jasmine
|
||||
const Jasmine = require("jasmine");
|
||||
const jasmine = new Jasmine();
|
||||
jasmine.loadConfig({
|
||||
spec_dir: "build",
|
||||
spec_files: ["**/*.spec.js"],
|
||||
helpers: [],
|
||||
random: false,
|
||||
seed: null,
|
||||
stopSpecOnExpectationFailure: false,
|
||||
});
|
||||
jasmine.jasmine.DEFAULT_TIMEOUT_INTERVAL = 15 * 1000;
|
||||
|
||||
// setup reporter
|
||||
const { SpecReporter } = require("jasmine-spec-reporter");
|
||||
const reporter = new SpecReporter({ ...defaultSpecReporterConfig });
|
||||
|
||||
// initialize and execute
|
||||
jasmine.env.clearReporters();
|
||||
jasmine.addReporter(reporter);
|
||||
jasmine.execute();
|
||||
47
packages/demo-protobuf/karma.conf.js
Normal file
47
packages/demo-protobuf/karma.conf.js
Normal file
@ -0,0 +1,47 @@
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
// base path that will be used to resolve all patterns (eg. files, exclude)
|
||||
basePath: ".",
|
||||
|
||||
// frameworks to use
|
||||
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
|
||||
frameworks: ["jasmine"],
|
||||
|
||||
// list of files / patterns to load in the browser
|
||||
files: ["dist/web/tests.js"],
|
||||
|
||||
client: {
|
||||
jasmine: {
|
||||
random: false,
|
||||
timeoutInterval: 15000,
|
||||
},
|
||||
},
|
||||
|
||||
// test results reporter to use
|
||||
// possible values: 'dots', 'progress'
|
||||
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
||||
reporters: ["progress", "kjhtml"],
|
||||
|
||||
// web server port
|
||||
port: 9876,
|
||||
|
||||
// enable / disable colors in the output (reporters and logs)
|
||||
colors: true,
|
||||
|
||||
// level of logging
|
||||
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
|
||||
logLevel: config.LOG_INFO,
|
||||
|
||||
// enable / disable watching file and executing tests whenever any file changes
|
||||
autoWatch: false,
|
||||
|
||||
// start these browsers
|
||||
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
|
||||
browsers: ["Firefox"],
|
||||
|
||||
browserNoActivityTimeout: 90000,
|
||||
|
||||
// Keep brower open for debugging. This is overridden by yarn scripts
|
||||
singleRun: false,
|
||||
});
|
||||
};
|
||||
1
packages/demo-protobuf/nonces/README.txt
Normal file
1
packages/demo-protobuf/nonces/README.txt
Normal file
@ -0,0 +1 @@
|
||||
Directory used to trigger lerna package updates for all packages
|
||||
46
packages/demo-protobuf/package.json
Normal file
46
packages/demo-protobuf/package.json
Normal file
@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "@cosmjs/demo-protobuf",
|
||||
"private": true,
|
||||
"version": "0.20.0",
|
||||
"description": "Utilities for Cosmos SDK 0.38",
|
||||
"author": "Ethan Frey <ethanfrey@users.noreply.github.com>",
|
||||
"license": "Apache-2.0",
|
||||
"main": "build/index.js",
|
||||
"types": "types/index.d.ts",
|
||||
"files": [
|
||||
"build/",
|
||||
"types/",
|
||||
"*.md",
|
||||
"!*.spec.*",
|
||||
"!**/testdata/"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/CosmWasm/cosmjs/tree/master/packages/demo-protobuf"
|
||||
},
|
||||
"scripts": {
|
||||
"docs": "shx rm -rf docs && typedoc --options typedoc.js",
|
||||
"format": "prettier --write --loglevel warn \"./src/**/*.ts\"",
|
||||
"lint": "eslint --max-warnings 0 \"**/*.{js,ts}\"",
|
||||
"lint-fix": "eslint --max-warnings 0 \"**/*.{js,ts}\" --fix",
|
||||
"move-types": "shx rm -rf ./types/* && shx mv build/types/* ./types && rm -rf ./types/testdata && shx rm -f ./types/*.spec.d.ts",
|
||||
"format-types": "prettier --write --loglevel warn \"./types/**/*.d.ts\"",
|
||||
"build": "shx rm -rf ./build && tsc && shx mkdir -p build/generated && shx cp ./src/generated/*.js ./build/generated && shx mkdir -p ./build/types/generated && shx cp ./src/generated/*.d.ts ./build/types/generated && yarn move-types && yarn format-types",
|
||||
"build-or-skip": "[ -n \"$SKIP_BUILD\" ] || yarn build",
|
||||
"test-node": "node jasmine-testrunner.js",
|
||||
"test-firefox": "yarn pack-web && karma start --single-run --browsers Firefox",
|
||||
"test-chrome": "yarn pack-web && karma start --single-run --browsers ChromeHeadless",
|
||||
"test": "yarn build-or-skip && yarn test-node",
|
||||
"pack-web": "yarn build-or-skip && webpack --mode development --config webpack.web.config.js",
|
||||
"get-proto": "REF=master ./scripts/get-proto.sh",
|
||||
"predefine-proto": "mkdir -p src/generated && pbjs -t static-module -w commonjs -o src/generated/codecimpl.tmp.js --sparse --no-beautify --no-delimited --no-verify --no-convert ./proto/cosmos/cosmos-sdk/{x/bank/types/types.proto,types/types.proto,types/tx/types.proto,types/tx/signing/types.proto,third_party/proto/tendermint/**/*.proto,crypto/types/types.proto}",
|
||||
"define-proto": "pbts src/generated/codecimpl.tmp.js -o src/generated/codecimpl.d.ts && tsc --removeComments --outFile src/generated/codecimpl.js --allowJs src/generated/codecimpl.tmp.js && rm src/generated/codecimpl.tmp.js",
|
||||
"postdefine-proto": "prettier --write \"src/generated/codecimpl.*\""
|
||||
},
|
||||
"dependencies": {
|
||||
"protobufjs": "~6.9.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cosmjs/utils": "^0.20.0"
|
||||
}
|
||||
}
|
||||
19
packages/demo-protobuf/scripts/get-proto.sh
Executable file
19
packages/demo-protobuf/scripts/get-proto.sh
Executable file
@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
set -o errexit -o nounset -o pipefail
|
||||
command -v shellcheck > /dev/null && shellcheck "$0"
|
||||
|
||||
PROTO_DIR="./proto"
|
||||
COSMOS_DIR="$PROTO_DIR/cosmos"
|
||||
COSMOS_SDK_DIR="$COSMOS_DIR/cosmos-sdk"
|
||||
ZIP_FILE="$COSMOS_DIR/tmp.zip"
|
||||
REF=${REF:-"master"}
|
||||
SUFFIX=${REF}
|
||||
|
||||
[[ $SUFFIX =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] && SUFFIX=${SUFFIX#v}
|
||||
|
||||
mkdir -p "$COSMOS_DIR"
|
||||
|
||||
wget -qO "$ZIP_FILE" "https://github.com/cosmos/cosmos-sdk/archive/$REF.zip" \
|
||||
&& unzip "$ZIP_FILE" "*.proto" -d "$COSMOS_DIR" \
|
||||
&& mv "$COSMOS_SDK_DIR-$SUFFIX" "$COSMOS_SDK_DIR" \
|
||||
&& rm "$ZIP_FILE"
|
||||
95
packages/demo-protobuf/src/decorator.spec.ts
Normal file
95
packages/demo-protobuf/src/decorator.spec.ts
Normal file
@ -0,0 +1,95 @@
|
||||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
import { assert } from "@cosmjs/utils";
|
||||
import { Message } from "protobufjs";
|
||||
|
||||
import { CosmosField, CosmosMessage } from "./decorator";
|
||||
import { Registry } from "./registry";
|
||||
|
||||
describe("decorator demo", () => {
|
||||
it("works with a custom msg", () => {
|
||||
const nestedTypeUrl = "/demo.MsgNestedDemo";
|
||||
const typeUrl = "/demo.MsgDemo";
|
||||
const myRegistry = new Registry();
|
||||
|
||||
@CosmosMessage(myRegistry, nestedTypeUrl)
|
||||
class MsgNestedDemo extends Message<{}> {
|
||||
@CosmosField.String(1)
|
||||
public readonly foo?: string;
|
||||
}
|
||||
|
||||
@CosmosMessage(myRegistry, typeUrl)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
class MsgDemo extends Message<{}> {
|
||||
@CosmosField.Boolean(1)
|
||||
public readonly booleanDemo?: boolean;
|
||||
|
||||
@CosmosField.String(2)
|
||||
public readonly stringDemo?: string;
|
||||
|
||||
@CosmosField.Bytes(3)
|
||||
public readonly bytesDemo?: Uint8Array;
|
||||
|
||||
@CosmosField.Int64(4)
|
||||
public readonly int64Demo?: number;
|
||||
|
||||
@CosmosField.Uint64(5)
|
||||
public readonly uint64Demo?: number;
|
||||
|
||||
@CosmosField.RepeatedString(6)
|
||||
public readonly listDemo?: readonly string[];
|
||||
|
||||
@CosmosField.Nested(7, MsgNestedDemo)
|
||||
public readonly nestedDemo?: MsgNestedDemo;
|
||||
}
|
||||
|
||||
const MsgNestedDemoT = myRegistry.lookupType(nestedTypeUrl)!;
|
||||
const MsgDemoT = myRegistry.lookupType(typeUrl)!;
|
||||
const TxBody = myRegistry.lookupType("/cosmos.tx.TxBody")!;
|
||||
const Any = myRegistry.lookupType("/google.protobuf.Any")!;
|
||||
|
||||
const msgNestedDemoFields = {
|
||||
foo: "bar",
|
||||
};
|
||||
const msgNestedDemo = MsgNestedDemoT.create(msgNestedDemoFields);
|
||||
|
||||
const msgDemoFields = {
|
||||
booleanDemo: true,
|
||||
stringDemo: "example text",
|
||||
bytesDemo: Uint8Array.from([1, 2, 3, 4, 5, 6, 7, 8]),
|
||||
int64Demo: -123,
|
||||
uint64Demo: 123,
|
||||
listDemo: ["this", "is", "a", "list"],
|
||||
nestedDemo: msgNestedDemo,
|
||||
};
|
||||
const msgDemo = MsgDemoT.create(msgDemoFields);
|
||||
const msgDemoBytes = MsgDemoT.encode(msgDemo).finish();
|
||||
const msgDemoWrapped = Any.create({
|
||||
type_url: typeUrl,
|
||||
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);
|
||||
const msg = txBodyDecoded.messages[0];
|
||||
assert(msg.type_url);
|
||||
assert(msg.value);
|
||||
|
||||
const msgDemoDecoded = MsgDemoT.decode(msg.value);
|
||||
expect(msgDemoDecoded.booleanDemo).toEqual(msgDemoFields.booleanDemo);
|
||||
expect(msgDemoDecoded.stringDemo).toEqual(msgDemoFields.stringDemo);
|
||||
// bytesDemo decodes to a Buffer in Node
|
||||
expect(Uint8Array.from(msgDemoDecoded.bytesDemo)).toEqual(msgDemoFields.bytesDemo);
|
||||
// int64Demo and uint64Demo decode to Long in Node
|
||||
expect(Number(msgDemoDecoded.int64Demo)).toEqual(msgDemoFields.int64Demo);
|
||||
expect(Number(msgDemoDecoded.uint64Demo)).toEqual(msgDemoFields.uint64Demo);
|
||||
|
||||
expect(msgDemoDecoded.listDemo).toEqual(msgDemoFields.listDemo);
|
||||
expect(msgDemoDecoded.nestedDemo).toEqual(msgDemoFields.nestedDemo);
|
||||
});
|
||||
});
|
||||
29
packages/demo-protobuf/src/decorator.ts
Normal file
29
packages/demo-protobuf/src/decorator.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { Constructor, Field, Message, TypeDecorator, util } from "protobufjs";
|
||||
|
||||
import { Registry } from "./registry";
|
||||
|
||||
function getTypeName(typeUrl: string): string {
|
||||
const parts = typeUrl.split(".");
|
||||
return parts[parts.length - 1];
|
||||
}
|
||||
|
||||
export function CosmosMessage(registry: Registry, typeUrl: string): TypeDecorator<any> {
|
||||
return (ctor: Constructor<Message<any>>) => {
|
||||
const typeName = getTypeName(typeUrl);
|
||||
const generatedType = util.decorateType(ctor, typeName);
|
||||
registry.register(typeUrl, generatedType);
|
||||
};
|
||||
}
|
||||
|
||||
export const CosmosField = {
|
||||
Boolean: (id: number) => Field.d<boolean>(id, "bool"),
|
||||
|
||||
String: (id: number) => Field.d<string>(id, "string"),
|
||||
Bytes: (id: number) => Field.d<Uint8Array>(id, "bytes"),
|
||||
|
||||
Int64: (id: number) => Field.d<number>(id, "int64"),
|
||||
Uint64: (id: number) => Field.d<number>(id, "uint64"),
|
||||
|
||||
RepeatedString: (id: number) => Field.d<string[]>(id, "string", "repeated"),
|
||||
Nested: (id: number, ctor: Constructor<Message<{}>>) => Field.d(id, ctor),
|
||||
};
|
||||
12
packages/demo-protobuf/src/demo.json
Normal file
12
packages/demo-protobuf/src/demo.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"nested": {
|
||||
"MsgDemo": {
|
||||
"fields": {
|
||||
"example": {
|
||||
"type": "string",
|
||||
"id": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
packages/demo-protobuf/src/demo.proto.ts
Normal file
12
packages/demo-protobuf/src/demo.proto.ts
Normal file
@ -0,0 +1,12 @@
|
||||
// Without this TS infers this is a string literal.
|
||||
// eslint-disable-next-line @typescript-eslint/no-inferrable-types
|
||||
const proto: string = `
|
||||
syntax = "proto3";
|
||||
package demo;
|
||||
|
||||
message MsgDemo {
|
||||
string example = 1;
|
||||
}
|
||||
`;
|
||||
|
||||
export default proto;
|
||||
151
packages/demo-protobuf/src/demo.spec.ts
Normal file
151
packages/demo-protobuf/src/demo.spec.ts
Normal file
@ -0,0 +1,151 @@
|
||||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
import { assert } from "@cosmjs/utils";
|
||||
import protobuf from "protobufjs";
|
||||
|
||||
import reflectionRoot from "./demo";
|
||||
import demoJson from "./demo.json";
|
||||
import demoProto from "./demo.proto";
|
||||
import { cosmos_sdk as cosmosSdk, google } from "./generated/codecimpl";
|
||||
|
||||
type MsgDemo = {
|
||||
readonly example: string;
|
||||
};
|
||||
|
||||
const { Coin } = cosmosSdk.v1;
|
||||
const { TxBody } = cosmosSdk.tx.v1;
|
||||
const { MsgSend } = cosmosSdk.x.bank.v1;
|
||||
const { Any } = google.protobuf;
|
||||
|
||||
function getTypeName(typeUrl: string): string {
|
||||
const parts = typeUrl.split(".");
|
||||
return parts[parts.length - 1];
|
||||
}
|
||||
|
||||
describe("protobuf demo", () => {
|
||||
it("works with generated static code", () => {
|
||||
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],
|
||||
});
|
||||
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();
|
||||
|
||||
// Deserialization
|
||||
const txBodyDecoded = TxBody.decode(txBodyBytes);
|
||||
const msg = txBodyDecoded.messages[0];
|
||||
assert(msg.value);
|
||||
const msgSendDecoded = MsgSend.decode(msg.value);
|
||||
|
||||
// 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 dynamically loaded proto files", () => {
|
||||
const { root } = protobuf.parse(demoProto);
|
||||
const typeUrl = "/demo.MsgDemo";
|
||||
const encoder = root.lookupType(getTypeName(typeUrl));
|
||||
const msgDemo = (encoder.create({
|
||||
example: "Some example text",
|
||||
}) as unknown) as MsgDemo;
|
||||
const msgDemoBytes = encoder.encode(msgDemo).finish();
|
||||
const msgDemoWrapped = Any.create({
|
||||
type_url: typeUrl,
|
||||
value: msgDemoBytes,
|
||||
});
|
||||
const txBody = TxBody.create({
|
||||
messages: [msgDemoWrapped],
|
||||
memo: "Some memo",
|
||||
timeoutHeight: 9999,
|
||||
extensionOptions: [],
|
||||
});
|
||||
const txBodyBytes = TxBody.encode(txBody).finish();
|
||||
|
||||
// Deserialization
|
||||
const txBodyDecoded = TxBody.decode(txBodyBytes);
|
||||
const msg = txBodyDecoded.messages[0];
|
||||
assert(msg.type_url);
|
||||
assert(msg.value);
|
||||
|
||||
const decoder = root.lookupType(getTypeName(msg.type_url));
|
||||
const msgDemoDecoded = (decoder.decode(msg.value) as unknown) as MsgDemo;
|
||||
expect(msgDemoDecoded.example).toEqual(msgDemo.example);
|
||||
});
|
||||
|
||||
it("works with dynamically loaded json files", () => {
|
||||
const root = protobuf.Root.fromJSON(demoJson);
|
||||
const typeUrl = "/demo.MsgDemo";
|
||||
const encoder = root.lookupType(getTypeName(typeUrl));
|
||||
const msgDemo = (encoder.create({
|
||||
example: "Some example text",
|
||||
}) as unknown) as MsgDemo;
|
||||
const msgDemoBytes = encoder.encode(msgDemo).finish();
|
||||
const msgDemoWrapped = Any.create({
|
||||
type_url: typeUrl,
|
||||
value: msgDemoBytes,
|
||||
});
|
||||
const txBody = TxBody.create({
|
||||
messages: [msgDemoWrapped],
|
||||
memo: "Some memo",
|
||||
timeoutHeight: 9999,
|
||||
extensionOptions: [],
|
||||
});
|
||||
const txBodyBytes = TxBody.encode(txBody).finish();
|
||||
|
||||
// Deserialization
|
||||
const txBodyDecoded = TxBody.decode(txBodyBytes);
|
||||
const msg = txBodyDecoded.messages[0];
|
||||
assert(msg.type_url);
|
||||
assert(msg.value);
|
||||
|
||||
const decoder = root.lookupType(getTypeName(msg.type_url));
|
||||
const msgDemoDecoded = (decoder.decode(msg.value) as unknown) as MsgDemo;
|
||||
expect(msgDemoDecoded.example).toEqual(msgDemo.example);
|
||||
});
|
||||
|
||||
it("works with reflection", () => {
|
||||
const typeUrl = "/demo.MsgDemo";
|
||||
const encoder = reflectionRoot.lookupType(getTypeName(typeUrl));
|
||||
const msgDemo = (encoder.create({
|
||||
example: "Some example text",
|
||||
}) as unknown) as MsgDemo;
|
||||
const msgDemoBytes = encoder.encode(msgDemo).finish();
|
||||
const msgDemoWrapped = Any.create({
|
||||
type_url: typeUrl,
|
||||
value: msgDemoBytes,
|
||||
});
|
||||
const txBody = TxBody.create({
|
||||
messages: [msgDemoWrapped],
|
||||
memo: "Some memo",
|
||||
timeoutHeight: 9999,
|
||||
extensionOptions: [],
|
||||
});
|
||||
const txBodyBytes = TxBody.encode(txBody).finish();
|
||||
|
||||
// Deserialization
|
||||
const txBodyDecoded = TxBody.decode(txBodyBytes);
|
||||
const msg = txBodyDecoded.messages[0];
|
||||
assert(msg.type_url);
|
||||
assert(msg.value);
|
||||
|
||||
const decoder = reflectionRoot.lookupType(getTypeName(msg.type_url));
|
||||
const msgDemoDecoded = (decoder.decode(msg.value) as unknown) as MsgDemo;
|
||||
expect(msgDemoDecoded.example).toEqual(msgDemo.example);
|
||||
});
|
||||
});
|
||||
7
packages/demo-protobuf/src/demo.ts
Normal file
7
packages/demo-protobuf/src/demo.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { Field, Root, Type } from "protobufjs";
|
||||
|
||||
export const MsgDemo = new Type("MsgDemo").add(new Field("example", 1, "string"));
|
||||
|
||||
const root = new Root().define("demo").add(MsgDemo);
|
||||
|
||||
export default root;
|
||||
4699
packages/demo-protobuf/src/generated/codecimpl.d.ts
vendored
Normal file
4699
packages/demo-protobuf/src/generated/codecimpl.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3791
packages/demo-protobuf/src/generated/codecimpl.js
Normal file
3791
packages/demo-protobuf/src/generated/codecimpl.js
Normal file
File diff suppressed because it is too large
Load Diff
88
packages/demo-protobuf/src/registry.spec.ts
Normal file
88
packages/demo-protobuf/src/registry.spec.ts
Normal file
@ -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);
|
||||
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);
|
||||
|
||||
// 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",
|
||||
});
|
||||
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: 9999,
|
||||
extensionOptions: [],
|
||||
});
|
||||
const txBodyBytes = TxBody.encode(txBody).finish();
|
||||
|
||||
const txBodyDecoded = TxBody.decode(txBodyBytes);
|
||||
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);
|
||||
expect(msgDemoDecoded.example).toEqual(msgDemo.example);
|
||||
});
|
||||
});
|
||||
31
packages/demo-protobuf/src/registry.ts
Normal file
31
packages/demo-protobuf/src/registry.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import protobuf from "protobufjs";
|
||||
|
||||
import { cosmos_sdk as cosmosSdk, google } from "./generated/codecimpl";
|
||||
|
||||
export interface GeneratedType {
|
||||
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 class Registry {
|
||||
private readonly types: Map<string, GeneratedType>;
|
||||
|
||||
constructor(customTypes: Iterable<[string, GeneratedType]> = []) {
|
||||
this.types = new Map<string, GeneratedType>([
|
||||
["/cosmos.Coin", cosmosSdk.v1.Coin],
|
||||
["/cosmos.bank.MsgSend", cosmosSdk.x.bank.v1.MsgSend],
|
||||
["/cosmos.tx.TxBody", cosmosSdk.tx.v1.TxBody],
|
||||
["/google.protobuf.Any", google.protobuf.Any],
|
||||
...customTypes,
|
||||
]);
|
||||
}
|
||||
|
||||
public register(name: string, type: GeneratedType): void {
|
||||
this.types.set(name, type);
|
||||
}
|
||||
|
||||
public lookupType(name: string): GeneratedType | undefined {
|
||||
return this.types.get(name);
|
||||
}
|
||||
}
|
||||
11
packages/demo-protobuf/tsconfig.json
Normal file
11
packages/demo-protobuf/tsconfig.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"outDir": "build",
|
||||
"declarationDir": "build/types",
|
||||
"experimentalDecorators": true,
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
14
packages/demo-protobuf/typedoc.js
Normal file
14
packages/demo-protobuf/typedoc.js
Normal file
@ -0,0 +1,14 @@
|
||||
const packageJson = require("./package.json");
|
||||
|
||||
module.exports = {
|
||||
src: ["./src"],
|
||||
out: "docs",
|
||||
exclude: "**/*.spec.ts",
|
||||
target: "es6",
|
||||
name: `${packageJson.name} Documentation`,
|
||||
readme: "README.md",
|
||||
mode: "file",
|
||||
excludeExternals: true,
|
||||
excludeNotExported: true,
|
||||
excludePrivate: true,
|
||||
};
|
||||
12
packages/demo-protobuf/types/decorator.d.ts
vendored
Normal file
12
packages/demo-protobuf/types/decorator.d.ts
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
import { Constructor, Message, TypeDecorator } from "protobufjs";
|
||||
import { Registry } from "./registry";
|
||||
export declare function CosmosMessage(registry: Registry, typeUrl: string): TypeDecorator<any>;
|
||||
export declare const CosmosField: {
|
||||
Boolean: (id: number) => import("protobufjs").FieldDecorator;
|
||||
String: (id: number) => import("protobufjs").FieldDecorator;
|
||||
Bytes: (id: number) => import("protobufjs").FieldDecorator;
|
||||
Int64: (id: number) => import("protobufjs").FieldDecorator;
|
||||
Uint64: (id: number) => import("protobufjs").FieldDecorator;
|
||||
RepeatedString: (id: number) => import("protobufjs").FieldDecorator;
|
||||
Nested: (id: number, ctor: Constructor<Message<{}>>) => import("protobufjs").FieldDecorator;
|
||||
};
|
||||
4
packages/demo-protobuf/types/demo.d.ts
vendored
Normal file
4
packages/demo-protobuf/types/demo.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
import { Type } from "protobufjs";
|
||||
export declare const MsgDemo: Type;
|
||||
declare const root: import("protobufjs").Namespace;
|
||||
export default root;
|
||||
2
packages/demo-protobuf/types/demo.proto.d.ts
vendored
Normal file
2
packages/demo-protobuf/types/demo.proto.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
declare const proto: string;
|
||||
export default proto;
|
||||
4699
packages/demo-protobuf/types/generated/codecimpl.d.ts
vendored
Normal file
4699
packages/demo-protobuf/types/generated/codecimpl.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
19
packages/demo-protobuf/types/registry.d.ts
vendored
Normal file
19
packages/demo-protobuf/types/registry.d.ts
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
import protobuf from "protobufjs";
|
||||
export interface GeneratedType {
|
||||
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 declare class Registry {
|
||||
private readonly types;
|
||||
constructor(customTypes?: Iterable<[string, GeneratedType]>);
|
||||
register(name: string, type: GeneratedType): void;
|
||||
lookupType(name: string): GeneratedType | undefined;
|
||||
}
|
||||
19
packages/demo-protobuf/webpack.web.config.js
Normal file
19
packages/demo-protobuf/webpack.web.config.js
Normal file
@ -0,0 +1,19 @@
|
||||
const glob = require("glob");
|
||||
const path = require("path");
|
||||
const webpack = require("webpack");
|
||||
|
||||
const target = "web";
|
||||
const distdir = path.join(__dirname, "dist", "web");
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
// bundle used for Karma tests
|
||||
target: target,
|
||||
entry: glob.sync("./build/**/*.spec.js"),
|
||||
output: {
|
||||
path: distdir,
|
||||
filename: "tests.js",
|
||||
},
|
||||
plugins: [new webpack.EnvironmentPlugin(["WASMD_ENABLED"])],
|
||||
},
|
||||
];
|
||||
87
yarn.lock
87
yarn.lock
@ -890,6 +890,59 @@
|
||||
dependencies:
|
||||
"@types/node" ">= 8"
|
||||
|
||||
"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf"
|
||||
integrity sha1-m4sMxmPWaafY9vXQiToU00jzD78=
|
||||
|
||||
"@protobufjs/base64@^1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735"
|
||||
integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==
|
||||
|
||||
"@protobufjs/codegen@^2.0.4":
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb"
|
||||
integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==
|
||||
|
||||
"@protobufjs/eventemitter@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70"
|
||||
integrity sha1-NVy8mLr61ZePntCV85diHx0Ga3A=
|
||||
|
||||
"@protobufjs/fetch@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45"
|
||||
integrity sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=
|
||||
dependencies:
|
||||
"@protobufjs/aspromise" "^1.1.1"
|
||||
"@protobufjs/inquire" "^1.1.0"
|
||||
|
||||
"@protobufjs/float@^1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1"
|
||||
integrity sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=
|
||||
|
||||
"@protobufjs/inquire@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089"
|
||||
integrity sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=
|
||||
|
||||
"@protobufjs/path@^1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d"
|
||||
integrity sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=
|
||||
|
||||
"@protobufjs/pool@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54"
|
||||
integrity sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=
|
||||
|
||||
"@protobufjs/utf8@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
|
||||
integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=
|
||||
|
||||
"@types/accepts@*":
|
||||
version "1.3.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/accepts/-/accepts-1.3.5.tgz#c34bec115cfc746e04fe5a059df4ce7e7b391575"
|
||||
@ -1057,6 +1110,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/libsodium-wrappers/-/libsodium-wrappers-0.7.7.tgz#cdb25e85458612ec80f0157c3815fac187d0b6d2"
|
||||
integrity sha512-Li91pVKcLvQJK3ZolwCPo85oxf2gKBCApgnesRxYg4OVYchLXcJB2eivX8S87vfQVv6ZRnyCO1lLDosZGJfpRg==
|
||||
|
||||
"@types/long@^4.0.1":
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9"
|
||||
integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==
|
||||
|
||||
"@types/mime@*":
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d"
|
||||
@ -1077,6 +1135,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.6.tgz#df929d1bb2eee5afdda598a41930fe50b43eaa6a"
|
||||
integrity sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==
|
||||
|
||||
"@types/node@^13.7.0":
|
||||
version "13.13.12"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.12.tgz#9c72e865380a7dc99999ea0ef20fc9635b503d20"
|
||||
integrity sha512-zWz/8NEPxoXNT9YyF2osqyA9WjssZukYpgI4UYZpOjcyqwIUqWGkcCionaEb9Ki+FULyPyvNFpg/329Kd2/pbw==
|
||||
|
||||
"@types/pako@^1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/pako/-/pako-1.0.1.tgz#33b237f3c9aff44d0f82fe63acffa4a365ef4a61"
|
||||
@ -5038,6 +5101,11 @@ log4js@^6.2.1:
|
||||
rfdc "^1.1.4"
|
||||
streamroller "^2.2.4"
|
||||
|
||||
long@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28"
|
||||
integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==
|
||||
|
||||
loud-rejection@^1.0.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
|
||||
@ -6186,6 +6254,25 @@ proto-list@~1.2.1:
|
||||
resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
|
||||
integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=
|
||||
|
||||
protobufjs@~6.9.0:
|
||||
version "6.9.0"
|
||||
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.9.0.tgz#c08b2bf636682598e6fabbf0edb0b1256ff090bd"
|
||||
integrity sha512-LlGVfEWDXoI/STstRDdZZKb/qusoAWUnmLg9R8OLSO473mBLWHowx8clbX5/+mKDEI+v7GzjoK9tRPZMMcoTrg==
|
||||
dependencies:
|
||||
"@protobufjs/aspromise" "^1.1.2"
|
||||
"@protobufjs/base64" "^1.1.2"
|
||||
"@protobufjs/codegen" "^2.0.4"
|
||||
"@protobufjs/eventemitter" "^1.1.0"
|
||||
"@protobufjs/fetch" "^1.1.0"
|
||||
"@protobufjs/float" "^1.0.2"
|
||||
"@protobufjs/inquire" "^1.1.0"
|
||||
"@protobufjs/path" "^1.1.2"
|
||||
"@protobufjs/pool" "^1.1.0"
|
||||
"@protobufjs/utf8" "^1.1.0"
|
||||
"@types/long" "^4.0.1"
|
||||
"@types/node" "^13.7.0"
|
||||
long "^4.0.0"
|
||||
|
||||
protocols@^1.1.0, protocols@^1.4.0:
|
||||
version "1.4.7"
|
||||
resolved "https://registry.yarnpkg.com/protocols/-/protocols-1.4.7.tgz#95f788a4f0e979b291ffefcf5636ad113d037d32"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user