Expose proposal txid stability on receiver states#1718
Open
chavic wants to merge 1 commit into
Open
Conversation
Monitor::check_for_transaction already knows the proposal's transaction ID cannot be tracked when the sender contributed non-SegWit inputs, and concludes the session as PayjoinProposalSent without checking the network. That knowledge arrives too late for receivers that record the expected transaction ID when handing out the proposal, e.g. to reconcile an incoming payment: with a non-SegWit sender input the recorded ID is silently wrong, because the sender's final signature rewrites the script_sig and changes the ID. Expose the predicate Monitor uses as proposal_txid_is_stable() on every state that holds the fallback transaction, and mirror it in payjoin-ffi. Receivers can now pick a policy as soon as the original payload is known: decline to contribute and let the fallback pay, or reconcile that session by script instead of by transaction ID.
2 tasks
Collaborator
Coverage Report for CI Build 29016109853Coverage increased (+0.004%) to 85.872%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is the 1.0-sized companion to the problem #1692 solves properly. #1692 makes non-SegWit sessions monitorable by classifying spends of the contested outpoints; this PR only makes the existing limitation visible at the right moment, without touching any frozen type. It's intended as the machine-readable form of the disclaimer suggested as the 1.0 mitigation in #1692 (document that
check_for_transactiondoesn't properly support non-SegWit inputs).Today,
Monitor::check_for_transactionknows the proposal's transaction ID cannot be tracked when the sender contributed non-SegWit inputs, and concludes the session asPayjoinProposalSentwithout checking the network. That knowledge arrives too late for receivers that do settlement accounting. A receiver that credits payments (a merchant server, an exchange) typically records the expected final transaction ID when it hands out the proposal — for SegWit-only sender inputs,unsigned_tx.compute_txid()stays valid once the sender re-signs, so pinning it enables exact reconciliation later. With any non-SegWit sender input the pinned ID is silently wrong: the sender's final signature rewrites the script_sig and changes the ID. Nothing warns the host at the moment the expectation is recorded; the first signal is the blind conclude at Monitor time.This exposes the predicate Monitor already uses as
proposal_txid_is_stable()on every state that holds the fallback transaction (theHasFallbackTxstates), refactorscheck_for_transactionto use it (behavior unchanged), and mirrors it in payjoin-ffi. Receivers can then pick a policy as soon as the original payload is checked: decline to contribute and let the fallback pay, or reconcile that session by script/outpoint instead of by transaction ID. The BTCPay Server payjoin plugin currently implements the conservative policy by parsing the original transaction host-side (ValeraFinebits/btcpayserver-payjoin-plugin#78); this accessor lets any wallet make the same call without re-deriving protocol internals.Relationship to #1692: strictly additive and shape-neutral, so it neither constrains nor competes with contested-outpoint classification. If/when that lands, this accessor degrades gracefully from "necessary policy input" to "convenience": hosts that reconcile by pinned transaction ID still want to know stability up front, while hosts on
classify()won't need it for monitoring at all.Disclosure: co-authored by Claude Code
Pull Request Checklist
Please confirm the following before requesting review:
AI
in the body of this PR.