@aztec/pxe 4.0.0-nightly.20260112 → 4.0.0-nightly.20260114

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 (78) 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 +19 -13
  4. package/dest/contract_function_simulator/oracle/interfaces.d.ts +3 -3
  5. package/dest/contract_function_simulator/oracle/interfaces.d.ts.map +1 -1
  6. package/dest/contract_function_simulator/oracle/note_packing_utils.d.ts +4 -4
  7. package/dest/contract_function_simulator/oracle/note_packing_utils.d.ts.map +1 -1
  8. package/dest/contract_function_simulator/oracle/note_packing_utils.js +5 -5
  9. package/dest/contract_function_simulator/oracle/oracle.js +1 -1
  10. package/dest/contract_function_simulator/oracle/private_execution.d.ts +1 -1
  11. package/dest/contract_function_simulator/oracle/private_execution.d.ts.map +1 -1
  12. package/dest/contract_function_simulator/oracle/private_execution.js +1 -2
  13. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +1 -16
  14. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts.map +1 -1
  15. package/dest/contract_function_simulator/oracle/private_execution_oracle.js +4 -31
  16. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +1 -1
  17. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
  18. package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +15 -13
  19. package/dest/events/event_service.d.ts +1 -1
  20. package/dest/events/event_service.d.ts.map +1 -1
  21. package/dest/events/event_service.js +8 -12
  22. package/dest/logs/log_service.d.ts +3 -2
  23. package/dest/logs/log_service.d.ts.map +1 -1
  24. package/dest/logs/log_service.js +4 -2
  25. package/dest/notes/note_service.d.ts +2 -2
  26. package/dest/notes/note_service.d.ts.map +1 -1
  27. package/dest/notes/note_service.js +14 -22
  28. package/dest/private_kernel/hints/build_private_kernel_reset_private_inputs.d.ts +2 -2
  29. package/dest/private_kernel/hints/build_private_kernel_reset_private_inputs.d.ts.map +1 -1
  30. package/dest/private_kernel/hints/build_private_kernel_reset_private_inputs.js +2 -2
  31. package/dest/private_kernel/private_kernel_execution_prover.d.ts +1 -1
  32. package/dest/private_kernel/private_kernel_execution_prover.d.ts.map +1 -1
  33. package/dest/private_kernel/private_kernel_execution_prover.js +3 -4
  34. package/dest/private_kernel/private_kernel_oracle.d.ts +24 -28
  35. package/dest/private_kernel/private_kernel_oracle.d.ts.map +1 -1
  36. package/dest/private_kernel/private_kernel_oracle.js +92 -2
  37. package/dest/pxe.d.ts +7 -36
  38. package/dest/pxe.d.ts.map +1 -1
  39. package/dest/pxe.js +12 -59
  40. package/dest/storage/capsule_store/capsule_store.d.ts +24 -9
  41. package/dest/storage/capsule_store/capsule_store.d.ts.map +1 -1
  42. package/dest/storage/capsule_store/capsule_store.js +132 -23
  43. package/dest/storage/note_store/note_store.d.ts +6 -5
  44. package/dest/storage/note_store/note_store.d.ts.map +1 -1
  45. package/dest/storage/note_store/note_store.js +89 -94
  46. package/dest/storage/private_event_store/private_event_store.d.ts +13 -6
  47. package/dest/storage/private_event_store/private_event_store.d.ts.map +1 -1
  48. package/dest/storage/private_event_store/private_event_store.js +70 -56
  49. package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.d.ts +1 -1
  50. package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.d.ts.map +1 -1
  51. package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.js +1 -1
  52. package/dest/tagging/sender_sync/utils/get_status_change_of_pending.d.ts +1 -1
  53. package/dest/tagging/sender_sync/utils/get_status_change_of_pending.d.ts.map +1 -1
  54. package/dest/tagging/sender_sync/utils/get_status_change_of_pending.js +2 -2
  55. package/package.json +16 -16
  56. package/src/block_synchronizer/block_synchronizer.ts +23 -12
  57. package/src/contract_function_simulator/oracle/interfaces.ts +2 -2
  58. package/src/contract_function_simulator/oracle/note_packing_utils.ts +6 -6
  59. package/src/contract_function_simulator/oracle/oracle.ts +1 -1
  60. package/src/contract_function_simulator/oracle/private_execution.ts +0 -2
  61. package/src/contract_function_simulator/oracle/private_execution_oracle.ts +2 -36
  62. package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +15 -10
  63. package/src/events/event_service.ts +12 -26
  64. package/src/logs/log_service.ts +2 -1
  65. package/src/notes/note_service.ts +14 -23
  66. package/src/private_kernel/hints/build_private_kernel_reset_private_inputs.ts +1 -2
  67. package/src/private_kernel/private_kernel_execution_prover.ts +2 -4
  68. package/src/private_kernel/private_kernel_oracle.ts +119 -36
  69. package/src/pxe.ts +10 -81
  70. package/src/storage/capsule_store/capsule_store.ts +159 -23
  71. package/src/storage/note_store/note_store.ts +98 -95
  72. package/src/storage/private_event_store/private_event_store.ts +92 -65
  73. package/src/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.ts +4 -1
  74. package/src/tagging/sender_sync/utils/get_status_change_of_pending.ts +6 -2
  75. package/dest/private_kernel/private_kernel_oracle_impl.d.ts +0 -46
  76. package/dest/private_kernel/private_kernel_oracle_impl.d.ts.map +0 -1
  77. package/dest/private_kernel/private_kernel_oracle_impl.js +0 -86
  78. package/src/private_kernel/private_kernel_oracle_impl.ts +0 -133
