Fabcoin Core  0.16.2
P2P Digital Currency
peer.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 */
23 #include <boost/test/unit_test.hpp>
24 #include <chrono>
25 #include <thread>
26 #include <libp2p/Host.h>
28 #include <libp2p/Capability.h>
29 #include <libp2p/HostCapability.h>
30 
31 using namespace std;
32 using namespace dev;
33 using namespace dev::test;
34 using namespace dev::p2p;
35 
36 struct P2PFixture: public TestOutputHelper
37 {
40 };
41 
42 class TestCap: public Capability
43 {
44 public:
45  TestCap(std::shared_ptr<SessionFace> _s, HostCapabilityFace* _h, unsigned _idOffset, CapDesc const&, uint16_t _capID): Capability(_s, _h, _idOffset, _capID) {}
46  virtual ~TestCap() {}
47  static std::string name() { return "p2pTestCapability"; }
48  static u256 version() { return 2; }
49  static unsigned messageCount() { return UserPacket + 1; }
50 
51 protected:
52  virtual bool interpret(unsigned _id, RLP const& _r) override { return _id > 0 || _r.size() > 0; }
53 };
54 
55 class TestHostCap: public HostCapability<TestCap>, public Worker
56 {
57 public:
58  TestHostCap(): Worker("test") {}
59  virtual ~TestHostCap() {}
60 };
61 
62 
64 
66 {
67  if (test::Options::get().nonetwork)
68  return;
69 
70  VerbosityHolder setTemporaryLevel(10);
71 
72  Host host1("Test", NetworkPreferences("127.0.0.1", 0, false));
73  host1.start();
74  auto host1port = host1.listenPort();
75  BOOST_REQUIRE(host1port);
76 
77  Host host2("Test", NetworkPreferences("127.0.0.1", 0, false));
78  host2.start();
79  auto host2port = host2.listenPort();
80  BOOST_REQUIRE(host2port);
81 
82  BOOST_REQUIRE_NE(host1port, host2port);
83 
84  host1.registerCapability(make_shared<TestHostCap>());
85  host2.registerCapability(make_shared<TestHostCap>());
86 
87  auto node2 = host2.id();
88  int const step = 10;
89 
90  // Wait for up to 6 seconds, to give the hosts time to start.
91  for (unsigned i = 0; i < 6000; i += step)
92  {
93  this_thread::sleep_for(chrono::milliseconds(step));
94 
95  if (host1.isStarted() && host2.isStarted())
96  break;
97  }
98 
99  BOOST_REQUIRE(host1.isStarted() && host2.isStarted());
100 
101  // Wait for up to 6 seconds, to give the hosts time to get their network connection established
102  for (unsigned i = 0; i < 6000; i += step)
103  {
104  this_thread::sleep_for(chrono::milliseconds(step));
105 
106  if (host1.haveNetwork() && host2.haveNetwork())
107  break;
108  }
109 
110  BOOST_REQUIRE(host1.haveNetwork() && host2.haveNetwork());
111  host1.addNode(node2, NodeIPEndpoint(bi::address::from_string("127.0.0.1"), host2port, host2port));
112 
113  // Wait for up to 24 seconds, to give the hosts time to find each other
114  for (unsigned i = 0; i < 24000; i += step)
115  {
116  this_thread::sleep_for(chrono::milliseconds(step));
117 
118  if ((host1.peerCount() > 0) && (host2.peerCount() > 0))
119  break;
120  }
121 
122  BOOST_REQUIRE_EQUAL(host1.peerCount(), 1);
123  BOOST_REQUIRE_EQUAL(host2.peerCount(), 1);
124 }
125 
126 BOOST_AUTO_TEST_CASE(networkConfig)
127 {
128  if (test::Options::get().nonetwork)
129  return;
130 
131  Host save("Test", NetworkPreferences(false));
132  bytes store(save.saveNetwork());
133 
134  Host restore("Test", NetworkPreferences(false), bytesConstRef(&store));
135  BOOST_REQUIRE(save.id() == restore.id());
136 }
137 
139 {
140  if (test::Options::get().nonetwork)
141  return;
142 
143  VerbosityHolder setTemporaryLevel(2);
144 
145  std::list<Host*> hosts;
146  unsigned const c_step = 10;
147  unsigned const c_nodes = 6;
148  unsigned const c_peers = c_nodes - 1;
149  std::set<short unsigned> ports;
150 
151  for (unsigned i = 0; i < c_nodes; ++i)
152  {
153  Host* h = new Host("Test", NetworkPreferences("127.0.0.1", 0, false));
154  h->setIdealPeerCount(10);
155  h->start(); // starting host is required so listenport is available
156  while (!h->haveNetwork())
157  this_thread::sleep_for(chrono::milliseconds(c_step));
158 
159  BOOST_REQUIRE(h->listenPort());
160  bool inserted = ports.insert(h->listenPort()).second;
161  BOOST_REQUIRE(inserted);
162  h->registerCapability(make_shared<TestHostCap>());
163  hosts.push_back(h);
164  }
165 
166  Host& host = *hosts.front();
167  for (auto const& h: hosts)
168  host.addNode(h->id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), h->listenPort(), h->listenPort()));
169 
170  for (unsigned i = 0; i < c_peers * 1000 && host.peerCount() < c_peers; i += c_step)
171  this_thread::sleep_for(chrono::milliseconds(c_step));
172 
173  Host& host2 = *hosts.back();
174  for (auto const& h: hosts)
175  host2.addNode(h->id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), h->listenPort(), h->listenPort()));
176 
177  for (unsigned i = 0; i < c_peers * 2000 && host2.peerCount() < c_peers; i += c_step)
178  this_thread::sleep_for(chrono::milliseconds(c_step));
179 
180  BOOST_CHECK_EQUAL(host.peerCount(), c_peers);
181  BOOST_CHECK_EQUAL(host2.peerCount(), c_peers);
182 
183  bytes firstHostNetwork(host.saveNetwork());
184  bytes secondHostNetwork(host.saveNetwork());
185  BOOST_REQUIRE_EQUAL(sha3(firstHostNetwork), sha3(secondHostNetwork));
186 
187  RLP r(firstHostNetwork);
188  BOOST_REQUIRE(r.itemCount() == 3);
189  BOOST_REQUIRE(r[0].toInt<unsigned>() == dev::p2p::c_protocolVersion);
190  BOOST_REQUIRE_EQUAL(r[1].toBytes().size(), 32); // secret
191  BOOST_REQUIRE(r[2].itemCount() >= c_nodes);
192 
193  for (auto i: r[2])
194  {
195  BOOST_REQUIRE(i.itemCount() == 4 || i.itemCount() == 11);
196  BOOST_REQUIRE(i[0].size() == 4 || i[0].size() == 16);
197  }
198 
199  for (auto host: hosts)
200  delete host;
201 }
202 
204 
206 
208 {
209  if (test::Options::get().nonetwork)
210  return;
211 
212  VerbosityHolder setTemporaryLevel(10);
213 
214  unsigned const step = 10;
215  const char* const localhost = "127.0.0.1";
216  NetworkPreferences prefs1(localhost, 0, false);
217  NetworkPreferences prefs2(localhost, 0, false);
218  Host host1("Test", prefs1);
219  Host host2("Test", prefs2);
220  host1.start();
221  host2.start();
222  auto node2 = host2.id();
223  auto port1 = host1.listenPort();
224  auto port2 = host2.listenPort();
225  BOOST_REQUIRE(port1);
226  BOOST_REQUIRE(port2);
227  BOOST_REQUIRE_NE(port1, port2);
228 
229  host1.registerCapability(make_shared<TestHostCap>());
230  host2.registerCapability(make_shared<TestHostCap>());
231 
232  host1.requirePeer(node2, NodeIPEndpoint(bi::address::from_string(localhost), port2, port2));
233 
234  // Wait for up to 12 seconds, to give the hosts time to connect to each other.
235  for (unsigned i = 0; i < 12000; i += step)
236  {
237  this_thread::sleep_for(chrono::milliseconds(step));
238 
239  if ((host1.peerCount() > 0) && (host2.peerCount() > 0))
240  break;
241  }
242 
243  auto host1peerCount = host1.peerCount();
244  auto host2peerCount = host2.peerCount();
245  BOOST_REQUIRE_EQUAL(host1peerCount, 1);
246  BOOST_REQUIRE_EQUAL(host2peerCount, 1);
247 
248  PeerSessionInfos sis1 = host1.peerSessionInfo();
249  PeerSessionInfos sis2 = host2.peerSessionInfo();
250 
251  BOOST_REQUIRE_EQUAL(sis1.size(), 1);
252  BOOST_REQUIRE_EQUAL(sis2.size(), 1);
253 
254  Peers peers1 = host1.getPeers();
255  Peers peers2 = host2.getPeers();
256  BOOST_REQUIRE_EQUAL(peers1.size(), 1);
257  BOOST_REQUIRE_EQUAL(peers2.size(), 1);
258 
259  DisconnectReason disconnect1 = peers1[0].lastDisconnect();
260  DisconnectReason disconnect2 = peers2[0].lastDisconnect();
261  BOOST_REQUIRE_EQUAL(disconnect1, disconnect2);
262 
263  host1.relinquishPeer(node2);
264 
265  // Wait for up to 6 seconds, to give the hosts time to disconnect from each other.
266  for (unsigned i = 0; i < 6000; i += step)
267  {
268  this_thread::sleep_for(chrono::milliseconds(step));
269 
270  if ((host1.peerCount() == 0) && (host2.peerCount() == 0))
271  break;
272  }
273 
274  host1peerCount = host1.peerCount();
275  host2peerCount = host2.peerCount();
276  BOOST_REQUIRE_EQUAL(host1peerCount, 1);
277  BOOST_REQUIRE_EQUAL(host2peerCount, 1);
278 }
279 
281 
282 BOOST_AUTO_TEST_SUITE(peerTypes)
283 
284 BOOST_AUTO_TEST_CASE(emptySharedPeer)
285 {
286  if (test::Options::get().nonetwork)
287  return;
288 
289  shared_ptr<Peer> p;
290  BOOST_REQUIRE(!p);
291 
292  std::map<NodeID, std::shared_ptr<Peer>> peers;
293  p = peers[NodeID()];
294  BOOST_REQUIRE(!p);
295 
296  p.reset(new Peer(UnspecifiedNode));
297  BOOST_REQUIRE(!p->id);
298  BOOST_REQUIRE(!*p);
299 
301  BOOST_REQUIRE(!(!*p));
302  BOOST_REQUIRE(*p);
303  BOOST_REQUIRE(p);
304 }
305 
307 
308 int peerTest(int argc, char** argv)
309 {
310  Public remoteAlias;
311  short listenPort = 30304;
312  string remoteHost;
313  short remotePort = 30304;
314 
315  for (int i = 1; i < argc; ++i)
316  {
317  string arg = argv[i];
318  if (arg == "-l" && i + 1 < argc)
319  listenPort = (short)atoi(argv[++i]);
320  else if (arg == "-r" && i + 1 < argc)
321  remoteHost = argv[++i];
322  else if (arg == "-p" && i + 1 < argc)
323  remotePort = (short)atoi(argv[++i]);
324  else if (arg == "-ra" && i + 1 < argc)
325  remoteAlias = Public(dev::fromHex(argv[++i]));
326  else
327  remoteHost = argv[i];
328  }
329 
330  Host ph("Test", NetworkPreferences(listenPort));
331 
332  if (!remoteHost.empty() && !remoteAlias)
333  ph.addNode(remoteAlias, NodeIPEndpoint(bi::address::from_string(remoteHost), remotePort, remotePort));
334 
335  this_thread::sleep_for(chrono::milliseconds(200));
336 
337  return 0;
338 }
339 
h512 NodeID
Definition: Common.h:62
h256 EmptySHA3
Definition: SHA3.cpp:35
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
void setIdealPeerCount(unsigned _n)
Set ideal number of peers.
Definition: Host.h:183
bool isStarted() const
Definition: Host.h:218
std::pair< std::string, u256 > CapDesc
Definition: Common.h:142
size_t itemCount() const
Definition: RLP.h:118
bool haveNetwork() const
Definition: Host.h:224
#define h(i)
Definition: sha.cpp:736
The Host class Capabilities should be registered prior to startNetwork, since m_capabilities is not t...
Definition: Host.h:129
std::vector< PeerSessionInfo > PeerSessionInfos
Definition: Common.h:164
Peers getPeers() const
Definition: Host.h:204
static unsigned messageCount()
Definition: peer.cpp:49
unsigned short listenPort() const
Get the port we&#39;re listening on currently.
Definition: Host.h:198
std::hash for asio::adress
Definition: Common.h:323
virtual bool interpret(unsigned _id, RLP const &_r) override
Definition: peer.cpp:52
const unsigned c_protocolVersion
Peer network protocol version.
Definition: Common.cpp:28
IPv4,UDP/TCP endpoints.
Definition: Common.h:175
h512 Public
A public key: 64 bytes.
Definition: Common.h:39
size_t peerCount() const
Get number of peers connected.
Definition: Host.cpp:639
Definition: peer.cpp:42
DisconnectReason
Definition: Common.h:106
bytes saveNetwork() const
Serialise the set of known peers.
Definition: Host.cpp:811
BOOST_AUTO_TEST_CASE(host)
Definition: peer.cpp:65
~P2PFixture()
Definition: peer.cpp:39
bytes fromHex(std::string const &_s, WhenError _throw=WhenError::DontThrow)
Definition: CommonData.cpp:99
NodeID id() const
Get our current node ID.
Definition: Host.h:233
std::vector< Peer > Peers
Definition: Peer.h:99
P2PFixture()
Definition: peer.cpp:38
PeerSessionInfos peerSessionInfo() const
Get peer information.
Definition: Host.cpp:625
std::vector< byte > bytes
Definition: Common.h:75
const Node UnspecifiedNode
Definition: Common.cpp:33
void requirePeer(NodeID const &_node, NodeIPEndpoint const &_endpoint)
Create Peer and attempt keeping peer connected.
Definition: Host.cpp:517
vector_ref< byte const > bytesConstRef
Definition: Common.h:77
static u256 version()
Definition: peer.cpp:48
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void >> u256
Definition: Common.h:125
int peerTest(int argc, char **argv)
Definition: peer.cpp:308
TestHostCap()
Definition: peer.cpp:58
Temporary changes system&#39;s verbosity for specific function.
Definition: Log.h:80
void addNode(NodeID const &_node, NodeIPEndpoint const &_endpoint)
Add node as a peer candidate. Node is added if discovery ping is successful and table has capacity...
Definition: Host.cpp:501
virtual ~TestHostCap()
Definition: peer.cpp:59
void start()
Start network. .
Definition: Host.cpp:124
std::shared_ptr< T > registerCapability(std::shared_ptr< T > const &_t)
Register a peer-capability; all new peer connections will have this capability.
Definition: Host.h:160
#define BOOST_FIXTURE_TEST_SUITE(a, b)
Definition: object.cpp:14
uint8_t const size_t const size
Definition: sha3.h:20
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18
void relinquishPeer(NodeID const &_node)
Note peer as no longer being required.
Definition: Host.cpp:562
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
static std::string name()
Definition: peer.cpp:47
Representation of connectivity state and all other pertinent Peer metadata.
Definition: Peer.h:52
virtual ~TestCap()
Definition: peer.cpp:46
const NodeIPEndpoint UnspecifiedNodeIPEndpoint
Definition: Common.cpp:32
Class for interpreting Recursive Linear-Prefix Data.
Definition: RLP.h:64
TestCap(std::shared_ptr< SessionFace > _s, HostCapabilityFace *_h, unsigned _idOffset, CapDesc const &, uint16_t _capID)
Definition: peer.cpp:45
int atoi(const std::string &str)
size_t size() const
Definition: RLP.h:122
static bool test_allowLocal
Setting true causes isAllowed to return true for all addresses. (Used by test fixtures) ...
Definition: Common.h:185
Helper functions to work with json::spirit and test files.