@aztec/pxe 0.0.1-commit.e3c1de76 → 0.0.1-commit.e558bd1c

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 (58) hide show
  1. package/dest/block_synchronizer/block_synchronizer.d.ts +4 -2
  2. package/dest/block_synchronizer/block_synchronizer.d.ts.map +1 -1
  3. package/dest/block_synchronizer/block_synchronizer.js +7 -1
  4. package/dest/contract_function_simulator/contract_function_simulator.d.ts +4 -2
  5. package/dest/contract_function_simulator/contract_function_simulator.d.ts.map +1 -1
  6. package/dest/contract_function_simulator/contract_function_simulator.js +4 -2
  7. package/dest/contract_function_simulator/oracle/interfaces.d.ts +8 -8
  8. package/dest/contract_function_simulator/oracle/interfaces.d.ts.map +1 -1
  9. package/dest/contract_function_simulator/oracle/oracle.d.ts +4 -4
  10. package/dest/contract_function_simulator/oracle/oracle.d.ts.map +1 -1
  11. package/dest/contract_function_simulator/oracle/oracle.js +29 -17
  12. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +4 -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 +6 -6
  15. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +18 -12
  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 +35 -27
  18. package/dest/contract_sync/contract_sync_service.d.ts +41 -0
  19. package/dest/contract_sync/contract_sync_service.d.ts.map +1 -0
  20. package/dest/contract_sync/contract_sync_service.js +82 -0
  21. package/dest/contract_sync/helpers.d.ts +28 -0
  22. package/dest/contract_sync/helpers.d.ts.map +1 -0
  23. package/dest/contract_sync/{index.js → helpers.js} +13 -12
  24. package/dest/debug/pxe_debug_utils.d.ts +12 -7
  25. package/dest/debug/pxe_debug_utils.d.ts.map +1 -1
  26. package/dest/debug/pxe_debug_utils.js +16 -12
  27. package/dest/entrypoints/server/index.d.ts +2 -2
  28. package/dest/entrypoints/server/index.d.ts.map +1 -1
  29. package/dest/entrypoints/server/index.js +1 -1
  30. package/dest/logs/log_service.d.ts +2 -2
  31. package/dest/logs/log_service.d.ts.map +1 -1
  32. package/dest/logs/log_service.js +2 -4
  33. package/dest/oracle_version.d.ts +3 -3
  34. package/dest/oracle_version.d.ts.map +1 -1
  35. package/dest/oracle_version.js +2 -2
  36. package/dest/pxe.d.ts +2 -1
  37. package/dest/pxe.d.ts.map +1 -1
  38. package/dest/pxe.js +23 -12
  39. package/dest/storage/note_store/note_store.d.ts +1 -1
  40. package/dest/storage/note_store/note_store.d.ts.map +1 -1
  41. package/dest/storage/note_store/note_store.js +3 -0
  42. package/package.json +25 -16
  43. package/src/block_synchronizer/block_synchronizer.ts +6 -0
  44. package/src/contract_function_simulator/contract_function_simulator.ts +3 -0
  45. package/src/contract_function_simulator/oracle/interfaces.ts +9 -9
  46. package/src/contract_function_simulator/oracle/oracle.ts +32 -15
  47. package/src/contract_function_simulator/oracle/private_execution_oracle.ts +6 -5
  48. package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +39 -30
  49. package/src/contract_sync/contract_sync_service.ts +129 -0
  50. package/src/contract_sync/{index.ts → helpers.ts} +15 -20
  51. package/src/debug/pxe_debug_utils.ts +46 -13
  52. package/src/entrypoints/server/index.ts +1 -1
  53. package/src/logs/log_service.ts +2 -2
  54. package/src/oracle_version.ts +2 -2
  55. package/src/pxe.ts +33 -13
  56. package/src/storage/note_store/note_store.ts +4 -0
  57. package/dest/contract_sync/index.d.ts +0 -23
  58. package/dest/contract_sync/index.d.ts.map +0 -1
@@ -88,35 +88,49 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
88
88
  * @param pkMHash - The master public key hash.
89
89
  * @returns A Promise that resolves to nullifier keys.
90
90
  * @throws If the keys are not registered in the key store.
91
+ * @throws If scopes are defined and the account is not in the scopes.
91
92
  */
