From 49c4bba9935d9ea05cfa553d900e94b3b8a3d4c3 Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 14 Apr 2015 02:22:39 -0400 Subject: [PATCH 01/12] cleanup/prep endpoint semantics for #1558 and #1557 --- alethzero/MainWin.cpp | 2 +- libp2p/Common.cpp | 13 ++++-- libp2p/Common.h | 31 +++++++++------ libp2p/Host.cpp | 85 +++++++++++++++++----------------------- libp2p/Host.h | 7 +++- libp2p/NodeTable.cpp | 61 ++++++++++++++-------------- libp2p/NodeTable.h | 63 ++++++++++++++--------------- libp2p/Peer.h | 2 - libp2p/Session.cpp | 12 +++--- libwebthree/WebThree.cpp | 4 +- test/net.cpp | 16 +++++--- test/peer.cpp | 16 +++++--- 12 files changed, 159 insertions(+), 153 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 374829a61..a2dc58416 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1034,7 +1034,7 @@ void Main::refreshNetwork() for (p2p::Peer const& i: ns) ui->nodes->insertItem(sessions.count(i.id) ? 0 : ui->nodes->count(), QString("[%1 %3] %2 - ( =%5s | /%4s%6 ) - *%7 $%8") .arg(QString::fromStdString(i.id.abridged())) - .arg(QString::fromStdString(i.peerEndpoint().address().to_string())) + .arg(QString::fromStdString(i.endpoint.address.to_string())) .arg(i.id == web3()->id() ? "self" : sessions.count(i.id) ? sessions[i.id] : "disconnected") .arg(i.isOffline() ? " | " + QString::fromStdString(reasonOf(i.lastDisconnect())) + " | " + QString::number(i.failedAttempts()) + "x" : "") .arg(i.rating()) diff --git a/libp2p/Common.cpp b/libp2p/Common.cpp index 95c96e346..5a3803563 100644 --- a/libp2p/Common.cpp +++ b/libp2p/Common.cpp @@ -27,6 +27,8 @@ using namespace dev::p2p; const unsigned dev::p2p::c_protocolVersion = 3; const unsigned dev::p2p::c_defaultIPPort = 30303; +bool dev::p2p::NodeIPEndpoint::test_allowLocal = false; + bool p2p::isPublicAddress(std::string const& _addressToCheck) { return _addressToCheck.empty() ? false : isPublicAddress(bi::address::from_string(_addressToCheck)); @@ -111,8 +113,13 @@ std::string p2p::reasonOf(DisconnectReason _r) } } -void Node::cullEndpoint() +namespace dev { + +std::ostream& operator<<(std::ostream& _out, dev::p2p::NodeIPEndpoint const& _ep) { - if (!isPublicAddress(endpoint.tcp.address()) && isPublicAddress(endpoint.udp.address())) - endpoint.tcp.address(endpoint.udp.address()); + _out << _ep.address << _ep.udpPort << _ep.tcpPort; + return _out; } + +} + diff --git a/libp2p/Common.h b/libp2p/Common.h index c9aee9a0e..8d85d215e 100644 --- a/libp2p/Common.h +++ b/libp2p/Common.h @@ -156,29 +156,31 @@ using PeerSessionInfos = std::vector; */ struct NodeIPEndpoint { - NodeIPEndpoint(): udp(bi::udp::endpoint()), tcp(bi::tcp::endpoint()) {} - NodeIPEndpoint(bi::udp::endpoint _udp): udp(_udp) {} - NodeIPEndpoint(bi::tcp::endpoint _tcp): tcp(_tcp) {} - NodeIPEndpoint(bi::udp::endpoint _udp, bi::tcp::endpoint _tcp): udp(_udp), tcp(_tcp) {} + static bool test_allowLocal; + + NodeIPEndpoint(): address() {} + NodeIPEndpoint(bi::address _addr, uint16_t _udp, uint16_t _tcp): address(_addr), udpPort(_udp), tcpPort(_tcp) {} - bi::udp::endpoint udp; - bi::tcp::endpoint tcp; + bi::address address; + uint16_t udpPort = 0; + uint16_t tcpPort = 0; + + operator bi::udp::endpoint() const { return std::move(bi::udp::endpoint(address, udpPort)); } + operator bi::tcp::endpoint() const { return std::move(bi::tcp::endpoint(address, tcpPort)); } + + operator bool() const { return !address.is_unspecified() && udpPort > 0 && tcpPort > 0; } - operator bool() const { return !udp.address().is_unspecified() || !tcp.address().is_unspecified(); } + bool isValid() const { return NodeIPEndpoint::test_allowLocal ? true : isPublicAddress(address); } }; - + struct Node { Node(): endpoint(NodeIPEndpoint()) {}; Node(Public _pubk, NodeIPEndpoint _ip, bool _required = false): id(_pubk), endpoint(_ip), required(_required) {} - Node(Public _pubk, bi::udp::endpoint _udp, bool _required = false): Node(_pubk, NodeIPEndpoint(_udp), _required) {} - + virtual NodeId const& address() const { return id; } virtual Public const& publicKey() const { return id; } - /// Adopt UDP address for TCP if TCP isn't public and UDP is. (to be removed when protocol is updated for nat) - void cullEndpoint(); - NodeId id; /// Endpoints by which we expect to reach node. @@ -192,4 +194,7 @@ struct Node }; } + +/// Simple stream output for a NodeIPEndpoint. +std::ostream& operator<<(std::ostream& _out, dev::p2p::NodeIPEndpoint const& _ep); } diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 5704f4727..ae213d71d 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -184,7 +184,7 @@ void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameIO* _io p = m_peers[_id]; if (p->isOffline()) p->m_lastConnected = std::chrono::system_clock::now(); - p->endpoint.tcp.address(_endpoint.address()); + p->endpoint.address = _endpoint.address(); auto protocolVersion = _rlp[0].toInt(); auto clientVersion = _rlp[1].toString(); @@ -231,7 +231,7 @@ void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameIO* _io } clog(NetNote) << "p2p.host.peer.register" << _id.abridged(); - StructuredLogger::p2pConnected(_id.abridged(), ps->m_peer->peerEndpoint(), ps->m_peer->m_lastConnected, clientVersion, peerCount()); + StructuredLogger::p2pConnected(_id.abridged(), ps->m_peer->endpoint, ps->m_peer->m_lastConnected, clientVersion, peerCount()); } void Host::onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e) @@ -251,16 +251,14 @@ void Host::onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e) p = m_peers[_n]; else { - // TODO p2p: construct peer from node p.reset(new Peer()); p->id = _n; - p->endpoint = NodeIPEndpoint(n.endpoint.udp, n.endpoint.tcp); p->required = n.required; m_peers[_n] = p; - clog(NetNote) << "p2p.host.peers.events.peersAdded " << _n << "udp:" << p->endpoint.udp.address() << "tcp:" << p->endpoint.tcp.address(); + clog(NetNote) << "p2p.host.peers.events.peersAdded " << _n << p->endpoint; } - p->endpoint.tcp = n.endpoint.tcp; + p->endpoint = n.endpoint; } // TODO: Implement similar to discover. Attempt connecting to nodes @@ -381,7 +379,7 @@ string Host::pocHost() return "poc-" + strs[1] + ".ethdev.com"; } -void Host::addNode(NodeId const& _node, bi::address const& _addr, unsigned short _udpNodePort, unsigned short _tcpPeerPort) +void Host::addNode(NodeId const& _node, NodeIPEndpoint const& _endpoint) { // return if network is stopped while waiting on Host::run() or nodeTable to start while (!haveNetwork()) @@ -390,26 +388,16 @@ void Host::addNode(NodeId const& _node, bi::address const& _addr, unsigned short else return; - if (_tcpPeerPort < 30300 || _tcpPeerPort > 30305) - cwarn << "Non-standard port being recorded: " << _tcpPeerPort; + if (_endpoint.tcpPort < 30300 || _endpoint.tcpPort > 30305) + clog(NetConnect) << "Non-standard port being recorded: " << _endpoint.tcpPort; - if (_tcpPeerPort >= /*49152*/32768) - { - cwarn << "Private port being recorded - setting to 0"; - _tcpPeerPort = 0; - } - if (m_nodeTable) - m_nodeTable->addNode(Node(_node, NodeIPEndpoint(bi::udp::endpoint(_addr, _udpNodePort), bi::tcp::endpoint(_addr, _tcpPeerPort)))); + m_nodeTable->addNode(Node(_node, _endpoint)); } -void Host::requirePeer(NodeId const& _n, bi::address const& _udpAddr, unsigned short _udpPort, bi::address const& _tcpAddr, unsigned short _tcpPort) +void Host::requirePeer(NodeId const& _n, NodeIPEndpoint const& _endpoint) { - auto naddr = _udpAddr; - auto paddr = _tcpAddr.is_unspecified() ? naddr : _tcpAddr; - auto udp = bi::udp::endpoint(naddr, _udpPort); - auto tcp = bi::tcp::endpoint(paddr, _tcpPort ? _tcpPort : _udpPort); - Node node(_n, NodeIPEndpoint(udp, tcp)); + Node node(_n, _endpoint, true); if (_n) { // add or replace peer @@ -425,8 +413,7 @@ void Host::requirePeer(NodeId const& _n, bi::address const& _udpAddr, unsigned s p->required = true; m_peers[_n] = p; } - p->endpoint.udp = node.endpoint.udp; - p->endpoint.tcp = node.endpoint.tcp; + p->endpoint = node.endpoint; } connect(p); } @@ -441,7 +428,7 @@ void Host::requirePeer(NodeId const& _n, bi::address const& _udpAddr, unsigned s { if (!_ec && m_nodeTable) if (auto n = m_nodeTable->node(_n)) - requirePeer(n.id, n.endpoint.udp.address(), n.endpoint.udp.port(), n.endpoint.tcp.address(), n.endpoint.tcp.port()); + requirePeer(n.id, n.endpoint); }); } } @@ -482,22 +469,23 @@ void Host::connect(std::shared_ptr const& _p) m_pendingPeerConns.insert(nptr); } - clog(NetConnect) << "Attempting connection to node" << _p->id.abridged() << "@" << _p->peerEndpoint() << "from" << id().abridged(); + bi::tcp::endpoint ep(_p->endpoint); + clog(NetConnect) << "Attempting connection to node" << _p->id.abridged() << "@" << ep << "from" << id().abridged(); auto socket = make_shared(new bi::tcp::socket(m_ioService)); - socket->ref().async_connect(_p->peerEndpoint(), [=](boost::system::error_code const& ec) + socket->ref().async_connect(ep, [=](boost::system::error_code const& ec) { _p->m_lastAttempted = std::chrono::system_clock::now(); _p->m_failedAttempts++; if (ec) { - clog(NetConnect) << "Connection refused to node" << _p->id.abridged() << "@" << _p->peerEndpoint() << "(" << ec.message() << ")"; + clog(NetConnect) << "Connection refused to node" << _p->id.abridged() << "@" << ep << "(" << ec.message() << ")"; // Manually set error (session not present) _p->m_lastDisconnect = TCPError; } else { - clog(NetConnect) << "Connecting to" << _p->id.abridged() << "@" << _p->peerEndpoint(); + clog(NetConnect) << "Connecting to" << _p->id.abridged() << "@" << ep; auto handshake = make_shared(this, socket, _p->id); { Guard l(x_connecting); @@ -637,7 +625,7 @@ void Host::startedWorking() else clog(NetNote) << "p2p.start.notice id:" << id().abridged() << "TCP Listen port is invalid or unavailable."; - shared_ptr nodeTable(new NodeTable(m_ioService, m_alias, bi::address::from_string(listenAddress()), listenPort())); + shared_ptr nodeTable(new NodeTable(m_ioService, m_alias, NodeIPEndpoint(bi::address::from_string(listenAddress()), listenPort(), listenPort()))); nodeTable->setEventHandler(new HostNodeTableHandler(*this)); m_nodeTable = nodeTable; restoreNetwork(&m_restoreNetwork); @@ -696,11 +684,11 @@ bytes Host::saveNetwork() const { // Only save peers which have connected within 2 days, with properly-advertised port and public IP address // todo: e2e ipv6 support - bi::tcp::endpoint endpoint(p.peerEndpoint()); + bi::tcp::endpoint endpoint(p.endpoint); if (!endpoint.address().is_v4()) continue; - - if (chrono::system_clock::now() - p.m_lastConnected < chrono::seconds(3600 * 48) && endpoint.port() > 0 && endpoint.port() < /*49152*/32768 && p.id != id() && !isPrivateAddress(p.endpoint.udp.address()) && !isPrivateAddress(endpoint.address())) + + if (chrono::system_clock::now() - p.m_lastConnected < chrono::seconds(3600 * 48) && endpoint.port() > 0 && p.id != id() && (p.required || p.endpoint.isValid())) { network.appendList(10); network << endpoint.port() << p.id << p.required @@ -715,14 +703,14 @@ bytes Host::saveNetwork() const { auto state = m_nodeTable->snapshot(); state.sort(); - for (auto const& s: state) + for (auto const& entry: state) { network.appendList(3); - if (s.endpoint.tcp.address().is_v4()) - network << s.endpoint.tcp.address().to_v4().to_bytes(); + if (entry.endpoint.address.is_v4()) + network << entry.endpoint.address.to_v4().to_bytes(); else - network << s.endpoint.tcp.address().to_v6().to_bytes(); - network << s.endpoint.tcp.port() << s.id; + network << entry.endpoint.address.to_v6().to_bytes(); + network << entry.endpoint.tcpPort << entry.id; count++; } } @@ -755,36 +743,33 @@ void Host::restoreNetwork(bytesConstRef _b) for (auto i: r[2]) { - // todo: e2e ipv6 support - // bi::tcp::endpoint(bi::address_v6(i[0].toArray()), i[1].toInt()); if (i[0].itemCount() != 4) continue; - bi::tcp::endpoint tcp; - bi::udp::endpoint udp; - tcp = bi::tcp::endpoint(bi::address_v4(i[0].toArray()), i[1].toInt()); - udp = bi::udp::endpoint(bi::address_v4(i[0].toArray()), i[1].toInt()); - if (isPrivateAddress(tcp.address()) || isPrivateAddress(udp.address())) + + // todo: ipv6, bi::address_v6(i[0].toArray() + NodeIPEndpoint ep(bi::address_v4(i[0].toArray()), i[1].toInt(), i[1].toInt()); + bool required = i[3].toInt(); + if (!ep.isValid() && !required) continue; auto id = (NodeId)i[2]; if (i.itemCount() == 3) - m_nodeTable->addNode(id, udp, tcp); + m_nodeTable->addNode(id, ep); else if (i.itemCount() == 10) { shared_ptr p = make_shared(); p->id = id; - p->required = i[3].toInt(); + p->required = required; p->m_lastConnected = chrono::system_clock::time_point(chrono::seconds(i[4].toInt())); p->m_lastAttempted = chrono::system_clock::time_point(chrono::seconds(i[5].toInt())); p->m_failedAttempts = i[6].toInt(); p->m_lastDisconnect = (DisconnectReason)i[7].toInt(); p->m_score = (int)i[8].toInt(); p->m_rating = (int)i[9].toInt(); - p->endpoint.tcp = tcp; - p->endpoint.udp = udp; + p->endpoint = ep; m_peers[p->id] = p; if (p->required) - requirePeer(p->id, p->endpoint.udp.address(), p->endpoint.udp.port()); + requirePeer(p->id, ep); else m_nodeTable->addNode(*p.get()); } diff --git a/libp2p/Host.h b/libp2p/Host.h index e4d43f233..375481c38 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -103,10 +103,13 @@ public: template std::shared_ptr cap() const { try { return std::static_pointer_cast(m_capabilities.at(std::make_pair(T::staticName(), T::staticVersion()))); } catch (...) { return nullptr; } } /// Add node as a peer candidate. Node is added if discovery ping is successful and table has capacity. - void addNode(NodeId const& _node, bi::address const& _addr, unsigned short _udpPort, unsigned short _tcpPort); + void addNode(NodeId const& _node, NodeIPEndpoint const& _endpoint); /// Create Peer and attempt keeping peer connected. - void requirePeer(NodeId const& _node, bi::address const& _udpAddr, unsigned short _udpPort, bi::address const& _tcpAddr = bi::address(), unsigned short _tcpPort = 0); + void requirePeer(NodeId const& _node, NodeIPEndpoint const& _endpoint); + + /// Create Peer and attempt keeping peer connected. + void requirePeer(NodeId const& _node, bi::address const& _addr, unsigned short _udpPort, unsigned short _tcpPort) { requirePeer(_node, NodeIPEndpoint(_addr, _udpPort, _tcpPort)); } /// Note peer as no longer being required. void relinquishPeer(NodeId const& _node); diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 2837e8f07..e4326bd17 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -25,13 +25,12 @@ using namespace dev; using namespace dev::p2p; NodeEntry::NodeEntry(Node _src, Public _pubk, NodeIPEndpoint _gw): Node(_pubk, _gw), distance(NodeTable::distance(_src.id,_pubk)) {} -NodeEntry::NodeEntry(Node _src, Public _pubk, bi::udp::endpoint _udp): Node(_pubk, NodeIPEndpoint(_udp)), distance(NodeTable::distance(_src.id,_pubk)) {} -NodeTable::NodeTable(ba::io_service& _io, KeyPair _alias, bi::address const& _udpAddress, uint16_t _udp): - m_node(Node(_alias.pub(), bi::udp::endpoint(_udpAddress, _udp))), +NodeTable::NodeTable(ba::io_service& _io, KeyPair const& _alias, NodeIPEndpoint const& _endpoint): + m_node(Node(_alias.pub(), _endpoint)), m_secret(_alias.sec()), m_io(_io), - m_socket(new NodeSocket(m_io, *this, m_node.endpoint.udp)), + m_socket(new NodeSocket(m_io, *this, (bi::udp::endpoint)m_node.endpoint)), m_socketPointer(m_socket.get()), m_bucketRefreshTimer(m_io), m_evictionCheckTimer(m_io) @@ -62,9 +61,9 @@ void NodeTable::processEvents() m_nodeEventHandler->processEvents(); } -shared_ptr NodeTable::addNode(Public const& _pubk, bi::udp::endpoint const& _udp, bi::tcp::endpoint const& _tcp) +shared_ptr NodeTable::addNode(Public const& _pubk, NodeIPEndpoint const& _ep) { - auto node = Node(_pubk, NodeIPEndpoint(_udp, _tcp)); + auto node = Node(_pubk, _ep); return addNode(node); } @@ -72,7 +71,7 @@ shared_ptr NodeTable::addNode(Node const& _node) { // re-enable tcp checks when NAT hosts are handled by discover // we handle when tcp endpoint is 0 below - if (_node.endpoint.udp.address().to_string() == "0.0.0.0") + if (_node.endpoint.address.to_string() == "0.0.0.0") { clog(NodeTableWarn) << "addNode Failed. Invalid UDP address 0.0.0.0 for" << _node.id.abridged(); return move(shared_ptr()); @@ -81,12 +80,12 @@ shared_ptr NodeTable::addNode(Node const& _node) // ping address to recover nodeid if nodeid is empty if (!_node.id) { - clog(NodeTableConnect) << "Sending public key discovery Ping to" << _node.endpoint.udp << "(Advertising:" << m_node.endpoint.udp << ")"; + clog(NodeTableConnect) << "Sending public key discovery Ping to" << (bi::udp::endpoint)_node.endpoint << "(Advertising:" << (bi::udp::endpoint)m_node.endpoint << ")"; { Guard l(x_pubkDiscoverPings); - m_pubkDiscoverPings[_node.endpoint.udp.address()] = std::chrono::steady_clock::now(); + m_pubkDiscoverPings[_node.endpoint.address] = std::chrono::steady_clock::now(); } - PingNode p(_node.endpoint.udp, m_node.endpoint.udp.address().to_string(), m_node.endpoint.udp.port()); + PingNode p((bi::udp::endpoint)_node.endpoint, m_node.endpoint.address.to_string(), m_node.endpoint.udpPort); p.sign(m_secret); m_socketPointer->send(p); return move(shared_ptr()); @@ -98,11 +97,10 @@ shared_ptr NodeTable::addNode(Node const& _node) return m_nodes[_node.id]; } - shared_ptr ret(new NodeEntry(m_node, _node.id, NodeIPEndpoint(_node.endpoint.udp, _node.endpoint.tcp))); + shared_ptr ret(new NodeEntry(m_node, _node.id, _node.endpoint)); m_nodes[_node.id] = ret; - ret->cullEndpoint(); - clog(NodeTableConnect) << "addNode pending for" << _node.endpoint.udp << _node.endpoint.tcp; - PingNode p(_node.endpoint.udp, m_node.endpoint.udp.address().to_string(), m_node.endpoint.udp.port()); + clog(NodeTableConnect) << "addNode pending for" << _node.endpoint; + PingNode p(_node.endpoint, m_node.endpoint.address.to_string(), m_node.endpoint.udpPort); p.sign(m_secret); m_socketPointer->send(p); return ret; @@ -143,7 +141,7 @@ Node NodeTable::node(NodeId const& _id) if (m_nodes.count(_id)) { auto entry = m_nodes[_id]; - Node n(_id, NodeIPEndpoint(entry->endpoint.udp, entry->endpoint.tcp), entry->required); + Node n(_id, entry->endpoint, entry->required); return move(n); } return move(Node()); @@ -176,7 +174,7 @@ void NodeTable::discover(NodeId _node, unsigned _round, shared_ptrendpoint.udp, _node); + FindNode p(r->endpoint, _node); p.sign(m_secret); m_socketPointer->send(p); } @@ -273,13 +271,14 @@ vector> NodeTable::nearestNodeEntries(NodeId _target) vector> ret; for (auto& nodes: found) for (auto n: nodes.second) - ret.push_back(n); + if (n->endpoint.isValid()) + ret.push_back(n); return move(ret); } void NodeTable::ping(bi::udp::endpoint _to) const { - PingNode p(_to, m_node.endpoint.udp.address().to_string(), m_node.endpoint.udp.port()); + PingNode p(_to, m_node.endpoint.address.to_string(), m_node.endpoint.udpPort); p.sign(m_secret); m_socketPointer->send(p); } @@ -287,7 +286,7 @@ void NodeTable::ping(bi::udp::endpoint _to) const void NodeTable::ping(NodeEntry* _n) const { if (_n) - ping(_n->endpoint.udp); + ping(_n->endpoint); } void NodeTable::evict(shared_ptr _leastSeen, shared_ptr _new) @@ -306,16 +305,15 @@ void NodeTable::evict(shared_ptr _leastSeen, shared_ptr _n void NodeTable::noteActiveNode(Public const& _pubk, bi::udp::endpoint const& _endpoint) { - if (_pubk == m_node.address()) + if (_pubk == m_node.address() || !NodeIPEndpoint(_endpoint.address(), _endpoint.port(), _endpoint.port()).isValid()) return; shared_ptr node = nodeEntry(_pubk); if (!!node && !node->pending) { clog(NodeTableConnect) << "Noting active node:" << _pubk.abridged() << _endpoint.address().to_string() << ":" << _endpoint.port(); - node->endpoint.udp.address(_endpoint.address()); - node->endpoint.udp.port(_endpoint.port()); - node->cullEndpoint(); + node->endpoint.address = _endpoint.address(); + node->endpoint.udpPort = _endpoint.port(); shared_ptr contested; { @@ -445,7 +443,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes m_pubkDiscoverPings.erase(_from.address()); } if (!haveNode(nodeid)) - addNode(nodeid, _from, bi::tcp::endpoint(_from.address(), _from.port())); + addNode(nodeid, NodeIPEndpoint(_from.address(), _from.port(), _from.port())); } else return; // unsolicited pong; don't note node as active @@ -459,7 +457,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes { Neighbours in = Neighbours::fromBytesConstRef(_from, rlpBytes); for (auto n: in.nodes) - addNode(n.node, bi::udp::endpoint(bi::address::from_string(n.ipAddress), n.port), bi::tcp::endpoint(bi::address::from_string(n.ipAddress), n.port)); + addNode(n.node, NodeIPEndpoint(bi::address::from_string(n.ipAddress), n.udpPort, n.udpPort)); break; } @@ -490,7 +488,8 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes return; } - addNode(nodeid, _from, bi::tcp::endpoint(bi::address::from_string(in.ipAddress), in.port)); + // TODO: Feedback if _from.address() != in.ipAddress + addNode(nodeid, NodeIPEndpoint(_from.address(), _from.port(), in.tcpPort)); Pong p(_from); p.echo = sha3(rlpBytes); @@ -568,7 +567,7 @@ void NodeTable::doRefreshBuckets(boost::system::error_code const& _ec) void PingNode::streamRLP(RLPStream& _s) const { _s.appendList(4); - _s << dev::p2p::c_protocolVersion << ipAddress << port << expiration; + _s << dev::p2p::c_protocolVersion << ipAddress << tcpPort << ts; } void PingNode::interpretRLP(bytesConstRef _bytes) @@ -578,15 +577,15 @@ void PingNode::interpretRLP(bytesConstRef _bytes) { version = 2; ipAddress = r[0].toString(); - port = r[1].toInt(RLP::Strict); - expiration = r[2].toInt(RLP::Strict); + tcpPort = r[1].toInt(RLP::Strict); + ts = r[2].toInt(RLP::Strict); } else if (r.itemCountStrict() == 4) { version = r[0].toInt(RLP::Strict); ipAddress = r[1].toString(); - port = r[2].toInt(RLP::Strict); - expiration = r[3].toInt(RLP::Strict); + tcpPort = r[2].toInt(RLP::Strict); + ts = r[3].toInt(RLP::Strict); } else BOOST_THROW_EXCEPTION(InvalidRLP()); diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index 4aee93e99..86dc14ba3 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -41,10 +41,7 @@ namespace p2p struct NodeEntry: public Node { NodeEntry(Node _src, Public _pubk, NodeIPEndpoint _gw); - NodeEntry(Node _src, Public _pubk, bi::udp::endpoint _udp); - unsigned const distance; ///< Node's distance (xor of _src as integer). - bool pending = true; ///< Node will be ignored until Pong is received }; @@ -136,7 +133,7 @@ class NodeTable: UDPSocketEvents, public std::enable_shared_from_this public: /// Constructor requiring host for I/O, credentials, and IP Address and port to listen on. - NodeTable(ba::io_service& _io, KeyPair _alias, bi::address const& _udpAddress, uint16_t _udpPort = 30303); + NodeTable(ba::io_service& _io, KeyPair const& _alias, NodeIPEndpoint const& _endpoint); ~NodeTable(); /// Returns distance based on xor metric two node ids. Used by NodeEntry and NodeTable. @@ -149,7 +146,7 @@ public: void processEvents(); /// Add node. Node will be pinged and empty shared_ptr is returned if NodeId is uknown. - std::shared_ptr addNode(Public const& _pubk, bi::udp::endpoint const& _udp, bi::tcp::endpoint const& _tcp); + std::shared_ptr addNode(Public const& _pubk, NodeIPEndpoint const& _ep); /// Add node. Node will be pinged and empty shared_ptr is returned if node has never been seen. std::shared_ptr addNode(Node const& _node); @@ -212,7 +209,7 @@ private: void ping(NodeEntry* _n) const; /// Returns center node entry which describes this node and used with dist() to calculate xor metric for node table nodes. - NodeEntry center() const { return NodeEntry(m_node, m_node.publicKey(), m_node.endpoint.udp); } + NodeEntry center() const { return NodeEntry(m_node, m_node.publicKey(), m_node.endpoint); } /// Used by asynchronous operations to return NodeEntry which is active and managed by node table. std::shared_ptr nodeEntry(NodeId _id); @@ -281,10 +278,10 @@ private: inline std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable) { - _out << _nodeTable.center().address() << "\t" << "0\t" << _nodeTable.center().endpoint.udp.address() << ":" << _nodeTable.center().endpoint.udp.port() << std::endl; + _out << _nodeTable.center().address() << "\t" << "0\t" << _nodeTable.center().endpoint.address << ":" << _nodeTable.center().endpoint.udpPort << std::endl; auto s = _nodeTable.snapshot(); for (auto n: s) - _out << n.address() << "\t" << n.distance << "\t" << n.endpoint.udp.address() << ":" << n.endpoint.udp.port() << std::endl; + _out << n.address() << "\t" << n.distance << "\t" << n.endpoint.address << ":" << n.endpoint.udpPort << std::endl; return _out; } @@ -292,7 +289,7 @@ struct InvalidRLP: public Exception {}; /** * Ping packet: Sent to check if node is alive. - * PingNode is cached and regenerated after expiration - t, where t is timeout. + * PingNode is cached and regenerated after ts + t, where t is timeout. * * Ping is used to implement evict. When a new node is seen for * a given bucket which is full, the least-responsive node is pinged. @@ -306,7 +303,6 @@ struct InvalidRLP: public Exception {}; * signature: Signature of message. * ipAddress: Our IP address. * port: Our port. - * expiration: Triggers regeneration of packet. May also provide control over synchronization. * * @todo uint128_t for ip address (<->integer ipv4/6, asio-address, asio-endpoint) * @@ -314,14 +310,15 @@ struct InvalidRLP: public Exception {}; struct PingNode: RLPXDatagram { PingNode(bi::udp::endpoint _ep): RLPXDatagram(_ep) {} - PingNode(bi::udp::endpoint _ep, std::string _src, uint16_t _srcPort, std::chrono::seconds _expiration = std::chrono::seconds(60)): RLPXDatagram(_ep), ipAddress(_src), port(_srcPort), expiration(futureFromEpoch(_expiration)) {} + PingNode(bi::udp::endpoint _ep, std::string _src, uint16_t _srcPort, std::chrono::seconds _ts = std::chrono::seconds(60)): RLPXDatagram(_ep), ipAddress(_src), tcpPort(_srcPort), ts(futureFromEpoch(_ts)) {} static const uint8_t type = 1; unsigned version = 0; std::string ipAddress; - unsigned port; - unsigned expiration; +// unsigned udpPort; + unsigned tcpPort; + unsigned ts; void streamRLP(RLPStream& _s) const override; void interpretRLP(bytesConstRef _bytes) override; @@ -336,20 +333,20 @@ struct PingNode: RLPXDatagram */ struct Pong: RLPXDatagram { - Pong(bi::udp::endpoint _ep): RLPXDatagram(_ep), expiration(futureFromEpoch(std::chrono::seconds(60))) {} + Pong(bi::udp::endpoint _ep): RLPXDatagram(_ep), ts(futureFromEpoch(std::chrono::seconds(60))) {} static const uint8_t type = 2; h256 echo; ///< MCD of PingNode - unsigned expiration; + unsigned ts; - void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << echo << expiration; } - void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); echo = (h256)r[0]; expiration = r[1].toInt(); } + void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << echo << ts; } + void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); echo = (h256)r[0]; ts = r[1].toInt(); } }; /** * FindNode Packet: Request k-nodes, closest to the target. - * FindNode is cached and regenerated after expiration - t, where t is timeout. + * FindNode is cached and regenerated after ts + t, where t is timeout. * FindNode implicitly results in finding neighbours of a given node. * * RLP Encoded Items: 2 @@ -357,21 +354,20 @@ struct Pong: RLPXDatagram * Maximum Encoded Size: 30 bytes * * target: NodeId of node. The responding node will send back nodes closest to the target. - * expiration: Triggers regeneration of packet. May also provide control over synchronization. * */ struct FindNode: RLPXDatagram { FindNode(bi::udp::endpoint _ep): RLPXDatagram(_ep) {} - FindNode(bi::udp::endpoint _ep, NodeId _target, std::chrono::seconds _expiration = std::chrono::seconds(30)): RLPXDatagram(_ep), target(_target), expiration(futureFromEpoch(_expiration)) {} + FindNode(bi::udp::endpoint _ep, NodeId _target, std::chrono::seconds _ts = std::chrono::seconds(60)): RLPXDatagram(_ep), target(_target), ts(futureFromEpoch(_ts)) {} static const uint8_t type = 3; h512 target; - unsigned expiration; + unsigned ts; - void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << target << expiration; } - void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); target = r[0].toHash(); expiration = r[1].toInt(); } + void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << target << ts; } + void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); target = r[0].toHash(); ts = r[1].toInt(); } }; /** @@ -387,21 +383,22 @@ struct Neighbours: RLPXDatagram Node() = default; Node(RLP const& _r) { interpretRLP(_r); } std::string ipAddress; - unsigned port; + unsigned udpPort; +// unsigned tcpPort; NodeId node; - void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << node; } - void interpretRLP(RLP const& _r) { ipAddress = _r[0].toString(); port = _r[1].toInt(); node = h512(_r[2].toBytes()); } + void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << udpPort << node; } + void interpretRLP(RLP const& _r) { ipAddress = _r[0].toString(); udpPort = _r[1].toInt(); node = h512(_r[2].toBytes()); } }; - Neighbours(bi::udp::endpoint _ep): RLPXDatagram(_ep), expiration(futureFromEpoch(std::chrono::seconds(30))) {} - Neighbours(bi::udp::endpoint _to, std::vector> const& _nearest, unsigned _offset = 0, unsigned _limit = 0): RLPXDatagram(_to), expiration(futureFromEpoch(std::chrono::seconds(30))) + Neighbours(bi::udp::endpoint _ep): RLPXDatagram(_ep), ts(futureFromEpoch(std::chrono::seconds(30))) {} + Neighbours(bi::udp::endpoint _to, std::vector> const& _nearest, unsigned _offset = 0, unsigned _limit = 0): RLPXDatagram(_to), ts(futureFromEpoch(std::chrono::seconds(30))) { auto limit = _limit ? std::min(_nearest.size(), (size_t)(_offset + _limit)) : _nearest.size(); for (auto i = _offset; i < limit; i++) { Node node; - node.ipAddress = _nearest[i]->endpoint.udp.address().to_string(); - node.port = _nearest[i]->endpoint.udp.port(); + node.ipAddress = _nearest[i]->endpoint.address.to_string(); + node.udpPort = _nearest[i]->endpoint.udpPort; node.node = _nearest[i]->publicKey(); nodes.push_back(node); } @@ -409,10 +406,10 @@ struct Neighbours: RLPXDatagram static const uint8_t type = 4; std::vector nodes; - unsigned expiration = 1; + unsigned ts = 1; - void streamRLP(RLPStream& _s) const { _s.appendList(2); _s.appendList(nodes.size()); for (auto& n: nodes) n.streamRLP(_s); _s << expiration; } - void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); for (auto n: r[0]) nodes.push_back(Node(n)); expiration = r[1].toInt(); } + void streamRLP(RLPStream& _s) const { _s.appendList(2); _s.appendList(nodes.size()); for (auto& n: nodes) n.streamRLP(_s); _s << ts; } + void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); for (auto n: r[0]) nodes.push_back(Node(n)); ts = r[1].toInt(); } }; struct NodeTableWarn: public LogChannel { static const char* name() { return "!P!"; } static const int verbosity = 0; }; diff --git a/libp2p/Peer.h b/libp2p/Peer.h index cb9155bbc..18809d075 100644 --- a/libp2p/Peer.h +++ b/libp2p/Peer.h @@ -59,8 +59,6 @@ class Peer: public Node public: bool isOffline() const { return !m_session.lock(); } - bi::tcp::endpoint const& peerEndpoint() const { return endpoint.tcp; } - virtual bool operator<(Peer const& _p) const; /// WIP: Returns current peer rating. diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 8c5a50750..55e96f311 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -138,11 +138,11 @@ void Session::serviceNodesRequest() auto rs = randomSelection(peers, 10); for (auto const& i: rs) { - clogS(NetTriviaDetail) << "Sending peer " << i.id.abridged() << i.peerEndpoint(); - if (i.peerEndpoint().address().is_v4()) - s.appendList(3) << bytesConstRef(i.peerEndpoint().address().to_v4().to_bytes().data(), 4) << i.peerEndpoint().port() << i.id; + clogS(NetTriviaDetail) << "Sending peer " << i.id.abridged() << i.endpoint; + if (i.endpoint.address.is_v4()) + s.appendList(3) << bytesConstRef(i.endpoint.address.to_v4().to_bytes().data(), 4) << i.endpoint.tcpPort << i.id; else// if (i.second.address().is_v6()) - assumed - s.appendList(3) << bytesConstRef(i.peerEndpoint().address().to_v6().to_bytes().data(), 16) << i.peerEndpoint().port() << i.id; + s.appendList(3) << bytesConstRef(i.endpoint.address.to_v6().to_bytes().data(), 16) << i.endpoint.tcpPort << i.id; } sealAndSend(s); m_theyRequestedNodes = false; @@ -237,7 +237,7 @@ bool Session::interpret(PacketType _t, RLP const& _r) // OK passed all our checks. Assume it's good. addRating(1000); - m_server->addNode(id, ep.address(), ep.port(), ep.port()); + m_server->addNode(id, NodeIPEndpoint(ep.address(), ep.port(), ep.port())); clogS(NetTriviaDetail) << "New peer: " << ep << "(" << id .abridged()<< ")"; CONTINUE:; LAMEPEER:; @@ -370,7 +370,7 @@ void Session::disconnect(DisconnectReason _reason) clogS(NetConnect) << "Disconnecting (our reason:" << reasonOf(_reason) << ")"; StructuredLogger::p2pDisconnected( m_info.id.abridged(), - m_peer->peerEndpoint(), + m_peer->endpoint, // TODO: may not be 100% accurate m_server->peerCount() ); if (m_socket.is_open()) diff --git a/libwebthree/WebThree.cpp b/libwebthree/WebThree.cpp index 8ea2133f0..b3bc98a49 100644 --- a/libwebthree/WebThree.cpp +++ b/libwebthree/WebThree.cpp @@ -104,12 +104,12 @@ bytes WebThreeDirect::saveNetwork() void WebThreeDirect::addNode(NodeId const& _node, bi::tcp::endpoint const& _host) { - m_net.addNode(_node, _host.address(), _host.port(), _host.port()); + m_net.addNode(_node, NodeIPEndpoint(_host.address(), _host.port(), _host.port())); } void WebThreeDirect::requirePeer(NodeId const& _node, bi::tcp::endpoint const& _host) { - m_net.requirePeer(_node, _host.address(), _host.port()); + m_net.requirePeer(_node, NodeIPEndpoint(_host.address(), _host.port(), _host.port())); } diff --git a/test/net.cpp b/test/net.cpp index ec1efb360..1cc00e095 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -32,7 +32,13 @@ using namespace dev::p2p; namespace ba = boost::asio; namespace bi = ba::ip; -BOOST_AUTO_TEST_SUITE(net) +struct NetFixture +{ + NetFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = true;; } + ~NetFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = false; } +}; + +BOOST_FIXTURE_TEST_SUITE(net, NetFixture) /** * Only used for testing. Not useful beyond tests. @@ -53,7 +59,7 @@ protected: struct TestNodeTable: public NodeTable { /// Constructor - TestNodeTable(ba::io_service& _io, KeyPair _alias, bi::address const& _addr, uint16_t _port = 30300): NodeTable(_io, _alias, _addr, _port) {} + TestNodeTable(ba::io_service& _io, KeyPair _alias, bi::address const& _addr, uint16_t _port = 30300): NodeTable(_io, _alias, NodeIPEndpoint(_addr, _port, _port)) {} static std::vector> createTestNodes(unsigned _count) { @@ -93,7 +99,7 @@ struct TestNodeTable: public NodeTable // manually add node for test { Guard ln(x_nodes); - shared_ptr node(new NodeEntry(m_node, n.first.pub(), NodeIPEndpoint(bi::udp::endpoint(ourIp, n.second), bi::tcp::endpoint(ourIp, n.second)))); + shared_ptr node(new NodeEntry(m_node, n.first.pub(), NodeIPEndpoint(ourIp, n.second, n.second))); node->pending = false; m_nodes[node->id] = node; } @@ -201,7 +207,7 @@ BOOST_AUTO_TEST_CASE(test_neighbours_packet) { Neighbours::Node node; node.ipAddress = boost::asio::ip::address::from_string("127.0.0.1").to_string(); - node.port = n.second; + node.udpPort = n.second; node.node = n.first.pub(); out.nodes.push_back(node); } @@ -213,7 +219,7 @@ BOOST_AUTO_TEST_CASE(test_neighbours_packet) int count = 0; for (auto n: in.nodes) { - BOOST_REQUIRE_EQUAL(testNodes[count].second, n.port); + BOOST_REQUIRE_EQUAL(testNodes[count].second, n.udpPort); BOOST_REQUIRE_EQUAL(testNodes[count].first.pub(), n.node); BOOST_REQUIRE_EQUAL(sha3(testNodes[count].first.pub()), sha3(n.node)); count++; diff --git a/test/peer.cpp b/test/peer.cpp index 2aeb99469..1d593534a 100644 --- a/test/peer.cpp +++ b/test/peer.cpp @@ -28,7 +28,13 @@ using namespace std; using namespace dev; using namespace dev::p2p; -BOOST_AUTO_TEST_SUITE(p2p) +struct P2PFixture +{ + P2PFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = true;; } + ~P2PFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = false; } +}; + +BOOST_FIXTURE_TEST_SUITE(p2p, P2PFixture) BOOST_AUTO_TEST_CASE(host) { @@ -45,7 +51,7 @@ BOOST_AUTO_TEST_CASE(host) auto node2 = host2.id(); host2.start(); - host1.addNode(node2, bi::address::from_string("127.0.0.1"), host2prefs.listenPort, host2prefs.listenPort); + host1.addNode(node2, NodeIPEndpoint(bi::address::from_string("127.0.0.1"), host2prefs.listenPort, host2prefs.listenPort)); this_thread::sleep_for(chrono::seconds(3)); @@ -82,11 +88,11 @@ BOOST_AUTO_TEST_CASE(save_nodes) Host& host = *hosts.front(); for (auto const& h: hosts) - host.addNode(h->id(), bi::address::from_string("127.0.0.1"), h->listenPort(), h->listenPort()); + host.addNode(h->id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), h->listenPort(), h->listenPort())); Host& host2 = *hosts.back(); for (auto const& h: hosts) - host2.addNode(h->id(), bi::address::from_string("127.0.0.1"), h->listenPort(), h->listenPort()); + host2.addNode(h->id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), h->listenPort(), h->listenPort())); this_thread::sleep_for(chrono::milliseconds(2000)); bytes firstHostNetwork(host.saveNetwork()); @@ -131,7 +137,7 @@ int peerTest(int argc, char** argv) Host ph("Test", NetworkPreferences(listenPort)); if (!remoteHost.empty() && !remoteAlias) - ph.addNode(remoteAlias, bi::address::from_string(remoteHost), remotePort, remotePort); + ph.addNode(remoteAlias, NodeIPEndpoint(bi::address::from_string(remoteHost), remotePort, remotePort)); this_thread::sleep_for(chrono::milliseconds(200)); From 8cbf9439be5d679bd02ba09f6098d0eaf5771010 Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 14 Apr 2015 02:48:23 -0400 Subject: [PATCH 02/12] remove unneeded cast --- libp2p/NodeTable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index e4326bd17..238d9606e 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -85,7 +85,7 @@ shared_ptr NodeTable::addNode(Node const& _node) Guard l(x_pubkDiscoverPings); m_pubkDiscoverPings[_node.endpoint.address] = std::chrono::steady_clock::now(); } - PingNode p((bi::udp::endpoint)_node.endpoint, m_node.endpoint.address.to_string(), m_node.endpoint.udpPort); + PingNode p(_node.endpoint, m_node.endpoint.address.to_string(), m_node.endpoint.udpPort); p.sign(m_secret); m_socketPointer->send(p); return move(shared_ptr()); From 37035877533f3ed26fa913a8304f9f5fdf1db380 Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 14 Apr 2015 03:32:23 -0400 Subject: [PATCH 03/12] doc static for testing --- libp2p/Common.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libp2p/Common.h b/libp2p/Common.h index 8d85d215e..858b220ab 100644 --- a/libp2p/Common.h +++ b/libp2p/Common.h @@ -156,6 +156,7 @@ using PeerSessionInfos = std::vector; */ struct NodeIPEndpoint { + /// Setting true causes isValid to return true for all addresses. Defaults to false. Used by test fixtures. static bool test_allowLocal; NodeIPEndpoint(): address() {} From aa705c1dd725f9cdac6a3e1a45203426ca246f69 Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 15 Apr 2015 21:23:49 -0400 Subject: [PATCH 04/12] update test --- test/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/net.cpp b/test/net.cpp index 28b4f4286..ae6053795 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -246,7 +246,7 @@ BOOST_AUTO_TEST_CASE(neighboursPacketLength) { Neighbours::Node node; node.ipAddress = boost::asio::ip::address::from_string("200.200.200.200").to_string(); - node.port = testNodes[i].second; + node.udpPort = testNodes[i].second; node.node = testNodes[i].first.pub(); out.nodes.push_back(node); } From 280df58d9418bdcdb0d97fe3fb4874d2794b8a22 Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 15 Apr 2015 22:27:03 -0400 Subject: [PATCH 05/12] More explicit initialization of nodes and peers. --- libp2p/Common.cpp | 3 +++ libp2p/Common.h | 13 ++++++++----- libp2p/NodeTable.cpp | 2 +- libp2p/Peer.h | 1 + 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/libp2p/Common.cpp b/libp2p/Common.cpp index 5a3803563..7206ec835 100644 --- a/libp2p/Common.cpp +++ b/libp2p/Common.cpp @@ -27,6 +27,9 @@ using namespace dev::p2p; const unsigned dev::p2p::c_protocolVersion = 3; const unsigned dev::p2p::c_defaultIPPort = 30303; +const dev::p2p::NodeIPEndpoint dev::p2p::UnspecifiedNodeIPEndpoint = NodeIPEndpoint(bi::address(), 0, 0); +const dev::p2p::Node dev::p2p::UnspecifiedNode = dev::p2p::Node(NodeId(), UnspecifiedNodeIPEndpoint); + bool dev::p2p::NodeIPEndpoint::test_allowLocal = false; bool p2p::isPublicAddress(std::string const& _addressToCheck) diff --git a/libp2p/Common.h b/libp2p/Common.h index cd18c54f3..5b770887f 100644 --- a/libp2p/Common.h +++ b/libp2p/Common.h @@ -52,6 +52,11 @@ namespace p2p extern const unsigned c_protocolVersion; extern const unsigned c_defaultIPPort; +struct NodeIPEndpoint; +struct Node; +extern const NodeIPEndpoint UnspecifiedNodeIPEndpoint; +extern const Node UnspecifiedNode; + using NodeId = h512; bool isPrivateAddress(bi::address const& _addressToCheck); @@ -158,13 +163,12 @@ struct NodeIPEndpoint { /// Setting true causes isValid to return true for all addresses. Defaults to false. Used by test fixtures. static bool test_allowLocal; - - NodeIPEndpoint(): address() {} + NodeIPEndpoint(bi::address _addr, uint16_t _udp, uint16_t _tcp): address(_addr), udpPort(_udp), tcpPort(_tcp) {} bi::address address; - uint16_t udpPort = 0; - uint16_t tcpPort = 0; + uint16_t udpPort; + uint16_t tcpPort; operator bi::udp::endpoint() const { return std::move(bi::udp::endpoint(address, udpPort)); } operator bi::tcp::endpoint() const { return std::move(bi::tcp::endpoint(address, tcpPort)); } @@ -176,7 +180,6 @@ struct NodeIPEndpoint struct Node { - Node(): endpoint(NodeIPEndpoint()) {}; Node(Public _pubk, NodeIPEndpoint _ip, bool _required = false): id(_pubk), endpoint(_ip), required(_required) {} virtual NodeId const& address() const { return id; } diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 31a612128..7ddef0857 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -144,7 +144,7 @@ Node NodeTable::node(NodeId const& _id) Node n(_id, entry->endpoint, entry->required); return move(n); } - return move(Node()); + return UnspecifiedNode; } shared_ptr NodeTable::nodeEntry(NodeId _id) diff --git a/libp2p/Peer.h b/libp2p/Peer.h index 18809d075..547d7371f 100644 --- a/libp2p/Peer.h +++ b/libp2p/Peer.h @@ -57,6 +57,7 @@ class Peer: public Node friend class RLPXHandshake; public: + Peer(): Node(NodeId(), UnspecifiedNodeIPEndpoint) {} bool isOffline() const { return !m_session.lock(); } virtual bool operator<(Peer const& _p) const; From 91a8522a9bd60e56d20de5ae39e71504ac3b2eb1 Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 15 Apr 2015 22:51:09 -0400 Subject: [PATCH 06/12] Strict Peer construction. --- libp2p/Host.cpp | 47 ++++++++++++++++++++++++++++------------------- libp2p/Peer.h | 4 +++- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index ae213d71d..5c20bbd7f 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -175,16 +175,28 @@ void Host::doneWorking() void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameIO* _io, bi::tcp::endpoint _endpoint) { shared_ptr p; - if (!m_peers.count(_id)) { - p.reset(new Peer()); - p->id = _id; + RecursiveGuard l(x_sessions); + if (!m_peers.count(_id)) + { + // peer doesn't exist, try to get info from node table + Node n = m_nodeTable->node(_id); + if (!n) + { + n.id = _id; + n.endpoint = NodeIPEndpoint(_endpoint.address(), 0, 0); + } + + p.reset(new Peer(n)); + } + else + { + p = m_peers[_id]; + p->endpoint.address = _endpoint.address(); + } } - else - p = m_peers[_id]; if (p->isOffline()) p->m_lastConnected = std::chrono::system_clock::now(); - p->endpoint.address = _endpoint.address(); auto protocolVersion = _rlp[0].toInt(); auto clientVersion = _rlp[1].toString(); @@ -248,17 +260,16 @@ void Host::onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e) { RecursiveGuard l(x_sessions); if (m_peers.count(_n)) + { p = m_peers[_n]; + p->endpoint = n.endpoint; + } else { - p.reset(new Peer()); - p->id = _n; - p->required = n.required; + p.reset(new Peer(n)); m_peers[_n] = p; - clog(NetNote) << "p2p.host.peers.events.peersAdded " << _n << p->endpoint; } - p->endpoint = n.endpoint; } // TODO: Implement similar to discover. Attempt connecting to nodes @@ -405,15 +416,16 @@ void Host::requirePeer(NodeId const& _n, NodeIPEndpoint const& _endpoint) { RecursiveGuard l(x_sessions); if (m_peers.count(_n)) + { p = m_peers[_n]; + p->endpoint = node.endpoint; + p->required = true; + } else { - p.reset(new Peer()); - p->id = _n; - p->required = true; + p.reset(new Peer(node)); m_peers[_n] = p; } - p->endpoint = node.endpoint; } connect(p); } @@ -757,16 +769,13 @@ void Host::restoreNetwork(bytesConstRef _b) m_nodeTable->addNode(id, ep); else if (i.itemCount() == 10) { - shared_ptr p = make_shared(); - p->id = id; - p->required = required; + shared_ptr p = make_shared(Node(id, ep, required)); p->m_lastConnected = chrono::system_clock::time_point(chrono::seconds(i[4].toInt())); p->m_lastAttempted = chrono::system_clock::time_point(chrono::seconds(i[5].toInt())); p->m_failedAttempts = i[6].toInt(); p->m_lastDisconnect = (DisconnectReason)i[7].toInt(); p->m_score = (int)i[8].toInt(); p->m_rating = (int)i[9].toInt(); - p->endpoint = ep; m_peers[p->id] = p; if (p->required) requirePeer(p->id, ep); diff --git a/libp2p/Peer.h b/libp2p/Peer.h index 547d7371f..1cf9cd778 100644 --- a/libp2p/Peer.h +++ b/libp2p/Peer.h @@ -57,7 +57,9 @@ class Peer: public Node friend class RLPXHandshake; public: - Peer(): Node(NodeId(), UnspecifiedNodeIPEndpoint) {} + /// Construct Peer from Node. + Peer(Node const& _node): Node(_node.id, _node.endpoint, _node.required) {} + bool isOffline() const { return !m_session.lock(); } virtual bool operator<(Peer const& _p) const; From 0981d9b477ca60999b10ae7edbe4b79973a3e919 Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 15 Apr 2015 23:00:27 -0400 Subject: [PATCH 07/12] revert adding to peer list --- libp2p/Host.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 5c20bbd7f..d9bc9673d 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -177,7 +177,12 @@ void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameIO* _io shared_ptr p; { RecursiveGuard l(x_sessions); - if (!m_peers.count(_id)) + if (m_peers.count(_id)) + { + p = m_peers[_id]; + p->endpoint.address = _endpoint.address(); + } + else { // peer doesn't exist, try to get info from node table Node n = m_nodeTable->node(_id); @@ -189,11 +194,6 @@ void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameIO* _io p.reset(new Peer(n)); } - else - { - p = m_peers[_id]; - p->endpoint.address = _endpoint.address(); - } } if (p->isOffline()) p->m_lastConnected = std::chrono::system_clock::now(); From acffe3687dd87be07df8dc5fb73a5f4ae9b5012a Mon Sep 17 00:00:00 2001 From: subtly Date: Thu, 16 Apr 2015 01:04:12 -0400 Subject: [PATCH 08/12] More peer/node cleanup. --- libp2p/Host.cpp | 46 +++++++++++++++------------------------------- libp2p/Peer.cpp | 2 +- 2 files changed, 16 insertions(+), 32 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index d9bc9673d..4a6e704ec 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -174,29 +174,25 @@ void Host::doneWorking() void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameIO* _io, bi::tcp::endpoint _endpoint) { + // session maybe ingress or egress so m_peers and node table entries may not exist shared_ptr p; + ETH_RECURSIVE_GUARDED(x_sessions) { - RecursiveGuard l(x_sessions); if (m_peers.count(_id)) - { p = m_peers[_id]; - p->endpoint.address = _endpoint.address(); - } else { - // peer doesn't exist, try to get info from node table - Node n = m_nodeTable->node(_id); - if (!n) - { - n.id = _id; - n.endpoint = NodeIPEndpoint(_endpoint.address(), 0, 0); - } - - p.reset(new Peer(n)); + // peer doesn't exist, try to get port info from node table + if (Node n = m_nodeTable->node(_id)) + p.reset(new Peer(n)); + else + p.reset(new Peer(Node(_id, UnspecifiedNodeIPEndpoint))); + m_peers[_id] = p; } } if (p->isOffline()) p->m_lastConnected = std::chrono::system_clock::now(); + p->endpoint.address = _endpoint.address(); auto protocolVersion = _rlp[0].toInt(); auto clientVersion = _rlp[1].toString(); @@ -248,17 +244,15 @@ void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameIO* _io void Host::onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e) { - if (_e == NodeEntryAdded) { clog(NetNote) << "p2p.host.nodeTable.events.nodeEntryAdded " << _n; - - auto n = m_nodeTable->node(_n); - if (n) + // only add iff node is in node table + if (Node n = m_nodeTable->node(_n)) { shared_ptr p; + ETH_RECURSIVE_GUARDED(x_sessions) { - RecursiveGuard l(x_sessions); if (m_peers.count(_n)) { p = m_peers[_n]; @@ -268,18 +262,9 @@ void Host::onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e) { p.reset(new Peer(n)); m_peers[_n] = p; - clog(NetNote) << "p2p.host.peers.events.peersAdded " << _n << p->endpoint; + clog(NetNote) << "p2p.host.peers.events.peerAdded " << _n << p->endpoint; } } - - // TODO: Implement similar to discover. Attempt connecting to nodes - // until ideal peer count is reached; if all nodes are tried, - // repeat. Notably, this is an integrated process such that - // when onNodeTableEvent occurs we should also update +/- - // the list of nodes to be tried. Thus: - // 1) externalize connection attempts - // 2) attempt copies potentialPeer list - // 3) replace this logic w/maintenance of potentialPeers if (peerCount() < m_idealPeerCount) connect(p); } @@ -287,7 +272,6 @@ void Host::onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e) else if (_e == NodeEntryDropped) { clog(NetNote) << "p2p.host.nodeTable.events.NodeEntryDropped " << _n; - RecursiveGuard l(x_sessions); m_peers.erase(_n); } @@ -411,10 +395,10 @@ void Host::requirePeer(NodeId const& _n, NodeIPEndpoint const& _endpoint) Node node(_n, _endpoint, true); if (_n) { - // add or replace peer + // create or update m_peers entry shared_ptr p; + ETH_RECURSIVE_GUARDED(x_sessions) { - RecursiveGuard l(x_sessions); if (m_peers.count(_n)) { p = m_peers[_n]; diff --git a/libp2p/Peer.cpp b/libp2p/Peer.cpp index e37953e12..6f368a4b4 100644 --- a/libp2p/Peer.cpp +++ b/libp2p/Peer.cpp @@ -33,7 +33,7 @@ namespace p2p bool Peer::shouldReconnect() const { - return chrono::system_clock::now() > m_lastAttempted + chrono::seconds(fallbackSeconds()); + return id && endpoint && chrono::system_clock::now() > m_lastAttempted + chrono::seconds(fallbackSeconds()); } unsigned Peer::fallbackSeconds() const From 2dbee779c88f8fd1923e64912edf9859b7ff5d6e Mon Sep 17 00:00:00 2001 From: subtly Date: Thu, 16 Apr 2015 04:07:48 -0400 Subject: [PATCH 09/12] naming. consistent use of uint16_t for port. --- libp2p/Common.h | 4 ++-- libp2p/Host.cpp | 6 +++--- libp2p/NodeTable.cpp | 4 ++-- libp2p/NodeTable.h | 10 +++++----- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/libp2p/Common.h b/libp2p/Common.h index 5b770887f..9ad5bb206 100644 --- a/libp2p/Common.h +++ b/libp2p/Common.h @@ -161,7 +161,7 @@ using PeerSessionInfos = std::vector; */ struct NodeIPEndpoint { - /// Setting true causes isValid to return true for all addresses. Defaults to false. Used by test fixtures. + /// Setting true causes isAllowed to return true for all addresses. (Used by test fixtures) static bool test_allowLocal; NodeIPEndpoint(bi::address _addr, uint16_t _udp, uint16_t _tcp): address(_addr), udpPort(_udp), tcpPort(_tcp) {} @@ -175,7 +175,7 @@ struct NodeIPEndpoint operator bool() const { return !address.is_unspecified() && udpPort > 0 && tcpPort > 0; } - bool isValid() const { return NodeIPEndpoint::test_allowLocal ? true : isPublicAddress(address); } + bool isAllowed() const { return NodeIPEndpoint::test_allowLocal ? !address.is_unspecified() : isPublicAddress(address); } }; struct Node diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 4a6e704ec..f474951b9 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -684,7 +684,7 @@ bytes Host::saveNetwork() const if (!endpoint.address().is_v4()) continue; - if (chrono::system_clock::now() - p.m_lastConnected < chrono::seconds(3600 * 48) && endpoint.port() > 0 && p.id != id() && (p.required || p.endpoint.isValid())) + if (chrono::system_clock::now() - p.m_lastConnected < chrono::seconds(3600 * 48) && endpoint.port() > 0 && p.id != id() && (p.required || p.endpoint.isAllowed())) { network.appendList(10); network << endpoint.port() << p.id << p.required @@ -743,9 +743,9 @@ void Host::restoreNetwork(bytesConstRef _b) continue; // todo: ipv6, bi::address_v6(i[0].toArray() - NodeIPEndpoint ep(bi::address_v4(i[0].toArray()), i[1].toInt(), i[1].toInt()); + NodeIPEndpoint ep({bi::address_v4(i[0].toArray()), i[1].toInt(), i[1].toInt()}); bool required = i[3].toInt(); - if (!ep.isValid() && !required) + if (!ep.isAllowed() && !required) continue; auto id = (NodeId)i[2]; diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 7ddef0857..428b94e7c 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -272,7 +272,7 @@ vector> NodeTable::nearestNodeEntries(NodeId _target) vector> ret; for (auto& nodes: found) for (auto n: nodes.second) - if (n->endpoint.isValid()) + if (n->endpoint.isAllowed()) ret.push_back(n); return move(ret); } @@ -306,7 +306,7 @@ void NodeTable::evict(shared_ptr _leastSeen, shared_ptr _n void NodeTable::noteActiveNode(Public const& _pubk, bi::udp::endpoint const& _endpoint) { - if (_pubk == m_node.address() || !NodeIPEndpoint(_endpoint.address(), _endpoint.port(), _endpoint.port()).isValid()) + if (_pubk == m_node.address() || !NodeIPEndpoint(_endpoint.address(), _endpoint.port(), _endpoint.port()).isAllowed()) return; shared_ptr node = nodeEntry(_pubk); diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index 9e0553590..a308883fb 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -320,8 +320,8 @@ struct PingNode: RLPXDatagram unsigned version = 0; std::string ipAddress; -// unsigned udpPort; - unsigned tcpPort; +// uint16_t udpPort; + uint16_t tcpPort; unsigned ts; void streamRLP(RLPStream& _s) const override; @@ -387,11 +387,11 @@ struct Neighbours: RLPXDatagram Node() = default; Node(RLP const& _r) { interpretRLP(_r); } std::string ipAddress; - unsigned udpPort; -// unsigned tcpPort; + uint16_t udpPort; +// uint16_t tcpPort; NodeId node; void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << udpPort << node; } - void interpretRLP(RLP const& _r) { ipAddress = _r[0].toString(); udpPort = _r[1].toInt(); node = h512(_r[2].toBytes()); } + void interpretRLP(RLP const& _r) { ipAddress = _r[0].toString(); udpPort = _r[1].toInt(); node = h512(_r[2].toBytes()); } }; Neighbours(bi::udp::endpoint _ep): RLPXDatagram(_ep), ts(futureFromEpoch(std::chrono::seconds(30))) {} From fdc28893c44b7ac1f8a4e84f2a311534aa973832 Mon Sep 17 00:00:00 2001 From: subtly Date: Thu, 16 Apr 2015 20:53:12 -0400 Subject: [PATCH 10/12] test constants --- test/net.cpp | 27 +++++++++++++++++++++++++++ test/peer.cpp | 23 +++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/test/net.cpp b/test/net.cpp index ae6053795..fff3c182e 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -343,3 +343,30 @@ BOOST_AUTO_TEST_CASE(test_udp_once) BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE(netTypes) + +BOOST_AUTO_TEST_CASE(unspecifiedNode) +{ + Node n = UnspecifiedNode; + BOOST_REQUIRE(!n); + + Node node(Public(sha3("0")), NodeIPEndpoint(bi::address(), 0, 0)); + BOOST_REQUIRE(node); + BOOST_REQUIRE(n != node); + + Node nodeEq(Public(sha3("0")), NodeIPEndpoint(bi::address(), 0, 0)); + BOOST_REQUIRE_EQUAL(node, nodeEq); +} + +BOOST_AUTO_TEST_CASE(nodeTableReturnsUnspecifiedNode) +{ + ba::io_service io; + NodeTable t(io, KeyPair::create(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), 30303, 30303)); + if (Node n = t.node(NodeId())) + BOOST_REQUIRE(false); + else + BOOST_REQUIRE(n == UnspecifiedNode); +} + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/test/peer.cpp b/test/peer.cpp index 1d593534a..494231e3c 100644 --- a/test/peer.cpp +++ b/test/peer.cpp @@ -112,6 +112,29 @@ BOOST_AUTO_TEST_CASE(save_nodes) BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE(peerTypes) + +BOOST_AUTO_TEST_CASE(emptySharedPeer) +{ + shared_ptr p; + BOOST_REQUIRE(!p); + + std::map> peers; + p = peers[NodeId()]; + BOOST_REQUIRE(!p); + + p.reset(new Peer(UnspecifiedNode)); + BOOST_REQUIRE(!p->id); + BOOST_REQUIRE(!*p); + + p.reset(new Peer(Node(NodeId(EmptySHA3), UnspecifiedNodeIPEndpoint))); + BOOST_REQUIRE(!(!*p)); + BOOST_REQUIRE(*p); + BOOST_REQUIRE(p); +} + +BOOST_AUTO_TEST_SUITE_END() + int peerTest(int argc, char** argv) { Public remoteAlias; From aaf1835c3e0cc279da9e4688eaaf17b19e5a0816 Mon Sep 17 00:00:00 2001 From: subtly Date: Fri, 17 Apr 2015 06:41:45 -0400 Subject: [PATCH 11/12] style --- test/net.cpp | 2 +- test/peer.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/net.cpp b/test/net.cpp index fff3c182e..9a5dbb32f 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -34,7 +34,7 @@ namespace bi = ba::ip; struct NetFixture { - NetFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = true;; } + NetFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = true; } ~NetFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = false; } }; diff --git a/test/peer.cpp b/test/peer.cpp index 494231e3c..8271c1807 100644 --- a/test/peer.cpp +++ b/test/peer.cpp @@ -30,7 +30,7 @@ using namespace dev::p2p; struct P2PFixture { - P2PFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = true;; } + P2PFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = true; } ~P2PFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = false; } }; From db21824064e79e34487f556a06dc02daa7f0f672 Mon Sep 17 00:00:00 2001 From: subtly Date: Fri, 17 Apr 2015 07:54:22 -0400 Subject: [PATCH 12/12] network save/restore: merge fixes, simpler code, limit parse of require flag to peers (reflecting save code). --- libp2p/Host.cpp | 25 +++++++++++-------------- test/peer.cpp | 2 +- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 33dcc6310..fff718295 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -680,14 +680,13 @@ bytes Host::saveNetwork() const { // Only save peers which have connected within 2 days, with properly-advertised port and public IP address // todo: e2e ipv6 support - bi::tcp::endpoint endpoint(p.endpoint); - if (!endpoint.address().is_v4()) + if (!p.endpoint.address.is_v4()) continue; - if (chrono::system_clock::now() - p.m_lastConnected < chrono::seconds(3600 * 48) && endpoint.port() > 0 && p.id != id() && (p.required || p.endpoint.isAllowed())) + if (chrono::system_clock::now() - p.m_lastConnected < chrono::seconds(3600 * 48) && p.endpoint.tcpPort > 0 && p.id != id() && (p.required || p.endpoint.isAllowed())) { network.appendList(10); - network << endpoint.address().to_v4().to_bytes() << endpoint.port() << p.id << p.required + network << p.endpoint.address.to_v4().to_bytes() << p.endpoint.tcpPort << p.id << p.required << chrono::duration_cast(p.m_lastConnected.time_since_epoch()).count() << chrono::duration_cast(p.m_lastAttempted.time_since_epoch()).count() << p.m_failedAttempts << (unsigned)p.m_lastDisconnect << p.m_score << p.m_rating; @@ -743,17 +742,15 @@ void Host::restoreNetwork(bytesConstRef _b) continue; // todo: ipv6, bi::address_v6(i[0].toArray() - NodeIPEndpoint ep({bi::address_v4(i[0].toArray()), i[1].toInt(), i[1].toInt()}); - bool required = i[3].toInt(); - if (!ep.isAllowed() && !required) - continue; - - auto id = (NodeId)i[2]; - if (i.itemCount() == 3) - m_nodeTable->addNode(id, ep); + Node n((NodeId)i[2], NodeIPEndpoint(bi::address_v4(i[0].toArray()), i[1].toInt(), i[1].toInt())); + if (i.itemCount() == 3 && n.endpoint.isAllowed()) + m_nodeTable->addNode(n); else if (i.itemCount() == 10) { - shared_ptr p = make_shared(Node(id, ep, required)); + n.required = i[3].toInt(); + if (!n.endpoint.isAllowed() && !n.required) + continue; + shared_ptr p = make_shared(n); p->m_lastConnected = chrono::system_clock::time_point(chrono::seconds(i[4].toInt())); p->m_lastAttempted = chrono::system_clock::time_point(chrono::seconds(i[5].toInt())); p->m_failedAttempts = i[6].toInt(); @@ -762,7 +759,7 @@ void Host::restoreNetwork(bytesConstRef _b) p->m_rating = (int)i[9].toInt(); m_peers[p->id] = p; if (p->required) - requirePeer(p->id, ep); + requirePeer(p->id, n.endpoint); else m_nodeTable->addNode(*p.get()); } diff --git a/test/peer.cpp b/test/peer.cpp index 459b758ce..727430fc8 100644 --- a/test/peer.cpp +++ b/test/peer.cpp @@ -107,7 +107,7 @@ BOOST_AUTO_TEST_CASE(save_nodes) BOOST_REQUIRE(r.itemCount() == 3); BOOST_REQUIRE(r[0].toInt() == dev::p2p::c_protocolVersion); BOOST_REQUIRE_EQUAL(r[1].toBytes().size(), 32); // secret - BOOST_REQUIRE_EQUAL(r[2].itemCount(), 5); + BOOST_REQUIRE(r[2].itemCount() >= 5); for (auto i: r[2]) {