@aztec/pxe 0.75.0-commit.c03ba01a2a4122e43e90d5133ba017e54b90e9d2 → 0.75.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 (101) hide show
  1. package/dest/bin/index.d.ts +3 -0
  2. package/dest/bin/index.d.ts.map +1 -0
  3. package/dest/bin/index.js +5 -3
  4. package/dest/config/index.d.ts +46 -0
  5. package/dest/config/index.d.ts.map +1 -0
  6. package/dest/config/index.js +21 -18
  7. package/dest/config/package_info.d.ts +5 -0
  8. package/dest/config/package_info.d.ts.map +1 -0
  9. package/dest/config/package_info.js +2 -4
  10. package/dest/contract_data_oracle/index.d.ts +104 -0
  11. package/dest/contract_data_oracle/index.d.ts.map +1 -0
  12. package/dest/contract_data_oracle/index.js +79 -69
  13. package/dest/contract_data_oracle/private_functions_tree.d.ts +65 -0
  14. package/dest/contract_data_oracle/private_functions_tree.d.ts.map +1 -0
  15. package/dest/contract_data_oracle/private_functions_tree.js +50 -44
  16. package/dest/database/contracts/contract_artifact_db.d.ts +20 -0
  17. package/dest/database/contracts/contract_artifact_db.d.ts.map +1 -0
  18. package/dest/database/contracts/contract_artifact_db.js +2 -3
  19. package/dest/database/contracts/contract_instance_db.d.ts +19 -0
  20. package/dest/database/contracts/contract_instance_db.d.ts.map +1 -0
  21. package/dest/database/contracts/contract_instance_db.js +2 -3
  22. package/dest/database/index.d.ts +3 -0
  23. package/dest/database/index.d.ts.map +1 -0
  24. package/dest/database/index.js +1 -0
  25. package/dest/database/kv_pxe_database.d.ts +55 -0
  26. package/dest/database/kv_pxe_database.d.ts.map +1 -0
  27. package/dest/database/kv_pxe_database.js +259 -243
  28. package/dest/database/note_dao.d.ts +103 -0
  29. package/dest/database/note_dao.d.ts.map +1 -0
  30. package/dest/database/note_dao.js +43 -28
  31. package/dest/database/outgoing_note_dao.d.ts +73 -0
  32. package/dest/database/outgoing_note_dao.d.ts.map +1 -0
  33. package/dest/database/outgoing_note_dao.js +34 -20
  34. package/dest/database/pxe_database.d.ts +216 -0
  35. package/dest/database/pxe_database.d.ts.map +1 -0
  36. package/dest/database/pxe_database.js +2 -4
  37. package/dest/database/pxe_database_test_suite.d.ts +7 -0
  38. package/dest/database/pxe_database_test_suite.d.ts.map +1 -0
  39. package/dest/database/pxe_database_test_suite.js +151 -296
  40. package/dest/index.d.ts +15 -0
  41. package/dest/index.d.ts.map +1 -0
  42. package/dest/index.js +1 -0
  43. package/dest/kernel_oracle/index.d.ts +34 -0
  44. package/dest/kernel_oracle/index.d.ts.map +1 -0
  45. package/dest/kernel_oracle/index.js +6 -9
  46. package/dest/kernel_prover/hints/build_private_kernel_reset_private_inputs.d.ts +28 -0
  47. package/dest/kernel_prover/hints/build_private_kernel_reset_private_inputs.d.ts.map +1 -0
  48. package/dest/kernel_prover/hints/build_private_kernel_reset_private_inputs.js +66 -68
  49. package/dest/kernel_prover/hints/index.d.ts +2 -0
  50. package/dest/kernel_prover/hints/index.d.ts.map +1 -0
  51. package/dest/kernel_prover/hints/index.js +1 -0
  52. package/dest/kernel_prover/index.d.ts +3 -0
  53. package/dest/kernel_prover/index.d.ts.map +1 -0
  54. package/dest/kernel_prover/index.js +1 -0
  55. package/dest/kernel_prover/kernel_prover.d.ts +38 -0
  56. package/dest/kernel_prover/kernel_prover.d.ts.map +1 -0
  57. package/dest/kernel_prover/kernel_prover.js +65 -60
  58. package/dest/kernel_prover/proving_data_oracle.d.ts +65 -0
  59. package/dest/kernel_prover/proving_data_oracle.d.ts.map +1 -0
  60. package/dest/kernel_prover/proving_data_oracle.js +2 -4
  61. package/dest/note_decryption_utils/add_public_values_to_payload.d.ts +10 -0
  62. package/dest/note_decryption_utils/add_public_values_to_payload.d.ts.map +1 -0
  63. package/dest/note_decryption_utils/add_public_values_to_payload.js +9 -8
  64. package/dest/pxe_http/index.d.ts +2 -0
  65. package/dest/pxe_http/index.d.ts.map +1 -0
  66. package/dest/pxe_http/index.js +1 -0
  67. package/dest/pxe_http/pxe_http_server.d.ts +16 -0
  68. package/dest/pxe_http/pxe_http_server.d.ts.map +1 -0
  69. package/dest/pxe_http/pxe_http_server.js +6 -8
  70. package/dest/pxe_service/error_enriching.d.ts +11 -0
  71. package/dest/pxe_service/error_enriching.d.ts.map +1 -0
  72. package/dest/pxe_service/error_enriching.js +13 -10
  73. package/dest/pxe_service/index.d.ts +4 -0
  74. package/dest/pxe_service/index.d.ts.map +1 -0
  75. package/dest/pxe_service/index.js +1 -0
  76. package/dest/pxe_service/pxe_service.d.ts +98 -0
  77. package/dest/pxe_service/pxe_service.d.ts.map +1 -0
  78. package/dest/pxe_service/pxe_service.js +290 -282
  79. package/dest/pxe_service/test/pxe_test_suite.d.ts +3 -0
  80. package/dest/pxe_service/test/pxe_test_suite.d.ts.map +1 -0
  81. package/dest/pxe_service/test/pxe_test_suite.js +27 -40
  82. package/dest/simulator/index.d.ts +10 -0
  83. package/dest/simulator/index.d.ts.map +1 -0
  84. package/dest/simulator/index.js +3 -1
  85. package/dest/simulator_oracle/index.d.ts +129 -0
  86. package/dest/simulator_oracle/index.d.ts.map +1 -0
  87. package/dest/simulator_oracle/index.js +231 -266
  88. package/dest/simulator_oracle/tagging_utils.d.ts +16 -0
  89. package/dest/simulator_oracle/tagging_utils.d.ts.map +1 -0
  90. package/dest/simulator_oracle/tagging_utils.js +6 -4
  91. package/dest/synchronizer/index.d.ts +2 -0
  92. package/dest/synchronizer/index.d.ts.map +1 -0
  93. package/dest/synchronizer/index.js +1 -0
  94. package/dest/synchronizer/synchronizer.d.ts +30 -0
  95. package/dest/synchronizer/synchronizer.d.ts.map +1 -0
  96. package/dest/synchronizer/synchronizer.js +42 -42
  97. package/dest/utils/create_pxe_service.d.ts +16 -0
  98. package/dest/utils/create_pxe_service.d.ts.map +1 -0
  99. package/dest/utils/create_pxe_service.js +9 -9
  100. package/package.json +15 -15
  101. package/src/pxe_service/pxe_service.ts +10 -5
