@aztec/pxe 0.0.1-commit.8c0b8ff → 0.0.1-commit.8cb2d04d8

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 (49) hide show
  1. package/dest/block_synchronizer/block_synchronizer.d.ts +6 -2
  2. package/dest/block_synchronizer/block_synchronizer.d.ts.map +1 -1
  3. package/dest/block_synchronizer/block_synchronizer.js +13 -1
  4. package/dest/config/index.d.ts +2 -2
  5. package/dest/config/index.d.ts.map +1 -1
  6. package/dest/config/index.js +8 -15
  7. package/dest/config/package_info.js +1 -1
  8. package/dest/contract_function_simulator/contract_function_simulator.d.ts +1 -1
  9. package/dest/contract_function_simulator/contract_function_simulator.d.ts.map +1 -1
  10. package/dest/contract_function_simulator/contract_function_simulator.js +3 -5
  11. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +3 -2
  12. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts.map +1 -1
  13. package/dest/contract_function_simulator/oracle/private_execution_oracle.js +10 -5
  14. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +3 -4
  15. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
  16. package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +2 -3
  17. package/dest/contract_function_simulator/pick_notes.d.ts +1 -1
  18. package/dest/contract_function_simulator/pick_notes.d.ts.map +1 -1
  19. package/dest/contract_function_simulator/pick_notes.js +6 -0
  20. package/dest/events/event_service.d.ts +1 -1
  21. package/dest/events/event_service.d.ts.map +1 -1
  22. package/dest/events/event_service.js +10 -1
  23. package/dest/private_kernel/private_kernel_oracle.d.ts +5 -5
  24. package/dest/private_kernel/private_kernel_oracle.d.ts.map +1 -1
  25. package/dest/private_kernel/private_kernel_oracle.js +12 -15
  26. package/dest/pxe.d.ts +3 -2
  27. package/dest/pxe.d.ts.map +1 -1
  28. package/dest/pxe.js +12 -9
  29. package/dest/storage/private_event_store/private_event_store.d.ts +1 -1
  30. package/dest/storage/private_event_store/private_event_store.d.ts.map +1 -1
  31. package/dest/storage/private_event_store/private_event_store.js +3 -0
  32. package/dest/storage/private_event_store/stored_private_event.js +1 -1
  33. package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.d.ts +1 -1
  34. package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.d.ts.map +1 -1
  35. package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.js +1 -1
  36. package/package.json +16 -16
  37. package/src/block_synchronizer/block_synchronizer.ts +16 -2
  38. package/src/config/index.ts +3 -9
  39. package/src/config/package_info.ts +1 -1
  40. package/src/contract_function_simulator/contract_function_simulator.ts +3 -5
  41. package/src/contract_function_simulator/oracle/private_execution_oracle.ts +17 -5
  42. package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +2 -3
  43. package/src/contract_function_simulator/pick_notes.ts +8 -0
  44. package/src/events/event_service.ts +13 -1
  45. package/src/private_kernel/private_kernel_oracle.ts +14 -14
  46. package/src/pxe.ts +10 -7
  47. package/src/storage/private_event_store/private_event_store.ts +4 -0
  48. package/src/storage/private_event_store/stored_private_event.ts +1 -1
  49. package/src/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.ts +3 -1
@@ -2,7 +2,7 @@ import type { Fr } from '@aztec/foundation/curves/bn254';
2
2
  import { createLogger } from '@aztec/foundation/log';
3
3
  import type { EventSelector } from '@aztec/stdlib/abi';
4
4
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
5
- import { siloNullifier } from '@aztec/stdlib/hash';
5
+ import { computePrivateEventCommitment, siloNullifier } from '@aztec/stdlib/hash';
6
6
  import type { AztecNode } from '@aztec/stdlib/interfaces/server';
7
7
  import type { BlockHeader, TxHash } from '@aztec/stdlib/tx';
8
8
 
