Skip to content

Commit 3cf396f

Browse files
ouiliameLuke Wilson
andauthored
Add support for saving debugging messages, generic queriers (#55)
* Fix types import * add debugMsgs to VMInstance, make BasicQuerier generic Co-authored-by: Luke Wilson <[email protected]>
1 parent e56304c commit 3cf396f

File tree

6 files changed

+63
-51
lines changed

6 files changed

+63
-51
lines changed

src/backend/backendApi.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@ export class GasInfo implements IGasInfo {
2929
}
3030

3131
export interface IBackendApi {
32+
bech32_prefix: string;
3233
canonical_address(human: string): Uint8Array;
33-
3434
human_address(canonical: Uint8Array): string;
3535
}
3636

37-
export class BasicBackendApi implements BasicBackendApi {
37+
export class BasicBackendApi implements IBackendApi {
3838
// public GAS_COST_CANONICALIZE = 55;
3939
public CANONICAL_LENGTH = 54;
4040
public EXCESS_PADDING = 6;

src/backend/querier.ts

Lines changed: 9 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,28 @@
11
export interface IQuerier {
22
query_raw(request: Uint8Array, gas_limit: number /* Uint64 */): Uint8Array;
3-
update_balance(addr: string, balance: { amount: string, denom: string }[]): { amount: string, denom: string }[];
43
}
54

65
export class BasicQuerier implements IQuerier {
7-
private balances: Map<string, { amount: string, denom: string }[]> = new Map();
8-
9-
constructor() {
10-
this.query_raw = this.query_raw.bind(this);
11-
}
12-
13-
update_balance(addr: string, balance: { amount: string; denom: string; }[]): { amount: string; denom: string; }[] {
14-
this.balances.set(addr, balance);
15-
return balance;
16-
}
176

187
// eslint-disable-next-line @typescript-eslint/no-unused-vars
198
query_raw(request: Uint8Array, gas_limit: number): Uint8Array {
20-
const [query, type] = parseQuery(request);
9+
const queryRequest = parseQuery(request);
2110

22-
switch (type) {
23-
case QueryType.AllBalances:
24-
const address = query.bank.all_balances.address as string;
25-
const balances = { amount: this.balances.get(address) || [] };
26-
return objectToUint8Array({ok: {ok: objectToBase64(balances)}});
11+
// TODO: make room for error
12+
// The Ok(Ok(x)) represents SystemResult<ContractResult<Binary>>
2713

28-
default:
29-
throw new Error('Not implemented');
30-
}
14+
return objectToUint8Array({ ok: { ok: objectToBase64(this.handleQuery(queryRequest)) }});
15+
}
3116

32-
// ToDo: gas
17+
handleQuery(queryRequest: any): any {
18+
throw new Error(`Unimplemented - subclass BasicQuerier and provide handleQuery() implementation.`)
3319
}
3420
}
3521

36-
enum QueryType { AllBalances }
3722

38-
function parseQuery(bytes: Uint8Array): [any, QueryType] {
23+
function parseQuery(bytes: Uint8Array): any {
3924
const query = JSON.parse(new TextDecoder().decode(bytes));
40-
return [query, queryType(query)];
41-
}
42-
43-
function queryType(query: any): QueryType {
44-
if (query.bank?.all_balances) {
45-
return QueryType.AllBalances;
46-
}
47-
48-
throw new Error('Not implemented');
25+
return query;
4926
}
5027

5128
function objectToBase64(obj: object): string {

src/backend/storage.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Immutable from 'immutable';
44
import { MAX_LENGTH_DB_KEY } from '../instance';
55

66
export interface IStorage {
7+
dict: Immutable.Map<string, string>;
78
get(key: Uint8Array): Uint8Array | null;
89

910
set(key: Uint8Array, value: Uint8Array): void;
@@ -71,8 +72,8 @@ export class BasicKVStorage implements IStorage {
7172
}
7273

7374
export class BasicKVIterStorage extends BasicKVStorage implements IIterStorage {
74-
constructor(public iterators: Map<number, Iter> = new Map()) {
75-
super();
75+
constructor(public dict: Immutable.Map<string, string> = Immutable.Map(), public iterators: Map<number, Iter> = new Map()) {
76+
super(dict);
7677
}
7778

7879
all(iterator_id: Uint8Array): Array<Record> {

src/instance.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ export const MAX_LENGTH_CANONICAL_ADDRESS: number = 64;
1212
export const MAX_LENGTH_HUMAN_ADDRESS: number = 256;
1313

1414
export class VMInstance {
15-
public PREFIX: string = 'terra';
1615
public instance?: WebAssembly.Instance;
1716
public bech32: BechLib;
17+
public debugMsgs: string[] = [];
1818

1919
constructor(public backend: IBackend, public readonly gasLimit?: number | undefined) {
2020
this.bech32 = bech32;
@@ -336,9 +336,8 @@ export class VMInstance {
336336
throw new Error('Invalid address.');
337337
}
338338

339-
// TODO: Change prefix to be configurable per environment
340339
const human = this.bech32.encode(
341-
this.PREFIX,
340+
this.backend.backend_api.bech32_prefix,
342341
this.bech32.toWords(canonical)
343342
);
344343
if (human !== source.str) {
@@ -453,7 +452,7 @@ export class VMInstance {
453452
}
454453

455454
do_debug(message: Region) {
456-
console.log(message.read_str());
455+
this.debugMsgs.push(message.read_str());
457456
}
458457

459458
do_query_chain(request: Region): Region {

test/integration/burner.test.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,17 @@ import {
1717
import { toAscii } from '@cosmjs/encoding';
1818
import { Env, MessageInfo } from '../../src/types';
1919

20+
class MockQuerier extends BasicQuerier {
21+
handleQuery(request: any): any {
22+
return { amount: [{ denom: 'earth', amount: '1000' }] }
23+
}
24+
}
25+
2026
const wasmBytecode = readFileSync('testdata/v1.1/burner.wasm');
2127
const backend: IBackend = {
2228
backend_api: new BasicBackendApi('terra'),
2329
storage: new BasicKVIterStorage(),
24-
querier: new BasicQuerier(),
30+
querier: new MockQuerier(),
2531
};
2632

2733
const creator = 'terra1337xewwfv3jdjuz8e0nea9vd8dpugc0k2dcyt3';

test/integration/hackatom.test.ts

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,39 @@ import {
44
BasicBackendApi,
55
BasicKVIterStorage,
66
BasicQuerier,
7-
IBackend,
87
} from '../../src/backend';
98
import { fromBase64 } from '@cosmjs/encoding';
109
import { Region } from '../../src/memory';
1110
import { expectResponseToBeOk, parseBase64Response } from '../common/test-vm';
1211

12+
type HackatomQueryRequest = {
13+
bank: {
14+
all_balances: {
15+
address: string
16+
}
17+
}
18+
}
19+
class HackatomMockQuerier extends BasicQuerier {
20+
private balances: Map<string, { amount: string, denom: string }[]> = new Map();
21+
22+
update_balance(addr: string, balance: { amount: string; denom: string; }[]): { amount: string; denom: string; }[] {
23+
this.balances.set(addr, balance);
24+
return balance;
25+
}
26+
27+
handleQuery(queryRequest: HackatomQueryRequest): any {
28+
if ('bank' in queryRequest) {
29+
if ('all_balances' in queryRequest.bank) {
30+
const { address } = queryRequest.bank.all_balances;
31+
return { amount: this.balances.get(address) || [] }
32+
}
33+
}
34+
35+
throw new Error(`unknown query: ${JSON.stringify(queryRequest)}`);
36+
}
37+
}
38+
1339
const wasmBytecode = readFileSync('testdata/v1.1/hackatom.wasm');
14-
const backend: IBackend = {
15-
backend_api: new BasicBackendApi('terra'),
16-
storage: new BasicKVIterStorage(),
17-
querier: new BasicQuerier(),
18-
};
1940

2041
const verifier = 'terra1kzsrgcktshvqe9p089lqlkadscqwkezy79t8y9';
2142
const beneficiary = 'terra1zdpgj8am5nqqvht927k3etljyl6a52kwqup0je';
@@ -38,11 +59,19 @@ const mockInfo: { sender: string, funds: { amount: string, denom: string }[] } =
3859

3960
let vm: VMInstance;
4061
describe('hackatom', () => {
62+
let querier: HackatomMockQuerier;
63+
4164
beforeEach(async () => {
42-
vm = new VMInstance(backend);
65+
querier = new HackatomMockQuerier();
66+
vm = new VMInstance({
67+
backend_api: new BasicBackendApi('terra'),
68+
storage: new BasicKVIterStorage(),
69+
querier
70+
});
4371
await vm.build(wasmBytecode);
4472
});
4573

74+
4675
it('proper_initialization', async () => {
4776
// Act
4877
const instantiateResponse = vm.instantiate(mockEnv, mockInfo, { verifier, beneficiary });
@@ -93,7 +122,7 @@ describe('hackatom', () => {
93122
// Arrange
94123
const richAddress = 'foobar';
95124
const richBalance = [{ amount: '10000', denom: 'gold' }];
96-
vm.backend.querier.update_balance(richAddress, richBalance);
125+
querier.update_balance(richAddress, richBalance);
97126

98127
vm.instantiate(mockEnv, mockInfo, { verifier, beneficiary });
99128

@@ -123,7 +152,7 @@ describe('hackatom', () => {
123152
it('execute_release_works', async () => {
124153
// Arrange
125154
vm.instantiate(mockEnv, mockInfo, { verifier, beneficiary });
126-
vm.backend.querier.update_balance(mockContractAddr, [{ amount: '1000', denom: 'earth' }]);
155+
querier.update_balance(mockContractAddr, [{ amount: '1000', denom: 'earth' }]);
127156

128157
// Act
129158
const execResponse = vm.execute(
@@ -149,7 +178,7 @@ describe('hackatom', () => {
149178
it('execute_release_fails_for_wrong_sender', async () => {
150179
// Arrange
151180
vm.instantiate(mockEnv, mockInfo, { verifier, beneficiary });
152-
vm.backend.querier.update_balance(mockContractAddr, [{ amount: '1000', denom: 'earth' }]);
181+
querier.update_balance(mockContractAddr, [{ amount: '1000', denom: 'earth' }]);
153182

154183
// Act
155184
const execResponse = vm.execute(

0 commit comments

Comments
 (0)