Skip to content

Commit

Permalink
Merge pull request #28 from Terran-One/fix/cleanup-wasm
Browse files Browse the repository at this point in the history
Cleanup WASM Module & fix rethrow issue
  • Loading branch information
Kiruse authored Dec 23, 2022
2 parents a4ed361 + 30b01f9 commit 1e51573
Show file tree
Hide file tree
Showing 11 changed files with 312 additions and 280 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@terran-one/cw-simulate",
"version": "2.8.0",
"version": "2.8.1",
"description": "Mock blockchain environment for simulating CosmWasm interactions",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
Expand Down
4 changes: 2 additions & 2 deletions src/CWSimulateApp.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { QuerierBase } from '@terran-one/cosmwasm-vm-js';
import { Err, Ok, Result } from 'ts-results';
import { Err, Result } from 'ts-results';
import { WasmModule, WasmQuery } from './modules/wasm';
import { BankModule, BankQuery } from './modules/bank';
import { fromImmutable, toImmutable, Transactional, TransactionalLens } from './store/transactional';
import { Transactional, TransactionalLens } from './store/transactional';
import { AppResponse, Binary } from './types';

export interface CWSimulateAppOptions {
Expand Down
148 changes: 148 additions & 0 deletions src/modules/wasm/contract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import { BasicBackendApi, BasicKVIterStorage, IBackend } from "@terran-one/cosmwasm-vm-js";
import { Map } from "immutable";
import { Ok, Result } from "ts-results";
import { CWSimulateVMInstance } from "../../instrumentation/CWSimulateVMInstance";
import { Coin, ContractResponse, DebugLog, ReplyMsg, Snapshot } from "../../types";
import { fromBinary, fromRustResult } from "../../util";
import type { WasmModule } from "./module";

/** An interface to interact with CW SCs */
export default class Contract {
private _vm: CWSimulateVMInstance | undefined;

constructor(private _wasm: WasmModule, public readonly address: string) {}

async init() {
if (!this._vm) {
const { _wasm: wasm, address } = this;
const contractInfo = wasm.getContractInfo(address);
if (!contractInfo)
throw new Error(`contract ${address} not found`);

const { codeId } = contractInfo;
const codeInfo = wasm.getCodeInfo(codeId);
if (!codeInfo)
throw new Error(`code ${codeId} not found`);

const { wasmCode } = codeInfo;
const contractState = this.getStorage();

let storage = new BasicKVIterStorage();
storage.dict = contractState;

let backend: IBackend = {
backend_api: new BasicBackendApi(wasm.chain.bech32Prefix),
storage,
querier: wasm.chain.querier,
};

const logs: DebugLog[] = [];
const vm = new CWSimulateVMInstance(logs, backend);
await vm.build(wasmCode);
this._vm = vm;
}
return this;
}

instantiate(
sender: string,
funds: Coin[],
instantiateMsg: any,
logs: DebugLog[]
): Result<ContractResponse, string> {
if (!this._vm) throw new NoVMError(this.address);
const vm = this._vm;
const env = this.getExecutionEnv();
const info = { sender, funds };

const res = fromRustResult<ContractResponse>(vm.instantiate(env, info, instantiateMsg).json);

this.setStorage((vm.backend.storage as BasicKVIterStorage).dict);

logs.push(...vm.logs);

return res;
}

execute(
sender: string,
funds: Coin[],
executeMsg: any,
logs: DebugLog[],
): Result<ContractResponse, string>
{
const vm = this._vm;
if (!vm) throw new NoVMError(this.address);
vm.resetDebugInfo();

const env = this.getExecutionEnv();
const info = { sender, funds };

const res = fromRustResult<ContractResponse>(vm.execute(env, info, executeMsg).json);

this.setStorage((vm.backend.storage as BasicKVIterStorage).dict);

logs.push(...vm.logs);

return res;
}

reply(
replyMsg: ReplyMsg,
logs: DebugLog[],
): Result<ContractResponse, string> {
if (!this._vm) throw new NoVMError(this.address);
const vm = this._vm;
const res = fromRustResult<ContractResponse>(vm.reply(this.getExecutionEnv(), replyMsg).json);

this.setStorage((vm.backend.storage as BasicKVIterStorage).dict);

logs.push(...vm.logs);

return res;
}

query(queryMsg: any, store?: Map<string, string>): Result<any, string> {
if (!this._vm) throw new NoVMError(this.address);
const vm = this._vm;

// time travel
const currBackend = vm.backend;
const storage = new BasicKVIterStorage(this.getStorage(store));
vm.backend = {
...vm.backend,
storage,
};

try {
let env = this.getExecutionEnv();
return fromRustResult<string>(vm.query(env, queryMsg).json)
.andThen(v => Ok(fromBinary(v)));
}
// reset time travel
finally {
vm.backend = currBackend;
}
}

setStorage(value: Map<string, string>) {
this._wasm.setContractStorage(this.address, value);
}

getStorage(storage?: Snapshot): Map<string, string> {
return this._wasm.getContractStorage(this.address, storage);
}

getExecutionEnv() {
return this._wasm.getExecutionEnv(this.address);
}

get vm() { return this._vm }
get valid() { return !!this._vm }
}

class NoVMError extends Error {
constructor(contractAddress: string) {
super(`No VM for contract ${contractAddress}`);
}
}
1 change: 1 addition & 0 deletions src/modules/wasm/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './module';
Loading

0 comments on commit 1e51573

Please sign in to comment.