Browse Source

Merge pull request #1436 from subtly/reqpeer

requirePeer
cl-refactor
Gav Wood 10 years ago
parent
commit
6ad2098411
  1. 3
      alethzero/CMakeLists.txt
  2. 63
      alethzero/Connect.cpp
  3. 55
      alethzero/Connect.h
  4. 123
      alethzero/Connect.ui
  5. 74
      alethzero/Main.ui
  6. 70
      alethzero/MainWin.cpp
  7. 3
      alethzero/MainWin.h
  8. 24
      eth/main.cpp
  9. 7
      libp2p/Common.cpp
  10. 1
      libp2p/Common.h
  11. 168
      libp2p/Host.cpp
  12. 33
      libp2p/Host.h
  13. 64
      libp2p/Network.cpp
  14. 24
      libp2p/Network.h
  15. 27
      libp2p/NodeTable.cpp
  16. 2
      libp2p/NodeTable.h
  17. 1
      libp2p/Peer.h
  18. 8
      libp2p/Session.cpp
  19. 7
      libp2p/UDP.h
  20. 16
      libwebthree/WebThree.cpp
  21. 33
      libwebthree/WebThree.h
  22. 30
      neth/main.cpp
  23. 14
      test/peer.cpp

3
alethzero/CMakeLists.txt

@ -19,6 +19,7 @@ find_package (Qt5WebEngine QUIET)
find_package (Qt5WebEngineWidgets QUIET) find_package (Qt5WebEngineWidgets QUIET)
qt5_wrap_ui(ui_Main.h Main.ui) 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_Debugger.h Debugger.ui)
qt5_wrap_ui(ui_Transact.h Transact.ui) qt5_wrap_ui(ui_Transact.h Transact.ui)
@ -33,7 +34,7 @@ endif ()
# eth_add_executable is defined in cmake/EthExecutableHelper.cmake # eth_add_executable is defined in cmake/EthExecutableHelper.cmake
eth_add_executable(${EXECUTABLE} eth_add_executable(${EXECUTABLE}
ICON alethzero ICON alethzero
UI_RESOURCES alethzero.icns Main.ui Debugger.ui Transact.ui UI_RESOURCES alethzero.icns Main.ui Connect.ui Debugger.ui Transact.ui
WIN_RESOURCES alethzero.rc WIN_RESOURCES alethzero.rc
) )

63
alethzero/Connect.cpp

@ -0,0 +1,63 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @file Connect.cpp
* @author Alex Leverington <nessence@gmail.com>
* @date 2015
*/
#include "Connect.h"
#include <libp2p/Host.h>
#include "ui_Connect.h"
Connect::Connect(QWidget *parent) :
QDialog(parent),
ui(new Ui::Connect)
{
ui->setupUi(this);
}
Connect::~Connect()
{
delete ui;
}
void Connect::setEnvironment(QStringList const& _nodes)
{
ui->host->addItems(_nodes);
}
void Connect::reset()
{
ui->nodeId->clear();
ui->required->setChecked(false);
}
QString Connect::host()
{
return ui->host->currentText();
}
QString Connect::nodeId()
{
return ui->nodeId->text();
}
bool Connect::required()
{
return ui->required->isChecked();
}

55
alethzero/Connect.h

@ -0,0 +1,55 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @file Connect.h
* @author Alex Leverington <nessence@gmail.com>
* @date 2015
*/
#pragma once
#include <QDialog>
#include <QList>
namespace Ui { class Connect; }
namespace dev { namespace p2p { class Host; } }
class Connect : public QDialog
{
Q_OBJECT
public:
explicit Connect(QWidget* _parent = 0);
~Connect();
/// Populate host chooser with default host entries.
void setEnvironment(QStringList const& _nodes);
/// Clear dialogue inputs.
void reset();
/// @returns the host string, as chosen or entered by the user. Assumed to be "hostOrIP:port" (:port is optional).
QString host();
/// @returns the identity of the node, as entered by the user. Assumed to be a 64-character hex string.
QString nodeId();
/// @returns true if Required is checked by the user, indicating that the host is a required Peer.
bool required();
private:
Ui::Connect* ui;
};

123
alethzero/Connect.ui

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Connect</class>
<widget class="QDialog" name="Connect">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>343</width>
<height>178</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>343</width>
<height>178</height>
</size>
</property>
<property name="windowTitle">
<string>Connect to Peer</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="1" column="0">
<layout class="QFormLayout" name="formLayout">
<item row="1" column="0" colspan="2">
<widget class="QComboBox" name="host">
<property name="minimumSize">
<size>
<width>311</width>
<height>0</height>
</size>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLineEdit" name="nodeId">
<property name="placeholderText">
<string>Node Id</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="required">
<property name="text">
<string>Required (Always Connect to this Peer)</string>
</property>
<property name="tristate">
<bool>false</bool>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QLabel" name="formLabel">
<property name="text">
<string>Enter a peer to which a connection may be made:</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>Connect</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>Connect</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

74
alethzero/Main.ui

@ -118,7 +118,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1617</width> <width>1617</width>
<height>24</height> <height>22</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="menu_File"> <widget class="QMenu" name="menu_File">
@ -134,8 +134,7 @@
<addaction name="go"/> <addaction name="go"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="upnp"/> <addaction name="upnp"/>
<addaction name="usePast"/> <addaction name="dropPeers"/>
<addaction name="localNetworking"/>
<addaction name="net"/> <addaction name="net"/>
<addaction name="connect"/> <addaction name="connect"/>
</widget> </widget>
@ -284,7 +283,27 @@
</widget> </widget>
<widget class="QWidget" name="layoutWidget"> <widget class="QWidget" name="layoutWidget">
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="2"> <item row="3" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>&amp;Listen on</string>
</property>
<property name="buddy">
<cstring>port</cstring>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QSpinBox" name="idealPeers">
<property name="minimum">
<number>1</number>
</property>
<property name="value">
<number>5</number>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QSpinBox" name="port"> <widget class="QSpinBox" name="port">
<property name="minimum"> <property name="minimum">
<number>1024</number> <number>1024</number>
@ -297,8 +316,8 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="3" column="1">
<widget class="QLineEdit" name="forceAddress"> <widget class="QLineEdit" name="listenIP">
<property name="inputMask"> <property name="inputMask">
<string/> <string/>
</property> </property>
@ -310,16 +329,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>&amp;Listen on</string>
</property>
<property name="buddy">
<cstring>port</cstring>
</property>
</widget>
</item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label_3"> <widget class="QLabel" name="label_3">
<property name="text"> <property name="text">
@ -330,20 +339,17 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1" colspan="2"> <item row="5" column="1">
<widget class="QSpinBox" name="idealPeers"> <widget class="QLineEdit" name="forcePublicIP">
<property name="minimum"> <property name="placeholderText">
<number>1</number> <string>Automatic</string>
</property>
<property name="value">
<number>5</number>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1" colspan="2"> <item row="5" column="0">
<widget class="QLineEdit" name="clientName"> <widget class="QLabel" name="label_2">
<property name="placeholderText"> <property name="text">
<string>Anonymous</string> <string>Public IP</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -357,6 +363,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1">
<widget class="QLineEdit" name="clientName">
<property name="placeholderText">
<string>Anonymous</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</widget> </widget>
@ -1443,12 +1456,12 @@ font-size: 14pt</string>
<string>Show &amp;Anonymous Accounts</string> <string>Show &amp;Anonymous Accounts</string>
</property> </property>
</action> </action>
<action name="usePast"> <action name="dropPeers">
<property name="checkable"> <property name="checkable">
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="text"> <property name="text">
<string>Use &amp;Past Peers</string> <string>&amp;Drop Past Peers</string>
</property> </property>
</action> </action>
<action name="loadJS"> <action name="loadJS">
@ -1694,9 +1707,8 @@ font-size: 14pt</string>
<tabstop>tabWidget</tabstop> <tabstop>tabWidget</tabstop>
<tabstop>urlEdit</tabstop> <tabstop>urlEdit</tabstop>
<tabstop>idealPeers</tabstop> <tabstop>idealPeers</tabstop>
<tabstop>forceAddress</tabstop> <tabstop>listenIP</tabstop>
<tabstop>port</tabstop> <tabstop>port</tabstop>
<tabstop>clientName</tabstop>
<tabstop>transactionQueue</tabstop> <tabstop>transactionQueue</tabstop>
<tabstop>pendingInfo</tabstop> <tabstop>pendingInfo</tabstop>
<tabstop>blockChainFilter</tabstop> <tabstop>blockChainFilter</tabstop>