92
- public utilityGetKeyValidationRequest(pkMHash: Fr): Promise<KeyValidationRequest> {
93
+ public async utilityGetKeyValidationRequest(pkMHash: Fr): Promise<KeyValidationRequest> {
94
+ // If scopes are defined, check that the key belongs to an account in the scopes
95
+ if (this.scopes && this.scopes.length > 0) {
96
+ const [, account] = await this.keyStore.getKeyPrefixAndAccount(pkMHash);
97
+ if (!this.scopes.some(scope => scope.equals(account))) {
98
+ throw new Error(`Key validation request denied: account ${account.toString()} is not in the allowed scopes.`);
99
+ }
100
+ }
93
101
  return this.keyStore.getKeyValidationRequest(pkMHash, this.contractAddress);
94
102
  }
95
103
 
96
104
  /**
97
105
  * Fetches the index and sibling path of a leaf at a given block from the note hash tree.
98
- * @param blockHash - The block hash at which to get the membership witness.
99
- * @param leafValue - The leaf value
106
+ * @param anchorBlockHash - The hash of a block that contains the note hash tree root in which to find the membership
107
+ * witness.
108
+ * @param noteHash - The note hash to find in the note hash tree.
100
109
  * @returns The membership witness containing the leaf index and sibling path
101
110
  */
102
111
  public utilityGetNoteHashMembershipWitness(
103
- blockHash: BlockHash,
104
- leafValue: Fr,
112
+ anchorBlockHash: BlockHash,
113
+ noteHash: Fr,
105
114
  ): Promise<MembershipWitness<typeof NOTE_HASH_TREE_HEIGHT> | undefined> {
106
- return this.aztecNode.getNoteHashMembershipWitness(blockHash, leafValue);
115
+ return this.aztecNode.getNoteHashMembershipWitness(anchorBlockHash, noteHash);
107
116
  }
108
117
 
109
118
  /**
110
- * Fetches the index and sibling path of a leaf at a given block from the archive tree.
111
- * @param blockHash - The block hash at which to get the membership witness.
112
- * @param leafValue - The leaf value
119
+ * Fetches the index and sibling path of a block hash in the archive tree.
120
+ *
121
+ * Block hashes are the leaves of the archive tree. Each time a new block is added to the chain,
122
+ * its block hash is appended as a new leaf to the archive tree.
123
+ *
124
+ * @param anchorBlockHash - The hash of a block that contains the archive tree root in which to find the membership
125
+ * witness.
126
+ * @param blockHash - The block hash to find in the archive tree.
113
127
  * @returns The membership witness containing the leaf index and sibling path
114
128
  */
115
- public utilityGetArchiveMembershipWitness(
129
+ public utilityGetBlockHashMembershipWitness(
130
+ anchorBlockHash: BlockHash,
116
131
  blockHash: BlockHash,
117
- leafValue: Fr,
118
132
  ): Promise<MembershipWitness<typeof ARCHIVE_HEIGHT> | undefined> {
119
- return this.aztecNode.getArchiveMembershipWitness(blockHash, leafValue);
133
+ return this.aztecNode.getBlockHashMembershipWitness(anchorBlockHash, blockHash);
120
134
  }
121
135
 
122
136
  /**
@@ -176,14 +190,13 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
176
190
  /**
177
191
  * Retrieve the complete address associated to a given address.
178
192
  * @param account - The account address.
179
- * @returns A complete address associated with the input address.
180
- * @throws An error if the account is not registered in the database.
193
+ * @returns A complete address associated with the input address, or `undefined` if not registered.
181
194
  */
182
- public utilityGetPublicKeysAndPartialAddress(account: AztecAddress): Promise<CompleteAddress> {
183
- return this.getCompleteAddress(account);
195
+ public utilityTryGetPublicKeysAndPartialAddress(account: AztecAddress): Promise<CompleteAddress | undefined> {
196
+ return this.addressStore.getCompleteAddress(account);
184
197
  }
185
198
 
186
- protected async getCompleteAddress(account: AztecAddress): Promise<CompleteAddress> {
199
+ protected async getCompleteAddressOrFail(account: AztecAddress): Promise<CompleteAddress> {
187
200
  const completeAddress = await this.addressStore.getCompleteAddress(account);
188
201
  if (!completeAddress) {
189
202
  throw new Error(
@@ -284,8 +297,13 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
284
297
  * @returns A boolean indicating whether the nullifier exists in the tree or not.
285
298
  */
286
299
  public async utilityCheckNullifierExists(innerNullifier: Fr) {
287
- const nullifier = await siloNullifier(this.contractAddress, innerNullifier!);
288
- const [leafIndex] = await this.aztecNode.findLeavesIndexes('latest', MerkleTreeId.NULLIFIER_TREE, [nullifier]);
300
+ const [nullifier, anchorBlockHash] = await Promise.all([
301
+ siloNullifier(this.contractAddress, innerNullifier!),
302
+ this.anchorBlockHeader.hash(),
303
+ ]);
304
+ const [leafIndex] = await this.aztecNode.findLeavesIndexes(anchorBlockHash, MerkleTreeId.NULLIFIER_TREE, [
305
+ nullifier,
306
+ ]);
289
307
  return leafIndex?.data !== undefined;
290
308
  }
291
309
 
@@ -357,16 +375,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
357
375
  this.log.getBindings(),
358
376
  );
359
377
 
360
- const noteService = new NoteService(this.noteStore, this.aztecNode, this.anchorBlockHeader, this.jobId);
361
-
362
- // It is acceptable to run the following operations in parallel for several reasons:
363
- // 1. syncTaggedLogs does not write to the note store — it only stores the pending tagged logs in a capsule array,
364
- // which is then processed in Noir after this handler returns.
365
- // 2. Even if syncTaggedLogs did write to the note store, it would not cause inconsistent state.
366
- await Promise.all([
367
- logService.syncTaggedLogs(this.contractAddress, pendingTaggedLogArrayBaseSlot, this.scopes),
368
- noteService.syncNoteNullifiers(this.contractAddress),
369
- ]);
378
+ await logService.fetchTaggedLogs(this.contractAddress, pendingTaggedLogArrayBaseSlot, this.scopes);
370
379
  }
371
380
 
372
381
  /**
@@ -538,7 +547,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
538
547
 
539
548
  protected async getSharedSecret(address: AztecAddress, ephPk: Point): Promise<Point> {
540
549
  // TODO(#12656): return an app-siloed secret
541
- const recipientCompleteAddress = await this.getCompleteAddress(address);
550
+ const recipientCompleteAddress = await this.getCompleteAddressOrFail(address);
542
551
  const ivskM = await this.keyStore.getMasterSecretKey(
543
552
  recipientCompleteAddress.publicKeys.masterIncomingViewingPublicKey,
544
553
  );
@@ -0,0 +1,129 @@
1
+ import type { Logger } from '@aztec/foundation/log';
2
+ import type { FunctionCall, FunctionSelector } from '@aztec/stdlib/abi';
3
+ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
4
+ import type { AztecNode } from '@aztec/stdlib/interfaces/client';
5
+ import type { BlockHeader } from '@aztec/stdlib/tx';
6
+
7
+ import type { StagedStore } from '../job_coordinator/job_coordinator.js';
8
+ import type { ContractStore } from '../storage/contract_store/contract_store.js';
9
+ import type { NoteStore } from '../storage/note_store/note_store.js';
10
+ import { syncState, verifyCurrentClassId } from './helpers.js';
11
+
12
+ /**
13
+ * Service for syncing the private state of contracts and verifying that the PXE holds the current class artifact.
14
+ * It uses a cache to avoid redundant sync operations - the cache is wiped when the anchor block changes.
15
+ *
16
+ * TODO: The StagedStore naming is broken here. Figure out a better name.
17
+ */
18
+ export class ContractSyncService implements StagedStore {
19
+ readonly storeName = 'contract_sync';
20
+
21
+ // Tracks contracts synced since last wipe. Key is contract address string, value is a promise that resolves when
22
+ // the contract is synced.
23
+ private syncedContracts: Map<string, Promise<void>> = new Map();
24
+
25
+ // Per-job overridden contract addresses - these contracts should not be synced.
26
+ private overriddenContracts: Map<string, Set<string>> = new Map();
27
+
28
+ constructor(
29
+ private aztecNode: AztecNode,
30
+ private contractStore: ContractStore,
31
+ private noteStore: NoteStore,
32
+ private log: Logger,
33
+ ) {}
34
+
35
+ /** Sets contracts that should be skipped during sync for a specific job. */
36
+ setOverriddenContracts(jobId: string, addresses: Set<string>): void {
37
+ this.overriddenContracts.set(jobId, addresses);
38
+ }
39
+
40
+ /**
41
+ * Ensures a contract's private state is synchronized and that the PXE holds the current class artifact.
42
+ * Uses a cache to avoid redundant sync operations - the cache is wiped when the anchor block changes.
43
+ * @param contractAddress - The address of the contract to sync.
44
+ * @param functionToInvokeAfterSync - The function selector that will be called after sync (used to validate it's
45
+ * not sync_state itself).
46
+ * @param utilityExecutor - Executor function for running the sync_state utility function.
47
+ */
48
+ async ensureContractSynced(
49
+ contractAddress: AztecAddress,
50
+ functionToInvokeAfterSync: FunctionSelector | null,
51
+ utilityExecutor: (call: FunctionCall) => Promise<any>,
52
+ anchorBlockHeader: BlockHeader,
53
+ jobId: string,
54
+ ): Promise<void> {
55
+ const key = contractAddress.toString();
56
+
57
+ // Skip sync if this contract has an override for this job
58
+ const overrides = this.overriddenContracts.get(jobId);
59
+ if (overrides?.has(key)) {
60
+ return;
61
+ }
62
+
63
+ const existing = this.syncedContracts.get(key);
64
+ if (existing) {
65
+ return existing;
66
+ }
67
+
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;
83
+ }
84
+ }
85
+
86
+ async #doSync(
87
+ contractAddress: AztecAddress,
88
+ functionToInvokeAfterSync: FunctionSelector | null,
89
+ utilityExecutor: (call: FunctionCall) => Promise<any>,
90
+ anchorBlockHeader: BlockHeader,
91
+ jobId: string,
92
+ ): Promise<void> {
93
+ this.log.debug(`Syncing contract ${contractAddress}`);
94
+ await Promise.all([
95
+ syncState(
96
+ contractAddress,
97
+ this.contractStore,
98
+ functionToInvokeAfterSync,
99
+ utilityExecutor,
100
+ this.noteStore,
101
+ this.aztecNode,
102
+ anchorBlockHeader,
103
+ jobId,
104
+ ),
105
+ verifyCurrentClassId(contractAddress, this.aztecNode, this.contractStore, anchorBlockHeader),
106
+ ]);
107
+ this.log.debug(`Contract ${contractAddress} synced`);
108
+ }
109
+
110
+ /** Clears sync cache. Called by BlockSynchronizer when anchor block changes. */
111
+ wipe(): void {
112
+ this.log.debug(`Wiping contract sync cache (${this.syncedContracts.size} entries)`);
113
+ this.syncedContracts.clear();
114
+ }
115
+
116
+ commit(jobId: string): Promise<void> {
117
+ // Clear overridden contracts for this job
118
+ this.overriddenContracts.delete(jobId);
119
+ return Promise.resolve();
120
+ }
121
+
122
+ discardStaged(jobId: string): Promise<void> {
123
+ // We clear the synced contracts cache here because, when the job is discarded, any associated database writes from
124
+ // the sync are also undone.
125
+ this.syncedContracts.clear();
126
+ this.overriddenContracts.delete(jobId);
127
+ return Promise.resolve();
128
+ }
129
+ }
@@ -6,7 +6,9 @@ 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 { NoteService } from '../notes/note_service.js';
9
10
  import type { ContractStore } from '../storage/contract_store/contract_store.js';
11
+ import type { NoteStore } from '../storage/note_store/note_store.js';
10
12
 
11
13
  /**
12
14
  * Read the current class id of a contract from the execution data provider or AztecNode. If not found, class id
@@ -41,6 +43,10 @@ export async function syncState(
41
43
  contractStore: ContractStore,
42
44
  functionToInvokeAfterSync: FunctionSelector | null,
43
45
  utilityExecutor: (privateSyncCall: FunctionCall) => Promise<any>,
46
+ noteStore: NoteStore,
47
+ aztecNode: AztecNode,
48
+ anchorBlockHeader: BlockHeader,
49
+ jobId: string,
44
50
  ) {
45
51
  // Protocol contracts don't have private state to sync
46
52
  if (!isProtocolContract(contractAddress)) {
@@ -51,16 +57,23 @@ export async function syncState(
51
57
  );
52
58
  }
53
59
 
54
- return utilityExecutor(syncStateFunctionCall);
60
+ const noteService = new NoteService(noteStore, aztecNode, anchorBlockHeader, jobId);
61
+
62
+ // Both sync_state and syncNoteNullifiers interact with the note store, but running them in parallel is safe
63
+ // because note store is designed to handle concurrent operations.
64
+ await Promise.all([utilityExecutor(syncStateFunctionCall), noteService.syncNoteNullifiers(contractAddress)]);
55
65
  }
56
66
  }
57
67
 
58
68
  /**
59
69
  * Verify that the current class id of a contract obtained from AztecNode is the same as the one in contract data
60
70
  * provider (i.e. PXE's own storage).
71
+ * @param contractAddress - The address of the contract to verify.
72
+ * @param aztecNode - The Aztec node to query for storage.
73
+ * @param contractStore - The contract store to fetch the local instance from.
61
74
  * @param header - The header of the block at which to verify the current class id.
62
75
  */
63
- async function verifyCurrentClassId(
76
+ export async function verifyCurrentClassId(
64
77
  contractAddress: AztecAddress,
65
78
  aztecNode: AztecNode,
66
79
  contractStore: ContractStore,
@@ -78,21 +91,3 @@ async function verifyCurrentClassId(
78
91
  );
79
92
  }
80
93
  }
81
-
82
- /**
83
- * Ensures the contract's private state is synchronized and that the PXE holds the current class artifact for
84
- * the contract.
85
- */
86
- export async function ensureContractSynced(
87
- contractAddress: AztecAddress,
88
- functionToInvokeAfterSync: FunctionSelector | null,
89
- utilityExecutor: (call: FunctionCall) => Promise<any>,
90
- aztecNode: AztecNode,
91
- contractStore: ContractStore,
92
- header: BlockHeader,
93
- ): Promise<void> {
94
- await Promise.all([
95
- syncState(contractAddress, contractStore, functionToInvokeAfterSync, utilityExecutor),
96
- verifyCurrentClassId(contractAddress, aztecNode, contractStore, header),
97
- ]);
98
- }
@@ -1,10 +1,12 @@
1
- import { randomBytes } from '@aztec/foundation/crypto/random';
1
+ import type { FunctionCall } from '@aztec/stdlib/abi';
2
+ import type { AuthWitness } from '@aztec/stdlib/auth-witness';
3
+ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
2
4
  import type { NoteDao, NotesFilter } from '@aztec/stdlib/note';
3
- import type { BlockHeader } from '@aztec/stdlib/tx';
5
+ import type { BlockHeader, ContractOverrides } from '@aztec/stdlib/tx';
4
6
 
5
7
  import type { BlockSynchronizer } from '../block_synchronizer/block_synchronizer.js';
6
- import type { PXE } from '../pxe.js';
7
- import type { ContractStore } from '../storage/contract_store/contract_store.js';
8
+ import type { ContractFunctionSimulator } from '../contract_function_simulator/contract_function_simulator.js';
9
+ import type { ContractSyncService } from '../contract_sync/contract_sync_service.js';
8
10
  import type { AnchorBlockStore } from '../storage/index.js';
9
11
  import type { NoteStore } from '../storage/note_store/note_store.js';
10
12
 
@@ -13,20 +15,38 @@ import type { NoteStore } from '../storage/note_store/note_store.js';
13
15
  * No backwards compatibility or API stability should be expected. Use at your own risk.
14
16
  */
15
17
  export class PXEDebugUtils {
16
- #pxe!: PXE;
17
18
  #putJobInQueue!: <T>(job: (jobId: string) => Promise<T>) => Promise<T>;
19
+ #getSimulatorForTx!: (overrides?: { contracts?: ContractOverrides }) => ContractFunctionSimulator;
20
+ #simulateUtility!: (
21
+ contractFunctionSimulator: ContractFunctionSimulator,
22
+ call: FunctionCall,
23
+ authWitnesses: AuthWitness[] | undefined,
24
+ scopes: AztecAddress[] | undefined,
25
+ jobId: string,
26
+ ) => Promise<any>;
18
27
 
19
28
  constructor(
20
- private contractStore: ContractStore,
29
+ private contractSyncService: ContractSyncService,
21
30
  private noteStore: NoteStore,
22
31
  private blockStateSynchronizer: BlockSynchronizer,
23
32
  private anchorBlockStore: AnchorBlockStore,
24
33
  ) {}
25
34
 
26
35
  /** Not injected through constructor since they're are co-dependant */
27
- public setPXE(pxe: PXE, putJobInQueue: <T>(job: (jobId: string) => Promise<T>) => Promise<T>) {
28
- this.#pxe = pxe;
36
+ public setPXEHelpers(
37
+ putJobInQueue: <T>(job: (jobId: string) => Promise<T>) => Promise<T>,
38
+ getSimulatorForTx: (overrides?: { contracts?: ContractOverrides }) => ContractFunctionSimulator,
39
+ simulateUtility: (
40
+ contractFunctionSimulator: ContractFunctionSimulator,
41
+ call: FunctionCall,
42
+ authWitnesses: AuthWitness[] | undefined,
43
+ scopes: AztecAddress[] | undefined,
44
+ jobId: string,
45
+ ) => Promise<any>,
46
+ ) {
29
47
  this.#putJobInQueue = putJobInQueue;
48
+ this.#getSimulatorForTx = getSimulatorForTx;
49
+ this.#simulateUtility = simulateUtility;
30
50
  }
31
51
 
32
52
  /**
@@ -40,12 +60,25 @@ export class PXEDebugUtils {
40
60
  * @param filter - The filter to apply to the notes.
41
61
  * @returns The requested notes.
42
62
  */
43
- public async getNotes(filter: NotesFilter): Promise<NoteDao[]> {
44
- // We need to manually trigger private state sync to have a guarantee that all the notes are available.
45
- const call = await this.contractStore.getFunctionCall('sync_state', [], filter.contractAddress);
46
- await this.#pxe.simulateUtility(call);
63
+ public getNotes(filter: NotesFilter): Promise<NoteDao[]> {
64
+ return this.#putJobInQueue(async (jobId: string) => {
65
+ await this.blockStateSynchronizer.sync();
47
66
 
48
- return this.noteStore.getNotes(filter, randomBytes(8).toString('hex'));
67
+ const anchorBlockHeader = await this.anchorBlockStore.getBlockHeader();
68
+
69
+ const contractFunctionSimulator = this.#getSimulatorForTx();
70
+
71
+ await this.contractSyncService.ensureContractSynced(
72
+ filter.contractAddress,
73
+ null,
74
+ async privateSyncCall =>
75
+ await this.#simulateUtility(contractFunctionSimulator, privateSyncCall, [], undefined, jobId),
76
+ anchorBlockHeader,
77
+ jobId,
78
+ );
79
+
80
+ return this.noteStore.getNotes(filter, jobId);
81
+ });
49
82
  }
50
83
 
51
84
  /** Returns the block header up to which the PXE has synced. */
@@ -7,4 +7,4 @@ export { NoteService } from '../../notes/note_service.js';
7
7
  export { ORACLE_VERSION } from '../../oracle_version.js';
8
8
  export { type PXECreationOptions } from '../pxe_creation_options.js';
9
9
  export { JobCoordinator } from '../../job_coordinator/job_coordinator.js';
10
- export { syncState } from '../../contract_sync/index.js';
10
+ export { ContractSyncService } from '../../contract_sync/contract_sync_service.js';
@@ -108,12 +108,12 @@ export class LogService {
108
108
  );
109
109
  }
110
110
 
111
- public async syncTaggedLogs(
111
+ public async fetchTaggedLogs(
112
112
  contractAddress: AztecAddress,
113
113
  pendingTaggedLogArrayBaseSlot: Fr,
114
114
  scopes?: AztecAddress[],
115
115
  ) {
116
- this.log.verbose('Searching for tagged logs', { contract: contractAddress });
116
+ this.log.verbose(`Fetching tagged logs for ${contractAddress.toString()}`);
117
117
 
118
118
  // We only load logs from block up to and including the anchor block number
119
119
  const anchorBlockNumber = this.anchorBlockHeader.getBlockNumber();
@@ -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 = 9;
7
+ export const ORACLE_VERSION = 11;
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 = '9866cc52510acaef75a3d47a0ed501fd9ff92b9d53b2c8a88c8a3ffd04ced81f';
12
+ export const ORACLE_INTERFACE_HASH = '20c4d02d8cd5e448c11001a5f72ea2e0927630aeda75e537550872a9627bf40b';
package/src/pxe.ts CHANGED
@@ -59,7 +59,8 @@ import {
59
59
  generateSimulatedProvingResult,
60
60
  } from './contract_function_simulator/contract_function_simulator.js';
61
61
  import { ProxiedContractStoreFactory } from './contract_function_simulator/proxied_contract_data_source.js';
62
- import { ensureContractSynced, readCurrentClassId } from './contract_sync/index.js';
62
+ import { ContractSyncService } from './contract_sync/contract_sync_service.js';
63
+ import { readCurrentClassId } from './contract_sync/helpers.js';
63
64
  import { PXEDebugUtils } from './debug/pxe_debug_utils.js';
64
65
  import { enrichPublicSimulationError, enrichSimulationError } from './error_enriching.js';
65
66
  import { PrivateEventFilterValidator } from './events/private_event_filter_validator.js';
@@ -102,6 +103,7 @@ export class PXE {
102
103
  private recipientTaggingStore: RecipientTaggingStore,
103
104
  private addressStore: AddressStore,
104
105
  private privateEventStore: PrivateEventStore,
106
+ private contractSyncService: ContractSyncService,
105
107
  private simulator: CircuitSimulator,
106
108
  private proverEnabled: boolean,
107
109
  private proofCreator: PrivateKernelProver,
@@ -149,6 +151,12 @@ export class PXE {
149
151
  const capsuleStore = new CapsuleStore(store);
150
152
  const keyStore = new KeyStore(store);
151
153
  const tipsStore = new L2TipsKVStore(store, 'pxe');
154
+ const contractSyncService = new ContractSyncService(
155
+ node,
156
+ contractStore,
157
+ noteStore,
158
+ createLogger('pxe:contract_sync', bindings),
159
+ );
152
160
  const synchronizer = new BlockSynchronizer(
153
161
  node,
154
162
  store,
@@ -156,6 +164,7 @@ export class PXE {
156
164
  noteStore,
157
165
  privateEventStore,
158
166
  tipsStore,
167
+ contractSyncService,
159
168
  config,
160
169
  bindings,
161
170
  );
@@ -167,9 +176,10 @@ export class PXE {
167
176
  recipientTaggingStore,
168
177
  privateEventStore,
169
178
  noteStore,
179
+ contractSyncService,
170
180
  ]);
171
181
 
172
- const debugUtils = new PXEDebugUtils(contractStore, noteStore, synchronizer, anchorBlockStore);
182
+ const debugUtils = new PXEDebugUtils(contractSyncService, noteStore, synchronizer, anchorBlockStore);
173
183
 
174
184
  const jobQueue = new SerialQueue();
175
185
 
@@ -186,6 +196,7 @@ export class PXE {
186
196
  recipientTaggingStore,
187
197
  addressStore,
188
198
  privateEventStore,
199
+ contractSyncService,
189
200
  simulator,
190
201
  proverEnabled,
191
202
  proofCreator,
@@ -196,7 +207,11 @@ export class PXE {
196
207
  debugUtils,
197
208
  );
198
209
 
199
- debugUtils.setPXE(pxe, pxe.#putInJobQueue.bind(pxe));
210
+ debugUtils.setPXEHelpers(
211
+ pxe.#putInJobQueue.bind(pxe),
212
+ pxe.#getSimulatorForTx.bind(pxe),
213
+ pxe.#simulateUtility.bind(pxe),
214
+ );
200
215
 
201
216
  pxe.jobQueue.start();
202
217
 
@@ -223,6 +238,7 @@ export class PXE {
223
238
  this.capsuleStore,
224
239
  this.privateEventStore,
225
240
  this.simulator,
241
+ this.contractSyncService,
226
242
  );
227
243
  }
228
244
 
@@ -297,13 +313,12 @@ export class PXE {
297
313
  try {
298
314
  const anchorBlockHeader = await this.anchorBlockStore.getBlockHeader();
299
315
 
300
- await ensureContractSynced(
316
+ await this.contractSyncService.ensureContractSynced(
301
317
  contractAddress,
302
318
  functionSelector,
303
319
  privateSyncCall => this.#simulateUtility(contractFunctionSimulator, privateSyncCall, [], undefined, jobId),
304
- this.node,
305
- this.contractStore,
306
320
  anchorBlockHeader,
321
+ jobId,
307
322
  );
308
323
 
309
324
  const result = await contractFunctionSimulator.run(
@@ -848,7 +863,14 @@ export class PXE {
848
863
  // Temporary: in case there are overrides, we have to skip the kernels or validations
849
864
  // will fail. Consider handing control to the user/wallet on whether they want to run them
850
865
  // or not.
851
- const skipKernels = overrides?.contracts !== undefined && Object.keys(overrides.contracts ?? {}).length > 0;
866
+ const overriddenContracts = overrides?.contracts ? new Set(Object.keys(overrides.contracts)) : undefined;
867
+ const hasOverriddenContracts = overriddenContracts !== undefined && overriddenContracts.size > 0;
868
+ const skipKernels = hasOverriddenContracts;
869
+
870
+ // Set overridden contracts on the sync service so it knows to skip syncing them
871
+ if (hasOverriddenContracts) {
872
+ this.contractSyncService.setOverriddenContracts(jobId, overriddenContracts);
873
+ }
852
874
 
853
875
  // Execution of private functions only; no proving, and no kernel logic.
854
876
  const privateExecutionResult = await this.#executePrivate(contractFunctionSimulator, txRequest, scopes, jobId);
@@ -970,13 +992,12 @@ export class PXE {
970
992
  const contractFunctionSimulator = this.#getSimulatorForTx();
971
993
 
972
994
  const anchorBlockHeader = await this.anchorBlockStore.getBlockHeader();
973
- await ensureContractSynced(
995
+ await this.contractSyncService.ensureContractSynced(
974
996
  call.to,
975
997
  call.selector,
976
998
  privateSyncCall => this.#simulateUtility(contractFunctionSimulator, privateSyncCall, [], undefined, jobId),
977
- this.node,
978
- this.contractStore,
979
999
  anchorBlockHeader,
1000
+ jobId,
980
1001
  );
981
1002
 
982
1003
  const executionResult = await this.#simulateUtility(
@@ -1040,14 +1061,13 @@ export class PXE {
1040
1061
 
1041
1062
  const contractFunctionSimulator = this.#getSimulatorForTx();
1042
1063
 
1043
- await ensureContractSynced(
1064
+ await this.contractSyncService.ensureContractSynced(
1044
1065
  filter.contractAddress,
1045
1066
  null,
1046
1067
  async privateSyncCall =>
1047
1068
  await this.#simulateUtility(contractFunctionSimulator, privateSyncCall, [], undefined, jobId),
1048
- this.node,
1049
- this.contractStore,
1050
1069
  anchorBlockHeader,
1070
+ jobId,
1051
1071
  );
1052
1072
  });
1053
1073
 
@@ -220,6 +220,10 @@ export class NoteStore implements StagedStore {
220
220
  return Promise.resolve([]);
221
221
  }
222
222
 
223
+ if (nullifiers.some(n => n.l2BlockNumber === 0)) {
224
+ return Promise.reject(new Error('applyNullifiers: nullifiers cannot have been emitted at block 0'));
225
+ }
226
+
223
227
  return this.#withJobLock(jobId, () =>
224
228
  this.#store.transactionAsync(async () => {
225
229
  const notesToNullify = await Promise.all(
@@ -1,23 +0,0 @@
1
- import type { FunctionCall, FunctionSelector } from '@aztec/stdlib/abi';
2
- import type { AztecAddress } from '@aztec/stdlib/aztec-address';
3
- import type { ContractInstance } from '@aztec/stdlib/contract';
4
- import type { AztecNode } from '@aztec/stdlib/interfaces/client';
5
- import type { BlockHeader } from '@aztec/stdlib/tx';
6
- import type { ContractStore } from '../storage/contract_store/contract_store.js';
7
- /**
8
- * Read the current class id of a contract from the execution data provider or AztecNode. If not found, class id
9
- * from the instance is used.
10
- * @param contractAddress - The address of the contract to read the class id for.
11
- * @param instance - The instance of the contract.
12
- * @param aztecNode - The Aztec node to query for storage.
13
- * @param header - The header of the block at which to load the DelayedPublicMutable storing the class id.
14
- * @returns The current class id.
15
- */
16
- export declare function readCurrentClassId(contractAddress: AztecAddress, instance: ContractInstance, aztecNode: AztecNode, header: BlockHeader): Promise<import("@aztec/foundation/schemas").Fr>;
17
- export declare function syncState(contractAddress: AztecAddress, contractStore: ContractStore, functionToInvokeAfterSync: FunctionSelector | null, utilityExecutor: (privateSyncCall: FunctionCall) => Promise<any>): Promise<any>;
18
- /**
19
- * Ensures the contract's private state is synchronized and that the PXE holds the current class artifact for
20
- * the contract.
21
- */
22
- export declare function ensureContractSynced(contractAddress: AztecAddress, functionToInvokeAfterSync: FunctionSelector | null, utilityExecutor: (call: FunctionCall) => Promise<any>, aztecNode: AztecNode, contractStore: ContractStore, header: BlockHeader): Promise<void>;
23
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb250cmFjdF9zeW5jL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sS0FBSyxFQUFFLFlBQVksRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ3hFLE9BQU8sS0FBSyxFQUFFLFlBQVksRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ2hFLE9BQU8sS0FBSyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFL0QsT0FBTyxLQUFLLEVBQUUsU0FBUyxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDakUsT0FBTyxLQUFLLEVBQUUsV0FBVyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFFcEQsT0FBTyxLQUFLLEVBQUUsYUFBYSxFQUFFLE1BQU0sNkNBQTZDLENBQUM7QUFFakY7Ozs7Ozs7O0dBUUc7QUFDSCx3QkFBc0Isa0JBQWtCLENBQ3RDLGVBQWUsRUFBRSxZQUFZLEVBQzdCLFFBQVEsRUFBRSxnQkFBZ0IsRUFDMUIsU0FBUyxFQUFFLFNBQVMsRUFDcEIsTUFBTSxFQUFFLFdBQVcsbURBYXBCO0FBRUQsd0JBQXNCLFNBQVMsQ0FDN0IsZUFBZSxFQUFFLFlBQVksRUFDN0IsYUFBYSxFQUFFLGFBQWEsRUFDNUIseUJBQXlCLEVBQUUsZ0JBQWdCLEdBQUcsSUFBSSxFQUNsRCxlQUFlLEVBQUUsQ0FBQyxlQUFlLEVBQUUsWUFBWSxLQUFLLE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0JBYWpFO0FBMEJEOzs7R0FHRztBQUNILHdCQUFzQixvQkFBb0IsQ0FDeEMsZUFBZSxFQUFFLFlBQVksRUFDN0IseUJBQXlCLEVBQUUsZ0JBQWdCLEdBQUcsSUFBSSxFQUNsRCxlQUFlLEVBQUUsQ0FBQyxJQUFJLEVBQUUsWUFBWSxLQUFLLE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFDckQsU0FBUyxFQUFFLFNBQVMsRUFDcEIsYUFBYSxFQUFFLGFBQWEsRUFDNUIsTUFBTSxFQUFFLFdBQVcsR0FDbEIsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUtmIn0=
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/contract_sync/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;AAEjF;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,eAAe,EAAE,YAAY,EAC7B,QAAQ,EAAE,gBAAgB,EAC1B,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,WAAW,mDAapB;AAED,wBAAsB,SAAS,CAC7B,eAAe,EAAE,YAAY,EAC7B,aAAa,EAAE,aAAa,EAC5B,yBAAyB,EAAE,gBAAgB,GAAG,IAAI,EAClD,eAAe,EAAE,CAAC,eAAe,EAAE,YAAY,KAAK,OAAO,CAAC,GAAG,CAAC,gBAajE;AA0BD;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,eAAe,EAAE,YAAY,EAC7B,yBAAyB,EAAE,gBAAgB,GAAG,IAAI,EAClD,eAAe,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,GAAG,CAAC,EACrD,SAAS,EAAE,SAAS,EACpB,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,IAAI,CAAC,CAKf"}