@@ -1,11 +1,13 @@
1
- import { L1NotePayload, MerkleTreeId, Note, TxHash, getNonNullifiedL1ToL2MessageWitness } from '@aztec/circuit-types';
2
- import { Fr, FunctionSelector, IndexedTaggingSecret, MAX_NOTE_HASHES_PER_TX, PRIVATE_LOG_SIZE_IN_FIELDS, PrivateLog, PublicLog, computeAddressSecret, computeTaggingSecretPoint } from '@aztec/circuits.js';
1
+ var _SimulatorOracle_instances, _SimulatorOracle_findLeafIndex, _SimulatorOracle_getSiblingPath, _SimulatorOracle_calculateAppTaggingSecret, _SimulatorOracle_getIndexedTaggingSecretsForSenders, _SimulatorOracle_decryptTaggedLogs;
2
+ import { __classPrivateFieldGet } from "tslib";
3
+ import { L1NotePayload, MerkleTreeId, Note, TxHash, getNonNullifiedL1ToL2MessageWitness, } from '@aztec/circuit-types';
4
+ import { Fr, FunctionSelector, IndexedTaggingSecret, MAX_NOTE_HASHES_PER_TX, PRIVATE_LOG_SIZE_IN_FIELDS, PrivateLog, PublicLog, computeAddressSecret, computeTaggingSecretPoint, } from '@aztec/circuits.js';
3
5
  import { computeUniqueNoteHash, siloNoteHash, siloNullifier } from '@aztec/circuits.js/hash';
4
- import { FunctionType, NoteSelector, encodeArguments, getFunctionArtifact } from '@aztec/foundation/abi';
6
+ import { FunctionType, NoteSelector, encodeArguments, getFunctionArtifact, } from '@aztec/foundation/abi';
5
7
  import { timesParallel } from '@aztec/foundation/collection';
6
8
  import { poseidon2Hash } from '@aztec/foundation/crypto';
7
9
  import { createLogger } from '@aztec/foundation/log';
8
- import { MessageLoadOracleInputs } from '@aztec/simulator/client';
10
+ import { MessageLoadOracleInputs, } from '@aztec/simulator/client';
9
11
  import { ContractDataOracle } from '../contract_data_oracle/index.js';
10
12
  import { NoteDao } from '../database/note_dao.js';
11
13
  import { getOrderedNoteItems } from '../note_decryption_utils/add_public_values_to_payload.js';
@@ -13,14 +15,10 @@ import { getAcirSimulator } from '../simulator/index.js';
13
15
  import { WINDOW_HALF_SIZE, getIndexedTaggingSecretsForTheWindow, getInitialIndexesMap } from './tagging_utils.js';
