@ton/sandbox 0.39.0 → 0.41.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 +23 -0
- package/dist/blockchain/Blockchain.d.ts +15 -1
- package/dist/blockchain/Blockchain.js +45 -8
- package/dist/blockchain/MessageQueueManager.d.ts +2 -2
- package/dist/blockchain/MessageQueueManager.js +6 -3
- package/dist/blockchain/SmartContract.d.ts +3 -2
- package/dist/blockchain/SmartContract.js +5 -4
- package/dist/executor/Executor.d.ts +0 -2
- package/dist/executor/Executor.js +38 -33
- package/dist/executor/emulator-emscripten.debugger.bpatch.gzip.js +1 -1
- package/dist/executor/emulator-emscripten.debugger.js +2 -2
- package/dist/executor/emulator-emscripten.js +2 -20
- package/dist/executor/emulator-emscripten.wasm.js +1 -1
- package/dist/jest/uiSetup.d.ts +1 -0
- package/dist/jest/uiSetup.js +38 -0
- package/dist/ui/UIManager.d.ts +18 -0
- package/dist/ui/UIManager.js +31 -0
- package/dist/ui/connection/UIConnector.d.ts +3 -0
- package/dist/ui/connection/UIConnector.js +2 -0
- package/dist/ui/connection/websocket/ManagedWebSocketConnector.d.ts +10 -0
- package/dist/ui/connection/websocket/ManagedWebSocketConnector.js +38 -0
- package/dist/ui/connection/websocket/OneTimeWebSocketConnector.d.ts +7 -0
- package/dist/ui/connection/websocket/OneTimeWebSocketConnector.js +31 -0
- package/dist/ui/connection/websocket/constants.d.ts +3 -0
- package/dist/ui/connection/websocket/constants.js +6 -0
- package/dist/ui/connection/websocket/types.d.ts +4 -0
- package/dist/ui/connection/websocket/types.js +2 -0
- package/dist/ui/protocol.d.ts +48 -0
- package/dist/ui/protocol.js +48 -0
- package/dist/utils/environment.d.ts +7 -0
- package/dist/utils/environment.js +15 -0
- package/dist/utils/noop.d.ts +1 -0
- package/dist/utils/noop.js +4 -0
- package/dist/utils/require.d.ts +1 -1
- package/dist/utils/require.js +5 -8
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,29 @@ 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.41.0] - 2025-12-05
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Updated emulator WASM binary
|
|
13
|
+
- Debug logs are now extracted from VM logs (due to emulator changes), which interacts in subtle ways with the verbosity settings
|
|
14
|
+
|
|
15
|
+
## [0.40.0] - 2025-12-04
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- Sandbox UI support
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- Updated emulator WASM binary
|
|
24
|
+
- Updated dependencies
|
|
25
|
+
- `Blockchain` now allows null code and data in state init
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- Fixed `@ton/test-utils` import
|
|
30
|
+
|
|
8
31
|
## [0.39.0] - 2025-10-29
|
|
9
32
|
|
|
10
33
|
### Changed
|
|
@@ -10,6 +10,9 @@ import { Coverage } from '../coverage';
|
|
|
10
10
|
import { MessageQueueManager } from './MessageQueueManager';
|
|
11
11
|
import { AsyncLock } from '../utils/AsyncLock';
|
|
12
12
|
import { BlockchainSnapshot } from './BlockchainSnapshot';
|
|
13
|
+
import { IUIConnector } from '../ui/connection/UIConnector';
|
|
14
|
+
import { WebSocketConnectionOptions } from '../ui/connection/websocket/types';
|
|
15
|
+
import { IUIManager } from '../ui/UIManager';
|
|
13
16
|
export type ExternalOutInfo = {
|
|
14
17
|
type: 'external-out';
|
|
15
18
|
src: Address;
|
|
@@ -59,6 +62,7 @@ export type SandboxContract<F> = {
|
|
|
59
62
|
export declare function toSandboxContract<T>(contract: OpenedContract<T>): SandboxContract<T>;
|
|
60
63
|
export type PendingMessage = (({
|
|
61
64
|
type: 'message';
|
|
65
|
+
callStack?: string;
|
|
62
66
|
mode?: number;
|
|
63
67
|
} & Message) | {
|
|
64
68
|
type: 'ticktock';
|
|
@@ -84,6 +88,10 @@ export type BlockchainConfig = Cell | 'default' | 'slim';
|
|
|
84
88
|
export type SendMessageIterParams = MessageParams & {
|
|
85
89
|
allowParallel?: boolean;
|
|
86
90
|
};
|
|
91
|
+
export type UIOptions = {
|
|
92
|
+
enabled?: boolean;
|
|
93
|
+
connector?: IUIConnector;
|
|
94
|
+
} & WebSocketConnectionOptions;
|
|
87
95
|
export declare class Blockchain {
|
|
88
96
|
protected lock: AsyncLock;
|
|
89
97
|
protected storage: BlockchainStorage;
|
|
@@ -102,6 +110,7 @@ export declare class Blockchain {
|
|
|
102
110
|
protected autoDeployLibs: boolean;
|
|
103
111
|
protected transactions: BlockchainTransaction[];
|
|
104
112
|
protected defaultQueueManager: MessageQueueManager;
|
|
113
|
+
protected uiManager: IUIManager;
|
|
105
114
|
protected collectCoverage: boolean;
|
|
106
115
|
protected readonly coverageTransactions: BlockchainTransaction[][];
|
|
107
116
|
protected readonly coverageGetMethodResults: GetMethodResult[];
|
|
@@ -155,7 +164,9 @@ export declare class Blockchain {
|
|
|
155
164
|
storage: BlockchainStorage;
|
|
156
165
|
meta?: ContractsMeta;
|
|
157
166
|
autoDeployLibs?: boolean;
|
|
167
|
+
uiOptions?: UIOptions;
|
|
158
168
|
});
|
|
169
|
+
protected createUiManager(opts?: UIOptions): IUIManager;
|
|
159
170
|
protected createQueueManager(): MessageQueueManager;
|
|
160
171
|
/**
|
|
161
172
|
* @returns Config used in blockchain.
|
|
@@ -332,11 +343,12 @@ export declare class Blockchain {
|
|
|
332
343
|
* Opens contract. Returns proxy that substitutes the blockchain Provider in methods starting with get and set.
|
|
333
344
|
*
|
|
334
345
|
* @param contract Contract to open.
|
|
346
|
+
* @param name Name of the contract.
|
|
335
347
|
*
|
|
336
348
|
* @example
|
|
337
349
|
* const contract = blockchain.openContract(new Contract(address));
|
|
338
350
|
*/
|
|
339
|
-
openContract<T extends Contract>(contract: T): SandboxContract<T>;
|
|
351
|
+
openContract<T extends Contract>(contract: T, name?: string): SandboxContract<T>;
|
|
340
352
|
protected startFetchingContract(address: Address): Promise<SmartContract>;
|
|
341
353
|
/**
|
|
342
354
|
* Retrieves {@link SmartContract} from {@link BlockchainStorage}.
|
|
@@ -444,6 +456,7 @@ export declare class Blockchain {
|
|
|
444
456
|
* @param [opts.storage] Contracts storage used for blockchain. If omitted {@link LocalBlockchainStorage} is used.
|
|
445
457
|
* @param [opts.meta] Optional contracts metadata provider. If not provided, {@link @ton/test-utils.contractsMeta} will be used to accumulate contracts metadata.
|
|
446
458
|
* @param [opts.autoDeployLibs] Optional flag. If set to true, libraries will be collected automatically
|
|
459
|
+
* @param [opts.uiOptions] Optional object to configure the UI connector.
|
|
447
460
|
* @example
|
|
448
461
|
* const blockchain = await Blockchain.create({ config: 'slim' });
|
|
449
462
|
*
|
|
@@ -462,6 +475,7 @@ export declare class Blockchain {
|
|
|
462
475
|
storage?: BlockchainStorage;
|
|
463
476
|
meta?: ContractsMeta;
|
|
464
477
|
autoDeployLibs?: boolean;
|
|
478
|
+
uiOptions?: UIOptions;
|
|
465
479
|
}): Promise<Blockchain>;
|
|
466
480
|
}
|
|
467
481
|
export {};
|
|
@@ -19,6 +19,10 @@ const coverage_1 = require("../coverage");
|
|
|
19
19
|
const MessageQueueManager_1 = require("./MessageQueueManager");
|
|
20
20
|
const AsyncLock_1 = require("../utils/AsyncLock");
|
|
21
21
|
const require_1 = require("../utils/require");
|
|
22
|
+
const noop_1 = require("../utils/noop");
|
|
23
|
+
const environment_1 = require("../utils/environment");
|
|
24
|
+
const OneTimeWebSocketConnector_1 = require("../ui/connection/websocket/OneTimeWebSocketConnector");
|
|
25
|
+
const UIManager_1 = require("../ui/UIManager");
|
|
22
26
|
const CREATE_WALLETS_PREFIX = 'CREATE_WALLETS';
|
|
23
27
|
function createWalletsSeed(idx) {
|
|
24
28
|
return `${CREATE_WALLETS_PREFIX}${idx}`;
|
|
@@ -72,6 +76,7 @@ class Blockchain {
|
|
|
72
76
|
autoDeployLibs;
|
|
73
77
|
transactions = [];
|
|
74
78
|
defaultQueueManager;
|
|
79
|
+
uiManager;
|
|
75
80
|
collectCoverage = false;
|
|
76
81
|
coverageTransactions = [];
|
|
77
82
|
coverageGetMethodResults = [];
|
|
@@ -180,6 +185,18 @@ class Blockchain {
|
|
|
180
185
|
this.meta = opts.meta;
|
|
181
186
|
this.autoDeployLibs = opts.autoDeployLibs ?? false;
|
|
182
187
|
this.defaultQueueManager = this.createQueueManager();
|
|
188
|
+
this.uiManager = this.createUiManager(opts.uiOptions);
|
|
189
|
+
}
|
|
190
|
+
createUiManager(opts) {
|
|
191
|
+
if (!opts?.enabled) {
|
|
192
|
+
// noop implementation
|
|
193
|
+
return { publishTransactions: noop_1.noop };
|
|
194
|
+
}
|
|
195
|
+
const connector = opts.connector ?? new OneTimeWebSocketConnector_1.OneTimeWebSocketConnector(opts);
|
|
196
|
+
return new UIManager_1.UIManager(connector, {
|
|
197
|
+
getMeta: (address) => this.meta?.get(address),
|
|
198
|
+
knownContracts: () => this.storage.knownContracts(),
|
|
199
|
+
});
|
|
183
200
|
}
|
|
184
201
|
createQueueManager() {
|
|
185
202
|
return new MessageQueueManager_1.MessageQueueManager(this.lock, {
|
|
@@ -189,8 +206,11 @@ class Blockchain {
|
|
|
189
206
|
getLibs: () => this.libs,
|
|
190
207
|
setLibs: (value) => (this.libs = value),
|
|
191
208
|
getAutoDeployLibs: () => this.autoDeployLibs,
|
|
192
|
-
|
|
193
|
-
|
|
209
|
+
onTransactions: (txs) => {
|
|
210
|
+
this.registerTxsForCoverage(txs);
|
|
211
|
+
this.uiManager.publishTransactions(txs);
|
|
212
|
+
},
|
|
213
|
+
onTransaction: (transaction) => this.transactions.push(transaction),
|
|
194
214
|
});
|
|
195
215
|
}
|
|
196
216
|
/**
|
|
@@ -456,11 +476,12 @@ class Blockchain {
|
|
|
456
476
|
* Opens contract. Returns proxy that substitutes the blockchain Provider in methods starting with get and set.
|
|
457
477
|
*
|
|
458
478
|
* @param contract Contract to open.
|
|
479
|
+
* @param name Name of the contract.
|
|
459
480
|
*
|
|
460
481
|
* @example
|
|
461
482
|
* const contract = blockchain.openContract(new Contract(address));
|
|
462
483
|
*/
|
|
463
|
-
openContract(contract) {
|
|
484
|
+
openContract(contract, name) {
|
|
464
485
|
let address;
|
|
465
486
|
let init = undefined;
|
|
466
487
|
if (!core_1.Address.isAddress(contract.address)) {
|
|
@@ -468,15 +489,19 @@ class Blockchain {
|
|
|
468
489
|
}
|
|
469
490
|
address = contract.address;
|
|
470
491
|
if (contract.init) {
|
|
471
|
-
if (
|
|
492
|
+
if (contract.init.code !== undefined &&
|
|
493
|
+
contract.init.code !== null &&
|
|
494
|
+
!(contract.init.code instanceof core_1.Cell)) {
|
|
472
495
|
throw Error('Invalid init.code');
|
|
473
496
|
}
|
|
474
|
-
if (
|
|
497
|
+
if (contract.init.data !== undefined &&
|
|
498
|
+
contract.init.data !== null &&
|
|
499
|
+
!(contract.init.data instanceof core_1.Cell)) {
|
|
475
500
|
throw Error('Invalid init.data');
|
|
476
501
|
}
|
|
477
502
|
init = contract.init;
|
|
478
503
|
}
|
|
479
|
-
this.meta?.upsert(address, { wrapperName: contract?.constructor?.name, abi: contract.abi });
|
|
504
|
+
this.meta?.upsert(address, { wrapperName: name ?? contract?.constructor?.name, abi: contract.abi });
|
|
480
505
|
const provider = this.provider(address, init);
|
|
481
506
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
482
507
|
return new Proxy(contract, {
|
|
@@ -596,6 +621,7 @@ class Blockchain {
|
|
|
596
621
|
*/
|
|
597
622
|
enableCoverage(enable = true) {
|
|
598
623
|
this.collectCoverage = enable;
|
|
624
|
+
this.verbosity.print = false;
|
|
599
625
|
this.verbosity.vmLogs = 'vm_logs_verbose';
|
|
600
626
|
}
|
|
601
627
|
/**
|
|
@@ -678,6 +704,7 @@ class Blockchain {
|
|
|
678
704
|
* @param [opts.storage] Contracts storage used for blockchain. If omitted {@link LocalBlockchainStorage} is used.
|
|
679
705
|
* @param [opts.meta] Optional contracts metadata provider. If not provided, {@link @ton/test-utils.contractsMeta} will be used to accumulate contracts metadata.
|
|
680
706
|
* @param [opts.autoDeployLibs] Optional flag. If set to true, libraries will be collected automatically
|
|
707
|
+
* @param [opts.uiOptions] Optional object to configure the UI connector.
|
|
681
708
|
* @example
|
|
682
709
|
* const blockchain = await Blockchain.create({ config: 'slim' });
|
|
683
710
|
*
|
|
@@ -691,12 +718,22 @@ class Blockchain {
|
|
|
691
718
|
* });
|
|
692
719
|
*/
|
|
693
720
|
static async create(opts) {
|
|
694
|
-
|
|
721
|
+
const uiEnabled = opts?.uiOptions?.enabled ?? (0, environment_1.getOptionalEnv)('SANDBOX_UI_ENABLED', 'boolean');
|
|
722
|
+
const blockchain = new Blockchain({
|
|
695
723
|
executor: opts?.executor ?? (await Executor_1.Executor.create()),
|
|
696
724
|
storage: opts?.storage ?? new BlockchainStorage_1.LocalBlockchainStorage(),
|
|
697
|
-
meta: opts?.meta ?? (0, require_1.
|
|
725
|
+
meta: opts?.meta ?? (0, require_1.requireTestUtils)()?.contractsMeta,
|
|
698
726
|
...opts,
|
|
727
|
+
uiOptions: {
|
|
728
|
+
enabled: uiEnabled,
|
|
729
|
+
...opts?.uiOptions,
|
|
730
|
+
},
|
|
699
731
|
});
|
|
732
|
+
if (uiEnabled) {
|
|
733
|
+
blockchain.verbosity.print = false;
|
|
734
|
+
blockchain.verbosity.vmLogs = 'vm_logs_verbose';
|
|
735
|
+
}
|
|
736
|
+
return blockchain;
|
|
700
737
|
}
|
|
701
738
|
}
|
|
702
739
|
exports.Blockchain = Blockchain;
|
|
@@ -14,8 +14,8 @@ export declare class MessageQueueManager {
|
|
|
14
14
|
getLibs(): Cell | undefined;
|
|
15
15
|
setLibs(libs: Cell | undefined): void;
|
|
16
16
|
getAutoDeployLibs(): boolean;
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
onTransactions(txs: BlockchainTransaction[]): void;
|
|
18
|
+
onTransaction(transaction: BlockchainTransaction): void;
|
|
19
19
|
});
|
|
20
20
|
pushMessage(message: Message | Cell): Promise<void>;
|
|
21
21
|
pushTickTock(on: Address, which: TickOrTock): Promise<void>;
|
|
@@ -65,7 +65,7 @@ class MessageQueueManager {
|
|
|
65
65
|
}
|
|
66
66
|
return result;
|
|
67
67
|
});
|
|
68
|
-
this.blockchain.
|
|
68
|
+
this.blockchain.onTransactions(results);
|
|
69
69
|
return results;
|
|
70
70
|
}
|
|
71
71
|
async processMessage(params) {
|
|
@@ -73,16 +73,18 @@ class MessageQueueManager {
|
|
|
73
73
|
let done = this.messageQueue.length == 0;
|
|
74
74
|
while (!done) {
|
|
75
75
|
const message = this.messageQueue.shift();
|
|
76
|
+
let callStack;
|
|
76
77
|
let tx;
|
|
77
78
|
let smartContract;
|
|
78
79
|
if (message.type === 'message') {
|
|
80
|
+
callStack = message.callStack;
|
|
79
81
|
if (message.info.type === 'external-out') {
|
|
80
82
|
done = this.messageQueue.length == 0;
|
|
81
83
|
continue;
|
|
82
84
|
}
|
|
83
85
|
this.blockchain.increaseLt();
|
|
84
86
|
smartContract = await this.blockchain.getContract(message.info.dest);
|
|
85
|
-
tx = await smartContract.receiveMessage(message, params);
|
|
87
|
+
tx = await smartContract.receiveMessage(message, params, callStack);
|
|
86
88
|
}
|
|
87
89
|
else {
|
|
88
90
|
this.blockchain.increaseLt();
|
|
@@ -98,7 +100,7 @@ class MessageQueueManager {
|
|
|
98
100
|
mode: message.type === 'message' ? message.mode : undefined,
|
|
99
101
|
};
|
|
100
102
|
transaction.parent?.children.push(transaction);
|
|
101
|
-
this.blockchain.
|
|
103
|
+
this.blockchain.onTransaction(transaction);
|
|
102
104
|
result = transaction;
|
|
103
105
|
done = true;
|
|
104
106
|
const sendMsgActions = (transaction.outActions?.filter((action) => action.type === 'sendMsg') ??
|
|
@@ -122,6 +124,7 @@ class MessageQueueManager {
|
|
|
122
124
|
type: 'message',
|
|
123
125
|
parentTransaction: transaction,
|
|
124
126
|
mode: sendMsgActions[index]?.mode,
|
|
127
|
+
callStack,
|
|
125
128
|
...message,
|
|
126
129
|
});
|
|
127
130
|
if (message.info.type === 'internal') {
|
|
@@ -30,6 +30,7 @@ export type SmartContractTransaction = Transaction & {
|
|
|
30
30
|
blockchainLogs: string;
|
|
31
31
|
vmLogs: string;
|
|
32
32
|
debugLogs: string;
|
|
33
|
+
callStack?: string;
|
|
33
34
|
oldStorage?: Cell;
|
|
34
35
|
newStorage?: Cell;
|
|
35
36
|
outActions?: OutActionExtended[];
|
|
@@ -109,9 +110,9 @@ export declare class SmartContract {
|
|
|
109
110
|
}): SmartContract;
|
|
110
111
|
static empty(blockchain: Blockchain, address: Address): SmartContract;
|
|
111
112
|
protected createCommonArgs(params?: MessageParams): RunCommonArgs;
|
|
112
|
-
receiveMessage(message: Message, params?: MessageParams): Promise<SmartContractTransaction>;
|
|
113
|
+
receiveMessage(message: Message, params?: MessageParams, callStack?: string): Promise<SmartContractTransaction>;
|
|
113
114
|
runTickTock(which: TickOrTock, params?: MessageParams): Promise<SmartContractTransaction>;
|
|
114
|
-
protected runCommon(run: () => Promise<EmulationResult
|
|
115
|
+
protected runCommon(run: () => Promise<EmulationResult>, callStack?: string): Promise<SmartContractTransaction>;
|
|
115
116
|
get(method: string | number, stack?: TupleItem[], params?: GetMethodParams): Promise<GetMethodResult>;
|
|
116
117
|
get verbosity(): LogsVerbosity;
|
|
117
118
|
set verbosity(value: LogsVerbosity);
|
|
@@ -294,7 +294,7 @@ class SmartContract {
|
|
|
294
294
|
prevBlocksInfo: this.blockchain.prevBlocks,
|
|
295
295
|
};
|
|
296
296
|
}
|
|
297
|
-
async receiveMessage(message, params) {
|
|
297
|
+
async receiveMessage(message, params, callStack) {
|
|
298
298
|
const args = {
|
|
299
299
|
...this.createCommonArgs(params),
|
|
300
300
|
message: (0, core_1.beginCell)().store((0, core_1.storeMessage)(message)).endCell(),
|
|
@@ -304,14 +304,14 @@ class SmartContract {
|
|
|
304
304
|
const { uninitialized, debugInfo } = debugContext.getDebugInfo(this.account);
|
|
305
305
|
if (debugInfo !== undefined) {
|
|
306
306
|
const executor = await this.blockchain.getDebuggerExecutor();
|
|
307
|
-
return await this.runCommon(() => debugContext.debugTransaction(executor, args, debugInfo));
|
|
307
|
+
return await this.runCommon(() => debugContext.debugTransaction(executor, args, debugInfo), callStack);
|
|
308
308
|
}
|
|
309
309
|
else if (uninitialized) {
|
|
310
310
|
// eslint-disable-next-line no-console
|
|
311
311
|
console.log('Debugging uninitialized accounts is unsupported in debugger beta');
|
|
312
312
|
}
|
|
313
313
|
}
|
|
314
|
-
return await this.runCommon(() => this.blockchain.executor.runTransaction(args));
|
|
314
|
+
return await this.runCommon(() => this.blockchain.executor.runTransaction(args), callStack);
|
|
315
315
|
}
|
|
316
316
|
async runTickTock(which, params) {
|
|
317
317
|
return await this.runCommon(() => this.blockchain.executor.runTickTock({
|
|
@@ -319,7 +319,7 @@ class SmartContract {
|
|
|
319
319
|
which,
|
|
320
320
|
}));
|
|
321
321
|
}
|
|
322
|
-
async runCommon(run) {
|
|
322
|
+
async runCommon(run, callStack) {
|
|
323
323
|
let oldStorage = undefined;
|
|
324
324
|
if (this.blockchain.recordStorage && this.account.account?.storage.state.type === 'active') {
|
|
325
325
|
oldStorage = this.account.account?.storage.state.state.data ?? undefined;
|
|
@@ -357,6 +357,7 @@ class SmartContract {
|
|
|
357
357
|
blockchainLogs: res.logs,
|
|
358
358
|
vmLogs: res.result.vmLog,
|
|
359
359
|
debugLogs: res.debugLogs,
|
|
360
|
+
callStack,
|
|
360
361
|
oldStorage,
|
|
361
362
|
newStorage,
|
|
362
363
|
outActions,
|
|
@@ -96,10 +96,8 @@ export declare class Executor implements IExecutor {
|
|
|
96
96
|
private module;
|
|
97
97
|
private heap;
|
|
98
98
|
private emulator?;
|
|
99
|
-
private debugLogs;
|
|
100
99
|
debugLogFunc: (s: string) => void;
|
|
101
100
|
private constructor();
|
|
102
|
-
private handleDebugLog;
|
|
103
101
|
static create(opts?: {
|
|
104
102
|
debug?: boolean;
|
|
105
103
|
}): Promise<Executor>;
|
|
@@ -164,62 +164,63 @@ function getDebuggerWasmBinary() {
|
|
|
164
164
|
debuggerWasmBinary = (0, bpatch_1.decodePatch)(getWasmBinary(), unzipped);
|
|
165
165
|
return debuggerWasmBinary;
|
|
166
166
|
}
|
|
167
|
+
function splitVmLog(log) {
|
|
168
|
+
const vm = [];
|
|
169
|
+
const debug = [];
|
|
170
|
+
for (const line of log.split('\n')) {
|
|
171
|
+
if (line.startsWith('#DEBUG#')) {
|
|
172
|
+
debug.push(line);
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
vm.push(line);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return { vmLog: vm.join('\n'), debugLog: debug.join('\n') };
|
|
179
|
+
}
|
|
167
180
|
class Executor {
|
|
168
181
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
169
182
|
module;
|
|
170
183
|
heap;
|
|
171
184
|
emulator;
|
|
172
|
-
|
|
185
|
+
// TODO: this is not used anymore - debug logs are now included in the VM log, and so we cannot emit them during execution
|
|
173
186
|
debugLogFunc = () => { };
|
|
174
187
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
175
188
|
constructor(module) {
|
|
176
189
|
this.module = module;
|
|
177
190
|
this.heap = new Heap(module);
|
|
178
191
|
}
|
|
179
|
-
handleDebugLog(text) {
|
|
180
|
-
this.debugLogs.push(text);
|
|
181
|
-
this.debugLogFunc(text);
|
|
182
|
-
}
|
|
183
192
|
static async create(opts) {
|
|
184
193
|
const binary = opts?.debug ? getDebuggerWasmBinary() : getWasmBinary();
|
|
185
194
|
const module = opts?.debug ? DebuggerEmulatorModule : EmulatorModule;
|
|
186
195
|
let ex = undefined;
|
|
187
|
-
const printErr = (text) => {
|
|
188
|
-
if (ex === undefined) {
|
|
189
|
-
// eslint-disable-next-line no-console
|
|
190
|
-
console.error('Debug log received before executor was created:', text);
|
|
191
|
-
}
|
|
192
|
-
else {
|
|
193
|
-
ex.handleDebugLog(text);
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
196
|
ex = new Executor(await module({
|
|
197
197
|
wasmBinary: binary,
|
|
198
|
-
printErr,
|
|
199
198
|
}));
|
|
200
199
|
return ex;
|
|
201
200
|
}
|
|
202
201
|
async runGetMethod(args) {
|
|
203
202
|
const params = getMethodArgsToInternalParams(args);
|
|
204
203
|
let stack = (0, core_1.serializeTuple)(args.stack);
|
|
205
|
-
this.debugLogs = [];
|
|
206
204
|
const resp = JSON.parse(this.extractString(this.invoke('_run_get_method', [JSON.stringify(params), stack.toBoc().toString('base64'), args.config])));
|
|
207
|
-
const debugLogs = this.debugLogs.join('\n');
|
|
208
205
|
if (resp.fail) {
|
|
209
206
|
// eslint-disable-next-line no-console
|
|
210
207
|
console.error(resp);
|
|
211
208
|
throw new Error('Unknown emulation error');
|
|
212
209
|
}
|
|
210
|
+
const { vmLog, debugLog } = splitVmLog('vm_log' in resp.output ? resp.output.vm_log : '');
|
|
213
211
|
return {
|
|
214
|
-
output: resp.output
|
|
212
|
+
output: 'vm_log' in resp.output
|
|
213
|
+
? {
|
|
214
|
+
...resp.output,
|
|
215
|
+
vm_log: vmLog,
|
|
216
|
+
}
|
|
217
|
+
: resp.output,
|
|
215
218
|
logs: resp.logs,
|
|
216
|
-
debugLogs,
|
|
219
|
+
debugLogs: debugLog,
|
|
217
220
|
};
|
|
218
221
|
}
|
|
219
222
|
runCommon(args) {
|
|
220
|
-
this.debugLogs = [];
|
|
221
223
|
const resp = JSON.parse(this.extractString(this.invoke('_emulate_with_emulator', args)));
|
|
222
|
-
const debugLogs = this.debugLogs.join('\n');
|
|
223
224
|
if (resp.fail) {
|
|
224
225
|
// eslint-disable-next-line no-console
|
|
225
226
|
console.error(resp);
|
|
@@ -227,13 +228,14 @@ class Executor {
|
|
|
227
228
|
}
|
|
228
229
|
const logs = resp.logs;
|
|
229
230
|
const result = resp.output;
|
|
231
|
+
const { vmLog, debugLog } = splitVmLog('vm_log' in result ? result.vm_log : '');
|
|
230
232
|
return {
|
|
231
233
|
result: result.success
|
|
232
234
|
? {
|
|
233
235
|
success: true,
|
|
234
236
|
transaction: result.transaction,
|
|
235
237
|
shardAccount: result.shard_account,
|
|
236
|
-
vmLog:
|
|
238
|
+
vmLog: vmLog,
|
|
237
239
|
actions: result.actions,
|
|
238
240
|
}
|
|
239
241
|
: {
|
|
@@ -241,13 +243,13 @@ class Executor {
|
|
|
241
243
|
error: result.error,
|
|
242
244
|
vmResults: 'vm_log' in result
|
|
243
245
|
? {
|
|
244
|
-
vmLog:
|
|
246
|
+
vmLog: vmLog,
|
|
245
247
|
vmExitCode: result.vm_exit_code,
|
|
246
248
|
}
|
|
247
249
|
: undefined,
|
|
248
250
|
},
|
|
249
251
|
logs,
|
|
250
|
-
debugLogs,
|
|
252
|
+
debugLogs: debugLog,
|
|
251
253
|
};
|
|
252
254
|
}
|
|
253
255
|
async runTickTock(args) {
|
|
@@ -312,7 +314,6 @@ class Executor {
|
|
|
312
314
|
sbsGetMethodSetup(args) {
|
|
313
315
|
const params = getMethodArgsToInternalParams(args);
|
|
314
316
|
let stack = (0, core_1.serializeTuple)(args.stack);
|
|
315
|
-
this.debugLogs = [];
|
|
316
317
|
const res = this.invoke('_setup_sbs_get_method', [
|
|
317
318
|
JSON.stringify(params),
|
|
318
319
|
stack.toBoc().toString('base64'),
|
|
@@ -360,17 +361,21 @@ class Executor {
|
|
|
360
361
|
}
|
|
361
362
|
sbsGetMethodResult(ptr) {
|
|
362
363
|
const resp = JSON.parse(this.extractString(this.invoke('_sbs_get_method_result', [ptr])));
|
|
363
|
-
const
|
|
364
|
+
const { vmLog, debugLog } = splitVmLog('vm_log' in resp ? resp.vm_log : '');
|
|
364
365
|
return {
|
|
365
|
-
output: resp
|
|
366
|
+
output: 'vm_log' in resp
|
|
367
|
+
? {
|
|
368
|
+
...resp,
|
|
369
|
+
vm_log: vmLog,
|
|
370
|
+
}
|
|
371
|
+
: resp,
|
|
366
372
|
logs: 'BLOCKCHAIN LOGS ARE NOT AVAILABLE IN DEBUGGER BETA',
|
|
367
|
-
debugLogs,
|
|
373
|
+
debugLogs: debugLog,
|
|
368
374
|
};
|
|
369
375
|
}
|
|
370
376
|
sbsTransactionSetup(args) {
|
|
371
377
|
const emptr = this.invoke('_create_emulator', [args.config, verbosityToNum[args.verbosity]]);
|
|
372
378
|
const params = runCommonArgsToInternalParams(args);
|
|
373
|
-
this.debugLogs = [];
|
|
374
379
|
const res = this.invoke('_emulate_sbs', [
|
|
375
380
|
emptr,
|
|
376
381
|
args.libs?.toBoc().toString('base64') ?? 0,
|
|
@@ -420,14 +425,14 @@ class Executor {
|
|
|
420
425
|
}
|
|
421
426
|
sbsTransactionResult(ptr) {
|
|
422
427
|
const result = JSON.parse(this.extractString(this.invoke('_em_sbs_result', [ptr])));
|
|
423
|
-
const
|
|
428
|
+
const { vmLog, debugLog } = splitVmLog('vm_log' in result ? result.vm_log : '');
|
|
424
429
|
return {
|
|
425
430
|
result: result.success
|
|
426
431
|
? {
|
|
427
432
|
success: true,
|
|
428
433
|
transaction: result.transaction,
|
|
429
434
|
shardAccount: result.shard_account,
|
|
430
|
-
vmLog:
|
|
435
|
+
vmLog: vmLog,
|
|
431
436
|
actions: result.actions,
|
|
432
437
|
}
|
|
433
438
|
: {
|
|
@@ -435,13 +440,13 @@ class Executor {
|
|
|
435
440
|
error: result.error,
|
|
436
441
|
vmResults: 'vm_log' in result
|
|
437
442
|
? {
|
|
438
|
-
vmLog:
|
|
443
|
+
vmLog: vmLog,
|
|
439
444
|
vmExitCode: result.vm_exit_code,
|
|
440
445
|
}
|
|
441
446
|
: undefined,
|
|
442
447
|
},
|
|
443
448
|
logs: 'BLOCKCHAIN LOGS ARE NOT AVAILABLE IN DEBUGGER BETA',
|
|
444
|
-
debugLogs,
|
|
449
|
+
debugLogs: debugLog,
|
|
445
450
|
};
|
|
446
451
|
}
|
|
447
452
|
extractString(ptr) {
|