Skip to content

Navigation Menu

Sign in
Appearance settings
Sign up
Appearance settings

Multiprocess bitcoin - #10102

#10102
Draft
ryanofsky wants to merge 24 commits into
bitcoin:masterbitcoin/bitcoin:masterfrom
ryanofsky:pr/ipcryanofsky/bitcoin:pr/ipcCopy head branch name to clipboard
Draft

Multiprocess bitcoin#10102
ryanofsky wants to merge 24 commits into
bitcoin:masterbitcoin/bitcoin:masterfrom
ryanofsky:pr/ipcryanofsky/bitcoin:pr/ipcCopy head branch name to clipboard

Conversation

@ryanofsky

@ryanofsky ryanofsky commented Mar 27, 2017

Copy link
Copy Markdown
Contributor

This is based on # + #29409. The non-base commits are:


This PR adds an --enable-multiprocess configure option which builds new bitcoin-node, bitcoin-wallet, and bitcoin-gui executables with relevant functionality isolated into different processes. See doc/design/multiprocess.md for usage details and future plans.

The change is implemented by adding a new Init interface that spawns new wallet and node subprocesses that can be controlled over a socketpair by calling Node, Wallet, and ChainClient methods. When running with split processes, you can see the IPC messages going back and forth in -debug=1 output. Followup PR's #19460 and #19461 add -ipcbind and -ipcconnect options that allow more flexibility in how processes are connected.

The IPC protocol used is Cap'n Proto, but this could be swapped out for another protocol. Cap'n Proto types and libraries are only accessed in the src/ipc/capnp/ directory, and not in any public headers or other parts of bitcoin code.

Slides from a presentation describing this change are available on google drive. Demo code used in the presentation was from an older version this PR (tag ipc.21, commits).


This PR is part of the process separation project.

@jonasschnelli

Copy link
Copy Markdown
Contributor

Oh. Nice.
I expected much more code to achieve this.

Conceptually I think this goes into the right direction, though, I'm not sure if this could end up being only a temporary in-between step that may end up being replaced.
Because, it may be more effective to split the Qt/d part completely and let them communicate over the p2p protocol (SPV and eventually RPC). More effective because it would also allow to run Qt independent from a trusted full node (if not trusted, use mechanism like full block SPV, etc.).

Though, I'm aware that capnp has an RPC layer. But this would introduce another API (RPC / ZMQ / REST and then capnp RPC).

I'm not saying this is the wrong direction, but we should be careful about adding another API.

Three questions:

  • Would the performance be impractical if we would try to use the existing RPC API?
  • Could the capnp approach (or lets say IPC approach) be designed as a (or the) new API ("JSON RPC v2" and replacement for ZMQ)?
  • Does capnp provide a basic form of authentication? Would that even be required?

@ryanofsky

Copy link
Copy Markdown
Contributor Author

Would the performance be impractical if we would try to use the existing RPC API?

Reason this is currently using capnp is not performance but convenience. Capnp provides a high level API that supports bidirectional, synchronous, and asynchronous calls out of the box and allows me to easily explore implementation choices in bitcoin-qt without having to worry about low level protocol details, write a lot of parameter packing/unpacking boilerplate, and implement things like long polling.

Capnp could definitely be replaced by JSON-RPC, though, and I've gone out of my way to support this by not calling capnp functions or using capnp types or headers anywhere except the ipc/server.cpp and ipc/client.cpp files. No code outside of these two files has to change in order to move to a different protocol.

Could the capnp approach (or lets say IPC approach) be designed as a (or the) new API ("JSON RPC v2" and replacement for ZMQ)?