@@ -26,6 +26,18 @@ export class EventService {
26
26
  txHash: TxHash,
27
27
  scope: AztecAddress,
28
28
  ): Promise<void> {
29
+ // Defense-in-depth: the built-in private-event path derives this commitment from content before enqueueing, but
30
+ // unconstrained PXE-side code (e.g. a custom message handler) can reach this oracle with arbitrary
31
+ // (content, commitment) pairs. Without this check it could bind arbitrary content to a legitimate tx nullifier,
32
+ // causing PXE to surface fabricated event data.
33
+ const recomputedCommitment = await computePrivateEventCommitment(randomness, selector.toField(), content);
34
+ if (!recomputedCommitment.equals(eventCommitment)) {
35
+ this.log.warn(
36
+ `Skipping event whose content does not hash to the provided commitment. contract=${contractAddress}, selector=${selector}, eventCommitment=${eventCommitment}, txHash=${txHash}, recomputedCommitment=${recomputedCommitment}`,
37
+ );
38
+ return;
39
+ }
40
+
29
41
  // While using 'latest' block number would be fine for private events since they cannot be accessed from Aztec.nr
30
42
  // (and thus we're less concerned about being ahead of the synced block), we use the synced block number to
31
43
  // maintain consistent behavior in the PXE. Additionally, events should never be ahead of the synced block here
@@ -7,13 +7,13 @@ import { getVKIndex, getVKSiblingPath } from '@aztec/noir-protocol-circuits-type
7
7
  import { ProtocolContractAddress } from '@aztec/protocol-contracts';
8
8
  import type { FunctionSelector } from '@aztec/stdlib/abi';
9
9
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
10
- import { BlockHash } from '@aztec/stdlib/block';
11
10
  import { type ContractInstanceWithAddress, computeSaltedInitializationHash } from '@aztec/stdlib/contract';
12
11
  import { DelayedPublicMutableValues, DelayedPublicMutableValuesWithHash } from '@aztec/stdlib/delayed-public-mutable';
13
12
  import { computePublicDataTreeLeafSlot } from '@aztec/stdlib/hash';
14
13
  import type { AztecNode } from '@aztec/stdlib/interfaces/client';
15
14
  import { UpdatedClassIdHints } from '@aztec/stdlib/kernel';
16
15
  import type { NullifierMembershipWitness } from '@aztec/stdlib/trees';
16
+ import type { BlockHeader } from '@aztec/stdlib/tx';
17
17
  import type { VerificationKeyAsFields } from '@aztec/stdlib/vks';
18
18
 
19
19
  import type { ContractStore } from '../storage/contract_store/contract_store.js';
@@ -26,7 +26,7 @@ export class PrivateKernelOracle {
26
26
  private contractStore: ContractStore,
27
27
  private keyStore: KeyStore,
28
28
  private node: AztecNode,
29
- private blockHash: BlockHash,
29
+ private blockHeader: BlockHeader,
30
30
  ) {}
31
31
 
32
32
  /** Retrieves the preimage of a contract address from the registered contract instances db. */
@@ -80,22 +80,20 @@ export class PrivateKernelOracle {
80
80
  }
81
81
 
82
82
  /** Returns a membership witness with the sibling path and leaf index in our note hash tree. */
83
- getNoteHashMembershipWitness(noteHash: Fr): Promise<MembershipWitness<typeof NOTE_HASH_TREE_HEIGHT> | undefined> {
84
- return this.node.getNoteHashMembershipWitness(this.blockHash, noteHash);
83
+ async getNoteHashMembershipWitness(
84
+ noteHash: Fr,
85
+ ): Promise<MembershipWitness<typeof NOTE_HASH_TREE_HEIGHT> | undefined> {
86
+ return this.node.getNoteHashMembershipWitness(await this.blockHeader.hash(), noteHash);
85
87
  }
86
88
 
87
89
  /** Returns a membership witness with the sibling path and leaf index in our nullifier indexed merkle tree. */
88
- getNullifierMembershipWitness(nullifier: Fr): Promise<NullifierMembershipWitness | undefined> {
89
- return this.node.getNullifierMembershipWitness(this.blockHash, nullifier);
90
+ async getNullifierMembershipWitness(nullifier: Fr): Promise<NullifierMembershipWitness | undefined> {
91
+ return this.node.getNullifierMembershipWitness(await this.blockHeader.hash(), nullifier);
90
92
  }
91
93
 
92
94
  /** Returns the root of our note hash merkle tree. */
93
- async getNoteHashTreeRoot(): Promise<Fr> {
94
- const header = await this.node.getBlockHeader(this.blockHash);
95
- if (!header) {
96
- throw new Error(`No block header found for block hash ${this.blockHash}`);
97
- }
98
- return header.state.partial.noteHashTree.root;
95
+ getNoteHashTreeRoot(): Fr {
96
+ return this.blockHeader.state.partial.noteHashTree.root;
99
97
  }
100
98
 
101
99
  /**
@@ -126,14 +124,16 @@ export class PrivateKernelOracle {
126
124
  ProtocolContractAddress.ContractInstanceRegistry,
127
125
  delayedPublicMutableHashSlot,
128
126
  );
129
- const updatedClassIdWitness = await this.node.getPublicDataWitness(this.blockHash, hashLeafSlot);
127
+ const blockHash = await this.blockHeader.hash();
128
+
129
+ const updatedClassIdWitness = await this.node.getPublicDataWitness(blockHash, hashLeafSlot);
130
130
 
131
131
  if (!updatedClassIdWitness) {
132
132
  throw new Error(`No public data tree witness found for ${hashLeafSlot}`);
133
133
  }
134
134
 
135
135
  const readStorage = (storageSlot: Fr) =>
136
- this.node.getPublicStorageAt(this.blockHash, ProtocolContractAddress.ContractInstanceRegistry, storageSlot);
136
+ this.node.getPublicStorageAt(blockHash, ProtocolContractAddress.ContractInstanceRegistry, storageSlot);
137
137
  const delayedPublicMutableValues = await DelayedPublicMutableValues.readFromTree(
138
138
  delayedPublicMutableSlot,
139
139
  readStorage,
package/src/pxe.ts CHANGED
@@ -148,6 +148,7 @@ export type PXECreateArgs = {
148
148
  export class PXE {
149
149
  private constructor(
150
150
  private node: AztecNode,
151
+ private db: AztecAsyncKVStore,
151
152
  private blockStateSynchronizer: BlockSynchronizer,
152
153
  private keyStore: KeyStore,
153
154
  private contractStore: ContractStore,
@@ -247,6 +248,7 @@ export class PXE {
247
248
 
248
249
  const pxe = new PXE(
249
250
  node,
251
+ store,
250
252
  synchronizer,
251
253
  keyStore,
252
254
  contractStore,
@@ -484,8 +486,7 @@ export class PXE {
484
486
  config: PrivateKernelExecutionProverConfig,
485
487
  ): Promise<PrivateKernelExecutionProofOutput<PrivateKernelTailCircuitPublicInputs>> {
486
488
  const anchorBlockHeader = await this.anchorBlockStore.getBlockHeader();
487
- const anchorBlockHash = await anchorBlockHeader.hash();
488
- const kernelOracle = new PrivateKernelOracle(this.contractStore, this.keyStore, this.node, anchorBlockHash);
489
+ const kernelOracle = new PrivateKernelOracle(this.contractStore, this.keyStore, this.node, anchorBlockHeader);
489
490
  const kernelTraceProver = new PrivateKernelExecutionProver(
490
491
  kernelOracle,
491
492
  proofCreator,
@@ -579,8 +580,8 @@ export class PXE {
579
580
  if (wasAdded) {
580
581
  this.log.info(`Added sender:\n ${sender.toString()}`);
581
582
  // Wipe the entire sync cache: the new sender's tagged logs could contain notes/events for any contract, so
582
- // all contracts must re-sync to discover them.
583
- this.contractSyncService.wipe();
583
+ // all contracts must re-sync to discover them. Queued to avoid wiping while a job is in flight.
584
+ await this.#putInJobQueue(() => Promise.resolve(this.contractSyncService.wipe()));
584
585
  } else {
585
586
  this.log.info(`Sender:\n "${sender.toString()}"\n already registered.`);
586
587
  }
@@ -1174,9 +1175,11 @@ export class PXE {
1174
1175
  }
1175
1176
 
1176
1177
  /**
1177
- * Stops the PXE's job queue.
1178
+ * Stops the PXE's job queue and closes the backing store.
1178
1179
  */
1179
- public stop(): Promise<void> {
1180
- return this.jobQueue.end();
1180
+ public async stop(): Promise<void> {
1181
+ await this.jobQueue.end();
1182
+ await this.blockStateSynchronizer.stop();
1183
+ await this.db.close();
1181
1184
  }
1182
1185
  }
@@ -234,6 +234,10 @@ export class PrivateEventStore implements StagedStore {
234
234
  * IMPORTANT: This method must be called within a transaction to ensure atomicity.
235
235
  */
236
236
  public async rollback(blockNumber: number, synchedBlockNumber: number): Promise<void> {
237
+ if (this.#eventsForJob.size > 0) {
238
+ throw new Error('PXE private event store rollback is not allowed while jobs are running');
239
+ }
240
+
237
241
  // First pass: collect all event IDs for all blocks, starting reads during iteration to keep tx alive.
238
242
  const eventsByBlock: Map<number, { eventId: string; eventReadPromise: Promise<Buffer | undefined> }[]> = new Map();
239
243
 
@@ -49,7 +49,7 @@ export class StoredPrivateEvent {
49
49
  const msgContentLength = reader.readNumber();
50
50
  const msgContent = reader.readArray(msgContentLength, Fr);
51
51
  const l2BlockNumber = reader.readNumber();
52
- const l2BlockHash = new BlockHash(Fr.fromBuffer(reader));
52
+ const l2BlockHash = BlockHash.fromBuffer(reader);
53
53
  const txHash = TxHash.fromBuffer(reader);
54
54
  const txIndexInBlock = reader.readNumber();
55
55
  const eventIndexInTx = reader.readNumber();
@@ -113,7 +113,9 @@ export async function loadPrivateLogsForSenderRecipientPair(
113
113
 
114
114
  if (highestAgedIndex !== undefined && highestAgedIndex > highestFinalizedIndex) {
115
115
  // This is just a sanity check as this should never happen.
116
- throw new Error('Highest aged index lower than highest finalized index invariant violated');
116
+ throw new Error(
117
+ `Highest aged index (${highestAgedIndex}) must not exceed highest finalized index (${highestFinalizedIndex})`,
118
+ );
117
119
  }
118
120
 
119
121
  await taggingStore.updateHighestFinalizedIndex(secret, highestFinalizedIndex, jobId);