#36566 private broadcast: wait synchronously for mempool acceptance

ReviewabilityReviewsAgreementSize
#36566 andrewtoth private broadcast: wait synchronously for mempool acceptanceWaiting on author0Blocked107 + 152 tests
  • Ensure transactions sent via private broadcast are accepted into the mempool before returning success
  • Prevent third-party wallet failures and unblock future private broadcast support in the wallet
  • Ready to review
  • No review verdicts recorded
  • Unaddressed objection: synchronous waiting could cause wallet hangs leading to double payments (instagibbs)
  • Asks which third-party software currently requires synchronous mempool acceptance (instagibbs)
  • 107 lines added or modified outside tests
  • 152 lines added or modified in tests
  • 42 lines removed in total
  • 17 files, 4 commits
P2P#25 of 71
P2 · unblocks #N
  • P2 because it unblocks private transaction broadcast integration in the wallet
  • It provides the synchronization needed by external broadcast clients
RPC / REST / ZMQ#12 of 55
P2 · user request
  • P2 after comparing with the other PRs here (assessed alone as P3): Raised to P2 and moved up 17: it repairs a silent semantic break of sendrawtransaction for existing third-party callers and is a stated prerequisite for wallet private broadcast.
  • P3 because it allows callers to wait for mempool inclusion rather than returning immediately
  • It fixes broken assumptions for third-party wallets and services using sendrawtransaction
Reviewability: ReadyStalePaused
Agreement: StrongPositivePositive w/ caveatsNeutralMildDisputedBlockedCrickets
Reviews: current code-review ACKs, then (+stale ACKs) and -NACKs; greener = more ACKs.
Size: lines added or modified outside tests, then in tests; greener = smaller.

Goal

Adds synchronous mempool acceptance waiting to BroadcastTransaction for private broadcasts, exposed via an optional timeout argument (defaulting to 10 minutes) on sendrawtransaction. It introduces a synchronous TransactionAddedToMempoolSync callback to CValidationInterface that fires immediately upon mempool insertion instead of routing through the background validation queue. Setting timeout to 0 allows callers to bypass waiting and preserve the previous non-blocking behavior.

Problem: Private transaction broadcast skips local mempool insertion, returning immediately once queued for external broadcast. External software and third-party wallets calling sendrawtransaction expect a successful return to guarantee the transaction is already in the mempool. Furthermore, future wallet integration cannot wait on the asynchronous validation interface queue while holding cs_wallet without risking deadlocks or timeouts from blocked queue processing.

Evidence of importance:

  • PR description: "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."
  • PR description: "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."

Scope: Adds a synchronous callback to CValidationInterface alongside the asynchronous queue, and introduces a timeout loop with periodic shutdown checks in BroadcastTransaction.

Risk of a mistake: medium (validation, rpc_api). A synchronization or lock-order bug in the synchronous validation interface notification could hang RPC worker threads or disrupt transaction submission.

Reviewability

Paused · Waiting on author

Open objections from instagibbs with no author reply for 11 days; review would repeat what has been asked.

Waiting on (from the thread read):

  • author: address instagibbs's question regarding affected software and objection regarding wallet UX and double-spend risks 2026-10-21
  • author: response to instagibbs' question, suggestion for end-to-end integration, and UX safety concerns 2026-10-21

Agreement

Blocked

objection that needs a change, nobody has replied (instagibbs)

Thread notes: Initial record. instagibbs raised a question about which software requires synchronous mempool acceptance and objected that synchronous waiting can cause wallet hangs leading to double payments. / Initial review by instagibbs questioning the motivation for third-party software and raising safety concerns regarding wallet integration UX.

Objections, suggestions, and questions:

ReviewerTypeHarm, request, or questionStatusMust beAuthor repliedQuote
instagibbs (member)question, usefulnessCan we gather a list of third-party software and services that expect transactions to be in the mempool after sendrawtransaction returns?openansweredno2026-10-21: 'Can we gather a list of these?'
instagibbs (member)objection, safetyWaiting synchronously for mempool acceptance can cause wallet operations to hang for up to 10 minutes, leading users to cancel and retry, which risks paying twice and losing funds.openchangedno2026-10-21: 'Naively done, it could end up with some dangerous behavior for users, such as: ... broadens the scope of possible loss through unclear UX.'
instagibbs (member)objection, safetySynchronously waiting for mempool acceptance risks users accidentally paying twice if they abort a hanging broadcast and retryopenansweredno2026-10-21: 'I just think this broadens the scope of possible loss through unclear UX.'

Participants:

  • instagibbs (member, objection, 1 statements 2026-10-21 to 2026-10-21): asks which software needs this and objects that synchronous waiting could cause wallet hangs and duplicate payments

Dependencies

Enables:

  • Private broadcast support in the wallet

Files

166 lines under test/bench/ci.

  • src/node/transaction.cpp +63/-24
  • src/test/validationinterface_tests.cpp +79/-1
  • test/functional/p2p_private_broadcast_wait.py +59/-0
  • test/functional/p2p_private_broadcast.py +7/-7
  • src/node/transaction.h +11/-1
  • src/rpc/mempool.cpp +8/-3
  • doc/release-notes-private-broadcast-wait.md +10/-0
  • test/functional/p2p_private_broadcast_cap.py +3/-3
  • src/validationinterface.h +5/-0
  • src/common/messages.cpp +4/-0
  • test/functional/p2p_private_broadcast_completion.py +2/-2
  • src/node/types.h +2/-0
  • src/rpc/util.cpp +2/-0
  • test/functional/p2p_private_broadcast_retry_v1.py +1/-1
  • src/rpc/client.cpp +1/-0
  • src/validationinterface.cpp +1/-0
  • test/functional/test_runner.py +1/-0

Card

The short text the ranking pass compares across PRs.

Private transaction broadcasts bypass local mempool insertion and return immediately upon queueing, breaking downstream software and wallets that expect sendrawtransaction to guarantee mempool presence. This pull request adds a synchronous TransactionAddedToMempoolSync callback to CValidationInterface and makes BroadcastTransaction block until the transaction is accepted into the mempool or times out, defaulting to 10 minutes. By bypassing the asynchronous validation queue, the synchronous notification allows callers holding the wallet mutex to wait without risk of deadlocks from blocked background events. Setting the new timeout RPC parameter to zero preserves immediate return. This synchronous wait is a stated prerequisite for supporting private broadcast in the Bitcoin Core wallet.

Data

dossier JSON · extract JSON · model ledger, generated 2026-10-22T01:17, confidence high, input hash b4e68c7592f6587d
thread read through 2026-10-21 (1 statements), head bccae01515
labels: Private Broadcast

Categories

P2P

P2 · unblocks #N

Provides the synchronization needed for external clients and unblocks private broadcast integration in the wallet. The PR description notes that waiting synchronously for mempool acceptance resolves issues where software expects transactions in the mempool post-broadcast, and is a prerequisite for adding private broadcast support to the wallet.

Membership: Carries the Private Broadcast label and alters the node's private transaction broadcast synchronization behavior.

Factors: security/stability 1, bug 1, performance 0, user value 2, leverage 2

RPC / REST / ZMQ

P2 · user request (assessed alone as P3; Raised to P2 and moved up 17: it repairs a silent semantic break of sendrawtransaction for existing third-party callers and is a stated prerequisite for wallet private broadcast.)

Fixes caller assumptions around sendrawtransaction by allowing callers to wait for mempool inclusion. The PR description notes that third-party wallets and services call sendrawtransaction and expect the transaction to be in the mempool after a successful response.

Membership: Touches src/rpc/mempool.cpp and src/rpc/client.cpp, adding an optional timeout parameter to sendrawtransaction.

Factors: security/stability 1, bug 1, performance 0, user value 2, leverage 2