-
Notifications
You must be signed in to change notification settings - Fork 575
refactor!: expanding return value of getLogsByTags #19233
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 12-18-feat_integrating_new_log_sync
Are you sure you want to change the base?
Changes from all commits
b1c756a
56ace7f
64e0cfb
468d96d
ee96435
6b89008
eb9692a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| import { INITIAL_L2_BLOCK_NUM, MAX_NOTE_HASHES_PER_TX } from '@aztec/constants'; | ||
| import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants'; | ||
| import { BlockNumber } from '@aztec/foundation/branded-types'; | ||
| import { Fr } from '@aztec/foundation/curves/bn254'; | ||
| import { createLogger } from '@aztec/foundation/log'; | ||
|
|
@@ -57,21 +57,16 @@ export class LogStore { | |
| * @param block - The L2 block to extract logs from. | ||
| * @returns An object containing the private and public tagged logs for the block. | ||
| */ | ||
| async #extractTaggedLogsFromBlock(block: L2BlockNew) { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| const blockHash = L2BlockHash.fromField(await block.hash()); | ||
| #extractTaggedLogsFromBlock(block: L2BlockNew) { | ||
| // SiloedTag (as string) -> array of log buffers. | ||
| const privateTaggedLogs = new Map<string, Buffer[]>(); | ||
| // "{contractAddress}_{tag}" (as string) -> array of log buffers. | ||
| const publicTaggedLogs = new Map<string, Buffer[]>(); | ||
| const dataStartIndexForBlock = | ||
| block.header.state.partial.noteHashTree.nextAvailableLeafIndex - | ||
| block.body.txEffects.length * MAX_NOTE_HASHES_PER_TX; | ||
|
|
||
| block.body.txEffects.forEach((txEffect, txIndex) => { | ||
| block.body.txEffects.forEach(txEffect => { | ||
| const txHash = txEffect.txHash; | ||
| const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX; | ||
|
|
||
| txEffect.privateLogs.forEach((log, logIndex) => { | ||
| txEffect.privateLogs.forEach(log => { | ||
| // Private logs use SiloedTag (already siloed by kernel) | ||
| const tag = log.fields[0]; | ||
| this.#log.debug(`Found private log with tag ${tag.toString()} in block ${block.number}`); | ||
|
|
@@ -80,18 +75,17 @@ export class LogStore { | |
| currentLogs.push( | ||
| new TxScopedL2Log( | ||
| txHash, | ||
| dataStartIndexForTx, | ||
| logIndex, | ||
| block.number, | ||
| blockHash, | ||
| block.timestamp, | ||
| log, | ||
| log.getEmittedFields(), | ||
| txEffect.noteHashes, | ||
| txEffect.nullifiers[0], | ||
| ).toBuffer(), | ||
| ); | ||
| privateTaggedLogs.set(tag.toString(), currentLogs); | ||
| }); | ||
|
|
||
| txEffect.publicLogs.forEach((log, logIndex) => { | ||
| txEffect.publicLogs.forEach(log => { | ||
| // Public logs use Tag directly (not siloed) and are stored with contract address | ||
| const tag = log.fields[0]; | ||
| const contractAddress = log.contractAddress; | ||
|
|
@@ -104,12 +98,11 @@ export class LogStore { | |
| currentLogs.push( | ||
| new TxScopedL2Log( | ||
| txHash, | ||
| dataStartIndexForTx, | ||
| logIndex, | ||
| block.number, | ||
| blockHash, | ||
| block.timestamp, | ||
| log, | ||
| log.getEmittedFields(), | ||
| txEffect.noteHashes, | ||
| txEffect.nullifiers[0], | ||
| ).toBuffer(), | ||
| ); | ||
| publicTaggedLogs.set(key, currentLogs); | ||
|
|
@@ -125,10 +118,11 @@ export class LogStore { | |
| * @returns A map from tag (as string) to an array of serialized private logs belonging to that tag, and a map from | ||
| * "{contractAddress}_{tag}" (as string) to an array of serialized public logs belonging to that key. | ||
| */ | ||
| async #extractTaggedLogs( | ||
| blocks: L2BlockNew[], | ||
| ): Promise<{ privateTaggedLogs: Map<string, Buffer[]>; publicTaggedLogs: Map<string, Buffer[]> }> { | ||
| const taggedLogsInBlocks = await Promise.all(blocks.map(block => this.#extractTaggedLogsFromBlock(block))); | ||
| #extractTaggedLogs(blocks: L2BlockNew[]): { | ||
| privateTaggedLogs: Map<string, Buffer[]>; | ||
| publicTaggedLogs: Map<string, Buffer[]>; | ||
| } { | ||
| const taggedLogsInBlocks = blocks.map(block => this.#extractTaggedLogsFromBlock(block)); | ||
|
|
||
| // Now we merge the maps from each block into a single map. | ||
| const privateTaggedLogs = taggedLogsInBlocks.reduce((acc, { privateTaggedLogs }) => { | ||
|
|
@@ -155,8 +149,8 @@ export class LogStore { | |
| * @param blocks - The blocks for which to add the logs. | ||
| * @returns True if the operation is successful. | ||
| */ | ||
| async addLogs(blocks: L2BlockNew[]): Promise<boolean> { | ||
| const { privateTaggedLogs, publicTaggedLogs } = await this.#extractTaggedLogs(blocks); | ||
| addLogs(blocks: L2BlockNew[]): Promise<boolean> { | ||
| const { privateTaggedLogs, publicTaggedLogs } = this.#extractTaggedLogs(blocks); | ||
|
|
||
| const keysOfPrivateLogsToUpdate = Array.from(privateTaggedLogs.keys()); | ||
| const keysOfPublicLogsToUpdate = Array.from(publicTaggedLogs.keys()); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,10 @@ | ||
| import { BlockNumber } from '@aztec/foundation/branded-types'; | ||
| import { randomInt } from '@aztec/foundation/crypto/random'; | ||
| import { Fr } from '@aztec/foundation/curves/bn254'; | ||
| import { KeyStore } from '@aztec/key-store'; | ||
| import { openTmpStore } from '@aztec/kv-store/lmdb-v2'; | ||
| import { AztecAddress } from '@aztec/stdlib/aztec-address'; | ||
| import { L2BlockHash } from '@aztec/stdlib/block'; | ||
| import type { AztecNode } from '@aztec/stdlib/interfaces/server'; | ||
| import { PublicLog, Tag, TxScopedL2Log } from '@aztec/stdlib/logs'; | ||
| import { TxHash, randomIndexedTxEffect } from '@aztec/stdlib/tx'; | ||
| import { Tag } from '@aztec/stdlib/logs'; | ||
| import { randomTxScopedPrivateL2Log } from '@aztec/stdlib/testing'; | ||
|
|
||
| import { type MockProxy, mock } from 'jest-mock-extended'; | ||
|
|
||
|
|
@@ -70,18 +67,12 @@ describe('LogService', () => { | |
| }); | ||
|
|
||
| it('returns a public log if one is found', async () => { | ||
| const scopedLog = await TxScopedL2Log.random(true); | ||
| (scopedLog.log as PublicLog).contractAddress = contractAddress; | ||
| const scopedLog = randomTxScopedPrivateL2Log(); | ||
|
|
||
| aztecNode.getPublicLogsByTagsFromContract.mockResolvedValue([[scopedLog]]); | ||
| aztecNode.getPrivateLogsByTags.mockResolvedValue([[]]); | ||
| const indexedTxEffect = await randomIndexedTxEffect(); | ||
|
|
||
| aztecNode.getTxEffect.mockImplementation((txHash: TxHash) => | ||
| txHash.equals(scopedLog.txHash) ? Promise.resolve(indexedTxEffect) : Promise.resolve(undefined), | ||
| ); | ||
|
|
||
| const request = new LogRetrievalRequest(contractAddress, new Tag(scopedLog.log.fields[0])); | ||
| const request = new LogRetrievalRequest(contractAddress, new Tag(scopedLog.logData[0])); | ||
|
|
||
| const responses = await logService.bulkRetrieveLogs([request]); | ||
|
|
||
|
|
@@ -90,106 +81,17 @@ describe('LogService', () => { | |
| }); | ||
|
|
||
| it('returns a private log if one is found', async () => { | ||
| const scopedLog = await TxScopedL2Log.random(false); | ||
| const scopedLog = randomTxScopedPrivateL2Log(); | ||
|
|
||
| aztecNode.getPrivateLogsByTags.mockResolvedValue([[scopedLog]]); | ||
| aztecNode.getPublicLogsByTagsFromContract.mockResolvedValue([[]]); | ||
| const indexedTxEffect = await randomIndexedTxEffect(); | ||
| aztecNode.getTxEffect.mockResolvedValue(indexedTxEffect); | ||
|
|
||
| aztecNode.getTxEffect.mockImplementation((txHash: TxHash) => | ||
| txHash.equals(scopedLog.txHash) ? Promise.resolve(indexedTxEffect) : Promise.resolve(undefined), | ||
| ); | ||
|
|
||
| const request = new LogRetrievalRequest(contractAddress, new Tag(scopedLog.log.fields[0])); | ||
| const request = new LogRetrievalRequest(contractAddress, new Tag(scopedLog.logData[0])); | ||
|
|
||
| const responses = await logService.bulkRetrieveLogs([request]); | ||
|
|
||
| expect(responses.length).toEqual(1); | ||
| expect(responses[0]).not.toBeNull(); | ||
| }); | ||
| }); | ||
|
|
||
| describe('getPublicLogByTag', () => { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I made the |
||
| const tag = new Tag(Fr.random()); | ||
|
|
||
| beforeEach(() => { | ||
| aztecNode.getPublicLogsByTagsFromContract.mockReset(); | ||
| aztecNode.getTxEffect.mockReset(); | ||
| }); | ||
|
|
||
| it('returns null if no logs found for tag', async () => { | ||
| aztecNode.getPublicLogsByTagsFromContract.mockResolvedValue([[]]); | ||
|
|
||
| const result = await logService.getPublicLogByTag(tag, contractAddress); | ||
| expect(result).toBeNull(); | ||
| }); | ||
|
|
||
| it('returns log data when single log found', async () => { | ||
| const scopedLog = await TxScopedL2Log.random(true); | ||
| const logContractAddress = (scopedLog.log as PublicLog).contractAddress; | ||
|
|
||
| aztecNode.getPublicLogsByTagsFromContract.mockResolvedValue([[scopedLog]]); | ||
| const indexedTxEffect = await randomIndexedTxEffect(); | ||
| aztecNode.getTxEffect.mockImplementation((txHash: TxHash) => | ||
| txHash.equals(scopedLog.txHash) ? Promise.resolve(indexedTxEffect) : Promise.resolve(undefined), | ||
| ); | ||
|
|
||
| const result = (await logService.getPublicLogByTag(tag, logContractAddress))!; | ||
|
|
||
| expect(result.logPayload).toEqual(scopedLog.log.getEmittedFieldsWithoutTag()); | ||
| expect(result.uniqueNoteHashesInTx).toEqual(indexedTxEffect.data.noteHashes); | ||
| expect(result.txHash).toEqual(scopedLog.txHash); | ||
| expect(result.firstNullifierInTx).toEqual(indexedTxEffect.data.nullifiers[0]); | ||
|
|
||
| expect(aztecNode.getPublicLogsByTagsFromContract).toHaveBeenCalledWith(logContractAddress, [tag]); | ||
| expect(aztecNode.getTxEffect).toHaveBeenCalledWith(scopedLog.txHash); | ||
| }); | ||
|
|
||
| it('throws if multiple logs found for tag', async () => { | ||
| const scopedLog = await TxScopedL2Log.random(true); | ||
| aztecNode.getPublicLogsByTagsFromContract.mockResolvedValue([[scopedLog, scopedLog]]); | ||
| const logContractAddress = (scopedLog.log as PublicLog).contractAddress; | ||
|
|
||
| await expect(logService.getPublicLogByTag(tag, logContractAddress)).rejects.toThrow(/Got 2 logs for tag/); | ||
| }); | ||
|
|
||
| it('throws if tx effect not found', async () => { | ||
| const scopedLog = await TxScopedL2Log.random(true); | ||
| aztecNode.getPublicLogsByTagsFromContract.mockResolvedValue([[scopedLog]]); | ||
| aztecNode.getTxEffect.mockResolvedValue(undefined); | ||
| const logContractAddress = (scopedLog.log as PublicLog).contractAddress; | ||
|
|
||
| await expect(logService.getPublicLogByTag(tag, logContractAddress)).rejects.toThrow( | ||
| /failed to retrieve tx effects/, | ||
| ); | ||
| }); | ||
|
|
||
| it('returns log fields that are actually emitted', async () => { | ||
| const logContractAddress = await AztecAddress.random(); | ||
| const logPlaintext = [Fr.random()]; | ||
| const logContent = [tag.value, ...logPlaintext]; | ||
|
|
||
| const log = PublicLog.from({ | ||
| contractAddress: logContractAddress, | ||
| fields: logContent, | ||
| }); | ||
| const scopedLogWithPadding = new TxScopedL2Log( | ||
| TxHash.random(), | ||
| randomInt(100), | ||
| randomInt(100), | ||
| BlockNumber(randomInt(100)), | ||
| L2BlockHash.random(), | ||
| 0n, | ||
| log, | ||
| ); | ||
|
|
||
| aztecNode.getPublicLogsByTagsFromContract.mockResolvedValue([[scopedLogWithPadding]]); | ||
| aztecNode.getTxEffect.mockResolvedValue(await randomIndexedTxEffect()); | ||
|
|
||
| const result = await logService.getPublicLogByTag(tag, logContractAddress); | ||
|
|
||
| expect(result?.logPayload).toEqual(logPlaintext); | ||
| }); | ||
| }); | ||
| }); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just run formatting below.