The PR branch HEAD was 8a18a12a232 at the time of this review club meeting.
Currently Bitcoin Core code always runs within a single operating system
process. So if you are
running bitcoind, then you are running node and wallet code together in the
same process. If you are running bitcoin-qt, then you are running node,
wallet, and GUI code in the same process. Running all code in one process does
not provide a lot of isolation, so it means a crash in wallet code could bring
down the node, or a vulnerablility in the node could expose wallet data.
Additionally it’s not possible to run the node and wallet on different machines,
or to stop and start the GUI independently of the node, or use the GUI to
connect to nodes or wallets on headless machines.
PR #10102 starts to move away
from the single process model by adding basic support needed for bitcoin node,
wallet, and GUI code to run in different processes and communicate with each
other internally. Followups
#19461 expand on it to allow
wallet and GUI processes to be started and stopped independently, and allow the
processes to communicate with each other externally, and run on different
PR #10102, combined with the
--enable-multiprocess build option, builds a new bitcoin-node executable
that can be used as a drop-in replacement for bitcoind, and a new
bitcoin-gui executable that can be used a drop-in replacement of bitcoin-qt.
The new executables are used the same way as the previous ones and don’t provide
any new features externally, but internally they will spawn multiple processes
and use process separation. Instructions for building and testing #10102 can be
and can be done in a few commands on linux:
make -C depends NO_QT=1 MULTIPROCESS=1
When this is run, bitcoin-node will spawn a bitcoin-wallet executable to run
wallet code. The node and wallet processes will communicate across a socket,
with the node code controlling the wallet with
methods, and the wallet code calling the node with
methods. Similarly when GUI support is enabled, bitcoin-gui will spawn a
bitcoin-node process, and control it by calling
methods, and control wallets by calling
#10102 adds the plumbing that allows gui <-> node <-> wallet cross-process
communication to work transparently, without changing existing code, only
adding new code. This is possible because the interfaces in src/interfaces/
(interfaces::Chain, interfaces::Node, interfaces::Wallet described above)
are all abstract classes with virtual methods, so different implementations can
be substituted without changes to calling code. This PR adds new implementations
of each interface that forward method calls from one process to another. In
early versions of this PR, adding new implementations of each interface required
adding a lot of boilerplate code. Every method in every interface, and every
argument and return value of every method had to had custom C++ code written
that would handle the method call serialization and forwarding from the calling
process to the called process. For example, the
which is the same method that would have been called directly if code were
running in a single process instead of multiple processes.
Because the ipc::capnp::WalletImpl::encryptWallet and
ipc::capnp::WalletServer::encryptWallet methods above and all similar methods
just contain boilerplate code forwarding arguments and return values, newer
versions of this PR no longer define these methods manually, and instead
generate them automatically. (You can see these methods in generated
src/ipc/capnp/wallet.capnp.proxy-server.c++ files after building this PR, but
they are not part of the PR source code). The code generation means that adding
a new method or changing an existing method signature now just requires editing
a single line in the interface’s
The most significant commits are the “Add canp serialization…” and “Add capnp
wrapper…” commits which add Cap’n Proto schema
definitions describing Bitcoin’s struct
and interface types that are shared between processes:
These commits also add a lot of glue code in BuildField / ReadField/
BuildMessage / ReadMessage function. There is a lot of ugly C++ template
syntax needed to declare the function types, but the actual function bodies are
pretty straightforward and just copy information between Bitcoin Core’s native
data structures and corresponding capnp messages.
The other two significant commits in this PR are the “Make bitcoin-gui spawn a
bitcoin-node process” commit and “Make bitcoin-node spawn a bitcoin-wallet
process” commit. These commits don’t add much new code. Instead they strip out
wallet initialiatation code from the BitcoinNodeInit class (so the
bitcoin-node process no longer has wallet functionality linked in) and strip
out node and wallet initialization code from the BitcoinGuiInit class (so the
bitcoin-gui class no longer has node and wallet functionality linked in. Then
they add spawnProcess calls in appropriate places to start making
cross-process calls. A good entry point into these two commits is to search for
the new spawnProcess calls they add.
The other commits in this PR are needed for completeness but aren’t related to
its core functionality. They are smaller and just update dependencies, logging,
and test code.
<ryanofsky> I wonder what a better name for WalletClient might be. Really it only exists for backwards compatability so bitcoin-node will continue to load wallets by default. More ideally bitcoin-wallet would just connect to node, I think
<lightlike> advantages: there could be alternative implementations for parts, such as GUI or wallet; separating code like this makes it easier to be sure that parts that should be independent really are
<michaelfolkson> I guess in an idealized world there would be less cross talk and they would only talk when absolutely necessary or when they need something. But in reality we are dealing with Satoshi's inheritance so I'm not sure what the idealized state would be
<ryanofsky> michaelfolkson, very much agree. I think removing the most egregious polling is probably low hanging fruit for cleanup prs (independent of anything in 10102), and would also be good for improving gui performance
<ryanofsky> Q5 What is the difference between node and wallet running on different processes vs different threads? Why must they communicate via an IPC framework instead of calling each other's functions normally?
<ryanofsky> Q6 Where are the `spawnProcess` calls added in the "Make bitcoin-gui spawn..." and "Make bitcoin-node spawn..." commits? What type of interface pointer is requested from each of the spawned processes?
<lightlike> isn't one idea of the mulitprocess build that it could also apply in situations where sharing state in other ways would be physically impossible (like different processes running on different computers)?
<michaelfolkson> The wallet can't do anything without the node so it is not like the wallet process can continue doing useful stuff if the node goes down. So the wallet giving the node a bit of extra information that isn't strictly node information could make sense