@ton/sandbox 0.11.1 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +5 -2
- package/dist/blockchain/Blockchain.d.ts +4 -0
- package/dist/blockchain/Blockchain.js +76 -47
- package/dist/blockchain/SmartContract.js +6 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.12.0] - 2023-10-03
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Step by step execution (`blockchain.sendMessageIter`)
|
|
13
|
+
- Better docs
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- `now` from `Blockchain` is now honored in `SmartContract.receiveMessage`
|
|
18
|
+
- Exit code 1 is now counted as success in get methods
|
|
19
|
+
|
|
8
20
|
## [0.11.1] - 2023-07-26
|
|
9
21
|
|
|
10
22
|
### Changed
|
package/README.md
CHANGED
|
@@ -261,9 +261,12 @@ it('minter admin should be able to mint jettons', async () => {
|
|
|
261
261
|
});
|
|
262
262
|
```
|
|
263
263
|
|
|
264
|
-
### Test
|
|
265
|
-
You can typically find various tests for Sandbox-based project contracts in the `./tests` directory.
|
|
264
|
+
### Test Examples
|
|
265
|
+
You can typically find various tests for Sandbox-based project contracts in the `./tests` directory.
|
|
266
|
+
Learn more from examples:
|
|
266
267
|
|
|
268
|
+
* [FunC Test Examples](https://docs.ton.org/develop/smart-contracts/examples#examples-of-tests-for-smart-contracts)
|
|
269
|
+
* [Tact Test Examples](docs/tact-testing-examples.md)
|
|
267
270
|
|
|
268
271
|
## Viewing logs
|
|
269
272
|
|
|
@@ -88,11 +88,15 @@ export declare class Blockchain {
|
|
|
88
88
|
get config(): Cell;
|
|
89
89
|
get configBase64(): string;
|
|
90
90
|
sendMessage(message: Message | Cell, params?: MessageParams): Promise<SendMessageResult>;
|
|
91
|
+
sendMessageIter(message: Message | Cell, params?: MessageParams): Promise<AsyncIterator<BlockchainTransaction> & AsyncIterable<BlockchainTransaction>>;
|
|
91
92
|
runTickTock(on: Address | Address[], which: TickOrTock, params?: MessageParams): Promise<SendMessageResult>;
|
|
92
93
|
runGetMethod(address: Address, method: number | string, stack?: TupleItem[], params?: GetMethodParams): Promise<import("./SmartContract").GetMethodResult>;
|
|
93
94
|
protected pushMessage(message: Message | Cell): Promise<void>;
|
|
94
95
|
protected pushTickTock(on: Address, which: TickOrTock): Promise<void>;
|
|
95
96
|
protected runQueue(params?: MessageParams): Promise<SendMessageResult>;
|
|
97
|
+
protected txIter(needsLocking: boolean, params?: MessageParams): AsyncIterator<BlockchainTransaction> & AsyncIterable<BlockchainTransaction>;
|
|
98
|
+
protected processInternal(params?: MessageParams): Promise<IteratorResult<BlockchainTransaction>>;
|
|
99
|
+
protected processTx(needsLocking: boolean, params?: MessageParams): Promise<IteratorResult<BlockchainTransaction>>;
|
|
96
100
|
protected processQueue(params?: MessageParams): Promise<BlockchainTransaction[]>;
|
|
97
101
|
provider(address: Address, init?: {
|
|
98
102
|
code: Cell;
|
|
@@ -89,6 +89,15 @@ class Blockchain {
|
|
|
89
89
|
await this.pushMessage(message);
|
|
90
90
|
return await this.runQueue(params);
|
|
91
91
|
}
|
|
92
|
+
async sendMessageIter(message, params) {
|
|
93
|
+
params = {
|
|
94
|
+
now: this.now,
|
|
95
|
+
...params,
|
|
96
|
+
};
|
|
97
|
+
await this.pushMessage(message);
|
|
98
|
+
// Iterable will lock on per tx basis
|
|
99
|
+
return await this.txIter(true, params);
|
|
100
|
+
}
|
|
92
101
|
async runTickTock(on, which, params) {
|
|
93
102
|
for (const addr of (Array.isArray(on) ? on : [on])) {
|
|
94
103
|
await this.pushTickTock(addr, which);
|
|
@@ -130,60 +139,80 @@ class Blockchain {
|
|
|
130
139
|
externals: txes.map(tx => tx.externals).flat(),
|
|
131
140
|
};
|
|
132
141
|
}
|
|
142
|
+
txIter(needsLocking, params) {
|
|
143
|
+
const it = { next: () => this.processTx(needsLocking, params), [Symbol.asyncIterator]() { return it; } };
|
|
144
|
+
return it;
|
|
145
|
+
}
|
|
146
|
+
async processInternal(params) {
|
|
147
|
+
let result = undefined;
|
|
148
|
+
let done = this.messageQueue.length == 0;
|
|
149
|
+
while (!done) {
|
|
150
|
+
const message = this.messageQueue.shift();
|
|
151
|
+
let tx;
|
|
152
|
+
if (message.type === 'message') {
|
|
153
|
+
if (message.info.type === 'external-out') {
|
|
154
|
+
done = this.messageQueue.length == 0;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
this.currentLt += LT_ALIGN;
|
|
158
|
+
tx = (await this.getContract(message.info.dest)).receiveMessage(message, params);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
this.currentLt += LT_ALIGN;
|
|
162
|
+
tx = (await this.getContract(message.on)).runTickTock(message.which, params);
|
|
163
|
+
}
|
|
164
|
+
const transaction = {
|
|
165
|
+
...tx,
|
|
166
|
+
events: (0, Event_1.extractEvents)(tx),
|
|
167
|
+
parent: message.parentTransaction,
|
|
168
|
+
children: [],
|
|
169
|
+
externals: [],
|
|
170
|
+
};
|
|
171
|
+
transaction.parent?.children.push(transaction);
|
|
172
|
+
result = transaction;
|
|
173
|
+
done = true;
|
|
174
|
+
for (const message of transaction.outMessages.values()) {
|
|
175
|
+
if (message.info.type === 'external-out') {
|
|
176
|
+
transaction.externals.push({
|
|
177
|
+
info: {
|
|
178
|
+
type: 'external-out',
|
|
179
|
+
src: message.info.src,
|
|
180
|
+
dest: message.info.dest ?? undefined,
|
|
181
|
+
createdAt: message.info.createdAt,
|
|
182
|
+
createdLt: message.info.createdLt,
|
|
183
|
+
},
|
|
184
|
+
init: message.init ?? undefined,
|
|
185
|
+
body: message.body,
|
|
186
|
+
});
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
this.messageQueue.push({
|
|
190
|
+
type: 'message',
|
|
191
|
+
parentTransaction: transaction,
|
|
192
|
+
...message,
|
|
193
|
+
});
|
|
194
|
+
if (message.info.type === 'internal') {
|
|
195
|
+
this.startFetchingContract(message.info.dest);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return result === undefined ? { value: result, done: true } : { value: result, done: false };
|
|
200
|
+
}
|
|
201
|
+
async processTx(needsLocking, params) {
|
|
202
|
+
// Lock only if not locked already
|
|
203
|
+
return needsLocking ? await this.lock.with(async () => this.processInternal(params)) : await this.processInternal(params);
|
|
204
|
+
}
|
|
133
205
|
async processQueue(params) {
|
|
134
206
|
params = {
|
|
135
207
|
now: this.now,
|
|
136
208
|
...params,
|
|
137
209
|
};
|
|
138
210
|
return await this.lock.with(async () => {
|
|
211
|
+
// Locked already
|
|
212
|
+
const txs = this.txIter(false, params);
|
|
139
213
|
const result = [];
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
let tx;
|
|
143
|
-
if (message.type === 'message') {
|
|
144
|
-
if (message.info.type === 'external-out') {
|
|
145
|
-
continue;
|
|
146
|
-
}
|
|
147
|
-
this.currentLt += LT_ALIGN;
|
|
148
|
-
tx = (await this.getContract(message.info.dest)).receiveMessage(message, params);
|
|
149
|
-
}
|
|
150
|
-
else {
|
|
151
|
-
this.currentLt += LT_ALIGN;
|
|
152
|
-
tx = (await this.getContract(message.on)).runTickTock(message.which, params);
|
|
153
|
-
}
|
|
154
|
-
const transaction = {
|
|
155
|
-
...tx,
|
|
156
|
-
events: (0, Event_1.extractEvents)(tx),
|
|
157
|
-
parent: message.parentTransaction,
|
|
158
|
-
children: [],
|
|
159
|
-
externals: [],
|
|
160
|
-
};
|
|
161
|
-
transaction.parent?.children.push(transaction);
|
|
162
|
-
result.push(transaction);
|
|
163
|
-
for (const message of transaction.outMessages.values()) {
|
|
164
|
-
if (message.info.type === 'external-out') {
|
|
165
|
-
transaction.externals.push({
|
|
166
|
-
info: {
|
|
167
|
-
type: 'external-out',
|
|
168
|
-
src: message.info.src,
|
|
169
|
-
dest: message.info.dest ?? undefined,
|
|
170
|
-
createdAt: message.info.createdAt,
|
|
171
|
-
createdLt: message.info.createdLt,
|
|
172
|
-
},
|
|
173
|
-
init: message.init ?? undefined,
|
|
174
|
-
body: message.body,
|
|
175
|
-
});
|
|
176
|
-
continue;
|
|
177
|
-
}
|
|
178
|
-
this.messageQueue.push({
|
|
179
|
-
type: 'message',
|
|
180
|
-
parentTransaction: transaction,
|
|
181
|
-
...message,
|
|
182
|
-
});
|
|
183
|
-
if (message.info.type === 'internal') {
|
|
184
|
-
this.startFetchingContract(message.info.dest);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
214
|
+
for await (const tx of txs) {
|
|
215
|
+
result.push(tx);
|
|
187
216
|
}
|
|
188
217
|
return result;
|
|
189
218
|
});
|
|
@@ -181,6 +181,11 @@ class SmartContract {
|
|
|
181
181
|
};
|
|
182
182
|
}
|
|
183
183
|
receiveMessage(message, params) {
|
|
184
|
+
// Sync now with blockchain instance if not specified in parameters
|
|
185
|
+
params = {
|
|
186
|
+
now: this.blockchain.now,
|
|
187
|
+
...params,
|
|
188
|
+
};
|
|
184
189
|
return this.runCommon(() => this.blockchain.executor.runTransaction({
|
|
185
190
|
...this.createCommonArgs(params),
|
|
186
191
|
message: (0, core_1.beginCell)().store((0, core_1.storeMessage)(message)).endCell(),
|
|
@@ -249,7 +254,7 @@ class SmartContract {
|
|
|
249
254
|
if (this.verbosity.print && this.verbosity.debugLogs && res.debugLogs.length > 0) {
|
|
250
255
|
console.log(res.debugLogs);
|
|
251
256
|
}
|
|
252
|
-
if (res.output.vm_exit_code !== 0) {
|
|
257
|
+
if (res.output.vm_exit_code !== 0 && res.output.vm_exit_code !== 1) {
|
|
253
258
|
throw new GetMethodError(res.output.vm_exit_code, BigInt(res.output.gas_used), res.logs, res.output.vm_log, res.debugLogs);
|
|
254
259
|
}
|
|
255
260
|
const resStack = (0, core_1.parseTuple)(core_1.Cell.fromBase64(res.output.stack));
|