@aztec/pxe 0.0.1-commit.4d79d1f2d → 0.0.1-commit.4eabbdb

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 (90) 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/config/package_info.js +1 -1
  5. package/dest/contract_function_simulator/contract_function_simulator.d.ts +8 -6
  6. package/dest/contract_function_simulator/contract_function_simulator.d.ts.map +1 -1
  7. package/dest/contract_function_simulator/contract_function_simulator.js +107 -37
  8. package/dest/contract_function_simulator/noir-structs/event_validation_request.js +1 -1
  9. package/dest/contract_function_simulator/noir-structs/note_validation_request.d.ts +2 -2
  10. package/dest/contract_function_simulator/noir-structs/note_validation_request.d.ts.map +1 -1
  11. package/dest/contract_function_simulator/noir-structs/note_validation_request.js +1 -1
  12. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +3 -2
  13. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts.map +1 -1
  14. package/dest/contract_function_simulator/oracle/private_execution_oracle.js +1 -1
  15. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +4 -3
  16. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
  17. package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +1 -1
  18. package/dest/contract_sync/contract_sync_service.d.ts +4 -3
  19. package/dest/contract_sync/contract_sync_service.d.ts.map +1 -1
  20. package/dest/contract_sync/contract_sync_service.js +10 -10
  21. package/dest/contract_sync/helpers.d.ts +3 -2
  22. package/dest/contract_sync/helpers.d.ts.map +1 -1
  23. package/dest/contract_sync/helpers.js +3 -3
  24. package/dest/debug/pxe_debug_utils.d.ts +5 -4
  25. package/dest/debug/pxe_debug_utils.d.ts.map +1 -1
  26. package/dest/debug/pxe_debug_utils.js +4 -4
  27. package/dest/entrypoints/client/bundle/index.d.ts +3 -1
  28. package/dest/entrypoints/client/bundle/index.d.ts.map +1 -1
  29. package/dest/entrypoints/client/bundle/index.js +2 -0
  30. package/dest/entrypoints/client/lazy/index.d.ts +3 -1
  31. package/dest/entrypoints/client/lazy/index.d.ts.map +1 -1
  32. package/dest/entrypoints/client/lazy/index.js +2 -0
  33. package/dest/entrypoints/server/index.d.ts +3 -1
  34. package/dest/entrypoints/server/index.d.ts.map +1 -1
  35. package/dest/entrypoints/server/index.js +2 -0
  36. package/dest/logs/log_service.d.ts +3 -2
  37. package/dest/logs/log_service.d.ts.map +1 -1
  38. package/dest/logs/log_service.js +1 -1
  39. package/dest/notes/note_service.d.ts +4 -3
  40. package/dest/notes/note_service.d.ts.map +1 -1
  41. package/dest/notes/note_service.js +3 -2
  42. package/dest/notes_filter.d.ts +25 -0
  43. package/dest/notes_filter.d.ts.map +1 -0
  44. package/dest/notes_filter.js +4 -0
  45. package/dest/private_kernel/hints/compute_tx_expiration_timestamp.d.ts +4 -0
  46. package/dest/private_kernel/hints/compute_tx_expiration_timestamp.d.ts.map +1 -0
  47. package/dest/private_kernel/hints/{compute_tx_include_by_timestamp.js → compute_tx_expiration_timestamp.js} +12 -12
  48. package/dest/private_kernel/hints/index.d.ts +1 -1
  49. package/dest/private_kernel/hints/index.js +1 -1
  50. package/dest/private_kernel/hints/private_kernel_reset_private_inputs_builder.js +4 -4
  51. package/dest/private_kernel/private_kernel_execution_prover.js +6 -6
  52. package/dest/pxe.d.ts +12 -11
  53. package/dest/pxe.d.ts.map +1 -1
  54. package/dest/pxe.js +17 -15
  55. package/dest/storage/note_store/note_store.d.ts +3 -2
  56. package/dest/storage/note_store/note_store.d.ts.map +1 -1
  57. package/dest/storage/note_store/note_store.js +2 -2
  58. package/dest/tagging/get_all_logs_by_tags.d.ts +1 -1
  59. package/dest/tagging/get_all_logs_by_tags.d.ts.map +1 -1
  60. package/dest/tagging/get_all_logs_by_tags.js +17 -3
  61. package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.js +4 -4
  62. package/dest/tagging/recipient_sync/utils/find_highest_indexes.js +2 -2
  63. package/package.json +16 -16
  64. package/src/access_scopes.ts +9 -0
  65. package/src/config/package_info.ts +1 -1
  66. package/src/contract_function_simulator/contract_function_simulator.ts +213 -55
  67. package/src/contract_function_simulator/noir-structs/event_validation_request.ts +1 -1
  68. package/src/contract_function_simulator/noir-structs/note_validation_request.ts +1 -1
  69. package/src/contract_function_simulator/oracle/private_execution_oracle.ts +4 -3
  70. package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +4 -3
  71. package/src/contract_sync/contract_sync_service.ts +19 -12
  72. package/src/contract_sync/helpers.ts +7 -2
  73. package/src/debug/pxe_debug_utils.ts +9 -8
  74. package/src/entrypoints/client/bundle/index.ts +2 -0
  75. package/src/entrypoints/client/lazy/index.ts +2 -0
  76. package/src/entrypoints/server/index.ts +2 -0
  77. package/src/logs/log_service.ts +3 -6
  78. package/src/notes/note_service.ts +4 -3
  79. package/src/notes_filter.ts +26 -0
  80. package/src/private_kernel/hints/{compute_tx_include_by_timestamp.ts → compute_tx_expiration_timestamp.ts} +13 -13
  81. package/src/private_kernel/hints/index.ts +1 -1
  82. package/src/private_kernel/hints/private_kernel_reset_private_inputs_builder.ts +7 -7
  83. package/src/private_kernel/private_kernel_execution_prover.ts +6 -6
  84. package/src/pxe.ts +29 -27
  85. package/src/storage/note_store/note_store.ts +7 -3
  86. package/src/tagging/get_all_logs_by_tags.ts +28 -4
  87. package/src/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.ts +4 -4
  88. package/src/tagging/recipient_sync/utils/find_highest_indexes.ts +2 -2
  89. package/dest/private_kernel/hints/compute_tx_include_by_timestamp.d.ts +0 -4
  90. package/dest/private_kernel/hints/compute_tx_include_by_timestamp.d.ts.map +0 -1
