mutiny-node
mutiny-node copied to clipboard
Receive payjoin
Request + receive payjoin v2. This change includes v1 backwards-compatible payjoin v2 sending.
In order to become a production feature some implementation details should be considered:
Fetch Oblivious HTTP Configuration
The payjoin directory server's OHTTP Key Configuration defines it's encryption keys independent of TLS. This information is fetched in this PR using an HTTPS-in-WebSocket tunnel so it can be retrieved without revealing the client IP to the payjoin directory server in order to preserve the privacy described in BIP 77.
Display &ohttp=
gateway configuration in bip21 uri
This is done via https://github.com/MutinyWallet/mutiny-web/pull/947
Oblivious HTTP Relays
Independent oblivious HTTP relays are being run by obscuravpn.io and bobspaces.net. Their URLs are included in the changed files.
closes #194
I'm curious what ohttp adoption is looking like
Oblivious HTTP is still a draft, but is implemented in Chrome, Firefox, Cloudflare and Apple operating systems. It is used for Oblivious DNS over HTTP with a relay deployed by Fastly.
and what information is gained by running one? I guess the assumption would be that the ohttp proxy and the service are not the same people and not colluding? What, if any, information gained by the payjoin server or ohttp proxy? Trying to think through what it makes sense to host or have others host that we link to in app.
OHTTP relies on 2 distinct servers. The OHTTP Relay Resource sees the client IP and the OHTTP Gateway Resource target IP, behind which the target resource may be accessed. The OHTTP Relay sees an encrypted ohttp-req
message. It does NOT see the contents of the message. It only sees an ohttp-res
message and not the contents of a response either.
The OHTTP Gateway sees that the request came from the OHTTP Relay IP, and may decrypt the contents of the request: a second layer of e2ee between sender and receiver and the pubkey associated with that session (a pseudonymous subdirectory identifier for the session)
The threat model in the BIP assumes they do not collude. If they do collude, they may correlate the subdirectory with sender and receiver IP addresses to discover only that 2 IP addresses may have communicated with one another at the Payjoin relay subdirectory at a given time.
Would users be able to select their own ohttp proxy and their own payjoin servers? Ideally we don't have to host or hard code it in order for it to work, though potentially willing to if it makes sense.
I would suggest users don't select their own proxy for the initial rollout for three reasons.
- Dependency compatibility: OHTTP's specified Hybrid Pub Key Encryption HMAC-based Extract-and-Expand Key Derivation Function does not support the secp256k1 curve. I've specified a change which uses secp256k1 so that bitcoin software does not need any external crypto in order to use payjoin v2. Secp256k1, sha256, and chacha20poly1305 are all already part of the bitcoin stack and secure for the purposes of such a protocol. There is a formal process to get secp256k1 into the spec Key Encapsulation Mechanisms via IANA and potentially the browsers/operating systems. However, the spec does not prevent us from building working software today. EDIT: someone is already registering secp256k1 with IANA!
- UX: Any external relay would need to support secp256k1 or potentially be incompatible with a payjoin peer. Any draft spec external OHTTP Relay will not support secp256k1 at time of writing. If a payjoin Relay relied on an OHTTP Gateway configuration using only curves other than secp256k1, which is guaranteed to be available in bitcoin software, some payjoin-enabled wallets may not be able to communicate with them.
- Privacy: Mutiny clients already reveal their IP address to Mutiny and don't need to reveal it to another service. There is also an anonymity set benefit of having as many users using the same OHTTP relay as possible.
By running an OHTTP relay, could anyone use that to connect to any other OHTTP gateway? I'm guessing the relay would see what IP is connecting to what gateway, but could there be multiple services behind any given gateway?
By running an OHTTP relay, could anyone use that to connect to any other OHTTP gateway?
In section 8.2: "The relay will only forward for Oblivious Gateway Resources that it has explicitly configured and allowed."
I'm guessing the relay would see what IP is connecting to what gateway, but could there be multiple services behind any given gateway?
Yes, yes, and specific path, query, methods, request body, headers are all encrypted from the ohttp relay's view
Okay thank you, this is very helpful. Just trying to understand the operational side of OHTTP and whether we should stand one up. Regardless of who runs what, I like the approach and the code is clean and makes sense. Appreciate the work there!
edit: ohttp-relay is now available as a docker container here: BYO ssl cert and the rest just workstm
FYI standing up a relay is as simple as adding a couple blocks to nginx if you're already running it somewhere
http {
# HTTP Server Block
server {
listen 80;
server_name your-server-name.com;
location /ohttp-relay {
# Forward requests to the OHTTP Gateway
proxy_pass https://ohttp-gateway.example.com;
# Clear the X-Real-IP header
proxy_set_header X-Real-IP "";
# Make default proxy_pass behavior explicit for good measure
access_log /path/to/http-access.log;
error_log /path/to/http-error.log;
}
}
# HTTPS Server Block
server {
listen 443 ssl;
server_name your-server-name.com;
ssl_certificate /path/to/your/certificate.crt;
ssl_certificate_key /path/to/your/private.key;
location /ohttp-relay {
# Forward requests to the OHTTP Gateway
proxy_pass https://ohttp-gateway.example.com;
# Clear the X-Real-IP header
proxy_set_header X-Real-IP "";
# Make default proxy_pass behavior explicit for good measure
access_log /path/to/https-access.log;
error_log /path/to/https-error.log;
}
}
}
This should now be receiving v2 payjoins, however the persistence and asynchronous completion is still a bit janky in this form factor. It does not seem like resume_payjoins
is properly resuming sessions on startup.
We've also got to consider how to display pending payjoin in activity. It seems like that UI list is only considering broadcasted transactions and pending lightning payments at the moment. This introduces a new tx pending state where a PSBT has been signed and posted to a payjoin directory but not yet responded to (from a sender) or responded to but not yet broadcast by the sender (for a receiver).
I think v2 payjoin receivers who sign should show transactions pending, since only 1 step remains before the transaction is broadcast, and they've effectively been probed and revealed their utxo. v2 Senders perhaps should not treat a single signature as pending, since they both need to have receiver sign and check the result, at least until BDK allows us to lock UTXOs. Still, a sender in this state could have their original psbt broadcast by a receiver. I'll have to look into how you're handling pending lightning payments to become inspired with a solution regarding pending payjoins.
I think it's valid to consider it as pending in the UI. I think we just do a filter on ActivityItems
before returning it. We may have to save these in our DB for it to reflect state accurately.
This is now based on the payjoin-0.13.0
release, persists receive payjoin sessions, and adds pending transactions to the wallet
using insert_tx
and cancel_tx
before they hit mempool. Though tracked payjoins are not explicitly marked as such. Their PSBTs are just put in the ActivityItem::Onchain
list. One way to explicitly mark them as payjoin would be to manually construct payjoin TransactionDetails
, add an is_payjoin
field or similar, store them in MutinyStorage
, and pull from that list in get_activity()
if this solution seems incomplete. This solution should work with the existing add_onchain_labels
since it attaches labels to addresses.
For now, the way the receiver here gets payjoin directory's ohttp-keys
does reveal IP address to the directory but that will be solved with the next deployment of ohttp-relay @teemie1
This would require the addition of &ohttp=
bip21 param parsing, ideally in bitcoin-waila, for ui support.
It might make some sense to separate backwards compatible send
payjoin support in another PR before this one to simplify review. #940 makes that possible.
While I've left a few TODOs that are in progress, this change is ready for deeper review
Sorry for the delay on this.
I want to be transparent, that we're pretty unsure about what we want to do with the on chain wallet long term. We're really not optimizing for on chain related activities and it has just caused various friction. Ideally long term we get to move towards something like splicing and can do splice outs for on chain payments, but until then, we've talked about removing the on chain wallet and defaulting to on chain going into a fedimint.
I've seen the discussions here which are great to see but would imagine it might be complex.
Not sure about this TBH, but curious your thoughts here.