@aztec/pxe 0.0.1-commit.18ccd8f0 → 0.0.1-commit.1bb068fb5

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 (127) hide show
  1. package/dest/access_scopes.d.ts +9 -0
  2. package/dest/access_scopes.d.ts.map +1 -0
  3. package/dest/access_scopes.js +6 -0
  4. package/dest/block_synchronizer/block_synchronizer.d.ts +4 -2
  5. package/dest/block_synchronizer/block_synchronizer.d.ts.map +1 -1
  6. package/dest/block_synchronizer/block_synchronizer.js +7 -1
  7. package/dest/contract_function_simulator/contract_function_simulator.d.ts +54 -30
  8. package/dest/contract_function_simulator/contract_function_simulator.d.ts.map +1 -1
  9. package/dest/contract_function_simulator/contract_function_simulator.js +169 -65
  10. package/dest/contract_function_simulator/oracle/interfaces.d.ts +9 -9
  11. package/dest/contract_function_simulator/oracle/interfaces.d.ts.map +1 -1
  12. package/dest/contract_function_simulator/oracle/oracle.d.ts +5 -5
  13. package/dest/contract_function_simulator/oracle/oracle.d.ts.map +1 -1
  14. package/dest/contract_function_simulator/oracle/oracle.js +32 -20
  15. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +36 -36
  16. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts.map +1 -1
  17. package/dest/contract_function_simulator/oracle/private_execution_oracle.js +74 -21
  18. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +48 -24
  19. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
  20. package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +85 -61
  21. package/dest/contract_sync/contract_sync_service.d.ts +43 -0
  22. package/dest/contract_sync/contract_sync_service.d.ts.map +1 -0
  23. package/dest/contract_sync/contract_sync_service.js +97 -0
  24. package/dest/contract_sync/helpers.d.ts +29 -0
  25. package/dest/contract_sync/helpers.d.ts.map +1 -0
  26. package/dest/contract_sync/{index.js → helpers.js} +13 -12
  27. package/dest/debug/pxe_debug_utils.d.ts +14 -10
  28. package/dest/debug/pxe_debug_utils.d.ts.map +1 -1
  29. package/dest/debug/pxe_debug_utils.js +16 -15
  30. package/dest/entrypoints/client/bundle/index.d.ts +3 -1
  31. package/dest/entrypoints/client/bundle/index.d.ts.map +1 -1
  32. package/dest/entrypoints/client/bundle/index.js +2 -0
  33. package/dest/entrypoints/client/bundle/utils.d.ts +1 -1
  34. package/dest/entrypoints/client/bundle/utils.d.ts.map +1 -1
  35. package/dest/entrypoints/client/bundle/utils.js +11 -2
  36. package/dest/entrypoints/client/lazy/index.d.ts +3 -1
  37. package/dest/entrypoints/client/lazy/index.d.ts.map +1 -1
  38. package/dest/entrypoints/client/lazy/index.js +2 -0
  39. package/dest/entrypoints/client/lazy/utils.d.ts +1 -1
  40. package/dest/entrypoints/client/lazy/utils.d.ts.map +1 -1
  41. package/dest/entrypoints/client/lazy/utils.js +11 -2
  42. package/dest/entrypoints/server/index.d.ts +4 -2
  43. package/dest/entrypoints/server/index.d.ts.map +1 -1
  44. package/dest/entrypoints/server/index.js +3 -1
  45. package/dest/entrypoints/server/utils.js +9 -1
  46. package/dest/events/event_service.d.ts +4 -5
  47. package/dest/events/event_service.d.ts.map +1 -1
  48. package/dest/events/event_service.js +5 -6
  49. package/dest/logs/log_service.d.ts +6 -5
  50. package/dest/logs/log_service.d.ts.map +1 -1
  51. package/dest/logs/log_service.js +14 -24
  52. package/dest/notes/note_service.d.ts +7 -7
  53. package/dest/notes/note_service.d.ts.map +1 -1
  54. package/dest/notes/note_service.js +9 -9
  55. package/dest/notes_filter.d.ts +25 -0
  56. package/dest/notes_filter.d.ts.map +1 -0
  57. package/dest/notes_filter.js +4 -0
  58. package/dest/oracle_version.d.ts +3 -3
  59. package/dest/oracle_version.d.ts.map +1 -1
  60. package/dest/oracle_version.js +2 -2
  61. package/dest/pxe.d.ts +69 -23
  62. package/dest/pxe.d.ts.map +1 -1
  63. package/dest/pxe.js +72 -44
  64. package/dest/storage/address_store/address_store.d.ts +1 -1
  65. package/dest/storage/address_store/address_store.d.ts.map +1 -1
  66. package/dest/storage/address_store/address_store.js +12 -11
  67. package/dest/storage/anchor_block_store/anchor_block_store.d.ts +9 -1
  68. package/dest/storage/anchor_block_store/anchor_block_store.d.ts.map +1 -1
  69. package/dest/storage/anchor_block_store/anchor_block_store.js +8 -1
  70. package/dest/storage/capsule_store/capsule_store.js +6 -8
  71. package/dest/storage/contract_store/contract_store.d.ts +1 -1
  72. package/dest/storage/contract_store/contract_store.d.ts.map +1 -1
  73. package/dest/storage/contract_store/contract_store.js +27 -18
  74. package/dest/storage/metadata.d.ts +1 -1
  75. package/dest/storage/metadata.js +1 -1
  76. package/dest/storage/note_store/note_store.d.ts +13 -3
  77. package/dest/storage/note_store/note_store.d.ts.map +1 -1
  78. package/dest/storage/note_store/note_store.js +173 -131
  79. package/dest/storage/private_event_store/private_event_store.d.ts +1 -1
  80. package/dest/storage/private_event_store/private_event_store.d.ts.map +1 -1
  81. package/dest/storage/private_event_store/private_event_store.js +126 -101
  82. package/dest/storage/private_event_store/stored_private_event.js +1 -1
  83. package/dest/storage/tagging_store/recipient_tagging_store.d.ts +1 -1
  84. package/dest/storage/tagging_store/recipient_tagging_store.d.ts.map +1 -1
  85. package/dest/storage/tagging_store/recipient_tagging_store.js +31 -19
  86. package/dest/storage/tagging_store/sender_address_book_store.d.ts +1 -1
  87. package/dest/storage/tagging_store/sender_address_book_store.d.ts.map +1 -1
  88. package/dest/storage/tagging_store/sender_address_book_store.js +20 -14
  89. package/dest/storage/tagging_store/sender_tagging_store.d.ts +1 -1
  90. package/dest/storage/tagging_store/sender_tagging_store.d.ts.map +1 -1
  91. package/dest/storage/tagging_store/sender_tagging_store.js +183 -113
  92. package/package.json +25 -16
  93. package/src/access_scopes.ts +9 -0
  94. package/src/block_synchronizer/block_synchronizer.ts +6 -0
  95. package/src/contract_function_simulator/contract_function_simulator.ts +317 -124
  96. package/src/contract_function_simulator/oracle/interfaces.ts +10 -10
  97. package/src/contract_function_simulator/oracle/oracle.ts +35 -18
  98. package/src/contract_function_simulator/oracle/private_execution_oracle.ts +97 -101
  99. package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +129 -63
  100. package/src/contract_sync/contract_sync_service.ts +152 -0
  101. package/src/contract_sync/{index.ts → helpers.ts} +21 -21
  102. package/src/debug/pxe_debug_utils.ts +48 -18
  103. package/src/entrypoints/client/bundle/index.ts +2 -0
  104. package/src/entrypoints/client/bundle/utils.ts +12 -2
  105. package/src/entrypoints/client/lazy/index.ts +2 -0
  106. package/src/entrypoints/client/lazy/utils.ts +12 -2
  107. package/src/entrypoints/server/index.ts +3 -1
  108. package/src/entrypoints/server/utils.ts +7 -7
  109. package/src/events/event_service.ts +4 -6
  110. package/src/logs/log_service.ts +14 -29
  111. package/src/notes/note_service.ts +9 -10
  112. package/src/notes_filter.ts +26 -0
  113. package/src/oracle_version.ts +2 -2
  114. package/src/pxe.ts +151 -88
  115. package/src/storage/address_store/address_store.ts +15 -15
  116. package/src/storage/anchor_block_store/anchor_block_store.ts +8 -0
  117. package/src/storage/capsule_store/capsule_store.ts +8 -8
  118. package/src/storage/contract_store/contract_store.ts +26 -15
  119. package/src/storage/metadata.ts +1 -1
  120. package/src/storage/note_store/note_store.ts +195 -153
  121. package/src/storage/private_event_store/private_event_store.ts +151 -128
  122. package/src/storage/private_event_store/stored_private_event.ts +1 -1
  123. package/src/storage/tagging_store/recipient_tagging_store.ts +31 -21
  124. package/src/storage/tagging_store/sender_address_book_store.ts +20 -14
  125. package/src/storage/tagging_store/sender_tagging_store.ts +210 -126
  126. package/dest/contract_sync/index.d.ts +0 -23
  127. package/dest/contract_sync/index.d.ts.map +0 -1
