@aztec/simulator 0.82.2-alpha-testnet.4 → 0.82.3
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/README.md +6 -0
- package/dest/private/acvm/oracle/oracle.d.ts +1 -1
- package/dest/private/acvm/oracle/oracle.d.ts.map +1 -1
- package/dest/private/acvm/oracle/oracle.js +1 -3
- package/dest/public/avm/avm_contract_call_result.d.ts +4 -2
- package/dest/public/avm/avm_contract_call_result.d.ts.map +1 -1
- package/dest/public/avm/avm_contract_call_result.js +9 -5
- package/dest/public/avm/avm_machine_state.d.ts +2 -0
- package/dest/public/avm/avm_machine_state.d.ts.map +1 -1
- package/dest/public/avm/avm_machine_state.js +2 -0
- package/dest/public/avm/avm_simulator.d.ts.map +1 -1
- package/dest/public/avm/avm_simulator.js +5 -6
- package/dest/public/avm/fixtures/avm_simulation_tester.d.ts.map +1 -1
- package/dest/public/avm/fixtures/avm_simulation_tester.js +1 -2
- package/dest/public/avm/fixtures/base_avm_simulation_tester.d.ts +1 -2
- package/dest/public/avm/fixtures/base_avm_simulation_tester.d.ts.map +1 -1
- package/dest/public/avm/fixtures/base_avm_simulation_tester.js +0 -5
- package/dest/public/avm/fixtures/index.d.ts +1 -0
- package/dest/public/avm/fixtures/index.d.ts.map +1 -1
- package/dest/public/avm/fixtures/index.js +1 -1
- package/dest/public/avm/fixtures/simple_contract_data_source.d.ts +3 -2
- package/dest/public/avm/fixtures/simple_contract_data_source.d.ts.map +1 -1
- package/dest/public/avm/fixtures/simple_contract_data_source.js +30 -6
- package/dest/public/avm/opcodes/external_calls.d.ts.map +1 -1
- package/dest/public/avm/opcodes/external_calls.js +2 -0
- package/dest/public/avm/opcodes/memory.d.ts.map +1 -1
- package/dest/public/avm/opcodes/memory.js +8 -10
- package/dest/public/avm/serialization/instruction_serialization.d.ts +5 -2
- package/dest/public/avm/serialization/instruction_serialization.d.ts.map +1 -1
- package/dest/public/avm/serialization/instruction_serialization.js +23 -3
- package/dest/public/executor_metrics.d.ts +11 -3
- package/dest/public/executor_metrics.d.ts.map +1 -1
- package/dest/public/executor_metrics.js +40 -6
- package/dest/public/executor_metrics_interface.d.ts +10 -0
- package/dest/public/executor_metrics_interface.d.ts.map +1 -0
- package/dest/public/executor_metrics_interface.js +1 -0
- package/dest/public/fixtures/public_tx_simulation_tester.d.ts +12 -6
- package/dest/public/fixtures/public_tx_simulation_tester.d.ts.map +1 -1
- package/dest/public/fixtures/public_tx_simulation_tester.js +39 -19
- package/dest/public/hinting_db_sources.d.ts +26 -3
- package/dest/public/hinting_db_sources.d.ts.map +1 -1
- package/dest/public/hinting_db_sources.js +102 -1
- package/dest/public/index.d.ts +1 -1
- package/dest/public/index.d.ts.map +1 -1
- package/dest/public/index.js +1 -1
- package/dest/public/public_db_sources.d.ts +2 -3
- package/dest/public/public_db_sources.d.ts.map +1 -1
- package/dest/public/public_db_sources.js +26 -16
- package/dest/public/public_processor/public_processor.d.ts +1 -1
- package/dest/public/public_processor/public_processor.d.ts.map +1 -1
- package/dest/public/public_processor/public_processor.js +3 -3
- package/dest/public/public_tx_simulator/apps_tests/amm_test.d.ts +9 -0
- package/dest/public/public_tx_simulator/apps_tests/amm_test.d.ts.map +1 -0
- package/dest/public/public_tx_simulator/apps_tests/amm_test.js +237 -0
- package/dest/public/public_tx_simulator/apps_tests/token_test.d.ts +7 -0
- package/dest/public/public_tx_simulator/apps_tests/token_test.d.ts.map +1 -0
- package/dest/public/public_tx_simulator/apps_tests/token_test.js +109 -0
- package/dest/public/public_tx_simulator/index.d.ts +3 -0
- package/dest/public/public_tx_simulator/index.d.ts.map +1 -0
- package/dest/public/public_tx_simulator/index.js +2 -0
- package/dest/public/public_tx_simulator/measured_public_tx_simulator.d.ts +23 -0
- package/dest/public/public_tx_simulator/measured_public_tx_simulator.d.ts.map +1 -0
- package/dest/public/public_tx_simulator/measured_public_tx_simulator.js +58 -0
- package/dest/public/public_tx_simulator/public_tx_context.d.ts +2 -2
- package/dest/public/public_tx_simulator/public_tx_context.d.ts.map +1 -1
- package/dest/public/public_tx_simulator/public_tx_context.js +9 -7
- package/dest/public/public_tx_simulator/public_tx_simulator.d.ts +16 -16
- package/dest/public/public_tx_simulator/public_tx_simulator.d.ts.map +1 -1
- package/dest/public/public_tx_simulator/public_tx_simulator.js +24 -64
- package/dest/public/public_tx_simulator/telemetry_public_tx_simulator.d.ts +19 -0
- package/dest/public/public_tx_simulator/telemetry_public_tx_simulator.d.ts.map +1 -0
- package/dest/public/public_tx_simulator/telemetry_public_tx_simulator.js +39 -0
- package/dest/public/test_executor_metrics.d.ts +43 -0
- package/dest/public/test_executor_metrics.d.ts.map +1 -0
- package/dest/public/test_executor_metrics.js +158 -0
- package/package.json +14 -14
- package/src/private/acvm/oracle/oracle.ts +2 -2
- package/src/public/avm/avm_contract_call_result.ts +15 -3
- package/src/public/avm/avm_machine_state.ts +5 -0
- package/src/public/avm/avm_simulator.ts +18 -7
- package/src/public/avm/fixtures/avm_simulation_tester.ts +1 -1
- package/src/public/avm/fixtures/base_avm_simulation_tester.ts +1 -7
- package/src/public/avm/fixtures/index.ts +1 -1
- package/src/public/avm/fixtures/simple_contract_data_source.ts +33 -6
- package/src/public/avm/opcodes/external_calls.ts +3 -0
- package/src/public/avm/opcodes/memory.ts +8 -10
- package/src/public/avm/serialization/instruction_serialization.ts +22 -5
- package/src/public/executor_metrics.ts +54 -6
- package/src/public/executor_metrics_interface.ts +15 -0
- package/src/public/fixtures/public_tx_simulation_tester.ts +74 -18
- package/src/public/hinting_db_sources.ts +184 -3
- package/src/public/index.ts +1 -1
- package/src/public/public_db_sources.ts +36 -23
- package/src/public/public_processor/public_processor.ts +4 -4
- package/src/public/public_tx_simulator/apps_tests/amm_test.ts +316 -0
- package/src/public/public_tx_simulator/apps_tests/token_test.ts +138 -0
- package/src/public/public_tx_simulator/index.ts +2 -0
- package/src/public/public_tx_simulator/measured_public_tx_simulator.ts +111 -0
- package/src/public/public_tx_simulator/public_tx_context.ts +9 -13
- package/src/public/public_tx_simulator/public_tx_simulator.ts +31 -76
- package/src/public/public_tx_simulator/telemetry_public_tx_simulator.ts +62 -0
- package/src/public/test_executor_metrics.ts +222 -0
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Fr } from '@aztec/foundation/fields';
|
|
2
2
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
3
|
-
import { Timer } from '@aztec/foundation/timer';
|
|
4
3
|
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
5
4
|
import { computeFeePayerBalanceStorageSlot } from '@aztec/protocol-contracts/fee-juice';
|
|
6
5
|
import {
|
|
@@ -14,7 +13,6 @@ import {
|
|
|
14
13
|
import { SimulationError } from '@aztec/stdlib/errors';
|
|
15
14
|
import type { Gas, GasUsed } from '@aztec/stdlib/gas';
|
|
16
15
|
import { ProvingRequestType } from '@aztec/stdlib/proofs';
|
|
17
|
-
import type { AvmSimulationStats } from '@aztec/stdlib/stats';
|
|
18
16
|
import {
|
|
19
17
|
type GlobalVariables,
|
|
20
18
|
NestedProcessReturnValues,
|
|
@@ -22,7 +20,6 @@ import {
|
|
|
22
20
|
Tx,
|
|
23
21
|
TxExecutionPhase,
|
|
24
22
|
} from '@aztec/stdlib/tx';
|
|
25
|
-
import { Attributes, type TelemetryClient, type Tracer, getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
|
|
26
23
|
|
|
27
24
|
import { strict as assert } from 'assert';
|
|
28
25
|
|
|
@@ -30,13 +27,12 @@ import { getPublicFunctionDebugName } from '../../common/debug_fn_name.js';
|
|
|
30
27
|
import type { AvmFinalizedCallResult } from '../avm/avm_contract_call_result.js';
|
|
31
28
|
import { type AvmPersistableStateManager, AvmSimulator } from '../avm/index.js';
|
|
32
29
|
import { NullifierCollisionError } from '../avm/journal/nullifiers.js';
|
|
33
|
-
import { ExecutorMetrics } from '../executor_metrics.js';
|
|
34
30
|
import type { PublicContractsDB, PublicTreesDB } from '../public_db_sources.js';
|
|
35
31
|
import { PublicTxContext } from './public_tx_context.js';
|
|
36
32
|
|
|
37
33
|
export type ProcessedPhase = {
|
|
38
34
|
phase: TxExecutionPhase;
|
|
39
|
-
durationMs
|
|
35
|
+
durationMs?: number;
|
|
40
36
|
returnValues: NestedProcessReturnValues[];
|
|
41
37
|
reverted: boolean;
|
|
42
38
|
revertReason?: SimulationError;
|
|
@@ -53,25 +49,18 @@ export type PublicTxResult = {
|
|
|
53
49
|
};
|
|
54
50
|
|
|
55
51
|
export class PublicTxSimulator {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
private log: Logger;
|
|
52
|
+
protected log: Logger;
|
|
59
53
|
|
|
60
54
|
constructor(
|
|
61
55
|
private treesDB: PublicTreesDB,
|
|
62
|
-
|
|
56
|
+
protected contractsDB: PublicContractsDB,
|
|
63
57
|
private globalVariables: GlobalVariables,
|
|
64
58
|
private doMerkleOperations: boolean = false,
|
|
65
59
|
private skipFeeEnforcement: boolean = false,
|
|
66
|
-
telemetryClient: TelemetryClient = getTelemetryClient(),
|
|
67
60
|
) {
|
|
68
61
|
this.log = createLogger(`simulator:public_tx_simulator`);
|
|
69
|
-
this.metrics = new ExecutorMetrics(telemetryClient, 'PublicTxSimulator');
|
|
70
62
|
}
|
|
71
63
|
|
|
72
|
-
get tracer(): Tracer {
|
|
73
|
-
return this.metrics.tracer;
|
|
74
|
-
}
|
|
75
64
|
/**
|
|
76
65
|
* Simulate a transaction's public portion including all of its phases.
|
|
77
66
|
* @param tx - The transaction to simulate.
|
|
@@ -79,11 +68,9 @@ export class PublicTxSimulator {
|
|
|
79
68
|
*/
|
|
80
69
|
public async simulate(tx: Tx): Promise<PublicTxResult> {
|
|
81
70
|
try {
|
|
82
|
-
const
|
|
71
|
+
const txHash = await this.computeTxHash(tx);
|
|
83
72
|
|
|
84
|
-
const txHash = await tx.getTxHash();
|
|
85
73
|
this.log.debug(`Simulating ${tx.publicFunctionCalldata.length} public calls for tx ${txHash}`, { txHash });
|
|
86
|
-
|
|
87
74
|
const context = await PublicTxContext.create(
|
|
88
75
|
this.treesDB,
|
|
89
76
|
this.contractsDB,
|
|
@@ -92,13 +79,7 @@ export class PublicTxSimulator {
|
|
|
92
79
|
this.doMerkleOperations,
|
|
93
80
|
);
|
|
94
81
|
|
|
95
|
-
|
|
96
|
-
await this.insertNonRevertiblesFromPrivate(context);
|
|
97
|
-
// add new contracts to the contracts db so that their functions may be found and called
|
|
98
|
-
// TODO(#6464): Should we allow emitting contracts in the private setup phase?
|
|
99
|
-
await this.contractsDB.addNewNonRevertibleContracts(tx);
|
|
100
|
-
const nonRevertEnd = process.hrtime.bigint();
|
|
101
|
-
this.metrics.recordPrivateEffectsInsertion(Number(nonRevertEnd - nonRevertStart) / 1_000, 'non-revertible');
|
|
82
|
+
await this.insertNonRevertiblesFromPrivate(context, tx);
|
|
102
83
|
|
|
103
84
|
const processedPhases: ProcessedPhase[] = [];
|
|
104
85
|
if (context.hasPhase(TxExecutionPhase.SETUP)) {
|
|
@@ -106,14 +87,8 @@ export class PublicTxSimulator {
|
|
|
106
87
|
processedPhases.push(setupResult);
|
|
107
88
|
}
|
|
108
89
|
|
|
109
|
-
const
|
|
110
|
-
const success = await this.insertRevertiblesFromPrivate(context);
|
|
90
|
+
const success = await this.insertRevertiblesFromPrivate(context, tx);
|
|
111
91
|
if (success) {
|
|
112
|
-
// add new contracts to the contracts db so that their functions may be found and called
|
|
113
|
-
await this.contractsDB.addNewRevertibleContracts(tx);
|
|
114
|
-
const revertEnd = process.hrtime.bigint();
|
|
115
|
-
this.metrics.recordPrivateEffectsInsertion(Number(revertEnd - revertStart) / 1_000, 'revertible');
|
|
116
|
-
|
|
117
92
|
// Only proceed with app logic if there was no revert during revertible insertion
|
|
118
93
|
if (context.hasPhase(TxExecutionPhase.APP_LOGIC)) {
|
|
119
94
|
const appLogicResult: ProcessedPhase = await this.simulateAppLogicPhase(context);
|
|
@@ -131,7 +106,7 @@ export class PublicTxSimulator {
|
|
|
131
106
|
await context.halt();
|
|
132
107
|
await this.payFee(context);
|
|
133
108
|
|
|
134
|
-
const publicInputs = await context.generateAvmCircuitPublicInputs(
|
|
109
|
+
const publicInputs = await context.generateAvmCircuitPublicInputs();
|
|
135
110
|
const avmProvingRequest = PublicTxSimulator.generateProvingRequest(publicInputs, context.hints);
|
|
136
111
|
|
|
137
112
|
const revertCode = context.getFinalRevertCode();
|
|
@@ -142,11 +117,10 @@ export class PublicTxSimulator {
|
|
|
142
117
|
// Commit contracts from this TX to the block-level cache and clear tx cache
|
|
143
118
|
// If the tx reverted, only commit non-revertible contracts
|
|
144
119
|
// NOTE: You can't create contracts in public, so this is only relevant for private-created contracts
|
|
120
|
+
// FIXME(fcarreiro): this should conceptually use the hinted contracts db.
|
|
121
|
+
// However things should work as they are now because the hinted db would still pick up the new contracts.
|
|
145
122
|
this.contractsDB.commitContractsForTx(/*onlyNonRevertibles=*/ !revertCode.isOK());
|
|
146
123
|
|
|
147
|
-
const endTime = process.hrtime.bigint();
|
|
148
|
-
this.log.debug(`Public TX simulator took ${Number(endTime - startTime) / 1_000_000} ms\n`);
|
|
149
|
-
|
|
150
124
|
return {
|
|
151
125
|
avmProvingRequest,
|
|
152
126
|
gasUsed: {
|
|
@@ -162,10 +136,16 @@ export class PublicTxSimulator {
|
|
|
162
136
|
} finally {
|
|
163
137
|
// Make sure there are no new contracts in the tx-level cache.
|
|
164
138
|
// They should either be committed to block-level cache or cleared.
|
|
139
|
+
// FIXME(fcarreiro): this should conceptually use the hinted contracts db.
|
|
140
|
+
// However things should work as they are now because the hinted db would still pick up the new contracts.
|
|
165
141
|
this.contractsDB.clearContractsForTx();
|
|
166
142
|
}
|
|
167
143
|
}
|
|
168
144
|
|
|
145
|
+
protected async computeTxHash(tx: Tx) {
|
|
146
|
+
return await tx.getTxHash();
|
|
147
|
+
}
|
|
148
|
+
|
|
169
149
|
/**
|
|
170
150
|
* Simulate the setup phase of a transaction's public execution.
|
|
171
151
|
* @param context - WILL BE MUTATED. The context of the currently executing public transaction portion
|
|
@@ -229,7 +209,7 @@ export class PublicTxSimulator {
|
|
|
229
209
|
* @param context - WILL BE MUTATED. The context of the currently executing public transaction portion
|
|
230
210
|
* @returns The phase result.
|
|
231
211
|
*/
|
|
232
|
-
|
|
212
|
+
protected async simulatePhase(phase: TxExecutionPhase, context: PublicTxContext): Promise<ProcessedPhase> {
|
|
233
213
|
const callRequests = context.getCallRequestsForPhase(phase);
|
|
234
214
|
|
|
235
215
|
this.log.debug(`Processing phase ${TxExecutionPhase[phase]} for tx ${context.txHash}`, {
|
|
@@ -241,7 +221,6 @@ export class PublicTxSimulator {
|
|
|
241
221
|
const returnValues: NestedProcessReturnValues[] = [];
|
|
242
222
|
let reverted = false;
|
|
243
223
|
let revertReason: SimulationError | undefined;
|
|
244
|
-
const phaseTimer = new Timer();
|
|
245
224
|
for (let i = callRequests.length - 1; i >= 0; i--) {
|
|
246
225
|
if (reverted) {
|
|
247
226
|
break;
|
|
@@ -261,7 +240,6 @@ export class PublicTxSimulator {
|
|
|
261
240
|
|
|
262
241
|
return {
|
|
263
242
|
phase,
|
|
264
|
-
durationMs: phaseTimer.ms(),
|
|
265
243
|
returnValues,
|
|
266
244
|
reverted,
|
|
267
245
|
revertReason,
|
|
@@ -275,13 +253,7 @@ export class PublicTxSimulator {
|
|
|
275
253
|
* @param callRequest - The public function call request, including the calldata.
|
|
276
254
|
* @returns The result of execution.
|
|
277
255
|
*/
|
|
278
|
-
|
|
279
|
-
[Attributes.TX_HASH]: context.txHash.toString(),
|
|
280
|
-
[Attributes.TARGET_ADDRESS]: callRequest.request.contractAddress.toString(),
|
|
281
|
-
[Attributes.SENDER_ADDRESS]: callRequest.request.msgSender.toString(),
|
|
282
|
-
[Attributes.SIMULATOR_PHASE]: TxExecutionPhase[phase].toString(),
|
|
283
|
-
}))
|
|
284
|
-
private async simulateEnqueuedCall(
|
|
256
|
+
protected async simulateEnqueuedCall(
|
|
285
257
|
phase: TxExecutionPhase,
|
|
286
258
|
context: PublicTxContext,
|
|
287
259
|
callRequest: PublicCallRequestWithCalldata,
|
|
@@ -335,19 +307,12 @@ export class PublicTxSimulator {
|
|
|
335
307
|
* while still simulating phases and generating a proving request.
|
|
336
308
|
*
|
|
337
309
|
* @param stateManager - The state manager for AvmSimulation
|
|
338
|
-
* @param context - The context of the currently executing public transaction portion
|
|
339
310
|
* @param callRequest - The public function call request, including the calldata.
|
|
340
311
|
* @param allocatedGas - The gas allocated to the enqueued call
|
|
341
312
|
* @param fnName - The name of the function
|
|
342
313
|
* @returns The result of execution.
|
|
343
314
|
*/
|
|
344
|
-
|
|
345
|
-
'PublicTxSimulator.simulateEnqueuedCallInternal',
|
|
346
|
-
(_stateManager, _callRequest, _allocatedGas, _transactionFee, fnName) => ({
|
|
347
|
-
[Attributes.APP_CIRCUIT_NAME]: fnName,
|
|
348
|
-
}),
|
|
349
|
-
)
|
|
350
|
-
private async simulateEnqueuedCallInternal(
|
|
315
|
+
protected async simulateEnqueuedCallInternal(
|
|
351
316
|
stateManager: AvmPersistableStateManager,
|
|
352
317
|
{ request, calldata }: PublicCallRequestWithCalldata,
|
|
353
318
|
allocatedGas: Gas,
|
|
@@ -360,7 +325,6 @@ export class PublicTxSimulator {
|
|
|
360
325
|
this.log.debug(
|
|
361
326
|
`Executing enqueued public call to external function ${fnName}@${address} with ${allocatedGas.l2Gas} allocated L2 gas.`,
|
|
362
327
|
);
|
|
363
|
-
const timer = new Timer();
|
|
364
328
|
|
|
365
329
|
const simulator = await AvmSimulator.create(
|
|
366
330
|
stateManager,
|
|
@@ -373,32 +337,13 @@ export class PublicTxSimulator {
|
|
|
373
337
|
allocatedGas,
|
|
374
338
|
);
|
|
375
339
|
const avmCallResult = await simulator.execute();
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
this.log.verbose(
|
|
379
|
-
result.reverted
|
|
380
|
-
? `Simulation of enqueued public call ${fnName} reverted with reason ${result.revertReason}.`
|
|
381
|
-
: `Simulation of enqueued public call ${fnName} completed successfully.`,
|
|
382
|
-
{
|
|
383
|
-
eventName: 'avm-simulation',
|
|
384
|
-
appCircuitName: fnName,
|
|
385
|
-
duration: timer.ms(),
|
|
386
|
-
} satisfies AvmSimulationStats,
|
|
387
|
-
);
|
|
388
|
-
|
|
389
|
-
if (result.reverted) {
|
|
390
|
-
this.metrics.recordFunctionSimulationFailure();
|
|
391
|
-
} else {
|
|
392
|
-
this.metrics.recordFunctionSimulation(timer.ms(), allocatedGas.sub(result.gasLeft).l2Gas, fnName);
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
return result;
|
|
340
|
+
return avmCallResult.finalize();
|
|
396
341
|
}
|
|
397
342
|
|
|
398
343
|
/**
|
|
399
344
|
* Insert the non-revertible accumulated data from private into the public state.
|
|
400
345
|
*/
|
|
401
|
-
|
|
346
|
+
protected async insertNonRevertiblesFromPrivate(context: PublicTxContext, tx: Tx) {
|
|
402
347
|
const stateManager = context.state.getActiveStateManager();
|
|
403
348
|
try {
|
|
404
349
|
await stateManager.writeSiloedNullifiersFromPrivate(context.nonRevertibleAccumulatedDataFromPrivate.nullifiers);
|
|
@@ -414,13 +359,18 @@ export class PublicTxSimulator {
|
|
|
414
359
|
await stateManager.writeUniqueNoteHash(noteHash);
|
|
415
360
|
}
|
|
416
361
|
}
|
|
362
|
+
// add new contracts to the contracts db so that their functions may be found and called
|
|
363
|
+
// TODO(#6464): Should we allow emitting contracts in the private setup phase?
|
|
364
|
+
// FIXME(fcarreiro): this should conceptually use the hinted contracts db.
|
|
365
|
+
// However things should work as they are now because the hinted db would still pick up the new contracts.
|
|
366
|
+
await this.contractsDB.addNewNonRevertibleContracts(tx);
|
|
417
367
|
}
|
|
418
368
|
|
|
419
369
|
/**
|
|
420
370
|
* Insert the revertible accumulated data from private into the public state.
|
|
421
371
|
* Start by forking state so we can rollback to the end of setup if app logic or teardown reverts.
|
|
422
372
|
*/
|
|
423
|
-
|
|
373
|
+
protected async insertRevertiblesFromPrivate(context: PublicTxContext, tx: Tx): /*success=*/ Promise<boolean> {
|
|
424
374
|
// Fork the state manager so we can rollback to end of setup if app logic reverts.
|
|
425
375
|
await context.state.fork();
|
|
426
376
|
const stateManager = context.state.getActiveStateManager();
|
|
@@ -448,6 +398,11 @@ export class PublicTxSimulator {
|
|
|
448
398
|
await stateManager.writeSiloedNoteHash(noteHash);
|
|
449
399
|
}
|
|
450
400
|
}
|
|
401
|
+
// add new contracts to the contracts db so that their functions may be found and called
|
|
402
|
+
// FIXME(fcarreiro): this should conceptually use the hinted contracts db.
|
|
403
|
+
// However things should work as they are now because the hinted db would still pick up the new contracts.
|
|
404
|
+
await this.contractsDB.addNewRevertibleContracts(tx);
|
|
405
|
+
|
|
451
406
|
return /*success=*/ true;
|
|
452
407
|
}
|
|
453
408
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { Fr } from '@aztec/foundation/fields';
|
|
2
|
+
import type { Gas } from '@aztec/stdlib/gas';
|
|
3
|
+
import { type GlobalVariables, PublicCallRequestWithCalldata, TxExecutionPhase } from '@aztec/stdlib/tx';
|
|
4
|
+
import { Attributes, type TelemetryClient, type Tracer, getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
|
|
5
|
+
|
|
6
|
+
import type { AvmFinalizedCallResult } from '../avm/avm_contract_call_result.js';
|
|
7
|
+
import type { AvmPersistableStateManager } from '../avm/index.js';
|
|
8
|
+
import { ExecutorMetrics } from '../executor_metrics.js';
|
|
9
|
+
import type { PublicContractsDB, PublicTreesDB } from '../public_db_sources.js';
|
|
10
|
+
import { MeasuredPublicTxSimulator } from './measured_public_tx_simulator.js';
|
|
11
|
+
import { PublicTxContext } from './public_tx_context.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A public tx simulator that tracks runtime/production metrics with telemetry.
|
|
15
|
+
*/
|
|
16
|
+
export class TelemetryPublicTxSimulator extends MeasuredPublicTxSimulator {
|
|
17
|
+
/* tracer needed by trackSpans */
|
|
18
|
+
public readonly tracer: Tracer;
|
|
19
|
+
|
|
20
|
+
constructor(
|
|
21
|
+
treesDB: PublicTreesDB,
|
|
22
|
+
contractsDB: PublicContractsDB,
|
|
23
|
+
globalVariables: GlobalVariables,
|
|
24
|
+
doMerkleOperations: boolean = false,
|
|
25
|
+
skipFeeEnforcement: boolean = false,
|
|
26
|
+
telemetryClient: TelemetryClient = getTelemetryClient(),
|
|
27
|
+
) {
|
|
28
|
+
const metrics = new ExecutorMetrics(telemetryClient, 'PublicTxSimulator');
|
|
29
|
+
super(treesDB, contractsDB, globalVariables, doMerkleOperations, skipFeeEnforcement, metrics);
|
|
30
|
+
this.tracer = metrics.tracer;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@trackSpan('PublicTxSimulator.simulateEnqueuedCall', (phase, context, callRequest) => ({
|
|
34
|
+
[Attributes.TX_HASH]: context.txHash.toString(),
|
|
35
|
+
[Attributes.TARGET_ADDRESS]: callRequest.request.contractAddress.toString(),
|
|
36
|
+
[Attributes.SENDER_ADDRESS]: callRequest.request.msgSender.toString(),
|
|
37
|
+
[Attributes.SIMULATOR_PHASE]: TxExecutionPhase[phase].toString(),
|
|
38
|
+
}))
|
|
39
|
+
protected override async simulateEnqueuedCall(
|
|
40
|
+
phase: TxExecutionPhase,
|
|
41
|
+
context: PublicTxContext,
|
|
42
|
+
callRequest: PublicCallRequestWithCalldata,
|
|
43
|
+
): Promise<AvmFinalizedCallResult> {
|
|
44
|
+
return await super.simulateEnqueuedCall(phase, context, callRequest);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@trackSpan(
|
|
48
|
+
'PublicTxSimulator.simulateEnqueuedCallInternal',
|
|
49
|
+
(_stateManager, _callRequest, _allocatedGas, _transactionFee, fnName) => ({
|
|
50
|
+
[Attributes.APP_CIRCUIT_NAME]: fnName,
|
|
51
|
+
}),
|
|
52
|
+
)
|
|
53
|
+
protected override async simulateEnqueuedCallInternal(
|
|
54
|
+
stateManager: AvmPersistableStateManager,
|
|
55
|
+
callRequest: PublicCallRequestWithCalldata,
|
|
56
|
+
allocatedGas: Gas,
|
|
57
|
+
transactionFee: Fr,
|
|
58
|
+
fnName: string,
|
|
59
|
+
): Promise<AvmFinalizedCallResult> {
|
|
60
|
+
return await super.simulateEnqueuedCallInternal(stateManager, callRequest, allocatedGas, transactionFee, fnName);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { sum } from '@aztec/foundation/collection';
|
|
2
|
+
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
3
|
+
import { Timer } from '@aztec/foundation/timer';
|
|
4
|
+
import type { RevertCode } from '@aztec/stdlib/avm';
|
|
5
|
+
|
|
6
|
+
import { strict as assert } from 'assert';
|
|
7
|
+
|
|
8
|
+
import type { ExecutorMetricsInterface } from './executor_metrics_interface.js';
|
|
9
|
+
|
|
10
|
+
export interface PublicEnqueuedCallMetrics {
|
|
11
|
+
fnName: string;
|
|
12
|
+
durationMs: number;
|
|
13
|
+
manaUsed: number;
|
|
14
|
+
totalInstructions: number;
|
|
15
|
+
reverted: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface PublicTxMetrics {
|
|
19
|
+
totalDurationMs: number;
|
|
20
|
+
manaUsed: number;
|
|
21
|
+
totalInstructions: number;
|
|
22
|
+
txHashMs: number | undefined;
|
|
23
|
+
nonRevertiblePrivateInsertionsUs: number | undefined;
|
|
24
|
+
revertiblePrivateInsertionsUs: number | undefined;
|
|
25
|
+
enqueuedCalls: PublicEnqueuedCallMetrics[];
|
|
26
|
+
revertedCode: RevertCode | undefined;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const NUM_SPACES = 4;
|
|
30
|
+
const H1 = '# ';
|
|
31
|
+
const H2 = '\n## ';
|
|
32
|
+
const INDENT = ' '.repeat(NUM_SPACES);
|
|
33
|
+
const INDENT0 = '- ';
|
|
34
|
+
const INDENT1 = INDENT + '- ';
|
|
35
|
+
const INDENT2 = INDENT + INDENT + '- ';
|
|
36
|
+
const H_LINE = '\n---------------------------------------------------------------------';
|
|
37
|
+
|
|
38
|
+
export enum PublicTxMetricsFilter {
|
|
39
|
+
ALL,
|
|
40
|
+
TOTALS,
|
|
41
|
+
DURATIONS,
|
|
42
|
+
INSTRUCTIONS,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class TestExecutorMetrics implements ExecutorMetricsInterface {
|
|
46
|
+
private logger: Logger;
|
|
47
|
+
// tx label -> tx metrics
|
|
48
|
+
private txMetrics: Map<string, PublicTxMetrics> = new Map();
|
|
49
|
+
private currentTxLabel: string | undefined;
|
|
50
|
+
private txTimer: Timer | undefined;
|
|
51
|
+
|
|
52
|
+
constructor() {
|
|
53
|
+
this.logger = createLogger(`simulator:test_executor_metrics`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
startRecordingTxSimulation(txLabel: string) {
|
|
57
|
+
assert(!this.currentTxLabel, 'Cannot start recording tx simulation when another is live');
|
|
58
|
+
assert(!this.txMetrics.has(txLabel), 'Cannot start recording metrics for tx with duplicate label');
|
|
59
|
+
this.txMetrics.set(txLabel, {
|
|
60
|
+
totalDurationMs: 0,
|
|
61
|
+
manaUsed: 0,
|
|
62
|
+
totalInstructions: 0,
|
|
63
|
+
txHashMs: undefined,
|
|
64
|
+
nonRevertiblePrivateInsertionsUs: undefined,
|
|
65
|
+
revertiblePrivateInsertionsUs: undefined,
|
|
66
|
+
enqueuedCalls: [],
|
|
67
|
+
revertedCode: undefined,
|
|
68
|
+
});
|
|
69
|
+
this.currentTxLabel = txLabel;
|
|
70
|
+
this.txTimer = new Timer();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
stopRecordingTxSimulation(txLabel: string, revertedCode?: RevertCode) {
|
|
74
|
+
assert(this.currentTxLabel === txLabel, 'Cannot stop recording metrics for tx when another is live');
|
|
75
|
+
|
|
76
|
+
const txMetrics = this.txMetrics.get(txLabel)!;
|
|
77
|
+
|
|
78
|
+
// total duration of tx
|
|
79
|
+
txMetrics.totalDurationMs = this.txTimer!.ms();
|
|
80
|
+
this.logger.debug(`Public TX simulation of ${txLabel} took ${txMetrics.totalDurationMs}ms`);
|
|
81
|
+
|
|
82
|
+
// add manaUsed across all enqueued calls
|
|
83
|
+
txMetrics.manaUsed = sum(txMetrics.enqueuedCalls.map(call => call.manaUsed));
|
|
84
|
+
// add totalInstructions across all enqueued calls
|
|
85
|
+
txMetrics.totalInstructions = sum(txMetrics.enqueuedCalls.map(call => call.totalInstructions));
|
|
86
|
+
txMetrics.revertedCode = revertedCode;
|
|
87
|
+
|
|
88
|
+
this.currentTxLabel = undefined;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
recordEnqueuedCallSimulation(fnName: string, durationMs: number, manaUsed: number, totalInstructions: number) {
|
|
92
|
+
this.#recordEnqueuedCallSimulation(fnName, durationMs, manaUsed, totalInstructions, false);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
recordEnqueuedCallSimulationFailure(fnName: string, durationMs: number, manaUsed: number, totalInstructions: number) {
|
|
96
|
+
this.#recordEnqueuedCallSimulation(fnName, durationMs, manaUsed, totalInstructions, true);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
#recordEnqueuedCallSimulation(
|
|
100
|
+
fnName: string,
|
|
101
|
+
durationMs: number,
|
|
102
|
+
manaUsed: number,
|
|
103
|
+
totalInstructions: number,
|
|
104
|
+
reverted: boolean,
|
|
105
|
+
) {
|
|
106
|
+
assert(this.currentTxLabel, 'Cannot record enqueued call simulation when no tx is live');
|
|
107
|
+
const txMetrics = this.txMetrics.get(this.currentTxLabel)!;
|
|
108
|
+
txMetrics.enqueuedCalls.push({
|
|
109
|
+
fnName,
|
|
110
|
+
durationMs,
|
|
111
|
+
manaUsed,
|
|
112
|
+
totalInstructions,
|
|
113
|
+
reverted,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
recordTxHashComputation(durationMs: number) {
|
|
118
|
+
assert(this.currentTxLabel, 'Cannot record tx hash computation time when no tx is live');
|
|
119
|
+
const txMetrics = this.txMetrics.get(this.currentTxLabel)!;
|
|
120
|
+
assert(txMetrics.txHashMs === undefined, 'Cannot RE-record tx hash computation time');
|
|
121
|
+
txMetrics.txHashMs = durationMs;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
recordPrivateEffectsInsertion(durationUs: number, type: 'revertible' | 'non-revertible') {
|
|
125
|
+
assert(this.currentTxLabel, 'Cannot record private effects insertion when no tx is live');
|
|
126
|
+
const txMetrics = this.txMetrics.get(this.currentTxLabel)!;
|
|
127
|
+
if (type === 'revertible') {
|
|
128
|
+
assert(
|
|
129
|
+
txMetrics.revertiblePrivateInsertionsUs === undefined,
|
|
130
|
+
'Cannot RE-record revertible insertions of private effects',
|
|
131
|
+
);
|
|
132
|
+
txMetrics.revertiblePrivateInsertionsUs = durationUs;
|
|
133
|
+
} else {
|
|
134
|
+
assert(
|
|
135
|
+
txMetrics.nonRevertiblePrivateInsertionsUs === undefined,
|
|
136
|
+
'Cannot RE-record non-revertible insertions of private effects',
|
|
137
|
+
);
|
|
138
|
+
txMetrics.nonRevertiblePrivateInsertionsUs = durationUs;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
prettyPrint(filter: PublicTxMetricsFilter = PublicTxMetricsFilter.ALL) {
|
|
143
|
+
this.logger.info(this.toPrettyString(filter));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
toPrettyString(filter: PublicTxMetricsFilter = PublicTxMetricsFilter.ALL) {
|
|
147
|
+
let pretty = '';
|
|
148
|
+
//pretty += H_LINE + '\n';
|
|
149
|
+
pretty += `${H1}Public TX Simulation Metrics (${PublicTxMetricsFilter[filter]})\n`;
|
|
150
|
+
for (const [txLabel, txMetrics] of this.txMetrics.entries()) {
|
|
151
|
+
//pretty += H_LINE + '\n';
|
|
152
|
+
pretty += `${H2}TX Label: ${txLabel}\n`;
|
|
153
|
+
if (
|
|
154
|
+
filter == PublicTxMetricsFilter.DURATIONS ||
|
|
155
|
+
filter === PublicTxMetricsFilter.TOTALS ||
|
|
156
|
+
filter === PublicTxMetricsFilter.ALL
|
|
157
|
+
) {
|
|
158
|
+
pretty += `${INDENT0}Total duration: ${fmtNum(txMetrics.totalDurationMs, 'ms')}\n`;
|
|
159
|
+
}
|
|
160
|
+
if (filter === PublicTxMetricsFilter.TOTALS || filter === PublicTxMetricsFilter.ALL) {
|
|
161
|
+
pretty += `${INDENT0}Total mana used: ${fmtNum(txMetrics.manaUsed)}\n`;
|
|
162
|
+
const manaPerSecond = Math.round((txMetrics.manaUsed * 1000) / txMetrics.totalDurationMs);
|
|
163
|
+
pretty += `${INDENT0}Mana per second: ${fmtNum(manaPerSecond)}\n`;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (
|
|
167
|
+
filter === PublicTxMetricsFilter.INSTRUCTIONS ||
|
|
168
|
+
filter === PublicTxMetricsFilter.TOTALS ||
|
|
169
|
+
filter === PublicTxMetricsFilter.ALL
|
|
170
|
+
) {
|
|
171
|
+
pretty += `${INDENT0}Total instructions executed: ${fmtNum(txMetrics.totalInstructions)}\n`;
|
|
172
|
+
}
|
|
173
|
+
if (filter === PublicTxMetricsFilter.DURATIONS || filter === PublicTxMetricsFilter.ALL) {
|
|
174
|
+
pretty += `${INDENT0}Tx hash computation: ${fmtNum(txMetrics.txHashMs!, 'ms')}\n`;
|
|
175
|
+
pretty += `${INDENT0}Private insertions:\n`;
|
|
176
|
+
pretty += `${INDENT1}Non-revertible: ${fmtNum(txMetrics.nonRevertiblePrivateInsertionsUs! / 1_000, 'ms')}\n`;
|
|
177
|
+
pretty += `${INDENT1}Revertible: ${fmtNum(txMetrics.revertiblePrivateInsertionsUs! / 1_000, 'ms')}\n`;
|
|
178
|
+
}
|
|
179
|
+
if (filter !== PublicTxMetricsFilter.TOTALS) {
|
|
180
|
+
// totals exclude enqueued calls
|
|
181
|
+
pretty += this.#enqueuedCallsToPrettyString(txMetrics, filter);
|
|
182
|
+
}
|
|
183
|
+
if (txMetrics.revertedCode !== undefined && !txMetrics.revertedCode.isOK()) {
|
|
184
|
+
pretty += `${INDENT0}Reverted code: ${txMetrics.revertedCode?.getDescription()}\n`;
|
|
185
|
+
}
|
|
186
|
+
pretty += H_LINE + '\n';
|
|
187
|
+
}
|
|
188
|
+
return pretty;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
#enqueuedCallsToPrettyString(txMetrics: PublicTxMetrics, filter: PublicTxMetricsFilter) {
|
|
192
|
+
let pretty = '';
|
|
193
|
+
pretty += `${INDENT0}Enqueued public calls:\n`;
|
|
194
|
+
for (const enqueuedCall of txMetrics.enqueuedCalls) {
|
|
195
|
+
pretty += `${INDENT1}**Fn: ${enqueuedCall.fnName}**\n`;
|
|
196
|
+
if (filter === PublicTxMetricsFilter.DURATIONS || filter === PublicTxMetricsFilter.ALL) {
|
|
197
|
+
pretty += `${INDENT2}Duration: ${fmtNum(enqueuedCall.durationMs, 'ms')}\n`;
|
|
198
|
+
}
|
|
199
|
+
if (filter === PublicTxMetricsFilter.ALL) {
|
|
200
|
+
pretty += `${INDENT2}Mana used: ${fmtNum(enqueuedCall.manaUsed)}\n`;
|
|
201
|
+
const manaPerSecond = Math.round((enqueuedCall.manaUsed * 1000) / enqueuedCall.durationMs);
|
|
202
|
+
pretty += `${INDENT2}Mana per second: ${fmtNum(manaPerSecond)}\n`;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (filter === PublicTxMetricsFilter.INSTRUCTIONS || filter === PublicTxMetricsFilter.ALL) {
|
|
206
|
+
pretty += `${INDENT2}Instructions executed: ${fmtNum(enqueuedCall.totalInstructions)}\n`;
|
|
207
|
+
}
|
|
208
|
+
if (enqueuedCall.reverted) {
|
|
209
|
+
pretty += `${INDENT2}Reverted!\n`;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return pretty;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
toJSON(indent = 2) {
|
|
216
|
+
return JSON.stringify(Object.fromEntries(this.txMetrics.entries()), null, indent);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function fmtNum(num: number, unit?: string) {
|
|
221
|
+
return `\`${num.toLocaleString()}${unit ? ` ${unit}` : ''}\``;
|
|
222
|
+
}
|