Merge pull request #694 from cosmos/remove-unused

Remove unused modules from proto-signing
This commit is contained in:
Will Clark 2021-02-24 15:30:36 +01:00 committed by GitHub
commit e46db075f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 0 additions and 481 deletions

View File

@ -1,239 +0,0 @@
import { fromHex } from "@cosmjs/encoding";
import Long from "long";
import { parse } from "protobufjs";
import { omitDefault, omitDefaults } from "./adr27";
describe("adr27", () => {
describe("omitDefault", () => {
it("works for strings", () => {
expect(omitDefault("abc")).toEqual("abc");
expect(omitDefault("")).toEqual(null);
});
it("works for bytes", () => {
expect(omitDefault(fromHex("ab"))).toEqual(fromHex("ab"));
expect(omitDefault(fromHex(""))).toEqual(null);
});
it("works for integers", () => {
expect(omitDefault(123)).toEqual(123);
expect(omitDefault(0)).toEqual(null);
});
it("works for floats", () => {
expect(omitDefault(1.234)).toEqual(1.234);
expect(omitDefault(0.0)).toEqual(null);
});
it("works for Long", () => {
// unsigned
expect(omitDefault(Long.fromNumber(123, true))).toEqual(Long.fromNumber(123, true));
expect(omitDefault(Long.fromNumber(0, true))).toEqual(null);
// signed
expect(omitDefault(Long.fromNumber(123, false))).toEqual(Long.fromNumber(123, false));
expect(omitDefault(Long.fromNumber(0, false))).toEqual(null);
});
it("works for booleans", () => {
expect(omitDefault(true)).toEqual(true);
expect(omitDefault(false)).toEqual(null);
});
it("works for repeated", () => {
expect(omitDefault(["a", "b", "c"])).toEqual(["a", "b", "c"]);
expect(omitDefault([])).toEqual(null);
});
it("works for enums", () => {
const proto = `
package blog;
syntax = "proto3";
enum Review {
UNSPECIFIED = 0;
ACCEPTED = 1;
REJECTED = 2;
};
`;
// eslint-disable-next-line @typescript-eslint/naming-convention
const Review = parse(proto).root.lookupEnum("blog.Review");
expect(omitDefault(Review.values["ACCEPTED"])).toEqual(Review.values["ACCEPTED"]);
expect(omitDefault(Review.values["UNSPECIFIED"])).toEqual(null);
});
it("works for unset", () => {
// null and undefined both represent unset in protobuf.js serialization
expect(omitDefault(undefined)).toEqual(null);
expect(omitDefault(null)).toEqual(null);
});
});
describe("omitDefaults", () => {
it("works for scalars", () => {
expect(omitDefaults("abc")).toEqual("abc");
expect(omitDefaults("")).toEqual(null);
expect(omitDefaults(fromHex("ab"))).toEqual(fromHex("ab"));
expect(omitDefaults(fromHex(""))).toEqual(null);
expect(omitDefaults(123)).toEqual(123);
expect(omitDefaults(0)).toEqual(null);
expect(omitDefaults(1.234)).toEqual(1.234);
expect(omitDefaults(0.0)).toEqual(null);
expect(omitDefaults(Long.fromNumber(123, true))).toEqual(Long.fromNumber(123, true));
expect(omitDefaults(Long.fromNumber(0, true))).toEqual(null);
expect(omitDefaults(Long.fromNumber(123, false))).toEqual(Long.fromNumber(123, false));
expect(omitDefaults(Long.fromNumber(0, false))).toEqual(null);
expect(omitDefaults(true)).toEqual(true);
expect(omitDefaults(false)).toEqual(null);
});
it("works for repeated", () => {
expect(omitDefaults(["a", "b", "c"])).toEqual(["a", "b", "c"]);
expect(omitDefaults([])).toEqual(null);
});
it("works for enums", () => {
const proto = `
package blog;
syntax = "proto3";
enum Review {
UNSPECIFIED = 0;
ACCEPTED = 1;
REJECTED = 2;
};
`;
// eslint-disable-next-line @typescript-eslint/naming-convention
const Review = parse(proto).root.lookupEnum("blog.Review");
expect(omitDefaults(Review.values["ACCEPTED"])).toEqual(Review.values["ACCEPTED"]);
expect(omitDefaults(Review.values["UNSPECIFIED"])).toEqual(null);
});
it("works for unset", () => {
// null and undefined both represent unset in protobuf.js serialization
expect(omitDefaults(undefined)).toEqual(null);
expect(omitDefaults(null)).toEqual(null);
});
it("works for objects", () => {
// empty
expect(omitDefaults({})).toEqual({});
// simple
expect(
omitDefaults({
a: "foo",
b: "",
c: 100,
d: 0,
}),
).toEqual({
a: "foo",
b: null,
c: 100,
d: null,
});
// nested
expect(
omitDefaults({
a: {
x: "foo",
y: "",
},
b: {
x: {
o: 1.2,
p: false,
q: 0,
},
},
}),
).toEqual({
a: {
x: "foo",
y: null,
},
b: {
x: {
o: 1.2,
p: null,
q: null,
},
},
});
});
it("can be used to reproduce ADR 027 test vector", () => {
const proto = `
// Article.proto
package blog;
syntax = "proto3";
enum Type {
UNSPECIFIED = 0;
IMAGES = 1;
NEWS = 2;
};
enum Review {
UNSPECIFIED = 0;
ACCEPTED = 1;
REJECTED = 2;
};
message Article {
string title = 1;
string description = 2;
uint64 created = 3;
uint64 updated = 4;
bool public = 5;
bool promoted = 6;
Type type = 7;
Review review = 8;
repeated string comments = 9;
repeated string backlinks = 10;
};
`;
const root = parse(proto).root;
// eslint-disable-next-line @typescript-eslint/naming-convention
const Article = root.lookupType("blog.Article");
// eslint-disable-next-line @typescript-eslint/naming-convention
const Type = root.lookupEnum("blog.Type");
// eslint-disable-next-line @typescript-eslint/naming-convention
const Review = root.lookupEnum("blog.Review");
const expected = fromHex(
"0a1654686520776f726c64206e65656473206368616e676518e8bebec8bc2e280138024a084e696365206f6e654a095468616e6b20796f75",
);
const serialization = Uint8Array.from(
Article.encode(
omitDefaults({
title: "The world needs change",
description: "",
created: 1596806111080,
updated: 0,
public: true,
promoted: false,
type: Type.values["NEWS"],
review: Review.values["UNSPECIFIED"],
comments: ["Nice one", "Thank you"],
backlinks: [],
}),
).finish(),
);
expect(serialization).toEqual(expected);
});
});
});

