@ton/sandbox 0.30.0 → 0.32.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 (38) hide show
  1. package/CHANGELOG.md +17 -1
  2. package/README.md +104 -0
  3. package/dist/blockchain/Blockchain.d.ts +16 -2
  4. package/dist/blockchain/Blockchain.js +31 -13
  5. package/dist/blockchain/SmartContract.js +2 -0
  6. package/dist/executor/Executor.d.ts +14 -0
  7. package/dist/executor/Executor.js +34 -1
  8. package/dist/executor/emulator-emscripten.js +1 -1
  9. package/dist/executor/emulator-emscripten.wasm.js +1 -1
  10. package/dist/index.d.ts +2 -1
  11. package/dist/index.js +15 -0
  12. package/dist/jest/BenchmarkCommand.d.ts +10 -0
  13. package/dist/jest/BenchmarkCommand.js +14 -0
  14. package/dist/jest/BenchmarkEnvironment.d.ts +19 -0
  15. package/dist/jest/BenchmarkEnvironment.js +46 -0
  16. package/dist/jest/BenchmarkReporter.d.ts +45 -0
  17. package/dist/jest/BenchmarkReporter.js +207 -0
  18. package/dist/meta/ContractsMeta.d.ts +10 -0
  19. package/dist/meta/ContractsMeta.js +2 -0
  20. package/dist/metric/ContractDatabase.d.ts +21 -0
  21. package/dist/metric/ContractDatabase.js +111 -0
  22. package/dist/metric/collectMetric.d.ts +106 -0
  23. package/dist/metric/collectMetric.js +217 -0
  24. package/dist/metric/defaultColor.d.ts +2 -0
  25. package/dist/metric/defaultColor.js +45 -0
  26. package/dist/metric/deltaResult.d.ts +39 -0
  27. package/dist/metric/deltaResult.js +210 -0
  28. package/dist/metric/gasReportTable.d.ts +2 -0
  29. package/dist/metric/gasReportTable.js +112 -0
  30. package/dist/metric/index.d.ts +6 -0
  31. package/dist/metric/index.js +22 -0
  32. package/dist/metric/readSnapshots.d.ts +2 -0
  33. package/dist/metric/readSnapshots.js +33 -0
  34. package/dist/utils/readJsonl.d.ts +1 -0
  35. package/dist/utils/readJsonl.js +25 -0
  36. package/jest-environment.js +1 -0
  37. package/jest-reporter.js +1 -0
  38. package/package.json +24 -5
package/dist/index.d.ts CHANGED
@@ -4,10 +4,11 @@ export { BlockchainContractProvider, SandboxContractProvider, } from './blockcha
4
4
  export { BlockchainSender, } from './blockchain/BlockchainSender';
5
5
  export { BlockchainStorage, LocalBlockchainStorage, RemoteBlockchainStorage, RemoteBlockchainStorageClient, wrapTonClient4ForRemote, } from './blockchain/BlockchainStorage';
6
6
  export { Verbosity, LogsVerbosity, SmartContract, SmartContractTransaction, MessageParams, GetMethodParams, GetMethodResult, createEmptyShardAccount, createShardAccount, GetMethodError, TimeError, SmartContractSnapshot, EmulationError, } from './blockchain/SmartContract';
7
- export { TickOrTock, IExecutor, Executor, GetMethodArgs as ExecutorGetMethodArgs, GetMethodResult as ExecutorGetMethodResult, RunTickTockArgs as ExecutorRunTickTockArgs, EmulationResult as ExecutorEmulationResult, RunTransactionArgs as ExecutorRunTransactionArgs, ExecutorVerbosity, } from './executor/Executor';
7
+ export { TickOrTock, IExecutor, Executor, GetMethodArgs as ExecutorGetMethodArgs, GetMethodResult as ExecutorGetMethodResult, RunTickTockArgs as ExecutorRunTickTockArgs, EmulationResult as ExecutorEmulationResult, RunTransactionArgs as ExecutorRunTransactionArgs, ExecutorVerbosity, BlockId, PrevBlocksInfo, } from './executor/Executor';
8
8
  export { Event, EventAccountCreated, EventAccountDestroyed, EventMessageSent, } from './event/Event';
