Skip to content

test(e2e): onchain message delivery harness#24373

Merged
vezenovm merged 52 commits into
merge-train/fairies-v5from
mv/e2e-onchain-delivery-harness
Jul 7, 2026
Merged

test(e2e): onchain message delivery harness#24373
vezenovm merged 52 commits into
merge-train/fairies-v5from
mv/e2e-onchain-delivery-harness

Conversation

@vezenovm

@vezenovm vezenovm commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

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 into onchain.test.ts (the generic strategy x mode harness) and constrained.test.ts (single-PXE constrained sequencing + the soundness boundary), both wired into bootstrap.sh.

buildMessageDeliveryTest({ strategy, mode, senderHook, recipientRegistration? }). PXE A sends, isolated PXE B discovers from on-chain logs + the HandshakeRegistry. senderHook is required: every cell states its source explicitly rather than leaning on the PXE default. mode can split per message type ({ events, notes }) to exercise cross-mode reuse.

  • handshake x constrained: green
  • handshake x unconstrained: green
  • arbitrary secret x unconstrained (recipient registers it): green
  • address-derived x unconstrained (recipient registers the sender): green
  • cross-mode, constrained bootstrap then unconstrained reuse on one handshake: green
  • cross-mode, unconstrained bootstrap then constrained reuse on one handshake: green (the stricter direction: the constrained reuse proves the predecessor sequence nullifier and validates the reused secret against the registry at index 0, where the tolerant unconstrained scan in the forward cell would absorb it silently)

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.ts keeps the single-PXE constrained sequencing suite (handshake reuse, concurrency/batching) plus rejects unsound sources.

Renames e2e_constrained_delivery -> the automine/delivery split above, and the ConstrainedDeliveryTest contract -> OnchainDeliveryTest. Adds emit_*_unconstrained test-contract fns + TestWallet.registerTaggingSecretSource (passthrough to PXE.registerTaggingSecretSource for any non-sender source, replacing the narrower registerArbitrarySecret).

…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.
@vezenovm vezenovm added the ci-draft Run CI on draft PRs. label Jun 29, 2026
vezenovm added 7 commits June 29, 2026 13:05
It now exercises both constrained and unconstrained delivery, matching the e2e_onchain_delivery suite. Also dedupes two redundant harness comments.
An earlier prepare:check regen rewrote jest.testEnvironment to the package.common.json template value, which disables #24281's per-test TimingEnvironment. Restore the base value (net-zero vs base; the template mismatch is #24281's pre-existing concern).
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.
@vezenovm vezenovm changed the title test(end-to-end): onchain message delivery harness test(e2e): onchain message delivery harness Jun 29, 2026
Comment thread yarn-project/end-to-end/package.local.json
vezenovm added 6 commits June 29, 2026 15:37
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', () => {

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.

These are all constrained delivery specific tests I felt would be good to keep such as the concurrency and batching tests.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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)

@vezenovm vezenovm requested a review from nchamo June 29, 2026 20:52
@vezenovm vezenovm marked this pull request as ready for review June 29, 2026 20:53
@vezenovm vezenovm marked this pull request as draft June 29, 2026 20:55
vezenovm added 2 commits June 29, 2026 17:14
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.
@vezenovm vezenovm marked this pull request as ready for review June 29, 2026 21:29

@nchamo nchamo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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 } }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why does this happen? I though the CI would check formatting now, but we keep having formatting differences?

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.

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.

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 think fmt might be non-deterministic or something I need to investigate further why we keep seeing formatting drift.

Comment thread yarn-project/end-to-end/src/test-wallet/test_wallet.ts Outdated
Comment thread yarn-project/end-to-end/src/e2e_onchain_delivery.test.ts Outdated
});
});

describe('constrained delivery', () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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)

Comment thread yarn-project/end-to-end/src/e2e_onchain_delivery.test.ts Outdated
// 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;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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 =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we should be only testing "green" or "discovered" outcomes:

  • xfail-discovered will go away with feat(pxe): default unconstrained delivery to a handshake #24387
  • not-discoverable is 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)
  • rejected feels 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)

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.

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.

vezenovm and others added 3 commits July 2, 2026 17:24
…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.
@vezenovm vezenovm added the claudebox Owned by claudebox. it can push to this PR. label Jul 6, 2026
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).
@AztecBot AztecBot added the ci-draft Run CI on draft PRs. label Jul 6, 2026
AztecBot and others added 2 commits July 6, 2026 18:02
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.
Comment thread yarn-project/end-to-end/src/automine/delivery/constrained.test.ts Outdated
Comment thread yarn-project/end-to-end/src/automine/delivery/constrained.test.ts Outdated
Comment thread yarn-project/end-to-end/src/automine/delivery/constrained.test.ts Outdated
Comment thread yarn-project/end-to-end/src/automine/delivery/constrained.test.ts Outdated
Co-authored-by: Maxim Vezenov <mvezenov@gmail.com>
@vezenovm vezenovm requested a review from nchamo July 6, 2026 18:44

@nchamo nchamo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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

Comment thread yarn-project/end-to-end/src/automine/delivery/onchain.test.ts Outdated
Comment thread yarn-project/end-to-end/src/automine/delivery/onchain.test.ts
Comment thread yarn-project/end-to-end/src/automine/delivery/handshake_reuse.test.ts Outdated
Comment thread yarn-project/end-to-end/src/automine/delivery/constrained.test.ts Outdated
Comment thread yarn-project/end-to-end/src/automine/delivery/constrained.test.ts Outdated
Comment thread yarn-project/end-to-end/src/automine/delivery/onchain.test.ts Outdated
Comment thread yarn-project/end-to-end/src/automine/delivery/onchain.test.ts Outdated
Comment thread yarn-project/end-to-end/src/automine/delivery/onchain.test.ts Outdated
});

// 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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
// for senders in `getSenders()` (plus its own accounts). This pins that gate through `fetchTaggedLogs` end to end.
// for explicitly registered senders.

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 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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should we link resolveTaggingSecretStrategy properly?

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.

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.

vezenovm and others added 6 commits July 6, 2026 17:10
@vezenovm vezenovm requested a review from nchamo July 6, 2026 21:37
Comment thread ci3/docker_isolate Outdated

@nchamo nchamo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Great work!

@vezenovm vezenovm merged commit ba55176 into merge-train/fairies-v5 Jul 7, 2026
12 checks passed
@vezenovm vezenovm deleted the mv/e2e-onchain-delivery-harness branch July 7, 2026 13:41
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. ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure claudebox Owned by claudebox. it can push to this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants