Fabcoin Core  0.16.2
P2P Digital Currency
net.cpp
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 #include <boost/test/unit_test.hpp>
23 
24 #include <libdevcore/Worker.h>
25 #include <libdevcore/Assertions.h>
26 #include <libdevcrypto/Common.h>
27 #include <libp2p/UDP.h>
28 #include <libp2p/NodeTable.h>
30 
31 using namespace std;
32 using namespace dev;
33 using namespace dev::test;
34 using namespace dev::p2p;
35 namespace ba = boost::asio;
36 namespace bi = ba::ip;
37 
39 {
42 };
43 
45 
46 
49 class TestHost: public Worker
50 {
51 public:
52  TestHost(): Worker("test",0), m_io() {};
53  virtual ~TestHost() { m_io.stop(); stopWorking(); }
54  void start() { startWorking(); }
55  void doWork() { m_io.run(); }
56  void doneWorking() { m_io.reset(); m_io.poll(); m_io.reset(); }
57 
58 protected:
59  ba::io_service m_io;
60 };
61 
62 struct TestNodeTable: public NodeTable
63 {
65  TestNodeTable(ba::io_service& _io, KeyPair _alias, bi::address const& _addr, uint16_t _port = 30300): NodeTable(_io, _alias, NodeIPEndpoint(_addr, _port, _port)) {}
66 
67  static std::vector<std::pair<KeyPair,unsigned>> createTestNodes(unsigned _count)
68  {
69  std::vector<std::pair<KeyPair,unsigned>> ret;
70  asserts(_count < 1000);
71  static uint16_t s_basePort = 30500;
72 
73  ret.clear();
74  for (unsigned i = 0; i < _count; i++)
75  {
76  KeyPair k = KeyPair::create();
77  ret.push_back(make_pair(k,s_basePort+i));
78  }
79 
80  return ret;
81  }
82 
83  void pingTestNodes(std::vector<std::pair<KeyPair,unsigned>> const& _testNodes)
84  {
85  bi::address ourIp = bi::address::from_string("127.0.0.1");
86  for (auto& n: _testNodes)
87  {
88  ping(NodeIPEndpoint(ourIp, n.second, n.second));
89  this_thread::sleep_for(chrono::milliseconds(2));
90  }
91  }
92 
93  void populateTestNodes(std::vector<std::pair<KeyPair,unsigned>> const& _testNodes, size_t _count = 0)
94  {
95  if (!_count)
96  _count = _testNodes.size();
97 
98  bi::address ourIp = bi::address::from_string("127.0.0.1");
99  for (auto& n: _testNodes)
100  if (_count--)
101  {
102  // manually add node for test
103  {
104  Guard ln(x_nodes);
105  shared_ptr<NodeEntry> node(new NodeEntry(m_node.id, n.first.pub(), NodeIPEndpoint(ourIp, n.second, n.second)));
106  node->pending = false;
107  m_nodes[node->id] = node;
108  }
109  noteActiveNode(n.first.pub(), bi::udp::endpoint(ourIp, n.second));
110  }
111  else
112  break;
113  }
114 
115  void reset()
116  {
117  Guard l(x_state);
118  for (auto& n: m_state) n.nodes.clear();
119  }
120 };
121 
126 {
127  TestNodeTableHost(unsigned _count = 8): m_alias(KeyPair::create()), nodeTable(new TestNodeTable(m_io, m_alias, bi::address::from_string("127.0.0.1"))), testNodes(TestNodeTable::createTestNodes(_count)) {};
128  ~TestNodeTableHost() { m_io.stop(); stopWorking(); }
129 
130  void setup() { for (auto n: testNodes) nodeTables.push_back(make_shared<TestNodeTable>(m_io,n.first, bi::address::from_string("127.0.0.1"),n.second)); }
131 
132  void pingAll() { for (auto& t: nodeTables) t->pingTestNodes(testNodes); }
133 
134  void populateAll(size_t _count = 0) { for (auto& t: nodeTables) t->populateTestNodes(testNodes, _count); }
135 
136  void populate(size_t _count = 0) { nodeTable->populateTestNodes(testNodes, _count); }
137 
139  shared_ptr<TestNodeTable> nodeTable;
140  std::vector<std::pair<KeyPair,unsigned>> testNodes; // keypair and port
141  std::vector<shared_ptr<TestNodeTable>> nodeTables;
142 };
143 
145 {
146 public:
147  TestUDPSocket(): m_socket(new UDPSocket<TestUDPSocket, 1024>(m_io, *this, 30300)) {}
148 
150  void onReceived(UDPSocketFace*, bi::udp::endpoint const&, bytesConstRef _packet) { if (_packet.toString() == "AAAA") success = true; }
151 
152  shared_ptr<UDPSocket<TestUDPSocket, 1024>> m_socket;
153 
154  bool success = false;
155 };
156 
157 BOOST_AUTO_TEST_CASE(requestTimeout)
158 {
159  if (test::Options::get().nonetwork)
160  return;
161 
162  using TimePoint = std::chrono::steady_clock::time_point;
163  using RequestTimeout = std::pair<NodeID, TimePoint>;
164 
165  std::chrono::milliseconds timeout(300);
166  std::list<RequestTimeout> timeouts;
167 
168  NodeID nodeA(sha3("a"));
169  NodeID nodeB(sha3("b"));
170  timeouts.push_back(make_pair(nodeA, chrono::steady_clock::now()));
171  this_thread::sleep_for(std::chrono::milliseconds(100));
172  timeouts.push_back(make_pair(nodeB, chrono::steady_clock::now()));
173  this_thread::sleep_for(std::chrono::milliseconds(210));
174 
175  bool nodeAtriggered = false;
176  bool nodeBtriggered = false;
177  timeouts.remove_if([&](RequestTimeout const& t)
178  {
179  auto now = chrono::steady_clock::now();
180  auto diff = now - t.second;
181  if (t.first == nodeA && diff < timeout)
182  nodeAtriggered = true;
183  if (t.first == nodeB && diff < timeout)
184  nodeBtriggered = true;
185  return (t.first == nodeA || t.first == nodeB);
186  });
187 
188  BOOST_REQUIRE(nodeAtriggered == false);
189  BOOST_REQUIRE(nodeBtriggered == true);
190  BOOST_REQUIRE(timeouts.size() == 0);
191 }
192 
193 BOOST_AUTO_TEST_CASE(isIPAddressType)
194 {
195  string wildcard = "0.0.0.0";
196  BOOST_REQUIRE(bi::address::from_string(wildcard).is_unspecified());
197 
198  string empty = "";
199  BOOST_REQUIRE_THROW(bi::address::from_string(empty).is_unspecified(), std::exception);
200 
201  string publicAddress192 = "192.169.0.0";
202  BOOST_REQUIRE(isPublicAddress(publicAddress192));
203  BOOST_REQUIRE(!isPrivateAddress(publicAddress192));
204  BOOST_REQUIRE(!isLocalHostAddress(publicAddress192));
205 
206  string publicAddress172 = "172.32.0.0";
207  BOOST_REQUIRE(isPublicAddress(publicAddress172));
208  BOOST_REQUIRE(!isPrivateAddress(publicAddress172));
209  BOOST_REQUIRE(!isLocalHostAddress(publicAddress172));
210 
211  string privateAddress192 = "192.168.1.0";
212  BOOST_REQUIRE(isPrivateAddress(privateAddress192));
213  BOOST_REQUIRE(!isPublicAddress(privateAddress192));
214  BOOST_REQUIRE(!isLocalHostAddress(privateAddress192));
215 
216  string privateAddress172 = "172.16.0.0";
217  BOOST_REQUIRE(isPrivateAddress(privateAddress172));
218  BOOST_REQUIRE(!isPublicAddress(privateAddress172));
219  BOOST_REQUIRE(!isLocalHostAddress(privateAddress172));
220 
221  string privateAddress10 = "10.0.0.0";
222  BOOST_REQUIRE(isPrivateAddress(privateAddress10));
223  BOOST_REQUIRE(!isPublicAddress(privateAddress10));
224  BOOST_REQUIRE(!isLocalHostAddress(privateAddress10));
225 }
226 
227 BOOST_AUTO_TEST_CASE(neighboursPacketLength)
228 {
229  if (test::Options::get().nonetwork)
230  return;
231 
232  KeyPair k = KeyPair::create();
233  std::vector<std::pair<KeyPair,unsigned>> testNodes(TestNodeTable::createTestNodes(16));
234  bi::udp::endpoint to(boost::asio::ip::address::from_string("127.0.0.1"), 30000);
235 
236  // hash(32), signature(65), overhead: packetSz(3), type(1), nodeListSz(3), ts(5),
237  static unsigned const nlimit = (1280 - 109) / 90; // neighbour: 2 + 65 + 3 + 3 + 17
238  for (unsigned offset = 0; offset < testNodes.size(); offset += nlimit)
239  {
240  Neighbours out(to);
241 
242  auto limit = nlimit ? std::min(testNodes.size(), (size_t)(offset + nlimit)) : testNodes.size();
243  for (auto i = offset; i < limit; i++)
244  {
245  Node n(testNodes[i].first.pub(), NodeIPEndpoint(boost::asio::ip::address::from_string("200.200.200.200"), testNodes[i].second, testNodes[i].second));
246  Neighbours::Neighbour neighbour(n);
247  out.neighbours.push_back(neighbour);
248  }
249 
250  out.sign(k.secret());
251  BOOST_REQUIRE_LE(out.data.size(), 1280);
252  }
253 }
254 
255 BOOST_AUTO_TEST_CASE(neighboursPacket)
256 {
257  if (test::Options::get().nonetwork)
258  return;
259 
260  KeyPair k = KeyPair::create();
261  std::vector<std::pair<KeyPair,unsigned>> testNodes(TestNodeTable::createTestNodes(16));
262  bi::udp::endpoint to(boost::asio::ip::address::from_string("127.0.0.1"), 30000);
263 
264  Neighbours out(to);
265  for (auto n: testNodes)
266  {
267  Node node(n.first.pub(), NodeIPEndpoint(boost::asio::ip::address::from_string("200.200.200.200"), n.second, n.second));
268  Neighbours::Neighbour neighbour(node);
269  out.neighbours.push_back(neighbour);
270  }
271  out.sign(k.secret());
272 
273  bytesConstRef packet(out.data.data(), out.data.size());
274  auto in = DiscoveryDatagram::interpretUDP(to, packet);
275  int count = 0;
276  for (auto n: dynamic_cast<Neighbours&>(*in).neighbours)
277  {
278  BOOST_REQUIRE_EQUAL(testNodes[count].second, n.endpoint.udpPort);
279  BOOST_REQUIRE_EQUAL(testNodes[count].first.pub(), n.node);
280  BOOST_REQUIRE_EQUAL(sha3(testNodes[count].first.pub()), sha3(n.node));
281  count++;
282  }
283 }
284 
285 BOOST_AUTO_TEST_CASE(test_findnode_neighbours)
286 {
287  // Executing findNode should result in a list which is serialized
288  // into Neighbours packet. Neighbours packet should then be deserialized
289  // into the same list of nearest nodes.
290 }
291 
293 {
294  if (test::Options::get().nonetwork)
295  return;
296 
298  node.start();
299  node.setup();
300  node.populate();
301  node.populateAll();
302  auto nodes = node.nodeTable->nodes();
303  nodes.sort();
304  node.nodeTable->reset();
305  node.populate(1);
306  this_thread::sleep_for(chrono::milliseconds(2000));
307  BOOST_REQUIRE_EQUAL(node.nodeTable->count(), 8);
308 }
309 
311 {
312  if (test::Options::get().nonetwork)
313  return;
314 
315  UDPDatagram d(bi::udp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 30300), bytes({65,65,65,65}));
316  TestUDPSocket a; a.m_socket->connect(); a.start();
317  a.m_socket->send(d);
318  this_thread::sleep_for(chrono::seconds(1));
319  BOOST_REQUIRE_EQUAL(true, a.success);
320 }
321 
323 
324 BOOST_AUTO_TEST_SUITE(netTypes)
325 
326 /*
327 
328  Test disabled by Bob Summerwill on 1st Sep 2016, because it is
329  consistently failing on Ubuntu within TravisCI, and also appears
330  to be testing timing-specific behaviour within Boost code which
331  we did not author.
332 
333  See https://github.com/ethereum/cpp-ethereum/issues/3253.
334 
335  TODO - Work out why this test was written in the first place,
336  and why it has started failing. Re-add it or remove it.
337 
338 
339 BOOST_AUTO_TEST_CASE(deadlineTimer)
340 {
341  if (test::Options::get().nonetwork)
342  return;
343 
344  ba::io_service io;
345  ba::deadline_timer t(io);
346  bool start = false;
347  boost::system::error_code ec;
348  std::atomic<unsigned> fired(0);
349 
350  thread thread([&](){ while(!start) this_thread::sleep_for(chrono::milliseconds(10)); io.run(); });
351  t.expires_from_now(boost::posix_time::milliseconds(200));
352  start = true;
353  t.async_wait([&](boost::system::error_code const& _ec){ ec = _ec; fired++; });
354  BOOST_REQUIRE_NO_THROW(t.wait());
355  this_thread::sleep_for(chrono::milliseconds(250));
356  auto expire = t.expires_from_now().total_milliseconds();
357  BOOST_REQUIRE(expire <= 0);
358  BOOST_REQUIRE(fired == 1);
359  BOOST_REQUIRE(!ec);
360  io.stop();
361  thread.join();
362 }
363 */
364 
365 BOOST_AUTO_TEST_CASE(unspecifiedNode)
366 {
367  if (test::Options::get().nonetwork)
368  return;
369 
370  Node n = UnspecifiedNode;
371  BOOST_REQUIRE(!n);
372 
373  Node node(Public(sha3("0")), NodeIPEndpoint(bi::address(), 0, 0));
374  BOOST_REQUIRE(node);
375  BOOST_REQUIRE(n != node);
376 
377  Node nodeEq(Public(sha3("0")), NodeIPEndpoint(bi::address(), 0, 0));
378  BOOST_REQUIRE_EQUAL(node, nodeEq);
379 }
380 
381 BOOST_AUTO_TEST_CASE(nodeTableReturnsUnspecifiedNode)
382 {
383  if (test::Options::get().nonetwork)
384  return;
385 
386  ba::io_service io;
387  NodeTable t(io, KeyPair::create(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), 30303, 30303));
388  if (Node n = t.node(NodeID()))
389  BOOST_REQUIRE(false);
390  else
391  BOOST_REQUIRE(n == UnspecifiedNode);
392 }
393 
395 
std::vector< std::pair< KeyPair, unsigned > > testNodes
Definition: net.cpp:140
void onReceived(UDPSocketFace *, bi::udp::endpoint const &, bytesConstRef _packet)
Definition: net.cpp:150
union node node
Only used for testing.
Definition: net.cpp:125
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
NetFixture()
Definition: net.cpp:40
NodeEntry.
Definition: NodeTable.h:41
Node node(NodeID const &_id)
Returns the Node to the corresponding node id or the empty Node if that id is not found...
Definition: NodeTable.cpp:138
TestUDPSocket()
Definition: net.cpp:147
TestNodeTableHost(unsigned _count=8)
Definition: net.cpp:127
bool isPrivateAddress(bi::address const &_addressToCheck)
Definition: Common.cpp:84
void doWork()
Called continuously following sleep for m_idleWaitMs.
Definition: net.cpp:55
#define asserts(A)
Definition: Assertions.h:41
bool isLocalHostAddress(bi::address const &_addressToCheck)
Definition: Common.cpp:116
UDP Interface Handler must implement UDPSocketEvents.
Definition: UDP.h:107
Simple class that represents a "key pair".
Definition: Common.h:150
size_t count
Definition: ExecStats.cpp:37
BOOST_AUTO_TEST_CASE(requestTimeout)
Definition: net.cpp:157
bool isPublicAddress(bi::address const &_addressToCheck)
Definition: Common.cpp:76
void start()
Definition: net.cpp:54
std::hash for asio::adress
Definition: Common.h:323
void reset()
Definition: net.cpp:115
Secret const & secret() const
Definition: Common.h:167
ba::io_service m_io
Definition: net.cpp:59
IPv4,UDP/TCP endpoints.
Definition: Common.h:175
~NetFixture()
Definition: net.cpp:41
ExecStats::duration min
Definition: ExecStats.cpp:35
h512 Public
A public key: 64 bytes.
Definition: Common.h:39
void populateTestNodes(std::vector< std::pair< KeyPair, unsigned >> const &_testNodes, size_t _count=0)
Definition: net.cpp:93
TestHost()
Definition: net.cpp:52
KeyPair m_alias
Definition: net.cpp:138
#define a(i)
~TestNodeTableHost()
Definition: net.cpp:128
virtual ~TestHost()
Definition: net.cpp:53
std::lock_guard< std::mutex > Guard
Definition: Guards.h:41
void doneWorking()
Called when is to be stopped, just prior to thread being joined.
Definition: net.cpp:56
bool success
Definition: net.cpp:154
NodeTable using modified kademlia for node discovery and preference.
Definition: NodeTable.h:121
std::vector< byte > bytes
Definition: Common.h:75
const Node UnspecifiedNode
Definition: Common.cpp:33
Only used for testing.
Definition: net.cpp:49
TestNodeTable(ba::io_service &_io, KeyPair _alias, bi::address const &_addr, uint16_t _port=30300)
Constructor.
Definition: net.cpp:65
UniValue ping(const JSONRPCRequest &request)
Definition: net.cpp:45
shared_ptr< UDPSocket< TestUDPSocket, 1024 > > m_socket
Definition: net.cpp:152
virtual h256 sign(Secret const &_from)
Definition: UDP.cpp:30
std::vector< shared_ptr< TestNodeTable > > nodeTables
Definition: net.cpp:141
std::vector< Neighbour > neighbours
Definition: NodeTable.h:429
#define BOOST_FIXTURE_TEST_SUITE(a, b)
Definition: object.cpp:14
static std::vector< std::pair< KeyPair, unsigned > > createTestNodes(unsigned _count)
Definition: net.cpp:67
N diff(N const &_a, N const &_b)
Definition: Common.h:212
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
#define BOOST_AUTO_TEST_SUITE_END()
Definition: object.cpp:16
void setup()
Definition: net.cpp:130
Interface which UDPSocket will implement.
Definition: UDP.h:84
#define d(i)
Definition: sha.cpp:732
struct evm_uint160be address(struct evm_env *env)
Definition: capi.c:13
void pingTestNodes(std::vector< std::pair< KeyPair, unsigned >> const &_testNodes)
Definition: net.cpp:83
UDP Datagram.
Definition: UDP.h:51
void populate(size_t _count=0)
Definition: net.cpp:136
std::string toString() const
Definition: vector_ref.h:46
void onDisconnected(UDPSocketFace *)
Definition: net.cpp:149
void populateAll(size_t _count=0)
Definition: net.cpp:134
void pingAll()
Definition: net.cpp:132
static bool test_allowLocal
Setting true causes isAllowed to return true for all addresses. (Used by test fixtures) ...
Definition: Common.h:185
shared_ptr< TestNodeTable > nodeTable
Definition: net.cpp:139
Helper functions to work with json::spirit and test files.
Node Packet: One or more node packets are sent in response to FindNode.
Definition: NodeTable.h:406
Definition: internal.h:25
Interface which a UDPSocket&#39;s owner must implement.
Definition: UDP.h:93