70
alethzero/MainWin.cpp

@ -28,6 +28,7 @@
//pragma GCC diagnostic ignored "-Werror=pedantic" //pragma GCC diagnostic ignored "-Werror=pedantic"
#include <QtNetwork/QNetworkReply> #include <QtNetwork/QNetworkReply>
#include <QtWidgets/QFileDialog> #include <QtWidgets/QFileDialog>
#include <QtWidgets/QDialog>
#include <QtWidgets/QMessageBox> #include <QtWidgets/QMessageBox>
#include <QtWidgets/QInputDialog> #include <QtWidgets/QInputDialog>
#include <QtWebEngine/QtWebEngine> #include <QtWebEngine/QtWebEngine>
@ -141,7 +142,7 @@ Main::Main(QWidget *parent) :
#endif #endif
#if ETH_DEBUG #if ETH_DEBUG
m_servers.append("localhost:30300"); m_servers.append("127.0.0.1:30300");
#endif #endif
m_servers.append(QString::fromStdString(Host::pocHost() + ":30303")); m_servers.append(QString::fromStdString(Host::pocHost() + ":30303"));
@ -251,7 +252,30 @@ void Main::addNewId(QString _ids)
NetworkPreferences Main::netPrefs() const NetworkPreferences Main::netPrefs() const
{ {
return NetworkPreferences(ui->port->value(), ui->forceAddress->text().toStdString(), ui->upnp->isChecked(), ui->localNetworking->isChecked()); auto listenIP = ui->listenIP->text().toStdString();
try
{
listenIP = bi::address::from_string(listenIP).to_string();
}
catch (...)
{
listenIP.clear();
}
auto publicIP = ui->forcePublicIP->text().toStdString();
try
{
publicIP = bi::address::from_string(publicIP).to_string();
}
catch (...)
{
publicIP.clear();
}
if (isPublicAddress(publicIP))
return NetworkPreferences(publicIP, listenIP, ui->port->value(), ui->upnp->isChecked());
else
return NetworkPreferences(listenIP, ui->port->value(), ui->upnp->isChecked());
} }
void Main::onKeysChanged() void Main::onKeysChanged()
@ -675,9 +699,7 @@ void Main::writeSettings()
} }
s.setValue("upnp", ui->upnp->isChecked()); s.setValue("upnp", ui->upnp->isChecked());
s.setValue("forceAddress", ui->forceAddress->text()); s.setValue("forceAddress", ui->forcePublicIP->text());
s.setValue("usePast", ui->usePast->isChecked());
s.setValue("localNetworking", ui->localNetworking->isChecked());
s.setValue("forceMining", ui->forceMining->isChecked()); s.setValue("forceMining", ui->forceMining->isChecked());
s.setValue("paranoia", ui->paranoia->isChecked()); s.setValue("paranoia", ui->paranoia->isChecked());
s.setValue("natSpec", ui->natSpec->isChecked()); s.setValue("natSpec", ui->natSpec->isChecked());
@ -685,6 +707,7 @@ void Main::writeSettings()
s.setValue("showAllAccounts", ui->showAllAccounts->isChecked()); s.setValue("showAllAccounts", ui->showAllAccounts->isChecked());
s.setValue("clientName", ui->clientName->text()); s.setValue("clientName", ui->clientName->text());
s.setValue("idealPeers", ui->idealPeers->value()); s.setValue("idealPeers", ui->idealPeers->value());
s.setValue("listenIP", ui->listenIP->text());
s.setValue("port", ui->port->value()); s.setValue("port", ui->port->value());
s.setValue("url", ui->urlEdit->text()); s.setValue("url", ui->urlEdit->text());
s.setValue("privateChain", m_privateChain); s.setValue("privateChain", m_privateChain);
@ -744,9 +767,8 @@ void Main::readSettings(bool _skipGeometry)
} }
ui->upnp->setChecked(s.value("upnp", true).toBool()); ui->upnp->setChecked(s.value("upnp", true).toBool());
ui->forceAddress->setText(s.value("forceAddress", "").toString()); ui->forcePublicIP->setText(s.value("forceAddress", "").toString());
ui->usePast->setChecked(s.value("usePast", true).toBool()); ui->dropPeers->setChecked(false);
ui->localNetworking->setChecked(s.value("localNetworking", true).toBool());
ui->forceMining->setChecked(s.value("forceMining", false).toBool()); ui->forceMining->setChecked(s.value("forceMining", false).toBool());
on_forceMining_triggered(); on_forceMining_triggered();
ui->paranoia->setChecked(s.value("paranoia", false).toBool()); ui->paranoia->setChecked(s.value("paranoia", false).toBool());
@ -757,6 +779,7 @@ void Main::readSettings(bool _skipGeometry)
if (ui->clientName->text().isEmpty()) 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->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->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->port->setValue(s.value("port", ui->port->value()).toInt());
ui->nameReg->setText(s.value("nameReg", "").toString()); ui->nameReg->setText(s.value("nameReg", "").toString());
m_privateChain = s.value("privateChain", "").toString(); m_privateChain = s.value("privateChain", "").toString();
@ -1743,11 +1766,8 @@ void Main::on_net_triggered()
if (ui->net->isChecked()) if (ui->net->isChecked())
{ {
web3()->setIdealPeerCount(ui->idealPeers->value()); web3()->setIdealPeerCount(ui->idealPeers->value());
web3()->setNetworkPreferences(netPrefs()); web3()->setNetworkPreferences(netPrefs(), ui->dropPeers->isChecked());
ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : h256()); 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(); web3()->startNetwork();
ui->downloadView->setDownloadMan(ethereum()->downloadMan()); ui->downloadView->setDownloadMan(ethereum()->downloadMan());
} }
@ -1765,13 +1785,25 @@ void Main::on_connect_triggered()
ui->net->setChecked(true); ui->net->setChecked(true);
on_net_triggered(); 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); m_connect.setEnvironment(m_servers);
if (ok && s.contains(":")) if (m_connect.exec() == QDialog::Accepted)
{ {
string host = s.section(":", 0, 0).toStdString(); bool required = m_connect.required();
unsigned short port = s.section(":", 1).toInt(); string host(m_connect.host().toStdString());
web3()->connect(host, port); NodeId nodeID;
try
{
nodeID = NodeId(fromHex(m_connect.nodeId().toStdString()));
}
catch (BadHexCharacter&) {}
m_connect.reset();
if (required)
web3()->requirePeer(nodeID, host);
else
web3()->addNode(nodeID, host);
} }
} }
@ -1882,7 +1914,7 @@ void Main::on_go_triggered()
ui->net->setChecked(true); ui->net->setChecked(true);
on_net_triggered(); on_net_triggered();
} }
web3()->connect(Host::pocHost()); web3()->addNode(p2p::NodeId(), Host::pocHost());
} }
QString Main::prettyU256(dev::u256 _n) const QString Main::prettyU256(dev::u256 _n) const

3
alethzero/MainWin.h

@ -40,6 +40,7 @@
#include "Context.h" #include "Context.h"
#include "Transact.h" #include "Transact.h"
#include "NatspecHandler.h" #include "NatspecHandler.h"
#include "Connect.h"
namespace Ui { namespace Ui {
class Main; class Main;
@ -256,4 +257,6 @@ private:
std::unique_ptr<DappHost> m_dappHost; std::unique_ptr<DappHost> m_dappHost;
DappLoader* m_dappLoader; DappLoader* m_dappLoader;
QWebEnginePage* m_webPage; QWebEnginePage* m_webPage;
Connect m_connect;
}; };

24
eth/main.cpp

@ -121,8 +121,9 @@ void help()
<< " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: " << SensibleHttpPort << ")." << endl << " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: " << SensibleHttpPort << ")." << endl
#endif #endif
<< " -K,--kill-blockchain First kill the blockchain." << endl << " -K,--kill-blockchain First kill the blockchain." << endl
<< " -l,--listen <port> Listen on the given port for incoming connected (default: 30303)." << endl << " --listen-ip <port> Listen on the given port for incoming connections (default: 30303)." << endl
<< " -L,--local-networking Use peers whose addresses are local." << endl << " -l,--listen <ip> Listen on the given IP for incoming connections (default: 0.0.0.0)." << endl
<< " -u,--public-ip <ip> Force public ip to given (default: auto)." << endl
<< " -m,--mining <on/off/number> Enable mining, optionally for a specified number of blocks (Default: off)" << endl << " -m,--mining <on/off/number> Enable mining, optionally for a specified number of blocks (Default: off)" << endl
<< " -n,--upnp <on/off> Use upnp for NAT (default: on)." << endl << " -n,--upnp <on/off> Use upnp for NAT (default: on)." << endl
<< " -o,--mode <full/peer> Start a full node or a peer node (Default: full)." << endl << " -o,--mode <full/peer> Start a full node or a peer node (Default: full)." << endl
@ -131,7 +132,6 @@ void help()
<< " -r,--remote <host> Connect to remote host (default: none)." << endl << " -r,--remote <host> Connect to remote host (default: none)." << endl
<< " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl << " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl
<< " -t,--miners <number> Number of mining threads to start (Default: " << thread::hardware_concurrency() << ")" << endl << " -t,--miners <number> Number of mining threads to start (Default: " << thread::hardware_concurrency() << ")" << endl
<< " -u,--public-ip <ip> Force public ip to given (default; auto)." << endl
<< " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (Default: 8)." << endl << " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (Default: 8)." << endl
<< " -x,--peers <number> Attempt to connect to given number of peers (Default: 5)." << endl << " -x,--peers <number> Attempt to connect to given number of peers (Default: 5)." << endl
<< " -V,--version Show the version and exit." << endl << " -V,--version Show the version and exit." << endl
@ -199,7 +199,9 @@ enum class NodeMode
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
string listenIP;
unsigned short listenPort = 30303; unsigned short listenPort = 30303;
string publicIP;
string remoteHost; string remoteHost;
unsigned short remotePort = 30303; unsigned short remotePort = 30303;
string dbPath; string dbPath;
@ -211,10 +213,8 @@ int main(int argc, char** argv)
#if ETH_JSONRPC #if ETH_JSONRPC
int jsonrpc = -1; int jsonrpc = -1;
#endif #endif
string publicIP;
bool bootstrap = false; bool bootstrap = false;
bool upnp = true; bool upnp = true;
bool useLocal = false;
bool forceMining = false; bool forceMining = false;
bool killChain = false; bool killChain = false;
bool jit = false; bool jit = false;
@ -250,7 +250,9 @@ int main(int argc, char** argv)
for (int i = 1; i < argc; ++i) for (int i = 1; i < argc; ++i)
{ {
string arg = argv[i]; string arg = argv[i];
if ((arg == "-l" || arg == "--listen" || arg == "--listen-port") && i + 1 < argc) if (arg == "--listen-ip" && i + 1 < argc)
listenIP = argv[++i];
else if ((arg == "-l" || arg == "--listen" || arg == "--listen-port") && i + 1 < argc)
listenPort = (short)atoi(argv[++i]); listenPort = (short)atoi(argv[++i]);
else if ((arg == "-u" || arg == "--public-ip" || arg == "--public") && i + 1 < argc) else if ((arg == "-u" || arg == "--public-ip" || arg == "--public") && i + 1 < argc)
publicIP = argv[++i]; publicIP = argv[++i];
@ -271,8 +273,6 @@ int main(int argc, char** argv)
return -1; return -1;
} }
} }
else if (arg == "-L" || arg == "--local-networking")
useLocal = true;
else if (arg == "-K" || arg == "--kill-blockchain") else if (arg == "-K" || arg == "--kill-blockchain")
killChain = true; killChain = true;
else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc) else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc)
@ -421,7 +421,7 @@ int main(int argc, char** argv)
StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat); StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat);
VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter); VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter);
NetworkPreferences netPrefs(listenPort, publicIP, upnp, useLocal); auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp);
auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp"); 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" : ""); std::string clientImplString = "Ethereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM) + (jit ? "/JIT" : "");
dev::WebThreeDirect web3( dev::WebThreeDirect web3(
@ -449,9 +449,9 @@ int main(int argc, char** argv)
web3.startNetwork(); web3.startNetwork();
if (bootstrap) if (bootstrap)
web3.connect(Host::pocHost()); web3.addNode(p2p::NodeId(), Host::pocHost());
if (remoteHost.size()) if (remoteHost.size())
web3.connect(remoteHost, remotePort); web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort));
#if ETH_JSONRPC #if ETH_JSONRPC
shared_ptr<WebThreeStubServer> jsonrpcServer; shared_ptr<WebThreeStubServer> jsonrpcServer;
@ -511,7 +511,7 @@ int main(int argc, char** argv)
string addr; string addr;
unsigned port; unsigned port;
iss >> addr >> port; iss >> addr >> port;
web3.connect(addr, (short)port); web3.addNode(p2p::NodeId(), addr + ":" + toString(port ? port : p2p::c_defaultIPPort));
} }
else if (cmd == "netstop") else if (cmd == "netstop")
{ {

7
libp2p/Common.cpp

@ -25,10 +25,11 @@ using namespace dev;
using namespace dev::p2p; using namespace dev::p2p;
const unsigned dev::p2p::c_protocolVersion = 3; const unsigned dev::p2p::c_protocolVersion = 3;
const unsigned dev::p2p::c_defaultIPPort = 30303;
bool p2p::isPublicAddress(std::string const& _addressToCheck) bool p2p::isPublicAddress(std::string const& _addressToCheck)
{ {
return isPublicAddress(bi::address::from_string(_addressToCheck)); return _addressToCheck.empty() ? false : isPublicAddress(bi::address::from_string(_addressToCheck));
} }
bool p2p::isPublicAddress(bi::address const& _addressToCheck) bool p2p::isPublicAddress(bi::address const& _addressToCheck)
@ -67,7 +68,7 @@ bool p2p::isPrivateAddress(bi::address const& _addressToCheck)
bool p2p::isPrivateAddress(std::string const& _addressToCheck) bool p2p::isPrivateAddress(std::string const& _addressToCheck)
{ {
return isPrivateAddress(bi::address::from_string(_addressToCheck)); return _addressToCheck.empty() ? false : isPrivateAddress(bi::address::from_string(_addressToCheck));
} }
// Helper function to determine if an address is localhost // Helper function to determine if an address is localhost
@ -86,7 +87,7 @@ bool p2p::isLocalHostAddress(bi::address const& _addressToCheck)
bool p2p::isLocalHostAddress(std::string const& _addressToCheck) bool p2p::isLocalHostAddress(std::string const& _addressToCheck)
{ {
return isLocalHostAddress(bi::address::from_string(_addressToCheck)); return _addressToCheck.empty() ? false : isLocalHostAddress(bi::address::from_string(_addressToCheck));
} }
std::string p2p::reasonOf(DisconnectReason _r) std::string p2p::reasonOf(DisconnectReason _r)

1
libp2p/Common.h

@ -50,6 +50,7 @@ namespace p2p
/// Peer network protocol version. /// Peer network protocol version.
extern const unsigned c_protocolVersion; extern const unsigned c_protocolVersion;
extern const unsigned c_defaultIPPort;
using NodeId = h512; using NodeId = h512;

168
libp2p/Host.cpp

@ -66,10 +66,6 @@ Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, byte
m_alias(networkAlias(_restoreNetwork)), m_alias(networkAlias(_restoreNetwork)),
m_lastPing(chrono::steady_clock::time_point::min()) 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(); clog(NetNote) << "Id:" << id();
} }
@ -287,67 +283,53 @@ void Host::onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e)
} }
} }
void Host::determinePublic(string const& _publicAddress, bool _upnp) void Host::determinePublic()
{ {
m_peerAddresses.clear(); // set m_tcpPublic := listenIP (if public) > public > upnp > unspecified address.
// no point continuing if there are no interface addresses or valid listen port auto ifAddresses = Network::getInterfaceAddresses();
if (!m_ifAddresses.size() || m_listenPort < 1) auto laddr = m_netPrefs.listenIPAddress.empty() ? bi::address() : bi::address::from_string(m_netPrefs.listenIPAddress);
return; auto lset = !laddr.is_unspecified();
auto paddr = m_netPrefs.publicIPAddress.empty() ? bi::address() : bi::address::from_string(m_netPrefs.publicIPAddress);
auto pset = !paddr.is_unspecified();
// populate interfaces we'll listen on (eth listens on all interfaces); ignores local bool listenIsPublic = lset && isPublicAddress(laddr);
for (auto addr: m_ifAddresses) bool publicIsHost = !lset && pset && ifAddresses.count(paddr);
if ((m_netPrefs.localNetworking || !isPrivateAddress(addr)) && !isLocalHostAddress(addr))
m_peerAddresses.insert(addr);
// if user supplied address is a public address then we use it
// if user supplied address is private, and localnetworking is enabled, we use it
bi::address reqPublicAddr(bi::address(_publicAddress.empty() ? bi::address() : bi::address::from_string(_publicAddress)));
bi::tcp::endpoint reqPublic(reqPublicAddr, m_listenPort);
bool isprivate = isPrivateAddress(reqPublicAddr);
bool ispublic = !isprivate && !isLocalHostAddress(reqPublicAddr);
if (!reqPublicAddr.is_unspecified() && (ispublic || (isprivate && m_netPrefs.localNetworking)))
{
if (!m_peerAddresses.count(reqPublicAddr))
m_peerAddresses.insert(reqPublicAddr);
m_tcpPublic = reqPublic;
return;
}
// if address wasn't provided, then use first public ipv4 address found bi::tcp::endpoint ep(bi::address(), m_netPrefs.listenPort);
for (auto addr: m_peerAddresses) if (m_netPrefs.traverseNAT && listenIsPublic)
if (addr.is_v4() && !isPrivateAddress(addr))
{ {
m_tcpPublic = bi::tcp::endpoint(*m_peerAddresses.begin(), m_listenPort); clog(NetNote) << "Listen address set to Public address:" << laddr << ". UPnP disabled.";
return; ep.address(laddr);
} }
else if (m_netPrefs.traverseNAT && publicIsHost)
// or find address via upnp
if (_upnp)
{ {
bi::address upnpifaddr; clog(NetNote) << "Public address set to Host configured address:" << paddr << ". UPnP disabled.";
bi::tcp::endpoint upnpep = Network::traverseNAT(m_ifAddresses, m_listenPort, upnpifaddr); ep.address(paddr);
if (!upnpep.address().is_unspecified() && !upnpifaddr.is_unspecified())
{
if (!m_peerAddresses.count(upnpep.address()))
m_peerAddresses.insert(upnpep.address());
m_tcpPublic = upnpep;
return;
}
} }
else if (m_netPrefs.traverseNAT)
{
bi::address natIFAddr;
if (lset && ifAddresses.count(laddr))
ep = Network::traverseNAT(std::set<bi::address>({laddr}), m_netPrefs.listenPort, natIFAddr);
else
ep = Network::traverseNAT(ifAddresses, m_netPrefs.listenPort, natIFAddr);
// or if no address provided, use private ipv4 address if local networking is enabled if (lset && natIFAddr != laddr)
if (reqPublicAddr.is_unspecified()) // if listen address is set, Host will use it, even if upnp returns different
if (m_netPrefs.localNetworking) clog(NetWarn) << "Listen address" << laddr << "differs from local address" << natIFAddr << "returned by UPnP!";
for (auto addr: m_peerAddresses)
if (addr.is_v4() && isPrivateAddress(addr)) if (pset && ep.address() != paddr)
{ {
m_tcpPublic = bi::tcp::endpoint(addr, m_listenPort); // if public address is set, Host will advertise it, even if upnp returns different
return; clog(NetWarn) << "Specified public address" << paddr << "differs from external address" << ep.address() << "returned by UPnP!";
ep.address(paddr);
}
} }
else if (pset)
ep.address(paddr);
// otherwise address is unspecified m_tcpPublic = ep;
m_tcpPublic = bi::tcp::endpoint(bi::address(), m_listenPort);
} }
void Host::runAcceptor() void Host::runAcceptor()
@ -401,7 +383,7 @@ string Host::pocHost()
return "poc-" + strs[1] + ".ethdev.com"; 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) // TODO: p2p clean this up (bring tested acceptor code over from network branch)
while (isWorking() && !m_run) while (isWorking() && !m_run)
@ -418,23 +400,58 @@ void Host::addNode(NodeId const& _node, std::string const& _addr, unsigned short
_tcpPeerPort = 0; _tcpPeerPort = 0;
} }
boost::system::error_code ec; if (m_nodeTable)
bi::address addr = bi::address::from_string(_addr, ec); m_nodeTable->addNode(Node(_node, NodeIPEndpoint(bi::udp::endpoint(_addr, _udpNodePort), bi::tcp::endpoint(_addr, _tcpPeerPort))));
if (ec) }
void Host::requirePeer(NodeId const& _n, bi::address const& _udpAddr, unsigned short _udpPort, bi::address const& _tcpAddr, unsigned short _tcpPort)
{ {
bi::tcp::resolver *r = new bi::tcp::resolver(m_ioService); auto naddr = _udpAddr;
r->async_resolve({_addr, toString(_tcpPeerPort)}, [=](boost::system::error_code const& _ec, bi::tcp::resolver::iterator _epIt) 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));
if (_n)
{ {
if (!_ec) // add or replace peer
shared_ptr<Peer> p;
{
RecursiveGuard l(x_sessions);
if (m_peers.count(_n))
p = m_peers[_n];
else
{ {
bi::tcp::endpoint tcp = *_epIt; p.reset(new Peer());
if (m_nodeTable) m_nodeTable->addNode(Node(_node, NodeIPEndpoint(bi::udp::endpoint(tcp.address(), _udpNodePort), tcp))); p->id = _n;
p->required = true;
m_peers[_n] = p;
}
p->endpoint.udp = node.endpoint.udp;
p->endpoint.tcp = node.endpoint.tcp;
} }
delete r; connect(p);
}
else if (m_nodeTable)
{
shared_ptr<boost::asio::deadline_timer> t(new boost::asio::deadline_timer(m_ioService));
m_timers.push_back(t);
m_nodeTable->addNode(node);
t->expires_from_now(boost::posix_time::milliseconds(600));
t->async_wait([this, _n](boost::system::error_code const& _ec)
{
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());
}); });
} }
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);
} }
void Host::connect(std::shared_ptr<Peer> const& _p) void Host::connect(std::shared_ptr<Peer> const& _p)
@ -485,6 +502,9 @@ void Host::connect(std::shared_ptr<Peer> const& _p)
Guard l(x_connecting); Guard l(x_connecting);
m_connecting.push_back(handshake); m_connecting.push_back(handshake);
} }
// preempt setting failedAttempts; this value is cleared upon success
_p->m_failedAttempts++;
handshake->start(); handshake->start();
} }
@ -541,6 +561,13 @@ void Host::run(boost::system::error_code const&)
Guard l(x_connecting); Guard l(x_connecting);
m_connecting.remove_if([](std::weak_ptr<RLPXHandshake> h){ return h.lock(); }); m_connecting.remove_if([](std::weak_ptr<RLPXHandshake> h){ return h.lock(); });
} }
{
Guard l(x_timers);
m_timers.remove_if([](std::shared_ptr<boost::asio::deadline_timer> t)
{
return t->expires_from_now().total_milliseconds() > 0;
});
}
for (auto p: m_sessions) for (auto p: m_sessions)
if (auto pp = p.second.lock()) if (auto pp = p.second.lock())
@ -597,21 +624,21 @@ void Host::startedWorking()
h.second->onStarting(); h.second->onStarting();
// try to open acceptor (todo: ipv6) // try to open acceptor (todo: ipv6)
m_listenPort = Network::tcp4Listen(m_tcp4Acceptor, m_netPrefs.listenPort); m_listenPort = Network::tcp4Listen(m_tcp4Acceptor, m_netPrefs);
// determine public IP, but only if we're able to listen for connections // determine public IP, but only if we're able to listen for connections
// todo: GUI when listen is unavailable in UI // todo: GUI when listen is unavailable in UI
if (m_listenPort) if (m_listenPort)
{ {
determinePublic(m_netPrefs.publicIP, m_netPrefs.upnp); determinePublic();
if (m_listenPort > 0) if (m_listenPort > 0)
runAcceptor(); runAcceptor();
} }
else else
clog(NetNote) << "p2p.start.notice id:" << id().abridged() << "Listen port is invalid or unavailable. Node Table using default port (30303)."; clog(NetNote) << "p2p.start.notice id:" << id().abridged() << "TCP Listen port is invalid or unavailable.";
m_nodeTable.reset(new NodeTable(m_ioService, m_alias, bi::address::from_string(listenAddress()), listenPort() > 0 ? listenPort() : 30303)); m_nodeTable.reset(new NodeTable(m_ioService, m_alias, bi::address::from_string(listenAddress()), listenPort()));
m_nodeTable->setEventHandler(new HostNodeTableHandler(*this)); m_nodeTable->setEventHandler(new HostNodeTableHandler(*this));
restoreNetwork(&m_restoreNetwork); restoreNetwork(&m_restoreNetwork);
@ -720,6 +747,9 @@ void Host::restoreNetwork(bytesConstRef _b)
if (!isStarted()) if (!isStarted())
BOOST_THROW_EXCEPTION(NetworkStartRequired()); BOOST_THROW_EXCEPTION(NetworkStartRequired());
if (m_dropPeers)
return;
RecursiveGuard l(x_sessions); RecursiveGuard l(x_sessions);
RLP r(_b); RLP r(_b);
if (r.itemCount() > 0 && r[0].isInt() && r[0].toInt<unsigned>() == dev::p2p::c_protocolVersion) if (r.itemCount() > 0 && r[0].isInt() && r[0].toInt<unsigned>() == dev::p2p::c_protocolVersion)

33
libp2p/Host.h

@ -70,9 +70,7 @@ private:
* @brief The Host class * @brief The Host class
* Capabilities should be registered prior to startNetwork, since m_capabilities is not thread-safe. * Capabilities should be registered prior to startNetwork, since m_capabilities is not thread-safe.
* *
* @todo cleanup startPeerSession
* @todo determinePublic: ipv6, udp * @todo determinePublic: ipv6, udp
* @todo handle conflict if addNode/requireNode called and Node already exists w/conflicting tcp or udp port
* @todo per-session keepalive/ping instead of broadcast; set ping-timeout via median-latency * @todo per-session keepalive/ping instead of broadcast; set ping-timeout via median-latency
*/ */
class Host: public Worker class Host: public Worker
@ -105,7 +103,13 @@ public:
template <class T> std::shared_ptr<T> cap() const { try { return std::static_pointer_cast<T>(m_capabilities.at(std::make_pair(T::staticName(), T::staticVersion()))); } catch (...) { return nullptr; } } template <class T> std::shared_ptr<T> cap() const { try { return std::static_pointer_cast<T>(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. /// 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, 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);
/// Set ideal number of peers. /// Set ideal number of peers.
void setIdealPeerCount(unsigned _n) { m_idealPeerCount = _n; } void setIdealPeerCount(unsigned _n) { m_idealPeerCount = _n; }
@ -117,10 +121,10 @@ public:
size_t peerCount() const; size_t peerCount() const;
/// Get the address we're listening on currently. /// Get the address we're listening on currently.
std::string listenAddress() const { return m_tcpPublic.address().to_string(); } std::string listenAddress() const { return m_netPrefs.listenIPAddress.empty() ? "0.0.0.0" : m_netPrefs.listenIPAddress; }
/// Get the port we're listening on currently. /// Get the port we're listening on currently.
unsigned short listenPort() const { return m_tcpPublic.port(); } unsigned short listenPort() const { return m_netPrefs.listenPort; }
/// Serialise the set of known peers. /// Serialise the set of known peers.
bytes saveNetwork() const; bytes saveNetwork() const;
@ -128,7 +132,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. // 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; } 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 /// Start network. @threadsafe
void start(); void start();
@ -154,8 +158,8 @@ protected:
private: private:
bool havePeerSession(NodeId _id) { RecursiveGuard l(x_sessions); return m_sessions.count(_id) ? !!m_sessions[_id].lock() : false; } bool havePeerSession(NodeId _id) { RecursiveGuard l(x_sessions); return m_sessions.count(_id) ? !!m_sessions[_id].lock() : false; }
/// Populate m_peerAddresses with available public addresses. /// Determines and sets m_tcpPublic to publicly advertised address.
void determinePublic(std::string const& _publicAddress, bool _upnp); void determinePublic();
void connect(std::shared_ptr<Peer> const& _p); void connect(std::shared_ptr<Peer> const& _p);
@ -192,7 +196,7 @@ private:
NetworkPreferences m_netPrefs; ///< Network settings. NetworkPreferences m_netPrefs; ///< Network settings.
/// Interface addresses (private, public) /// Interface addresses (private, public)
std::vector<bi::address> m_ifAddresses; ///< Interface addresses. std::set<bi::address> m_ifAddresses; ///< Interface addresses.
int m_listenPort = -1; ///< What port are we listening on. -1 means binding failed or acceptor hasn't been initialized. int m_listenPort = -1; ///< What port are we listening on. -1 means binding failed or acceptor hasn't been initialized.
@ -212,6 +216,10 @@ private:
/// Shared storage of Peer objects. Peers are created or destroyed on demand by the Host. Active sessions maintain a shared_ptr to a Peer; /// Shared storage of Peer objects. Peers are created or destroyed on demand by the Host. Active sessions maintain a shared_ptr to a Peer;
std::map<NodeId, std::shared_ptr<Peer>> m_peers; std::map<NodeId, std::shared_ptr<Peer>> m_peers;
/// Peers we try to connect regardless of p2p network.
std::set<NodeId> m_requiredPeers;
Mutex x_requiredPeers;
/// The nodes to which we are currently connected. Used by host to service peer requests and keepAlivePeers and for shutdown. (see run()) /// The nodes to which we are currently connected. Used by host to service peer requests and keepAlivePeers and for shutdown. (see run())
/// Mutable because we flush zombie entries (null-weakptrs) as regular maintenance from a const method. /// Mutable because we flush zombie entries (null-weakptrs) as regular maintenance from a const method.
mutable std::map<NodeId, std::weak_ptr<Session>> m_sessions; mutable std::map<NodeId, std::weak_ptr<Session>> m_sessions;
@ -222,12 +230,15 @@ private:
unsigned m_idealPeerCount = 5; ///< Ideal number of peers to be connected to. unsigned m_idealPeerCount = 5; ///< Ideal number of peers to be connected to.
std::set<bi::address> m_peerAddresses; ///< Public addresses that peers (can) know us by.
std::map<CapDesc, std::shared_ptr<HostCapabilityFace>> m_capabilities; ///< Each of the capabilities we support. std::map<CapDesc, std::shared_ptr<HostCapabilityFace>> m_capabilities; ///< Each of the capabilities we support.
/// Deadline timers used for isolated network events. GC'd by run.
std::list<std::shared_ptr<boost::asio::deadline_timer>> m_timers;
Mutex x_timers;
std::chrono::steady_clock::time_point m_lastPing; ///< Time we sent the last ping to all peers. std::chrono::steady_clock::time_point m_lastPing; ///< Time we sent the last ping to all peers.
bool m_accepting = false; bool m_accepting = false;
bool m_dropPeers = false;
}; };
} }