9
9
  export { Treasury, TreasuryContract, } from './treasury/Treasury';
10
10
  export { prettyLogTransaction, prettyLogTransactions, } from './utils/prettyLogTransaction';
11
11
  export { printTransactionFees, } from './utils/printTransactionFees';
12
12
  export { internal, } from './utils/message';
13
13
  export { ExtraCurrency, } from './utils/ec';
14
+ export * from './metric';
package/dist/index.js CHANGED
@@ -1,4 +1,18 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
2
16
  Object.defineProperty(exports, "__esModule", { value: true });
3
17
  exports.internal = exports.printTransactionFees = exports.prettyLogTransactions = exports.prettyLogTransaction = exports.TreasuryContract = exports.Executor = exports.EmulationError = exports.TimeError = exports.GetMethodError = exports.createShardAccount = exports.createEmptyShardAccount = exports.SmartContract = exports.wrapTonClient4ForRemote = exports.RemoteBlockchainStorage = exports.LocalBlockchainStorage = exports.BlockchainSender = exports.BlockchainContractProvider = exports.toSandboxContract = exports.Blockchain = exports.defaultConfigSeqno = exports.defaultConfig = void 0;
4
18
  var defaultConfig_1 = require("./config/defaultConfig");
@@ -33,3 +47,4 @@ var printTransactionFees_1 = require("./utils/printTransactionFees");
33
47
  Object.defineProperty(exports, "printTransactionFees", { enumerable: true, get: function () { return printTransactionFees_1.printTransactionFees; } });
34
48
  var message_1 = require("./utils/message");
35
49
  Object.defineProperty(exports, "internal", { enumerable: true, get: function () { return message_1.internal; } });
