Skip to content

Commit 1e51573

Browse files
authored
Merge pull request #28 from Terran-One/fix/cleanup-wasm
Cleanup WASM Module & fix rethrow issue
2 parents a4ed361 + 30b01f9 commit 1e51573

File tree

11 files changed

+312
-280
lines changed

11 files changed

+312
-280
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@terran-one/cw-simulate",
3-
"version": "2.8.0",
3+
"version": "2.8.1",
44
"description": "Mock blockchain environment for simulating CosmWasm interactions",
55
"main": "dist/index.js",
66
"typings": "dist/index.d.ts",

src/CWSimulateApp.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { QuerierBase } from '@terran-one/cosmwasm-vm-js';
2-
import { Err, Ok, Result } from 'ts-results';
2+
import { Err, Result } from 'ts-results';
33
import { WasmModule, WasmQuery } from './modules/wasm';
44
import { BankModule, BankQuery } from './modules/bank';
5-
import { fromImmutable, toImmutable, Transactional, TransactionalLens } from './store/transactional';
5+
import { Transactional, TransactionalLens } from './store/transactional';
66
import { AppResponse, Binary } from './types';
77

88
export interface CWSimulateAppOptions {

src/modules/wasm/contract.ts

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
import { BasicBackendApi, BasicKVIterStorage, IBackend } from "@terran-one/cosmwasm-vm-js";
2+
import { Map } from "immutable";
3+
import { Ok, Result } from "ts-results";
4+
import { CWSimulateVMInstance } from "../../instrumentation/CWSimulateVMInstance";
5+
import { Coin, ContractResponse, DebugLog, ReplyMsg, Snapshot } from "../../types";
6+
import { fromBinary, fromRustResult } from "../../util";
7+
import type { WasmModule } from "./module";
8+
9+
/** An interface to interact with CW SCs */
10+
export default class Contract {
11+
private _vm: CWSimulateVMInstance | undefined;
12+
13+
constructor(private _wasm: WasmModule, public readonly address: string) {}
14+
15+
async init() {
16+
if (!this._vm) {
17+
const { _wasm: wasm, address } = this;
18+
const contractInfo = wasm.getContractInfo(address);
19+
if (!contractInfo)
20+
throw new Error(`contract ${address} not found`);
21+
22+
const { codeId } = contractInfo;
23+
const codeInfo = wasm.getCodeInfo(codeId);
24+
if (!codeInfo)
25+
throw new Error(`code ${codeId} not found`);
26+
27+
const { wasmCode } = codeInfo;
28+
const contractState = this.getStorage();
29+
30+
let storage = new BasicKVIterStorage();
31+
storage.dict = contractState;
32+
33+
let backend: IBackend = {
34+
backend_api: new BasicBackendApi(wasm.chain.bech32Prefix),
35+
storage,
36+
querier: wasm.chain.querier,
37+
};
38+
39+
const logs: DebugLog[] = [];
40+
const vm = new CWSimulateVMInstance(logs, backend);
41+
await vm.build(wasmCode);
42+
this._vm = vm;
43+
}
44+
return this;
45+
}
46+
47+
instantiate(
48+
sender: string,
49+
funds: Coin[],
50+
instantiateMsg: any,
51+
logs: DebugLog[]
52+
): Result<ContractResponse, string> {
53+
if (!this._vm) throw new NoVMError(this.address);
54+
const vm = this._vm;
55+
const env = this.getExecutionEnv();
56+
const info = { sender, funds };
57+
58+
const res = fromRustResult<ContractResponse>(vm.instantiate(env, info, instantiateMsg).json);
59+
60+
this.setStorage((vm.backend.storage as BasicKVIterStorage).dict);
61+
62+
logs.push(...vm.logs);
63+
64+
return res;
65+
}
66+
67+
execute(
68+
sender: string,
69+
funds: Coin[],
70+
executeMsg: any,
71+
logs: DebugLog[],
72+
): Result<ContractResponse, string>
73+
{
74+
const vm = this._vm;
75+
if (!vm) throw new NoVMError(this.address);
76+
vm.resetDebugInfo();
77+
78+
const env = this.getExecutionEnv();
79+
const info = { sender, funds };
80+
81+
const res = fromRustResult<ContractResponse>(vm.execute(env, info, executeMsg).json);
82+
83+
this.setStorage((vm.backend.storage as BasicKVIterStorage).dict);
84+
85+
logs.push(...vm.logs);
86+
87+
return res;
88+
}
89+
90+
reply(
91+
replyMsg: ReplyMsg,
92+
logs: DebugLog[],
93+
): Result<ContractResponse, string> {
94+
if (!this._vm) throw new NoVMError(this.address);
95+
const vm = this._vm;
96+
const res = fromRustResult<ContractResponse>(vm.reply(this.getExecutionEnv(), replyMsg).json);
97+
98+
this.setStorage((vm.backend.storage as BasicKVIterStorage).dict);
99+
100+
logs.push(...vm.logs);
101+
102+
return res;
103+
}
104+
105+
query(queryMsg: any, store?: Map<string, string>): Result<any, string> {
106+
if (!this._vm) throw new NoVMError(this.address);
107+
const vm = this._vm;
108+
109+
// time travel
110+
const currBackend = vm.backend;
111+
const storage = new BasicKVIterStorage(this.getStorage(store));
112+
vm.backend = {
113+
...vm.backend,
114+
storage,
115+
};
116+
117+
try {
118+
let env = this.getExecutionEnv();
119+
return fromRustResult<string>(vm.query(env, queryMsg).json)
120+
.andThen(v => Ok(fromBinary(v)));
121+
}
122+
// reset time travel
123+
finally {
124+
vm.backend = currBackend;
125+
}
126+
}
127+
128+
setStorage(value: Map<string, string>) {
129+
this._wasm.setContractStorage(this.address, value);
130+
}
131+
132+
getStorage(storage?: Snapshot): Map<string, string> {
133+
return this._wasm.getContractStorage(this.address, storage);
134+
}
135+
136+
getExecutionEnv() {
137+
return this._wasm.getExecutionEnv(this.address);
138+
}
139+
140+
get vm() { return this._vm }
141+
get valid() { return !!this._vm }
142+
}
143+
144+
class NoVMError extends Error {
145+
constructor(contractAddress: string) {
146+
super(`No VM for contract ${contractAddress}`);
147+
}
148+
}

src/modules/wasm/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './module';

0 commit comments

Comments
 (0)