Restructure makeMultisignedTx test to use offline signers

This commit is contained in:
Simon Warta 2021-03-24 14:08:49 +01:00
parent 40b1daf381
commit 6d361e2c88

View File

@ -6,7 +6,7 @@ import { MsgSend } from "./codec/cosmos/bank/v1beta1/tx";
import { TxRaw } from "./codec/cosmos/tx/v1beta1/tx";
import { makeCompactBitArray, makeMultisignedTx } from "./multisignature";
import { SignerData, SigningStargateClient } from "./signingstargateclient";
import { assertIsBroadcastTxSuccess } from "./stargateclient";
import { assertIsBroadcastTxSuccess, StargateClient } from "./stargateclient";
import { faucet, pendingWithoutSimapp, simapp } from "./testutils.spec";
describe("multisignature", () => {
@ -165,90 +165,178 @@ describe("multisignature", () => {
describe("makeMultisignedTx", () => {
it("works", async () => {
pendingWithoutSimapp();
const wallet0 = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic, makeCosmoshubPath(0));
const wallet1 = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic, makeCosmoshubPath(1));
const wallet2 = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic, makeCosmoshubPath(2));
const wallet3 = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic, makeCosmoshubPath(3));
const wallet4 = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic, makeCosmoshubPath(4));
const pubkey0 = encodeSecp256k1Pubkey((await wallet0.getAccounts())[0].pubkey);
const pubkey1 = encodeSecp256k1Pubkey((await wallet1.getAccounts())[0].pubkey);
const pubkey2 = encodeSecp256k1Pubkey((await wallet2.getAccounts())[0].pubkey);
const pubkey3 = encodeSecp256k1Pubkey((await wallet3.getAccounts())[0].pubkey);
const pubkey4 = encodeSecp256k1Pubkey((await wallet4.getAccounts())[0].pubkey);
const address0 = (await wallet0.getAccounts())[0].address;
const address1 = (await wallet1.getAccounts())[0].address;
const address2 = (await wallet2.getAccounts())[0].address;
const address3 = (await wallet3.getAccounts())[0].address;
const address4 = (await wallet4.getAccounts())[0].address;
const multisigPubkey = createMultisigThresholdPubkey([pubkey0, pubkey1, pubkey2, pubkey3, pubkey4], 2);
const multisigAddress = pubkeyToAddress(multisigPubkey, "cosmos");
expect(multisigAddress).toEqual("cosmos1h90ml36rcu7yegwduzgzderj2jmq49hcpfclw9");
const multisigAccountAddress = "cosmos1h90ml36rcu7yegwduzgzderj2jmq49hcpfclw9";
const client0 = await SigningStargateClient.connectWithSigner(simapp.tendermintUrl, wallet0);
const client1 = await SigningStargateClient.connectWithSigner(simapp.tendermintUrl, wallet1);
const client2 = await SigningStargateClient.connectWithSigner(simapp.tendermintUrl, wallet2);
const client3 = await SigningStargateClient.connectWithSigner(simapp.tendermintUrl, wallet3);
const client4 = await SigningStargateClient.connectWithSigner(simapp.tendermintUrl, wallet4);
// On the composer's machine signing instructions are created.
// The composer does not need to be one of the signers.
const signingInstruction = await (async () => {
const client = await StargateClient.connect(simapp.tendermintUrl);
const accountOnChain = await client.getAccount(multisigAccountAddress);
assert(accountOnChain, "Account does not exist on chain");
const msgSend: MsgSend = {
fromAddress: multisigAddress,
toAddress: "cosmos19rvl6ja9h0erq9dc2xxfdzypc739ej8k5esnhg",
amount: coins(1234, "ucosm"),
};
const msg = {
typeUrl: "/cosmos.bank.v1beta1.MsgSend",
value: msgSend,
};
const gasLimit = 200000;
const fee = {
amount: coins(2000, "ucosm"),
gas: gasLimit.toString(),
};
const memo = "Use your tokens wisely";
const msgSend: MsgSend = {
fromAddress: multisigAccountAddress,
toAddress: "cosmos19rvl6ja9h0erq9dc2xxfdzypc739ej8k5esnhg",
amount: coins(1234, "ucosm"),
};
const msg = {
typeUrl: "/cosmos.bank.v1beta1.MsgSend",
value: msgSend,
};
const gasLimit = 200000;
const fee = {
amount: coins(2000, "ucosm"),
gas: gasLimit.toString(),
};
const multisigAccount = await client0.getAccount(multisigAddress);
assert(multisigAccount, "Account does not exist on chain");
const signerData: SignerData = {
accountNumber: multisigAccount.accountNumber,
sequence: multisigAccount.sequence,
chainId: await client0.getChainId(),
};
return {
accountNumber: accountOnChain.accountNumber,
sequence: accountOnChain.sequence,
chainId: await client.getChainId(),
msgs: [msg],
fee: fee,
memo: "Use your tokens wisely",
};
})();
const {
bodyBytes,
signatures: [signature0],
} = await client0.sign(faucet.address0, [msg], fee, memo, signerData);
const {
signatures: [signature1],
} = await client1.sign(faucet.address1, [msg], fee, memo, signerData);
const {
signatures: [signature2],
} = await client2.sign(faucet.address2, [msg], fee, memo, signerData);
const {
signatures: [signature3],
} = await client3.sign(faucet.address3, [msg], fee, memo, signerData);
const {
signatures: [signature4],
} = await client4.sign(faucet.address4, [msg], fee, memo, signerData);
// Signing environment 0
const [pubkey0, signature0, bodyBytes] = await (async () => {
const wallet = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic, makeCosmoshubPath(0));
const pubkey = encodeSecp256k1Pubkey((await wallet.getAccounts())[0].pubkey);
const address = (await wallet.getAccounts())[0].address;
const signingClient = await SigningStargateClient.offline(wallet);
const signerData: SignerData = {
accountNumber: signingInstruction.accountNumber,
sequence: signingInstruction.sequence,
chainId: signingInstruction.chainId,
};
const { bodyBytes: bb, signatures } = await signingClient.sign(
address,
signingInstruction.msgs,
signingInstruction.fee,
signingInstruction.memo,
signerData,
);
return [pubkey, signatures[0], bb] as const;
})();
const signatures = new Map<string, Uint8Array>([
[address0, signature0],
[address1, signature1],
[address2, signature2],
[address3, signature3],
[address4, signature4],
]);
const signedTx = makeMultisignedTx(
multisigPubkey,
multisigAccount.sequence,
fee,
bodyBytes,
signatures,
);
// Signing environment 1
const [pubkey1, signature1] = await (async () => {
const wallet = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic, makeCosmoshubPath(1));
const pubkey = encodeSecp256k1Pubkey((await wallet.getAccounts())[0].pubkey);
const address = (await wallet.getAccounts())[0].address;
const signingClient = await SigningStargateClient.offline(wallet);
const signerData: SignerData = {
accountNumber: signingInstruction.accountNumber,
sequence: signingInstruction.sequence,
chainId: signingInstruction.chainId,
};
const { signatures } = await signingClient.sign(
address,
signingInstruction.msgs,
signingInstruction.fee,
signingInstruction.memo,
signerData,
);
return [pubkey, signatures[0]] as const;
})();
// ensure signature is valid
const result = await client0.broadcastTx(Uint8Array.from(TxRaw.encode(signedTx).finish()));
assertIsBroadcastTxSuccess(result);
// Signing environment 2
const [pubkey2, signature2] = await (async () => {
const wallet = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic, makeCosmoshubPath(2));
const pubkey = encodeSecp256k1Pubkey((await wallet.getAccounts())[0].pubkey);
const address = (await wallet.getAccounts())[0].address;
const signingClient = await SigningStargateClient.offline(wallet);
const signerData: SignerData = {
accountNumber: signingInstruction.accountNumber,
sequence: signingInstruction.sequence,
chainId: signingInstruction.chainId,
};
const { signatures } = await signingClient.sign(
address,
signingInstruction.msgs,
signingInstruction.fee,
signingInstruction.memo,
signerData,
);
return [pubkey, signatures[0]] as const;
})();
// Signing environment 3
const [pubkey3, signature3] = await (async () => {
const wallet = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic, makeCosmoshubPath(3));
const pubkey = encodeSecp256k1Pubkey((await wallet.getAccounts())[0].pubkey);
const address = (await wallet.getAccounts())[0].address;
const signingClient = await SigningStargateClient.offline(wallet);
const signerData: SignerData = {
accountNumber: signingInstruction.accountNumber,
sequence: signingInstruction.sequence,
chainId: signingInstruction.chainId,
};
const { signatures } = await signingClient.sign(
address,
signingInstruction.msgs,
signingInstruction.fee,
signingInstruction.memo,
signerData,
);
return [pubkey, signatures[0]] as const;
})();
// Signing environment 4
const [pubkey4, signature4] = await (async () => {
const wallet = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic, makeCosmoshubPath(4));
const pubkey = encodeSecp256k1Pubkey((await wallet.getAccounts())[0].pubkey);
const address = (await wallet.getAccounts())[0].address;
const signingClient = await SigningStargateClient.offline(wallet);
const signerData: SignerData = {
accountNumber: signingInstruction.accountNumber,
sequence: signingInstruction.sequence,
chainId: signingInstruction.chainId,
};
const { signatures } = await signingClient.sign(
address,
signingInstruction.msgs,
signingInstruction.fee,
signingInstruction.memo,
signerData,
);
return [pubkey, signatures[0]] as const;
})();
// From here on, no private keys are required anymore. Any anonymous entity
// can collect, assemble and broadcast.
{
const multisigPubkey = createMultisigThresholdPubkey(
[pubkey0, pubkey1, pubkey2, pubkey3, pubkey4],
2,
);
expect(pubkeyToAddress(multisigPubkey, "cosmos")).toEqual(multisigAccountAddress);
const address0 = pubkeyToAddress(pubkey0, "cosmos");
const address1 = pubkeyToAddress(pubkey1, "cosmos");
const address2 = pubkeyToAddress(pubkey2, "cosmos");
const address3 = pubkeyToAddress(pubkey3, "cosmos");
const address4 = pubkeyToAddress(pubkey4, "cosmos");
const broadcaster = await StargateClient.connect(simapp.tendermintUrl);
const signedTx = makeMultisignedTx(
multisigPubkey,
signingInstruction.sequence,
signingInstruction.fee,
bodyBytes,
new Map<string, Uint8Array>([
[address0, signature0],
[address1, signature1],
[address2, signature2],
[address3, signature3],
[address4, signature4],
]),
);
// ensure signature is valid
const result = await broadcaster.broadcastTx(Uint8Array.from(TxRaw.encode(signedTx).finish()));
assertIsBroadcastTxSuccess(result);
}
});
});
});