50
+ __exportStar(require("./metric"), exports);
@@ -0,0 +1,10 @@
1
+ export interface BenchmarkCommandOption {
2
+ label: string;
3
+ doDiff: boolean;
4
+ }
5
+ export declare class BenchmarkCommand {
6
+ readonly label?: string;
7
+ readonly doDiff: boolean;
8
+ constructor(option?: Partial<BenchmarkCommandOption>);
9
+ get doBenchmark(): boolean;
10
+ }
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BenchmarkCommand = void 0;
4
+ class BenchmarkCommand {
5
+ constructor(option) {
6
+ option = option || {};
7
+ this.label = option?.label ?? process.env?.BENCH_NEW;
8
+ this.doDiff = option?.doDiff ?? process.env?.BENCH_DIFF === 'true' ?? false;
9
+ }
10
+ get doBenchmark() {
11
+ return this.doDiff || typeof this.label !== 'undefined';
12
+ }
13
+ }
14
+ exports.BenchmarkCommand = BenchmarkCommand;
@@ -0,0 +1,19 @@
1
+ import type { EnvironmentContext } from '@jest/environment';
2
+ import NodeEnvironment from 'jest-environment-node';
3
+ import { Config } from '@jest/types';
4
+ import { BenchmarkCommand, BenchmarkCommandOption } from './BenchmarkCommand';
5
+ export declare const sandboxMetricRawFile = ".sandbox-metric-raw.jsonl";
6
+ export type BenchmarkEnvironmentConfig = {
7
+ projectConfig: Config.ProjectConfig & {
8
+ testEnvironmentCommand?: Partial<BenchmarkCommandOption>;
9
+ };
10
+ globalConfig: Config.GlobalConfig;
11
+ };
12
+ export default class BenchmarkEnvironment extends NodeEnvironment {
13
+ protected command: BenchmarkCommand;
14
+ protected rootDir: string;
15
+ constructor(config: BenchmarkEnvironmentConfig, context: EnvironmentContext);
16
+ setup(): Promise<void>;
17
+ get resultFile(): string;
18
+ teardown(): Promise<void>;
19
+ }
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.sandboxMetricRawFile = void 0;
7
+ const path_1 = require("path");
8
+ const node_fs_1 = require("node:fs");
9
+ const jest_environment_node_1 = __importDefault(require("jest-environment-node"));
10
+ const BenchmarkCommand_1 = require("./BenchmarkCommand");
11
+ const metric_1 = require("../metric");
12
+ exports.sandboxMetricRawFile = '.sandbox-metric-raw.jsonl';
13
+ class BenchmarkEnvironment extends jest_environment_node_1.default {
14
+ constructor(config, context) {
15
+ super(config, context);
16
+ this.command = new BenchmarkCommand_1.BenchmarkCommand(config.projectConfig.testEnvironmentCommand);
17
+ this.rootDir = config.globalConfig.rootDir;
18
+ }
19
+ async setup() {
20
+ if (this.command.doBenchmark) {
21
+ (0, metric_1.createMetricStore)(this.global);
22
+ }
23
+ }
24
+ get resultFile() {
25
+ return (0, path_1.join)(this.rootDir, exports.sandboxMetricRawFile);
26
+ }
27
+ async teardown() {
28
+ if (this.command.doBenchmark) {
29
+ const store = (0, metric_1.getMetricStore)(this.global) || [];
30
+ const fileName = this.resultFile;
31
+ const folder = (0, path_1.dirname)(fileName);
32
+ if (!(0, node_fs_1.existsSync)(folder)) {
33
+ (0, node_fs_1.mkdirSync)(folder, { recursive: true });
34
+ }
35
+ if (!(0, node_fs_1.existsSync)(fileName)) {
36
+ (0, node_fs_1.writeFileSync)(fileName, '');
37
+ }
38
+ for (const item of store) {
39
+ (0, node_fs_1.appendFileSync)(fileName, JSON.stringify(item) + '\n');
40
+ }
41
+ (0, metric_1.resetMetricStore)(this.global);
42
+ }
43
+ await super.teardown();
44
+ }
45
+ }
46
+ exports.default = BenchmarkEnvironment;
@@ -0,0 +1,45 @@
1
+ import { BaseReporter } from '@jest/reporters';
2
+ import type { Config } from '@jest/types';
3
+ import { ContractABI } from '@ton/core';
4
+ import { BenchmarkCommand } from './BenchmarkCommand';
5
+ import { Metric, CodeHash, SnapshotMetric, ContractDatabase } from '../metric';
6
+ export declare const defaultSnapshotDir = ".snapshot";
7
+ export declare const defaultReportName = "gas-report";
8
+ export declare const defaultContractDatabaseName = "contract.abi.json";
9
+ export declare const defaultDepthCompare = 2;
10
+ export declare const minComparisonDepth = 1;
11
+ type ReportMode = 'gas' | 'average';
12
+ export interface Options {
13
+ reportMode?: ReportMode;
14
+ reportName?: string;
15
+ snapshotDir?: string;
16
+ depthCompare?: number;
17
+ contractExcludes?: string[];
18
+ removeRawResult?: boolean;
19
+ contractDatabase?: Record<CodeHash, ContractABI> | string;
20
+ }
21
+ export default class BenchmarkReporter extends BaseReporter {
22
+ protected rootDirPath: string;
23
+ protected options: Options;
24
+ protected command: BenchmarkCommand;
25
+ contractDatabase: ContractDatabase;
26
+ constructor(globalConfig: Config.GlobalConfig, options?: Options);
27
+ get reportMode(): ReportMode;
28
+ get reportName(): string;
29
+ get snapshotDir(): string;
30
+ get snapshotDirPath(): string;
31
+ get depthCompare(): number;
32
+ get snapshotFiles(): Promise<import("../metric").SnapshotMetricList>;
33
+ get snapshots(): Promise<SnapshotMetric[]>;
34
+ get snapshotCurrent(): Promise<SnapshotMetric>;
35
+ get removeRawResult(): true;
36
+ get contractExcludes(): string[];
37
+ get sandboxMetricRawFile(): string;
38
+ get metricStore(): Promise<Metric[]>;
39
+ readContractDatabase(): ContractDatabase;
40
+ saveContractDatabase(): void;
41
+ onRunComplete(): Promise<void>;
42
+ gasReportReport(data: SnapshotMetric[], benchmarkDepth: number): string[];
43
+ saveSnapshot(label: string): Promise<string>;
44
+ }
45
+ export {};
@@ -0,0 +1,207 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.minComparisonDepth = exports.defaultDepthCompare = exports.defaultContractDatabaseName = exports.defaultReportName = exports.defaultSnapshotDir = void 0;
27
+ const path_1 = require("path");
28
+ const fs_1 = require("fs");
29
+ const chalk_1 = __importStar(require("chalk"));
30
+ const reporters_1 = require("@jest/reporters");
31
+ const BenchmarkCommand_1 = require("./BenchmarkCommand");
32
+ const BenchmarkEnvironment_1 = require("./BenchmarkEnvironment");
33
+ const readJsonl_1 = require("../utils/readJsonl");
34
+ const metric_1 = require("../metric");
35
+ exports.defaultSnapshotDir = '.snapshot';
36
+ exports.defaultReportName = 'gas-report';
37
+ exports.defaultContractDatabaseName = 'contract.abi.json';
38
+ exports.defaultDepthCompare = 2;
39
+ exports.minComparisonDepth = 1;
40
+ const PASS_TEXT = 'PASS';
41
+ const PASS = chalk_1.supportsColor ? chalk_1.default.reset.inverse.bold.green(` ${PASS_TEXT} `) : PASS_TEXT;
42
+ const SKIP_TEXT = 'SKIP';
43
+ const SKIP = chalk_1.supportsColor ? chalk_1.default.reset.inverse.bold.yellow(` ${SKIP_TEXT} `) : SKIP_TEXT;
44
+ class BenchmarkReporter extends reporters_1.BaseReporter {
45
+ constructor(globalConfig, options = {}) {
46
+ super();
47
+ this.rootDirPath = globalConfig.rootDir;
48
+ this.options = options;
49
+ this.command = new BenchmarkCommand_1.BenchmarkCommand();
50
+ if (this.depthCompare < exports.minComparisonDepth) {
51
+ throw new Error(`The minimum depth compare must be greater than or equal to ${exports.minComparisonDepth}`);
52
+ }
53
+ this.contractDatabase = this.readContractDatabase();
54
+ }
55
+ get reportMode() {
56
+ return this.options.reportMode || 'gas';
57
+ }
58
+ get reportName() {
59
+ return this.options.reportName || exports.defaultReportName;
60
+ }
61
+ get snapshotDir() {
62
+ return this.options.snapshotDir || exports.defaultSnapshotDir;
63
+ }
64
+ get snapshotDirPath() {
65
+ const dirPath = (0, path_1.join)(this.rootDirPath, this.snapshotDir);
66
+ try {
67
+ if (!(0, fs_1.existsSync)(dirPath)) {
68
+ (0, fs_1.mkdirSync)(dirPath, { recursive: true });
69
+ }
70
+ }
71
+ catch (_) {
72
+ throw new Error(`Can not create directory: ${dirPath}`);
73
+ }
74
+ return dirPath;
75
+ }
76
+ get depthCompare() {
77
+ return this.options.depthCompare || exports.defaultDepthCompare;
78
+ }
79
+ get snapshotFiles() {
80
+ return (0, metric_1.readSnapshots)(this.snapshotDirPath);
81
+ }
82
+ get snapshots() {
83
+ return this.snapshotFiles.then((list) => Object.values(list).map((item) => item.content));
84
+ }
85
+ get snapshotCurrent() {
86
+ return this.metricStore.then((store) => (0, metric_1.makeSnapshotMetric)(store, {
87
+ contractDatabase: this.contractDatabase,
88
+ contractExcludes: this.contractExcludes,
89
+ }));
90
+ }
91
+ get removeRawResult() {
92
+ return this.options.removeRawResult || true;
93
+ }
94
+ get contractExcludes() {
95
+ return this.options.contractExcludes || [];
96
+ }
97
+ get sandboxMetricRawFile() {
98
+ return (0, path_1.join)(this.rootDirPath, BenchmarkEnvironment_1.sandboxMetricRawFile);
99
+ }
100
+ get metricStore() {
101
+ if ((0, fs_1.existsSync)(this.sandboxMetricRawFile)) {
102
+ return (0, readJsonl_1.readJsonl)(this.sandboxMetricRawFile);
103
+ }
104
+ return new Promise((resolve) => resolve([]));
105
+ }
106
+ readContractDatabase() {
107
+ let data = {};
108
+ const filePath = this.options.contractDatabase || exports.defaultContractDatabaseName;
109
+ if (typeof filePath === 'string') {
110
+ try {
111
+ if ((0, fs_1.existsSync)((0, path_1.join)(this.rootDirPath, filePath))) {
112
+ data = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(this.rootDirPath, filePath), 'utf-8'));
113
+ }
114
+ }
115
+ catch (error) {
116
+ throw new Error(`Could not parse contract database: ${filePath}`);
117
+ }
118
+ }
119
+ return metric_1.ContractDatabase.from(data);
120
+ }
121
+ saveContractDatabase() {
122
+ const contractDatabase = this.options.contractDatabase;
123
+ let filePath = typeof contractDatabase === 'string' ? contractDatabase : exports.defaultContractDatabaseName;
124
+ try {
125
+ const content = JSON.stringify(this.contractDatabase.data, null, 2) + '\n';
126
+ (0, fs_1.writeFileSync)((0, path_1.join)(this.rootDirPath, filePath), content, {
127
+ encoding: 'utf8',
128
+ });
129
+ }
130
+ catch (_) {
131
+ throw new Error(`Can not write: ${filePath}`);
132
+ }
133
+ }
134
+ async onRunComplete() {
135
+ const log = [];
136
+ let status = SKIP;
137
+ if (this.command.doBenchmark) {
138
+ const list = await this.snapshots;
139
+ const snapshots = [await this.snapshotCurrent, ...list];
140
+ let doDiff = this.command.doDiff;
141
+ const depthCompare = Math.min(snapshots.length, this.depthCompare);
142
+ if (doDiff) {
143
+ log.push(`Comparison metric mode: ${this.reportMode} depth: ${depthCompare}`);
144
+ switch (this.reportMode) {
145
+ case 'gas':
146
+ log.push(...this.gasReportReport(snapshots, depthCompare));
147
+ status = PASS;
148
+ break;
149
+ default:
150
+ throw new Error(`Report mode ${this.reportMode} not supported`);
151
+ }
152
+ }
153
+ else if (this.command.label) {
154
+ log.push(`Collect metric mode: "${this.reportMode}"`);
155
+ const file = await this.saveSnapshot(this.command.label);
156
+ log.push(`Report write in '${file}'`);
157
+ status = PASS;
158
+ }
159
+ if (this.removeRawResult) {
160
+ (0, fs_1.unlinkSync)(this.sandboxMetricRawFile);
161
+ }
162
+ this.saveContractDatabase();
163
+ }
164
+ else {
165
+ log.push(`Reporter mode: ${this.reportMode}`);
166
+ }
167
+ this.log(`${status} ${log.join('\n')}`);
168
+ }
169
+ gasReportReport(data, benchmarkDepth) {
170
+ const log = [];
171
+ const reportFile = `${this.reportName}.json`;
172
+ const report = (0, metric_1.makeGasReport)(data);
173
+ try {
174
+ const reportFilePath = (0, path_1.join)(this.rootDirPath, reportFile);
175
+ (0, fs_1.writeFileSync)(reportFilePath, JSON.stringify(report, null, 2) + '\n', {
176
+ encoding: 'utf8',
177
+ });
178
+ log.push(`Gas report write in '${reportFile}'`);
179
+ }
180
+ catch (_) {
181
+ throw new Error(`Can not write: ${reportFile}`);
182
+ }
183
+ const list = report.sort((0, metric_1.sortByCreatedAt)(true)).slice(0, benchmarkDepth);
184
+ log.push((0, metric_1.gasReportTable)(list, metric_1.defaultColor));
185
+ return log;
186
+ }
187
+ async saveSnapshot(label) {
188
+ const snapshot = await this.snapshotCurrent;
189
+ snapshot.label = label;
190
+ const list = await this.snapshotFiles;
191
+ let snapshotFile = `${snapshot.createdAt.getTime()}.json`;
192
+ if (list[snapshot.label]) {
193
+ snapshotFile = list[snapshot.label].name;
194
+ }
195
+ const snapshotFilePath = (0, path_1.join)(this.snapshotDirPath, snapshotFile);
196
+ try {
197
+ (0, fs_1.writeFileSync)(snapshotFilePath, JSON.stringify(snapshot, null, 2) + '\n', {
198
+ encoding: 'utf8',
199
+ });
200
+ }
201
+ catch (_) {
202
+ throw new Error(`Can not write: ${(0, path_1.join)(this.snapshotDir, snapshotFile)}`);
203
+ }
204
+ return (0, path_1.join)(this.snapshotDir, snapshotFile);
205
+ }
206
+ }
207
+ exports.default = BenchmarkReporter;
@@ -0,0 +1,10 @@
1
+ import { Address, ContractABI } from "@ton/core";
2
+ export type ContractMeta = {
3
+ wrapperName?: string;
4
+ abi?: ContractABI | null;
5
+ treasurySeed?: string;
6
+ };
7
+ export interface ContractsMeta {
8
+ get(key: Address): ContractMeta | undefined;
9
+ upsert(key: Address, value: Partial<ContractMeta>): void;
10
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,21 @@
1
+ import { ContractABI } from '@ton/core';
2
+ import { CodeHash, Metric, OpCode } from './collectMetric';
3
+ type Condition = {
4
+ codeHash: CodeHash;
5
+ opCode: OpCode;
6
+ receiver: 'internal' | 'external-in' | 'external-out';
7
+ };
8
+ export type ContractDataKey = CodeHash | string;
9
+ export type ContractData = Record<ContractDataKey, ContractABI | ContractDataKey>;
10
+ export declare class ContractDatabase {
11
+ protected list: Map<ContractDataKey, ContractABI>;
12
+ protected match: Map<ContractDataKey, ContractDataKey>;
13
+ constructor(abiList: Map<ContractDataKey, ContractABI>, codeHashMatch: Map<ContractDataKey, ContractDataKey>);
14
+ static from(data: ContractData): ContractDatabase;
15
+ get data(): ContractData;
16
+ origin(needle: ContractDataKey): string;
17
+ get(needle: ContractDataKey): ContractABI | undefined;
18
+ extract(metric: Metric): void;
19
+ by(where: Partial<Condition>): Partial<Metric>;
20
+ }
21
+ export {};
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ContractDatabase = void 0;
4
+ const collectMetric_1 = require("./collectMetric");
5
+ class ContractDatabase {
6
+ constructor(abiList, codeHashMatch) {
7
+ this.list = abiList;
8
+ this.match = codeHashMatch;
9
+ }
10
+ static from(data) {
11
+ const list = new Map();
12
+ const match = new Map();
13
+ Object.entries(data).forEach(([key, value]) => {
14
+ if (((0, collectMetric_1.isCodeHash)(key) && typeof value === 'string') || ((0, collectMetric_1.isCodeHash)(value) && typeof key === 'string')) {
15
+ match.set(key, value);
16
+ }
17
+ else if (!(0, collectMetric_1.isCodeHash)(value) && typeof value !== 'string') {
18
+ list.set(key, value);
19
+ }
20
+ });
21
+ return new ContractDatabase(list, match);
22
+ }
23
+ get data() {
24
+ const out = {};
25
+ for (const [key, value] of this.match) {
26
+ out[key] = value;
27
+ }
28
+ for (const [key, value] of this.list) {
29
+ out[key] = value;
30
+ }
31
+ return out;
32
+ }
33
+ origin(needle) {
34
+ return this.match.get(needle) || needle;
35
+ }
36
+ get(needle) {
37
+ return this.list.get(this.origin(needle));
38
+ }
39
+ extract(metric) {
40
+ const abiKeyNeedle = metric.contractName || metric.codeHash;
41
+ if (!abiKeyNeedle) {
42
+ return;
43
+ }
44
+ const codeHash = metric.codeHash;
45
+ if ((0, collectMetric_1.isCodeHash)(codeHash) && abiKeyNeedle !== codeHash) {
46
+ this.match.set(codeHash, abiKeyNeedle);
47
+ }
48
+ const abiKey = this.origin(abiKeyNeedle);
49
+ const abi = this.list.get(abiKey) || {};
50
+ if (!abi.receivers) {
51
+ abi.receivers = [];
52
+ }
53
+ if (!abi.types) {
54
+ abi.types = [];
55
+ }
56
+ const find = this.by(metric);
57
+ if (!find.methodName) {
58
+ if (!abi.name) {
59
+ abi.name = metric.contractName || metric.codeHash;
60
+ }
61
+ if (metric.opCode !== '0x0') {
62
+ abi.types.push({
63
+ name: metric.methodName || metric.opCode,
64
+ header: Number(metric.opCode),
65
+ });
66
+ abi.receivers.push({
67
+ receiver: metric.receiver == 'internal' ? 'internal' : 'external',
68
+ message: {
69
+ kind: 'typed',
70
+ type: metric.methodName || metric.opCode,
71
+ },
72
+ });
73
+ }
74
+ }
75
+ this.list.set(abiKey, abi);
76
+ }
77
+ by(where) {
78
+ if (!where.codeHash) {
79
+ return {};
80
+ }
81
+ const abi = this.get(where.codeHash);
82
+ if (!abi) {
83
+ return {};
84
+ }
85
+ const out = {};
86
+ out.contractName = abi.name ? abi.name : undefined;
87
+ let abiType;
88
+ if (where.opCode) {
89
+ for (const item of abi.types || []) {
90
+ if (item.header && item.header === Number(where.opCode)) {
91
+ abiType = item;
92
+ break;
93
+ }
94
+ }
95
+ }
96
+ if (abiType) {
97
+ const receiver = where.receiver ? (where.receiver == 'internal' ? 'internal' : 'external') : undefined;
98
+ for (const item of abi.receivers || []) {
99
+ if (receiver && receiver !== item.receiver) {
100
+ continue;
101
+ }
102
+ if (item.message.kind === 'typed' && item.message.type == abiType.name) {
103
+ out.methodName = item.message.type;
104
+ break;
105
+ }
106
+ }
107
+ }
108
+ return out;
109
+ }
110
+ }
111
+ exports.ContractDatabase = ContractDatabase;
@@ -0,0 +1,106 @@
1
+ import { Cell, Contract, Message } from '@ton/core';
2
+ import { Dictionary, DictionaryKeyTypes, TransactionComputePhase } from '@ton/core';
3
+ import { Maybe } from '@ton/core/src/utils/maybe';
4
+ import { Blockchain, SendMessageResult } from '../blockchain/Blockchain';
5
+ import { ContractDatabase } from './ContractDatabase';
6
+ export type MetricContext<T extends Contract> = {
7
+ contract: T;
8
+ methodName: string;
9
+ };
10
+ type StateShort = {
11
+ code: Cell;
12
+ data: Cell;
13
+ };
14
+ export type CellMetric = {
15
+ cells: number;
16
+ bits: number;
17
+ };
18
+ export type ComputePhaseMetric = {
19
+ type: string;
20
+ success?: boolean;
21
+ gasUsed?: number;
22
+ exitCode?: number;
23
+ vmSteps?: number;
24
+ };
25
+ export type ActionPhaseMetric = {
26
+ success: boolean;
27
+ totalActions: number;
28
+ skippedActions: number;
29
+ resultCode: number;
30
+ totalFwdFees?: number;
31
+ totalActionFees: number;
32
+ totalMessageSize: CellMetric;
33
+ };
34
+ export type AddressFriendly = string;
35
+ export declare function isAddressFriendly(value: unknown): value is AddressFriendly;
36
+ export type ContractName = string;
37
+ export type ContractMethodName = string;
38
+ export type CodeHash = `0x${string}`;
39
+ export type OpCode = `0x${string}`;
40
+ export declare function isCodeHash(value: unknown): value is CodeHash;
41
+ export type StateMetric = {
42
+ code: CellMetric;
43
+ data: CellMetric;
44
+ };
45
+ export type Metric = {
46
+ testName?: string;
47
+ address: AddressFriendly;
48
+ codeHash?: CodeHash;
49
+ state: StateMetric;
50
+ contractName?: ContractName;
51
+ methodName?: ContractMethodName;
52
+ receiver?: 'internal' | 'external-in' | 'external-out';
53
+ opCode: OpCode;
54
+ execute: {
55
+ compute: ComputePhaseMetric;
56
+ action?: ActionPhaseMetric;
57
+ };
58
+ message: {
59
+ in: CellMetric;
60
+ out: CellMetric;
61
+ };
62
+ };
63
+ export type SnapshotMetric = {
64
+ label: string;
65
+ createdAt: Date;
66
+ items: Metric[];
67
+ };
68
+ interface HasCreatedAt {
69
+ createdAt: Date;
70
+ }
71
+ export declare function sortByCreatedAt(reverse?: boolean): (a: HasCreatedAt, b: HasCreatedAt) => number;
72
+ export type SnapshotMetricFile = {
73
+ name: string;
74
+ content: SnapshotMetric;
75
+ };
76
+ export type SnapshotMetricList = Record<string, SnapshotMetricFile>;
77
+ export type SnapshotMetricConfig = {
78
+ label: string;
79
+ contractExcludes: ContractName[];
80
+ contractDatabase: ContractDatabase;
81
+ };
82
+ export declare function makeSnapshotMetric(store: Metric[], config?: Partial<SnapshotMetricConfig>): SnapshotMetric;
83
+ export declare function getMetricStore(context?: any): Array<Metric> | undefined;
84
+ export declare function createMetricStore(context?: any): Array<Metric>;
85
+ export declare function resetMetricStore(context?: any): Array<Metric>;
86
+ export declare function calcMessageSize(msg: Maybe<Message>): {
87
+ cells: number;
88
+ bits: number;
89
+ };
90
+ export declare function calcDictSize<K extends DictionaryKeyTypes, V>(dict: Dictionary<K, V>): {
91
+ cells: number;
92
+ bits: number;
93
+ };
94
+ export declare function calcCellSize(root: Cell, visited?: Set<string>): {
95
+ cells: number;
96
+ bits: number;
97
+ };
98
+ export declare function calcStateSize(state: StateShort): StateMetric;
99
+ export declare function calcComputePhase(phase: TransactionComputePhase): ComputePhaseMetric;
100
+ export declare enum OpCodeReserved {
101
+ send = 0,
102
+ notSupported = 4294967295,
103
+ notAllowed = 4294967294
104
+ }
105
+ export declare function collectMetric<T extends Contract>(blockchain: Blockchain, ctx: MetricContext<T>, result: SendMessageResult): Promise<void>;
106
+ export {};