Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
benesjan committed Oct 2, 2024
1 parent 1769eeb commit 45e2d31
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,26 @@ import { ContractNotFoundError } from '@aztec/simulator';

import { type PxeDatabase } from '../database/pxe_database.js';

/**
* Inserts publicly delivered nullable fields into the note payload.
* @param db - PXE database used to fetch contract instance and artifact.
* @param payload - Note payload to which nullable fields should be added.
* @param nullableFields - List of nullable fields to be added to the note payload.
* @returns Note payload with nullable fields added.
*/
export async function addNullableFieldsToPayload(
pxeDb: PxeDatabase,
db: PxeDatabase,
payload: L1NotePayload,
nullableFields: Fr[],
): Promise<L1NotePayload> {
const instance = await pxeDb.getContractInstance(payload.contractAddress);
const instance = await db.getContractInstance(payload.contractAddress);
if (!instance) {
throw new ContractNotFoundError(
`Could not find instance for ${payload.contractAddress.toString()}. This should never happen here as the partial notes flow should be triggered only for non-deferred notes.`,
);
}

const artifact = await pxeDb.getContractArtifact(instance.contractClassId);
const artifact = await db.getContractArtifact(instance.contractClassId);
if (!artifact) {
throw new Error(
`Could not find artifact for contract class ${instance.contractClassId.toString()}. This should never happen here as the partial notes flow should be triggered only for non-deferred notes.`,
Expand All @@ -29,7 +36,10 @@ export async function addNullableFieldsToPayload(
throw new Error(`Could not find note fields for note type ${payload.noteTypeId.toString()}.`);
}

// Now we insert the nullable fields into the note
// We sort note fields by index so that we can iterate over them in order.
noteFields.sort((a, b) => a.index - b.index);

// Now we insert the nullable fields into the note based on its indices defined in the ABI.
const modifiedNoteItems = [...payload.note.items];
let indexInNullable = 0;
for (let i = 0; i < noteFields.length; i++) {
Expand Down
98 changes: 61 additions & 37 deletions yarn-project/pxe/src/note_processor/produce_note_dao.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ export async function produceNoteDaos(
incomingDeferredNote: DeferredNoteDao | undefined;
outgoingDeferredNote: DeferredNoteDao | undefined;
}> {
// WARNING: This code is full of tech debt and will be refactored once we have final design of partial notes
// delivery.
if (!ivpkM && !ovpkM) {
throw new Error('Both ivpkM and ovpkM are undefined. Cannot create note.');
}
Expand Down Expand Up @@ -98,12 +100,16 @@ export async function produceNoteDaos(
unencryptedLogs,
);
}
} else if ((e as any).message.includes('failed to solve blackbox function: embedded_curve_add')) {
} else if (
(e as any).message.includes('failed to solve blackbox function: embedded_curve_add') ||
(e as any).message.includes('Could not find key prefix.')
) {
// TODO(#8769): This branch is a temporary partial notes delivery solution that should be eventually replaced.
// This error occurs when we are dealing with a partial note and is thrown when calling
// `note.compute_note_hash()` in `compute_note_hash_and_optionally_a_nullifier` function. It occurs with
// partial notes because in the partial flow we receive a note log of a note that is missing some fields
// here and then we try to compute the note hash with MSM while some of the fields are zeroed out.
// Both error messages above occur only when we are dealing with a partial note and are thrown when calling
// `note.compute_note_hash()` or `note.compute_nullifier_without_context()`
// in `compute_note_hash_and_optionally_a_nullifier` function. It occurs with partial notes because in the
// partial flow we receive a note log of a note that is missing some fields here and then we try to compute
// the note hash with MSM while some of the fields are zeroed out (or get a nsk for zero npk_m_hash).
for (const functionLogs of unencryptedLogs.functionLogs) {
for (const log of functionLogs.logs) {
const { data } = log;
Expand All @@ -119,19 +125,26 @@ export async function produceNoteDaos(
// We insert the nullable fields into the note and then we try to produce the note dao again
const payloadWithNullableFields = await addNullableFieldsToPayload(pxeDb, payload, nullableFields);

({ incomingNote, incomingDeferredNote } = await produceNoteDaos(
simulator,
pxeDb,
ivpkM,
undefined, // We only care about incoming notes in this case as that is where the partial flow got triggered.
payloadWithNullableFields,
txHash,
noteHashes,
dataStartIndexForTx,
excludedIndices,
logger,
UnencryptedTxL2Logs.empty(), // We set unencrypted logs to empty to prevent infinite recursion.
));
try {
({ incomingNote, incomingDeferredNote } = await produceNoteDaos(
simulator,
pxeDb,
ivpkM,
undefined, // We only care about incoming notes in this case as that is where the partial flow got triggered.
payloadWithNullableFields,
txHash,
noteHashes,
dataStartIndexForTx,
excludedIndices,
logger,
UnencryptedTxL2Logs.empty(), // We set unencrypted logs to empty to prevent infinite recursion.
));
} catch (e) {
if (!(e as any).message.includes('Could not find key prefix.')) {
throw e;
}
}

if (incomingDeferredNote) {
// This should not happen as we should first get contract not found error before the blackbox func error.
throw new Error('Partial notes should never be deferred.');
Expand All @@ -146,7 +159,7 @@ export async function produceNoteDaos(
}

if (!incomingNote) {
logger.error(`Could not process partial note because of "${e}". Discarding note...`);
logger.error(`Partial note note found. Discarding note...`);
}
} else {
logger.error(`Could not process note because of "${e}". Discarding note...`);
Expand Down Expand Up @@ -210,12 +223,16 @@ export async function produceNoteDaos(
unencryptedLogs,
);
}
} else if ((e as any).message.includes('failed to solve blackbox function: embedded_curve_add')) {
} else if (
(e as any).message.includes('failed to solve blackbox function: embedded_curve_add') ||
(e as any).message.includes('Could not find key prefix.')
) {
// TODO(#8769): This branch is a temporary partial notes delivery solution that should be eventually replaced.
// This error occurs when we are dealing with a partial note and is thrown when calling
// `note.compute_note_hash()` in `compute_note_hash_and_optionally_a_nullifier` function. It occurs with
// partial notes because in the partial flow we receive a note log of a note that is missing some fields
// here and then we try to compute the note hash with MSM while some of the fields are zeroed out.
// Both error messages above occur only when we are dealing with a partial note and are thrown when calling
// `note.compute_note_hash()` or `note.compute_nullifier_without_context()`
// in `compute_note_hash_and_optionally_a_nullifier` function. It occurs with partial notes because in the
// partial flow we receive a note log of a note that is missing some fields here and then we try to compute
// the note hash with MSM while some of the fields are zeroed out (or get a nsk for zero npk_m_hash).
for (const functionLogs of unencryptedLogs.functionLogs) {
for (const log of functionLogs.logs) {
const { data } = log;
Expand All @@ -231,19 +248,26 @@ export async function produceNoteDaos(
// We insert the nullable fields into the note and then we try to produce the note dao again
const payloadWithNullableFields = await addNullableFieldsToPayload(pxeDb, payload, nullableFields);

({ outgoingNote, outgoingDeferredNote } = await produceNoteDaos(
simulator,
pxeDb,
undefined, // We only care about outgoing notes in this case as that is where the partial flow got triggered.
ovpkM,
payloadWithNullableFields,
txHash,
noteHashes,
dataStartIndexForTx,
excludedIndices,
logger,
UnencryptedTxL2Logs.empty(), // We set unencrypted logs to empty to prevent infinite recursion.
));
try {
({ outgoingNote, outgoingDeferredNote } = await produceNoteDaos(
simulator,
pxeDb,
undefined, // We only care about outgoing notes in this case as that is where the partial flow got triggered.
ovpkM,
payloadWithNullableFields,
txHash,
noteHashes,
dataStartIndexForTx,
excludedIndices,
logger,
UnencryptedTxL2Logs.empty(), // We set unencrypted logs to empty to prevent infinite recursion.
));
} catch (e) {
if (!(e as any).message.includes('Could not find key prefix.')) {
throw e;
}
}

if (outgoingNote || outgoingDeferredNote) {
// We managed to complete the partial note so we terminate the search.
break;
Expand Down

0 comments on commit 45e2d31

Please sign in to comment.