diff --git a/docs/docs-developers/docs/resources/migration_notes.md b/docs/docs-developers/docs/resources/migration_notes.md index cfc21d84d7a2..259002aaa815 100644 --- a/docs/docs-developers/docs/resources/migration_notes.md +++ b/docs/docs-developers/docs/resources/migration_notes.md @@ -9,6 +9,17 @@ Aztec is in active development. Each version may introduce breaking changes that ## TBD +### [Aztec.js] `getPublicEvents` now returns an object instead of an array + +`getPublicEvents` now returns a `GetPublicEventsResult` object with `events` and `maxLogsHit` fields instead of a plain array. This enables pagination through large result sets using the new `afterLog` filter option. + +```diff +- const events = await getPublicEvents(node, MyContract.events.MyEvent, filter); ++ const { events } = await getPublicEvents(node, MyContract.events.MyEvent, filter); +``` + +The `maxLogsHit` flag indicates whether the log limit was reached, meaning more results may be available. You can use `afterLog` in the filter to fetch the next page. + ### [Aztec.nr] Removed `get_random_bytes` The `get_random_bytes` unconstrained function has been removed from `aztec::utils::random`. If you were using it, you can replace it with direct calls to the `random` oracle from `aztec::oracle::random` and convert to bytes yourself. diff --git a/docs/examples/ts/aztecjs_advanced/index.ts b/docs/examples/ts/aztecjs_advanced/index.ts index 84dec7eb87d9..f553450e8354 100644 --- a/docs/examples/ts/aztecjs_advanced/index.ts +++ b/docs/examples/ts/aztecjs_advanced/index.ts @@ -282,7 +282,7 @@ async function pollForTransferEvents() { const currentBlock = await node.getBlockNumber(); if (currentBlock > lastProcessedBlock) { - const events = await getPublicEvents( + const { events } = await getPublicEvents( node, TokenContract.events.Transfer, { diff --git a/yarn-project/aztec.js/src/api/events.ts b/yarn-project/aztec.js/src/api/events.ts index 6b4ea9dd2b0e..a683718a8ee8 100644 --- a/yarn-project/aztec.js/src/api/events.ts +++ b/yarn-project/aztec.js/src/api/events.ts @@ -3,6 +3,14 @@ import type { AztecNode } from '@aztec/stdlib/interfaces/client'; import type { PublicEvent, PublicEventFilter } from '../wallet/wallet.js'; +/** Result of a paginated public event query. */ +export type GetPublicEventsResult = { + /** The decoded events with metadata. */ + events: PublicEvent[]; + /** Whether the log limit was reached, indicating more results may be available. */ + maxLogsHit: boolean; +}; + /** * Returns decoded public events given search parameters. * @param node - The node to request events from @@ -12,21 +20,23 @@ import type { PublicEvent, PublicEventFilter } from '../wallet/wallet.js'; * - `txHash`: Transaction in which the events were emitted. * - `fromBlock`: The block number from which to start fetching events (inclusive). Defaults to 1. * - `toBlock`: The block number until which to fetch events (not inclusive). Defaults to latest + 1. - * @returns - The decoded events with metadata. + * - `afterLog`: Log id after which to start fetching logs. Used for pagination. + * @returns The decoded events with metadata and a flag indicating if more results are available. */ export async function getPublicEvents( node: AztecNode, eventMetadataDef: EventMetadataDefinition, filter: PublicEventFilter, -): Promise[]> { - const { logs } = await node.getPublicLogs({ +): Promise> { + const { logs, maxLogsHit } = await node.getPublicLogs({ fromBlock: filter.fromBlock ? Number(filter.fromBlock) : undefined, toBlock: filter.toBlock ? Number(filter.toBlock) : undefined, txHash: filter.txHash, contractAddress: filter.contractAddress, + afterLog: filter.afterLog, }); - const decodedEvents: PublicEvent[] = []; + const events: PublicEvent[] = []; for (const log of logs) { const logFields = log.log.getEmittedFields(); @@ -37,7 +47,7 @@ export async function getPublicEvents( continue; } - decodedEvents.push({ + events.push({ event: decodeFromAbi([eventMetadataDef.abiType], log.log.fields) as T, metadata: { l2BlockNumber: log.id.blockNumber, @@ -48,5 +58,5 @@ export async function getPublicEvents( }); } - return decodedEvents; + return { events, maxLogsHit }; } diff --git a/yarn-project/aztec.js/src/wallet/wallet.ts b/yarn-project/aztec.js/src/wallet/wallet.ts index 0e48f2f42726..7f7b61befdcc 100644 --- a/yarn-project/aztec.js/src/wallet/wallet.ts +++ b/yarn-project/aztec.js/src/wallet/wallet.ts @@ -13,6 +13,7 @@ import { AuthWitness } from '@aztec/stdlib/auth-witness'; import type { AztecAddress } from '@aztec/stdlib/aztec-address'; import { type ContractInstanceWithAddress, ContractInstanceWithAddressSchema } from '@aztec/stdlib/contract'; import { Gas } from '@aztec/stdlib/gas'; +import { LogId } from '@aztec/stdlib/logs'; import { AbiDecodedSchema, type ApiSchemaFor, optional, schemas, zodFor } from '@aztec/stdlib/schemas'; import type { ExecutionPayload, InTx } from '@aztec/stdlib/tx'; import { @@ -153,6 +154,8 @@ export type EventFilterBase = { * Optional. If provided, it must be greater than fromBlock. */ toBlock?: BlockNumber; + /** Log id after which to start fetching logs. Used for pagination. */ + afterLog?: LogId; }; /** @@ -340,6 +343,7 @@ const EventFilterBaseSchema = z.object({ txHash: optional(TxHash.schema), fromBlock: optional(BlockNumberPositiveSchema), toBlock: optional(BlockNumberPositiveSchema), + afterLog: optional(LogId.schema), }); export const PrivateEventFilterSchema = EventFilterBaseSchema.extend({ diff --git a/yarn-project/end-to-end/src/e2e_event_logs.test.ts b/yarn-project/end-to-end/src/e2e_event_logs.test.ts index 64d89526709f..1fde8fe14556 100644 --- a/yarn-project/end-to-end/src/e2e_event_logs.test.ts +++ b/yarn-project/end-to-end/src/e2e_event_logs.test.ts @@ -143,13 +143,13 @@ describe('Logs', () => { toBlock: BlockNumber(lastTx.blockNumber! + 1), }; - const collectedEvent0s = await getPublicEvents( + const { events: collectedEvent0s } = await getPublicEvents( aztecNode, TestLogContract.events.ExampleEvent0, publicEventFilter, ); - const collectedEvent1s = await getPublicEvents( + const { events: collectedEvent1s } = await getPublicEvents( aztecNode, TestLogContract.events.ExampleEvent1, publicEventFilter, @@ -188,7 +188,7 @@ describe('Logs', () => { .emit_nested_event(a, b, c, extra) .send({ from: account1Address }); - const collectedEvents = await getPublicEvents( + const { events: collectedEvents } = await getPublicEvents( aztecNode, TestLogContract.events.ExampleNestedEvent, { diff --git a/yarn-project/end-to-end/src/e2e_orderbook.test.ts b/yarn-project/end-to-end/src/e2e_orderbook.test.ts index 22efa02edd17..4f566ca466c8 100644 --- a/yarn-project/end-to-end/src/e2e_orderbook.test.ts +++ b/yarn-project/end-to-end/src/e2e_orderbook.test.ts @@ -81,7 +81,7 @@ describe('Orderbook', () => { .with({ authWitnesses: [makerAuthwit] }) .send({ from: makerAddress }); - const orderCreatedEvents = await getPublicEvents( + const { events: orderCreatedEvents } = await getPublicEvents( aztecNode, OrderbookContract.events.OrderCreated, {}, @@ -137,7 +137,7 @@ describe('Orderbook', () => { .send({ from: takerAddress }); // Verify order was fulfilled by checking events - const orderFulfilledEvents = await getPublicEvents( + const { events: orderFulfilledEvents } = await getPublicEvents( aztecNode, OrderbookContract.events.OrderFulfilled, {}, diff --git a/yarn-project/pxe/src/contract_function_simulator/oracle/interfaces.ts b/yarn-project/pxe/src/contract_function_simulator/oracle/interfaces.ts index 3b6dba3494cf..139f1204700d 100644 --- a/yarn-project/pxe/src/contract_function_simulator/oracle/interfaces.ts +++ b/yarn-project/pxe/src/contract_function_simulator/oracle/interfaces.ts @@ -6,8 +6,9 @@ import { MembershipWitness } from '@aztec/foundation/trees'; import type { FunctionSelector, NoteSelector } from '@aztec/stdlib/abi'; import type { AztecAddress } from '@aztec/stdlib/aztec-address'; import { BlockHash } from '@aztec/stdlib/block'; -import type { CompleteAddress, ContractInstance } from '@aztec/stdlib/contract'; +import type { ContractInstance, PartialAddress } from '@aztec/stdlib/contract'; import type { KeyValidationRequest } from '@aztec/stdlib/kernel'; +import type { PublicKeys } from '@aztec/stdlib/keys'; import type { ContractClassLog, Tag } from '@aztec/stdlib/logs'; import type { Note, NoteStatus } from '@aztec/stdlib/note'; import { type NullifierMembershipWitness, PublicDataWitness } from '@aztec/stdlib/trees'; @@ -85,7 +86,9 @@ export interface IUtilityExecutionOracle { nullifier: Fr, ): Promise; getBlockHeader(blockNumber: BlockNumber): Promise; - tryGetPublicKeysAndPartialAddress(account: AztecAddress): Promise; + tryGetPublicKeysAndPartialAddress( + account: AztecAddress, + ): Promise<{ publicKeys: PublicKeys; partialAddress: PartialAddress } | undefined>; getAuthWitness(messageHash: Fr): Promise; getNotes( owner: AztecAddress | undefined, diff --git a/yarn-project/pxe/src/contract_function_simulator/oracle/utility_execution_oracle.ts b/yarn-project/pxe/src/contract_function_simulator/oracle/utility_execution_oracle.ts index c52e4de97c9f..915b079737a3 100644 --- a/yarn-project/pxe/src/contract_function_simulator/oracle/utility_execution_oracle.ts +++ b/yarn-project/pxe/src/contract_function_simulator/oracle/utility_execution_oracle.ts @@ -9,11 +9,11 @@ import type { KeyStore } from '@aztec/key-store'; import type { AuthWitness } from '@aztec/stdlib/auth-witness'; import { AztecAddress } from '@aztec/stdlib/aztec-address'; import { BlockHash } from '@aztec/stdlib/block'; -import type { CompleteAddress, ContractInstance } from '@aztec/stdlib/contract'; +import type { CompleteAddress, ContractInstance, PartialAddress } from '@aztec/stdlib/contract'; import { siloNullifier } from '@aztec/stdlib/hash'; import type { AztecNode } from '@aztec/stdlib/interfaces/server'; import type { KeyValidationRequest } from '@aztec/stdlib/kernel'; -import { computeAddressSecret } from '@aztec/stdlib/keys'; +import { type PublicKeys, computeAddressSecret } from '@aztec/stdlib/keys'; import { deriveEcdhSharedSecret } from '@aztec/stdlib/logs'; import { getNonNullifiedL1ToL2MessageWitness } from '@aztec/stdlib/messaging'; import type { NoteStatus } from '@aztec/stdlib/note'; @@ -232,12 +232,18 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra } /** - * Retrieve the complete address associated to a given address. + * Retrieve the public keys and partial address associated to a given address. * @param account - The account address. - * @returns A complete address associated with the input address, or `undefined` if not registered. + * @returns The public keys and partial address, or `undefined` if the account is not registered. */ - public tryGetPublicKeysAndPartialAddress(account: AztecAddress): Promise { - return this.addressStore.getCompleteAddress(account); + public async tryGetPublicKeysAndPartialAddress( + account: AztecAddress, + ): Promise<{ publicKeys: PublicKeys; partialAddress: PartialAddress } | undefined> { + const completeAddress = await this.addressStore.getCompleteAddress(account); + if (!completeAddress) { + return undefined; + } + return { publicKeys: completeAddress.publicKeys, partialAddress: completeAddress.partialAddress }; } protected async getCompleteAddressOrFail(account: AztecAddress): Promise {