@aztec/pxe 0.62.0 → 0.63.1
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.
- package/dest/config/index.d.ts +2 -3
- package/dest/config/index.d.ts.map +1 -1
- package/dest/config/index.js +4 -5
- package/dest/contract_data_oracle/index.d.ts +1 -0
- package/dest/contract_data_oracle/index.d.ts.map +1 -1
- package/dest/contract_data_oracle/index.js +5 -1
- package/dest/database/incoming_note_dao.d.ts +1 -1
- package/dest/database/incoming_note_dao.d.ts.map +1 -1
- package/dest/database/kv_pxe_database.d.ts +5 -12
- package/dest/database/kv_pxe_database.d.ts.map +1 -1
- package/dest/database/kv_pxe_database.js +31 -62
- package/dest/database/outgoing_note_dao.d.ts +1 -1
- package/dest/database/outgoing_note_dao.d.ts.map +1 -1
- package/dest/database/pxe_database.d.ts +17 -25
- package/dest/database/pxe_database.d.ts.map +1 -1
- package/dest/kernel_oracle/index.d.ts +3 -3
- package/dest/kernel_oracle/index.d.ts.map +1 -1
- package/dest/kernel_prover/hints/build_private_kernel_reset_private_inputs.d.ts.map +1 -1
- package/dest/kernel_prover/hints/build_private_kernel_reset_private_inputs.js +12 -4
- package/dest/kernel_prover/kernel_prover.d.ts +3 -1
- package/dest/kernel_prover/kernel_prover.d.ts.map +1 -1
- package/dest/kernel_prover/kernel_prover.js +39 -7
- package/dest/kernel_prover/test/test_circuit_prover.d.ts +1 -0
- package/dest/kernel_prover/test/test_circuit_prover.d.ts.map +1 -1
- package/dest/kernel_prover/test/test_circuit_prover.js +5 -1
- package/dest/{note_processor/utils → note_decryption_utils}/add_public_values_to_payload.d.ts +1 -1
- package/dest/note_decryption_utils/add_public_values_to_payload.d.ts.map +1 -0
- package/dest/{note_processor/utils → note_decryption_utils}/add_public_values_to_payload.js +1 -1
- package/dest/note_decryption_utils/brute_force_note_info.d.ts.map +1 -0
- package/dest/{note_processor/utils → note_decryption_utils}/brute_force_note_info.js +1 -1
- package/dest/note_decryption_utils/index.d.ts.map +1 -0
- package/dest/{note_processor/utils → note_decryption_utils}/index.js +1 -1
- package/dest/{note_processor/utils → note_decryption_utils}/produce_note_daos.d.ts +5 -8
- package/dest/note_decryption_utils/produce_note_daos.d.ts.map +1 -0
- package/dest/note_decryption_utils/produce_note_daos.js +47 -0
- package/dest/note_decryption_utils/produce_note_daos_for_key.d.ts +8 -0
- package/dest/note_decryption_utils/produce_note_daos_for_key.d.ts.map +1 -0
- package/dest/note_decryption_utils/produce_note_daos_for_key.js +17 -0
- package/dest/pxe_http/pxe_http_server.d.ts +1 -2
- package/dest/pxe_http/pxe_http_server.d.ts.map +1 -1
- package/dest/pxe_http/pxe_http_server.js +5 -51
- package/dest/pxe_service/create_pxe_service.d.ts.map +1 -1
- package/dest/pxe_service/create_pxe_service.js +7 -4
- package/dest/pxe_service/error_enriching.d.ts.map +1 -1
- package/dest/pxe_service/error_enriching.js +7 -6
- package/dest/pxe_service/pxe_service.d.ts +11 -25
- package/dest/pxe_service/pxe_service.d.ts.map +1 -1
- package/dest/pxe_service/pxe_service.js +45 -48
- package/dest/pxe_service/test/pxe_test_suite.d.ts.map +1 -1
- package/dest/pxe_service/test/pxe_test_suite.js +4 -3
- package/dest/simulator_oracle/index.d.ts +15 -16
- package/dest/simulator_oracle/index.d.ts.map +1 -1
- package/dest/simulator_oracle/index.js +195 -65
- package/dest/synchronizer/synchronizer.d.ts +0 -48
- package/dest/synchronizer/synchronizer.d.ts.map +1 -1
- package/dest/synchronizer/synchronizer.js +3 -201
- package/package.json +14 -14
- package/src/config/index.ts +4 -7
- package/src/contract_data_oracle/index.ts +5 -0
- package/src/database/incoming_note_dao.ts +1 -1
- package/src/database/kv_pxe_database.ts +33 -70
- package/src/database/outgoing_note_dao.ts +1 -1
- package/src/database/pxe_database.ts +19 -28
- package/src/kernel_prover/hints/build_private_kernel_reset_private_inputs.ts +13 -3
- package/src/kernel_prover/kernel_prover.ts +49 -5
- package/src/kernel_prover/test/test_circuit_prover.ts +8 -4
- package/src/{note_processor/utils → note_decryption_utils}/add_public_values_to_payload.ts +1 -1
- package/src/{note_processor/utils → note_decryption_utils}/produce_note_daos.ts +6 -16
- package/src/{note_processor/utils → note_decryption_utils}/produce_note_daos_for_key.ts +6 -15
- package/src/pxe_http/pxe_http_server.ts +5 -84
- package/src/pxe_service/create_pxe_service.ts +9 -3
- package/src/pxe_service/error_enriching.ts +12 -5
- package/src/pxe_service/pxe_service.ts +61 -78
- package/src/pxe_service/test/pxe_test_suite.ts +6 -2
- package/src/simulator_oracle/index.ts +280 -60
- package/src/synchronizer/synchronizer.ts +3 -253
- package/dest/database/deferred_note_dao.d.ts +0 -40
- package/dest/database/deferred_note_dao.d.ts.map +0 -1
- package/dest/database/deferred_note_dao.js +0 -38
- package/dest/note_processor/index.d.ts +0 -2
- package/dest/note_processor/index.d.ts.map +0 -1
- package/dest/note_processor/index.js +0 -2
- package/dest/note_processor/note_processor.d.ts +0 -83
- package/dest/note_processor/note_processor.d.ts.map +0 -1
- package/dest/note_processor/note_processor.js +0 -231
- package/dest/note_processor/utils/add_public_values_to_payload.d.ts.map +0 -1
- package/dest/note_processor/utils/brute_force_note_info.d.ts.map +0 -1
- package/dest/note_processor/utils/index.d.ts.map +0 -1
- package/dest/note_processor/utils/produce_note_daos.d.ts.map +0 -1
- package/dest/note_processor/utils/produce_note_daos.js +0 -51
- package/dest/note_processor/utils/produce_note_daos_for_key.d.ts +0 -9
- package/dest/note_processor/utils/produce_note_daos_for_key.d.ts.map +0 -1
- package/dest/note_processor/utils/produce_note_daos_for_key.js +0 -26
- package/src/database/deferred_note_dao.ts +0 -47
- package/src/note_processor/index.ts +0 -1
- package/src/note_processor/note_processor.ts +0 -358
- /package/dest/{note_processor/utils → note_decryption_utils}/brute_force_note_info.d.ts +0 -0
- /package/dest/{note_processor/utils → note_decryption_utils}/index.d.ts +0 -0
- /package/src/{note_processor/utils → note_decryption_utils}/brute_force_note_info.ts +0 -0
- /package/src/{note_processor/utils → note_decryption_utils}/index.ts +0 -0
|
@@ -1,34 +1,42 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type AztecNode,
|
|
3
|
-
|
|
3
|
+
L1NotePayload,
|
|
4
4
|
type L2Block,
|
|
5
|
+
type L2BlockNumber,
|
|
5
6
|
MerkleTreeId,
|
|
6
7
|
type NoteStatus,
|
|
7
8
|
type NullifierMembershipWitness,
|
|
8
9
|
type PublicDataWitness,
|
|
10
|
+
type TxEffect,
|
|
11
|
+
type TxScopedL2Log,
|
|
9
12
|
getNonNullifiedL1ToL2MessageWitness,
|
|
10
13
|
} from '@aztec/circuit-types';
|
|
11
14
|
import {
|
|
12
15
|
type AztecAddress,
|
|
13
16
|
type CompleteAddress,
|
|
14
17
|
type ContractInstance,
|
|
15
|
-
|
|
18
|
+
Fr,
|
|
16
19
|
type FunctionSelector,
|
|
17
20
|
type Header,
|
|
18
21
|
IndexedTaggingSecret,
|
|
19
22
|
type KeyValidationRequest,
|
|
20
23
|
type L1_TO_L2_MSG_TREE_HEIGHT,
|
|
21
|
-
|
|
24
|
+
computeAddressSecret,
|
|
25
|
+
computePoint,
|
|
22
26
|
computeTaggingSecret,
|
|
23
27
|
} from '@aztec/circuits.js';
|
|
24
28
|
import { type FunctionArtifact, getFunctionArtifact } from '@aztec/foundation/abi';
|
|
25
29
|
import { poseidon2Hash } from '@aztec/foundation/crypto';
|
|
26
30
|
import { createDebugLogger } from '@aztec/foundation/log';
|
|
27
31
|
import { type KeyStore } from '@aztec/key-store';
|
|
28
|
-
import { type DBOracle, MessageLoadOracleInputs } from '@aztec/simulator';
|
|
32
|
+
import { type AcirSimulator, type DBOracle, MessageLoadOracleInputs } from '@aztec/simulator';
|
|
29
33
|
|
|
30
34
|
import { type ContractDataOracle } from '../contract_data_oracle/index.js';
|
|
35
|
+
import { type IncomingNoteDao } from '../database/incoming_note_dao.js';
|
|
31
36
|
import { type PxeDatabase } from '../database/index.js';
|
|
37
|
+
import { type OutgoingNoteDao } from '../database/outgoing_note_dao.js';
|
|
38
|
+
import { produceNoteDaos } from '../note_decryption_utils/produce_note_daos.js';
|
|
39
|
+
import { getAcirSimulator } from '../simulator/index.js';
|
|
32
40
|
|
|
33
41
|
/**
|
|
34
42
|
* A data oracle that provides information needed for simulating a transaction.
|
|
@@ -153,7 +161,7 @@ export class SimulatorOracle implements DBOracle {
|
|
|
153
161
|
* @returns - The index of the commitment. Undefined if it does not exist in the tree.
|
|
154
162
|
*/
|
|
155
163
|
async getCommitmentIndex(commitment: Fr) {
|
|
156
|
-
return await this.
|
|
164
|
+
return await this.findLeafIndex('latest', MerkleTreeId.NOTE_HASH_TREE, commitment);
|
|
157
165
|
}
|
|
158
166
|
|
|
159
167
|
// We need this in public as part of the EXISTS calls - but isn't used in private
|
|
@@ -162,11 +170,16 @@ export class SimulatorOracle implements DBOracle {
|
|
|
162
170
|
}
|
|
163
171
|
|
|
164
172
|
async getNullifierIndex(nullifier: Fr) {
|
|
165
|
-
return await this.
|
|
173
|
+
return await this.findLeafIndex('latest', MerkleTreeId.NULLIFIER_TREE, nullifier);
|
|
166
174
|
}
|
|
167
175
|
|
|
168
|
-
public async findLeafIndex(
|
|
169
|
-
|
|
176
|
+
public async findLeafIndex(
|
|
177
|
+
blockNumber: L2BlockNumber,
|
|
178
|
+
treeId: MerkleTreeId,
|
|
179
|
+
leafValue: Fr,
|
|
180
|
+
): Promise<bigint | undefined> {
|
|
181
|
+
const [leafIndex] = await this.aztecNode.findLeavesIndexes(blockNumber, treeId, [leafValue]);
|
|
182
|
+
return leafIndex;
|
|
170
183
|
}
|
|
171
184
|
|
|
172
185
|
public async getSiblingPath(blockNumber: number, treeId: MerkleTreeId, leafIndex: bigint): Promise<Fr[]> {
|
|
@@ -244,20 +257,20 @@ export class SimulatorOracle implements DBOracle {
|
|
|
244
257
|
|
|
245
258
|
/**
|
|
246
259
|
* Returns the tagging secret for a given sender and recipient pair. For this to work, the ivpsk_m of the sender must be known.
|
|
247
|
-
* Includes the
|
|
260
|
+
* Includes the next index to be used used for tagging with this secret.
|
|
248
261
|
* @param contractAddress - The contract address to silo the secret for
|
|
249
262
|
* @param sender - The address sending the note
|
|
250
263
|
* @param recipient - The address receiving the note
|
|
251
264
|
* @returns A siloed tagging secret that can be used to tag notes.
|
|
252
265
|
*/
|
|
253
|
-
public async
|
|
266
|
+
public async getAppTaggingSecretAsSender(
|
|
254
267
|
contractAddress: AztecAddress,
|
|
255
268
|
sender: AztecAddress,
|
|
256
269
|
recipient: AztecAddress,
|
|
257
270
|
): Promise<IndexedTaggingSecret> {
|
|
258
|
-
const
|
|
259
|
-
const [index] = await this.db.
|
|
260
|
-
return IndexedTaggingSecret
|
|
271
|
+
const secret = await this.#calculateTaggingSecret(contractAddress, sender, recipient);
|
|
272
|
+
const [index] = await this.db.getTaggingSecretsIndexesAsSender([secret]);
|
|
273
|
+
return new IndexedTaggingSecret(secret, index);
|
|
261
274
|
}
|
|
262
275
|
|
|
263
276
|
/**
|
|
@@ -266,94 +279,301 @@ export class SimulatorOracle implements DBOracle {
|
|
|
266
279
|
* @param sender - The address sending the note
|
|
267
280
|
* @param recipient - The address receiving the note
|
|
268
281
|
*/
|
|
269
|
-
public async
|
|
282
|
+
public async incrementAppTaggingSecretIndexAsSender(
|
|
270
283
|
contractAddress: AztecAddress,
|
|
271
284
|
sender: AztecAddress,
|
|
272
285
|
recipient: AztecAddress,
|
|
273
286
|
): Promise<void> {
|
|
274
|
-
const
|
|
275
|
-
await this.
|
|
287
|
+
const secret = await this.#calculateTaggingSecret(contractAddress, sender, recipient);
|
|
288
|
+
const contractName = await this.contractDataOracle.getDebugContractName(contractAddress);
|
|
289
|
+
this.log.verbose(
|
|
290
|
+
`Incrementing secret ${secret} as sender ${sender} for recipient: ${recipient} at contract: ${contractName}(${contractAddress})`,
|
|
291
|
+
);
|
|
292
|
+
await this.db.incrementTaggingSecretsIndexesAsSender([secret]);
|
|
276
293
|
}
|
|
277
294
|
|
|
278
|
-
async #
|
|
295
|
+
async #calculateTaggingSecret(contractAddress: AztecAddress, sender: AztecAddress, recipient: AztecAddress) {
|
|
279
296
|
const senderCompleteAddress = await this.getCompleteAddress(sender);
|
|
280
297
|
const senderIvsk = await this.keyStore.getMasterIncomingViewingSecretKey(sender);
|
|
281
298
|
const sharedSecret = computeTaggingSecret(senderCompleteAddress, senderIvsk, recipient);
|
|
282
299
|
// Silo the secret to the app so it can't be used to track other app's notes
|
|
283
300
|
const siloedSecret = poseidon2Hash([sharedSecret.x, sharedSecret.y, contractAddress]);
|
|
284
|
-
|
|
285
|
-
const directionalSecret = new TaggingSecret(siloedSecret, recipient);
|
|
286
|
-
return directionalSecret;
|
|
301
|
+
return siloedSecret;
|
|
287
302
|
}
|
|
288
303
|
|
|
289
304
|
/**
|
|
290
305
|
* Returns the siloed tagging secrets for a given recipient and all the senders in the address book
|
|
306
|
+
* This method should be exposed as an oracle call to allow aztec.nr to perform the orchestration
|
|
307
|
+
* of the syncTaggedLogs and processTaggedLogs methods. However, it is not possible to do so at the moment,
|
|
308
|
+
* so we're keeping it private for now.
|
|
291
309
|
* @param contractAddress - The contract address to silo the secret for
|
|
292
310
|
* @param recipient - The address receiving the notes
|
|
293
311
|
* @returns A list of siloed tagging secrets
|
|
294
312
|
*/
|
|
295
|
-
|
|
313
|
+
async #getAppTaggingSecretsForContacts(
|
|
296
314
|
contractAddress: AztecAddress,
|
|
297
315
|
recipient: AztecAddress,
|
|
298
316
|
): Promise<IndexedTaggingSecret[]> {
|
|
299
317
|
const recipientCompleteAddress = await this.getCompleteAddress(recipient);
|
|
300
318
|
const recipientIvsk = await this.keyStore.getMasterIncomingViewingSecretKey(recipient);
|
|
301
319
|
|
|
302
|
-
// We implicitly add
|
|
303
|
-
const contacts = [...this.db.getContactAddresses(),
|
|
320
|
+
// We implicitly add all PXE accounts as contacts, this helps us decrypt tags on notes that we send to ourselves (recipient = us, sender = us)
|
|
321
|
+
const contacts = [...this.db.getContactAddresses(), ...(await this.keyStore.getAccounts())].filter(
|
|
322
|
+
(address, index, self) => index === self.findIndex(otherAddress => otherAddress.equals(address)),
|
|
323
|
+
);
|
|
304
324
|
const appTaggingSecrets = contacts.map(contact => {
|
|
305
325
|
const sharedSecret = computeTaggingSecret(recipientCompleteAddress, recipientIvsk, contact);
|
|
306
326
|
return poseidon2Hash([sharedSecret.x, sharedSecret.y, contractAddress]);
|
|
307
327
|
});
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
const indexes = await this.db.getTaggingSecretsIndexes(directionalSecrets);
|
|
311
|
-
return directionalSecrets.map((directionalSecret, i) =>
|
|
312
|
-
IndexedTaggingSecret.fromTaggingSecret(directionalSecret, indexes[i]),
|
|
313
|
-
);
|
|
328
|
+
const indexes = await this.db.getTaggingSecretsIndexesAsRecipient(appTaggingSecrets);
|
|
329
|
+
return appTaggingSecrets.map((secret, i) => new IndexedTaggingSecret(secret, indexes[i]));
|
|
314
330
|
}
|
|
315
331
|
|
|
316
332
|
/**
|
|
317
|
-
* Synchronizes the logs tagged with
|
|
333
|
+
* Synchronizes the logs tagged with scoped addresses and all the senders in the addressbook.
|
|
318
334
|
* Returns the unsynched logs and updates the indexes of the secrets used to tag them until there are no more logs to sync.
|
|
319
335
|
* @param contractAddress - The address of the contract that the logs are tagged for
|
|
320
336
|
* @param recipient - The address of the recipient
|
|
321
337
|
* @returns A list of encrypted logs tagged with the recipient's address
|
|
322
338
|
*/
|
|
323
|
-
public async syncTaggedLogs(
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
//
|
|
336
|
-
|
|
337
|
-
|
|
339
|
+
public async syncTaggedLogs(
|
|
340
|
+
contractAddress: AztecAddress,
|
|
341
|
+
maxBlockNumber: number,
|
|
342
|
+
scopes?: AztecAddress[],
|
|
343
|
+
): Promise<Map<string, TxScopedL2Log[]>> {
|
|
344
|
+
const recipients = scopes ? scopes : await this.keyStore.getAccounts();
|
|
345
|
+
const result = new Map<string, TxScopedL2Log[]>();
|
|
346
|
+
const contractName = await this.contractDataOracle.getDebugContractName(contractAddress);
|
|
347
|
+
for (const recipient of recipients) {
|
|
348
|
+
const logs: TxScopedL2Log[] = [];
|
|
349
|
+
// Ideally this algorithm would be implemented in noir, exposing its building blocks as oracles.
|
|
350
|
+
// However it is impossible at the moment due to the language not supporting nested slices.
|
|
351
|
+
// This nesting is necessary because for a given set of tags we don't
|
|
352
|
+
// know how many logs we will get back. Furthermore, these logs are of undetermined
|
|
353
|
+
// length, since we don't really know the note they correspond to until we decrypt them.
|
|
354
|
+
|
|
355
|
+
// 1. Get all the secrets for the recipient and sender pairs (#9365)
|
|
356
|
+
const appTaggingSecrets = await this.#getAppTaggingSecretsForContacts(contractAddress, recipient);
|
|
357
|
+
|
|
358
|
+
// 1.1 Set up a sliding window with an offset. Chances are the sender might have messed up
|
|
359
|
+
// and inadvertedly incremented their index without use getting any logs (for example, in case
|
|
360
|
+
// of a revert). If we stopped looking for logs the first time
|
|
361
|
+
// we receive 0 for a tag, we might never receive anything from that sender again.
|
|
362
|
+
// Also there's a possibility that we have advanced our index, but the sender has reused it, so
|
|
363
|
+
// we might have missed some logs. For these reasons, we have to look both back and ahead of the
|
|
364
|
+
// stored index
|
|
365
|
+
const INDEX_OFFSET = 10;
|
|
366
|
+
type SearchState = {
|
|
367
|
+
currentTagggingSecrets: IndexedTaggingSecret[];
|
|
368
|
+
maxIndexesToCheck: { [k: string]: number };
|
|
369
|
+
initialSecretIndexes: { [k: string]: number };
|
|
370
|
+
secretsToIncrement: { [k: string]: number };
|
|
371
|
+
};
|
|
372
|
+
const searchState = appTaggingSecrets.reduce<SearchState>(
|
|
373
|
+
(acc, appTaggingSecret) => ({
|
|
374
|
+
// Start looking for logs before the stored index
|
|
375
|
+
currentTagggingSecrets: acc.currentTagggingSecrets.concat([
|
|
376
|
+
new IndexedTaggingSecret(appTaggingSecret.secret, Math.max(0, appTaggingSecret.index - INDEX_OFFSET)),
|
|
377
|
+
]),
|
|
378
|
+
// Keep looking for logs beyond the stored index
|
|
379
|
+
maxIndexesToCheck: {
|
|
380
|
+
...acc.maxIndexesToCheck,
|
|
381
|
+
...{ [appTaggingSecret.secret.toString()]: appTaggingSecret.index + INDEX_OFFSET },
|
|
382
|
+
},
|
|
383
|
+
// Keeps track of the secrets we have to increment in the database
|
|
384
|
+
secretsToIncrement: {},
|
|
385
|
+
// Store the initial set of indexes for the secrets
|
|
386
|
+
initialSecretIndexes: {
|
|
387
|
+
...acc.initialSecretIndexes,
|
|
388
|
+
...{ [appTaggingSecret.secret.toString()]: appTaggingSecret.index },
|
|
389
|
+
},
|
|
390
|
+
}),
|
|
391
|
+
{ currentTagggingSecrets: [], maxIndexesToCheck: {}, secretsToIncrement: {}, initialSecretIndexes: {} },
|
|
392
|
+
);
|
|
393
|
+
|
|
394
|
+
let { currentTagggingSecrets } = searchState;
|
|
395
|
+
const { maxIndexesToCheck, secretsToIncrement, initialSecretIndexes } = searchState;
|
|
396
|
+
|
|
397
|
+
while (currentTagggingSecrets.length > 0) {
|
|
398
|
+
// 2. Compute tags using the secrets, recipient and index. Obtain logs for each tag (#9380)
|
|
399
|
+
const currentTags = currentTagggingSecrets.map(taggingSecret => taggingSecret.computeTag(recipient));
|
|
400
|
+
const logsByTags = await this.aztecNode.getLogsByTags(currentTags);
|
|
401
|
+
const newTaggingSecrets: IndexedTaggingSecret[] = [];
|
|
402
|
+
logsByTags.forEach((logsByTag, logIndex) => {
|
|
403
|
+
const { secret: currentSecret, index: currentIndex } = currentTagggingSecrets[logIndex];
|
|
404
|
+
const currentSecretAsStr = currentSecret.toString();
|
|
405
|
+
this.log.debug(
|
|
406
|
+
`Syncing logs for recipient ${recipient}, secret ${currentSecretAsStr}:${currentIndex} at contract: ${contractName}(${contractAddress})`,
|
|
407
|
+
);
|
|
408
|
+
// 3.1. Append logs to the list and increment the index for the tags that have logs (#9380)
|
|
409
|
+
if (logsByTag.length > 0) {
|
|
410
|
+
this.log.verbose(
|
|
411
|
+
`Found ${
|
|
412
|
+
logsByTag.length
|
|
413
|
+
} logs for secret ${currentSecretAsStr} as recipient ${recipient}. Incrementing index to ${
|
|
414
|
+
currentIndex + 1
|
|
415
|
+
} at contract: ${contractName}(${contractAddress})`,
|
|
416
|
+
);
|
|
417
|
+
logs.push(...logsByTag);
|
|
418
|
+
|
|
419
|
+
if (currentIndex >= initialSecretIndexes[currentSecretAsStr]) {
|
|
420
|
+
// 3.2. Increment the index for the tags that have logs, provided they're higher than the one
|
|
421
|
+
// we have stored in the db (#9380)
|
|
422
|
+
secretsToIncrement[currentSecretAsStr] = currentIndex + 1;
|
|
423
|
+
// 3.3. Slide the window forwards if we have found logs beyond the initial index
|
|
424
|
+
maxIndexesToCheck[currentSecretAsStr] = currentIndex + INDEX_OFFSET;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
// 3.4 Keep increasing the index (inside the window) temporarily for the tags that have no logs
|
|
428
|
+
// There's a chance the sender missed some and we want to catch up
|
|
429
|
+
if (currentIndex < maxIndexesToCheck[currentSecretAsStr]) {
|
|
430
|
+
const newTaggingSecret = new IndexedTaggingSecret(currentSecret, currentIndex + 1);
|
|
431
|
+
newTaggingSecrets.push(newTaggingSecret);
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
await this.db.setTaggingSecretsIndexesAsRecipient(
|
|
435
|
+
Object.keys(secretsToIncrement).map(
|
|
436
|
+
secret => new IndexedTaggingSecret(Fr.fromString(secret), secretsToIncrement[secret]),
|
|
437
|
+
),
|
|
438
|
+
);
|
|
439
|
+
currentTagggingSecrets = newTaggingSecrets;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
result.set(
|
|
443
|
+
recipient.toString(),
|
|
444
|
+
logs.filter(log => log.blockNumber <= maxBlockNumber),
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
return result;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Decrypts logs tagged for a recipient and returns them.
|
|
452
|
+
* @param scopedLogs - The logs to decrypt.
|
|
453
|
+
* @param recipient - The recipient of the logs.
|
|
454
|
+
* @param simulator - The simulator to use for decryption.
|
|
455
|
+
* @returns The decrypted notes.
|
|
456
|
+
*/
|
|
457
|
+
async #decryptTaggedLogs(scopedLogs: TxScopedL2Log[], recipient: AztecAddress, simulator?: AcirSimulator) {
|
|
458
|
+
const recipientCompleteAddress = await this.getCompleteAddress(recipient);
|
|
459
|
+
const ivskM = await this.keyStore.getMasterSecretKey(
|
|
460
|
+
recipientCompleteAddress.publicKeys.masterIncomingViewingPublicKey,
|
|
461
|
+
);
|
|
462
|
+
const addressSecret = computeAddressSecret(recipientCompleteAddress.getPreaddress(), ivskM);
|
|
463
|
+
const ovskM = await this.keyStore.getMasterSecretKey(
|
|
464
|
+
recipientCompleteAddress.publicKeys.masterOutgoingViewingPublicKey,
|
|
465
|
+
);
|
|
466
|
+
// Since we could have notes with the same index for different txs, we need
|
|
467
|
+
// to keep track of them scoping by txHash
|
|
468
|
+
const excludedIndices: Map<string, Set<number>> = new Map();
|
|
469
|
+
const incomingNotes: IncomingNoteDao[] = [];
|
|
470
|
+
const outgoingNotes: OutgoingNoteDao[] = [];
|
|
471
|
+
|
|
472
|
+
const txEffectsCache = new Map<string, TxEffect | undefined>();
|
|
473
|
+
|
|
474
|
+
for (const scopedLog of scopedLogs) {
|
|
475
|
+
const incomingNotePayload = L1NotePayload.decryptAsIncoming(
|
|
476
|
+
scopedLog.logData,
|
|
477
|
+
addressSecret,
|
|
478
|
+
scopedLog.isFromPublic,
|
|
338
479
|
);
|
|
339
|
-
const
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
new IndexedTaggingSecret(appTaggingSecrets[index].secret, recipient, appTaggingSecrets[index].index + 1),
|
|
480
|
+
const outgoingNotePayload = L1NotePayload.decryptAsOutgoing(scopedLog.logData, ovskM, scopedLog.isFromPublic);
|
|
481
|
+
|
|
482
|
+
if (incomingNotePayload || outgoingNotePayload) {
|
|
483
|
+
if (incomingNotePayload && outgoingNotePayload && !incomingNotePayload.equals(outgoingNotePayload)) {
|
|
484
|
+
this.log.warn(
|
|
485
|
+
`Incoming and outgoing note payloads do not match. Incoming: ${JSON.stringify(
|
|
486
|
+
incomingNotePayload,
|
|
487
|
+
)}, Outgoing: ${JSON.stringify(outgoingNotePayload)}`,
|
|
348
488
|
);
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const payload = incomingNotePayload || outgoingNotePayload;
|
|
493
|
+
|
|
494
|
+
const txEffect =
|
|
495
|
+
txEffectsCache.get(scopedLog.txHash.toString()) ?? (await this.aztecNode.getTxEffect(scopedLog.txHash));
|
|
496
|
+
|
|
497
|
+
if (!txEffect) {
|
|
498
|
+
this.log.warn(`No tx effect found for ${scopedLog.txHash} while decrypting tagged logs`);
|
|
499
|
+
continue;
|
|
349
500
|
}
|
|
501
|
+
|
|
502
|
+
txEffectsCache.set(scopedLog.txHash.toString(), txEffect);
|
|
503
|
+
|
|
504
|
+
if (!excludedIndices.has(scopedLog.txHash.toString())) {
|
|
505
|
+
excludedIndices.set(scopedLog.txHash.toString(), new Set());
|
|
506
|
+
}
|
|
507
|
+
const { incomingNote, outgoingNote } = await produceNoteDaos(
|
|
508
|
+
// I don't like this at all, but we need a simulator to run `computeNoteHashAndOptionallyANullifier`. This generates
|
|
509
|
+
// a chicken-and-egg problem due to this oracle requiring a simulator, which in turn requires this oracle. Furthermore, since jest doesn't allow
|
|
510
|
+
// mocking ESM exports, we have to pollute the method even more by providing a simulator parameter so tests can inject a fake one.
|
|
511
|
+
simulator ?? getAcirSimulator(this.db, this.aztecNode, this.keyStore, this.contractDataOracle),
|
|
512
|
+
this.db,
|
|
513
|
+
incomingNotePayload ? computePoint(recipient) : undefined,
|
|
514
|
+
outgoingNotePayload ? recipientCompleteAddress.publicKeys.masterOutgoingViewingPublicKey : undefined,
|
|
515
|
+
payload!,
|
|
516
|
+
txEffect.txHash,
|
|
517
|
+
txEffect.noteHashes,
|
|
518
|
+
scopedLog.dataStartIndexForTx,
|
|
519
|
+
excludedIndices.get(scopedLog.txHash.toString())!,
|
|
520
|
+
this.log,
|
|
521
|
+
);
|
|
522
|
+
|
|
523
|
+
if (incomingNote) {
|
|
524
|
+
incomingNotes.push(incomingNote);
|
|
525
|
+
}
|
|
526
|
+
if (outgoingNote) {
|
|
527
|
+
outgoingNotes.push(outgoingNote);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
return { incomingNotes, outgoingNotes };
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Processes the tagged logs returned by syncTaggedLogs by decrypting them and storing them in the database.
|
|
536
|
+
* @param logs - The logs to process.
|
|
537
|
+
* @param recipient - The recipient of the logs.
|
|
538
|
+
*/
|
|
539
|
+
public async processTaggedLogs(
|
|
540
|
+
logs: TxScopedL2Log[],
|
|
541
|
+
recipient: AztecAddress,
|
|
542
|
+
simulator?: AcirSimulator,
|
|
543
|
+
): Promise<void> {
|
|
544
|
+
const { incomingNotes, outgoingNotes } = await this.#decryptTaggedLogs(logs, recipient, simulator);
|
|
545
|
+
if (incomingNotes.length || outgoingNotes.length) {
|
|
546
|
+
await this.db.addNotes(incomingNotes, outgoingNotes, recipient);
|
|
547
|
+
incomingNotes.forEach(noteDao => {
|
|
548
|
+
this.log.verbose(
|
|
549
|
+
`Added incoming note for contract ${noteDao.contractAddress} at slot ${
|
|
550
|
+
noteDao.storageSlot
|
|
551
|
+
} with nullifier ${noteDao.siloedNullifier.toString()}`,
|
|
552
|
+
);
|
|
553
|
+
});
|
|
554
|
+
outgoingNotes.forEach(noteDao => {
|
|
555
|
+
this.log.verbose(`Added outgoing note for contract ${noteDao.contractAddress} at slot ${noteDao.storageSlot}`);
|
|
350
556
|
});
|
|
351
|
-
// 4. Consolidate in db and replace initial appTaggingSecrets with the new ones (updated indexes)
|
|
352
|
-
await this.db.incrementTaggingSecretsIndexes(
|
|
353
|
-
newTaggingSecrets.map(secret => new TaggingSecret(secret.secret, recipient)),
|
|
354
|
-
);
|
|
355
|
-
appTaggingSecrets = newTaggingSecrets;
|
|
356
557
|
}
|
|
357
|
-
|
|
558
|
+
const nullifiedNotes: IncomingNoteDao[] = [];
|
|
559
|
+
const currentNotesForRecipient = await this.db.getIncomingNotes({ owner: recipient });
|
|
560
|
+
const nullifierIndexes = await this.aztecNode.findLeavesIndexes(
|
|
561
|
+
'latest',
|
|
562
|
+
MerkleTreeId.NULLIFIER_TREE,
|
|
563
|
+
currentNotesForRecipient.map(note => note.siloedNullifier),
|
|
564
|
+
);
|
|
565
|
+
|
|
566
|
+
const foundNullifiers = currentNotesForRecipient
|
|
567
|
+
.filter((_, i) => nullifierIndexes[i] !== undefined)
|
|
568
|
+
.map(note => note.siloedNullifier);
|
|
569
|
+
|
|
570
|
+
await this.db.removeNullifiedNotes(foundNullifiers, computePoint(recipient));
|
|
571
|
+
nullifiedNotes.forEach(noteDao => {
|
|
572
|
+
this.log.verbose(
|
|
573
|
+
`Removed note for contract ${noteDao.contractAddress} at slot ${
|
|
574
|
+
noteDao.storageSlot
|
|
575
|
+
} with nullifier ${noteDao.siloedNullifier.toString()}`,
|
|
576
|
+
);
|
|
577
|
+
});
|
|
358
578
|
}
|
|
359
579
|
}
|