#19461 multiprocess: Add bitcoin-gui -ipcconnect option
https://github.com/bitcoin/bitcoin/pull/19461 · · +4047/-567 in 142 files, 27 commits · labels: GUI, Utils/log/libs · draft
Goal
- Connect a GUI directly to an already running node process over IPC
- Allow users to start and close the graphical interface without shutting down the node
This pull request adds an `-ipcconnect` command-line option to `bitcoin-gui` when built with multiprocess support (`--enable-multiprocess`). It enables the GUI process to connect to an already-running `bitcoin-node` via Unix domain socket rather than spawning a dedicated node subprocess, allowing the GUI to start and stop independently. The PR also includes btcsignals changes to eagerly destroy callbacks on disconnect, resolving proxy object lifetime hangs.
Problem: In multiprocess mode, `bitcoin-gui` previously had to spawn and manage its own `bitcoin-node` subprocess, preventing users from attaching a graphical interface to an existing background daemon or stopping the GUI without killing the node.
Category: IPC / multiprocess (#5 of 20)
P2 · new feature
- P2 because it completes a central milestone of the multiprocess architecture
- Enables the GUI to attach to and detach from an external node process independently
Directly advances the multiprocess separation project by allowing bitcoin-gui to connect to an existing running node process instead of having to spawn one. ryanofsky notes: 'This allows the GUI to be started and stopped independently of the node.'
Membership: Adds `-ipcconnect` to bitcoin-gui and updates IPC initialization, connection lifecycle, and libmultiprocess subtree integration.
Factors: security/stability 1, bug 0, performance 1, user value 2, leverage 2
Category: Utilities (logging, arguments, libraries) (#26 of 66)
P3 · cleanup
- Improves `btcsignals` by making `disconnect()` eagerly destroy callbacks and their associated state, fixing a problem where node notification callbacks owning IPC proxy objects kept processes from exiting cleanly.
Improves `btcsignals` by making `disconnect()` eagerly destroy callbacks and their associated state, fixing a problem where node notification callbacks owning IPC proxy objects kept processes from exiting cleanly.
Membership: Labeled Utils/log/libs by maintainers; modifies src/util/btcsignals.h to align callback destruction semantics with boost::signals2.
Factors: security/stability 1, bug 1, performance 0, user value 0, leverage 1
Reviewability: Ready: Review #19460 first
The PR is at the tip of the multiprocess PR stack (on top of #10102, #29409, and #19460). While reviewable on its own merits, reviewing the base PRs first avoids reviewing code that is still subject to change upstream.
Author status: Active, periodically rebasing the branch across major releases and tracking reported multiprocess issues upstream.
Open concerns:
- A node started with `-disablewallet` crashes if `bitcoin-gui` connects to it without `-disablewallet` (tracked in libmultiprocess #169)
- Assertions fail when using external signer flows or PSBT creation over the IPC connection
Resolved concerns:
- Command-line option syntax and naming consistency settled on `-ipcconnect` matching `bitcoin-cli -rpcconnect`
- Node hangs on exit caused by deferred callback destruction in `btcsignals` addressed by eager destruction commit
Agreement: Mild
- Broad agreement on the feature and interface design
- Concept approval noting consistency with rpcconnect conventions (laanwj)
- Concept approval without stated reasons (meshcollider)
- Verified by testing remote GUI connections over an SSH socket (Sjors)
- Identified node crash on wallet flag mismatch, tracked as a follow-up (jimhashhq)
Positive with Concept ACKs (laanwj, meshcollider) and successful remote testing (Sjors), with nonblocking bug reports on edge cases (Sjors, jimhashhq)
The project strongly supports multiprocess process separation. Reviewers have confirmed the approach works in remote tunneling setups, and identified bugs are treated as normal experimental development issues tracked upstream rather than objections to merging.
- laanwj: 'Concept ACK, I've only reviewed the option help yet but -ipcconnect SGTM as option name'
- Sjors: 'Other than that, it seems to work. Cool stuff!'
- jimhashhq: 'I tried out -ipcconnect using rebased pr-19641... everything seemed to work consistent with my new understanding of multiprocess interactions'
Objections:
| Reviewer | Kind | Harm | Status | Blocking | Author replied | Quote |
|---|---|---|---|---|---|---|
| jimhashhq | correctness | bitcoin-node crashes when bitcoin-gui connects without -disablewallet to a node running with -disablewallet | open | no | yes | 2025-03-27: 'If bitcoin-node is run with -disablewallet subsequent start of a bitcoin-gui with -ipcconnect=auto, but without -disablewallet will crash bitcoin-node.' |
| Sjors | correctness | Assertion failure in sendButtonClicked when using external signer or PSBTs over IPC | open | no | yes | 2023-05-05: 'Assertion failed: (!complete), function sendButtonClicked, file sendcoinsdialog.cpp, line 525.' |
Support:
- laanwj: Supports the option naming and functionality: '-ipcconnect SGTM as option name, it reminds of -rpcconnect of the -cli client.'
- meshcollider: Concept ACK on multiprocess GUI connection [not substantive]
- Sjors: Successfully tested remote GUI connected to Ubuntu node over SSH socket tunnel
Participants: laanwj (support), maflcko (neutral), meshcollider (support), Sjors (objection), ClaraBara22 (support), jimhashhq (objection)
State derived from the lists: nonblocking objection open (jimhashhq, Sjors) (model's own read: Positive)
Review verdicts (DrahtBot): 0
- Concept ACK: laanwj, meshcollider
Dependencies
Depends on: #10102, #19460, #29409
Enables:
- Running headless bitcoind/bitcoin-node as a system daemon and connecting the GUI on demand
Based on (shares commits with): #10102, #19460, #29409
Files
173 lines under test/bench/ci.
- src/ipc/capnp/wallet.capnp +269/-0
- src/ipc/capnp/common-types.h +251/-2
- src/ipc/capnp/wallet.cpp +251/-0
- src/ipc/libmultiprocess/src/mp/util.cpp +216/-31
- src/ipc/capnp/node.capnp +213/-0
- src/ipc/libmultiprocess/test/mp/test/connect_tests.cpp +212/-0
- src/ipc/capnp/chain.cpp +208/-0
- src/ipc/libmultiprocess/test/mp/test/test.cpp +190/-6
- src/ipc/capnp/chain.capnp +189/-0
- src/ipc/libmultiprocess/src/mp/proxy.cpp +94/-35
- src/ipc/libmultiprocess/test/mp/test/listen_tests.cpp +47/-77
- src/ipc/capnp/chain-types.h +112/-0
- src/ipc/capnp/node-types.h +110/-0
- src/ipc/libmultiprocess/include/mp/proxy-io.h +74/-28
- src/ipc/capnp/node.cpp +97/-0
- src/init/bitcoin-wallet-ipc.cpp +85/-0
- src/ipc/capnp/common.capnp +84/-0
- src/ipc/libmultiprocess/test/mp/test/unixlistener.h +84/-0
- src/ipc/libmultiprocess/src/mp/gen.cpp +39/-41
- src/ipc/libmultiprocess/include/mp/util.h +63/-15
- src/util/btcsignals.h +69/-9
- src/ipc/capnp/wallet-types.h +55/-0
- src/ipc/capnp/common.cpp +51/-0
- src/test/btcsignals_tests.cpp +46/-0
- src/ipc/libmultiprocess/include/mp/proxy-types.h +31/-12
- src/qt/bitcoin.cpp +35/-8
- src/ipc/libmultiprocess/cmake/compat_config.cmake +0/-42
- src/ipc/capnp/init.cpp +40/-0
- src/ipc/capnp/node.h +40/-0
- src/ipc/libmultiprocess/include/mp/type-number.h +24/-15
- test/functional/test_framework/test_node.py +31/-8
- src/ipc/capnp/wallet.h +36/-0
- src/init/bitcoin-node.cpp +23/-12
- src/ipc/libmultiprocess/test/mp/test/spawn_tests.cpp +28/-5
- src/ipc/libmultiprocess/test/mp/test/foo.h +31/-1
- src/init/bitcoin-gui.cpp +9/-20
- src/ipc/capnp/common.h +27/-0
- src/ipc/libmultiprocess/include/mp/type-chrono.h +25/-2
- src/ipc/libmultiprocess/test/mp/test/common.h +27/-0
- src/ipc/capnp/init-types.h +25/-0
- src/ipc/libmultiprocess/.github/workflows/ci.yml +15/-9
- src/ipc/libmultiprocess/CMakeLists.txt +17/-7
- src/ipc/libmultiprocess/include/mp/type-struct.h +12/-12
- src/bitcoin-wallet.cpp +19/-3
- src/ipc/libmultiprocess/include/mp/type-interface.h +10/-10
- src/ipc/CMakeLists.txt +19/-0
- src/ipc/libmultiprocess/ci/scripts/ci.sh +18/-0
- src/ipc/libmultiprocess/include/mp/type-context.h +15/-3
- src/ipc/libmultiprocess/shell.nix +12/-6
- src/ipc/capnp/handler.capnp +17/-0
- CMakeLists.txt +14/-0
- src/ipc/capnp/context.h +14/-0
- src/ipc/libmultiprocess/include/mp/proxy.h +8/-6
- src/node/interfaces.cpp +10/-4
- src/ipc/libmultiprocess/example/calculator.cpp +4/-9
- src/ipc/libmultiprocess/example/printer.cpp +4/-9
- src/CMakeLists.txt +9/-3
- src/ipc/libmultiprocess/example/example.cpp +7/-5
- src/ipc/libmultiprocess/include/mp/type-char.h +9/-3
- src/ipc/libmultiprocess/test/mp/test/foo.capnp +12/-0
- test/functional/combine_logs.py +12/-0
- test/functional/feature_block.py +10/-2
- test/functional/wallet_multiwallet.py +6/-6
- src/wallet/wallettool.cpp +5/-6
- src/interfaces/node.h +5/-5
- src/ipc/capnp/handler-types.h +10/-0
- src/ipc/interfaces.cpp +6/-4
- src/ipc/libmultiprocess/doc/versions.md +8/-2
- src/init.cpp +6/-3
- src/interfaces/chain.h +5/-4
- src/ipc/capnp/init.capnp +9/-0
- src/qt/bitcoin.h +7/-2
- src/ipc/libmultiprocess/ci/configs/netbsd.bash +1/-7
- src/ipc/libmultiprocess/cmake/pthread_checks.cmake +8/-0
- src/ipc/libmultiprocess/include/mp/type-threadmap.h +4/-4
- src/wallet/init.cpp +8/-0
- test/functional/wallet_fast_rescan.py +4/-4
- test/functional/wallet_resendwallettransactions.py +4/-4
- doc/multiprocess.md +6/-0
- src/bitcoind.cpp +4/-2
- src/init/basic.cpp +3/-3
- src/ipc/libmultiprocess/ci/configs/newdeps.bash +6/-0
- src/ipc/libmultiprocess/doc/usage.md +6/-0
- src/ipc/libmultiprocess/test/mp/test/foo-types.h +6/-0
- src/qt/initexecutor.cpp +3/-3
- src/qt/test/apptests.h +5/-1
- src/wallet/wallettool.h +5/-1
- test/functional/wallet_groups.py +3/-3
- src/interfaces/init.h +4/-1
- src/interfaces/ipc.h +4/-1
- src/ipc/context.h +5/-0
- src/ipc/libmultiprocess/ci/configs/olddeps.bash +4/-1
- src/ipc/libmultiprocess/include/mp/type-data.h +2/-3
- src/wallet/types.h +5/-0
- src/init.h +2/-2
- src/interfaces/wallet.h +3/-1
- src/ipc/libmultiprocess/ci/configs/sanitize.bash +2/-2
- src/ipc/libmultiprocess/doc/design.md +2/-2
- src/ipc/libmultiprocess/include/mp/type-string.h +3/-1
- src/qt/test/apptests.cpp +2/-2
- src/qt/walletcontroller.cpp +2/-2
- src/init/common.cpp +2/-1
- src/ipc/libmultiprocess/.github/workflows/bitcoin-core-ci.yml +3/-0
- src/net.h +3/-0
- src/net_processing.h +3/-0
- src/wallet/coincontrol.h +3/-0
- test/lint/git-subtree-check.sh +2/-1
- contrib/devtools/circular-dependencies.py +1/-1
- doc/design/libraries.md +1/-1
- src/bitcoin-cli.cpp +1/-1
- src/init/common.h +1/-1
- src/ipc/libmultiprocess/ci/configs/default.bash +1/-1
- src/ipc/libmultiprocess/ci/configs/freebsd.bash +1/-1
- src/ipc/libmultiprocess/ci/configs/llvm.bash +1/-1
- src/ipc/libmultiprocess/ci/configs/macos.bash +1/-1
- src/ipc/libmultiprocess/ci/configs/openbsd.bash +1/-1
- src/ipc/libmultiprocess/cmake/TargetCapnpSources.cmake +1/-1
- src/ipc/libmultiprocess/doc/install.md +1/-1
- src/ipc/libmultiprocess/include/mp/type-function.h +1/-1
- src/ipc/libmultiprocess/include/mp/type-map.h +2/-0
- src/ipc/libmultiprocess/include/mp/version.h +1/-1
- src/ipc/stub.cpp +1/-1
- src/netbase.h +2/-0
- src/policy/fees/block_policy_estimator.h +2/-0
- src/qt/initexecutor.h +1/-1
- src/rpc/request.h +2/-0
- src/test/util/setup_common.cpp +1/-1
- src/util/result.h +1/-1
- src/wallet/interfaces.cpp +1/-1
- src/wallet/wallet.h +2/-0
- test/functional/wallet_createwallet.py +1/-1
- test/functional/wallet_descriptor.py +1/-1
- test/functional/wallet_encryption.py +1/-1
- test/functional/wallet_importdescriptors.py +1/-1
- test/functional/wallet_reorgsrestore.py +1/-1
- src/ipc/libmultiprocess/.clang-tidy +1/-0
- src/ipc/libmultiprocess/ci/README.md +1/-0
- src/ipc/libmultiprocess/include/mp/config.h.in +1/-0
- src/ipc/libmultiprocess/test/CMakeLists.txt +1/-0
- test/functional/feature_config_args.py +1/-0
- test/functional/feature_taproot.py +1/-0
- test/functional/wallet_transactiontime_rescan.py +1/-0
Card
multiprocess: Add bitcoin-gui -ipcconnect option allows the Qt GUI to connect to an existing bitcoin-node process via socket instead of spawning a new one. This unblocks running a continuous background node while attaching and detaching the GUI interface on demand. The PR is part of the multiprocess separation project and sits on top of #19460 and #10102. Reviewers have successfully tested remote connectivity over SSH socket forwarding, though minor edge cases around disabled wallet handling remain open.