It could, but I'm going out of my way right now specifically NOT to add yet another bitcoind public API that could add to the JSON-RPC/REST/ZMQ/-blocknotify/-walletnotify confusion. The IPC here doesn't happen over a TCP port or even a unix socket path but over an anonymous socketpair using an inherited file descriptor. (I haven't done a windows implementation yet but similar things are possible there).

I'm trying to make the change completely internal for now and transparent to users. Bitcoin-qt should still be invoked the same way and behave the same way as before, starting its own node and wallet. It just will happen to do this internally now by forking a bitcoind executable rather than calling in-process functions.

This change will not add any new command line or GUI options allowing bitcoin-qt to connect to bitcoinds other than the one it spawns internally. Adding these features and supporting new public APIs might be things we want to do in the future, but they would involve downsides and complications that I'm trying to avoid here.

Does capnp provide a basic form of authentication? Would that even be required?

It's not required here because this change doesn't expose any new socket or endpoint, but it could be supported. Capnp's security model is based on capabilities, so to add authentication, you would just define a factory function that takes credentials as parameters and returns a reference to an object exposing the appropriate functionality.

@gmaxwell

Copy link
Copy Markdown
Contributor

I'm really uncomfortable with using capn proto, but fine enough for some example testing stuff!

I'm a fan of this general approach (ignoring the use of capn proto) and I think we should have done something like it a long time ago.

@dcousens

dcousens commented Mar 28, 2017

Copy link
Copy Markdown
Contributor

strong concept ACK, but if is feasible, would prefer usage of the existing RPC instead of capn'proto

@laanwj

laanwj commented Mar 29, 2017

Copy link
Copy Markdown
Member

Concept ACK, nice.

I'm really uncomfortable with using capn proto, but fine enough for some example testing stuff!

Please, let's not turn this into a discussion of serialization and RPC frameworks. To be honest that's been one of the things that's putting me off of doing work like this. If you want to suggest what framework to use, please make a thorough investigation of what method would be best to use for our specific use case, and propose that, but let's not start throwing random "I'm not comfortable with X" comments.

We already use google protocol buffers in the GUI for payment requests to in a way that would be the straightforward choice. I'm also happy you didn't choose some XML-based abomonation or ASN.1. But anyhow, not here. For this pull it's fine to use whatever RPC mechanism you're comfortable with.

This change will not add any new command line or GUI options allowing bitcoin-qt to connect to bitcoinds other than the one it spawns internally.

I'm also perfectly fine with keeping the scope here to "communication between GUI and bitcoind". This is not the place for introducing another external interface. Might be an option at some point in the future, but for now process isolation is enough motivation.

Comment thread src/qt/walletmodel.cpp Outdated
Comment thread src/ipc/messages.capnp Outdated
Comment thread src/ipc/client.cpp Outdated
Comment thread src/qt/bitcoin.cpp Outdated
Comment thread src/qt/bitcoin.cpp Outdated
Comment thread src/qt/walletmodel.cpp Outdated
Comment thread src/ipc/server.cpp Outdated

@ryanofsky ryanofsky left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated and rebased bf5f8ed -> 0ca73bc (pr/ipc.0 -> pr/ipc.1)

There's a lot of new changes here. More functions and callbacks have been wrapped, and there's now support for asynchronous calls that don't block event threads in the client and server.

At this point it would be very helpful to have code review for the main commit (0ca73bc "Add barebones IPC framework to bitcoin-qt and bitcoind"), because all the real infrastructure is now in place, and the main thing left to do is wrap up more functions and callbacks in IPC calls so the GUI can be functional.

Comment thread src/qt/bitcoin.cpp Outdated
@ryanofsky

ryanofsky commented Apr 7, 2017

Copy link
Copy Markdown
Contributor Author

Updated and rebased 0ca73bc -> 5e28c2f (pr/ipc.1 -> pr/ipc.3) to avoid a conflict. Main addition is an expanded src/ipc/README.md file.

Again it would be very helpful to have some code review for the main commit (5e28c2f "Add barebones IPC framework to bitcoin-qt and bitcoind"). Giving feedback on the README file would be an easy place to start.

@ryanofsky
ryanofsky force-pushed the pr/ipc branch 2 times, most recently from 5e28c2f to dda3756 Compare April 10, 2017 22:00
@ryanofsky

Copy link
Copy Markdown
Contributor Author

Updated 5e28c2f -> dda3756 (pr/ipc.3 -> pr/ipc.4)

This implements two suggestions from @JeremyRubin:

  • It includes a small commit demonstrating what it looks like to add a single new method to the API:
    dda3756 Add ipc::Node::getNodeCount method. This should help give a clearer picture of the layers involved in implementing an IPC call.

  • Instead of adding Cap'n Proto code and modifying Qt code in a single commit, it includes a new early commit (1407a2b Add ipc::Node and ipc::Wallet interfaces that introduces new src/ipc/interfaces.h and src/ipc/interfaces.cpp files and ports Qt code to use them without any Cap'n Proto stuff. This shows the separation between Qt updates and IPC implementation details better and makes it easier to see how a different IPC system could be substituted in for Cap'n Proto. This commit could even be made into a separate PR.

@ryanofsky

ryanofsky commented Apr 14, 2017

Copy link
Copy Markdown
Contributor Author

@laanwj pointed out in IRC (https://botbot.me/freenode/bitcoin-core-dev/msg/83983170/) that this change could help make the GUI more responsive by preventing Qt event processing from getting blocked, which currently happens in the monolithic bitcoin-qt when the main GUI thread makes a call to a slow libbitcoin function, or waits a long time for a cs_main or cs_wallet lock.

At the time in IRC, I didn't think this change could directly help gui responsiveness, because although it does move libbitcoin and LOCK calls out of the bitcoin-qt process and into the bitcoind process, it just replaces these calls with blocking IPCs that make the GUI equally unresponsive when they tie up the main GUI thread.

However, this doesn't have to be the case. The place where IPC calls currently block waiting for responses is the return promise.get_future().get(); line in ipc::util::Call::send method here: https://github.com/ryanofsky/bitcoin/blob/pr/ipc.4/src/ipc/util.h#L166

But the std::promise object used in that line could easily be replaced with a Qt-aware promise object that processes GUI events while the promise is blocked. (The Qt-aware promise implementation would check if it is being used on the main GUI thread, and if so use a local Qt event loop substituting
loop.exec() for std::future::get() and loop.quit() for std::promise::set_value().)

This would add more overhead and make the average IPC call a little slower. But it would avoid situations where an unexpectedly slow IPC call ties up the whole gui, so it might be worth doing anyway.

@laanwj

laanwj commented Apr 14, 2017

Copy link
Copy Markdown
Member

@ryanofsky Yes, integrating the IPC event loop and Qt event loop would help responsiveness.
Though I remember there were some issues in some cases with recursively calling into the Qt event loop (e.g. things need to be reentrant, deleteLater stuff runs earlier than expected, to keep in mind).

@sipa

sipa commented Apr 17, 2017

Copy link
Copy Markdown
Member

@ryanofsky I'm not familiar with Qt or capnproto, but I don't understand what the move to a different process has to do with making things less blocking. Any changes in architecture that would result in less blocks should equally be possible within the same process.

@sipa

sipa commented Apr 17, 2017

Copy link
Copy Markdown
Member

This change will not add any new command line or GUI options allowing bitcoin-qt to connect to bitcoinds other than the one it spawns internally. Adding these features and supporting new public APIs might be things we want to do in the future, but they would involve downsides and complications that I'm trying to avoid here.

I don't understand the goal here. On itself, there seems little benefit in separating the GUI and the rest into separate processes if those two processes still depend on each other (this is different from separating the wallet from the node, for example, as there as security considerations there... but for that use case the easiest approach seems to just have a lightweight mode and running two instances).

I think it would be awesome if bitcoin-qt could be started and stopped independently to control a bitcoind process in the background, but if that's not the intent, what is the purpose?

@ryanofsky

Copy link
Copy Markdown
Contributor Author

Any changes in architecture that would result in less blocks should equally be possible within the same process.

Let's say there are 50 places where bitcoin-qt calls a libbitcoin function. That means there are 50 places to update if you want bitcoin-qt handle to events while the function calls are executing. WIth the IPC framework, there is only one place you have to update instead of 50 places (if you want to do this).

On itself, there seems little benefit in separating the GUI and the rest into separate processes if those two processes still depend on each other.

Ok, so you think the benefits are small, and I think they are more significant.

I think it would be awesome if bitcoin-qt could be started and stopped independently to control a bitcoind process in the background,

This is trivial once bitcoin-qt is controlling bitcoind across a socket. I'm just implementing the socket part first, without introducing new UI features for now.

@sipa

sipa commented Apr 17, 2017

Copy link
Copy Markdown
Member

I think it would be awesome if bitcoin-qt could be started and stopped independently to control a bitcoind process in the background,

This is trivial once bitcoin-qt is controlling bitcoind across a socket. I'm just implementing the socket part first, without introducing new UI features for now.

Ok, that's what I was missing. It wasn't clear to me that this was a just first step towards a more useful separation.

ryanofsky added a commit to ryanofsky/bitcoin that referenced this pull request Apr 20, 2017
This doesn't crash currently because the method doesn't access any object
members, but this behavior is fragile and incompatible with bitcoin#10102.
ryanofsky and others added 24 commits August 21, 2026 08:40
- Add capnp ToBlob, ToArray, Wrap, Serialize, and Unserialize helper functions
- Add support for std::chrono::seconds capnp serialization
- Add support for util::Result and util::Expected capnp serialization
275c8ee Merge bitcoin-core/libmultiprocess#345: Remove trailing whitespace and Add -Wtrailing-whitespace to default ci config
cd7162f Merge bitcoin-core/libmultiprocess#304: proxy: fix BuildList to use non-const iteration for interface types
9b13678 ci: Add -Wtrailing-whitespace to default config
2f4be9e refactor: Remove trailing whitespace
390b5f9 Merge bitcoin-core/libmultiprocess#344: test: listen_tests and connect_tests follow-ups
d6f8588 proxy: fix BuildList to use non-const iteration for interface types
e18ca52 Merge bitcoin-core/libmultiprocess#343: test: fix race in connect_tests disconnect-deferred-failure test
c39c785 doc: note construct() call in valid init interface test
b9c36c6 test: close sockets unconditionally and check errors with KJ_SYSCALL
7eb741e test: drop unnecessary KJ_EXPECT(true)
113f1d4 test: join server thread unconditionally in connect tests
44bc463 test: drop mp:: prefixes in connect tests
038d33e test: share DefaultLogHandler between test files
b54a163 test: drop TestSetup socket members in connect tests
70467c5 test: add m_ prefix to TestSetup members in connect tests
cc260f2 test: replace capnp fix link with upstream PR
137a6e4 test: fix race in connect_tests disconnect-deferred-failure test
8dab0d4 Merge bitcoin-core/libmultiprocess#341: ci: add -Wextra-semi to llvm config
b3b134e ci: add -Wextra-semi to llvm config
bdd0cd6 Merge bitcoin-core/libmultiprocess#339: refactor: add `[[noreturn]]` attributes
a779a09 ci: add -Wmissing-noreturn
636aaff refactor: add missing [[noreturn]] attributes
cc11c2b Merge bitcoin-core/libmultiprocess#338: test: check ReadList return value
2d6e863 Merge bitcoin-core/libmultiprocess#334: ci: Set CMAKE_BUILD_PARALLEL_LEVEL to enable parallelism by default
d4d10ff Merge bitcoin-core/libmultiprocess#332: ci: add -Wextra-semi to default config
b540e70 Merge bitcoin-core/libmultiprocess#324: proxy: Name threads spawned by the event loop
e5e367e Merge bitcoin-core/libmultiprocess#312: util: report back child errors to parent and throw
2220df6 Merge bitcoin-core/libmultiprocess#298: Fix error handling when creating clients (`mp::ConnectStream`)
51defb7 Merge bitcoin-core/libmultiprocess#340: ci: Update `capnproto` prerequisites on NetBSD
7e94790 ci: Update `capnproto` prerequisites on NetBSD
9f25ffc test: Cover OS thread names for worker, pool, and async threads
648a185 proxy: Name threads spawned by the event loop
49834b2 ci: add -Wextra-semi to default config
fae9a63 example: Remove unused kj/async.h include
bb47369 Fix error handling when creating clients
44d1914 Add test coverage for ConnectStream
231361a Correct stale UnixListener doc comment
060c1a5 Extract `UnixListener` class to a dedicated file
62f25af test: check ReadList return value
ce51d73 ci: Set CMAKE_BUILD_PARALLEL_LEVEL to enable parallism in build jobs by default
67302cd Merge bitcoin-core/libmultiprocess#331: Remove code for Cap'n Proto versions before 0.9
f13c64a Merge bitcoin-core/libmultiprocess#330: ci: Compile with minimum supported g++ in olddeps
8e026f6 Merge bitcoin-core/libmultiprocess#327: build: avoid unnecessary capnp-rpc dependency for mpgen
e5206e9 Merge bitcoin-core/libmultiprocess#325: cmake: Remove `QUIET` option from `find_package(CapnProto ...)`
879efea Merge bitcoin-core/libmultiprocess#321: ci: Roll NetBSD releases to 11.0, drop 9.4
abf127a Merge bitcoin-core/libmultiprocess#317: ipc: Fix mpgen capnp tool path for vcpkg/Windows builds
c437d7f Merge bitcoin-core/libmultiprocess#310: test: cover immediate client disconnects for `ListenConnections`
31bff8a Merge bitcoin-core/libmultiprocess#307: refactor: memcpy -> std::ranges::copy
f355108 Merge bitcoin-core/libmultiprocess#303: type-chrono: Add CustomBuildField/CustomReadField overloads for std::chrono::time_point
2d67817 Merge bitcoin-core/libmultiprocess#296: ci: Bump channel to nixos-26.05
3f05b11 util: kill and reap child on SpawnProcess error
4a56c18 util: report back child error to parent and throw
a9e70db ci: Add NetBSD release 11.0
2d33b14 ci: Switch to default compiler on NetBSD 9.4
36f7400 ci: Drop NetBSD release 9.4
bd50831 refactor: Drop stray semicolons after function definitions
788f17a Remove code for Cap'n Proto versions before 0.9
7402aff ci: Pin oldeps config to older nixpkgs channel to compile older cmake with older gcc
edf6343 ci: Compile with minimum supported g++-11 in olddeps
fa47449 cmake: avoid unnecessary capnp-rpc dependency for mpgen
a494b76 cmake: Remove `QUIET` option from `find_package(CapnProto ...)`
26452e0 refactor: memcpy -> std::ranges::copy
e1dcc6e Merge bitcoin-core/libmultiprocess#316: cmake: Fix stale codegen when mpgen binary changes
7a72df0 type-chrono: Add CustomBuildField/CustomReadField overloads for std::chrono::time_point
45b685c type-number, type-chrono: Fix static assert signed/unsigned comparisons
45f6255 type-number: exclude bool from the integral overload
8d6d464 Merge bitcoin-core/libmultiprocess#315: Fix startup race in example
a6fc80d Merge bitcoin-core/libmultiprocess#311: bugfix: clear FD_CLOEXEC in child instead of parent before fork
496fb84 test: cover immediate client disconnects for `ListenConnections`
36c6c63 doc: Document reference-counted EventLoop lifetime
3a997e1 Fix startup race in mpexample
f5c15ce Merge bitcoin-core/libmultiprocess#323: refactor: access ThreadContext through CurrentThread(), ci: switch Bitcoin Core to master
66298c7 ci: Switch back to Bitcoin Core's master branch
86b4810 refactor: access ThreadContext through CurrentThread()
eea9c64 cmake: Fix stale codegen when mpgen binary changes
a26a084 cmake: Fix mpgen capnp tool path for vcpkg/Windows builds
140d9ba test: allow custom log handler in `ListenSetup`
1e0c7ff util: Clear FD_CLOEXEC in child instead of parent before fork
8550ee6 util, refactor: Add ChildFail helper for post-fork child errors
17eab90 test: Fix typo in listen_tests.cpp
ce865a9 refactor: Directly use value in CustomBuildField
3f221b5 Merge bitcoin-core/libmultiprocess#274: Add nonunix platform support
1b0f605 doc: Remove trailing whitespace
d8f8ca3 ipc: Wrap mpgen main() in try-catch to print errors
fbe5a14 ci: Check out bitcoin/bitcoin PR bitcoin#35084 instead of master
39d3690 types: Replace SFINAE with requires clauses to avoid MSVC C2039 error
ba68520 proxy, refactor: Fix C4305 truncation warning in Accessor on MSVC
1d81d47 util, refactor: Fix PtrOrValue constructor for move-only types on MSVC
b883fe1 proxy: Fix shutdownWrite() exception handling on macOS with dynamic libraries
0012411 proxy: Call shutdownWrite() in Connection destructor
38312ad proxy, refactor: Change ConnectStream and ServeStream to accept stream objects
e96d5d7 proxy, refactor: Replace EventLoop wakeup fd integers with KJ stream objects
db4f9a3 cmake: Bump minimum required Cap'n Proto version to 0.9
652934f util, refactor: Add SocketPair() and use it in SpawnProcess
1c6ef7a util, refactor: Do not fork() and exec() separately
1389cf3 util, refactor: Add SpawnConnectInfo type alias and use it
c7ca1f0 util, refactor: Add SocketId type alias and use it
be46a35 util, refactor: Add ProcessId type alias and use it
91a78db doc: Bump version 13 > 14
fa2c56e ci: Bump channel to nixos-26.05

git-subtree-dir: src/ipc/libmultiprocess
git-subtree-split: 275c8ee
Expose Chain interface to external processes spawning or connecting to
bitcoin-node.
Lambda [[noreturn]] attributes before the parameter list are a C++23
extension intentionally used in C++20 builds (needed for compatibility
with -Wmissing-noreturn). Suppress the extension warning rather than
removing the attributes or working around them.

Uses the existing IF_CHECK_PASSED idiom so GCC, which silently ignores
unknown -Wno-* flags, is unaffected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Needed because BlockConnected notifications are a lot slower with the wallet
running in separate process.
Make default constructor more generic so it doesn't only work with void types.
Add tests pinning down when a callback object (and any state it owns)
is destroyed. Currently disconnect() only disables the callback: the
object stays alive until a later connect() call on the same signal
garbage collects it and every connection handle referencing it has been
released; with no connection handle held it lives until the signal
itself is destroyed.

This differs from boost::signals2, which btcsignals aims to be
api-compatible with: there, disconnecting destroys the slot's function
object as soon as no emission is using it.

No behavior change; these tests document the status quo so the next
commit changing the destruction timing has a clear before/after diff.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Previously a disconnected callback and any state it owned could stay
alive indefinitely: destruction required both a later connect() call on
the same signal to garbage collect it and release of every connection
handle referencing it. That made destruction timing unpredictable for
callbacks that own resources whose release has side effects, and it
diverges from boost::signals2, which destroys a disconnected slot's
function object as soon as no emission is running it. (The concrete
fallout was in multiprocess bitcoin-gui, where node notification
callbacks own IPC proxy objects: their deferred destruction kept
bitcoin-node from exiting and hung interface_gui.py until timeout.)

Make disconnect() destroy the callback, deferring only while a
concurrent emission is mid-call into it, matching boost::signals2
semantics. The previous commit's characterization tests are updated;
their diff shows the ownership change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…hared_ptr

std::atomic<shared_ptr<T>> is a C++20 library feature, but library
implementations are not required to ship all C++20 features at once;
__cpp_lib_atomic_shared_ptr is the feature-test macro that indicates its
presence. Without it, the generic std::atomic<T> requires trivially copyable
T — shared_ptr is not, causing build failures on macOS (Xcode 16.2),
FreeBSD 15.1, and the MSan/TSan custom libc++ builds in CI.

Fall back to the C++14 atomic_load/atomic_store free functions, which are
specifically overloaded for shared_ptr. The fallback is intended to be
temporary: those functions are deprecated in C++20 and will eventually be
removed, so the #else branch can be dropped once all CI platforms carry the
C++20 specialization.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Libmultiprocess requires output parameters to be ordered after input parameter,
so move warnings parameter last. Problematic order was introduced in
4ec2d18 from
bitcoin-core/gui#877
Spawn node subprocess instead of running node code internally
Spawn wallet subprocess instead of running wallet code internally
Add .wallet/.gui suffixes to log files created by bitcoin-gui and
bitcoin-wallet processes so they don't clash with bitcoin-node log file.
Needed due to base PR, can be dropped before merge
@DrahtBot

Copy link
Copy Markdown
Contributor

🚧 At least one of the CI tasks failed.
Task test ancestor commits: https://github.com/bitcoin/bitcoin/actions/runs/32738095305/job/97465707554
LLM reason (✨ experimental): CI failed during the build because src/ipc capnp proxy code couldn’t compile (missing interfaces::Chain methods estimateSmartFee/estimateMaxBlocks, leading to abstract-final/pure-virtual errors).

Hints

Try to run the tests locally, according to the documentation. However, a CI failure may still
happen due to a number of reasons, for example:

  • Possibly due to a silent merge conflict (the changes in this pull request being
    incompatible with the current code in the target branch). If so, make sure to rebase on the latest
    commit of the target branch.

  • A sanitizer issue, which can only be found by compiling with the sanitizer and running the
    affected test.

  • An intermittent issue.

Leave a comment here, if you need help tracking down a confusing failure.

@DrahtBot

Copy link
Copy Markdown
Contributor

🐙 This pull request conflicts with the target branch and needs rebase.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

Morty Proxy This is a proxified and sanitized view of the page, visit original site.