refactor(pxe): introduce typed oracle registry for serialization#23516
refactor(pxe): introduce typed oracle registry for serialization#23516nchamo wants to merge 6 commits into
Conversation
| /// | ||
| /// 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'; |
There was a problem hiding this comment.
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() | |||
There was a problem hiding this comment.
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
| 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'; |
There was a problem hiding this comment.
DIE IMPORTS, DIE! 🔥
…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>
| anchorBlockHash: BlockHash, | ||
| blockHash: BlockHash, | ||
| ): Promise<MembershipWitness<typeof ARCHIVE_HEIGHT> | undefined>; | ||
| ): Promise<Option<MembershipWitness<typeof ARCHIVE_HEIGHT>>>; |
There was a problem hiding this comment.
Handlers now deal with some serialization types (Option, BoundedVec, FixedArray) that oracle.ts used to handle internally. This is intentional: if we want to eventually auto-generate the interface from Noir oracle definitions, the handler return types need to match what Noir expects on the wire. The wrapper classes (BoundedVec, FixedArray, Option) keep most of that complexity out of the handler code itself.
Why we are doing this
The 53 oracle methods in
oracle.tseach 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 reusableTypeMappingobjects. EachTypeMappingprovides bidirectional field serialization/deserialization, and the registry entry wires them together via acallHandlerhelper that deserializes inputs, calls the handler, and serializes the result.Every oracle method in
oracle.tsis converted to a consistent pattern:With this shape,
oracle.tsis ready to be fully replaced by a mechanical loop in a follow-up PR.Additional changes:
BoundedVec,FixedArray,Option) so oracle return types can carry wire-format metadata needed by the ACVM serializernull → undefinedingetTxEffectandgetCapsulehandler interfaces to align with TypeScript conventionsThis 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-paddedBoundedVec, discriminatedOption). The new struct mirrors encapsulate this complexity so handlers don't need to think about wire formats directly.What's next
oracle.tsentirely — replacing 53 identical methods with a mechanical loop over the registryNoir -> Typescript -> Noirroundtrip. No more "this serialization should match the one on typescript" tests