Remove telemetry signature partitions (#3014)
* Remove telemetry signature partitions * Doesn't like [[maybe_unused]] used here for some reason. * Add test for max size with unknown_data * Telemetry mask off by 1 in debug_assert check
This commit is contained in:
parent
7b85388dce
commit
053c4ffda7
6 changed files with 85 additions and 22 deletions
|
@ -193,7 +193,7 @@ TEST (telemetry, signatures)
|
|||
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));
|
||||
ASSERT_FALSE (data.validate_signature ());
|
||||
auto signature = data.signature;
|
||||
// Check that the signature is different if changing a piece of data
|
||||
data.maker = 2;
|
||||
|
@ -201,6 +201,22 @@ TEST (telemetry, signatures)
|
|||
ASSERT_NE (data.signature, signature);
|
||||
}
|
||||
|
||||
TEST (telemetry, unknown_data)
|
||||
{
|
||||
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.unknown_data.push_back (1);
|
||||
data.sign (node_id);
|
||||
ASSERT_FALSE (data.validate_signature ());
|
||||
}
|
||||
|
||||
TEST (telemetry, no_peers)
|
||||
{
|
||||
nano::system system (1);
|
||||
|
@ -504,6 +520,29 @@ TEST (telemetry, disable_metrics)
|
|||
ASSERT_TIMELY (10s, done);
|
||||
}
|
||||
|
||||
TEST (telemetry, max_possible_size)
|
||||
{
|
||||
nano::system system;
|
||||
nano::node_flags node_flags;
|
||||
node_flags.disable_initial_telemetry_requests = true;
|
||||
node_flags.disable_ongoing_telemetry_requests = true;
|
||||
auto node_client = system.add_node (node_flags);
|
||||
auto node_server = system.add_node (node_flags);
|
||||
|
||||
nano::telemetry_data data;
|
||||
data.unknown_data.resize (nano::message_header::telemetry_size_mask.to_ulong () - nano::telemetry_data::latest_size);
|
||||
|
||||
nano::telemetry_ack message (data);
|
||||
wait_peer_connections (system);
|
||||
|
||||
auto channel = node_client->network.tcp_channels.find_channel (nano::transport::map_endpoint_to_tcp (node_server->network.endpoint ()));
|
||||
channel->send (message, [](boost::system::error_code const & ec, size_t size_a) {
|
||||
ASSERT_FALSE (ec);
|
||||
});
|
||||
|
||||
ASSERT_TIMELY (10s, 1 == node_server->stats.count (nano::stat::type::message, nano::stat::detail::telemetry_ack, nano::stat::dir::in));
|
||||
}
|
||||
|
||||
namespace nano
|
||||
{
|
||||
TEST (telemetry, remove_peer_different_genesis)
|
||||
|
@ -634,4 +673,4 @@ TEST (telemetry, maker_pruning)
|
|||
}
|
||||
|
||||
ASSERT_EQ (nano::telemetry_maker::nf_pruned_node, static_cast<nano::telemetry_maker> (telemetry_data.maker));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,11 +10,11 @@ namespace nano
|
|||
using stream = std::basic_streambuf<uint8_t>;
|
||||
// Read a raw byte stream the size of `T' and fill value. Returns true if there was an error, false otherwise
|
||||
template <typename T>
|
||||
bool try_read (nano::stream & stream_a, T & value)
|
||||
bool try_read (nano::stream & stream_a, T & value_a)
|
||||
{
|
||||
static_assert (std::is_standard_layout<T>::value, "Can't stream read non-standard layout types");
|
||||
auto amount_read (stream_a.sgetn (reinterpret_cast<uint8_t *> (&value), sizeof (value)));
|
||||
return amount_read != sizeof (value);
|
||||
auto amount_read (stream_a.sgetn (reinterpret_cast<uint8_t *> (&value_a), sizeof (value_a)));
|
||||
return amount_read != sizeof (value_a);
|
||||
}
|
||||
// A wrapper of try_read which throws if there is an error
|
||||
template <typename T>
|
||||
|
@ -27,12 +27,28 @@ void read (nano::stream & stream_a, T & value)
|
|||
}
|
||||
}
|
||||
|
||||
inline void read (nano::stream & stream_a, std::vector<uint8_t> & value_a, size_t size_a)
|
||||
{
|
||||
value_a.resize (size_a);
|
||||
if (stream_a.sgetn (value_a.data (), size_a) != size_a)
|
||||
{
|
||||
throw std::runtime_error ("Failed to read this number of bytes");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void write (nano::stream & stream_a, T const & value)
|
||||
void write (nano::stream & stream_a, T const & value_a)
|
||||
{
|
||||
static_assert (std::is_standard_layout<T>::value, "Can't stream write non-standard layout types");
|
||||
auto amount_written (stream_a.sputn (reinterpret_cast<uint8_t const *> (&value), sizeof (value)));
|
||||
auto amount_written (stream_a.sputn (reinterpret_cast<uint8_t const *> (&value_a), sizeof (value_a)));
|
||||
(void)amount_written;
|
||||
debug_assert (amount_written == sizeof (value));
|
||||
debug_assert (amount_written == sizeof (value_a));
|
||||
}
|
||||
|
||||
inline void write (nano::stream & stream_a, std::vector<uint8_t> const & value_a)
|
||||
{
|
||||
auto amount_written (stream_a.sputn (value_a.data (), value_a.size ()));
|
||||
(void)amount_written;
|
||||
debug_assert (amount_written == value_a.size ());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1108,9 +1108,9 @@ nano::telemetry_ack::telemetry_ack (nano::telemetry_data const & telemetry_data_
|
|||
message (nano::message_type::telemetry_ack),
|
||||
data (telemetry_data_a)
|
||||
{
|
||||
debug_assert (telemetry_data::size < 2048); // Maximum size the mask allows
|
||||
debug_assert (telemetry_data::size + telemetry_data_a.unknown_data.size () <= message_header::telemetry_size_mask.to_ulong ()); // Maximum size the mask allows
|
||||
header.extensions &= ~message_header::telemetry_size_mask;
|
||||
header.extensions |= std::bitset<16> (static_cast<unsigned long long> (telemetry_data::size));
|
||||
header.extensions |= std::bitset<16> (static_cast<unsigned long long> (telemetry_data::size) + telemetry_data_a.unknown_data.size ());
|
||||
}
|
||||
|
||||
void nano::telemetry_ack::serialize (nano::stream & stream_a, bool use_epoch_2_min_version_a) const
|
||||
|
@ -1193,9 +1193,13 @@ void nano::telemetry_data::deserialize (nano::stream & stream_a, uint16_t payloa
|
|||
timestamp = std::chrono::system_clock::time_point (std::chrono::milliseconds (timestamp_l));
|
||||
read (stream_a, active_difficulty);
|
||||
boost::endian::big_to_native_inplace (active_difficulty);
|
||||
if (payload_length_a > latest_size)
|
||||
{
|
||||
read (stream_a, unknown_data, payload_length_a - latest_size);
|
||||
}
|
||||
}
|
||||
|
||||
void nano::telemetry_data::serialize_without_signature (nano::stream & stream_a, uint16_t /* size_a */) const
|
||||
void nano::telemetry_data::serialize_without_signature (nano::stream & stream_a) const
|
||||
{
|
||||
// All values should be serialized in big endian
|
||||
write (stream_a, node_id);
|
||||
|
@ -1215,12 +1219,13 @@ void nano::telemetry_data::serialize_without_signature (nano::stream & stream_a,
|
|||
write (stream_a, maker);
|
||||
write (stream_a, boost::endian::native_to_big (std::chrono::duration_cast<std::chrono::milliseconds> (timestamp.time_since_epoch ()).count ()));
|
||||
write (stream_a, boost::endian::native_to_big (active_difficulty));
|
||||
write (stream_a, unknown_data);
|
||||
}
|
||||
|
||||
void nano::telemetry_data::serialize (nano::stream & stream_a) const
|
||||
{
|
||||
write (stream_a, signature);
|
||||
serialize_without_signature (stream_a, size);
|
||||
serialize_without_signature (stream_a);
|
||||
}
|
||||
|
||||
nano::error nano::telemetry_data::serialize_json (nano::jsonconfig & json, bool ignore_identification_metrics_a) const
|
||||
|
@ -1307,7 +1312,7 @@ nano::error nano::telemetry_data::deserialize_json (nano::jsonconfig & json, boo
|
|||
|
||||
bool nano::telemetry_data::operator== (nano::telemetry_data const & data_a) const
|
||||
{
|
||||
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 && active_difficulty == data_a.active_difficulty);
|
||||
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 && active_difficulty == data_a.active_difficulty && unknown_data == data_a.unknown_data);
|
||||
}
|
||||
|
||||
bool nano::telemetry_data::operator!= (nano::telemetry_data const & data_a) const
|
||||
|
@ -1321,18 +1326,18 @@ void nano::telemetry_data::sign (nano::keypair const & node_id_a)
|
|||
std::vector<uint8_t> bytes;
|
||||
{
|
||||
nano::vectorstream stream (bytes);
|
||||
serialize_without_signature (stream, size);
|
||||
serialize_without_signature (stream);
|
||||
}
|
||||
|
||||
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
|
||||
bool nano::telemetry_data::validate_signature () const
|
||||
{
|
||||
std::vector<uint8_t> bytes;
|
||||
{
|
||||
nano::vectorstream stream (bytes);
|
||||
serialize_without_signature (stream, size_a);
|
||||
serialize_without_signature (stream);
|
||||
}
|
||||
|
||||
return nano::validate_message (node_id, bytes.data (), bytes.size (), signature);
|
||||
|
|
|
@ -220,7 +220,7 @@ public:
|
|||
|
||||
static std::bitset<16> constexpr block_type_mask{ 0x0f00 };
|
||||
static std::bitset<16> constexpr count_mask{ 0xf000 };
|
||||
static std::bitset<16> constexpr telemetry_size_mask{ 0x07ff };
|
||||
static std::bitset<16> constexpr telemetry_size_mask{ 0x3ff };
|
||||
};
|
||||
class message
|
||||
{
|
||||
|
@ -368,20 +368,22 @@ public:
|
|||
uint8_t maker{ static_cast<std::underlying_type_t<telemetry_maker>> (telemetry_maker::nf_node) }; // Where this telemetry information originated
|
||||
std::chrono::system_clock::time_point timestamp;
|
||||
uint64_t active_difficulty{ 0 };
|
||||
std::vector<uint8_t> unknown_data;
|
||||
|
||||
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 validate_signature () const;
|
||||
bool operator== (nano::telemetry_data const &) const;
|
||||
bool operator!= (nano::telemetry_data const &) const;
|
||||
|
||||
// Size does not include unknown_data
|
||||
static auto constexpr size = 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) + sizeof (minor_version) + sizeof (patch_version) + sizeof (pre_release_version) + sizeof (maker) + sizeof (uint64_t) + sizeof (active_difficulty);
|
||||
|
||||
static auto constexpr latest_size = size; // This needs to be updated for each new telemetry version
|
||||
private:
|
||||
void serialize_without_signature (nano::stream &, uint16_t) const;
|
||||
void serialize_without_signature (nano::stream &) const;
|
||||
};
|
||||
class telemetry_req final : public message
|
||||
{
|
||||
|
|
|
@ -90,7 +90,7 @@ bool nano::telemetry::verify_message (nano::telemetry_ack const & message_a, nan
|
|||
if (!node_id_mismatch)
|
||||
{
|
||||
// The data could be correctly signed but for a different node id
|
||||
remove_channel = message_a.data.validate_signature (message_a.size ());
|
||||
remove_channel = message_a.data.validate_signature ();
|
||||
if (!remove_channel)
|
||||
{
|
||||
// Check for different genesis blocks
|
||||
|
|
|
@ -21,11 +21,12 @@ void nano::compare_default_telemetry_response_data_excluding_signature (nano::te
|
|||
ASSERT_EQ (telemetry_data_a.maker, static_cast<std::underlying_type_t<nano::telemetry_maker>> (nano::telemetry_maker::nf_node));
|
||||
ASSERT_GT (telemetry_data_a.timestamp, std::chrono::system_clock::now () - std::chrono::seconds (100));
|
||||
ASSERT_EQ (telemetry_data_a.active_difficulty, active_difficulty_a);
|
||||
ASSERT_EQ (telemetry_data_a.unknown_data, std::vector<uint8_t>{});
|
||||
}
|
||||
|
||||
void nano::compare_default_telemetry_response_data (nano::telemetry_data const & telemetry_data_a, nano::network_params const & network_params_a, uint64_t bandwidth_limit_a, uint64_t active_difficulty_a, nano::keypair const & node_id_a)
|
||||
{
|
||||
ASSERT_FALSE (telemetry_data_a.validate_signature (nano::telemetry_data::size));
|
||||
ASSERT_FALSE (telemetry_data_a.validate_signature ());
|
||||
nano::telemetry_data telemetry_data_l = telemetry_data_a;
|
||||
telemetry_data_l.signature.clear ();
|
||||
telemetry_data_l.sign (node_id_a);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue