#36608 Reimplement private broadcast as node state-less jobs + package relay support

ReviewabilityReviewsAgreementSize
#36608 instagibbs Reimplement private broadcast as node state-less jobs + package relay supportNeeds rebase0Crickets7,403 + 9,808 tests
  • Eliminate deanonymization risks and timing leaks when broadcasting private transactions
  • Allow broadcasting low-fee private transactions that rely on child-pays-for-parent package relay
  • Author directed review to slimmed-down PR #36628 instead
  • No review verdicts recorded
  • No substantive discussion or review comments yet
  • Author noted that reviewers should look at PR #36628 instead
  • 7,403 lines added or modified outside tests
  • 9,808 lines added or modified in tests
  • 4,442 lines removed in total
  • 121 files, 35 commits
Mempool and policy#9 of 14
P3 · bug fix
  • P3 because it enables 1-parent-1-child package relay for transactions needing fee bumping
  • Fixes a fee sum overflow bug during package handling with extreme prioritisetransaction deltas
P2P#6 of 71
P1 · bug fix
  • P1 because it eliminates critical deanonymization risks and timing oracles in private broadcasting
  • Removes reliance on node state that peers could probe or manipulate via address gossip
  • Ranking pass: Ranked just below its base #36628, which it depends on and whose direction must be decided first.
Tools and scripts#4 of 16
P2 · new feature
  • P2 after comparing with the other PRs here (assessed alone as P3): Raised to P2: the problem is recurring privacy/deanonymization leaks in private broadcast, a security-class issue, not merely a new CLI utility.
  • P3 because it provides a standalone utility to privately broadcast transactions without running bitcoind
  • Offers isolated relay over Tor and BIP324 as a dedicated CLI tool
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

Replaces Bitcoin Core's private broadcast implementation with an isolated, node-stateless job engine and introduces a standalone bitcoin-privbcast CLI tool. Transaction broadcast targets are selected by resolving DNS seeds through Tor SOCKS5 proxies using dedicated circuits, and connections are established strictly over BIP324 v2 transport according to a pre-calculated random schedule. The PR removes legacy private broadcast peer connections and relay code from net and PeerManager, and extends the new engine to support 1-parent-1-child package relay via submitpackage.

Problem: The existing in-tree private broadcast mechanism relies on node state (such as addrman, peer discouragement, and mempool arrival monitoring). This creates observable timing oracles and fingerprinting vectors that an adversary can probe or manipulate via address gossip. In addition, the existing subsystem lacks package relay support, preventing private broadcast of low-fee transactions needing child-pays-for-parent to enter the mempool.

Evidence of importance:

  • PR description details historical privacy regressions and leaks from relying on node state, including a proxy bypass on v2-to-v1 retry (#35319/#35410), peer discouragement creating a clearnet oracle (#36312), mempool inspection leaking completion timing (#36277), and addrman state pollution (#35032)
  • PR description notes that drawing destinations from addrman allows remote peers to influence and fingerprint destination selection through address gossip
  • Commit ee5719d0c6 fixes a validation bug where two prioritisetransaction deltas near INT64_MIN caused a modified fee sum overflow in package handling

Scope: Very large multi-part change (+17k/-4.4k lines across 121 files) organized in four distinct sections: moving shared transport and BIP324 code into the common library, specifying and implementing the standalone bitcoin-privbcast tool, refactoring bitcoind -privatebroadcast into job queues while deleting legacy net/peerman broadcast logic, and adding 1P1C package validation and relay support. More than 11,000 lines are new unit, functional, and fuzz tests.

Risk of a mistake: high (p2p, validation, rpc_api, tooling). Mistakes in the new SOCKS5 proxy state machine or BIP324 attempt loops could leak user IP addresses or fail transaction broadcasting entirely, while changes to package acceptance logic in validation could introduce mempool inconsistencies or crashes.

What the assessment lacked:

  • rest_of_diff

Reviewability

Ready · Needs rebase

Conflicts with master; review the logic now, the rebase is mechanical.

Waiting on (from the thread read):

  • author: PR is in draft; author pointed reviewers to slimmed down PR #36628 2026-10-23
  • author: PR is in draft; author directed review to PR #36628 instead 2026-10-23

Agreement

Crickets

no substantive comment either way

Thread notes: Initial record for draft PR. No reviewer comments yet; the author noted in c:6369998981 that #36628 is the branch to review. / Initial record. Draft PR with no reviewer comments; the author directed review to slimmed-down PR #36628.

Objections, suggestions, and questions: none recorded.

Files

11641 lines under test/bench/ci.

  • src/test/privbcast_job_tests.cpp +1413/-0
  • test/functional/p2p_private_broadcast.py +761/-388
  • src/net.cpp +16/-1113
  • src/net_transport.cpp +917/-0
  • src/test/privbcast_attempt_tests.cpp +824/-0
  • src/test/fuzz/privbcast_queue.cpp +712/-0
  • src/test/privbcast_queue_tests.cpp +698/-0
  • doc/design/private-broadcast-tool.md +589/-0
  • src/net.h +7/-567
  • src/test/fuzz/privbcast_attempt.cpp +513/-0
  • src/test/privbcast_input_tests.cpp +511/-0
  • test/functional/tool_privbcast.py +505/-0
  • src/privbcast/job.cpp +504/-0
  • src/net_transport.h +495/-0
  • src/node/privbcast.cpp +464/-0
  • src/test/fuzz/privbcast_discovery.cpp +462/-0
  • src/rpc/mempool.cpp +320/-83
  • src/privbcast/attempt.cpp +400/-0
  • src/test/privbcast_rpc_tests.cpp +361/-0
  • src/bitcoin-privbcast.cpp +353/-0
  • test/functional/test_framework/privbcast.py +335/-0
  • src/test/private_broadcast_tests.cpp +0/-334
  • src/test/privbcast_discovery_tests.cpp +316/-0
  • src/node/privbcast.h +310/-0
  • src/private_broadcast.h +0/-271
  • src/net_processing.cpp +15/-251
  • test/functional/tool_privbcast_package.py +266/-0
  • src/test/fuzz/p2p_private_broadcast.cpp +0/-258
  • test/functional/tool_privbcast_peers.py +256/-0
  • src/test/fuzz/private_broadcast.cpp +0/-250
  • src/privbcast/stream.cpp +234/-0
  • src/test/privbcast_assign_tests.cpp +233/-0
  • src/privbcast/attempt.h +232/-0
  • src/test/fuzz/privbcast_socks5.cpp +223/-0
  • src/privbcast/job.h +215/-0
  • src/test/util/net.cpp +209/-4
  • src/private_broadcast.cpp +0/-209
  • src/privbcast/socks5.cpp +204/-0
  • test/functional/p2p_private_broadcast_retry_v1.py +0/-199
  • src/privbcast/input.cpp +198/-0
  • src/test/privbcast_plan_tests.cpp +185/-0
  • src/test/privbcast_socks5_tests.cpp +178/-0
  • src/privbcast/discovery.cpp +171/-0
  • src/privbcast/report.cpp +171/-0
  • test/functional/tool_privbcast_proxy.py +168/-0
  • src/privbcast/params.h +153/-0
  • doc/private-broadcast.md +137/-0
  • test/functional/test_framework/test_framework.py +9/-120
  • src/privbcast/report.h +118/-0
  • src/privbcast/socks5.h +115/-0
  • test/functional/p2p_private_broadcast_cap.py +43/-72
  • test/functional/test_framework/socks5.py +101/-13
  • src/privbcast/stream.h +111/-0
  • src/test/txpackage_tests.cpp +109/-0
  • src/privbcast/assign.cpp +106/-0
  • src/privbcast/assign.h +104/-0
  • src/test/util/net.h +103/-1
  • src/validation.cpp +83/-20
  • src/privbcast/discovery.h +101/-0
  • test/functional/p2p_private_broadcast_completion.py +0/-99
  • src/test/fuzz/privbcast_input.cpp +97/-0
  • src/privbcast/input.h +94/-0
  • src/init.cpp +55/-30
  • src/privbcast/plan.cpp +75/-0
  • src/test/util/privbcast.h +75/-0
  • doc/release-notes-privbcast-node.md +58/-0
  • src/privbcast/plan.h +53/-0
  • src/test/fuzz/package_eval.cpp +44/-0
  • doc/release-notes-privbcast-package.md +36/-0
  • src/test/denialofservice_tests.cpp +1/-34
  • src/bitcoin-privbcast-res.rc +33/-0
  • test/functional/feature_config_args.py +17/-16
  • src/test/net_tests.cpp +0/-30
  • src/net_processing.h +0/-29
  • src/test/util/privbcast_queue.h +29/-0
  • src/CMakeLists.txt +24/-3
  • src/privbcast/CMakeLists.txt +24/-0
  • doc/release-notes-privbcast-tool.md +22/-0
  • src/node/transaction.cpp +21/-1
  • src/node/transaction.h +13/-0
  • src/test/CMakeLists.txt +10/-1
  • test/functional/feature_signet.py +9/-0
  • src/test/fuzz/CMakeLists.txt +6/-2
  • src/test/fuzz/connman.cpp +1/-7
  • src/node/connection_types.h +0/-7
  • src/rpc/net.cpp +3/-4
  • src/validation.h +6/-1
  • test/functional/test_runner.py +5/-2
  • src/node/types.h +4/-2
  • test/functional/feature_init.py +6/-0
  • doc/man/bitcoin-privbcast.1 +5/-0
  • src/qt/rpcconsole.cpp +1/-4
  • test/functional/test_framework/util.py +5/-0
  • src/common/messages.cpp +4/-0
  • test/functional/test_framework/p2p.py +3/-1
  • CMakeLists.txt +3/-0
  • cmake/module/Maintenance.cmake +2/-1
  • src/bitcoin.cpp +3/-0
  • src/netbase.h +3/-0
  • src/netmessagemaker.h +2/-1
  • src/node/context.h +3/-0
  • src/primitives/transaction.h +1/-2
  • src/test/fuzz/p2p_transport_serialization.cpp +2/-1
  • src/bench/txorphanage.cpp +1/-1
  • src/bitcoin-cli.cpp +0/-2
  • src/kernel/chainparams.cpp +2/-0
  • src/netbase.cpp +1/-1
  • src/node/connection_types.cpp +0/-2
  • src/node/peerman_args.cpp +0/-2
  • src/node/txorphanage.h +1/-1
  • src/qt/guiutil.cpp +0/-2
  • src/rpc/util.cpp +2/-0
  • .github/ci-windows.py +1/-0
  • contrib/devtools/gen-manpages.py +1/-0
  • doc/README.md +1/-0
  • src/interfaces/node.h +1/-0
  • src/node/context.cpp +1/-0
  • src/node/interfaces.cpp +1/-0
  • src/rpc/blockchain.cpp +1/-0
  • test/CMakeLists.txt +1/-0
  • test/config.ini.in +1/-0

Card

The short text the ranking pass compares across PRs.

This PR completely replaces Bitcoin Core's private broadcast subsystem with an isolated, node-stateless job runner and introduces a standalone bitcoin-privbcast utility. The new design contacts DNS seeds over Tor to find IPv4/IPv6 peers and connects according to a predetermined randomized schedule over BIP324 v2 transport, eliminating reliance on internal node state and addrman. It removes the previous private broadcast peer connection and relay logic from net and PeerManager and adds 1-parent-1-child package relay support to submitpackage. The change is motivated by recurring privacy leaks in the legacy design, including direct proxy bypasses and clearnet peer discouragement oracles. It touches P2P networking, package validation, RPC, and CLI tooling across 121 files.

Data

dossier JSON · extract JSON · model ledger, generated 2026-10-24T01:19, confidence high, input hash c94a90d369174beb
thread read through 2026-10-23 (1 statements), head eec78ccf7d
labels: Needs rebase, Private Broadcast · draft

Categories

Mempool and policy

P3 · bug fix

Adds 1-parent-1-child package support to private broadcast and fixes a package fee overflow bug. Commit ee5719d0c6 fixes a validation bug where prioritisetransaction deltas near INT64_MIN caused a modified fee sum overflow in package handling.

Membership: Modifies package acceptance and relay handling in src/rpc/mempool.cpp and fixes package fee validation logic.

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

P2P

P1 · bug fix (ranking pass: Ranked just below its base #36628, which it depends on and whose direction must be decided first.)

Eliminates severe deanonymization risks and timing oracles in transaction broadcasting. Relying on node state creates observable timing oracles, addrman manipulation vectors, and proxy bypasses (#35319/#35410, #36312, #36277), making an isolated broadcast engine critical for network privacy.

Membership: Carries the 'Private Broadcast' label and rewrites P2P private broadcast connection, relay, and peer management logic in src/net.cpp and src/net_processing.cpp.

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

Tools and scripts

P2 · new feature (assessed alone as P3; Raised to P2: the problem is recurring privacy/deanonymization leaks in private broadcast, a security-class issue, not merely a new CLI utility.)

Introduces bitcoin-privbcast as an isolated standalone tool for private transaction relay. It allows broadcasting over Tor SOCKS5 and BIP324 without requiring bitcoind node state.

Membership: Adds the new standalone bitcoin-privbcast command-line utility in src/bitcoin-privbcast.cpp.

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