Merge pull request #340 from CosmWasm/335-bech32-encode-90-chars

Allow Bech32.decode to decode long addresses
This commit is contained in:
Simon Warta 2020-08-04 23:14:17 +02:00 committed by GitHub
commit 4c5c12e1c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 11 deletions

View File

@ -6,6 +6,9 @@
- @cosmjs/cosmwasm: Rename `SigningCosmWasmClient.signAndPost` method to
`.signAndBroadcast`.
- @cosmjs/demo-staking: Remove package and supporting scripts.
- @cosmjs/encoding: Add `limit` parameter to `Bech32.encode` and `.decode`. The
new default limit for decoding is infinity (was 90 before). Set it to 90 to
create a strict decoder.
- @cosmjs/launchpad: Rename `CosmosClient.postTx` method to `.broadcastTx`.
- @cosmjs/launchpad: Rename `SigningCosmosClient.signAndPost` method to
`.signAndBroadcast`.

View File

@ -6,14 +6,69 @@ describe("Bech32", () => {
// bech32 -e -h eth 9d4e856e572e442f0a4b2763e72d08a0e99d8ded
const ethAddressRaw = fromHex("9d4e856e572e442f0a4b2763e72d08a0e99d8ded");
it("encodes", () => {
expect(Bech32.encode("eth", ethAddressRaw)).toEqual("eth1n48g2mjh9ezz7zjtya37wtgg5r5emr0drkwlgw");
describe("encode", () => {
it("works", () => {
expect(Bech32.encode("eth", ethAddressRaw)).toEqual("eth1n48g2mjh9ezz7zjtya37wtgg5r5emr0drkwlgw");
});
it("works for very short data", () => {
expect(() => Bech32.encode("eth", new Uint8Array(1))).not.toThrow();
});
it("works for very long prefixes", () => {
expect(() => Bech32.encode("p".repeat(70), new Uint8Array(20))).toThrowError(/exceeds length limit/i);
});
// See https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#Bech32
it("works if result is 90 characters", () => {
const result = Bech32.encode("eth", new Uint8Array(50));
expect(result.length).toEqual(90);
});
it("throws if result exceeds 90 characters", () => {
expect(() => Bech32.encode("eth", new Uint8Array(51))).toThrowError(/exceeds length limit/i);
});
it("works if a limit parameter is provided", () => {
const limit = 1024;
const result = Bech32.encode("eth", new Uint8Array(51), limit);
expect(result).toEqual(
"eth1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqug55er",
);
expect(result.length).toBeGreaterThan(90);
});
it("throws if result exceeds the provided limit parameter", () => {
const limit = 10;
expect(() => Bech32.encode("eth", ethAddressRaw, limit)).toThrowError(/exceeds length limit/i);
});
});
it("decodes", () => {
expect(Bech32.decode("eth1n48g2mjh9ezz7zjtya37wtgg5r5emr0drkwlgw")).toEqual({
prefix: "eth",
data: ethAddressRaw,
describe("decode", () => {
it("works", () => {
expect(Bech32.decode("eth1n48g2mjh9ezz7zjtya37wtgg5r5emr0drkwlgw")).toEqual({
prefix: "eth",
data: ethAddressRaw,
});
});
it("works for addresses which exceed the specification limit of 90 characters", () => {
// Example from https://github.com/cosmos/cosmos-sdk/pull/6237#issuecomment-658116534
expect(() =>
Bech32.decode(
"cosmospub1ytql0csgqvfzd666axrjzqmn5q2ucztcyxw8hvlzen94ay05tegaerkug5pn3xn8wqdymt598ufzd666axrjzqsxllmwacap3f6xyc4x30jl8ecrcs2tze3zzgxkmthcsqxnqxhwwgfzd666axrjzqs2rlu3wz5gnslgpprszjr8r65n0d6y39q657th77eyvengtk3z0y6h2pnk",
),
).not.toThrow();
});
it("throws for addresses which exceed the specification limit of 90 characters if a limit is specified", () => {
// Example from https://github.com/cosmos/cosmos-sdk/pull/6237#issuecomment-658116534
expect(() =>
Bech32.decode(
"cosmospub1ytql0csgqvfzd666axrjzqmn5q2ucztcyxw8hvlzen94ay05tegaerkug5pn3xn8wqdymt598ufzd666axrjzqsxllmwacap3f6xyc4x30jl8ecrcs2tze3zzgxkmthcsqxnqxhwwgfzd666axrjzqs2rlu3wz5gnslgpprszjr8r65n0d6y39q657th77eyvengtk3z0y6h2pnk",
90,
),
).toThrowError(/exceeds length limit/i);
});
});
});

View File

@ -1,13 +1,16 @@
import * as bech32 from "bech32";
export class Bech32 {
public static encode(prefix: string, data: Uint8Array): string {
const address = bech32.encode(prefix, bech32.toWords(data));
public static encode(prefix: string, data: Uint8Array, limit?: number): string {
const address = bech32.encode(prefix, bech32.toWords(data), limit);
return address;
}
public static decode(address: string): { readonly prefix: string; readonly data: Uint8Array } {
const decodedAddress = bech32.decode(address);
public static decode(
address: string,
limit = Infinity,
): { readonly prefix: string; readonly data: Uint8Array } {
const decodedAddress = bech32.decode(address, limit);
return {
prefix: decodedAddress.prefix,
data: new Uint8Array(bech32.fromWords(decodedAddress.words)),

View File

@ -1,7 +1,8 @@
export declare class Bech32 {
static encode(prefix: string, data: Uint8Array): string;
static encode(prefix: string, data: Uint8Array, limit?: number): string;
static decode(
address: string,
limit?: number,
): {
readonly prefix: string;
readonly data: Uint8Array;