From 621ffabaef027281b99e5aeecb9c87187f645a19 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Wed, 20 Nov 2024 22:51:18 +0000 Subject: [PATCH] better approach --- .../pxe/src/database/kv_pxe_database.ts | 13 ++- yarn-project/pxe/src/database/pxe_database.ts | 5 + .../pxe/src/simulator_oracle/index.ts | 100 +++++++----------- .../simulator_oracle/simulator_oracle.test.ts | 40 ++++++- 4 files changed, 90 insertions(+), 68 deletions(-) diff --git a/yarn-project/pxe/src/database/kv_pxe_database.ts b/yarn-project/pxe/src/database/kv_pxe_database.ts index 13ee92037b31..a86198fde40c 100644 --- a/yarn-project/pxe/src/database/kv_pxe_database.ts +++ b/yarn-project/pxe/src/database/kv_pxe_database.ts @@ -677,13 +677,12 @@ export class KVPxeDatabase implements PxeDatabase { await this.#setTaggingSecretsIndexes(indexedSecrets, this.#taggingSecretIndexesForRecipients); } - #setTaggingSecretsIndexes( - indexedSecrets: IndexedTaggingSecret[], - storageMap: AztecMap, - ): Promise[]> { - return this.db.transaction(() => - indexedSecrets.map(indexedSecret => storageMap.set(indexedSecret.secret.toString(), indexedSecret.index)), - ); + #setTaggingSecretsIndexes(indexedSecrets: IndexedTaggingSecret[], storageMap: AztecMap) { + return this.db.transaction(() => { + indexedSecrets.forEach( + indexedSecret => void storageMap.set(indexedSecret.secret.toString(), indexedSecret.index), + ); + }); } async getTaggingSecretsIndexesAsRecipient(appTaggingSecrets: Fr[]) { diff --git a/yarn-project/pxe/src/database/pxe_database.ts b/yarn-project/pxe/src/database/pxe_database.ts index 57465ed76354..94962aa0e881 100644 --- a/yarn-project/pxe/src/database/pxe_database.ts +++ b/yarn-project/pxe/src/database/pxe_database.ts @@ -201,6 +201,11 @@ export interface PxeDatabase extends ContractArtifactDatabase, ContractInstanceD */ getTaggingSecretsIndexesAsSender(appTaggingSecrets: Fr[]): Promise; + /** + * Sets the index for the provided app siloed tagging secrets + * To be used when the generated tags have been "seen" as a sender + * @param appTaggingSecrets - The app siloed tagging secrets. + */ setTaggingSecretsIndexesAsSender(indexedTaggingSecrets: IndexedTaggingSecret[]): Promise; /** diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index 993bb33780de..a80cc5764f4a 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -295,7 +295,7 @@ export class SimulatorOracle implements DBOracle { ); const [index] = await this.db.getTaggingSecretsIndexesAsSender([secret]); - await this.db.setTaggingSecretsIndexesAsSender([new IndexedTaggingSecret(secret, index)]); + await this.db.setTaggingSecretsIndexesAsSender([new IndexedTaggingSecret(secret, index + 1)]); } async #calculateTaggingSecret(contractAddress: AztecAddress, sender: AztecAddress, recipient: AztecAddress) { @@ -335,19 +335,39 @@ export class SimulatorOracle implements DBOracle { return appTaggingSecrets.map((secret, i) => new IndexedTaggingSecret(secret, indexes[i])); } - async #getAppTaggingSecretAsSender( + /** + * Updates the local index of the shared tagging secret of a sender / recipient pair + * if a log with a larger index is found from the node. + * @param contractAddress - The address of the contract that the logs are tagged for + * @param sender - The address of the sender, we must know the sender's ivsk_m. + * @param recipient - The address of the recipient. + */ + public async syncTaggedLogsAsSender( contractAddress: AztecAddress, sender: AztecAddress, recipient: AztecAddress, - ): Promise { - const senderCompleteAddress = await this.getCompleteAddress(sender); - const senderIvsk = await this.keyStore.getMasterIncomingViewingSecretKey(sender); + ): Promise { + const contractName = await this.contractDataOracle.getDebugContractName(contractAddress); + const appTaggingSecret = await this.#calculateTaggingSecret(contractAddress, sender, recipient); + let [currentIndex] = await this.db.getTaggingSecretsIndexesAsSender([appTaggingSecret]); - const sharedSecret = computeTaggingSecret(senderCompleteAddress, senderIvsk, recipient); - const appTaggingSecret = poseidon2Hash([sharedSecret.x, sharedSecret.y, contractAddress]); - const [index] = await this.db.getTaggingSecretsIndexesAsSender([appTaggingSecret]); + while (true) { + const currentIndexedAppTaggingSecret = new IndexedTaggingSecret(appTaggingSecret, currentIndex); + const currentTag = currentIndexedAppTaggingSecret.computeTag(recipient); + + const [[possibleLog]] = await this.aztecNode.getLogsByTags([currentTag]); - return new IndexedTaggingSecret(appTaggingSecret, index); + if (possibleLog !== undefined) { + currentIndex++; + } else { + this.log.debug( + `Syncing logs for sender ${sender}, secret ${appTaggingSecret}:${currentIndex} at contract: ${contractName}(${contractAddress})`, + ); + + await this.db.setTaggingSecretsIndexesAsSender([new IndexedTaggingSecret(appTaggingSecret, currentIndex)]); + break; + } + } } /** @@ -363,34 +383,6 @@ export class SimulatorOracle implements DBOracle { scopes?: AztecAddress[], ): Promise> { const recipients = scopes ? scopes : await this.keyStore.getAccounts(); - - const result = await this.#syncTaggedLogs(contractAddress, recipients); - - for (const [key, value] of result) { - result.set( - key, - value.filter(log => log.blockNumber <= maxBlockNumber), - ); - } - - return result; - } - - public async syncTaggedLogsAsSender( - contractAddress: AztecAddress, - sender: AztecAddress, - recipient: AztecAddress, - ): Promise> { - const result = await this.#syncTaggedLogs(contractAddress, [recipient], sender); - - return result; - } - - async #syncTaggedLogs( - contractAddress: AztecAddress, - recipients: AztecAddress[], - asSender?: AztecAddress, - ): Promise> { const result = new Map(); const contractName = await this.contractDataOracle.getDebugContractName(contractAddress); for (const recipient of recipients) { @@ -402,12 +394,7 @@ export class SimulatorOracle implements DBOracle { // length, since we don't really know the note they correspond to until we decrypt them. // 1. Get all the secrets for the recipient and sender pairs (#9365) - const appTaggingSecrets: IndexedTaggingSecret[] = []; - if (asSender === undefined) { - appTaggingSecrets.push(...(await this.#getAppTaggingSecretsForContacts(contractAddress, recipient))); - } else { - appTaggingSecrets.push(await this.#getAppTaggingSecretAsSender(contractAddress, asSender, recipient)); - } + const appTaggingSecrets = await this.#getAppTaggingSecretsForContacts(contractAddress, recipient); // 1.1 Set up a sliding window with an offset. Chances are the sender might have messed up // and inadvertedly incremented their index without use getting any logs (for example, in case @@ -485,27 +472,22 @@ export class SimulatorOracle implements DBOracle { newTaggingSecrets.push(newTaggingSecret); } }); - if (asSender === undefined) { - await this.db.setTaggingSecretsIndexesAsRecipient( - Object.keys(secretsToIncrement).map( - secret => new IndexedTaggingSecret(Fr.fromString(secret), secretsToIncrement[secret]), - ), - ); - } else { - await this.db.setTaggingSecretsIndexesAsSender( - Object.keys(secretsToIncrement).map( - secret => new IndexedTaggingSecret(Fr.fromString(secret), secretsToIncrement[secret]), - ), - ); - } - + await this.db.setTaggingSecretsIndexesAsRecipient( + Object.keys(secretsToIncrement).map( + secret => new IndexedTaggingSecret(Fr.fromString(secret), secretsToIncrement[secret]), + ), + ); currentTagggingSecrets = newTaggingSecrets; } result.set( recipient.toString(), - // Duplicates are likely to happen due to the sliding window, so we filter them out - logs.filter((log, index, self) => index === self.findIndex(otherLog => otherLog.equals(log))), + // Remove logs with a block number higher than the max block number + // Duplicates are likely to happen due to the sliding window, so we also filter them out + logs.filter( + (log, index, self) => + log.blockNumber <= maxBlockNumber && index === self.findIndex(otherLog => otherLog.equals(log)), + ), ); } return result; diff --git a/yarn-project/pxe/src/simulator_oracle/simulator_oracle.test.ts b/yarn-project/pxe/src/simulator_oracle/simulator_oracle.test.ts index 9e160d98e827..4a21acb33dd0 100644 --- a/yarn-project/pxe/src/simulator_oracle/simulator_oracle.test.ts +++ b/yarn-project/pxe/src/simulator_oracle/simulator_oracle.test.ts @@ -144,7 +144,7 @@ describe('Simulator oracle', () => { describe('sync tagged logs', () => { const NUM_SENDERS = 10; const SENDER_OFFSET_WINDOW_SIZE = 10; - let senders: { completeAddress: CompleteAddress; ivsk: Fq }[]; + let senders: { completeAddress: CompleteAddress; ivsk: Fq; secretKey: Fr }[]; function generateMockLogs(senderOffset: number) { const logs: { [k: string]: TxScopedL2Log[] } = {}; @@ -232,7 +232,7 @@ describe('Simulator oracle', () => { const partialAddress = Fr.random(); const address = computeAddress(keys.publicKeys, partialAddress); const completeAddress = new CompleteAddress(address, keys.publicKeys, partialAddress); - return { completeAddress, ivsk: keys.masterIncomingViewingSecretKey }; + return { completeAddress, ivsk: keys.masterIncomingViewingSecretKey, secretKey: new Fr(index) }; }); for (const sender of senders) { await database.addContactAddress(sender.completeAddress.address); @@ -268,6 +268,42 @@ describe('Simulator oracle', () => { expect(aztecNode.getLogsByTags.mock.calls.length).toBe(2 + SENDER_OFFSET_WINDOW_SIZE); }); + it('should sync tagged logs as senders', async () => { + for (const sender of senders) { + await database.addCompleteAddress(sender.completeAddress); + await keyStore.addAccount(sender.secretKey, sender.completeAddress.partialAddress); + } + + const senderOffset = 0; + generateMockLogs(senderOffset); + + // Recompute the secrets (as recipient) to ensure indexes are updated + const ivsk = await keyStore.getMasterIncomingViewingSecretKey(recipient.address); + const secrets = senders.map(sender => { + const firstSenderSharedSecret = computeTaggingSecret(recipient, ivsk, sender.completeAddress.address); + return poseidon2Hash([firstSenderSharedSecret.x, firstSenderSharedSecret.y, contractAddress]); + }); + + const indexesAsSender = await database.getTaggingSecretsIndexesAsSender(secrets); + expect(indexesAsSender).toStrictEqual([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + + expect(aztecNode.getLogsByTags.mock.calls.length).toBe(0); + + for (let i = 0; i < senders.length; i++) { + await simulatorOracle.syncTaggedLogsAsSender( + contractAddress, + senders[i].completeAddress.address, + recipient.address, + ); + } + + const indexesAsSenderAfterSync = await database.getTaggingSecretsIndexesAsSender(secrets); + expect(indexesAsSenderAfterSync).toStrictEqual([1, 1, 1, 1, 1, 2, 2, 2, 2, 2]); + + // We expect getLogsByTags to be called N + 1 times, where N is the index. + expect(aztecNode.getLogsByTags.mock.calls.length).toBe(2 * 5 + 3 * 5); + }); + it('should sync tagged logs with a sender index offset', async () => { const senderOffset = 5; generateMockLogs(senderOffset);