Skip to content

payjoin-mailroom: let relay operators accept OHTTP gateway purposes other than BIP77 #2024

Open

Description

@gf5901

Which crate is this feature request for (if any)?

payjoin-mailroom

Question

Please describe the feature you'd like to see added.

A config option for the OHTTP relay in payjoin-mailroom that lists the
gateway purposes the operator accepts, in addition to BIP77. For example:

[ohttp_relay]
# BIP77 is always accepted. Operators may opt in to other purposes.
extra_allowed_purposes = ["LanternZero v0 4bca76ac-1094-4330-97df-03d5c81b576d"]

The prober would treat a gateway as allowed if its
/.well-known/ohttp-gateway?allowed_purposes response lists any configured
purpose. Today it checks only MAGIC_BIP77_PURPOSE
(ohttp_relay/gateway_prober.rs).

Is your feature related to a problem, if so please describe it.

We're building Lantern Zero, an open-source (MIT/Apache-2.0) service that
gives Zcash wallets faster sync and payment notifications. All wallet
requests go over OHTTP through relays run by third parties: Zcash community
organizations, never the server operator.

We'd like those operators to run your relay rather than a new one we write.
It already has the hardening we'd otherwise have to reimplement: metadata
side-channel work (#1421), Retry-After handling in the prober (#1475), and
relay selection (#1514). The purpose check means it won't forward to our
gateway, and we don't want to claim the BIP77 purpose to get around that.

Describe the solution you'd like

  • Keep the opt-in model from [👣 TRACKING] Specify OHTTP relay <-> directory opt-in mechanism #472 as it is. The relay still forwards only to
    gateways that declare a purpose, and only to purposes the operator chose.
    BIP77 stays the default, so existing deployments don't change.
  • Replace Policy { bip77_allowed } with a check against the configured set.
    We're happy to write the PR, with tests.
  • Optional, could be a separate issue: a way to run the relay without the
    directory, for operators who only want to relay.

This also has an upside for Payjoin. A relay that carries more than one
protocol mixes their traffic, which gives each protocol's users a larger
crowd to hide in.

Describe any alternatives you've considered

  • Claiming the BIP77 purpose on our gateway: rejected. It would misuse
    relay operators' consent.
  • Writing our own relay: workable, but it duplicates security-sensitive
    code that you already maintain.
  • Forking payjoin-mailroom: the same duplication, with a maintenance
    burden on top.

Please leave any additional context

Our protocol spec, including the purpose string we declare (§3.1) and why
the server operator never chooses relays (§1.1):
https://github.com/principlezerolabs/lanternzero/blob/main/spec/v0.md

If you'd rather keep payjoin-mailroom Payjoin-only, we understand. A
quick yes or no would help us decide what to ship in our self-host kit.

Activity

  1. DanGould commented on Oct 31, 2026

    @DanGould
    Member

    How did you find this option? I'm not opposed to it in principle. Is completely different OHTTP Gateway infrastructure required and this just uses the relay? or does this proposal use mailboxes too?

  2. gf5901 commented on Oct 31, 2026

    @gf5901
    Author

    Thanks, Dan.

    How we found it: we were looking for an open-source OHTTP relay that Zcash community organizations could run. payjoin/ohttp-relay was the obvious Rust option. We saw it had been archived and moved into payjoin-mailroom, and while reading the code we found the opt-in check from #472 in ohttp_relay/gateway_prober.rs.

    Yes, the gateway is completely separate, and we only want the relay. Each Lantern Zero server runs its own RFC 9458 gateway at its origin root, the same layout the relay already expects:

    • GET /.well-known/ohttp-gateway: key configuration (RFC 9540)
    • GET /.well-known/ohttp-gateway?allowed_purposes: application/x-ohttp-allowed-purposes, in the u16-count format parse_alpn_encoded reads, listing only LanternZero v0 4bca76ac-1094-4330-97df-03d5c81b576d
    • POST /.well-known/ohttp-gateway: encapsulated requests

    Wallets would POST to https://<relay>/https://<lantern-zero-host>, exactly as BIP77 clients do today.

    No mailboxes and no directory. Lantern Zero is plain request and response between a wallet and its own server. For live updates the wallet long-polls its server for 25–30 s. That's the same shape as a BIP77 receiver polling a mailbox through the relay. Mailroom always starts the directory alongside the relay today, which is why we listed a relay-only mode as an optional follow-up.

    Number of gateways: small. There's one per hosted or wallet-sponsored server. Self-hosted servers mostly use a Tor onion service instead of OHTTP, so we don't expect relays to probe many origins.

    One question back: we have wallets fetch the key configuration through two different relays and compare the copies before using it. With mailroom, that would go through the CONNECT bootstrap tunnel, which also passes the purpose check. Is that tunnel fine for other protocols to use, and do you expect it to stay on by default?

    A correction to the issue: I listed relay selection (#1514) as something the relay already has. It's an open PR for client-side selection, so it isn't a reason by itself. #1421 and #1475 are the relay hardening I meant.

    If this works for you, I'm happy to open a PR. It would add a configured set of accepted purposes to RelayConfig, with BIP77 always included, and have the prober and parse_gateway_uri check against that set instead of Policy { bip77_allowed }. Tests would cover a non-BIP77 opt-in and the existing BIP77-only behavior. Do you have a preferred config shape, or should I follow the TOML in the issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions