@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.
Files changed (36) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/blockchain/Blockchain.d.ts +15 -1
  3. package/dist/blockchain/Blockchain.js +45 -8
  4. package/dist/blockchain/MessageQueueManager.d.ts +2 -2
  5. package/dist/blockchain/MessageQueueManager.js +6 -3
  6. package/dist/blockchain/SmartContract.d.ts +3 -2
  7. package/dist/blockchain/SmartContract.js +5 -4
  8. package/dist/executor/Executor.d.ts +0 -2
  9. package/dist/executor/Executor.js +38 -33
  10. package/dist/executor/emulator-emscripten.debugger.bpatch.gzip.js +1 -1
  11. package/dist/executor/emulator-emscripten.debugger.js +2 -2
  12. package/dist/executor/emulator-emscripten.js +2 -20
  13. package/dist/executor/emulator-emscripten.wasm.js +1 -1
  14. package/dist/jest/uiSetup.d.ts +1 -0
  15. package/dist/jest/uiSetup.js +38 -0
  16. package/dist/ui/UIManager.d.ts +18 -0
  17. package/dist/ui/UIManager.js +31 -0
  18. package/dist/ui/connection/UIConnector.d.ts +3 -0
  19. package/dist/ui/connection/UIConnector.js +2 -0
  20. package/dist/ui/connection/websocket/ManagedWebSocketConnector.d.ts +10 -0
  21. package/dist/ui/connection/websocket/ManagedWebSocketConnector.js +38 -0
  22. package/dist/ui/connection/websocket/OneTimeWebSocketConnector.d.ts +7 -0
  23. package/dist/ui/connection/websocket/OneTimeWebSocketConnector.js +31 -0
  24. package/dist/ui/connection/websocket/constants.d.ts +3 -0
  25. package/dist/ui/connection/websocket/constants.js +6 -0
  26. package/dist/ui/connection/websocket/types.d.ts +4 -0
  27. package/dist/ui/connection/websocket/types.js +2 -0
  28. package/dist/ui/protocol.d.ts +48 -0
  29. package/dist/ui/protocol.js +48 -0
  30. package/dist/utils/environment.d.ts +7 -0
  31. package/dist/utils/environment.js +15 -0
  32. package/dist/utils/noop.d.ts +1 -0
  33. package/dist/utils/noop.js +4 -0
  34. package/dist/utils/require.d.ts +1 -1
  35. package/dist/utils/require.js +5 -8
  36. 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
- registerTxsForCoverage: (txs) => this.registerTxsForCoverage(txs),
193
- addTransaction: (transaction) => this.transactions.push(transaction),
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 (!(contract.init.code instanceof core_1.Cell)) {
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 (!(contract.init.data instanceof core_1.Cell)) {
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
- return new Blockchain({
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.requireOptional)('@ton/test-utils')?.contractsMeta,
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
- registerTxsForCoverage(txs: BlockchainTransaction[]): void;
18
- addTransaction(transaction: BlockchainTransaction): void;
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.registerTxsForCoverage(results);
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.addTransaction(transaction);
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>): Promise<SmartContractTransaction>;
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
- debugLogs = [];
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: result.vm_log,
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: result.vm_log,
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 debugLogs = this.debugLogs.join('\n');
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 debugLogs = this.debugLogs.join('\n');
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: result.vm_log,
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: result.vm_log,
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) {