rust-payjoin icon indicating copy to clipboard operation
rust-payjoin copied to clipboard

There is no documented best practice or API to display historical payjoin activity

Open DanGould opened this issue 1 year ago • 4 comments

there is no off-the-shelf way to display historical activity for both senders receivers once a payjoin was initiated, updated, and completed. Basically we want to be able to add "payjoin happened" to a tx history screen (or cli output) in a consistent way. And we want to have documentation and an API around best practices wrt that

any particular protocol offers a number of user-facing APIs that are ~independent from the particular implementation. For Payjoin users, they need some thing that allows them to identify where their money went, and probably the'd expect this thing to be the same independently from which particular wallet they use. Similar probably could be said for some kind of identifier for the flow by which they can easily discern which payment is which if they, e.g., have multiple concurrent payments going on. We probably can find some good contenders for both of these in the concrete LDK Node implementation, but it feels almost like a layer violation as it's essentially not up to us to make up typical APIs for the payjoin protocol. Hence my view that, as all implementors would have the same issue, it might be good to provide clear guidance in rust-payjoin itself.

@tnull

Fortunately there are multiple implementations (payjoin-cli, nolooking, LDK-Node, Mutiny) to reference and come up with a unified solution:

This seems more like a wallet issue than a rust-payjoin issue since the historical activity is related to a label of activity.

payjoin-cli details

payjoin-cli stores Sender and Receiver structs serialized as json and identified by Sender::pj_uri() and Receiver::id() respectively I think the first thing to figure out is whether or not this is sufficient. Historical data is maintained by the blockchain at bitcoin core without issue. Does this serialization make sense?

DanGould avatar Aug 06 '24 15:08 DanGould

related: https://github.com/SatoshiPortal/bullbitcoin-mobile/pull/372

arminsabouri avatar Feb 24 '25 18:02 arminsabouri

There seems to be two motivations for this work:

  1. Restore state in case of crashes. For example if we require the reciever to store the state machine state at each step they can recover at the last state in case of an application crash. This has an interesting consequence of also allowing the application to revert states. Not sure why you would want to at this moment.
  2. Displaying Payjoin history to the end user

Imo there is two ways to consider this.

  1. We make it non optional. i.e for every reciver state machine update you must pass in a closure that will accept a encoded version of the state and persist it. If the caller really is not interested in persisting they can just pass in a dummy closure. Or we can keep it Optional. This will break the current interface unless we have a "persist" versions of the state transition functions. For example
pub fn check_broadcast_suitability_and_persist(
        self,
        min_fee_rate: Option<FeeRate>,
        can_broadcast: impl Fn(&bitcoin::Transaction) -> Result<bool, ImplementationError>,
        persist_state: Option<impl Fn(&Self) -> ()>,
    ) -> Result<MaybeInputsOwned, ReplyableError> {
      ...
      if let Some(persist_state) = persist_state {
                persist_state(&self);
      }

  1. We can impl serde on each state machine struct. The caller can chose to persist the state machine however they want.

Edit: meeting notes Save state trait for sender + reciver. A simple interface would include a get method to get a key and a body which is serialized.

arminsabouri avatar Feb 24 '25 19:02 arminsabouri

One open question is what format do we chose for the serialized data? JSON comes with some data overhead but its ussually universally accepted by most software projects. And it would make the implementation easier as we can just use serde::json.

It looks like its also the prefered option of payjoin cli

cc @DanGould

arminsabouri avatar Feb 24 '25 21:02 arminsabouri

Update:

We are considering two different designs for the persistence layer:

#560 – Ephemeral Receiver and Sender #552 – Persistable Types Both approaches enable the application to persist the sender/receiver when they are first instantiated. In future iterations, we can explore more granular state machine persistence—for example, persisting the receiver state after processing data from the directory. That would be a separate effort.

As of now, both PRs maintain feature parity with the current payjoin-cli behavior: persisting the receiver/sender at instantiation and removing them when the Payjoin is complete.

#552 introduces a unifying trait to standardize persistence across multiple types, making it easier to extend persistence to other state machine components in the future. #560 focuses on ensuring data integrity by delaying the instantiation of specific components until after persistence is complete.

arminsabouri avatar Mar 12 '25 14:03 arminsabouri

Are we satisfied that the Session Event Log resolves this issue? If not, what else is missing?

spacebear21 avatar Jul 17 '25 21:07 spacebear21

The only thing missing is a refrence for "displaying historical payjoin activity" in payjoin-cli. But that can be its own ticket.

arminsabouri avatar Jul 18 '25 13:07 arminsabouri

I think a reference is fair bounds within this ticket. we still have not demonstrated best practice. getting there

DanGould avatar Jul 18 '25 13:07 DanGould

The only thing missing is a refrence for "displaying historical payjoin activity" in payjoin-cli. But that can be its own ticket.

This can take the shape of a new command --history <active | inactive>. Maybe by default we display all. Inactive sessions should be sorted by created_at. Active sessions should be sorted by completed_at. If session is fatally terminated error should be provided in human readable format. All sessions should be printed in a tabular format with \n delimiting sessions

arminsabouri avatar Sep 02 '25 19:09 arminsabouri

I'd prefer a subcommand -- history just like send, receive. vs an option --history. A first iteration that displays all seems appropriate.

DanGould avatar Sep 03 '25 15:09 DanGould

Our refrence implementation has suitable db schema that can be used as a refrence for other integrations https://github.com/payjoin/rust-payjoin/blob/master/payjoin-cli/src/db/mod.rs

arminsabouri avatar Oct 03 '25 16:10 arminsabouri