From 6bb81c32361666211be9499648f4083b6b1cc673 Mon Sep 17 00:00:00 2001 From: WeebDataHoarder Date: Fri, 29 Aug 2025 19:06:22 +0200 Subject: [PATCH 1/1] WIP: added json-full-chain_alt and json-minimal-chain_alt to ZMQ notify --- src/cryptonote_core/blockchain.cpp | 12 +++++++ src/cryptonote_core/blockchain.h | 8 +++++ src/daemon/daemon.cpp | 2 ++ src/rpc/zmq_pub.cpp | 52 ++++++++++++++++++++++++++++-- src/rpc/zmq_pub.h | 13 ++++++++ 5 files changed, 85 insertions(+), 2 deletions(-) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 97275a462..2638459be 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -2080,6 +2080,9 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id m_db->add_alt_block(id, data, cryptonote::block_to_blob(bei.bl)); alt_chain.push_back(bei); + for (const auto& notifier: m_alt_block_notifiers) + notifier(bei.height, {std::addressof(bei.bl), 1}); + // FIXME: is it even possible for a checkpoint to show up not on the main chain? if(is_a_checkpoint) { @@ -5476,6 +5479,15 @@ void Blockchain::set_txpool_notify(TxpoolNotifyCallback&& notify) m_txpool_notifier = notify; } +void Blockchain::add_alt_block_notify(BlockNotifyCallback&& notify) +{ + if (notify) + { + CRITICAL_REGION_LOCAL(m_blockchain_lock); + m_alt_block_notifiers.push_back(std::move(notify)); + } +} + void Blockchain::add_block_notify(BlockNotifyCallback&& notify) { if (notify) diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index f16bc7415..6e97c976e 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -848,6 +848,13 @@ namespace cryptonote */ void set_txpool_notify(TxpoolNotifyCallback&& notify); + /** + * @brief sets a block notify object to call for every new alternate block + * + * @param notify the notify object to call at every new alternate block + */ + void add_alt_block_notify(BlockNotifyCallback&& notify); + /** * @brief sets a block notify object to call for every new block * @@ -1249,6 +1256,7 @@ namespace cryptonote the callable object has a single `std::shared_ptr` or `std::weap_ptr` internally. Whereas, the libstdc++ `std::function` will allocate. */ + std::vector m_alt_block_notifiers; std::vector m_block_notifiers; std::vector m_miner_notifiers; std::shared_ptr m_reorg_notify; diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index 2512e5430..7caeb60ff 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -48,6 +48,7 @@ #include "daemon/command_line_args.h" #include "net/net_ssl.h" #include "version.h" +#include "rpc/zmq_pub.h" using namespace epee; @@ -120,6 +121,7 @@ public: if (shared) { core.get().get_blockchain_storage().set_txpool_notify(cryptonote::listener::zmq_pub::txpool_add{shared}); + core.get().get_blockchain_storage().add_alt_block_notify(cryptonote::listener::zmq_pub::chain_alt{shared}); core.get().get_blockchain_storage().add_block_notify(cryptonote::listener::zmq_pub::chain_main{shared}); core.get().get_blockchain_storage().add_miner_notify(cryptonote::listener::zmq_pub::miner_data{shared}); } diff --git a/src/rpc/zmq_pub.cpp b/src/rpc/zmq_pub.cpp index 81e6de99a..a4b715d37 100644 --- a/src/rpc/zmq_pub.cpp +++ b/src/rpc/zmq_pub.cpp @@ -226,6 +226,12 @@ namespace json_pub(buf, (txes | adapt::filtered(is_valid{}) | adapt::transformed(to_minimal_tx))); } + constexpr const std::array, 2> altchain_contexts = + {{ + {u8"json-full-chain_alt", json_full_chain}, + {u8"json-minimal-chain_alt", json_minimal_chain}, + }}; + constexpr const std::array, 2> chain_contexts = {{ {u8"json-full-chain_main", json_full_chain}, @@ -359,6 +365,7 @@ namespace cryptonote { namespace listener zmq_pub::zmq_pub(void* context) : relay_(), + altchain_subs_{{0}}, chain_subs_{{0}}, miner_subs_{{0}}, txpool_subs_{{0}}, @@ -388,24 +395,27 @@ bool zmq_pub::sub_request(boost::string_ref message) const char tag = message[0]; message.remove_prefix(1); + const auto altchain_range = get_range(altchain_contexts, message); const auto chain_range = get_range(chain_contexts, message); const auto miner_range = get_range(miner_contexts, message); const auto txpool_range = get_range(txpool_contexts, message); - if (!chain_range.empty() || !miner_range.empty() || !txpool_range.empty()) + if (!altchain_range.empty() || !chain_range.empty() || !miner_range.empty() || !txpool_range.empty()) { MDEBUG("Client " << (tag ? "subscribed" : "unsubscribed") << " to " << - chain_range.size() << " chain topic(s), " << miner_range.size() << " miner topic(s) and " << txpool_range.size() << " txpool topic(s)"); + altchain_range.size() << " altchain topic(s), " << chain_range.size() << " chain topic(s), " << miner_range.size() << " miner topic(s) and " << txpool_range.size() << " txpool topic(s)"); const boost::lock_guard lock{sync_}; switch (tag) { case 0: + remove_subscriptions(altchain_subs_, chain_range, altchain_contexts.begin()); remove_subscriptions(chain_subs_, chain_range, chain_contexts.begin()); remove_subscriptions(miner_subs_, miner_range, miner_contexts.begin()); remove_subscriptions(txpool_subs_, txpool_range, txpool_contexts.begin()); return true; case 1: + add_subscriptions(altchain_subs_, chain_range, altchain_contexts.begin()); add_subscriptions(chain_subs_, chain_range, chain_contexts.begin()); add_subscriptions(miner_subs_, miner_range, miner_contexts.begin()); add_subscriptions(txpool_subs_, txpool_range, txpool_contexts.begin()); @@ -451,6 +461,35 @@ bool zmq_pub::relay_to_pub(void* const relay, void* const pub) return true; } + std::size_t zmq_pub::send_chain_alt(const std::uint64_t height, const epee::span blocks) +{ + if (blocks.empty()) + return 0; + + /* Block format only sends one block at a time - multiple block notifications + are less common and only occur on rollbacks. */ + + boost::unique_lock guard{sync_}; + + const auto subs_copy = altchain_subs_; + guard.unlock(); + + for (const std::size_t sub : subs_copy) + { + if (sub) + { + /* cryptonote_core/blockchain.cpp cannot "give" us the block like core + does for txpool events. Since copying the block is expensive anyway, + serialization is done right here on the p2p thread (for now). */ + + auto messages = make_pubs(subs_copy, altchain_contexts, height, blocks); + guard.lock(); + return send_messages(relay_.get(), messages); + } + } + return 0; +} + std::size_t zmq_pub::send_chain_main(const std::uint64_t height, const epee::span blocks) { if (blocks.empty()) @@ -520,6 +559,15 @@ std::size_t zmq_pub::send_txpool_add(std::vector txes) return 0; } +void zmq_pub::chain_alt::operator()(const std::uint64_t height, epee::span blocks) const +{ + const std::shared_ptr self = self_.lock(); + if (self) + self->send_chain_alt(height, blocks); + else + MERROR("Unable to send ZMQ/Pub - ZMQ server destroyed"); +} + void zmq_pub::chain_main::operator()(const std::uint64_t height, epee::span blocks) const { const std::shared_ptr self = self_.lock(); diff --git a/src/rpc/zmq_pub.h b/src/rpc/zmq_pub.h index 9554f26be..e1ac57362 100644 --- a/src/rpc/zmq_pub.h +++ b/src/rpc/zmq_pub.h @@ -60,6 +60,7 @@ class zmq_pub net::zmq::socket relay_; std::deque> txes_; + std::array altchain_subs_; std::array chain_subs_; std::array miner_subs_; std::array txpool_subs_; @@ -86,6 +87,11 @@ class zmq_pub `send_txpool_add` to `pub`. Used by `ZmqServer`. */ bool relay_to_pub(void* relay, void* pub); + /*! Send a `ZMQ_PUB` notification for a change to the alt chain. + Thread-safe. + \return Number of ZMQ messages sent to relay. */ + std::size_t send_chain_alt(std::uint64_t height, epee::span blocks); + /*! Send a `ZMQ_PUB` notification for a change to the main chain. Thread-safe. \return Number of ZMQ messages sent to relay. */ @@ -101,6 +107,13 @@ class zmq_pub \return Number of ZMQ messages sent to relay. */ std::size_t send_txpool_add(std::vector txes); + //! Callable for `send_chain_alt` with weak ownership to `zmq_pub` object. + struct chain_alt + { + std::weak_ptr self_; + void operator()(std::uint64_t height, epee::span blocks) const; + }; + //! Callable for `send_chain_main` with weak ownership to `zmq_pub` object. struct chain_main { -- 2.50.0