Merge pull request #4154 from pwojcikdev/prs/cleanup-handshake-message

Encapsulate handshake parts into `query_payload` and `response_payload`
This commit is contained in:
clemahieu 2023-03-07 19:41:59 +00:00 committed by GitHub
commit bc6c154a41
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 184 additions and 109 deletions

View file

@ -178,7 +178,7 @@ TEST (message_deserializer, exact_bulk_push)
TEST (message_deserializer, exact_node_id_handshake)
{
nano::node_id_handshake message{ nano::dev::network_params.network, boost::none, boost::none };
nano::node_id_handshake message{ nano::dev::network_params.network, std::nullopt, std::nullopt };
message_deserializer_success_checker<decltype (message)> (message);
}

View file

@ -706,7 +706,9 @@ TEST (tcp_listener, tcp_node_id_handshake)
auto socket (std::make_shared<nano::transport::client_socket> (*system.nodes[0]));
auto bootstrap_endpoint (system.nodes[0]->tcp_listener.endpoint ());
auto cookie (system.nodes[0]->network.syn_cookies.assign (nano::transport::map_tcp_to_endpoint (bootstrap_endpoint)));
nano::node_id_handshake node_id_handshake{ nano::dev::network_params.network, cookie, boost::none };
ASSERT_TRUE (cookie);
nano::node_id_handshake::query_payload query{ *cookie };
nano::node_id_handshake node_id_handshake{ nano::dev::network_params.network, query };
auto input (node_id_handshake.to_shared_const_buffer ());
std::atomic<bool> write_done (false);
socket->async_connect (bootstrap_endpoint, [&input, socket, &write_done] (boost::system::error_code const & ec) {
@ -720,8 +722,8 @@ TEST (tcp_listener, tcp_node_id_handshake)
ASSERT_TIMELY (5s, write_done);
boost::optional<std::pair<nano::account, nano::signature>> response_zero (std::make_pair (nano::account{}, nano::signature (0)));
nano::node_id_handshake node_id_handshake_response{ nano::dev::network_params.network, boost::none, response_zero };
nano::node_id_handshake::response_payload response_zero{ 0 };
nano::node_id_handshake node_id_handshake_response{ nano::dev::network_params.network, std::nullopt, response_zero };
auto output (node_id_handshake_response.to_bytes ());
std::atomic<bool> done (false);
socket->async_read (output, output->size (), [&output, &done] (boost::system::error_code const & ec, size_t size_a) {
@ -764,7 +766,9 @@ TEST (tcp_listener, tcp_listener_timeout_node_id_handshake)
auto node0 (system.nodes[0]);
auto socket (std::make_shared<nano::transport::client_socket> (*node0));
auto cookie (node0->network.syn_cookies.assign (nano::transport::map_tcp_to_endpoint (node0->tcp_listener.endpoint ())));
nano::node_id_handshake node_id_handshake{ nano::dev::network_params.network, cookie, boost::none };
ASSERT_TRUE (cookie);
nano::node_id_handshake::query_payload query{ *cookie };
nano::node_id_handshake node_id_handshake{ nano::dev::network_params.network, query };
auto channel = std::make_shared<nano::transport::channel_tcp> (*node0, socket);
socket->async_connect (node0->tcp_listener.endpoint (), [&node_id_handshake, channel] (boost::system::error_code const & ec) {
ASSERT_FALSE (ec);

View file

@ -238,32 +238,6 @@ bool nano::message_header::frontier_req_is_only_confirmed_present () const
return result;
}
bool nano::message_header::node_id_handshake_is_query () const
{
auto result (false);
if (type == nano::message_type::node_id_handshake)
{
if (extensions.test (node_id_handshake_query_flag))
{
result = true;
}
}
return result;
}
bool nano::message_header::node_id_handshake_is_response () const
{
auto result (false);
if (type == nano::message_type::node_id_handshake)
{
if (extensions.test (node_id_handshake_response_flag))
{
result = true;
}
}
return result;
}
std::size_t nano::message_header::payload_length_bytes () const
{
switch (type)
@ -1612,75 +1586,77 @@ bool nano::telemetry_data::validate_signature () const
*/
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),
response (boost::none)
message (header_a)
{
error_a = deserialize (stream_a);
}
nano::node_id_handshake::node_id_handshake (nano::network_constants const & constants, boost::optional<nano::uint256_union> query, boost::optional<std::pair<nano::account, nano::signature>> response) :
nano::node_id_handshake::node_id_handshake (nano::network_constants const & constants, std::optional<query_payload> query_a, std::optional<response_payload> response_a) :
message (constants, nano::message_type::node_id_handshake),
query (query),
response (response)
query{ query_a },
response{ response_a }
{
if (query)
{
header.flag_set (nano::message_header::node_id_handshake_query_flag);
header.flag_set (query_flag);
}
if (response)
{
header.flag_set (nano::message_header::node_id_handshake_response_flag);
header.flag_set (response_flag);
}
}
void nano::node_id_handshake::serialize (nano::stream & stream_a) const
void nano::node_id_handshake::serialize (nano::stream & stream) const
{
header.serialize (stream_a);
header.serialize (stream);
if (query)
{
write (stream_a, *query);
query->serialize (stream);
}
if (response)
{
write (stream_a, response->first);
write (stream_a, response->second);
response->serialize (stream);
}
}
bool nano::node_id_handshake::deserialize (nano::stream & stream_a)
bool nano::node_id_handshake::deserialize (nano::stream & stream)
{
debug_assert (header.type == nano::message_type::node_id_handshake);
auto error (false);
bool error = false;
try
{
if (header.node_id_handshake_is_query ())
if (is_query (header))
{
nano::uint256_union query_hash;
read (stream_a, query_hash);
query = query_hash;
query_payload pld{};
pld.deserialize (stream);
query = pld;
}
if (header.node_id_handshake_is_response ())
if (is_response (header))
{
nano::account response_account;
read (stream_a, response_account);
nano::signature response_signature;
read (stream_a, response_signature);
response = std::make_pair (response_account, response_signature);
response_payload pld{};
pld.deserialize (stream);
response = pld;
}
}
catch (std::runtime_error const &)
{
error = true;
}
return error;
}
bool nano::node_id_handshake::operator== (nano::node_id_handshake const & other_a) const
bool nano::node_id_handshake::is_query (nano::message_header const & header)
{
auto result (*query == *other_a.query && *response == *other_a.response);
debug_assert (header.type == nano::message_type::node_id_handshake);
bool result = header.extensions.test (query_flag);
return result;
}
bool nano::node_id_handshake::is_response (nano::message_header const & header)
{
debug_assert (header.type == nano::message_type::node_id_handshake);
bool result = header.extensions.test (response_flag);
return result;
}
@ -1694,16 +1670,16 @@ std::size_t nano::node_id_handshake::size () const
return size (header);
}
std::size_t nano::node_id_handshake::size (nano::message_header const & header_a)
std::size_t nano::node_id_handshake::size (nano::message_header const & header)
{
std::size_t result (0);
if (header_a.node_id_handshake_is_query ())
std::size_t result = 0;
if (is_query (header))
{
result = sizeof (nano::uint256_union);
result += query_payload::size;
}
if (header_a.node_id_handshake_is_response ())
if (is_response (header))
{
result += sizeof (nano::account) + sizeof (nano::signature);
result += response_payload::size;
}
return result;
}
@ -1711,21 +1687,48 @@ std::size_t nano::node_id_handshake::size (nano::message_header const & header_a
std::string nano::node_id_handshake::to_string () const
{
std::string s = header.to_string ();
if (query.has_value ())
if (query)
{
s += "\ncookie=" + query->to_string ();
s += "\ncookie=" + query->cookie.to_string ();
}
if (response.has_value ())
if (response)
{
s += "\nresp_node_id=" + response->first.to_string ();
s += "\nresp_sig=" + response->second.to_string ();
s += "\nresp_node_id=" + response->node_id.to_string ();
s += "\nresp_sig=" + response->signature.to_string ();
}
return s;
}
/*
* node_id_handshake::query_payload
*/
void nano::node_id_handshake::query_payload::serialize (nano::stream & stream) const
{
nano::write (stream, cookie);
}
void nano::node_id_handshake::query_payload::deserialize (nano::stream & stream)
{
nano::read (stream, cookie);
}
/*
* node_id_handshake::response_payload
*/
void nano::node_id_handshake::response_payload::serialize (nano::stream & stream) const
{
nano::write (stream, node_id);
nano::write (stream, signature);
}
void nano::node_id_handshake::response_payload::deserialize (nano::stream & stream)
{
nano::read (stream, node_id);
nano::read (stream, signature);
}
/*
* asc_pull_req
*/

View file

@ -81,10 +81,6 @@ public:
bool bulk_pull_ascending () const;
static uint8_t constexpr frontier_req_only_confirmed = 1;
bool frontier_req_is_only_confirmed_present () const;
static uint8_t constexpr node_id_handshake_query_flag = 0;
static uint8_t constexpr node_id_handshake_response_flag = 1;
bool node_id_handshake_is_query () const;
bool node_id_handshake_is_response () const;
/** Size of the payload in bytes. For some messages, the payload size is based on header flags. */
std::size_t payload_length_bytes () const;
@ -351,18 +347,54 @@ public:
class node_id_handshake final : public message
{
public: // Payload definitions
class query_payload
{
public:
void serialize (nano::stream &) const;
void deserialize (nano::stream &);
static std::size_t constexpr size = sizeof (nano::uint256_union);
public:
nano::uint256_union cookie;
};
class response_payload
{
public:
void serialize (nano::stream &) const;
void deserialize (nano::stream &);
static std::size_t constexpr size = sizeof (nano::account) + sizeof (nano::signature);
public:
nano::account node_id;
nano::signature signature;
};
public:
explicit node_id_handshake (nano::network_constants const &, std::optional<query_payload> query = std::nullopt, std::optional<response_payload> response = std::nullopt);
node_id_handshake (bool &, nano::stream &, nano::message_header const &);
node_id_handshake (nano::network_constants const & constants, boost::optional<nano::uint256_union>, boost::optional<std::pair<nano::account, nano::signature>>);
void serialize (nano::stream &) const override;
bool deserialize (nano::stream &);
void visit (nano::message_visitor &) const override;
bool operator== (nano::node_id_handshake const &) const;
boost::optional<nano::uint256_union> query;
boost::optional<std::pair<nano::account, nano::signature>> response;
std::size_t size () const;
static std::size_t size (nano::message_header const &);
std::string to_string () const;
public: // Header
static uint8_t constexpr query_flag = 0;
static uint8_t constexpr response_flag = 1;
static bool is_query (nano::message_header const &);
static bool is_response (nano::message_header const &);
public: // Payload
std::optional<query_payload> query;
std::optional<response_payload> response;
};
/**

View file

@ -113,19 +113,30 @@ void nano::network::send_keepalive_self (std::shared_ptr<nano::transport::channe
channel_a->send (message);
}
void nano::network::send_node_id_handshake (std::shared_ptr<nano::transport::channel> const & channel_a, boost::optional<nano::uint256_union> const & query, boost::optional<nano::uint256_union> const & respond_to)
void nano::network::send_node_id_handshake (std::shared_ptr<nano::transport::channel> const & channel_a, std::optional<nano::uint256_union> const & cookie, std::optional<nano::uint256_union> const & respond_to)
{
boost::optional<std::pair<nano::account, nano::signature>> response (boost::none);
std::optional<nano::node_id_handshake::response_payload> response;
if (respond_to)
{
response = std::make_pair (node.node_id.pub, nano::sign_message (node.node_id.prv, node.node_id.pub, *respond_to));
debug_assert (!nano::validate_message (response->first, *respond_to, response->second));
nano::node_id_handshake::response_payload pld{ node.node_id.pub, nano::sign_message (node.node_id.prv, node.node_id.pub, *respond_to) };
debug_assert (!nano::validate_message (pld.node_id, *respond_to, pld.signature));
response = pld;
}
std::optional<nano::node_id_handshake::query_payload> query;
if (cookie)
{
nano::node_id_handshake::query_payload pld{ *cookie };
query = pld;
}
nano::node_id_handshake message{ node.network_params.network, query, response };
if (node.config.logging.network_node_id_handshake_logging ())
{
node.logger.try_log (boost::str (boost::format ("Node ID handshake sent with node ID %1% to %2%: query %3%, respond_to %4% (signature %5%)") % node.node_id.pub.to_node_id () % channel_a->get_endpoint () % (query ? query->to_string () : std::string ("[none]")) % (respond_to ? respond_to->to_string () : std::string ("[none]")) % (response ? response->second.to_string () : std::string ("[none]"))));
node.logger.try_log (boost::str (boost::format ("Node ID handshake sent with node ID %1% to %2%: query %3%, respond_to %4% (signature %5%)") % node.node_id.pub.to_node_id () % channel_a->get_endpoint () % (query ? query->cookie.to_string () : std::string ("[none]")) % (respond_to ? respond_to->to_string () : std::string ("[none]")) % (response ? response->signature.to_string () : std::string ("[none]"))));
}
channel_a->send (message);
}

View file

@ -35,8 +35,8 @@ private:
friend class network_tcp_message_manager_Test;
};
/**
* Node ID cookies for node ID handshakes
*/
* Node ID cookies for node ID handshakes
*/
class syn_cookies final
{
public:
@ -87,7 +87,7 @@ public:
void merge_peer (nano::endpoint const &);
void send_keepalive (std::shared_ptr<nano::transport::channel> const &);
void send_keepalive_self (std::shared_ptr<nano::transport::channel> const &);
void send_node_id_handshake (std::shared_ptr<nano::transport::channel> const &, boost::optional<nano::uint256_union> const & query, boost::optional<nano::uint256_union> const & respond_to);
void send_node_id_handshake (std::shared_ptr<nano::transport::channel> const &, std::optional<nano::uint256_union> const & cookie, std::optional<nano::uint256_union> const & respond_to);
void send_confirm_req (std::shared_ptr<nano::transport::channel> const & channel_a, std::pair<nano::block_hash, nano::block_hash> const & hash_root_a);
void broadcast_confirm_req (std::shared_ptr<nano::block> const &);
void broadcast_confirm_req_base (std::shared_ptr<nano::block> const &, std::shared_ptr<std::vector<std::shared_ptr<nano::transport::channel>>> const &, unsigned, bool = false);

View file

@ -544,12 +544,21 @@ void nano::transport::tcp_channels::start_tcp (nano::endpoint const & endpoint_a
if (!ec && channel)
{
// TCP node ID handshake
auto cookie (node_l->network.syn_cookies.assign (endpoint_a));
nano::node_id_handshake message (node_l->network_params.network, cookie, boost::none);
std::optional<nano::node_id_handshake::query_payload> query;
if (auto cookie = node_l->network.syn_cookies.assign (endpoint_a); cookie)
{
nano::node_id_handshake::query_payload pld{ *cookie };
query = pld;
}
nano::node_id_handshake message{ node_l->network_params.network, query };
if (node_l->config.logging.network_node_id_handshake_logging ())
{
node_l->logger.try_log (boost::str (boost::format ("Node ID handshake request sent with node ID %1% to %2%: query %3%") % node_l->node_id.pub.to_node_id () % endpoint_a % (cookie.has_value () ? cookie->to_string () : "not set")));
node_l->logger.try_log (boost::str (boost::format ("Node ID handshake request sent with node ID %1% to %2%: query %3%") % node_l->node_id.pub.to_node_id () % endpoint_a % (query ? query->cookie.to_string () : "not set")));
}
channel->set_endpoint ();
std::shared_ptr<std::vector<uint8_t>> receive_buffer (std::make_shared<std::vector<uint8_t>> ());
receive_buffer->resize (256);
@ -670,12 +679,17 @@ void nano::transport::tcp_channels::start_tcp_receive_node_id (std::shared_ptr<n
return;
}
channel_a->set_network_version (header.version_using);
auto node_id (message.response->first);
bool process (!node_l->network.syn_cookies.validate (endpoint_a, node_id, message.response->second) && node_id != node_l->node_id.pub);
debug_assert (message.query);
debug_assert (message.response);
auto node_id = message.response->node_id;
bool process = (!node_l->network.syn_cookies.validate (endpoint_a, node_id, message.response->signature) && node_id != node_l->node_id.pub);
if (!process)
{
return;
}
/* If node ID is known, don't establish new connection
Exception: temporary channels from tcp_server */
auto existing_channel (node_l->network.tcp_channels.find_node_id (node_id));
@ -683,15 +697,19 @@ void nano::transport::tcp_channels::start_tcp_receive_node_id (std::shared_ptr<n
{
return;
}
channel_a->set_node_id (node_id);
channel_a->set_last_packet_received (std::chrono::steady_clock::now ());
boost::optional<std::pair<nano::account, nano::signature>> response (std::make_pair (node_l->node_id.pub, nano::sign_message (node_l->node_id.prv, node_l->node_id.pub, *message.query)));
nano::node_id_handshake response_message (node_l->network_params.network, boost::none, response);
nano::node_id_handshake::response_payload response{ node_l->node_id.pub, nano::sign_message (node_l->node_id.prv, node_l->node_id.pub, message.query->cookie) };
nano::node_id_handshake handshake_response (node_l->network_params.network, std::nullopt, response);
if (node_l->config.logging.network_node_id_handshake_logging ())
{
node_l->logger.try_log (boost::str (boost::format ("Node ID handshake response sent with node ID %1% to %2%: query %3%") % node_l->node_id.pub.to_node_id () % endpoint_a % (*message.query).to_string ()));
node_l->logger.try_log (boost::str (boost::format ("Node ID handshake response sent with node ID %1% to %2%: query %3%") % node_l->node_id.pub.to_node_id () % endpoint_a % message.query->cookie.to_string ()));
}
channel_a->send (response_message, [node_w, channel_a, endpoint_a, cleanup_node_id_handshake_socket] (boost::system::error_code const & ec, std::size_t size_a) {
channel_a->send (handshake_response, [node_w, channel_a, endpoint_a, cleanup_node_id_handshake_socket] (boost::system::error_code const & ec, std::size_t size_a) {
auto node_l = node_w.lock ();
if (!node_l)
{

View file

@ -340,10 +340,10 @@ void nano::transport::tcp_server::handshake_message_visitor::node_id_handshake (
{
server->send_handshake_response (*message.query);
}
else if (message.response)
if (message.response)
{
nano::account const & node_id (message.response->first);
if (!server->node->network.syn_cookies.validate (nano::transport::map_tcp_to_endpoint (server->remote_endpoint), node_id, message.response->second) && node_id != server->node->node_id.pub)
nano::account const & node_id = message.response->node_id;
if (!server->node->network.syn_cookies.validate (nano::transport::map_tcp_to_endpoint (server->remote_endpoint), node_id, message.response->signature) && node_id != server->node->node_id.pub)
{
server->to_realtime_connection (node_id);
}
@ -357,15 +357,22 @@ void nano::transport::tcp_server::handshake_message_visitor::node_id_handshake (
process = true;
}
void nano::transport::tcp_server::send_handshake_response (nano::uint256_union query)
void nano::transport::tcp_server::send_handshake_response (nano::node_id_handshake::query_payload const & query)
{
boost::optional<std::pair<nano::account, nano::signature>> response (std::make_pair (node->node_id.pub, nano::sign_message (node->node_id.prv, node->node_id.pub, query)));
debug_assert (!nano::validate_message (response->first, query, response->second));
nano::node_id_handshake::response_payload response{ node->node_id.pub, nano::sign_message (node->node_id.prv, node->node_id.pub, query.cookie) };
debug_assert (!nano::validate_message (response.node_id, query.cookie, response.signature));
auto cookie (node->network.syn_cookies.assign (nano::transport::map_tcp_to_endpoint (remote_endpoint)));
nano::node_id_handshake response_message (node->network_params.network, cookie, response);
std::optional<nano::node_id_handshake::query_payload> own_query;
if (auto own_cookie = node->network.syn_cookies.assign (nano::transport::map_tcp_to_endpoint (remote_endpoint)); own_cookie)
{
nano::node_id_handshake::query_payload pld{ *own_cookie };
own_query = pld;
}
auto shared_const_buffer = response_message.to_shared_const_buffer ();
nano::node_id_handshake handshake_response{ node->network_params.network, own_query, response };
// TODO: Use channel
auto shared_const_buffer = handshake_response.to_shared_const_buffer ();
socket->async_write (shared_const_buffer, [this_l = shared_from_this ()] (boost::system::error_code const & ec, std::size_t size_a) {
if (ec)
{

View file

@ -52,8 +52,6 @@ public:
void timeout ();
void send_handshake_response (nano::uint256_union query);
std::shared_ptr<nano::transport::socket> const socket;
std::shared_ptr<nano::node> const node;
nano::mutex mutex;
@ -65,6 +63,8 @@ public:
std::chrono::steady_clock::time_point last_telemetry_req{};
private:
void send_handshake_response (nano::node_id_handshake::query_payload const & query);
void receive_message ();
void received_message (std::unique_ptr<nano::message> message);
bool process_message (std::unique_ptr<nano::message> message);