@aztec/simulator 0.65.0 → 0.65.2
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/dest/avm/avm_memory_types.d.ts +3 -1
- package/dest/avm/avm_memory_types.d.ts.map +1 -1
- package/dest/avm/avm_memory_types.js +22 -24
- package/dest/avm/avm_simulator.d.ts +5 -1
- package/dest/avm/avm_simulator.d.ts.map +1 -1
- package/dest/avm/avm_simulator.js +16 -9
- package/dest/avm/avm_tree.d.ts +56 -7
- package/dest/avm/avm_tree.d.ts.map +1 -1
- package/dest/avm/avm_tree.js +155 -83
- package/dest/avm/errors.d.ts +19 -0
- package/dest/avm/errors.d.ts.map +1 -1
- package/dest/avm/errors.js +29 -1
- package/dest/avm/journal/journal.d.ts +8 -7
- package/dest/avm/journal/journal.d.ts.map +1 -1
- package/dest/avm/journal/journal.js +47 -29
- package/dest/avm/journal/nullifiers.d.ts +11 -58
- package/dest/avm/journal/nullifiers.d.ts.map +1 -1
- package/dest/avm/journal/nullifiers.js +27 -107
- package/dest/avm/opcodes/memory.d.ts.map +1 -1
- package/dest/avm/opcodes/memory.js +6 -2
- package/dest/avm/serialization/buffer_cursor.d.ts +2 -0
- package/dest/avm/serialization/buffer_cursor.d.ts.map +1 -1
- package/dest/avm/serialization/buffer_cursor.js +8 -3
- package/dest/avm/serialization/bytecode_serialization.d.ts +1 -0
- package/dest/avm/serialization/bytecode_serialization.d.ts.map +1 -1
- package/dest/avm/serialization/bytecode_serialization.js +27 -13
- package/dest/avm/serialization/instruction_serialization.d.ts +1 -0
- package/dest/avm/serialization/instruction_serialization.d.ts.map +1 -1
- package/dest/avm/serialization/instruction_serialization.js +9 -6
- package/dest/avm/test_utils.d.ts.map +1 -1
- package/dest/avm/test_utils.js +3 -2
- package/dest/common/errors.d.ts.map +1 -1
- package/dest/common/errors.js +3 -2
- package/dest/public/dual_side_effect_trace.d.ts +2 -2
- package/dest/public/dual_side_effect_trace.d.ts.map +1 -1
- package/dest/public/dual_side_effect_trace.js +7 -7
- package/dest/public/enqueued_call_side_effect_trace.d.ts +8 -23
- package/dest/public/enqueued_call_side_effect_trace.d.ts.map +1 -1
- package/dest/public/enqueued_call_side_effect_trace.js +31 -92
- package/dest/public/executor_metrics.d.ts +4 -2
- package/dest/public/executor_metrics.d.ts.map +1 -1
- package/dest/public/executor_metrics.js +20 -3
- package/dest/public/fixtures/index.d.ts.map +1 -1
- package/dest/public/fixtures/index.js +82 -36
- package/dest/public/public_db_sources.d.ts +3 -1
- package/dest/public/public_db_sources.d.ts.map +1 -1
- package/dest/public/public_db_sources.js +26 -11
- package/dest/public/public_processor.d.ts.map +1 -1
- package/dest/public/public_processor.js +12 -5
- package/dest/public/public_tx_context.d.ts +5 -6
- package/dest/public/public_tx_context.d.ts.map +1 -1
- package/dest/public/public_tx_context.js +19 -17
- package/dest/public/public_tx_simulator.d.ts +13 -2
- package/dest/public/public_tx_simulator.d.ts.map +1 -1
- package/dest/public/public_tx_simulator.js +278 -217
- package/dest/public/side_effect_trace.d.ts +2 -2
- package/dest/public/side_effect_trace.d.ts.map +1 -1
- package/dest/public/side_effect_trace.js +8 -6
- package/dest/public/side_effect_trace_interface.d.ts +2 -2
- package/dest/public/side_effect_trace_interface.d.ts.map +1 -1
- package/dest/public/transitional_adapters.d.ts.map +1 -1
- package/dest/public/transitional_adapters.js +2 -6
- package/package.json +9 -9
- package/src/avm/avm_memory_types.ts +26 -24
- package/src/avm/avm_simulator.ts +20 -13
- package/src/avm/avm_tree.ts +196 -94
- package/src/avm/errors.ts +31 -0
- package/src/avm/journal/journal.ts +61 -47
- package/src/avm/journal/nullifiers.ts +29 -121
- package/src/avm/opcodes/memory.ts +6 -1
- package/src/avm/serialization/buffer_cursor.ts +9 -3
- package/src/avm/serialization/bytecode_serialization.ts +29 -13
- package/src/avm/serialization/instruction_serialization.ts +12 -6
- package/src/avm/test_utils.ts +9 -1
- package/src/common/errors.ts +2 -1
- package/src/public/dual_side_effect_trace.ts +6 -30
- package/src/public/enqueued_call_side_effect_trace.ts +35 -154
- package/src/public/executor_metrics.ts +23 -1
- package/src/public/fixtures/index.ts +119 -44
- package/src/public/public_db_sources.ts +29 -15
- package/src/public/public_processor.ts +11 -4
- package/src/public/public_tx_context.ts +21 -23
- package/src/public/public_tx_simulator.ts +62 -8
- package/src/public/side_effect_trace.ts +7 -9
- package/src/public/side_effect_trace_interface.ts +2 -4
- package/src/public/transitional_adapters.ts +0 -11
|
@@ -14,11 +14,12 @@ import {
|
|
|
14
14
|
ContractInstanceDeployedEvent,
|
|
15
15
|
type ContractInstanceWithAddress,
|
|
16
16
|
Fr,
|
|
17
|
-
FunctionSelector,
|
|
17
|
+
type FunctionSelector,
|
|
18
18
|
type L1_TO_L2_MSG_TREE_HEIGHT,
|
|
19
19
|
type NULLIFIER_TREE_HEIGHT,
|
|
20
20
|
type NullifierLeafPreimage,
|
|
21
21
|
type PublicDataTreeLeafPreimage,
|
|
22
|
+
computePublicBytecodeCommitment,
|
|
22
23
|
} from '@aztec/circuits.js';
|
|
23
24
|
import { computeL1ToL2MessageNullifier, computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash';
|
|
24
25
|
import { createDebugLogger } from '@aztec/foundation/log';
|
|
@@ -38,11 +39,11 @@ import {
|
|
|
38
39
|
export class ContractsDataSourcePublicDB implements PublicContractsDB {
|
|
39
40
|
private instanceCache = new Map<string, ContractInstanceWithAddress>();
|
|
40
41
|
private classCache = new Map<string, ContractClassPublic>();
|
|
42
|
+
private bytecodeCommitmentCache = new Map<string, Fr>();
|
|
41
43
|
|
|
42
44
|
private log = createDebugLogger('aztec:sequencer:contracts-data-source');
|
|
43
45
|
|
|
44
46
|
constructor(private dataSource: ContractDataSource) {}
|
|
45
|
-
|
|
46
47
|
/**
|
|
47
48
|
* Add new contracts from a transaction
|
|
48
49
|
* @param tx - The transaction to add contracts from.
|
|
@@ -92,6 +93,31 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB {
|
|
|
92
93
|
return this.classCache.get(contractClassId.toString()) ?? (await this.dataSource.getContractClass(contractClassId));
|
|
93
94
|
}
|
|
94
95
|
|
|
96
|
+
public async getBytecodeCommitment(contractClassId: Fr): Promise<Fr | undefined> {
|
|
97
|
+
// Try and retrieve from cache
|
|
98
|
+
const key = contractClassId.toString();
|
|
99
|
+
const result = this.bytecodeCommitmentCache.get(key);
|
|
100
|
+
if (result !== undefined) {
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
// Now try from the store
|
|
104
|
+
const fromStore = await this.dataSource.getBytecodeCommitment(contractClassId);
|
|
105
|
+
if (fromStore !== undefined) {
|
|
106
|
+
this.bytecodeCommitmentCache.set(key, fromStore);
|
|
107
|
+
return fromStore;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Not in either the store or the cache, build it here and cache
|
|
111
|
+
const contractClass = await this.getContractClass(contractClassId);
|
|
112
|
+
if (contractClass === undefined) {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const value = computePublicBytecodeCommitment(contractClass.packedBytecode);
|
|
117
|
+
this.bytecodeCommitmentCache.set(key, value);
|
|
118
|
+
return value;
|
|
119
|
+
}
|
|
120
|
+
|
|
95
121
|
async getBytecode(address: AztecAddress, selector: FunctionSelector): Promise<Buffer | undefined> {
|
|
96
122
|
const instance = await this.getContractInstance(address);
|
|
97
123
|
if (!instance) {
|
|
@@ -105,19 +131,7 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB {
|
|
|
105
131
|
}
|
|
106
132
|
|
|
107
133
|
public async getDebugFunctionName(address: AztecAddress, selector: FunctionSelector): Promise<string | undefined> {
|
|
108
|
-
|
|
109
|
-
if (!artifact) {
|
|
110
|
-
return Promise.resolve(undefined);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const f = artifact.functions.find(f =>
|
|
114
|
-
FunctionSelector.fromNameAndParameters(f.name, f.parameters).equals(selector),
|
|
115
|
-
);
|
|
116
|
-
if (!f) {
|
|
117
|
-
return Promise.resolve(undefined);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return Promise.resolve(`${artifact.name}:${f.name}`);
|
|
134
|
+
return await this.dataSource.getContractFunctionName(address, selector);
|
|
121
135
|
}
|
|
122
136
|
}
|
|
123
137
|
|
|
@@ -80,7 +80,7 @@ export class PublicProcessor {
|
|
|
80
80
|
protected worldStateDB: WorldStateDB,
|
|
81
81
|
protected publicTxSimulator: PublicTxSimulator,
|
|
82
82
|
telemetryClient: TelemetryClient,
|
|
83
|
-
private log = createDebugLogger('aztec:
|
|
83
|
+
private log = createDebugLogger('aztec:simulator:public-processor'),
|
|
84
84
|
) {
|
|
85
85
|
this.metrics = new PublicProcessorMetrics(telemetryClient, 'PublicProcessor');
|
|
86
86
|
}
|
|
@@ -201,6 +201,7 @@ export class PublicProcessor {
|
|
|
201
201
|
feePayer: AztecAddress,
|
|
202
202
|
): Promise<PublicDataWrite | undefined> {
|
|
203
203
|
if (feePayer.isZero()) {
|
|
204
|
+
this.log.debug(`No one is paying the fee of ${txFee.toBigInt()}`);
|
|
204
205
|
return;
|
|
205
206
|
}
|
|
206
207
|
|
|
@@ -208,7 +209,7 @@ export class PublicProcessor {
|
|
|
208
209
|
const balanceSlot = computeFeePayerBalanceStorageSlot(feePayer);
|
|
209
210
|
const leafSlot = computeFeePayerBalanceLeafSlot(feePayer);
|
|
210
211
|
|
|
211
|
-
this.log.debug(`Deducting ${txFee} balance in Fee Juice for ${feePayer}`);
|
|
212
|
+
this.log.debug(`Deducting ${txFee.toBigInt()} balance in Fee Juice for ${feePayer}`);
|
|
212
213
|
|
|
213
214
|
const existingBalanceWrite = publicDataWrites.find(write => write.leafSlot.equals(leafSlot));
|
|
214
215
|
|
|
@@ -217,7 +218,9 @@ export class PublicProcessor {
|
|
|
217
218
|
: await this.worldStateDB.storageRead(feeJuiceAddress, balanceSlot);
|
|
218
219
|
|
|
219
220
|
if (balance.lt(txFee)) {
|
|
220
|
-
throw new Error(
|
|
221
|
+
throw new Error(
|
|
222
|
+
`Not enough balance for fee payer to pay for transaction (got ${balance.toBigInt()} needs ${txFee.toBigInt()})`,
|
|
223
|
+
);
|
|
221
224
|
}
|
|
222
225
|
|
|
223
226
|
const updatedBalance = balance.sub(txFee);
|
|
@@ -226,6 +229,9 @@ export class PublicProcessor {
|
|
|
226
229
|
return new PublicDataWrite(leafSlot, updatedBalance);
|
|
227
230
|
}
|
|
228
231
|
|
|
232
|
+
@trackSpan('PublicProcessor.processPrivateOnlyTx', (tx: Tx) => ({
|
|
233
|
+
[Attributes.TX_HASH]: tx.getTxHash().toString(),
|
|
234
|
+
}))
|
|
229
235
|
private async processPrivateOnlyTx(tx: Tx): Promise<[ProcessedTx]> {
|
|
230
236
|
const gasFees = this.globalVariables.gasFees;
|
|
231
237
|
const transactionFee = tx.data.gasUsed.computeFee(gasFees);
|
|
@@ -276,7 +282,8 @@ export class PublicProcessor {
|
|
|
276
282
|
);
|
|
277
283
|
|
|
278
284
|
const phaseCount = processedPhases.length;
|
|
279
|
-
|
|
285
|
+
const durationMs = timer.ms();
|
|
286
|
+
this.metrics.recordTx(phaseCount, durationMs);
|
|
280
287
|
|
|
281
288
|
const data = avmProvingRequest.inputs.output;
|
|
282
289
|
const feePaymentPublicDataWrite = await this.getFeePaymentPublicDataWrite(
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type AvmProvingRequest,
|
|
3
|
+
MerkleTreeId,
|
|
3
4
|
type MerkleTreeReadOperations,
|
|
4
5
|
type PublicExecutionRequest,
|
|
5
6
|
type SimulationError,
|
|
@@ -67,10 +68,9 @@ export class PublicTxContext {
|
|
|
67
68
|
private readonly setupExecutionRequests: PublicExecutionRequest[],
|
|
68
69
|
private readonly appLogicExecutionRequests: PublicExecutionRequest[],
|
|
69
70
|
private readonly teardownExecutionRequests: PublicExecutionRequest[],
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
public readonly nonRevertibleAccumulatedDataFromPrivate: PrivateToPublicAccumulatedData,
|
|
72
|
+
public readonly revertibleAccumulatedDataFromPrivate: PrivateToPublicAccumulatedData,
|
|
72
73
|
public trace: PublicEnqueuedCallSideEffectTrace, // FIXME(dbanks12): should be private
|
|
73
|
-
private doMerkleOperations: boolean,
|
|
74
74
|
) {
|
|
75
75
|
this.log = createDebugLogger(`aztec:public_tx_context`);
|
|
76
76
|
this.gasUsed = startGasUsed;
|
|
@@ -84,23 +84,12 @@ export class PublicTxContext {
|
|
|
84
84
|
doMerkleOperations: boolean,
|
|
85
85
|
) {
|
|
86
86
|
const nonRevertibleAccumulatedDataFromPrivate = tx.data.forPublic!.nonRevertibleAccumulatedData;
|
|
87
|
-
const revertibleAccumulatedDataFromPrivate = tx.data.forPublic!.revertibleAccumulatedData;
|
|
88
|
-
const nonRevertibleNullifiersFromPrivate = nonRevertibleAccumulatedDataFromPrivate.nullifiers.filter(
|
|
89
|
-
n => !n.isEmpty(),
|
|
90
|
-
);
|
|
91
|
-
const _revertibleNullifiersFromPrivate = revertibleAccumulatedDataFromPrivate.nullifiers.filter(n => !n.isEmpty());
|
|
92
87
|
|
|
93
88
|
const innerCallTrace = new PublicSideEffectTrace();
|
|
94
|
-
|
|
95
89
|
const previousAccumulatedDataArrayLengths = new SideEffectArrayLengths(
|
|
96
|
-
/*publicDataReads*/ 0,
|
|
97
90
|
/*publicDataWrites*/ 0,
|
|
98
|
-
/*noteHashReadRequests*/ 0,
|
|
99
91
|
countAccumulatedItems(nonRevertibleAccumulatedDataFromPrivate.noteHashes),
|
|
100
|
-
/*nullifierReadRequests*/ 0,
|
|
101
|
-
/*nullifierNonExistentReadRequests*/ 0,
|
|
102
92
|
countAccumulatedItems(nonRevertibleAccumulatedDataFromPrivate.nullifiers),
|
|
103
|
-
/*l1ToL2MsgReadRequests*/ 0,
|
|
104
93
|
countAccumulatedItems(nonRevertibleAccumulatedDataFromPrivate.l2ToL1Msgs),
|
|
105
94
|
/*unencryptedLogsHashes*/ 0,
|
|
106
95
|
);
|
|
@@ -111,12 +100,7 @@ export class PublicTxContext {
|
|
|
111
100
|
const trace = new DualSideEffectTrace(innerCallTrace, enqueuedCallTrace);
|
|
112
101
|
|
|
113
102
|
// Transaction level state manager that will be forked for revertible phases.
|
|
114
|
-
const txStateManager = await AvmPersistableStateManager.
|
|
115
|
-
worldStateDB,
|
|
116
|
-
trace,
|
|
117
|
-
nonRevertibleNullifiersFromPrivate,
|
|
118
|
-
doMerkleOperations,
|
|
119
|
-
);
|
|
103
|
+
const txStateManager = await AvmPersistableStateManager.create(worldStateDB, trace, doMerkleOperations);
|
|
120
104
|
|
|
121
105
|
return new PublicTxContext(
|
|
122
106
|
new PhaseStateManager(txStateManager),
|
|
@@ -134,7 +118,6 @@ export class PublicTxContext {
|
|
|
134
118
|
tx.data.forPublic!.nonRevertibleAccumulatedData,
|
|
135
119
|
tx.data.forPublic!.revertibleAccumulatedData,
|
|
136
120
|
enqueuedCallTrace,
|
|
137
|
-
doMerkleOperations,
|
|
138
121
|
);
|
|
139
122
|
}
|
|
140
123
|
|
|
@@ -144,6 +127,9 @@ export class PublicTxContext {
|
|
|
144
127
|
* Actual transaction fee and actual total consumed gas can now be queried.
|
|
145
128
|
*/
|
|
146
129
|
halt() {
|
|
130
|
+
if (this.state.isForked()) {
|
|
131
|
+
this.state.mergeForkedState();
|
|
132
|
+
}
|
|
147
133
|
this.halted = true;
|
|
148
134
|
}
|
|
149
135
|
|
|
@@ -315,6 +301,11 @@ export class PublicTxContext {
|
|
|
315
301
|
*/
|
|
316
302
|
private generateAvmCircuitPublicInputs(endStateReference: StateReference): AvmCircuitPublicInputs {
|
|
317
303
|
assert(this.halted, 'Can only get AvmCircuitPublicInputs after tx execution ends');
|
|
304
|
+
// TODO(dbanks12): use the state roots from ephemeral trees
|
|
305
|
+
endStateReference.partial.nullifierTree.root = this.state
|
|
306
|
+
.getActiveStateManager()
|
|
307
|
+
.merkleTrees.treeMap.get(MerkleTreeId.NULLIFIER_TREE)!
|
|
308
|
+
.getRoot();
|
|
318
309
|
return generateAvmCircuitPublicInputs(
|
|
319
310
|
this.trace,
|
|
320
311
|
this.globalVariables,
|
|
@@ -379,16 +370,21 @@ export class PublicTxContext {
|
|
|
379
370
|
* so that we can conditionally fork at the start of a phase.
|
|
380
371
|
*
|
|
381
372
|
* There is a state manager that lives at the level of the entire transaction,
|
|
382
|
-
* but for
|
|
373
|
+
* but for app logic and teardown the active state manager will be a fork of the
|
|
383
374
|
* transaction level one.
|
|
384
375
|
*/
|
|
385
376
|
class PhaseStateManager {
|
|
377
|
+
private log: DebugLogger;
|
|
378
|
+
|
|
386
379
|
private currentlyActiveStateManager: AvmPersistableStateManager | undefined;
|
|
387
380
|
|
|
388
|
-
constructor(private readonly txStateManager: AvmPersistableStateManager) {
|
|
381
|
+
constructor(private readonly txStateManager: AvmPersistableStateManager) {
|
|
382
|
+
this.log = createDebugLogger(`aztec:public_phase_state_manager`);
|
|
383
|
+
}
|
|
389
384
|
|
|
390
385
|
fork() {
|
|
391
386
|
assert(!this.currentlyActiveStateManager, 'Cannot fork when already forked');
|
|
387
|
+
this.log.debug(`Forking phase state manager`);
|
|
392
388
|
this.currentlyActiveStateManager = this.txStateManager.fork();
|
|
393
389
|
}
|
|
394
390
|
|
|
@@ -402,12 +398,14 @@ class PhaseStateManager {
|
|
|
402
398
|
|
|
403
399
|
mergeForkedState() {
|
|
404
400
|
assert(this.currentlyActiveStateManager, 'No forked state to merge');
|
|
401
|
+
this.log.debug(`Merging in forked state`);
|
|
405
402
|
this.txStateManager.merge(this.currentlyActiveStateManager!);
|
|
406
403
|
// Drop the forked state manager now that it is merged
|
|
407
404
|
this.currentlyActiveStateManager = undefined;
|
|
408
405
|
}
|
|
409
406
|
|
|
410
407
|
discardForkedState() {
|
|
408
|
+
this.log.debug(`Discarding forked state`);
|
|
411
409
|
assert(this.currentlyActiveStateManager, 'No forked state to discard');
|
|
412
410
|
this.txStateManager.reject(this.currentlyActiveStateManager!);
|
|
413
411
|
// Drop the forked state manager. We don't want it!
|
|
@@ -20,10 +20,13 @@ import {
|
|
|
20
20
|
} from '@aztec/circuits.js';
|
|
21
21
|
import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log';
|
|
22
22
|
import { Timer } from '@aztec/foundation/timer';
|
|
23
|
-
import { type TelemetryClient } from '@aztec/telemetry-client';
|
|
23
|
+
import { Attributes, type TelemetryClient, type Tracer, trackSpan } from '@aztec/telemetry-client';
|
|
24
|
+
|
|
25
|
+
import { strict as assert } from 'assert';
|
|
24
26
|
|
|
25
27
|
import { type AvmFinalizedCallResult } from '../avm/avm_contract_call_result.js';
|
|
26
28
|
import { type AvmPersistableStateManager, AvmSimulator } from '../avm/index.js';
|
|
29
|
+
import { NullifierCollisionError } from '../avm/journal/nullifiers.js';
|
|
27
30
|
import { getPublicFunctionDebugName } from '../common/debug_fn_name.js';
|
|
28
31
|
import { ExecutorMetrics } from './executor_metrics.js';
|
|
29
32
|
import { type WorldStateDB } from './public_db_sources.js';
|
|
@@ -55,15 +58,18 @@ export class PublicTxSimulator {
|
|
|
55
58
|
constructor(
|
|
56
59
|
private db: MerkleTreeReadOperations,
|
|
57
60
|
private worldStateDB: WorldStateDB,
|
|
58
|
-
|
|
61
|
+
telemetryClient: TelemetryClient,
|
|
59
62
|
private globalVariables: GlobalVariables,
|
|
60
63
|
private realAvmProvingRequests: boolean = true,
|
|
61
64
|
private doMerkleOperations: boolean = false,
|
|
62
65
|
) {
|
|
63
66
|
this.log = createDebugLogger(`aztec:public_tx_simulator`);
|
|
64
|
-
this.metrics = new ExecutorMetrics(
|
|
67
|
+
this.metrics = new ExecutorMetrics(telemetryClient, 'PublicTxSimulator');
|
|
65
68
|
}
|
|
66
69
|
|
|
70
|
+
get tracer(): Tracer {
|
|
71
|
+
return this.metrics.tracer;
|
|
72
|
+
}
|
|
67
73
|
/**
|
|
68
74
|
* Simulate a transaction's public portion including all of its phases.
|
|
69
75
|
* @param tx - The transaction to simulate.
|
|
@@ -89,11 +95,14 @@ export class PublicTxSimulator {
|
|
|
89
95
|
// FIXME: we shouldn't need to directly modify worldStateDb here!
|
|
90
96
|
await this.worldStateDB.addNewContracts(tx);
|
|
91
97
|
|
|
98
|
+
await this.insertNonRevertiblesFromPrivate(context);
|
|
92
99
|
const processedPhases: ProcessedPhase[] = [];
|
|
93
100
|
if (context.hasPhase(TxExecutionPhase.SETUP)) {
|
|
94
101
|
const setupResult: ProcessedPhase = await this.simulateSetupPhase(context);
|
|
95
102
|
processedPhases.push(setupResult);
|
|
96
103
|
}
|
|
104
|
+
|
|
105
|
+
await this.insertRevertiblesFromPrivate(context);
|
|
97
106
|
if (context.hasPhase(TxExecutionPhase.APP_LOGIC)) {
|
|
98
107
|
const appLogicResult: ProcessedPhase = await this.simulateAppLogicPhase(context);
|
|
99
108
|
processedPhases.push(appLogicResult);
|
|
@@ -149,9 +158,7 @@ export class PublicTxSimulator {
|
|
|
149
158
|
* @returns The phase result.
|
|
150
159
|
*/
|
|
151
160
|
private async simulateAppLogicPhase(context: PublicTxContext): Promise<ProcessedPhase> {
|
|
152
|
-
|
|
153
|
-
// Don't need to fork for setup since it's non-revertible (if setup fails, transaction is thrown out).
|
|
154
|
-
context.state.fork();
|
|
161
|
+
assert(context.state.isForked(), 'App logic phase should operate with forked state.');
|
|
155
162
|
|
|
156
163
|
const result = await this.simulatePhase(TxExecutionPhase.APP_LOGIC, context);
|
|
157
164
|
|
|
@@ -175,7 +182,7 @@ export class PublicTxSimulator {
|
|
|
175
182
|
*/
|
|
176
183
|
private async simulateTeardownPhase(context: PublicTxContext): Promise<ProcessedPhase> {
|
|
177
184
|
if (!context.state.isForked()) {
|
|
178
|
-
// If state isn't forked (app logic
|
|
185
|
+
// If state isn't forked (app logic reverted), fork now
|
|
179
186
|
// so we can rollback to the end of setup if teardown reverts.
|
|
180
187
|
context.state.fork();
|
|
181
188
|
}
|
|
@@ -244,6 +251,12 @@ export class PublicTxSimulator {
|
|
|
244
251
|
* @param executionRequest - The execution request (includes args)
|
|
245
252
|
* @returns The result of execution.
|
|
246
253
|
*/
|
|
254
|
+
@trackSpan('PublicTxSimulator.simulateEnqueuedCall', (phase, context, _callRequest, executionRequest) => ({
|
|
255
|
+
[Attributes.TX_HASH]: context.getTxHash().toString(),
|
|
256
|
+
[Attributes.TARGET_ADDRESS]: executionRequest.callContext.contractAddress.toString(),
|
|
257
|
+
[Attributes.SENDER_ADDRESS]: executionRequest.callContext.msgSender.toString(),
|
|
258
|
+
[Attributes.SIMULATOR_PHASE]: TxExecutionPhase[phase].toString(),
|
|
259
|
+
}))
|
|
247
260
|
private async simulateEnqueuedCall(
|
|
248
261
|
phase: TxExecutionPhase,
|
|
249
262
|
context: PublicTxContext,
|
|
@@ -312,6 +325,12 @@ export class PublicTxSimulator {
|
|
|
312
325
|
* @param fnName - The name of the function
|
|
313
326
|
* @returns The result of execution.
|
|
314
327
|
*/
|
|
328
|
+
@trackSpan(
|
|
329
|
+
'PublicTxSimulator.simulateEnqueuedCallInternal',
|
|
330
|
+
(_stateManager, _executionRequest, _allocatedGas, _transactionFee, fnName) => ({
|
|
331
|
+
[Attributes.APP_CIRCUIT_NAME]: fnName,
|
|
332
|
+
}),
|
|
333
|
+
)
|
|
315
334
|
private async simulateEnqueuedCallInternal(
|
|
316
335
|
stateManager: AvmPersistableStateManager,
|
|
317
336
|
executionRequest: PublicExecutionRequest,
|
|
@@ -356,9 +375,44 @@ export class PublicTxSimulator {
|
|
|
356
375
|
if (result.reverted) {
|
|
357
376
|
this.metrics.recordFunctionSimulationFailure();
|
|
358
377
|
} else {
|
|
359
|
-
this.metrics.recordFunctionSimulation(timer.ms());
|
|
378
|
+
this.metrics.recordFunctionSimulation(timer.ms(), allocatedGas.sub(result.gasLeft).l2Gas, fnName);
|
|
360
379
|
}
|
|
361
380
|
|
|
362
381
|
return result;
|
|
363
382
|
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Insert the non-revertible accumulated data from private into the public state.
|
|
386
|
+
*/
|
|
387
|
+
public async insertNonRevertiblesFromPrivate(context: PublicTxContext) {
|
|
388
|
+
const stateManager = context.state.getActiveStateManager();
|
|
389
|
+
try {
|
|
390
|
+
await stateManager.writeSiloedNullifiersFromPrivate(context.nonRevertibleAccumulatedDataFromPrivate.nullifiers);
|
|
391
|
+
} catch (e) {
|
|
392
|
+
if (e instanceof NullifierCollisionError) {
|
|
393
|
+
throw new NullifierCollisionError(
|
|
394
|
+
`Nullifier collision encountered when inserting non-revertible nullifiers from private.\nDetails: ${e.message}\n.Stack:${e.stack}`,
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Insert the revertible accumulated data from private into the public state.
|
|
402
|
+
* Start by forking state so we can rollback to the end of setup if app logic or teardown reverts.
|
|
403
|
+
*/
|
|
404
|
+
public async insertRevertiblesFromPrivate(context: PublicTxContext) {
|
|
405
|
+
// Fork the state manager so we can rollback to end of setup if app logic reverts.
|
|
406
|
+
context.state.fork();
|
|
407
|
+
const stateManager = context.state.getActiveStateManager();
|
|
408
|
+
try {
|
|
409
|
+
await stateManager.writeSiloedNullifiersFromPrivate(context.revertibleAccumulatedDataFromPrivate.nullifiers);
|
|
410
|
+
} catch (e) {
|
|
411
|
+
if (e instanceof NullifierCollisionError) {
|
|
412
|
+
throw new NullifierCollisionError(
|
|
413
|
+
`Nullifier collision encountered when inserting revertible nullifiers from private. Details:\n${e.message}\n.Stack:${e.stack}`,
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
364
418
|
}
|
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
TreeLeafReadRequest,
|
|
46
46
|
} from '@aztec/circuits.js';
|
|
47
47
|
import { Fr } from '@aztec/foundation/fields';
|
|
48
|
+
import { jsonStringify } from '@aztec/foundation/json-rpc';
|
|
48
49
|
import { createDebugLogger } from '@aztec/foundation/log';
|
|
49
50
|
|
|
50
51
|
import { assert } from 'console';
|
|
@@ -214,8 +215,7 @@ export class PublicSideEffectTrace implements PublicSideEffectTraceInterface {
|
|
|
214
215
|
}
|
|
215
216
|
|
|
216
217
|
public traceNullifierCheck(
|
|
217
|
-
|
|
218
|
-
nullifier: Fr,
|
|
218
|
+
siloedNullifier: Fr,
|
|
219
219
|
exists: boolean,
|
|
220
220
|
lowLeafPreimage: NullifierLeafPreimage = NullifierLeafPreimage.empty(),
|
|
221
221
|
lowLeafIndex: Fr = Fr.zero(),
|
|
@@ -226,7 +226,7 @@ export class PublicSideEffectTrace implements PublicSideEffectTraceInterface {
|
|
|
226
226
|
|
|
227
227
|
this.enforceLimitOnNullifierChecks();
|
|
228
228
|
|
|
229
|
-
const readRequest = new ReadRequest(
|
|
229
|
+
const readRequest = new ReadRequest(siloedNullifier, this.sideEffectCounter);
|
|
230
230
|
if (exists) {
|
|
231
231
|
this.nullifierReadRequests.push(readRequest);
|
|
232
232
|
} else {
|
|
@@ -245,8 +245,7 @@ export class PublicSideEffectTrace implements PublicSideEffectTraceInterface {
|
|
|
245
245
|
}
|
|
246
246
|
|
|
247
247
|
public traceNewNullifier(
|
|
248
|
-
|
|
249
|
-
nullifier: Fr,
|
|
248
|
+
siloedNullifier: Fr,
|
|
250
249
|
lowLeafPreimage: NullifierLeafPreimage = NullifierLeafPreimage.empty(),
|
|
251
250
|
lowLeafIndex: Fr = Fr.zero(),
|
|
252
251
|
lowLeafPath: Fr[] = emptyNullifierPath(),
|
|
@@ -256,7 +255,8 @@ export class PublicSideEffectTrace implements PublicSideEffectTraceInterface {
|
|
|
256
255
|
if (this.nullifiers.length >= MAX_NULLIFIERS_PER_TX) {
|
|
257
256
|
throw new SideEffectLimitReachedError('nullifier', MAX_NULLIFIERS_PER_TX);
|
|
258
257
|
}
|
|
259
|
-
this
|
|
258
|
+
// this will be wrong for siloedNullifier
|
|
259
|
+
this.nullifiers.push(new Nullifier(siloedNullifier, this.sideEffectCounter, /*noteHash=*/ Fr.ZERO));
|
|
260
260
|
// New hinting
|
|
261
261
|
const lowLeafReadHint = new AvmNullifierReadTreeHint(lowLeafPreimage, lowLeafIndex, lowLeafPath);
|
|
262
262
|
this.avmCircuitHints.nullifierWriteHints.items.push(new AvmNullifierWriteTreeHint(lowLeafReadHint, insertionPath));
|
|
@@ -362,9 +362,7 @@ export class PublicSideEffectTrace implements PublicSideEffectTraceInterface {
|
|
|
362
362
|
new AvmContractBytecodeHints(bytecode, instance, contractClass),
|
|
363
363
|
);
|
|
364
364
|
this.log.debug(
|
|
365
|
-
`Bytecode retrieval for contract execution traced: exists=${exists}, instance=${
|
|
366
|
-
contractInstance,
|
|
367
|
-
)}`,
|
|
365
|
+
`Bytecode retrieval for contract execution traced: exists=${exists}, instance=${jsonStringify(contractInstance)}`,
|
|
368
366
|
);
|
|
369
367
|
}
|
|
370
368
|
|
|
@@ -40,16 +40,14 @@ export interface PublicSideEffectTraceInterface {
|
|
|
40
40
|
traceNoteHashCheck(contractAddress: AztecAddress, noteHash: Fr, leafIndex: Fr, exists: boolean, path?: Fr[]): void;
|
|
41
41
|
traceNewNoteHash(contractAddress: AztecAddress, noteHash: Fr, leafIndex?: Fr, path?: Fr[]): void;
|
|
42
42
|
traceNullifierCheck(
|
|
43
|
-
|
|
44
|
-
nullifier: Fr,
|
|
43
|
+
siloedNullifier: Fr,
|
|
45
44
|
exists: boolean,
|
|
46
45
|
lowLeafPreimage?: NullifierLeafPreimage,
|
|
47
46
|
lowLeafIndex?: Fr,
|
|
48
47
|
lowLeafPath?: Fr[],
|
|
49
48
|
): void;
|
|
50
49
|
traceNewNullifier(
|
|
51
|
-
|
|
52
|
-
nullifier: Fr,
|
|
50
|
+
siloedNullifier: Fr,
|
|
53
51
|
lowLeafPreimage?: NullifierLeafPreimage,
|
|
54
52
|
lowLeafIndex?: Fr,
|
|
55
53
|
lowLeafPath?: Fr[],
|
|
@@ -20,7 +20,6 @@ import {
|
|
|
20
20
|
MAX_NOTE_HASHES_PER_TX,
|
|
21
21
|
MAX_NOTE_HASH_READ_REQUESTS_PER_CALL,
|
|
22
22
|
MAX_NULLIFIERS_PER_CALL,
|
|
23
|
-
MAX_NULLIFIERS_PER_TX,
|
|
24
23
|
MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL,
|
|
25
24
|
MAX_NULLIFIER_READ_REQUESTS_PER_CALL,
|
|
26
25
|
MAX_PUBLIC_DATA_READS_PER_CALL,
|
|
@@ -146,16 +145,6 @@ export function generateAvmCircuitPublicInputs(
|
|
|
146
145
|
}
|
|
147
146
|
}
|
|
148
147
|
|
|
149
|
-
const nullifiersFromPrivate = revertCode.isOK()
|
|
150
|
-
? mergeAccumulatedData(
|
|
151
|
-
avmCircuitPublicInputs.previousNonRevertibleAccumulatedData.nullifiers,
|
|
152
|
-
avmCircuitPublicInputs.previousRevertibleAccumulatedData.nullifiers,
|
|
153
|
-
)
|
|
154
|
-
: avmCircuitPublicInputs.previousNonRevertibleAccumulatedData.nullifiers;
|
|
155
|
-
avmCircuitPublicInputs.accumulatedData.nullifiers = assertLength(
|
|
156
|
-
mergeAccumulatedData(nullifiersFromPrivate, avmCircuitPublicInputs.accumulatedData.nullifiers),
|
|
157
|
-
MAX_NULLIFIERS_PER_TX,
|
|
158
|
-
);
|
|
159
148
|
const msgsFromPrivate = revertCode.isOK()
|
|
160
149
|
? mergeAccumulatedData(
|
|
161
150
|
avmCircuitPublicInputs.previousNonRevertibleAccumulatedData.l2ToL1Msgs,
|