@aztec/pxe 0.67.0 → 0.67.1-devnet
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.map +1 -1
- package/dest/database/kv_pxe_database.js +2 -2
- 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/pxe_service.d.ts.map +1 -1
- package/dest/pxe_service/pxe_service.js +7 -4
- package/dest/simulator_oracle/index.d.ts +7 -5
- package/dest/simulator_oracle/index.d.ts.map +1 -1
- package/dest/simulator_oracle/index.js +131 -118
- package/dest/simulator_oracle/tagging_utils.d.ts +15 -0
- package/dest/simulator_oracle/tagging_utils.d.ts.map +1 -0
- package/dest/simulator_oracle/tagging_utils.js +23 -0
- package/dest/utils/create_pxe_service.d.ts.map +1 -1
- package/dest/utils/create_pxe_service.js +8 -5
- package/package.json +14 -14
- package/src/database/kv_pxe_database.ts +3 -1
- 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/pxe_service.ts +6 -7
- package/src/simulator_oracle/index.ts +163 -143
- package/src/simulator_oracle/tagging_utils.ts +28 -0
- package/src/utils/create_pxe_service.ts +7 -4
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
import { makeTuple } from '@aztec/foundation/array';
|
|
38
38
|
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
39
39
|
import { type Tuple, assertLength } from '@aztec/foundation/serialize';
|
|
40
|
-
import { privateKernelResetDimensionsConfig } from '@aztec/noir-protocol-circuits-types';
|
|
40
|
+
import { privateKernelResetDimensionsConfig } from '@aztec/noir-protocol-circuits-types/client';
|
|
41
41
|
|
|
42
42
|
import { type ProvingDataOracle } from '../proving_data_oracle.js';
|
|
43
43
|
|
|
@@ -31,7 +31,8 @@ import { vkAsFieldsMegaHonk } from '@aztec/foundation/crypto';
|
|
|
31
31
|
import { createLogger } from '@aztec/foundation/log';
|
|
32
32
|
import { assertLength } from '@aztec/foundation/serialize';
|
|
33
33
|
import { pushTestData } from '@aztec/foundation/testing';
|
|
34
|
-
import {
|
|
34
|
+
import { Timer } from '@aztec/foundation/timer';
|
|
35
|
+
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/client';
|
|
35
36
|
import {
|
|
36
37
|
getProtocolContractSiblingPath,
|
|
37
38
|
isProtocolContract,
|
|
@@ -118,6 +119,8 @@ export class KernelProver {
|
|
|
118
119
|
profile: boolean = false,
|
|
119
120
|
dryRun: boolean = false,
|
|
120
121
|
): Promise<PrivateKernelSimulateOutput<PrivateKernelTailCircuitPublicInputs>> {
|
|
122
|
+
const timer = new Timer();
|
|
123
|
+
|
|
121
124
|
const isPrivateOnlyTx = this.isPrivateOnly(executionResult);
|
|
122
125
|
|
|
123
126
|
const executionStack = [executionResult];
|
|
@@ -197,7 +200,9 @@ export class KernelProver {
|
|
|
197
200
|
privateCallData,
|
|
198
201
|
isPrivateOnlyTx,
|
|
199
202
|
);
|
|
203
|
+
|
|
200
204
|
pushTestData('private-kernel-inputs-init', proofInput);
|
|
205
|
+
|
|
201
206
|
output = await this.proofCreator.simulateProofInit(proofInput);
|
|
202
207
|
|
|
203
208
|
acirs.push(output.bytecode);
|
|
@@ -214,7 +219,9 @@ export class KernelProver {
|
|
|
214
219
|
assertLength<Fr, typeof VK_TREE_HEIGHT>(previousVkMembershipWitness.siblingPath, VK_TREE_HEIGHT),
|
|
215
220
|
);
|
|
216
221
|
const proofInput = new PrivateKernelInnerCircuitPrivateInputs(previousKernelData, privateCallData);
|
|
222
|
+
|
|
217
223
|
pushTestData('private-kernel-inputs-inner', proofInput);
|
|
224
|
+
|
|
218
225
|
output = await this.proofCreator.simulateProofInner(proofInput);
|
|
219
226
|
|
|
220
227
|
acirs.push(output.bytecode);
|
|
@@ -267,6 +274,7 @@ export class KernelProver {
|
|
|
267
274
|
const privateInputs = new PrivateKernelTailCircuitPrivateInputs(previousKernelData);
|
|
268
275
|
|
|
269
276
|
pushTestData('private-kernel-inputs-ordering', privateInputs);
|
|
277
|
+
|
|
270
278
|
const tailOutput = await this.proofCreator.simulateProofTail(privateInputs);
|
|
271
279
|
if (tailOutput.publicInputs.forPublic) {
|
|
272
280
|
const privateLogs = privateInputs.previousKernel.publicInputs.end.privateLogs;
|
|
@@ -282,6 +290,8 @@ export class KernelProver {
|
|
|
282
290
|
tailOutput.profileResult = { gateCounts };
|
|
283
291
|
}
|
|
284
292
|
|
|
293
|
+
this.log.info(`Witness generation took ${timer.ms()}ms`);
|
|
294
|
+
|
|
285
295
|
// TODO(#7368) how do we 'bincode' encode these inputs?
|
|
286
296
|
if (!dryRun) {
|
|
287
297
|
const ivcProof = await this.proofCreator.createClientIvcProof(acirs, witnessStack);
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type AppCircuitSimulateOutput,
|
|
3
|
-
type PrivateKernelProver,
|
|
4
|
-
type PrivateKernelSimulateOutput,
|
|
5
|
-
} from '@aztec/circuit-types';
|
|
1
|
+
import { type PrivateKernelProver, type PrivateKernelSimulateOutput } from '@aztec/circuit-types';
|
|
6
2
|
import type { CircuitSimulationStats } from '@aztec/circuit-types/stats';
|
|
7
3
|
import {
|
|
8
|
-
CLIENT_IVC_VERIFICATION_KEY_LENGTH_IN_FIELDS,
|
|
9
4
|
ClientIvcProof,
|
|
10
5
|
type PrivateKernelCircuitPublicInputs,
|
|
11
6
|
type PrivateKernelInitCircuitPrivateInputs,
|
|
@@ -13,13 +8,12 @@ import {
|
|
|
13
8
|
type PrivateKernelResetCircuitPrivateInputs,
|
|
14
9
|
type PrivateKernelTailCircuitPrivateInputs,
|
|
15
10
|
type PrivateKernelTailCircuitPublicInputs,
|
|
16
|
-
VerificationKeyAsFields,
|
|
17
11
|
} from '@aztec/circuits.js';
|
|
18
12
|
import { createLogger } from '@aztec/foundation/log';
|
|
19
13
|
import { elapsed } from '@aztec/foundation/timer';
|
|
20
14
|
import {
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
ClientCircuitVks,
|
|
16
|
+
type ClientProtocolArtifact,
|
|
23
17
|
executeInit,
|
|
24
18
|
executeInner,
|
|
25
19
|
executeReset,
|
|
@@ -27,7 +21,7 @@ import {
|
|
|
27
21
|
executeTailForPublic,
|
|
28
22
|
getPrivateKernelResetArtifactName,
|
|
29
23
|
maxPrivateKernelResetDimensions,
|
|
30
|
-
} from '@aztec/noir-protocol-circuits-types';
|
|
24
|
+
} from '@aztec/noir-protocol-circuits-types/client';
|
|
31
25
|
|
|
32
26
|
import { type WitnessMap } from '@noir-lang/types';
|
|
33
27
|
|
|
@@ -114,22 +108,12 @@ export class TestPrivateKernelProver implements PrivateKernelProver {
|
|
|
114
108
|
return Promise.resolve(0);
|
|
115
109
|
}
|
|
116
110
|
|
|
117
|
-
computeAppCircuitVerificationKey(
|
|
118
|
-
_bytecode: Buffer,
|
|
119
|
-
_appCircuitName?: string | undefined,
|
|
120
|
-
): Promise<AppCircuitSimulateOutput> {
|
|
121
|
-
const appCircuitProofOutput: AppCircuitSimulateOutput = {
|
|
122
|
-
verificationKey: VerificationKeyAsFields.makeEmpty(CLIENT_IVC_VERIFICATION_KEY_LENGTH_IN_FIELDS),
|
|
123
|
-
};
|
|
124
|
-
return Promise.resolve(appCircuitProofOutput);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
111
|
private makeEmptyKernelSimulateOutput<
|
|
128
112
|
PublicInputsType extends PrivateKernelTailCircuitPublicInputs | PrivateKernelCircuitPublicInputs,
|
|
129
|
-
>(publicInputs: PublicInputsType, circuitType:
|
|
113
|
+
>(publicInputs: PublicInputsType, circuitType: ClientProtocolArtifact) {
|
|
130
114
|
const kernelProofOutput: PrivateKernelSimulateOutput<PublicInputsType> = {
|
|
131
115
|
publicInputs,
|
|
132
|
-
verificationKey:
|
|
116
|
+
verificationKey: ClientCircuitVks[circuitType].keyAsFields,
|
|
133
117
|
outputWitness: new Map(),
|
|
134
118
|
bytecode: Buffer.from([]),
|
|
135
119
|
};
|
|
@@ -56,13 +56,11 @@ import {
|
|
|
56
56
|
} from '@aztec/foundation/abi';
|
|
57
57
|
import { Fr, type Point } from '@aztec/foundation/fields';
|
|
58
58
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
59
|
+
import { Timer } from '@aztec/foundation/timer';
|
|
59
60
|
import { type KeyStore } from '@aztec/key-store';
|
|
60
61
|
import { type L2TipsStore } from '@aztec/kv-store/stores';
|
|
61
|
-
import {
|
|
62
|
-
|
|
63
|
-
getCanonicalProtocolContract,
|
|
64
|
-
protocolContractNames,
|
|
65
|
-
} from '@aztec/protocol-contracts';
|
|
62
|
+
import { ProtocolContractAddress, protocolContractNames } from '@aztec/protocol-contracts';
|
|
63
|
+
import { getCanonicalProtocolContract } from '@aztec/protocol-contracts/bundle';
|
|
66
64
|
import { type AcirSimulator } from '@aztec/simulator/client';
|
|
67
65
|
|
|
68
66
|
import { inspect } from 'util';
|
|
@@ -494,10 +492,11 @@ export class PXEService implements PXE {
|
|
|
494
492
|
version: txRequest.txContext.version,
|
|
495
493
|
authWitnesses: txRequest.authWitnesses.map(w => w.requestHash),
|
|
496
494
|
};
|
|
497
|
-
this.log.
|
|
495
|
+
this.log.info(
|
|
498
496
|
`Simulating transaction execution request to ${txRequest.functionSelector} at ${txRequest.origin}`,
|
|
499
497
|
txInfo,
|
|
500
498
|
);
|
|
499
|
+
const timer = new Timer();
|
|
501
500
|
await this.synchronizer.sync();
|
|
502
501
|
const privateExecutionResult = await this.#executePrivate(txRequest, msgSender, scopes);
|
|
503
502
|
|
|
@@ -526,7 +525,7 @@ export class PXEService implements PXE {
|
|
|
526
525
|
}
|
|
527
526
|
}
|
|
528
527
|
|
|
529
|
-
this.log.info(`Simulation completed for ${simulatedTx.tryGetTxHash()}`, {
|
|
528
|
+
this.log.info(`Simulation completed for ${simulatedTx.tryGetTxHash()} in ${timer.ms()}ms`, {
|
|
530
529
|
txHash: simulatedTx.tryGetTxHash(),
|
|
531
530
|
...txInfo,
|
|
532
531
|
...(profileResult ? { gateCounts: profileResult.gateCounts } : {}),
|
|
@@ -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 { getIndexedTaggingSecretsForTheWindow, getInitialIndexesMap } from './tagging_utils.js';
|
|
41
42
|
|
|
42
43
|
/**
|
|
43
44
|
* A data oracle that provides information needed for simulating a transaction.
|
|
@@ -257,28 +258,28 @@ export class SimulatorOracle implements DBOracle {
|
|
|
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,25 +303,25 @@ 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 #getIndexedTaggingSecretsForContacts(
|
|
324
325
|
contractAddress: AztecAddress,
|
|
325
326
|
recipient: AztecAddress,
|
|
326
327
|
): Promise<IndexedTaggingSecret[]> {
|
|
@@ -332,7 +333,7 @@ export class SimulatorOracle implements DBOracle {
|
|
|
332
333
|
(address, index, self) => index === self.findIndex(otherAddress => otherAddress.equals(address)),
|
|
333
334
|
);
|
|
334
335
|
const appTaggingSecrets = contacts.map(contact => {
|
|
335
|
-
const sharedSecret =
|
|
336
|
+
const sharedSecret = computeTaggingSecretPoint(recipientCompleteAddress, recipientIvsk, contact);
|
|
336
337
|
return poseidon2Hash([sharedSecret.x, sharedSecret.y, contractAddress]);
|
|
337
338
|
});
|
|
338
339
|
const indexes = await this.db.getTaggingSecretsIndexesAsRecipient(appTaggingSecrets);
|
|
@@ -351,7 +352,7 @@ export class SimulatorOracle implements DBOracle {
|
|
|
351
352
|
sender: AztecAddress,
|
|
352
353
|
recipient: AztecAddress,
|
|
353
354
|
): Promise<void> {
|
|
354
|
-
const appTaggingSecret = await this.#
|
|
355
|
+
const appTaggingSecret = await this.#calculateAppTaggingSecret(contractAddress, sender, recipient);
|
|
355
356
|
let [currentIndex] = await this.db.getTaggingSecretsIndexesAsSender([appTaggingSecret]);
|
|
356
357
|
|
|
357
358
|
const INDEX_OFFSET = 10;
|
|
@@ -409,7 +410,8 @@ export class SimulatorOracle implements DBOracle {
|
|
|
409
410
|
|
|
410
411
|
/**
|
|
411
412
|
* 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
|
|
413
|
+
* Returns the unsynched logs and updates the indexes of the secrets used to tag them until there are no more logs
|
|
414
|
+
* to sync.
|
|
413
415
|
* @param contractAddress - The address of the contract that the logs are tagged for
|
|
414
416
|
* @param recipient - The address of the recipient
|
|
415
417
|
* @returns A list of encrypted logs tagged with the recipient's address
|
|
@@ -419,125 +421,140 @@ export class SimulatorOracle implements DBOracle {
|
|
|
419
421
|
maxBlockNumber: number,
|
|
420
422
|
scopes?: AztecAddress[],
|
|
421
423
|
): Promise<Map<string, TxScopedL2Log[]>> {
|
|
424
|
+
// Half the size of the window we slide over the tagging secret indexes.
|
|
425
|
+
const WINDOW_HALF_SIZE = 10;
|
|
426
|
+
|
|
427
|
+
// Ideally this algorithm would be implemented in noir, exposing its building blocks as oracles.
|
|
428
|
+
// However it is impossible at the moment due to the language not supporting nested slices.
|
|
429
|
+
// This nesting is necessary because for a given set of tags we don't
|
|
430
|
+
// know how many logs we will get back. Furthermore, these logs are of undetermined
|
|
431
|
+
// length, since we don't really know the note they correspond to until we decrypt them.
|
|
432
|
+
|
|
422
433
|
const recipients = scopes ? scopes : await this.keyStore.getAccounts();
|
|
423
|
-
|
|
434
|
+
// A map of logs going from recipient address to logs. Note that the logs might have been processed before
|
|
435
|
+
// due to us having a sliding window that "looks back" for logs as well. (We look back as there is no guarantee
|
|
436
|
+
// that a logs will be received ordered by a given tax index and that the tags won't be reused).
|
|
437
|
+
const logsMap = new Map<string, TxScopedL2Log[]>();
|
|
424
438
|
const contractName = await this.contractDataOracle.getDebugContractName(contractAddress);
|
|
425
439
|
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
|
-
|
|
447
|
-
|
|
448
|
-
|
|
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
|
-
);
|
|
440
|
+
const logsForRecipient: TxScopedL2Log[] = [];
|
|
441
|
+
|
|
442
|
+
// Get all the secrets for the recipient and sender pairs (#9365)
|
|
443
|
+
const secrets = await this.#getIndexedTaggingSecretsForContacts(contractAddress, recipient);
|
|
444
|
+
|
|
445
|
+
// We fetch logs for a window of indexes in a range:
|
|
446
|
+
// <latest_log_index - WINDOW_HALF_SIZE, latest_log_index + WINDOW_HALF_SIZE>.
|
|
447
|
+
//
|
|
448
|
+
// We use this window approach because it could happen that a sender might have messed up and inadvertently
|
|
449
|
+
// incremented their index without us getting any logs (for example, in case of a revert). If we stopped looking
|
|
450
|
+
// for logs the first time we don't receive any logs for a tag, we might never receive anything from that sender again.
|
|
451
|
+
// Also there's a possibility that we have advanced our index, but the sender has reused it, so we might have missed
|
|
452
|
+
// some logs. For these reasons, we have to look both back and ahead of the stored index.
|
|
453
|
+
let secretsAndWindows = secrets.map(secret => {
|
|
454
|
+
return {
|
|
455
|
+
appTaggingSecret: secret.appTaggingSecret,
|
|
456
|
+
leftMostIndex: Math.max(0, secret.index - WINDOW_HALF_SIZE),
|
|
457
|
+
rightMostIndex: secret.index + WINDOW_HALF_SIZE,
|
|
458
|
+
};
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
// As we iterate we store the largest index we have seen for a given secret to later on store it in the db.
|
|
462
|
+
const newLargestIndexMapToStore: { [k: string]: number } = {};
|
|
471
463
|
|
|
472
|
-
|
|
473
|
-
const
|
|
464
|
+
// The initial/unmodified indexes of the secrets stored in a key-value map where key is the app tagging secret.
|
|
465
|
+
const initialIndexesMap = getInitialIndexesMap(secrets);
|
|
474
466
|
|
|
475
|
-
while (
|
|
476
|
-
|
|
477
|
-
const
|
|
478
|
-
|
|
467
|
+
while (secretsAndWindows.length > 0) {
|
|
468
|
+
const secretsForTheWholeWindow = getIndexedTaggingSecretsForTheWindow(secretsAndWindows);
|
|
469
|
+
const tagsForTheWholeWindow = secretsForTheWholeWindow.map(secret =>
|
|
470
|
+
secret.computeSiloedTag(recipient, contractAddress),
|
|
479
471
|
);
|
|
480
|
-
|
|
481
|
-
|
|
472
|
+
|
|
473
|
+
// We store the new largest indexes we find in the iteration in the following map to later on construct
|
|
474
|
+
// a new set of secrets and windows to fetch logs for.
|
|
475
|
+
const newLargestIndexMapForIteration: { [k: string]: number } = {};
|
|
476
|
+
|
|
477
|
+
// Fetch the logs for the tags and iterate over them
|
|
478
|
+
const logsByTags = await this.aztecNode.getLogsByTags(tagsForTheWholeWindow);
|
|
479
|
+
|
|
482
480
|
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
481
|
if (logsByTag.length > 0) {
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
482
|
+
// The logs for the given tag exist so we store them for later processing
|
|
483
|
+
logsForRecipient.push(...logsByTag);
|
|
484
|
+
|
|
485
|
+
// We retrieve the indexed tagging secret corresponding to the log as I need that to evaluate whether
|
|
486
|
+
// a new largest index have been found.
|
|
487
|
+
const secretCorrespondingToLog = secretsForTheWholeWindow[logIndex];
|
|
488
|
+
const initialIndex = initialIndexesMap[secretCorrespondingToLog.appTaggingSecret.toString()];
|
|
489
|
+
|
|
490
|
+
this.log.debug(`Found ${logsByTag.length} logs as recipient ${recipient}`, {
|
|
491
|
+
recipient,
|
|
492
|
+
secret: secretCorrespondingToLog.appTaggingSecret,
|
|
493
|
+
contractName,
|
|
494
|
+
contractAddress,
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
if (
|
|
498
|
+
secretCorrespondingToLog.index >= initialIndex &&
|
|
499
|
+
(newLargestIndexMapForIteration[secretCorrespondingToLog.appTaggingSecret.toString()] === undefined ||
|
|
500
|
+
secretCorrespondingToLog.index >=
|
|
501
|
+
newLargestIndexMapForIteration[secretCorrespondingToLog.appTaggingSecret.toString()])
|
|
502
|
+
) {
|
|
503
|
+
// We have found a new largest index so we store it for later processing (storing it in the db + fetching
|
|
504
|
+
// the difference of the window sets of current and the next iteration)
|
|
505
|
+
newLargestIndexMapForIteration[secretCorrespondingToLog.appTaggingSecret.toString()] =
|
|
506
|
+
secretCorrespondingToLog.index + 1;
|
|
507
|
+
|
|
508
|
+
this.log.debug(
|
|
509
|
+
`Incrementing index to ${
|
|
510
|
+
secretCorrespondingToLog.index + 1
|
|
511
|
+
} at contract ${contractName}(${contractAddress})`,
|
|
512
|
+
);
|
|
513
513
|
}
|
|
514
514
|
}
|
|
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
515
|
});
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
516
|
+
|
|
517
|
+
// Now based on the new largest indexes we found, we will construct a new secrets and windows set to fetch logs
|
|
518
|
+
// for. Note that it's very unlikely that a new log from the current window would appear between the iterations
|
|
519
|
+
// so we fetch the logs only for the difference of the window sets.
|
|
520
|
+
const newSecretsAndWindows = [];
|
|
521
|
+
for (const [appTaggingSecret, newIndex] of Object.entries(newLargestIndexMapForIteration)) {
|
|
522
|
+
const secret = secrets.find(secret => secret.appTaggingSecret.toString() === appTaggingSecret);
|
|
523
|
+
if (secret) {
|
|
524
|
+
newSecretsAndWindows.push({
|
|
525
|
+
appTaggingSecret: secret.appTaggingSecret,
|
|
526
|
+
// We set the left most index to the new index to avoid fetching the same logs again
|
|
527
|
+
leftMostIndex: newIndex,
|
|
528
|
+
rightMostIndex: newIndex + WINDOW_HALF_SIZE,
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
// We store the new largest index in the map to later store it in the db.
|
|
532
|
+
newLargestIndexMapToStore[appTaggingSecret] = newIndex;
|
|
533
|
+
} else {
|
|
534
|
+
throw new Error(
|
|
535
|
+
`Secret not found for appTaggingSecret ${appTaggingSecret}. This is a bug as it should never happen!`,
|
|
536
|
+
);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// Now we set the new secrets and windows and proceed to the next iteration.
|
|
541
|
+
secretsAndWindows = newSecretsAndWindows;
|
|
528
542
|
}
|
|
529
543
|
|
|
530
|
-
|
|
544
|
+
// We filter the logs by block number and store them in the map.
|
|
545
|
+
logsMap.set(
|
|
531
546
|
recipient.toString(),
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
547
|
+
logsForRecipient.filter(log => log.blockNumber <= maxBlockNumber),
|
|
548
|
+
);
|
|
549
|
+
|
|
550
|
+
// At this point we have processed all the logs for the recipient so we store the new largest indexes in the db.
|
|
551
|
+
await this.db.setTaggingSecretsIndexesAsRecipient(
|
|
552
|
+
Object.entries(newLargestIndexMapToStore).map(
|
|
553
|
+
([appTaggingSecret, index]) => new IndexedTaggingSecret(Fr.fromHexString(appTaggingSecret), index),
|
|
537
554
|
),
|
|
538
555
|
);
|
|
539
556
|
}
|
|
540
|
-
return
|
|
557
|
+
return logsMap;
|
|
541
558
|
}
|
|
542
559
|
|
|
543
560
|
/**
|
|
@@ -628,27 +645,30 @@ export class SimulatorOracle implements DBOracle {
|
|
|
628
645
|
});
|
|
629
646
|
});
|
|
630
647
|
}
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
const
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
slot
|
|
650
|
-
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
public async removeNullifiedNotes(contractAddress: AztecAddress) {
|
|
651
|
+
for (const recipient of await this.keyStore.getAccounts()) {
|
|
652
|
+
const currentNotesForRecipient = await this.db.getIncomingNotes({ contractAddress, owner: recipient });
|
|
653
|
+
const nullifiersToCheck = currentNotesForRecipient.map(note => note.siloedNullifier);
|
|
654
|
+
const nullifierIndexes = await this.aztecNode.findNullifiersIndexesWithBlock('latest', nullifiersToCheck);
|
|
655
|
+
|
|
656
|
+
const foundNullifiers = nullifiersToCheck
|
|
657
|
+
.map((nullifier, i) => {
|
|
658
|
+
if (nullifierIndexes[i] !== undefined) {
|
|
659
|
+
return { ...nullifierIndexes[i], ...{ data: nullifier } } as InBlock<Fr>;
|
|
660
|
+
}
|
|
661
|
+
})
|
|
662
|
+
.filter(nullifier => nullifier !== undefined) as InBlock<Fr>[];
|
|
663
|
+
|
|
664
|
+
const nullifiedNotes = await this.db.removeNullifiedNotes(foundNullifiers, recipient.toAddressPoint());
|
|
665
|
+
nullifiedNotes.forEach(noteDao => {
|
|
666
|
+
this.log.verbose(`Removed note for contract ${noteDao.contractAddress} at slot ${noteDao.storageSlot}`, {
|
|
667
|
+
contract: noteDao.contractAddress,
|
|
668
|
+
slot: noteDao.storageSlot,
|
|
669
|
+
nullifier: noteDao.siloedNullifier.toString(),
|
|
670
|
+
});
|
|
651
671
|
});
|
|
652
|
-
}
|
|
672
|
+
}
|
|
653
673
|
}
|
|
654
674
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type Fr, IndexedTaggingSecret } from '@aztec/circuits.js';
|
|
2
|
+
|
|
3
|
+
export function getIndexedTaggingSecretsForTheWindow(
|
|
4
|
+
secretsAndWindows: { appTaggingSecret: Fr; leftMostIndex: number; rightMostIndex: number }[],
|
|
5
|
+
): IndexedTaggingSecret[] {
|
|
6
|
+
const secrets: IndexedTaggingSecret[] = [];
|
|
7
|
+
for (const secretAndWindow of secretsAndWindows) {
|
|
8
|
+
for (let i = secretAndWindow.leftMostIndex; i <= secretAndWindow.rightMostIndex; i++) {
|
|
9
|
+
secrets.push(new IndexedTaggingSecret(secretAndWindow.appTaggingSecret, i));
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return secrets;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Creates a map from app tagging secret to initial index.
|
|
17
|
+
* @param indexedTaggingSecrets - The indexed tagging secrets to get the initial indexes from.
|
|
18
|
+
* @returns The map from app tagging secret to initial index.
|
|
19
|
+
*/
|
|
20
|
+
export function getInitialIndexesMap(indexedTaggingSecrets: IndexedTaggingSecret[]): { [k: string]: number } {
|
|
21
|
+
const initialIndexes: { [k: string]: number } = {};
|
|
22
|
+
|
|
23
|
+
for (const indexedTaggingSecret of indexedTaggingSecrets) {
|
|
24
|
+
initialIndexes[indexedTaggingSecret.appTaggingSecret.toString()] = indexedTaggingSecret.index;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return initialIndexes;
|
|
28
|
+
}
|
|
@@ -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
|
}
|