[ZMQ] Notify when an IS double spend is attempted (#2262)
* Implement IS Double spend notifications in zmq * copy/paste error * typo * Send both conflicting and conflicts against as ZMQ notifications * CTransaction based not hash based * @UdjinM6 requested changes
This commit is contained in:
parent
28e0476f4c
commit
1e74bcace9
@ -16,11 +16,13 @@ zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashtx")
|
||||
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashtxlock")
|
||||
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashgovernancevote")
|
||||
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashgovernanceobject")
|
||||
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashinstantsenddoublespend")
|
||||
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"rawblock")
|
||||
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"rawtx")
|
||||
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"rawtxlock")
|
||||
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"rawgovernancevote")
|
||||
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"rawgovernanceobject")
|
||||
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"rawinstantsenddoublespend")
|
||||
zmqSubSocket.connect("tcp://127.0.0.1:%i" % port)
|
||||
|
||||
try:
|
||||
@ -52,6 +54,9 @@ try:
|
||||
elif topic == "rawtxlock":
|
||||
print('- RAW TX LOCK ('+sequence+') -')
|
||||
print(binascii.hexlify(body).decode("utf-8"))
|
||||
elif topic == "rawinstantsenddoublespend":
|
||||
print('- RAW IS DOUBLE SPEND ('+sequence+') -')
|
||||
print(binascii.hexlify(body).decode("utf-8"))
|
||||
elif topic == "hashgovernancevote":
|
||||
print('- HASH GOVERNANCE VOTE ('+sequence+') -')
|
||||
print(binascii.hexlify(body).decode("utf-8"))
|
||||
@ -64,7 +69,9 @@ try:
|
||||
elif topic == "rawgovernanceobject":
|
||||
print('- RAW GOVERNANCE OBJECT ('+sequence+') -')
|
||||
print(binascii.hexlify(body).decode("utf-8"))
|
||||
|
||||
elif topic == "hashinstantsenddoublespend":
|
||||
print('- HASH IS DOUBLE SPEND ('+sequence+') -')
|
||||
print(binascii.hexlify(body).decode("utf-8"))
|
||||
|
||||
except KeyboardInterrupt:
|
||||
zmqContext.destroy()
|
||||
|
@ -66,6 +66,8 @@ Currently, the following notifications are supported:
|
||||
-zmqpubhashgovernanceobject=address
|
||||
-zmqpubrawgovernancevote=address
|
||||
-zmqpubhashgovernanceobject=address
|
||||
-zmqpubrawinstantsenddoublespend=address
|
||||
-zmqpubhashinstantsenddoublespend=address
|
||||
|
||||
The socket type is PUB and the address must be a valid ZeroMQ socket
|
||||
address. The same address can be used in more than one notification.
|
||||
|
@ -508,9 +508,11 @@ std::string HelpMessage(HelpMessageMode mode)
|
||||
strUsage += HelpMessageOpt("-zmqpubhashtxlock=<address>", _("Enable publish hash transaction (locked via InstantSend) in <address>"));
|
||||
strUsage += HelpMessageOpt("-zmqpubhashgovernancevote=<address>", _("Enable publish hash of governance votes in <address>"));
|
||||
strUsage += HelpMessageOpt("-zmqpubhashgovernanceobject=<address>", _("Enable publish hash of governance objects (like proposals) in <address>"));
|
||||
strUsage += HelpMessageOpt("-zmqpubhashinstantsenddoublespend=<address>", _("Enable publish transaction hashes of attempted InstantSend double spend in <address>"));
|
||||
strUsage += HelpMessageOpt("-zmqpubrawblock=<address>", _("Enable publish raw block in <address>"));
|
||||
strUsage += HelpMessageOpt("-zmqpubrawtx=<address>", _("Enable publish raw transaction in <address>"));
|
||||
strUsage += HelpMessageOpt("-zmqpubrawtxlock=<address>", _("Enable publish raw transaction (locked via InstantSend) in <address>"));
|
||||
strUsage += HelpMessageOpt("-zmqpubrawinstantsenddoublespend=<address>", _("Enable publish raw transactions of attempted InstantSend double spend in <address>"));
|
||||
#endif
|
||||
|
||||
strUsage += HelpMessageGroup(_("Debugging/Testing options:"));
|
||||
|
@ -117,7 +117,13 @@ bool CInstantSend::ProcessTxLockRequest(const CTxLockRequest& txLockRequest, CCo
|
||||
if(hash != txLockRequest.GetHash()) {
|
||||
LogPrint("instantsend", "CInstantSend::ProcessTxLockRequest -- Double spend attempt! %s\n", txin.prevout.ToStringShort());
|
||||
// do not fail here, let it go and see which one will get the votes to be locked
|
||||
// TODO: notify zmq+script
|
||||
// NOTIFY ZMQ
|
||||
CTransaction txCurrent = *txLockRequest.tx; // currently processed tx
|
||||
auto itPrevious = mapTxLockCandidates.find(hash);
|
||||
if (itPrevious != mapTxLockCandidates.end() && itPrevious->second.txLockRequest) {
|
||||
CTransaction txPrevious = *itPrevious->second.txLockRequest.tx; // previously locked one
|
||||
GetMainSignals().NotifyInstantSendDoubleSpendAttempt(txCurrent, txPrevious);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
|
||||
g_signals.NewPoWValidBlock.connect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
|
||||
g_signals.NotifyGovernanceObject.connect(boost::bind(&CValidationInterface::NotifyGovernanceObject, pwalletIn, _1));
|
||||
g_signals.NotifyGovernanceVote.connect(boost::bind(&CValidationInterface::NotifyGovernanceVote, pwalletIn, _1));
|
||||
g_signals.NotifyInstantSendDoubleSpendAttempt.connect(boost::bind(&CValidationInterface::NotifyInstantSendDoubleSpendAttempt, pwalletIn, _1, _2));
|
||||
}
|
||||
|
||||
void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
|
||||
@ -46,6 +47,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
|
||||
g_signals.AcceptedBlockHeader.disconnect(boost::bind(&CValidationInterface::AcceptedBlockHeader, pwalletIn, _1));
|
||||
g_signals.NotifyGovernanceObject.disconnect(boost::bind(&CValidationInterface::NotifyGovernanceObject, pwalletIn, _1));
|
||||
g_signals.NotifyGovernanceVote.disconnect(boost::bind(&CValidationInterface::NotifyGovernanceVote, pwalletIn, _1));
|
||||
g_signals.NotifyInstantSendDoubleSpendAttempt.disconnect(boost::bind(&CValidationInterface::NotifyInstantSendDoubleSpendAttempt, pwalletIn, _1, _2));
|
||||
}
|
||||
|
||||
void UnregisterAllValidationInterfaces() {
|
||||
@ -64,4 +66,5 @@ void UnregisterAllValidationInterfaces() {
|
||||
g_signals.AcceptedBlockHeader.disconnect_all_slots();
|
||||
g_signals.NotifyGovernanceObject.disconnect_all_slots();
|
||||
g_signals.NotifyGovernanceVote.disconnect_all_slots();
|
||||
g_signals.NotifyInstantSendDoubleSpendAttempt.disconnect_all_slots();
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ protected:
|
||||
virtual void NotifyTransactionLock(const CTransaction &tx) {}
|
||||
virtual void NotifyGovernanceVote(const CGovernanceVote &vote) {}
|
||||
virtual void NotifyGovernanceObject(const CGovernanceObject &object) {}
|
||||
virtual void NotifyInstantSendDoubleSpendAttempt(const CTransaction ¤tTx, const CTransaction &previousTx) {}
|
||||
virtual void SetBestChain(const CBlockLocator &locator) {}
|
||||
virtual bool UpdatedTransaction(const uint256 &hash) { return false;}
|
||||
virtual void Inventory(const uint256 &hash) {}
|
||||
@ -77,6 +78,8 @@ struct CMainSignals {
|
||||
boost::signals2::signal<void (const CGovernanceVote &)> NotifyGovernanceVote;
|
||||
/** Notifies listeners of a new governance object. */
|
||||
boost::signals2::signal<void (const CGovernanceObject &)> NotifyGovernanceObject;
|
||||
/** Notifies listeners of a attempted InstantSend double spend*/
|
||||
boost::signals2::signal<void(const CTransaction ¤tTx, const CTransaction &previousTx)> NotifyInstantSendDoubleSpendAttempt;
|
||||
/** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */
|
||||
boost::signals2::signal<bool (const uint256 &)> UpdatedTransaction;
|
||||
/** Notifies listeners of a new active block chain. */
|
||||
|
@ -35,3 +35,8 @@ bool CZMQAbstractNotifier::NotifyGovernanceObject(const CGovernanceObject& /*obj
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CZMQAbstractNotifier::NotifyInstantSendDoubleSpendAttempt(const CTransaction& /*currentTx*/, const CTransaction& /*previousTx*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ public:
|
||||
virtual bool NotifyTransactionLock(const CTransaction &transaction);
|
||||
virtual bool NotifyGovernanceVote(const CGovernanceVote &vote);
|
||||
virtual bool NotifyGovernanceObject(const CGovernanceObject &object);
|
||||
virtual bool NotifyInstantSendDoubleSpendAttempt(const CTransaction ¤tTx, const CTransaction &previousTx);
|
||||
|
||||
|
||||
protected:
|
||||
|
@ -22,6 +22,8 @@
|
||||
#include "governance-object.h"
|
||||
#include "governance-vote.h"
|
||||
|
||||
#include "instantx.h"
|
||||
|
||||
void zmqError(const char *str);
|
||||
|
||||
#endif // BITCOIN_ZMQ_ZMQCONFIG_H
|
||||
|
@ -40,11 +40,13 @@ CZMQNotificationInterface* CZMQNotificationInterface::Create()
|
||||
factories["pubhashtxlock"] = CZMQAbstractNotifier::Create<CZMQPublishHashTransactionLockNotifier>;
|
||||
factories["pubhashgovernancevote"] = CZMQAbstractNotifier::Create<CZMQPublishHashGovernanceVoteNotifier>;
|
||||
factories["pubhashgovernanceobject"] = CZMQAbstractNotifier::Create<CZMQPublishHashGovernanceObjectNotifier>;
|
||||
factories["pubhashinstantsenddoublespend"] = CZMQAbstractNotifier::Create<CZMQPublishHashInstantSendDoubleSpendNotifier>;
|
||||
factories["pubrawblock"] = CZMQAbstractNotifier::Create<CZMQPublishRawBlockNotifier>;
|
||||
factories["pubrawtx"] = CZMQAbstractNotifier::Create<CZMQPublishRawTransactionNotifier>;
|
||||
factories["pubrawtxlock"] = CZMQAbstractNotifier::Create<CZMQPublishRawTransactionLockNotifier>;
|
||||
factories["pubrawgovernancevote"] = CZMQAbstractNotifier::Create<CZMQPublishRawGovernanceVoteNotifier>;
|
||||
factories["pubrawgovernanceobject"] = CZMQAbstractNotifier::Create<CZMQPublishRawGovernanceObjectNotifier>;
|
||||
factories["pubrawinstantsenddoublespend"] = CZMQAbstractNotifier::Create<CZMQPublishRawInstantSendDoubleSpendNotifier>;
|
||||
|
||||
for (std::map<std::string, CZMQNotifierFactory>::const_iterator i=factories.begin(); i!=factories.end(); ++i)
|
||||
{
|
||||
@ -217,3 +219,16 @@ void CZMQNotificationInterface::NotifyGovernanceObject(const CGovernanceObject &
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CZMQNotificationInterface::NotifyInstantSendDoubleSpendAttempt(const CTransaction ¤tTx, const CTransaction &previousTx)
|
||||
{
|
||||
for (auto it = notifiers.begin(); it != notifiers.end();) {
|
||||
CZMQAbstractNotifier *notifier = *it;
|
||||
if (notifier->NotifyInstantSendDoubleSpendAttempt(currentTx, previousTx)) {
|
||||
++it;
|
||||
} else {
|
||||
notifier->Shutdown();
|
||||
it = notifiers.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ protected:
|
||||
void NotifyTransactionLock(const CTransaction &tx) override;
|
||||
void NotifyGovernanceVote(const CGovernanceVote& vote) override;
|
||||
void NotifyGovernanceObject(const CGovernanceObject& object) override;
|
||||
void NotifyInstantSendDoubleSpendAttempt(const CTransaction ¤tTx, const CTransaction &previousTx) override;
|
||||
|
||||
|
||||
private:
|
||||
|
@ -15,11 +15,13 @@ static const char *MSG_HASHTX = "hashtx";
|
||||
static const char *MSG_HASHTXLOCK = "hashtxlock";
|
||||
static const char *MSG_HASHGVOTE = "hashgovernancevote";
|
||||
static const char *MSG_HASHGOBJ = "hashgovernanceobject";
|
||||
static const char *MSG_HASHISCON = "hashinstantsenddoublespend";
|
||||
static const char *MSG_RAWBLOCK = "rawblock";
|
||||
static const char *MSG_RAWTX = "rawtx";
|
||||
static const char *MSG_RAWTXLOCK = "rawtxlock";
|
||||
static const char *MSG_RAWGVOTE = "rawgovernancevote";
|
||||
static const char *MSG_RAWGOBJ = "rawgovernanceobject";
|
||||
static const char *MSG_RAWISCON = "rawinstantsenddoublespend";
|
||||
|
||||
// Internal function to send multipart message
|
||||
static int zmq_send_multipart(void *sock, const void* data, size_t size, ...)
|
||||
@ -197,6 +199,20 @@ bool CZMQPublishHashGovernanceObjectNotifier::NotifyGovernanceObject(const CGove
|
||||
return SendMessage(MSG_HASHGOBJ, data, 32);
|
||||
}
|
||||
|
||||
bool CZMQPublishHashInstantSendDoubleSpendNotifier::NotifyInstantSendDoubleSpendAttempt(const CTransaction ¤tTx, const CTransaction &previousTx)
|
||||
{
|
||||
uint256 currentHash = currentTx.GetHash(), previousHash = previousTx.GetHash();
|
||||
LogPrint("zmq", "zmq: Publish hashinstantsenddoublespend %s conflicts against %s\n", currentHash.ToString(), previousHash.ToString());
|
||||
char dataCurrentHash[32], dataPreviousHash[32];
|
||||
for (unsigned int i = 0; i < 32; i++) {
|
||||
dataCurrentHash[31 - i] = currentHash.begin()[i];
|
||||
dataPreviousHash[31 - i] = previousHash.begin()[i];
|
||||
}
|
||||
return SendMessage(MSG_HASHISCON, dataCurrentHash, 32)
|
||||
&& SendMessage(MSG_HASHISCON, dataPreviousHash, 32);
|
||||
}
|
||||
|
||||
|
||||
bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex)
|
||||
{
|
||||
LogPrint("zmq", "zmq: Publish rawblock %s\n", pindex->GetBlockHash().GetHex());
|
||||
@ -253,3 +269,13 @@ bool CZMQPublishRawGovernanceObjectNotifier::NotifyGovernanceObject(const CGover
|
||||
ss << govobj;
|
||||
return SendMessage(MSG_RAWGOBJ, &(*ss.begin()), ss.size());
|
||||
}
|
||||
|
||||
bool CZMQPublishRawInstantSendDoubleSpendNotifier::NotifyInstantSendDoubleSpendAttempt(const CTransaction ¤tTx, const CTransaction &previousTx)
|
||||
{
|
||||
LogPrint("zmq", "zmq: Publish rawinstantsenddoublespend %s conflicts with %s\n", currentTx.GetHash().ToString(), previousTx.GetHash().ToString());
|
||||
CDataStream ssCurrent(SER_NETWORK, PROTOCOL_VERSION), ssPrevious(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ssCurrent << currentTx;
|
||||
ssPrevious << previousTx;
|
||||
return SendMessage(MSG_RAWISCON, &(*ssCurrent.begin()), ssCurrent.size())
|
||||
&& SendMessage(MSG_RAWISCON, &(*ssPrevious.begin()), ssPrevious.size());
|
||||
}
|
||||
|
@ -60,6 +60,12 @@ public:
|
||||
bool NotifyGovernanceObject(const CGovernanceObject &object) override;
|
||||
};
|
||||
|
||||
class CZMQPublishHashInstantSendDoubleSpendNotifier : public CZMQAbstractPublishNotifier
|
||||
{
|
||||
public:
|
||||
bool NotifyInstantSendDoubleSpendAttempt(const CTransaction ¤tTx, const CTransaction &previousTx) override;
|
||||
};
|
||||
|
||||
class CZMQPublishRawBlockNotifier : public CZMQAbstractPublishNotifier
|
||||
{
|
||||
public:
|
||||
@ -89,4 +95,10 @@ class CZMQPublishRawGovernanceObjectNotifier : public CZMQAbstractPublishNotifie
|
||||
public:
|
||||
bool NotifyGovernanceObject(const CGovernanceObject &object) override;
|
||||
};
|
||||
|
||||
class CZMQPublishRawInstantSendDoubleSpendNotifier : public CZMQAbstractPublishNotifier
|
||||
{
|
||||
public:
|
||||
bool NotifyInstantSendDoubleSpendAttempt(const CTransaction ¤tTx, const CTransaction &previousTx) override;
|
||||
};
|
||||
#endif // BITCOIN_ZMQ_ZMQPUBLISHNOTIFIER_H
|
||||
|
Loading…
Reference in New Issue
Block a user