From 4a05735744234eae0aa963ccef820b112dd12ca2 Mon Sep 17 00:00:00 2001 From: spypsy Date: Wed, 30 Oct 2024 12:02:49 +0000 Subject: [PATCH 1/5] fix: EventMetadata class implementation for serialisation --- yarn-project/aztec.js/src/index.ts | 13 ++-- .../aztec.js/src/rpc_clients/pxe_client.ts | 5 +- .../src/contract-interface-gen/typescript.ts | 30 +-------- .../circuit-types/src/interfaces/pxe.ts | 18 +----- .../circuit-types/src/logs/event_metadata.ts | 63 +++++++++++++++++++ yarn-project/circuit-types/src/logs/index.ts | 1 + .../end-to-end/src/e2e_event_logs.test.ts | 58 ++++++++++++----- .../private_transfer_recursion.test.ts | 26 ++++++-- .../transfer_private.test.ts | 14 ++++- .../src/protocol_contract_data.ts | 4 +- .../pxe/src/pxe_http/pxe_http_server.ts | 41 ++++++------ 11 files changed, 181 insertions(+), 92 deletions(-) create mode 100644 yarn-project/circuit-types/src/logs/event_metadata.ts diff --git a/yarn-project/aztec.js/src/index.ts b/yarn-project/aztec.js/src/index.ts index 9192fce979f..542bbb01c1b 100644 --- a/yarn-project/aztec.js/src/index.ts +++ b/yarn-project/aztec.js/src/index.ts @@ -105,16 +105,22 @@ export { Comparator, CompleteAddress, EncryptedL2BlockL2Logs, + EncryptedLogPayload, + EncryptedNoteL2BlockL2Logs, + EpochProofQuote, + EpochProofQuotePayload, + EventMetadata, EventType, ExtendedNote, UniqueNote, FunctionCall, L1Actor, + L1EventPayload, + L1NotePayload, L1ToL2Message, L2Actor, L2Block, L2BlockL2Logs, - EncryptedNoteL2BlockL2Logs, type LogFilter, LogId, LogType, @@ -137,11 +143,6 @@ export { merkleTreeIds, mockTx, mockEpochProofQuote, - EncryptedLogPayload, - L1NotePayload, - L1EventPayload, - EpochProofQuote, - EpochProofQuotePayload, } from '@aztec/circuit-types'; // TODO: These kinds of things have no place on our public api. diff --git a/yarn-project/aztec.js/src/rpc_clients/pxe_client.ts b/yarn-project/aztec.js/src/rpc_clients/pxe_client.ts index 34ce3848390..0e7a81a0714 100644 --- a/yarn-project/aztec.js/src/rpc_clients/pxe_client.ts +++ b/yarn-project/aztec.js/src/rpc_clients/pxe_client.ts @@ -5,6 +5,7 @@ import { EncryptedL2Log, EncryptedL2NoteLog, EncryptedNoteL2BlockL2Logs, + EventMetadata, ExtendedNote, ExtendedUnencryptedL2Log, L2Block, @@ -36,7 +37,7 @@ import { PrivateCircuitPublicInputs, PublicKeys, } from '@aztec/circuits.js'; -import { NoteSelector } from '@aztec/foundation/abi'; +import { EventSelector, NoteSelector } from '@aztec/foundation/abi'; import { Buffer32 } from '@aztec/foundation/buffer'; import { createJsonRpcClient, makeFetch } from '@aztec/foundation/json-rpc/client'; @@ -55,6 +56,7 @@ export const createPXEClient = (url: string, fetch = makeFetch([1, 2, 3], false) CompleteAddress, FunctionSelector, EthAddress, + EventSelector, ExtendedNote, UniqueNote, ExtendedUnencryptedL2Log, @@ -75,6 +77,7 @@ export const createPXEClient = (url: string, fetch = makeFetch([1, 2, 3], false) EncryptedNoteL2BlockL2Logs, EncryptedL2NoteLog, EncryptedL2Log, + EventMetadata, UnencryptedL2Log, NoteSelector, NullifierMembershipWitness, diff --git a/yarn-project/builder/src/contract-interface-gen/typescript.ts b/yarn-project/builder/src/contract-interface-gen/typescript.ts index 200337cb22b..455378a3d13 100644 --- a/yarn-project/builder/src/contract-interface-gen/typescript.ts +++ b/yarn-project/builder/src/contract-interface-gen/typescript.ts @@ -257,12 +257,12 @@ function generateEvents(events: any[] | undefined) { `; const fieldNames = event.fields.map((field: any) => `"${field.name}"`); - const eventType = `${eventName}: {decode: (payload: L1EventPayload | UnencryptedL2Log | undefined) => ${eventName} | undefined, eventSelector: EventSelector, fieldNames: string[] }`; + const eventType = `${eventName}: {abiType: AbiType, eventSelector: EventSelector, fieldNames: string[] }`; // Reusing the decodeFunctionSignature const eventSignature = decodeFunctionSignature(eventName, event.fields); const eventSelector = `EventSelector.fromSignature('${eventSignature}')`; const eventImpl = `${eventName}: { - decode: this.decodeEvent(${eventSelector}, ${JSON.stringify(event, null, 4)}), + abiType: ${JSON.stringify(event, null, 4)}, eventSelector: ${eventSelector}, fieldNames: [${fieldNames}], }`; @@ -277,32 +277,6 @@ function generateEvents(events: any[] | undefined) { return { eventDefs: eventsMetadata.map(({ eventDef }) => eventDef).join('\n'), events: ` - // Partial application is chosen is to avoid the duplication of so much codegen. - private static decodeEvent( - eventSelector: EventSelector, - eventType: AbiType, - ): (payload: L1EventPayload | UnencryptedL2Log | undefined) => T | undefined { - return (payload: L1EventPayload | UnencryptedL2Log | undefined): T | undefined => { - if (payload === undefined) { - return undefined; - } - - if (payload instanceof L1EventPayload) { - if (!eventSelector.equals(payload.eventTypeId)) { - return undefined; - } - return decodeFromAbi([eventType], payload.event.items) as T; - } else { - let items = []; - for (let i = 0; i < payload.data.length; i += 32) { - items.push(new Fr(payload.data.subarray(i, i + 32))); - } - - return decodeFromAbi([eventType], items) as T; - } - }; - } - public static get events(): { ${eventsMetadata.map(({ eventType }) => eventType).join(', ')} } { return { ${eventsMetadata.map(({ eventImpl }) => eventImpl).join(',\n')} diff --git a/yarn-project/circuit-types/src/interfaces/pxe.ts b/yarn-project/circuit-types/src/interfaces/pxe.ts index 26721aee915..f38ec889cf5 100644 --- a/yarn-project/circuit-types/src/interfaces/pxe.ts +++ b/yarn-project/circuit-types/src/interfaces/pxe.ts @@ -10,16 +10,11 @@ import { type Point, type ProtocolContractAddresses, } from '@aztec/circuits.js'; -import { type ContractArtifact, type EventSelector } from '@aztec/foundation/abi'; +import { type ContractArtifact } from '@aztec/foundation/abi'; import { type AuthWitness } from '../auth_witness.js'; import { type L2Block } from '../l2_block.js'; -import { - type GetUnencryptedLogsResponse, - type L1EventPayload, - type LogFilter, - type UnencryptedL2Log, -} from '../logs/index.js'; +import { type EventMetadata, type GetUnencryptedLogsResponse, type LogFilter } from '../logs/index.js'; import { type IncomingNotesFilter } from '../notes/incoming_notes_filter.js'; import { type ExtendedNote, type OutgoingNotesFilter, type UniqueNote } from '../notes/index.js'; import { type PrivateExecutionResult } from '../private_execution_result.js'; @@ -425,15 +420,6 @@ export interface PXE { } // docs:end:pxe-interface -/** - * The shape of the event generated on the Contract. - */ -export interface EventMetadata { - decode(payload: L1EventPayload | UnencryptedL2Log): T | undefined; - eventSelector: EventSelector; - fieldNames: string[]; -} - /** * This is used in getting events via the filter */ diff --git a/yarn-project/circuit-types/src/logs/event_metadata.ts b/yarn-project/circuit-types/src/logs/event_metadata.ts new file mode 100644 index 00000000000..cdcf33a1d92 --- /dev/null +++ b/yarn-project/circuit-types/src/logs/event_metadata.ts @@ -0,0 +1,63 @@ +import { L1EventPayload, type UnencryptedL2Log } from '@aztec/circuit-types'; +import { type AbiType } from '@aztec/foundation/abi'; +import { EventSelector, decodeFromAbi } from '@aztec/foundation/abi'; +import { Fr } from '@aztec/foundation/fields'; + +/** + * Represents metadata for an event decoder, including all information needed to reconstruct it. + */ +export class EventMetadata { + public readonly decode: (payload: L1EventPayload | UnencryptedL2Log) => T | undefined; + + constructor(public eventSelector: EventSelector, private readonly eventType: AbiType, public fieldNames: string[]) { + this.decode = EventMetadata.decodeEvent(eventSelector, eventType); + } + + public static decodeEvent( + eventSelector: EventSelector, + eventType: AbiType, + ): (payload: L1EventPayload | UnencryptedL2Log | undefined) => T | undefined { + return (payload: L1EventPayload | UnencryptedL2Log | undefined): T | undefined => { + if (payload === undefined) { + return undefined; + } + + if (payload instanceof L1EventPayload) { + if (!eventSelector.equals(payload.eventTypeId)) { + return undefined; + } + return decodeFromAbi([eventType], payload.event.items) as T; + } else { + const items = []; + for (let i = 0; i < payload.data.length; i += 32) { + items.push(new Fr(payload.data.subarray(i, i + 32))); + } + + return decodeFromAbi([eventType], items) as T; + } + }; + } + + /** + * Serializes the metadata to a JSON-friendly format + */ + public toJSON() { + return { + type: 'event_metadata', + eventSelector: this.eventSelector.toString(), + eventType: this.eventType, + fieldNames: this.fieldNames, + }; + } + + /** + * Creates an EventMetadata instance from a JSON representation + */ + public static fromJSON(json: any): EventMetadata { + if (json?.type !== 'event_metadata') { + throw new Error('Invalid event metadata format'); + } + + return new EventMetadata(EventSelector.fromString(json.eventSelector), json.eventType, json.fieldNames); + } +} diff --git a/yarn-project/circuit-types/src/logs/index.ts b/yarn-project/circuit-types/src/logs/index.ts index 14cb33aa006..af29a4c9677 100644 --- a/yarn-project/circuit-types/src/logs/index.ts +++ b/yarn-project/circuit-types/src/logs/index.ts @@ -1,5 +1,6 @@ export * from './encrypted_l2_note_log.js'; export * from './encrypted_l2_log.js'; +export * from './event_metadata.js'; export * from './get_unencrypted_logs_response.js'; export * from './function_l2_logs.js'; export * from './l2_block_l2_logs.js'; 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 e508c603aff..3c082431757 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 @@ -1,6 +1,7 @@ import { type AccountWalletWithSecretKey, type AztecNode, + EventMetadata, EventType, Fr, L1EventPayload, @@ -113,33 +114,50 @@ describe('Logs', () => { .wait(); // We get all the events we can decrypt with either our incoming or outgoing viewing keys - const collectedEvent0s = await wallets[0].getEvents( + + const collectedEvent0s = await wallets[0].getEvents( EventType.Encrypted, - TestLogContract.events.ExampleEvent0, + new EventMetadata( + TestLogContract.events.ExampleEvent0.eventSelector, + TestLogContract.events.ExampleEvent0.abiType, + TestLogContract.events.ExampleEvent0.fieldNames, + ), firstTx.blockNumber!, lastTx.blockNumber! - firstTx.blockNumber! + 1, ); - const collectedEvent0sWithIncoming = await wallets[0].getEvents( + const collectedEvent0sWithIncoming = await wallets[0].getEvents( EventType.Encrypted, - TestLogContract.events.ExampleEvent0, + new EventMetadata( + TestLogContract.events.ExampleEvent0.eventSelector, + TestLogContract.events.ExampleEvent0.abiType, + TestLogContract.events.ExampleEvent0.fieldNames, + ), firstTx.blockNumber!, lastTx.blockNumber! - firstTx.blockNumber! + 1, // This function can be called specifying the viewing public keys associated with the encrypted event. [wallets[0].getCompleteAddress().publicKeys.masterIncomingViewingPublicKey], ); - const collectedEvent0sWithOutgoing = await wallets[0].getEvents( + const collectedEvent0sWithOutgoing = await wallets[0].getEvents( EventType.Encrypted, - TestLogContract.events.ExampleEvent0, + new EventMetadata( + TestLogContract.events.ExampleEvent0.eventSelector, + TestLogContract.events.ExampleEvent0.abiType, + TestLogContract.events.ExampleEvent0.fieldNames, + ), firstTx.blockNumber!, lastTx.blockNumber! - firstTx.blockNumber! + 1, [wallets[0].getCompleteAddress().publicKeys.masterOutgoingViewingPublicKey], ); - const collectedEvent1s = await wallets[0].getEvents( + const collectedEvent1s = await wallets[0].getEvents( EventType.Encrypted, - TestLogContract.events.ExampleEvent1, + new EventMetadata( + TestLogContract.events.ExampleEvent1.eventSelector, + TestLogContract.events.ExampleEvent1.abiType, + TestLogContract.events.ExampleEvent1.fieldNames, + ), firstTx.blockNumber!, lastTx.blockNumber! - firstTx.blockNumber! + 1, [wallets[0].getCompleteAddress().publicKeys.masterIncomingViewingPublicKey], @@ -150,9 +168,13 @@ describe('Logs', () => { expect(collectedEvent0s.length).toBe(10); expect(collectedEvent1s.length).toBe(5); - const emptyEvent1s = await wallets[0].getEvents( + const emptyEvent1s = await wallets[0].getEvents( EventType.Encrypted, - TestLogContract.events.ExampleEvent1, + new EventMetadata( + TestLogContract.events.ExampleEvent1.eventSelector, + TestLogContract.events.ExampleEvent1.abiType, + TestLogContract.events.ExampleEvent1.fieldNames, + ), firstTx.blockNumber!, lastTx.blockNumber! - firstTx.blockNumber! + 1, [wallets[0].getCompleteAddress().publicKeys.masterOutgoingViewingPublicKey], @@ -199,16 +221,24 @@ describe('Logs', () => { ); const lastTx = await testLogContract.methods.emit_unencrypted_events(preimage[++i]).send().wait(); - const collectedEvent0s = await wallets[0].getEvents( + const collectedEvent0s = await wallets[0].getEvents( EventType.Unencrypted, - TestLogContract.events.ExampleEvent0, + new EventMetadata( + TestLogContract.events.ExampleEvent0.eventSelector, + TestLogContract.events.ExampleEvent0.abiType, + TestLogContract.events.ExampleEvent0.fieldNames, + ), firstTx.blockNumber!, lastTx.blockNumber! - firstTx.blockNumber! + 1, ); - const collectedEvent1s = await wallets[0].getEvents( + const collectedEvent1s = await wallets[0].getEvents( EventType.Unencrypted, - TestLogContract.events.ExampleEvent1, + new EventMetadata( + TestLogContract.events.ExampleEvent1.eventSelector, + TestLogContract.events.ExampleEvent1.abiType, + TestLogContract.events.ExampleEvent1.fieldNames, + ), firstTx.blockNumber!, lastTx.blockNumber! - firstTx.blockNumber! + 1, ); diff --git a/yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts index cdb65ecca6a..dd6de6503cb 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts @@ -1,5 +1,5 @@ -import { BatchCall, EventType } from '@aztec/aztec.js'; -import { TokenContract } from '@aztec/noir-contracts.js'; +import { BatchCall, EventMetadata, EventType } from '@aztec/aztec.js'; +import { TokenContract, type Transfer } from '@aztec/noir-contracts.js'; import { TokenContractTest } from './token_contract_test.js'; @@ -40,7 +40,16 @@ describe('e2e_token_contract private transfer recursion', () => { // We should have created a single new note, for the recipient expect(tx.debugInfo?.noteHashes.length).toBe(1); - const events = await wallets[1].getEvents(EventType.Encrypted, TokenContract.events.Transfer, tx.blockNumber!, 1); + const events = await wallets[1].getEvents( + EventType.Encrypted, + new EventMetadata( + TokenContract.events.Transfer.eventSelector, + TokenContract.events.Transfer.abiType, + TokenContract.events.Transfer.fieldNames, + ), + tx.blockNumber!, + 1, + ); expect(events[0]).toEqual({ from: accounts[0].address, @@ -66,7 +75,16 @@ describe('e2e_token_contract private transfer recursion', () => { const senderBalance = await asset.methods.balance_of_private(accounts[0].address).simulate(); expect(senderBalance).toEqual(expectedChange); - const events = await wallets[1].getEvents(EventType.Encrypted, TokenContract.events.Transfer, tx.blockNumber!, 1); + const events = await wallets[1].getEvents( + EventType.Encrypted, + new EventMetadata( + TokenContract.events.Transfer.eventSelector, + TokenContract.events.Transfer.abiType, + TokenContract.events.Transfer.fieldNames, + ), + tx.blockNumber!, + 1, + ); expect(events[0]).toEqual({ from: accounts[0].address, diff --git a/yarn-project/end-to-end/src/e2e_token_contract/transfer_private.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/transfer_private.test.ts index 5865ac3343a..be2e77c2cf9 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/transfer_private.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/transfer_private.test.ts @@ -1,12 +1,13 @@ import { AztecAddress, CompleteAddress, + EventMetadata, EventType, Fr, computeAuthWitMessageHash, computeInnerAuthWitHashFromAction, } from '@aztec/aztec.js'; -import { TokenContract } from '@aztec/noir-contracts.js'; +import { TokenContract, type Transfer } from '@aztec/noir-contracts.js'; import { DUPLICATE_NULLIFIER_ERROR } from '../fixtures/fixtures.js'; import { TokenContractTest } from './token_contract_test.js'; @@ -41,7 +42,16 @@ describe('e2e_token_contract transfer private', () => { const tx = await asset.methods.transfer(accounts[1].address, amount).send().wait(); tokenSim.transferPrivate(accounts[0].address, accounts[1].address, amount); - const events = await wallets[1].getEvents(EventType.Encrypted, TokenContract.events.Transfer, tx.blockNumber!, 1); + const events = await wallets[1].getEvents( + EventType.Encrypted, + new EventMetadata( + TokenContract.events.Transfer.eventSelector, + TokenContract.events.Transfer.abiType, + TokenContract.events.Transfer.fieldNames, + ), + tx.blockNumber!, + 1, + ); expect(events[0]).toEqual({ from: accounts[0].address, diff --git a/yarn-project/protocol-contracts/src/protocol_contract_data.ts b/yarn-project/protocol-contracts/src/protocol_contract_data.ts index 11810f96b37..8512d948c85 100644 --- a/yarn-project/protocol-contracts/src/protocol_contract_data.ts +++ b/yarn-project/protocol-contracts/src/protocol_contract_data.ts @@ -55,9 +55,9 @@ export const ProtocolContractLeaf = { ContractClassRegisterer: Fr.fromString('0x147ba3294403576dbad10f86d3ffd4eb83fb230ffbcd5c8b153dd02942d0611f'), MultiCallEntrypoint: Fr.fromString('0x154b701b41d6cf6da7204fef36b2ee9578b449d21b3792a9287bf45eba48fd26'), FeeJuice: Fr.fromString('0x21c9ab2e339c9b3394e4e1ff3b7cf37be4e0fc0bc177a192d287d98963b9b254'), - Router: Fr.fromString('0x2779d7e4ccba389da358a0c9362364d0c65e14cd4d9df929e6722187e808e068'), + Router: Fr.fromString('0x2b0b558e92b7a13cde0a2ecc7570c181a6fbae2bdc6f966cacfc39a784635394'), }; export const protocolContractTreeRoot = Fr.fromString( - '0x00724e4de088411c873c3d6975491eb48889bfa51bc854744a4fcc307ee9abd8', + '0x0d560ad12f14dd5026070bc037ac343535db339212f0904dfc96c4aea4dcc8ab', ); diff --git a/yarn-project/pxe/src/pxe_http/pxe_http_server.ts b/yarn-project/pxe/src/pxe_http/pxe_http_server.ts index 7f1f814278b..373b908a270 100644 --- a/yarn-project/pxe/src/pxe_http/pxe_http_server.ts +++ b/yarn-project/pxe/src/pxe_http/pxe_http_server.ts @@ -6,6 +6,7 @@ import { EncryptedL2Log, EncryptedL2NoteLog, EncryptedNoteL2BlockL2Logs, + EventMetadata, ExtendedNote, ExtendedUnencryptedL2Log, L2Block, @@ -27,7 +28,7 @@ import { UniqueNote, } from '@aztec/circuit-types'; import { FunctionSelector, PrivateCircuitPublicInputs, PublicKeys } from '@aztec/circuits.js'; -import { NoteSelector } from '@aztec/foundation/abi'; +import { EventSelector, NoteSelector } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Buffer32 } from '@aztec/foundation/buffer'; import { EthAddress } from '@aztec/foundation/eth-address'; @@ -44,43 +45,45 @@ export function createPXERpcServer(pxeService: PXE): JsonRpcServer { return new JsonRpcServer( pxeService, { - CompleteAddress, + AuthWitness, AztecAddress, - TxExecutionRequest, - ExtendedUnencryptedL2Log, - FunctionSelector, - TxHash, Buffer32, + CompleteAddress, EthAddress, - Point, + EventSelector, + ExtendedNote, + ExtendedUnencryptedL2Log, Fr, + FunctionSelector, GrumpkinScalar, + L2Block, + LogId, Note, - ExtendedNote, + Point, PublicKeys, - UniqueNote, SiblingPath, - AuthWitness, - L2Block, TxEffect, - LogId, + TxExecutionRequest, + TxHash, + UniqueNote, }, { - EncryptedNoteL2BlockL2Logs, - EncryptedL2NoteLog, + CountedPublicExecutionRequest, + CountedNoteLog, EncryptedL2Log, - UnencryptedL2Log, + EncryptedL2NoteLog, + EncryptedNoteL2BlockL2Logs, + EventMetadata, NoteSelector, NullifierMembershipWitness, - TxSimulationResult, - TxProvingResult, PrivateCircuitPublicInputs, PrivateExecutionResult, - CountedPublicExecutionRequest, - CountedNoteLog, + TxSimulationResult, + TxProvingResult, Tx, TxReceipt, UnencryptedL2BlockL2Logs, + UnencryptedL2Log, }, ['start', 'stop'], ); From 968e766a76e83e768f61cf7a46252673146f2893 Mon Sep 17 00:00:00 2001 From: spypsy Date: Wed, 30 Oct 2024 15:10:15 +0000 Subject: [PATCH 2/5] fix e2e test --- .../end-to-end/src/e2e_event_logs.test.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) 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 3c082431757..217ef034f40 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 @@ -62,14 +62,19 @@ describe('Logs', () => { expect(decryptedEvent0.eventTypeId).toStrictEqual(EventSelector.fromSignature('ExampleEvent0(Field,Field)')); // We decode our event into the event type - const event0 = TestLogContract.events.ExampleEvent0.decode(decryptedEvent0); + const event0Metadata = new EventMetadata( + TestLogContract.events.ExampleEvent0.eventSelector, + TestLogContract.events.ExampleEvent0.abiType, + TestLogContract.events.ExampleEvent0.fieldNames, + ); + const event0 = event0Metadata.decode(decryptedEvent0); // We check that the event was decoded correctly expect(event0?.value0).toStrictEqual(preimage[0].toBigInt()); expect(event0?.value1).toStrictEqual(preimage[1].toBigInt()); // We check that an event that does not match, is not decoded correctly due to an event type id mismatch - const badEvent0 = TestLogContract.events.ExampleEvent1.decode(decryptedEvent0); + const badEvent0 = event0Metadata.decode(decryptedEvent0); expect(badEvent0).toBe(undefined); const decryptedEvent1 = L1EventPayload.decryptAsIncoming(encryptedLogs[2], wallets[0].getEncryptionSecret())!; @@ -79,7 +84,12 @@ describe('Logs', () => { expect(decryptedEvent1.eventTypeId).toStrictEqual(EventSelector.fromSignature('ExampleEvent1((Field),u8)')); // We check our second event, which is a different type - const event1 = TestLogContract.events.ExampleEvent1.decode(decryptedEvent1); + const event1Metadata = new EventMetadata( + TestLogContract.events.ExampleEvent1.eventSelector, + TestLogContract.events.ExampleEvent1.abiType, + TestLogContract.events.ExampleEvent1.fieldNames, + ); + const event1 = event1Metadata.decode(decryptedEvent1); // We expect the fields to have been populated correctly expect(event1?.value2).toStrictEqual(preimage[2]); @@ -87,7 +97,7 @@ describe('Logs', () => { expect(event1?.value3).toStrictEqual(BigInt(preimage[3].toBuffer().subarray(31).readUint8())); // Again, trying to decode another event with mismatching data does not yield anything - const badEvent1 = TestLogContract.events.ExampleEvent0.decode(decryptedEvent1); + const badEvent1 = event1Metadata.decode(decryptedEvent1); expect(badEvent1).toBe(undefined); }); From acdc2fd969ce6b646b997810c79fb45992caed7d Mon Sep 17 00:00:00 2001 From: spypsy Date: Wed, 30 Oct 2024 16:05:36 +0000 Subject: [PATCH 3/5] improve getEvents API --- cspell.json | 1 + .../aztec.js/src/wallet/base_wallet.ts | 16 ++++-- .../circuit-types/src/interfaces/pxe.ts | 8 +-- .../circuit-types/src/logs/event_metadata.ts | 22 ++++++-- .../end-to-end/src/e2e_event_logs.test.ts | 53 +++++-------------- .../private_transfer_recursion.test.ts | 19 ++----- .../transfer_private.test.ts | 7 +-- .../pxe/src/pxe_service/pxe_service.ts | 10 ++-- 8 files changed, 57 insertions(+), 79 deletions(-) diff --git a/cspell.json b/cspell.json index d964b9afe22..dd5586ddbc8 100644 --- a/cspell.json +++ b/cspell.json @@ -283,6 +283,7 @@ "Validium", "vals", "viem", + "vpks", "Vyper", "wasms", "webassembly", diff --git a/yarn-project/aztec.js/src/wallet/base_wallet.ts b/yarn-project/aztec.js/src/wallet/base_wallet.ts index e64396187a7..118f3ac8429 100644 --- a/yarn-project/aztec.js/src/wallet/base_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/base_wallet.ts @@ -1,6 +1,6 @@ import { type AuthWitness, - type EventMetadata, + EventMetadata, type EventType, type ExtendedNote, type GetUnencryptedLogsResponse, @@ -34,7 +34,7 @@ import { type PartialAddress, type Point, } from '@aztec/circuits.js'; -import { type ContractArtifact } from '@aztec/foundation/abi'; +import type { AbiType, ContractArtifact, EventSelector } from '@aztec/foundation/abi'; import { type Wallet } from '../account/wallet.js'; import { type ExecutionRequestInit } from '../entrypoint/entrypoint.js'; @@ -199,14 +199,22 @@ export abstract class BaseWallet implements Wallet { } getEvents( type: EventType, - eventMetadata: EventMetadata, + event: { + /** The event selector */ + eventSelector: EventSelector; + /** The event's abi type */ + abiType: AbiType; + /** The field names */ + fieldNames: string[]; + }, from: number, limit: number, vpks: Point[] = [ this.getCompleteAddress().publicKeys.masterIncomingViewingPublicKey, this.getCompleteAddress().publicKeys.masterOutgoingViewingPublicKey, ], - ) { + ): Promise { + const eventMetadata = new EventMetadata(type, event); return this.pxe.getEvents(type, eventMetadata, from, limit, vpks); } public getL1ToL2MembershipWitness( diff --git a/yarn-project/circuit-types/src/interfaces/pxe.ts b/yarn-project/circuit-types/src/interfaces/pxe.ts index f38ec889cf5..9b8da020962 100644 --- a/yarn-project/circuit-types/src/interfaces/pxe.ts +++ b/yarn-project/circuit-types/src/interfaces/pxe.ts @@ -10,11 +10,11 @@ import { type Point, type ProtocolContractAddresses, } from '@aztec/circuits.js'; -import { type ContractArtifact } from '@aztec/foundation/abi'; +import type { AbiType, ContractArtifact, EventSelector } from '@aztec/foundation/abi'; import { type AuthWitness } from '../auth_witness.js'; import { type L2Block } from '../l2_block.js'; -import { type EventMetadata, type GetUnencryptedLogsResponse, type LogFilter } from '../logs/index.js'; +import { type GetUnencryptedLogsResponse, type LogFilter } from '../logs/index.js'; import { type IncomingNotesFilter } from '../notes/incoming_notes_filter.js'; import { type ExtendedNote, type OutgoingNotesFilter, type UniqueNote } from '../notes/index.js'; import { type PrivateExecutionResult } from '../private_execution_result.js'; @@ -404,7 +404,7 @@ export interface PXE { /** * Returns the events of a specified type given search parameters. * @param type - The type of the event to search for—Encrypted, or Unencrypted. - * @param eventMetadata - Identifier of the event. This should be the class generated from the contract. e.g. Contract.events.Event + * @param eventMetadata - Metadata of the event. This should be the class generated from the contract. e.g. Contract.events.Event * @param from - The block number to search from. * @param limit - The amount of blocks to search. * @param vpks - (Used for encrypted logs only) The viewing (incoming and outgoing) public keys that correspond to the viewing secret keys that can decrypt the log. @@ -412,7 +412,7 @@ export interface PXE { */ getEvents( type: EventType, - eventMetadata: EventMetadata, + eventMetadata: { eventSelector: EventSelector; abiType: AbiType; fieldNames: string[] }, from: number, limit: number, vpks: Point[], diff --git a/yarn-project/circuit-types/src/logs/event_metadata.ts b/yarn-project/circuit-types/src/logs/event_metadata.ts index cdcf33a1d92..a1bcc3385ca 100644 --- a/yarn-project/circuit-types/src/logs/event_metadata.ts +++ b/yarn-project/circuit-types/src/logs/event_metadata.ts @@ -1,4 +1,4 @@ -import { L1EventPayload, type UnencryptedL2Log } from '@aztec/circuit-types'; +import { EventType, L1EventPayload, type UnencryptedL2Log } from '@aztec/circuit-types'; import { type AbiType } from '@aztec/foundation/abi'; import { EventSelector, decodeFromAbi } from '@aztec/foundation/abi'; import { Fr } from '@aztec/foundation/fields'; @@ -9,8 +9,18 @@ import { Fr } from '@aztec/foundation/fields'; export class EventMetadata { public readonly decode: (payload: L1EventPayload | UnencryptedL2Log) => T | undefined; - constructor(public eventSelector: EventSelector, private readonly eventType: AbiType, public fieldNames: string[]) { - this.decode = EventMetadata.decodeEvent(eventSelector, eventType); + public readonly eventSelector: EventSelector; + public readonly abiType: AbiType; + public readonly fieldNames: string[]; + + constructor( + public readonly eventType: EventType, + event: { eventSelector: EventSelector; abiType: AbiType; fieldNames: string[] }, + ) { + this.eventSelector = event.eventSelector; + this.abiType = event.abiType; + this.fieldNames = event.fieldNames; + this.decode = EventMetadata.decodeEvent(event.eventSelector, event.abiType); } public static decodeEvent( @@ -58,6 +68,10 @@ export class EventMetadata { throw new Error('Invalid event metadata format'); } - return new EventMetadata(EventSelector.fromString(json.eventSelector), json.eventType, json.fieldNames); + return new EventMetadata(EventType.Encrypted, { + eventSelector: EventSelector.fromString(json.eventSelector), + abiType: json.eventType, + fieldNames: json.fieldNames, + }); } } 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 217ef034f40..c678873bb49 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 @@ -63,9 +63,8 @@ describe('Logs', () => { // We decode our event into the event type const event0Metadata = new EventMetadata( - TestLogContract.events.ExampleEvent0.eventSelector, - TestLogContract.events.ExampleEvent0.abiType, - TestLogContract.events.ExampleEvent0.fieldNames, + EventType.Encrypted, + TestLogContract.events.ExampleEvent0, ); const event0 = event0Metadata.decode(decryptedEvent0); @@ -85,10 +84,10 @@ describe('Logs', () => { // We check our second event, which is a different type const event1Metadata = new EventMetadata( - TestLogContract.events.ExampleEvent1.eventSelector, - TestLogContract.events.ExampleEvent1.abiType, - TestLogContract.events.ExampleEvent1.fieldNames, + EventType.Encrypted, + TestLogContract.events.ExampleEvent1, ); + const event1 = event1Metadata.decode(decryptedEvent1); // We expect the fields to have been populated correctly @@ -127,22 +126,14 @@ describe('Logs', () => { const collectedEvent0s = await wallets[0].getEvents( EventType.Encrypted, - new EventMetadata( - TestLogContract.events.ExampleEvent0.eventSelector, - TestLogContract.events.ExampleEvent0.abiType, - TestLogContract.events.ExampleEvent0.fieldNames, - ), + TestLogContract.events.ExampleEvent0, firstTx.blockNumber!, lastTx.blockNumber! - firstTx.blockNumber! + 1, ); const collectedEvent0sWithIncoming = await wallets[0].getEvents( EventType.Encrypted, - new EventMetadata( - TestLogContract.events.ExampleEvent0.eventSelector, - TestLogContract.events.ExampleEvent0.abiType, - TestLogContract.events.ExampleEvent0.fieldNames, - ), + TestLogContract.events.ExampleEvent0, firstTx.blockNumber!, lastTx.blockNumber! - firstTx.blockNumber! + 1, // This function can be called specifying the viewing public keys associated with the encrypted event. @@ -151,11 +142,7 @@ describe('Logs', () => { const collectedEvent0sWithOutgoing = await wallets[0].getEvents( EventType.Encrypted, - new EventMetadata( - TestLogContract.events.ExampleEvent0.eventSelector, - TestLogContract.events.ExampleEvent0.abiType, - TestLogContract.events.ExampleEvent0.fieldNames, - ), + TestLogContract.events.ExampleEvent0, firstTx.blockNumber!, lastTx.blockNumber! - firstTx.blockNumber! + 1, [wallets[0].getCompleteAddress().publicKeys.masterOutgoingViewingPublicKey], @@ -163,11 +150,7 @@ describe('Logs', () => { const collectedEvent1s = await wallets[0].getEvents( EventType.Encrypted, - new EventMetadata( - TestLogContract.events.ExampleEvent1.eventSelector, - TestLogContract.events.ExampleEvent1.abiType, - TestLogContract.events.ExampleEvent1.fieldNames, - ), + TestLogContract.events.ExampleEvent1, firstTx.blockNumber!, lastTx.blockNumber! - firstTx.blockNumber! + 1, [wallets[0].getCompleteAddress().publicKeys.masterIncomingViewingPublicKey], @@ -180,11 +163,7 @@ describe('Logs', () => { const emptyEvent1s = await wallets[0].getEvents( EventType.Encrypted, - new EventMetadata( - TestLogContract.events.ExampleEvent1.eventSelector, - TestLogContract.events.ExampleEvent1.abiType, - TestLogContract.events.ExampleEvent1.fieldNames, - ), + TestLogContract.events.ExampleEvent1, firstTx.blockNumber!, lastTx.blockNumber! - firstTx.blockNumber! + 1, [wallets[0].getCompleteAddress().publicKeys.masterOutgoingViewingPublicKey], @@ -233,22 +212,14 @@ describe('Logs', () => { const collectedEvent0s = await wallets[0].getEvents( EventType.Unencrypted, - new EventMetadata( - TestLogContract.events.ExampleEvent0.eventSelector, - TestLogContract.events.ExampleEvent0.abiType, - TestLogContract.events.ExampleEvent0.fieldNames, - ), + TestLogContract.events.ExampleEvent0, firstTx.blockNumber!, lastTx.blockNumber! - firstTx.blockNumber! + 1, ); const collectedEvent1s = await wallets[0].getEvents( EventType.Unencrypted, - new EventMetadata( - TestLogContract.events.ExampleEvent1.eventSelector, - TestLogContract.events.ExampleEvent1.abiType, - TestLogContract.events.ExampleEvent1.fieldNames, - ), + TestLogContract.events.ExampleEvent1, firstTx.blockNumber!, lastTx.blockNumber! - firstTx.blockNumber! + 1, ); diff --git a/yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts index 8db63b2def8..1425c0b16f0 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts @@ -1,4 +1,4 @@ -import { BatchCall, EventMetadata, EventType } from '@aztec/aztec.js'; +import { BatchCall, EventType } from '@aztec/aztec.js'; import { TokenContract, type Transfer } from '@aztec/noir-contracts.js'; import { TokenContractTest } from './token_contract_test.js'; @@ -44,11 +44,7 @@ describe('e2e_token_contract private transfer recursion', () => { const events = await wallets[1].getEvents( EventType.Encrypted, - new EventMetadata( - TokenContract.events.Transfer.eventSelector, - TokenContract.events.Transfer.abiType, - TokenContract.events.Transfer.fieldNames, - ), + TokenContract.events.Transfer, tx.blockNumber!, 1, ); @@ -77,16 +73,7 @@ describe('e2e_token_contract private transfer recursion', () => { const senderBalance = await asset.methods.balance_of_private(accounts[0].address).simulate(); expect(senderBalance).toEqual(expectedChange); - const events = await wallets[1].getEvents( - EventType.Encrypted, - new EventMetadata( - TokenContract.events.Transfer.eventSelector, - TokenContract.events.Transfer.abiType, - TokenContract.events.Transfer.fieldNames, - ), - tx.blockNumber!, - 1, - ); + const events = await wallets[1].getEvents(EventType.Encrypted, TokenContract.events.Transfer, tx.blockNumber!, 1); expect(events[0]).toEqual({ from: accounts[0].address, diff --git a/yarn-project/end-to-end/src/e2e_token_contract/transfer_private.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/transfer_private.test.ts index be2e77c2cf9..ced087e5320 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/transfer_private.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/transfer_private.test.ts @@ -1,7 +1,6 @@ import { AztecAddress, CompleteAddress, - EventMetadata, EventType, Fr, computeAuthWitMessageHash, @@ -44,11 +43,7 @@ describe('e2e_token_contract transfer private', () => { const events = await wallets[1].getEvents( EventType.Encrypted, - new EventMetadata( - TokenContract.events.Transfer.eventSelector, - TokenContract.events.Transfer.abiType, - TokenContract.events.Transfer.fieldNames, - ), + TokenContract.events.Transfer, tx.blockNumber!, 1, ); diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index c2bea391e5d..0f5bf72ae8b 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -1,7 +1,7 @@ import { type AuthWitness, type AztecNode, - type EventMetadata, + EventMetadata, EventType, type ExtendedNote, type FunctionCall, @@ -49,6 +49,7 @@ import { import { computeNoteHashNonce, siloNullifier } from '@aztec/circuits.js/hash'; import { type AbiDecoded, + type AbiType, type ContractArtifact, EventSelector, FunctionSelector, @@ -830,24 +831,25 @@ export class PXEService implements PXE { public getEvents( type: EventType.Encrypted, - eventMetadata: EventMetadata, + event: { eventSelector: EventSelector; abiType: AbiType; fieldNames: string[] }, from: number, limit: number, vpks: Point[], ): Promise; public getEvents( type: EventType.Unencrypted, - eventMetadata: EventMetadata, + event: { eventSelector: EventSelector; abiType: AbiType; fieldNames: string[] }, from: number, limit: number, ): Promise; public getEvents( type: EventType, - eventMetadata: EventMetadata, + event: { eventSelector: EventSelector; abiType: AbiType; fieldNames: string[] }, from: number, limit: number, vpks: Point[] = [], ): Promise { + const eventMetadata = new EventMetadata(type, event); if (type.includes(EventType.Encrypted)) { return this.getEncryptedEvents(from, limit, eventMetadata, vpks); } From 5c5a9d1bfdec5c9948701649cd6165f74f795a0d Mon Sep 17 00:00:00 2001 From: spypsy Date: Wed, 30 Oct 2024 16:40:53 +0000 Subject: [PATCH 4/5] small fixes --- yarn-project/aztec.js/src/wallet/base_wallet.ts | 3 +-- yarn-project/circuit-types/src/logs/event_metadata.ts | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/yarn-project/aztec.js/src/wallet/base_wallet.ts b/yarn-project/aztec.js/src/wallet/base_wallet.ts index 118f3ac8429..bb4c497c60e 100644 --- a/yarn-project/aztec.js/src/wallet/base_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/base_wallet.ts @@ -214,8 +214,7 @@ export abstract class BaseWallet implements Wallet { this.getCompleteAddress().publicKeys.masterOutgoingViewingPublicKey, ], ): Promise { - const eventMetadata = new EventMetadata(type, event); - return this.pxe.getEvents(type, eventMetadata, from, limit, vpks); + return this.pxe.getEvents(type, event, from, limit, vpks); } public getL1ToL2MembershipWitness( contractAddress: AztecAddress, diff --git a/yarn-project/circuit-types/src/logs/event_metadata.ts b/yarn-project/circuit-types/src/logs/event_metadata.ts index a1bcc3385ca..9e2e44f7abf 100644 --- a/yarn-project/circuit-types/src/logs/event_metadata.ts +++ b/yarn-project/circuit-types/src/logs/event_metadata.ts @@ -25,7 +25,7 @@ export class EventMetadata { public static decodeEvent( eventSelector: EventSelector, - eventType: AbiType, + abiType: AbiType, ): (payload: L1EventPayload | UnencryptedL2Log | undefined) => T | undefined { return (payload: L1EventPayload | UnencryptedL2Log | undefined): T | undefined => { if (payload === undefined) { @@ -36,14 +36,14 @@ export class EventMetadata { if (!eventSelector.equals(payload.eventTypeId)) { return undefined; } - return decodeFromAbi([eventType], payload.event.items) as T; + return decodeFromAbi([abiType], payload.event.items) as T; } else { const items = []; for (let i = 0; i < payload.data.length; i += 32) { items.push(new Fr(payload.data.subarray(i, i + 32))); } - return decodeFromAbi([eventType], items) as T; + return decodeFromAbi([abiType], items) as T; } }; } @@ -70,7 +70,7 @@ export class EventMetadata { return new EventMetadata(EventType.Encrypted, { eventSelector: EventSelector.fromString(json.eventSelector), - abiType: json.eventType, + abiType: json.abiType, fieldNames: json.fieldNames, }); } From ad380c20e95f3218d7dc46149dedea5eaa29f60f Mon Sep 17 00:00:00 2001 From: spypsy Date: Wed, 30 Oct 2024 16:58:23 +0000 Subject: [PATCH 5/5] rm unused import --- yarn-project/aztec.js/src/wallet/base_wallet.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/yarn-project/aztec.js/src/wallet/base_wallet.ts b/yarn-project/aztec.js/src/wallet/base_wallet.ts index bb4c497c60e..2ec4fe257b8 100644 --- a/yarn-project/aztec.js/src/wallet/base_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/base_wallet.ts @@ -1,6 +1,5 @@ import { type AuthWitness, - EventMetadata, type EventType, type ExtendedNote, type GetUnencryptedLogsResponse,