@@ -354,6 +354,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
354
354
  this.recipientTaggingStore,
355
355
  this.senderAddressBookStore,
356
356
  this.addressStore,
357
+ this.jobId,
357
358
  );
358
359
 
359
360
  await logService.syncTaggedLogs(this.contractAddress, pendingTaggedLogArrayBaseSlot, this.scopes);
@@ -385,11 +386,11 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
385
386
  // We read all note and event validation requests and process them all concurrently. This makes the process much
386
387
  // faster as we don't need to wait for the network round-trip.
387
388
  const noteValidationRequests = (
388
- await this.capsuleStore.readCapsuleArray(contractAddress, noteValidationRequestsArrayBaseSlot)
389
+ await this.capsuleStore.readCapsuleArray(contractAddress, noteValidationRequestsArrayBaseSlot, this.jobId)
389
390
  ).map(NoteValidationRequest.fromFields);
390
391
 
391
392
  const eventValidationRequests = (
392
- await this.capsuleStore.readCapsuleArray(contractAddress, eventValidationRequestsArrayBaseSlot)
393
+ await this.capsuleStore.readCapsuleArray(contractAddress, eventValidationRequestsArrayBaseSlot, this.jobId)
393
394
  ).map(EventValidationRequest.fromFields);
394
395
 
395
396
  const noteService = new NoteService(this.noteStore, this.aztecNode, this.anchorBlockStore);
@@ -424,8 +425,8 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
424
425
  await Promise.all([...noteDeliveries, ...eventDeliveries]);
425
426
 
426
427
  // Requests are cleared once we're done.
427
- await this.capsuleStore.setCapsuleArray(contractAddress, noteValidationRequestsArrayBaseSlot, []);
428
- await this.capsuleStore.setCapsuleArray(contractAddress, eventValidationRequestsArrayBaseSlot, []);
428
+ await this.capsuleStore.setCapsuleArray(contractAddress, noteValidationRequestsArrayBaseSlot, [], this.jobId);
429
+ await this.capsuleStore.setCapsuleArray(contractAddress, eventValidationRequestsArrayBaseSlot, [], this.jobId);
429
430
  }
430
431
 
431
432
  public async utilityBulkRetrieveLogs(
@@ -441,7 +442,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
441
442
  // We read all log retrieval requests and process them all concurrently. This makes the process much faster as we
442
443
  // don't need to wait for the network round-trip.
443
444
  const logRetrievalRequests = (
444
- await this.capsuleStore.readCapsuleArray(contractAddress, logRetrievalRequestsArrayBaseSlot)
445
+ await this.capsuleStore.readCapsuleArray(contractAddress, logRetrievalRequestsArrayBaseSlot, this.jobId)
445
446
  ).map(LogRetrievalRequest.fromFields);
446
447
 
447
448
  const logService = new LogService(
@@ -452,18 +453,20 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
452
453
  this.recipientTaggingStore,
453
454
  this.senderAddressBookStore,
454
455
  this.addressStore,
456
+ this.jobId,
455
457
  );
456
458
 
457
459
  const maybeLogRetrievalResponses = await logService.bulkRetrieveLogs(logRetrievalRequests);
458
460
 
459
461
  // Requests are cleared once we're done.
460
- await this.capsuleStore.setCapsuleArray(contractAddress, logRetrievalRequestsArrayBaseSlot, []);
462
+ await this.capsuleStore.setCapsuleArray(contractAddress, logRetrievalRequestsArrayBaseSlot, [], this.jobId);
461
463
 
462
464
  // The responses are stored as Option<LogRetrievalResponse> in a second CapsuleArray.
463
465
  await this.capsuleStore.setCapsuleArray(
464
466
  contractAddress,
465
467
  logRetrievalResponsesArrayBaseSlot,
466
468
  maybeLogRetrievalResponses.map(LogRetrievalResponse.toSerializedOption),
469
+ this.jobId,
467
470
  );
468
471
  }
469
472
 
@@ -472,7 +475,8 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
472
475
  // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
473
476
  throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
474
477
  }
475
- return this.capsuleStore.storeCapsule(this.contractAddress, slot, capsule);
478
+ this.capsuleStore.storeCapsule(this.contractAddress, slot, capsule, this.jobId);
479
+ return Promise.resolve();
476
480
  }
477
481
 
478
482
  public async utilityLoadCapsule(contractAddress: AztecAddress, slot: Fr): Promise<Fr[] | null> {
@@ -483,7 +487,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
483
487
  return (
484
488
  // TODO(#12425): On the following line, the pertinent capsule gets overshadowed by the transient one. Tackle this.
485
489
  this.capsules.find(c => c.contractAddress.equals(contractAddress) && c.storageSlot.equals(slot))?.data ??
486
- (await this.capsuleStore.loadCapsule(this.contractAddress, slot))
490
+ (await this.capsuleStore.loadCapsule(this.contractAddress, slot, this.jobId))
487
491
  );
488
492
  }
