Skip to content

refactor(pxe): introduce typed oracle registry for serialization#23516

Draft
nchamo wants to merge 6 commits into
merge-train/fairiesfrom
nchamo/registry-introduction
Draft

refactor(pxe): introduce typed oracle registry for serialization#23516
nchamo wants to merge 6 commits into
merge-train/fairiesfrom
nchamo/registry-introduction

Conversation

@nchamo
Copy link
Copy Markdown
Contributor

@nchamo nchamo commented May 22, 2026

Why we are doing this

The 53 oracle methods in oracle.ts each manually deserialize ACVM inputs and serialize outputs using ad-hoc patterns (Fr.fromString, toACVMField, destructuring, etc.). This transport layer also contained business logic interleaved with serialization, making the code hard to follow, error-prone, and impossible to auto-generate.

Ideally, this entire layer would be auto-generated from the Noir oracle declarations. This PR is a stepping stone toward that goal.

Our fix

Introduces a typed oracle registry (oracle_registry.ts) that describes every oracle's parameter and return types via reusable TypeMapping objects. Each TypeMapping provides bidirectional field serialization/deserialization, and the registry entry wires them together via a callHandler helper that deserializes inputs, calls the handler, and serializes the result.

Every oracle method in oracle.ts is converted to a consistent pattern:

aztec_utl_getBlockHeader(...inputs: ACVMField[][]): Promise<(ACVMField | ACVMField[])[]> {
  return callHandler({
    oracle: 'aztec_utl_getBlockHeader',
    inputs,
    handler: ([blockNumber]) => this.handlerAsUtility().getBlockHeader(blockNumber),
  });
}

With this shape, oracle.ts is ready to be fully replaced by a mechanical loop in a follow-up PR.

Additional changes:

  • Adds Noir struct mirrors (BoundedVec, FixedArray, Option) so oracle return types can carry wire-format metadata needed by the ACVM serializer
  • Normalizes null → undefined in getTxEffect and getCapsule handler interfaces to align with TypeScript conventions

This PR covers only the PXE oracle layer. The TXE (rpc_translator.ts) will be converted in a follow-up PR. Some serialization/deserialization logic had to move from the transport layer into the handlers, because Noir expects specific empty-value representations (e.g., zero-padded BoundedVec, discriminated Option). The new struct mirrors encapsulate this complexity so handlers don't need to think about wire formats directly.

What's next

  • Getting rid of oracle.ts entirely — replacing 53 identical methods with a mechanical loop over the registry
  • Real serialization tests that validate the Noir -> Typescript -> Noir roundtrip. No more "this serialization should match the one on typescript" tests
  • Automatic interface generation from the registry entries
  • Detecting Noir oracles that don't have a matching registry entry (compile-time safety net)

@nchamo nchamo added the ci-draft Run CI on draft PRs. label May 22, 2026
@nchamo nchamo self-assigned this May 22, 2026
///
/// These constants must be kept in sync between this file and `noir-projects/aztec-nr/aztec/src/oracle/version.nr`.
export const ORACLE_INTERFACE_HASH = '47e38a49abc0fa5eaaa1f270a98b8e8c9d78e0f71099119ebf326aab354e4563';
export const ORACLE_INTERFACE_HASH = 'da24bdc7eb9cdee8bcdb61905a5306d62b9c2da5565c28ff75c44f9404efd571';
Copy link
Copy Markdown
Contributor Author

@nchamo nchamo May 22, 2026

Choose a reason for hiding this comment

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

The hash changed, but we didn't update the version since we actually didn't make any changes to the oracle

@@ -508,8 +510,8 @@ export class RPCTranslator {
) {
// Parse Option<AztecAddress>: ownerIsSome is 0 for None, 1 for Some
const owner = fromSingle(foreignOwnerIsSome).toBool()
Copy link
Copy Markdown
Contributor Author

@nchamo nchamo May 22, 2026

Choose a reason for hiding this comment

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

Had to make this type of changes on this file, but in a following PR I'll apply changes similar to oracle.ts. So we can also get rid of this file

Comment on lines -1 to -28
import {
ARCHIVE_HEIGHT,
MAX_CONTRACT_CLASS_LOGS_PER_TX,
MAX_L2_TO_L1_MSGS_PER_TX,
MAX_NOTE_HASHES_PER_TX,
MAX_NULLIFIERS_PER_TX,
MAX_PRIVATE_LOGS_PER_TX,
MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
} from '@aztec/constants';
import { BlockNumber } from '@aztec/foundation/branded-types';
import { padArrayEnd } from '@aztec/foundation/collection';
import { Fr } from '@aztec/foundation/curves/bn254';
import { MembershipWitness } from '@aztec/foundation/trees';
import {
type ACIRCallback,
type ACVMField,
arrayOfArraysToBoundedVecOfArrays,
bufferToBoundedVec,
fromUintArray,
fromUintBoundedVec,
toACVMField,
} from '@aztec/simulator/client';
import { FunctionSelector, NoteSelector } from '@aztec/stdlib/abi';
import { PublicDataWrite } from '@aztec/stdlib/avm';
import { AztecAddress } from '@aztec/stdlib/aztec-address';
import { BlockHash } from '@aztec/stdlib/block';
import { ContractClassLog, ContractClassLogFields, FlatPublicLogs, PrivateLog } from '@aztec/stdlib/logs';
import { TxEffect, TxHash } from '@aztec/stdlib/tx';
Copy link
Copy Markdown
Contributor Author

@nchamo nchamo May 22, 2026

Choose a reason for hiding this comment

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

DIE IMPORTS, DIE! 🔥

Comment thread yarn-project/pxe/src/contract_function_simulator/oracle/oracle.ts Outdated
@nchamo nchamo requested a review from mverzilli May 23, 2026 09:35
…oding logic

The registry-introduction branch was based on an older snapshot that predated PR #23428,
which replaced V1's throw-on-None with V2's Option encoding. This re-applies that change
and removes the now-redundant V2 method.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-draft Run CI on draft PRs.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant