@aztec/pxe 4.0.0-devnet.1-patch.1 → 4.0.0-devnet.2-patch.0

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 (98) 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/contract_function_simulator/contract_function_simulator.d.ts +5 -4
  5. package/dest/contract_function_simulator/contract_function_simulator.d.ts.map +1 -1
  6. package/dest/contract_function_simulator/contract_function_simulator.js +7 -11
  7. package/dest/contract_function_simulator/noir-structs/event_validation_request.js +1 -1
  8. package/dest/contract_function_simulator/noir-structs/note_validation_request.d.ts +2 -2
  9. package/dest/contract_function_simulator/noir-structs/note_validation_request.d.ts.map +1 -1
  10. package/dest/contract_function_simulator/noir-structs/note_validation_request.js +1 -1
  11. package/dest/contract_function_simulator/oracle/interfaces.d.ts +2 -2
  12. package/dest/contract_function_simulator/oracle/interfaces.d.ts.map +1 -1
  13. package/dest/contract_function_simulator/oracle/oracle.d.ts +2 -2
  14. package/dest/contract_function_simulator/oracle/oracle.d.ts.map +1 -1
  15. package/dest/contract_function_simulator/oracle/oracle.js +2 -2
  16. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +3 -2
  17. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts.map +1 -1
  18. package/dest/contract_function_simulator/oracle/private_execution_oracle.js +10 -2
  19. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +5 -4
  20. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
  21. package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +12 -7
  22. package/dest/contract_sync/contract_sync_service.d.ts +4 -2
  23. package/dest/contract_sync/contract_sync_service.d.ts.map +1 -1
  24. package/dest/contract_sync/contract_sync_service.js +34 -19
  25. package/dest/contract_sync/helpers.d.ts +3 -2
  26. package/dest/contract_sync/helpers.d.ts.map +1 -1
  27. package/dest/contract_sync/helpers.js +3 -3
  28. package/dest/debug/pxe_debug_utils.d.ts +5 -4
  29. package/dest/debug/pxe_debug_utils.d.ts.map +1 -1
  30. package/dest/debug/pxe_debug_utils.js +1 -1
  31. package/dest/entrypoints/client/bundle/index.d.ts +3 -1
  32. package/dest/entrypoints/client/bundle/index.d.ts.map +1 -1
  33. package/dest/entrypoints/client/bundle/index.js +2 -0
  34. package/dest/entrypoints/client/lazy/index.d.ts +3 -1
  35. package/dest/entrypoints/client/lazy/index.d.ts.map +1 -1
  36. package/dest/entrypoints/client/lazy/index.js +2 -0
  37. package/dest/entrypoints/server/index.d.ts +3 -1
  38. package/dest/entrypoints/server/index.d.ts.map +1 -1
  39. package/dest/entrypoints/server/index.js +2 -0
  40. package/dest/logs/log_service.d.ts +3 -2
  41. package/dest/logs/log_service.d.ts.map +1 -1
  42. package/dest/logs/log_service.js +5 -10
  43. package/dest/notes/note_service.d.ts +4 -3
  44. package/dest/notes/note_service.d.ts.map +1 -1
  45. package/dest/notes/note_service.js +3 -2
  46. package/dest/notes_filter.d.ts +25 -0
  47. package/dest/notes_filter.d.ts.map +1 -0
  48. package/dest/notes_filter.js +4 -0
  49. package/dest/oracle_version.d.ts +2 -2
  50. package/dest/oracle_version.js +2 -2
  51. package/dest/private_kernel/hints/compute_tx_expiration_timestamp.d.ts +4 -0
  52. package/dest/private_kernel/hints/compute_tx_expiration_timestamp.d.ts.map +1 -0
  53. package/dest/private_kernel/hints/{compute_tx_include_by_timestamp.js → compute_tx_expiration_timestamp.js} +12 -12
  54. package/dest/private_kernel/hints/index.d.ts +1 -1
  55. package/dest/private_kernel/hints/index.js +1 -1
  56. package/dest/private_kernel/hints/private_kernel_reset_private_inputs_builder.js +4 -4
  57. package/dest/private_kernel/private_kernel_execution_prover.js +6 -6
  58. package/dest/pxe.d.ts +11 -7
  59. package/dest/pxe.d.ts.map +1 -1
  60. package/dest/pxe.js +13 -10
  61. package/dest/storage/note_store/note_store.d.ts +3 -3
  62. package/dest/storage/note_store/note_store.d.ts.map +1 -1
  63. package/dest/storage/note_store/note_store.js +3 -4
  64. package/dest/tagging/get_all_logs_by_tags.d.ts +1 -1
  65. package/dest/tagging/get_all_logs_by_tags.d.ts.map +1 -1
  66. package/dest/tagging/get_all_logs_by_tags.js +17 -3
  67. package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.js +4 -4
  68. package/dest/tagging/recipient_sync/utils/find_highest_indexes.js +2 -2
  69. package/package.json +16 -16
  70. package/src/access_scopes.ts +9 -0
  71. package/src/contract_function_simulator/contract_function_simulator.ts +11 -15
  72. package/src/contract_function_simulator/noir-structs/event_validation_request.ts +1 -1
  73. package/src/contract_function_simulator/noir-structs/note_validation_request.ts +1 -1
  74. package/src/contract_function_simulator/oracle/interfaces.ts +1 -1
  75. package/src/contract_function_simulator/oracle/oracle.ts +2 -2
  76. package/src/contract_function_simulator/oracle/private_execution_oracle.ts +14 -3
  77. package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +15 -9
  78. package/src/contract_sync/contract_sync_service.ts +49 -26
  79. package/src/contract_sync/helpers.ts +7 -2
  80. package/src/debug/pxe_debug_utils.ts +8 -6
  81. package/src/entrypoints/client/bundle/index.ts +2 -0
  82. package/src/entrypoints/client/lazy/index.ts +2 -0
  83. package/src/entrypoints/server/index.ts +2 -0
  84. package/src/logs/log_service.ts +7 -19
  85. package/src/notes/note_service.ts +4 -3
  86. package/src/notes_filter.ts +26 -0
  87. package/src/oracle_version.ts +2 -2
  88. package/src/private_kernel/hints/{compute_tx_include_by_timestamp.ts → compute_tx_expiration_timestamp.ts} +13 -13
  89. package/src/private_kernel/hints/index.ts +1 -1
  90. package/src/private_kernel/hints/private_kernel_reset_private_inputs_builder.ts +7 -7
  91. package/src/private_kernel/private_kernel_execution_prover.ts +6 -6
  92. package/src/pxe.ts +26 -22
  93. package/src/storage/note_store/note_store.ts +8 -5
  94. package/src/tagging/get_all_logs_by_tags.ts +28 -4
  95. package/src/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.ts +4 -4
  96. package/src/tagging/recipient_sync/utils/find_highest_indexes.ts +2 -2
  97. package/dest/private_kernel/hints/compute_tx_include_by_timestamp.d.ts +0 -4
  98. package/dest/private_kernel/hints/compute_tx_include_by_timestamp.d.ts.map +0 -1
@@ -2,12 +2,10 @@ 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,
12
10
  L2_GAS_PER_L2_TO_L1_MSG,
13
11
  L2_GAS_PER_NOTE_HASH,
@@ -23,7 +21,6 @@ import {
23
21
  MAX_PRIVATE_LOGS_PER_TX,
24
22
  } from '@aztec/constants';
25
23
  import { arrayNonEmptyLength, padArrayEnd } from '@aztec/foundation/collection';
26
- import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto/poseidon';
27
24
  import { Fr } from '@aztec/foundation/curves/bn254';
28
25
  import { type Logger, createLogger } from '@aztec/foundation/log';
29
26
  import { Timer } from '@aztec/foundation/timer';
@@ -48,6 +45,7 @@ import { Gas } from '@aztec/stdlib/gas';
48
45
  import {
49
46
  computeNoteHashNonce,
50
47
  computeProtocolNullifier,
48
+ computeSiloedPrivateLogFirstField,
51
49
  computeUniqueNoteHash,
52
50
  siloNoteHash,
53
51
  siloNullifier,
@@ -88,6 +86,7 @@ import {
88
86
  getFinalMinRevertibleSideEffectCounter,
89
87
  } from '@aztec/stdlib/tx';
90
88
 
89
+ import type { AccessScopes } from '../access_scopes.js';
91
90
  import type { ContractSyncService } from '../contract_sync/contract_sync_service.js';
92
91
  import type { AddressStore } from '../storage/address_store/address_store.js';
93
92
  import type { CapsuleStore } from '../storage/capsule_store/capsule_store.js';
@@ -118,8 +117,8 @@ export type ContractSimulatorRunOpts = {
118
117
  anchorBlockHeader: BlockHeader;
119
118
  /** The address used as a tagging sender when emitting private logs. */
120
119
  senderForTags?: AztecAddress;
121
- /** The accounts whose notes we can access in this call. Defaults to all. */
122
- scopes?: AztecAddress[];
120
+ /** The accounts whose notes we can access in this call. */
121
+ scopes: AccessScopes;
123
122
  /** The job ID for staged writes. */
124
123
  jobId: string;
125
124
  };
@@ -223,8 +222,8 @@ export class ContractFunctionSimulator {
223
222
  txContext: request.txContext,
224
223
  callContext,
225
224
  anchorBlockHeader,
226
- utilityExecutor: async call => {
227
- await this.runUtility(call, [], anchorBlockHeader, scopes, jobId);
225
+ utilityExecutor: async (call, execScopes) => {
226
+ await this.runUtility(call, [], anchorBlockHeader, execScopes, jobId);
228
227
  },
229
228
  authWitnesses: request.authWitnesses,
230
229
  capsules: request.capsules,
@@ -312,7 +311,7 @@ export class ContractFunctionSimulator {
312
311
  call: FunctionCall,
313
312
  authwits: AuthWitness[],
314
313
  anchorBlockHeader: BlockHeader,
315
- scopes: AztecAddress[] | undefined,
314
+ scopes: AccessScopes,
316
315
  jobId: string,
317
316
  ): Promise<Fr[]> {
318
317
  const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
@@ -451,10 +450,7 @@ export async function generateSimulatedProvingResult(
451
450
  taggedPrivateLogs.push(
452
451
  ...(await Promise.all(
453
452
  execution.publicInputs.privateLogs.getActiveItems().map(async metadata => {
454
- metadata.log.fields[0] = await poseidon2HashWithSeparator(
455
- [contractAddress, metadata.log.fields[0]],
456
- GeneratorIndex.PRIVATE_LOG_FIRST_FIELD,
457
- );
453
+ metadata.log.fields[0] = await computeSiloedPrivateLogFirstField(contractAddress, metadata.log.fields[0]);
458
454
  return new OrderedSideEffect(metadata, metadata.counter);
459
455
  }),
460
456
  )),
@@ -659,7 +655,7 @@ export async function generateSimulatedProvingResult(
659
655
  constantData,
660
656
  /*gasUsed=*/ gasUsed.add(Gas.from({ l2Gas: FIXED_L2_GAS, daGas: FIXED_DA_GAS })),
661
657
  /*feePayer=*/ AztecAddress.zero(),
662
- /*includeByTimestamp=*/ 0n,
658
+ /*expirationTimestamp=*/ 0n,
663
659
  hasPublicCalls ? inputsForPublic : undefined,
664
660
  !hasPublicCalls ? inputsForRollup : undefined,
665
661
  );
@@ -821,7 +817,7 @@ function meterGasUsed(data: PrivateToRollupAccumulatedData | PrivateToPublicAccu
821
817
  );
822
818
  meteredL2Gas += numContractClassLogs * L2_GAS_PER_CONTRACT_CLASS_LOG;
823
819
 
824
- const meteredDAGas = meteredDAFields * DA_BYTES_PER_FIELD * DA_GAS_PER_BYTE;
820
+ const meteredDAGas = meteredDAFields * DA_GAS_PER_FIELD;
825
821
 
826
822
  if ((data as PrivateToPublicAccumulatedData).publicCallRequests) {
827
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
@@ -54,7 +54,7 @@ export interface IMiscOracle {
54
54
 
55
55
  utilityGetRandomField(): Fr;
56
56
  utilityAssertCompatibleOracleVersion(version: number): void;
57
- utilityDebugLog(level: number, message: string, fields: Fr[]): Promise<void>;
57
+ utilityLog(level: number, message: string, fields: Fr[]): Promise<void>;
58
58
  }
59
59
 
60
60
  /**
@@ -417,7 +417,7 @@ export class Oracle {
417
417
  return Promise.resolve([]);
418
418
  }
419
419
 
420
- async utilityDebugLog(
420
+ async utilityLog(
421
421
  level: ACVMField[],
422
422
  message: ACVMField[],
423
423
  _ignoredFieldsSize: ACVMField[],
@@ -426,7 +426,7 @@ export class Oracle {
426
426
  const levelFr = Fr.fromString(level[0]);
427
427
  const messageStr = message.map(acvmField => String.fromCharCode(Fr.fromString(acvmField).toNumber())).join('');
428
428
  const fieldsFr = fields.map(Fr.fromString);
429
- await this.handlerAsMisc().utilityDebugLog(levelFr.toNumber(), messageStr, fieldsFr);
429
+ await this.handlerAsMisc().utilityLog(levelFr.toNumber(), messageStr, fieldsFr);
430
430
  return [];
431
431
  }
432
432
 
@@ -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) => 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) => 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;
@@ -526,12 +527,22 @@ export class PrivateExecutionOracle extends UtilityExecutionOracle implements IP
526
527
 
527
528
  isStaticCall = isStaticCall || this.callContext.isStaticCall;
528
529
 
530
+ // When scopes are set and the target contract is a registered account (has keys in the keyStore),
531
+ // expand scopes to include it so nested private calls can sync and read the contract's own notes.
532
+ // We only expand for registered accounts because the log service needs the recipient's keys to derive
533
+ // tagging secrets, which are only available for registered accounts.
534
+ const expandedScopes =
535
+ this.scopes !== 'ALL_SCOPES' && (await this.keyStore.hasAccount(targetContractAddress))
536
+ ? [...this.scopes, targetContractAddress]
537
+ : this.scopes;
538
+
529
539
  await this.contractSyncService.ensureContractSynced(
530
540
  targetContractAddress,
531
541
  functionSelector,
532
542
  this.utilityExecutor,
533
543
  this.anchorBlockHeader,
534
544
  this.jobId,
545
+ expandedScopes,
535
546
  );
536
547
 
537
548
  const targetArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(
@@ -569,7 +580,7 @@ export class PrivateExecutionOracle extends UtilityExecutionOracle implements IP
569
580
  totalPublicCalldataCount: this.totalPublicCalldataCount,
570
581
  sideEffectCounter,
571
582
  log: this.log,
572
- scopes: this.scopes,
583
+ scopes: expandedScopes,
573
584
  senderForTags: this.senderForTags,
574
585
  simulator: this.simulator!,
575
586
  });
@@ -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;
@@ -128,11 +129,16 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
128
129
  * @throws If scopes are defined and the account is not in the scopes.
129
130
  */
130
131
  public async utilityGetKeyValidationRequest(pkMHash: Fr): Promise<KeyValidationRequest> {
131
- // If scopes are defined, check that the key belongs to an account in the scopes
132
- if (this.scopes && this.scopes.length > 0) {
133
- const [, account] = await this.keyStore.getKeyPrefixAndAccount(pkMHash);
134
- if (!this.scopes.some(scope => scope.equals(account))) {
135
- throw new Error(`Key validation request denied: account ${account.toString()} is not in the allowed scopes.`);
132
+ // If scopes are defined, check that the key belongs to an account in the scopes.
133
+ if (this.scopes !== 'ALL_SCOPES' && this.scopes.length > 0) {
134
+ let hasAccess = false;
135
+ for (let i = 0; i < this.scopes.length && !hasAccess; i++) {
136
+ if (await this.keyStore.accountHasKey(this.scopes[i], pkMHash)) {
137
+ hasAccess = true;
138
+ }
139
+ }
140
+ if (!hasAccess) {
141
+ throw new Error(`Key validation request denied: no scoped account has a key with hash ${pkMHash.toString()}.`);
136
142
  }
137
143
  }
138
144
  return this.keyStore.getKeyValidationRequest(pkMHash, this.contractAddress);
@@ -406,9 +412,9 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
406
412
  return this.contractLogger;
407
413
  }
408
414
 
409
- public async utilityDebugLog(level: number, message: string, fields: Fr[]): Promise<void> {
415
+ public async utilityLog(level: number, message: string, fields: Fr[]): Promise<void> {
410
416
  if (!LogLevels[level]) {
411
- throw new Error(`Invalid debug log level: ${level}`);
417
+ throw new Error(`Invalid log level: ${level}`);
412
418
  }
413
419
  const levelName = LogLevels[level];
414
420
  const logger = await this.#getContractLogger();
@@ -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';
@@ -18,8 +19,9 @@ import { syncState, verifyCurrentClassId } from './helpers.js';
18
19
  export class ContractSyncService implements StagedStore {
19
20
  readonly storeName = 'contract_sync';
20
21
 
21
- // Tracks contracts synced since last wipe. Key is contract address string, value is a promise that resolves when
22
- // the contract is synced.
22
+ // Tracks contracts synced since last wipe. The cache is keyed per individual scope address
23
+ // (`contractAddress:scopeAddress`), or `contractAddress:*` for undefined scopes (all accounts).
24
+ // The value is a promise that resolves when the contract is synced.
23
25
  private syncedContracts: Map<string, Promise<void>> = new Map();
24
26
 
25
27
  // Per-job overridden contract addresses - these contracts should not be synced.
@@ -44,51 +46,63 @@ export class ContractSyncService implements StagedStore {
44
46
  * @param functionToInvokeAfterSync - The function selector that will be called after sync (used to validate it's
45
47
  * not sync_state itself).
46
48
  * @param utilityExecutor - Executor function for running the sync_state utility function.
49
+ * @param scopes - Access scopes to pass through to the utility executor (affects whose account's private state is discovered).
47
50
  */
48
51
  async ensureContractSynced(
49
52
  contractAddress: AztecAddress,
50
53
  functionToInvokeAfterSync: FunctionSelector | null,
51
- utilityExecutor: (call: FunctionCall) => Promise<any>,
54
+ utilityExecutor: (call: FunctionCall, scopes: AccessScopes) => Promise<any>,
52
55
  anchorBlockHeader: BlockHeader,
53
56
  jobId: string,
57
+ scopes: AccessScopes,
54
58
  ): Promise<void> {
55
- const key = contractAddress.toString();
56
-
57
- // Skip sync if this contract has an override for this job
59
+ // Skip sync if this contract has an override for this job (overrides are keyed by contract address only)
58
60
  const overrides = this.overriddenContracts.get(jobId);
59
- if (overrides?.has(key)) {
61
+ if (overrides?.has(contractAddress.toString())) {
60
62
  return;
61
63
  }
62
64
 
63
- const existing = this.syncedContracts.get(key);
64
- if (existing) {
65
- return existing;
65
+ // Skip sync if we already synced for "all scopes", or if we have an empty list of scopes
66
+ const allScopesKey = toKey(contractAddress, 'ALL_SCOPES');
67
+ const allScopesExisting = this.syncedContracts.get(allScopesKey);
68
+ if (allScopesExisting || (scopes !== 'ALL_SCOPES' && scopes.length == 0)) {
69
+ return;
66
70
  }
67
71
 
68
- const syncPromise = this.#doSync(
69
- contractAddress,
70
- functionToInvokeAfterSync,
71
- utilityExecutor,
72
- anchorBlockHeader,
73
- jobId,
74
- );
75
- this.syncedContracts.set(key, syncPromise);
76
-
77
- try {
78
- await syncPromise;
79
- } catch (err) {
80
- // There was an error syncing the contract, so we remove it from the cache so that it can be retried.
81
- this.syncedContracts.delete(key);
82
- throw err;
72
+ const unsyncedScopes =
73
+ scopes === 'ALL_SCOPES'
74
+ ? scopes
75
+ : scopes.filter(scope => !this.syncedContracts.has(toKey(contractAddress, scope)));
76
+ const unsyncedScopesKeys = toKeys(contractAddress, unsyncedScopes);
77
+
78
+ if (unsyncedScopesKeys.length > 0) {
79
+ // Start sync and store the promise for all unsynced scopes
80
+ const promise = this.#doSync(
81
+ contractAddress,
82
+ functionToInvokeAfterSync,
83
+ utilityExecutor,
84
+ anchorBlockHeader,
85
+ jobId,
86
+ unsyncedScopes,
87
+ ).catch(err => {
88
+ // There was an error syncing the contract, so we remove it from the cache so that it can be retried.
89
+ unsyncedScopesKeys.forEach(key => this.syncedContracts.delete(key));
90
+ throw err;
91
+ });
92
+ unsyncedScopesKeys.forEach(key => this.syncedContracts.set(key, promise));
83
93
  }
94
+
95
+ const promises = toKeys(contractAddress, scopes).map(key => this.syncedContracts.get(key)!);
96
+ await Promise.all(promises);
84
97
  }
85
98
 
86
99
  async #doSync(
87
100
  contractAddress: AztecAddress,
88
101
  functionToInvokeAfterSync: FunctionSelector | null,
89
- utilityExecutor: (call: FunctionCall) => Promise<any>,
102
+ utilityExecutor: (call: FunctionCall, scopes: AccessScopes) => Promise<any>,
90
103
  anchorBlockHeader: BlockHeader,
91
104
  jobId: string,
105
+ scopes: AccessScopes,
92
106
  ): Promise<void> {
93
107
  this.log.debug(`Syncing contract ${contractAddress}`);
94
108
  await Promise.all([
@@ -101,6 +115,7 @@ export class ContractSyncService implements StagedStore {
101
115
  this.aztecNode,
102
116
  anchorBlockHeader,
103
117
  jobId,
118
+ scopes,
104
119
  ),
105
120
  verifyCurrentClassId(contractAddress, this.aztecNode, this.contractStore, anchorBlockHeader),
106
121
  ]);
@@ -127,3 +142,11 @@ export class ContractSyncService implements StagedStore {
127
142
  return Promise.resolve();
128
143
  }
129
144
  }
145
+
146
+ function toKeys(contract: AztecAddress, scopes: AccessScopes) {
147
+ return scopes === 'ALL_SCOPES' ? [toKey(contract, scopes)] : scopes.map(scope => toKey(contract, scope));
148
+ }
149
+
150
+ function toKey(contract: AztecAddress, scope: AztecAddress | 'ALL_SCOPES') {
151
+ return scope === 'ALL_SCOPES' ? `${contract.toString()}:*` : `${contract.toString()}:${scope.toString()}`;
152
+ }
@@ -6,6 +6,7 @@ import { DelayedPublicMutableValues, DelayedPublicMutableValuesWithHash } from '
6
6
  import type { AztecNode } from '@aztec/stdlib/interfaces/client';
7
7
  import type { BlockHeader } from '@aztec/stdlib/tx';
8
8
 
9
+ import type { AccessScopes } from '../access_scopes.js';
9
10
  import { NoteService } from '../notes/note_service.js';
10
11
  import type { ContractStore } from '../storage/contract_store/contract_store.js';
11
12
  import type { NoteStore } from '../storage/note_store/note_store.js';
@@ -42,11 +43,12 @@ export async function syncState(
42
43
  contractAddress: AztecAddress,
43
44
  contractStore: ContractStore,
44
45
  functionToInvokeAfterSync: FunctionSelector | null,
45
- utilityExecutor: (privateSyncCall: FunctionCall) => Promise<any>,
46
+ utilityExecutor: (privateSyncCall: FunctionCall, scopes: AccessScopes) => Promise<any>,
46
47
  noteStore: NoteStore,
47
48
  aztecNode: AztecNode,
48
49
  anchorBlockHeader: BlockHeader,
49
50
  jobId: string,
51
+ scopes: AccessScopes,
50
52
  ) {
51
53
  // Protocol contracts don't have private state to sync
52
54
  if (!isProtocolContract(contractAddress)) {
@@ -61,7 +63,10 @@ export async function syncState(
61
63
 
62
64
  // Both sync_state and syncNoteNullifiers interact with the note store, but running them in parallel is safe
63
65
  // because note store is designed to handle concurrent operations.
64
- await Promise.all([utilityExecutor(syncStateFunctionCall), noteService.syncNoteNullifiers(contractAddress)]);
66
+ await Promise.all([
67
+ utilityExecutor(syncStateFunctionCall, scopes),
68
+ noteService.syncNoteNullifiers(contractAddress, scopes),
69
+ ]);
65
70
  }
66
71
  }
67
72
 
@@ -1,12 +1,13 @@
1
1
  import type { FunctionCall } from '@aztec/stdlib/abi';
2
2
  import type { AuthWitness } from '@aztec/stdlib/auth-witness';
3
- import type { AztecAddress } from '@aztec/stdlib/aztec-address';
4
- import type { NoteDao, NotesFilter } from '@aztec/stdlib/note';
3
+ import type { NoteDao } from '@aztec/stdlib/note';
5
4
  import type { ContractOverrides } from '@aztec/stdlib/tx';
6
5
 
6
+ import type { AccessScopes } from '../access_scopes.js';
7
7
  import type { BlockSynchronizer } from '../block_synchronizer/block_synchronizer.js';
8
8
  import type { ContractFunctionSimulator } from '../contract_function_simulator/contract_function_simulator.js';
9
9
  import type { ContractSyncService } from '../contract_sync/contract_sync_service.js';
10
+ import type { NotesFilter } from '../notes_filter.js';
10
11
  import type { AnchorBlockStore } from '../storage/index.js';
11
12
  import type { NoteStore } from '../storage/note_store/note_store.js';
12
13
 
@@ -21,7 +22,7 @@ export class PXEDebugUtils {
21
22
  contractFunctionSimulator: ContractFunctionSimulator,
22
23
  call: FunctionCall,
23
24
  authWitnesses: AuthWitness[] | undefined,
24
- scopes: AztecAddress[] | undefined,
25
+ scopes: AccessScopes,
25
26
  jobId: string,
26
27
  ) => Promise<any>;
27
28
 
@@ -40,7 +41,7 @@ export class PXEDebugUtils {
40
41
  contractFunctionSimulator: ContractFunctionSimulator,
41
42
  call: FunctionCall,
42
43
  authWitnesses: AuthWitness[] | undefined,
43
- scopes: AztecAddress[] | undefined,
44
+ scopes: AccessScopes,
44
45
  jobId: string,
45
46
  ) => Promise<any>,
46
47
  ) {
@@ -71,10 +72,11 @@ export class PXEDebugUtils {
71
72
  await this.contractSyncService.ensureContractSynced(
72
73
  filter.contractAddress,
73
74
  null,
74
- async privateSyncCall =>
75
- await this.#simulateUtility(contractFunctionSimulator, privateSyncCall, [], undefined, jobId),
75
+ async (privateSyncCall, execScopes) =>
76
+ await this.#simulateUtility(contractFunctionSimulator, privateSyncCall, [], execScopes, jobId),
76
77
  anchorBlockHeader,
77
78
  jobId,
79
+ filter.scopes,
78
80
  );
79
81
 
80
82
  return this.noteStore.getNotes(filter, jobId);
@@ -1,3 +1,5 @@
1
+ export * from '../../../access_scopes.js';
2
+ export * from '../../../notes_filter.js';
1
3
  export * from '../../../pxe.js';
2
4
  export * from '../../../config/index.js';
3
5
  export * from '../../../error_enriching.js';
@@ -1,3 +1,5 @@
1
+ export * from '../../../access_scopes.js';
2
+ export * from '../../../notes_filter.js';
1
3
  export * from '../../../pxe.js';
2
4
  export * from '../../../config/index.js';
3
5
  export * from '../../../storage/index.js';
@@ -1,3 +1,5 @@
1
+ export * from '../../access_scopes.js';
2
+ export * from '../../notes_filter.js';
1
3
  export * from '../../pxe.js';
2
4
  export * from '../../config/index.js';
3
5
  export * from '../../error_enriching.js';
@@ -2,11 +2,11 @@ import type { Fr } from '@aztec/foundation/curves/bn254';
2
2
  import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
3
3
  import type { KeyStore } from '@aztec/key-store';
4
4
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
5
- import type { CompleteAddress } from '@aztec/stdlib/contract';
6
5
  import type { AztecNode } from '@aztec/stdlib/interfaces/server';
7
6
  import { DirectionalAppTaggingSecret, PendingTaggedLog, SiloedTag, Tag, TxScopedL2Log } from '@aztec/stdlib/logs';
8
7
  import type { BlockHeader } from '@aztec/stdlib/tx';
9
8
 
9
+ import type { AccessScopes } from '../access_scopes.js';
10
10
  import type { LogRetrievalRequest } from '../contract_function_simulator/noir-structs/log_retrieval_request.js';
11
11
  import { LogRetrievalResponse } from '../contract_function_simulator/noir-structs/log_retrieval_response.js';
12
12
  import { AddressStore } from '../storage/address_store/address_store.js';
@@ -108,11 +108,7 @@ export class LogService {
108
108
  );
109
109
  }
110
110
 
111
- public async fetchTaggedLogs(
112
- contractAddress: AztecAddress,
113
- pendingTaggedLogArrayBaseSlot: Fr,
114
- scopes?: AztecAddress[],
115
- ) {
111
+ public async fetchTaggedLogs(contractAddress: AztecAddress, pendingTaggedLogArrayBaseSlot: Fr, scopes: AccessScopes) {
116
112
  this.log.verbose(`Fetching tagged logs for ${contractAddress.toString()}`);
117
113
 
118
114
  // We only load logs from block up to and including the anchor block number
@@ -120,7 +116,7 @@ export class LogService {
120
116
  const anchorBlockHash = await this.anchorBlockHeader.hash();
121
117
 
122
118
  // Determine recipients: use scopes if provided, otherwise get all accounts
123
- const recipients = scopes && scopes.length > 0 ? scopes : await this.keyStore.getAccounts();
119
+ const recipients = scopes !== 'ALL_SCOPES' && scopes.length > 0 ? scopes : await this.keyStore.getAccounts();
124
120
 
125
121
  // For each recipient, fetch secrets, load logs, and store them.
126
122
  // We run these per-recipient tasks in parallel so that logs are loaded for all recipients concurrently.
@@ -159,7 +155,10 @@ export class LogService {
159
155
  contractAddress: AztecAddress,
160
156
  recipient: AztecAddress,
161
157
  ): Promise<DirectionalAppTaggingSecret[]> {
162
- const recipientCompleteAddress = await this.#getCompleteAddress(recipient);
158
+ const recipientCompleteAddress = await this.addressStore.getCompleteAddress(recipient);
159
+ if (!recipientCompleteAddress) {
160
+ return [];
161
+ }
163
162
  const recipientIvsk = await this.keyStore.getMasterIncomingViewingSecretKey(recipient);
164
163
 
165
164
  // We implicitly add all PXE accounts as senders, this helps us decrypt tags on notes that we send to ourselves
@@ -206,15 +205,4 @@ export class LogService {
206
205
  // TODO: This looks like it could belong more at the oracle interface level
207
206
  return this.capsuleStore.appendToCapsuleArray(contractAddress, capsuleArrayBaseSlot, pendingTaggedLogs, this.jobId);
208
207
  }
209
-
210
- async #getCompleteAddress(account: AztecAddress): Promise<CompleteAddress> {
211
- const completeAddress = await this.addressStore.getCompleteAddress(account);
212
- if (!completeAddress) {
213
- throw new Error(
214
- `No public key registered for address ${account}.
215
- Register it by calling pxe.addAccount(...).\nSee docs for context: https://docs.aztec.network/developers/resources/debugging/aztecnr-errors#simulation-error-no-public-key-registered-for-address-0x0-register-it-by-calling-pxeregisterrecipient-or-pxeregisteraccount`,
216
- );
217
- }
218
- return completeAddress;
219
- }
220
208
  }
@@ -7,6 +7,7 @@ import { Note, NoteDao, NoteStatus } from '@aztec/stdlib/note';
7
7
  import { MerkleTreeId } from '@aztec/stdlib/trees';
8
8
  import type { BlockHeader, TxHash } from '@aztec/stdlib/tx';
9
9
 
10
+ import type { AccessScopes } from '../access_scopes.js';
10
11
  import type { NoteStore } from '../storage/note_store/note_store.js';
11
12
 
12
13
  export class NoteService {
@@ -31,7 +32,7 @@ export class NoteService {
31
32
  owner: AztecAddress | undefined,
32
33
  storageSlot: Fr,
33
34
  status: NoteStatus,
34
- scopes?: AztecAddress[],
35
+ scopes: AccessScopes,
35
36
  ) {
36
37
  const noteDaos = await this.noteStore.getNotes(
37
38
  {
@@ -70,10 +71,10 @@ export class NoteService {
70
71
  *
71
72
  * @param contractAddress - The contract whose notes should be checked and nullified.
72
73
  */
73
- public async syncNoteNullifiers(contractAddress: AztecAddress): Promise<void> {
74
+ public async syncNoteNullifiers(contractAddress: AztecAddress, scopes: AccessScopes): Promise<void> {
74
75
  const anchorBlockHash = await this.anchorBlockHeader.hash();
75
76
 
76
- const contractNotes = await this.noteStore.getNotes({ contractAddress }, this.jobId);
77
+ const contractNotes = await this.noteStore.getNotes({ contractAddress, scopes }, this.jobId);
77
78
 
78
79
  if (contractNotes.length === 0) {
79
80
  return;
@@ -0,0 +1,26 @@
1
+ import type { Fr } from '@aztec/foundation/curves/bn254';
2
+ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
3
+ import type { NoteStatus } from '@aztec/stdlib/note';
4
+
5
+ import type { AccessScopes } from './access_scopes.js';
6
+
7
+ /**
8
+ * A filter used to fetch notes.
9
+ * @remarks This filter is applied as an intersection of all its params.
10
+ */
11
+ export type NotesFilter = {
12
+ /**
13
+ * The contract address the note belongs to.
14
+ * @remarks Providing a contract address is required as we need that information to trigger private state sync.
15
+ */
16
+ contractAddress: AztecAddress;
17
+ /** The owner of the note. */
18
+ owner?: AztecAddress;
19
+ /** The specific storage location of the note on the contract. */
20
+ storageSlot?: Fr;
21
+ /** The status of the note. Defaults to 'ACTIVE'. */
22
+ status?: NoteStatus;
23
+ /** The siloed nullifier for the note. */
24
+ siloedNullifier?: Fr;
25
+ scopes: AccessScopes;
26
+ };
@@ -4,9 +4,9 @@
4
4
  ///
5
5
  /// @dev Whenever a contract function or Noir test is run, the `utilityAssertCompatibleOracleVersion` oracle is called
6
6
  /// and if the oracle version is incompatible an error is thrown.
7
- export const ORACLE_VERSION = 11;
7
+ export const ORACLE_VERSION = 12;
8
8
 
9
9
  /// This hash is computed as by hashing the Oracle interface and it is used to detect when the Oracle interface changes,
10
10
  /// which in turn implies that you need to update the ORACLE_VERSION constant in this file and in
11
11
  /// `noir-projects/aztec-nr/aztec/src/oracle/version.nr`.
12
- export const ORACLE_INTERFACE_HASH = '20c4d02d8cd5e448c11001a5f72ea2e0927630aeda75e537550872a9627bf40b';
12
+ export const ORACLE_INTERFACE_HASH = '666a8a7fc697f72b29dbf0ae7464db269cf5afa019acac8861f814543147dbb4';