Pull out wasm contract actions as test helper functions

This commit is contained in:
Ethan Frey 2020-02-05 16:26:37 +01:00
parent 477511f1b3
commit da9eff547e
4 changed files with 140 additions and 91 deletions

View File

@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/camelcase */
import { ChainId, PrehashType, SignableBytes } from "@iov/bcp";
import { ChainId, Identity, PrehashType, SignableBytes } from "@iov/bcp";
import { Random } from "@iov/crypto";
import { Bech32, Encoding } from "@iov/encoding";
import { HdPaths, Secp256k1HdWallet } from "@iov/keycontrol";
@ -7,7 +7,7 @@ import { HdPaths, Secp256k1HdWallet } from "@iov/keycontrol";
import { encodeSecp256k1Signature, makeSignBytes, marshalTx } from "./encoding";
import { leb128Encode } from "./leb128.spec";
import { Attribute, Log, parseLogs } from "./logs";
import { RestClient } from "./restclient";
import { PostTxsResponse, RestClient } from "./restclient";
import contract from "./testdata/contract.json";
import cosmoshub from "./testdata/cosmoshub.json";
import {
@ -174,6 +174,112 @@ describe("RestClient", () => {
expect(result.code).toBeFalsy();
});
async function uploadContract(
client: RestClient,
wallet: Secp256k1HdWallet,
signer: Identity,
): Promise<PostTxsResponse> {
const memo = "My first contract on chain";
const theMsg: MsgStoreCode = {
type: "wasm/store-code",
value: {
sender: faucetAddress,
wasm_byte_code: toBase64(getRandomizedContract()),
source: "https://github.com/confio/cosmwasm/raw/0.7/lib/vm/testdata/contract_0.6.wasm",
builder: "cosmwasm-opt:0.6.2",
},
};
const fee: StdFee = {
amount: [
{
amount: "5000000",
denom: "ucosm",
},
],
gas: "89000000",
};
const account = (await client.authAccounts(faucetAddress)).result.value;
const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account) as SignableBytes;
const rawSignature = await wallet.createTransactionSignature(signer, signBytes, PrehashType.Sha256);
const signature = encodeSecp256k1Signature(signer.pubkey.data, rawSignature);
const signedTx = makeSignedTx(theMsg, fee, memo, signature);
return client.postTx(marshalTx(signedTx));
}
async function instantiateContract(
client: RestClient,
wallet: Secp256k1HdWallet,
signer: Identity,
codeId: number,
beneficiaryAddress: string,
transferAmount: readonly Coin[],
): Promise<PostTxsResponse> {
const memo = "Create an escrow instance";
const theMsg: MsgInstantiateContract = {
type: "wasm/instantiate",
value: {
sender: faucetAddress,
code_id: codeId.toString(),
init_msg: {
verifier: faucetAddress,
beneficiary: beneficiaryAddress,
},
init_funds: transferAmount,
},
};
const fee: StdFee = {
amount: [
{
amount: "5000000",
denom: "ucosm",
},
],
gas: "89000000",
};
const account = (await client.authAccounts(faucetAddress)).result.value;
const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account) as SignableBytes;
const rawSignature = await wallet.createTransactionSignature(signer, signBytes, PrehashType.Sha256);
const signature = encodeSecp256k1Signature(signer.pubkey.data, rawSignature);
const signedTx = makeSignedTx(theMsg, fee, memo, signature);
return client.postTx(marshalTx(signedTx));
}
async function executeContract(
client: RestClient,
wallet: Secp256k1HdWallet,
signer: Identity,
contractAddress: string,
): Promise<PostTxsResponse> {
const memo = "Time for action";
const theMsg: MsgExecuteContract = {
type: "wasm/execute",
value: {
sender: faucetAddress,
contract: contractAddress,
msg: {},
sent_funds: [],
},
};
const fee: StdFee = {
amount: [
{
amount: "5000000",
denom: "ucosm",
},
],
gas: "89000000",
};
const account = (await client.authAccounts(faucetAddress)).result.value;
const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account) as SignableBytes;
const rawSignature = await wallet.createTransactionSignature(signer, signBytes, PrehashType.Sha256);
const signature = encodeSecp256k1Signature(signer.pubkey.data, rawSignature);
const signedTx = makeSignedTx(theMsg, fee, memo, signature);
return client.postTx(marshalTx(signedTx));
}
it("can upload, instantiate and execute wasm", async () => {
pendingWithoutCosmos();
const wallet = Secp256k1HdWallet.fromMnemonic(faucetMnemonic);
@ -196,33 +302,8 @@ describe("RestClient", () => {
// upload
{
const memo = "My first contract on chain";
const theMsg: MsgStoreCode = {
type: "wasm/store-code",
value: {
sender: faucetAddress,
wasm_byte_code: toBase64(getRandomizedContract()),
source: "https://github.com/confio/cosmwasm/raw/0.7/lib/vm/testdata/contract_0.6.wasm",
builder: "cosmwasm-opt:0.6.2",
},
};
const fee: StdFee = {
amount: [
{
amount: "5000000",
denom: "ucosm",
},
],
gas: "89000000",
};
const account = (await client.authAccounts(faucetAddress)).result.value;
const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account) as SignableBytes;
const rawSignature = await wallet.createTransactionSignature(signer, signBytes, PrehashType.Sha256);
const signature = encodeSecp256k1Signature(signer.pubkey.data, rawSignature);
const signedTx = makeSignedTx(theMsg, fee, memo, signature);
const result = await client.postTx(marshalTx(signedTx));
// console.log("Raw log:", result.raw_log);
const result = await uploadContract(client, wallet, signer);
expect(result.code).toBeFalsy();
const logs = parseSuccess(result.raw_log);
const codeIdAttr = findAttribute(logs, "message", "code_id");
@ -235,35 +316,14 @@ describe("RestClient", () => {
// instantiate
{
const memo = "Create an escrow instance";
const theMsg: MsgInstantiateContract = {
type: "wasm/instantiate",
value: {
sender: faucetAddress,
code_id: codeId.toString(),
init_msg: {
verifier: faucetAddress,
beneficiary: beneficiaryAddress,
},
init_funds: transferAmount,
},
};
const fee: StdFee = {
amount: [
{
amount: "5000000",
denom: "ucosm",
},
],
gas: "89000000",
};
const account = (await client.authAccounts(faucetAddress)).result.value;
const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account) as SignableBytes;
const rawSignature = await wallet.createTransactionSignature(signer, signBytes, PrehashType.Sha256);
const signature = encodeSecp256k1Signature(signer.pubkey.data, rawSignature);
const signedTx = makeSignedTx(theMsg, fee, memo, signature);
const result = await client.postTx(marshalTx(signedTx));
const result = await instantiateContract(
client,
wallet,
signer,
codeId,
beneficiaryAddress,
transferAmount,
);
expect(result.code).toBeFalsy();
// console.log("Raw log:", result.raw_log);
const logs = parseSuccess(result.raw_log);
@ -278,32 +338,7 @@ describe("RestClient", () => {
// execute
{
const memo = "Time for action";
const theMsg: MsgExecuteContract = {
type: "wasm/execute",
value: {
sender: faucetAddress,
contract: contractAddress,
msg: {},
sent_funds: [],
},
};
const fee: StdFee = {
amount: [
{
amount: "5000000",
denom: "ucosm",
},
],
gas: "89000000",
};
const account = (await client.authAccounts(faucetAddress)).result.value;
const signBytes = makeSignBytes([theMsg], fee, defaultNetworkId, memo, account) as SignableBytes;
const rawSignature = await wallet.createTransactionSignature(signer, signBytes, PrehashType.Sha256);
const signature = encodeSecp256k1Signature(signer.pubkey.data, rawSignature);
const signedTx = makeSignedTx(theMsg, fee, memo, signature);
const result = await client.postTx(marshalTx(signedTx));
const result = await executeContract(client, wallet, signer, contractAddress);
expect(result.code).toBeFalsy();
// console.log("Raw log:", result.raw_log);
const [firstLog] = parseSuccess(result.raw_log);

View File

@ -73,7 +73,7 @@ interface SearchTxsResponse {
interface PostTxsParams {}
interface PostTxsResponse {
export interface PostTxsResponse {
readonly height: string;
readonly txhash: string;
readonly code?: number;
@ -236,6 +236,7 @@ export class RestClient {
// this will download the original wasm bytecode by code id
// throws error if no code with this id
public async getCode(id: number): Promise<Uint8Array> {
// TODO: broken currently
const path = `/wasm/code/${id}`;
const responseData = await this.get(path);
const { code } = parseWasmResponse(responseData as WasmResponse);

View File

@ -1,4 +1,4 @@
import { AminoTx, BaseAccount, CodeInfo, CodeInfoWithId, ContractInfo, StdTx } from "./types";
import { AminoTx, BaseAccount, CodeInfo, ContractInfo, StdTx, WasmData } from "./types";
interface NodeInfo {
readonly network: string;
}
@ -29,9 +29,14 @@ interface AuthAccountsResponse {
readonly value: BaseAccount;
};
}
interface WasmResponse {
declare type WasmResponse = WasmSuccess | WasmError;
interface WasmSuccess {
readonly height: string;
readonly result: string;
}
interface WasmError {
readonly error: string;
}
export interface TxsResponse {
readonly height: string;
readonly txhash: string;
@ -47,7 +52,7 @@ interface SearchTxsResponse {
readonly txs: readonly TxsResponse[];
}
interface PostTxsParams {}
interface PostTxsResponse {
export interface PostTxsResponse {
readonly height: string;
readonly txhash: string;
readonly code?: number;
@ -87,9 +92,12 @@ export declare class RestClient {
txs(query: string): Promise<SearchTxsResponse>;
txsById(id: string): Promise<TxsResponse>;
postTx(tx: Uint8Array): Promise<PostTxsResponse>;
listCodeInfo(): Promise<readonly CodeInfoWithId[]>;
getCodeInfo(id: number): Promise<CodeInfo>;
listCodeInfo(): Promise<readonly CodeInfo[]>;
getCode(id: number): Promise<Uint8Array>;
listContractAddresses(): Promise<readonly string[]>;
getContractInfo(address: string): Promise<ContractInfo>;
getAllContractState(address: string): Promise<readonly WasmData[]>;
getContractKey(address: string, key: Uint8Array): Promise<unknown | null>;
queryContract(address: string, query: object): Promise<unknown>;
}
export {};

View File

@ -121,6 +121,7 @@ export interface BaseAccount {
/** The data we need from BaseAccount to create a nonce */
export declare type NonceInfo = Pick<BaseAccount, "account_number" | "sequence">;
export interface CodeInfo {
readonly id: number;
/** Bech32 account address */
readonly creator: string;
/** Hex-encoded sha256 hash of the code stored here */
@ -128,8 +129,8 @@ export interface CodeInfo {
readonly source?: string;
readonly builder?: string;
}
export interface CodeInfoWithId extends CodeInfo {
readonly id: number;
export interface CodeDetails {
readonly code: string;
}
export interface ContractInfo {
readonly code_id: number;
@ -138,4 +139,8 @@ export interface ContractInfo {
/** Argument passed on initialization of the contract */
readonly init_msg: object;
}
export interface WasmData {
readonly key: string;
readonly val: unknown;
}
export {};