Skip to content

Commit

Permalink
feat: storing outgoing + API for outgoing (#7022)
Browse files Browse the repository at this point in the history
  • Loading branch information
benesjan authored Jun 17, 2024
1 parent 024e85f commit 8281ec6
Show file tree
Hide file tree
Showing 33 changed files with 546 additions and 182 deletions.
4 changes: 4 additions & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@
"initialise",
"interruptible",
"isequal",
"ivpk",
"ivsk",
"jsons",
"Kademlia",
"keccak",
Expand Down Expand Up @@ -170,6 +172,8 @@
"otterscan",
"outdir",
"overlayfs",
"ovpk",
"ovsk",
"pako",
"Palla",
"parallelizable",
Expand Down
8 changes: 5 additions & 3 deletions yarn-project/aztec.js/src/contract/sent_tx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,15 @@ export class SentTx {
if (opts?.debug) {
const txHash = await this.getTxHash();
const tx = (await this.pxe.getTxEffect(txHash))!;
const visibleNotes = await this.pxe.getNotes({ txHash });
const visibleIncomingNotes = await this.pxe.getIncomingNotes({ txHash });
const visibleOutgoingNotes = await this.pxe.getOutgoingNotes({ txHash });
receipt.debugInfo = {
noteHashes: tx.noteHashes,
nullifiers: tx.nullifiers,
publicDataWrites: tx.publicDataWrites,
l2ToL1Msgs: tx.l2ToL1Msgs,
visibleNotes,
visibleIncomingNotes,
visibleOutgoingNotes,
};
}
return receipt;
Expand All @@ -109,7 +111,7 @@ export class SentTx {
*/
public async getVisibleNotes(): Promise<ExtendedNote[]> {
await this.wait();
return this.pxe.getNotes({ txHash: await this.getTxHash() });
return this.pxe.getIncomingNotes({ txHash: await this.getTxHash() });
}

protected async waitForReceipt(opts?: WaitOpts): Promise<TxReceipt> {
Expand Down
6 changes: 5 additions & 1 deletion yarn-project/aztec.js/src/utils/cheat_codes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,11 @@ export class AztecCheatCodes {
* @returns The notes stored at the given slot
*/
public async loadPrivate(owner: AztecAddress, contract: AztecAddress, slot: Fr | bigint): Promise<Note[]> {
const extendedNotes = await this.pxe.getNotes({ owner, contractAddress: contract, storageSlot: new Fr(slot) });
const extendedNotes = await this.pxe.getIncomingNotes({
owner,
contractAddress: contract,
storageSlot: new Fr(slot),
});
return extendedNotes.map(extendedNote => extendedNote.note);
}
}
10 changes: 7 additions & 3 deletions yarn-project/aztec.js/src/wallet/base_wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import {
type ExtendedNote,
type FunctionCall,
type GetUnencryptedLogsResponse,
type IncomingNotesFilter,
type L2Block,
type LogFilter,
type NoteFilter,
type OutgoingNotesFilter,
type PXE,
type PXEInfo,
type SimulatedTx,
Expand Down Expand Up @@ -129,8 +130,11 @@ export abstract class BaseWallet implements Wallet {
getTxReceipt(txHash: TxHash): Promise<TxReceipt> {
return this.pxe.getTxReceipt(txHash);
}
getNotes(filter: NoteFilter): Promise<ExtendedNote[]> {
return this.pxe.getNotes(filter);
getIncomingNotes(filter: IncomingNotesFilter): Promise<ExtendedNote[]> {
return this.pxe.getIncomingNotes(filter);
}
getOutgoingNotes(filter: OutgoingNotesFilter): Promise<ExtendedNote[]> {
return this.pxe.getOutgoingNotes(filter);
}
// TODO(#4956): Un-expose this
getNoteNonces(note: ExtendedNote): Promise<Fr[]> {
Expand Down
15 changes: 11 additions & 4 deletions yarn-project/circuit-types/src/interfaces/pxe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import { type NodeInfo } from '@aztec/types/interfaces';
import { type AuthWitness } from '../auth_witness.js';
import { type L2Block } from '../l2_block.js';
import { type GetUnencryptedLogsResponse, type L1EventPayload, type LogFilter } from '../logs/index.js';
import { type ExtendedNote } from '../notes/index.js';
import { type NoteFilter } from '../notes/note_filter.js';
import { type IncomingNotesFilter } from '../notes/incoming_notes_filter.js';
import { type ExtendedNote, type OutgoingNotesFilter } from '../notes/index.js';
import { type NoteProcessorStats } from '../stats/stats.js';
import { type SimulatedTx, type Tx, type TxHash, type TxReceipt } from '../tx/index.js';
import { type TxEffect } from '../tx_effect.js';
Expand Down Expand Up @@ -224,11 +224,18 @@ export interface PXE {
getPublicStorageAt(contract: AztecAddress, slot: Fr): Promise<Fr>;

/**
* Gets notes of accounts registered in this PXE based on the provided filter.
* Gets incoming notes of accounts registered in this PXE based on the provided filter.
* @param filter - The filter to apply to the notes.
* @returns The requested notes.
*/
getNotes(filter: NoteFilter): Promise<ExtendedNote[]>;
getIncomingNotes(filter: IncomingNotesFilter): Promise<ExtendedNote[]>;

/**
* Gets outgoing notes of accounts registered in this PXE based on the provided filter.
* @param filter - The filter to apply to the notes.
* @returns The requested notes.
*/
getOutgoingNotes(filter: OutgoingNotesFilter): Promise<ExtendedNote[]>;

/**
* Finds the nonce(s) for a given note.
Expand Down
11 changes: 11 additions & 0 deletions yarn-project/circuit-types/src/notes/comparator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* The comparator to use to compare.
*/
export enum Comparator {
EQ = 1,
NEQ = 2,
LT = 3,
LTE = 4,
GT = 5,
GTE = 6,
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
import { type AztecAddress, type Fr } from '@aztec/circuits.js';

import { type TxHash } from '../tx/tx_hash.js';
import { type NoteStatus } from './note_status.js';

/**
* The status of notes to retrieve.
* A filter used to fetch incoming notes.
* @remarks This filter is applied as an intersection of all its params.
*/
export enum NoteStatus {
ACTIVE = 1,
ACTIVE_OR_NULLIFIED = 2,
// TODO 4217: add 'NULLIFIED'
}

/**
* A filter used to fetch Notes.
* @remarks This filter is applied as an intersection of all it's params.
*/
export type NoteFilter = {
export type IncomingNotesFilter = {
/** Hash of a transaction from which to fetch the notes. */
txHash?: TxHash;
/** The contract address the note belongs to. */
Expand All @@ -29,15 +21,3 @@ export type NoteFilter = {
/** The siloed nullifier for the note. */
siloedNullifier?: Fr;
};

/**
* The comparator to use to compare.
*/
export enum Comparator {
EQ = 1,
NEQ = 2,
LT = 3,
LTE = 4,
GT = 5,
GTE = 6,
}
5 changes: 4 additions & 1 deletion yarn-project/circuit-types/src/notes/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
export * from './note_filter.js';
export * from './comparator.js';
export * from './extended_note.js';
export * from './incoming_notes_filter.js';
export * from './note_status.js';
export * from './outgoing_notes_filter.js';
8 changes: 8 additions & 0 deletions yarn-project/circuit-types/src/notes/note_status.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* The status of notes to retrieve.
*/
export enum NoteStatus {
ACTIVE = 1,
ACTIVE_OR_NULLIFIED = 2,
// TODO 4217: add 'NULLIFIED'
}
18 changes: 18 additions & 0 deletions yarn-project/circuit-types/src/notes/outgoing_notes_filter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { type AztecAddress, type Fr } from '@aztec/circuits.js';

import { type TxHash } from '../tx/tx_hash.js';

/**
* A filter used to fetch outgoing notes.
* @remarks This filter is applied as an intersection of all its params.
*/
export type OutgoingNotesFilter = {
/** Hash of a transaction from which to fetch the notes. */
txHash?: TxHash;
/** The contract address the note belongs to. */
contractAddress?: AztecAddress;
/** The specific storage location of the note on the contract. */
storageSlot?: Fr;
/** The owner of the note (whose public key was used to encrypt the note). */
owner?: AztecAddress;
};
4 changes: 3 additions & 1 deletion yarn-project/circuit-types/src/stats/stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,9 @@ export type NoteProcessorStats = {
/** How many notes have been seen and trial-decrypted. */
seen: number;
/** How many notes had decryption deferred due to a missing contract */
deferred: number;
deferredIncoming: number;
/** How many notes had decryption deferred due to a missing contract */
deferredOutgoing: number;
/** How many incoming notes were successfully decrypted. */
decryptedIncoming: number;
/** How many outgoing notes were successfully decrypted. */
Expand Down
14 changes: 10 additions & 4 deletions yarn-project/circuit-types/src/tx/tx_receipt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,15 @@ interface DebugInfo {
*/
l2ToL1Msgs: Fr[];
/**
* Notes created in this tx which belong to accounts which are registered in the PXE which was used to submit the
* tx. You will not receive notes of accounts which are not registered in the PXE here even though they were
* created in this tx.
* Notes created in this tx which were successfully decoded with the incoming keys of accounts which are registered
* in the PXE which was used to submit the tx. You will not get notes of accounts which are not registered in
* the PXE here even though they were created in this tx.
*/
visibleNotes: ExtendedNote[];
visibleIncomingNotes: ExtendedNote[];
/**
* Notes created in this tx which were successfully decoded with the outgoing keys of accounts which are registered
* in the PXE which was used to submit the tx. You will not get notes of accounts which are not registered in
* the PXE here even though they were created in this tx.
*/
visibleOutgoingNotes: ExtendedNote[];
}
9 changes: 4 additions & 5 deletions yarn-project/circuits.js/src/keys/derivation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { getKeyGenerator } from './utils.js';
const curve = new Grumpkin();

export function computeAppNullifierSecretKey(masterNullifierSecretKey: GrumpkinPrivateKey, app: AztecAddress): Fr {
return poseidon2Hash([masterNullifierSecretKey.high, masterNullifierSecretKey.low, app, GeneratorIndex.NSK_M]);
return computeAppSecretKey(masterNullifierSecretKey, app, 'n'); // 'n' is the key prefix for nullifier secret key
}

export function computeAppSecretKey(skM: GrumpkinPrivateKey, app: AztecAddress, keyPrefix: KeyPrefix): Fr {
Expand All @@ -40,12 +40,11 @@ export function computeIvskApp(ivsk: GrumpkinPrivateKey, address: AztecAddress)
return new Fq((I.toBigInt() + ivsk.toBigInt()) % Fq.MODULUS);
}

export function computeOvskApp(ovsk: GrumpkinPrivateKey, address: AztecAddress) {
export function computeOvskApp(ovsk: GrumpkinPrivateKey, app: AztecAddress) {
const ovskAppFr = computeAppSecretKey(ovsk, app, 'ov'); // 'ov' is the key prefix for outgoing viewing key
// Here we are intentionally converting Fr (output of poseidon) to Fq. This is fine even though a distribution of
// P = s * G will not be uniform because 2 * (q - r) / q is small.
return GrumpkinPrivateKey.fromBuffer(
poseidon2Hash([address.toField(), ovsk.high, ovsk.low, GeneratorIndex.OVSK_M]).toBuffer(),
);
return GrumpkinPrivateKey.fromBuffer(ovskAppFr.toBuffer());
}

export function deriveMasterNullifierSecretKey(secretKey: Fr): GrumpkinScalar {
Expand Down
4 changes: 2 additions & 2 deletions yarn-project/cli/src/inspect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export async function inspectTx(
const [receipt, effects, notes] = await Promise.all([
pxe.getTxReceipt(txHash),
pxe.getTxEffect(txHash),
pxe.getNotes({ txHash, status: NoteStatus.ACTIVE_OR_NULLIFIED }),
pxe.getIncomingNotes({ txHash, status: NoteStatus.ACTIVE_OR_NULLIFIED }),
]);

if (!receipt || !effects) {
Expand Down Expand Up @@ -103,7 +103,7 @@ export async function inspectTx(
if (nullifierCount > 0) {
log(' Nullifiers:');
for (const nullifier of effects.nullifiers) {
const [note] = await pxe.getNotes({ siloedNullifier: nullifier });
const [note] = await pxe.getIncomingNotes({ siloedNullifier: nullifier });
const deployed = deployNullifiers[nullifier.toString()];
const initialized = initNullifiers[nullifier.toString()];
const registered = classNullifiers[nullifier.toString()];
Expand Down
15 changes: 11 additions & 4 deletions yarn-project/end-to-end/src/e2e_2_pxes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,13 +347,20 @@ describe('e2e_2_pxes', () => {
const noteValue = 5;
let note: ExtendedNote;
{
const owner = walletA.getAddress();
const outgoingViewer = owner;

const receipt = await testContract.methods
.call_create_note(noteValue, walletA.getAddress(), walletA.getAddress(), noteStorageSlot)
.call_create_note(noteValue, owner, outgoingViewer, noteStorageSlot)
.send()
.wait({ debug: true });
const notes = receipt.debugInfo?.visibleNotes;
expect(notes).toHaveLength(1);
note = notes![0];
const { visibleIncomingNotes, visibleOutgoingNotes } = receipt.debugInfo!;
expect(visibleIncomingNotes).toHaveLength(1);
note = visibleIncomingNotes![0];

// Since owner is the same as outgoing viewer the incoming and outgoing notes should be the same
expect(visibleOutgoingNotes).toHaveLength(1);
expect(visibleOutgoingNotes![0]).toEqual(note);
}

// 3. Nullify the note
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@ describe('e2e_blacklist_token_contract mint', () => {

tokenSim.redeemShield(wallets[0].getAddress(), amount);
// 1 note should be created containing `amount` of tokens
const { visibleNotes } = receiptClaim.debugInfo!;
expect(visibleNotes.length).toBe(1);
expect(visibleNotes[0].note.items[0].toBigInt()).toBe(amount);
const { visibleIncomingNotes } = receiptClaim.debugInfo!;
expect(visibleIncomingNotes.length).toBe(1);
expect(visibleIncomingNotes[0].note.items[0].toBigInt()).toBe(amount);
});
});

Expand Down
10 changes: 5 additions & 5 deletions yarn-project/end-to-end/src/e2e_crowdfunding_and_claim.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ describe('e2e_crowdfunding_and_claim', () => {
});

// Get the notes emitted by the Crowdfunding contract and check that only 1 was emitted (the value note)
const notes = donateTxReceipt.debugInfo?.visibleNotes.filter(x =>
const notes = donateTxReceipt.debugInfo?.visibleIncomingNotes.filter(x =>
x.contractAddress.equals(crowdfundingContract.address),
);
expect(notes!.length).toEqual(1);
Expand Down Expand Up @@ -291,7 +291,7 @@ describe('e2e_crowdfunding_and_claim', () => {
});

// Get the notes emitted by the Crowdfunding contract and check that only 1 was emitted (the value note)
const notes = donateTxReceipt.debugInfo?.visibleNotes.filter(x =>
const notes = donateTxReceipt.debugInfo?.visibleIncomingNotes.filter(x =>
x.contractAddress.equals(crowdfundingContract.address),
);
expect(notes!.length).toEqual(1);
Expand Down Expand Up @@ -347,9 +347,9 @@ describe('e2e_crowdfunding_and_claim', () => {
let note: any;
{
const receipt = await inclusionsProofsContract.methods.create_note(owner, 5n).send().wait({ debug: true });
const { visibleNotes } = receipt.debugInfo!;
expect(visibleNotes.length).toEqual(1);
note = await processExtendedNote(visibleNotes![0]);
const { visibleIncomingNotes } = receipt.debugInfo!;
expect(visibleIncomingNotes.length).toEqual(1);
note = await processExtendedNote(visibleIncomingNotes![0]);
}

// 3) Test the note was included
Expand Down
4 changes: 2 additions & 2 deletions yarn-project/end-to-end/src/e2e_key_rotation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,8 @@ describe('e2e_key_rotation', () => {
// 5. Now we check that a correct nullifier keys were used in both transfers
{
await awaitUserSynchronized(walletB, walletB.getAddress());
const transfer1Notes = await walletB.getNotes({ txHash: txHashTransfer1 });
const transfer2Notes = await walletB.getNotes({ txHash: txHashTransfer2 });
const transfer1Notes = await walletB.getIncomingNotes({ txHash: txHashTransfer1 });
const transfer2Notes = await walletB.getIncomingNotes({ txHash: txHashTransfer2 });
expect(transfer1Notes.length).toBe(1);
expect(transfer2Notes.length).toBe(1);
// Second field in the token note is the npk_m_hash
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ describe('e2e_token_contract minting', () => {
// docs:end:debug
tokenSim.redeemShield(accounts[0].address, amount);
// 1 note should be created containing `amount` of tokens
const { visibleNotes } = receiptClaim.debugInfo!;
expect(visibleNotes.length).toBe(1);
expect(visibleNotes[0].note.items[0].toBigInt()).toBe(amount);
const { visibleIncomingNotes } = receiptClaim.debugInfo!;
expect(visibleIncomingNotes.length).toBe(1);
expect(visibleIncomingNotes[0].note.items[0].toBigInt()).toBe(amount);
});
});

Expand Down
Loading

0 comments on commit 8281ec6

Please sign in to comment.