Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
sklppy88 committed Jun 27, 2024
1 parent ed815a3 commit 9dbebbd
Show file tree
Hide file tree
Showing 10 changed files with 228 additions and 20 deletions.
9 changes: 4 additions & 5 deletions noir-projects/aztec-nr/aztec/src/context/public_context.nr
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,23 @@ impl PublicContext {
pub fn storage_address(self) -> AztecAddress {
storage_address()
}

pub fn fee_per_l2_gas(self) -> Field {
fee_per_l2_gas()
}

pub fn fee_per_da_gas(self) -> Field {
fee_per_da_gas()
}
/**
* Emit a log with the given event selector and message.
* @param event_selector The event selector for the log.
* @param message The message to emit in the log.
*/

pub fn emit_unencrypted_log<T, N>(&mut self, log: T) where T: Serialize<N> {
emit_unencrypted_log(Serialize::serialize(log).as_slice());
}

pub fn note_hash_exists(self, note_hash: Field, leaf_index: Field) -> bool {
note_hash_exists(note_hash, leaf_index) == 1
}

pub fn l1_to_l2_msg_exists(self, msg_hash: Field, msg_leaf_index: Field) -> bool {
l1_to_l2_msg_exists(msg_hash, msg_leaf_index) == 1
}
Expand Down
1 change: 1 addition & 0 deletions noir-projects/aztec-nr/aztec/src/lib.nr
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ mod state_vars;
mod prelude;
mod public_storage;
mod encrypted_logs;
mod unencrypted_logs;
use dep::protocol_types;
mod utils;

Expand Down
1 change: 1 addition & 0 deletions noir-projects/aztec-nr/aztec/src/unencrypted_logs.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mod unencrypted_event_emission;
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use crate::{
context::{PrivateContext, PublicContext}, event::event_interface::EventInterface,
encrypted_logs::payload::compute_encrypted_event_log, oracle::logs_traits::LensForEncryptedEvent
};
use dep::protocol_types::{address::AztecAddress, grumpkin_point::GrumpkinPoint, traits::Serialize};

fn emit_with_keys<Event, NB, MB, OB, N, M>(
context: &mut PublicContext,
event: Event,
) where Event: EventInterface<NB, MB>, Event: Serialize<N>, [Field; N]: LensForEventSelector<N, M> {
let selector = Event::get_event_type_id();

let serialized_event = event.serialize();
let mut emitted_log = [0; M];

// We put the selector in the "last" place, to avoid reading or assigning to an expression in an index
for i in 0..serialized_event.len() {
emitted_log[i] = serialized_event[i];
}

emitted_log[serialized_event.len()] = selector.to_field();

context.emit_unencrypted_log(emitted_log);
}

pub fn encode_event<Event, NB, MB, OB, N, M>(
context: &mut PublicContext,
) -> fn[(&mut PublicContext,)](Event) -> () where Event: EventInterface<NB, MB>, Event: Serialize<N>, [Field; N]: LensForEventSelector<N, M> {
| e: Event | {
emit_with_keys(
context,
e,
);
}
}

trait LensForEventSelector<N, M> {
// N = event preimage input in fields
// M = event preimage input in fields + event selector as field
fn output(self: [Field; N]) -> [Field; M];
}

impl LensForEventSelector<1, 2> for [Field; 1] {
fn output(self) -> [Field; 2] {[self[0] as Field; 2]}
}
impl LensForEventSelector<2, 3> for [Field; 2] {
fn output(self) -> [Field; 3] {[self[0] as Field; 3]}
}
impl LensForEventSelector<3, 4> for [Field; 3] {
fn output(self) -> [Field; 4] {[self[0] as Field; 4]}
}
impl LensForEventSelector<4, 5> for [Field; 4] {
fn output(self) -> [Field; 5] {[self[0] as Field; 5]}
}
impl LensForEventSelector<5, 6> for [Field; 5] {
fn output(self) -> [Field; 6] {[self[0] as Field; 6]}
}
impl LensForEventSelector<6, 7> for [Field; 6] {
fn output(self) -> [Field; 7] {[self[0] as Field; 7]}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ contract TestLog {
use dep::aztec::encrypted_logs::incoming_body::EncryptedLogIncomingBody;
use dep::aztec::event::event_interface::EventInterface;
use dep::aztec::encrypted_logs::encrypted_event_emission::{encode_and_encrypt_event, encode_and_encrypt_event_with_keys};
use dep::aztec::unencrypted_logs::unencrypted_event_emission::{encode_event};

#[aztec(event)]
struct ExampleEvent0 {
Expand Down Expand Up @@ -64,4 +65,15 @@ contract TestLog {
)
);
}

#[aztec(public)]
fn emit_unencrypted_events(preimages: [Field; 4]) {
let event0 = ExampleEvent0 { value0: preimages[0], value1: preimages[1] };

event0.emit(encode_event(&mut context));

let event1 = ExampleEvent1 { value2: preimages[2], value3: preimages[3] };

event1.emit(encode_event(&mut context));
}
}
1 change: 1 addition & 0 deletions yarn-project/aztec.js/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export {
EncryptedLogHeader,
EncryptedNoteLogIncomingBody,
EncryptedLogOutgoingBody,
EventType,
ExtendedNote,
FunctionCall,
GrumpkinPrivateKey,
Expand Down
8 changes: 5 additions & 3 deletions yarn-project/aztec.js/src/wallet/base_wallet.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
type AuthWitness,
type EventMetadata,
type EventType,
type ExtendedNote,
type GetUnencryptedLogsResponse,
type IncomingNotesFilter,
Expand Down Expand Up @@ -182,11 +183,12 @@ export abstract class BaseWallet implements Wallet {
return this.pxe.getPXEInfo();
}
getEvents<T>(
type: EventType,
eventMetadata: EventMetadata<T>,
from: number,
limit: number,
eventMetadata: EventMetadata<T>,
ivpk: Point = this.getCompleteAddress().publicKeys.masterIncomingViewingPublicKey,
): Promise<T[]> {
return this.pxe.getEvents(from, limit, eventMetadata, ivpk);
) {
return this.pxe.getEvents(type, eventMetadata, from, limit, ivpk);
}
}
23 changes: 19 additions & 4 deletions yarn-project/circuit-types/src/interfaces/pxe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -381,14 +381,21 @@ export interface PXE {
isContractPubliclyDeployed(address: AztecAddress): Promise<boolean>;

/**
* Returns the events of a specified type.
* 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 from - The block number to search from.
* @param limit - The amount of blocks to search.
* @param eventMetadata - Identifier of the event. This should be the class generated from the contract. e.g. Contract.events.Event
* @param ivpk - The incoming viewing public key that corresponds to the incoming viewing secret key that can decrypt the log.
* @param ivpk - (Used for encrypted logs only) The incoming viewing public key that corresponds to the incoming viewing secret key that can decrypt the log.
* @returns - The deserialized events.
*/
getEvents<T>(from: number, limit: number, eventMetadata: EventMetadata<T>, ivpk: Point): Promise<T[]>;
getEvents<T>(
type: EventType,
eventMetadata: EventMetadata<T>,
from: number,
limit: number,
ivpk: Point,
): Promise<T[]>;
}
// docs:end:pxe-interface

Expand All @@ -401,6 +408,14 @@ export interface EventMetadata<T> {
fieldNames: string[];
}

/**
* This is used in getting events via the filter
*/
export enum EventType {
Encrypted = 'Encrypted',
Unencrypted = 'Unencrypted',
}

/**
* Provides basic information about the running PXE.
*/
Expand Down
57 changes: 52 additions & 5 deletions yarn-project/end-to-end/src/e2e_event_logs.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { type AccountWalletWithSecretKey, type AztecNode, Fr, L1EventPayload, TaggedLog } from '@aztec/aztec.js';
import {
type AccountWalletWithSecretKey,
type AztecNode,
EventType,
Fr,
L1EventPayload,
TaggedLog,
} from '@aztec/aztec.js';
import { deriveMasterIncomingViewingSecretKey } from '@aztec/circuits.js';
import { EventSelector } from '@aztec/foundation/abi';
import { makeTuple } from '@aztec/foundation/array';
Expand Down Expand Up @@ -31,7 +38,7 @@ describe('Logs', () => {
afterAll(() => teardown());

describe('functionality around emitting an encrypted log', () => {
it('emits multiple events as encrypted logs and decodes them', async () => {
it('emits multiple events as encrypted logs and decodes a single one manually', async () => {
const randomness = makeTuple(2, Fr.random);
const preimage = makeTuple(4, Fr.random);

Expand Down Expand Up @@ -89,7 +96,7 @@ describe('Logs', () => {
expect(badEvent1).toBe(undefined);
});

it('emits multiple events as encrypted logs and decodes them', async () => {
it('emits multiple events as unencrypted logs and decodes them', async () => {
const randomness = makeTuple(5, makeTuple.bind(undefined, 2, Fr.random)) as Tuple<Tuple<Fr, 2>, 5>;
const preimage = makeTuple(5, makeTuple.bind(undefined, 4, Fr.random)) as Tuple<Tuple<Fr, 4>, 5>;

Expand All @@ -103,15 +110,17 @@ describe('Logs', () => {
const lastTx = await testLogContract.methods.emit_encrypted_events(randomness[++i], preimage[i]).send().wait();

const collectedEvent0s = await wallets[0].getEvents(
EventType.Encrypted,
TestLogContract.events.ExampleEvent0,
firstTx.blockNumber!,
lastTx.blockNumber! - firstTx.blockNumber! + 1,
TestLogContract.events.ExampleEvent0,
);

const collectedEvent1s = await wallets[0].getEvents(
EventType.Encrypted,
TestLogContract.events.ExampleEvent1,
firstTx.blockNumber!,
lastTx.blockNumber! - firstTx.blockNumber! + 1,
TestLogContract.events.ExampleEvent1,
// This function can also be called specifying the incoming viewing public key associated with the encrypted event.
wallets[0].getCompleteAddress().publicKeys.masterIncomingViewingPublicKey,
);
Expand All @@ -129,5 +138,43 @@ describe('Logs', () => {
preimage.map(preimage => ({ value2: preimage[2], value3: preimage[3] })).sort(exampleEvent1Sort),
);
});

it('emits multiple events as encrypted logs and decodes them', async () => {
const preimage = makeTuple(5, makeTuple.bind(undefined, 4, Fr.random)) as Tuple<Tuple<Fr, 4>, 5>;

let i = 0;
const firstTx = await testLogContract.methods.emit_unencrypted_events(preimage[i]).send().wait();
await Promise.all(
[...new Array(3)].map(() => testLogContract.methods.emit_unencrypted_events(preimage[++i]).send().wait()),
);
const lastTx = await testLogContract.methods.emit_unencrypted_events(preimage[++i]).send().wait();

const collectedEvent0s = await wallets[0].getEvents(
EventType.Unencrypted,
TestLogContract.events.ExampleEvent0,
firstTx.blockNumber!,
lastTx.blockNumber! - firstTx.blockNumber! + 1,
);

const collectedEvent1s = await wallets[0].getEvents(
EventType.Unencrypted,
TestLogContract.events.ExampleEvent1,
firstTx.blockNumber!,
lastTx.blockNumber! - firstTx.blockNumber! + 1,
);

expect(collectedEvent0s.length).toBe(5);
expect(collectedEvent1s.length).toBe(5);

const exampleEvent0Sort = (a: ExampleEvent0, b: ExampleEvent0) => (a.value0 > b.value0 ? 1 : -1);
expect(collectedEvent0s.sort(exampleEvent0Sort)).toStrictEqual(
preimage.map(preimage => ({ value0: preimage[0], value1: preimage[1] })).sort(exampleEvent0Sort),
);

const exampleEvent1Sort = (a: ExampleEvent1, b: ExampleEvent1) => (a.value2 > b.value2 ? 1 : -1);
expect(collectedEvent1s.sort(exampleEvent1Sort)).toStrictEqual(
preimage.map(preimage => ({ value2: preimage[2], value3: preimage[3] })).sort(exampleEvent1Sort),
);
});
});
});
76 changes: 73 additions & 3 deletions yarn-project/pxe/src/pxe_service/pxe_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
EncryptedNoteTxL2Logs,
EncryptedTxL2Logs,
type EventMetadata,
EventType,
ExtendedNote,
type FunctionCall,
type GetUnencryptedLogsResponse,
Expand Down Expand Up @@ -35,8 +36,14 @@ import {
getContractClassFromArtifact,
} from '@aztec/circuits.js';
import { computeNoteHashNonce, siloNullifier } from '@aztec/circuits.js/hash';
import { type ContractArtifact, type DecodedReturn, FunctionSelector, encodeArguments } from '@aztec/foundation/abi';
import { type Fq, Fr, type Point } from '@aztec/foundation/fields';
import {
type ContractArtifact,
type DecodedReturn,
EventSelector,
FunctionSelector,
encodeArguments,
} from '@aztec/foundation/abi';
import { type Fq, Fr, Point } from '@aztec/foundation/fields';
import { SerialQueue } from '@aztec/foundation/fifo';
import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log';
import { type KeyStore } from '@aztec/key-store';
Expand Down Expand Up @@ -834,7 +841,34 @@ export class PXEService implements PXE {
return !!(await this.node.getContract(address));
}

public async getEvents<T>(from: number, limit: number, eventMetadata: EventMetadata<T>, ivpk: Point): Promise<T[]> {
public getEvents<T>(
type: EventType.Encrypted,
eventMetadata: EventMetadata<T>,
from: number,
limit: number,
ivpk: Point,
): Promise<T[]>;
public getEvents<T>(
type: EventType.Unencrypted,
eventMetadata: EventMetadata<T>,
from: number,
limit: number,
): Promise<T[]>;
public getEvents<T>(
type: EventType,
eventMetadata: EventMetadata<T>,
from: number,
limit: number,
ivpk: Point = Point.ZERO,
): Promise<T[]> {
if (type.includes(EventType.Encrypted)) {
return this.getEncryptedEvents(from, limit, eventMetadata, ivpk);
}

return this.getUnencryptedEvents(from, limit, eventMetadata);
}

async getEncryptedEvents<T>(from: number, limit: number, eventMetadata: EventMetadata<T>, ivpk: Point): Promise<T[]> {
const blocks = await this.node.getBlocks(from, limit);

const txEffects = blocks.flatMap(block => block.body.txEffects);
Expand Down Expand Up @@ -874,4 +908,40 @@ export class PXEService implements PXE {

return decodedEvents;
}

async getUnencryptedEvents<T>(from: number, limit: number, eventMetadata: EventMetadata<T>): Promise<T[]> {
const { logs: unencryptedLogs } = await this.node.getUnencryptedLogs({
fromBlock: from,
toBlock: from + limit,
});

const decodedEvents = unencryptedLogs
.map(unencryptedLog => {
const unencryptedLogBuf = unencryptedLog.log.data;
if (
!EventSelector.fromBuffer(unencryptedLogBuf.subarray(unencryptedLogBuf.byteLength - 4)).equals(
eventMetadata.eventSelector,
)
) {
return undefined;
}

if (unencryptedLogBuf.byteLength !== eventMetadata.fieldNames.length * 32 + 32) {
throw new Error(
'Something is weird here, we have matching FunctionSelectors, but the actual payload has mismatched length',
);
}

return eventMetadata.fieldNames.reduce(
(acc, curr, i) => ({
...acc,
[curr]: new Fr(unencryptedLogBuf.subarray(i * 32, i * 32 + 32)),
}),
{} as T,
);
})
.filter(unencryptedLog => unencryptedLog !== undefined) as T[];

return decodedEvents;
}
}

0 comments on commit 9dbebbd

Please sign in to comment.