Fabcoin Core  0.16.2
P2P Digital Currency
NodeTable.h
Go to the documentation of this file.
1 /*
2  This file is part of cpp-ethereum.
3 
4  cpp-ethereum is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  cpp-ethereum is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16  */
22 #pragma once
23 
24 #include <algorithm>
25 #include <deque>
26 
27 #include <boost/integer/static_log2.hpp>
28 
29 #include <libp2p/UDP.h>
30 #include "Common.h"
31 
32 namespace dev
33 {
34 namespace p2p
35 {
36 
41 struct NodeEntry: public Node
42 {
43  NodeEntry(NodeID const& _src, Public const& _pubk, NodeIPEndpoint const& _gw);
44  unsigned const distance;
45  bool pending = true;
46 };
47 
49 {
52 };
53 
54 class NodeTable;
56 {
57  friend class NodeTable;
58 public:
59  virtual void processEvent(NodeID const& _n, NodeTableEventType const& _e) = 0;
60 
61 protected:
64  {
65  std::list<std::pair<NodeID, NodeTableEventType>> events;
66  {
67  Guard l(x_events);
68  if (!m_nodeEventHandler.size())
69  return;
70  m_nodeEventHandler.unique();
71  for (auto const& n: m_nodeEventHandler)
72  events.push_back(std::make_pair(n,m_events[n]));
73  m_nodeEventHandler.clear();
74  m_events.clear();
75  }
76  for (auto const& e: events)
77  processEvent(e.first, e.second);
78  }
79 
81  virtual void appendEvent(NodeID _n, NodeTableEventType _e) { Guard l(x_events); m_nodeEventHandler.push_back(_n); m_events[_n] = _e; }
82 
84  std::list<NodeID> m_nodeEventHandler;
85  std::unordered_map<NodeID, NodeTableEventType> m_events;
86 };
87 
88 class NodeTable;
89 inline std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable);
90 
121 class NodeTable: UDPSocketEvents, public std::enable_shared_from_this<NodeTable>
122 {
123  friend std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable);
126  using NodeIdTimePoint = std::pair<NodeID, TimePoint>;
127  using EvictionTimeout = std::pair<NodeIdTimePoint, NodeID>;
128 
129 public:
130  enum NodeRelation { Unknown = 0, Known };
131  enum DiscoverType { Random = 0 };
132 
134  NodeTable(ba::io_service& _io, KeyPair const& _alias, NodeIPEndpoint const& _endpoint, bool _enabled = true);
135  ~NodeTable();
136 
138  static unsigned distance(NodeID const& _a, NodeID const& _b) { u256 d = sha3(_a) ^ sha3(_b); unsigned ret; for (ret = 0; d >>= 1; ++ret) {}; return ret; }
139 
141  void setEventHandler(NodeTableEventHandler* _handler) { m_nodeEventHandler.reset(_handler); }
142 
144  void processEvents();
145 
147  std::shared_ptr<NodeEntry> addNode(Node const& _node, NodeRelation _relation = NodeRelation::Unknown);
148 
150  std::list<NodeID> nodes() const;
151 
153  unsigned count() const { return m_nodes.size(); }
154 
156  std::list<NodeEntry> snapshot() const;
157 
159  bool haveNode(NodeID const& _id) { Guard l(x_nodes); return m_nodes.count(_id) > 0; }
160 
162  Node node(NodeID const& _id);
163 
164 #if defined(BOOST_AUTO_TEST_SUITE) || defined(_MSC_VER) // MSVC includes access specifier in symbol name
165 protected:
166 #else
167 private:
168 #endif
169 
171 
172  static unsigned const s_addressByteSize = h256::size;
173  static unsigned const s_bits = 8 * s_addressByteSize;
174  static unsigned const s_bins = s_bits - 1;
175  static unsigned const s_maxSteps = boost::static_log2<s_bits>::value;
176 
178 
179  static unsigned const s_bucketSize = 16;
180  static unsigned const s_alpha = 3;
181 
183 
184  /* todo: replace boost::posix_time; change constants to upper camelcase */
185  std::chrono::milliseconds const c_evictionCheckInterval = std::chrono::milliseconds(75);
186  std::chrono::milliseconds const c_reqTimeout = std::chrono::milliseconds(300);
187  std::chrono::milliseconds const c_bucketRefresh = std::chrono::milliseconds(7200);
188 
189  struct NodeBucket
190  {
191  unsigned distance;
192  std::list<std::weak_ptr<NodeEntry>> nodes;
193  };
194 
196  void ping(NodeIPEndpoint _to) const;
197 
199  void ping(NodeEntry* _n) const;
200 
202  NodeEntry center() const { return NodeEntry(m_node.id, m_node.publicKey(), m_node.endpoint); }
203 
205  std::shared_ptr<NodeEntry> nodeEntry(NodeID _id);
206 
209  void doDiscover(NodeID _target, unsigned _round = 0, std::shared_ptr<std::set<std::shared_ptr<NodeEntry>>> _tried = std::shared_ptr<std::set<std::shared_ptr<NodeEntry>>>());
210 
212  std::vector<std::shared_ptr<NodeEntry>> nearestNodeEntries(NodeID _target);
213 
215  void evict(std::shared_ptr<NodeEntry> _leastSeen, std::shared_ptr<NodeEntry> _new);
216 
218  void noteActiveNode(Public const& _pubk, bi::udp::endpoint const& _endpoint);
219 
221  void dropNode(std::shared_ptr<NodeEntry> _n);
222 
225  // TODO p2p: Remove this method after removing offset-by-one functionality.
226  NodeBucket& bucket_UNSAFE(NodeEntry const* _n);
227 
229 
231  void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet);
232 
235 
237 
239  void doCheckEvictions();
240 
242  void doDiscovery();
243 
244  std::unique_ptr<NodeTableEventHandler> m_nodeEventHandler;
245 
248 
249  mutable Mutex x_nodes;
250  std::unordered_map<NodeID, std::shared_ptr<NodeEntry>> m_nodes;
251 
252  mutable Mutex x_state;
253  std::array<NodeBucket, s_bins> m_state;
254 
256  std::deque<EvictionTimeout> m_evictions;
257 
259  std::unordered_map<bi::address, TimePoint> m_pubkDiscoverPings;
260 
262  std::list<NodeIdTimePoint> m_findNodeTimeout;
263 
264  std::shared_ptr<NodeSocket> m_socket;
266 
268 };
269 
270 inline std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable)
271 {
272  _out << _nodeTable.center().address() << "\t" << "0\t" << _nodeTable.center().endpoint.address << ":" << _nodeTable.center().endpoint.udpPort << std::endl;
273  auto s = _nodeTable.snapshot();
274  for (auto n: s)
275  _out << n.address() << "\t" << n.distance << "\t" << n.endpoint.address << ":" << n.endpoint.udpPort << std::endl;
276  return _out;
277 }
278 
280 {
282  DiscoveryDatagram(bi::udp::endpoint const& _to): RLPXDatagramFace(_to), ts(futureFromEpoch(std::chrono::seconds(60))) {}
283 
285  DiscoveryDatagram(bi::udp::endpoint const& _from, NodeID const& _fromid, h256 const& _echo): RLPXDatagramFace(_from), sourceid(_fromid), echo(_echo) {}
286 
287  // These two are set for inbound packets only.
288  NodeID sourceid; // sender public key (from signature)
289  h256 echo; // hash of encoded packet, for reply tracking
290 
291  // All discovery packets carry a timestamp, which must be greater
292  // than the current local time. This prevents replay attacks.
293  uint32_t ts = 0;
294  bool isExpired() const { return secondsSinceEpoch() > ts; }
295 
297  static std::unique_ptr<DiscoveryDatagram> interpretUDP(bi::udp::endpoint const& _from, bytesConstRef _packet);
298 };
299 
310 {
312  PingNode(NodeIPEndpoint const& _src, NodeIPEndpoint const& _dest): DiscoveryDatagram(_dest), source(_src), destination(_dest) {}
313  PingNode(bi::udp::endpoint const& _from, NodeID const& _fromid, h256 const& _echo): DiscoveryDatagram(_from, _fromid, _echo) {}
314 
315  static const uint8_t type = 1;
316  uint8_t packetType() const { return type; }
317 
318  unsigned version = 0;
321 
322  void streamRLP(RLPStream& _s) const
323  {
324  _s.appendList(4);
326  source.streamRLP(_s);
327  destination.streamRLP(_s);
328  _s << ts;
329  }
331  {
333  version = r[0].toInt<unsigned>();
334  source.interpretRLP(r[1]);
335  destination.interpretRLP(r[2]);
336  ts = r[3].toInt<uint32_t>();
337  }
338 };
339 
344 {
345  Pong(NodeIPEndpoint const& _dest): DiscoveryDatagram((bi::udp::endpoint)_dest), destination(_dest) {}
346  Pong(bi::udp::endpoint const& _from, NodeID const& _fromid, h256 const& _echo): DiscoveryDatagram(_from, _fromid, _echo) {}
347 
348  static const uint8_t type = 2;
349  uint8_t packetType() const { return type; }
350 
352 
353  void streamRLP(RLPStream& _s) const
354  {
355  _s.appendList(3);
356  destination.streamRLP(_s);
357  _s << echo;
358  _s << ts;
359  }
361  {
363  destination.interpretRLP(r[0]);
364  echo = (h256)r[1];
365  ts = r[2].toInt<uint32_t>();
366  }
367 };
368 
382 {
383  FindNode(bi::udp::endpoint _to, h512 _target): DiscoveryDatagram(_to), target(_target) {}
384  FindNode(bi::udp::endpoint const& _from, NodeID const& _fromid, h256 const& _echo): DiscoveryDatagram(_from, _fromid, _echo) {}
385 
386  static const uint8_t type = 3;
387  uint8_t packetType() const { return type; }
388 
390 
391  void streamRLP(RLPStream& _s) const
392  {
393  _s.appendList(2); _s << target << ts;
394  }
396  {
398  target = r[0].toHash<h512>();
399  ts = r[1].toInt<uint32_t>();
400  }
401 };
402 
407 {
408  Neighbours(bi::udp::endpoint _to, std::vector<std::shared_ptr<NodeEntry>> const& _nearest, unsigned _offset = 0, unsigned _limit = 0): DiscoveryDatagram(_to)
409  {
410  auto limit = _limit ? std::min(_nearest.size(), (size_t)(_offset + _limit)) : _nearest.size();
411  for (auto i = _offset; i < limit; i++)
412  neighbours.push_back(Neighbour(*_nearest[i]));
413  }
414  Neighbours(bi::udp::endpoint const& _to): DiscoveryDatagram(_to) {}
415  Neighbours(bi::udp::endpoint const& _from, NodeID const& _fromid, h256 const& _echo): DiscoveryDatagram(_from, _fromid, _echo) {}
416 
417  struct Neighbour
418  {
419  Neighbour(Node const& _node): endpoint(_node.endpoint), node(_node.id) {}
420  Neighbour(RLP const& _r): endpoint(_r) { node = h512(_r[3].toBytes()); }
423  void streamRLP(RLPStream& _s) const { _s.appendList(4); endpoint.streamRLP(_s, NodeIPEndpoint::StreamInline); _s << node; }
424  };
425 
426  static const uint8_t type = 4;
427  uint8_t packetType() const { return type; }
428 
429  std::vector<Neighbour> neighbours;
430 
431  void streamRLP(RLPStream& _s) const
432  {
433  _s.appendList(2);
434  _s.appendList(neighbours.size());
435  for (auto const& n: neighbours)
436  n.streamRLP(_s);
437  _s << ts;
438  }
440  {
442  for (auto const& n: r[0])
443  neighbours.emplace_back(n);
444  ts = r[1].toInt<uint32_t>();
445  }
446 };
447 
448 struct NodeTableWarn: public LogChannel { static const char* name(); static const int verbosity = 0; };
449 struct NodeTableNote: public LogChannel { static const char* name(); static const int verbosity = 1; };
450 struct NodeTableMessageSummary: public LogChannel { static const char* name(); static const int verbosity = 2; };
451 struct NodeTableMessageDetail: public LogChannel { static const char* name(); static const int verbosity = 5; };
452 struct NodeTableConnect: public LogChannel { static const char* name(); static const int verbosity = 10; };
453 struct NodeTableEvent: public LogChannel { static const char* name(); static const int verbosity = 10; };
454 struct NodeTableTimer: public LogChannel { static const char* name(); static const int verbosity = 10; };
455 struct NodeTableUpdate: public LogChannel { static const char* name(); static const int verbosity = 10; };
456 struct NodeTableTriviaSummary: public LogChannel { static const char* name(); static const int verbosity = 10; };
457 struct NodeTableTriviaDetail: public LogChannel { static const char* name(); static const int verbosity = 11; };
458 struct NodeTableAllDetail: public LogChannel { static const char* name(); static const int verbosity = 13; };
459 struct NodeTableEgress: public LogChannel { static const char* name(); static const int verbosity = 14; };
460 struct NodeTableIngress: public LogChannel { static const char* name(); static const int verbosity = 15; };
461 
462 }
463 }
void setEventHandler(NodeTableEventHandler *_handler)
Set event handler for NodeEntryAdded and NodeEntryDropped events.
Definition: NodeTable.h:141
union node node
void streamRLP(RLPStream &_s, RLPAppend _append=StreamList) const
Definition: Common.cpp:155
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
std::list< NodeIdTimePoint > m_findNodeTimeout
Timeouts for pending Ping and FindNode requests.
Definition: NodeTable.h:262
NodeEntry.
Definition: NodeTable.h:41
bi::address address
Definition: Common.h:209
void interpretRLP(RLP const &_r)
Definition: Common.cpp:168
void streamRLP(RLPStream &_s) const
Definition: NodeTable.h:353
Neighbours(bi::udp::endpoint const &_from, NodeID const &_fromid, h256 const &_echo)
Definition: NodeTable.h:415
std::pair< NodeIdTimePoint, NodeID > EvictionTimeout
First NodeID (NodeIdTimePoint) may be evicted and replaced with second NodeID.
Definition: NodeTable.h:127
NodeIPEndpoint destination
Definition: NodeTable.h:320
PingNode(bi::udp::endpoint const &_from, NodeID const &_fromid, h256 const &_echo)
Definition: NodeTable.h:313
void interpretRLP(bytesConstRef _bytes)
Definition: NodeTable.h:395
Node m_node
This node. LOCK x_state if endpoint access or mutation is required. Do not modify id...
Definition: NodeTable.h:246
UDP Interface Handler must implement UDPSocketEvents.
Definition: UDP.h:107
Simple class that represents a "key pair".
Definition: Common.h:150
void interpretRLP(bytesConstRef _bytes)
Definition: NodeTable.h:360
std::unordered_map< NodeID, NodeTableEventType > m_events
Definition: NodeTable.h:85
NodeEntry center() const
Returns center node entry which describes this node and used with dist() to calculate xor metric for ...
Definition: NodeTable.h:202
std::chrono::steady_clock::time_point TimePoint
Steady time point.
Definition: NodeTable.h:125
uint8_t packetType() const
Definition: NodeTable.h:387
std::unordered_map< bi::address, TimePoint > m_pubkDiscoverPings
List of pending pings where node entry wasn&#39;t created due to unkown pubk.
Definition: NodeTable.h:259
std::pair< NodeID, TimePoint > NodeIdTimePoint
Definition: NodeTable.h:126
std::hash for asio::adress
Definition: Common.h:323
NodeTableEventType
Definition: NodeTable.h:48
bool pending
Node will be ignored until Pong is received.
Definition: NodeTable.h:45
const unsigned c_protocolVersion
Peer network protocol version.
Definition: Common.cpp:28
NodeSocket * m_socketPointer
Set to m_socket.get(). Socket is created in constructor and disconnected in destructor to ensure acce...
Definition: NodeTable.h:265
IPv4,UDP/TCP endpoints.
Definition: Common.h:175
ExecStats::duration min
Definition: ExecStats.cpp:35
FixedHash< 64 > h512
Definition: FixedHash.h:339
std::list< NodeID > m_nodeEventHandler
Definition: NodeTable.h:84
unsigned const distance
Node&#39;s distance (xor of _src as integer).
Definition: NodeTable.h:44
FindNode(bi::udp::endpoint const &_from, NodeID const &_fromid, h256 const &_echo)
Definition: NodeTable.h:384
void version()
Definition: main.cpp:53
static unsigned distance(NodeID const &_a, NodeID const &_b)
Returns distance based on xor metric two node ids. Used by NodeEntry and NodeTable.
Definition: NodeTable.h:138
Mutex x_pubkDiscoverPings
LOCK x_nodes first if both x_nodes and x_pubkDiscoverPings locks are required.
Definition: NodeTable.h:258
_N toHash(int _flags=Strict) const
Definition: RLP.h:298
const char * source
Definition: rpcconsole.cpp:60
std::list< std::weak_ptr< NodeEntry > > nodes
Definition: NodeTable.h:192
NodeIPEndpoint source
Definition: NodeTable.h:319
Ping packet: Sent to check if node is alive.
Definition: NodeTable.h:309
Pong(bi::udp::endpoint const &_from, NodeID const &_fromid, h256 const &_echo)
Definition: NodeTable.h:346
std::lock_guard< std::mutex > Guard
Definition: Guards.h:41
const char * name
Definition: rest.cpp:36
void interpretRLP(bytesConstRef _bytes)
Definition: NodeTable.h:330
void streamRLP(RLPStream &_s) const
Definition: NodeTable.h:423
void processEvents()
Called by NodeTable on behalf of an implementation (Host) to process new events without blocking node...
Definition: NodeTable.h:63
NodeTable using modified kademlia for node discovery and preference.
Definition: NodeTable.h:121
std::shared_ptr< NodeSocket > m_socket
Shared pointer for our UDPSocket; ASIO requires shared_ptr.
Definition: NodeTable.h:264
uint8_t packetType() const
Definition: NodeTable.h:316
PingNode(NodeIPEndpoint const &_src, NodeIPEndpoint const &_dest)
Definition: NodeTable.h:312
RLPStream & appendList(size_t _items)
Appends a list.
Definition: RLP.cpp:276
Mutex x_evictions
LOCK x_evictions first if both x_nodes and x_evictions locks are required.
Definition: NodeTable.h:255
NodeID id
Definition: Common.h:254
Mutex x_nodes
LOCK x_state first if both locks are required. Mutable for thread-safe copy in nodes() const...
Definition: NodeTable.h:249
FixedHash< 32 > h256
Definition: FixedHash.h:340
RLPX Datagram which can be signed.
Definition: UDP.h:66
UniValue ping(const JSONRPCRequest &request)
Definition: net.cpp:45
bool haveNode(NodeID const &_id)
Returns true if node id is in node table.
Definition: NodeTable.h:159
DiscoveryDatagram(bi::udp::endpoint const &_to)
Constructor used for sending.
Definition: NodeTable.h:282
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void >> u256
Definition: Common.h:125
Pong(NodeIPEndpoint const &_dest)
Definition: NodeTable.h:345
std::unique_ptr< NodeTableEventHandler > m_nodeEventHandler
Event handler for node events.
Definition: NodeTable.h:244
std::vector< Neighbour > neighbours
Definition: NodeTable.h:429
DeadlineOps m_timers
this should be the last member - it must be destroyed first
Definition: NodeTable.h:267
PlatformStyle::TableColorType type
Definition: rpcconsole.cpp:61
virtual NodeID const & address() const
Definition: Common.h:248
void streamRLP(RLPStream &_s) const
Definition: NodeTable.h:431
Secret m_secret
This nodes secret key.
Definition: NodeTable.h:247
FindNode(bi::udp::endpoint _to, h512 _target)
Definition: NodeTable.h:383
clock::time_point time_point
Definition: bench.h:49
bool sha3(bytesConstRef _input, bytesRef o_output)
Calculate SHA3-256 hash of the given input and load it into the given output.
Definition: SHA3.cpp:214
DiscoveryDatagram(bi::udp::endpoint const &_from, NodeID const &_fromid, h256 const &_echo)
Constructor used for parsing inbound packets.
Definition: NodeTable.h:285
unsigned count() const
Returns node count.
Definition: NodeTable.h:153
void interpretRLP(bytesConstRef _bytes)
Definition: NodeTable.h:439
uint8_t packetType() const
Definition: NodeTable.h:427
#define e(i)
Definition: sha.cpp:733
The default logging channels.
Definition: Log.h:130
Neighbours(bi::udp::endpoint const &_to)
Definition: NodeTable.h:414
void streamRLP(RLPStream &_s) const
Definition: NodeTable.h:391
std::array< NodeBucket, s_bins > m_state
State of p2p node network.
Definition: NodeTable.h:253
Interface which UDPSocket will implement.
Definition: UDP.h:84
#define d(i)
Definition: sha.cpp:732
std::mutex Mutex
Definition: Guards.h:37
Neighbour(Node const &_node)
Definition: NodeTable.h:419
Pong packet: Sent in response to ping.
Definition: NodeTable.h:343
void onDisconnected(UDPSocketFace *)
Called by m_socket when socket is disconnected.
Definition: NodeTable.h:234
uint8_t packetType() const
Definition: NodeTable.h:349
std::ostream & operator<<(std::ostream &_out, NodeTable const &_nodeTable)
Definition: NodeTable.h:270
_T toInt(int _flags=Strict) const
Converts to int of type given; if isString(), decodes as big-endian bytestream.
Definition: RLP.h:275
Class for writing to an RLP bytestream.
Definition: RLP.h:383
virtual void appendEvent(NodeID _n, NodeTableEventType _e)
Called by NodeTable to append event.
Definition: NodeTable.h:81
UniValue echo(const JSONRPCRequest &request)
Definition: misc.cpp:639
Class for interpreting Recursive Linear-Prefix Data.
Definition: RLP.h:64
Neighbours(bi::udp::endpoint _to, std::vector< std::shared_ptr< NodeEntry >> const &_nearest, unsigned _offset=0, unsigned _limit=0)
Definition: NodeTable.h:408
NodeIPEndpoint destination
Definition: NodeTable.h:351
Mutex x_state
LOCK x_state first if both x_nodes and x_state locks are required.
Definition: NodeTable.h:252
FindNode Packet: Request k-nodes, closest to the target.
Definition: NodeTable.h:381
std::list< NodeEntry > snapshot() const
Returns snapshot of table.
Definition: NodeTable.cpp:127
std::unordered_map< NodeID, std::shared_ptr< NodeEntry > > m_nodes
Known Node Endpoints.
Definition: NodeTable.h:250
NodeEntry(NodeID const &_src, Public const &_pubk, NodeIPEndpoint const &_gw)
Definition: NodeTable.cpp:41
std::deque< EvictionTimeout > m_evictions
Eviction timeouts.
Definition: NodeTable.h:256
Node Packet: One or more node packets are sent in response to FindNode.
Definition: NodeTable.h:406
Definition: internal.h:25
NodeIPEndpoint endpoint
Endpoints by which we expect to reach node.
Definition: Common.h:258
Interface which a UDPSocket&#39;s owner must implement.
Definition: UDP.h:93
void streamRLP(RLPStream &_s) const
Definition: NodeTable.h:322