test(e2e): onchain message delivery harness#24373
Conversation
…rce) Cross-PXE buildMessageDeliveryTest over constrained/unconstrained delivery x handshake/arbitrary-secret sources, plus an it.failing F-770 cell. Renames e2e_constrained_delivery -> e2e_onchain_delivery; adds unconstrained emit fns + TestWallet.registerArbitrarySecret. Also regenerates a stale e2e jest testEnvironment ref flagged by prepare:check.
It now exercises both constrained and unconstrained delivery, matching the e2e_onchain_delivery suite. Also dedupes two redundant harness comments.
Extend the onchain-delivery harness with two coverage cells: - constrained x arbitrary secret, asserting the in-circuit rejection (an unconstrained secret cannot back constrained delivery), pinning the PXE->circuit soundness boundary end to end. - a handshake bootstrapped constrained and reused unconstrained, with a tripwire hook so cross-PXE discovery is a durable proof of mode-agnostic reuse even after the unconstrained default changes. Replace the expectRed boolean with a discovered/undiscoverable/rejected outcome and allow per-message-type modes.
… into mv/e2e-onchain-delivery-harness
Add a permanent `not-discoverable` outcome (asserts PXE B discovers nothing) alongside the temporary `xfail-discovered` (F-770), plus cells pinning that an arbitrary secret or an address-derived sender the recipient never registered is undiscoverable, while a registered one is discovered.
| }); | ||
| }); | ||
|
|
||
| describe('constrained delivery', () => { |
There was a problem hiding this comment.
These are all constrained delivery specific tests I felt would be good to keep such as the concurrency and batching tests.
There was a problem hiding this comment.
I think we shouldn't mix the two. This file should be for generic automatic tests. Specific tests should be on another file (maybe we shouldn't delete the other e2e test)
Add the reverse of the existing cross-mode cell: unconstrained events bootstrap the handshake, constrained notes reuse it. This is the stricter reuse direction. A constrained reuse validates the reused secret against the registry at index 0 and chains by sequence nullifier, so a cross-mode tagging index leak would fail in-circuit here, where the tolerant unconstrained scan in the forward cell absorbs it silently. The mode-keyed sender index this relies on is PXE-side (unit tests mock the index oracle), so e2e is the only level that exercises this direction.
nchamo
left a comment
There was a problem hiding this comment.
I love that we are going to have this! We actually never tested arbitrary points before, and it's great that we can now easily tell they work
| kind: NEW_NON_INTERACTIVE_HANDSHAKE, | ||
| secrets: AppSiloedHandshakeSecrets { shared: 0, sender_only: 0 }, | ||
| } | ||
| Self { kind: NEW_NON_INTERACTIVE_HANDSHAKE, secrets: AppSiloedHandshakeSecrets { shared: 0, sender_only: 0 } } |
There was a problem hiding this comment.
Why does this happen? I though the CI would check formatting now, but we keep having formatting differences?
There was a problem hiding this comment.
Yeah this is weird, I will rebuild my local noir-repo (although we have been at beta.22 for some time). nargo fmt is being checked so this must be version drift.
There was a problem hiding this comment.
I think fmt might be non-deterministic or something I need to investigate further why we keep seeing formatting drift.
| }); | ||
| }); | ||
|
|
||
| describe('constrained delivery', () => { |
There was a problem hiding this comment.
I think we shouldn't mix the two. This file should be for generic automatic tests. Specific tests should be on another file (maybe we shouldn't delete the other e2e test)
| // Cross-PXE is the meaningful setup: PXE B holds no sender state, so a cell only "discovers" a message if the source | ||
| // truly reached it, which is also what makes the not-discoverable and rejected cells meaningful. | ||
| function buildMessageDeliveryTest(opts: { | ||
| description: string; |
There was a problem hiding this comment.
I think that instead of description we can call it strategy and then build description = ${strategy} - ${mode} or something like that
| // PERMANENT privacy boundary asserted with `it`; a leak that surfaces the delivery to PXE B flips it red. | ||
| // - 'rejected': PXE A's send is rejected in-circuit because the resolved source cannot back the mode. Asserted with | ||
| // `it` against `message`. | ||
| type DeliveryOutcome = |
There was a problem hiding this comment.
I think we should be only testing "green" or "discovered" outcomes:
xfail-discoveredwill go away with feat(pxe): default unconstrained delivery to a handshake #24387not-discoverableis the "opposite test" of the actual discovered test. They can be inferred by looking at what the actual discovered tests did. And they already document what and why they are doing what they are doing (like registering a point or a sender)rejectedfeels more like a specific test for those methods, not something we should generalize
I think this tests should simply focus on available msg delivery methods, and what each one of them needs to do to make it work (clear by senderHook and recipientRegistration)
There was a problem hiding this comment.
Done. The matrix is discovered-only now.
One negative I kept coverage for, just not in this PR's matrix. Dropping the address-derived negative removed the only check that registerSender actually gates discovery. I added a unit test to log_service.test.ts.
…ice test Semantic conflict with #24451 from the fairies-v5 merge: addAccount now takes AccountPrivacyKeys instead of a secret-key Fr.
ContractInstancePreimage no longer carries an address field; derive it from the address returned by pxe.registerContract instead of reading the removed instance.address. Fixes the tsgo TS2339 build failure on merge-train/fairies-v5.
The tests array listed the automine subdirectories explicitly and also kept the src/automine/!(simulation)/**/*.test.ts catch-all (a merge artifact), so every nested automine test was emitted as two identical cmds. Both copies run under the same docker container name; when they overlap, one docker_isolate force-removes the other's live container, failing that test, and the fresh-named retry then passes. That is the mass automine FLAKED pattern (49 per run) on this stack. The deduplicated unique cmd set is unchanged (145 automine jobs).
The polling loop from #24469 was guarding against dockerd's "container name still bound after inspect returns not-found" race under host load. In practice the exit condition (`docker container inspect` returns not-found) is a strictly weaker invariant than the one docker run --name actually needs, so the poll broke out fast and `docker run` still hit Conflict. The observed 'Conflict, name already in use' failures on this stack turned out to be a duplicate-emission bug in `test_cmds` (fixed on this PR), which produced two sibling docker_isolate invocations racing on the same name. With the tests-array dedup in place, no two invocations claim the same name in a run, so the polling has nothing left to guard. Left the pre-existing `docker rm -f "$name"` line intact — cheap, useful for the ordinary 'leftover container from an earlier phase' case. Added a note in end-to-end/bootstrap.sh next to the tests array so a future reader who accidentally reintroduces a duplicate path sees the symptom-to-cause mapping without having to re-derive it.
Co-authored-by: Maxim Vezenov <mvezenov@gmail.com>
nchamo
left a comment
There was a problem hiding this comment.
Amazing work! Left some comments because I think we are over-explaining logic in comments, even though you've made the code perfectly clear. Some of then were already outdated, since we changed defaults
| }); | ||
|
|
||
| // Address-derived discovery is gated on registering the sender: the recipient can only reconstruct a sender's tags | ||
| // for senders in `getSenders()` (plus its own accounts). This pins that gate through `fetchTaggedLogs` end to end. |
There was a problem hiding this comment.
| // for senders in `getSenders()` (plus its own accounts). This pins that gate through `fetchTaggedLogs` end to end. | |
| // for explicitly registered senders. |
There was a problem hiding this comment.
I just folded this into the test title
|
|
||
| // Onchain private delivery has two orthogonal axes: the delivery MODE (constrained = nullifier-chained sequence; | ||
| // unconstrained = no nullifier, windowed scan) and the tagging-secret SOURCE, which the wallet's | ||
| // `resolveTaggingSecretStrategy` hook selects. This harness exercises (strategy, mode) cells end to end across two |
There was a problem hiding this comment.
Should we link resolveTaggingSecretStrategy properly?
There was a problem hiding this comment.
There is some more info on SenderHook. @aztec/pxe/server exposes the hook through PXECreationOptions, so SenderHook derives the callback type from that public type instead of importing the internal hook type. A proper link would require a new public export of ExecutionHooks which feels unnecessary for just the test harness comment.
Co-authored-by: Nicolas Chamo <nicolas@chamo.com.ar>
Co-authored-by: Nicolas Chamo <nicolas@chamo.com.ar>
…test.ts Co-authored-by: Nicolas Chamo <nicolas@chamo.com.ar>
…test.ts Co-authored-by: Nicolas Chamo <nicolas@chamo.com.ar>
Fixes F-701
Fixes F-768
Cross-PXE harness for onchain private delivery over two axes: delivery mode x tagging-secret source. Lives in
yarn-project/end-to-end/src/automine/delivery/, split intoonchain.test.ts(the generic strategy x mode harness) andconstrained.test.ts(single-PXE constrained sequencing + the soundness boundary), both wired intobootstrap.sh.buildMessageDeliveryTest({ strategy, mode, senderHook, recipientRegistration? }). PXE A sends, isolated PXE B discovers from on-chain logs + the HandshakeRegistry.senderHookis required: every cell states its source explicitly rather than leaning on the PXE default.modecan split per message type ({ events, notes }) to exercise cross-mode reuse.These green cells are not unit-coverable: discovery is PXE-side scanning, so only a cross-PXE harness proves a message reached an isolated wallet.
constrained.test.tskeeps the single-PXE constrained sequencing suite (handshake reuse, concurrency/batching) plusrejects unsound sources.Renames
e2e_constrained_delivery-> theautomine/deliverysplit above, and theConstrainedDeliveryTestcontract ->OnchainDeliveryTest. Addsemit_*_unconstrainedtest-contract fns +TestWallet.registerTaggingSecretSource(passthrough toPXE.registerTaggingSecretSourcefor any non-sender source, replacing the narrowerregisterArbitrarySecret).