|
|
|
@ -57,9 +57,11 @@
|
|
|
|
|
namespace
|
|
|
|
|
{
|
|
|
|
|
constexpr const char txpool_signal[] = "tx_signal";
|
|
|
|
|
constexpr const char sync_signal[] = "sync_signal";
|
|
|
|
|
|
|
|
|
|
using chain_writer = void(epee::byte_stream&, std::uint64_t, epee::span<const cryptonote::block>);
|
|
|
|
|
using miner_writer = void(epee::byte_stream&, uint8_t, uint64_t, const crypto::hash&, const crypto::hash&, cryptonote::difficulty_type, uint64_t, uint64_t, const std::vector<cryptonote::tx_block_template_backlog_entry>&);
|
|
|
|
|
using sync_writer = void(epee::byte_stream&, bool, std::uint64_t, std::uint64_t);
|
|
|
|
|
using txpool_writer = void(epee::byte_stream&, epee::span<const cryptonote::txpool_event>);
|
|
|
|
|
|
|
|
|
|
template<typename F>
|
|
|
|
@ -132,6 +134,14 @@ namespace
|
|
|
|
|
const std::vector<cryptonote::tx_block_template_backlog_entry>& tx_backlog;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//! Object for sync notification serialization
|
|
|
|
|
struct minimal_sync
|
|
|
|
|
{
|
|
|
|
|
const bool syncing;
|
|
|
|
|
const std::uint64_t height;
|
|
|
|
|
const std::uint64_t target;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//! Object for "minimal" tx serialization
|
|
|
|
|
struct minimal_txpool
|
|
|
|
|
{
|
|
|
|
@ -187,6 +197,17 @@ namespace
|
|
|
|
|
dest.EndObject();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const minimal_sync self)
|
|
|
|
|
{
|
|
|
|
|
namespace adapt = boost::adaptors;
|
|
|
|
|
|
|
|
|
|
dest.StartObject();
|
|
|
|
|
INSERT_INTO_JSON_OBJECT(dest, syncing, self.syncing);
|
|
|
|
|
INSERT_INTO_JSON_OBJECT(dest, height, self.height);
|
|
|
|
|
INSERT_INTO_JSON_OBJECT(dest, target, self.target);
|
|
|
|
|
dest.EndObject();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void json_full_chain(epee::byte_stream& buf, const std::uint64_t height, const epee::span<const cryptonote::block> blocks)
|
|
|
|
|
{
|
|
|
|
|
json_pub(buf, blocks);
|
|
|
|
@ -202,6 +223,11 @@ namespace
|
|
|
|
|
json_pub(buf, miner_data{major_version, height, prev_id, seed_hash, diff, median_weight, already_generated_coins, tx_backlog});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void json_minimal_sync(epee::byte_stream& buf, bool syncing, const std::uint64_t height, const std::uint64_t target)
|
|
|
|
|
{
|
|
|
|
|
json_pub(buf, minimal_sync{syncing, height, target});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// boost::adaptors are in place "views" - no copy/move takes place
|
|
|
|
|
// moving transactions (via sort, etc.), is expensive!
|
|
|
|
|
|
|
|
|
@ -236,6 +262,12 @@ namespace
|
|
|
|
|
{u8"json-full-miner_data", json_miner_data},
|
|
|
|
|
}};
|
|
|
|
|
|
|
|
|
|
constexpr const std::array<context<sync_writer>, 2> sync_contexts =
|
|
|
|
|
{{
|
|
|
|
|
{u8"json-full-sync", json_minimal_sync},
|
|
|
|
|
{u8"json-minimal-sync", json_minimal_sync},
|
|
|
|
|
}};
|
|
|
|
|
|
|
|
|
|
constexpr const std::array<context<txpool_writer>, 2> txpool_contexts =
|
|
|
|
|
{{
|
|
|
|
|
{u8"json-full-txpool_add", json_full_txpool},
|
|
|
|
@ -336,7 +368,7 @@ namespace
|
|
|
|
|
zmq_msg_size(std::addressof(msg))
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (payload == txpool_signal)
|
|
|
|
|
if (payload == txpool_signal || payload == sync_signal)
|
|
|
|
|
{
|
|
|
|
|
zmq_msg_close(std::addressof(msg));
|
|
|
|
|
return false;
|
|
|
|
@ -360,6 +392,7 @@ zmq_pub::zmq_pub(void* context)
|
|
|
|
|
: relay_(),
|
|
|
|
|
chain_subs_{{0}},
|
|
|
|
|
miner_subs_{{0}},
|
|
|
|
|
sync_subs_({0}),
|
|
|
|
|
txpool_subs_{{0}},
|
|
|
|
|
sync_()
|
|
|
|
|
{
|
|
|
|
@ -368,6 +401,7 @@ zmq_pub::zmq_pub(void* context)
|
|
|
|
|
|
|
|
|
|
verify_sorted(chain_contexts, "chain_contexts");
|
|
|
|
|
verify_sorted(miner_contexts, "miner_contexts");
|
|
|
|
|
verify_sorted(sync_contexts, "sync_contexts");
|
|
|
|
|
verify_sorted(txpool_contexts, "txpool_contexts");
|
|
|
|
|
|
|
|
|
|
relay_.reset(zmq_socket(context, ZMQ_PAIR));
|
|
|
|
@ -389,12 +423,13 @@ bool zmq_pub::sub_request(boost::string_ref message)
|
|
|
|
|
|
|
|
|
|
const auto chain_range = get_range(chain_contexts, message);
|
|
|
|
|
const auto miner_range = get_range(miner_contexts, message);
|
|
|
|
|
const auto sync_range = get_range(sync_contexts, message);
|
|
|
|
|
const auto txpool_range = get_range(txpool_contexts, message);
|
|
|
|
|
|
|
|
|
|
if (!chain_range.empty() || !miner_range.empty() || !txpool_range.empty())
|
|
|
|
|
if (!chain_range.empty() || !miner_range.empty() || !sync_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)");
|
|
|
|
|
chain_range.size() << " chain topic(s), " << miner_range.size() << " miner topic(s), " << sync_range.size() << " sync topic(s) and " << txpool_range.size() << " txpool topic(s)");
|
|
|
|
|
|
|
|
|
|
const boost::lock_guard<boost::mutex> lock{sync_};
|
|
|
|
|
switch (tag)
|
|
|
|
@ -402,11 +437,13 @@ bool zmq_pub::sub_request(boost::string_ref message)
|
|
|
|
|
case 0:
|
|
|
|
|
remove_subscriptions(chain_subs_, chain_range, chain_contexts.begin());
|
|
|
|
|
remove_subscriptions(miner_subs_, miner_range, miner_contexts.begin());
|
|
|
|
|
remove_subscriptions(sync_subs_, sync_range, sync_contexts.begin());
|
|
|
|
|
remove_subscriptions(txpool_subs_, txpool_range, txpool_contexts.begin());
|
|
|
|
|
return true;
|
|
|
|
|
case 1:
|
|
|
|
|
add_subscriptions(chain_subs_, chain_range, chain_contexts.begin());
|
|
|
|
|
add_subscriptions(miner_subs_, miner_range, miner_contexts.begin());
|
|
|
|
|
add_subscriptions(sync_subs_, sync_range, sync_contexts.begin());
|
|
|
|
|
add_subscriptions(txpool_subs_, txpool_range, txpool_contexts.begin());
|
|
|
|
|
return true;
|
|
|
|
|
default:
|
|
|
|
@ -498,6 +535,20 @@ std::size_t zmq_pub::send_miner_data(uint8_t major_version, uint64_t height, con
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::size_t zmq_pub::send_sync(bool syncing, std::uint64_t height, std::uint64_t target)
|
|
|
|
|
{
|
|
|
|
|
const boost::lock_guard<boost::mutex> lock{sync_};
|
|
|
|
|
for (const std::size_t sub : sync_subs_)
|
|
|
|
|
{
|
|
|
|
|
if (sub)
|
|
|
|
|
{
|
|
|
|
|
auto messages = make_pubs(sync_subs_, sync_contexts, syncing, height, target);
|
|
|
|
|
return send_messages(relay_.get(), messages);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::size_t zmq_pub::send_txpool_add(std::vector<txpool_event> txes)
|
|
|
|
|
{
|
|
|
|
|
if (txes.empty())
|
|
|
|
@ -537,6 +588,15 @@ void zmq_pub::miner_data::operator()(uint8_t major_version, uint64_t height, con
|
|
|
|
|
MERROR("Unable to send ZMQ/Pub - ZMQ server destroyed");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void zmq_pub::sync::operator()(bool syncing, std::uint64_t height, std::uint64_t target) const
|
|
|
|
|
{
|
|
|
|
|
const std::shared_ptr<zmq_pub> self = self_.lock();
|
|
|
|
|
if (self)
|
|
|
|
|
self->send_sync(syncing, height, target);
|
|
|
|
|
else
|
|
|
|
|
MERROR("Unable to send ZMQ/Pub - ZMQ server destroyed");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void zmq_pub::txpool_add::operator()(std::vector<cryptonote::txpool_event> txes) const
|
|
|
|
|
{
|
|
|
|
|
const std::shared_ptr<zmq_pub> self = self_.lock();
|
|
|
|
|