@@ -7,18 +7,21 @@ import {
7
7
  FIXED_AVM_STARTUP_L2_GAS,
8
8
  FIXED_DA_GAS,
9
9
  FIXED_L2_GAS,
10
- GeneratorIndex,
11
10
  L2_GAS_PER_CONTRACT_CLASS_LOG,
11
+ L2_GAS_PER_L2_TO_L1_MSG,
12
+ L2_GAS_PER_NOTE_HASH,
13
+ L2_GAS_PER_NULLIFIER,
12
14
  L2_GAS_PER_PRIVATE_LOG,
13
15
  MAX_CONTRACT_CLASS_LOGS_PER_TX,
14
16
  MAX_ENQUEUED_CALLS_PER_TX,
15
17
  MAX_L2_TO_L1_MSGS_PER_TX,
16
18
  MAX_NOTE_HASHES_PER_TX,
19
+ MAX_NOTE_HASH_READ_REQUESTS_PER_TX,
17
20
  MAX_NULLIFIERS_PER_TX,
21
+ MAX_NULLIFIER_READ_REQUESTS_PER_TX,
18
22
  MAX_PRIVATE_LOGS_PER_TX,
19
23
  } from '@aztec/constants';
20
24
  import { arrayNonEmptyLength, padArrayEnd } from '@aztec/foundation/collection';
21
- import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto/poseidon';
22
25
  import { Fr } from '@aztec/foundation/curves/bn254';
23
26
  import { type Logger, createLogger } from '@aztec/foundation/log';
24
27
  import { Timer } from '@aztec/foundation/timer';
