ZMQ Instructions
Introducing How to Use ZMQ Functionality and How to Configure It
Introduction to ZMQ
ZeroMQ is a lightweight messaging queue solution that provides publish-subscribe services via TCP links, inter-process communication (IPC), and shared memory. ZeroMQ is known for being lightweight, high-performance, low-latency, supporting multiple languages, multiple operating systems, and various messaging patterns.
While the node P2P protocol in MVC can itself serve as a trusted messaging propagation route to facilitate communication within the MVC network, make consensus decisions, broadcast transactions, etc., in some scenarios, a more flexible messaging queue solution is needed. Applications that need to listen for events like mempool transactions and new blocks require real-time and high availability, which are more cumbersome to implement via the P2P protocol and not as user-friendly for clients.
Therefore, we have introduced ZeroMQ as a messaging queue solution to provide more flexible messaging services. ZeroMQ allows for real-time notifications by subscribing to events of interest, such as listening for new blocks and mempool transactions.
Features of MVC Node ZMQ Push
The ZeroMQ functionality implements a specific set of notification interfaces, primarily including notifiers for new blocks and new transactions. Node ZMQ is read-only, requiring only connection to the corresponding ZeroMQ subscription port in the receiving software; it does not perform authentication nor does it involve bidirectional protocols. Therefore, subscribers should verify the received data (e.g., using merkle proofs, making secondary node RPC verifications, etc.), as this data might be outdated, incomplete, or even invalid.
ZeroMQ sockets are self-connecting and self-healing; that is, the connection between two endpoints will automatically resume after an interruption, and either end can freely start or stop in any order.
Additionally, because ZeroMQ is message-oriented, the transactions and blocks received by subscribers are one-time occurrences and do not require any buffering or reassembly.
Enabling ZMQ Functionality When Building the Node
When compiling the node, you can specify whether to enable ZMQ functionality. If you need to enable ZMQ, you will need to install the libzmq3-dev dependency library on the build machine. The official default binary package already includes support for ZMQ. If you are compiling the node yourself and wish to include ZMQ functionality, you can refer to the following compile option:
If you are using the default binary package, no additional steps are necessary; you can start the node directly as the ZMQ functionality is already installed in the node.
ZMQ Configuration
ZMQ functionality needs to be configured in the node's configuration file. You can freely choose the port number and the types of events to subscribe to. Configure the following in the mvc.conf file (refer to the ZMQ-related content in Startup Options):
The socket type is PUB, and the address starts with "tcp://" or "ipc://". If you do not need notifications for a particular event, you do not need to configure an address for that event. The same address can be used to listen to multiple channels. For example:
Similarly, these configurations can also be set in the mvc.conf file, such as:
Each PUB notification comes with a topic and a message body, with the notification type included in the message header. For example, the zmqpubhashtx notification's topic is "hashtx," and the message body is the transaction hash. The message body is a 32-byte hexadecimal string, which can be obtained in detail via the node's RPC interface.
Meanwhile, the topics for zmqpubdiscardedfrommempool and zmqpubremovedfrommempoolblock notifications are " discardedfrommempool" and "removedfrommempoolblock," respectively, and their message bodies are JSON strings:
The collidedWith
field indicates which transaction this transaction conflicted with, and the blockhash
field indicates which block this transaction was included in.
The reason
field in zmqpubdiscardedfrommempool indicates why this transaction was discarded, with reasons including:
expired
mempool-sizelimit-exceeded
collision-in-block-tx
The reason
field in zmqpubremovedfrommempoolblock indicates why this transaction was removed from the mempool, with reasons including:
reorg
included-in-block
zmqpub2 (such as zmqpubhashtx2 and other suffixes ending with 2) functions similarly to their non-suffix counterparts, the only difference being that they no longer push duplicate messages. For example, the original zmqpubhashtx would push messages twice, both when entering the mempool and when being packaged into a block, whereas zmqpubhashtx2 pushes only once. Additionally, in the event of a reorganization, the entire reorganization chain is pushed, not just the tip.
Remarks
From the perspective of mvcd
, ZeroMQ sockets are write-only; PUB sockets do not even have a read function. Therefore, they do not directly introduce any state into MVC. Additionally, MVC does not broadcast any information that has not been received from the public P2P network.
When connecting clients, no authentication or authorization is performed; thus, it is crucial to ensure that the ZeroMQ ports are open only to trusted networks and are protected by firewalls or other means.
Please note that reorganizations can occur when the highest point of the blockchain changes, and only the highest point will be notified. Subscribers need to retrieve from the last known block to the new highest point.
Depending on the type of communication used, ZMQ notifications may be lost during transmission. MVC includes an incrementing sequence number in each notification, allowing listeners to detect missing notifications.
Practice: Using a ZMQ Client to Listen for ZMQ Events
This example uses Python to demonstrate how to use a ZMQ client to listen for ZMQ events.
Ensure that your local system has installed the ZMQ and Python libraries and that the ZMQ port is open.
Install Python3 and related dependencies:
Create the following Python file zmq_subscriber.py. The code below listens to the local ZMQ port, listens to the hashtx channel, and prints the data received:
If the program is correctly configured and running successfully, you will see the following output:
The message includes messages from the hashtx channel, the message body, and the transaction hash (real transaction, can be confirmed on-chain), as well as an additional continuous sequence to detect missing messages. You can also set up to listen to other channels and print output for debugging.