@aztec/simulator 1.2.0 → 2.0.0-nightly.20250813
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/private/circuit_recording/circuit_recorder.js +2 -2
- package/dest/public/avm/fixtures/base_avm_simulation_tester.js +2 -2
- package/dest/public/avm/fixtures/utils.js +2 -2
- package/dest/public/avm/opcodes/accrued_substate.d.ts.map +1 -1
- package/dest/public/avm/opcodes/accrued_substate.js +5 -3
- package/dest/public/avm/opcodes/comparators.js +1 -1
- package/dest/public/avm/opcodes/environment_getters.d.ts +2 -2
- package/dest/public/avm/opcodes/environment_getters.d.ts.map +1 -1
- package/dest/public/avm/opcodes/environment_getters.js +6 -6
- package/dest/public/avm/opcodes/misc.js +1 -1
- package/dest/public/avm/test_utils.d.ts +2 -2
- package/dest/public/avm/test_utils.d.ts.map +1 -1
- package/dest/public/avm/test_utils.js +2 -2
- package/dest/public/executor_metrics.d.ts +0 -1
- package/dest/public/executor_metrics.d.ts.map +1 -1
- package/dest/public/executor_metrics.js +0 -3
- package/dest/public/executor_metrics_interface.d.ts +0 -1
- package/dest/public/executor_metrics_interface.d.ts.map +1 -1
- package/dest/public/fixtures/index.d.ts +1 -0
- package/dest/public/fixtures/index.d.ts.map +1 -1
- package/dest/public/fixtures/index.js +1 -0
- package/dest/public/fixtures/minimal_public_tx.d.ts.map +1 -1
- package/dest/public/fixtures/minimal_public_tx.js +1 -1
- package/dest/public/fixtures/public_tx_simulation_tester.d.ts +1 -1
- package/dest/public/fixtures/public_tx_simulation_tester.d.ts.map +1 -1
- package/dest/public/fixtures/public_tx_simulation_tester.js +2 -1
- package/dest/public/fixtures/utils.d.ts +5 -2
- package/dest/public/fixtures/utils.d.ts.map +1 -1
- package/dest/public/fixtures/utils.js +37 -13
- package/dest/public/public_db_sources.js +4 -4
- package/dest/public/public_processor/public_processor.d.ts +3 -2
- package/dest/public/public_processor/public_processor.d.ts.map +1 -1
- package/dest/public/public_processor/public_processor.js +30 -19
- package/dest/public/public_processor/public_processor_metrics.d.ts +2 -2
- package/dest/public/public_processor/public_processor_metrics.d.ts.map +1 -1
- package/dest/public/public_processor/public_processor_metrics.js +1 -1
- package/dest/public/public_tx_simulator/apps_tests/amm_test.js +4 -4
- package/dest/public/public_tx_simulator/apps_tests/token_test.d.ts +1 -1
- package/dest/public/public_tx_simulator/apps_tests/token_test.d.ts.map +1 -1
- package/dest/public/public_tx_simulator/apps_tests/token_test.js +2 -2
- package/dest/public/public_tx_simulator/measured_public_tx_simulator.d.ts +0 -1
- package/dest/public/public_tx_simulator/measured_public_tx_simulator.d.ts.map +1 -1
- package/dest/public/public_tx_simulator/measured_public_tx_simulator.js +0 -6
- package/dest/public/public_tx_simulator/public_tx_context.d.ts +1 -1
- package/dest/public/public_tx_simulator/public_tx_context.d.ts.map +1 -1
- package/dest/public/public_tx_simulator/public_tx_context.js +6 -12
- package/dest/public/public_tx_simulator/public_tx_simulator.d.ts +1 -20
- package/dest/public/public_tx_simulator/public_tx_simulator.d.ts.map +1 -1
- package/dest/public/public_tx_simulator/public_tx_simulator.js +49 -81
- package/dest/public/side_effect_trace.d.ts.map +1 -1
- package/dest/public/side_effect_trace.js +17 -11
- package/dest/public/state_manager/state_manager.d.ts +1 -1
- package/dest/public/state_manager/state_manager.d.ts.map +1 -1
- package/dest/public/state_manager/state_manager.js +16 -16
- package/dest/public/test_executor_metrics.d.ts +13 -3
- package/dest/public/test_executor_metrics.d.ts.map +1 -1
- package/dest/public/test_executor_metrics.js +159 -47
- package/package.json +15 -15
- package/src/private/circuit_recording/circuit_recorder.ts +2 -2
- package/src/public/avm/fixtures/base_avm_simulation_tester.ts +2 -2
- package/src/public/avm/fixtures/utils.ts +2 -2
- package/src/public/avm/opcodes/accrued_substate.ts +6 -3
- package/src/public/avm/opcodes/comparators.ts +1 -1
- package/src/public/avm/opcodes/environment_getters.ts +8 -8
- package/src/public/avm/opcodes/misc.ts +1 -1
- package/src/public/avm/test_utils.ts +4 -4
- package/src/public/executor_metrics.ts +0 -4
- package/src/public/executor_metrics_interface.ts +0 -1
- package/src/public/fixtures/index.ts +1 -0
- package/src/public/fixtures/minimal_public_tx.ts +2 -0
- package/src/public/fixtures/public_tx_simulation_tester.ts +3 -2
- package/src/public/fixtures/utils.ts +45 -16
- package/src/public/public_db_sources.ts +7 -7
- package/src/public/public_processor/public_processor.ts +38 -29
- package/src/public/public_processor/public_processor_metrics.ts +2 -2
- package/src/public/public_tx_simulator/apps_tests/amm_test.ts +4 -4
- package/src/public/public_tx_simulator/apps_tests/token_test.ts +2 -2
- package/src/public/public_tx_simulator/measured_public_tx_simulator.ts +0 -7
- package/src/public/public_tx_simulator/public_tx_context.ts +13 -19
- package/src/public/public_tx_simulator/public_tx_simulator.ts +63 -105
- package/src/public/side_effect_trace.ts +29 -23
- package/src/public/state_manager/state_manager.ts +23 -21
- package/src/public/test_executor_metrics.ts +172 -46
|
@@ -22,14 +22,11 @@ import {
|
|
|
22
22
|
TxExecutionPhase,
|
|
23
23
|
} from '@aztec/stdlib/tx';
|
|
24
24
|
|
|
25
|
-
import { strict as assert } from 'assert';
|
|
26
|
-
|
|
27
25
|
import type { AvmFinalizedCallResult } from '../avm/avm_contract_call_result.js';
|
|
28
26
|
import { AvmSimulator } from '../avm/index.js';
|
|
29
27
|
import { getPublicFunctionDebugName } from '../debug_fn_name.js';
|
|
30
28
|
import { HintingMerkleWriteOperations, HintingPublicContractsDB } from '../hinting_db_sources.js';
|
|
31
29
|
import { type PublicContractsDB, PublicTreesDB } from '../public_db_sources.js';
|
|
32
|
-
import { NullifierCollisionError } from '../state_manager/nullifiers.js';
|
|
33
30
|
import type { PublicPersistableStateManager } from '../state_manager/state_manager.js';
|
|
34
31
|
import { PublicTxContext } from './public_tx_context.js';
|
|
35
32
|
|
|
@@ -72,11 +69,11 @@ export class PublicTxSimulator {
|
|
|
72
69
|
*/
|
|
73
70
|
public async simulate(tx: Tx): Promise<PublicTxResult> {
|
|
74
71
|
try {
|
|
75
|
-
const txHash =
|
|
72
|
+
const txHash = this.computeTxHash(tx);
|
|
76
73
|
this.log.debug(`Simulating ${tx.publicFunctionCalldata.length} public calls for tx ${txHash}`, { txHash });
|
|
77
74
|
|
|
78
75
|
// Create hinting DBs.
|
|
79
|
-
const hints = new AvmExecutionHints(
|
|
76
|
+
const hints = new AvmExecutionHints(this.globalVariables, AvmTxHint.fromTx(tx));
|
|
80
77
|
const hintingMerkleTree = await HintingMerkleWriteOperations.create(this.merkleTree, hints);
|
|
81
78
|
const hintingTreesDB = new PublicTreesDB(hintingMerkleTree);
|
|
82
79
|
const hintingContractsDB = new HintingPublicContractsDB(this.contractsDB, hints);
|
|
@@ -89,31 +86,64 @@ export class PublicTxSimulator {
|
|
|
89
86
|
this.doMerkleOperations,
|
|
90
87
|
);
|
|
91
88
|
|
|
89
|
+
// This will throw if there is a nullifier collision.
|
|
90
|
+
// In that case the transaction will be thrown out.
|
|
92
91
|
await this.insertNonRevertiblesFromPrivate(context, tx);
|
|
93
92
|
|
|
94
93
|
const processedPhases: ProcessedPhase[] = [];
|
|
95
94
|
if (context.hasPhase(TxExecutionPhase.SETUP)) {
|
|
96
|
-
|
|
95
|
+
// This will throw if the setup phase reverts.
|
|
96
|
+
// In that case the transaction will be thrown out.
|
|
97
|
+
const setupResult = await this.simulatePhase(TxExecutionPhase.SETUP, context);
|
|
98
|
+
if (setupResult.reverted) {
|
|
99
|
+
throw new Error(
|
|
100
|
+
`Setup phase reverted! The transaction will be thrown out. ${setupResult.revertReason?.message}`,
|
|
101
|
+
);
|
|
102
|
+
}
|
|
97
103
|
processedPhases.push(setupResult);
|
|
98
104
|
}
|
|
99
105
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
106
|
+
// The checkpoint we should go back to if anything from now on reverts.
|
|
107
|
+
await context.state.fork();
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
// This will throw if there is a nullifier collision.
|
|
111
|
+
await this.insertRevertiblesFromPrivate(context, tx);
|
|
112
|
+
// Only proceed with app logic if there was no revert during revertible insertion.
|
|
103
113
|
if (context.hasPhase(TxExecutionPhase.APP_LOGIC)) {
|
|
104
|
-
const appLogicResult
|
|
114
|
+
const appLogicResult = await this.simulatePhase(TxExecutionPhase.APP_LOGIC, context);
|
|
105
115
|
processedPhases.push(appLogicResult);
|
|
116
|
+
if (appLogicResult.reverted) {
|
|
117
|
+
throw new Error(`App logic phase reverted! ${appLogicResult.revertReason?.message}`);
|
|
118
|
+
}
|
|
106
119
|
}
|
|
107
|
-
}
|
|
108
|
-
this.log.debug(
|
|
120
|
+
} catch (e) {
|
|
121
|
+
this.log.debug(String(e));
|
|
122
|
+
// We revert to the post-setup state.
|
|
123
|
+
await context.state.discardForkedState();
|
|
124
|
+
// But we also create a new fork so that the teardown phase can transparently
|
|
125
|
+
// commit or rollback at the end of teardown.
|
|
126
|
+
await context.state.fork();
|
|
109
127
|
}
|
|
110
128
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
129
|
+
try {
|
|
130
|
+
if (context.hasPhase(TxExecutionPhase.TEARDOWN)) {
|
|
131
|
+
const teardownResult = await this.simulatePhase(TxExecutionPhase.TEARDOWN, context);
|
|
132
|
+
processedPhases.push(teardownResult);
|
|
133
|
+
if (teardownResult.reverted) {
|
|
134
|
+
throw new Error(`Teardown phase reverted! ${teardownResult.revertReason?.message}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// We commit the forked state and we are done.
|
|
139
|
+
await context.state.mergeForkedState();
|
|
140
|
+
} catch (e) {
|
|
141
|
+
this.log.debug(String(e));
|
|
142
|
+
// We rollback to the post-setup state.
|
|
143
|
+
await context.state.discardForkedState();
|
|
114
144
|
}
|
|
115
145
|
|
|
116
|
-
|
|
146
|
+
context.halt();
|
|
117
147
|
await this.payFee(context);
|
|
118
148
|
|
|
119
149
|
const publicInputs = await context.generateAvmCircuitPublicInputs();
|
|
@@ -149,8 +179,8 @@ export class PublicTxSimulator {
|
|
|
149
179
|
}
|
|
150
180
|
}
|
|
151
181
|
|
|
152
|
-
protected
|
|
153
|
-
return
|
|
182
|
+
protected computeTxHash(tx: Tx) {
|
|
183
|
+
return tx.getTxHash();
|
|
154
184
|
}
|
|
155
185
|
|
|
156
186
|
/**
|
|
@@ -158,64 +188,6 @@ export class PublicTxSimulator {
|
|
|
158
188
|
* @param context - WILL BE MUTATED. The context of the currently executing public transaction portion
|
|
159
189
|
* @returns The phase result.
|
|
160
190
|
*/
|
|
161
|
-
private async simulateSetupPhase(context: PublicTxContext): Promise<ProcessedPhase> {
|
|
162
|
-
return await this.simulatePhase(TxExecutionPhase.SETUP, context);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Simulate the app logic phase of a transaction's public execution.
|
|
167
|
-
* @param context - WILL BE MUTATED. The context of the currently executing public transaction portion
|
|
168
|
-
* @returns The phase result.
|
|
169
|
-
*/
|
|
170
|
-
private async simulateAppLogicPhase(context: PublicTxContext): Promise<ProcessedPhase> {
|
|
171
|
-
assert(context.state.isForked(), 'App logic phase should operate with forked state.');
|
|
172
|
-
|
|
173
|
-
const result = await this.simulatePhase(TxExecutionPhase.APP_LOGIC, context);
|
|
174
|
-
|
|
175
|
-
if (result.reverted) {
|
|
176
|
-
// Drop the currently active forked state manager and rollback to end of setup.
|
|
177
|
-
await context.state.discardForkedState();
|
|
178
|
-
} else {
|
|
179
|
-
if (!context.hasPhase(TxExecutionPhase.TEARDOWN)) {
|
|
180
|
-
// Nothing to do after this (no teardown), so merge state updates now instead of letting teardown handle it.
|
|
181
|
-
await context.state.mergeForkedState();
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
return result;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Simulate the teardown phase of a transaction's public execution.
|
|
190
|
-
* @param context - WILL BE MUTATED. The context of the currently executing public transaction portion
|
|
191
|
-
* @returns The phase result.
|
|
192
|
-
*/
|
|
193
|
-
private async simulateTeardownPhase(context: PublicTxContext): Promise<ProcessedPhase> {
|
|
194
|
-
if (!context.state.isForked()) {
|
|
195
|
-
// If state isn't forked (app logic reverted), fork now
|
|
196
|
-
// so we can rollback to the end of setup if teardown reverts.
|
|
197
|
-
await context.state.fork();
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
const result = await this.simulatePhase(TxExecutionPhase.TEARDOWN, context);
|
|
201
|
-
|
|
202
|
-
if (result.reverted) {
|
|
203
|
-
// Drop the currently active forked state manager and rollback to end of setup.
|
|
204
|
-
await context.state.discardForkedState();
|
|
205
|
-
} else {
|
|
206
|
-
// Merge state updates from teardown,
|
|
207
|
-
await context.state.mergeForkedState();
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
return result;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Simulate a phase of a transaction's public execution.
|
|
215
|
-
* @param phase - The current phase
|
|
216
|
-
* @param context - WILL BE MUTATED. The context of the currently executing public transaction portion
|
|
217
|
-
* @returns The phase result.
|
|
218
|
-
*/
|
|
219
191
|
protected async simulatePhase(phase: TxExecutionPhase, context: PublicTxContext): Promise<ProcessedPhase> {
|
|
220
192
|
const callRequests = context.getCallRequestsForPhase(phase);
|
|
221
193
|
|
|
@@ -287,7 +259,7 @@ export class PublicTxSimulator {
|
|
|
287
259
|
|
|
288
260
|
if (result.reverted) {
|
|
289
261
|
const culprit = `${contractAddress}:${callRequest.functionSelector}`;
|
|
290
|
-
context.revert(phase, result.revertReason, culprit);
|
|
262
|
+
context.revert(phase, result.revertReason, culprit);
|
|
291
263
|
}
|
|
292
264
|
|
|
293
265
|
return result;
|
|
@@ -340,18 +312,11 @@ export class PublicTxSimulator {
|
|
|
340
312
|
*/
|
|
341
313
|
protected async insertNonRevertiblesFromPrivate(context: PublicTxContext, tx: Tx) {
|
|
342
314
|
const stateManager = context.state.getActiveStateManager();
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
}
|
|
349
|
-
} catch (e) {
|
|
350
|
-
if (e instanceof NullifierCollisionError) {
|
|
351
|
-
throw new NullifierCollisionError(
|
|
352
|
-
`Nullifier collision encountered when inserting non-revertible nullifiers from private.\nDetails: ${e.message}\nStack:${e.stack}`,
|
|
353
|
-
);
|
|
354
|
-
}
|
|
315
|
+
|
|
316
|
+
for (const siloedNullifier of context.nonRevertibleAccumulatedDataFromPrivate.nullifiers.filter(
|
|
317
|
+
n => !n.isEmpty(),
|
|
318
|
+
)) {
|
|
319
|
+
await stateManager.writeSiloedNullifier(siloedNullifier);
|
|
355
320
|
}
|
|
356
321
|
for (const noteHash of context.nonRevertibleAccumulatedDataFromPrivate.noteHashes) {
|
|
357
322
|
if (!noteHash.isEmpty()) {
|
|
@@ -376,28 +341,21 @@ export class PublicTxSimulator {
|
|
|
376
341
|
* Start by forking state so we can rollback to the end of setup if app logic or teardown reverts.
|
|
377
342
|
*/
|
|
378
343
|
protected async insertRevertiblesFromPrivate(context: PublicTxContext, tx: Tx): /*success=*/ Promise<boolean> {
|
|
379
|
-
// Fork the state manager so we can rollback to end of setup if app logic reverts.
|
|
380
|
-
await context.state.fork();
|
|
381
344
|
const stateManager = context.state.getActiveStateManager();
|
|
345
|
+
|
|
382
346
|
try {
|
|
383
347
|
for (const siloedNullifier of context.revertibleAccumulatedDataFromPrivate.nullifiers.filter(n => !n.isEmpty())) {
|
|
384
348
|
await stateManager.writeSiloedNullifier(siloedNullifier);
|
|
385
349
|
}
|
|
386
350
|
} catch (e) {
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
/*culprit=*/ 'insertRevertiblesFromPrivate',
|
|
396
|
-
);
|
|
397
|
-
return /*success=*/ false;
|
|
398
|
-
} else {
|
|
399
|
-
throw e;
|
|
400
|
-
}
|
|
351
|
+
context.revert(
|
|
352
|
+
TxExecutionPhase.APP_LOGIC,
|
|
353
|
+
new SimulationError(
|
|
354
|
+
`Nullifier collision encountered when inserting revertible nullifiers from private.\nDetails: ${String(e)}`,
|
|
355
|
+
[],
|
|
356
|
+
),
|
|
357
|
+
);
|
|
358
|
+
throw e;
|
|
401
359
|
}
|
|
402
360
|
for (const noteHash of context.revertibleAccumulatedDataFromPrivate.noteHashes) {
|
|
403
361
|
if (!noteHash.isEmpty()) {
|
|
@@ -113,8 +113,6 @@ export class SideEffectTrace implements PublicSideEffectTraceInterface {
|
|
|
113
113
|
|
|
114
114
|
this.sideEffectCounter = forkedTrace.sideEffectCounter;
|
|
115
115
|
this.uniqueClassIds.acceptAndMerge(forkedTrace.uniqueClassIds);
|
|
116
|
-
// Accept even if reverted, since the user already paid for the writes
|
|
117
|
-
this.writtenPublicDataSlots = new Set(forkedTrace.writtenPublicDataSlots);
|
|
118
116
|
|
|
119
117
|
if (!reverted) {
|
|
120
118
|
this.publicDataWrites.push(...forkedTrace.publicDataWrites);
|
|
@@ -122,6 +120,11 @@ export class SideEffectTrace implements PublicSideEffectTraceInterface {
|
|
|
122
120
|
this.nullifiers.push(...forkedTrace.nullifiers);
|
|
123
121
|
this.l2ToL1Messages.push(...forkedTrace.l2ToL1Messages);
|
|
124
122
|
this.publicLogs.push(...forkedTrace.publicLogs);
|
|
123
|
+
this.userPublicDataWritesLength += forkedTrace.userPublicDataWritesLength;
|
|
124
|
+
this.protocolPublicDataWritesLength += forkedTrace.protocolPublicDataWritesLength;
|
|
125
|
+
for (const slot of forkedTrace.writtenPublicDataSlots) {
|
|
126
|
+
this.writtenPublicDataSlots.add(slot);
|
|
127
|
+
}
|
|
125
128
|
}
|
|
126
129
|
}
|
|
127
130
|
|
|
@@ -143,28 +146,31 @@ export class SideEffectTrace implements PublicSideEffectTraceInterface {
|
|
|
143
146
|
value: Fr,
|
|
144
147
|
protocolWrite: boolean,
|
|
145
148
|
): Promise<void> {
|
|
146
|
-
if
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
149
|
+
// Only increment counts if the storage slot has not been written to before.
|
|
150
|
+
if (this.isStorageCold(contractAddress, slot)) {
|
|
151
|
+
if (protocolWrite) {
|
|
152
|
+
if (
|
|
153
|
+
this.protocolPublicDataWritesLength + this.previousSideEffectArrayLengths.protocolPublicDataWrites >=
|
|
154
|
+
PROTOCOL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX
|
|
155
|
+
) {
|
|
156
|
+
throw new SideEffectLimitReachedError(
|
|
157
|
+
'protocol public data (contract storage) write',
|
|
158
|
+
PROTOCOL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
this.protocolPublicDataWritesLength++;
|
|
162
|
+
} else {
|
|
163
|
+
if (
|
|
164
|
+
this.userPublicDataWritesLength + this.previousSideEffectArrayLengths.publicDataWrites >=
|
|
165
|
+
MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX
|
|
166
|
+
) {
|
|
167
|
+
throw new SideEffectLimitReachedError(
|
|
168
|
+
'public data (contract storage) write',
|
|
169
|
+
MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
this.userPublicDataWritesLength++;
|
|
166
173
|
}
|
|
167
|
-
this.userPublicDataWritesLength++;
|
|
168
174
|
}
|
|
169
175
|
|
|
170
176
|
const leafSlot = await computePublicDataTreeLeafSlot(contractAddress, slot);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CANONICAL_AUTH_REGISTRY_ADDRESS,
|
|
3
|
-
|
|
3
|
+
CONTRACT_CLASS_REGISTRY_CONTRACT_ADDRESS,
|
|
4
|
+
CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS,
|
|
4
5
|
FEE_JUICE_ADDRESS,
|
|
5
6
|
MULTI_CALL_ENTRYPOINT_ADDRESS,
|
|
6
|
-
REGISTERER_CONTRACT_ADDRESS,
|
|
7
7
|
ROUTER_ADDRESS,
|
|
8
8
|
} from '@aztec/constants';
|
|
9
9
|
import { poseidon2Hash } from '@aztec/foundation/crypto';
|
|
@@ -14,9 +14,9 @@ import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
|
14
14
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
15
15
|
import type { ContractClassPublicWithCommitment, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
|
|
16
16
|
import { SerializableContractInstance } from '@aztec/stdlib/contract';
|
|
17
|
+
import { DelayedPublicMutableValues, DelayedPublicMutableValuesWithHash } from '@aztec/stdlib/delayed-public-mutable';
|
|
17
18
|
import { computeNoteHashNonce, computeUniqueNoteHash, siloNoteHash, siloNullifier } from '@aztec/stdlib/hash';
|
|
18
19
|
import { ScopedL2ToL1Message } from '@aztec/stdlib/messaging';
|
|
19
|
-
import { SharedMutableValues, SharedMutableValuesWithHash } from '@aztec/stdlib/shared-mutable';
|
|
20
20
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
21
21
|
import type { TreeSnapshots } from '@aztec/stdlib/tx';
|
|
22
22
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
@@ -182,8 +182,8 @@ export class PublicPersistableStateManager {
|
|
|
182
182
|
* @param leafIndex - the leaf index being checked
|
|
183
183
|
* @returns true if the note hash exists at the given leaf index, false otherwise
|
|
184
184
|
*/
|
|
185
|
-
public async checkNoteHashExists(contractAddress: AztecAddress, noteHash: Fr, leafIndex:
|
|
186
|
-
const gotLeafValue = await this.treesDB.getNoteHash(leafIndex
|
|
185
|
+
public async checkNoteHashExists(contractAddress: AztecAddress, noteHash: Fr, leafIndex: bigint): Promise<boolean> {
|
|
186
|
+
const gotLeafValue = await this.treesDB.getNoteHash(leafIndex);
|
|
187
187
|
const exists = gotLeafValue !== undefined && gotLeafValue.equals(noteHash);
|
|
188
188
|
this.log.trace(
|
|
189
189
|
`noteHashes(${contractAddress})@${noteHash} ?? leafIndex: ${leafIndex} | gotLeafValue: ${gotLeafValue}, exists: ${exists}.`,
|
|
@@ -353,7 +353,7 @@ export class PublicPersistableStateManager {
|
|
|
353
353
|
|
|
354
354
|
// This will decide internally whether to check the nullifier tree or not depending on doMerkleOperations.
|
|
355
355
|
const nullifierExistsInTree = await this.checkNullifierExists(
|
|
356
|
-
AztecAddress.fromNumber(
|
|
356
|
+
AztecAddress.fromNumber(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS),
|
|
357
357
|
contractAddress.toField(),
|
|
358
358
|
);
|
|
359
359
|
assert(
|
|
@@ -375,23 +375,25 @@ export class PublicPersistableStateManager {
|
|
|
375
375
|
// All failures are fatal and the simulation is not expected to be provable.
|
|
376
376
|
if (this.doMerkleOperations) {
|
|
377
377
|
// Conceptually, we want to do the following:
|
|
378
|
-
// * Read a
|
|
379
|
-
// * Obtain the expected current class id from the
|
|
378
|
+
// * Read a DelayedPublicMutable at the contract update slot.
|
|
379
|
+
// * Obtain the expected current class id from the DelayedPublicMutable, at the current block.
|
|
380
380
|
// * if expectedId == 0 then currentClassId should be original contract class id
|
|
381
381
|
// * if expectedId != 0 then currentClassId should be expectedId
|
|
382
382
|
//
|
|
383
|
-
// However, we will also be checking the hash of the
|
|
383
|
+
// However, we will also be checking the hash of the delayed public mutable values.
|
|
384
384
|
// This is a bit of a leak of information, since the circuit will use it to prove
|
|
385
|
-
// one public read insted of N of the
|
|
386
|
-
const {
|
|
387
|
-
instance.address
|
|
388
|
-
);
|
|
385
|
+
// one public read insted of N of the delayed public mutable values.
|
|
386
|
+
const { delayedPublicMutableSlot, delayedPublicMutableHashSlot } =
|
|
387
|
+
await DelayedPublicMutableValuesWithHash.getContractUpdateSlots(instance.address);
|
|
389
388
|
const readDeployerStorage = async (storageSlot: Fr) =>
|
|
390
|
-
await this.readStorage(ProtocolContractAddress.
|
|
389
|
+
await this.readStorage(ProtocolContractAddress.ContractInstanceRegistry, storageSlot);
|
|
391
390
|
|
|
392
|
-
const hash = await readDeployerStorage(
|
|
393
|
-
const
|
|
394
|
-
|
|
391
|
+
const hash = await readDeployerStorage(delayedPublicMutableHashSlot);
|
|
392
|
+
const delayedPublicMutableValues = await DelayedPublicMutableValues.readFromTree(
|
|
393
|
+
delayedPublicMutableSlot,
|
|
394
|
+
readDeployerStorage,
|
|
395
|
+
);
|
|
396
|
+
const preImage = delayedPublicMutableValues.toFields();
|
|
395
397
|
|
|
396
398
|
// 1) update never scheduled: hash == 0 and preimage should be empty (but poseidon2hash(preimage) will not be 0s)
|
|
397
399
|
if (hash.isZero()) {
|
|
@@ -410,11 +412,11 @@ export class PublicPersistableStateManager {
|
|
|
410
412
|
const computedHash = await poseidon2Hash(preImage);
|
|
411
413
|
assert(
|
|
412
414
|
hash.equals(computedHash),
|
|
413
|
-
`
|
|
415
|
+
`Delayed public mutable values hash mismatch for contract instance ${instance.address}. Expected: ${hash}, computed: ${computedHash}`,
|
|
414
416
|
);
|
|
415
417
|
|
|
416
418
|
// We now check that, depending on the current block, the current class id is correct.
|
|
417
|
-
const expectedClassIdRaw =
|
|
419
|
+
const expectedClassIdRaw = delayedPublicMutableValues.svc.getCurrentAt(this.timestamp).at(0)!;
|
|
418
420
|
const expectedClassId = expectedClassIdRaw.isZero() ? instance.originalContractClassId : expectedClassIdRaw;
|
|
419
421
|
assert(
|
|
420
422
|
instance.currentContractClassId.equals(expectedClassId),
|
|
@@ -493,8 +495,8 @@ export class PublicPersistableStateManager {
|
|
|
493
495
|
function contractAddressIsCanonical(contractAddress: AztecAddress): boolean {
|
|
494
496
|
return (
|
|
495
497
|
contractAddress.equals(AztecAddress.fromNumber(CANONICAL_AUTH_REGISTRY_ADDRESS)) ||
|
|
496
|
-
contractAddress.equals(AztecAddress.fromNumber(
|
|
497
|
-
contractAddress.equals(AztecAddress.fromNumber(
|
|
498
|
+
contractAddress.equals(AztecAddress.fromNumber(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS)) ||
|
|
499
|
+
contractAddress.equals(AztecAddress.fromNumber(CONTRACT_CLASS_REGISTRY_CONTRACT_ADDRESS)) ||
|
|
498
500
|
contractAddress.equals(AztecAddress.fromNumber(MULTI_CALL_ENTRYPOINT_ADDRESS)) ||
|
|
499
501
|
contractAddress.equals(AztecAddress.fromNumber(FEE_JUICE_ADDRESS)) ||
|
|
500
502
|
contractAddress.equals(AztecAddress.fromNumber(ROUTER_ADDRESS))
|