489
493
 
@@ -492,7 +496,8 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
492
496
  // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
493
497
  throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
494
498
  }
495
- return this.capsuleStore.deleteCapsule(this.contractAddress, slot);
499
+ this.capsuleStore.deleteCapsule(this.contractAddress, slot, this.jobId);
500
+ return Promise.resolve();
496
501
  }
497
502
 
498
503
  public utilityCopyCapsule(
@@ -505,7 +510,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
505
510
  // TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
506
511
  throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
507
512
  }
508
- return this.capsuleStore.copyCapsule(this.contractAddress, srcSlot, dstSlot, numEntries);
513
+ return this.capsuleStore.copyCapsule(this.contractAddress, srcSlot, dstSlot, numEntries, this.jobId);
509
514
  }
510
515
 
511
516
  // TODO(#11849): consider replacing this oracle with a pure Noir implementation of aes decryption.
@@ -3,7 +3,6 @@ import type { EventSelector } from '@aztec/stdlib/abi';
3
3
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
4
4
  import { siloNullifier } from '@aztec/stdlib/hash';
5
5
  import type { AztecNode } from '@aztec/stdlib/interfaces/server';
6
- import { MerkleTreeId } from '@aztec/stdlib/trees';
7
6
  import type { TxHash } from '@aztec/stdlib/tx';
8
7
 
9
8
  import { AnchorBlockStore } from '../storage/anchor_block_store/anchor_block_store.js';
@@ -45,35 +44,22 @@ export class EventService {
45
44
  throw new Error(`Could not find tx effect for tx hash ${txHash} as of block number ${syncedBlockNumber}`);
46
45
  }
47
46
 
48
- const eventInTx = txEffect.data.nullifiers.some(n => n.equals(siloedEventCommitment));
49
- if (!eventInTx) {
47
+ // Find the index of the event commitment in the nullifiers array to determine event ordering within the tx
48
+ const eventIndexInTx = txEffect.data.nullifiers.findIndex(n => n.equals(siloedEventCommitment));
49
+ if (eventIndexInTx === -1) {
50
50
  throw new Error(
51
51
  `Event commitment ${eventCommitment} (siloed as ${siloedEventCommitment}) is not present in tx ${txHash}`,
52
52
  );
53
53
  }
54
54
 
55
- const [nullifierIndex] = await this.aztecNode.findLeavesIndexes(syncedBlockNumber, MerkleTreeId.NULLIFIER_TREE, [
56
- siloedEventCommitment,
57
- ]);
58
-
59
- if (nullifierIndex === undefined) {
60
- throw new Error(
61
- `Event commitment ${eventCommitment} (siloed as ${siloedEventCommitment}) is not present on the nullifier tree at block ${syncedBlockNumber} (from tx ${txHash})`,
62
- );
63
- }
64
-
65
- return this.privateEventStore.storePrivateEventLog(
66
- selector,
67
- randomness,
68
- content,
69
- Number(nullifierIndex.data), // Index of the event commitment in the nullifier tree
70
- {
71
- contractAddress,
72
- scope,
73
- txHash,
74
- l2BlockNumber: nullifierIndex.l2BlockNumber, // Block number in which the event was emitted
75
- l2BlockHash: nullifierIndex.l2BlockHash, // Block hash in which the event was emitted
76
- },
77
- );
55
+ return this.privateEventStore.storePrivateEventLog(selector, randomness, content, siloedEventCommitment, {
56
+ contractAddress,
57
+ scope,
58
+ txHash,
59
+ l2BlockNumber: txEffect.l2BlockNumber,
60
+ l2BlockHash: txEffect.l2BlockHash,
61
+ txIndexInBlock: txEffect.txIndexInBlock,
62
+ eventIndexInTx,
63
+ });
78
64
  }
79
65
  }
@@ -26,6 +26,7 @@ export class LogService {
26
26
  private readonly recipientTaggingStore: RecipientTaggingStore,
27
27
  private readonly senderAddressBookStore: SenderAddressBookStore,
28
28
  private readonly addressStore: AddressStore,
29
+ private readonly jobId: string,
29
30
  ) {}
30
31
 
31
32
  public async bulkRetrieveLogs(logRetrievalRequests: LogRetrievalRequest[]): Promise<(LogRetrievalResponse | null)[]> {
@@ -186,7 +187,7 @@ export class LogService {
186
187
  });
187
188
 
188
189
  // TODO: This looks like it could belong more at the oracle interface level
189
- return this.capsuleStore.appendToCapsuleArray(contractAddress, capsuleArrayBaseSlot, pendingTaggedLogs);
190
+ return this.capsuleStore.appendToCapsuleArray(contractAddress, capsuleArrayBaseSlot, pendingTaggedLogs, this.jobId);
190
191
  }
191
192
 
192
193
  async #getCompleteAddress(account: AztecAddress): Promise<CompleteAddress> {
@@ -41,7 +41,7 @@ export class NoteService {
41
41
  scopes,
42
42
  });
