Skip to content

fix(pxe): respect slot boundaries in oracle (de)serialization#24211

Open
nchamo wants to merge 5 commits into
merge-train/fairies-v5from
nchamo/oracle-serialization-improve
Open

fix(pxe): respect slot boundaries in oracle (de)serialization#24211
nchamo wants to merge 5 commits into
merge-train/fairies-v5from
nchamo/oracle-serialization-improve

Conversation

@nchamo

@nchamo nchamo commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Motivation

When deserializing an oracle's inputs, every slot of a value was read through a single shared FieldReader cursor with no notion of where one slot ends and the next begins. For a fixed single-field value this is fine, but a value spanning multiple fields had no boundary to stop at. The clearest symptom: a None Option nested inside an ARRAY/BOUNDED_VEC drained all remaining fields of the collection (it called reader.skip(remaining)), swallowing the elements after it instead of skipping just its own zero-padding.

The change

Each TypeMapping now declares a shape: the wire width of every slot it occupies. Deserialization slices a value's fields into one FieldReader per slot via splitByShape, so slot boundaries are structural instead of being tracked inside a shared cursor. This replaces the old per-mapping slots: number count.

  • Collection elements are reconstructed slot-by-slot from their shape, so a None skips only its own fields.
  • Option derives its None padding from the inner's shape instead of a template, so a None takes no argument (or just a size descriptor for variable-size types).
  • Every element and param now asserts its slots were fully consumed, and an oracle's input slot count must match what the registry models.

@nchamo nchamo added the ci-draft Run CI on draft PRs. label Jun 20, 2026
@nchamo nchamo self-assigned this Jun 20, 2026
@nchamo nchamo changed the title refactor(pxe): shape-based oracle (de)serialization fix(pxe): respect slot boundaries in oracle (de)serialization Jun 20, 2026
@AztecBot

AztecBot commented Jun 20, 2026

Copy link
Copy Markdown
Collaborator

Flakey Tests

🤖 says: This CI run detected 2 tests that failed, but were tolerated due to a .test_patterns.yml entry.

\033FLAKED\033 (8;;http://ci.aztec-labs.com/c530e49c831f0f5b�c530e49c831f0f5b8;;�): yarn-project/kv-store/scripts/run_test.sh src/bench/sqlite-opfs-encrypted/map_bench.test.ts (2s) (code: 0)
\033FLAKED\033 (8;;http://ci.aztec-labs.com/9467ece993eb030e�9467ece993eb030e8;;�): yarn-project/kv-store/scripts/run_test.sh src/sqlite-opfs/internal/ordered-binary-browser.test.ts (2s) (code: 0)

@nchamo nchamo marked this pull request as ready for review June 20, 2026 15:06
private constructor(
public readonly value: T | undefined,
public readonly template: T | undefined,
// `unknown` (not the descriptor shape) keeps this generic Option decoupled from the serialization layer's

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is so that we can do things like Option.none({ maxLength: ciphertext.maxLength });

I tried passing a Size type all the way from the registry to the Option, but in most cases, a size isn't needed. So I thought the extra type added more noise than it helped

params: [{ name: 'pkMHash', type: FIELD }],
params: [
{ name: 'pkMHash', type: FIELD },
{ name: 'keyIndex', type: FIELD },

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The keyIndex was not used, but it was present on the oracle. So I added it so that tests passed

///
/// 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 = 'f5cd3321b32371186f30dfd11b246946fb425cadffb8e6564b897d5184e43fe9';
export const ORACLE_INTERFACE_HASH = '04e973e69ac73ab958cec7908abcfc40fdac5615a10c890808928c962d91c652';

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This was needed because I added keyIndex to the registry. But nothing really changed, it was a parameter previously ignored

* Most tests *round-trip*: serialize a value, deserialize the result, and assert it comes back unchanged (see the
* `roundTrip` helper at the bottom). The rest pin a specific encoding, or check that malformed wire input is rejected.
*/
describe('oracle type mappings', () => {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I moved many of the tests from oracle_registry.test.ts here

});
// Every input slot must be modelled by a param: oracles whose Noir decl passes an extra field must declare it
// (the handler can ignore it). Otherwise an under-declared shape would silently drop a field into nothing.
if (offset !== inputs.length) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This new check asserts we are not messing up

export const BLOCK_HEADER: TypeMapping<BlockHeader> = {
serialization: { fn: v => v.toFields() },
deserialization: { fn: ([reader]) => BlockHeader.fromFields(reader.readFieldArray(BLOCK_HEADER_LENGTH)), slots: 1 },
shape: Array<SlotShape>(BLOCK_HEADER_LENGTH).fill('scalar'),

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Other cases like this one where we have to say "this is an array of many scalars" will go away in a PR I'm working on that introduces the helper STRUCT (like we have ARRAY or BOUNDED_VEC today). When we introduce that, this will be calculated automatically

@nchamo nchamo requested a review from mverzilli June 22, 2026 01:04
Comment thread yarn-project/pxe/src/contract_function_simulator/noir-structs/option.ts Outdated
Comment thread yarn-project/pxe/src/contract_function_simulator/oracle/oracle_registry.ts Outdated
Comment thread yarn-project/pxe/src/contract_function_simulator/oracle/oracle_registry.ts Outdated
@nchamo nchamo requested a review from mverzilli June 22, 2026 11:49
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.

3 participants