dncurrency/nano/node/common.hpp
cryptocode bab4474274
Network selector (#1729)
* Network selector

* Make sure network option is checked before working path is called (migration). Also remove bool assignment from error.

* Formatting

* Fix merge error

* Use network_params for RPC port config (rebase)

* Formatting

* Rebase

* Rebase (debug_opencl, merge fix)

* Rebase fix

* post-rebase update
2019-03-11 16:10:33 +01:00

407 lines
12 KiB
C++

#pragma once
#include <nano/lib/config.hpp>
#include <nano/lib/interface.h>
#include <nano/secure/common.hpp>
#include <boost/asio.hpp>
#include <bitset>
#include <crypto/xxhash/xxhash.h>
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 &);
bool reserved_address (nano::endpoint const &, bool = false);
}
namespace
{
uint64_t endpoint_hash_raw (nano::endpoint const & endpoint_a)
{
assert (endpoint_a.address ().is_v6 ());
nano::uint128_union address;
address.bytes = endpoint_a.address ().to_v6 ().to_bytes ();
XXH64_state_t * const state = XXH64_createState ();
XXH64_reset (state, 0);
XXH64_update (state, address.bytes.data (), address.bytes.size ());
auto port (endpoint_a.port ());
XXH64_update (state, &port, sizeof (port));
auto result (XXH64_digest (state));
XXH64_freeState (state);
return result;
}
uint64_t endpoint_hash_raw (nano::tcp_endpoint const & endpoint_a)
{
assert (endpoint_a.address ().is_v6 ());
nano::uint128_union address;
address.bytes = endpoint_a.address ().to_v6 ().to_bytes ();
XXH64_state_t * const state = XXH64_createState ();
XXH64_reset (state, 0);
XXH64_update (state, address.bytes.data (), address.bytes.size ());
auto port (endpoint_a.port ());
XXH64_update (state, &port, sizeof (port));
auto result (XXH64_digest (state));
XXH64_freeState (state);
return result;
}
uint64_t ip_address_hash_raw (boost::asio::ip::address const & ip_a)
{
assert (ip_a.is_v6 ());
nano::uint128_union bytes;
bytes.bytes = ip_a.to_v6 ().to_bytes ();
auto result (XXH64 (bytes.bytes.data (), bytes.bytes.size (), 0));
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);
}
};
}
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
{
public:
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 version_max;
uint8_t version_using;
uint8_t version_min;
nano::message_type type;
std::bitset<16> extensions;
static size_t constexpr bulk_pull_count_present_flag = 0;
bool bulk_pull_is_count_present () 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);
};
class message
{
public:
message (nano::message_type);
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
{
std::shared_ptr<std::vector<uint8_t>> bytes (new std::vector<uint8_t>);
nano::vectorstream stream (*bytes);
serialize (stream);
return bytes;
}
nano::message_header header;
};
class work_pool;
class message_parser
{
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 : public message
{
public:
keepalive (bool &, nano::stream &, nano::message_header const &);
keepalive ();
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 : public message
{
public:
publish (bool &, nano::stream &, nano::message_header const &, nano::block_uniquer * = nullptr);
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 : public message
{
public:
confirm_req (bool &, nano::stream &, nano::message_header const &, nano::block_uniquer * = nullptr);
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;
};
class confirm_ack : public message
{
public:
confirm_ack (bool &, nano::stream &, nano::message_header const &, nano::vote_uniquer * = nullptr);
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;
};
class frontier_req : 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 : public message
{
public:
typedef uint32_t count_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 : 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 : public message
{
public:
bulk_push ();
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 : 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;
bool is_query_flag () const;
void set_query_flag (bool);
bool is_response_flag () const;
void set_response_flag (bool);
boost::optional<nano::uint256_union> query;
boost::optional<std::pair<nano::account, nano::signature>> response;
static size_t constexpr query_flag = 0;
static size_t constexpr response_flag = 1;
};
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 ();
};
/**
* Returns seconds passed since unix epoch (posix time)
*/
inline uint64_t seconds_since_epoch ()
{
return std::chrono::duration_cast<std::chrono::seconds> (std::chrono::system_clock::now ().time_since_epoch ()).count ();
}
}