Bitcoin ABC 0.33.10
P2P Digital Currency
zmqnotificationinterface.cpp
Go to the documentation of this file.
1// Copyright (c) 2015-2018 The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
7#include <zmq/zmqutil.h>
8
9#include <zmq.h>
10
11#include <common/args.h>
12#include <kernel/chain.h>
13#include <logging.h>
14#include <netbase.h>
15#include <primitives/block.h>
16
18
20 Shutdown();
21}
22
23std::list<const CZMQAbstractNotifier *>
25 std::list<const CZMQAbstractNotifier *> result;
26 for (const auto &n : notifiers) {
27 result.push_back(n.get());
28 }
29 return result;
30}
31
32std::unique_ptr<CZMQNotificationInterface> CZMQNotificationInterface::Create(
33 std::function<bool(CBlock &, const CBlockIndex &)> get_block_by_index) {
34 std::map<std::string, CZMQNotifierFactory> factories;
35 factories["pubhashblock"] =
36 CZMQAbstractNotifier::Create<CZMQPublishHashBlockNotifier>;
37 factories["pubhashtx"] =
38 CZMQAbstractNotifier::Create<CZMQPublishHashTransactionNotifier>;
39 factories["pubrawblock"] =
40 [&get_block_by_index]() -> std::unique_ptr<CZMQAbstractNotifier> {
41 return std::make_unique<CZMQPublishRawBlockNotifier>(
42 get_block_by_index);
43 };
44 factories["pubrawtx"] =
45 CZMQAbstractNotifier::Create<CZMQPublishRawTransactionNotifier>;
46 factories["pubsequence"] =
47 CZMQAbstractNotifier::Create<CZMQPublishSequenceNotifier>;
48
49 std::list<std::unique_ptr<CZMQAbstractNotifier>> notifiers;
50 for (const auto &entry : factories) {
51 std::string arg("-zmq" + entry.first);
52 const auto &factory = entry.second;
53
54 for (std::string &address : gArgs.GetArgs(arg)) {
55 // libzmq uses prefix "ipc://" for UNIX domain sockets
56 if (address.substr(0, ADDR_PREFIX_UNIX.length()) ==
58 address.replace(0, ADDR_PREFIX_UNIX.length(), ADDR_PREFIX_IPC);
59 }
60
61 std::unique_ptr<CZMQAbstractNotifier> notifier = factory();
62 notifier->SetType(entry.first);
63 notifier->SetAddress(address);
64 notifier->SetOutboundMessageHighWaterMark(
65 static_cast<int>(gArgs.GetIntArg(
67 notifiers.push_back(std::move(notifier));
68 }
69 }
70
71 if (!notifiers.empty()) {
72 std::unique_ptr<CZMQNotificationInterface> notificationInterface(
74 notificationInterface->notifiers = std::move(notifiers);
75
76 if (notificationInterface->Initialize()) {
77 return notificationInterface;
78 }
79 }
80
81 return nullptr;
82}
83
84// Called at startup to conditionally set up ZMQ socket(s)
86 int major = 0, minor = 0, patch = 0;
87 zmq_version(&major, &minor, &patch);
88 LogPrint(BCLog::ZMQ, "zmq: version %d.%d.%d\n", major, minor, patch);
89
90 LogPrint(BCLog::ZMQ, "zmq: Initialize notification interface\n");
92
93 pcontext = zmq_ctx_new();
94
95 if (!pcontext) {
96 zmqError("Unable to initialize context");
97 return false;
98 }
99
100 for (auto &notifier : notifiers) {
101 if (notifier->Initialize(pcontext)) {
102 LogPrint(BCLog::ZMQ, "zmq: Notifier %s ready (address = %s)\n",
103 notifier->GetType(), notifier->GetAddress());
104 } else {
105 LogPrint(BCLog::ZMQ, "zmq: Notifier %s failed (address = %s)\n",
106 notifier->GetType(), notifier->GetAddress());
107 return false;
108 }
109 }
110
111 return true;
112}
113
114// Called during shutdown sequence
116 LogPrint(BCLog::ZMQ, "zmq: Shutdown notification interface\n");
117 if (pcontext) {
118 for (auto &notifier : notifiers) {
119 LogPrint(BCLog::ZMQ, "zmq: Shutdown notifier %s at %s\n",
120 notifier->GetType(), notifier->GetAddress());
121 notifier->Shutdown();
122 }
123 zmq_ctx_term(pcontext);
124
125 pcontext = nullptr;
126 }
127}
128
129namespace {
130
131template <typename Function>
132void TryForEachAndRemoveFailed(
133 std::list<std::unique_ptr<CZMQAbstractNotifier>> &notifiers,
134 const Function &func) {
135 for (auto i = notifiers.begin(); i != notifiers.end();) {
136 CZMQAbstractNotifier *notifier = i->get();
137 if (func(notifier)) {
138 ++i;
139 } else {
140 notifier->Shutdown();
141 i = notifiers.erase(i);
142 }
143 }
144}
145
146} // anonymous namespace
147
149 const CBlockIndex *pindexFork,
150 bool fInitialDownload) {
151 // In IBD or blocks were disconnected without any new ones
152 if (fInitialDownload || pindexNew == pindexFork) {
153 return;
154 }
155
156 TryForEachAndRemoveFailed(notifiers,
157 [pindexNew](CZMQAbstractNotifier *notifier) {
158 return notifier->NotifyBlock(pindexNew);
159 });
160}
161
163 const CTransactionRef &ptx, std::shared_ptr<const std::vector<Coin>>,
164 uint64_t mempool_sequence) {
165 const CTransaction &tx = *ptx;
166
167 TryForEachAndRemoveFailed(
168 notifiers, [&tx, mempool_sequence](CZMQAbstractNotifier *notifier) {
169 return notifier->NotifyTransaction(tx) &&
170 notifier->NotifyTransactionAcceptance(tx, mempool_sequence);
171 });
172}
173
175 const CTransactionRef &ptx, MemPoolRemovalReason reason,
176 uint64_t mempool_sequence) {
177 // Called for all non-block inclusion reasons
178 const CTransaction &tx = *ptx;
179
180 TryForEachAndRemoveFailed(
181 notifiers, [&tx, mempool_sequence](CZMQAbstractNotifier *notifier) {
182 return notifier->NotifyTransactionRemoval(tx, mempool_sequence);
183 });
184}
185
187 ChainstateRole role, const std::shared_ptr<const CBlock> &pblock,
188 const CBlockIndex *pindexConnected) {
189 if (role == ChainstateRole::BACKGROUND) {
190 return;
191 }
192 for (const CTransactionRef &ptx : pblock->vtx) {
193 const CTransaction &tx = *ptx;
194 TryForEachAndRemoveFailed(notifiers,
195 [&tx](CZMQAbstractNotifier *notifier) {
196 return notifier->NotifyTransaction(tx);
197 });
198 }
199
200 // Next we notify BlockConnect listeners for *all* blocks
201 TryForEachAndRemoveFailed(
202 notifiers, [pindexConnected](CZMQAbstractNotifier *notifier) {
203 return notifier->NotifyBlockConnect(pindexConnected);
204 });
205}
206
208 const std::shared_ptr<const CBlock> &pblock,
209 const CBlockIndex *pindexDisconnected) {
210 for (const CTransactionRef &ptx : pblock->vtx) {
211 const CTransaction &tx = *ptx;
212 TryForEachAndRemoveFailed(notifiers,
213 [&tx](CZMQAbstractNotifier *notifier) {
214 return notifier->NotifyTransaction(tx);
215 });
216 }
217
218 // Next we notify BlockDisconnect listeners for *all* blocks
219 TryForEachAndRemoveFailed(
220 notifiers, [pindexDisconnected](CZMQAbstractNotifier *notifier) {
221 return notifier->NotifyBlockDisconnect(pindexDisconnected);
222 });
223}
224
225std::unique_ptr<CZMQNotificationInterface> g_zmq_notification_interface;
ArgsManager gArgs
Definition: args.cpp:39
std::vector< std::string > GetArgs(const std::string &strArg) const
Return a vector of strings of the given argument.
Definition: args.cpp:361
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
Definition: args.cpp:494
Definition: block.h:60
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: blockindex.h:25
virtual void Shutdown()=0
virtual bool NotifyBlockConnect(const CBlockIndex *pindex)
static const int DEFAULT_ZMQ_SNDHWM
virtual bool NotifyTransactionRemoval(const CTransaction &transaction, uint64_t mempool_sequence)
virtual bool NotifyBlock(const CBlockIndex *pindex)
virtual bool NotifyTransaction(const CTransaction &transaction)
virtual bool NotifyBlockDisconnect(const CBlockIndex *pindex)
virtual bool NotifyTransactionAcceptance(const CTransaction &transaction, uint64_t mempool_sequence)
void TransactionAddedToMempool(const CTransactionRef &tx, std::shared_ptr< const std::vector< Coin > >, uint64_t mempool_sequence) override
Notifies listeners of a transaction having been added to mempool.
static std::unique_ptr< CZMQNotificationInterface > Create(std::function< bool(CBlock &, const CBlockIndex &)> get_block_by_index)
void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override
Notifies listeners when the block chain tip advances.
std::list< std::unique_ptr< CZMQAbstractNotifier > > notifiers
void BlockDisconnected(const std::shared_ptr< const CBlock > &pblock, const CBlockIndex *pindexDisconnected) override
Notifies listeners of a block being disconnected.
void BlockConnected(ChainstateRole role, const std::shared_ptr< const CBlock > &pblock, const CBlockIndex *pindexConnected) override
Notifies listeners of a block being connected.
void TransactionRemovedFromMempool(const CTransactionRef &tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) override
Notifies listeners of a transaction leaving mempool.
std::list< const CZMQAbstractNotifier * > GetActiveNotifiers() const
ChainstateRole
This enum describes the various roles a specific Chainstate instance can take.
Definition: chain.h:14
#define LogPrint(category,...)
Definition: logging.h:452
@ ZMQ
Definition: logging.h:74
const std::string ADDR_PREFIX_UNIX
Prefix for unix domain socket addresses (which are local filesystem paths)
Definition: netbase.h:35
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:315
MemPoolRemovalReason
Reason why a transaction was removed from the mempool, this is passed to the notification signal.
Definition: txmempool.h:158
assert(!tx.IsCoinBase())
std::unique_ptr< CZMQNotificationInterface > g_zmq_notification_interface
void zmqError(const char *str)
Definition: zmqutil.cpp:11
const std::string ADDR_PREFIX_IPC
Prefix for unix domain socket addresses (which are local filesystem paths) Used by libzmq,...
Definition: zmqutil.h:16