@aztec/pxe 0.67.1 → 0.68.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.
- package/dest/database/kv_pxe_database.d.ts +3 -3
- package/dest/database/kv_pxe_database.d.ts.map +1 -1
- package/dest/database/kv_pxe_database.js +5 -5
- package/dest/database/pxe_database.d.ts +6 -6
- package/dest/database/pxe_database.d.ts.map +1 -1
- package/dest/kernel_oracle/index.js +2 -2
- package/dest/kernel_prover/hints/build_private_kernel_reset_private_inputs.js +2 -2
- package/dest/kernel_prover/kernel_prover.d.ts.map +1 -1
- package/dest/kernel_prover/kernel_prover.js +5 -2
- package/dest/kernel_prover/test/test_circuit_prover.d.ts +1 -2
- package/dest/kernel_prover/test/test_circuit_prover.d.ts.map +1 -1
- package/dest/kernel_prover/test/test_circuit_prover.js +4 -10
- package/dest/pxe_service/error_enriching.d.ts.map +1 -1
- package/dest/pxe_service/error_enriching.js +6 -3
- package/dest/pxe_service/pxe_service.d.ts +6 -5
- package/dest/pxe_service/pxe_service.d.ts.map +1 -1
- package/dest/pxe_service/pxe_service.js +33 -24
- package/dest/simulator_oracle/index.d.ts +8 -6
- package/dest/simulator_oracle/index.d.ts.map +1 -1
- package/dest/simulator_oracle/index.js +170 -158
- package/dest/simulator_oracle/tagging_utils.d.ts +16 -0
- package/dest/simulator_oracle/tagging_utils.d.ts.map +1 -0
- package/dest/simulator_oracle/tagging_utils.js +25 -0
- package/dest/utils/create_pxe_service.d.ts.map +1 -1
- package/dest/utils/create_pxe_service.js +8 -5
- package/package.json +17 -17
- package/src/database/kv_pxe_database.ts +6 -4
- package/src/database/pxe_database.ts +6 -6
- package/src/kernel_oracle/index.ts +1 -1
- package/src/kernel_prover/hints/build_private_kernel_reset_private_inputs.ts +1 -1
- package/src/kernel_prover/kernel_prover.ts +11 -1
- package/src/kernel_prover/test/test_circuit_prover.ts +6 -22
- package/src/pxe_service/error_enriching.ts +5 -2
- package/src/pxe_service/pxe_service.ts +44 -35
- package/src/simulator_oracle/index.ts +203 -188
- package/src/simulator_oracle/tagging_utils.ts +31 -0
- package/src/utils/create_pxe_service.ts +7 -4
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
type L1_TO_L2_MSG_TREE_HEIGHT,
|
|
25
25
|
PrivateLog,
|
|
26
26
|
computeAddressSecret,
|
|
27
|
-
|
|
27
|
+
computeTaggingSecretPoint,
|
|
28
28
|
} from '@aztec/circuits.js';
|
|
29
29
|
import { type FunctionArtifact, getFunctionArtifact } from '@aztec/foundation/abi';
|
|
30
30
|
import { poseidon2Hash } from '@aztec/foundation/crypto';
|
|
@@ -38,6 +38,7 @@ import { type IncomingNoteDao } from '../database/incoming_note_dao.js';
|
|
|
38
38
|
import { type PxeDatabase } from '../database/index.js';
|
|
39
39
|
import { produceNoteDaos } from '../note_decryption_utils/produce_note_daos.js';
|
|
40
40
|
import { getAcirSimulator } from '../simulator/index.js';
|
|
41
|
+
import { WINDOW_HALF_SIZE, getIndexedTaggingSecretsForTheWindow, getInitialIndexesMap } from './tagging_utils.js';
|
|
41
42
|
|
|
42
43
|
/**
|
|
43
44
|
* A data oracle that provides information needed for simulating a transaction.
|
|
@@ -252,33 +253,33 @@ export class SimulatorOracle implements DBOracle {
|
|
|
252
253
|
* finally the index specified tag. We will then query the node with this tag for each address in the address book.
|
|
253
254
|
* @returns The full list of the users contact addresses.
|
|
254
255
|
*/
|
|
255
|
-
public
|
|
256
|
-
return this.db.
|
|
256
|
+
public getSenders(): Promise<AztecAddress[]> {
|
|
257
|
+
return this.db.getSenderAddresses();
|
|
257
258
|
}
|
|
258
259
|
|
|
259
260
|
/**
|
|
260
|
-
* Returns the tagging secret for a given sender and recipient pair. For this to work, the
|
|
261
|
+
* Returns the tagging secret for a given sender and recipient pair. For this to work, the ivsk_m of the sender must be known.
|
|
261
262
|
* Includes the next index to be used used for tagging with this secret.
|
|
262
263
|
* @param contractAddress - The contract address to silo the secret for
|
|
263
264
|
* @param sender - The address sending the note
|
|
264
265
|
* @param recipient - The address receiving the note
|
|
265
|
-
* @returns
|
|
266
|
+
* @returns An indexed tagging secret that can be used to tag notes.
|
|
266
267
|
*/
|
|
267
|
-
public async
|
|
268
|
+
public async getIndexedTaggingSecretAsSender(
|
|
268
269
|
contractAddress: AztecAddress,
|
|
269
270
|
sender: AztecAddress,
|
|
270
271
|
recipient: AztecAddress,
|
|
271
272
|
): Promise<IndexedTaggingSecret> {
|
|
272
273
|
await this.syncTaggedLogsAsSender(contractAddress, sender, recipient);
|
|
273
274
|
|
|
274
|
-
const
|
|
275
|
-
const [index] = await this.db.getTaggingSecretsIndexesAsSender([
|
|
275
|
+
const appTaggingSecret = await this.#calculateAppTaggingSecret(contractAddress, sender, recipient);
|
|
276
|
+
const [index] = await this.db.getTaggingSecretsIndexesAsSender([appTaggingSecret]);
|
|
276
277
|
|
|
277
|
-
return new IndexedTaggingSecret(
|
|
278
|
+
return new IndexedTaggingSecret(appTaggingSecret, index);
|
|
278
279
|
}
|
|
279
280
|
|
|
280
281
|
/**
|
|
281
|
-
* Increments the tagging secret for a given sender and recipient pair. For this to work, the
|
|
282
|
+
* Increments the tagging secret for a given sender and recipient pair. For this to work, the ivsk_m of the sender must be known.
|
|
282
283
|
* @param contractAddress - The contract address to silo the secret for
|
|
283
284
|
* @param sender - The address sending the note
|
|
284
285
|
* @param recipient - The address receiving the note
|
|
@@ -288,7 +289,7 @@ export class SimulatorOracle implements DBOracle {
|
|
|
288
289
|
sender: AztecAddress,
|
|
289
290
|
recipient: AztecAddress,
|
|
290
291
|
): Promise<void> {
|
|
291
|
-
const secret = await this.#
|
|
292
|
+
const secret = await this.#calculateAppTaggingSecret(contractAddress, sender, recipient);
|
|
292
293
|
const contractName = await this.contractDataOracle.getDebugContractName(contractAddress);
|
|
293
294
|
this.log.debug(`Incrementing app tagging secret at ${contractName}(${contractAddress})`, {
|
|
294
295
|
secret,
|
|
@@ -302,37 +303,38 @@ export class SimulatorOracle implements DBOracle {
|
|
|
302
303
|
await this.db.setTaggingSecretsIndexesAsSender([new IndexedTaggingSecret(secret, index + 1)]);
|
|
303
304
|
}
|
|
304
305
|
|
|
305
|
-
async #
|
|
306
|
+
async #calculateAppTaggingSecret(contractAddress: AztecAddress, sender: AztecAddress, recipient: AztecAddress) {
|
|
306
307
|
const senderCompleteAddress = await this.getCompleteAddress(sender);
|
|
307
308
|
const senderIvsk = await this.keyStore.getMasterIncomingViewingSecretKey(sender);
|
|
308
|
-
const
|
|
309
|
-
// Silo the secret
|
|
310
|
-
const
|
|
311
|
-
return
|
|
309
|
+
const secretPoint = computeTaggingSecretPoint(senderCompleteAddress, senderIvsk, recipient);
|
|
310
|
+
// Silo the secret so it can't be used to track other app's notes
|
|
311
|
+
const appSecret = poseidon2Hash([secretPoint.x, secretPoint.y, contractAddress]);
|
|
312
|
+
return appSecret;
|
|
312
313
|
}
|
|
313
314
|
|
|
314
315
|
/**
|
|
315
|
-
* Returns the
|
|
316
|
+
* Returns the indexed tagging secrets for a given recipient and all the senders in the address book
|
|
316
317
|
* This method should be exposed as an oracle call to allow aztec.nr to perform the orchestration
|
|
317
318
|
* of the syncTaggedLogs and processTaggedLogs methods. However, it is not possible to do so at the moment,
|
|
318
319
|
* so we're keeping it private for now.
|
|
319
320
|
* @param contractAddress - The contract address to silo the secret for
|
|
320
321
|
* @param recipient - The address receiving the notes
|
|
321
|
-
* @returns A list of
|
|
322
|
+
* @returns A list of indexed tagging secrets
|
|
322
323
|
*/
|
|
323
|
-
async #
|
|
324
|
+
async #getIndexedTaggingSecretsForSenders(
|
|
324
325
|
contractAddress: AztecAddress,
|
|
325
326
|
recipient: AztecAddress,
|
|
326
327
|
): Promise<IndexedTaggingSecret[]> {
|
|
327
328
|
const recipientCompleteAddress = await this.getCompleteAddress(recipient);
|
|
328
329
|
const recipientIvsk = await this.keyStore.getMasterIncomingViewingSecretKey(recipient);
|
|
329
330
|
|
|
330
|
-
// We implicitly add all PXE accounts as
|
|
331
|
-
|
|
331
|
+
// We implicitly add all PXE accounts as senders, this helps us decrypt tags on notes that we send to ourselves
|
|
332
|
+
// (recipient = us, sender = us)
|
|
333
|
+
const senders = [...(await this.db.getSenderAddresses()), ...(await this.keyStore.getAccounts())].filter(
|
|
332
334
|
(address, index, self) => index === self.findIndex(otherAddress => otherAddress.equals(address)),
|
|
333
335
|
);
|
|
334
|
-
const appTaggingSecrets =
|
|
335
|
-
const sharedSecret =
|
|
336
|
+
const appTaggingSecrets = senders.map(contact => {
|
|
337
|
+
const sharedSecret = computeTaggingSecretPoint(recipientCompleteAddress, recipientIvsk, contact);
|
|
336
338
|
return poseidon2Hash([sharedSecret.x, sharedSecret.y, contractAddress]);
|
|
337
339
|
});
|
|
338
340
|
const indexes = await this.db.getTaggingSecretsIndexesAsRecipient(appTaggingSecrets);
|
|
@@ -351,65 +353,63 @@ export class SimulatorOracle implements DBOracle {
|
|
|
351
353
|
sender: AztecAddress,
|
|
352
354
|
recipient: AztecAddress,
|
|
353
355
|
): Promise<void> {
|
|
354
|
-
const appTaggingSecret = await this.#
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
// is a window in which we see the combination of them to be greater than the window's size. If true, we rewind current index to the start of said window and use it.
|
|
367
|
-
// Assuming two windows of 5:
|
|
368
|
-
// [0, 1, 0, 1, 0], [0, 0, 0, 0, 0]
|
|
369
|
-
// We can see that when processing the second window, the previous amount of empty slots from the back of the window (1), added with the empty elements from the front of the window (5)
|
|
370
|
-
// is greater than 5 (6) and therefore we have found a window to use.
|
|
371
|
-
// We simply need to take the number of elements (10) - the size of the window (5) - the number of consecutive empty elements from the back of the last window (1) = 4;
|
|
372
|
-
// This is the first index of our desired window.
|
|
373
|
-
// Note that if we ever see a situation like so:
|
|
374
|
-
// [0, 1, 0, 1, 0], [0, 0, 0, 0, 1]
|
|
375
|
-
// This also returns the correct index (4), but this is indicative of a problem / desync. i.e. we should never have a window that has a log that exists after the window.
|
|
376
|
-
|
|
356
|
+
const appTaggingSecret = await this.#calculateAppTaggingSecret(contractAddress, sender, recipient);
|
|
357
|
+
const [oldIndex] = await this.db.getTaggingSecretsIndexesAsSender([appTaggingSecret]);
|
|
358
|
+
|
|
359
|
+
// This algorithm works such that:
|
|
360
|
+
// 1. If we find minimum consecutive empty logs in a window of logs we set the index to the index of the last log
|
|
361
|
+
// we found and quit.
|
|
362
|
+
// 2. If we don't find minimum consecutive empty logs in a window of logs we slide the window to latest log index
|
|
363
|
+
// and repeat the process.
|
|
364
|
+
const MIN_CONSECUTIVE_EMPTY_LOGS = 10;
|
|
365
|
+
const WINDOW_SIZE = MIN_CONSECUTIVE_EMPTY_LOGS * 2;
|
|
366
|
+
|
|
367
|
+
let [numConsecutiveEmptyLogs, currentIndex] = [0, oldIndex];
|
|
377
368
|
do {
|
|
378
|
-
|
|
369
|
+
// We compute the tags for the current window of indexes
|
|
370
|
+
const currentTags = [...new Array(WINDOW_SIZE)].map((_, i) => {
|
|
379
371
|
const indexedAppTaggingSecret = new IndexedTaggingSecret(appTaggingSecret, currentIndex + i);
|
|
380
372
|
return indexedAppTaggingSecret.computeSiloedTag(recipient, contractAddress);
|
|
381
373
|
});
|
|
382
|
-
previousEmptyBack = currentEmptyBack;
|
|
383
374
|
|
|
375
|
+
// We fetch the logs for the tags
|
|
384
376
|
const possibleLogs = await this.aztecNode.getLogsByTags(currentTags);
|
|
385
377
|
|
|
386
|
-
|
|
387
|
-
currentEmptyFront = indexOfFirstLog === -1 ? INDEX_OFFSET : indexOfFirstLog;
|
|
388
|
-
|
|
378
|
+
// We find the index of the last log in the window that is not empty
|
|
389
379
|
const indexOfLastLog = possibleLogs.findLastIndex(possibleLog => possibleLog.length !== 0);
|
|
390
|
-
currentEmptyBack = indexOfLastLog === -1 ? INDEX_OFFSET : INDEX_OFFSET - 1 - indexOfLastLog;
|
|
391
380
|
|
|
392
|
-
|
|
393
|
-
|
|
381
|
+
if (indexOfLastLog === -1) {
|
|
382
|
+
// We haven't found any logs in the current window so we stop looking
|
|
383
|
+
break;
|
|
384
|
+
}
|
|
394
385
|
|
|
395
|
-
|
|
396
|
-
|
|
386
|
+
// We move the current index to that of the last log we found
|
|
387
|
+
currentIndex += indexOfLastLog + 1;
|
|
397
388
|
|
|
398
|
-
|
|
389
|
+
// We compute the number of consecutive empty logs we found and repeat the process if we haven't found enough.
|
|
390
|
+
numConsecutiveEmptyLogs = WINDOW_SIZE - indexOfLastLog - 1;
|
|
391
|
+
} while (numConsecutiveEmptyLogs < MIN_CONSECUTIVE_EMPTY_LOGS);
|
|
399
392
|
|
|
400
393
|
const contractName = await this.contractDataOracle.getDebugContractName(contractAddress);
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
394
|
+
if (currentIndex !== oldIndex) {
|
|
395
|
+
await this.db.setTaggingSecretsIndexesAsSender([new IndexedTaggingSecret(appTaggingSecret, currentIndex)]);
|
|
396
|
+
|
|
397
|
+
this.log.debug(`Syncing logs for sender ${sender} at contract ${contractName}(${contractAddress})`, {
|
|
398
|
+
sender,
|
|
399
|
+
secret: appTaggingSecret,
|
|
400
|
+
index: currentIndex,
|
|
401
|
+
contractName,
|
|
402
|
+
contractAddress,
|
|
403
|
+
});
|
|
404
|
+
} else {
|
|
405
|
+
this.log.debug(`No new logs found for sender ${sender} at contract ${contractName}(${contractAddress})`);
|
|
406
|
+
}
|
|
408
407
|
}
|
|
409
408
|
|
|
410
409
|
/**
|
|
411
410
|
* Synchronizes the logs tagged with scoped addresses and all the senders in the address book.
|
|
412
|
-
* Returns the unsynched logs and updates the indexes of the secrets used to tag them until there are no more logs
|
|
411
|
+
* Returns the unsynched logs and updates the indexes of the secrets used to tag them until there are no more logs
|
|
412
|
+
* to sync.
|
|
413
413
|
* @param contractAddress - The address of the contract that the logs are tagged for
|
|
414
414
|
* @param recipient - The address of the recipient
|
|
415
415
|
* @returns A list of encrypted logs tagged with the recipient's address
|
|
@@ -419,125 +419,137 @@ export class SimulatorOracle implements DBOracle {
|
|
|
419
419
|
maxBlockNumber: number,
|
|
420
420
|
scopes?: AztecAddress[],
|
|
421
421
|
): Promise<Map<string, TxScopedL2Log[]>> {
|
|
422
|
+
// Ideally this algorithm would be implemented in noir, exposing its building blocks as oracles.
|
|
423
|
+
// However it is impossible at the moment due to the language not supporting nested slices.
|
|
424
|
+
// This nesting is necessary because for a given set of tags we don't
|
|
425
|
+
// know how many logs we will get back. Furthermore, these logs are of undetermined
|
|
426
|
+
// length, since we don't really know the note they correspond to until we decrypt them.
|
|
427
|
+
|
|
422
428
|
const recipients = scopes ? scopes : await this.keyStore.getAccounts();
|
|
423
|
-
|
|
429
|
+
// A map of logs going from recipient address to logs. Note that the logs might have been processed before
|
|
430
|
+
// due to us having a sliding window that "looks back" for logs as well. (We look back as there is no guarantee
|
|
431
|
+
// that a logs will be received ordered by a given tax index and that the tags won't be reused).
|
|
432
|
+
const logsMap = new Map<string, TxScopedL2Log[]>();
|
|
424
433
|
const contractName = await this.contractDataOracle.getDebugContractName(contractAddress);
|
|
425
434
|
for (const recipient of recipients) {
|
|
426
|
-
const
|
|
427
|
-
|
|
428
|
-
//
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
//
|
|
432
|
-
|
|
433
|
-
//
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
//
|
|
437
|
-
//
|
|
438
|
-
//
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
maxIndexesToCheck: { [k: string]: number };
|
|
447
|
-
initialSecretIndexes: { [k: string]: number };
|
|
448
|
-
secretsToIncrement: { [k: string]: number };
|
|
449
|
-
};
|
|
450
|
-
const searchState = appTaggingSecrets.reduce<SearchState>(
|
|
451
|
-
(acc, appTaggingSecret) => ({
|
|
452
|
-
// Start looking for logs before the stored index
|
|
453
|
-
currentTagggingSecrets: acc.currentTagggingSecrets.concat([
|
|
454
|
-
new IndexedTaggingSecret(appTaggingSecret.secret, Math.max(0, appTaggingSecret.index - INDEX_OFFSET)),
|
|
455
|
-
]),
|
|
456
|
-
// Keep looking for logs beyond the stored index
|
|
457
|
-
maxIndexesToCheck: {
|
|
458
|
-
...acc.maxIndexesToCheck,
|
|
459
|
-
...{ [appTaggingSecret.secret.toString()]: appTaggingSecret.index + INDEX_OFFSET },
|
|
460
|
-
},
|
|
461
|
-
// Keeps track of the secrets we have to increment in the database
|
|
462
|
-
secretsToIncrement: {},
|
|
463
|
-
// Store the initial set of indexes for the secrets
|
|
464
|
-
initialSecretIndexes: {
|
|
465
|
-
...acc.initialSecretIndexes,
|
|
466
|
-
...{ [appTaggingSecret.secret.toString()]: appTaggingSecret.index },
|
|
467
|
-
},
|
|
468
|
-
}),
|
|
469
|
-
{ currentTagggingSecrets: [], maxIndexesToCheck: {}, secretsToIncrement: {}, initialSecretIndexes: {} },
|
|
470
|
-
);
|
|
435
|
+
const logsForRecipient: TxScopedL2Log[] = [];
|
|
436
|
+
|
|
437
|
+
// Get all the secrets for the recipient and sender pairs (#9365)
|
|
438
|
+
const secrets = await this.#getIndexedTaggingSecretsForSenders(contractAddress, recipient);
|
|
439
|
+
|
|
440
|
+
// We fetch logs for a window of indexes in a range:
|
|
441
|
+
// <latest_log_index - WINDOW_HALF_SIZE, latest_log_index + WINDOW_HALF_SIZE>.
|
|
442
|
+
//
|
|
443
|
+
// We use this window approach because it could happen that a sender might have messed up and inadvertently
|
|
444
|
+
// incremented their index without us getting any logs (for example, in case of a revert). If we stopped looking
|
|
445
|
+
// for logs the first time we don't receive any logs for a tag, we might never receive anything from that sender again.
|
|
446
|
+
// Also there's a possibility that we have advanced our index, but the sender has reused it, so we might have missed
|
|
447
|
+
// some logs. For these reasons, we have to look both back and ahead of the stored index.
|
|
448
|
+
let secretsAndWindows = secrets.map(secret => {
|
|
449
|
+
return {
|
|
450
|
+
appTaggingSecret: secret.appTaggingSecret,
|
|
451
|
+
leftMostIndex: Math.max(0, secret.index - WINDOW_HALF_SIZE),
|
|
452
|
+
rightMostIndex: secret.index + WINDOW_HALF_SIZE,
|
|
453
|
+
};
|
|
454
|
+
});
|
|
471
455
|
|
|
472
|
-
|
|
473
|
-
const {
|
|
456
|
+
// As we iterate we store the largest index we have seen for a given secret to later on store it in the db.
|
|
457
|
+
const newLargestIndexMapToStore: { [k: string]: number } = {};
|
|
474
458
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
459
|
+
// The initial/unmodified indexes of the secrets stored in a key-value map where key is the app tagging secret.
|
|
460
|
+
const initialIndexesMap = getInitialIndexesMap(secrets);
|
|
461
|
+
|
|
462
|
+
while (secretsAndWindows.length > 0) {
|
|
463
|
+
const secretsForTheWholeWindow = getIndexedTaggingSecretsForTheWindow(secretsAndWindows);
|
|
464
|
+
const tagsForTheWholeWindow = secretsForTheWholeWindow.map(secret =>
|
|
465
|
+
secret.computeSiloedTag(recipient, contractAddress),
|
|
479
466
|
);
|
|
480
|
-
|
|
481
|
-
|
|
467
|
+
|
|
468
|
+
// We store the new largest indexes we find in the iteration in the following map to later on construct
|
|
469
|
+
// a new set of secrets and windows to fetch logs for.
|
|
470
|
+
const newLargestIndexMapForIteration: { [k: string]: number } = {};
|
|
471
|
+
|
|
472
|
+
// Fetch the logs for the tags and iterate over them
|
|
473
|
+
const logsByTags = await this.aztecNode.getLogsByTags(tagsForTheWholeWindow);
|
|
474
|
+
|
|
482
475
|
logsByTags.forEach((logsByTag, logIndex) => {
|
|
483
|
-
const { secret: currentSecret, index: currentIndex } = currentTagggingSecrets[logIndex];
|
|
484
|
-
const currentSecretAsStr = currentSecret.toString();
|
|
485
|
-
this.log.debug(`Syncing logs for recipient ${recipient} at contract ${contractName}(${contractAddress})`, {
|
|
486
|
-
recipient,
|
|
487
|
-
secret: currentSecret,
|
|
488
|
-
index: currentIndex,
|
|
489
|
-
contractName,
|
|
490
|
-
contractAddress,
|
|
491
|
-
});
|
|
492
|
-
// 3.1. Append logs to the list and increment the index for the tags that have logs (#9380)
|
|
493
476
|
if (logsByTag.length > 0) {
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
477
|
+
// The logs for the given tag exist so we store them for later processing
|
|
478
|
+
logsForRecipient.push(...logsByTag);
|
|
479
|
+
|
|
480
|
+
// We retrieve the indexed tagging secret corresponding to the log as I need that to evaluate whether
|
|
481
|
+
// a new largest index have been found.
|
|
482
|
+
const secretCorrespondingToLog = secretsForTheWholeWindow[logIndex];
|
|
483
|
+
const initialIndex = initialIndexesMap[secretCorrespondingToLog.appTaggingSecret.toString()];
|
|
484
|
+
|
|
485
|
+
this.log.debug(`Found ${logsByTag.length} logs as recipient ${recipient}`, {
|
|
486
|
+
recipient,
|
|
487
|
+
secret: secretCorrespondingToLog.appTaggingSecret,
|
|
488
|
+
contractName,
|
|
489
|
+
contractAddress,
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
if (
|
|
493
|
+
secretCorrespondingToLog.index >= initialIndex &&
|
|
494
|
+
(newLargestIndexMapForIteration[secretCorrespondingToLog.appTaggingSecret.toString()] === undefined ||
|
|
495
|
+
secretCorrespondingToLog.index >=
|
|
496
|
+
newLargestIndexMapForIteration[secretCorrespondingToLog.appTaggingSecret.toString()])
|
|
497
|
+
) {
|
|
498
|
+
// We have found a new largest index so we store it for later processing (storing it in the db + fetching
|
|
499
|
+
// the difference of the window sets of current and the next iteration)
|
|
500
|
+
newLargestIndexMapForIteration[secretCorrespondingToLog.appTaggingSecret.toString()] =
|
|
501
|
+
secretCorrespondingToLog.index + 1;
|
|
502
|
+
|
|
503
|
+
this.log.debug(
|
|
504
|
+
`Incrementing index to ${
|
|
505
|
+
secretCorrespondingToLog.index + 1
|
|
506
|
+
} at contract ${contractName}(${contractAddress})`,
|
|
507
|
+
);
|
|
513
508
|
}
|
|
514
509
|
}
|
|
515
|
-
// 3.4 Keep increasing the index (inside the window) temporarily for the tags that have no logs
|
|
516
|
-
// There's a chance the sender missed some and we want to catch up
|
|
517
|
-
if (currentIndex < maxIndexesToCheck[currentSecretAsStr]) {
|
|
518
|
-
const newTaggingSecret = new IndexedTaggingSecret(currentSecret, currentIndex + 1);
|
|
519
|
-
newTaggingSecrets.push(newTaggingSecret);
|
|
520
|
-
}
|
|
521
510
|
});
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
511
|
+
|
|
512
|
+
// Now based on the new largest indexes we found, we will construct a new secrets and windows set to fetch logs
|
|
513
|
+
// for. Note that it's very unlikely that a new log from the current window would appear between the iterations
|
|
514
|
+
// so we fetch the logs only for the difference of the window sets.
|
|
515
|
+
const newSecretsAndWindows = [];
|
|
516
|
+
for (const [appTaggingSecret, newIndex] of Object.entries(newLargestIndexMapForIteration)) {
|
|
517
|
+
const secret = secrets.find(secret => secret.appTaggingSecret.toString() === appTaggingSecret);
|
|
518
|
+
if (secret) {
|
|
519
|
+
newSecretsAndWindows.push({
|
|
520
|
+
appTaggingSecret: secret.appTaggingSecret,
|
|
521
|
+
// We set the left most index to the new index to avoid fetching the same logs again
|
|
522
|
+
leftMostIndex: newIndex,
|
|
523
|
+
rightMostIndex: newIndex + WINDOW_HALF_SIZE,
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
// We store the new largest index in the map to later store it in the db.
|
|
527
|
+
newLargestIndexMapToStore[appTaggingSecret] = newIndex;
|
|
528
|
+
} else {
|
|
529
|
+
throw new Error(
|
|
530
|
+
`Secret not found for appTaggingSecret ${appTaggingSecret}. This is a bug as it should never happen!`,
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// Now we set the new secrets and windows and proceed to the next iteration.
|
|
536
|
+
secretsAndWindows = newSecretsAndWindows;
|
|
528
537
|
}
|
|
529
538
|
|
|
530
|
-
|
|
539
|
+
// We filter the logs by block number and store them in the map.
|
|
540
|
+
logsMap.set(
|
|
531
541
|
recipient.toString(),
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
542
|
+
logsForRecipient.filter(log => log.blockNumber <= maxBlockNumber),
|
|
543
|
+
);
|
|
544
|
+
|
|
545
|
+
// At this point we have processed all the logs for the recipient so we store the new largest indexes in the db.
|
|
546
|
+
await this.db.setTaggingSecretsIndexesAsRecipient(
|
|
547
|
+
Object.entries(newLargestIndexMapToStore).map(
|
|
548
|
+
([appTaggingSecret, index]) => new IndexedTaggingSecret(Fr.fromHexString(appTaggingSecret), index),
|
|
537
549
|
),
|
|
538
550
|
);
|
|
539
551
|
}
|
|
540
|
-
return
|
|
552
|
+
return logsMap;
|
|
541
553
|
}
|
|
542
554
|
|
|
543
555
|
/**
|
|
@@ -628,27 +640,30 @@ export class SimulatorOracle implements DBOracle {
|
|
|
628
640
|
});
|
|
629
641
|
});
|
|
630
642
|
}
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
const
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
slot
|
|
650
|
-
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
public async removeNullifiedNotes(contractAddress: AztecAddress) {
|
|
646
|
+
for (const recipient of await this.keyStore.getAccounts()) {
|
|
647
|
+
const currentNotesForRecipient = await this.db.getIncomingNotes({ contractAddress, owner: recipient });
|
|
648
|
+
const nullifiersToCheck = currentNotesForRecipient.map(note => note.siloedNullifier);
|
|
649
|
+
const nullifierIndexes = await this.aztecNode.findNullifiersIndexesWithBlock('latest', nullifiersToCheck);
|
|
650
|
+
|
|
651
|
+
const foundNullifiers = nullifiersToCheck
|
|
652
|
+
.map((nullifier, i) => {
|
|
653
|
+
if (nullifierIndexes[i] !== undefined) {
|
|
654
|
+
return { ...nullifierIndexes[i], ...{ data: nullifier } } as InBlock<Fr>;
|
|
655
|
+
}
|
|
656
|
+
})
|
|
657
|
+
.filter(nullifier => nullifier !== undefined) as InBlock<Fr>[];
|
|
658
|
+
|
|
659
|
+
const nullifiedNotes = await this.db.removeNullifiedNotes(foundNullifiers, recipient.toAddressPoint());
|
|
660
|
+
nullifiedNotes.forEach(noteDao => {
|
|
661
|
+
this.log.verbose(`Removed note for contract ${noteDao.contractAddress} at slot ${noteDao.storageSlot}`, {
|
|
662
|
+
contract: noteDao.contractAddress,
|
|
663
|
+
slot: noteDao.storageSlot,
|
|
664
|
+
nullifier: noteDao.siloedNullifier.toString(),
|
|
665
|
+
});
|
|
651
666
|
});
|
|
652
|
-
}
|
|
667
|
+
}
|
|
653
668
|
}
|
|
654
669
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type Fr, IndexedTaggingSecret } from '@aztec/circuits.js';
|
|
2
|
+
|
|
3
|
+
// Half the size of the window we slide over the tagging secret indexes.
|
|
4
|
+
export const WINDOW_HALF_SIZE = 10;
|
|
5
|
+
|
|
6
|
+
export function getIndexedTaggingSecretsForTheWindow(
|
|
7
|
+
secretsAndWindows: { appTaggingSecret: Fr; leftMostIndex: number; rightMostIndex: number }[],
|
|
8
|
+
): IndexedTaggingSecret[] {
|
|
9
|
+
const secrets: IndexedTaggingSecret[] = [];
|
|
10
|
+
for (const secretAndWindow of secretsAndWindows) {
|
|
11
|
+
for (let i = secretAndWindow.leftMostIndex; i <= secretAndWindow.rightMostIndex; i++) {
|
|
12
|
+
secrets.push(new IndexedTaggingSecret(secretAndWindow.appTaggingSecret, i));
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return secrets;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Creates a map from app tagging secret to initial index.
|
|
20
|
+
* @param indexedTaggingSecrets - The indexed tagging secrets to get the initial indexes from.
|
|
21
|
+
* @returns The map from app tagging secret to initial index.
|
|
22
|
+
*/
|
|
23
|
+
export function getInitialIndexesMap(indexedTaggingSecrets: IndexedTaggingSecret[]): { [k: string]: number } {
|
|
24
|
+
const initialIndexes: { [k: string]: number } = {};
|
|
25
|
+
|
|
26
|
+
for (const indexedTaggingSecret of indexedTaggingSecrets) {
|
|
27
|
+
initialIndexes[indexedTaggingSecret.appTaggingSecret.toString()] = indexedTaggingSecret.index;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return initialIndexes;
|
|
31
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BBNativePrivateKernelProver } from '@aztec/bb-prover';
|
|
2
|
+
import { BBWasmPrivateKernelProver } from '@aztec/bb-prover/wasm';
|
|
2
3
|
import { type AztecNode, type PrivateKernelProver } from '@aztec/circuit-types';
|
|
3
4
|
import { randomBytes } from '@aztec/foundation/crypto';
|
|
4
5
|
import { createLogger } from '@aztec/foundation/log';
|
|
@@ -59,9 +60,11 @@ function createProver(config: PXEServiceConfig, logSuffix?: string) {
|
|
|
59
60
|
|
|
60
61
|
// (@PhilWindle) Temporary validation until WASM is implemented
|
|
61
62
|
if (!config.bbBinaryPath || !config.bbWorkingDirectory) {
|
|
62
|
-
|
|
63
|
+
return new BBWasmPrivateKernelProver(16);
|
|
64
|
+
} else {
|
|
65
|
+
const bbConfig = config as Required<Pick<PXEServiceConfig, 'bbBinaryPath' | 'bbWorkingDirectory'>> &
|
|
66
|
+
PXEServiceConfig;
|
|
67
|
+
const log = createLogger('pxe:bb-native-prover' + (logSuffix ? `:${logSuffix}` : ''));
|
|
68
|
+
return BBNativePrivateKernelProver.new({ bbSkipCleanup: false, ...bbConfig }, log);
|
|
63
69
|
}
|
|
64
|
-
const bbConfig = config as Required<Pick<PXEServiceConfig, 'bbBinaryPath' | 'bbWorkingDirectory'>> & PXEServiceConfig;
|
|
65
|
-
const log = createLogger('pxe:bb-native-prover' + (logSuffix ? `:${logSuffix}` : ''));
|
|
66
|
-
return BBNativePrivateKernelProver.new({ bbSkipCleanup: false, ...bbConfig }, log);
|
|
67
70
|
}
|