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
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DirectionalAppTaggingSecret, type IndexedTaggingSecret } from '@aztec/stdlib/logs';
import { DirectionalAppTaggingSecret, type PreTag } from '@aztec/stdlib/logs';

/**
* A map that stores the tagging index for a given directional app tagging secret.
Expand All @@ -21,9 +21,9 @@ export class ExecutionTaggingIndexCache {
}

/**
* Returns the indexed tagging secrets that were used in this execution.
* Returns the pre tags that were used in this execution (and that need to be stored in the db).
*/
public getUsedIndexedTaggingSecrets(): IndexedTaggingSecret[] {
public getUsedPreTags(): PreTag[] {
return Array.from(this.taggingIndexMap.entries()).map(([secret, index]) => ({
secret: DirectionalAppTaggingSecret.fromString(secret),
index,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export async function executePrivateFunction(
const newNotes = privateExecutionOracle.getNewNotes();
const noteHashNullifierCounterMap = privateExecutionOracle.getNoteHashNullifierCounterMap();
const offchainEffects = privateExecutionOracle.getOffchainEffects();
const indexedTaggingSecrets = privateExecutionOracle.getUsedIndexedTaggingSecrets();
const preTags = privateExecutionOracle.getUsedPreTags();
const nestedExecutionResults = privateExecutionOracle.getNestedExecutionResults();

let timerSubtractionList = nestedExecutionResults;
Expand All @@ -112,7 +112,7 @@ export async function executePrivateFunction(
noteHashNullifierCounterMap,
rawReturnValues,
offchainEffects,
indexedTaggingSecrets,
preTags,
nestedExecutionResults,
contractClassLogs,
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import type { AuthWitness } from '@aztec/stdlib/auth-witness';
import { AztecAddress } from '@aztec/stdlib/aztec-address';
import { computeUniqueNoteHash, siloNoteHash, siloNullifier } from '@aztec/stdlib/hash';
import { PrivateContextInputs } from '@aztec/stdlib/kernel';
import type { ContractClassLog, DirectionalAppTaggingSecret, IndexedTaggingSecret } from '@aztec/stdlib/logs';
import type { ContractClassLog, DirectionalAppTaggingSecret, PreTag } from '@aztec/stdlib/logs';
import { Note, type NoteStatus } from '@aztec/stdlib/note';
import {
type BlockHeader,
Expand Down Expand Up @@ -152,10 +152,10 @@ export class PrivateExecutionOracle extends UtilityExecutionOracle implements IP
}

/**
* Returns the indexed tagging secrets that were used in this execution.
* Returns the pre tags that were used in this execution (and that need to be stored in the db).
*/
public getUsedIndexedTaggingSecrets(): IndexedTaggingSecret[] {
return this.taggingIndexCache.getUsedIndexedTaggingSecrets();
public getUsedPreTags(): PreTag[] {
return this.taggingIndexCache.getUsedPreTags();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ import {
SiloedTag,
Tag,
WINDOW_HALF_SIZE,
getIndexedTaggingSecretsForTheWindow,
getInitialIndexesMap,
getPreTagsForTheWindow,
} from '../tagging/index.js';
import { EventValidationRequest } from './noir-structs/event_validation_request.js';
import { LogRetrievalRequest } from './noir-structs/log_retrieval_request.js';
Expand Down Expand Up @@ -289,15 +289,19 @@ export class PXEOracleInterface implements ExecutionDataProvider {
}

/**
* Returns the indexed tagging secrets for a given recipient and all the senders in the address book
* Returns the last used tagging indexes along with the directional app tagging secrets for a given recipient and all
* the senders in the address book.
* This method should be exposed as an oracle call to allow aztec.nr to perform the orchestration
* of the syncTaggedLogs and processTaggedLogs methods. However, it is not possible to do so at the moment,
* so we're keeping it private for now.
* @param contractAddress - The contract address to silo the secret for
* @param recipient - The address receiving the notes
* @returns A list of indexed tagging secrets. If the corresponding secret was never used, the index is undefined.
* @returns A list of directional app tagging secrets along with the last used tagging indexes. If the corresponding
* secret was never used, the index is undefined.
* TODO(benesjan): The naming here is broken as the function name does not reflect the return type. Fix when associating
* indexes with tx hash.
*/
async #getLastUsedIndexedTaggingSecretsForSenders(
async #getLastUsedTaggingIndexesForSenders(
Copy link
Contributor Author

@benesjan benesjan Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The naming here is confusing as it doesn't return PreTags. Put the TODO above as I expect this all to just go away in followup PRs where the whole tagging sync algo will be rewritten and moved from this file to separate standalone functions in pxe/src/tagging dir.

contractAddress: AztecAddress,
recipient: AztecAddress,
): Promise<{ secret: DirectionalAppTaggingSecret; index: number | undefined }[]> {
Expand Down Expand Up @@ -425,7 +429,7 @@ export class PXEOracleInterface implements ExecutionDataProvider {
const contractName = await this.contractDataProvider.getDebugContractName(contractAddress);
for (const recipient of recipients) {
// Get all the secrets for the recipient and sender pairs (#9365)
const indexedSecrets = await this.#getLastUsedIndexedTaggingSecretsForSenders(contractAddress, recipient);
const indexedSecrets = await this.#getLastUsedTaggingIndexesForSenders(contractAddress, recipient);

// We fetch logs for a window of indexes in a range:
// <latest_log_index - WINDOW_HALF_SIZE, latest_log_index + WINDOW_HALF_SIZE>.
Expand Down Expand Up @@ -459,10 +463,10 @@ export class PXEOracleInterface implements ExecutionDataProvider {
const initialIndexesMap = getInitialIndexesMap(indexedSecrets);

while (secretsAndWindows.length > 0) {
const secretsForTheWholeWindow = getIndexedTaggingSecretsForTheWindow(secretsAndWindows);
const preTagsForTheWholeWindow = getPreTagsForTheWindow(secretsAndWindows);
const tagsForTheWholeWindow = await Promise.all(
secretsForTheWholeWindow.map(async indexedSecret => {
return SiloedTag.compute(await Tag.compute(indexedSecret), contractAddress);
preTagsForTheWholeWindow.map(async preTag => {
return SiloedTag.compute(await Tag.compute(preTag), contractAddress);
}),
);

Expand Down Expand Up @@ -495,25 +499,25 @@ export class PXEOracleInterface implements ExecutionDataProvider {
filteredLogsByBlockNumber,
);

// We retrieve the indexed tagging secret corresponding to the log as I need that to evaluate whether
// We retrieve the pre tag corresponding to the log as I need that to evaluate whether
// a new largest index have been found.
const secretCorrespondingToLog = secretsForTheWholeWindow[logIndex];
const initialIndex = initialIndexesMap[secretCorrespondingToLog.secret.toString()];
const preTagCorrespondingToLog = preTagsForTheWholeWindow[logIndex];
const initialIndex = initialIndexesMap[preTagCorrespondingToLog.secret.toString()];

if (
secretCorrespondingToLog.index >= initialIndex &&
(newLargestIndexMapForIteration[secretCorrespondingToLog.secret.toString()] === undefined ||
secretCorrespondingToLog.index >=
newLargestIndexMapForIteration[secretCorrespondingToLog.secret.toString()])
preTagCorrespondingToLog.index >= initialIndex &&
(newLargestIndexMapForIteration[preTagCorrespondingToLog.secret.toString()] === undefined ||
preTagCorrespondingToLog.index >=
newLargestIndexMapForIteration[preTagCorrespondingToLog.secret.toString()])
) {
// We have found a new largest index so we store it for later processing (storing it in the db + fetching
// the difference of the window sets of current and the next iteration)
newLargestIndexMapForIteration[secretCorrespondingToLog.secret.toString()] =
secretCorrespondingToLog.index + 1;
newLargestIndexMapForIteration[preTagCorrespondingToLog.secret.toString()] =
preTagCorrespondingToLog.index + 1;

this.log.debug(
`Incrementing index to ${
secretCorrespondingToLog.index + 1
preTagCorrespondingToLog.index + 1
} at contract ${contractName}(${contractAddress})`,
);
}
Expand Down
12 changes: 6 additions & 6 deletions yarn-project/pxe/src/pxe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -743,14 +743,14 @@ export class PXE {
nodeRPCCalls: contractFunctionSimulator?.getStats().nodeRPCCalls,
});

const indexedTaggingSecretsIncrementedInTheTx = privateExecutionResult.entrypoint.indexedTaggingSecrets;
if (indexedTaggingSecretsIncrementedInTheTx.length > 0) {
await this.taggingDataProvider.setLastUsedIndexesAsSender(indexedTaggingSecretsIncrementedInTheTx);
this.log.debug(`Stored last used tagging secret indexes as sender for the tx`, {
indexedTaggingSecretsIncrementedInTheTx,
const preTagsUsedInTheTx = privateExecutionResult.entrypoint.preTags;
if (preTagsUsedInTheTx.length > 0) {
await this.taggingDataProvider.setLastUsedIndexesAsSender(preTagsUsedInTheTx);
this.log.debug(`Stored used pre tags as sender for the tx`, {
preTagsUsedInTheTx,
});
} else {
this.log.debug(`No tagging secret indexes incremented in the tx`);
this.log.debug(`No pre tags used in the tx`);
}

return txProvingResult;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { toArray } from '@aztec/foundation/iterable';
import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
import { AztecAddress } from '@aztec/stdlib/aztec-address';
import type { DirectionalAppTaggingSecret, IndexedTaggingSecret } from '@aztec/stdlib/logs';
import type { DirectionalAppTaggingSecret, PreTag } from '@aztec/stdlib/logs';

export class TaggingDataProvider {
#store: AztecAsyncKVStore;
Expand All @@ -23,34 +23,37 @@ export class TaggingDataProvider {

/**
* Sets the last used indexes when sending a log.
* @param indexedSecrets - The indexed secrets to set the last used indexes for.
* @throws If there are duplicate secrets in the input array
* @param preTags - The pre tags containing the directional app tagging secrets and the indexes that are to be
* updated in the db.
* @throws If any two pre tags contain the same directional app tagging secret
*/
setLastUsedIndexesAsSender(indexedSecrets: IndexedTaggingSecret[]) {
this.#assertUniqueSecrets(indexedSecrets, 'sender');
setLastUsedIndexesAsSender(preTags: PreTag[]) {
this.#assertUniqueSecrets(preTags, 'sender');

return Promise.all(
indexedSecrets.map(({ secret, index }) => this.#lastUsedIndexesAsSenders.set(secret.toString(), index)),
preTags.map(({ secret, index }) => this.#lastUsedIndexesAsSenders.set(secret.toString(), index)),
);
}

/**
* Sets the last used indexes when looking for logs.
* @param indexedSecrets - The indexed secrets to set the last used indexes for.
* @throws If there are duplicate secrets in the input array
* @param preTags - The pre tags containing the directional app tagging secrets and the indexes that are to be
* updated in the db.
* @throws If any two pre tags contain the same directional app tagging secret
*/
setLastUsedIndexesAsRecipient(indexedSecrets: IndexedTaggingSecret[]) {
this.#assertUniqueSecrets(indexedSecrets, 'recipient');
setLastUsedIndexesAsRecipient(preTags: PreTag[]) {
this.#assertUniqueSecrets(preTags, 'recipient');

return Promise.all(
indexedSecrets.map(({ secret, index }) => this.#lastUsedIndexesAsRecipients.set(secret.toString(), index)),
preTags.map(({ secret, index }) => this.#lastUsedIndexesAsRecipients.set(secret.toString(), index)),
);
}

// It should never happen that we would receive a duplicate secrets on the input of the setters as everywhere
// we always just apply the largest index. Hence this check is a good way to catch bugs.
#assertUniqueSecrets(indexedSecrets: IndexedTaggingSecret[], role: 'sender' | 'recipient'): void {
const secretStrings = indexedSecrets.map(({ secret }) => secret.toString());
// It should never happen that we would receive any two pre tags on the input containing the same directional app
// tagging secret as everywhere we always just apply the largest index. Hence this check is a good way to catch
// bugs.
#assertUniqueSecrets(preTags: PreTag[], role: 'sender' | 'recipient'): void {
const secretStrings = preTags.map(({ secret }) => secret.toString());
const uniqueSecrets = new Set(secretStrings);
if (uniqueSecrets.size !== secretStrings.length) {
throw new Error(`Duplicate secrets found when setting last used indexes as ${role}`);
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/pxe/src/tagging/constants.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
// Half the size of the window we slide over the tagging secret indexes.
// Half the size of the window we slide over the tagging indexes.
export const WINDOW_HALF_SIZE = 10;
2 changes: 1 addition & 1 deletion yarn-project/pxe/src/tagging/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ export * from './constants.js';
export * from './siloed_tag.js';
export * from './utils.js';
export { DirectionalAppTaggingSecret } from '@aztec/stdlib/logs';
export { type IndexedTaggingSecret } from '@aztec/stdlib/logs';
export { type PreTag } from '@aztec/stdlib/logs';
6 changes: 3 additions & 3 deletions yarn-project/pxe/src/tagging/tag.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { poseidon2Hash } from '@aztec/foundation/crypto';
import type { Fr } from '@aztec/foundation/fields';
import type { IndexedTaggingSecret } from '@aztec/stdlib/logs';
import type { PreTag } from '@aztec/stdlib/logs';

/**
* Represents a tag of a private log. This is not the tag that "appears" on the chain as this tag is first siloed
Expand All @@ -9,8 +9,8 @@ import type { IndexedTaggingSecret } from '@aztec/stdlib/logs';
export class Tag {
private constructor(public readonly value: Fr) {}

static async compute(indexedTaggingSecret: IndexedTaggingSecret): Promise<Tag> {
const tag = await poseidon2Hash([indexedTaggingSecret.secret.value, indexedTaggingSecret.index]);
static async compute(preTag: PreTag): Promise<Tag> {
const tag = await poseidon2Hash([preTag.secret.value, preTag.index]);
return new Tag(tag);
}
}
16 changes: 7 additions & 9 deletions yarn-project/pxe/src/tagging/utils.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { DirectionalAppTaggingSecret, IndexedTaggingSecret } from '@aztec/stdlib/logs';
import type { DirectionalAppTaggingSecret, PreTag } from '@aztec/stdlib/logs';

// TODO(benesjan): Make this return tags instead - this will moves some complexity from syncTaggedLogs
export function getIndexedTaggingSecretsForTheWindow(
export function getPreTagsForTheWindow(
secretsAndWindows: { secret: DirectionalAppTaggingSecret; leftMostIndex: number; rightMostIndex: number }[],
): IndexedTaggingSecret[] {
): PreTag[] {
const secrets = [];
for (const secretAndWindow of secretsAndWindows) {
for (let i = secretAndWindow.leftMostIndex; i <= secretAndWindow.rightMostIndex; i++) {
Expand All @@ -15,18 +15,16 @@ export function getIndexedTaggingSecretsForTheWindow(

/**
* Creates a map from directional app tagging secret to initial index.
* @param indexedTaggingSecrets - The indexed tagging secrets to get the initial indexes from.
* @param preTags - The pre tags to get the initial indexes map from.
* @returns The map from directional app tagging secret to initial index.
*/
export function getInitialIndexesMap(
indexedTaggingSecrets: { secret: DirectionalAppTaggingSecret; index: number | undefined }[],
): {
export function getInitialIndexesMap(preTags: { secret: DirectionalAppTaggingSecret; index: number | undefined }[]): {
[k: string]: number;
} {
const initialIndexes: { [k: string]: number } = {};

for (const indexedTaggingSecret of indexedTaggingSecrets) {
initialIndexes[indexedTaggingSecret.secret.toString()] = indexedTaggingSecret.index ?? 0;
for (const preTag of preTags) {
initialIndexes[preTag.secret.toString()] = preTag.index ?? 0;
}

return initialIndexes;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { computeAddressSecret, computePreaddress } from '../keys/derivation.js';
* address: A→B differs from B→A even with the same participants and app.
*
* Note: It's a bit unfortunate that this type resides in `stdlib` as the rest of the tagging functionality resides
* in `pxe/src/tagging`. We need to use this type in `IndexedTaggingSecret` that in turn is used by other types
* in `pxe/src/tagging`. We need to use this type in `PreTag` that in turn is used by other types
* in stdlib hence there doesn't seem to be a good way around this.
*/
export class DirectionalAppTaggingSecret {
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/stdlib/src/logs/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export * from './log_with_tx_data.js';
export * from './directional_app_tagging_secret.js';
export * from './indexed_tagging_secret.js';
export * from './pre_tag.js';
export * from './contract_class_log.js';
export * from './public_log.js';
export * from './private_log.js';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ import {
* in `pxe/src/tagging`. But this type is used by other types in stdlib hence there doesn't seem to be a good way
* around this.
*/
export type IndexedTaggingSecret = {
export type PreTag = {
secret: DirectionalAppTaggingSecret;
index: number;
};

export const IndexedTaggingSecretSchema = z.object({
export const PreTagSchema = z.object({
secret: DirectionalAppTaggingSecretSchema,
index: schemas.Integer,
});
10 changes: 5 additions & 5 deletions yarn-project/stdlib/src/tx/private_execution_result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { PrivateCircuitPublicInputs } from '../kernel/private_circuit_public_inp
import type { IsEmpty } from '../kernel/utils/interfaces.js';
import { sortByCounter } from '../kernel/utils/order_and_comparison.js';
import { ContractClassLog, ContractClassLogFields } from '../logs/contract_class_log.js';
import { type IndexedTaggingSecret, IndexedTaggingSecretSchema } from '../logs/indexed_tagging_secret.js';
import { type PreTag, PreTagSchema } from '../logs/pre_tag.js';
import { Note } from '../note/note.js';
import { type ZodFor, mapSchema, schemas } from '../schemas/index.js';
import type { UInt32 } from '../types/index.js';
Expand Down Expand Up @@ -136,8 +136,8 @@ export class PrivateCallExecutionResult {
public returnValues: Fr[],
/** The offchain effects emitted during execution of this function call via the `emit_offchain_effect` oracle. */
public offchainEffects: { data: Fr[] }[],
/** The tagging indexes incremented by this execution along with the directional app tagging secrets. */
public indexedTaggingSecrets: IndexedTaggingSecret[],
/** The pre tags used in this tx to compute tags for private logs */
public preTags: PreTag[],
/** The nested executions. */
public nestedExecutionResults: PrivateCallExecutionResult[],
/**
Expand All @@ -161,7 +161,7 @@ export class PrivateCallExecutionResult {
noteHashNullifierCounterMap: mapSchema(z.coerce.number(), z.number()),
returnValues: z.array(schemas.Fr),
offchainEffects: z.array(z.object({ data: z.array(schemas.Fr) })),
indexedTaggingSecrets: z.array(IndexedTaggingSecretSchema),
preTags: z.array(PreTagSchema),
nestedExecutionResults: z.array(z.lazy(() => PrivateCallExecutionResult.schema)),
contractClassLogs: z.array(CountedContractClassLog.schema),
})
Expand All @@ -179,7 +179,7 @@ export class PrivateCallExecutionResult {
fields.noteHashNullifierCounterMap,
fields.returnValues,
fields.offchainEffects,
fields.indexedTaggingSecrets,
fields.preTags,
fields.nestedExecutionResults,
fields.contractClassLogs,
);
Expand Down
Loading