dncurrency/nano/node/common.hpp
Wesley Shillingford f8158fc03c
Remove compiler warnings (incl from third party headers) (#2072)
* Remove compiler warnings

* Fix new warnings in test

* Remove new msvc warnings
2019-07-12 17:28:21 +01:00

422 lines
13 KiB
C++

#pragma once
#include <nano/boost/asio.hpp>
#include <nano/crypto_lib/random_pool.hpp>
#include <nano/lib/config.hpp>
#include <nano/lib/memory.hpp>
#include <nano/secure/common.hpp>
#include <bitset>
namespace nano
{
using endpoint = boost::asio::ip::udp::endpoint;
bool parse_port (std::string const &, uint16_t &);
bool parse_address_port (std::string const &, boost::asio::ip::address &, uint16_t &);
using tcp_endpoint = boost::asio::ip::tcp::endpoint;
bool parse_endpoint (std::string const &, nano::endpoint &);
bool parse_tcp_endpoint (std::string const &, nano::tcp_endpoint &);
}
namespace
{
uint64_t ip_address_hash_raw (boost::asio::ip::address const & ip_a, uint16_t port = 0)
{
static nano::random_constants constants;
assert (ip_a.is_v6 ());
uint64_t result;
nano::uint128_union address;
address.bytes = ip_a.to_v6 ().to_bytes ();
blake2b_state state;
blake2b_init (&state, sizeof (result));
blake2b_update (&state, constants.random_128.bytes.data (), constants.random_128.bytes.size ());
if (port != 0)
{
blake2b_update (&state, &port, sizeof (port));
}
blake2b_update (&state, address.bytes.data (), address.bytes.size ());
blake2b_final (&state, &result, sizeof (result));
return result;
}
uint64_t endpoint_hash_raw (nano::endpoint const & endpoint_a)
{
uint64_t result (ip_address_hash_raw (endpoint_a.address (), endpoint_a.port ()));
return result;
}
uint64_t endpoint_hash_raw (nano::tcp_endpoint const & endpoint_a)
{
uint64_t result (ip_address_hash_raw (endpoint_a.address (), endpoint_a.port ()));
return result;
}
template <size_t size>
struct endpoint_hash
{
};
template <>
struct endpoint_hash<8>
{
size_t operator() (nano::endpoint const & endpoint_a) const
{
return endpoint_hash_raw (endpoint_a);
}
size_t operator() (nano::tcp_endpoint const & endpoint_a) const
{
return endpoint_hash_raw (endpoint_a);
}
};
template <>
struct endpoint_hash<4>
{
size_t operator() (nano::endpoint const & endpoint_a) const
{
uint64_t big (endpoint_hash_raw (endpoint_a));
uint32_t result (static_cast<uint32_t> (big) ^ static_cast<uint32_t> (big >> 32));
return result;
}
size_t operator() (nano::tcp_endpoint const & endpoint_a) const
{
uint64_t big (endpoint_hash_raw (endpoint_a));
uint32_t result (static_cast<uint32_t> (big) ^ static_cast<uint32_t> (big >> 32));
return result;
}
};
template <size_t size>
struct ip_address_hash
{
};
template <>
struct ip_address_hash<8>
{
size_t operator() (boost::asio::ip::address const & ip_address_a) const
{
return ip_address_hash_raw (ip_address_a);
}
};
template <>
struct ip_address_hash<4>
{
size_t operator() (boost::asio::ip::address const & ip_address_a) const
{
uint64_t big (ip_address_hash_raw (ip_address_a));
uint32_t result (static_cast<uint32_t> (big) ^ static_cast<uint32_t> (big >> 32));
return result;
}
};
}
namespace std
{
template <>
struct hash<::nano::endpoint>
{
size_t operator() (::nano::endpoint const & endpoint_a) const
{
endpoint_hash<sizeof (size_t)> ehash;
return ehash (endpoint_a);
}
};
template <>
struct hash<::nano::tcp_endpoint>
{
size_t operator() (::nano::tcp_endpoint const & endpoint_a) const
{
endpoint_hash<sizeof (size_t)> ehash;
return ehash (endpoint_a);
}
};
template <>
struct hash<boost::asio::ip::address>
{
size_t operator() (boost::asio::ip::address const & ip_a) const
{
ip_address_hash<sizeof (size_t)> ihash;
return ihash (ip_a);
}
};
}
namespace boost
{
template <>
struct hash<::nano::endpoint>
{
size_t operator() (::nano::endpoint const & endpoint_a) const
{
std::hash<::nano::endpoint> hash;
return hash (endpoint_a);
}
};
template <>
struct hash<::nano::tcp_endpoint>
{
size_t operator() (::nano::tcp_endpoint const & endpoint_a) const
{
std::hash<::nano::tcp_endpoint> hash;
return hash (endpoint_a);
}
};
template <>
struct hash<boost::asio::ip::address>
{
size_t operator() (boost::asio::ip::address const & ip_a) const
{
std::hash<boost::asio::ip::address> hash;
return hash (ip_a);
}
};
}
namespace nano
{
/**
* Message types are serialized to the network and existing values must thus never change as
* types are added, removed and reordered in the enum.
*/
enum class message_type : uint8_t
{
invalid = 0x0,
not_a_type = 0x1,
keepalive = 0x2,
publish = 0x3,
confirm_req = 0x4,
confirm_ack = 0x5,
bulk_pull = 0x6,
bulk_push = 0x7,
frontier_req = 0x8,
/* deleted 0x9 */
node_id_handshake = 0x0a,
bulk_pull_account = 0x0b
};
enum class bulk_pull_account_flags : uint8_t
{
pending_hash_and_amount = 0x0,
pending_address_only = 0x1,
pending_hash_amount_and_address = 0x2
};
class message_visitor;
class message_header final
{
public:
explicit message_header (nano::message_type);
message_header (bool &, nano::stream &);
void serialize (nano::stream &) const;
bool deserialize (nano::stream &);
nano::block_type block_type () const;
void block_type_set (nano::block_type);
uint8_t count_get () const;
void count_set (uint8_t);
uint8_t version_max;
uint8_t version_using;
uint8_t version_min;
nano::message_type type;
std::bitset<16> extensions;
void flag_set (uint8_t);
static uint8_t constexpr bulk_pull_count_present_flag = 0;
bool bulk_pull_is_count_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. */
size_t payload_length_bytes () const;
static std::bitset<16> constexpr block_type_mask = std::bitset<16> (0x0f00);
static std::bitset<16> constexpr count_mask = std::bitset<16> (0xf000);
};
class message
{
public:
explicit message (nano::message_type);
explicit message (nano::message_header const &);
virtual ~message () = default;
virtual void serialize (nano::stream &) const = 0;
virtual void visit (nano::message_visitor &) const = 0;
virtual std::shared_ptr<std::vector<uint8_t>> to_bytes () const
{
auto bytes = std::make_shared<std::vector<uint8_t>> ();
nano::vectorstream stream (*bytes);
serialize (stream);
return bytes;
}
nano::message_header header;
};
class work_pool;
class message_parser final
{
public:
enum class parse_status
{
success,
insufficient_work,
invalid_header,
invalid_message_type,
invalid_keepalive_message,
invalid_publish_message,
invalid_confirm_req_message,
invalid_confirm_ack_message,
invalid_node_id_handshake_message,
outdated_version,
invalid_magic,
invalid_network
};
message_parser (nano::block_uniquer &, nano::vote_uniquer &, nano::message_visitor &, nano::work_pool &);
void deserialize_buffer (uint8_t const *, size_t);
void deserialize_keepalive (nano::stream &, nano::message_header const &);
void deserialize_publish (nano::stream &, nano::message_header const &);
void deserialize_confirm_req (nano::stream &, nano::message_header const &);
void deserialize_confirm_ack (nano::stream &, nano::message_header const &);
void deserialize_node_id_handshake (nano::stream &, nano::message_header const &);
bool at_end (nano::stream &);
nano::block_uniquer & block_uniquer;
nano::vote_uniquer & vote_uniquer;
nano::message_visitor & visitor;
nano::work_pool & pool;
parse_status status;
std::string status_string ();
static const size_t max_safe_udp_message_size;
};
class keepalive final : public message
{
public:
keepalive ();
keepalive (bool &, nano::stream &, nano::message_header const &);
void visit (nano::message_visitor &) const override;
void serialize (nano::stream &) const override;
bool deserialize (nano::stream &);
bool operator== (nano::keepalive const &) const;
std::array<nano::endpoint, 8> peers;
static size_t constexpr size = 8 * (16 + 2);
};
class publish final : public message
{
public:
publish (bool &, nano::stream &, nano::message_header const &, nano::block_uniquer * = nullptr);
explicit publish (std::shared_ptr<nano::block>);
void visit (nano::message_visitor &) const override;
void serialize (nano::stream &) const override;
bool deserialize (nano::stream &, nano::block_uniquer * = nullptr);
bool operator== (nano::publish const &) const;
std::shared_ptr<nano::block> block;
};
class confirm_req final : public message
{
public:
confirm_req (bool &, nano::stream &, nano::message_header const &, nano::block_uniquer * = nullptr);
explicit confirm_req (std::shared_ptr<nano::block>);
confirm_req (std::vector<std::pair<nano::block_hash, nano::block_hash>> const &);
confirm_req (nano::block_hash const &, nano::block_hash const &);
void serialize (nano::stream &) const override;
bool deserialize (nano::stream &, nano::block_uniquer * = nullptr);
void visit (nano::message_visitor &) const override;
bool operator== (nano::confirm_req const &) const;
std::shared_ptr<nano::block> block;
std::vector<std::pair<nano::block_hash, nano::block_hash>> roots_hashes;
std::string roots_string () const;
static size_t size (nano::block_type, size_t = 0);
};
class confirm_ack final : public message
{
public:
confirm_ack (bool &, nano::stream &, nano::message_header const &, nano::vote_uniquer * = nullptr);
explicit confirm_ack (std::shared_ptr<nano::vote>);
void serialize (nano::stream &) const override;
void visit (nano::message_visitor &) const override;
bool operator== (nano::confirm_ack const &) const;
std::shared_ptr<nano::vote> vote;
static size_t size (nano::block_type, size_t = 0);
};
class frontier_req final : public message
{
public:
frontier_req ();
frontier_req (bool &, nano::stream &, nano::message_header const &);
void serialize (nano::stream &) const override;
bool deserialize (nano::stream &);
void visit (nano::message_visitor &) const override;
bool operator== (nano::frontier_req const &) const;
nano::account start;
uint32_t age;
uint32_t count;
static size_t constexpr size = sizeof (start) + sizeof (age) + sizeof (count);
};
class bulk_pull final : public message
{
public:
using count_t = uint32_t;
bulk_pull ();
bulk_pull (bool &, nano::stream &, nano::message_header const &);
void serialize (nano::stream &) const override;
bool deserialize (nano::stream &);
void visit (nano::message_visitor &) const override;
nano::uint256_union start;
nano::block_hash end;
count_t count;
bool is_count_present () const;
void set_count_present (bool);
static size_t constexpr count_present_flag = nano::message_header::bulk_pull_count_present_flag;
static size_t constexpr extended_parameters_size = 8;
static size_t constexpr size = sizeof (start) + sizeof (end);
};
class bulk_pull_account final : public message
{
public:
bulk_pull_account ();
bulk_pull_account (bool &, nano::stream &, nano::message_header const &);
void serialize (nano::stream &) const override;
bool deserialize (nano::stream &);
void visit (nano::message_visitor &) const override;
nano::uint256_union account;
nano::uint128_union minimum_amount;
bulk_pull_account_flags flags;
static size_t constexpr size = sizeof (account) + sizeof (minimum_amount) + sizeof (bulk_pull_account_flags);
};
class bulk_push final : public message
{
public:
bulk_push ();
explicit bulk_push (nano::message_header const &);
void serialize (nano::stream &) const override;
bool deserialize (nano::stream &);
void visit (nano::message_visitor &) const override;
};
class node_id_handshake final : public message
{
public:
node_id_handshake (bool &, nano::stream &, nano::message_header const &);
node_id_handshake (boost::optional<nano::block_hash>, 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;
size_t size () const;
static size_t size (nano::message_header const &);
};
class message_visitor
{
public:
virtual void keepalive (nano::keepalive const &) = 0;
virtual void publish (nano::publish const &) = 0;
virtual void confirm_req (nano::confirm_req const &) = 0;
virtual void confirm_ack (nano::confirm_ack const &) = 0;
virtual void bulk_pull (nano::bulk_pull const &) = 0;
virtual void bulk_pull_account (nano::bulk_pull_account const &) = 0;
virtual void bulk_push (nano::bulk_push const &) = 0;
virtual void frontier_req (nano::frontier_req const &) = 0;
virtual void node_id_handshake (nano::node_id_handshake const &) = 0;
virtual ~message_visitor ();
};
/** Helper guard which contains all the necessary purge (remove all memory even if used) functions */
class node_singleton_memory_pool_purge_guard
{
public:
node_singleton_memory_pool_purge_guard ();
private:
nano::cleanup_guard cleanup_guard;
};
}