diff --git a/contrib/zmq/zmq_sub.py b/contrib/zmq/zmq_sub.py index decf29d42..2dbe2923b 100755 --- a/contrib/zmq/zmq_sub.py +++ b/contrib/zmq/zmq_sub.py @@ -10,8 +10,10 @@ zmqContext = zmq.Context() zmqSubSocket = zmqContext.socket(zmq.SUB) zmqSubSocket.setsockopt(zmq.SUBSCRIBE, "hashblock") zmqSubSocket.setsockopt(zmq.SUBSCRIBE, "hashtx") +zmqSubSocket.setsockopt(zmq.SUBSCRIBE, "hashtxlock") zmqSubSocket.setsockopt(zmq.SUBSCRIBE, "rawblock") zmqSubSocket.setsockopt(zmq.SUBSCRIBE, "rawtx") +zmqSubSocket.setsockopt(zmq.SUBSCRIBE, "rawtxlock") zmqSubSocket.connect("tcp://127.0.0.1:%i" % port) try: @@ -26,12 +28,18 @@ try: elif topic == "hashtx": print '- HASH TX -' print binascii.hexlify(body) + elif topic == "hashtxlock": + print '- HASH TX LOCK -' + print binascii.hexlify(body) elif topic == "rawblock": print "- RAW BLOCK HEADER -" print binascii.hexlify(body[:80]) elif topic == "rawtx": print '- RAW TX -' print binascii.hexlify(body) + elif topic == "rawtxlock": + print '- RAW TX LOCK -' + print binascii.hexlify(body) except KeyboardInterrupt: zmqContext.destroy() diff --git a/doc/zmq.md b/doc/zmq.md index 8d7ef37d7..f85c338b7 100644 --- a/doc/zmq.md +++ b/doc/zmq.md @@ -57,9 +57,11 @@ the commandline or in the configuration file. Currently, the following notifications are supported: -zmqpubhashtx=address + -zmqpubhashtxlock=address -zmqpubhashblock=address -zmqpubrawblock=address -zmqpubrawtx=address + -zmqpubrawtxlock=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. diff --git a/src/init.cpp b/src/init.cpp index 06f9e0427..25f0cf443 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -481,8 +481,10 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageGroup(_("ZeroMQ notification options:")); strUsage += HelpMessageOpt("-zmqpubhashblock=
", _("Enable publish hash block in
")); strUsage += HelpMessageOpt("-zmqpubhashtx=
", _("Enable publish hash transaction in
")); + strUsage += HelpMessageOpt("-zmqpubhashtxlock=
", _("Enable publish hash transaction (locked via InstantSend) in
")); strUsage += HelpMessageOpt("-zmqpubrawblock=
", _("Enable publish raw block in
")); strUsage += HelpMessageOpt("-zmqpubrawtx=
", _("Enable publish raw transaction in
")); + strUsage += HelpMessageOpt("-zmqpubrawtxlock=
", _("Enable publish raw transaction (locked via InstantSend) in
")); #endif strUsage += HelpMessageGroup(_("Debugging/Testing options:")); diff --git a/src/instantx.cpp b/src/instantx.cpp index 4f58e42d0..e938d082d 100644 --- a/src/instantx.cpp +++ b/src/instantx.cpp @@ -386,11 +386,12 @@ void UpdateLockedTransaction(CTransaction& tx, bool fForceNotification) { // there must be a successfully verified lock request if (!mapTxLockReq.count(txHash)) return; + int nSignatures = GetTransactionLockSignatures(txHash); + #ifdef ENABLE_WALLET if(pwalletMain && pwalletMain->UpdatedTransaction(txHash)){ // bumping this to update UI nCompleteTXLocks++; - int nSignatures = GetTransactionLockSignatures(txHash); // a transaction lock must have enough signatures to trigger this notification if(nSignatures == INSTANTX_SIGNATURES_REQUIRED || (fForceNotification && nSignatures > INSTANTX_SIGNATURES_REQUIRED)) { // notify an external script once threshold is reached @@ -403,6 +404,10 @@ void UpdateLockedTransaction(CTransaction& tx, bool fForceNotification) { } } #endif + + if(nSignatures == INSTANTX_SIGNATURES_REQUIRED || (fForceNotification && nSignatures > INSTANTX_SIGNATURES_REQUIRED)) { + GetMainSignals().NotifyTransactionLock(tx); + } } void LockTransactionInputs(CTransaction& tx) { diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 81f3b775f..b6c5752ce 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -15,6 +15,7 @@ CMainSignals& GetMainSignals() void RegisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1)); g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2)); + g_signals.NotifyTransactionLock.connect(boost::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, _1)); g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); @@ -32,6 +33,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); + g_signals.NotifyTransactionLock.disconnect(boost::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, _1)); g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2)); g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1)); } @@ -44,6 +46,7 @@ void UnregisterAllValidationInterfaces() { g_signals.Inventory.disconnect_all_slots(); g_signals.SetBestChain.disconnect_all_slots(); g_signals.UpdatedTransaction.disconnect_all_slots(); + g_signals.NotifyTransactionLock.disconnect_all_slots(); g_signals.SyncTransaction.disconnect_all_slots(); g_signals.UpdatedBlockTip.disconnect_all_slots(); } diff --git a/src/validationinterface.h b/src/validationinterface.h index d52a96264..d621fd709 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -33,6 +33,7 @@ class CValidationInterface { protected: virtual void UpdatedBlockTip(const CBlockIndex *pindex) {} virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock) {} + virtual void NotifyTransactionLock(const CTransaction &tx) {} virtual void SetBestChain(const CBlockLocator &locator) {} virtual bool UpdatedTransaction(const uint256 &hash) { return false;} virtual void Inventory(const uint256 &hash) {} @@ -50,6 +51,8 @@ struct CMainSignals { boost::signals2::signal UpdatedBlockTip; /** Notifies listeners of updated transaction data (transaction, and optionally the block it is found in. */ boost::signals2::signal SyncTransaction; + /** Notifies listeners of an updated transaction lock without new data. */ + boost::signals2::signal NotifyTransactionLock; /** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */ boost::signals2::signal UpdatedTransaction; /** Notifies listeners of a new active block chain. */ diff --git a/src/zmq/zmqabstractnotifier.cpp b/src/zmq/zmqabstractnotifier.cpp index 9f5cb3ba6..76543a4a7 100644 --- a/src/zmq/zmqabstractnotifier.cpp +++ b/src/zmq/zmqabstractnotifier.cpp @@ -20,3 +20,8 @@ bool CZMQAbstractNotifier::NotifyTransaction(const CTransaction &/*transaction*/ { return true; } + +bool CZMQAbstractNotifier::NotifyTransactionLock(const CTransaction &/*transaction*/) +{ + return true; +} diff --git a/src/zmq/zmqabstractnotifier.h b/src/zmq/zmqabstractnotifier.h index 77cf5141e..0d3f1fcd4 100644 --- a/src/zmq/zmqabstractnotifier.h +++ b/src/zmq/zmqabstractnotifier.h @@ -34,6 +34,7 @@ public: virtual bool NotifyBlock(const CBlockIndex *pindex); virtual bool NotifyTransaction(const CTransaction &transaction); + virtual bool NotifyTransactionLock(const CTransaction &transaction); protected: void *psocket; diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp index be2aec7d1..a8d3b2b89 100644 --- a/src/zmq/zmqnotificationinterface.cpp +++ b/src/zmq/zmqnotificationinterface.cpp @@ -37,8 +37,10 @@ CZMQNotificationInterface* CZMQNotificationInterface::CreateWithArguments(const factories["pubhashblock"] = CZMQAbstractNotifier::Create; factories["pubhashtx"] = CZMQAbstractNotifier::Create; + factories["pubhashtxlock"] = CZMQAbstractNotifier::Create; factories["pubrawblock"] = CZMQAbstractNotifier::Create; factories["pubrawtx"] = CZMQAbstractNotifier::Create; + factories["pubrawtxlock"] = CZMQAbstractNotifier::Create; for (std::map::const_iterator i=factories.begin(); i!=factories.end(); ++i) { @@ -158,3 +160,20 @@ void CZMQNotificationInterface::SyncTransaction(const CTransaction &tx, const CB } } } + +void CZMQNotificationInterface::NotifyTransactionLock(const CTransaction &tx) +{ + for (std::list::iterator i = notifiers.begin(); i!=notifiers.end(); ) + { + CZMQAbstractNotifier *notifier = *i; + if (notifier->NotifyTransactionLock(tx)) + { + i++; + } + else + { + notifier->Shutdown(); + i = notifiers.erase(i); + } + } +} diff --git a/src/zmq/zmqnotificationinterface.h b/src/zmq/zmqnotificationinterface.h index 3ccfaf341..11d4db83d 100644 --- a/src/zmq/zmqnotificationinterface.h +++ b/src/zmq/zmqnotificationinterface.h @@ -26,6 +26,7 @@ protected: // CValidationInterface void SyncTransaction(const CTransaction &tx, const CBlock *pblock); void UpdatedBlockTip(const CBlockIndex *pindex); + void NotifyTransactionLock(const CTransaction &tx); private: CZMQNotificationInterface(); diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp index ddc8fe93e..07f0167be 100644 --- a/src/zmq/zmqpublishnotifier.cpp +++ b/src/zmq/zmqpublishnotifier.cpp @@ -139,6 +139,17 @@ bool CZMQPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &t return rc == 0; } +bool CZMQPublishHashTransactionLockNotifier::NotifyTransactionLock(const CTransaction &transaction) +{ + uint256 hash = transaction.GetHash(); + LogPrint("zmq", "zmq: Publish hashtxlock %s\n", hash.GetHex()); + char data[32]; + for (unsigned int i = 0; i < 32; i++) + data[31 - i] = hash.begin()[i]; + int rc = zmq_send_multipart(psocket, "hashtxlock", 10, data, 32, 0); + return rc == 0; +} + bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex) { LogPrint("zmq", "zmq: Publish rawblock %s\n", pindex->GetBlockHash().GetHex()); @@ -170,3 +181,13 @@ bool CZMQPublishRawTransactionNotifier::NotifyTransaction(const CTransaction &tr int rc = zmq_send_multipart(psocket, "rawtx", 5, &(*ss.begin()), ss.size(), 0); return rc == 0; } + +bool CZMQPublishRawTransactionLockNotifier::NotifyTransactionLock(const CTransaction &transaction) +{ + uint256 hash = transaction.GetHash(); + LogPrint("zmq", "zmq: Publish rawtxlock %s\n", hash.GetHex()); + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << transaction; + int rc = zmq_send_multipart(psocket, "rawtxlock", 9, &(*ss.begin()), ss.size(), 0); + return rc == 0; +} diff --git a/src/zmq/zmqpublishnotifier.h b/src/zmq/zmqpublishnotifier.h index 44d5cbea6..c92150472 100644 --- a/src/zmq/zmqpublishnotifier.h +++ b/src/zmq/zmqpublishnotifier.h @@ -28,6 +28,12 @@ public: bool NotifyTransaction(const CTransaction &transaction); }; +class CZMQPublishHashTransactionLockNotifier : public CZMQAbstractPublishNotifier +{ +public: + bool NotifyTransactionLock(const CTransaction &transaction); +}; + class CZMQPublishRawBlockNotifier : public CZMQAbstractPublishNotifier { public: @@ -40,4 +46,10 @@ public: bool NotifyTransaction(const CTransaction &transaction); }; +class CZMQPublishRawTransactionLockNotifier : public CZMQAbstractPublishNotifier +{ +public: + bool NotifyTransactionLock(const CTransaction &transaction); +}; + #endif // BITCOIN_ZMQ_ZMQPUBLISHNOTIFIER_H