diff --git a/nano/core_test/websocket.cpp b/nano/core_test/websocket.cpp index e12c11a7..9b3bbbed 100644 --- a/nano/core_test/websocket.cpp +++ b/nano/core_test/websocket.cpp @@ -463,7 +463,7 @@ TEST (websocket, confirmation_options) std::thread client_thread_2 ([&client_thread_2_finished]() { // Re-subscribe with options for all local wallet accounts auto response = websocket_test_call ("::1", "24078", - R"json({"action": "subscribe", "topic": "confirmation", "ack": "true", "options": {"confirmation_type": "active_quorum", "all_local_accounts": "true"}})json", true, true); + R"json({"action": "subscribe", "topic": "confirmation", "ack": "true", "options": {"confirmation_type": "active_quorum", "all_local_accounts": "true", "include_election_info": "true"}})json", true, true); ASSERT_TRUE (response); boost::property_tree::ptree event; @@ -471,6 +471,20 @@ TEST (websocket, confirmation_options) stream << response.get (); boost::property_tree::read_json (stream, event); ASSERT_EQ (event.get ("topic"), "confirmation"); + try + { + boost::property_tree::ptree election_info = event.get_child ("message.election_info"); + auto tally (election_info.get ("tally")); + auto time (election_info.get ("time")); + election_info.get ("duration"); + // Make sure tally and time are non-zero. Duration may be zero on testnet, so we only check that it's present (exception thrown otherwise) + ASSERT_NE ("0", tally); + ASSERT_NE ("0", time); + } + catch (std::runtime_error const & ex) + { + FAIL () << ex.what (); + } client_thread_2_finished = true; }); diff --git a/nano/node/node.cpp b/nano/node/node.cpp index 69a88e6f..5547f8f8 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -260,7 +260,7 @@ startup_time (std::chrono::steady_clock::now ()) } } - this->websocket_server->broadcast_confirmation (block_a, account_a, amount_a, subtype, status_a.type); + this->websocket_server->broadcast_confirmation (block_a, account_a, amount_a, subtype, status_a); } }); diff --git a/nano/node/websocket.cpp b/nano/node/websocket.cpp index 3c9ab5fd..7019880f 100644 --- a/nano/node/websocket.cpp +++ b/nano/node/websocket.cpp @@ -7,11 +7,17 @@ #include #include +nano::websocket::confirmation_options::confirmation_options (nano::node & node_a) : +node (node_a) +{ +} + nano::websocket::confirmation_options::confirmation_options (boost::property_tree::ptree const & options_a, nano::node & node_a) : node (node_a) { // Non-account filtering options include_block = options_a.get ("include_block", true); + include_election_info = options_a.get ("include_election_info", false); confirmation_types = 0; auto type_l (options_a.get ("confirmation_type", "all")); @@ -497,7 +503,7 @@ void nano::websocket::listener::on_accept (boost::system::error_code ec) } } -void nano::websocket::listener::broadcast_confirmation (std::shared_ptr block_a, nano::account const & account_a, nano::amount const & amount_a, std::string subtype, nano::election_status_type election_status_type_a) +void nano::websocket::listener::broadcast_confirmation (std::shared_ptr block_a, nano::account const & account_a, nano::amount const & amount_a, std::string subtype, nano::election_status const & election_status_a) { nano::websocket::message_builder builder; @@ -512,16 +518,21 @@ void nano::websocket::listener::broadcast_confirmation (std::shared_ptrsubscriptions.find (nano::websocket::topic::confirmation)); if (subscription != session_ptr->subscriptions.end ()) { + nano::websocket::confirmation_options default_options (node); auto conf_options (dynamic_cast (subscription->second.get ())); + if (conf_options == nullptr) + { + conf_options = &default_options; + } auto include_block (conf_options == nullptr ? true : conf_options->get_include_block ()); if (include_block && !msg_with_block) { - msg_with_block = builder.block_confirmed (block_a, account_a, amount_a, subtype, include_block, election_status_type_a); + msg_with_block = builder.block_confirmed (block_a, account_a, amount_a, subtype, include_block, election_status_a, *conf_options); } else if (!include_block && !msg_without_block) { - msg_without_block = builder.block_confirmed (block_a, account_a, amount_a, subtype, include_block, election_status_type_a); + msg_without_block = builder.block_confirmed (block_a, account_a, amount_a, subtype, include_block, election_status_a, *conf_options); } else { @@ -571,7 +582,7 @@ nano::websocket::message nano::websocket::message_builder::stopped_election (nan return message_l; } -nano::websocket::message nano::websocket::message_builder::block_confirmed (std::shared_ptr block_a, nano::account const & account_a, nano::amount const & amount_a, std::string subtype, bool include_block_a, nano::election_status_type election_status_type_a) +nano::websocket::message nano::websocket::message_builder::block_confirmed (std::shared_ptr block_a, nano::account const & account_a, nano::amount const & amount_a, std::string subtype, bool include_block_a, nano::election_status const & election_status_a, nano::websocket::confirmation_options const & options_a) { nano::websocket::message message_l (nano::websocket::topic::confirmation); set_common_fields (message_l); @@ -583,7 +594,7 @@ nano::websocket::message nano::websocket::message_builder::block_confirmed (std: message_node_l.add ("hash", block_a->hash ().to_string ()); std::string confirmation_type = "unknown"; - switch (election_status_type_a) + switch (election_status_a.type) { case nano::election_status_type::active_confirmed_quorum: confirmation_type = "active_quorum"; @@ -599,6 +610,15 @@ nano::websocket::message nano::websocket::message_builder::block_confirmed (std: }; message_node_l.add ("confirmation_type", confirmation_type); + if (options_a.get_include_election_info ()) + { + boost::property_tree::ptree election_node_l; + election_node_l.add ("duration", election_status_a.election_duration.count ()); + election_node_l.add ("time", election_status_a.election_end.count ()); + election_node_l.add ("tally", election_status_a.tally.to_string_dec ()); + message_node_l.add_child ("election_info", election_node_l); + } + if (include_block_a) { boost::property_tree::ptree block_node_l; diff --git a/nano/node/websocket.hpp b/nano/node/websocket.hpp index 325b80aa..663581fd 100644 --- a/nano/node/websocket.hpp +++ b/nano/node/websocket.hpp @@ -36,6 +36,7 @@ enum class election_status_type : uint8_t; namespace websocket { class listener; + class confirmation_options; /** Supported topics */ enum class topic @@ -78,7 +79,7 @@ namespace websocket class message_builder final { public: - message block_confirmed (std::shared_ptr block_a, nano::account const & account_a, nano::amount const & amount_a, std::string subtype, bool include_block, nano::election_status_type election_status_type_a); + message block_confirmed (std::shared_ptr block_a, nano::account const & account_a, nano::amount const & amount_a, std::string subtype, bool include_block, nano::election_status const & election_status_a, nano::websocket::confirmation_options const & options_a); message stopped_election (nano::block_hash const & hash_a); message vote_received (std::shared_ptr vote_a); message difficulty_changed (uint64_t publish_threshold, uint64_t difficulty_active); @@ -117,7 +118,7 @@ namespace websocket class confirmation_options final : public options { public: - confirmation_options (); + confirmation_options (nano::node & node_a); confirmation_options (boost::property_tree::ptree const & options_a, nano::node & node_a); /** @@ -133,6 +134,12 @@ namespace websocket return include_block; } + /** Returns whether or not to include election info, such as tally and duration */ + bool get_include_election_info () const + { + return include_election_info; + } + static constexpr const uint8_t type_active_quorum = 1; static constexpr const uint8_t type_active_confirmation_height = 2; static constexpr const uint8_t type_inactive = 4; @@ -141,6 +148,7 @@ namespace websocket private: nano::node & node; + bool include_election_info{ false }; bool include_block{ true }; bool has_account_filtering_options{ false }; bool all_local_accounts{ false }; @@ -241,7 +249,7 @@ namespace websocket void stop (); /** Broadcast block confirmation. The content of the message depends on subscription options (such as "include_block") */ - void broadcast_confirmation (std::shared_ptr block_a, nano::account const & account_a, nano::amount const & amount_a, std::string subtype, nano::election_status_type election_status_type_a); + void broadcast_confirmation (std::shared_ptr block_a, nano::account const & account_a, nano::amount const & amount_a, std::string subtype, nano::election_status const & election_status_a); /** Broadcast \p message to all session subscribing to the message topic. */ void broadcast (nano::websocket::message message_a);