payjoin / rust-payjoin

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

V2: Confusing sender/receiver UX flow #267

Closed thebrandonlucas closed 2 weeks ago

thebrandonlucas commented 1 month ago

Attempting to do a V2 transaction asynchronously results in some confusing behavior. I may be misunderstanding the intended flow. If I do:

  1. payjoin-cli receive 10000 and wait for the BIP_21 string
  2. Hit CTRL-C
  3. Run payjoin-cli send $BIP_21 --fee-rate=2

I see:

Sending fallback request to https://pj.bobspacebkk.com/

Then, after about 30 seconds:

Sent fallback transaction
The receiver sent an invalid response: v2 error: Payload too small
Sending fallback request to https://pj.bobspacebkk.com/

I see more of the same output after waiting, indicating that the sender is polling the above commands repeatedly. If the receiver comes back online with the --retry option, the payjoin completes successfully. However, if after the Sent fallback transaction message, you CTRL-C, then do payjoin-cli --retry receive 10000, I just get a new BIP 21 with a new address. It doesn't seem to acknowledge in any way that I have a session in place and that it retrieved the Original PSBT from the sender, modified it, and sent the Payjoin PSBT to the directory.

1) This polling from the sender unnecessary to me, unless it is simply to check if the receiver has modified the Original PSBT, since the directory is supposed to serve as a buffer and therefore the Original PSBT (called fallback transaction in payjoin-cli). In case this is simply a check for PSBT modification then the terminal output should reflect that with a message like "Checking for receiver PSBT modification..." instead of "Sending fallback transaction" multiple times.

2) It appears that under this scenario, the sender and receiver must be online at the same time during the Original PSBT modification by the receiver and while the sender is waiting for the Payjoin PSBT to be sent back so the sender broadcast. Interestingly, this mutual liveness requirement appears to be reflected in the final (non-polled) transmissions in the Payjoin V2 Draft BIP (shouldn't the last Directory -> Sender transmission containing the Payjoin PSBT be polled/retry-able?).

3) The message The receiver sent an invalid response: v2 error: Payload too small appears to be a bug? Considering that the payjoin completes successfully if the receiver comes back online during sender polling, payload size doesn't seem to be the issue.

Current UX:

Assumed/Ideal UX:

Apologies if I'm just misunderstanding something.

DanGould commented 1 month ago

The UI prints are no doubt lacking. However, session retry should work as long as you're retrying the first session that was saved. I was able to async receive with the following steps and I recorded a loom video to watch demonstrating on 6c34ea3. The receiver and sender are configured to different wallets, and I'm printing RUST_LOG=debug logs which share session details. Of course payjoin-cli is compiled with the v2 feature.

  1. Generate a bip21 from v2 receiver: payjoin-cli receive 12345
  2. Interrupt receiver C-c
  3. Save output `BIP21="bitcoin:..."
  4. payjoin-cli send $BIP21 --fee-rate=1. If successful, this posts an encrypted Original PSBT payload to the directory
  5. Interrupt sender C-c
  6. Retry receive payjoin-cli --retry receive 12345. This fetches the Original PSBT and POSTs a Payjoin PSBT to the directory.
  7. Interrupt receiver C-c
  8. Retry send payjoin-cli --retry send $BIP21 --fee-rate=1 Pulls the Payjoin PSBT payload, signs, and broadcasts, printing a Payjoin sent: <txid> message.

To answer your concerns:

This polling from the sender unnecessary to me, unless it is simply to check if the receiver has modified the Original PSBT ... shouldn't the last Directory -> Sender transmission containing the Payjoin PSBT be polled/retry-able?

The Original PSBT POST request is retried until the directory returns an error, the bip21 expires, or a response contains a Payjoin PSBT. The response is not retried.

The receiver sent an invalid response: v2 error: Payload too small appears to be a bug?

Perhaps. The payload may be small / response code is 204 instead of 200 to initiate another poll try.

My conclusion is that the session store in your environment must have only an old session. The payjoin-cli must manage multiple session states in the future instead of the alpha / PoC single state store. Currently it only saves one, and I'm not sure whether or not it overwrites old states. Retry the flow by first deleting the session states and starting with a clean directory and the retry should work.

DanGould commented 2 weeks ago