Let makeSignBytes take account number and sequence as two args

This commit is contained in:
Simon Warta 2020-02-11 10:26:13 +01:00
parent b4b36c3a34
commit ae586cc012
13 changed files with 55 additions and 61 deletions

View File

@ -4,7 +4,6 @@ import {
isValidAddress,
makeSignBytes,
marshalTx,
types,
unmarshalTx,
} from "@cosmwasm/sdk";
import {
@ -46,16 +45,13 @@ export class CosmWasmCodec implements TxCodec {
public bytesToSign(unsigned: UnsignedTransaction, nonce: Nonce): SigningJob {
const built = buildUnsignedTx(unsigned, this.bankTokens, this.erc20Tokens);
const nonceInfo: types.NonceInfo = {
account_number: nonceToAccountNumber(nonce),
sequence: nonceToSequence(nonce),
};
const signBytes = makeSignBytes(
built.value.msg,
built.value.fee,
Caip5.decode(unsigned.chainId),
built.value.memo || "",
nonceInfo,
nonceToAccountNumber(nonce),
nonceToSequence(nonce),
);
return {

View File

@ -204,8 +204,8 @@ export class CosmWasmConnection implements BlockchainConnection {
public async getNonce(query: AddressQuery | PubkeyQuery): Promise<Nonce> {
const address = isPubkeyQuery(query) ? pubkeyToAddress(query.pubkey, this.addressPrefix) : query.address;
const { result } = await this.restClient.authAccounts(address);
const account = result.value;
return accountToNonce(account);
const { account_number, sequence } = result.value;
return accountToNonce(account_number, sequence);
}
public async getNonces(query: AddressQuery | PubkeyQuery, count: number): Promise<readonly Nonce[]> {

View File

@ -3,26 +3,13 @@ import { accountToNonce, nonceToAccountNumber, nonceToSequence } from "./types";
describe("nonceEncoding", () => {
it("works for input in range", () => {
const nonce = accountToNonce({
account_number: 1234,
sequence: 7890,
});
const nonce = accountToNonce(1234, 7890);
expect(nonceToAccountNumber(nonce)).toEqual(1234);
expect(nonceToSequence(nonce)).toEqual(7890);
});
it("errors on input too large", () => {
expect(() =>
accountToNonce({
account_number: 1234567890,
sequence: 7890,
}),
).toThrow();
expect(() =>
accountToNonce({
account_number: 178,
sequence: 97320247923,
}),
).toThrow();
expect(() => accountToNonce(1234567890, 7890)).toThrow();
expect(() => accountToNonce(178, 97320247923)).toThrow();
});
});

View File

@ -1,4 +1,3 @@
import { types } from "@cosmwasm/sdk";
import { Nonce } from "@iov/bcp";
export interface BankToken {
@ -40,17 +39,17 @@ const maxSeq = 1 << 20;
// this (lossily) encodes the two pieces of info (uint64) needed to sign into
// one (53-bit) number. Cross your fingers.
export function accountToNonce({ account_number: account, sequence }: types.NonceInfo): Nonce {
export function accountToNonce(accountNumber: number, sequence: number): Nonce {
// we allow 23 bits (8 million) for accounts, and 20 bits (1 million) for tx/account
// let's fix this soon
if (account > maxAcct) {
if (accountNumber > maxAcct) {
throw new Error("Account number is greater than 2^23, must update Nonce handler");
}
if (sequence > maxSeq) {
throw new Error("Sequence is greater than 2^20, must update Nonce handler");
}
const val = account * maxSeq + sequence;
const val = accountNumber * maxSeq + sequence;
return val as Nonce;
}

View File

@ -1,4 +1,3 @@
import { types } from "@cosmwasm/sdk";
import { Nonce } from "@iov/bcp";
export interface BankToken {
readonly denom: string;
@ -29,6 +28,6 @@ export interface Erc20Token {
*/
readonly fractionalDigits: number;
}
export declare function accountToNonce({ account_number: account, sequence }: types.NonceInfo): Nonce;
export declare function accountToNonce(accountNumber: number, sequence: number): Nonce;
export declare function nonceToAccountNumber(nonce: Nonce): number;
export declare function nonceToSequence(nonce: Nonce): number;

View File

@ -45,7 +45,7 @@ $ cosmwasm-cli
```ts
// Get account information
const account = (await client.authAccounts(faucetAddress)).result.value;
const { account_number, sequence } = (await client.authAccounts(faucetAddress)).result.value;
// Craft a send transaction
const emptyAddress = Bech32.encode("cosmos", Random.getBytes(20));
@ -64,7 +64,7 @@ const sendTokensMsg: types.MsgSend = {
},
};
const signBytes = makeSignBytes([sendTokensMsg], defaultFee, defaultNetworkId, memo, account);
const signBytes = makeSignBytes([sendTokensMsg], defaultFee, defaultNetworkId, memo, account_number, sequence);
const signature = encodeSecp256k1Signature(pen.pubkey, await pen.createSignature(signBytes));
const signedTx: types.StdTx = {
msg: [sendTokensMsg],

View File

@ -82,9 +82,12 @@ export class CosmWasmClient {
gas: "89000000",
};
const account = (await this.restClient.authAccounts(this.senderAddress)).result.value;
// eslint-disable-next-line @typescript-eslint/camelcase
const { account_number, sequence } = (
await this.restClient.authAccounts(this.senderAddress)
).result.value;
const chainId = await this.chainId();
const signBytes = makeSignBytes([storeCodeMsg], fee, chainId, memo, account);
const signBytes = makeSignBytes([storeCodeMsg], fee, chainId, memo, account_number, sequence);
const signature = await this.signCallback(signBytes);
const signedTx = {
msg: [storeCodeMsg],
@ -131,9 +134,12 @@ export class CosmWasmClient {
gas: "89000000",
};
const account = (await this.restClient.authAccounts(this.senderAddress)).result.value;
// eslint-disable-next-line @typescript-eslint/camelcase
const { account_number, sequence } = (
await this.restClient.authAccounts(this.senderAddress)
).result.value;
const chainId = await this.chainId();
const signBytes = makeSignBytes([instantiateMsg], fee, chainId, memo, account);
const signBytes = makeSignBytes([instantiateMsg], fee, chainId, memo, account_number, sequence);
const signature = await this.signCallback(signBytes);
const signedTx = {
@ -177,9 +183,12 @@ export class CosmWasmClient {
gas: "89000000",
};
const account = (await this.restClient.authAccounts(this.senderAddress)).result.value;
// eslint-disable-next-line @typescript-eslint/camelcase
const { account_number, sequence } = (
await this.restClient.authAccounts(this.senderAddress)
).result.value;
const chainId = await this.chainId();
const signBytes = makeSignBytes([executeMsg], fee, chainId, memo, account);
const signBytes = makeSignBytes([executeMsg], fee, chainId, memo, account_number, sequence);
const signature = await this.signCallback(signBytes);
const signedTx = {
msg: [executeMsg],

View File

@ -2,7 +2,7 @@ import { Secp256k1 } from "@iov/crypto";
import { Encoding } from "@iov/encoding";
import { encodeSecp256k1Pubkey } from "./pubkey";
import { Msg, NonceInfo, StdFee, StdSignature, StdTx } from "./types";
import { Msg, StdFee, StdSignature, StdTx } from "./types";
const { toBase64, toUtf8 } = Encoding;
@ -43,17 +43,18 @@ export function makeSignBytes(
fee: StdFee,
chainId: string,
memo: string,
account: NonceInfo,
accountNumber: number,
sequence: number,
): Uint8Array {
const signJson: SignJson = {
// eslint-disable-next-line @typescript-eslint/camelcase
account_number: account.account_number.toString(),
account_number: accountNumber.toString(),
// eslint-disable-next-line @typescript-eslint/camelcase
chain_id: chainId,
fee: fee,
memo: memo,
msgs: msgs,
sequence: account.sequence.toString(),
sequence: sequence.toString(),
};
const signMsg = sortJson(signJson);
return toUtf8(JSON.stringify(signMsg));

View File

@ -84,8 +84,8 @@ async function uploadCustomContract(
gas: "89000000",
};
const account = (await client.authAccounts(faucet.address)).result.value;
const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account);
const { account_number, sequence } = (await client.authAccounts(faucet.address)).result.value;
const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account_number, sequence);
const signature = encodeSecp256k1Signature(pen.pubkey, await pen.createSignature(signBytes));
const signedTx = makeSignedTx(theMsg, fee, memo, signature);
return client.postTx(marshalTx(signedTx));
@ -125,8 +125,8 @@ async function instantiateContract(
gas: "89000000",
};
const account = (await client.authAccounts(faucet.address)).result.value;
const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account);
const { account_number, sequence } = (await client.authAccounts(faucet.address)).result.value;
const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account_number, sequence);
const signature = encodeSecp256k1Signature(pen.pubkey, await pen.createSignature(signBytes));
const signedTx = makeSignedTx(theMsg, fee, memo, signature);
return client.postTx(marshalTx(signedTx));
@ -157,8 +157,8 @@ async function executeContract(
gas: "89000000",
};
const account = (await client.authAccounts(faucet.address)).result.value;
const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account);
const { account_number, sequence } = (await client.authAccounts(faucet.address)).result.value;
const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account_number, sequence);
const signature = encodeSecp256k1Signature(pen.pubkey, await pen.createSignature(signBytes));
const signedTx = makeSignedTx(theMsg, fee, memo, signature);
return client.postTx(marshalTx(signedTx));
@ -258,9 +258,9 @@ describe("RestClient", () => {
};
const client = new RestClient(httpUrl);
const account = (await client.authAccounts(faucet.address)).result.value;
const { account_number, sequence } = (await client.authAccounts(faucet.address)).result.value;
const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account);
const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account_number, sequence);
const signature = encodeSecp256k1Signature(pen.pubkey, await pen.createSignature(signBytes));
const signedTx = makeSignedTx(theMsg, fee, memo, signature);
const result = await client.postTx(marshalTx(signedTx));

View File

@ -160,9 +160,6 @@ export interface CosmosSdkAccount {
readonly sequence: number;
}
/** The data we need from CosmosSdkAccount to create a nonce */
export type NonceInfo = Pick<CosmosSdkAccount, "account_number" | "sequence">;
export interface CodeInfo {
readonly id: number;
/** Bech32 account address */

View File

@ -1,10 +1,11 @@
import { Msg, NonceInfo, StdFee, StdSignature, StdTx } from "./types";
import { Msg, StdFee, StdSignature, StdTx } from "./types";
export declare function marshalTx(tx: StdTx): Uint8Array;
export declare function makeSignBytes(
msgs: readonly Msg[],
fee: StdFee,
chainId: string,
memo: string,
account: NonceInfo,
accountNumber: number,
sequence: number,
): Uint8Array;
export declare function encodeSecp256k1Signature(pubkey: Uint8Array, signature: Uint8Array): StdSignature;

View File

@ -116,8 +116,6 @@ export interface CosmosSdkAccount {
readonly account_number: number;
readonly sequence: number;
}
/** The data we need from CosmosSdkAccount to create a nonce */
export declare type NonceInfo = Pick<CosmosSdkAccount, "account_number" | "sequence">;
export interface CodeInfo {
readonly id: number;
/** Bech32 account address */

View File

@ -40,8 +40,8 @@ async function uploadContract(client, pen, wasm) {
},
};
const account = (await client.authAccounts(faucetAddress)).result.value;
const signBytes = makeSignBytes([storeCodeMsg], defaultFee, networkId, memo, account);
const { account_number, sequence } = (await client.authAccounts(faucetAddress)).result.value;
const signBytes = makeSignBytes([storeCodeMsg], defaultFee, networkId, memo, account_number, sequence);
const signature = encodeSecp256k1Signature(pen.pubkey, await pen.createSignature(signBytes));
const signedTx = {
msg: [storeCodeMsg],
@ -63,8 +63,15 @@ async function instantiateContract(client, pen, codeId, msg, transferAmount) {
init_funds: transferAmount || [],
},
};
const account = (await client.authAccounts(faucetAddress)).result.value;
const signBytes = makeSignBytes([instantiateContractMsg], defaultFee, networkId, memo, account);
const { account_number, sequence } = (await client.authAccounts(faucetAddress)).result.value;
const signBytes = makeSignBytes(
[instantiateContractMsg],
defaultFee,
networkId,
memo,
account_number,
sequence,
);
const signature = encodeSecp256k1Signature(pen.pubkey, await pen.createSignature(signBytes));
const signedTx = {
msg: [instantiateContractMsg],