View File

@ -1,60 +0,0 @@
import { isNonNullObject, isUint8Array } from "@cosmjs/utils";
import Long from "long";
/**
* Converts default values to null in order to tell protobuf.js
* to not serialize them.
*
* @see https://github.com/cosmos/cosmos-sdk/pull/6979
*/
export function omitDefault<T>(input: T): T | null {
if (input === undefined || input === null) return null;
if (typeof input === "number" || typeof input === "boolean" || typeof input === "string") {
return input || null;
}
if (Long.isLong(input)) {
return !input.isZero() ? input : null;
}
if (Array.isArray(input) || isUint8Array(input)) {
return input.length ? input : null;
}
throw new Error("Input type not supported");
}
/**
* Walks through a potentially nested object and calls omitDefault on each element.
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function omitDefaults(input: any): any {
// Unset
if (input === undefined || input === null) return null;
// Protobuf element
if (
typeof input === "number" ||
typeof input === "boolean" ||
typeof input === "string" ||
Long.isLong(input) ||
Array.isArray(input) ||
isUint8Array(input)
) {
return omitDefault(input);
}
// Object
if (isNonNullObject(input)) {
return Object.entries(input).reduce(
(accumulator, [key, value]) => ({
...accumulator,
[key]: omitDefaults(value),
}),
{},
);
}
throw new Error(`Input type not supported: ${typeof input}`);
}

View File

@ -1,12 +0,0 @@
{
"nested": {
"MsgDemo": {
"fields": {
"example": {
"type": "string",
"id": 1
}
}
}
}
}

View File

@ -1,12 +0,0 @@
// 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;

View File

@ -1,150 +0,0 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { assert } from "@cosmjs/utils";
import Long from "long";
import protobuf from "protobufjs";
import { MsgSend } from "./codec/cosmos/bank/v1beta1/tx";
import { Coin } from "./codec/cosmos/base/v1beta1/coin";
import { TxBody } from "./codec/cosmos/tx/v1beta1/tx";
import { Any } from "./codec/google/protobuf/any";
import reflectionRoot from "./demo";
import demoJson from "./demo.json";
import demoProto from "./demo.proto";
type MsgDemo = {
readonly example: string;
};
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.fromPartial({
denom: "ucosm",
amount: "1234567890",
});
const msgSend = MsgSend.fromPartial({
fromAddress: "cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6",
toAddress: "cosmos1qypqxpq9qcrsszg2pvxq6rs0zqg3yyc5lzv7xu",
amount: [coin],
});
const msgSendBytes = MsgSend.encode(msgSend).finish();
const msgSendWrapped = Any.fromPartial({
typeUrl: "/cosmos.bank.v1beta1.MsgSend",
value: msgSendBytes,
});
const txBody = TxBody.fromPartial({
messages: [msgSendWrapped],
memo: "Some memo",
timeoutHeight: Long.fromNumber(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(msgSendDecoded.fromAddress).toEqual(msgSend.fromAddress);
expect(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.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();
// Deserialization
const txBodyDecoded = TxBody.decode(txBodyBytes);
const msg = txBodyDecoded.messages[0];
assert(msg.typeUrl);
assert(msg.value);
const decoder = root.lookupType(getTypeName(msg.typeUrl));
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.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();
// Deserialization
const txBodyDecoded = TxBody.decode(txBodyBytes);
const msg = txBodyDecoded.messages[0];
assert(msg.typeUrl);
assert(msg.value);
const decoder = root.lookupType(getTypeName(msg.typeUrl));
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.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();
// Deserialization
const txBodyDecoded = TxBody.decode(txBodyBytes);
const msg = txBodyDecoded.messages[0];
assert(msg.typeUrl);
assert(msg.value);
const decoder = reflectionRoot.lookupType(getTypeName(msg.typeUrl));
const msgDemoDecoded = (decoder.decode(msg.value) as unknown) as MsgDemo;
expect(msgDemoDecoded.example).toEqual(msgDemo.example);
});
});

View File

@ -1,8 +0,0 @@
/* eslint-disable @typescript-eslint/naming-convention */
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;