diff --git a/nano/core_test/node_telemetry.cpp b/nano/core_test/node_telemetry.cpp index bff5609f..03a31255 100644 --- a/nano/core_test/node_telemetry.cpp +++ b/nano/core_test/node_telemetry.cpp @@ -11,7 +11,6 @@ using namespace std::chrono_literals; namespace { void wait_peer_connections (nano::system & system_a); -void compare_default_test_result_data (nano::telemetry_data const & telemetry_data_a, nano::node const & node_server_a); } TEST (node_telemetry, consolidate_data) @@ -152,7 +151,7 @@ TEST (node_telemetry, serialize_deserialize_json_optional) data.timestamp = std::chrono::system_clock::time_point (100ms); nano::jsonconfig config; - data.serialize_json (config); + data.serialize_json (config, false); uint8_t val; ASSERT_FALSE (config.get ("minor_version", val).get_error ()); @@ -168,7 +167,7 @@ TEST (node_telemetry, serialize_deserialize_json_optional) ASSERT_EQ (timestamp, 100); nano::telemetry_data data1; - data1.deserialize_json (config); + data1.deserialize_json (config, false); ASSERT_EQ (*data1.minor_version, 1); ASSERT_EQ (*data1.patch_version, 4); ASSERT_EQ (*data1.pre_release_version, 6); @@ -177,7 +176,7 @@ TEST (node_telemetry, serialize_deserialize_json_optional) nano::telemetry_data no_optional_data; nano::jsonconfig config1; - no_optional_data.serialize_json (config1); + no_optional_data.serialize_json (config1, false); ASSERT_FALSE (config1.get_optional ("minor_version").is_initialized ()); ASSERT_FALSE (config1.get_optional ("patch_version").is_initialized ()); ASSERT_FALSE (config1.get_optional ("pre_release_version").is_initialized ()); @@ -185,7 +184,7 @@ TEST (node_telemetry, serialize_deserialize_json_optional) ASSERT_FALSE (config1.get_optional ("timestamp").is_initialized ()); nano::telemetry_data no_optional_data1; - no_optional_data1.deserialize_json (config1); + no_optional_data1.deserialize_json (config1, false); ASSERT_FALSE (no_optional_data1.minor_version.is_initialized ()); ASSERT_FALSE (no_optional_data1.patch_version.is_initialized ()); ASSERT_FALSE (no_optional_data1.pre_release_version.is_initialized ()); @@ -258,6 +257,26 @@ TEST (node_telemetry, consolidate_data_remove_outliers) ASSERT_EQ (data, consolidated_telemetry_data); } +TEST (node_telemetry, signatures) +{ + nano::keypair node_id; + nano::telemetry_data data; + data.node_id = node_id.pub; + data.major_version = 20; + data.minor_version = 1; + data.patch_version = 5; + data.pre_release_version = 2; + data.maker = 1; + data.timestamp = std::chrono::system_clock::time_point (100ms); + data.sign (node_id); + ASSERT_FALSE (data.validate_signature (nano::telemetry_data::size)); + auto signature = data.signature; + // Check that the signature is different if changing a piece of data + data.maker = 2; + data.sign (node_id); + ASSERT_NE (data.signature, signature); +} + TEST (node_telemetry, no_peers) { nano::system system (1); @@ -296,7 +315,7 @@ TEST (node_telemetry, basic) } // Check the metrics are correct - compare_default_test_result_data (telemetry_data, *node_server); + nano::compare_default_telemetry_response_data (telemetry_data, node_server->network_params, node_server->config.bandwidth_limit, node_server->node_id); // Call again straight away. It should use the cache { @@ -454,7 +473,7 @@ TEST (node_telemetry, over_udp) auto channel = node_client->network.find_channel (node_server->network.endpoint ()); node_client->telemetry->get_metrics_single_peer_async (channel, [&done, &node_server](nano::telemetry_data_response const & response_a) { ASSERT_FALSE (response_a.error); - compare_default_test_result_data (response_a.telemetry_data, *node_server); + nano::compare_default_telemetry_response_data (response_a.telemetry_data, node_server->network_params, node_server->config.bandwidth_limit, node_server->node_id); done = true; }); @@ -527,7 +546,7 @@ TEST (node_telemetry, blocking_request) // Now try single request metric auto telemetry_data_response = node_client->telemetry->get_metrics_single_peer (node_client->network.find_channel (node_server->network.endpoint ())); ASSERT_FALSE (telemetry_data_response.error); - compare_default_test_result_data (telemetry_data_response.telemetry_data, *node_server); + nano::compare_default_telemetry_response_data (telemetry_data_response.telemetry_data, node_server->network_params, node_server->config.bandwidth_limit, node_server->node_id); done = true; promise.get_future ().wait (); @@ -754,9 +773,9 @@ TEST (node_telemetry, disable_metrics) // It should still be able to receive metrics though done = false; auto channel1 = node_server->network.find_channel (node_client->network.endpoint ()); - node_server->telemetry->get_metrics_single_peer_async (channel1, [&done, node_server](nano::telemetry_data_response const & response_a) { + node_server->telemetry->get_metrics_single_peer_async (channel1, [&done, node_client](nano::telemetry_data_response const & response_a) { ASSERT_FALSE (response_a.error); - compare_default_test_result_data (response_a.telemetry_data, *node_server); + nano::compare_default_telemetry_response_data (response_a.telemetry_data, node_client->network_params, node_client->config.bandwidth_limit, node_client->node_id); done = true; }); @@ -796,23 +815,4 @@ void wait_peer_connections (nano::system & system_a) wait_peer_count (true); wait_peer_count (false); } - -void compare_default_test_result_data (nano::telemetry_data const & telemetry_data_a, nano::node const & node_server_a) -{ - ASSERT_EQ (telemetry_data_a.block_count, 1); - ASSERT_EQ (telemetry_data_a.cemented_count, 1); - ASSERT_EQ (telemetry_data_a.bandwidth_cap, node_server_a.config.bandwidth_limit); - ASSERT_EQ (telemetry_data_a.peer_count, 1); - ASSERT_EQ (telemetry_data_a.protocol_version, node_server_a.network_params.protocol.telemetry_protocol_version_min); - ASSERT_EQ (telemetry_data_a.unchecked_count, 0); - ASSERT_EQ (telemetry_data_a.account_count, 1); - ASSERT_LT (telemetry_data_a.uptime, 100); - ASSERT_EQ (telemetry_data_a.genesis_block, node_server_a.network_params.ledger.genesis_hash); - ASSERT_EQ (telemetry_data_a.major_version, nano::get_major_node_version ()); - ASSERT_EQ (*telemetry_data_a.minor_version, nano::get_minor_node_version ()); - ASSERT_EQ (*telemetry_data_a.patch_version, nano::get_patch_node_version ()); - ASSERT_EQ (*telemetry_data_a.pre_release_version, nano::get_pre_release_node_version ()); - ASSERT_EQ (*telemetry_data_a.maker, 0); - ASSERT_GT (*telemetry_data_a.timestamp, std::chrono::system_clock::now () - 100s); -} } diff --git a/nano/core_test/testutil.hpp b/nano/core_test/testutil.hpp index 612f207e..13753677 100644 --- a/nano/core_test/testutil.hpp +++ b/nano/core_test/testutil.hpp @@ -3,6 +3,14 @@ #include #include +// This test header is unfortunately included in many different files. +// Requires guarding in some cases. +#ifndef IGNORE_GTEST_INCL +#include + +#include +#endif + #include #include #include @@ -229,4 +237,37 @@ inline uint16_t get_available_port () return available_port; } + +#ifndef IGNORE_GTEST_INCL +inline void compare_default_telemetry_response_data_excluding_signature (nano::telemetry_data const & telemetry_data_a, nano::network_params const & network_params_a, uint64_t bandwidth_limit_a) +{ + ASSERT_EQ (telemetry_data_a.block_count, 1); + ASSERT_EQ (telemetry_data_a.cemented_count, 1); + ASSERT_EQ (telemetry_data_a.bandwidth_cap, bandwidth_limit_a); + ASSERT_EQ (telemetry_data_a.peer_count, 1); + ASSERT_EQ (telemetry_data_a.protocol_version, network_params_a.protocol.telemetry_protocol_version_min); + ASSERT_EQ (telemetry_data_a.unchecked_count, 0); + ASSERT_EQ (telemetry_data_a.account_count, 1); + ASSERT_LT (telemetry_data_a.uptime, 100); + ASSERT_EQ (telemetry_data_a.genesis_block, network_params_a.ledger.genesis_hash); + ASSERT_EQ (telemetry_data_a.major_version, nano::get_major_node_version ()); + ASSERT_EQ (*telemetry_data_a.minor_version, nano::get_minor_node_version ()); + ASSERT_EQ (*telemetry_data_a.patch_version, nano::get_patch_node_version ()); + ASSERT_EQ (*telemetry_data_a.pre_release_version, nano::get_pre_release_node_version ()); + ASSERT_EQ (*telemetry_data_a.maker, 0); + ASSERT_GT (*telemetry_data_a.timestamp, std::chrono::system_clock::now () - std::chrono::seconds (100)); +} + +inline void compare_default_telemetry_response_data (nano::telemetry_data const & telemetry_data_a, nano::network_params const & network_params_a, uint64_t bandwidth_limit_a, nano::keypair const & node_id_a) +{ + ASSERT_FALSE (telemetry_data_a.validate_signature (nano::telemetry_data::size)); + nano::telemetry_data telemetry_data_l = telemetry_data_a; + telemetry_data_l.signature.clear (); + telemetry_data_l.sign (node_id_a); + // Signature should be different because uptime/timestamp will have changed. + ASSERT_NE (telemetry_data_a.signature, telemetry_data_l.signature); + compare_default_telemetry_response_data_excluding_signature (telemetry_data_a, network_params_a, bandwidth_limit_a); + ASSERT_EQ (telemetry_data_a.node_id, node_id_a.pub); +} +#endif } diff --git a/nano/lib/numbers.cpp b/nano/lib/numbers.cpp index 542f4805..b546c0cd 100644 --- a/nano/lib/numbers.cpp +++ b/nano/lib/numbers.cpp @@ -396,13 +396,6 @@ nano::private_key const & nano::raw_key::as_private_key () const return reinterpret_cast (data); } -nano::signature nano::sign_message (nano::raw_key const & private_key, nano::public_key const & public_key, nano::uint256_union const & message) -{ - nano::signature result; - ed25519_sign (message.bytes.data (), sizeof (message.bytes), private_key.data.bytes.data (), public_key.bytes.data (), result.bytes.data ()); - return result; -} - nano::private_key nano::deterministic_key (nano::raw_key const & seed_a, uint32_t index_a) { nano::private_key prv_key; @@ -422,10 +415,26 @@ nano::public_key nano::pub_key (nano::private_key const & privatekey_a) return result; } +nano::signature nano::sign_message (nano::raw_key const & private_key, nano::public_key const & public_key, uint8_t const * data, size_t size) +{ + nano::signature result; + ed25519_sign (data, size, private_key.data.bytes.data (), public_key.bytes.data (), result.bytes.data ()); + return result; +} + +nano::signature nano::sign_message (nano::raw_key const & private_key, nano::public_key const & public_key, nano::uint256_union const & message) +{ + return nano::sign_message (private_key, public_key, message.bytes.data (), sizeof (message.bytes)); +} + +bool nano::validate_message (nano::public_key const & public_key, uint8_t const * data, size_t size, nano::signature const & signature) +{ + return 0 != ed25519_sign_open (data, size, public_key.bytes.data (), signature.bytes.data ()); +} + bool nano::validate_message (nano::public_key const & public_key, nano::uint256_union const & message, nano::signature const & signature) { - auto result (0 != ed25519_sign_open (message.bytes.data (), sizeof (message.bytes), public_key.bytes.data (), signature.bytes.data ())); - return result; + return validate_message (public_key, message.bytes.data (), sizeof (message.bytes), signature); } bool nano::validate_message_batch (const unsigned char ** m, size_t * mlen, const unsigned char ** pk, const unsigned char ** RS, size_t num, int * valid) diff --git a/nano/lib/numbers.hpp b/nano/lib/numbers.hpp index ee45ba76..fece757b 100644 --- a/nano/lib/numbers.hpp +++ b/nano/lib/numbers.hpp @@ -243,8 +243,10 @@ public: }; nano::signature sign_message (nano::raw_key const &, nano::public_key const &, nano::uint256_union const &); +nano::signature sign_message (nano::raw_key const &, nano::public_key const &, uint8_t const *, size_t); bool validate_message (nano::public_key const &, nano::uint256_union const &, nano::signature const &); -bool validate_message_batch (const unsigned char **, size_t *, const unsigned char **, const unsigned char **, size_t, int *); +bool validate_message (nano::public_key const &, uint8_t const *, size_t, nano::signature const &); +bool validate_message_batch (unsigned const char **, size_t *, unsigned const char **, unsigned const char **, size_t, int *); nano::private_key deterministic_key (nano::raw_key const &, uint32_t); nano::public_key pub_key (nano::private_key const &); diff --git a/nano/load_test/entry.cpp b/nano/load_test/entry.cpp index 2d279c6e..f5917aa8 100644 --- a/nano/load_test/entry.cpp +++ b/nano/load_test/entry.cpp @@ -3,6 +3,7 @@ #include #include #include +#define IGNORE_GTEST_INCL #include #include #include diff --git a/nano/node/common.cpp b/nano/node/common.cpp index 9b07ffc1..53f6f74e 100644 --- a/nano/node/common.cpp +++ b/nano/node/common.cpp @@ -1117,21 +1117,7 @@ void nano::telemetry_ack::serialize (nano::stream & stream_a) const header.serialize (stream_a); if (!is_empty_payload ()) { - write (stream_a, data.block_count); - write (stream_a, data.cemented_count); - write (stream_a, data.unchecked_count); - write (stream_a, data.account_count); - write (stream_a, data.bandwidth_cap); - write (stream_a, data.peer_count); - write (stream_a, data.protocol_version); - write (stream_a, data.major_version); - write (stream_a, data.uptime); - write (stream_a, data.genesis_block.bytes); - write (stream_a, *data.minor_version); - write (stream_a, *data.patch_version); - write (stream_a, *data.pre_release_version); - write (stream_a, *data.maker); - write (stream_a, std::chrono::duration_cast (data.timestamp->time_since_epoch ()).count ()); + data.serialize (stream_a); } } @@ -1143,36 +1129,7 @@ bool nano::telemetry_ack::deserialize (nano::stream & stream_a) { if (!is_empty_payload ()) { - read (stream_a, data.block_count); - read (stream_a, data.cemented_count); - read (stream_a, data.unchecked_count); - read (stream_a, data.account_count); - read (stream_a, data.bandwidth_cap); - read (stream_a, data.peer_count); - read (stream_a, data.protocol_version); - read (stream_a, data.major_version); - read (stream_a, data.uptime); - read (stream_a, data.genesis_block.bytes); - - if (header.extensions.to_ulong () > telemetry_data::size_v0) - { - uint8_t out; - read (stream_a, out); - data.minor_version = out; - read (stream_a, out); - data.patch_version = out; - read (stream_a, out); - data.pre_release_version = out; - read (stream_a, out); - data.maker = out; - } - - if (header.extensions.to_ulong () > telemetry_data::size_v1) - { - uint64_t timestamp; - read (stream_a, timestamp); - data.timestamp = std::chrono::system_clock::time_point (std::chrono::milliseconds (timestamp)); - } + data.deserialize (stream_a, header.extensions.to_ulong ()); } } catch (std::runtime_error const &) @@ -1203,8 +1160,75 @@ bool nano::telemetry_ack::is_empty_payload () const return size () == 0; } -nano::error nano::telemetry_data::serialize_json (nano::jsonconfig & json) const +void nano::telemetry_data::deserialize (nano::stream & stream_a, uint16_t payload_length_a) { + read (stream_a, signature); + read (stream_a, node_id); + read (stream_a, block_count); + read (stream_a, cemented_count); + read (stream_a, unchecked_count); + read (stream_a, account_count); + read (stream_a, bandwidth_cap); + read (stream_a, peer_count); + read (stream_a, protocol_version); + read (stream_a, major_version); + read (stream_a, uptime); + read (stream_a, genesis_block.bytes); + + if (payload_length_a > size_v0) + { + uint8_t out; + read (stream_a, out); + minor_version = out; + read (stream_a, out); + patch_version = out; + read (stream_a, out); + pre_release_version = out; + read (stream_a, out); + maker = out; + } + + if (payload_length_a > size_v1) + { + uint64_t timestamp_l; + read (stream_a, timestamp_l); + timestamp = std::chrono::system_clock::time_point (std::chrono::milliseconds (timestamp_l)); + } +} + +void nano::telemetry_data::serialize_without_signature (nano::stream & stream_a, uint16_t /* size_a */) const +{ + write (stream_a, node_id); + write (stream_a, block_count); + write (stream_a, cemented_count); + write (stream_a, unchecked_count); + write (stream_a, account_count); + write (stream_a, bandwidth_cap); + write (stream_a, peer_count); + write (stream_a, protocol_version); + write (stream_a, major_version); + write (stream_a, uptime); + write (stream_a, genesis_block.bytes); + write (stream_a, *minor_version); + write (stream_a, *patch_version); + write (stream_a, *pre_release_version); + write (stream_a, *maker); + write (stream_a, std::chrono::duration_cast (timestamp->time_since_epoch ()).count ()); +} + +void nano::telemetry_data::serialize (nano::stream & stream_a) const +{ + write (stream_a, signature); + serialize_without_signature (stream_a, size); +} + +nano::error nano::telemetry_data::serialize_json (nano::jsonconfig & json, bool ignore_identification_metrics_a) const +{ + if (!ignore_identification_metrics_a) + { + json.put ("signature", signature.to_string ()); + json.put ("node_id", node_id.to_string ()); + } json.put ("block_count", block_count); json.put ("cemented_count", cemented_count); json.put ("unchecked_count", unchecked_count); @@ -1238,8 +1262,31 @@ nano::error nano::telemetry_data::serialize_json (nano::jsonconfig & json) const return json.get_error (); } -nano::error nano::telemetry_data::deserialize_json (nano::jsonconfig & json) +nano::error nano::telemetry_data::deserialize_json (nano::jsonconfig & json, bool ignore_identification_metrics_a) { + if (!ignore_identification_metrics_a) + { + std::string signature_l; + json.get ("signature", signature_l); + if (!json.get_error ()) + { + if (signature.decode_hex (signature_l)) + { + json.get_error ().set ("Could not deserialize signature"); + } + } + + std::string node_id_l; + json.get ("node_id", node_id_l); + if (!json.get_error ()) + { + if (node_id.decode_hex (node_id_l)) + { + json.get_error ().set ("Could not deserialize node id"); + } + } + } + json.get ("block_count", block_count); json.get ("cemented_count", cemented_count); json.get ("unchecked_count", unchecked_count); @@ -1273,7 +1320,7 @@ nano::error nano::telemetry_data::deserialize_json (nano::jsonconfig & json) bool nano::telemetry_data::operator== (nano::telemetry_data const & data_a) const { - return (block_count == data_a.block_count && cemented_count == data_a.cemented_count && unchecked_count == data_a.unchecked_count && account_count == data_a.account_count && bandwidth_cap == data_a.bandwidth_cap && uptime == data_a.uptime && peer_count == data_a.peer_count && protocol_version == data_a.protocol_version && genesis_block == data_a.genesis_block && major_version == data_a.major_version && minor_version == data_a.minor_version && patch_version == data_a.patch_version && pre_release_version == data_a.pre_release_version && maker == data_a.maker && timestamp == data_a.timestamp); + return (signature == data_a.signature && node_id == data_a.node_id && block_count == data_a.block_count && cemented_count == data_a.cemented_count && unchecked_count == data_a.unchecked_count && account_count == data_a.account_count && bandwidth_cap == data_a.bandwidth_cap && uptime == data_a.uptime && peer_count == data_a.peer_count && protocol_version == data_a.protocol_version && genesis_block == data_a.genesis_block && major_version == data_a.major_version && minor_version == data_a.minor_version && patch_version == data_a.patch_version && pre_release_version == data_a.pre_release_version && maker == data_a.maker && timestamp == data_a.timestamp); } bool nano::telemetry_data::operator!= (nano::telemetry_data const & data_a) const @@ -1281,6 +1328,29 @@ bool nano::telemetry_data::operator!= (nano::telemetry_data const & data_a) cons return !(*this == data_a); } +void nano::telemetry_data::sign (nano::keypair const & node_id_a) +{ + debug_assert (node_id == node_id_a.pub); + std::vector bytes; + { + nano::vectorstream stream (bytes); + serialize_without_signature (stream, size); + } + + signature = nano::sign_message (node_id_a.prv, node_id_a.pub, bytes.data (), bytes.size ()); +} + +bool nano::telemetry_data::validate_signature (uint16_t size_a) const +{ + std::vector bytes; + { + nano::vectorstream stream (bytes); + serialize_without_signature (stream, size_a); + } + + return nano::validate_message (node_id, bytes.data (), bytes.size (), signature); +} + nano::node_id_handshake::node_id_handshake (bool & error_a, nano::stream & stream_a, nano::message_header const & header_a) : message (header_a), query (boost::none), diff --git a/nano/node/common.hpp b/nano/node/common.hpp index cd9612fd..faf35b0d 100644 --- a/nano/node/common.hpp +++ b/nano/node/common.hpp @@ -339,6 +339,8 @@ public: class telemetry_data { public: + nano::signature signature{ 0 }; + nano::account node_id{ 0 }; uint64_t block_count{ 0 }; uint64_t cemented_count{ 0 }; uint64_t unchecked_count{ 0 }; @@ -355,14 +357,21 @@ public: boost::optional maker; // 0 for NF node boost::optional timestamp; - nano::error serialize_json (nano::jsonconfig & json) const; - nano::error deserialize_json (nano::jsonconfig & json); + void serialize (nano::stream &) const; + void deserialize (nano::stream &, uint16_t); + nano::error serialize_json (nano::jsonconfig &, bool) const; + nano::error deserialize_json (nano::jsonconfig &, bool); + void sign (nano::keypair const &); + bool validate_signature (uint16_t) const; bool operator== (nano::telemetry_data const &) const; bool operator!= (nano::telemetry_data const &) const; - static auto constexpr size_v0 = sizeof (block_count) + sizeof (cemented_count) + sizeof (unchecked_count) + sizeof (account_count) + sizeof (bandwidth_cap) + sizeof (peer_count) + sizeof (protocol_version) + sizeof (uptime) + sizeof (genesis_block) + sizeof (major_version); + static auto constexpr size_v0 = sizeof (signature) + sizeof (node_id) + sizeof (block_count) + sizeof (cemented_count) + sizeof (unchecked_count) + sizeof (account_count) + sizeof (bandwidth_cap) + sizeof (peer_count) + sizeof (protocol_version) + sizeof (uptime) + sizeof (genesis_block) + sizeof (major_version); static auto constexpr size_v1 = size_v0 + sizeof (decltype (minor_version)::value_type) + sizeof (decltype (patch_version)::value_type) + sizeof (decltype (pre_release_version)::value_type) + sizeof (decltype (maker)::value_type); static auto constexpr size = size_v1 + sizeof (uint64_t); + +private: + void serialize_without_signature (nano::stream &, uint16_t) const; }; class telemetry_req final : public message { diff --git a/nano/node/json_handler.cpp b/nano/node/json_handler.cpp index cbf45281..5edf4b08 100644 --- a/nano/node/json_handler.cpp +++ b/nano/node/json_handler.cpp @@ -3940,10 +3940,11 @@ void nano::json_handler::telemetry () if (address.is_loopback () && port == rpc_l->node.network.endpoint ().port ()) { // Requesting telemetry metrics locally - auto telemetry_data = nano::local_telemetry_data (rpc_l->node.ledger.cache, rpc_l->node.network, rpc_l->node.config.bandwidth_limit, rpc_l->node.network_params, rpc_l->node.startup_time); + auto telemetry_data = nano::local_telemetry_data (rpc_l->node.ledger.cache, rpc_l->node.network, rpc_l->node.config.bandwidth_limit, rpc_l->node.network_params, rpc_l->node.startup_time, rpc_l->node.node_id); nano::jsonconfig config_l; - auto err = telemetry_data.serialize_json (config_l); + auto const should_ignore_identification_metrics = false; + auto err = telemetry_data.serialize_json (config_l, should_ignore_identification_metrics); auto const & ptree = config_l.get_tree (); if (!err) @@ -3987,7 +3988,8 @@ void nano::json_handler::telemetry () if (!telemetry_response_a.error) { nano::jsonconfig config_l; - auto err = telemetry_response_a.telemetry_data.serialize_json (config_l); + auto const should_ignore_identification_metrics = false; + auto err = telemetry_response_a.telemetry_data.serialize_json (config_l, should_ignore_identification_metrics); auto const & ptree = config_l.get_tree (); if (!err) @@ -4032,7 +4034,8 @@ void nano::json_handler::telemetry () for (auto & telemetry_metrics : telemetry_responses) { nano::jsonconfig config_l; - auto err = telemetry_metrics.second.serialize_json (config_l); + auto const should_ignore_identification_metrics = false; + auto err = telemetry_metrics.second.serialize_json (config_l, should_ignore_identification_metrics); config_l.put ("address", telemetry_metrics.first.address ()); config_l.put ("port", telemetry_metrics.first.port ()); if (!err) @@ -4057,7 +4060,9 @@ void nano::json_handler::telemetry () }); auto average_telemetry_metrics = nano::consolidate_telemetry_data (telemetry_datas); - auto err = average_telemetry_metrics.serialize_json (config_l); + // Don't add node_id/signature in consolidated metrics + auto const should_ignore_identification_metrics = true; + auto err = average_telemetry_metrics.serialize_json (config_l, should_ignore_identification_metrics); auto const & ptree = config_l.get_tree (); if (!err) diff --git a/nano/node/network.cpp b/nano/node/network.cpp index bb128348..0c5c8211 100644 --- a/nano/node/network.cpp +++ b/nano/node/network.cpp @@ -483,7 +483,7 @@ public: nano::telemetry_ack telemetry_ack; if (!node.flags.disable_providing_telemetry_metrics) { - auto telemetry_data = nano::local_telemetry_data (node.ledger.cache, node.network, node.config.bandwidth_limit, node.network_params, node.startup_time); + auto telemetry_data = nano::local_telemetry_data (node.ledger.cache, node.network, node.config.bandwidth_limit, node.network_params, node.startup_time, node.node_id); telemetry_ack = nano::telemetry_ack (telemetry_data); } channel->send (telemetry_ack, nullptr, nano::buffer_drop_policy::no_socket_drop); @@ -497,7 +497,7 @@ public: node.stats.inc (nano::stat::type::message, nano::stat::detail::telemetry_ack, nano::stat::dir::in); if (node.telemetry) { - node.telemetry->set (message_a.data, channel->get_endpoint (), message_a.is_empty_payload ()); + node.telemetry->set (message_a, *channel); } } nano::node & node; diff --git a/nano/node/node.cpp b/nano/node/node.cpp index 65cce5ad..a411bb73 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -1,3 +1,4 @@ +#define IGNORE_GTEST_INCL #include #include #include diff --git a/nano/node/telemetry.cpp b/nano/node/telemetry.cpp index aa599b76..016f6e98 100644 --- a/nano/node/telemetry.cpp +++ b/nano/node/telemetry.cpp @@ -37,24 +37,30 @@ void nano::telemetry::stop () stopped = true; } -void nano::telemetry::set (nano::telemetry_data const & telemetry_data_a, nano::endpoint const & endpoint_a, bool is_empty_a) +void nano::telemetry::set (nano::telemetry_ack const & message_a, nano::transport::channel const & channel_a) { if (!stopped) { nano::lock_guard guard (mutex); - auto it = recent_or_initial_request_telemetry_data.find (endpoint_a); + auto it = recent_or_initial_request_telemetry_data.find (channel_a.get_endpoint ()); if (it == recent_or_initial_request_telemetry_data.cend ()) { // Not requesting telemetry data from this peer so ignore it return; } - recent_or_initial_request_telemetry_data.modify (it, [&telemetry_data_a](nano::telemetry_info & telemetry_info_a) { - telemetry_info_a.data = telemetry_data_a; + recent_or_initial_request_telemetry_data.modify (it, [&message_a](nano::telemetry_info & telemetry_info_a) { + telemetry_info_a.data = message_a.data; telemetry_info_a.undergoing_request = false; }); - channel_processed (endpoint_a, is_empty_a); + auto error = false; + if (!message_a.is_empty_payload ()) + { + error = !message_a.data.validate_signature (message_a.size ()) && (channel_a.get_node_id () != message_a.data.node_id); + } + + channel_processed (channel_a.get_endpoint (), error || message_a.is_empty_payload ()); } } @@ -574,9 +580,10 @@ nano::telemetry_data nano::consolidate_telemetry_data (std::vector collect_container_info (telemetry & telemetry, const std::string & name); nano::telemetry_data consolidate_telemetry_data (std::vector const & telemetry_data); -nano::telemetry_data local_telemetry_data (nano::ledger_cache const &, nano::network &, uint64_t, nano::network_params const &, std::chrono::steady_clock::time_point); -} \ No newline at end of file +nano::telemetry_data local_telemetry_data (nano::ledger_cache const &, nano::network &, uint64_t, nano::network_params const &, std::chrono::steady_clock::time_point, nano::keypair const & node_id_a); +} diff --git a/nano/node/testing.cpp b/nano/node/testing.cpp index fa2f25bb..d546798e 100644 --- a/nano/node/testing.cpp +++ b/nano/node/testing.cpp @@ -1,3 +1,4 @@ +#define IGNORE_GTEST_INCL #include #include #include diff --git a/nano/rpc_test/rpc.cpp b/nano/rpc_test/rpc.cpp index ff073715..c0e4a381 100644 --- a/nano/rpc_test/rpc.cpp +++ b/nano/rpc_test/rpc.cpp @@ -7850,29 +7850,6 @@ TEST (rpc, receive_work_disabled) } } -namespace -{ -void compare_default_test_result_data (test_response & response, nano::node const & node_server_a) -{ - ASSERT_EQ (200, response.status); - ASSERT_EQ (1, response.json.get ("block_count")); - ASSERT_EQ (1, response.json.get ("cemented_count")); - ASSERT_EQ (0, response.json.get ("unchecked_count")); - ASSERT_EQ (1, response.json.get ("account_count")); - ASSERT_EQ (node_server_a.config.bandwidth_limit, response.json.get ("bandwidth_cap")); - ASSERT_EQ (1, response.json.get ("peer_count")); - ASSERT_EQ (node_server_a.network_params.protocol.protocol_version, response.json.get ("protocol_version")); - ASSERT_GE (100, response.json.get ("uptime")); - ASSERT_EQ (node_server_a.network_params.ledger.genesis_hash.to_string (), response.json.get ("genesis_block")); - ASSERT_EQ (nano::get_major_node_version (), response.json.get ("major_version")); - ASSERT_EQ (nano::get_minor_node_version (), response.json.get ("minor_version")); - ASSERT_EQ (nano::get_patch_node_version (), response.json.get ("patch_version")); - ASSERT_EQ (nano::get_pre_release_node_version (), response.json.get ("pre_release_version")); - ASSERT_EQ (0, response.json.get ("maker")); - ASSERT_GE (std::chrono::duration_cast (std::chrono::system_clock::now ().time_since_epoch ()).count (), response.json.get ("timestamp")); -} -} - TEST (rpc, node_telemetry_single) { nano::system system (1); @@ -7967,7 +7944,12 @@ TEST (rpc, node_telemetry_single) ASSERT_NO_ERROR (system.poll ()); } ASSERT_EQ (200, response.status); - compare_default_test_result_data (response, *node); + + nano::jsonconfig config (response.json); + nano::telemetry_data telemetry_data; + auto const should_ignore_identification_metrics = false; + ASSERT_FALSE (telemetry_data.deserialize_json (config, should_ignore_identification_metrics)); + nano::compare_default_telemetry_response_data (telemetry_data, node->network_params, node->config.bandwidth_limit, node->node_id); } } @@ -8017,7 +7999,13 @@ TEST (rpc, node_telemetry_all) { ASSERT_NO_ERROR (system.poll ()); } - compare_default_test_result_data (response, *node); + nano::jsonconfig config (response.json); + nano::telemetry_data telemetry_data; + auto const should_ignore_identification_metrics = true; + ASSERT_FALSE (telemetry_data.deserialize_json (config, should_ignore_identification_metrics)); + nano::compare_default_telemetry_response_data_excluding_signature (telemetry_data, node->network_params, node->config.bandwidth_limit); + ASSERT_FALSE (response.json.get_optional ("node_id").is_initialized ()); + ASSERT_FALSE (response.json.get_optional ("signature").is_initialized ()); } request.put ("raw", "true"); @@ -8031,55 +8019,17 @@ TEST (rpc, node_telemetry_all) // This may fail if the response has taken longer than the cache cutoff time. auto & all_metrics = response.json.get_child ("metrics"); + auto & metrics = all_metrics.front ().second; + ASSERT_EQ (1, all_metrics.size ()); - class telemetry_response_data - { - public: - uint64_t block_count; - uint64_t cemented_count; - uint64_t unchecked_count; - uint64_t account_count; - uint64_t bandwidth_cap; - uint32_t peer_count; - uint8_t protocol_version; - uint64_t uptime; - std::string genesis_block; - uint8_t major_version; - uint8_t minor_version; - uint8_t patch_version; - uint8_t pre_release_version; - uint8_t maker; - uint64_t timestamp; - std::string address; - uint16_t port; - }; + nano::jsonconfig config (metrics); + nano::telemetry_data data; + auto const should_ignore_identification_metrics = false; + ASSERT_FALSE (data.deserialize_json (config, should_ignore_identification_metrics)); + nano::compare_default_telemetry_response_data (data, node->network_params, node->config.bandwidth_limit, node->node_id); - std::vector raw_metrics_json_l; - for (auto & metrics_pair : all_metrics) - { - auto & metrics = metrics_pair.second; - raw_metrics_json_l.push_back ({ metrics.get ("block_count"), metrics.get ("cemented_count"), metrics.get ("unchecked_count"), metrics.get ("account_count"), metrics.get ("bandwidth_cap"), metrics.get ("peer_count"), metrics.get ("protocol_version"), metrics.get ("uptime"), metrics.get ("genesis_block"), metrics.get ("major_version"), metrics.get ("minor_version"), metrics.get ("patch_version"), metrics.get ("pre_release_version"), metrics.get ("maker"), metrics.get ("timestamp"), metrics.get ("address"), metrics.get ("port") }); - } - - ASSERT_EQ (1, raw_metrics_json_l.size ()); - auto const & metrics = raw_metrics_json_l.front (); - ASSERT_EQ (1, metrics.block_count); - ASSERT_EQ (1, metrics.cemented_count); - ASSERT_EQ (0, metrics.unchecked_count); - ASSERT_EQ (1, metrics.account_count); - ASSERT_EQ (node->config.bandwidth_limit, metrics.bandwidth_cap); - ASSERT_EQ (1, metrics.peer_count); - ASSERT_EQ (node->network_params.protocol.protocol_version, metrics.protocol_version); - ASSERT_GE (100, metrics.uptime); - ASSERT_EQ (node1.network_params.ledger.genesis_hash.to_string (), metrics.genesis_block); - ASSERT_EQ (nano::get_major_node_version (), metrics.major_version); - ASSERT_EQ (nano::get_minor_node_version (), metrics.minor_version); - ASSERT_EQ (nano::get_patch_node_version (), metrics.patch_version); - ASSERT_EQ (nano::get_pre_release_node_version (), metrics.pre_release_version); - ASSERT_EQ (0, metrics.maker); - ASSERT_GE (std::chrono::duration_cast (std::chrono::system_clock::now ().time_since_epoch ()).count (), metrics.timestamp); - ASSERT_EQ (node->network.endpoint ().address ().to_string (), metrics.address); - ASSERT_EQ (node->network.endpoint ().port (), metrics.port); + ASSERT_EQ (node->network.endpoint ().address ().to_string (), metrics.get ("address")); + ASSERT_EQ (node->network.endpoint ().port (), metrics.get ("port")); } // Also tests all forms of ipv4/ipv6 @@ -8103,6 +8053,7 @@ TEST (rpc, node_telemetry_self) request.put ("action", "node_telemetry"); request.put ("address", "::1"); request.put ("port", node1.network.endpoint ().port ()); + auto const should_ignore_identification_metrics = false; { test_response response (request, rpc.config.port, system.io_ctx); system.deadline_set (10s); @@ -8111,7 +8062,10 @@ TEST (rpc, node_telemetry_self) ASSERT_NO_ERROR (system.poll ()); } ASSERT_EQ (200, response.status); - compare_default_test_result_data (response, node1); + nano::telemetry_data data; + nano::jsonconfig config (response.json); + ASSERT_FALSE (data.deserialize_json (config, should_ignore_identification_metrics)); + nano::compare_default_telemetry_response_data (data, node1.network_params, node1.config.bandwidth_limit, node1.node_id); } request.put ("address", "[::1]"); @@ -8123,7 +8077,10 @@ TEST (rpc, node_telemetry_self) ASSERT_NO_ERROR (system.poll ()); } ASSERT_EQ (200, response.status); - compare_default_test_result_data (response, node1); + nano::telemetry_data data; + nano::jsonconfig config (response.json); + ASSERT_FALSE (data.deserialize_json (config, should_ignore_identification_metrics)); + nano::compare_default_telemetry_response_data (data, node1.network_params, node1.config.bandwidth_limit, node1.node_id); } request.put ("address", "127.0.0.1"); @@ -8135,7 +8092,10 @@ TEST (rpc, node_telemetry_self) ASSERT_NO_ERROR (system.poll ()); } ASSERT_EQ (200, response.status); - compare_default_test_result_data (response, node1); + nano::telemetry_data data; + nano::jsonconfig config (response.json); + ASSERT_FALSE (data.deserialize_json (config, should_ignore_identification_metrics)); + nano::compare_default_telemetry_response_data (data, node1.network_params, node1.config.bandwidth_limit, node1.node_id); } // Incorrect port should fail diff --git a/nano/secure/common.cpp b/nano/secure/common.cpp index c66f4720..bf52172e 100644 --- a/nano/secure/common.cpp +++ b/nano/secure/common.cpp @@ -1,3 +1,4 @@ +#define IGNORE_GTEST_INCL #include #include #include