64
libp2p/Network.cpp

@ -27,6 +27,7 @@
#endif #endif
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/split.hpp>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/Assertions.h> #include <libdevcore/Assertions.h>
@ -40,9 +41,9 @@ using namespace std;
using namespace dev; using namespace dev;
using namespace dev::p2p; using namespace dev::p2p;
std::vector<bi::address> Network::getInterfaceAddresses() std::set<bi::address> Network::getInterfaceAddresses()
{ {
std::vector<bi::address> addresses; std::set<bi::address> addresses;
#ifdef _WIN32 #ifdef _WIN32
WSAData wsaData; WSAData wsaData;
@ -72,7 +73,7 @@ std::vector<bi::address> Network::getInterfaceAddresses()
char *addrStr = inet_ntoa(addr); char *addrStr = inet_ntoa(addr);
bi::address address(bi::address::from_string(addrStr)); bi::address address(bi::address::from_string(addrStr));
if (!isLocalHostAddress(address)) if (!isLocalHostAddress(address))
addresses.push_back(address.to_v4()); addresses.insert(address.to_v4());
} }
WSACleanup(); WSACleanup();
@ -91,7 +92,7 @@ std::vector<bi::address> Network::getInterfaceAddresses()
in_addr addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; in_addr addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
boost::asio::ip::address_v4 address(boost::asio::detail::socket_ops::network_to_host_long(addr.s_addr)); boost::asio::ip::address_v4 address(boost::asio::detail::socket_ops::network_to_host_long(addr.s_addr));
if (!isLocalHostAddress(address)) if (!isLocalHostAddress(address))
addresses.push_back(address); addresses.insert(address);
} }
else if (ifa->ifa_addr->sa_family == AF_INET6) else if (ifa->ifa_addr->sa_family == AF_INET6)
{ {
@ -101,7 +102,7 @@ std::vector<bi::address> Network::getInterfaceAddresses()
memcpy(&bytes[0], addr.s6_addr, 16); memcpy(&bytes[0], addr.s6_addr, 16);
boost::asio::ip::address_v6 address(bytes, sockaddr->sin6_scope_id); boost::asio::ip::address_v6 address(bytes, sockaddr->sin6_scope_id);
if (!isLocalHostAddress(address)) if (!isLocalHostAddress(address))
addresses.push_back(address); addresses.insert(address);
} }
} }
@ -113,13 +114,14 @@ std::vector<bi::address> Network::getInterfaceAddresses()
return std::move(addresses); return std::move(addresses);
} }
int Network::tcp4Listen(bi::tcp::acceptor& _acceptor, unsigned short _listenPort) int Network::tcp4Listen(bi::tcp::acceptor& _acceptor, NetworkPreferences const& _netPrefs)
{ {
int retport = -1; int retport = -1;
if (_netPrefs.listenIPAddress.empty())
for (unsigned i = 0; i < 2; ++i) for (unsigned i = 0; i < 2; ++i)
{ {
// try to connect w/listenPort, else attempt net-allocated port // try to connect w/listenPort, else attempt net-allocated port
bi::tcp::endpoint endpoint(bi::tcp::v4(), i ? 0 : _listenPort); bi::tcp::endpoint endpoint(bi::tcp::v4(), i ? 0 : _netPrefs.listenPort);
try try
{ {
_acceptor.open(endpoint.protocol()); _acceptor.open(endpoint.protocol());
@ -142,10 +144,28 @@ int Network::tcp4Listen(bi::tcp::acceptor& _acceptor, unsigned short _listenPort
continue; continue;
} }
} }
else
{
bi::tcp::endpoint endpoint(bi::address::from_string(_netPrefs.listenIPAddress), _netPrefs.listenPort);
try
{
_acceptor.open(endpoint.protocol());
_acceptor.set_option(ba::socket_base::reuse_address(true));
_acceptor.bind(endpoint);
_acceptor.listen();
retport = _acceptor.local_endpoint().port();
}
catch (...)
{
clog(NetWarn) << "Couldn't start accepting connections on host. Failed to accept socket.\n" << boost::current_exception_diagnostic_information();
}
assert(retport == _netPrefs.listenPort);
return retport;
}
return retport; return retport;
} }
bi::tcp::endpoint Network::traverseNAT(std::vector<bi::address> const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpInterfaceAddr) bi::tcp::endpoint Network::traverseNAT(std::set<bi::address> const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpInterfaceAddr)
{ {
asserts(_listenPort != 0); asserts(_listenPort != 0);
@ -187,3 +207,31 @@ bi::tcp::endpoint Network::traverseNAT(std::vector<bi::address> const& _ifAddres
return upnpEP; return upnpEP;
} }
bi::tcp::endpoint Network::resolveHost(string const& _addr)
{
static boost::asio::io_service s_resolverIoService;
vector<string> split;
boost::split(split, _addr, boost::is_any_of(":"));
unsigned port = split.size() > 1 ? stoi(split[1]) : dev::p2p::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(s_resolverIoService);
auto it = r.resolve({split[0], toString(port)}, ec);
if (ec)
clog(NetWarn) << "Error resolving host address " << _addr << ":" << ec.message();
else
ep = *it;
}
return ep;
}

24
libp2p/Network.h

@ -39,12 +39,19 @@ namespace p2p
struct NetworkPreferences struct NetworkPreferences
{ {
NetworkPreferences(unsigned short p = 30303, std::string i = std::string(), bool u = true, bool l = false): listenPort(p), publicIP(i), upnp(u), localNetworking(l) {} // Default Network Preferences
NetworkPreferences(unsigned short lp = 30303): listenPort(lp) {}
// Network Preferences with specific Listen IP
NetworkPreferences(std::string const& l, unsigned short lp = 30303, bool u = true): publicIPAddress(), listenIPAddress(l), listenPort(lp), traverseNAT(u) {}
// Network Preferences with intended Public IP
NetworkPreferences(std::string const& publicIP, std::string const& l = std::string(), unsigned short lp = 30303, bool u = true): publicIPAddress(publicIP), listenIPAddress(l), listenPort(lp), traverseNAT(u) { if (!publicIPAddress.empty() && !isPublicAddress(publicIPAddress)) BOOST_THROW_EXCEPTION(InvalidPublicIPAddress()); }
std::string publicIPAddress;
std::string listenIPAddress;
unsigned short listenPort = 30303; unsigned short listenPort = 30303;
std::string publicIP; bool traverseNAT = true;
bool upnp = true;
bool localNetworking = false;
}; };
/** /**
@ -55,13 +62,16 @@ class Network
{ {
public: public:
/// @returns public and private interface addresses /// @returns public and private interface addresses
static std::vector<bi::address> getInterfaceAddresses(); static std::set<bi::address> getInterfaceAddresses();
/// Try to bind and listen on _listenPort, else attempt net-allocated port. /// Try to bind and listen on _listenPort, else attempt net-allocated port.
static int tcp4Listen(bi::tcp::acceptor& _acceptor, unsigned short _listenPort); static int tcp4Listen(bi::tcp::acceptor& _acceptor, NetworkPreferences const& _netPrefs);
/// Return public endpoint of upnp interface. If successful o_upnpifaddr will be a private interface address and endpoint will contain public address and port. /// 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::vector<bi::address> const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpInterfaceAddr); static bi::tcp::endpoint traverseNAT(std::set<bi::address> const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpInterfaceAddr);
/// Resolve "host:port" string as TCP endpoint. Returns unspecified endpoint on failure.
static bi::tcp::endpoint resolveHost(std::string const& _host);
}; };
} }

27
libp2p/NodeTable.cpp

@ -101,6 +101,7 @@ shared_ptr<NodeEntry> NodeTable::addNode(Node const& _node)
shared_ptr<NodeEntry> ret(new NodeEntry(m_node, _node.id, NodeIPEndpoint(_node.endpoint.udp, _node.endpoint.tcp))); shared_ptr<NodeEntry> ret(new NodeEntry(m_node, _node.id, NodeIPEndpoint(_node.endpoint.udp, _node.endpoint.tcp)));
m_nodes[_node.id] = ret; m_nodes[_node.id] = ret;
ret->cullEndpoint(); 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()); PingNode p(_node.endpoint.udp, m_node.endpoint.udp.address().to_string(), m_node.endpoint.udp.port());
p.sign(m_secret); p.sign(m_secret);
m_socketPointer->send(p); 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 return; // unsolicited pong; don't note node as active
} }
clog(NodeTableConnect) << "PONG from " << nodeid.abridged() << _from;
break; break;
} }
@ -550,31 +552,16 @@ void NodeTable::doRefreshBuckets(boost::system::error_code const& _ec)
clog(NodeTableEvent) << "refreshing buckets"; clog(NodeTableEvent) << "refreshing buckets";
bool connected = m_socketPointer->isOpen(); bool connected = m_socketPointer->isOpen();
bool refreshed = false;
if (connected) if (connected)
{ {
Guard l(x_state); NodeId randNodeId;
for (auto& d: m_state) crypto::Nonce::get().ref().copyTo(randNodeId.ref().cropped(0, h256::size));
if (chrono::steady_clock::now() - d.modified > c_bucketRefresh) crypto::Nonce::get().ref().copyTo(randNodeId.ref().cropped(h256::size, h256::size));
{ discover(randNodeId);
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();
}
}
} }
unsigned nextRefresh = connected ? (refreshed ? 200 : c_bucketRefresh.count()*1000) : 10000;
auto runcb = [this](boost::system::error_code const& error) { doRefreshBuckets(error); }; 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); m_bucketRefreshTimer.async_wait(runcb);
} }

2
libp2p/NodeTable.h

@ -195,7 +195,7 @@ private:
/* todo: replace boost::posix_time; change constants to upper camelcase */ /* 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. 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::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 struct NodeBucket
{ {

1
libp2p/Peer.h

@ -47,7 +47,6 @@ namespace p2p
* those peers. Modifying these properties via a storage backend alleviates * those peers. Modifying these properties via a storage backend alleviates
* Host of the responsibility. (&& remove save/restoreNetwork) * Host of the responsibility. (&& remove save/restoreNetwork)
* @todo reimplement recording of historical session information on per-transport basis * @todo reimplement recording of historical session information on per-transport basis
* @todo rebuild nodetable when localNetworking is enabled/disabled
* @todo move attributes into protected * @todo move attributes into protected
*/ */
class Peer: public Node class Peer: public Node

8
libp2p/Session.cpp

@ -216,12 +216,8 @@ bool Session::interpret(PacketType _t, RLP const& _r)
NodeId id = _r[i][2].toHash<NodeId>(); NodeId id = _r[i][2].toHash<NodeId>();
clogS(NetAllDetail) << "Checking: " << ep << "(" << id.abridged() << ")"; clogS(NetAllDetail) << "Checking: " << ep << "(" << id.abridged() << ")";
// clogS(NetAllDetail) << "Checking: " << ep << "(" << id.abridged() << ")" << isPrivateAddress(peerAddress) << this->id().abridged() << isPrivateAddress(endpoint().address()) << m_server->m_peers.count(id) << (m_server->m_peers.count(id) ? isPrivateAddress(m_server->m_peers.at(id)->address.address()) : -1);
// todo: draft spec: ignore if dist(us,item) - dist(us,them) > 1 if (!isPublicAddress(peerAddress))
// TODO: isPrivate
if (!m_server->m_netPrefs.localNetworking && isPrivateAddress(peerAddress))
goto CONTINUE; // Private address. Ignore. goto CONTINUE; // Private address. Ignore.
if (!id) if (!id)
@ -241,7 +237,7 @@ bool Session::interpret(PacketType _t, RLP const& _r)
// OK passed all our checks. Assume it's good. // OK passed all our checks. Assume it's good.
addRating(1000); 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()<< ")"; clogS(NetTriviaDetail) << "New peer: " << ep << "(" << id .abridged()<< ")";
CONTINUE:; CONTINUE:;
LAMEPEER:; LAMEPEER:;

7
libp2p/UDP.h

@ -203,7 +203,10 @@ void UDPSocket<Handler, MaxDatagramSize>::doRead()
auto self(UDPSocket<Handler, MaxDatagramSize>::shared_from_this()); auto self(UDPSocket<Handler, MaxDatagramSize>::shared_from_this());
m_socket.async_receive_from(boost::asio::buffer(m_recvData), m_recvEndpoint, [this, self](boost::system::error_code _ec, size_t _len) m_socket.async_receive_from(boost::asio::buffer(m_recvData), m_recvEndpoint, [this, self](boost::system::error_code _ec, size_t _len)
{ {
if (_ec) // ASIO Safety: It is possible that ASIO will call lambda w/o an error
// and after the socket has been disconnected. Checking m_closed
// guarantees that m_host will not be called after disconnect().
if (_ec || m_closed)
return disconnectWithError(_ec); return disconnectWithError(_ec);
assert(_len); assert(_len);
@ -222,7 +225,7 @@ void UDPSocket<Handler, MaxDatagramSize>::doWrite()
auto self(UDPSocket<Handler, MaxDatagramSize>::shared_from_this()); auto self(UDPSocket<Handler, MaxDatagramSize>::shared_from_this());
m_socket.async_send_to(boost::asio::buffer(datagram.data), datagram.endpoint(), [this, self](boost::system::error_code _ec, std::size_t) m_socket.async_send_to(boost::asio::buffer(datagram.data), datagram.endpoint(), [this, self](boost::system::error_code _ec, std::size_t)
{ {
if (_ec) if (_ec || m_closed)
return disconnectWithError(_ec); return disconnectWithError(_ec);
else else
{ {

16
libwebthree/WebThree.cpp

@ -27,7 +27,6 @@
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libp2p/Host.h>
#include <libethereum/Defaults.h> #include <libethereum/Defaults.h>
#include <libethereum/EthereumHost.h> #include <libethereum/EthereumHost.h>
#include <libwhisper/WhisperHost.h> #include <libwhisper/WhisperHost.h>
@ -73,12 +72,12 @@ WebThreeDirect::~WebThreeDirect()
m_ethereum.reset(); m_ethereum.reset();
} }
void WebThreeDirect::setNetworkPreferences(p2p::NetworkPreferences const& _n) void WebThreeDirect::setNetworkPreferences(p2p::NetworkPreferences const& _n, bool _dropPeers)
{ {
auto had = haveNetwork(); auto had = haveNetwork();
if (had) if (had)
stopNetwork(); stopNetwork();
m_net.setNetworkPreferences(_n); m_net.setNetworkPreferences(_n, _dropPeers);
if (had) if (had)
startNetwork(); startNetwork();
} }
@ -103,7 +102,14 @@ bytes WebThreeDirect::saveNetwork()
return m_net.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());
}

33
libwebthree/WebThree.h

@ -63,8 +63,11 @@ public:
/// Same as peers().size(), but more efficient. /// Same as peers().size(), but more efficient.
virtual size_t peerCount() const = 0; virtual size_t peerCount() const = 0;
/// Connect to a particular peer. /// Add node to connect to.
virtual void connect(std::string const& _seedHost, unsigned short _port) = 0; 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 /// Save peers
virtual dev::bytes saveNetwork() = 0; virtual dev::bytes saveNetwork() = 0;
@ -74,7 +77,7 @@ public:
virtual bool haveNetwork() const = 0; 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; virtual p2p::NodeId id() const = 0;
@ -138,21 +141,33 @@ public:
/// Same as peers().size(), but more efficient. /// Same as peers().size(), but more efficient.
size_t peerCount() const override; size_t peerCount() const override;
/// Connect to a particular peer. /// Add node to connect to.
void connect(std::string const& _seedHost, unsigned short _port = 30303) override; 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, p2p::Network::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, p2p::Network::resolveHost(_hostString)); }
/// Save peers /// Save peers
dev::bytes saveNetwork() override; dev::bytes saveNetwork() override;
// /// Restore peers
// void restoreNetwork(bytesConstRef _saved) override;
/// Sets the ideal number of peers. /// Sets the ideal number of peers.
void setIdealPeerCount(size_t _n) override; void setIdealPeerCount(size_t _n) override;
bool haveNetwork() const override { return m_net.isStarted(); } 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(); } p2p::NodeId id() const override { return m_net.id(); }

30
neth/main.cpp

@ -84,8 +84,9 @@ void help()
<< " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: 8080)." << endl << " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: 8080)." << endl
#endif #endif
<< " -K,--kill-blockchain First kill the blockchain." << endl << " -K,--kill-blockchain First kill the blockchain." << endl
<< " -l,--listen <port> Listen on the given port for incoming connected (default: 30303)." << endl << " --listen-ip <ip> Listen on the given IP for incoming connections (default: 0.0.0.0)." << endl
<< " -L,--local-networking Use peers whose addresses are local." << endl << " -l,--listen <port> Listen on the given port for incoming connections (default: 30303)." << endl
<< " -u,--public-ip <ip> Force public ip to given (default; auto)." << endl
<< " -m,--mining <on/off> Enable mining (default: off)" << endl << " -m,--mining <on/off> Enable mining (default: off)" << endl
<< " -n,--upnp <on/off> Use upnp for NAT (default: on)." << endl << " -n,--upnp <on/off> Use upnp for NAT (default: on)." << endl
<< " -o,--mode <full/peer> Start a full node or a peer node (Default: full)." << endl << " -o,--mode <full/peer> Start a full node or a peer node (Default: full)." << endl
@ -94,7 +95,6 @@ void help()
<< " -r,--remote <host> Connect to remote host (default: none)." << endl << " -r,--remote <host> Connect to remote host (default: none)." << endl
<< " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl << " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl
<< " -t,--miners <number> Number of mining threads to start (Default: " << thread::hardware_concurrency() << ")" << endl << " -t,--miners <number> Number of mining threads to start (Default: " << thread::hardware_concurrency() << ")" << endl
<< " -u,--public-ip <ip> Force public ip to given (default; auto)." << endl
<< " -v,--verbosity <0..9> Set the log verbosity from 0 to 9 (tmp forced to 1)." << endl << " -v,--verbosity <0..9> Set the log verbosity from 0 to 9 (tmp forced to 1)." << endl
<< " -x,--peers <number> Attempt to connect to given number of peers (default: 5)." << endl << " -x,--peers <number> Attempt to connect to given number of peers (default: 5)." << endl
<< " -V,--version Show the version and exit." << endl << " -V,--version Show the version and exit." << endl
@ -321,7 +321,9 @@ enum class NodeMode
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
string listenIP;
unsigned short listenPort = 30303; unsigned short listenPort = 30303;
string publicIP;
string remoteHost; string remoteHost;
unsigned short remotePort = 30303; unsigned short remotePort = 30303;
string dbPath; string dbPath;
@ -332,10 +334,8 @@ int main(int argc, char** argv)
#if ETH_JSONRPC #if ETH_JSONRPC
int jsonrpc = 8080; int jsonrpc = 8080;
#endif #endif
string publicIP;
bool bootstrap = false; bool bootstrap = false;
bool upnp = true; bool upnp = true;
bool useLocal = false;
bool forceMining = false; bool forceMining = false;
bool killChain = false; bool killChain = false;
bool jit = false; bool jit = false;
@ -371,7 +371,9 @@ int main(int argc, char** argv)
for (int i = 1; i < argc; ++i) for (int i = 1; i < argc; ++i)
{ {
string arg = argv[i]; string arg = argv[i];
if ((arg == "-l" || arg == "--listen" || arg == "--listen-port") && i + 1 < argc) if (arg == "--listen-ip" && i + 1 < argc)
listenIP = argv[++i];
else if ((arg == "-l" || arg == "--listen" || arg == "--listen-port") && i + 1 < argc)
listenPort = (short)atoi(argv[++i]); listenPort = (short)atoi(argv[++i]);
else if ((arg == "-u" || arg == "--public-ip" || arg == "--public") && i + 1 < argc) else if ((arg == "-u" || arg == "--public-ip" || arg == "--public") && i + 1 < argc)
publicIP = argv[++i]; publicIP = argv[++i];
@ -392,8 +394,6 @@ int main(int argc, char** argv)
return -1; return -1;
} }
} }
else if (arg == "-L" || arg == "--local-networking")
useLocal = true;
else if (arg == "-K" || arg == "--kill-blockchain") else if (arg == "-K" || arg == "--kill-blockchain")
killChain = true; killChain = true;
else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc) else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc)
@ -535,6 +535,8 @@ int main(int argc, char** argv)
} }
} }
if (!clientName.empty()) if (!clientName.empty())
clientName += "/"; clientName += "/";
@ -542,7 +544,7 @@ int main(int argc, char** argv)
StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat); StructuredLogger::get().initialize(structuredLogging, structuredLoggingFormat);
VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter); VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter);
NetworkPreferences netPrefs(listenPort, publicIP, upnp, useLocal); auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp);
auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp"); auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp");
std::string clientImplString = "NEthereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM) + (jit ? "/JIT" : ""); std::string clientImplString = "NEthereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM) + (jit ? "/JIT" : "");
dev::WebThreeDirect web3( dev::WebThreeDirect web3(
@ -570,9 +572,9 @@ int main(int argc, char** argv)
web3.startNetwork(); web3.startNetwork();
if (bootstrap) if (bootstrap)
web3.connect(Host::pocHost()); web3.addNode(p2p::NodeId(), Host::pocHost());
if (remoteHost.size()) if (remoteHost.size())
web3.connect(remoteHost, remotePort); web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort));
if (c && mining) if (c && mining)
c->startMining(); c->startMining();
@ -687,7 +689,9 @@ int main(int argc, char** argv)
{ {
unsigned port; unsigned port;
iss >> port; iss >> port;
web3.setNetworkPreferences(NetworkPreferences((short)port, publicIP, upnp)); if (port)
netPrefs.listenPort = port;
web3.setNetworkPreferences(netPrefs);
web3.startNetwork(); web3.startNetwork();
} }
else if (cmd == "connect") else if (cmd == "connect")
@ -695,7 +699,7 @@ int main(int argc, char** argv)
string addr; string addr;
unsigned port; unsigned port;
iss >> addr >> port; iss >> addr >> port;
web3.connect(addr, (short)port); web3.addNode(p2p::NodeId(), addr + ":" + toString(port ? port : p2p::c_defaultIPPort));
} }
else if (cmd == "netstop") else if (cmd == "netstop")
{ {

14
test/peer.cpp

@ -35,8 +35,8 @@ BOOST_AUTO_TEST_CASE(host)
auto oldLogVerbosity = g_logVerbosity; auto oldLogVerbosity = g_logVerbosity;
g_logVerbosity = 10; g_logVerbosity = 10;
NetworkPreferences host1prefs(30301, "127.0.0.1", false, true); NetworkPreferences host1prefs("127.0.0.1", 30301, false);
NetworkPreferences host2prefs(30302, "127.0.0.1", false, true); NetworkPreferences host2prefs("127.0.0.1", 30302, false);
Host host1("Test", host1prefs); Host host1("Test", host1prefs);
host1.start(); host1.start();
@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(host)
auto node2 = host2.id(); auto node2 = host2.id();
host2.start(); 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)); this_thread::sleep_for(chrono::seconds(3));
@ -62,7 +62,7 @@ BOOST_AUTO_TEST_CASE(save_nodes)
std::list<Host*> hosts; std::list<Host*> hosts;
for (auto i:{0,1,2,3,4,5}) for (auto i:{0,1,2,3,4,5})
{ {
Host* h = new Host("Test", NetworkPreferences(30300 + i, "127.0.0.1", false, true)); Host* h = new Host("Test", NetworkPreferences("127.0.0.1", 30300 + i, false));
h->setIdealPeerCount(10); h->setIdealPeerCount(10);
// starting host is required so listenport is available // starting host is required so listenport is available
h->start(); h->start();
@ -73,11 +73,11 @@ BOOST_AUTO_TEST_CASE(save_nodes)
Host& host = *hosts.front(); Host& host = *hosts.front();
for (auto const& h: hosts) 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(); Host& host2 = *hosts.back();
for (auto const& h: hosts) 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)); this_thread::sleep_for(chrono::milliseconds(2000));
bytes firstHostNetwork(host.saveNetwork()); bytes firstHostNetwork(host.saveNetwork());
@ -122,7 +122,7 @@ int peerTest(int argc, char** argv)
Host ph("Test", NetworkPreferences(listenPort)); Host ph("Test", NetworkPreferences(listenPort));
if (!remoteHost.empty() && !remoteAlias) 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)); this_thread::sleep_for(chrono::milliseconds(200));

Loading…
Cancel
Save