14
16
  /**
15
17
  * A data oracle that provides information needed for simulating a transaction.
16
- */ export class SimulatorOracle {
17
- contractDataOracle;
18
- db;
19
- keyStore;
20
- aztecNode;
21
- simulationProvider;
22
- log;
23
- constructor(contractDataOracle, db, keyStore, aztecNode, simulationProvider, log = createLogger('pxe:simulator_oracle')){
18
+ */
19
+ export class SimulatorOracle {
20
+ constructor(contractDataOracle, db, keyStore, aztecNode, simulationProvider, log = createLogger('pxe:simulator_oracle')) {
21
+ _SimulatorOracle_instances.add(this);
24
22
  this.contractDataOracle = contractDataOracle;
25
23
  this.db = db;
26
24
  this.keyStore = keyStore;
@@ -65,25 +63,25 @@ import { WINDOW_HALF_SIZE, getIndexedTaggingSecretsForTheWindow, getInitialIndex
65
63
  contractAddress,
66
64
  storageSlot,
67
65
  status,
68
- scopes
66
+ scopes,
69
67
  });
70
- return noteDaos.map(({ contractAddress, storageSlot, nonce, note, noteHash, siloedNullifier, index })=>({
71
- contractAddress,
72
- storageSlot,
73
- nonce,
74
- note,
75
- noteHash,
76
- siloedNullifier,
77
- // PXE can use this index to get full MembershipWitness
78
- index
79
- }));
68
+ return noteDaos.map(({ contractAddress, storageSlot, nonce, note, noteHash, siloedNullifier, index }) => ({
69
+ contractAddress,
70
+ storageSlot,
71
+ nonce,
72
+ note,
73
+ noteHash,
74
+ siloedNullifier,
75
+ // PXE can use this index to get full MembershipWitness
76
+ index,
77
+ }));
80
78
  }
81
79
  async getFunctionArtifact(contractAddress, selector) {
82
80
  const artifact = await this.contractDataOracle.getFunctionArtifact(contractAddress, selector);
83
81
  const debug = await this.contractDataOracle.getFunctionDebugMetadata(contractAddress, selector);
84
82
  return {
85
83
  ...artifact,
86
- debug
84
+ debug,
87
85
  };
88
86
  }
89
87
  async getFunctionArtifactByName(contractAddress, functionName) {
@@ -92,13 +90,14 @@ import { WINDOW_HALF_SIZE, getIndexedTaggingSecretsForTheWindow, getInitialIndex
92
90
  return artifact && getFunctionArtifact(artifact, functionName);
93
91
  }
94
92
  /**
95
- * Fetches a message from the db, given its key.
96
- * @param contractAddress - Address of a contract by which the message was emitted.
97
- * @param messageHash - Hash of the message.
98
- * @param secret - Secret used to compute a nullifier.
99
- * @dev Contract address and secret are only used to compute the nullifier to get non-nullified messages
100
- * @returns The l1 to l2 membership witness (index of message in the tree and sibling path).
101
- */ async getL1ToL2MembershipWitness(contractAddress, messageHash, secret) {
93
+ * Fetches a message from the db, given its key.
94
+ * @param contractAddress - Address of a contract by which the message was emitted.
95
+ * @param messageHash - Hash of the message.
96
+ * @param secret - Secret used to compute a nullifier.
97
+ * @dev Contract address and secret are only used to compute the nullifier to get non-nullified messages
98
+ * @returns The l1 to l2 membership witness (index of message in the tree and sibling path).
99
+ */
100
+ async getL1ToL2MembershipWitness(contractAddress, messageHash, secret) {
102
101
  const [messageIndex, siblingPath] = await getNonNullifiedL1ToL2MessageWitness(this.aztecNode, contractAddress, messageHash, secret);
103
102
  // Assuming messageIndex is what you intended to use for the index in MessageLoadOracleInputs
104
103
  return new MessageLoadOracleInputs(messageIndex, siblingPath);
@@ -108,49 +107,27 @@ import { WINDOW_HALF_SIZE, getIndexedTaggingSecretsForTheWindow, getInitialIndex
108
107
  throw new Error('Unimplemented in private!');
109
108
  }
110
109
  /**
111
- * Gets the index of a commitment in the note hash tree.
112
- * @param commitment - The commitment.
113
- * @returns - The index of the commitment. Undefined if it does not exist in the tree.
114
- */ async getCommitmentIndex(commitment) {
115
- return await this.#findLeafIndex('latest', MerkleTreeId.NOTE_HASH_TREE, commitment);
110
+ * Gets the index of a commitment in the note hash tree.
111
+ * @param commitment - The commitment.
112
+ * @returns - The index of the commitment. Undefined if it does not exist in the tree.
113
+ */
114
+ async getCommitmentIndex(commitment) {
115
+ return await __classPrivateFieldGet(this, _SimulatorOracle_instances, "m", _SimulatorOracle_findLeafIndex).call(this, 'latest', MerkleTreeId.NOTE_HASH_TREE, commitment);
116
116
  }
117
117
  // We need this in public as part of the EXISTS calls - but isn't used in private
118
118
  getCommitmentValue(_leafIndex) {
119
119
  throw new Error('Unimplemented in private!');
120
120
  }
121
121
  async getNullifierIndex(nullifier) {
122
- return await this.#findLeafIndex('latest', MerkleTreeId.NULLIFIER_TREE, nullifier);
123
- }
124
- async #findLeafIndex(blockNumber, treeId, leafValue) {
125
- const [leafIndex] = await this.aztecNode.findLeavesIndexes(blockNumber, treeId, [
126
- leafValue
127
- ]);
128
- return leafIndex;
122
+ return await __classPrivateFieldGet(this, _SimulatorOracle_instances, "m", _SimulatorOracle_findLeafIndex).call(this, 'latest', MerkleTreeId.NULLIFIER_TREE, nullifier);
129
123
  }
130
124
  async getMembershipWitness(blockNumber, treeId, leafValue) {
131
- const leafIndex = await this.#findLeafIndex(blockNumber, treeId, leafValue);
125
+ const leafIndex = await __classPrivateFieldGet(this, _SimulatorOracle_instances, "m", _SimulatorOracle_findLeafIndex).call(this, blockNumber, treeId, leafValue);
132
126
  if (!leafIndex) {
133
127
  throw new Error(`Leaf value: ${leafValue} not found in ${MerkleTreeId[treeId]}`);
134
128
  }
135
- const siblingPath = await this.#getSiblingPath(blockNumber, treeId, leafIndex);
136
- return [
137
- new Fr(leafIndex),
138
- ...siblingPath
139
- ];
140
- }
141
- async #getSiblingPath(blockNumber, treeId, leafIndex) {
142
- switch(treeId){
143
- case MerkleTreeId.NULLIFIER_TREE:
144
- return (await this.aztecNode.getNullifierSiblingPath(blockNumber, leafIndex)).toFields();
145
- case MerkleTreeId.NOTE_HASH_TREE:
146
- return (await this.aztecNode.getNoteHashSiblingPath(blockNumber, leafIndex)).toFields();
147
- case MerkleTreeId.PUBLIC_DATA_TREE:
148
- return (await this.aztecNode.getPublicDataSiblingPath(blockNumber, leafIndex)).toFields();
149
- case MerkleTreeId.ARCHIVE:
150
- return (await this.aztecNode.getArchiveSiblingPath(blockNumber, leafIndex)).toFields();
151
- default:
152
- throw new Error('Not implemented');
153
- }
129
+ const siblingPath = await __classPrivateFieldGet(this, _SimulatorOracle_instances, "m", _SimulatorOracle_getSiblingPath).call(this, blockNumber, treeId, leafIndex);
130
+ return [new Fr(leafIndex), ...siblingPath];
154
131
  }
155
132
  async getNullifierMembershipWitnessAtLatestBlock(nullifier) {
156
133
  return this.getNullifierMembershipWitness(await this.getBlockNumber(), nullifier);
@@ -168,118 +145,76 @@ import { WINDOW_HALF_SIZE, getIndexedTaggingSecretsForTheWindow, getInitialIndex
168
145
  return await this.aztecNode.getPublicDataTreeWitness(blockNumber, leafSlot);
169
146
  }
170
147
  /**
171
- * Retrieve the databases view of the Block Header object.
172
- * This structure is fed into the circuits simulator and is used to prove against certain historical roots.
173
- *
174
- * @returns A Promise that resolves to a BlockHeader object.
175
- */ getBlockHeader() {
148
+ * Retrieve the databases view of the Block Header object.
149
+ * This structure is fed into the circuits simulator and is used to prove against certain historical roots.
150
+ *
151
+ * @returns A Promise that resolves to a BlockHeader object.
152
+ */
153
+ getBlockHeader() {
176
154
  return this.db.getBlockHeader();
177
155
  }
178
156
  /**
179
- * Fetches the current block number.
180
- * @returns The block number.
181
- */ async getBlockNumber() {
157
+ * Fetches the current block number.
158
+ * @returns The block number.
159
+ */
160
+ async getBlockNumber() {
182
161
  return await this.aztecNode.getBlockNumber();
183
162
  }
184
163
  getDebugFunctionName(contractAddress, selector) {
185
164
  return this.contractDataOracle.getDebugFunctionName(contractAddress, selector);
186
165
  }
187
166
  /**
188
- * Returns the full contents of your address book.
189
- * This is used when calculating tags for incoming notes by deriving the shared secret, the contract-siloed tagging secret, and
190
- * finally the index specified tag. We will then query the node with this tag for each address in the address book.
191
- * @returns The full list of the users contact addresses.
192
- */ getSenders() {
167
+ * Returns the full contents of your address book.
168
+ * This is used when calculating tags for incoming notes by deriving the shared secret, the contract-siloed tagging secret, and
169
+ * finally the index specified tag. We will then query the node with this tag for each address in the address book.
170
+ * @returns The full list of the users contact addresses.
171
+ */
172
+ getSenders() {
193
173
  return this.db.getSenderAddresses();
194
174
  }
195
175
  /**
196
- * Returns the tagging secret for a given sender and recipient pair. For this to work, the ivsk_m of the sender must be known.
197
- * Includes the next index to be used used for tagging with this secret.
198
- * @param contractAddress - The contract address to silo the secret for
199
- * @param sender - The address sending the note
200
- * @param recipient - The address receiving the note
201
- * @returns An indexed tagging secret that can be used to tag notes.
202
- */ async getIndexedTaggingSecretAsSender(contractAddress, sender, recipient) {
176
+ * Returns the tagging secret for a given sender and recipient pair. For this to work, the ivsk_m of the sender must be known.
177
+ * Includes the next index to be used used for tagging with this secret.
178
+ * @param contractAddress - The contract address to silo the secret for
179
+ * @param sender - The address sending the note
180
+ * @param recipient - The address receiving the note
181
+ * @returns An indexed tagging secret that can be used to tag notes.
182
+ */
183
+ async getIndexedTaggingSecretAsSender(contractAddress, sender, recipient) {
203
184
  await this.syncTaggedLogsAsSender(contractAddress, sender, recipient);
204
- const appTaggingSecret = await this.#calculateAppTaggingSecret(contractAddress, sender, recipient);
205
- const [index] = await this.db.getTaggingSecretsIndexesAsSender([
206
- appTaggingSecret
207
- ]);
185
+ const appTaggingSecret = await __classPrivateFieldGet(this, _SimulatorOracle_instances, "m", _SimulatorOracle_calculateAppTaggingSecret).call(this, contractAddress, sender, recipient);
186
+ const [index] = await this.db.getTaggingSecretsIndexesAsSender([appTaggingSecret]);
208
187
  return new IndexedTaggingSecret(appTaggingSecret, index);
209
188
  }
210
189
  /**
211
- * Increments the tagging secret for a given sender and recipient pair. For this to work, the ivsk_m of the sender must be known.
212
- * @param contractAddress - The contract address to silo the secret for
213
- * @param sender - The address sending the note
214
- * @param recipient - The address receiving the note
215
- */ async incrementAppTaggingSecretIndexAsSender(contractAddress, sender, recipient) {
216
- const secret = await this.#calculateAppTaggingSecret(contractAddress, sender, recipient);
190
+ * Increments the tagging secret for a given sender and recipient pair. For this to work, the ivsk_m of the sender must be known.
191
+ * @param contractAddress - The contract address to silo the secret for
192
+ * @param sender - The address sending the note
193
+ * @param recipient - The address receiving the note
194
+ */
195
+ async incrementAppTaggingSecretIndexAsSender(contractAddress, sender, recipient) {
196
+ const secret = await __classPrivateFieldGet(this, _SimulatorOracle_instances, "m", _SimulatorOracle_calculateAppTaggingSecret).call(this, contractAddress, sender, recipient);
217
197
  const contractName = await this.contractDataOracle.getDebugContractName(contractAddress);
218
198
  this.log.debug(`Incrementing app tagging secret at ${contractName}(${contractAddress})`, {
219
199
  secret,
220
200
  sender,
221
201
  recipient,
222
202
  contractName,
223
- contractAddress
203
+ contractAddress,
224
204
  });
225
- const [index] = await this.db.getTaggingSecretsIndexesAsSender([
226
- secret
227
- ]);
228
- await this.db.setTaggingSecretsIndexesAsSender([
229
- new IndexedTaggingSecret(secret, index + 1)
230
- ]);
231
- }
232
- async #calculateAppTaggingSecret(contractAddress, sender, recipient) {
233
- const senderCompleteAddress = await this.getCompleteAddress(sender);
234
- const senderIvsk = await this.keyStore.getMasterIncomingViewingSecretKey(sender);
235
- const secretPoint = await computeTaggingSecretPoint(senderCompleteAddress, senderIvsk, recipient);
236
- // Silo the secret so it can't be used to track other app's notes
237
- const appSecret = poseidon2Hash([
238
- secretPoint.x,
239
- secretPoint.y,
240
- contractAddress
241
- ]);
242
- return appSecret;
205
+ const [index] = await this.db.getTaggingSecretsIndexesAsSender([secret]);
206
+ await this.db.setTaggingSecretsIndexesAsSender([new IndexedTaggingSecret(secret, index + 1)]);
243
207
  }
244
208
  /**
245
- * Returns the indexed tagging secrets for a given recipient and all the senders in the address book
246
- * This method should be exposed as an oracle call to allow aztec.nr to perform the orchestration
247
- * of the syncTaggedLogs and processTaggedLogs methods. However, it is not possible to do so at the moment,
248
- * so we're keeping it private for now.
249
- * @param contractAddress - The contract address to silo the secret for
250
- * @param recipient - The address receiving the notes
251
- * @returns A list of indexed tagging secrets
252
- */ async #getIndexedTaggingSecretsForSenders(contractAddress, recipient) {
253
- const recipientCompleteAddress = await this.getCompleteAddress(recipient);
254
- const recipientIvsk = await this.keyStore.getMasterIncomingViewingSecretKey(recipient);
255
- // We implicitly add all PXE accounts as senders, this helps us decrypt tags on notes that we send to ourselves
256
- // (recipient = us, sender = us)
257
- const senders = [
258
- ...await this.db.getSenderAddresses(),
259
- ...await this.keyStore.getAccounts()
260
- ].filter((address, index, self)=>index === self.findIndex((otherAddress)=>otherAddress.equals(address)));
261
- const appTaggingSecrets = await Promise.all(senders.map(async (contact)=>{
262
- const sharedSecret = await computeTaggingSecretPoint(recipientCompleteAddress, recipientIvsk, contact);
263
- return poseidon2Hash([
264
- sharedSecret.x,
265
- sharedSecret.y,
266
- contractAddress
267
- ]);
268
- }));
269
- const indexes = await this.db.getTaggingSecretsIndexesAsRecipient(appTaggingSecrets);
270
- return appTaggingSecrets.map((secret, i)=>new IndexedTaggingSecret(secret, indexes[i]));
271
- }
272
- /**
273
- * Updates the local index of the shared tagging secret of a sender / recipient pair
274
- * if a log with a larger index is found from the node.
275
- * @param contractAddress - The address of the contract that the logs are tagged for
276
- * @param sender - The address of the sender, we must know the sender's ivsk_m.
277
- * @param recipient - The address of the recipient.
278
- */ async syncTaggedLogsAsSender(contractAddress, sender, recipient) {
279
- const appTaggingSecret = await this.#calculateAppTaggingSecret(contractAddress, sender, recipient);
280
- const [oldIndex] = await this.db.getTaggingSecretsIndexesAsSender([
281
- appTaggingSecret
282
- ]);
209
+ * Updates the local index of the shared tagging secret of a sender / recipient pair
210
+ * if a log with a larger index is found from the node.
211
+ * @param contractAddress - The address of the contract that the logs are tagged for
212
+ * @param sender - The address of the sender, we must know the sender's ivsk_m.
213
+ * @param recipient - The address of the recipient.
214
+ */
215
+ async syncTaggedLogsAsSender(contractAddress, sender, recipient) {
216
+ const appTaggingSecret = await __classPrivateFieldGet(this, _SimulatorOracle_instances, "m", _SimulatorOracle_calculateAppTaggingSecret).call(this, contractAddress, sender, recipient);
217
+ const [oldIndex] = await this.db.getTaggingSecretsIndexesAsSender([appTaggingSecret]);
283
218
  // This algorithm works such that:
284
219
  // 1. If we find minimum consecutive empty logs in a window of logs we set the index to the index of the last log
285
220
  // we found and quit.
@@ -287,55 +222,51 @@ import { WINDOW_HALF_SIZE, getIndexedTaggingSecretsForTheWindow, getInitialIndex
287
222
  // and repeat the process.
288
223
  const MIN_CONSECUTIVE_EMPTY_LOGS = 10;
289
224
  const WINDOW_SIZE = MIN_CONSECUTIVE_EMPTY_LOGS * 2;
290
- let [numConsecutiveEmptyLogs, currentIndex] = [
291
- 0,
292
- oldIndex
293
- ];
225
+ let [numConsecutiveEmptyLogs, currentIndex] = [0, oldIndex];
294
226
  do {
295
227
  // We compute the tags for the current window of indexes
296
- const currentTags = await timesParallel(WINDOW_SIZE, (i)=>{
228
+ const currentTags = await timesParallel(WINDOW_SIZE, i => {
297
229
  const indexedAppTaggingSecret = new IndexedTaggingSecret(appTaggingSecret, currentIndex + i);
298
230
  return indexedAppTaggingSecret.computeSiloedTag(recipient, contractAddress);
299
231
  });
300
232
  // We fetch the logs for the tags
301
233
  const possibleLogs = await this.aztecNode.getLogsByTags(currentTags);
302
234
  // We find the index of the last log in the window that is not empty
303
- const indexOfLastLog = possibleLogs.findLastIndex((possibleLog)=>possibleLog.length !== 0);
235
+ const indexOfLastLog = possibleLogs.findLastIndex(possibleLog => possibleLog.length !== 0);
304
236
  if (indexOfLastLog === -1) {
237
+ // We haven't found any logs in the current window so we stop looking
305
238
  break;
306
239
  }
307
240
  // We move the current index to that of the last log we found
308
241
  currentIndex += indexOfLastLog + 1;
309
242
  // We compute the number of consecutive empty logs we found and repeat the process if we haven't found enough.
310
243
  numConsecutiveEmptyLogs = WINDOW_SIZE - indexOfLastLog - 1;
311
- }while (numConsecutiveEmptyLogs < MIN_CONSECUTIVE_EMPTY_LOGS)
244
+ } while (numConsecutiveEmptyLogs < MIN_CONSECUTIVE_EMPTY_LOGS);
312
245
  const contractName = await this.contractDataOracle.getDebugContractName(contractAddress);
313
246
  if (currentIndex !== oldIndex) {
314
- await this.db.setTaggingSecretsIndexesAsSender([
315
- new IndexedTaggingSecret(appTaggingSecret, currentIndex)
316
- ]);
247
+ await this.db.setTaggingSecretsIndexesAsSender([new IndexedTaggingSecret(appTaggingSecret, currentIndex)]);
317
248
  this.log.debug(`Syncing logs for sender ${sender} at contract ${contractName}(${contractAddress})`, {
318
249
  sender,
319
250
  secret: appTaggingSecret,
320
251
  index: currentIndex,
321
252
  contractName,
322
- contractAddress
253
+ contractAddress,
323
254
  });
324
- } else {
255
+ }
256
+ else {
325
257
  this.log.debug(`No new logs found for sender ${sender} at contract ${contractName}(${contractAddress})`);
326
258
  }
327
259
  }
328
260
  /**
329
- * Synchronizes the logs tagged with scoped addresses and all the senders in the address book.
330
- * Returns the unsynched logs and updates the indexes of the secrets used to tag them until there are no more logs
331
- * to sync.
332
- * @param contractAddress - The address of the contract that the logs are tagged for
333
- * @param recipient - The address of the recipient
334
- * @returns A list of encrypted logs tagged with the recipient's address
335
- */ async syncTaggedLogs(contractAddress, maxBlockNumber, scopes) {
336
- this.log.verbose('Searching for tagged logs', {
337
- contract: contractAddress
338
- });
261
+ * Synchronizes the logs tagged with scoped addresses and all the senders in the address book.
262
+ * Returns the unsynched logs and updates the indexes of the secrets used to tag them until there are no more logs
263
+ * to sync.
264
+ * @param contractAddress - The address of the contract that the logs are tagged for
265
+ * @param recipient - The address of the recipient
266
+ * @returns A list of encrypted logs tagged with the recipient's address
267
+ */
268
+ async syncTaggedLogs(contractAddress, maxBlockNumber, scopes) {
269
+ this.log.verbose('Searching for tagged logs', { contract: contractAddress });
339
270
  // Ideally this algorithm would be implemented in noir, exposing its building blocks as oracles.
340
271
  // However it is impossible at the moment due to the language not supporting nested slices.
341
272
  // This nesting is necessary because for a given set of tags we don't
@@ -347,10 +278,10 @@ import { WINDOW_HALF_SIZE, getIndexedTaggingSecretsForTheWindow, getInitialIndex
347
278
  // that a logs will be received ordered by a given tax index and that the tags won't be reused).
348
279
  const logsMap = new Map();
349
280
  const contractName = await this.contractDataOracle.getDebugContractName(contractAddress);
350
- for (const recipient of recipients){
281
+ for (const recipient of recipients) {
351
282
  const logsForRecipient = [];
352
283
  // Get all the secrets for the recipient and sender pairs (#9365)
353
- const secrets = await this.#getIndexedTaggingSecretsForSenders(contractAddress, recipient);
284
+ const secrets = await __classPrivateFieldGet(this, _SimulatorOracle_instances, "m", _SimulatorOracle_getIndexedTaggingSecretsForSenders).call(this, contractAddress, recipient);
354
285
  // We fetch logs for a window of indexes in a range:
355
286
  // <latest_log_index - WINDOW_HALF_SIZE, latest_log_index + WINDOW_HALF_SIZE>.
356
287
  //
@@ -359,32 +290,32 @@ import { WINDOW_HALF_SIZE, getIndexedTaggingSecretsForTheWindow, getInitialIndex
359
290
  // for logs the first time we don't receive any logs for a tag, we might never receive anything from that sender again.
360
291
  // Also there's a possibility that we have advanced our index, but the sender has reused it, so we might have missed
361
292
  // some logs. For these reasons, we have to look both back and ahead of the stored index.
362
- let secretsAndWindows = secrets.map((secret)=>{
293
+ let secretsAndWindows = secrets.map(secret => {
363
294
  return {
364
295
  appTaggingSecret: secret.appTaggingSecret,
365
296
  leftMostIndex: Math.max(0, secret.index - WINDOW_HALF_SIZE),
366
- rightMostIndex: secret.index + WINDOW_HALF_SIZE
297
+ rightMostIndex: secret.index + WINDOW_HALF_SIZE,
367
298
  };
368
299
  });
369
300
  // As we iterate we store the largest index we have seen for a given secret to later on store it in the db.
370
301
  const newLargestIndexMapToStore = {};
371
302
  // The initial/unmodified indexes of the secrets stored in a key-value map where key is the app tagging secret.
372
303
  const initialIndexesMap = getInitialIndexesMap(secrets);
373
- while(secretsAndWindows.length > 0){
304
+ while (secretsAndWindows.length > 0) {
374
305
  const secretsForTheWholeWindow = getIndexedTaggingSecretsForTheWindow(secretsAndWindows);
375
- const tagsForTheWholeWindow = await Promise.all(secretsForTheWholeWindow.map((secret)=>secret.computeSiloedTag(recipient, contractAddress)));
306
+ const tagsForTheWholeWindow = await Promise.all(secretsForTheWholeWindow.map(secret => secret.computeSiloedTag(recipient, contractAddress)));
376
307
  // We store the new largest indexes we find in the iteration in the following map to later on construct
377
308
  // a new set of secrets and windows to fetch logs for.
378
309
  const newLargestIndexMapForIteration = {};
379
310
  // Fetch the logs for the tags and iterate over them
380
311
  const logsByTags = await this.aztecNode.getLogsByTags(tagsForTheWholeWindow);
381
- logsByTags.forEach((logsByTag, logIndex)=>{
312
+ logsByTags.forEach((logsByTag, logIndex) => {
382
313
  if (logsByTag.length > 0) {
383
314
  // Check that public logs have the correct contract address
384
- const checkedLogsbyTag = logsByTag.filter((l)=>!l.isFromPublic || PublicLog.fromBuffer(l.logData).contractAddress.equals(contractAddress));
315
+ const checkedLogsbyTag = logsByTag.filter(l => !l.isFromPublic || PublicLog.fromBuffer(l.logData).contractAddress.equals(contractAddress));
385
316
  if (checkedLogsbyTag.length < logsByTag.length) {
386
- const discarded = logsByTag.filter((log)=>checkedLogsbyTag.find((filteredLog)=>filteredLog.equals(log)) === undefined);
387
- this.log.warn(`Discarded ${logsByTag.length - checkedLogsbyTag.length} public logs with mismatched contract address ${contractAddress}:`, discarded.map((l)=>PublicLog.fromBuffer(l.logData)));
317
+ const discarded = logsByTag.filter(log => checkedLogsbyTag.find(filteredLog => filteredLog.equals(log)) === undefined);
318
+ this.log.warn(`Discarded ${logsByTag.length - checkedLogsbyTag.length} public logs with mismatched contract address ${contractAddress}:`, discarded.map(l => PublicLog.fromBuffer(l.logData)));
388
319
  }
389
320
  // The logs for the given tag exist so we store them for later processing
390
321
  logsForRecipient.push(...checkedLogsbyTag);
@@ -396,12 +327,16 @@ import { WINDOW_HALF_SIZE, getIndexedTaggingSecretsForTheWindow, getInitialIndex
396
327
  recipient,
397
328
  secret: secretCorrespondingToLog.appTaggingSecret,
398
329
  contractName,
399
- contractAddress
330
+ contractAddress,
400
331
  });
401
- if (secretCorrespondingToLog.index >= initialIndex && (newLargestIndexMapForIteration[secretCorrespondingToLog.appTaggingSecret.toString()] === undefined || secretCorrespondingToLog.index >= newLargestIndexMapForIteration[secretCorrespondingToLog.appTaggingSecret.toString()])) {
332
+ if (secretCorrespondingToLog.index >= initialIndex &&
333
+ (newLargestIndexMapForIteration[secretCorrespondingToLog.appTaggingSecret.toString()] === undefined ||
334
+ secretCorrespondingToLog.index >=
335
+ newLargestIndexMapForIteration[secretCorrespondingToLog.appTaggingSecret.toString()])) {
402
336
  // We have found a new largest index so we store it for later processing (storing it in the db + fetching
403
337
  // the difference of the window sets of current and the next iteration)
404
- newLargestIndexMapForIteration[secretCorrespondingToLog.appTaggingSecret.toString()] = secretCorrespondingToLog.index + 1;
338
+ newLargestIndexMapForIteration[secretCorrespondingToLog.appTaggingSecret.toString()] =
339
+ secretCorrespondingToLog.index + 1;
405
340
  this.log.debug(`Incrementing index to ${secretCorrespondingToLog.index + 1} at contract ${contractName}(${contractAddress})`);
406
341
  }
407
342
  }
@@ -410,18 +345,19 @@ import { WINDOW_HALF_SIZE, getIndexedTaggingSecretsForTheWindow, getInitialIndex
410
345
  // for. Note that it's very unlikely that a new log from the current window would appear between the iterations
411
346
  // so we fetch the logs only for the difference of the window sets.
412
347
  const newSecretsAndWindows = [];
413
- for (const [appTaggingSecret, newIndex] of Object.entries(newLargestIndexMapForIteration)){
414
- const secret = secrets.find((secret)=>secret.appTaggingSecret.toString() === appTaggingSecret);
348
+ for (const [appTaggingSecret, newIndex] of Object.entries(newLargestIndexMapForIteration)) {
349
+ const secret = secrets.find(secret => secret.appTaggingSecret.toString() === appTaggingSecret);
415
350
  if (secret) {
416
351
  newSecretsAndWindows.push({
417
352
  appTaggingSecret: secret.appTaggingSecret,
418
353
  // We set the left most index to the new index to avoid fetching the same logs again
419
354
  leftMostIndex: newIndex,
420
- rightMostIndex: newIndex + WINDOW_HALF_SIZE
355
+ rightMostIndex: newIndex + WINDOW_HALF_SIZE,
421
356
  });
422
357
  // We store the new largest index in the map to later store it in the db.
423
358
  newLargestIndexMapToStore[appTaggingSecret] = newIndex;
424
- } else {
359
+ }
360
+ else {
425
361
  throw new Error(`Secret not found for appTaggingSecret ${appTaggingSecret}. This is a bug as it should never happen!`);
426
362
  }
427
363
  }
@@ -429,59 +365,24 @@ import { WINDOW_HALF_SIZE, getIndexedTaggingSecretsForTheWindow, getInitialIndex
429
365
  secretsAndWindows = newSecretsAndWindows;
430
366
  }
431
367
  // We filter the logs by block number and store them in the map.
432
- logsMap.set(recipient.toString(), logsForRecipient.filter((log)=>log.blockNumber <= maxBlockNumber));
368
+ logsMap.set(recipient.toString(), logsForRecipient.filter(log => log.blockNumber <= maxBlockNumber));
433
369
  // At this point we have processed all the logs for the recipient so we store the new largest indexes in the db.
434
- await this.db.setTaggingSecretsIndexesAsRecipient(Object.entries(newLargestIndexMapToStore).map(([appTaggingSecret, index])=>new IndexedTaggingSecret(Fr.fromHexString(appTaggingSecret), index)));
370
+ await this.db.setTaggingSecretsIndexesAsRecipient(Object.entries(newLargestIndexMapToStore).map(([appTaggingSecret, index]) => new IndexedTaggingSecret(Fr.fromHexString(appTaggingSecret), index)));
435
371
  }
436
372
  return logsMap;
437
373
  }
438
374
  /**
439
- * Decrypts logs tagged for a recipient and returns them.
440
- * @param scopedLogs - The logs to decrypt.
441
- * @param recipient - The recipient of the logs.
442
- * @returns The decrypted notes.
443
- */ async #decryptTaggedLogs(scopedLogs, recipient) {
444
- const recipientCompleteAddress = await this.getCompleteAddress(recipient);
445
- const ivskM = await this.keyStore.getMasterSecretKey(recipientCompleteAddress.publicKeys.masterIncomingViewingPublicKey);
446
- const addressSecret = await computeAddressSecret(await recipientCompleteAddress.getPreaddress(), ivskM);
447
- // Since we could have notes with the same index for different txs, we need
448
- // to keep track of them scoping by txHash
449
- const excludedIndices = new Map();
450
- const decrypted = [];
451
- for (const scopedLog of scopedLogs){
452
- const payload = scopedLog.isFromPublic ? await L1NotePayload.decryptAsIncomingFromPublic(PublicLog.fromBuffer(scopedLog.logData), addressSecret) : await L1NotePayload.decryptAsIncoming(PrivateLog.fromBuffer(scopedLog.logData), addressSecret);
453
- if (!payload) {
454
- this.log.verbose('Unable to decrypt log');
455
- continue;
456
- }
457
- if (!excludedIndices.has(scopedLog.txHash.toString())) {
458
- excludedIndices.set(scopedLog.txHash.toString(), new Set());
459
- }
460
- const note = await getOrderedNoteItems(this.db, payload);
461
- const plaintext = [
462
- payload.storageSlot,
463
- payload.noteTypeId.toField(),
464
- ...note.items
465
- ];
466
- decrypted.push({
467
- plaintext,
468
- txHash: scopedLog.txHash,
469
- contractAddress: payload.contractAddress
470
- });
471
- }
472
- return decrypted;
473
- }
474
- /**
475
- * Processes the tagged logs returned by syncTaggedLogs by decrypting them and storing them in the database.
476
- * @param logs - The logs to process.
477
- * @param recipient - The recipient of the logs.
478
- */ async processTaggedLogs(logs, recipient, simulator) {
479
- const decryptedLogs = await this.#decryptTaggedLogs(logs, recipient);
375
+ * Processes the tagged logs returned by syncTaggedLogs by decrypting them and storing them in the database.
376
+ * @param logs - The logs to process.
377
+ * @param recipient - The recipient of the logs.
378
+ */
379
+ async processTaggedLogs(logs, recipient, simulator) {
380
+ const decryptedLogs = await __classPrivateFieldGet(this, _SimulatorOracle_instances, "m", _SimulatorOracle_decryptTaggedLogs).call(this, logs, recipient);
480
381
  // We've produced the full NoteDao, which we'd be able to simply insert into the database. However, this is
481
382
  // only a temporary measure as we migrate from the PXE-driven discovery into the new contract-driven approach. We
482
383
  // discard most of the work done up to this point and reconstruct the note plaintext to then hand over to the
483
384
  // contract for further processing.
484
- for (const decryptedLog of decryptedLogs){
385
+ for (const decryptedLog of decryptedLogs) {
485
386
  // Log processing requires the note hashes in the tx in which the note was created. We are now assuming that the
486
387
  // note was included in the same block in which the log was delivered - note that partial notes will not work this
487
388
  // way.
@@ -497,42 +398,32 @@ import { WINDOW_HALF_SIZE, getIndexedTaggingSecretsForTheWindow, getInitialIndex
497
398
  // Called when notes are delivered, usually as a result to a call to the process_log contract function
498
399
  async deliverNote(contractAddress, storageSlot, nonce, content, noteHash, nullifier, txHash, recipient) {
499
400
  const noteDao = await this.produceNoteDao(contractAddress, storageSlot, nonce, content, noteHash, nullifier, txHash, recipient);
500
- await this.db.addNotes([
501
- noteDao
502
- ], recipient);
401
+ await this.db.addNotes([noteDao], recipient);
503
402
  this.log.verbose('Added note', {
504
403
  contract: noteDao.contractAddress,
505
404
  slot: noteDao.storageSlot,
506
- nullifier: noteDao.siloedNullifier.toString
405
+ nullifier: noteDao.siloedNullifier.toString,
507
406
  });
508
407
  }
509
408
  async removeNullifiedNotes(contractAddress) {
510
- this.log.verbose('Removing nullified notes', {
511
- contract: contractAddress
512
- });
513
- for (const recipient of (await this.keyStore.getAccounts())){
514
- const currentNotesForRecipient = await this.db.getNotes({
515
- contractAddress,
516
- owner: recipient
517
- });
518
- const nullifiersToCheck = currentNotesForRecipient.map((note)=>note.siloedNullifier);
409
+ this.log.verbose('Removing nullified notes', { contract: contractAddress });
410
+ for (const recipient of await this.keyStore.getAccounts()) {
411
+ const currentNotesForRecipient = await this.db.getNotes({ contractAddress, owner: recipient });
412
+ const nullifiersToCheck = currentNotesForRecipient.map(note => note.siloedNullifier);
519
413
  const nullifierIndexes = await this.aztecNode.findNullifiersIndexesWithBlock('latest', nullifiersToCheck);
520
- const foundNullifiers = nullifiersToCheck.map((nullifier, i)=>{
414
+ const foundNullifiers = nullifiersToCheck
415
+ .map((nullifier, i) => {
521
416
  if (nullifierIndexes[i] !== undefined) {
522
- return {
523
- ...nullifierIndexes[i],
524
- ...{
525
- data: nullifier
526
- }
527
- };
417
+ return { ...nullifierIndexes[i], ...{ data: nullifier } };
528
418
  }
529
- }).filter((nullifier)=>nullifier !== undefined);
419
+ })
420
+ .filter(nullifier => nullifier !== undefined);
530
421
  const nullifiedNotes = await this.db.removeNullifiedNotes(foundNullifiers, await recipient.toAddressPoint());
531
- nullifiedNotes.forEach((noteDao)=>{
422
+ nullifiedNotes.forEach(noteDao => {
532
423
  this.log.verbose(`Removed note for contract ${noteDao.contractAddress} at slot ${noteDao.storageSlot}`, {
533
424
  contract: noteDao.contractAddress,
534
425
  slot: noteDao.storageSlot,
535
- nullifier: noteDao.siloedNullifier.toString()
426
+ nullifier: noteDao.siloedNullifier.toString(),
536
427
  });
537
428
  });
538
429
  }
@@ -553,9 +444,7 @@ import { WINDOW_HALF_SIZE, getIndexedTaggingSecretsForTheWindow, getInitialIndex
553
444
  // locally synced block number which *should* be recent enough to be available. We avoid querying at 'latest' since
554
445
  // we want to avoid accidentally processing notes that only exist ahead in time of the locally synced state.
555
446
  const syncedBlockNumber = await this.db.getBlockNumber();
556
- const uniqueNoteHashTreeIndex = (await this.aztecNode.findLeavesIndexes(syncedBlockNumber, MerkleTreeId.NOTE_HASH_TREE, [
557
- uniqueNoteHash
558
- ]))[0];
447
+ const uniqueNoteHashTreeIndex = (await this.aztecNode.findLeavesIndexes(syncedBlockNumber, MerkleTreeId.NOTE_HASH_TREE, [uniqueNoteHash]))[0];
559
448
  if (uniqueNoteHashTreeIndex === undefined) {
560
449
  throw new Error(`Note hash ${noteHash} (uniqued as ${uniqueNoteHash}) is not present on the tree at block ${syncedBlockNumber} (from tx ${txHash})`);
561
450
  }
@@ -577,11 +466,12 @@ import { WINDOW_HALF_SIZE, getIndexedTaggingSecretsForTheWindow, getInitialIndex
577
466
  txHash.toString(),
578
467
  toBoundedVec(noteHashes, MAX_NOTE_HASHES_PER_TX),
579
468
  firstNullifier,
580
- recipient
469
+ recipient,
581
470
  ]),
582
- returnTypes: artifact.returnTypes
471
+ returnTypes: artifact.returnTypes,
583
472
  };
584
- await (simulator ?? getAcirSimulator(this.db, this.aztecNode, this.keyStore, this.simulationProvider, this.contractDataOracle)).runUnconstrained(execRequest, artifact, contractAddress, []);
473
+ await (simulator ??
474
+ getAcirSimulator(this.db, this.aztecNode, this.keyStore, this.simulationProvider, this.contractDataOracle)).runUnconstrained(execRequest, artifact, contractAddress, []);
585
475
  }
586
476
  dbStore(contractAddress, slot, values) {
587
477
  return this.db.dbStore(contractAddress, slot, values);
@@ -596,9 +486,84 @@ import { WINDOW_HALF_SIZE, getIndexedTaggingSecretsForTheWindow, getInitialIndex
596
486
  return this.db.dbCopy(contractAddress, srcSlot, dstSlot, numEntries);
597
487
  }
598
488
  }
489
+ _SimulatorOracle_instances = new WeakSet(), _SimulatorOracle_findLeafIndex = async function _SimulatorOracle_findLeafIndex(blockNumber, treeId, leafValue) {
490
+ const [leafIndex] = await this.aztecNode.findLeavesIndexes(blockNumber, treeId, [leafValue]);
491
+ return leafIndex;
492
+ }, _SimulatorOracle_getSiblingPath = async function _SimulatorOracle_getSiblingPath(blockNumber, treeId, leafIndex) {
493
+ switch (treeId) {
494
+ case MerkleTreeId.NULLIFIER_TREE:
495
+ return (await this.aztecNode.getNullifierSiblingPath(blockNumber, leafIndex)).toFields();
496
+ case MerkleTreeId.NOTE_HASH_TREE:
497
+ return (await this.aztecNode.getNoteHashSiblingPath(blockNumber, leafIndex)).toFields();
498
+ case MerkleTreeId.PUBLIC_DATA_TREE:
499
+ return (await this.aztecNode.getPublicDataSiblingPath(blockNumber, leafIndex)).toFields();
500
+ case MerkleTreeId.ARCHIVE:
501
+ return (await this.aztecNode.getArchiveSiblingPath(blockNumber, leafIndex)).toFields();
502
+ default:
503
+ throw new Error('Not implemented');
504
+ }
505
+ }, _SimulatorOracle_calculateAppTaggingSecret = async function _SimulatorOracle_calculateAppTaggingSecret(contractAddress, sender, recipient) {
506
+ const senderCompleteAddress = await this.getCompleteAddress(sender);
507
+ const senderIvsk = await this.keyStore.getMasterIncomingViewingSecretKey(sender);
508
+ const secretPoint = await computeTaggingSecretPoint(senderCompleteAddress, senderIvsk, recipient);
509
+ // Silo the secret so it can't be used to track other app's notes
510
+ const appSecret = poseidon2Hash([secretPoint.x, secretPoint.y, contractAddress]);
511
+ return appSecret;
512
+ }, _SimulatorOracle_getIndexedTaggingSecretsForSenders =
513
+ /**
514
+ * Returns the indexed tagging secrets for a given recipient and all the senders in the address book
515
+ * This method should be exposed as an oracle call to allow aztec.nr to perform the orchestration
516
+ * of the syncTaggedLogs and processTaggedLogs methods. However, it is not possible to do so at the moment,
517
+ * so we're keeping it private for now.
518
+ * @param contractAddress - The contract address to silo the secret for
519
+ * @param recipient - The address receiving the notes
520
+ * @returns A list of indexed tagging secrets
521
+ */
522
+ async function _SimulatorOracle_getIndexedTaggingSecretsForSenders(contractAddress, recipient) {
523
+ const recipientCompleteAddress = await this.getCompleteAddress(recipient);
524
+ const recipientIvsk = await this.keyStore.getMasterIncomingViewingSecretKey(recipient);
525
+ // We implicitly add all PXE accounts as senders, this helps us decrypt tags on notes that we send to ourselves
526
+ // (recipient = us, sender = us)
527
+ const senders = [...(await this.db.getSenderAddresses()), ...(await this.keyStore.getAccounts())].filter((address, index, self) => index === self.findIndex(otherAddress => otherAddress.equals(address)));
528
+ const appTaggingSecrets = await Promise.all(senders.map(async (contact) => {
529
+ const sharedSecret = await computeTaggingSecretPoint(recipientCompleteAddress, recipientIvsk, contact);
530
+ return poseidon2Hash([sharedSecret.x, sharedSecret.y, contractAddress]);
531
+ }));
532
+ const indexes = await this.db.getTaggingSecretsIndexesAsRecipient(appTaggingSecrets);
533
+ return appTaggingSecrets.map((secret, i) => new IndexedTaggingSecret(secret, indexes[i]));
534
+ }, _SimulatorOracle_decryptTaggedLogs =
535
+ /**
536
+ * Decrypts logs tagged for a recipient and returns them.
537
+ * @param scopedLogs - The logs to decrypt.
538
+ * @param recipient - The recipient of the logs.
539
+ * @returns The decrypted notes.
540
+ */
541
+ async function _SimulatorOracle_decryptTaggedLogs(scopedLogs, recipient) {
542
+ const recipientCompleteAddress = await this.getCompleteAddress(recipient);
543
+ const ivskM = await this.keyStore.getMasterSecretKey(recipientCompleteAddress.publicKeys.masterIncomingViewingPublicKey);
544
+ const addressSecret = await computeAddressSecret(await recipientCompleteAddress.getPreaddress(), ivskM);
545
+ // Since we could have notes with the same index for different txs, we need
546
+ // to keep track of them scoping by txHash
547
+ const excludedIndices = new Map();
548
+ const decrypted = [];
549
+ for (const scopedLog of scopedLogs) {
550
+ const payload = scopedLog.isFromPublic
551
+ ? await L1NotePayload.decryptAsIncomingFromPublic(PublicLog.fromBuffer(scopedLog.logData), addressSecret)
552
+ : await L1NotePayload.decryptAsIncoming(PrivateLog.fromBuffer(scopedLog.logData), addressSecret);
553
+ if (!payload) {
554
+ this.log.verbose('Unable to decrypt log');
555
+ continue;
556
+ }
557
+ if (!excludedIndices.has(scopedLog.txHash.toString())) {
558
+ excludedIndices.set(scopedLog.txHash.toString(), new Set());
559
+ }
560
+ const note = await getOrderedNoteItems(this.db, payload);
561
+ const plaintext = [payload.storageSlot, payload.noteTypeId.toField(), ...note.items];
562
+ decrypted.push({ plaintext, txHash: scopedLog.txHash, contractAddress: payload.contractAddress });
563
+ }
564
+ return decrypted;
565
+ };
599
566
  function toBoundedVec(array, maxLength) {
600
- return {
601
- storage: array.concat(Array(maxLength - array.length).fill(new Fr(0))),
602
- len: array.length
603
- };
567
+ return { storage: array.concat(Array(maxLength - array.length).fill(new Fr(0))), len: array.length };
604
568
  }
569
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2ltdWxhdG9yX29yYWNsZS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLE9BQU8sRUFJTCxhQUFhLEVBR2IsWUFBWSxFQUNaLElBQUksRUFJSixNQUFNLEVBRU4sbUNBQW1DLEdBQ3BDLE1BQU0sc0JBQXNCLENBQUM7QUFDOUIsT0FBTyxFQUtMLEVBQUUsRUFDRixnQkFBZ0IsRUFDaEIsb0JBQW9CLEVBR3BCLHNCQUFzQixFQUN0QiwwQkFBMEIsRUFDMUIsVUFBVSxFQUNWLFNBQVMsRUFDVCxvQkFBb0IsRUFDcEIseUJBQXlCLEdBQzFCLE1BQU0sb0JBQW9CLENBQUM7QUFDNUIsT0FBTyxFQUFFLHFCQUFxQixFQUFFLFlBQVksRUFBRSxhQUFhLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUM3RixPQUFPLEVBRUwsWUFBWSxFQUNaLFlBQVksRUFDWixlQUFlLEVBQ2YsbUJBQW1CLEdBQ3BCLE1BQU0sdUJBQXVCLENBQUM7QUFDL0IsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQzdELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFFckQsT0FBTyxFQUdMLHVCQUF1QixHQUV4QixNQUFNLHlCQUF5QixDQUFDO0FBRWpDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBRXRFLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUNsRCxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSwwREFBMEQsQ0FBQztBQUMvRixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsb0NBQW9DLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxv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