@@ -38,25 +41,36 @@ import type { FunctionCall } from '@aztec/stdlib/abi';
38
41
  import { FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
39
42
  import type { AuthWitness } from '@aztec/stdlib/auth-witness';
40
43
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
44
+ import type { BlockParameter } from '@aztec/stdlib/block';
41
45
  import { Gas } from '@aztec/stdlib/gas';
42
46
  import {
43
47
  computeNoteHashNonce,
44
48
  computeProtocolNullifier,
49
+ computeSiloedPrivateLogFirstField,
45
50
  computeUniqueNoteHash,
46
51
  siloNoteHash,
47
52
  siloNullifier,
48
53
  } from '@aztec/stdlib/hash';
49
54
  import type { AztecNode } from '@aztec/stdlib/interfaces/server';
50
55
  import {
56
+ ClaimedLengthArray,
51
57
  PartialPrivateTailPublicInputsForPublic,
52
58
  PartialPrivateTailPublicInputsForRollup,
53
59
  type PrivateExecutionStep,
54
60
  type PrivateKernelExecutionProofOutput,
55
61
  PrivateKernelTailCircuitPublicInputs,
62
+ PrivateLogData,
56
63
  PrivateToPublicAccumulatedData,
57
64
  PrivateToRollupAccumulatedData,
58
65
  PublicCallRequest,
66
+ ReadRequestActionEnum,
59
67
  ScopedLogHash,
68
+ ScopedNoteHash,
69
+ ScopedNullifier,
70
+ ScopedReadRequest,
71
+ buildTransientDataHints,
72
+ getNoteHashReadRequestResetActions,
73
+ getNullifierReadRequestResetActions,
60
74
  } from '@aztec/stdlib/kernel';
61
75
  import { PrivateLog } from '@aztec/stdlib/logs';
62
76
  import { ScopedL2ToL1Message } from '@aztec/stdlib/messaging';
@@ -69,11 +83,13 @@ import {
69
83
  TxConstantData,
70
84
  TxExecutionRequest,
71
85
  collectNested,
86
+ collectNoteHashNullifierCounterMap,
72
87
  getFinalMinRevertibleSideEffectCounter,
73
88
  } from '@aztec/stdlib/tx';
74
89
 
90
+ import type { AccessScopes } from '../access_scopes.js';
91
+ import type { ContractSyncService } from '../contract_sync/contract_sync_service.js';
75
92
  import type { AddressStore } from '../storage/address_store/address_store.js';
76
- import type { AnchorBlockStore } from '../storage/anchor_block_store/anchor_block_store.js';
77
93
  import type { CapsuleStore } from '../storage/capsule_store/capsule_store.js';
78
94
  import type { ContractStore } from '../storage/contract_store/contract_store.js';
79
95
  import type { NoteStore } from '../storage/note_store/note_store.js';
@@ -90,52 +106,89 @@ import { executePrivateFunction } from './oracle/private_execution.js';
90
106
  import { PrivateExecutionOracle } from './oracle/private_execution_oracle.js';
91
107
  import { UtilityExecutionOracle } from './oracle/utility_execution_oracle.js';
92
108
 
109
+ /** Options for ContractFunctionSimulator.run. */
110
+ export type ContractSimulatorRunOpts = {
111
+ /** The address of the contract (should match request.origin). */
112
+ contractAddress: AztecAddress;
113
+ /** The function selector of the entry point. */
114
+ selector: FunctionSelector;
115
+ /** The address calling the function. Can be replaced to simulate a call from another contract or account. */
116
+ msgSender?: AztecAddress;
117
+ /** The block header to use as base state for this run. */
118
+ anchorBlockHeader: BlockHeader;
119
+ /** The address used as a tagging sender when emitting private logs. */
120
+ senderForTags?: AztecAddress;
121
+ /** The accounts whose notes we can access in this call. */
122
+ scopes: AccessScopes;
123
+ /** The job ID for staged writes. */
124
+ jobId: string;
125
+ };
126
+
127
+ /** Args for ContractFunctionSimulator constructor. */
128
+ export type ContractFunctionSimulatorArgs = {
129
+ contractStore: ContractStore;
130
+ noteStore: NoteStore;
131
+ keyStore: KeyStore;
132
+ addressStore: AddressStore;
133
+ aztecNode: AztecNode;
134
+ senderTaggingStore: SenderTaggingStore;
135
+ recipientTaggingStore: RecipientTaggingStore;
136
+ senderAddressBookStore: SenderAddressBookStore;
137
+ capsuleStore: CapsuleStore;
138
+ privateEventStore: PrivateEventStore;
139
+ simulator: CircuitSimulator;
140
+ contractSyncService: ContractSyncService;
141
+ };
142
+
93
143
  /**
94
144
  * The contract function simulator.
95
145
  */
96
146
  export class ContractFunctionSimulator {
97
- private log: Logger;
98
-
99
- constructor(
100
- private contractStore: ContractStore,
101
- private noteStore: NoteStore,
102
- private keyStore: KeyStore,
103
- private addressStore: AddressStore,
104
- private aztecNode: AztecNode,
105
- private anchorBlockStore: AnchorBlockStore,
106
- private senderTaggingStore: SenderTaggingStore,
107
- private recipientTaggingStore: RecipientTaggingStore,
108
- private senderAddressBookStore: SenderAddressBookStore,
109
- private capsuleStore: CapsuleStore,
110
- private privateEventStore: PrivateEventStore,
111
- private simulator: CircuitSimulator,
112
- ) {
147
+ private readonly log: Logger;
148
+ private readonly contractStore: ContractStore;
149
+ private readonly noteStore: NoteStore;
150
+ private readonly keyStore: KeyStore;
151
+ private readonly addressStore: AddressStore;
152
+ private readonly aztecNode: AztecNode;
153
+ private readonly senderTaggingStore: SenderTaggingStore;
154
+ private readonly recipientTaggingStore: RecipientTaggingStore;
155
+ private readonly senderAddressBookStore: SenderAddressBookStore;
156
+ private readonly capsuleStore: CapsuleStore;
157
+ private readonly privateEventStore: PrivateEventStore;
158
+ private readonly simulator: CircuitSimulator;
159
+ private readonly contractSyncService: ContractSyncService;
160
+
161
+ constructor(args: ContractFunctionSimulatorArgs) {
162
+ this.contractStore = args.contractStore;
163
+ this.noteStore = args.noteStore;
164
+ this.keyStore = args.keyStore;
165
+ this.addressStore = args.addressStore;
166
+ this.aztecNode = args.aztecNode;
167
+ this.senderTaggingStore = args.senderTaggingStore;
168
+ this.recipientTaggingStore = args.recipientTaggingStore;
169
+ this.senderAddressBookStore = args.senderAddressBookStore;
170
+ this.capsuleStore = args.capsuleStore;
171
+ this.privateEventStore = args.privateEventStore;
172
+ this.simulator = args.simulator;
173
+ this.contractSyncService = args.contractSyncService;
113
174
  this.log = createLogger('simulator');
114
175
  }
115
176
 
116
177
  /**
117
178
  * Runs a private function.
118
179
  * @param request - The transaction request.
119
- * @param entryPointArtifact - The artifact of the entry point function.
120
- * @param contractAddress - The address of the contract (should match request.origin)
121
- * @param msgSender - The address calling the function. This can be replaced to simulate a call from another contract
122
- * or a specific account.
123
- * @param anchorBlockHeader - The block header to use as base state for this run.
124
- * @param senderForTags - The address that is used as a tagging sender when emitting private logs. Returned from
125
- * the `privateGetSenderForTags` oracle.
126
- * @param scopes - The accounts whose notes we can access in this call. Currently optional and will default to all.
127
- * @param jobId - The job ID for staged writes.
128
- * @returns The result of the execution.
129
180
  */
130
181
  public async run(
131
182
  request: TxExecutionRequest,
132
- contractAddress: AztecAddress,
133
- selector: FunctionSelector,
134
- msgSender = AztecAddress.fromField(Fr.MAX_FIELD_VALUE),
135
- anchorBlockHeader: BlockHeader,
136
- senderForTags: AztecAddress | undefined,
137
- scopes: AztecAddress[] | undefined,
138
- jobId: string,
183
+ {
184
+ contractAddress,
185
+ selector,
186
+ msgSender = AztecAddress.fromField(Fr.MAX_FIELD_VALUE),
187
+ anchorBlockHeader,
188
+ senderForTags,
189
+ scopes,
190
+ jobId,
191
+ }: ContractSimulatorRunOpts,
139
192
  ): Promise<PrivateExecutionResult> {
140
193
  const simulatorSetupTimer = new Timer();
141
194
 
@@ -165,38 +218,37 @@ export class ContractFunctionSimulator {
165
218
  const noteCache = new ExecutionNoteCache(protocolNullifier);
166
219
  const taggingIndexCache = new ExecutionTaggingIndexCache();
167
220
 
168
- const privateExecutionOracle = new PrivateExecutionOracle(
169
- request.firstCallArgsHash,
170
- request.txContext,
221
+ const privateExecutionOracle = new PrivateExecutionOracle({
222
+ argsHash: request.firstCallArgsHash,
223
+ txContext: request.txContext,
171
224
  callContext,
172
225
  anchorBlockHeader,
173
- async call => {
174
- await this.runUtility(call, [], anchorBlockHeader, scopes, jobId);
226
+ utilityExecutor: async (call, execScopes) => {
227
+ await this.runUtility(call, [], anchorBlockHeader, execScopes, jobId);
175
228
  },
176
- request.authWitnesses,
177
- request.capsules,
178
- HashedValuesCache.create(request.argsOfCalls),
229
+ authWitnesses: request.authWitnesses,
230
+ capsules: request.capsules,
231
+ executionCache: HashedValuesCache.create(request.argsOfCalls),
179
232
  noteCache,
180
233
  taggingIndexCache,
181
- this.contractStore,
182
- this.noteStore,
183
- this.keyStore,
184
- this.addressStore,
185
- this.aztecNode,
186
- this.anchorBlockStore,
187
- this.senderTaggingStore,
188
- this.recipientTaggingStore,
189
- this.senderAddressBookStore,
190
- this.capsuleStore,
191
- this.privateEventStore,
234
+ contractStore: this.contractStore,
235
+ noteStore: this.noteStore,
236
+ keyStore: this.keyStore,
237
+ addressStore: this.addressStore,
238
+ aztecNode: this.aztecNode,
239
+ senderTaggingStore: this.senderTaggingStore,
240
+ recipientTaggingStore: this.recipientTaggingStore,
241
+ senderAddressBookStore: this.senderAddressBookStore,
242
+ capsuleStore: this.capsuleStore,
243
+ privateEventStore: this.privateEventStore,
244
+ contractSyncService: this.contractSyncService,
192
245
  jobId,
193
- 0, // totalPublicArgsCount
194
- startSideEffectCounter,
195
- undefined, // log
246
+ totalPublicCalldataCount: 0,
247
+ sideEffectCounter: startSideEffectCounter,
196
248
  scopes,
197
249
  senderForTags,
198
- this.simulator,
199
- );
250
+ simulator: this.simulator,
251
+ });
200
252
 
201
253
  const setupTime = simulatorSetupTimer.ms();
202
254
 
@@ -260,7 +312,7 @@ export class ContractFunctionSimulator {
260
312
  call: FunctionCall,
261
313
  authwits: AuthWitness[],
262
314
  anchorBlockHeader: BlockHeader,
263
- scopes: AztecAddress[] | undefined,
315
+ scopes: AccessScopes,
264
316
  jobId: string,
265
317
  ): Promise<Fr[]> {
266
318
  const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
@@ -269,25 +321,23 @@ export class ContractFunctionSimulator {
269
321
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
270
322
  }
271
323
 
272
- const oracle = new UtilityExecutionOracle(
273
- call.to,
274
- authwits,
275
- [],
324
+ const oracle = new UtilityExecutionOracle({
325
+ contractAddress: call.to,
326
+ authWitnesses: authwits,
327
+ capsules: [],
276
328
  anchorBlockHeader,
277
- this.contractStore,
278
- this.noteStore,
279
- this.keyStore,
280
- this.addressStore,
281
- this.aztecNode,
282
- this.anchorBlockStore,
283
- this.recipientTaggingStore,
284
- this.senderAddressBookStore,
285
- this.capsuleStore,
286
- this.privateEventStore,
329
+ contractStore: this.contractStore,
330
+ noteStore: this.noteStore,
331
+ keyStore: this.keyStore,
332
+ addressStore: this.addressStore,
333
+ aztecNode: this.aztecNode,
334
+ recipientTaggingStore: this.recipientTaggingStore,
335
+ senderAddressBookStore: this.senderAddressBookStore,
336
+ capsuleStore: this.capsuleStore,
337
+ privateEventStore: this.privateEventStore,
287
338
  jobId,
288
- undefined,
289
339
  scopes,
290
- );
340
+ });
291
341
 
292
342
  try {
293
343
  this.log.verbose(`Executing utility function ${entryPointArtifact.name}`, {
@@ -353,24 +403,33 @@ class OrderedSideEffect<T> {
353
403
  * (allowing state overrides) and is much faster, while still generating a valid
354
404
  * output that can be sent to the node for public simulation
355
405
  * @param privateExecutionResult - The result of the private execution.
356
- * @param contractStore - A provider for contract data in order to get function names and debug info.
406
+ * @param debugFunctionNameGetter - A provider for contract data in order to get function names and debug info.
407
+ * @param node - AztecNode for verifying settled read requests against the note hash and nullifier trees.
357
408
  * @param minRevertibleSideEffectCounterOverride - Optional override for the min revertible side effect counter.
358
409
  * Used by TXE to simulate account contract behavior (setting the counter before app execution).
359
410
  * @returns The simulated proving result.
360
411
  */
361
412
  export async function generateSimulatedProvingResult(
362
413
  privateExecutionResult: PrivateExecutionResult,
363
- contractStore: ContractStore,
414
+ debugFunctionNameGetter: (contractAddress: AztecAddress, functionSelector: FunctionSelector) => Promise<string>,
415
+ node: AztecNode,
364
416
  minRevertibleSideEffectCounterOverride?: number,
365
417
  ): Promise<PrivateKernelExecutionProofOutput<PrivateKernelTailCircuitPublicInputs>> {
366
- const siloedNoteHashes: OrderedSideEffect<Fr>[] = [];
367
- const nullifiers: OrderedSideEffect<Fr>[] = [];
368
- const taggedPrivateLogs: OrderedSideEffect<PrivateLog>[] = [];
418
+ const taggedPrivateLogs: OrderedSideEffect<PrivateLogData>[] = [];
369
419
  const l2ToL1Messages: OrderedSideEffect<ScopedL2ToL1Message>[] = [];
370
420
  const contractClassLogsHashes: OrderedSideEffect<ScopedLogHash>[] = [];
371
421
  const publicCallRequests: OrderedSideEffect<PublicCallRequest>[] = [];
372
422
  const executionSteps: PrivateExecutionStep[] = [];
373
423
 
424
+ // Unsiloed scoped arrays — used for squashing, read request verification,
425
+ // and siloed at the end only for the surviving items
426
+ const scopedNoteHashes: ScopedNoteHash[] = [];
427
+ const scopedNullifiers: ScopedNullifier[] = [];
428
+
429
+ // Read requests for verification
430
+ const noteHashReadRequests: ScopedReadRequest[] = [];
431
+ const nullifierReadRequests: ScopedReadRequest[] = [];
432
+
374
433
  let publicTeardownCallRequest;
375
434
 
376
435
  const executions = [privateExecutionResult.entrypoint];
@@ -381,38 +440,25 @@ export async function generateSimulatedProvingResult(
381
440
 
382
441
  const { contractAddress } = execution.publicInputs.callContext;
383
442
 
384
- const noteHashesFromExecution = await Promise.all(
385
- execution.publicInputs.noteHashes
386
- .getActiveItems()
387
- .filter(noteHash => !noteHash.isEmpty())
388
- .map(
389
- async noteHash =>
390
- new OrderedSideEffect(await siloNoteHash(contractAddress, noteHash.value), noteHash.counter),
391
- ),
392
- );
393
-
394
- const nullifiersFromExecution = await Promise.all(
395
- execution.publicInputs.nullifiers
443
+ scopedNoteHashes.push(
444
+ ...execution.publicInputs.noteHashes
396
445
  .getActiveItems()
397
- .map(
398
- async nullifier =>
399
- new OrderedSideEffect(await siloNullifier(contractAddress, nullifier.value), nullifier.counter),
400
- ),
446
+ .filter(nh => !nh.isEmpty())
447
+ .map(nh => nh.scope(contractAddress)),
401
448
  );
449
+ scopedNullifiers.push(...execution.publicInputs.nullifiers.getActiveItems().map(n => n.scope(contractAddress)));
402
450
 
403
- const privateLogsFromExecution = await Promise.all(
404
- execution.publicInputs.privateLogs.getActiveItems().map(async metadata => {
405
- metadata.log.fields[0] = await poseidon2HashWithSeparator(
406
- [contractAddress, metadata.log.fields[0]],
407
- GeneratorIndex.PRIVATE_LOG_FIRST_FIELD,
408
- );
409
- return new OrderedSideEffect(metadata.log, metadata.counter);
410
- }),
451
+ taggedPrivateLogs.push(
452
+ ...(await Promise.all(
453
+ execution.publicInputs.privateLogs.getActiveItems().map(async metadata => {
454
+ metadata.log.fields[0] = await computeSiloedPrivateLogFirstField(contractAddress, metadata.log.fields[0]);
455
+ return new OrderedSideEffect(metadata, metadata.counter);
456
+ }),
457
+ )),
411
458
  );
412
459
 
413
- siloedNoteHashes.push(...noteHashesFromExecution);
414
- taggedPrivateLogs.push(...privateLogsFromExecution);
415
- nullifiers.push(...nullifiersFromExecution);
460
+ noteHashReadRequests.push(...execution.publicInputs.noteHashReadRequests.getActiveItems());
461
+ nullifierReadRequests.push(...execution.publicInputs.nullifierReadRequests.getActiveItems());
416
462
  l2ToL1Messages.push(
417
463
  ...execution.publicInputs.l2ToL1Msgs
418
464
  .getActiveItems()
@@ -441,7 +487,7 @@ export async function generateSimulatedProvingResult(
441
487
  : execution.publicInputs.publicTeardownCallRequest;
442
488
 
443
489
  executionSteps.push({
444
- functionName: await contractStore.getDebugFunctionName(
490
+ functionName: await debugFunctionNameGetter(
445
491
  execution.publicInputs.callContext.contractAddress,
446
492
  execution.publicInputs.callContext.functionSelector,
447
493
  ),
@@ -452,6 +498,47 @@ export async function generateSimulatedProvingResult(
452
498
  });
453
499
  }
454
500
 
501
+ const noteHashNullifierCounterMap = collectNoteHashNullifierCounterMap(privateExecutionResult);
502
+ const minRevertibleSideEffectCounter =
503
+ minRevertibleSideEffectCounterOverride ?? getFinalMinRevertibleSideEffectCounter(privateExecutionResult);
504
+
505
+ const scopedNoteHashesCLA = new ClaimedLengthArray<ScopedNoteHash, typeof MAX_NOTE_HASHES_PER_TX>(
506
+ padArrayEnd(scopedNoteHashes, ScopedNoteHash.empty(), MAX_NOTE_HASHES_PER_TX),
507
+ scopedNoteHashes.length,
508
+ );
509
+ const scopedNullifiersCLA = new ClaimedLengthArray<ScopedNullifier, typeof MAX_NULLIFIERS_PER_TX>(
510
+ padArrayEnd(scopedNullifiers, ScopedNullifier.empty(), MAX_NULLIFIERS_PER_TX),
511
+ scopedNullifiers.length,
512
+ );
513
+
514
+ const { filteredNoteHashes, filteredNullifiers, filteredPrivateLogs } = squashTransientSideEffects(
515
+ taggedPrivateLogs,
516
+ scopedNoteHashesCLA,
517
+ scopedNullifiersCLA,
518
+ noteHashNullifierCounterMap,
519
+ minRevertibleSideEffectCounter,
520
+ );
521
+
522
+ await verifyReadRequests(
523
+ node,
524
+ await privateExecutionResult.entrypoint.publicInputs.anchorBlockHeader.hash(),
525
+ noteHashReadRequests,
526
+ nullifierReadRequests,
527
+ scopedNoteHashesCLA,
528
+ scopedNullifiersCLA,
529
+ );
530
+
531
+ const siloedNoteHashes = await Promise.all(
532
+ filteredNoteHashes
533
+ .sort((a, b) => a.counter - b.counter)
534
+ .map(async nh => new OrderedSideEffect(await siloNoteHash(nh.contractAddress, nh.value), nh.counter)),
535
+ );
536
+ const siloedNullifiers = await Promise.all(
537
+ filteredNullifiers
538
+ .sort((a, b) => a.counter - b.counter)
539
+ .map(async n => new OrderedSideEffect(await siloNullifier(n.contractAddress, n.value), n.counter)),
540
+ );
541
+
455
542
  const constantData = new TxConstantData(
456
543
  privateExecutionResult.entrypoint.publicInputs.anchorBlockHeader,
457
544
  privateExecutionResult.entrypoint.publicInputs.txContext,
@@ -468,11 +555,9 @@ export async function generateSimulatedProvingResult(
468
555
  const getEffect = <T>(orderedSideEffect: OrderedSideEffect<T>) => orderedSideEffect.sideEffect;
469
556
 
470
557
  const isPrivateOnlyTx = privateExecutionResult.publicFunctionCalldata.length === 0;
471
- const minRevertibleSideEffectCounter =
472
- minRevertibleSideEffectCounterOverride ?? getFinalMinRevertibleSideEffectCounter(privateExecutionResult);
473
558
 
474
559
  const [nonRevertibleNullifiers, revertibleNullifiers] = splitOrderedSideEffects(
475
- nullifiers.sort(sortByCounter),
560
+ siloedNullifiers,
476
561
  minRevertibleSideEffectCounter,
477
562
  );
478
563
  const nonceGenerator = privateExecutionResult.firstNullifier;
@@ -486,7 +571,7 @@ export async function generateSimulatedProvingResult(
486
571
  // We must make the note hashes unique by using the
487
572
  // nonce generator and their index in the tx.
488
573
  const uniqueNoteHashes = await Promise.all(
489
- siloedNoteHashes.sort(sortByCounter).map(async (orderedSideEffect, i) => {
574
+ siloedNoteHashes.map(async (orderedSideEffect, i) => {
490
575
  const siloedNoteHash = orderedSideEffect.sideEffect;
491
576
  const nonce = await computeNoteHashNonce(nonceGenerator, i);
492
577
  const uniqueNoteHash = await computeUniqueNoteHash(nonce, siloedNoteHash);
@@ -501,18 +586,18 @@ export async function generateSimulatedProvingResult(
501
586
  ScopedL2ToL1Message.empty(),
502
587
  MAX_L2_TO_L1_MSGS_PER_TX,
503
588
  ),
504
- padArrayEnd(taggedPrivateLogs.sort(sortByCounter).map(getEffect), PrivateLog.empty(), MAX_PRIVATE_LOGS_PER_TX),
589
+ padArrayEnd(filteredPrivateLogs.sort(sortByCounter).map(getEffect), PrivateLog.empty(), MAX_PRIVATE_LOGS_PER_TX),
505
590
  padArrayEnd(
506
591
  contractClassLogsHashes.sort(sortByCounter).map(getEffect),
507
592
  ScopedLogHash.empty(),
508
593
  MAX_CONTRACT_CLASS_LOGS_PER_TX,
509
594
  ),
510
595
  );
511
- gasUsed = meterGasUsed(accumulatedDataForRollup);
596
+ gasUsed = meterGasUsed(accumulatedDataForRollup, isPrivateOnlyTx);
512
597
  inputsForRollup = new PartialPrivateTailPublicInputsForRollup(accumulatedDataForRollup);
513
598
  } else {
514
599
  const [nonRevertibleNoteHashes, revertibleNoteHashes] = splitOrderedSideEffects(
515
- siloedNoteHashes.sort(sortByCounter),
600
+ siloedNoteHashes,
516
601
  minRevertibleSideEffectCounter,
517
602
  );
518
603
  const nonRevertibleUniqueNoteHashes = await Promise.all(
@@ -526,7 +611,7 @@ export async function generateSimulatedProvingResult(
526
611
  minRevertibleSideEffectCounter,
527
612
  );
528
613
  const [nonRevertibleTaggedPrivateLogs, revertibleTaggedPrivateLogs] = splitOrderedSideEffects(
529
- taggedPrivateLogs,
614
+ filteredPrivateLogs,
530
615
  minRevertibleSideEffectCounter,
531
616
  );
532
617
  const [nonRevertibleContractClassLogHashes, revertibleContractClassLogHashes] = splitOrderedSideEffects(
@@ -555,9 +640,9 @@ export async function generateSimulatedProvingResult(
555
640
  padArrayEnd(revertibleContractClassLogHashes, ScopedLogHash.empty(), MAX_CONTRACT_CLASS_LOGS_PER_TX),
556
641
  padArrayEnd(revertiblePublicCallRequests, PublicCallRequest.empty(), MAX_ENQUEUED_CALLS_PER_TX),
557
642
  );
558
- gasUsed = meterGasUsed(revertibleData).add(meterGasUsed(nonRevertibleData));
643
+ gasUsed = meterGasUsed(revertibleData, isPrivateOnlyTx).add(meterGasUsed(nonRevertibleData, isPrivateOnlyTx));
559
644
  if (publicTeardownCallRequest) {
560
- gasUsed.add(privateExecutionResult.entrypoint.publicInputs.txContext.gasSettings.teardownGasLimits);
645
+ gasUsed = gasUsed.add(privateExecutionResult.entrypoint.publicInputs.txContext.gasSettings.teardownGasLimits);
561
646
  }
562
647
 
563
648
  inputsForPublic = new PartialPrivateTailPublicInputsForPublic(
@@ -583,6 +668,111 @@ export async function generateSimulatedProvingResult(
583
668
  };
584
669
  }
585
670
 
671
+ /**
672
+ * Squashes transient note hashes and nullifiers, mimicking the behavior
673
+ * of the reset kernels. Returns the filtered (surviving) scoped items and private logs.
674
+ */
675
+ function squashTransientSideEffects(
676
+ taggedPrivateLogs: OrderedSideEffect<PrivateLogData>[],
677
+ scopedNoteHashesCLA: ClaimedLengthArray<ScopedNoteHash, typeof MAX_NOTE_HASHES_PER_TX>,
678
+ scopedNullifiersCLA: ClaimedLengthArray<ScopedNullifier, typeof MAX_NULLIFIERS_PER_TX>,
679
+ noteHashNullifierCounterMap: Map<number, number>,
680
+ minRevertibleSideEffectCounter: number,
681
+ ) {
682
+ const { numTransientData, hints: transientDataHints } = buildTransientDataHints(
683
+ scopedNoteHashesCLA,
684
+ scopedNullifiersCLA,
685
+ /*futureNoteHashReads=*/ [],
686
+ /*futureNullifierReads=*/ [],
687
+ noteHashNullifierCounterMap,
688
+ minRevertibleSideEffectCounter,
689
+ );
690
+
691
+ const squashedNoteHashCounters = new Set<number>();
692
+ const squashedNullifierCounters = new Set<number>();
693
+ for (let i = 0; i < numTransientData; i++) {
694
+ const hint = transientDataHints[i];
695
+ squashedNoteHashCounters.add(scopedNoteHashesCLA.array[hint.noteHashIndex].counter);
696
+ squashedNullifierCounters.add(scopedNullifiersCLA.array[hint.nullifierIndex].counter);
697
+ }
698
+
699
+ return {
700
+ filteredNoteHashes: scopedNoteHashesCLA.getActiveItems().filter(nh => !squashedNoteHashCounters.has(nh.counter)),
701
+ filteredNullifiers: scopedNullifiersCLA.getActiveItems().filter(n => !squashedNullifierCounters.has(n.counter)),
702
+ filteredPrivateLogs: taggedPrivateLogs
703
+ .filter(item => !squashedNoteHashCounters.has(item.sideEffect.noteHashCounter))
704
+ .map(item => new OrderedSideEffect(item.sideEffect.log, item.counter)),
705
+ };
706
+ }
707
+
708
+ /**
709
+ * Verifies settled read requests by checking membership in the note hash and nullifier trees
710
+ * at the tx's anchor block, mimicking the behavior of the kernels
711
+ */
712
+ async function verifyReadRequests(
713
+ node: Pick<AztecNode, 'getNoteHashMembershipWitness' | 'getNullifierMembershipWitness'>,
714
+ anchorBlockHash: BlockParameter,
715
+ noteHashReadRequests: ScopedReadRequest[],
716
+ nullifierReadRequests: ScopedReadRequest[],
717
+ scopedNoteHashesCLA: ClaimedLengthArray<ScopedNoteHash, typeof MAX_NOTE_HASHES_PER_TX>,
718
+ scopedNullifiersCLA: ClaimedLengthArray<ScopedNullifier, typeof MAX_NULLIFIERS_PER_TX>,
719
+ ) {
720
+ const noteHashReadRequestsCLA = new ClaimedLengthArray<ScopedReadRequest, typeof MAX_NOTE_HASH_READ_REQUESTS_PER_TX>(
721
+ padArrayEnd(noteHashReadRequests, ScopedReadRequest.empty(), MAX_NOTE_HASH_READ_REQUESTS_PER_TX),
722
+ noteHashReadRequests.length,
723
+ );
724
+ const nullifierReadRequestsCLA = new ClaimedLengthArray<ScopedReadRequest, typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX>(
725
+ padArrayEnd(nullifierReadRequests, ScopedReadRequest.empty(), MAX_NULLIFIER_READ_REQUESTS_PER_TX),
726
+ nullifierReadRequests.length,
727
+ );
728
+
729
+ const noteHashResetActions = getNoteHashReadRequestResetActions(
730
+ noteHashReadRequestsCLA,
731
+ scopedNoteHashesCLA,
732
+ /*futureNoteHashes=*/ [],
733
+ );
734
+ const nullifierResetActions = getNullifierReadRequestResetActions(
735
+ nullifierReadRequestsCLA,
736
+ scopedNullifiersCLA,
737
+ /*futureNullifiers=*/ [],
738
+ );
739
+
740
+ const settledNoteHashReads: { index: number; value: Fr }[] = [];
741
+ for (let i = 0; i < noteHashResetActions.actions.length; i++) {
742
+ if (noteHashResetActions.actions[i] === ReadRequestActionEnum.READ_AS_SETTLED) {
743
+ settledNoteHashReads.push({ index: i, value: noteHashReadRequests[i].value });
744
+ }
745
+ }
746
+
747
+ const settledNullifierReads: { index: number; value: Fr }[] = [];
748
+ for (let i = 0; i < nullifierResetActions.actions.length; i++) {
749
+ if (nullifierResetActions.actions[i] === ReadRequestActionEnum.READ_AS_SETTLED) {
750
+ settledNullifierReads.push({ index: i, value: nullifierReadRequests[i].value });
751
+ }
752
+ }
753
+
754
+ const [noteHashWitnesses, nullifierWitnesses] = await Promise.all([
755
+ Promise.all(settledNoteHashReads.map(({ value }) => node.getNoteHashMembershipWitness(anchorBlockHash, value))),
756
+ Promise.all(settledNullifierReads.map(({ value }) => node.getNullifierMembershipWitness(anchorBlockHash, value))),
757
+ ]);
758
+
759
+ for (let i = 0; i < settledNoteHashReads.length; i++) {
760
+ if (!noteHashWitnesses[i]) {
761
+ throw new Error(
762
+ `Note hash read request at index ${settledNoteHashReads[i].index} is reading an unknown note hash: ${settledNoteHashReads[i].value}`,
763
+ );
764
+ }
765
+ }
766
+
767
+ for (let i = 0; i < settledNullifierReads.length; i++) {
768
+ if (!nullifierWitnesses[i]) {
769
+ throw new Error(
770
+ `Nullifier read request at index ${settledNullifierReads[i].index} is reading an unknown nullifier: ${settledNullifierReads[i].value}`,
771
+ );
772
+ }
773
+ }
774
+ }
775
+
586
776
  function splitOrderedSideEffects<T>(effects: OrderedSideEffect<T>[], minRevertibleSideEffectCounter: number) {
587
777
  const revertibleSideEffects: T[] = [];
588
778
  const nonRevertibleSideEffects: T[] = [];
@@ -596,21 +786,24 @@ function splitOrderedSideEffects<T>(effects: OrderedSideEffect<T>[], minRevertib
596
786
  return [nonRevertibleSideEffects, revertibleSideEffects];
597
787
  }
598
788
 
599
- function meterGasUsed(data: PrivateToRollupAccumulatedData | PrivateToPublicAccumulatedData) {
789
+ function meterGasUsed(data: PrivateToRollupAccumulatedData | PrivateToPublicAccumulatedData, isPrivateOnlyTx: boolean) {
600
790
  let meteredDAFields = 0;
601
791
  let meteredL2Gas = 0;
602
792
 
603
793
  const numNoteHashes = arrayNonEmptyLength(data.noteHashes, hash => hash.isEmpty());
604
794
  meteredDAFields += numNoteHashes;
605
- meteredL2Gas += numNoteHashes * AVM_EMITNOTEHASH_BASE_L2_GAS;
795
+ const noteHashBaseGas = isPrivateOnlyTx ? L2_GAS_PER_NOTE_HASH : AVM_EMITNOTEHASH_BASE_L2_GAS;
796
+ meteredL2Gas += numNoteHashes * noteHashBaseGas;
606
797
 
607
798
  const numNullifiers = arrayNonEmptyLength(data.nullifiers, nullifier => nullifier.isEmpty());
608
799
  meteredDAFields += numNullifiers;
609
- meteredL2Gas += numNullifiers * AVM_EMITNULLIFIER_BASE_L2_GAS;
800
+ const nullifierBaseGas = isPrivateOnlyTx ? L2_GAS_PER_NULLIFIER : AVM_EMITNULLIFIER_BASE_L2_GAS;
801
+ meteredL2Gas += numNullifiers * nullifierBaseGas;
610
802
 
611
803
  const numL2toL1Messages = arrayNonEmptyLength(data.l2ToL1Msgs, msg => msg.isEmpty());
612
804
  meteredDAFields += numL2toL1Messages;
613
- meteredL2Gas += numL2toL1Messages * AVM_SENDL2TOL1MSG_BASE_L2_GAS;
805
+ const l2ToL1MessageBaseGas = isPrivateOnlyTx ? L2_GAS_PER_L2_TO_L1_MSG : AVM_SENDL2TOL1MSG_BASE_L2_GAS;
806
+ meteredL2Gas += numL2toL1Messages * l2ToL1MessageBaseGas;
614
807
 
615
808
  const numPrivatelogs = arrayNonEmptyLength(data.privateLogs, log => log.isEmpty());
616
809
  // Every private log emits its length as an additional field