diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt index 49c847a16..c81c86222 100644 --- a/alethzero/CMakeLists.txt +++ b/alethzero/CMakeLists.txt @@ -19,6 +19,7 @@ find_package (Qt5WebEngine QUIET) find_package (Qt5WebEngineWidgets QUIET) qt5_wrap_ui(ui_Main.h Main.ui) +qt5_wrap_ui(ui_Connect.h Connect.ui) qt5_wrap_ui(ui_Debugger.h Debugger.ui) qt5_wrap_ui(ui_Transact.h Transact.ui) @@ -32,8 +33,8 @@ endif () # eth_add_executable is defined in cmake/EthExecutableHelper.cmake eth_add_executable(${EXECUTABLE} - ICON alethzero - UI_RESOURCES alethzero.icns Main.ui Debugger.ui Transact.ui + ICON alethzero + UI_RESOURCES alethzero.icns Main.ui Connect.ui Debugger.ui Transact.ui WIN_RESOURCES alethzero.rc ) diff --git a/alethzero/Connect.cpp b/alethzero/Connect.cpp new file mode 100644 index 000000000..076ebafe0 --- /dev/null +++ b/alethzero/Connect.cpp @@ -0,0 +1,62 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file Connect.cpp + * @author Alex Leverington + * @date 2015 + */ + +#include "Connect.h" + +#include +#include "ui_Connect.h" + +Connect::Connect(QWidget *parent) : + QDialog(parent), + ui(new Ui::Connect) +{ + reset(); +} + +Connect::~Connect() +{ + delete ui; +} + +void Connect::setEnvironment(QStringList const& _nodes) +{ + ui->host->addItems(_nodes); +} + +void Connect::reset() +{ + ui->setupUi(this); +} + +QString Connect::host() +{ + return ui->host->currentText(); +} + +QString Connect::nodeId() +{ + return ui->nodeId->text(); +} + +bool Connect::required() +{ + return ui->required->isChecked(); +} diff --git a/alethzero/Connect.h b/alethzero/Connect.h new file mode 100644 index 000000000..d8059acd4 --- /dev/null +++ b/alethzero/Connect.h @@ -0,0 +1,50 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file Connect.h + * @author Alex Leverington + * @date 2015 + */ + +#pragma once + +#include +#include + +namespace Ui { class Connect; } +namespace dev { namespace p2p { class Host; } } + +class Connect : public QDialog +{ + Q_OBJECT + +public: + explicit Connect(QWidget *parent = 0); + ~Connect(); + + void setEnvironment(QStringList const& _nodes); + + void reset(); + + QString host(); + + QString nodeId(); + + bool required(); + +private: + Ui::Connect *ui; +}; diff --git a/alethzero/Connect.ui b/alethzero/Connect.ui new file mode 100644 index 000000000..9a0522e5f --- /dev/null +++ b/alethzero/Connect.ui @@ -0,0 +1,123 @@ + + + Connect + + + Qt::WindowModal + + + + 0 + 0 + 343 + 178 + + + + + 0 + 0 + + + + + 343 + 178 + + + + Connect to Peer + + + true + + + + + + + + + 311 + 0 + + + + true + + + + + + + Node Id + + + + + + + Required (Always Connect to this Peer) + + + false + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + Enter a peer to which a connection may be made: + + + + + + + + + buttonBox + accepted() + Connect + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Connect + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/alethzero/Main.ui b/alethzero/Main.ui index 99fea901c..b59c9ce2d 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -134,7 +134,7 @@ - + @@ -283,7 +283,7 @@ - + &Listen on @@ -303,7 +303,7 @@ - + 1024 @@ -316,17 +316,7 @@ - - - - &Client Name - - - clientName - - - - + @@ -339,13 +329,6 @@ - - - - Anonymous - - - @@ -356,20 +339,37 @@ - + Automatic - + Public IP + + + + &Client Name + + + clientName + + + + + + + Anonymous + + + @@ -1456,12 +1456,12 @@ font-size: 14pt Show &Anonymous Accounts - + true - Use &Past Peers + &Drop Past Peers @@ -1709,7 +1709,6 @@ font-size: 14pt idealPeers listenIP port - clientName transactionQueue pendingInfo blockChainFilter diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 1ae139cce..4e5ed49a3 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -28,6 +28,7 @@ //pragma GCC diagnostic ignored "-Werror=pedantic" #include #include +#include #include #include #include @@ -251,8 +252,11 @@ void Main::addNewId(QString _ids) NetworkPreferences Main::netPrefs() const { - return NetworkPreferences(ui->forcePublicIP->text().toStdString(), ui->listenIP->text().toStdString(), ui->port->value(), ui->upnp->isChecked()); -// return NetworkPreferences(ui->port->value(), ui->forceAddress->text().toStdString(), ui->upnp->isChecked(), ui->localNetworking->isChecked()); + auto publicip = ui->forcePublicIP->text().toStdString(); + if (isPublicAddress(publicip)) + return NetworkPreferences(publicip, ui->listenIP->text().toStdString(), ui->port->value(), ui->upnp->isChecked()); + else + return NetworkPreferences(ui->listenIP->text().toStdString(), ui->port->value(), ui->upnp->isChecked()); } void Main::onKeysChanged() @@ -676,10 +680,7 @@ void Main::writeSettings() } s.setValue("upnp", ui->upnp->isChecked()); -#warning fixme -// s.setValue("forceAddress", ui->forceAddress->text()); - s.setValue("usePast", ui->usePast->isChecked()); -// s.setValue("localNetworking", ui->localNetworking->isChecked()); + s.setValue("forceAddress", ui->forcePublicIP->text()); s.setValue("forceMining", ui->forceMining->isChecked()); s.setValue("paranoia", ui->paranoia->isChecked()); s.setValue("natSpec", ui->natSpec->isChecked()); @@ -687,6 +688,7 @@ void Main::writeSettings() s.setValue("showAllAccounts", ui->showAllAccounts->isChecked()); s.setValue("clientName", ui->clientName->text()); s.setValue("idealPeers", ui->idealPeers->value()); + s.setValue("listenIP", ui->listenIP->text()); s.setValue("port", ui->port->value()); s.setValue("url", ui->urlEdit->text()); s.setValue("privateChain", m_privateChain); @@ -746,10 +748,8 @@ void Main::readSettings(bool _skipGeometry) } ui->upnp->setChecked(s.value("upnp", true).toBool()); -#warning fixme -// ui->forceAddress->setText(s.value("forceAddress", "").toString()); - ui->usePast->setChecked(s.value("usePast", true).toBool()); -// ui->localNetworking->setChecked(s.value("localNetworking", true).toBool()); + ui->forcePublicIP->setText(s.value("forceAddress", "").toString()); + ui->dropPeers->setChecked(false); ui->forceMining->setChecked(s.value("forceMining", false).toBool()); on_forceMining_triggered(); ui->paranoia->setChecked(s.value("paranoia", false).toBool()); @@ -760,6 +760,7 @@ void Main::readSettings(bool _skipGeometry) if (ui->clientName->text().isEmpty()) ui->clientName->setText(QInputDialog::getText(nullptr, "Enter identity", "Enter a name that will identify you on the peer network")); ui->idealPeers->setValue(s.value("idealPeers", ui->idealPeers->value()).toInt()); + ui->listenIP->setText(s.value("listenIP", "").toString()); ui->port->setValue(s.value("port", ui->port->value()).toInt()); ui->nameReg->setText(s.value("nameReg", "").toString()); m_privateChain = s.value("privateChain", "").toString(); @@ -1746,11 +1747,8 @@ void Main::on_net_triggered() if (ui->net->isChecked()) { web3()->setIdealPeerCount(ui->idealPeers->value()); - web3()->setNetworkPreferences(netPrefs()); + web3()->setNetworkPreferences(netPrefs(), ui->dropPeers->isChecked()); ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : h256()); - // TODO: p2p -// if (m_networkConfig.size()/* && ui->usePast->isChecked()*/) -// web3()->restoreNetwork(bytesConstRef((byte*)m_networkConfig.data(), m_networkConfig.size())); web3()->startNetwork(); ui->downloadView->setDownloadMan(ethereum()->downloadMan()); } @@ -1768,13 +1766,26 @@ void Main::on_connect_triggered() ui->net->setChecked(true); on_net_triggered(); } - bool ok = false; - QString s = QInputDialog::getItem(this, "Connect to a Network Peer", "Enter a peer to which a connection may be made:", m_servers, m_servers.count() ? rand() % m_servers.count() : 0, true, &ok); - if (ok && s.contains(":")) + + m_connect.setEnvironment(m_servers); + if (m_connect.exec() == QDialog::Accepted) { - string host = s.section(":", 0, 0).toStdString(); - unsigned short port = s.section(":", 1).toInt(); - web3()->connect(host, port); + bool required = m_connect.required(); + string host(m_connect.host().toUtf8().constData()); + NodeId nodeid; + try + { + string nstr(m_connect.nodeId().toUtf8().constData()); + nodeid = NodeId(fromHex(nstr)); + } + catch (BadHexCharacter()) {} + + m_connect.reset(); + + if (required) + web3()->requirePeer(nodeid, host); + else + web3()->addNode(nodeid, host); } } @@ -1885,7 +1896,7 @@ void Main::on_go_triggered() ui->net->setChecked(true); on_net_triggered(); } - web3()->connect(Host::pocHost()); + web3()->addNode(p2p::NodeId(), Host::pocHost()); } QString Main::prettyU256(dev::u256 _n) const diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index ba89b455a..fccbc855d 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -40,6 +40,7 @@ #include "Context.h" #include "Transact.h" #include "NatspecHandler.h" +#include "Connect.h" namespace Ui { class Main; @@ -256,4 +257,6 @@ private: std::unique_ptr m_dappHost; DappLoader* m_dappLoader; QWebEnginePage* m_webPage; + + Connect m_connect; }; diff --git a/eth/main.cpp b/eth/main.cpp index abac6462c..206a6df57 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -421,8 +421,7 @@ int main(int argc, char** argv) StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat); VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter); -#warning fixme - NetworkPreferences netPrefs(listenPort); + auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp); auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp"); std::string clientImplString = "Ethereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM) + (jit ? "/JIT" : ""); dev::WebThreeDirect web3( @@ -450,9 +449,9 @@ int main(int argc, char** argv) web3.startNetwork(); if (bootstrap) - web3.connect(Host::pocHost()); + web3.addNode(p2p::NodeId(), Host::pocHost()); if (remoteHost.size()) - web3.connect(remoteHost, remotePort); + web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort)); #if ETH_JSONRPC shared_ptr jsonrpcServer; @@ -512,7 +511,7 @@ int main(int argc, char** argv) string addr; unsigned port; iss >> addr >> port; - web3.connect(addr, (short)port); + web3.addNode(p2p::NodeId(), addr + ":" + toString(port ? port : p2p::c_defaultIPPort)); } else if (cmd == "netstop") { diff --git a/libp2p/Common.cpp b/libp2p/Common.cpp index 7051322a9..95c96e346 100644 --- a/libp2p/Common.cpp +++ b/libp2p/Common.cpp @@ -25,6 +25,7 @@ using namespace dev; using namespace dev::p2p; const unsigned dev::p2p::c_protocolVersion = 3; +const unsigned dev::p2p::c_defaultIPPort = 30303; bool p2p::isPublicAddress(std::string const& _addressToCheck) { diff --git a/libp2p/Common.h b/libp2p/Common.h index 3303c9c07..c9aee9a0e 100644 --- a/libp2p/Common.h +++ b/libp2p/Common.h @@ -50,7 +50,8 @@ namespace p2p /// Peer network protocol version. extern const unsigned c_protocolVersion; - +extern const unsigned c_defaultIPPort; + using NodeId = h512; bool isPrivateAddress(bi::address const& _addressToCheck); diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 3835b9504..ac9e9671b 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -66,10 +66,6 @@ Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, byte m_alias(networkAlias(_restoreNetwork)), m_lastPing(chrono::steady_clock::time_point::min()) { - for (auto address: m_ifAddresses) - if (address.is_v4()) - clog(NetNote) << "IP Address: " << address << " = " << (isPrivateAddress(address) ? "[LOCAL]" : "[PEER]"); - clog(NetNote) << "Id:" << id(); } @@ -387,7 +383,7 @@ string Host::pocHost() return "poc-" + strs[1] + ".ethdev.com"; } -void Host::addNode(NodeId const& _node, std::string const& _addr, unsigned short _tcpPeerPort, unsigned short _udpNodePort) +void Host::addNode(NodeId const& _node, bi::address const& _addr, unsigned short _udpNodePort, unsigned short _tcpPeerPort) { // TODO: p2p clean this up (bring tested acceptor code over from network branch) while (isWorking() && !m_run) @@ -403,37 +399,14 @@ void Host::addNode(NodeId const& _node, std::string const& _addr, unsigned short cwarn << "Private port being recorded - setting to 0"; _tcpPeerPort = 0; } - - boost::system::error_code ec; - bi::address addr = bi::address::from_string(_addr, ec); - if (ec) - { - bi::tcp::resolver *r = new bi::tcp::resolver(m_ioService); - r->async_resolve({_addr, toString(_tcpPeerPort)}, [=](boost::system::error_code const& _ec, bi::tcp::resolver::iterator _epIt) - { - if (!_ec) - { - bi::tcp::endpoint tcp = *_epIt; - if (m_nodeTable) m_nodeTable->addNode(Node(_node, NodeIPEndpoint(bi::udp::endpoint(tcp.address(), _udpNodePort), tcp))); - } - delete r; - }); - } - else - if (m_nodeTable) m_nodeTable->addNode(Node(_node, NodeIPEndpoint(bi::udp::endpoint(addr, _udpNodePort), bi::tcp::endpoint(addr, _tcpPeerPort)))); -} - -void Host::relinquishPeer(NodeId const& _node) -{ - Guard l(x_requiredPeers); - if (m_requiredPeers.count(_node)) - m_requiredPeers.erase(_node); + + if (m_nodeTable) m_nodeTable->addNode(Node(_node, NodeIPEndpoint(bi::udp::endpoint(_addr, _udpNodePort), bi::tcp::endpoint(_addr, _tcpPeerPort)))); } -void Host::requirePeer(NodeId const& _n, std::string const& _udpAddr, unsigned short _udpPort, std::string const& _tcpAddr, unsigned short _tcpPort) +void Host::requirePeer(NodeId const& _n, bi::address const& _udpAddr, unsigned short _udpPort, bi::address const& _tcpAddr, unsigned short _tcpPort) { - auto naddr = bi::address::from_string(_udpAddr); - auto paddr = _tcpAddr.empty() ? naddr : bi::address::from_string(_tcpAddr); + 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)); @@ -468,11 +441,18 @@ void Host::requirePeer(NodeId const& _n, std::string const& _udpAddr, unsigned s { if (!_ec && m_nodeTable) if (auto n = m_nodeTable->node(_n)) - requirePeer(n.id, n.endpoint.udp.address().to_string(), n.endpoint.udp.port(), n.endpoint.tcp.address().to_string(), n.endpoint.tcp.port()); + requirePeer(n.id, n.endpoint.udp.address(), n.endpoint.udp.port(), n.endpoint.tcp.address(), n.endpoint.tcp.port()); }); } } +void Host::relinquishPeer(NodeId const& _node) +{ + Guard l(x_requiredPeers); + if (m_requiredPeers.count(_node)) + m_requiredPeers.erase(_node); +} + void Host::connect(std::shared_ptr const& _p) { if (!m_run) @@ -760,6 +740,9 @@ void Host::restoreNetwork(bytesConstRef _b) if (!isStarted()) BOOST_THROW_EXCEPTION(NetworkStartRequired()); + if (m_dropPeers) + return; + RecursiveGuard l(x_sessions); RLP r(_b); if (r.itemCount() > 0 && r[0].isInt() && r[0].toInt() == dev::p2p::c_protocolVersion) diff --git a/libp2p/Host.h b/libp2p/Host.h index 7a18380c3..0df24ca79 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -94,6 +94,9 @@ public: /// Default host for current version of client. static std::string pocHost(); + + /// Resolve "host:port" or "ip:port" string as TCP endpoint. Returns unspecified endpoint on failure. + static bi::tcp::endpoint resolveHost(Host& _host, std::string const& _addr) { return Network::resolveHost(_host.m_ioService, _addr); } /// Register a peer-capability; all new peer connections will have this capability. template std::shared_ptr registerCapability(T* _t) { _t->m_host = this; auto ret = std::shared_ptr(_t); m_capabilities[std::make_pair(T::staticName(), T::staticVersion())] = ret; return ret; } @@ -103,10 +106,10 @@ 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, std::string const& _addr, unsigned short _tcpPort, unsigned short _udpPort); + void addNode(NodeId const& _node, bi::address const& _addr, unsigned short _udpPort, unsigned short _tcpPort); /// Create Peer and attempt keeping peer connected. - void requirePeer(NodeId const& _node, std::string const& _udpAddr, unsigned short _udpPort, std::string const& _tcpAddr = "", unsigned short _tcpPort = 0); + void requirePeer(NodeId const& _node, bi::address const& _udpAddr, unsigned short _udpPort, bi::address const& _tcpAddr = bi::address(), unsigned short _tcpPort = 0); /// Note peer as no longer being required. void relinquishPeer(NodeId const& _node); @@ -132,7 +135,7 @@ public: // TODO: P2P this should be combined with peers into a HostStat object of some kind; coalesce data, as it's only used for status information. Peers getPeers() const { RecursiveGuard l(x_sessions); Peers ret; for (auto const& i: m_peers) ret.push_back(*i.second); return ret; } - void setNetworkPreferences(NetworkPreferences const& _p) { auto had = isStarted(); if (had) stop(); m_netPrefs = _p; if (had) start(); } + void setNetworkPreferences(NetworkPreferences const& _p, bool _dropPeers = false) { m_dropPeers = _dropPeers; auto had = isStarted(); if (had) stop(); m_netPrefs = _p; if (had) start(); } /// Start network. @threadsafe void start(); @@ -236,6 +239,7 @@ private: std::chrono::steady_clock::time_point m_lastPing; ///< Time we sent the last ping to all peers. bool m_accepting = false; + bool m_dropPeers = false; }; } diff --git a/libp2p/Network.cpp b/libp2p/Network.cpp index 7be54d9fb..42208ad60 100644 --- a/libp2p/Network.cpp +++ b/libp2p/Network.cpp @@ -27,6 +27,7 @@ #endif #include +#include #include #include @@ -206,3 +207,27 @@ bi::tcp::endpoint Network::traverseNAT(std::set const& _ifAddresses return upnpep; } + +bi::tcp::endpoint Network::resolveHost(ba::io_service& _ioService, string const& _addr) +{ + vector split; + boost::split(split, _addr, boost::is_any_of(":")); + unsigned port = split.size() > 1 ? stoi(split[1]) : c_defaultIPPort; + + bi::tcp::endpoint ep(bi::address(), port); + boost::system::error_code ec; + bi::address address = bi::address::from_string(split[0], ec); + if (!ec) + ep.address(address); + else + { + boost::system::error_code ec; + // resolve returns an iterator (host can resolve to multiple addresses) + bi::tcp::resolver r(_ioService); + auto it = r.resolve({split[0], toString(port)}, ec); + if (!ec) + ep = *it; + } + return ep; +} + diff --git a/libp2p/Network.h b/libp2p/Network.h index 0e3a08398..46034aef3 100644 --- a/libp2p/Network.h +++ b/libp2p/Network.h @@ -54,6 +54,9 @@ public: /// Return public endpoint of upnp interface. If successful o_upnpifaddr will be a private interface address and endpoint will contain public address and port. static bi::tcp::endpoint traverseNAT(std::set const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpifaddr); + + /// Resolve "host:port" string as TCP endpoint. Returns unspecified endpoint on failure. + static bi::tcp::endpoint resolveHost(ba::io_service& _ioService, std::string const& _host); }; struct NetworkPreferences diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index c230c5441..7b9852672 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -101,6 +101,7 @@ shared_ptr NodeTable::addNode(Node const& _node) shared_ptr ret(new NodeEntry(m_node, _node.id, NodeIPEndpoint(_node.endpoint.udp, _node.endpoint.tcp))); m_nodes[_node.id] = ret; ret->cullEndpoint(); + clog(NodeTableConnect) << "addNode pending for" << m_node.endpoint.udp << m_node.endpoint.tcp; PingNode p(_node.endpoint.udp, m_node.endpoint.udp.address().to_string(), m_node.endpoint.udp.port()); p.sign(m_secret); m_socketPointer->send(p); @@ -450,6 +451,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes return; // unsolicited pong; don't note node as active } + clog(NodeTableConnect) << "PONG from " << nodeid.abridged() << _from; break; } @@ -550,31 +552,16 @@ void NodeTable::doRefreshBuckets(boost::system::error_code const& _ec) clog(NodeTableEvent) << "refreshing buckets"; bool connected = m_socketPointer->isOpen(); - bool refreshed = false; if (connected) { - Guard l(x_state); - for (auto& d: m_state) - if (chrono::steady_clock::now() - d.modified > c_bucketRefresh) - { - d.touch(); - while (!d.nodes.empty()) - { - auto n = d.nodes.front(); - if (auto p = n.lock()) - { - refreshed = true; - ping(p.get()); - break; - } - d.nodes.pop_front(); - } - } + NodeId randNodeId; + crypto::Nonce::get().ref().copyTo(randNodeId.ref().cropped(0,h256::size)); + crypto::Nonce::get().ref().copyTo(randNodeId.ref().cropped(h256::size,h256::size)); + discover(randNodeId); } - unsigned nextRefresh = connected ? (refreshed ? 200 : c_bucketRefresh.count()*1000) : 10000; auto runcb = [this](boost::system::error_code const& error) { doRefreshBuckets(error); }; - m_bucketRefreshTimer.expires_from_now(boost::posix_time::milliseconds(nextRefresh)); + m_bucketRefreshTimer.expires_from_now(boost::posix_time::milliseconds(c_bucketRefresh.count())); m_bucketRefreshTimer.async_wait(runcb); } diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index 6a167930d..9ff28b7f1 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -195,7 +195,7 @@ private: /* todo: replace boost::posix_time; change constants to upper camelcase */ boost::posix_time::milliseconds const c_evictionCheckInterval = boost::posix_time::milliseconds(75); ///< Interval at which eviction timeouts are checked. std::chrono::milliseconds const c_reqTimeout = std::chrono::milliseconds(300); ///< How long to wait for requests (evict, find iterations). - std::chrono::seconds const c_bucketRefresh = std::chrono::seconds(3600); ///< Refresh interval prevents bucket from becoming stale. [Kademlia] + std::chrono::milliseconds const c_bucketRefresh = std::chrono::milliseconds(112500); ///< Refresh interval prevents bucket from becoming stale. [Kademlia] struct NodeBucket { diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 65dedb302..dac588149 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -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().to_string(), ep.port(), ep.port()); + m_server->addNode(id, ep.address(), ep.port(), ep.port()); clogS(NetTriviaDetail) << "New peer: " << ep << "(" << id .abridged()<< ")"; CONTINUE:; LAMEPEER:; diff --git a/libwebthree/WebThree.cpp b/libwebthree/WebThree.cpp index 6c6414741..b2c6765b5 100644 --- a/libwebthree/WebThree.cpp +++ b/libwebthree/WebThree.cpp @@ -27,7 +27,6 @@ #include #include -#include #include #include #include @@ -73,12 +72,12 @@ WebThreeDirect::~WebThreeDirect() m_ethereum.reset(); } -void WebThreeDirect::setNetworkPreferences(p2p::NetworkPreferences const& _n) +void WebThreeDirect::setNetworkPreferences(p2p::NetworkPreferences const& _n, bool _dropPeers) { auto had = haveNetwork(); if (had) stopNetwork(); - m_net.setNetworkPreferences(_n); + m_net.setNetworkPreferences(_n, _dropPeers); if (had) startNetwork(); } @@ -103,7 +102,14 @@ bytes WebThreeDirect::saveNetwork() return m_net.saveNetwork(); } -void WebThreeDirect::connect(std::string const& _seedHost, unsigned short _port) +void WebThreeDirect::addNode(NodeId const& _node, bi::tcp::endpoint const& _host) { - m_net.addNode(NodeId(), _seedHost, _port, _port); + m_net.addNode(_node, _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()); +} + + diff --git a/libwebthree/WebThree.h b/libwebthree/WebThree.h index 242639af4..adb691753 100644 --- a/libwebthree/WebThree.h +++ b/libwebthree/WebThree.h @@ -63,9 +63,12 @@ public: /// Same as peers().size(), but more efficient. virtual size_t peerCount() const = 0; - /// Connect to a particular peer. - virtual void connect(std::string const& _seedHost, unsigned short _port) = 0; - + /// Add node to connect to. + virtual void addNode(p2p::NodeId const& _node, bi::tcp::endpoint const& _hostEndpoint) = 0; + + /// Require connection to peer. + virtual void requirePeer(p2p::NodeId const& _node, bi::tcp::endpoint const& _endpoint) = 0; + /// Save peers virtual dev::bytes saveNetwork() = 0; @@ -74,7 +77,7 @@ public: virtual bool haveNetwork() const = 0; - virtual void setNetworkPreferences(p2p::NetworkPreferences const& _n) = 0; + virtual void setNetworkPreferences(p2p::NetworkPreferences const& _n, bool _dropPeers) = 0; virtual p2p::NodeId id() const = 0; @@ -137,22 +140,37 @@ public: /// Same as peers().size(), but more efficient. size_t peerCount() const override; - - /// Connect to a particular peer. - void connect(std::string const& _seedHost, unsigned short _port = 30303) override; - + + /// Add node to connect to. + virtual void addNode(p2p::NodeId const& _node, bi::tcp::endpoint const& _hostEndpoint) override; + + /// Add node to connect to. + void addNode(p2p::NodeId const& _node, std::string const& _hostString) { addNode(_node, resolveHost(_hostString)); } + + /// Add node to connect to. + void addNode(bi::tcp::endpoint const& _endpoint) { addNode(p2p::NodeId(), _endpoint); } + + /// Add node to connect to. + void addNode(std::string const& _hostString) { addNode(p2p::NodeId(), _hostString); } + + /// Require connection to peer. + void requirePeer(p2p::NodeId const& _node, bi::tcp::endpoint const& _endpoint) override; + + /// Require connection to peer. + void requirePeer(p2p::NodeId const& _node, std::string const& _hostString) { requirePeer(_node, resolveHost(_hostString)); } + + /// Resolve "host[:port]" string as TCP endpoint. Returns unspecified endpoint on failure. + bi::tcp::endpoint resolveHost(std::string const& _host) { return haveNetwork() ? p2p::Host::resolveHost(m_net, _host) : bi::tcp::endpoint(); } + /// Save peers dev::bytes saveNetwork() override; -// /// Restore peers -// void restoreNetwork(bytesConstRef _saved) override; - /// Sets the ideal number of peers. void setIdealPeerCount(size_t _n) override; bool haveNetwork() const override { return m_net.isStarted(); } - void setNetworkPreferences(p2p::NetworkPreferences const& _n) override; + void setNetworkPreferences(p2p::NetworkPreferences const& _n, bool _dropPeers = false) override; p2p::NodeId id() const override { return m_net.id(); } diff --git a/neth/main.cpp b/neth/main.cpp index cd0944425..4d9870b44 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -572,9 +572,9 @@ int main(int argc, char** argv) web3.startNetwork(); if (bootstrap) - web3.connect(Host::pocHost()); + web3.addNode(p2p::NodeId(), Host::pocHost()); if (remoteHost.size()) - web3.connect(remoteHost, remotePort); + web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort)); if (c && mining) c->startMining(); @@ -699,7 +699,7 @@ int main(int argc, char** argv) string addr; unsigned port; iss >> addr >> port; - web3.connect(addr, (short)port); + web3.addNode(p2p::NodeId(), addr + ":" + toString(port ? port : p2p::c_defaultIPPort)); } else if (cmd == "netstop") { diff --git a/test/peer.cpp b/test/peer.cpp index b90fc7404..48431504f 100644 --- a/test/peer.cpp +++ b/test/peer.cpp @@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(host) auto node2 = host2.id(); host2.start(); - host1.addNode(node2, "127.0.0.1", host2prefs.listenPort, host2prefs.listenPort); + host1.addNode(node2, bi::address::from_string("127.0.0.1"), host2prefs.listenPort, host2prefs.listenPort); this_thread::sleep_for(chrono::seconds(3)); @@ -73,11 +73,11 @@ BOOST_AUTO_TEST_CASE(save_nodes) Host& host = *hosts.front(); for (auto const& h: hosts) - host.addNode(h->id(), "127.0.0.1", h->listenPort(), h->listenPort()); + host.addNode(h->id(), 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(), "127.0.0.1", h->listenPort(), h->listenPort()); + host2.addNode(h->id(), bi::address::from_string("127.0.0.1"), h->listenPort(), h->listenPort()); this_thread::sleep_for(chrono::milliseconds(2000)); bytes firstHostNetwork(host.saveNetwork()); @@ -122,7 +122,7 @@ int peerTest(int argc, char** argv) Host ph("Test", NetworkPreferences(listenPort)); if (!remoteHost.empty() && !remoteAlias) - ph.addNode(remoteAlias, remoteHost, remotePort, remotePort); + ph.addNode(remoteAlias, bi::address::from_string(remoteHost), remotePort, remotePort); this_thread::sleep_for(chrono::milliseconds(200));