Skip to content

feat: FactStore and offchain reception refactor - #23928

Closed
mverzilli wants to merge 85 commits into
merge-train/fairies-v5from
martin/fact-store
Closed

feat: FactStore and offchain reception refactor#23928
mverzilli wants to merge 85 commits into
merge-train/fairies-v5from
martin/fact-store

Conversation

@mverzilli

@mverzilli mverzilli commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Introduces a new set of oracles that lets contracts register retractable and not-retractable facts, useful to implement ad-hoc workflows without PXE knowing specifics of them.

A retractable fact is data that exists if and only if its origin block is included in the chain.
A non-retractable fact is data that exists independently of chain state.

In addition to introducing this mechanism, this PR re-implements the offchain reception workflows using it instead of the more generic capsules mechanism.

Closes F-682
Closes F-684

mverzilli added 21 commits June 5, 2026 11:45
…llback

Opens FactStore in openPxeStores, wires it into JobCoordinator and
BlockSynchronizer (reorg rollback via chain-pruned), and adds schema-compat
coverage. PXE_DATA_SCHEMA_VERSION unchanged (new store starts empty).
The offchain reception test helper relied on `&` short-circuiting, but Noir's `&`
evaluates both operands, so `keys.get(i)` ran past the end of the active-entities
BoundedVec once the test executed against a live TXE. Nest the bounds check so the
read only happens in range.
getEntityFacts and activeEntities now layer a job's staged record/terminate ops
over committed state: a fact recorded earlier in the same job is visible to a
later read, and a staged terminate hides the entity. This matches the
staged-over-committed read model of the sibling note and private-event stores and
makes the FactStore a predictable primitive for read-after-write consumers such as
offchain reception's sync_inbox.

Both reads take a jobId and use a non-creating staged-ops lookup, so a read for a
job with no writes never registers a phantom in-flight job (which would trip the
rollback guard).
@mverzilli
mverzilli requested a review from nventuro as a code owner June 8, 2026 09:06
@mverzilli
mverzilli removed the request for review from nventuro June 8, 2026 10:24
mverzilli added 28 commits June 9, 2026 16:03
Hide the create_non_retractable_entity oracle wrapper behind a typed
constructor. Types implementing EntityBody supply their own entity_type_id
and entity_id, so the offchain receive loop no longer passes those by hand.
…structors

The create_{retractable,non_retractable}_entity wrappers now have no callers
outside their NonRetractableEntity/RetractableEntity::create constructors, so
drop them from the public API to pub(crate).
…tive

Replace the free active_entities wrapper with a read_all_active static method
on NonRetractableEntity<T> and RetractableEntity<T>, deriving the entity type id
from T via EntityBody instead of passing it by hand.
…om handles

NonRetractableEntity/RetractableEntity::read_all_active now forward to a single
Entity<T>::read_all_active, so the oracle query lives in one place while both
specialized handle types keep the ergonomic API.
…t_entity

NonRetractableEntity/RetractableEntity now hold { body, facts } and
read_all_active returns populated handles (forwarding to Entity::read_all_active
and re-wrapping). sync_inbox reads body + facts straight off the handle, so its
two per-entity get_entity calls are gone — each active entity is fetched once.
…le move

The OffchainMessage type now resolves through the offchain::message
submodule, so macro-expanded references changed from
offchain::OffchainMessage to offchain::message::OffchainMessage in the
six contract expand snapshots.
…ction

process_reception now reads the OFFCHAIN_MESSAGE_PROCESSED fact directly
instead of folding it into an OffchainReceptionState. With state() gone,
its only producer, the OffchainReceptionState type, the reception_with_facts
test helper, and the two pure-fold unit tests (whose behavior the TXE tests
already cover) are removed; state_of becomes a boolean is_processed helper.
…txs oracle

The shared MessageContext was widened with tx_block_number/tx_block_hash for
offchain fact anchoring. But MessageContext is embedded in PendingTaggedLog and
returned by the message-context oracle, both of which every synced contract
serializes across the oracle boundary - including the committed pinned standard
contracts. The freshly built TXE therefore serialized two fields more than the
pinned handshake contract expected, failing its TXE test with "Foreign call
return value does not match expected size. Expected 84 but got 86".

The block fields are only read by offchain process_reception, so move them off
the shared type: keep MessageContext lean (3 fields) and add a dedicated
ResolvedTx returned by a new resolve_txs oracle (replacing
get_message_contexts_by_tx_hash), consumed only by the offchain inbox sync. The
TXE keeps a lean getMessageContextsByTxHash shim so artifacts pinned or compiled
against the old oracle keep working; the oracle minor is bumped 29.3 -> 29.4
(additive).

Fixes the handshake TXE test against the existing pin with no re-pin and no
canonical standard-contract address churn.
ResolvedTx is only consumed by PXE (the tx resolver and the resolveTxs oracle),
so it belongs alongside the other oracle return types in
contract_function_simulator/noir-structs (like LogRetrievalResponse) rather than
in stdlib. Re-exported from @aztec/pxe/simulator so the TXE oracle registry's
inferred type stays nameable.
@mverzilli

Copy link
Copy Markdown
Contributor Author

Closing. I spinned a series of PRs off this one.

@mverzilli mverzilli closed this Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant