Skip to content

Rename Receiver<Monitor>::check_for_broadcast to check_for_transaction, etc.#1684

Merged
spacebear21 merged 1 commit into
payjoin:masterfrom
DanGould:check-for-transaction-rename
Jun 26, 2026
Merged

Rename Receiver<Monitor>::check_for_broadcast to check_for_transaction, etc.#1684
spacebear21 merged 1 commit into
payjoin:masterfrom
DanGould:check-for-transaction-rename

Conversation

@DanGould

@DanGould DanGould commented Jun 26, 2026

Copy link
Copy Markdown
Member

close #1656

& rename the predicate transaction_exists to find_transaction, because it's not returning a bool it's returning a TxID.

This change is done because broadcast is one possible interpretation of the success condition. Really, it's up to the wallet to determine at what point a transaction = a success for Payjoin, so the name reflects that.

But thinking about this revealed deeper problems (and some solutions to past problems) about the state machine design here which is that we're even making the check based on TxId in the first place because it limits detection to segwit transactions and we're just skipping detection otherwise (see #1214 , #1218). I don't see a good reason to force that disability to fit a particular monitor shape. There's another problem with this which is that our design treats detection from this method as the final verdict when even after broadcast detection of a payjoin it's still possible the fallback or another transaction double-spends the same outpoint used as receiver input.

The non-segwit detection issue can be solved by monitoring sender and receiver input outpoints as well as the fallback & payjoin Txids (if predictable via segwit). The monitor would then return SettlementStatus. See details below. This would let the wallet deal with reorgs and consistently return the correct SettlementStatus computed according to the wallet state, and wouldn't go stale by serializing event that's the result of a wallet snapshot as the permanent status of a particular payjoin, which is where this stands even after my proposal here.

A proposal for payjoin-2.0 monitor design
impl Receiver<Monitor> {
    fn payjoin_txid(&self) -> Txid;             // the payjoin tx
    fn fallback_txid(&self) -> Option<Txid>;         // None when non-segwit (txid unpredictable)

    // or for simplicity, do we JUST provide the OutPoints @ monitor and always ingest the Txid with whatever we detect to come up with the status?

    fn contested_outpoints(&self) -> Vec<OutPoint>; // sender inputs BOTH txs spend — the battleground
    fn receiver_input(&self) -> OutPoint;       // our contributed input — the payjoin "fingerprint"

}

The wallet reports raw facts; the payjoin library classifies

struct ChainView { spends: Vec<OutpointSpend> }
struct OutpointSpend { outpoint: OutPoint, spent_by: Option<Txid>, tx: Option<Transaction>, confirmations: u32 }

enum SettlementStatus {
    Pending,                                              // contested outpoints unspent
    Detected { outcome: Outcome, confirmations: u32 },    // confirmations == 0 means mempool
}
enum Outcome {
    Payjoin { sender_witnesses: Vec<(ScriptBuf, Witness)> }, // privacy achieved + the proof
    Fallback,                                                // original won; no privacy
    Other(Txid),                                             // outpoints spent by an unrecognized tx
}

impl Receiver<Monitor> {
    // Pure: maps observed cs/outpoints. No I/O.
    fn classify(&self, view: &ChainView) -> SettlementStatus;
}

I doubt that this updated follow-up Receiver<Monitor> change is critically necessary for 1.0. What we've shipped seems good enough for mobile wallets to get status. it seems like a critical necessity for automated exchange/service use cases to be robust enough to go prod, but ultimately I think it depends on how much bikeshedding the correct monitor requires and how much we're willing to push back an already long-passed deadline.

Pull Request Checklist

Please confirm the following before requesting review:

Yes indeed this was co-authored by Claude Code

"broadcast" over-claims what this checks. The caller's closure, not
the method, decides the condition that counts as success. Mempool
presence, n confirmations, etc. Naming the method after one point on
that spectrum is misleading because different environments have
different success conditions.

Rename the Receiver<Monitor> method to the neutral
check_for_transaction and reword its doc to say the closure defines
the found condition. Update the payjoin-ffi and payjoin-cli callsites
to match.

Also rename the closure from transaction_exists to find_transaction
(and the payjoin-ffi trait TransactionExists to TransactionFinder):
it returns the Option<Transaction> the method then uses to extract
the sender witnesses, so it is a lookup, not an exists predicate.

Pre-1.0 (rc.3), so no deprecation shim is needed.
@coveralls

Copy link
Copy Markdown
Collaborator

Coverage Report for CI Build 28235658451

Coverage remained the same at 85.517%

Details

  • Coverage remained the same as the base build.
  • Patch coverage: 1 uncovered change across 1 file (9 of 10 lines covered, 90.0%).
  • No coverage regressions found.

Uncovered Changes

File Changed Covered %
payjoin/src/core/receive/v2/mod.rs 9 8 88.89%
Total (2 files) 10 9 90.0%

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 15128
Covered Lines: 12937
Line Coverage: 85.52%
Coverage Strength: 361.74 hits per line

💛 - Coveralls

@DanGould DanGould added the api label Jun 26, 2026
@DanGould DanGould requested a review from spacebear21 June 26, 2026 12:30

@spacebear21 spacebear21 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cACK

@spacebear21 spacebear21 merged commit 3b75b2f into payjoin:master Jun 26, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Receiver<Monitor>::check_payment needs rename

3 participants