refactor(pxe): compute oracle interface hash from wire-structural mapping labels - #24752
Conversation
| const { params, returnType } = extractRegistryEntry(property.initializer, sourceFile); | ||
| const paramSignatures = params.map(param => `${param.name}: ${param.type}`); | ||
| return `${oracleName}(${paramSignatures.join(', ')}): ${returnType}`; | ||
| export function getOracleRegistrySignature(registry: Record<string, OracleRegistryEntry>): string { |
There was a problem hiding this comment.
This is now so simple
| { name: 'ciphertext', type: BOUNDED_VEC(BYTE) }, | ||
| { name: 'iv', type: BUFFER(8, 16) }, | ||
| { name: 'symKey', type: BUFFER(8, 16) }, | ||
| { name: 'ciphertext', type: BOUNDED_VEC(U8) }, |
There was a problem hiding this comment.
Renamed BYTE to U8 to be consistent with Noir
| ciphertext: BoundedVec<number>, | ||
| iv: Buffer, | ||
| symKey: Buffer, | ||
| iv: number[], |
There was a problem hiding this comment.
This is actually more consistent with Noir. We can create the Buffer here
| const GAS_FEES: TypeMapping<GasFees> = STRUCT<GasFees>([ | ||
| { name: 'feePerDaGas', type: BIGINT }, | ||
| { name: 'feePerL2Gas', type: BIGINT }, | ||
| { name: 'feePerDaGas', type: U128 }, |
There was a problem hiding this comment.
This now reflects what Noir actually says
| serialization: { fn: resolved => [resolved.toFields()] }, | ||
| shape: [{ len: MAX_NOTE_HASHES_PER_TX + 5 }], | ||
| }; | ||
| export const RESOLVED_TX: TypeMapping<ResolvedTx> = STRUCT([ |
There was a problem hiding this comment.
RESOLVED_TX (and a few more below) are now STRUCTs. We are very close to having all types reflect their Noir counterpart 100%
| function SIBLING_PATH<N extends number>(height: N): TypeMapping<SiblingPath<N>> { | ||
| return LEAF({ | ||
| // On the wire (and in Noir) a sibling path is a plain `[Field; height]`, so it shares the fixed-array kind. | ||
| kind: `array(field,${height})`, |
There was a problem hiding this comment.
This is wrong. SIBLING_PATH should basically be an array, but we need to make some bigger changes to support that. I'll do that as a follow up, didn't want to make this PR too big
| /// | ||
| /// 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 = 'b302a8e65d37043c0a0dc08a39895603122dce334843f0442462edb3f56e32e2'; | ||
| export const ORACLE_INTERFACE_HASH = 'b1bcd3a71cb7142001d914f63d43be25d8508aacb99fe89c611a4b6e410d423f'; |
There was a problem hiding this comment.
No version bump needed since we didn't actually change the oracle, we just changed how we calculate the hash
| #[oracle(aztec_utl_getResolvedTxs)] | ||
| unconstrained fn get_resolved_txs_oracle(requests: EphemeralArray<Field>) -> EphemeralArray<Option<ResolvedTx>> {} | ||
|
|
||
| mod test { |
| #toTxEffectData(txEffect: TxEffect): TxEffectData { | ||
| return { | ||
| ...txEffect, | ||
| revertCode: txEffect.revertCode.getCode(), |
There was a problem hiding this comment.
were we missing this before and now we starting failing?
There was a problem hiding this comment.
When we cleaned things up a little bit to make the mapping closer to Noir, we made revert code a number instead of the previous ts type it had. That's why we have to get the code here
…amo/oracle-type-mapping-kinds
…ping labels (fwd-port #24752)
…ecProtocol#24932) Forward-ports the **pxe / client / txe** slice of the v5-next → next backlog (work merged to `v5-next` after the ~2026-07-08 cut that reshaped `next`). ## Applied (clean cherry-picks, chronological) - fix: tweak depositToAztec gas config (AztecProtocol#24607) - refactor: cache Aztec node reads per execution (AztecProtocol#24630) - fix: prevent access to secrets not in scope (AztecProtocol#24616) - docs: fee readme improvements (AztecProtocol#24666) - fix(pxe): widen tracked sender tagging ranges with onchain discovery evidence (AztecProtocol#24655) - fix: tagging secrets not being scoped by sender (AztecProtocol#24772) ## Conflict resolutions (cherry-picked with `-x`, resolved against reshaped `next`) - fix(txe): align tagging strategy oracle with PXE (AztecProtocol#24561) — TXE oracle version bumped to 4.0 (breaking rename `setTaggingSecretStrategy` -> `setTaggingSecretStrategies`; `next` was at 3.0 with its own hash), interface hash recomputed on the merged registry. Migration note dropped: already on `next` under 5.0.0. - feat(pxe)!: Add AppTaggingSecret kinds to keys in tagging stores (AztecProtocol#24604) — `PXE_DATA_SCHEMA_VERSION` 12 -> 13 applies cleanly on `next`. Migration note dropped: already on `next` under 5.0.0. - feat: add batch is block in archive oracle (AztecProtocol#24634) — applied cleanly on top of AztecProtocol#24561; contract oracle version 30.6 -> 30.7, v5 interface hash matched the merged registry. - feat: getTxEffects oracle (AztecProtocol#24636) — applied cleanly. - ~~feat: preserve stores on schema version or rollup address change (AztecProtocol#24631)~~ — ported separately via AztecProtocol#24947 together with the rest of the sqlite/OPFS line - feat(txe): add option to authorize all utility call targets (AztecProtocol#24662) — additive on our 4.0 -> TXE oracle version 4.1 (was 3.0 -> 3.1 on v5), hash recomputed. - refactor(pxe): compute oracle interface hash from wire-structural mapping labels (AztecProtocol#24752) — TXE hash recomputed under the new wire-structural scheme; PXE hash from the pick matched. Verified locally: full `yarn build`, `check_oracle_version` + `check_txe_oracle_version`, TXE unit suite (21), pxe tagging/type-mapping/utility-oracle suites, and 29 targeted aztec-nr + onchain_delivery_test_contract TXE tests — all green. Part of the manual v5-next → next backlog sweep. ## Added after review - AztecProtocol#24627 fix(aztec.js): give waitForNode a bounded default timeout — missed by the initial sweep (merge-commit wrapper + non-`(#N)` leaf); genuinely absent from `next`.
Problem
The oracle interface hash — the
major.minorguard that keeps PXE and Aztec.nr in sync — was computed by parsing the TypeScript source ofORACLE_REGISTRYwith a ~350-line TS-compiler AST walker, reading parameter names and type identifiers straight out of the source text. That was indirect and brittle: it tracked how the registry was written rather than the wire types the mappings actually produce, and no mapping ever named the Noir type it stands for.Our fix
First, some cleanup:
LEAF— a mapping the hash treats as atomic (its label is just its kind): scalars and hand-serialized types.SCALAR— a single-fieldLEAFthat omits the shape.ALIAS— a TS-side alias over a base mapping: identical wire, richer TS value (e.g.TX_HASHoverField).STRUCTover field mappings instead of hand-serializing, wherever the type is a plain record (ORIGIN_BLOCK,FACT,FACT_COLLECTION,RESOLVED_TX,PROVIDED_SECRET, …).BYTE→U8, split the catch-allBIGINTinto honestU64/U128/LEAF_INDEX, and mappedRETRACTABLE_FACT_ORIGIN.blockStateas a validatedorigin-block-statescalar instead of aU32placeholder.Then, two fields on every mapping:
kind— the discriminant the combinators already used ('array','option', …); now required on all mappings, and for a scalar it also names the Noir primitive.label— the canonical Noir type string the hash is computed from. Equal tokindfor a leaf, structural for a composite (array(field,4),{field,u32}). Labels are wire-structural: a struct's label drops its field names and splices nested struct labels into the parent, so anything the wire tolerates (a field rename, a struct-in-struct nesting refactor) never moves the hash, and a genuine layout change always does.The hash is now a keccak of the registry walked through these labels, so it reflects the real wire contract. Both interface hashes (PXE and TXE) are re-pinned — a TS-only build-time guard, so no contract bytecode or standard-contract addresses change, and the wire stays byte-identical so the oracle versions are untouched.
Moving
ResolvedTx's wire layout into theRESOLVED_TXstruct mapping orphaned the class'stoFields(), soResolvedTxbecomes a plain type: the class, its inline-data pin test, and the Noirresolved_tx_serialization_matches_typescriptcounterpart are deleted — the generated oracle tests already verify that wire end-to-end.As a bonus, anchoring each mapping to its Noir type also feeds the auto-generated oracle serialization tests.