private broadcast: wait synchronously for mempool acceptance #36566

pull andrewtoth wants to merge 4 commits into bitcoin:master from andrewtoth:private-broadcast-wait changing 17 files +259 −42
  1. andrewtoth commented at 5:57 PM on October 18, 2026: contributor

    Calling BroadcastTransaction with the NO_MEMPOOL_PRIVATE_BROADCAST method skips inserting the transaction into the mempool and returns immediately. This causes problems with software that expects the transaction to be in the mempool after the function returns. For example many third-party wallets or services call sendrawtransaction and expect the transaction to be in the mempool after it returns a successful response.

    This PR adds a new TransactionAddedToMempoolSync method to CValidationInterface. This is then used in BroadcastTransaction when the method is NO_MEMPOOL_PRIVATE_BROADCAST to wait for the transaction to have been accepted back into the mempool before returning. It also adds a timeout (default 10 minutes) to BroadcastTransaction and exposes it as an option for sendrawtransaction. Setting the timeout to 0 disables the wait and returns immediately, preserving the current behavior.

    Synchronously waiting for mempool acceptance is also a prerequisite for adding private broadcast support to the wallet. The TransactionAddedToMempoolSync method is added specifically for future wallet broadcasting, so a broadcast caller holding cs_wallet will not timeout waiting on another background event that is also trying to acquire cs_wallet.

  2. validation: add synchronous mempool acceptance notification
    Notify validation subscribers synchronously after queuing the existing mempool acceptance event. This allows acceptance waiters to wake independently of the background notification queue.
    9e7e5dcf78
  3. node: support waiting for private broadcast mempool acceptance
    Subscribe before private broadcast submission and wait for local mempool acceptance, timeout, or shutdown. Synchronous acceptance notifications allow callers holding the wallet lock to wait without draining its notification queue.
    8f89a7a95a
  4. rpc: wait for private broadcast acceptance in sendrawtransaction
    Expose the private broadcast timeout in sendrawtransaction and default private broadcasts to a ten-minute wait.
    9f3c95e8c4
  5. doc: add release notes for private broadcast wait bccae01515
  6. andrewtoth force-pushed on Oct 18, 2026
  7. fanquake added the label Private Broadcast on Oct 19, 2026
  8. DrahtBot commented at 12:28 PM on October 19, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--006a51241073e994b41acfe9ec718e94-->

    External sites

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline and AI policy for information on the review process. A summary of reviews will appear here.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #36628 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/36628.svg"></sub> (net: reimplement private broadcast as jobs isolated from the node by instagibbs)
    • #36608 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/36608.svg"></sub> (Reimplement private broadcast as node state-less jobs + package relay support by instagibbs)
    • #36607 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/36607.svg"></sub> (private broadcast: Extra guard against unintended non-private broadcast of private transactions by optout21)
    • #36597 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/36597.svg"></sub> (wallet: return broadcast errors from CommitTransaction by pseudoramdom)
    • #36482 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/36482.svg"></sub> (wallet: Only broadcast resubmitted transactions that were added to the mempool by achow101)
    • #36429 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/36429.svg"></sub> ([RFC] Delayed transaction broadcast, minimal by optout21)
    • #36384 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/36384.svg"></sub> (rpc: Use self.Arg<_>(name) helper over manual and duplicate parsing by maflcko)
    • #36167 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/36167.svg"></sub> ([RFC] Enable -Wunused by fanquake)
    • #36002 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/36002.svg"></sub> (txindex: allow running in pruned mode by andrewtoth)
    • #35728 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/35728.svg"></sub> (rpc: Properly throw on internal I/O errors in GetTransaction by maflcko)
    • #35511 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/35511.svg"></sub> (RFC: consensus: Make CAmount a class by hodlinator)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

  9. instagibbs commented at 5:22 PM on October 21, 2026: member

    For example many third-party wallets or services call sendrawtransaction and expect the transaction to be in the mempool after it returns a successful response.

    Can we gather a list of these?

    Given the Core wallet motivation in part I think I'd like to see end to end wallet integration before stepping through this change. Naively done, it could end up with some dangerous behavior for users, such as:

    • sendtoaddress hangs while Tor connects and the transaction travels out and back. Waits up to 10 minutes(?)
    • The user presses Ctrl-C. The transaction is already in the wallet and queued.
    • The user runs getbalance or listtransactions to check what happened. Both block on cs_wallet, so the user can't see that the first send went through. I think they'd have to inspect the private broadcast queue instead to know?
    • The user runs sendtoaddress again. It blocks on cs_wallet until the first call finishes. Then coin selection skips the now-spent inputs and builds a second transaction from other coins. Both get broadcast, and the user pays twice.

    sendtoaddress was never idempotent to begin with, which is kind of scary on its own, I just think this broadens the scope of possible loss through unclear UX. Users suddenly "losing" funds by stuff not being in mempool and not being accounted for will at least cause the users to slow down :/


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-10-30 09:40 UTC