TARAXA
|
#include <NodeTable.h>
Classes | |
struct | NodeBucket |
struct | NodeValidation |
Public Member Functions | |
NodeTable (ba::io_context &_io, KeyPair const &_alias, NodeIPEndpoint const &_endpoint, ENR const &_enr, bool _enabled=true, bool _allowLocalDiscovery=false, bool is_boot_node=false, uint32_t chain_id=0) | |
~NodeTable () | |
void | setEventHandler (NodeTableEventHandler *_handler) |
Set event handler for NodeEntryAdded and NodeEntryDropped events. More... | |
void | processEvents () |
bool | addNode (Node const &_node) |
bool | addKnownNode (Node const &_node, uint32_t _lastPongReceivedTime, uint32_t _lastPongSentTime) |
std::list< NodeID > | nodes () const |
Returns list of node ids active in node table. More... | |
unsigned | count () const |
Returns node count. More... | |
std::list< NodeEntry > | snapshot () const |
Returns snapshot of table. More... | |
bool | haveNode (NodeID const &_id) |
Returns true if node id is in node table. More... | |
Node | node (NodeID const &_id) |
void | invalidateNode (NodeID const &_id) |
ENR | hostENR () const |
void | runBackgroundTask (std::chrono::milliseconds const &_period, std::shared_ptr< ba::steady_timer > _timer, std::function< void()> _f) |
void | cancelTimer (std::shared_ptr< ba::steady_timer > _timer) |
Static Public Member Functions | |
static int | distance (h256 const &_a, h256 const &_b) |
Static Public Attributes | |
static constexpr uint32_t | c_bondingTimeSeconds {12 * 60 * 60} |
Protected Member Functions | |
bool | isValidNode (Node const &_node) const |
void | ping (Node const &_node, std::shared_ptr< NodeEntry > _replacementNodeEntry={}) |
void | schedulePing (Node const &_node) |
std::shared_ptr< NodeEntry > | nodeEntry (NodeID const &_id) |
void | doDiscoveryRound (NodeID _target, unsigned _round, std::shared_ptr< std::set< std::shared_ptr< NodeEntry >>> _tried) |
std::vector< std::shared_ptr< NodeEntry > > | nearestNodeEntries (NodeID const &_target) |
Returns s_bucketSize nodes from node table which are closest to target. More... | |
void | evict (NodeEntry const &_leastSeen, std::shared_ptr< NodeEntry > _replacement) |
void | noteActiveNode (std::shared_ptr< NodeEntry > _nodeEntry) |
void | dropNode (std::shared_ptr< NodeEntry > _n) |
NodeBucket & | bucket_UNSAFE (NodeEntry const *_n) |
void | onPacketReceived (UDPSocketFace *, bi::udp::endpoint const &_from, bytesConstRef _packet) override |
General Network Events. More... | |
std::shared_ptr< NodeEntry > | handlePong (bi::udp::endpoint const &_from, DiscoveryDatagram const &_packet) |
std::shared_ptr< NodeEntry > | handleNeighbours (bi::udp::endpoint const &_from, DiscoveryDatagram const &_packet) |
std::shared_ptr< NodeEntry > | handleFindNode (bi::udp::endpoint const &_from, DiscoveryDatagram const &_packet) |
std::shared_ptr< NodeEntry > | handlePingNode (bi::udp::endpoint const &_from, DiscoveryDatagram const &_packet) |
std::shared_ptr< NodeEntry > | handleENRRequest (bi::udp::endpoint const &_from, DiscoveryDatagram const &_packet) |
std::shared_ptr< NodeEntry > | handleENRResponse (bi::udp::endpoint const &_from, DiscoveryDatagram const &_packet) |
void | onSocketDisconnected (UDPSocketFace *) override |
Called by m_socket when socket is disconnected. More... | |
void | doDiscovery () |
Tasks. More... | |
void | doHandleTimeouts () |
void | doEndpointTracking () |
uint32_t | nextRequestExpirationTime () const |
bool | isAllowedEndpoint (NodeIPEndpoint const &_endpointToCheck) const |
NodeIPEndpoint | getSourceEndpoint (bi::udp::endpoint const &from, PingNode const &packet) |
Protected Attributes | |
unsigned | s_bucketSize = NODE_BUCKET_SIZE |
ba::strand< ba::io_context::executor_type > | strand_ |
std::unique_ptr< NodeTableEventHandler > | m_nodeEventHandler |
Event handler for node events. More... | |
const NodeID | m_hostNodeID |
const h256 | m_hostNodeIDHash |
const bool | m_allowLocalDiscovery |
bi::address const | m_hostStaticIP |
NodeIPEndpoint | m_hostNodeEndpoint |
ENR | m_hostENR |
Mutex | m_hostENRMutex |
Secret | m_secret |
This nodes secret key. More... | |
Mutex | x_nodes |
std::unordered_map< NodeID, std::shared_ptr< NodeEntry > > | m_allNodes |
Mutex | x_state |
std::unordered_map< NodeID, bi::udp::endpoint > | m_id2IpMap |
This map is used for maping between node id and real network IP. More... | |
std::unordered_map< bi::udp::endpoint, NodeIPEndpoint > | m_ipMappings |
This map keeps tracking between real IP and IP reported by node (external IP) More... | |
Mutex | x_ips |
std::array< NodeBucket, s_bins > | m_buckets |
std::list< NodeIdTimePoint > | m_sentFindNodes |
Timeouts for FindNode requests. More... | |
std::shared_ptr< NodeSocket > | m_socket |
std::unordered_map< bi::udp::endpoint, NodeValidation > | m_sentPings |
const std::chrono::seconds | m_requestTimeToLive |
Logger | m_logger {createLogger(VerbosityDebug, "discov")} |
EndpointTracker | m_endpointTracker |
std::shared_ptr< ba::steady_timer > | m_discoveryTimer |
std::shared_ptr< ba::steady_timer > | m_timeoutsTimer |
std::shared_ptr< ba::steady_timer > | m_endpointTrackingTimer |
const bool | is_boot_node_ = false |
const uint32_t | chain_id_ = 0 |
Static Protected Attributes | |
static constexpr unsigned | s_addressByteSize = h256::size |
Constants for Kademlia, derived from address space. More... | |
static constexpr unsigned | s_bits = 8 * s_addressByteSize |
Denoted by n in [Kademlia]. More... | |
static constexpr unsigned | s_bins = s_bits - 1 |
Size of m_buckets (excludes root, which is us). More... | |
static constexpr unsigned | s_maxSteps = boost::static_log2<s_bits>::value |
static constexpr size_t | BOOT_NODE_BUCKET_SIZE = 256 |
Chosen constants. More... | |
static constexpr size_t | NODE_BUCKET_SIZE = 16 |
static constexpr unsigned | s_alpha = 3 |
static constexpr std::chrono::milliseconds | c_reqTimeoutMs {600} |
Intervals. More... | |
static constexpr std::chrono::milliseconds | c_discoveryRoundIntervalMs {c_reqTimeoutMs * 2} |
How long to wait before starting a new discovery round. More... | |
static constexpr std::chrono::milliseconds | c_bucketRefreshMs {7200} |
Refresh interval prevents bucket from becoming stale. [Kademlia]. More... | |
Private Types | |
using | NodeSocket = UDPSocket< NodeTable, 1280 > |
using | TimePoint = std::chrono::steady_clock::time_point |
Steady time point. More... | |
using | NodeIdTimePoint = std::pair< NodeID, TimePoint > |
Friends | |
std::ostream & | operator<< (std::ostream &_out, NodeTable const &_nodeTable) |
Additional Inherited Members | |
Private Member Functions inherited from dev::p2p::UDPSocketEvents | |
virtual | ~UDPSocketEvents ()=default |
NodeTable using modified kademlia for node discovery and preference. Node table requires an IO service, creates a socket for incoming UDP messages and implements a kademlia-like protocol. Node requests and responses are used to build a node table which can be queried to obtain a list of potential nodes to connect to, and, passes events to Host whenever a node is added or removed to/from the table.
Thread-safety is ensured by modifying NodeEntry details via shared_ptr replacement instead of mutating values.
NodeTable accepts a port for UDP and will listen to the port on all available interfaces.
[Optimization]
serialize evictions per-bucket
store evictions in map, unit-test eviction logic
store root node in table
encapsulate discover into NetworkAlgorithm (task)
expiration and sha3(id) 'to' for messages which are replies (prevents replay)
cache Ping and FindSelf
[Networking]
eth/upnp/natpmp/stun/ice/etc for public-discovery
firewall
[Protocol]
optimize knowledge at opposite edges; eg, s_bitsPerStep lookups. (Can be done via pointers to NodeBucket)
^ s_bitsPerStep = 8; // Denoted by b in [Kademlia]. Bits by which address space is divided.
struct dev::p2p::NodeTable::NodeBucket |
Class Members | ||
---|---|---|
unsigned | distance | |
list< weak_ptr< NodeEntry > > | nodes |
|
private |
|
private |
|
private |
Steady time point.
dev::p2p::NodeTable::NodeTable | ( | ba::io_context & | _io, |
KeyPair const & | _alias, | ||
NodeIPEndpoint const & | _endpoint, | ||
ENR const & | _enr, | ||
bool | _enabled = true , |
||
bool | _allowLocalDiscovery = false , |
||
bool | is_boot_node = false , |
||
uint32_t | chain_id = 0 |
||
) |
Constructor requiring host for I/O, credentials, and IP Address, port to listen on and host ENR.
|
inline |
bool dev::p2p::NodeTable::addKnownNode | ( | Node const & | _node, |
uint32_t | _lastPongReceivedTime, | ||
uint32_t | _lastPongSentTime | ||
) |
Add node to the list of all nodes and add it to the node table. In case the node's endpoint proof expired, pings it. In case the nodes is already in the node table, ignores add request.
bool dev::p2p::NodeTable::addNode | ( | Node const & | _node | ) |
Starts async node add to the node table by pinging it to trigger the endpoint proof. In case the node is already in the node table, pings only if the endpoint proof expired.
|
protected |
Returns references to bucket which corresponds to distance of node id.
void dev::p2p::NodeTable::cancelTimer | ( | std::shared_ptr< ba::steady_timer > | _timer | ) |
|
inline |
Returns node count.
|
protected |
Tasks.
Looks up a random node at @c_bucketRefresh interval.
|
protected |
Used to discovery nodes on network which are close to the given target. Sends s_alpha concurrent requests to nodes nearest to target, for nodes nearest to target, up to s_maxSteps rounds.
|
protected |
|
protected |
Clear timed-out pings and drop nodes from the node table which haven't responded to ping and bring in their replacements
|
protected |
Used to drop node when timeout occurs or when evict() result is to keep previous node.
|
protected |
Asynchronously drops _leastSeen node if it doesn't reply and adds _replacement node, otherwise _replacement is thrown away.
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
inline |
Returns true if node id is in node table.
|
inline |
void dev::p2p::NodeTable::invalidateNode | ( | NodeID const & | _id | ) |
|
inlineprotected |
Determines if a node with the supplied endpoint is allowed to participate in discovery.
|
protected |
|
protected |
Returns s_bucketSize nodes from node table which are closest to target.
|
inlineprotected |
Used by asynchronous operations to return NodeEntry which is active and managed by node table.
std::list< NodeID > dev::p2p::NodeTable::nodes | ( | ) | const |
Returns list of node ids active in node table.
|
protected |
Called whenever activity is received from a node in order to maintain node table. Only called for nodes for which we've completed an endpoint proof.
|
overrideprotectedvirtual |
General Network Events.
Called by m_socket when packet is received.
Implements dev::p2p::UDPSocketEvents.
|
inlineoverrideprotectedvirtual |
Called by m_socket when socket is disconnected.
Reimplemented from dev::p2p::UDPSocketEvents.
|
protected |
Used to ping a node to initiate the endpoint proof. Used when contacting neighbours if they don't have a valid endpoint proof (see doDiscoveryRound), refreshing buckets and as part of eviction process (see evict). Synchronous, has to be called only from the network thread.
void dev::p2p::NodeTable::processEvents | ( | ) |
Called by implementation which provided handler to process NodeEntryAdded/NodeEntryDropped events. Events are coalesced by type whereby old events are ignored.
void dev::p2p::NodeTable::runBackgroundTask | ( | std::chrono::milliseconds const & | _period, |
std::shared_ptr< ba::steady_timer > | _timer, | ||
std::function< void()> | _f | ||
) |
|
protected |
Schedules ping() method to be called from the network thread. Not synchronous - the ping operation is queued via a timer.
|
inline |
Set event handler for NodeEntryAdded and NodeEntryDropped events.
std::list< NodeEntry > dev::p2p::NodeTable::snapshot | ( | ) | const |
Returns snapshot of table.
|
friend |
|
staticconstexprprotected |
Chosen constants.
|
staticconstexpr |
|
staticconstexprprotected |
Refresh interval prevents bucket from becoming stale. [Kademlia].
|
staticconstexprprotected |
How long to wait before starting a new discovery round.
|
staticconstexprprotected |
Intervals.
How long to wait for requests (evict, find iterations).
|
protected |
|
protected |
Node endpoints. Includes all nodes that were added into node table's buckets and have not been evicted yet.
|
protected |
Allow nodes with local addresses to be included in the discovery process
|
protected |
State of p2p node network. Only includes nodes for which we've completed the endpoint proof
|
protected |
|
protected |
|
protected |
|
protected |
|
mutableprotected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
This map is used for maping between node id and real network IP.
|
protected |
This map keeps tracking between real IP and IP reported by node (external IP)
|
mutableprotected |
|
protected |
Event handler for node events.
|
protected |
|
protected |
This nodes secret key.
|
protected |
Timeouts for FindNode requests.
|
protected |
|
protected |
Shared pointer for our UDPSocket; ASIO requires shared_ptr.
|
protected |
|
staticconstexprprotected |
|
staticconstexprprotected |
Constants for Kademlia, derived from address space.
Size of address type in bytes.
|
staticconstexprprotected |
Denoted by \alpha in [Kademlia]. Number of concurrent FindNode requests.
|
staticconstexprprotected |
Size of m_buckets (excludes root, which is us).
|
staticconstexprprotected |
Denoted by n in [Kademlia].
|
protected |
Denoted by k in [Kademlia]. Number of nodes stored in each bucket.
|
staticconstexprprotected |
Max iterations of discovery. (discover)
|
protected |
|
mutableprotected |
|
mutableprotected |
LOCK x_state first if both locks are required. Mutable for thread-safe copy in nodes() const.
|
mutableprotected |
LOCK x_state first if both x_nodes and x_state locks are required.