Create createMultisigThresholdPubkey
This commit is contained in:
parent
1a533fc24d
commit
7255af4186
@ -7,7 +7,17 @@ import {
|
||||
encodeBech32Pubkey,
|
||||
encodeSecp256k1Pubkey,
|
||||
} from "./encoding";
|
||||
import { MultisigThresholdPubkey, Pubkey } from "./pubkeys";
|
||||
import { Pubkey } from "./pubkeys";
|
||||
import {
|
||||
testgroup1,
|
||||
testgroup1Address,
|
||||
testgroup2,
|
||||
testgroup2Address,
|
||||
testgroup3,
|
||||
testgroup3Address,
|
||||
testgroup4,
|
||||
testgroup4Address,
|
||||
} from "./testutils.spec";
|
||||
|
||||
describe("encoding", () => {
|
||||
describe("encodeSecp256k1Pubkey", () => {
|
||||
@ -137,84 +147,16 @@ describe("encoding", () => {
|
||||
});
|
||||
|
||||
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
|
||||
// # By default pubkeys are sorted by its address data (https://github.com/cosmos/cosmos-sdk/blob/v0.42.2/client/keys/add.go#L172-L174)
|
||||
// ./build/wasmd keys add testgroup3 --multisig=test3,test1 --multisig-threshold 2
|
||||
// ./build/wasmd keys add testgroup4 --multisig=test3,test1 --nosort --multisig-threshold 2
|
||||
|
||||
const test1 = decodeBech32Pubkey(
|
||||
"wasmpub1addwnpepqwxttx8w2sfs6d8cuzqcuau84grp8xsw95qzdjkmvc44tnckskdxw3zw2km",
|
||||
// pubkey data: eb5ae98721038cb598ee54130d34f8e0818e7787aa06139a0e2d0026cadb662b55cf16859a67
|
||||
// address: wasm1jq59w7y34msq69g4w3zvq6d5h3stcajd8g62xm
|
||||
// address data: 9028577891aee00d15157444c069b4bc60bc764d
|
||||
);
|
||||
const test2 = decodeBech32Pubkey(
|
||||
"wasmpub1addwnpepq2gx7x7e29kge5a4ycunytyqr0u8ynql5h583s8r9wdads9m3v8ks6y0nhc",
|
||||
// pubkey data: eb5ae9872102906f1bd9516c8cd3b52639322c801bf8724c1fa5e878c0e32b9bd6c0bb8b0f68
|
||||
// address: wasm146e52j6zphxw8m67cz8860ad5uju892cqmawsg
|
||||
// address data: aeb3454b420dcce3ef5ec08e7d3fada725c39558
|
||||
);
|
||||
const test3 = decodeBech32Pubkey(
|
||||
"wasmpub1addwnpepq0xfx5vavxmgdkn0p6x0l9p3udttghu3qcldd7ql08wa3xy93qq0xuzvtxc",
|
||||
// pubkey data: eb5ae9872103cc93519d61b686da6f0e8cff9431e356b45f91063ed6f81f79ddd898858800f3
|
||||
// address: wasm1a6uxr25mw8qg8zz3l2avsdjsveh4yg9sw7h5np
|
||||
// address data: eeb861aa9b71c0838851fabac83650666f5220b0
|
||||
);
|
||||
|
||||
// 2/3 multisig
|
||||
const testgroup1: MultisigThresholdPubkey = {
|
||||
type: "tendermint/PubKeyMultisigThreshold",
|
||||
value: {
|
||||
threshold: "2",
|
||||
pubkeys: [test1, test2, test3],
|
||||
},
|
||||
};
|
||||
const expected1 = Bech32.decode(
|
||||
"wasmpub1ytql0csgqgfzd666axrjzquvkkvwu4qnp5603cyp3emc02sxzwdqutgqym9dke3t2h83dpv6vufzd666axrjzq5sdudaj5tv3nfm2f3exgkgqxlcwfxplf0g0rqwx2um6mqthzc0dqfzd666axrjzq7vjdge6cdksmdx7r5vl72rrc6kk30ezp376mup77wamzvgtzqq7v7aysdd",
|
||||
).data;
|
||||
const expected1 = Bech32.decode(testgroup1Address).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;
|
||||
const expected2 = Bech32.decode(testgroup2Address).data;
|
||||
expect(encodeAminoPubkey(testgroup2)).toEqual(expected2);
|
||||
|
||||
// 2/2 multisig
|
||||
const testgroup3: MultisigThresholdPubkey = {
|
||||
type: "tendermint/PubKeyMultisigThreshold",
|
||||
value: {
|
||||
threshold: "2",
|
||||
pubkeys: [test1, test3],
|
||||
},
|
||||
};
|
||||
const expected3 = Bech32.decode(
|
||||
"wasmpub1ytql0csgqgfzd666axrjzquvkkvwu4qnp5603cyp3emc02sxzwdqutgqym9dke3t2h83dpv6vufzd666axrjzq7vjdge6cdksmdx7r5vl72rrc6kk30ezp376mup77wamzvgtzqq7vzjhugu",
|
||||
).data;
|
||||
const expected3 = Bech32.decode(testgroup3Address).data;
|
||||
expect(encodeAminoPubkey(testgroup3)).toEqual(expected3);
|
||||
|
||||
// 2/2 multisig with custom sorting
|
||||
const testgroup4: MultisigThresholdPubkey = {
|
||||
type: "tendermint/PubKeyMultisigThreshold",
|
||||
value: {
|
||||
threshold: "2",
|
||||
pubkeys: [test3, test1],
|
||||
},
|
||||
};
|
||||
const expected4 = Bech32.decode(
|
||||
"wasmpub1ytql0csgqgfzd666axrjzq7vjdge6cdksmdx7r5vl72rrc6kk30ezp376mup77wamzvgtzqq7vfzd666axrjzquvkkvwu4qnp5603cyp3emc02sxzwdqutgqym9dke3t2h83dpv6vujvg56k",
|
||||
).data;
|
||||
const expected4 = Bech32.decode(testgroup4Address).data;
|
||||
expect(encodeAminoPubkey(testgroup4)).toEqual(expected4);
|
||||
});
|
||||
});
|
||||
|
||||
@ -18,3 +18,4 @@ export {
|
||||
isSinglePubkey,
|
||||
pubkeyType,
|
||||
} from "./pubkeys";
|
||||
export { createMultisigThresholdPubkey } from "./multisig";
|
||||
|
||||
63
packages/amino/src/multisig.spec.ts
Normal file
63
packages/amino/src/multisig.spec.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import { compareArrays, createMultisigThresholdPubkey } from "./multisig";
|
||||
import { test1, test2, test3, testgroup1, testgroup2, testgroup3, testgroup4 } from "./testutils.spec";
|
||||
|
||||
describe("multisig", () => {
|
||||
describe("compareArrays", () => {
|
||||
it("return 0 for equal arrays", () => {
|
||||
expect(compareArrays(new Uint8Array([]), new Uint8Array([]))).toEqual(0);
|
||||
expect(compareArrays(new Uint8Array([1]), new Uint8Array([1]))).toEqual(0);
|
||||
expect(compareArrays(new Uint8Array([3, 2, 1]), new Uint8Array([3, 2, 1]))).toEqual(0);
|
||||
});
|
||||
|
||||
it("return > 0 for left > right", () => {
|
||||
expect(compareArrays(new Uint8Array([5, 5, 5]), new Uint8Array([5, 5, 4]))).toBeGreaterThan(0);
|
||||
expect(compareArrays(new Uint8Array([5, 5, 5]), new Uint8Array([5, 4, 5]))).toBeGreaterThan(0);
|
||||
expect(compareArrays(new Uint8Array([5, 5, 5]), new Uint8Array([4, 5, 5]))).toBeGreaterThan(0);
|
||||
expect(compareArrays(new Uint8Array([5, 5, 5]), new Uint8Array([5, 5]))).toBeGreaterThan(0);
|
||||
expect(compareArrays(new Uint8Array([5, 5, 5]), new Uint8Array([5]))).toBeGreaterThan(0);
|
||||
expect(compareArrays(new Uint8Array([5, 5, 5]), new Uint8Array([]))).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("return < 0 for left < right", () => {
|
||||
expect(compareArrays(new Uint8Array([5, 5, 4]), new Uint8Array([5, 5, 5]))).toBeLessThan(0);
|
||||
expect(compareArrays(new Uint8Array([5, 4, 5]), new Uint8Array([5, 5, 5]))).toBeLessThan(0);
|
||||
expect(compareArrays(new Uint8Array([4, 5, 5]), new Uint8Array([5, 5, 5]))).toBeLessThan(0);
|
||||
expect(compareArrays(new Uint8Array([5, 5]), new Uint8Array([5, 5, 5]))).toBeLessThan(0);
|
||||
expect(compareArrays(new Uint8Array([5]), new Uint8Array([5, 5, 5]))).toBeLessThan(0);
|
||||
expect(compareArrays(new Uint8Array([]), new Uint8Array([5, 5, 5]))).toBeLessThan(0);
|
||||
});
|
||||
|
||||
it("can be used with sort", () => {
|
||||
const values = [
|
||||
new Uint8Array([2]),
|
||||
new Uint8Array([1]),
|
||||
new Uint8Array([2, 5]),
|
||||
new Uint8Array([3]),
|
||||
new Uint8Array([]),
|
||||
].sort(compareArrays);
|
||||
expect(values).toEqual([
|
||||
new Uint8Array([]),
|
||||
new Uint8Array([1]),
|
||||
new Uint8Array([2]),
|
||||
new Uint8Array([2, 5]),
|
||||
new Uint8Array([3]),
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("MultisigThresholdPubkey", () => {
|
||||
it("works with sorting", () => {
|
||||
expect(createMultisigThresholdPubkey([test1, test2, test3], 2)).toEqual(testgroup1);
|
||||
expect(createMultisigThresholdPubkey([test1, test2, test3], 1)).toEqual(testgroup2);
|
||||
expect(createMultisigThresholdPubkey([test3, test1], 2)).toEqual(testgroup3);
|
||||
|
||||
expect(createMultisigThresholdPubkey([test1, test2, test3], 2, false)).toEqual(testgroup1);
|
||||
expect(createMultisigThresholdPubkey([test1, test2, test3], 1, false)).toEqual(testgroup2);
|
||||
expect(createMultisigThresholdPubkey([test3, test1], 2, false)).toEqual(testgroup3);
|
||||
});
|
||||
|
||||
it("works with nosort", () => {
|
||||
expect(createMultisigThresholdPubkey([test3, test1], 2, true)).toEqual(testgroup4);
|
||||
});
|
||||
});
|
||||
});
|
||||
38
packages/amino/src/multisig.ts
Normal file
38
packages/amino/src/multisig.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import { toHex } from "@cosmjs/encoding";
|
||||
import { Uint53 } from "@cosmjs/math";
|
||||
|
||||
import { pubkeyToRawAddress } from "./addresses";
|
||||
import { MultisigThresholdPubkey, SinglePubkey } from "./pubkeys";
|
||||
|
||||
/**
|
||||
* Compare arrays lexicographically.
|
||||
*
|
||||
* Returns value < 0 if `a < b`.
|
||||
* Returns value > 0 if `a > b`.
|
||||
* Returns 0 if `a === b`.
|
||||
*/
|
||||
export function compareArrays(a: Uint8Array, b: Uint8Array): number {
|
||||
return toHex(a).localeCompare(toHex(b));
|
||||
}
|
||||
|
||||
export function createMultisigThresholdPubkey(
|
||||
pubkeys: readonly SinglePubkey[],
|
||||
threshold: number,
|
||||
nosort = false,
|
||||
): MultisigThresholdPubkey {
|
||||
const outPubkeys = nosort
|
||||
? pubkeys
|
||||
: Array.from(pubkeys).sort((lhs, rhs) => {
|
||||
// https://github.com/cosmos/cosmos-sdk/blob/v0.42.2/client/keys/add.go#L172-L174
|
||||
const addressLhs = pubkeyToRawAddress(lhs);
|
||||
const addressRhs = pubkeyToRawAddress(rhs);
|
||||
return compareArrays(addressLhs, addressRhs);
|
||||
});
|
||||
return {
|
||||
type: "tendermint/PubKeyMultisigThreshold",
|
||||
value: {
|
||||
threshold: new Uint53(threshold).toString(),
|
||||
pubkeys: outPubkeys,
|
||||
},
|
||||
};
|
||||
}
|
||||
73
packages/amino/src/testutils.spec.ts
Normal file
73
packages/amino/src/testutils.spec.ts
Normal file
@ -0,0 +1,73 @@
|
||||
import { decodeBech32Pubkey } from "./encoding";
|
||||
import { MultisigThresholdPubkey } from "./pubkeys";
|
||||
|
||||
// ./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
|
||||
// # By default pubkeys are sorted by its address data (https://github.com/cosmos/cosmos-sdk/blob/v0.42.2/client/keys/add.go#L172-L174)
|
||||
// ./build/wasmd keys add testgroup3 --multisig=test3,test1 --multisig-threshold 2
|
||||
// ./build/wasmd keys add testgroup4 --multisig=test3,test1 --nosort --multisig-threshold 2
|
||||
|
||||
export const test1 = decodeBech32Pubkey(
|
||||
"wasmpub1addwnpepqwxttx8w2sfs6d8cuzqcuau84grp8xsw95qzdjkmvc44tnckskdxw3zw2km",
|
||||
// pubkey data: eb5ae98721038cb598ee54130d34f8e0818e7787aa06139a0e2d0026cadb662b55cf16859a67
|
||||
// address: wasm1jq59w7y34msq69g4w3zvq6d5h3stcajd8g62xm
|
||||
// address data: 9028577891aee00d15157444c069b4bc60bc764d
|
||||
);
|
||||
export const test2 = decodeBech32Pubkey(
|
||||
"wasmpub1addwnpepq2gx7x7e29kge5a4ycunytyqr0u8ynql5h583s8r9wdads9m3v8ks6y0nhc",
|
||||
// pubkey data: eb5ae9872102906f1bd9516c8cd3b52639322c801bf8724c1fa5e878c0e32b9bd6c0bb8b0f68
|
||||
// address: wasm146e52j6zphxw8m67cz8860ad5uju892cqmawsg
|
||||
// address data: aeb3454b420dcce3ef5ec08e7d3fada725c39558
|
||||
);
|
||||
export const test3 = decodeBech32Pubkey(
|
||||
"wasmpub1addwnpepq0xfx5vavxmgdkn0p6x0l9p3udttghu3qcldd7ql08wa3xy93qq0xuzvtxc",
|
||||
// pubkey data: eb5ae9872103cc93519d61b686da6f0e8cff9431e356b45f91063ed6f81f79ddd898858800f3
|
||||
// address: wasm1a6uxr25mw8qg8zz3l2avsdjsveh4yg9sw7h5np
|
||||
// address data: eeb861aa9b71c0838851fabac83650666f5220b0
|
||||
);
|
||||
|
||||
// 2/3 multisig
|
||||
export const testgroup1: MultisigThresholdPubkey = {
|
||||
type: "tendermint/PubKeyMultisigThreshold",
|
||||
value: {
|
||||
threshold: "2",
|
||||
pubkeys: [test1, test2, test3],
|
||||
},
|
||||
};
|
||||
export const testgroup1Address =
|
||||
"wasmpub1ytql0csgqgfzd666axrjzquvkkvwu4qnp5603cyp3emc02sxzwdqutgqym9dke3t2h83dpv6vufzd666axrjzq5sdudaj5tv3nfm2f3exgkgqxlcwfxplf0g0rqwx2um6mqthzc0dqfzd666axrjzq7vjdge6cdksmdx7r5vl72rrc6kk30ezp376mup77wamzvgtzqq7v7aysdd";
|
||||
|
||||
export const testgroup2: MultisigThresholdPubkey = {
|
||||
type: "tendermint/PubKeyMultisigThreshold",
|
||||
value: {
|
||||
threshold: "1",
|
||||
pubkeys: [test1, test2, test3],
|
||||
},
|
||||
};
|
||||
export const testgroup2Address =
|
||||
"wasmpub1ytql0csgqyfzd666axrjzquvkkvwu4qnp5603cyp3emc02sxzwdqutgqym9dke3t2h83dpv6vufzd666axrjzq5sdudaj5tv3nfm2f3exgkgqxlcwfxplf0g0rqwx2um6mqthzc0dqfzd666axrjzq7vjdge6cdksmdx7r5vl72rrc6kk30ezp376mup77wamzvgtzqq7vc4ejke";
|
||||
|
||||
// 2/2 multisig
|
||||
export const testgroup3: MultisigThresholdPubkey = {
|
||||
type: "tendermint/PubKeyMultisigThreshold",
|
||||
value: {
|
||||
threshold: "2",
|
||||
pubkeys: [test1, test3],
|
||||
},
|
||||
};
|
||||
export const testgroup3Address =
|
||||
"wasmpub1ytql0csgqgfzd666axrjzquvkkvwu4qnp5603cyp3emc02sxzwdqutgqym9dke3t2h83dpv6vufzd666axrjzq7vjdge6cdksmdx7r5vl72rrc6kk30ezp376mup77wamzvgtzqq7vzjhugu";
|
||||
|
||||
// 2/2 multisig with custom sorting
|
||||
export const testgroup4: MultisigThresholdPubkey = {
|
||||
type: "tendermint/PubKeyMultisigThreshold",
|
||||
value: {
|
||||
threshold: "2",
|
||||
pubkeys: [test3, test1],
|
||||
},
|
||||
};
|
||||
export const testgroup4Address =
|
||||
"wasmpub1ytql0csgqgfzd666axrjzq7vjdge6cdksmdx7r5vl72rrc6kk30ezp376mup77wamzvgtzqq7vfzd666axrjzquvkkvwu4qnp5603cyp3emc02sxzwdqutgqym9dke3t2h83dpv6vujvg56k";
|
||||
Loading…
Reference in New Issue
Block a user