Conversation
Adds the ability to receive offchain messages to Aztec.nr contracts.
It works by using capsules to implement a persistent offchain message
inbox, and making sure that inbox is processed whenever `sync_state`
runs.
Apps deliver an offchain message to the inbox through a new utility
function `offchain_receive`, generated by the Aztec macro.
An `offchain::sync_inbox` function, takes the responsibility to let
`sync_state` know which messages should be processed like so:
1. Limits processed messages to those whose originating TX are available
at PXE's anchor block. To this end it uses a new
`resolve_message_contexts` oracle to determine which messages have
corresponding TXs known by PXE.
2. It is resilient to reorgs. Messages are re-processed for until
expiration time to make sure their effects don't get lost after re-orgs.
After expiration, they are safe to be discarded.
The feature can be exercised by invoking a function that emits offchain
messages on the sender side, saving the resulting offchain effects, and
then calling `offchain_receive` on the recipient side with them.
```typescript
// Alice sends the private transfer which emits offchain messages.
const { receipt, offchainMessages } = await contract.methods
.transfer_offchain(paymentAmount, bob)
.send({ from: alice });
expect(offchainMessages.length).toBeGreaterThan(0);
const messageForBob = offchainMessages.find(msg => msg.recipient.equals(bob));
expect(messageForBob).toBeTruthy();
await contract.methods
.offchain_receive([
{
ciphertext: messageForBob!.payload,
recipient: bob,
tx_hash: receipt.txHash.hash,
expiration_timestamp: messageForBob!.expirationTimestamp,
},
])
.simulate({ from: bob });
```
Known issues (can be addressed in subsequent PRs):
1. The new oracle, together with the long window offchain messages get
replayed for, means we should really cache `getTxEffects` node calls to
avoid performance regressions.
2. The current approach of PXE to caching contract sync calls, means
that with the current implementation we need to wait for one block
before a new message delivered to the inbox gets processed. We will
solve this by adding a new oracle to invalidate the contract sync cache.
3. Scopes aren't handled properly, which might need bigger refactors
that exceed offchain
Closes F-323
Closes F-327
Closes F-325
…itment capacity (#21264)
Collaborator
Author
|
🤖 Auto-merge enabled after 4 hours of inactivity. This PR will be merged automatically once all checks pass. |
This fixes the `Claims` contract (which is a bit odd anyway) by using `SingleUseClaim` instead of dangerously pushing a raw nullifier into state. It's another example of `SingleUseClaim` being a bit awkward to use - we may want to revisit that a bit. I took the opportunity to review and improve the docs sorrounding nullifiers, mostly noting how dangerous it is to use these functions directly. I moved the docs on what a nullifier even is to the `nullifier` mod, which seems like a better home for an explanation of the concept. --------- Co-authored-by: Claude Opus 4.6 <[email protected]>
…index (#21438) We now search in all indices instead of just the one for the corresponding note hash.
…ization race (#21452) ## Summary - Sets `anvilSlotsInAnEpoch: 32` in `e2e_offchain_payment` test setup, matching what `epochs_l1_reorgs` already does. ## Problem PR #21156 added `--slots-in-an-epoch 1` as the default for anvil, making `finalized = latest - 2`. PR #20893 added `e2e_offchain_payment` which simulates L1 reorgs. When both landed on `merge-train/fairies`, the reorg test fails deterministically because finalization races past the rollback target block. ## Fix Use `anvilSlotsInAnEpoch: 32` (matching Ethereum mainnet) so the finalized block stays far enough behind latest to allow rollbacks in the test. ClaudeBox log: https://claudebox.work/s/c5ac5d52da86e23a?run=4
## Summary - Expands legacy oracle aliases from 5 to 30 entries covering ALL oracles used by ALL pinned protocol contracts (AuthRegistry, ContractClassRegistry, ContractInstanceRegistry, FeeJuice, MultiCallEntrypoint, PublicChecks, SponsoredFPC) - Adds adapter functions for #21209 signature changes (`privateNotifyEnqueuedPublicFunctionCall` and `privateNotifySetPublicTeardownFunctionCall` 4-param → `validatePublicCalldata` 1-param) - Adds legacy mappings for #21209 renames (`privateNotifySetMinRevertibleSideEffectCounter` → `notifyRevertiblePhaseStart`, `privateIsSideEffectCounterRevertible` → `inRevertiblePhase`) - Replaces `isActualProtocolContract` (only checked 3 contracts) with `isProtocolContract` (checks all) for oracle version check skip ## Test plan - PXE tests pass (39 suites, 424 tests) - Build compiles cleanly - Lint passes - Verified all old-style oracle names in committed artifacts are covered by legacy mappings 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 <[email protected]>
#21399) ## Summary - Fixed inverted boolean comparison in `message_delivery.nr` line 208 that caused `ONCHAIN_CONSTRAINED` to run encryption unconstrained and vice versa. - The check was comparing against `ONCHAIN_UNCONSTRAINED` instead of `ONCHAIN_CONSTRAINED`, flipping the condition passed to `remove_constraints_if`. ## Backport This is a backport fix targeting `v4-next` via `merge-train/fairies`. ## Test plan - [ ] Verify constrained encryption is actually constrained when using `ONCHAIN_CONSTRAINED` delivery mode - [ ] Verify unconstrained encryption when using `ONCHAIN_UNCONSTRAINED` delivery mode cc @nventuro for review ClaudeBox log: https://claudebox.work/s/c8cf1c507575d776?run=3
The old API had two issues: - it required knowledge of the epoch for the tx in which the message was included, which is hard to acquire - it did not support duplicate messages (i.e. same hash) in the epoch at all - it only found the first one This changes things so that users no longer need to know the epoch, and instead query with `(message, txHash)`. If more than one message is found in the tx matching `message`, we throw and request an additional optional param `messageIndexInTx`. If this is passed, then we assert that the message at that index indeed matches `message`. Most users should not need to pass the index, but it is there in case it is needed. It is expected that apps would know the messages they're interested in, and can look at indices from the tx effects. Doing this requires fetching the epoch as well as checkpoint, block and tx indices from the node. There was no API for checkpoint data, so I exposed `getCheckpointsDataForEpoch` so that we can find the checkpoint's index in the epoch. I also added the epoch number to the tx receipt. --- I used Claude heavily here as I don't really know my way around the node and archiver code, but I think the result makes sense. Closes #20874 --------- Co-authored-by: Claude Opus 4.6 <[email protected]> Co-authored-by: AztecBot <[email protected]> Co-authored-by: Santiago Palladino <[email protected]>
## Summary PR #21231 changed the `computeL2ToL1MembershipWitness` API signature from `(node, epoch, message)` to `(node, message, txHash)`, but the `example_swap` docs example (added in PR #20233) was written against the old API. This caused the merge-train CI to fail with `TypeError: Cannot read properties of undefined (reading 'siblingPath')` because the function received wrong arguments and returned `undefined`. ## Changes - Removed `RollupContract` import and usage (no longer needed to manually compute epoch) - Updated both `computeL2ToL1MembershipWitness` calls to use new signature: `(node, message, txHash)` - Get epoch numbers from the returned witness (`witness.epochNumber`) instead of computing manually ClaudeBox log: https://claudebox.work/s/5eb93c1235ed3384?run=2 Co-authored-by: esau <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
BEGIN_COMMIT_OVERRIDE
fix: skip oracle version check for pinned protocol contracts (#21349)
fix: not reusing tags of partially reverted txs (#20817)
feat: move storage_slot from partial commitment to completion hash (#21351)
feat: offchain reception (#20893)
fix: handle workspace members in needsRecompile crate collection (#21284)
fix(aztec-nr): return Option from decode functions and fix event commitment capacity (#21264)
fix: handle bad note lengths on compute_note_hash_and_nullifier (#21271)
fix: address review feedback from PRs #21284 and #21237 (#21369)
fix: claim contract & improve nullif docs (#21234)
feat!: auto-enqueue public init nullifier for contracts with public functions (#20775)
fix: search for all note nonces instead of just the one for the note index (#21438)
fix: set anvilSlotsInAnEpoch in e2e_offchain_payment to prevent finalization race (#21452)
fix: complete legacy oracle mappings for all pinned contracts (#21404)
fix: correct inverted constrained encryption check in message delivery (#21399)
feat!: improve L2ToL1MessageWitness API (#21231)
fix: update example_swap to use new L2ToL1MembershipWitness API (#21466)
END_COMMIT_OVERRIDE