Skip to content

Commit

Permalink
feat: processing outgoing (#6766)
Browse files Browse the repository at this point in the history
  • Loading branch information
benesjan authored Jun 5, 2024
1 parent f43384d commit 4da66fd
Show file tree
Hide file tree
Showing 25 changed files with 614 additions and 370 deletions.
4 changes: 2 additions & 2 deletions yarn-project/aztec.js/src/utils/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ export async function waitForAccountSynch(
address: CompleteAddress,
{ interval, timeout }: WaitOpts = DefaultWaitOpts,
): Promise<void> {
const publicKey = address.publicKeys.masterIncomingViewingPublicKey.toString();
const accountAddress = address.address.toString();
await retryUntil(
async () => {
const status = await pxe.getSyncStatus();
const accountSynchedToBlock = status.notes[publicKey];
const accountSynchedToBlock = status.notes[accountAddress];
if (typeof accountSynchedToBlock === 'undefined') {
return false;
} else {
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/circuit-types/src/interfaces/sync-status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
export type SyncStatus = {
/** Up to which block has been synched for blocks and txs. */
blocks: number;
/** Up to which block has been synched for notes, indexed by each public key being monitored. */
/** Up to which block has been synched for notes, indexed by each account address being monitored. */
notes: Record<string, number>;
};
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,11 @@ export class L1NotePayload {

/**
* Create a random L1NotePayload object (useful for testing purposes).
* @param contract - The address of a contract the note was emitted from.
* @returns A random L1NotePayload object.
*/
static random() {
return new L1NotePayload(Note.random(), AztecAddress.random(), Fr.random(), Fr.random());
static random(contract = AztecAddress.random()) {
return new L1NotePayload(Note.random(), contract, Fr.random(), Fr.random());
}

/**
Expand Down Expand Up @@ -208,4 +209,13 @@ export class L1NotePayload {
incomingBody.noteTypeId,
);
}

public equals(other: L1NotePayload) {
return (
this.note.equals(other.note) &&
this.contractAddress.equals(other.contractAddress) &&
this.storageSlot.equals(other.storageSlot) &&
this.noteTypeId.equals(other.noteTypeId)
);
}
}
4 changes: 4 additions & 0 deletions yarn-project/circuit-types/src/logs/l1_note_payload/note.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,8 @@ export class Note extends Vector<Fr> {
get length() {
return this.items.length;
}

equals(other: Note) {
return this.items.every((item, index) => item.equals(other.items[index]));
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import {
type AztecAddress,
type GrumpkinPrivateKey,
type KeyValidationRequest,
type PublicKey,
} from '@aztec/circuits.js';
import { AztecAddress, type GrumpkinPrivateKey, type KeyValidationRequest, type PublicKey } from '@aztec/circuits.js';
import { Fr } from '@aztec/foundation/fields';
import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';

Expand Down Expand Up @@ -43,8 +38,13 @@ export class TaggedNote {
return serializeToBuffer(this.incomingTag, this.outgoingTag, this.notePayload);
}

static random(): TaggedNote {
return new TaggedNote(L1NotePayload.random());
/**
* Create a random TaggedNote (useful for testing purposes).
* @param contract - The address of a contract the note was emitted from.
* @returns A random TaggedNote object.
*/
static random(contract = AztecAddress.random()): TaggedNote {
return new TaggedNote(L1NotePayload.random(contract));
}

public encrypt(
Expand Down
10 changes: 6 additions & 4 deletions yarn-project/circuit-types/src/stats/stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,8 @@ export type L2BlockHandledStats = {
export type NoteProcessorCaughtUpStats = {
/** Name of the event. */
eventName: 'note-processor-caught-up';
/** Public key of the note processor. */
publicKey: string;
/** Account the note processor belongs to. */
account: string;
/** Total time to catch up with the tip of the chain from scratch in ms. */
duration: number;
/** Size of the notes db. */
Expand All @@ -175,8 +175,10 @@ export type NoteProcessorStats = {
seen: number;
/** How many notes had decryption deferred due to a missing contract */
deferred: number;
/** How many notes were successfully decrypted. */
decrypted: number;
/** How many incoming notes were successfully decrypted. */
decryptedIncoming: number;
/** How many outgoing notes were successfully decrypted. */
decryptedOutgoing: number;
/** How many notes failed processing. */
failed: number;
/** How many blocks were spanned. */
Expand Down
6 changes: 2 additions & 4 deletions yarn-project/end-to-end/src/benchmarks/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,7 @@ export async function waitNewPXESynced(
*/
export async function waitRegisteredAccountSynced(pxe: PXE, secretKey: Fr, partialAddress: PartialAddress) {
const l2Block = await pxe.getBlockNumber();
const masterIncomingViewingPublicKey = (await pxe.registerAccount(secretKey, partialAddress)).publicKeys
.masterIncomingViewingPublicKey;
const isAccountSynced = async () =>
(await pxe.getSyncStatus()).notes[masterIncomingViewingPublicKey.toString()] === l2Block;
const accountAddress = (await pxe.registerAccount(secretKey, partialAddress)).address;
const isAccountSynced = async () => (await pxe.getSyncStatus()).notes[accountAddress.toString()] === l2Block;
await retryUntil(isAccountSynced, 'pxe-notes-sync');
}
Original file line number Diff line number Diff line change
Expand Up @@ -306,11 +306,10 @@ describe('e2e_pending_note_hashes_contract', () => {
// Then emit another note log with the same counter as the one above, but with value 5
await deployedContract.methods.test_emit_bad_note_log(owner, outgoingViewer).send().wait();

const mIVPK = wallet.getCompleteAddress().publicKeys.masterIncomingViewingPublicKey.toString();
const syncStats = await wallet.getSyncStats();
// Expect two decryptable note logs to be emitted
expect(syncStats[mIVPK].decrypted).toEqual(2);
// Expect two incoming decryptable note logs to be emitted
expect(syncStats[owner.toString()].decryptedIncoming).toEqual(2);
// Expect one note log to be dropped
expect(syncStats[mIVPK].failed).toEqual(1);
expect(syncStats[owner.toString()].failed).toEqual(1);
});
});
30 changes: 0 additions & 30 deletions yarn-project/key-store/src/key_store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,36 +306,6 @@ export class KeyStore {
return Promise.resolve(skM);
}

/**
* Retrieves the master incoming viewing secret key (ivsk_m) corresponding to the specified master incoming viewing
* public key (Ivpk_m).
* @throws If the provided public key is not associated with any of the registered accounts.
* @param masterIncomingViewingPublicKey - The master nullifier public key to get secret key for.
* @returns A Promise that resolves to the master nullifier secret key.
* @dev Used when feeding the master nullifier secret key to the kernel circuit for nullifier keys verification.
*/
public getMasterIncomingViewingSecretKeyForPublicKey(
masterIncomingViewingPublicKey: PublicKey,
): Promise<GrumpkinPrivateKey> {
// We iterate over the map keys to find the account address that corresponds to the provided public key
for (const [key, value] of this.#keys.entries()) {
if (value.equals(masterIncomingViewingPublicKey.toBuffer())) {
// We extract the account address from the map key
const account = key.split('-')[0];
// We fetch the secret key and return it
const masterIncomingViewingSecretKeyBuffer = this.#keys.get(`${account.toString()}-ivsk_m`);
if (!masterIncomingViewingSecretKeyBuffer) {
throw new Error(`Could not find master incoming viewing secret key for account ${account.toString()}`);
}
return Promise.resolve(GrumpkinScalar.fromBuffer(masterIncomingViewingSecretKeyBuffer));
}
}

throw new Error(
`Could not find master incoming viewing secret key for public key ${masterIncomingViewingPublicKey.toString()}`,
);
}

/**
* Rotates the master nullifier key for the specified account.
*
Expand Down
4 changes: 2 additions & 2 deletions yarn-project/pxe/src/database/deferred_note_dao.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { randomInt } from '@aztec/foundation/crypto';
import { DeferredNoteDao } from './deferred_note_dao.js';

export const randomDeferredNoteDao = ({
publicKey = Point.random(),
ivpkM = Point.random(),
note = Note.random(),
contractAddress = AztecAddress.random(),
txHash = randomTxHash(),
Expand All @@ -15,7 +15,7 @@ export const randomDeferredNoteDao = ({
dataStartIndexForTx = randomInt(100),
}: Partial<DeferredNoteDao> = {}) => {
return new DeferredNoteDao(
publicKey,
ivpkM,
note,
contractAddress,
storageSlot,
Expand Down
9 changes: 6 additions & 3 deletions yarn-project/pxe/src/database/deferred_note_dao.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';
*/
export class DeferredNoteDao {
constructor(
/** The public key associated with this note */
public publicKey: PublicKey,
/**
* The incoming viewing public key the note was encrypted with.
* @dev Will never be ovpkM because there are no deferred notes for outgoing.
*/
public ivpkM: PublicKey,
/** The note as emitted from the Noir contract. */
public note: Note,
/** The contract address this note is created in. */
Expand All @@ -29,7 +32,7 @@ export class DeferredNoteDao {

toBuffer(): Buffer {
return serializeToBuffer(
this.publicKey,
this.ivpkM,
this.note,
this.contractAddress,
this.storageSlot,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Note, randomTxHash } from '@aztec/circuit-types';
import { AztecAddress, Fr, Point } from '@aztec/circuits.js';

import { NoteDao } from './note_dao.js';
import { IncomingNoteDao } from './incoming_note_dao.js';

export const randomNoteDao = ({
export const randomIncomingNoteDao = ({
note = Note.random(),
contractAddress = AztecAddress.random(),
txHash = randomTxHash(),
Expand All @@ -13,9 +13,9 @@ export const randomNoteDao = ({
innerNoteHash = Fr.random(),
siloedNullifier = Fr.random(),
index = Fr.random().toBigInt(),
publicKey = Point.random(),
}: Partial<NoteDao> = {}) => {
return new NoteDao(
ivpkM = Point.random(),
}: Partial<IncomingNoteDao> = {}) => {
return new IncomingNoteDao(
note,
contractAddress,
storageSlot,
Expand All @@ -25,14 +25,14 @@ export const randomNoteDao = ({
innerNoteHash,
siloedNullifier,
index,
publicKey,
ivpkM,
);
};

describe('Note DAO', () => {
describe('Incoming Note DAO', () => {
it('convert to and from buffer', () => {
const note = randomNoteDao();
const note = randomIncomingNoteDao();
const buf = note.toBuffer();
expect(NoteDao.fromBuffer(buf)).toEqual(note);
expect(IncomingNoteDao.fromBuffer(buf)).toEqual(note);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';
import { type NoteData } from '@aztec/simulator';

/**
* A note with contextual data.
* A note with contextual data which was decrypted as incoming.
*/
export class NoteDao implements NoteData {
export class IncomingNoteDao implements NoteData {
constructor(
/** The note as emitted from the Noir contract. */
public note: Note,
Expand All @@ -31,7 +31,7 @@ export class NoteDao implements NoteData {
/** The location of the relevant note in the note hash tree. */
public index: bigint,
/** The public key with which the note was encrypted. */
public publicKey: PublicKey,
public ivpkM: PublicKey,
) {}

toBuffer(): Buffer {
Expand All @@ -45,7 +45,7 @@ export class NoteDao implements NoteData {
this.innerNoteHash,
this.siloedNullifier,
this.index,
this.publicKey,
this.ivpkM,
]);
}
static fromBuffer(buffer: Buffer | BufferReader) {
Expand All @@ -62,7 +62,7 @@ export class NoteDao implements NoteData {
const index = toBigIntBE(reader.readBytes(32));
const publicKey = Point.fromBuffer(reader);

return new NoteDao(
return new IncomingNoteDao(
note,
contractAddress,
storageSlot,
Expand All @@ -82,7 +82,7 @@ export class NoteDao implements NoteData {

static fromString(str: string) {
const hex = str.replace(/^0x/, '');
return NoteDao.fromBuffer(Buffer.from(hex, 'hex'));
return IncomingNoteDao.fromBuffer(Buffer.from(hex, 'hex'));
}

/**
Expand Down
Loading

0 comments on commit 4da66fd

Please sign in to comment.