@@ -2,23 +2,25 @@ import {
2
2
  AVM_EMITNOTEHASH_BASE_L2_GAS,
3
3
  AVM_EMITNULLIFIER_BASE_L2_GAS,
4
4
  AVM_SENDL2TOL1MSG_BASE_L2_GAS,
5
- DA_BYTES_PER_FIELD,
6
- DA_GAS_PER_BYTE,
5
+ DA_GAS_PER_FIELD,
7
6
  FIXED_AVM_STARTUP_L2_GAS,
8
7
  FIXED_DA_GAS,
9
8
  FIXED_L2_GAS,
10
- GeneratorIndex,
11
9
  L2_GAS_PER_CONTRACT_CLASS_LOG,
10
+ L2_GAS_PER_L2_TO_L1_MSG,
11
+ L2_GAS_PER_NOTE_HASH,
12
+ L2_GAS_PER_NULLIFIER,
12
13
  L2_GAS_PER_PRIVATE_LOG,
13
14
  MAX_CONTRACT_CLASS_LOGS_PER_TX,
14
15
  MAX_ENQUEUED_CALLS_PER_TX,
15
16
  MAX_L2_TO_L1_MSGS_PER_TX,
16
17
  MAX_NOTE_HASHES_PER_TX,
18
+ MAX_NOTE_HASH_READ_REQUESTS_PER_TX,
17
19
  MAX_NULLIFIERS_PER_TX,
20
+ MAX_NULLIFIER_READ_REQUESTS_PER_TX,
18
21
  MAX_PRIVATE_LOGS_PER_TX,
19
22
  } from '@aztec/constants';
20
23
  import { arrayNonEmptyLength, padArrayEnd } from '@aztec/foundation/collection';
21
- import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto/poseidon';
22
24
  import { Fr } from '@aztec/foundation/curves/bn254';
23
25
  import { type Logger, createLogger } from '@aztec/foundation/log';
24
26
  import { Timer } from '@aztec/foundation/timer';
@@ -38,25 +40,36 @@ import type { FunctionCall } from '@aztec/stdlib/abi';
38
40
  import { FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
39
41
  import type { AuthWitness } from '@aztec/stdlib/auth-witness';
40
42
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
43
+ import type { BlockParameter } from '@aztec/stdlib/block';
41
44
  import { Gas } from '@aztec/stdlib/gas';
42
45
  import {
43
46
  computeNoteHashNonce,
44
47
  computeProtocolNullifier,
48
+ computeSiloedPrivateLogFirstField,
45
49
  computeUniqueNoteHash,
46
50
  siloNoteHash,
47
51
  siloNullifier,
48
52
  } from '@aztec/stdlib/hash';
49
53
  import type { AztecNode } from '@aztec/stdlib/interfaces/server';
50
54
  import {
55
+ ClaimedLengthArray,
51
56
  PartialPrivateTailPublicInputsForPublic,
52
57
  PartialPrivateTailPublicInputsForRollup,
53
58
  type PrivateExecutionStep,
54
59
  type PrivateKernelExecutionProofOutput,
55
60
  PrivateKernelTailCircuitPublicInputs,
61
+ PrivateLogData,
56
62
  PrivateToPublicAccumulatedData,
57
63
  PrivateToRollupAccumulatedData,
58
64
  PublicCallRequest,
65
+ ReadRequestActionEnum,
59
66
  ScopedLogHash,
67
+ ScopedNoteHash,
68
+ ScopedNullifier,
69
+ ScopedReadRequest,
70
+ buildTransientDataHints,
71
+ getNoteHashReadRequestResetActions,
72
+ getNullifierReadRequestResetActions,
60
73
  } from '@aztec/stdlib/kernel';
61
74
  import { PrivateLog } from '@aztec/stdlib/logs';
62
75
  import { ScopedL2ToL1Message } from '@aztec/stdlib/messaging';
@@ -69,9 +82,11 @@ import {
69
82
  TxConstantData,
70
83
  TxExecutionRequest,
71
84
  collectNested,
85
+ collectNoteHashNullifierCounterMap,
72
86
  getFinalMinRevertibleSideEffectCounter,
73
87
  } from '@aztec/stdlib/tx';
74
88
 
89
+ import type { AccessScopes } from '../access_scopes.js';
75
90
  import type { ContractSyncService } from '../contract_sync/contract_sync_service.js';
76
91
  import type { AddressStore } from '../storage/address_store/address_store.js';
77
92
  import type { CapsuleStore } from '../storage/capsule_store/capsule_store.js';
@@ -102,8 +117,8 @@ export type ContractSimulatorRunOpts = {
102
117
  anchorBlockHeader: BlockHeader;
103
118
  /** The address used as a tagging sender when emitting private logs. */
104
119
  senderForTags?: AztecAddress;
105
- /** The accounts whose notes we can access in this call. Defaults to all. */
106
- scopes?: AztecAddress[];
120
+ /** The accounts whose notes we can access in this call. */
121
+ scopes: AccessScopes;
107
122
  /** The job ID for staged writes. */
108
123
  jobId: string;
109
124
  };
@@ -296,7 +311,7 @@ export class ContractFunctionSimulator {
296
311
  call: FunctionCall,
297
312
  authwits: AuthWitness[],
298
313
  anchorBlockHeader: BlockHeader,
299
- scopes: AztecAddress[] | undefined,
314
+ scopes: AccessScopes,
300
315
  jobId: string,
301
316
  ): Promise<Fr[]> {
302
317
  const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
@@ -345,7 +360,7 @@ export class ContractFunctionSimulator {
345
360
  );
346
361
  });
