Add support for multisig in encodeAminoPubkey

This commit is contained in:
Simon Warta 2021-03-22 13:02:29 +01:00
parent 61aa989fb3
commit 99e1ac36b8
3 changed files with 69 additions and 2 deletions

View File

@ -7,7 +7,7 @@ import {
encodeBech32Pubkey,
encodeSecp256k1Pubkey,
} from "./encoding";
import { Pubkey } from "./pubkeys";
import { MultisigThresholdPubkey, Pubkey } from "./pubkeys";
describe("encoding", () => {
describe("encodeSecp256k1Pubkey", () => {
@ -135,5 +135,50 @@ describe("encoding", () => {
"coralvalconspub1zcjduepqvxg72ccnl9r65fv0wn3amlk4sfzqfe2k36l073kjx2qyaf6sk23qw7j8wq",
);
});
it("works for multisig", () => {
// ./build/wasmd keys add test1
// ./build/wasmd keys add test2
// ./build/wasmd keys add test3
// ./build/wasmd keys add testgroup1 --multisig=test1,test2,test3 --multisig-threshold 2
// ./build/wasmd keys add testgroup2 --multisig=test1,test2,test3 --multisig-threshold 1
// ./build/wasmd keys add testgroup3 --multisig=test3,test1 --multisig-threshold 2
const test1 = decodeBech32Pubkey(
"wasmpub1addwnpepqwxttx8w2sfs6d8cuzqcuau84grp8xsw95qzdjkmvc44tnckskdxw3zw2km",
);
const test2 = decodeBech32Pubkey(
"wasmpub1addwnpepq2gx7x7e29kge5a4ycunytyqr0u8ynql5h583s8r9wdads9m3v8ks6y0nhc",
);
const test3 = decodeBech32Pubkey(
"wasmpub1addwnpepq0xfx5vavxmgdkn0p6x0l9p3udttghu3qcldd7ql08wa3xy93qq0xuzvtxc",
);
// 2/3 multisig
const testgroup1: MultisigThresholdPubkey = {
type: "tendermint/PubKeyMultisigThreshold",
value: {
threshold: "2",
pubkeys: [test1, test2, test3],
},
};
const expected1 = Bech32.decode(
"wasmpub1ytql0csgqgfzd666axrjzquvkkvwu4qnp5603cyp3emc02sxzwdqutgqym9dke3t2h83dpv6vufzd666axrjzq5sdudaj5tv3nfm2f3exgkgqxlcwfxplf0g0rqwx2um6mqthzc0dqfzd666axrjzq7vjdge6cdksmdx7r5vl72rrc6kk30ezp376mup77wamzvgtzqq7v7aysdd",
).data;
expect(encodeAminoPubkey(testgroup1)).toEqual(expected1);
// 1/3 multisig
const testgroup2: MultisigThresholdPubkey = {
type: "tendermint/PubKeyMultisigThreshold",
value: {
threshold: "1",
pubkeys: [test1, test2, test3],
},
};
const expected2 = Bech32.decode(
"wasmpub1ytql0csgqyfzd666axrjzquvkkvwu4qnp5603cyp3emc02sxzwdqutgqym9dke3t2h83dpv6vufzd666axrjzq5sdudaj5tv3nfm2f3exgkgqxlcwfxplf0g0rqwx2um6mqthzc0dqfzd666axrjzq7vjdge6cdksmdx7r5vl72rrc6kk30ezp376mup77wamzvgtzqq7vc4ejke",
).data;
expect(encodeAminoPubkey(testgroup2)).toEqual(expected2);
});
});
});

View File

@ -1,7 +1,8 @@
import { Bech32, fromBase64, fromHex, toBase64, toHex } from "@cosmjs/encoding";
import { Uint53 } from "@cosmjs/math";
import { arrayContentStartsWith } from "@cosmjs/utils";
import { Pubkey, pubkeyType, Secp256k1Pubkey } from "./pubkeys";
import { isMultisigThresholdPubkey, Pubkey, pubkeyType, Secp256k1Pubkey } from "./pubkeys";
export function encodeSecp256k1Pubkey(pubkey: Uint8Array): Secp256k1Pubkey {
if (pubkey.length !== 33 || (pubkey[0] !== 0x02 && pubkey[0] !== 0x03)) {
@ -19,6 +20,8 @@ export function encodeSecp256k1Pubkey(pubkey: Uint8Array): Secp256k1Pubkey {
const pubkeyAminoPrefixSecp256k1 = fromHex("eb5ae987" + "21" /* fixed length */);
const pubkeyAminoPrefixEd25519 = fromHex("1624de64" + "20" /* fixed length */);
const pubkeyAminoPrefixSr25519 = fromHex("0dfb1005" + "20" /* fixed length */);
/** See https://github.com/tendermint/tendermint/commit/38b401657e4ad7a7eeb3c30a3cbf512037df3740 */
const pubkeyAminoPrefixMultisigThreshold = fromHex("22c1f7e2" /* variable length not included */);
/**
* Decodes a pubkey in the Amino binary format to a type/value object.
@ -67,10 +70,28 @@ export function decodeBech32Pubkey(bechEncoded: string): Pubkey {
return decodeAminoPubkey(data);
}
function encodeSmallUint(value: number | string): number[] {
const checked = Uint53.fromString(value.toString()).toNumber();
if (checked > 127) throw new Error("Encoding numbers > 127 is not supported here.");
return [checked];
}
/**
* Encodes a public key to binary Amino.
*/
export function encodeAminoPubkey(pubkey: Pubkey): Uint8Array {
if (isMultisigThresholdPubkey(pubkey)) {
const out = Array.from(pubkeyAminoPrefixMultisigThreshold);
out.push(8); // TODO: What is this?
out.push(...encodeSmallUint(pubkey.value.threshold));
for (const pubkeyData of pubkey.value.pubkeys.map((p) => encodeAminoPubkey(p))) {
out.push(18); // TODO: What is this?
out.push(...encodeSmallUint(pubkeyData.length));
out.push(...pubkeyData);
}
return new Uint8Array(out);
}
let aminoPrefix: Uint8Array;
switch (pubkey.type) {
// Note: please don't add cases here without writing additional unit tests

View File

@ -18,6 +18,7 @@ export const pubkeyType = {
ed25519: "tendermint/PubKeyEd25519" as const,
/** @see https://github.com/tendermint/tendermint/blob/v0.33.0/crypto/sr25519/codec.go#L12 */
sr25519: "tendermint/PubKeySr25519" as const,
multisigThreshold: "tendermint/PubKeyMultisigThreshold" as const,
};
/**