Skip to content

Commit c13b78c

Browse files
authored
Merge pull request #23 from Terran-One/feat/time-travel
Query Time Travel
2 parents 9c04aa7 + ff07089 commit c13b78c

File tree

3 files changed

+68
-7
lines changed

3 files changed

+68
-7
lines changed

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.6.0",
3+
"version": "2.6.1",
44
"description": "Mock blockchain environment for simulating CosmWasm interactions",
55
"main": "dist/index.js",
66
"typings": "dist/index.d.ts",

src/modules/wasm.spec.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,4 +509,40 @@ describe('Query', () => {
509509
admin: null,
510510
});
511511
});
512+
513+
it('time travel', async () => {
514+
const queryMsg = {
515+
get_buffer: {},
516+
};
517+
518+
const traces: TraceLog[] = [];
519+
await testContract.execute(
520+
info.sender,
521+
exec.run(
522+
cmd.msg(exec.push('M1')),
523+
cmd.msg(exec.push('M2')),
524+
cmd.msg(exec.push('M3')),
525+
),
526+
[],
527+
traces,
528+
);
529+
530+
await testContract.execute(
531+
info.sender,
532+
exec.run(
533+
cmd.msg(exec.push('M4')),
534+
),
535+
[],
536+
traces,
537+
);
538+
539+
expect(app.wasm.queryTrace(traces[0], queryMsg).val).toMatchObject({
540+
buffer: ['M1', 'M2', 'M3'],
541+
});
542+
// IMPORTANT: `queryTrace` temporarily alters the backend a VM uses
543+
// so we test here that it resets it
544+
expect(app.wasm.query(testContract.address, queryMsg).val).toMatchObject({
545+
buffer: ['M1', 'M2', 'M3', 'M4'],
546+
});
547+
});
512548
});

src/modules/wasm.ts

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,8 @@ export class WasmModule {
119119
);
120120
}
121121

122-
getContractStorage(contractAddress: string) {
123-
const existing = this.chain.store.getIn([
122+
getContractStorage(contractAddress: string, storage = this.chain.store) {
123+
const existing = storage.getIn([
124124
'wasm',
125125
'contractStorage',
126126
contractAddress,
@@ -135,8 +135,8 @@ export class WasmModule {
135135
);
136136
}
137137

138-
getCodeInfo(codeId: number): CodeInfo {
139-
return this.chain.store.getIn(['wasm', 'codes', codeId]) as CodeInfo;
138+
getCodeInfo(codeId: number, storage = this.chain.store): CodeInfo {
139+
return storage.getIn(['wasm', 'codes', codeId]) as CodeInfo;
140140
}
141141

142142
setContractInfo(contractAddress: string, contractInfo: ContractInfo) {
@@ -146,8 +146,8 @@ export class WasmModule {
146146
);
147147
}
148148

149-
getContractInfo(contractAddress: string) {
150-
return this.chain.store.getIn([
149+
getContractInfo(contractAddress: string, storage = this.chain.store) {
150+
return storage.getIn([
151151
'wasm',
152152
'contracts',
153153
contractAddress,
@@ -637,6 +637,31 @@ export class WasmModule {
637637
return fromRustResult(vm.query(env, queryMsg).json as RustResult<string>)
638638
.andThen(v => Ok(fromBinary(v)));
639639
}
640+
641+
queryTrace(
642+
trace: TraceLog,
643+
queryMsg: any,
644+
): Result<any, string> {
645+
let { contractAddress, storeSnapshot } = trace;
646+
let vm = this.vms[contractAddress];
647+
if (!vm) throw new Error(`No VM for contract ${contractAddress}`);
648+
649+
// time travel
650+
const currBackend = vm.backend;
651+
const storage = new BasicKVIterStorage(this.getContractStorage(contractAddress, storeSnapshot));
652+
vm.backend = {
653+
...vm.backend,
654+
storage,
655+
};
656+
657+
try {
658+
return this.query(contractAddress, queryMsg);
659+
}
660+
// reset time travel
661+
finally {
662+
vm.backend = currBackend;
663+
}
664+
}
640665

641666
buildAppResponse(
642667
contract: string,

0 commit comments

Comments
 (0)