347
362
 
348
- this.log.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
363
+ this.log.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
349
364
  return witnessMapToFields(acirExecutionResult.returnWitness);
350
365
  } catch (err) {
351
366
  throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
@@ -387,7 +402,8 @@ class OrderedSideEffect<T> {
387
402
  * (allowing state overrides) and is much faster, while still generating a valid
388
403
  * output that can be sent to the node for public simulation
389
404
  * @param privateExecutionResult - The result of the private execution.
390
- * @param contractStore - A provider for contract data in order to get function names and debug info.
405
+ * @param debugFunctionNameGetter - A provider for contract data in order to get function names and debug info.
406
+ * @param node - AztecNode for verifying settled read requests against the note hash and nullifier trees.
391
407
  * @param minRevertibleSideEffectCounterOverride - Optional override for the min revertible side effect counter.
392
408
  * Used by TXE to simulate account contract behavior (setting the counter before app execution).
393
409
  * @returns The simulated proving result.
@@ -395,16 +411,24 @@ class OrderedSideEffect<T> {
395
411
  export async function generateSimulatedProvingResult(
396
412
  privateExecutionResult: PrivateExecutionResult,
397
413
  debugFunctionNameGetter: (contractAddress: AztecAddress, functionSelector: FunctionSelector) => Promise<string>,
414
+ node: AztecNode,
398
415
  minRevertibleSideEffectCounterOverride?: number,
399
416
  ): Promise<PrivateKernelExecutionProofOutput<PrivateKernelTailCircuitPublicInputs>> {
400
- const siloedNoteHashes: OrderedSideEffect<Fr>[] = [];
401
- const nullifiers: OrderedSideEffect<Fr>[] = [];
402
- const taggedPrivateLogs: OrderedSideEffect<PrivateLog>[] = [];
417
+ const taggedPrivateLogs: OrderedSideEffect<PrivateLogData>[] = [];
403
418
  const l2ToL1Messages: OrderedSideEffect<ScopedL2ToL1Message>[] = [];
404
419
  const contractClassLogsHashes: OrderedSideEffect<ScopedLogHash>[] = [];
405
420
  const publicCallRequests: OrderedSideEffect<PublicCallRequest>[] = [];
406
421
  const executionSteps: PrivateExecutionStep[] = [];
407
422
 
423
+ // Unsiloed scoped arrays — used for squashing, read request verification,
424
+ // and siloed at the end only for the surviving items
425
+ const scopedNoteHashes: ScopedNoteHash[] = [];
426
+ const scopedNullifiers: ScopedNullifier[] = [];
427
+
428
+ // Read requests for verification
429
+ const noteHashReadRequests: ScopedReadRequest[] = [];
430
+ const nullifierReadRequests: ScopedReadRequest[] = [];
431
+
408
432
  let publicTeardownCallRequest;
409
433
 
410
434
  const executions = [privateExecutionResult.entrypoint];
@@ -415,38 +439,25 @@ export async function generateSimulatedProvingResult(
415
439
 
416
440
  const { contractAddress } = execution.publicInputs.callContext;
417
441
 
418
- const noteHashesFromExecution = await Promise.all(
419
- execution.publicInputs.noteHashes
420
- .getActiveItems()
421
- .filter(noteHash => !noteHash.isEmpty())
422
- .map(
423
- async noteHash =>
424
- new OrderedSideEffect(await siloNoteHash(contractAddress, noteHash.value), noteHash.counter),
425
- ),
426
- );
427
-
428
- const nullifiersFromExecution = await Promise.all(
429
- execution.publicInputs.nullifiers
442
+ scopedNoteHashes.push(
443
+ ...execution.publicInputs.noteHashes
430
444
  .getActiveItems()
431
- .map(
432
- async nullifier =>
433
- new OrderedSideEffect(await siloNullifier(contractAddress, nullifier.value), nullifier.counter),
434
- ),
445
+ .filter(nh => !nh.isEmpty())
446
+ .map(nh => nh.scope(contractAddress)),
435
447
  );
448
+ scopedNullifiers.push(...execution.publicInputs.nullifiers.getActiveItems().map(n => n.scope(contractAddress)));
436
449
 
437
- const privateLogsFromExecution = await Promise.all(
438
- execution.publicInputs.privateLogs.getActiveItems().map(async metadata => {
439
- metadata.log.fields[0] = await poseidon2HashWithSeparator(
440
- [contractAddress, metadata.log.fields[0]],
441
- GeneratorIndex.PRIVATE_LOG_FIRST_FIELD,
442
- );
443
- return new OrderedSideEffect(metadata.log, metadata.counter);
444
- }),
450
+ taggedPrivateLogs.push(
451
+ ...(await Promise.all(
452
+ execution.publicInputs.privateLogs.getActiveItems().map(async metadata => {
453
+ metadata.log.fields[0] = await computeSiloedPrivateLogFirstField(contractAddress, metadata.log.fields[0]);
454
+ return new OrderedSideEffect(metadata, metadata.counter);
455
+ }),
456
+ )),
445
457
  );
446
458
 
447
- siloedNoteHashes.push(...noteHashesFromExecution);
448
- taggedPrivateLogs.push(...privateLogsFromExecution);
449
- nullifiers.push(...nullifiersFromExecution);
459
+ noteHashReadRequests.push(...execution.publicInputs.noteHashReadRequests.getActiveItems());
460
+ nullifierReadRequests.push(...execution.publicInputs.nullifierReadRequests.getActiveItems());
450
461
  l2ToL1Messages.push(
451
462
  ...execution.publicInputs.l2ToL1Msgs
452
463
  .getActiveItems()
@@ -486,6 +497,47 @@ export async function generateSimulatedProvingResult(
486
497
  });
487
498
  }
488
499
 
500
+ const noteHashNullifierCounterMap = collectNoteHashNullifierCounterMap(privateExecutionResult);
501
+ const minRevertibleSideEffectCounter =
502
+ minRevertibleSideEffectCounterOverride ?? getFinalMinRevertibleSideEffectCounter(privateExecutionResult);
503
+
504
+ const scopedNoteHashesCLA = new ClaimedLengthArray<ScopedNoteHash, typeof MAX_NOTE_HASHES_PER_TX>(
505
+ padArrayEnd(scopedNoteHashes, ScopedNoteHash.empty(), MAX_NOTE_HASHES_PER_TX),
506
+ scopedNoteHashes.length,
507
+ );
508
+ const scopedNullifiersCLA = new ClaimedLengthArray<ScopedNullifier, typeof MAX_NULLIFIERS_PER_TX>(
509
+ padArrayEnd(scopedNullifiers, ScopedNullifier.empty(), MAX_NULLIFIERS_PER_TX),
510
+ scopedNullifiers.length,
511
+ );
512
+
513
+ const { filteredNoteHashes, filteredNullifiers, filteredPrivateLogs } = squashTransientSideEffects(
514
+ taggedPrivateLogs,
515
+ scopedNoteHashesCLA,
516
+ scopedNullifiersCLA,
517
+ noteHashNullifierCounterMap,
518
+ minRevertibleSideEffectCounter,
519
+ );
520
+
521
+ await verifyReadRequests(
522
+ node,
523
+ await privateExecutionResult.entrypoint.publicInputs.anchorBlockHeader.hash(),
524
+ noteHashReadRequests,
525
+ nullifierReadRequests,
526
+ scopedNoteHashesCLA,
527
+ scopedNullifiersCLA,
528
+ );
529
+
530
+ const siloedNoteHashes = await Promise.all(
531
+ filteredNoteHashes
532
+ .sort((a, b) => a.counter - b.counter)
533
+ .map(async nh => new OrderedSideEffect(await siloNoteHash(nh.contractAddress, nh.value), nh.counter)),
534
+ );
535
+ const siloedNullifiers = await Promise.all(
536
+ filteredNullifiers
537
+ .sort((a, b) => a.counter - b.counter)
538
+ .map(async n => new OrderedSideEffect(await siloNullifier(n.contractAddress, n.value), n.counter)),
539
+ );
540
+
489
541
  const constantData = new TxConstantData(
490
542
  privateExecutionResult.entrypoint.publicInputs.anchorBlockHeader,
491
543
  privateExecutionResult.entrypoint.publicInputs.txContext,
@@ -502,11 +554,9 @@ export async function generateSimulatedProvingResult(
502
554
  const getEffect = <T>(orderedSideEffect: OrderedSideEffect<T>) => orderedSideEffect.sideEffect;
503
555
 
504
556
  const isPrivateOnlyTx = privateExecutionResult.publicFunctionCalldata.length === 0;
505
- const minRevertibleSideEffectCounter =
506
- minRevertibleSideEffectCounterOverride ?? getFinalMinRevertibleSideEffectCounter(privateExecutionResult);
507
557
 
508
558
  const [nonRevertibleNullifiers, revertibleNullifiers] = splitOrderedSideEffects(
509
- nullifiers.sort(sortByCounter),
559
+ siloedNullifiers,
510
560
  minRevertibleSideEffectCounter,
511
561
  );
512
562
  const nonceGenerator = privateExecutionResult.firstNullifier;
@@ -520,7 +570,7 @@ export async function generateSimulatedProvingResult(
520
570
  // We must make the note hashes unique by using the
521
571
  // nonce generator and their index in the tx.
522
572
  const uniqueNoteHashes = await Promise.all(
523
- siloedNoteHashes.sort(sortByCounter).map(async (orderedSideEffect, i) => {
573
+ siloedNoteHashes.map(async (orderedSideEffect, i) => {
524
574
  const siloedNoteHash = orderedSideEffect.sideEffect;
525
575
  const nonce = await computeNoteHashNonce(nonceGenerator, i);
526
576
  const uniqueNoteHash = await computeUniqueNoteHash(nonce, siloedNoteHash);
@@ -535,18 +585,18 @@ export async function generateSimulatedProvingResult(
535
585
  ScopedL2ToL1Message.empty(),
536
586
  MAX_L2_TO_L1_MSGS_PER_TX,
537
587
  ),
538
- padArrayEnd(taggedPrivateLogs.sort(sortByCounter).map(getEffect), PrivateLog.empty(), MAX_PRIVATE_LOGS_PER_TX),
588
+ padArrayEnd(filteredPrivateLogs.sort(sortByCounter).map(getEffect), PrivateLog.empty(), MAX_PRIVATE_LOGS_PER_TX),
539
589
  padArrayEnd(
540
590
  contractClassLogsHashes.sort(sortByCounter).map(getEffect),
541
591
  ScopedLogHash.empty(),
542
592
  MAX_CONTRACT_CLASS_LOGS_PER_TX,
543
593
  ),
544
594
  );
545
- gasUsed = meterGasUsed(accumulatedDataForRollup);
595
+ gasUsed = meterGasUsed(accumulatedDataForRollup, isPrivateOnlyTx);
546
596
  inputsForRollup = new PartialPrivateTailPublicInputsForRollup(accumulatedDataForRollup);
547
597
  } else {
548
598
  const [nonRevertibleNoteHashes, revertibleNoteHashes] = splitOrderedSideEffects(
549
- siloedNoteHashes.sort(sortByCounter),
599
+ siloedNoteHashes,
550
600
  minRevertibleSideEffectCounter,
551
601
  );
552
602
  const nonRevertibleUniqueNoteHashes = await Promise.all(
@@ -560,7 +610,7 @@ export async function generateSimulatedProvingResult(
560
610
  minRevertibleSideEffectCounter,
561
611
  );
562
612
  const [nonRevertibleTaggedPrivateLogs, revertibleTaggedPrivateLogs] = splitOrderedSideEffects(
563
- taggedPrivateLogs,
613
+ filteredPrivateLogs,
564
614
  minRevertibleSideEffectCounter,
565
615
  );
566
616
  const [nonRevertibleContractClassLogHashes, revertibleContractClassLogHashes] = splitOrderedSideEffects(
@@ -589,9 +639,9 @@ export async function generateSimulatedProvingResult(
589
639
  padArrayEnd(revertibleContractClassLogHashes, ScopedLogHash.empty(), MAX_CONTRACT_CLASS_LOGS_PER_TX),
590
640
  padArrayEnd(revertiblePublicCallRequests, PublicCallRequest.empty(), MAX_ENQUEUED_CALLS_PER_TX),
591
641
  );
592
- gasUsed = meterGasUsed(revertibleData).add(meterGasUsed(nonRevertibleData));
642
+ gasUsed = meterGasUsed(revertibleData, isPrivateOnlyTx).add(meterGasUsed(nonRevertibleData, isPrivateOnlyTx));
593
643
  if (publicTeardownCallRequest) {
594
- gasUsed.add(privateExecutionResult.entrypoint.publicInputs.txContext.gasSettings.teardownGasLimits);
644
+ gasUsed = gasUsed.add(privateExecutionResult.entrypoint.publicInputs.txContext.gasSettings.teardownGasLimits);
595
645
  }
596
646
 
597
647
  inputsForPublic = new PartialPrivateTailPublicInputsForPublic(
@@ -605,7 +655,7 @@ export async function generateSimulatedProvingResult(
605
655
  constantData,
606
656
  /*gasUsed=*/ gasUsed.add(Gas.from({ l2Gas: FIXED_L2_GAS, daGas: FIXED_DA_GAS })),
607
657
  /*feePayer=*/ AztecAddress.zero(),
608
- /*includeByTimestamp=*/ 0n,
658
+ /*expirationTimestamp=*/ 0n,
609
659
  hasPublicCalls ? inputsForPublic : undefined,
610
660
  !hasPublicCalls ? inputsForRollup : undefined,
611
661
  );
@@ -617,6 +667,111 @@ export async function generateSimulatedProvingResult(
617
667
  };
618
668
  }
619
669
 
670
+ /**
671
+ * Squashes transient note hashes and nullifiers, mimicking the behavior
672
+ * of the reset kernels. Returns the filtered (surviving) scoped items and private logs.
673
+ */
674
+ function squashTransientSideEffects(
675
+ taggedPrivateLogs: OrderedSideEffect<PrivateLogData>[],
676
+ scopedNoteHashesCLA: ClaimedLengthArray<ScopedNoteHash, typeof MAX_NOTE_HASHES_PER_TX>,
677
+ scopedNullifiersCLA: ClaimedLengthArray<ScopedNullifier, typeof MAX_NULLIFIERS_PER_TX>,
678
+ noteHashNullifierCounterMap: Map<number, number>,
679
+ minRevertibleSideEffectCounter: number,
680
+ ) {
681
+ const { numTransientData, hints: transientDataHints } = buildTransientDataHints(
682
+ scopedNoteHashesCLA,
683
+ scopedNullifiersCLA,
684
+ /*futureNoteHashReads=*/ [],
685
+ /*futureNullifierReads=*/ [],
686
+ noteHashNullifierCounterMap,
687
+ minRevertibleSideEffectCounter,
688
+ );
689
+
690
+ const squashedNoteHashCounters = new Set<number>();
691
+ const squashedNullifierCounters = new Set<number>();
692
+ for (let i = 0; i < numTransientData; i++) {
693
+ const hint = transientDataHints[i];
694
+ squashedNoteHashCounters.add(scopedNoteHashesCLA.array[hint.noteHashIndex].counter);
695
+ squashedNullifierCounters.add(scopedNullifiersCLA.array[hint.nullifierIndex].counter);
696
+ }
697
+
698
+ return {
699
+ filteredNoteHashes: scopedNoteHashesCLA.getActiveItems().filter(nh => !squashedNoteHashCounters.has(nh.counter)),
700
+ filteredNullifiers: scopedNullifiersCLA.getActiveItems().filter(n => !squashedNullifierCounters.has(n.counter)),
701
+ filteredPrivateLogs: taggedPrivateLogs
702
+ .filter(item => !squashedNoteHashCounters.has(item.sideEffect.noteHashCounter))
703
+ .map(item => new OrderedSideEffect(item.sideEffect.log, item.counter)),
704
+ };
705
+ }
706
+
707
+ /**
708
+ * Verifies settled read requests by checking membership in the note hash and nullifier trees
709
+ * at the tx's anchor block, mimicking the behavior of the kernels
710
+ */
711
+ async function verifyReadRequests(
712
+ node: Pick<AztecNode, 'getNoteHashMembershipWitness' | 'getNullifierMembershipWitness'>,
713
+ anchorBlockHash: BlockParameter,
714
+ noteHashReadRequests: ScopedReadRequest[],
715
+ nullifierReadRequests: ScopedReadRequest[],
716
+ scopedNoteHashesCLA: ClaimedLengthArray<ScopedNoteHash, typeof MAX_NOTE_HASHES_PER_TX>,
717
+ scopedNullifiersCLA: ClaimedLengthArray<ScopedNullifier, typeof MAX_NULLIFIERS_PER_TX>,
718
+ ) {
719
+ const noteHashReadRequestsCLA = new ClaimedLengthArray<ScopedReadRequest, typeof MAX_NOTE_HASH_READ_REQUESTS_PER_TX>(
720
+ padArrayEnd(noteHashReadRequests, ScopedReadRequest.empty(), MAX_NOTE_HASH_READ_REQUESTS_PER_TX),
721
+ noteHashReadRequests.length,
722
+ );
723
+ const nullifierReadRequestsCLA = new ClaimedLengthArray<ScopedReadRequest, typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX>(
724
+ padArrayEnd(nullifierReadRequests, ScopedReadRequest.empty(), MAX_NULLIFIER_READ_REQUESTS_PER_TX),
725
+ nullifierReadRequests.length,
726
+ );
727
+
728
+ const noteHashResetActions = getNoteHashReadRequestResetActions(
729
+ noteHashReadRequestsCLA,
730
+ scopedNoteHashesCLA,
731
+ /*futureNoteHashes=*/ [],
732
+ );
733
+ const nullifierResetActions = getNullifierReadRequestResetActions(
734
+ nullifierReadRequestsCLA,
735
+ scopedNullifiersCLA,
736
+ /*futureNullifiers=*/ [],
737
+ );
738
+
739
+ const settledNoteHashReads: { index: number; value: Fr }[] = [];
740
+ for (let i = 0; i < noteHashResetActions.actions.length; i++) {
741
+ if (noteHashResetActions.actions[i] === ReadRequestActionEnum.READ_AS_SETTLED) {
742
+ settledNoteHashReads.push({ index: i, value: noteHashReadRequests[i].value });
743
+ }
744
+ }
745
+
746
+ const settledNullifierReads: { index: number; value: Fr }[] = [];
747
+ for (let i = 0; i < nullifierResetActions.actions.length; i++) {
748
+ if (nullifierResetActions.actions[i] === ReadRequestActionEnum.READ_AS_SETTLED) {
749
+ settledNullifierReads.push({ index: i, value: nullifierReadRequests[i].value });
750
+ }
751
+ }
752
+
753
+ const [noteHashWitnesses, nullifierWitnesses] = await Promise.all([
754
+ Promise.all(settledNoteHashReads.map(({ value }) => node.getNoteHashMembershipWitness(anchorBlockHash, value))),
755
+ Promise.all(settledNullifierReads.map(({ value }) => node.getNullifierMembershipWitness(anchorBlockHash, value))),
756
+ ]);
757
+
758
+ for (let i = 0; i < settledNoteHashReads.length; i++) {
759
+ if (!noteHashWitnesses[i]) {
760
+ throw new Error(
761
+ `Note hash read request at index ${settledNoteHashReads[i].index} is reading an unknown note hash: ${settledNoteHashReads[i].value}`,
762
+ );
763
+ }
764
+ }
765
+
766
+ for (let i = 0; i < settledNullifierReads.length; i++) {
767
+ if (!nullifierWitnesses[i]) {
768
+ throw new Error(
769
+ `Nullifier read request at index ${settledNullifierReads[i].index} is reading an unknown nullifier: ${settledNullifierReads[i].value}`,
770
+ );
771
+ }
772
+ }
773
+ }
774
+
620
775
  function splitOrderedSideEffects<T>(effects: OrderedSideEffect<T>[], minRevertibleSideEffectCounter: number) {
621
776
  const revertibleSideEffects: T[] = [];
622
777
  const nonRevertibleSideEffects: T[] = [];
@@ -630,21 +785,24 @@ function splitOrderedSideEffects<T>(effects: OrderedSideEffect<T>[], minRevertib
630
785
  return [nonRevertibleSideEffects, revertibleSideEffects];
631
786
  }
632
787
 
633
- function meterGasUsed(data: PrivateToRollupAccumulatedData | PrivateToPublicAccumulatedData) {
788
+ function meterGasUsed(data: PrivateToRollupAccumulatedData | PrivateToPublicAccumulatedData, isPrivateOnlyTx: boolean) {
634
789
  let meteredDAFields = 0;
635
790
  let meteredL2Gas = 0;
636
791
 
637
792
  const numNoteHashes = arrayNonEmptyLength(data.noteHashes, hash => hash.isEmpty());
638
793
  meteredDAFields += numNoteHashes;
639
- meteredL2Gas += numNoteHashes * AVM_EMITNOTEHASH_BASE_L2_GAS;
794
+ const noteHashBaseGas = isPrivateOnlyTx ? L2_GAS_PER_NOTE_HASH : AVM_EMITNOTEHASH_BASE_L2_GAS;
795
+ meteredL2Gas += numNoteHashes * noteHashBaseGas;
640
796
 
641
797
  const numNullifiers = arrayNonEmptyLength(data.nullifiers, nullifier => nullifier.isEmpty());
642
798
  meteredDAFields += numNullifiers;
643
- meteredL2Gas += numNullifiers * AVM_EMITNULLIFIER_BASE_L2_GAS;
799
+ const nullifierBaseGas = isPrivateOnlyTx ? L2_GAS_PER_NULLIFIER : AVM_EMITNULLIFIER_BASE_L2_GAS;
800
+ meteredL2Gas += numNullifiers * nullifierBaseGas;
644
801
 
645
802
  const numL2toL1Messages = arrayNonEmptyLength(data.l2ToL1Msgs, msg => msg.isEmpty());
646
803
  meteredDAFields += numL2toL1Messages;
647
- meteredL2Gas += numL2toL1Messages * AVM_SENDL2TOL1MSG_BASE_L2_GAS;
804
+ const l2ToL1MessageBaseGas = isPrivateOnlyTx ? L2_GAS_PER_L2_TO_L1_MSG : AVM_SENDL2TOL1MSG_BASE_L2_GAS;
805
+ meteredL2Gas += numL2toL1Messages * l2ToL1MessageBaseGas;
648
806
 
649
807
  const numPrivatelogs = arrayNonEmptyLength(data.privateLogs, log => log.isEmpty());
650
808
  // Every private log emits its length as an additional field
@@ -659,7 +817,7 @@ function meterGasUsed(data: PrivateToRollupAccumulatedData | PrivateToPublicAccu
659
817
  );
660
818
  meteredL2Gas += numContractClassLogs * L2_GAS_PER_CONTRACT_CLASS_LOG;
661
819
 
662
- const meteredDAGas = meteredDAFields * DA_BYTES_PER_FIELD * DA_GAS_PER_BYTE;
820
+ const meteredDAGas = meteredDAFields * DA_GAS_PER_FIELD;
663
821
 
664
822
  if ((data as PrivateToPublicAccumulatedData).publicCallRequests) {
665
823
  const dataForPublic = data as PrivateToPublicAccumulatedData;
@@ -5,7 +5,7 @@ import { AztecAddress } from '@aztec/stdlib/aztec-address';
5
5
  import { TxHash } from '@aztec/stdlib/tx';
6
6
 
7
7
  // TODO(#14617): should we compute this from constants? This value is aztec-nr specific.
8
- const MAX_EVENT_SERIALIZED_LEN = 12;
8
+ const MAX_EVENT_SERIALIZED_LEN = 11;
9
9
 
10
10
  /**
11
11
  * Intermediate struct used to perform batch event validation by PXE. The `utilityValidateAndStoreEnqueuedNotesAndEvents` oracle
@@ -4,7 +4,7 @@ import { AztecAddress } from '@aztec/stdlib/aztec-address';
4
4
  import { TxHash } from '@aztec/stdlib/tx';
5
5
 
6
6
  // TODO(#14617): should we compute this from constants? This value is aztec-nr specific.
7
- export const MAX_NOTE_PACKED_LEN = 10;
7
+ export const MAX_NOTE_PACKED_LEN = 9;
8
8
 
9
9
  /**
10
10
  * Intermediate struct used to perform batch note validation by PXE. The `utilityValidateAndStoreEnqueuedNotesAndEvents` oracle
@@ -25,6 +25,7 @@ import {
25
25
  type TxContext,
26
26
  } from '@aztec/stdlib/tx';
27
27
 
28
+ import type { AccessScopes } from '../../access_scopes.js';
28
29
  import type { ContractSyncService } from '../../contract_sync/contract_sync_service.js';
29
30
  import { NoteService } from '../../notes/note_service.js';
30
31
  import type { SenderTaggingStore } from '../../storage/tagging_store/sender_tagging_store.js';
@@ -43,7 +44,7 @@ export type PrivateExecutionOracleArgs = Omit<UtilityExecutionOracleArgs, 'contr
43
44
  txContext: TxContext;
44
45
  callContext: CallContext;
45
46
  /** Needed to trigger contract synchronization before nested calls */
46
- utilityExecutor: (call: FunctionCall, scopes: undefined | AztecAddress[]) => Promise<void>;
47
+ utilityExecutor: (call: FunctionCall, scopes: AccessScopes) => Promise<void>;
47
48
  executionCache: HashedValuesCache;
48
49
  noteCache: ExecutionNoteCache;
49
50
  taggingIndexCache: ExecutionTaggingIndexCache;
@@ -78,7 +79,7 @@ export class PrivateExecutionOracle extends UtilityExecutionOracle implements IP
78
79
  private readonly argsHash: Fr;
79
80
  private readonly txContext: TxContext;
80
81
  private readonly callContext: CallContext;
81
- private readonly utilityExecutor: (call: FunctionCall, scopes: undefined | AztecAddress[]) => Promise<void>;
82
+ private readonly utilityExecutor: (call: FunctionCall, scopes: AccessScopes) => Promise<void>;
82
83
  private readonly executionCache: HashedValuesCache;
83
84
  private readonly noteCache: ExecutionNoteCache;
84
85
  private readonly taggingIndexCache: ExecutionTaggingIndexCache;
@@ -531,7 +532,7 @@ export class PrivateExecutionOracle extends UtilityExecutionOracle implements IP
531
532
  // We only expand for registered accounts because the log service needs the recipient's keys to derive
532
533
  // tagging secrets, which are only available for registered accounts.
533
534
  const expandedScopes =
534
- this.scopes && (await this.keyStore.hasAccount(targetContractAddress))
535
+ this.scopes !== 'ALL_SCOPES' && (await this.keyStore.hasAccount(targetContractAddress))
535
536
  ? [...this.scopes, targetContractAddress]
536
537
  : this.scopes;
537
538
 
@@ -20,6 +20,7 @@ import type { NoteStatus } from '@aztec/stdlib/note';
20
20
  import { MerkleTreeId, type NullifierMembershipWitness, PublicDataWitness } from '@aztec/stdlib/trees';
21
21
  import type { BlockHeader, Capsule } from '@aztec/stdlib/tx';
22
22
 
23
+ import type { AccessScopes } from '../../access_scopes.js';
23
24
  import { EventService } from '../../events/event_service.js';
24
25
  import { LogService } from '../../logs/log_service.js';
25
26
  import { NoteService } from '../../notes/note_service.js';
@@ -58,7 +59,7 @@ export type UtilityExecutionOracleArgs = {
58
59
  privateEventStore: PrivateEventStore;
59
60
  jobId: string;
60
61
  log?: ReturnType<typeof createLogger>;
61
- scopes?: AztecAddress[];
62
+ scopes: AccessScopes;
62
63
  };
63
64
 
64
65
  /**
@@ -85,7 +86,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
85
86
  protected readonly privateEventStore: PrivateEventStore;
86
87
  protected readonly jobId: string;
87
88
  protected log: ReturnType<typeof createLogger>;
88
- protected readonly scopes?: AztecAddress[];
89
+ protected readonly scopes: AccessScopes;
89
90
 
90
91
  constructor(args: UtilityExecutionOracleArgs) {
91
92
  this.contractAddress = args.contractAddress;
@@ -129,7 +130,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
129
130
  */
130
131
  public async utilityGetKeyValidationRequest(pkMHash: Fr): Promise<KeyValidationRequest> {
131
132
  // If scopes are defined, check that the key belongs to an account in the scopes.
132
- if (this.scopes && this.scopes.length > 0) {
133
+ if (this.scopes !== 'ALL_SCOPES' && this.scopes.length > 0) {
133
134
  let hasAccess = false;
134
135
  for (let i = 0; i < this.scopes.length && !hasAccess; i++) {
135
136
  if (await this.keyStore.accountHasKey(this.scopes[i], pkMHash)) {
@@ -4,6 +4,7 @@ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
4
4
  import type { AztecNode } from '@aztec/stdlib/interfaces/client';
5
5
  import type { BlockHeader } from '@aztec/stdlib/tx';
6
6
 
7
+ import type { AccessScopes } from '../access_scopes.js';
7
8
  import type { StagedStore } from '../job_coordinator/job_coordinator.js';
8
9
  import type { ContractStore } from '../storage/contract_store/contract_store.js';
9
10
  import type { NoteStore } from '../storage/note_store/note_store.js';
@@ -45,15 +46,15 @@ export class ContractSyncService implements StagedStore {
45
46
  * @param functionToInvokeAfterSync - The function selector that will be called after sync (used to validate it's
46
47
  * not sync_state itself).
47
48
  * @param utilityExecutor - Executor function for running the sync_state utility function.
48
- * @param scopes - Scopes to pass through to the utility executor (affects which notes are discovered).
49
+ * @param scopes - Access scopes to pass through to the utility executor (affects whose account's private state is discovered).
49
50
  */
50
51
  async ensureContractSynced(
51
52
  contractAddress: AztecAddress,
52
53
  functionToInvokeAfterSync: FunctionSelector | null,
53
- utilityExecutor: (call: FunctionCall, scopes: undefined | AztecAddress[]) => Promise<any>,
54
+ utilityExecutor: (call: FunctionCall, scopes: AccessScopes) => Promise<any>,
54
55
  anchorBlockHeader: BlockHeader,
55
56
  jobId: string,
56
- scopes: undefined | AztecAddress[],
57
+ scopes: AccessScopes,
57
58
  ): Promise<void> {
58
59
  // Skip sync if this contract has an override for this job (overrides are keyed by contract address only)
59
60
  const overrides = this.overriddenContracts.get(jobId);
@@ -62,13 +63,16 @@ export class ContractSyncService implements StagedStore {
62
63
  }
63
64
 
64
65
  // Skip sync if we already synced for "all scopes", or if we have an empty list of scopes
65
- const allScopesKey = toKey(contractAddress, undefined);
66
+ const allScopesKey = toKey(contractAddress, 'ALL_SCOPES');
66
67
  const allScopesExisting = this.syncedContracts.get(allScopesKey);
67
- if (allScopesExisting || (scopes && scopes.length == 0)) {
68
+ if (allScopesExisting || (scopes !== 'ALL_SCOPES' && scopes.length == 0)) {
68
69
  return;
69
70
  }
70
71
 
71
- const unsyncedScopes = scopes?.filter(scope => !this.syncedContracts.has(toKey(contractAddress, scope)));
72
+ const unsyncedScopes =
73
+ scopes === 'ALL_SCOPES'
74
+ ? scopes
75
+ : scopes.filter(scope => !this.syncedContracts.has(toKey(contractAddress, scope)));
72
76
  const unsyncedScopesKeys = toKeys(contractAddress, unsyncedScopes);
73
77
 
74
78
  if (unsyncedScopesKeys.length > 0) {
@@ -76,9 +80,10 @@ export class ContractSyncService implements StagedStore {
76
80
  const promise = this.#doSync(
77
81
  contractAddress,
78
82
  functionToInvokeAfterSync,
79
- call => utilityExecutor(call, unsyncedScopes),
83
+ utilityExecutor,
80
84
  anchorBlockHeader,
81
85
  jobId,
86
+ unsyncedScopes,
82
87
  ).catch(err => {
83
88
  // There was an error syncing the contract, so we remove it from the cache so that it can be retried.
84
89
  unsyncedScopesKeys.forEach(key => this.syncedContracts.delete(key));
@@ -94,9 +99,10 @@ export class ContractSyncService implements StagedStore {
94
99
  async #doSync(
95
100
  contractAddress: AztecAddress,
96
101
  functionToInvokeAfterSync: FunctionSelector | null,
97
- utilityExecutor: (call: FunctionCall) => Promise<any>,
102
+ utilityExecutor: (call: FunctionCall, scopes: AccessScopes) => Promise<any>,
98
103
  anchorBlockHeader: BlockHeader,
99
104
  jobId: string,
105
+ scopes: AccessScopes,
100
106
  ): Promise<void> {
101
107
  this.log.debug(`Syncing contract ${contractAddress}`);
102
108
  await Promise.all([
@@ -109,6 +115,7 @@ export class ContractSyncService implements StagedStore {
109
115
  this.aztecNode,
110
116
  anchorBlockHeader,
111
117
  jobId,
118
+ scopes,
112
119
  ),
113
120
  verifyCurrentClassId(contractAddress, this.aztecNode, this.contractStore, anchorBlockHeader),
114
121
  ]);
@@ -136,10 +143,10 @@ export class ContractSyncService implements StagedStore {
136
143
  }
137
144
  }
138
145
 
139
- function toKeys(contract: AztecAddress, scopes: undefined | AztecAddress[]) {
140
- return scopes === undefined ? [toKey(contract, undefined)] : scopes.map(scope => toKey(contract, scope));
146
+ function toKeys(contract: AztecAddress, scopes: AccessScopes) {
147
+ return scopes === 'ALL_SCOPES' ? [toKey(contract, scopes)] : scopes.map(scope => toKey(contract, scope));
141
148
  }
142
149
 
143
- function toKey(contract: AztecAddress, scope: AztecAddress | undefined) {
144
- return scope === undefined ? `${contract.toString()}:*` : `${contract.toString()}:${scope.toString()}`;
150
+ function toKey(contract: AztecAddress, scope: AztecAddress | 'ALL_SCOPES') {
151
+ return scope === 'ALL_SCOPES' ? `${contract.toString()}:*` : `${contract.toString()}:${scope.toString()}`;
145
152
  }