@ton/sandbox 0.36.0-dev.20250804114000.4e90ae1 → 0.36.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 +2 -1
- package/dist/blockchain/Blockchain.d.ts +31 -2
- package/dist/blockchain/Blockchain.js +50 -6
- package/dist/blockchain/BlockchainContractProvider.d.ts +14 -4
- package/dist/blockchain/BlockchainContractProvider.js +11 -5
- package/dist/blockchain/MessageQueueManager.d.ts +1 -0
- package/dist/blockchain/MessageQueueManager.js +1 -0
- package/dist/utils/transaction.d.ts +2 -0
- package/dist/utils/transaction.js +22 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,10 +5,11 @@ 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
|
-
##
|
|
8
|
+
## [0.36.0] - 2025-08-04
|
|
9
9
|
|
|
10
10
|
### Added
|
|
11
11
|
|
|
12
|
+
- Added `Blockchain.getTransactions` method to fetch transactions
|
|
12
13
|
- Added coverage
|
|
13
14
|
- Added `allowParallel` flag to `Blockchain.sendMessageIter` method, allowing for testing MITM attack
|
|
14
15
|
- Added `autoDeployLibs` flag, that allow to detect libraries, deployed by contract in masterchain automatically
|
|
@@ -91,6 +91,7 @@ export type BlockchainSnapshot = {
|
|
|
91
91
|
prevBlocksInfo?: PrevBlocksInfo;
|
|
92
92
|
randomSeed?: Buffer;
|
|
93
93
|
autoDeployLibs: boolean;
|
|
94
|
+
transactions: BlockchainTransaction[];
|
|
94
95
|
};
|
|
95
96
|
export type SendMessageIterParams = MessageParams & {
|
|
96
97
|
allowParallel?: boolean;
|
|
@@ -111,10 +112,11 @@ export declare class Blockchain {
|
|
|
111
112
|
protected randomSeed?: Buffer;
|
|
112
113
|
protected shouldDebug: boolean;
|
|
113
114
|
protected autoDeployLibs: boolean;
|
|
115
|
+
protected transactions: BlockchainTransaction[];
|
|
114
116
|
protected defaultQueueManager: MessageQueueManager;
|
|
115
117
|
protected collectCoverage: boolean;
|
|
116
|
-
protected readonly
|
|
117
|
-
protected readonly
|
|
118
|
+
protected readonly coverageTransactions: BlockchainTransaction[][];
|
|
119
|
+
protected readonly coverageGetMethodResults: GetMethodResult[];
|
|
118
120
|
readonly executor: IExecutor;
|
|
119
121
|
protected debuggerExecutor?: Executor;
|
|
120
122
|
getDebuggerExecutor(): Promise<Executor>;
|
|
@@ -262,6 +264,33 @@ export declare class Blockchain {
|
|
|
262
264
|
* const now = res.stackReader.readNumber();
|
|
263
265
|
*/
|
|
264
266
|
runGetMethod(address: Address, method: number | string, stack?: TupleItem[], params?: GetMethodParams): Promise<GetMethodResult>;
|
|
267
|
+
/**
|
|
268
|
+
* Retrieves transactions for the specified address. Transactions are ordered from newest to oldest.
|
|
269
|
+
*
|
|
270
|
+
* If both `lt` and `hash` are provided, the result will include transactions up to and including the one matching them.
|
|
271
|
+
*
|
|
272
|
+
* @param {Address} address - The address to retrieve transactions for.
|
|
273
|
+
* @param opts - Options to fetch transactions
|
|
274
|
+
* @param [opts.lt] - Logical time of the transaction to start from. Must be used together with `hash`.
|
|
275
|
+
* @param [opts.hash] - Hash of the transaction to start from. Must be used together with `lt`.
|
|
276
|
+
* @param [opts.limit] - Maximum number of transactions to return.
|
|
277
|
+
*
|
|
278
|
+
* @returns {Promise<BlockchainTransaction[]>} Promise resolving to an array of transactions involving the given address.
|
|
279
|
+
*
|
|
280
|
+
* @throws {Error} If both `lt` and `hash` are provided but no matching transaction is found.
|
|
281
|
+
*
|
|
282
|
+
* @example
|
|
283
|
+
* const transactions = await blockchain.getTransactions(Address.parse(...), {
|
|
284
|
+
* lt: '1234567890',
|
|
285
|
+
* hash: 'abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890',
|
|
286
|
+
* limit: 10
|
|
287
|
+
* });
|
|
288
|
+
*/
|
|
289
|
+
getTransactions(address: Address, opts?: {
|
|
290
|
+
limit?: number;
|
|
291
|
+
lt?: string | bigint;
|
|
292
|
+
hash?: string | Buffer;
|
|
293
|
+
}): Promise<BlockchainTransaction[]>;
|
|
265
294
|
protected increaseLt(): void;
|
|
266
295
|
/**
|
|
267
296
|
* Creates new {@link ContractProvider} for contract address.
|
|
@@ -69,10 +69,11 @@ class Blockchain {
|
|
|
69
69
|
randomSeed;
|
|
70
70
|
shouldDebug = false;
|
|
71
71
|
autoDeployLibs;
|
|
72
|
+
transactions = [];
|
|
72
73
|
defaultQueueManager;
|
|
73
74
|
collectCoverage = false;
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
coverageTransactions = [];
|
|
76
|
+
coverageGetMethodResults = [];
|
|
76
77
|
executor;
|
|
77
78
|
debuggerExecutor;
|
|
78
79
|
async getDebuggerExecutor() {
|
|
@@ -100,6 +101,7 @@ class Blockchain {
|
|
|
100
101
|
prevBlocksInfo: (0, deepcopy_1.deepcopy)(this.prevBlocksInfo),
|
|
101
102
|
randomSeed: (0, deepcopy_1.deepcopy)(this.randomSeed),
|
|
102
103
|
autoDeployLibs: this.autoDeployLibs,
|
|
104
|
+
transactions: this.transactions.map((tx) => tx),
|
|
103
105
|
};
|
|
104
106
|
}
|
|
105
107
|
/**
|
|
@@ -124,6 +126,7 @@ class Blockchain {
|
|
|
124
126
|
this.prevBlocksInfo = (0, deepcopy_1.deepcopy)(snapshot.prevBlocksInfo);
|
|
125
127
|
this.randomSeed = (0, deepcopy_1.deepcopy)(snapshot.randomSeed);
|
|
126
128
|
this.autoDeployLibs = snapshot.autoDeployLibs;
|
|
129
|
+
this.transactions = snapshot.transactions.map((tx) => tx);
|
|
127
130
|
}
|
|
128
131
|
get recordStorage() {
|
|
129
132
|
return this.shouldRecordStorage;
|
|
@@ -186,6 +189,7 @@ class Blockchain {
|
|
|
186
189
|
setLibs: (value) => (this.libs = value),
|
|
187
190
|
getAutoDeployLibs: () => this.autoDeployLibs,
|
|
188
191
|
registerTxsForCoverage: (txs) => this.registerTxsForCoverage(txs),
|
|
192
|
+
addTransaction: (transaction) => this.transactions.push(transaction),
|
|
189
193
|
});
|
|
190
194
|
}
|
|
191
195
|
/**
|
|
@@ -315,6 +319,45 @@ class Blockchain {
|
|
|
315
319
|
this.registerGetMethodForCoverage(result);
|
|
316
320
|
return result;
|
|
317
321
|
}
|
|
322
|
+
/**
|
|
323
|
+
* Retrieves transactions for the specified address. Transactions are ordered from newest to oldest.
|
|
324
|
+
*
|
|
325
|
+
* If both `lt` and `hash` are provided, the result will include transactions up to and including the one matching them.
|
|
326
|
+
*
|
|
327
|
+
* @param {Address} address - The address to retrieve transactions for.
|
|
328
|
+
* @param opts - Options to fetch transactions
|
|
329
|
+
* @param [opts.lt] - Logical time of the transaction to start from. Must be used together with `hash`.
|
|
330
|
+
* @param [opts.hash] - Hash of the transaction to start from. Must be used together with `lt`.
|
|
331
|
+
* @param [opts.limit] - Maximum number of transactions to return.
|
|
332
|
+
*
|
|
333
|
+
* @returns {Promise<BlockchainTransaction[]>} Promise resolving to an array of transactions involving the given address.
|
|
334
|
+
*
|
|
335
|
+
* @throws {Error} If both `lt` and `hash` are provided but no matching transaction is found.
|
|
336
|
+
*
|
|
337
|
+
* @example
|
|
338
|
+
* const transactions = await blockchain.getTransactions(Address.parse(...), {
|
|
339
|
+
* lt: '1234567890',
|
|
340
|
+
* hash: 'abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890',
|
|
341
|
+
* limit: 10
|
|
342
|
+
* });
|
|
343
|
+
*/
|
|
344
|
+
async getTransactions(address, opts) {
|
|
345
|
+
const transactionByAddress = this.transactions.reverse().filter((transaction) => {
|
|
346
|
+
const dst = transaction.inMessage?.info?.dest;
|
|
347
|
+
return core_1.Address.isAddress(dst) && dst.equals(address);
|
|
348
|
+
});
|
|
349
|
+
const { lt, hash, limit } = opts ?? {};
|
|
350
|
+
let resultTransactions = transactionByAddress;
|
|
351
|
+
if (lt !== undefined && hash !== undefined) {
|
|
352
|
+
const hashBuffer = typeof hash === 'string' ? Buffer.from(hash, 'hex') : hash;
|
|
353
|
+
const transaction = transactionByAddress.find((tx) => tx.lt === BigInt(lt) && tx.hash() === hashBuffer);
|
|
354
|
+
if (!transaction) {
|
|
355
|
+
throw new Error('Transaction with provided lt and hash not found.');
|
|
356
|
+
}
|
|
357
|
+
resultTransactions = resultTransactions.filter((tx) => tx.lt <= transaction.lt);
|
|
358
|
+
}
|
|
359
|
+
return resultTransactions.slice(0, limit);
|
|
360
|
+
}
|
|
318
361
|
increaseLt() {
|
|
319
362
|
this.currentLt += LT_ALIGN;
|
|
320
363
|
}
|
|
@@ -329,6 +372,7 @@ class Blockchain {
|
|
|
329
372
|
*/
|
|
330
373
|
provider(address, init) {
|
|
331
374
|
return new BlockchainContractProvider_1.BlockchainContractProvider({
|
|
375
|
+
getTransactions: (address, opts) => this.getTransactions(address, opts),
|
|
332
376
|
getContract: (addr) => this.getContract(addr),
|
|
333
377
|
pushMessage: (msg) => this.defaultQueueManager.pushMessage(msg),
|
|
334
378
|
runGetMethod: (addr, method, args) => this.runGetMethod(addr, method, args),
|
|
@@ -589,12 +633,12 @@ class Blockchain {
|
|
|
589
633
|
registerTxsForCoverage(txs) {
|
|
590
634
|
if (!this.collectCoverage)
|
|
591
635
|
return;
|
|
592
|
-
this.
|
|
636
|
+
this.coverageTransactions.push(txs);
|
|
593
637
|
}
|
|
594
638
|
registerGetMethodForCoverage(get) {
|
|
595
639
|
if (!this.collectCoverage)
|
|
596
640
|
return;
|
|
597
|
-
this.
|
|
641
|
+
this.coverageGetMethodResults.push(get);
|
|
598
642
|
}
|
|
599
643
|
/**
|
|
600
644
|
* Returns coverage analysis for the specified code cell.
|
|
@@ -620,8 +664,8 @@ class Blockchain {
|
|
|
620
664
|
if (!this.collectCoverage || this.verbosity.vmLogs !== 'vm_logs_verbose') {
|
|
621
665
|
return undefined;
|
|
622
666
|
}
|
|
623
|
-
const txs = this.
|
|
624
|
-
const gets = this.
|
|
667
|
+
const txs = this.coverageTransactions.flatMap((tx) => (0, coverage_1.collectTxsCoverage)(code, address, tx));
|
|
668
|
+
const gets = this.coverageGetMethodResults.flatMap((get) => (0, coverage_1.collectAsmCoverage)(code, get.vmLogs));
|
|
625
669
|
const coverages = [...txs, ...gets];
|
|
626
670
|
return new coverage_1.Coverage((0, coverage_1.mergeCoverages)(...coverages));
|
|
627
671
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Address, Cell, Contract, ContractGetMethodResult, ContractProvider, ContractState, ExtraCurrency, Message, OpenedContract, Sender, SendMode, StateInit, Transaction, TupleItem } from '@ton/core';
|
|
2
2
|
import { TickOrTock } from '../executor/Executor';
|
|
3
3
|
import { GetMethodResult, SmartContract } from './SmartContract';
|
|
4
|
+
import { BlockchainTransaction } from './Blockchain';
|
|
4
5
|
export interface SandboxContractProvider extends ContractProvider {
|
|
5
6
|
tickTock(which: TickOrTock): Promise<void>;
|
|
6
7
|
}
|
|
@@ -12,6 +13,11 @@ export declare class BlockchainContractProvider implements SandboxContractProvid
|
|
|
12
13
|
private readonly address;
|
|
13
14
|
private readonly init?;
|
|
14
15
|
constructor(blockchain: {
|
|
16
|
+
getTransactions(address: Address, opts?: {
|
|
17
|
+
limit?: number;
|
|
18
|
+
lt?: string | bigint;
|
|
19
|
+
hash?: string | Buffer;
|
|
20
|
+
}): Promise<BlockchainTransaction[]>;
|
|
15
21
|
getContract(address: Address): Promise<SmartContract>;
|
|
16
22
|
pushMessage(message: Message): Promise<void>;
|
|
17
23
|
runGetMethod(address: Address, method: string, args: TupleItem[]): Promise<GetMethodResult>;
|
|
@@ -30,12 +36,16 @@ export declare class BlockchainContractProvider implements SandboxContractProvid
|
|
|
30
36
|
*/
|
|
31
37
|
get(name: string, args: TupleItem[]): Promise<ContractGetMethodResult>;
|
|
32
38
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
39
|
+
* Retrieves transactions for the specified address using the provided logical time (lt), hash, and optional limit.
|
|
40
|
+
* This implementation fetches transactions directly from the underlying blockchain instance.
|
|
35
41
|
*
|
|
36
|
-
* @
|
|
42
|
+
* @param address - The address to retrieve transactions for.
|
|
43
|
+
* @param lt - Logical time of transaction to start with, must be used with hash.
|
|
44
|
+
* @param hash - Hash of transaction to start with, in buffer or hex encoding, must be sent with lt.
|
|
45
|
+
* @param limit - Optional maximum number of transactions to fetch.
|
|
46
|
+
* @returns An array of transactions.
|
|
37
47
|
*/
|
|
38
|
-
getTransactions(
|
|
48
|
+
getTransactions(address: Address, lt: bigint, hash: Buffer, limit?: number | undefined): Promise<Transaction[]>;
|
|
39
49
|
/**
|
|
40
50
|
* Pushes external-in message to message queue.
|
|
41
51
|
* @param message Message to push
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BlockchainContractProvider = void 0;
|
|
4
4
|
const core_1 = require("@ton/core");
|
|
5
|
+
const transaction_1 = require("../utils/transaction");
|
|
5
6
|
function bigintToBuffer(x, n = 32) {
|
|
6
7
|
const b = Buffer.alloc(n);
|
|
7
8
|
for (let i = 0; i < n; i++) {
|
|
@@ -80,13 +81,18 @@ class BlockchainContractProvider {
|
|
|
80
81
|
return ret;
|
|
81
82
|
}
|
|
82
83
|
/**
|
|
83
|
-
*
|
|
84
|
-
*
|
|
84
|
+
* Retrieves transactions for the specified address using the provided logical time (lt), hash, and optional limit.
|
|
85
|
+
* This implementation fetches transactions directly from the underlying blockchain instance.
|
|
85
86
|
*
|
|
86
|
-
* @
|
|
87
|
+
* @param address - The address to retrieve transactions for.
|
|
88
|
+
* @param lt - Logical time of transaction to start with, must be used with hash.
|
|
89
|
+
* @param hash - Hash of transaction to start with, in buffer or hex encoding, must be sent with lt.
|
|
90
|
+
* @param limit - Optional maximum number of transactions to fetch.
|
|
91
|
+
* @returns An array of transactions.
|
|
87
92
|
*/
|
|
88
|
-
getTransactions(
|
|
89
|
-
|
|
93
|
+
async getTransactions(address, lt, hash, limit) {
|
|
94
|
+
const blockchainTransactions = await this.blockchain.getTransactions(address, { lt, hash, limit });
|
|
95
|
+
return blockchainTransactions.map((blockchainTx) => (0, transaction_1.extractTransaction)(blockchainTx));
|
|
90
96
|
}
|
|
91
97
|
/**
|
|
92
98
|
* Pushes external-in message to message queue.
|
|
@@ -15,6 +15,7 @@ export declare class MessageQueueManager {
|
|
|
15
15
|
setLibs(libs: Cell | undefined): void;
|
|
16
16
|
getAutoDeployLibs(): boolean;
|
|
17
17
|
registerTxsForCoverage(txs: BlockchainTransaction[]): void;
|
|
18
|
+
addTransaction(transaction: BlockchainTransaction): void;
|
|
18
19
|
});
|
|
19
20
|
pushMessage(message: Message | Cell): Promise<void>;
|
|
20
21
|
pushTickTock(on: Address, which: TickOrTock): Promise<void>;
|
|
@@ -98,6 +98,7 @@ class MessageQueueManager {
|
|
|
98
98
|
mode: message.type === 'message' ? message.mode : undefined,
|
|
99
99
|
};
|
|
100
100
|
transaction.parent?.children.push(transaction);
|
|
101
|
+
this.blockchain.addTransaction(transaction);
|
|
101
102
|
result = transaction;
|
|
102
103
|
done = true;
|
|
103
104
|
const sendMsgActions = (transaction.outActions?.filter((action) => action.type === 'sendMsg') ??
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractTransaction = extractTransaction;
|
|
4
|
+
function extractTransaction(transactionLike) {
|
|
5
|
+
return {
|
|
6
|
+
address: transactionLike.address,
|
|
7
|
+
lt: transactionLike.lt,
|
|
8
|
+
prevTransactionHash: transactionLike.prevTransactionHash,
|
|
9
|
+
prevTransactionLt: transactionLike.prevTransactionLt,
|
|
10
|
+
now: transactionLike.now,
|
|
11
|
+
outMessagesCount: transactionLike.outMessagesCount,
|
|
12
|
+
oldStatus: transactionLike.oldStatus,
|
|
13
|
+
endStatus: transactionLike.endStatus,
|
|
14
|
+
inMessage: transactionLike.inMessage,
|
|
15
|
+
outMessages: transactionLike.outMessages,
|
|
16
|
+
totalFees: transactionLike.totalFees,
|
|
17
|
+
stateUpdate: transactionLike.stateUpdate,
|
|
18
|
+
description: transactionLike.description,
|
|
19
|
+
raw: transactionLike.raw,
|
|
20
|
+
hash: transactionLike.hash,
|
|
21
|
+
};
|
|
22
|
+
}
|