-
Notifications
You must be signed in to change notification settings - Fork 38.8k
Adds publishing blocks and transactions over ZMQ #4594
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Pull tester unhappy, but merge, default configure, compile, and make check all pass ok here. |
src/main.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No whitespace changes please, they're going to be solved in one go at some point with clang-format (see #4498).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. My emacs is configured to automatically remove trailing whitespace, so this was unintended. I'll figure out a way to make a clean diff.
Thanks for that. For obelisk I had to find so many wrappers, high level wrappers, c++ wrappers for high-level wrappers (only some of them with an ubuntu package, which ofc was too old) that at some point I gave up. |
src/zmqports.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be its own category, zmq?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll change this.
|
Looks good to me apart from the nits -- async notification is superior to polling. Only minimal impact on the current code and is a no-op if |
|
Per feedback, updated and rebased commit:
|
|
Concept ACK. Supporting ZeroMQ in this fashion (publish public data) is a useful feature. One of the problems the Linux kernel ran into early on was a profusion of #ifdef'd features. Bitcoin Core does not have this problem, but it is creeping in that direction. As mentioned in another github issue days ago, conditionally compiled code is evil. Such code is only compiled by a few, rather than all. As a result, the code quickly breaks because it is not used by the primary developers. The solution is to create wrappers for the #ifndef MY_FEATURE branch in your my_feature.h, which creates an API that becomes a no-op at compile time. That way, zeromq code is always built, without ifdefs in the main codebase. As such, zeromq calls are built by all, and less likely to be broken. |
|
I intentionally made this such that you have to explicitly --enable-zmq in order to compile it in, for testing purposes. If this gets merged, at some point we'll decide to enable it for everyone. At that point, I'll rework things so that there are no ifdef's--instead, if libzmq-dev is not detected at configure time, the function calls become NOPs internally. |
|
There should be no need to disable zmq by default at compile time. Disabled at runtime is sufficient. Typical pattern is for configure to find a library and enable the building of that feature automatically, without --enable-foo support. You don't want to make the user work harder, just to get new features. Also, I'm in general strongly against doesn't-compile-by-default code. It's a recipe for bitrot. |
|
I'll go ahead then and rework this to eliminate the --enable-zmq and disable the feature at runtime if libzmq-dev is not detected. |
|
Looks like I missed a logging simplification; I'll get this when I make the above changes. |
|
I strongly disagree with @jgarzik here. I don't want a fixed dependency on zeromq. |
|
To be clear--my plan is to make it such that if ZeroMQ is missing, the feature is disabled, so there won't be a dependency. Did I misunderstand? |
|
That's fine with me. Defaulting to having it enabled when the library is installed sounds sane. And it should still be possible to override the autodetection with |
|
@jgarzik dislikes conditionally compiled code, and wants to have the ZeroMQ code always compiled (thus always having the dependency). @laanwj dislikes dependencies, and thus prefers the conditional compilation you're doing now. I agree with @laanwj here. I really want to minimize dependencies. Another way of doing it is exposing the signals interface for such notifications, and register them from an optionally compiled object file (the same could be done fo -blocknotify, etc). That avoid #ifdefs entirely. |
|
Ok, this has been reworked as follows:
|
|
Minor rebase to accommodate 'rawtx' merge. |
|
I didn't test it but I like what it does. |
|
Minor rebase to accommodate RPC help categorization. |
|
Suggest minor change to add check for libzmq version >=2.1 requirement. PKG_CHECK_MODULES([ZMQ],[libzmq >= 2.1], |
ZMQ-based features are encapsulated in zmqports.{cpp,h} and disabled
if libzmq-dev is not found, or configure is invoked with
--disable-zmq.
Use -zmqpub=<endpoint> to use feature.
See contrib/zmq/README.md for details.
|
Rebase and add zmq version check as requested. |
|
Automatic sanity-testing: FAILED BUILD/TEST, see http://jenkins.bluematt.me/pull-tester/p4594_3c9d0c12ac2476fc8fb5de9293edbf27081b1d4e/ for binaries and test log. This could happen for one of several reasons:
If you believe this to be in error, please ping BlueMatt on freenode or TheBlueMatt here. This test script verifies pulls every time they are updated. It, however, dies sometimes and fails to test properly. If you are waiting on a test, please check timestamps to verify that the test.log is moving at http://jenkins.bluematt.me/pull-tester/current/ |
|
To make the last comment more explicit, I do not like seeing "zmq" in main.cpp or net.cpp. This pull request has my ACK iff the ZMQPublish*() calls are turned into ui_interface.h signals, as illustrated in c7b6117. No objections other than that. |
|
Thanks for the clarification. It will be a week or two until I can turn my attention back to this, but I'll look over the signaling mechanism and see how I can refit this patch to use that. |
|
needs rebased |
|
I'm tempted to take this patch, add signals, and re-PR. ZMQ is conceptually acceptable AFAIK. |
|
@jgarzik do it! |
|
@jgarzik If you do, please take theuni@dd8d00b and theuni@25844d3 (feel free to squash) so that travis can build. Those are quite old though, let me know if there are merge problems and I'll rebase. |
|
@jgarzik Go for it. I haven't had much time to spend on bitcoin development these last few months, but I'd still like to see this get integrated. |
|
Closing in favor of #5303. |
Block and Transaction Broadcasting With ZeroMQ
ZeroMQ is a lightweight wrapper around TCP
connections, inter-process communications, and shared-memory,
providing various message-oriented semantics such as publish/subcribe,
request/reply, and push/pull.
The Bitcoin Core daemon can be configured to act as a trusted "border
router", implementing the bitcoin wire protocol and relay, making
consensus decisions, maintaining the local blockchain database,
broadcasting locally generated transactions into the network, and
providing a queryable RPC interface to interact on a polled basis for
requesting blockchain related data. However, there exists only a
limited service to notify external software of events like the arrival
of new blocks or transactions.
The ZeroMQ facility binds a "publish" port that broadcasts all newly
arrived and validated blocks and transactions to one or more
connected subscribers. This read-only facility requires only the
connection of a corresponding ZeroMQ subscriber port in receiving
software; it is not authenticated nor is there any two-way protocol
involvement.
In this fashion, external software can use a trusted Bitcoin Core
daemon to do the heavy lifting of communicating with the P2P network,
while still receiving network information asynchronously in real
time. As transactions and blocks arrive via the P2P network, Bitcoin
Core will apply all the validation and standardization rules to this
data, only passing along through ZeroMQ those items that pass.
ZeroMQ sockets are self-connecting and self-healing; that is, connects
made between two endpoints will be automatically restored after an
outage, and either end may be freely started or stopped in any order.
Because ZeroMQ is message oriented, subscribers receive transactions
and blocks all-at-once and do not need to implement any sort of
buffering or reassembly.
Prerequisites
The ZeroMQ feature in Bitcoin Core uses only a very small part of the
ZeroMQ C API, and is thus compatible with any version of ZeroMQ
from 2.1 onward, including all versions in the 3.x and 4.x release
series. Typically, it is packaged by distributions as something like
libzmq-dev.
The C++ wrapper for ZeroMQ is not needed.
Enabling
By default, the ZeroMQ port functionality is disabled. Two steps are
required to enable--compiling in the ZeroMQ code, and configuring
runtime operation on the command-line or configuration file.
This will produce a binary that is capable of providing the ZeroMQ
facility, but will not do so until also configured properly.
Configuration
Currently, the ZeroMQ facility only needs to have the ZeroMQ endpoint
specified:
This will cause bitcoind to establish a PUB listening socket at the
specified host address and port number. The endpoint specifier may
also be provided as the equivalent line item in bitcoin.conf.
ZeroMQ endpoint specifiers for TCP (and others) are documented in the
ZeroMQ API.
Operation
ZeroMQ publish sockets prepend each data item with an arbitrary topic
prefix that allows subscriber clients to request only those items with
a matching prefix. When publishing, bitcoind will prepend the topic
"TXN" (no quotes, no null terminator) to the binary, serialized form
of a published transaction, and "BLK" to the binary, serialized form
of a published block.
Client side, then, the ZeroMQ subscriber socket must have the ZMQ_SUBSCRIBE option set to one or either of these prefixes; without doing so will result in no messages arriving.
Here is a small example, in the Python language, using the python-zmq wrapper:
This example is provided in the contrib/zmq directory of the source code.
Security Considerations
From the perspective of bitcoind, the ZeroMQ socket is write-only; PUB sockets don't even have a read function. Thus, there is no state introduced into bitcoind directly. Furthermore, no information is broadcast that wasn't already received from the public P2P network.
No authentication or authorization is done on connecting clients; it is assumed that the ZeroMQ port is exposed only to trusted entities, using other means such as firewalling.
Transactions and blocks are broadcast in their serialized form directly as received and validated by bitcoind. External software may assume that these have passed all validity/consensus/standard checks, but of course is free to perform these functions again in part or in whole.