payjoin / rust-payjoin

Supercharged payment batching to save you fees and preserve your privacy
https://payjoindevkit.org
85 stars 36 forks source link

Enable transaction cut-through #313

Closed spacebear21 closed 2 weeks ago

spacebear21 commented 3 months ago

Background: https://bitcointalk.org/index.php?topic=281848.0

To enable transaction cut-through, receivers should be able to completely replace the Original PSBT output(s) paying them with one or more new outputs, as long as they can provide inputs that cover the new output amount + fees.

A discussion was started in #277, on how this might look in the payjoin API. It would be great to determine the specific API changes required to support transaction cut-through and get them implemented ahead of a 1.0 release.

DanGould commented 3 months ago

259 is a sort of mirror to this I'd like to mention alongside this cut-through topology enhancement. While cut-through is a complication, allowing contributions to sweeps provides some fee savings with a simplification.

This is also related to #69

spacebear21 commented 2 months ago

Thinking about the input contribution step more...

The way input selection currently works:

With tx cut-through, things are more complicated:

spacebear21 commented 2 months ago

Also, it would be very helpful to have a list of concrete examples/test cases that cover realistic use cases for tx cut-through, e.g. opening lightning channels, utxo consolidation, forwarding payments (this could be many things, such as paying an invoice or an exchange processing a withdrawal batch)... any others?

Knowing exactly what we're building for makes it much easier to design a nice usable interface. And each use case might have different privacy requirements or other constraints.

DanGould commented 2 months ago

It does seem like the ProvisionalProposal typestate will need to be split. The common flow as you mention seems to be defining outputs and then selecting inputs to cover them, and finally handling change. The Payjoin state machines identify a "payee" output which assumes the receiver is the final payee. If replaced, a "receiver change" output needs to be identified if the payee address has change and completely replaces the payee output. I think your gut to identify a change output manually is good enough for a first draft. After we have a draft and practice on some integrations, a better interface is likely to appear for us if it is to be found.

Are there special privacy considerations here?

There are privacy considerations regarding Unnecessary Input Heuristic (UIH). I have notes on the academic research as I understand it, but my notes ignore subsets of inputs, which would need to be understood in order to avoid conforming to this heuristic. See the notes' footnotes to read state of the art research.

As far as I understand, some software does produce UIH variants without payjoin just to consolidate or to do other sorts of batching. We probably need to collect more data and study to find out which ones and how to concern ourselves with them.

My gut tells me that 1. defeating Common Input Heuristic (CIH) is more important, since that's the foundational privacy leak from the Satoshi paper and 2. Those Payjoin implementers focused on cost-savings won't concern themselves as much with UIH avoidance. Since first-class cut-through support breaks CIH and promotes wider adoption, I'm inclined to proceed with a limited understanding of subset UIH and support cut-through transactions for the time being.

Some Concrete examples

DanGould commented 2 months ago

Output augmentation where a receiver adds outputs paid for exclusively in amounts exceeding the payment output is possible even with payment output substitution disabled. Our API should be able to make transactions like this as well. This is related to the API but not strictly output substitution.

DanGould commented 2 weeks ago

closed by #332