Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 3 additions & 17 deletions noir-projects/aztec-nr/aztec/src/macros/events.nr
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ pub comptime mut global EVENT_SELECTORS: CHashMap<Field, Quoted> = CHashMap::new

comptime fn generate_event_interface_and_get_selector(s: TypeDefinition) -> (Quoted, Field) {
let name = s.name();
let typ = s.as_type();
let event_type_name: str<_> = f"{name}".as_quoted_str!();
let max_event_serialized_len = crate::messages::logs::event::MAX_EVENT_SERIALIZED_LEN;

let event_selector = compute_struct_selector(s, quote { crate::event::EventSelector::from_signature });

Expand All @@ -26,18 +23,6 @@ comptime fn generate_event_interface_and_get_selector(s: TypeDefinition) -> (Quo
quote {
impl aztec::event::event_interface::EventInterface for $name {
fn get_event_type_id() -> aztec::event::EventSelector {
// This static assertion ensures the event's serialized length doesn't exceed the maximum
// allowed size. While this check would ideally live in the Serialize trait implementation, we
// place it here since this function is always generated by our macros and the Serialize trait
// implementation is not.
//
// Note: We set the event type name and max serialized length as local variables because
// injecting them directly into the error message doesn't work.
let event_type_name = $event_type_name;
let max_event_serialized_len: u32 = $max_event_serialized_len;
let event_serialized_len = <$typ as aztec::protocol::traits::Serialize>::N;
std::static_assert(event_serialized_len <= $max_event_serialized_len, f"{event_type_name} has a serialized length of {event_serialized_len} fields, which exceeds the maximum allowed length of {max_event_serialized_len} fields. See https://docs.aztec.network/errors/5");

$from_field($event_selector)
}
}
Expand All @@ -63,8 +48,9 @@ comptime fn register_event_selector(event_selector: Field, event_name: Quoted) {
///
/// ## Requirements
///
/// The event struct must not exceed
/// [`MAX_EVENT_SERIALIZED_LEN`](crate::messages::logs::event::MAX_EVENT_SERIALIZED_LEN) when serialized.
/// Events can be emitted both privately and publicly. Public emission imposes no requirements, but for an event to be
/// emittable privately its serialization length must not exceeed
/// [`MAX_EVENT_SERIALIZED_LEN`](crate::messages::logs::event::MAX_EVENT_SERIALIZED_LEN).
pub comptime fn event(s: TypeDefinition) -> Quoted {
let (event_interface_impl, event_selector) = generate_event_interface_and_get_selector(s);
register_event_selector(event_selector, s.name());
Expand Down
5 changes: 5 additions & 0 deletions noir-projects/aztec-nr/aztec/src/messages/logs/event.nr
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ pub fn encode_private_event_message<Event>(
where
Event: EventInterface + Serialize,
{
std::static_assert(
<Event as Serialize>::N <= MAX_EVENT_SERIALIZED_LEN,
"event's serialized length exceeds the maximum allowed for private events",
);

// We use `Serialize` because we want for events to be processable by off-chain actors, e.g. block explorers,
// wallets and apps, without having to rely on contract invocation. If we used `Packable` we'd need to call utility
// functions in order to unpack events, which would introduce a level of complexity we don't currently think is
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
InvalidEvent has a serialized length of 11 fields, which exceeds the maximum allowed length of 10 fields. See https://docs.aztec.network/errors/5
event's serialized length exceeds the maximum allowed for private events
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ use aztec::macros::aztec;
mod invalid_event;

#[aztec]
pub contract InvalidEventContract {
contract InvalidEventContract {
use crate::invalid_event::InvalidEvent;
use aztec::{event::event_interface::EventInterface, macros::functions::external};
use aztec::{macros::functions::external, messages::message_delivery::MessageDelivery};

// We have here this function in order for the static_assert in `get_event_type_id` to get triggered.
// Emitting an oversized event privately should fail at compile time because its serialized length exceeds
// MAX_EVENT_SERIALIZED_LEN.
#[external("private")]
fn trigger_event_check() {
let _ = InvalidEvent::get_event_type_id();
self.emit(InvalidEvent {}).deliver_to(
self.msg_sender(),
MessageDelivery.ONCHAIN_UNCONSTRAINED,
);
}
}
1 change: 1 addition & 0 deletions noir-projects/noir-contracts/Nargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ members = [
"contracts/test/counter/counter_contract",
"contracts/test/custom_message_contract",
"contracts/test/event_only_contract",
"contracts/test/large_public_event_contract",
"contracts/test/import_test_contract",
"contracts/test/init_test_contract",
"contracts/test/invalid_account_contract",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "large_public_event_contract"
authors = [""]
compiler_version = ">=0.25.0"
type = "contract"

[dependencies]
aztec = { path = "../../../../aztec-nr/aztec" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use aztec::macros::aztec;

/// Tests that events with a serialized length exceeding [`MAX_EVENT_SERIALIZED_LEN`] can be emitted publicly.
/// The private emission size limit does not apply to public logs.
#[aztec]
contract LargePublicEvent {
use aztec::{
macros::{events::event, functions::external},
messages::logs::event::MAX_EVENT_SERIALIZED_LEN,
};

#[event]
pub struct LargeEvent {
data: [Field; MAX_EVENT_SERIALIZED_LEN + 1],
}

#[external("public")]
fn emit_large_event(data: [Field; MAX_EVENT_SERIALIZED_LEN + 1]) {
self.emit(LargeEvent { data });
}
}
50 changes: 50 additions & 0 deletions yarn-project/end-to-end/src/e2e_large_public_event.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { getPublicEvents } from '@aztec/aztec.js/events';
import { Fr } from '@aztec/aztec.js/fields';
import type { AztecNode } from '@aztec/aztec.js/node';
import type { Wallet } from '@aztec/aztec.js/wallet';
import { BlockNumber } from '@aztec/foundation/branded-types';
import { type LargeEvent, LargePublicEventContract } from '@aztec/noir-test-contracts.js/LargePublicEvent';
import type { AztecAddress } from '@aztec/stdlib/aztec-address';

import { jest } from '@jest/globals';

import { setup } from './fixtures/utils.js';

const TIMEOUT = 120_000;

/// Tests that events exceeding MAX_EVENT_SERIALIZED_LEN can be emitted publicly.
describe('LargePublicEvent', () => {
let contract: LargePublicEventContract;
jest.setTimeout(TIMEOUT);

let wallet: Wallet;
let aztecNode: AztecNode;
let accountAddress: AztecAddress;
let teardown: () => Promise<void>;

beforeAll(async () => {
({
teardown,
wallet,
aztecNode,
accounts: [accountAddress],
} = await setup(1));
({ contract } = await LargePublicEventContract.deploy(wallet).send({ from: accountAddress }));
});

afterAll(() => teardown());

it('emits and retrieves a public event with more than MAX_EVENT_SERIALIZED_LEN fields', async () => {
const data = Array.from({ length: 11 }, () => Fr.random());

const { receipt: tx } = await contract.methods.emit_large_event(data).send({ from: accountAddress });

const { events } = await getPublicEvents<LargeEvent>(aztecNode, LargePublicEventContract.events.LargeEvent, {
fromBlock: BlockNumber(tx.blockNumber!),
toBlock: BlockNumber(tx.blockNumber! + 1),
});

expect(events.length).toBe(1);
expect(events[0].event.data).toEqual(data.map(f => f.toBigInt()));
});
});
Loading