Initial Vexta Core v0.1.0 release
This commit is contained in:
commit
25c454329d
2481 changed files with 689289 additions and 0 deletions
45
src/zmq/zmqabstractnotifier.cpp
Normal file
45
src/zmq/zmqabstractnotifier.cpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright (c) 2009-2019 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2019 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <zmq/zmqabstractnotifier.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
const int CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM;
|
||||
|
||||
CZMQAbstractNotifier::~CZMQAbstractNotifier()
|
||||
{
|
||||
assert(!psocket);
|
||||
}
|
||||
|
||||
bool CZMQAbstractNotifier::NotifyBlock(const CBlockIndex * /*CBlockIndex*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CZMQAbstractNotifier::NotifyTransaction(const CTransaction &/*transaction*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CZMQAbstractNotifier::NotifyBlockConnect(const CBlockIndex * /*CBlockIndex*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CZMQAbstractNotifier::NotifyBlockDisconnect(const CBlockIndex * /*CBlockIndex*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CZMQAbstractNotifier::NotifyTransactionAcceptance(const CTransaction &/*transaction*/, uint64_t mempool_sequence)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CZMQAbstractNotifier::NotifyTransactionRemoval(const CTransaction &/*transaction*/, uint64_t mempool_sequence)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
67
src/zmq/zmqabstractnotifier.h
Normal file
67
src/zmq/zmqabstractnotifier.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
// Copyright (c) 2009-2019 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2019 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_ZMQ_ZMQABSTRACTNOTIFIER_H
|
||||
#define DIGIBYTE_ZMQ_ZMQABSTRACTNOTIFIER_H
|
||||
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class CBlockIndex;
|
||||
class CTransaction;
|
||||
class CZMQAbstractNotifier;
|
||||
|
||||
using CZMQNotifierFactory = std::unique_ptr<CZMQAbstractNotifier> (*)();
|
||||
|
||||
class CZMQAbstractNotifier
|
||||
{
|
||||
public:
|
||||
static const int DEFAULT_ZMQ_SNDHWM {1000};
|
||||
|
||||
CZMQAbstractNotifier() : psocket(nullptr), outbound_message_high_water_mark(DEFAULT_ZMQ_SNDHWM) { }
|
||||
virtual ~CZMQAbstractNotifier();
|
||||
|
||||
template <typename T>
|
||||
static std::unique_ptr<CZMQAbstractNotifier> Create()
|
||||
{
|
||||
return std::make_unique<T>();
|
||||
}
|
||||
|
||||
std::string GetType() const { return type; }
|
||||
void SetType(const std::string &t) { type = t; }
|
||||
std::string GetAddress() const { return address; }
|
||||
void SetAddress(const std::string &a) { address = a; }
|
||||
int GetOutboundMessageHighWaterMark() const { return outbound_message_high_water_mark; }
|
||||
void SetOutboundMessageHighWaterMark(const int sndhwm) {
|
||||
if (sndhwm >= 0) {
|
||||
outbound_message_high_water_mark = sndhwm;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool Initialize(void *pcontext) = 0;
|
||||
virtual void Shutdown() = 0;
|
||||
|
||||
// Notifies of ConnectTip result, i.e., new active tip only
|
||||
virtual bool NotifyBlock(const CBlockIndex *pindex);
|
||||
// Notifies of every block connection
|
||||
virtual bool NotifyBlockConnect(const CBlockIndex *pindex);
|
||||
// Notifies of every block disconnection
|
||||
virtual bool NotifyBlockDisconnect(const CBlockIndex *pindex);
|
||||
// Notifies of every mempool acceptance
|
||||
virtual bool NotifyTransactionAcceptance(const CTransaction &transaction, uint64_t mempool_sequence);
|
||||
// Notifies of every mempool removal, except inclusion in blocks
|
||||
virtual bool NotifyTransactionRemoval(const CTransaction &transaction, uint64_t mempool_sequence);
|
||||
// Notifies of transactions added to mempool or appearing in blocks
|
||||
virtual bool NotifyTransaction(const CTransaction &transaction);
|
||||
|
||||
protected:
|
||||
void *psocket;
|
||||
std::string type;
|
||||
std::string address;
|
||||
int outbound_message_high_water_mark; // aka SNDHWM
|
||||
};
|
||||
|
||||
#endif // DIGIBYTE_ZMQ_ZMQABSTRACTNOTIFIER_H
|
||||
25
src/zmq/zmqconfig.h
Normal file
25
src/zmq/zmqconfig.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) 2009-2019 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2019 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_ZMQ_ZMQCONFIG_H
|
||||
#define DIGIBYTE_ZMQ_ZMQCONFIG_H
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
#include <config/vexta-config.h>
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string>
|
||||
|
||||
#if ENABLE_ZMQ
|
||||
#include <zmq.h>
|
||||
#endif
|
||||
|
||||
#include <primitives/block.h>
|
||||
#include <primitives/transaction.h>
|
||||
|
||||
void zmqError(const char *str);
|
||||
|
||||
#endif // DIGIBYTE_ZMQ_ZMQCONFIG_H
|
||||
192
src/zmq/zmqnotificationinterface.cpp
Normal file
192
src/zmq/zmqnotificationinterface.cpp
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
// Copyright (c) 2015-2018 The Bitcoin Core developers
|
||||
// Copyright (c) 2015-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <zmq/zmqnotificationinterface.h>
|
||||
#include <zmq/zmqpublishnotifier.h>
|
||||
#include <zmq/zmqutil.h>
|
||||
|
||||
#include <zmq.h>
|
||||
|
||||
#include <validation.h>
|
||||
#include <util/system.h>
|
||||
|
||||
CZMQNotificationInterface::CZMQNotificationInterface() : pcontext(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
CZMQNotificationInterface::~CZMQNotificationInterface()
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
std::list<const CZMQAbstractNotifier*> CZMQNotificationInterface::GetActiveNotifiers() const
|
||||
{
|
||||
std::list<const CZMQAbstractNotifier*> result;
|
||||
for (const auto& n : notifiers) {
|
||||
result.push_back(n.get());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
CZMQNotificationInterface* CZMQNotificationInterface::Create()
|
||||
{
|
||||
std::map<std::string, CZMQNotifierFactory> factories;
|
||||
factories["pubhashblock"] = CZMQAbstractNotifier::Create<CZMQPublishHashBlockNotifier>;
|
||||
factories["pubhashtx"] = CZMQAbstractNotifier::Create<CZMQPublishHashTransactionNotifier>;
|
||||
factories["pubrawblock"] = CZMQAbstractNotifier::Create<CZMQPublishRawBlockNotifier>;
|
||||
factories["pubrawtx"] = CZMQAbstractNotifier::Create<CZMQPublishRawTransactionNotifier>;
|
||||
factories["pubsequence"] = CZMQAbstractNotifier::Create<CZMQPublishSequenceNotifier>;
|
||||
|
||||
std::list<std::unique_ptr<CZMQAbstractNotifier>> notifiers;
|
||||
for (const auto& entry : factories)
|
||||
{
|
||||
std::string arg("-zmq" + entry.first);
|
||||
const auto& factory = entry.second;
|
||||
for (const std::string& address : gArgs.GetArgs(arg)) {
|
||||
std::unique_ptr<CZMQAbstractNotifier> notifier = factory();
|
||||
notifier->SetType(entry.first);
|
||||
notifier->SetAddress(address);
|
||||
notifier->SetOutboundMessageHighWaterMark(static_cast<int>(gArgs.GetArg(arg + "hwm", CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM)));
|
||||
notifiers.push_back(std::move(notifier));
|
||||
}
|
||||
}
|
||||
|
||||
if (!notifiers.empty())
|
||||
{
|
||||
std::unique_ptr<CZMQNotificationInterface> notificationInterface(new CZMQNotificationInterface());
|
||||
notificationInterface->notifiers = std::move(notifiers);
|
||||
|
||||
if (notificationInterface->Initialize()) {
|
||||
return notificationInterface.release();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Called at startup to conditionally set up ZMQ socket(s)
|
||||
bool CZMQNotificationInterface::Initialize()
|
||||
{
|
||||
int major = 0, minor = 0, patch = 0;
|
||||
zmq_version(&major, &minor, &patch);
|
||||
LogPrint(BCLog::ZMQ, "zmq: version %d.%d.%d\n", major, minor, patch);
|
||||
|
||||
LogPrint(BCLog::ZMQ, "zmq: Initialize notification interface\n");
|
||||
assert(!pcontext);
|
||||
|
||||
pcontext = zmq_ctx_new();
|
||||
|
||||
if (!pcontext)
|
||||
{
|
||||
zmqError("Unable to initialize context");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto& notifier : notifiers) {
|
||||
if (notifier->Initialize(pcontext)) {
|
||||
LogPrint(BCLog::ZMQ, "zmq: Notifier %s ready (address = %s)\n", notifier->GetType(), notifier->GetAddress());
|
||||
} else {
|
||||
LogPrint(BCLog::ZMQ, "zmq: Notifier %s failed (address = %s)\n", notifier->GetType(), notifier->GetAddress());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Called during shutdown sequence
|
||||
void CZMQNotificationInterface::Shutdown()
|
||||
{
|
||||
LogPrint(BCLog::ZMQ, "zmq: Shutdown notification interface\n");
|
||||
if (pcontext)
|
||||
{
|
||||
for (auto& notifier : notifiers) {
|
||||
LogPrint(BCLog::ZMQ, "zmq: Shutdown notifier %s at %s\n", notifier->GetType(), notifier->GetAddress());
|
||||
notifier->Shutdown();
|
||||
}
|
||||
zmq_ctx_term(pcontext);
|
||||
|
||||
pcontext = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename Function>
|
||||
void TryForEachAndRemoveFailed(std::list<std::unique_ptr<CZMQAbstractNotifier>>& notifiers, const Function& func)
|
||||
{
|
||||
for (auto i = notifiers.begin(); i != notifiers.end(); ) {
|
||||
CZMQAbstractNotifier* notifier = i->get();
|
||||
if (func(notifier)) {
|
||||
++i;
|
||||
} else {
|
||||
notifier->Shutdown();
|
||||
i = notifiers.erase(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void CZMQNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload)
|
||||
{
|
||||
if (fInitialDownload || pindexNew == pindexFork) // In IBD or blocks were disconnected without any new ones
|
||||
return;
|
||||
|
||||
TryForEachAndRemoveFailed(notifiers, [pindexNew](CZMQAbstractNotifier* notifier) {
|
||||
return notifier->NotifyBlock(pindexNew);
|
||||
});
|
||||
}
|
||||
|
||||
void CZMQNotificationInterface::TransactionAddedToMempool(const CTransactionRef& ptx, uint64_t mempool_sequence)
|
||||
{
|
||||
const CTransaction& tx = *ptx;
|
||||
|
||||
TryForEachAndRemoveFailed(notifiers, [&tx, mempool_sequence](CZMQAbstractNotifier* notifier) {
|
||||
return notifier->NotifyTransaction(tx) && notifier->NotifyTransactionAcceptance(tx, mempool_sequence);
|
||||
});
|
||||
}
|
||||
|
||||
void CZMQNotificationInterface::TransactionRemovedFromMempool(const CTransactionRef& ptx, MemPoolRemovalReason reason, uint64_t mempool_sequence)
|
||||
{
|
||||
// Called for all non-block inclusion reasons
|
||||
const CTransaction& tx = *ptx;
|
||||
|
||||
TryForEachAndRemoveFailed(notifiers, [&tx, mempool_sequence](CZMQAbstractNotifier* notifier) {
|
||||
return notifier->NotifyTransactionRemoval(tx, mempool_sequence);
|
||||
});
|
||||
}
|
||||
|
||||
void CZMQNotificationInterface::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected)
|
||||
{
|
||||
for (const CTransactionRef& ptx : pblock->vtx) {
|
||||
const CTransaction& tx = *ptx;
|
||||
TryForEachAndRemoveFailed(notifiers, [&tx](CZMQAbstractNotifier* notifier) {
|
||||
return notifier->NotifyTransaction(tx);
|
||||
});
|
||||
}
|
||||
|
||||
// Next we notify BlockConnect listeners for *all* blocks
|
||||
TryForEachAndRemoveFailed(notifiers, [pindexConnected](CZMQAbstractNotifier* notifier) {
|
||||
return notifier->NotifyBlockConnect(pindexConnected);
|
||||
});
|
||||
}
|
||||
|
||||
void CZMQNotificationInterface::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexDisconnected)
|
||||
{
|
||||
for (const CTransactionRef& ptx : pblock->vtx) {
|
||||
const CTransaction& tx = *ptx;
|
||||
TryForEachAndRemoveFailed(notifiers, [&tx](CZMQAbstractNotifier* notifier) {
|
||||
return notifier->NotifyTransaction(tx);
|
||||
});
|
||||
}
|
||||
|
||||
// Next we notify BlockDisconnect listeners for *all* blocks
|
||||
TryForEachAndRemoveFailed(notifiers, [pindexDisconnected](CZMQAbstractNotifier* notifier) {
|
||||
return notifier->NotifyBlockDisconnect(pindexDisconnected);
|
||||
});
|
||||
}
|
||||
|
||||
CZMQNotificationInterface* g_zmq_notification_interface = nullptr;
|
||||
45
src/zmq/zmqnotificationinterface.h
Normal file
45
src/zmq/zmqnotificationinterface.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright (c) 2015-2018 The Bitcoin Core developers
|
||||
// Copyright (c) 2015-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_ZMQ_ZMQNOTIFICATIONINTERFACE_H
|
||||
#define DIGIBYTE_ZMQ_ZMQNOTIFICATIONINTERFACE_H
|
||||
|
||||
#include <validationinterface.h>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
||||
class CBlockIndex;
|
||||
class CZMQAbstractNotifier;
|
||||
|
||||
class CZMQNotificationInterface final : public CValidationInterface
|
||||
{
|
||||
public:
|
||||
virtual ~CZMQNotificationInterface();
|
||||
|
||||
std::list<const CZMQAbstractNotifier*> GetActiveNotifiers() const;
|
||||
|
||||
static CZMQNotificationInterface* Create();
|
||||
|
||||
protected:
|
||||
bool Initialize();
|
||||
void Shutdown();
|
||||
|
||||
// CValidationInterface
|
||||
void TransactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) override;
|
||||
void TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) override;
|
||||
void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected) override;
|
||||
void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexDisconnected) override;
|
||||
void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override;
|
||||
|
||||
private:
|
||||
CZMQNotificationInterface();
|
||||
|
||||
void *pcontext;
|
||||
std::list<std::unique_ptr<CZMQAbstractNotifier>> notifiers;
|
||||
};
|
||||
|
||||
extern CZMQNotificationInterface* g_zmq_notification_interface;
|
||||
|
||||
#endif // DIGIBYTE_ZMQ_ZMQNOTIFICATIONINTERFACE_H
|
||||
272
src/zmq/zmqpublishnotifier.cpp
Normal file
272
src/zmq/zmqpublishnotifier.cpp
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
// Copyright (c) 2009-2019 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2019 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <zmq/zmqpublishnotifier.h>
|
||||
|
||||
#include <chain.h>
|
||||
#include <chainparams.h>
|
||||
#include <node/blockstorage.h>
|
||||
#include <rpc/server.h>
|
||||
#include <streams.h>
|
||||
#include <util/system.h>
|
||||
#include <validation.h> // For cs_main
|
||||
#include <zmq/zmqutil.h>
|
||||
|
||||
#include <zmq.h>
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
static std::multimap<std::string, CZMQAbstractPublishNotifier*> mapPublishNotifiers;
|
||||
|
||||
static const char *MSG_HASHBLOCK = "hashblock";
|
||||
static const char *MSG_HASHTX = "hashtx";
|
||||
static const char *MSG_RAWBLOCK = "rawblock";
|
||||
static const char *MSG_RAWTX = "rawtx";
|
||||
static const char *MSG_SEQUENCE = "sequence";
|
||||
|
||||
// Internal function to send multipart message
|
||||
static int zmq_send_multipart(void *sock, const void* data, size_t size, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, size);
|
||||
|
||||
while (1)
|
||||
{
|
||||
zmq_msg_t msg;
|
||||
|
||||
int rc = zmq_msg_init_size(&msg, size);
|
||||
if (rc != 0)
|
||||
{
|
||||
zmqError("Unable to initialize ZMQ msg");
|
||||
va_end(args);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void *buf = zmq_msg_data(&msg);
|
||||
memcpy(buf, data, size);
|
||||
|
||||
data = va_arg(args, const void*);
|
||||
|
||||
rc = zmq_msg_send(&msg, sock, data ? ZMQ_SNDMORE : 0);
|
||||
if (rc == -1)
|
||||
{
|
||||
zmqError("Unable to send ZMQ msg");
|
||||
zmq_msg_close(&msg);
|
||||
va_end(args);
|
||||
return -1;
|
||||
}
|
||||
|
||||
zmq_msg_close(&msg);
|
||||
|
||||
if (!data)
|
||||
break;
|
||||
|
||||
size = va_arg(args, size_t);
|
||||
}
|
||||
va_end(args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CZMQAbstractPublishNotifier::Initialize(void *pcontext)
|
||||
{
|
||||
assert(!psocket);
|
||||
|
||||
// check if address is being used by other publish notifier
|
||||
std::multimap<std::string, CZMQAbstractPublishNotifier*>::iterator i = mapPublishNotifiers.find(address);
|
||||
|
||||
if (i==mapPublishNotifiers.end())
|
||||
{
|
||||
psocket = zmq_socket(pcontext, ZMQ_PUB);
|
||||
if (!psocket)
|
||||
{
|
||||
zmqError("Failed to create socket");
|
||||
return false;
|
||||
}
|
||||
|
||||
LogPrint(BCLog::ZMQ, "zmq: Outbound message high water mark for %s at %s is %d\n", type, address, outbound_message_high_water_mark);
|
||||
|
||||
int rc = zmq_setsockopt(psocket, ZMQ_SNDHWM, &outbound_message_high_water_mark, sizeof(outbound_message_high_water_mark));
|
||||
if (rc != 0)
|
||||
{
|
||||
zmqError("Failed to set outbound message high water mark");
|
||||
zmq_close(psocket);
|
||||
return false;
|
||||
}
|
||||
|
||||
const int so_keepalive_option {1};
|
||||
rc = zmq_setsockopt(psocket, ZMQ_TCP_KEEPALIVE, &so_keepalive_option, sizeof(so_keepalive_option));
|
||||
if (rc != 0) {
|
||||
zmqError("Failed to set SO_KEEPALIVE");
|
||||
zmq_close(psocket);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = zmq_bind(psocket, address.c_str());
|
||||
if (rc != 0)
|
||||
{
|
||||
zmqError("Failed to bind address");
|
||||
zmq_close(psocket);
|
||||
return false;
|
||||
}
|
||||
|
||||
// register this notifier for the address, so it can be reused for other publish notifier
|
||||
mapPublishNotifiers.insert(std::make_pair(address, this));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint(BCLog::ZMQ, "zmq: Reusing socket for address %s\n", address);
|
||||
LogPrint(BCLog::ZMQ, "zmq: Outbound message high water mark for %s at %s is %d\n", type, address, outbound_message_high_water_mark);
|
||||
|
||||
psocket = i->second->psocket;
|
||||
mapPublishNotifiers.insert(std::make_pair(address, this));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void CZMQAbstractPublishNotifier::Shutdown()
|
||||
{
|
||||
// Early return if Initialize was not called
|
||||
if (!psocket) return;
|
||||
|
||||
int count = mapPublishNotifiers.count(address);
|
||||
|
||||
// remove this notifier from the list of publishers using this address
|
||||
typedef std::multimap<std::string, CZMQAbstractPublishNotifier*>::iterator iterator;
|
||||
std::pair<iterator, iterator> iterpair = mapPublishNotifiers.equal_range(address);
|
||||
|
||||
for (iterator it = iterpair.first; it != iterpair.second; ++it)
|
||||
{
|
||||
if (it->second==this)
|
||||
{
|
||||
mapPublishNotifiers.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (count == 1)
|
||||
{
|
||||
LogPrint(BCLog::ZMQ, "zmq: Close socket at address %s\n", address);
|
||||
int linger = 0;
|
||||
zmq_setsockopt(psocket, ZMQ_LINGER, &linger, sizeof(linger));
|
||||
zmq_close(psocket);
|
||||
}
|
||||
|
||||
psocket = nullptr;
|
||||
}
|
||||
|
||||
bool CZMQAbstractPublishNotifier::SendZmqMessage(const char *command, const void* data, size_t size)
|
||||
{
|
||||
assert(psocket);
|
||||
|
||||
/* send three parts, command & data & a LE 4byte sequence number */
|
||||
unsigned char msgseq[sizeof(uint32_t)];
|
||||
WriteLE32(msgseq, nSequence);
|
||||
int rc = zmq_send_multipart(psocket, command, strlen(command), data, size, msgseq, (size_t)sizeof(uint32_t), nullptr);
|
||||
if (rc == -1)
|
||||
return false;
|
||||
|
||||
/* increment memory only sequence number after sending */
|
||||
nSequence++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CZMQPublishHashBlockNotifier::NotifyBlock(const CBlockIndex *pindex)
|
||||
{
|
||||
uint256 hash = pindex->GetBlockHash();
|
||||
LogPrint(BCLog::ZMQ, "zmq: Publish hashblock %s to %s\n", hash.GetHex(), this->address);
|
||||
char data[32];
|
||||
for (unsigned int i = 0; i < 32; i++)
|
||||
data[31 - i] = hash.begin()[i];
|
||||
return SendZmqMessage(MSG_HASHBLOCK, data, 32);
|
||||
}
|
||||
|
||||
bool CZMQPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &transaction)
|
||||
{
|
||||
uint256 hash = transaction.GetHash();
|
||||
LogPrint(BCLog::ZMQ, "zmq: Publish hashtx %s to %s\n", hash.GetHex(), this->address);
|
||||
char data[32];
|
||||
for (unsigned int i = 0; i < 32; i++)
|
||||
data[31 - i] = hash.begin()[i];
|
||||
return SendZmqMessage(MSG_HASHTX, data, 32);
|
||||
}
|
||||
|
||||
bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex)
|
||||
{
|
||||
LogPrint(BCLog::ZMQ, "zmq: Publish rawblock %s to %s\n", pindex->GetBlockHash().GetHex(), this->address);
|
||||
|
||||
const Consensus::Params& consensusParams = Params().GetConsensus();
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
|
||||
{
|
||||
LOCK(cs_main);
|
||||
CBlock block;
|
||||
if(!ReadBlockFromDisk(block, pindex, consensusParams))
|
||||
{
|
||||
zmqError("Can't read block from disk");
|
||||
return false;
|
||||
}
|
||||
|
||||
ss << block;
|
||||
}
|
||||
|
||||
return SendZmqMessage(MSG_RAWBLOCK, &(*ss.begin()), ss.size());
|
||||
}
|
||||
|
||||
bool CZMQPublishRawTransactionNotifier::NotifyTransaction(const CTransaction &transaction)
|
||||
{
|
||||
uint256 hash = transaction.GetHash();
|
||||
LogPrint(BCLog::ZMQ, "zmq: Publish rawtx %s to %s\n", hash.GetHex(), this->address);
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
|
||||
ss << transaction;
|
||||
return SendZmqMessage(MSG_RAWTX, &(*ss.begin()), ss.size());
|
||||
}
|
||||
|
||||
// Helper function to send a 'sequence' topic message with the following structure:
|
||||
// <32-byte hash> | <1-byte label> | <8-byte LE sequence> (optional)
|
||||
static bool SendSequenceMsg(CZMQAbstractPublishNotifier& notifier, uint256 hash, char label, std::optional<uint64_t> sequence = {})
|
||||
{
|
||||
unsigned char data[sizeof(hash) + sizeof(label) + sizeof(uint64_t)];
|
||||
for (unsigned int i = 0; i < sizeof(hash); ++i) {
|
||||
data[sizeof(hash) - 1 - i] = hash.begin()[i];
|
||||
}
|
||||
data[sizeof(hash)] = label;
|
||||
if (sequence) WriteLE64(data + sizeof(hash) + sizeof(label), *sequence);
|
||||
return notifier.SendZmqMessage(MSG_SEQUENCE, data, sequence ? sizeof(data) : sizeof(hash) + sizeof(label));
|
||||
}
|
||||
|
||||
bool CZMQPublishSequenceNotifier::NotifyBlockConnect(const CBlockIndex *pindex)
|
||||
{
|
||||
uint256 hash = pindex->GetBlockHash();
|
||||
LogPrint(BCLog::ZMQ, "zmq: Publish sequence block connect %s to %s\n", hash.GetHex(), this->address);
|
||||
return SendSequenceMsg(*this, hash, /* Block (C)onnect */ 'C');
|
||||
}
|
||||
|
||||
bool CZMQPublishSequenceNotifier::NotifyBlockDisconnect(const CBlockIndex *pindex)
|
||||
{
|
||||
uint256 hash = pindex->GetBlockHash();
|
||||
LogPrint(BCLog::ZMQ, "zmq: Publish sequence block disconnect %s to %s\n", hash.GetHex(), this->address);
|
||||
return SendSequenceMsg(*this, hash, /* Block (D)isconnect */ 'D');
|
||||
}
|
||||
|
||||
bool CZMQPublishSequenceNotifier::NotifyTransactionAcceptance(const CTransaction &transaction, uint64_t mempool_sequence)
|
||||
{
|
||||
uint256 hash = transaction.GetHash();
|
||||
LogPrint(BCLog::ZMQ, "zmq: Publish hashtx mempool acceptance %s to %s\n", hash.GetHex(), this->address);
|
||||
return SendSequenceMsg(*this, hash, /* Mempool (A)cceptance */ 'A', mempool_sequence);
|
||||
}
|
||||
|
||||
bool CZMQPublishSequenceNotifier::NotifyTransactionRemoval(const CTransaction &transaction, uint64_t mempool_sequence)
|
||||
{
|
||||
uint256 hash = transaction.GetHash();
|
||||
LogPrint(BCLog::ZMQ, "zmq: Publish hashtx mempool removal %s to %s\n", hash.GetHex(), this->address);
|
||||
return SendSequenceMsg(*this, hash, /* Mempool (R)emoval */ 'R', mempool_sequence);
|
||||
}
|
||||
65
src/zmq/zmqpublishnotifier.h
Normal file
65
src/zmq/zmqpublishnotifier.h
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright (c) 2009-2019 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2019 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_ZMQ_ZMQPUBLISHNOTIFIER_H
|
||||
#define DIGIBYTE_ZMQ_ZMQPUBLISHNOTIFIER_H
|
||||
|
||||
#include <zmq/zmqabstractnotifier.h>
|
||||
|
||||
class CBlockIndex;
|
||||
|
||||
class CZMQAbstractPublishNotifier : public CZMQAbstractNotifier
|
||||
{
|
||||
private:
|
||||
uint32_t nSequence {0U}; //!< upcounting per message sequence number
|
||||
|
||||
public:
|
||||
|
||||
/* send zmq multipart message
|
||||
parts:
|
||||
* command
|
||||
* data
|
||||
* message sequence number
|
||||
*/
|
||||
bool SendZmqMessage(const char *command, const void* data, size_t size);
|
||||
|
||||
bool Initialize(void *pcontext) override;
|
||||
void Shutdown() override;
|
||||
};
|
||||
|
||||
class CZMQPublishHashBlockNotifier : public CZMQAbstractPublishNotifier
|
||||
{
|
||||
public:
|
||||
bool NotifyBlock(const CBlockIndex *pindex) override;
|
||||
};
|
||||
|
||||
class CZMQPublishHashTransactionNotifier : public CZMQAbstractPublishNotifier
|
||||
{
|
||||
public:
|
||||
bool NotifyTransaction(const CTransaction &transaction) override;
|
||||
};
|
||||
|
||||
class CZMQPublishRawBlockNotifier : public CZMQAbstractPublishNotifier
|
||||
{
|
||||
public:
|
||||
bool NotifyBlock(const CBlockIndex *pindex) override;
|
||||
};
|
||||
|
||||
class CZMQPublishRawTransactionNotifier : public CZMQAbstractPublishNotifier
|
||||
{
|
||||
public:
|
||||
bool NotifyTransaction(const CTransaction &transaction) override;
|
||||
};
|
||||
|
||||
class CZMQPublishSequenceNotifier : public CZMQAbstractPublishNotifier
|
||||
{
|
||||
public:
|
||||
bool NotifyBlockConnect(const CBlockIndex *pindex) override;
|
||||
bool NotifyBlockDisconnect(const CBlockIndex *pindex) override;
|
||||
bool NotifyTransactionAcceptance(const CTransaction &transaction, uint64_t mempool_sequence) override;
|
||||
bool NotifyTransactionRemoval(const CTransaction &transaction, uint64_t mempool_sequence) override;
|
||||
};
|
||||
|
||||
#endif // DIGIBYTE_ZMQ_ZMQPUBLISHNOTIFIER_H
|
||||
68
src/zmq/zmqrpc.cpp
Normal file
68
src/zmq/zmqrpc.cpp
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright (c) 2018 The Bitcoin Core developers
|
||||
// Copyright (c) 2018-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <zmq/zmqrpc.h>
|
||||
|
||||
#include <rpc/server.h>
|
||||
#include <rpc/util.h>
|
||||
#include <zmq/zmqabstractnotifier.h>
|
||||
#include <zmq/zmqnotificationinterface.h>
|
||||
|
||||
#include <univalue.h>
|
||||
|
||||
namespace {
|
||||
|
||||
static RPCHelpMan getzmqnotifications()
|
||||
{
|
||||
return RPCHelpMan{"getzmqnotifications",
|
||||
"\nReturns information about the active ZeroMQ notifications.\n",
|
||||
{},
|
||||
RPCResult{
|
||||
RPCResult::Type::ARR, "", "",
|
||||
{
|
||||
{RPCResult::Type::OBJ, "", "",
|
||||
{
|
||||
{RPCResult::Type::STR, "type", "Type of notification"},
|
||||
{RPCResult::Type::STR, "address", "Address of the publisher"},
|
||||
{RPCResult::Type::NUM, "hwm", "Outbound message high water mark"},
|
||||
}},
|
||||
}
|
||||
},
|
||||
RPCExamples{
|
||||
HelpExampleCli("getzmqnotifications", "")
|
||||
+ HelpExampleRpc("getzmqnotifications", "")
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
UniValue result(UniValue::VARR);
|
||||
if (g_zmq_notification_interface != nullptr) {
|
||||
for (const auto* n : g_zmq_notification_interface->GetActiveNotifiers()) {
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
obj.pushKV("type", n->GetType());
|
||||
obj.pushKV("address", n->GetAddress());
|
||||
obj.pushKV("hwm", n->GetOutboundMessageHighWaterMark());
|
||||
result.push_back(obj);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const CRPCCommand commands[] =
|
||||
{ // category actor (function)
|
||||
// ----------------- -----------------------
|
||||
{ "zmq", &getzmqnotifications, },
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void RegisterZMQRPCCommands(CRPCTable& t)
|
||||
{
|
||||
for (const auto& c : commands) {
|
||||
t.appendCommand(c.name, &c);
|
||||
}
|
||||
}
|
||||
12
src/zmq/zmqrpc.h
Normal file
12
src/zmq/zmqrpc.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright (c) 2018 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_ZMQ_ZMQRPC_H
|
||||
#define DIGIBYTE_ZMQ_ZMQRPC_H
|
||||
|
||||
class CRPCTable;
|
||||
|
||||
void RegisterZMQRPCCommands(CRPCTable& t);
|
||||
|
||||
#endif // DIGIBYTE_ZMQ_ZMRRPC_H
|
||||
16
src/zmq/zmqutil.cpp
Normal file
16
src/zmq/zmqutil.cpp
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (c) 2014-2018 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <zmq/zmqutil.h>
|
||||
|
||||
#include <logging.h>
|
||||
#include <zmq.h>
|
||||
|
||||
#include <cerrno>
|
||||
#include <string>
|
||||
|
||||
void zmqError(const std::string& str)
|
||||
{
|
||||
LogPrint(BCLog::ZMQ, "zmq: Error: %s, msg: %s\n", str, zmq_strerror(errno));
|
||||
}
|
||||
12
src/zmq/zmqutil.h
Normal file
12
src/zmq/zmqutil.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright (c) 2014-2018 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_ZMQ_ZMQUTIL_H
|
||||
#define DIGIBYTE_ZMQ_ZMQUTIL_H
|
||||
|
||||
#include <string>
|
||||
|
||||
void zmqError(const std::string& str);
|
||||
|
||||
#endif // DIGIBYTE_ZMQ_ZMQUTIL_H
|
||||
Loading…
Reference in a new issue