43
43
  return noteDaos.map(
44
- ({ contractAddress, owner, storageSlot, randomness, noteNonce, note, noteHash, siloedNullifier, index }) => ({
44
+ ({ contractAddress, owner, storageSlot, randomness, noteNonce, note, noteHash, siloedNullifier }) => ({
45
45
  contractAddress,
46
46
  owner,
47
47
  storageSlot,
@@ -49,9 +49,8 @@ export class NoteService {
49
49
  noteNonce,
50
50
  note,
51
51
  noteHash,
52
+ isPending: false, // Note service deals only with settled notes
52
53
  siloedNullifier,
53
- // PXE can use this index to get full MembershipWitness
54
- index,
55
54
  }),
56
55
  );
57
56
  }
@@ -146,7 +145,10 @@ export class NoteService {
146
145
  const uniqueNoteHash = await computeUniqueNoteHash(noteNonce, await siloNoteHash(contractAddress, noteHash));
147
146
  const siloedNullifier = await siloNullifier(contractAddress, nullifier);
148
147
 
149
- const txEffect = await this.aztecNode.getTxEffect(txHash);
148
+ const [txEffect, [nullifierIndex]] = await Promise.all([
149
+ this.aztecNode.getTxEffect(txHash),
150
+ this.aztecNode.findLeavesIndexes(syncedBlockNumber, MerkleTreeId.NULLIFIER_TREE, [siloedNullifier]),
151
+ ]);
150
152
  if (!txEffect) {
151
153
  throw new Error(`Could not find tx effect for tx hash ${txHash}`);
152
154
  }
@@ -155,25 +157,12 @@ export class NoteService {
155
157
  throw new Error(`Could not find tx effect for tx hash ${txHash} as of block number ${syncedBlockNumber}`);
156
158
  }
157
159
 
158
- const noteInTx = txEffect.data.noteHashes.some(nh => nh.equals(uniqueNoteHash));
159
- if (!noteInTx) {
160
+ // Find the index of the note hash in the noteHashes array to determine note ordering within the tx
161
+ const noteIndexInTx = txEffect.data.noteHashes.findIndex(nh => nh.equals(uniqueNoteHash));
162
+ if (noteIndexInTx === -1) {
160
163
  throw new Error(`Note hash ${noteHash} (uniqued as ${uniqueNoteHash}) is not present in tx ${txHash}`);
161
164
  }
162
165
 
163
- // We store notes by their index in the global note hash tree, which has the convenient side effect of validating
164
- // note existence in said tree. We concurrently also check if the note's nullifier exists, performing all node
165
- // queries in a single round-trip.
166
- const [[uniqueNoteHashTreeIndexInBlock], [nullifierIndex]] = await Promise.all([
167
- this.aztecNode.findLeavesIndexes(syncedBlockNumber, MerkleTreeId.NOTE_HASH_TREE, [uniqueNoteHash]),
168
- this.aztecNode.findLeavesIndexes(syncedBlockNumber, MerkleTreeId.NULLIFIER_TREE, [siloedNullifier]),
169
- ]);
170
-
171
- if (uniqueNoteHashTreeIndexInBlock === undefined) {
172
- throw new Error(
173
- `Note hash ${noteHash} (uniqued as ${uniqueNoteHash}) is not present on the tree at block ${syncedBlockNumber} (from tx ${txHash})`,
174
- );
175
- }
176
-
177
166
  const noteDao = new NoteDao(
178
167
  new Note(content),
179
168
  contractAddress,
@@ -184,15 +173,17 @@ export class NoteService {
184
173
  noteHash,
185
174
  siloedNullifier,
186
175
  txHash,
187
- uniqueNoteHashTreeIndexInBlock.l2BlockNumber,
188
- uniqueNoteHashTreeIndexInBlock.l2BlockHash.toString(),
189
- uniqueNoteHashTreeIndexInBlock.data,
176
+ txEffect.l2BlockNumber,
177
+ txEffect.l2BlockHash.toString(),
178
+ txEffect.txIndexInBlock,
179
+ noteIndexInTx,
190
180
  );
191
181
 
192
182
  // The note was found by `recipient`, so we use that as the scope when storing the note.
193
183
  await this.noteStore.addNotes([noteDao], recipient);
194
184
 
195
185
  if (nullifierIndex !== undefined) {
186
+ // We found nullifier index which implies that the note has already been nullified.
196
187
  const { data: _, ...blockHashAndNum } = nullifierIndex;
197
188
  await this.noteStore.applyNullifiers([{ data: siloedNullifier, ...blockHashAndNum }]);
198
189
  }
@@ -138,7 +138,7 @@ export class PrivateKernelResetPrivateInputsBuilder {
138
138
  }
139
139
  }
140
140
 
141
- async build(oracle: PrivateKernelOracle, noteHashLeafIndexMap: Map<bigint, bigint>) {
141
+ async build(oracle: PrivateKernelOracle) {
142
142
  if (privateKernelResetDimensionNames.every(name => !this.requestedDimensions[name])) {
143
143
  throw new Error('Reset is not required.');
144
144
  }
@@ -190,7 +190,6 @@ export class PrivateKernelResetPrivateInputsBuilder {
190
190
  this.previousKernel.validationRequests.noteHashReadRequests,
191
191
  this.previousKernel.end.noteHashes,
192
192
  this.noteHashResetActions,
193
- noteHashLeafIndexMap,
194
193
  ),
195
194
  await buildNullifierReadRequestHintsFromResetActions(
196
195
  { getNullifierMembershipWitness: getNullifierMembershipWitnessResolver(oracle) },
@@ -28,7 +28,6 @@ import {
28
28
  type PrivateCallExecutionResult,
29
29
  type PrivateExecutionResult,
30
30
  TxRequest,
31
- collectNoteHashLeafIndexMap,
32
31
  collectNoteHashNullifierCounterMap,
33
32
  getFinalMinRevertibleSideEffectCounter,
34
33
  } from '@aztec/stdlib/tx';
@@ -101,7 +100,6 @@ export class PrivateKernelExecutionProver {
101
100
 
102
101
  const executionSteps: PrivateExecutionStep[] = [];
103
102
 
104
- const noteHashLeafIndexMap = collectNoteHashLeafIndexMap(executionResult);
105
103
  const noteHashNullifierCounterMap = collectNoteHashNullifierCounterMap(executionResult);
106
104
  const minRevertibleSideEffectCounter = getFinalMinRevertibleSideEffectCounter(executionResult);
107
105
  const splitCounter = isPrivateOnlyTx ? 0 : minRevertibleSideEffectCounter;
@@ -116,7 +114,7 @@ export class PrivateKernelExecutionProver {
116
114
  );
117
115
  while (resetBuilder.needsReset()) {
118
116
  const witgenTimer = new Timer();
119
- const privateInputs = await resetBuilder.build(this.oracle, noteHashLeafIndexMap);
117
+ const privateInputs = await resetBuilder.build(this.oracle);
120
118
  output = generateWitnesses
121
119
  ? await this.proofCreator.generateResetOutput(privateInputs)
122
120
  : await this.proofCreator.simulateReset(privateInputs);
@@ -224,7 +222,7 @@ export class PrivateKernelExecutionProver {
224
222
  );
225
223
  while (resetBuilder.needsReset()) {
226
224
  const witgenTimer = new Timer();
227
- const privateInputs = await resetBuilder.build(this.oracle, noteHashLeafIndexMap);
225
+ const privateInputs = await resetBuilder.build(this.oracle);
228
226
  output = generateWitnesses
229
227
  ? await this.proofCreator.generateResetOutput(privateInputs)
230
228
  : await this.proofCreator.simulateReset(privateInputs);
@@ -1,72 +1,155 @@
1
- import { FUNCTION_TREE_HEIGHT, NOTE_HASH_TREE_HEIGHT, VK_TREE_HEIGHT } from '@aztec/constants';
1
+ import { FUNCTION_TREE_HEIGHT, NOTE_HASH_TREE_HEIGHT, PUBLIC_DATA_TREE_HEIGHT, VK_TREE_HEIGHT } from '@aztec/constants';
2
2
  import type { Fr } from '@aztec/foundation/curves/bn254';
3
3
  import type { GrumpkinScalar, Point } from '@aztec/foundation/curves/grumpkin';
4
4
  import { MembershipWitness } from '@aztec/foundation/trees';
5
+ import type { KeyStore } from '@aztec/key-store';
6
+ import { getVKIndex, getVKSiblingPath } from '@aztec/noir-protocol-circuits-types/vk-tree';
7
+ import { ProtocolContractAddress } from '@aztec/protocol-contracts';
5
8
  import type { FunctionSelector } from '@aztec/stdlib/abi';
6
9
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
10
+ import type { BlockParameter } from '@aztec/stdlib/block';
11
+ import {
12
+ type ContractInstanceWithAddress,
13
+ computeContractClassIdPreimage,
14
+ computeSaltedInitializationHash,
15
+ } from '@aztec/stdlib/contract';
16
+ import { DelayedPublicMutableValues, DelayedPublicMutableValuesWithHash } from '@aztec/stdlib/delayed-public-mutable';
17
+ import { computePublicDataTreeLeafSlot } from '@aztec/stdlib/hash';
18
+ import type { AztecNode } from '@aztec/stdlib/interfaces/client';
7
19
  import { UpdatedClassIdHints } from '@aztec/stdlib/kernel';
8
- import type { PublicKeys } from '@aztec/stdlib/keys';
9
20
  import type { NullifierMembershipWitness } from '@aztec/stdlib/trees';
10
21
  import type { VerificationKeyAsFields } from '@aztec/stdlib/vks';
11
22
 
23
+ import type { ContractStore } from '../storage/contract_store/contract_store.js';
24
+
25
+ // TODO: Block number should not be "latest".
26
+ // It should be fixed at the time the proof is being simulated. I.e., it should be the same as the value defined in the constant data.
27
+
12
28
  /**
13
29
  * Provides functionality needed by the private kernel for interacting with our state trees.
14
- * This is either PrivateKernelOracleImpl, or a mocked test implementation.
15
30
  */
16
- export interface PrivateKernelOracle {
31
+ export class PrivateKernelOracle {
32
+ constructor(
33
+ private contractStore: ContractStore,
34
+ private keyStore: KeyStore,
35
+ private node: AztecNode,
36
+ private blockNumber: BlockParameter = 'latest',
37
+ ) {}
38
+
17
39
  /** Retrieves the preimage of a contract address from the registered contract instances db. */
18
- getContractAddressPreimage(address: AztecAddress): Promise<{
19
- saltedInitializationHash: Fr;
20
- publicKeys: PublicKeys;
21
- currentContractClassId: Fr;
22
- originalContractClassId: Fr;
23
- }>;
40
+ public async getContractAddressPreimage(
41
+ address: AztecAddress,
42
+ ): Promise<ContractInstanceWithAddress & { saltedInitializationHash: Fr }> {
43
+ const instance = await this.contractStore.getContractInstance(address);
44
+ if (!instance) {
45
+ throw new Error(`Contract instance not found when getting address preimage. Contract address: ${address}.`);
46
+ }
47
+ return {
48
+ saltedInitializationHash: await computeSaltedInitializationHash(instance),
49
+ ...instance,
50
+ };
51
+ }
24
52
 
25
53
  /** Retrieves the preimage of a contract class id from the contract classes db. */
26
- getContractClassIdPreimage(
27
- contractClassId: Fr,
28
- ): Promise<{ artifactHash: Fr; publicBytecodeCommitment: Fr; privateFunctionsRoot: Fr }>;
54
+ public async getContractClassIdPreimage(contractClassId: Fr) {
55
+ const contractClass = await this.contractStore.getContractClass(contractClassId);
56
+ if (!contractClass) {
57
+ throw new Error(`Contract class not found when getting class id preimage. Class id: ${contractClassId}.`);
58
+ }
59
+ return computeContractClassIdPreimage(contractClass);
60
+ }
29
61
 
30
- /**
31
- * Returns a membership witness with the sibling path and leaf index in our private functions tree.
32
- */
33
- getFunctionMembershipWitness(
62
+ /** Returns a membership witness with the sibling path and leaf index in our private functions tree. */
63
+ public async getFunctionMembershipWitness(
34
64
  contractClassId: Fr,
35
65
  selector: FunctionSelector,
36
- ): Promise<MembershipWitness<typeof FUNCTION_TREE_HEIGHT>>;
66
+ ): Promise<MembershipWitness<typeof FUNCTION_TREE_HEIGHT>> {
67
+ const membershipWitness = await this.contractStore.getFunctionMembershipWitness(contractClassId, selector);
68
+ if (!membershipWitness) {
69
+ throw new Error(
70
+ `Membership witness not found for contract class id ${contractClassId} and selector ${selector}.`,
71
+ );
72
+ }
73
+ return membershipWitness;
74
+ }
37
75
 
38
76
  /**
39
77
  * Returns a membership witness with the sibling path and leaf index in our protocol VK indexed merkle tree.
40
78
  * Used to validate the previous kernel's verification key.
41
79
  */
42
- getVkMembershipWitness(vk: VerificationKeyAsFields): Promise<MembershipWitness<typeof VK_TREE_HEIGHT>>;
80
+ public getVkMembershipWitness(vk: VerificationKeyAsFields): Promise<MembershipWitness<typeof VK_TREE_HEIGHT>> {
81
+ const leafIndex = getVKIndex(vk);
82
+ return Promise.resolve(new MembershipWitness(VK_TREE_HEIGHT, BigInt(leafIndex), getVKSiblingPath(leafIndex)));
83
+ }
43
84
 
44
- /**
45
- * Returns a membership witness with the sibling path and leaf index in our private function indexed merkle tree.
46
- */ getNoteHashMembershipWitness(leafIndex: bigint): Promise<MembershipWitness<typeof NOTE_HASH_TREE_HEIGHT>>;
85
+ /** Returns a membership witness with the sibling path and leaf index in our note hash tree. */
86
+ getNoteHashMembershipWitness(noteHash: Fr): Promise<MembershipWitness<typeof NOTE_HASH_TREE_HEIGHT> | undefined> {
87
+ return this.node.getNoteHashMembershipWitness(this.blockNumber, noteHash);
88
+ }
47
89
 
48
- /**
49
- * Returns a membership witness with the sibling path and leaf index in our nullifier indexed merkle tree.
50
- */
51
- getNullifierMembershipWitness(nullifier: Fr): Promise<NullifierMembershipWitness | undefined>;
52
- /**
53
- * Returns the root of our note hash merkle tree.
54
- */
55
- getNoteHashTreeRoot(): Promise<Fr>;
90
+ /** Returns a membership witness with the sibling path and leaf index in our nullifier indexed merkle tree. */
91
+ getNullifierMembershipWitness(nullifier: Fr): Promise<NullifierMembershipWitness | undefined> {
92
+ return this.node.getNullifierMembershipWitness(this.blockNumber, nullifier);
93
+ }
94
+
95
+ /** Returns the root of our note hash merkle tree. */
96
+ async getNoteHashTreeRoot(): Promise<Fr> {
97
+ const header = await this.node.getBlockHeader(this.blockNumber);
98
+ if (!header) {
99
+ throw new Error(`No block header found for block number ${this.blockNumber}`);
100
+ }
101
+ return header.state.partial.noteHashTree.root;
102
+ }
56
103
 
57
104
  /**
58
105
  * Retrieves the sk_m corresponding to the pk_m.
59
106
  * @throws If the provided public key is not associated with any of the registered accounts.
60
- * @param pkM - The master public key to get secret key for.
107
+ * @param masterPublicKey - The master public key to get secret key for.
61
108
  * @returns A Promise that resolves to sk_m.
62
109
  * @dev Used when feeding the sk_m to the kernel circuit for keys verification.
63
110
  */
64
- getMasterSecretKey(masterPublicKey: Point): Promise<GrumpkinScalar>;
111
+ public getMasterSecretKey(masterPublicKey: Point): Promise<GrumpkinScalar> {
112
+ return this.keyStore.getMasterSecretKey(masterPublicKey);
113
+ }
65
114
 
66
115
  /** Use debug data to get the function name corresponding to a selector. */
67
- getDebugFunctionName(contractAddress: AztecAddress, selector: FunctionSelector): Promise<string | undefined>;
116
+ public getDebugFunctionName(contractAddress: AztecAddress, selector: FunctionSelector): Promise<string | undefined> {
117
+ return this.contractStore.getDebugFunctionName(contractAddress, selector);
118
+ }
119
+
120
+ /**
121
+ * Returns a membership witness and leaf index to our public data indexed merkle tree,
122
+ * along with an associated DelayedPublicMutable containing the class ID to update.
123
+ */
124
+ public async getUpdatedClassIdHints(contractAddress: AztecAddress): Promise<UpdatedClassIdHints> {
125
+ const { delayedPublicMutableSlot, delayedPublicMutableHashSlot } =
126
+ await DelayedPublicMutableValuesWithHash.getContractUpdateSlots(contractAddress);
127
+
128
+ const hashLeafSlot = await computePublicDataTreeLeafSlot(
129
+ ProtocolContractAddress.ContractInstanceRegistry,
130
+ delayedPublicMutableHashSlot,
131
+ );
132
+ const updatedClassIdWitness = await this.node.getPublicDataWitness(this.blockNumber, hashLeafSlot);
133
+
134
+ if (!updatedClassIdWitness) {
135
+ throw new Error(`No public data tree witness found for ${hashLeafSlot}`);
136
+ }
137
+
138
+ const readStorage = (storageSlot: Fr) =>
139
+ this.node.getPublicStorageAt(this.blockNumber, ProtocolContractAddress.ContractInstanceRegistry, storageSlot);
140
+ const delayedPublicMutableValues = await DelayedPublicMutableValues.readFromTree(
141
+ delayedPublicMutableSlot,
142
+ readStorage,
143
+ );
68
144
 
69
- /** Returns a membership witness and leaf index to our public data indexed merkle tree,
70
- * along with an associated DelayedPublicMutable containing the class ID to update. */
71
- getUpdatedClassIdHints(contractAddress: AztecAddress): Promise<UpdatedClassIdHints>;
145
+ return new UpdatedClassIdHints(
146
+ new MembershipWitness(
147
+ PUBLIC_DATA_TREE_HEIGHT,
148
+ updatedClassIdWitness.index,
149
+ updatedClassIdWitness.siblingPath.toTuple(),
150
+ ),
151
+ updatedClassIdWitness.leafPreimage,
152
+ delayedPublicMutableValues,
153
+ );
154
+ }
72
155
  }
package/src/pxe.ts CHANGED
@@ -19,14 +19,13 @@ import type { AuthWitness } from '@aztec/stdlib/auth-witness';
19
19
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
20
20
  import {
21
21
  CompleteAddress,
22
- type ContractClassWithId,
23
22
  type ContractInstanceWithAddress,
24
23
  type PartialAddress,
25
24
  computeContractAddressFromInstance,
26
25
  getContractClassFromArtifact,
27
26
  } from '@aztec/stdlib/contract';
28
27
  import { SimulationError } from '@aztec/stdlib/errors';
29
- import { computeProtocolNullifier, siloNullifier } from '@aztec/stdlib/hash';
28
+ import { computeProtocolNullifier } from '@aztec/stdlib/hash';
30
29
  import type { AztecNode, PrivateKernelProver } from '@aztec/stdlib/interfaces/client';
31
30
  import type {
32
31
  PrivateExecutionStep,
@@ -69,7 +68,7 @@ import {
69
68
  PrivateKernelExecutionProver,
70
69
  type PrivateKernelExecutionProverConfig,
71
70
  } from './private_kernel/private_kernel_execution_prover.js';
72
- import { PrivateKernelOracleImpl } from './private_kernel/private_kernel_oracle_impl.js';
71
+ import { PrivateKernelOracle } from './private_kernel/private_kernel_oracle.js';
73
72
  import { AddressStore } from './storage/address_store/address_store.js';
74
73
  import { AnchorBlockStore } from './storage/anchor_block_store/anchor_block_store.js';
75
74
  import { CapsuleStore } from './storage/capsule_store/capsule_store.js';
@@ -148,6 +147,7 @@ export class PXE {
148
147
  const tipsStore = new L2TipsKVStore(store, 'pxe');
149
148
  const synchronizer = new BlockSynchronizer(
150
149
  node,
150
+ store,
151
151
  anchorBlockStore,
152
152
  noteStore,
153
153
  privateEventStore,
@@ -157,6 +157,7 @@ export class PXE {
157
157
  );
158
158
 
159
159
  const jobCoordinator = new JobCoordinator(store);
160
+ jobCoordinator.registerStores([capsuleStore]);
160
161
 
161
162
  const debugUtils = new PXEDebugUtils(contractStore, noteStore);
162
163
 
@@ -274,19 +275,6 @@ export class PXE {
274
275
  this.log.verbose(`Registered protocol contracts in pxe`, registered);
275
276
  }
276
277
 
277
- async #isContractClassPubliclyRegistered(id: Fr): Promise<boolean> {
278
- return !!(await this.node.getContractClass(id));
279
- }
280
-
281
- async #isContractPublished(address: AztecAddress): Promise<boolean> {
282
- return !!(await this.node.getContract(address));
283
- }
284
-
285
- async #isContractInitialized(address: AztecAddress): Promise<boolean> {
286
- const initNullifier = await siloNullifier(address, address.toField());
287
- return !!(await this.node.getNullifierMembershipWitness('latest', initNullifier));
288
- }
289
-
290
278
  // Executes the entrypoint private function, as well as all nested private
291
279
  // functions that might arise.
292
280
  async #executePrivate(
@@ -395,12 +383,7 @@ export class PXE {
395
383
  config: PrivateKernelExecutionProverConfig,
396
384
  ): Promise<PrivateKernelExecutionProofOutput<PrivateKernelTailCircuitPublicInputs>> {
397
385
  const simulationAnchorBlock = privateExecutionResult.getSimulationAnchorBlockNumber();
398
- const kernelOracle = new PrivateKernelOracleImpl(
399
- this.contractStore,
400
- this.keyStore,
401
- this.node,
402
- simulationAnchorBlock,
403
- );
386
+ const kernelOracle = new PrivateKernelOracle(this.contractStore, this.keyStore, this.node, simulationAnchorBlock);
404
387
  const kernelTraceProver = new PrivateKernelExecutionProver(kernelOracle, proofCreator, !this.proverEnabled);
405
388
  this.log.debug(`Executing kernel trace prover (${JSON.stringify(config)})...`);
406
389
  return await kernelTraceProver.proveWithKernels(txExecutionRequest.toTxRequest(), privateExecutionResult, config);
@@ -413,66 +396,12 @@ export class PXE {
413
396
  }
414
397
 
415
398
  /**
416
- * Returns the contract class metadata given a contract class id.
417
- * The metadata consists of its contract class, whether it has been publicly registered, and its artifact.
418
- * @remark - it queries the node to check whether the contract class with the given id has been publicly registered.
419
- * @param id - Identifier of the class.
420
- * @param includeArtifact - Identifier of the class.
421
- * @returns - It returns the contract class metadata, with the artifact field being optional, and will only be returned if true is passed in
422
- * for `includeArtifact`
423
- * TODO(@spalladino): The PXE actually holds artifacts and not classes, what should we return? Also,
424
- * should the pxe query the node for contract public info, and merge it with its own definitions?
425
- * TODO(@spalladino): This method is strictly needed to decide whether to publicly register a class or not
426
- * during a public deployment. We probably want a nicer and more general API for this, but it'll have to
427
- * do for the time being.
399
+ * Returns the contract artifact for a given contract class id, if it's registered in the PXE.
400
+ * @param id - Identifier of the contract class.
401
+ * @returns The contract artifact if found, undefined otherwise.
428
402
  */
429
- public async getContractClassMetadata(
430
- id: Fr,
431
- includeArtifact: boolean = false,
432
- ): Promise<{
433
- contractClass: ContractClassWithId | undefined;
434
- isContractClassPubliclyRegistered: boolean;
435
- artifact: ContractArtifact | undefined;
436
- }> {
437
- const artifact = await this.contractStore.getContractArtifact(id);
438
- if (!artifact) {
439
- this.log.warn(`No artifact found for contract class ${id.toString()} when looking for its metadata`);
440
- }
441
-
442
- return {
443
- contractClass: artifact && (await getContractClassFromArtifact(artifact)),
444
- isContractClassPubliclyRegistered: await this.#isContractClassPubliclyRegistered(id),
445
- artifact: includeArtifact ? artifact : undefined,
446
- };
447
- }
448
-
449
- /**
450
- * Returns the contract metadata given an address.
451
- * The metadata consists of its contract instance, which includes the contract class identifier,
452
- * initialization hash, deployment salt, and public keys hash; whether the contract instance has been initialized;
453
- * and whether the contract instance with the given address has been publicly deployed.
454
- * @remark - it queries the node to check whether the contract instance has been initialized / publicly deployed through a node.
455
- * This query is not dependent on the PXE.
456
- * @param address - The address that the contract instance resides at.
457
- * @returns - It returns the contract metadata
458
- * TODO(@spalladino): Should we return the public keys in plain as well here?
459
- */
460
- public async getContractMetadata(address: AztecAddress): Promise<{
461
- contractInstance: ContractInstanceWithAddress | undefined;
462
- isContractInitialized: boolean;
463
- isContractPublished: boolean;
464
- }> {
465
- let instance;
466
- try {
467
- instance = await this.contractStore.getContractInstance(address);
468
- } catch {
469
- this.log.warn(`No instance found for contract ${address.toString()} when looking for its metadata`);
470
- }
471
- return {
472
- contractInstance: instance,
473
- isContractInitialized: await this.#isContractInitialized(address),
474
- isContractPublished: await this.#isContractPublished(address),
475
- };
403
+ public async getContractArtifact(id: Fr): Promise<ContractArtifact | undefined> {
404
+ return await this.contractStore.getContractArtifact(id);
476
405
  }
477
406
 
478
407
  /**