Browse Source

import/export peers and nodes

cl-refactor
subtly 10 years ago
parent
commit
92f9ec8c42
  1. 13
      alethzero/MainWin.cpp
  2. 2
      alethzero/MainWin.h
  3. 10
      eth/main.cpp
  4. 5
      libp2p/Common.h
  5. 198
      libp2p/Host.cpp
  6. 53
      libp2p/Host.h
  7. 3
      libp2p/NodeTable.h
  8. 4
      libp2p/Session.cpp
  9. 2
      libp2p/Session.h
  10. 13
      libwebthree/WebThree.cpp
  11. 13
      libwebthree/WebThree.h
  12. 9
      neth/main.cpp
  13. 11
      test/net.cpp
  14. 37
      test/peer.cpp
  15. 19
      third/MainWin.cpp
  16. 2
      third/MainWin.h

13
alethzero/MainWin.cpp

@ -660,10 +660,10 @@ void Main::writeSettings()
s.setValue("verbosity", ui->verbosity->value());
s.setValue("jitvm", ui->jitvm->isChecked());
bytes d = m_webThree->saveNodes();
bytes d = m_webThree->saveNetwork();
if (d.size())
m_peers = QByteArray((char*)d.data(), (int)d.size());
s.setValue("peers", m_peers);
m_networkConfig = QByteArray((char*)d.data(), (int)d.size());
s.setValue("peers", m_networkConfig);
s.setValue("nameReg", ui->nameReg->text());
s.setValue("geometry", saveGeometry());
@ -712,7 +712,7 @@ void Main::readSettings(bool _skipGeometry)
}
}
m_peers = s.value("peers").toByteArray();
m_networkConfig = s.value("peers").toByteArray();
ui->upnp->setChecked(s.value("upnp", true).toBool());
ui->forceAddress->setText(s.value("forceAddress", "").toString());
ui->usePast->setChecked(s.value("usePast", true).toBool());
@ -1859,8 +1859,9 @@ void Main::on_net_triggered()
web3()->setIdealPeerCount(ui->idealPeers->value());
web3()->setNetworkPreferences(netPrefs());
ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : 0);
if (m_peers.size()/* && ui->usePast->isChecked()*/)
web3()->restoreNodes(bytesConstRef((byte*)m_peers.data(), m_peers.size()));
// 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());
}

2
alethzero/MainWin.h

@ -251,7 +251,7 @@ private:
unsigned m_currenciesFilter = (unsigned)-1;
unsigned m_balancesFilter = (unsigned)-1;
QByteArray m_peers;
QByteArray m_networkConfig;
QStringList m_servers;
QList<dev::KeyPair> m_myKeys;
QList<dev::KeyPair> m_myIdentities;

10
eth/main.cpp

@ -332,13 +332,14 @@ int main(int argc, char** argv)
VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter);
NetworkPreferences netPrefs(listenPort, publicIP, upnp, useLocal);
auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp");
dev::WebThreeDirect web3(
"Ethereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM) + (jit ? "/JIT" : ""),
dbPath,
false,
mode == NodeMode::Full ? set<string>{"eth", "shh"} : set<string>(),
netPrefs
);
netPrefs,
&nodesState);
web3.setIdealPeerCount(peers);
eth::Client* c = mode == NodeMode::Full ? web3.ethereum() : nullptr;
@ -348,9 +349,6 @@ int main(int argc, char** argv)
c->setAddress(coinbase);
}
auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/nodeState.rlp");
web3.restoreNodes(&nodesState);
cout << "Address: " << endl << toHex(us.address().asArray()) << endl;
web3.startNetwork();
@ -824,7 +822,7 @@ int main(int argc, char** argv)
while (!g_exit)
this_thread::sleep_for(chrono::milliseconds(1000));
writeFile((dbPath.size() ? dbPath : getDataDir()) + "/nodeState.rlp", web3.saveNodes());
writeFile((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp", web3.saveNetwork());
return 0;
}

5
libp2p/Common.h

@ -32,6 +32,7 @@
#include <chrono>
#include <libdevcrypto/Common.h>
#include <libdevcore/Log.h>
#include <libdevcore/Exceptions.h>
namespace ba = boost::asio;
namespace bi = boost::asio::ip;
@ -54,6 +55,8 @@ class Capability;
class Host;
class Session;
struct NetworkStartRequired: virtual dev::Exception {};
struct NetWarn: public LogChannel { static const char* name() { return "!N!"; } static const int verbosity = 0; };
struct NetNote: public LogChannel { static const char* name() { return "*N*"; } static const int verbosity = 1; };
struct NetMessageSummary: public LogChannel { static const char* name() { return "-N-"; } static const int verbosity = 2; };
@ -168,7 +171,7 @@ struct Node
/// If true, node will not be removed from Node list.
bool required = false;
operator bool() const { return (bool)id; }
virtual operator bool() const { return (bool)id; }
};
}

198
libp2p/Host.cpp

@ -45,14 +45,15 @@ void HostNodeTableHandler::processEvent(NodeId const& _n, NodeTableEventType con
m_host.onNodeTableEvent(_n, _e);
}
Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n):
Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bytesConstRef _restoreNetwork):
Worker("p2p", 0),
m_restoreNetwork(_restoreNetwork.toBytes()),
m_clientVersion(_clientVersion),
m_netPrefs(_n),
m_ifAddresses(Network::getInterfaceAddresses()),
m_ioService(2),
m_tcp4Acceptor(m_ioService),
m_alias(move(getHostIdentifier())),
m_alias(getNetworkAlias(_restoreNetwork)),
m_lastPing(chrono::time_point<chrono::steady_clock>::min())
{
for (auto address: m_ifAddresses)
@ -124,7 +125,7 @@ void Host::doneWorking()
RecursiveGuard l(x_sessions);
for (auto i: m_sessions)
if (auto p = i.second.lock())
if (p->isOpen())
if (p->isConnected())
{
p->disconnect(ClientQuit);
n++;
@ -156,6 +157,7 @@ unsigned Host::protocolVersion() const
void Host::registerPeer(std::shared_ptr<Session> _s, CapDescs const& _caps)
{
{
clog(NetNote) << "p2p.host.peer.register" << _s->m_peer->id.abridged();
RecursiveGuard l(x_sessions);
// TODO: temporary loose-coupling; if m_peers already has peer,
// it is same as _s->m_peer. (fixing next PR)
@ -385,8 +387,6 @@ string Host::pocHost()
void Host::addNode(NodeId const& _node, std::string const& _addr, unsigned short _tcpPeerPort, unsigned short _udpNodePort)
{
if (_tcpPeerPort < 30300 || _tcpPeerPort > 30305)
cwarn << "Non-standard port being recorded: " << _tcpPeerPort;
@ -406,11 +406,11 @@ void Host::addNode(NodeId const& _node, std::string const& _addr, unsigned short
if (_ec)
return;
bi::tcp::endpoint tcp = *_epIt;
addNode(Node(_node, NodeIPEndpoint(bi::udp::endpoint(tcp.address(), _udpNodePort), tcp)));
if (m_nodeTable) m_nodeTable->addNode(Node(_node, NodeIPEndpoint(bi::udp::endpoint(tcp.address(), _udpNodePort), tcp)));
});
}
else
addNode(Node(_node, NodeIPEndpoint(bi::udp::endpoint(addr, _udpNodePort), bi::tcp::endpoint(addr, _tcpPeerPort))));
if (m_nodeTable) m_nodeTable->addNode(Node(_node, NodeIPEndpoint(bi::udp::endpoint(addr, _udpNodePort), bi::tcp::endpoint(addr, _tcpPeerPort))));
}
void Host::connect(std::shared_ptr<Peer> const& _p)
@ -473,11 +473,22 @@ PeerSessionInfos Host::peers() const
RecursiveGuard l(x_sessions);
for (auto& i: m_sessions)
if (auto j = i.second.lock())
if (j->m_socket.is_open())
if (j->isConnected())
ret.push_back(j->m_info);
return ret;
}
size_t Host::peerCount() const
{
unsigned retCount = 0;
RecursiveGuard l(x_sessions);
for (auto& i: m_sessions)
if (std::shared_ptr<Session> j = i.second.lock())
if (j->isConnected())
retCount++;
return retCount;
}
void Host::run(boost::system::error_code const&)
{
if (!m_run)
@ -537,16 +548,14 @@ void Host::startedWorking()
if (m_listenPort > 0)
runAcceptor();
if (!m_tcpPublic.address().is_unspecified())
// TODO: add m_tcpPublic endpoint; sort out endpoint stuff for nodetable
m_nodeTable.reset(new NodeTable(m_ioService, m_alias, m_listenPort));
else
m_nodeTable.reset(new NodeTable(m_ioService, m_alias, m_listenPort > 0 ? m_listenPort : 30303));
m_nodeTable->setEventHandler(new HostNodeTableHandler(*this));
}
else
clog(NetNote) << "p2p.start.notice id:" << id().abridged() << "Invalid listen-port. Node Table Disabled.";
clog(NetNote) << "p2p.start.notice id:" << id().abridged() << "Listen port is invalid or unavailable. Node Table using default port (30303).";
// TODO: add m_tcpPublic endpoint; sort out endpoint stuff for nodetable
m_nodeTable.reset(new NodeTable(m_ioService, m_alias, m_listenPort > 0 ? m_listenPort : 30303));
m_nodeTable->setEventHandler(new HostNodeTableHandler(*this));
restoreNetwork(&m_restoreNetwork);
clog(NetNote) << "p2p.started id:" << id().abridged();
@ -585,112 +594,117 @@ void Host::disconnectLatePeers()
pp->disconnect(PingTimeout);
}
bytes Host::saveNodes() const
bytes Host::saveNetwork() const
{
RLPStream nodes;
std::list<Peer> peers;
{
RecursiveGuard l(x_sessions);
for (auto p: m_peers)
if (p.second)
peers.push_back(*p.second);
}
peers.sort();
RLPStream network;
int count = 0;
{
RecursiveGuard l(x_sessions);
for (auto const& i: m_peers)
for (auto const& p: peers)
{
Peer const& n = *(i.second);
// TODO: alpha: Figure out why it ever shares these ports.//n.address.port() >= 30300 && n.address.port() <= 30305 &&
// TODO: alpha: Figure out why it ever shares these ports.//p.address.port() >= 30300 && p.address.port() <= 30305 &&
// TODO: alpha: if/how to save private addresses
// Only save peers which have connected within 2 days, with properly-advertised port and public IP address
if (chrono::system_clock::now() - n.lastConnected < chrono::seconds(3600 * 48) && n.peerEndpoint().port() > 0 && n.peerEndpoint().port() < /*49152*/32768 && n.id != id() && !isPrivateAddress(n.peerEndpoint().address()))
if (chrono::system_clock::now() - p.lastConnected < chrono::seconds(3600 * 48) && p.peerEndpoint().port() > 0 && p.peerEndpoint().port() < /*49152*/32768 && p.id != id() && !isPrivateAddress(p.peerEndpoint().address()))
{
nodes.appendList(10);
if (n.peerEndpoint().address().is_v4())
nodes << n.peerEndpoint().address().to_v4().to_bytes();
network.appendList(10);
if (p.peerEndpoint().address().is_v4())
network << p.peerEndpoint().address().to_v4().to_bytes();
else
nodes << n.peerEndpoint().address().to_v6().to_bytes();
network << p.peerEndpoint().address().to_v6().to_bytes();
// TODO: alpha: replace 0 with trust-state of node
nodes << n.peerEndpoint().port() << n.id << 0
<< chrono::duration_cast<chrono::seconds>(n.lastConnected.time_since_epoch()).count()
<< chrono::duration_cast<chrono::seconds>(n.lastAttempted.time_since_epoch()).count()
<< n.failedAttempts << (unsigned)n.lastDisconnect << n.score << n.rating;
network << p.peerEndpoint().port() << p.id << 0
<< chrono::duration_cast<chrono::seconds>(p.lastConnected.time_since_epoch()).count()
<< chrono::duration_cast<chrono::seconds>(p.lastAttempted.time_since_epoch()).count()
<< p.failedAttempts << (unsigned)p.lastDisconnect << p.score << p.rating;
count++;
}
}
}
auto state = m_nodeTable->state();
state.sort();
for (auto const& s: state)
{
network.appendList(3);
if (s.endpoint.tcp.address().is_v4())
network << s.endpoint.tcp.address().to_v4().to_bytes();
else
network << s.endpoint.tcp.address().to_v6().to_bytes();
network << s.endpoint.tcp.port() << s.id;
count++;
}
RLPStream ret(3);
ret << 0 << m_alias.secret();
ret.appendList(count).appendRaw(nodes.out(), count);
ret << 1 << m_alias.secret();
ret.appendList(count).appendRaw(network.out(), count);
return ret.out();
}
// TODO: p2p Import-ant
void Host::restoreNodes(bytesConstRef _b)
void Host::restoreNetwork(bytesConstRef _b)
{
// nodes can only be added if network is added
if (!isStarted())
BOOST_THROW_EXCEPTION(NetworkStartRequired());
RecursiveGuard l(x_sessions);
RLP r(_b);
if (r.itemCount() > 0 && r[0].isInt())
switch (r[0].toInt<int>())
{
case 0:
{
m_alias = KeyPair(r[1].toHash<Secret>());
// noteNode(id(), m_tcpPublic);
if (r.itemCount() > 0 && r[0].isInt() && r[0].toInt<int>() == 1)
{
// r[0] = version
// r[1] = key
// r[2] = nodes
for (auto i: r[2])
for (auto i: r[2])
{
bi::tcp::endpoint tcp;
bi::udp::endpoint udp;
if (i[0].itemCount() == 4)
{
bi::tcp::endpoint ep;
if (i[0].itemCount() == 4)
ep = bi::tcp::endpoint(bi::address_v4(i[0].toArray<byte, 4>()), i[1].toInt<short>());
else
ep = bi::tcp::endpoint(bi::address_v6(i[0].toArray<byte, 16>()), i[1].toInt<short>());
auto id = (NodeId)i[2];
if (!m_peers.count(id))
{
// TODO: p2p import/export :)
// auto n = noteNode(id, ep);
// n->lastConnected = chrono::system_clock::time_point(chrono::seconds(i[4].toInt<unsigned>()));
// n->lastAttempted = chrono::system_clock::time_point(chrono::seconds(i[5].toInt<unsigned>()));
// n->failedAttempts = i[6].toInt<unsigned>();
// n->lastDisconnect = (DisconnectReason)i[7].toInt<unsigned>();
// n->score = (int)i[8].toInt<unsigned>();
// n->rating = (int)i[9].toInt<unsigned>();
}
tcp = bi::tcp::endpoint(bi::address_v4(i[0].toArray<byte, 4>()), i[1].toInt<short>());
udp = bi::udp::endpoint(bi::address_v4(i[0].toArray<byte, 4>()), i[1].toInt<short>());
}
else
{
tcp = bi::tcp::endpoint(bi::address_v6(i[0].toArray<byte, 16>()), i[1].toInt<short>());
udp = bi::udp::endpoint(bi::address_v6(i[0].toArray<byte, 16>()), i[1].toInt<short>());
}
}
default:;
}
else
for (auto i: r)
{
auto id = (NodeId)i[2];
if (!m_peers.count(id))
if (i.itemCount() == 3)
m_nodeTable->addNode(id, udp, tcp);
else if (i.itemCount() == 10)
{
bi::tcp::endpoint ep;
if (i[0].itemCount() == 4)
ep = bi::tcp::endpoint(bi::address_v4(i[0].toArray<byte, 4>()), i[1].toInt<short>());
else
ep = bi::tcp::endpoint(bi::address_v6(i[0].toArray<byte, 16>()), i[1].toInt<short>());
// auto n = noteNode(id, ep);
shared_ptr<Peer> p = make_shared<Peer>();
p->id = id;
p->lastConnected = chrono::system_clock::time_point(chrono::seconds(i[4].toInt<unsigned>()));
p->lastAttempted = chrono::system_clock::time_point(chrono::seconds(i[5].toInt<unsigned>()));
p->failedAttempts = i[6].toInt<unsigned>();
p->lastDisconnect = (DisconnectReason)i[7].toInt<unsigned>();
p->score = (int)i[8].toInt<unsigned>();
p->rating = (int)i[9].toInt<unsigned>();
p->endpoint.tcp = tcp;
p->endpoint.udp = udp;
m_peers[p->id] = p;
m_nodeTable->addNode(*p.get());
}
}
}
}
KeyPair Host::getHostIdentifier()
KeyPair Host::getNetworkAlias(bytesConstRef _b)
{
static string s_file(getDataDir() + "/host");
static mutex s_x;
lock_guard<mutex> l(s_x);
h256 secret;
bytes b = contents(s_file);
if (b.size() == 32)
memcpy(secret.data(), b.data(), 32);
RLP r(_b);
if (r.itemCount() == 3 && r[0].isInt() && r[0].toInt<int>() == 1)
return move(KeyPair(move(Secret(r[1].toBytes()))));
else
{
// todo: replace w/user entropy; abstract to devcrypto
std::mt19937_64 s_eng(time(0) + chrono::high_resolution_clock::now().time_since_epoch().count());
std::uniform_int_distribution<uint16_t> d(0, 255);
for (unsigned i = 0; i < 32; ++i)
secret[i] = (byte)d(s_eng);
}
if (!secret)
BOOST_THROW_EXCEPTION(crypto::InvalidState());
return move(KeyPair(move(secret)));
return move(KeyPair::create());
}

53
libp2p/Host.h

@ -66,7 +66,7 @@ class Host;
* Specifically, peers can be utilized in a variety of
* many-to-many relationships while also needing to modify shared instances of
* those peers. Modifying these properties via a storage backend alleviates
* Host of the responsibility. (&& remove save/restoreNodes)
* Host of the responsibility. (&& remove save/restoreNetwork)
* @todo reimplement recording of historical session information on per-transport basis
* @todo rebuild nodetable when localNetworking is enabled/disabled
* @todo move attributes into protected
@ -74,7 +74,7 @@ class Host;
class Peer: public Node
{
friend class Session; /// Allows Session to update score and rating.
friend class Host; /// For Host: saveNodes(), restoreNodes()
friend class Host; /// For Host: saveNetwork(), restoreNetwork()
public:
bool isOffline() const { return !m_session.lock(); }
@ -90,6 +90,28 @@ public:
unsigned failedAttempts = 0;
DisconnectReason lastDisconnect = NoDisconnect; ///< Reason for disconnect that happened last.
virtual bool operator<(Peer const& _p) const
{
if (isOffline() != _p.isOffline())
return isOffline();
else if (isOffline())
if (lastAttempted == _p.lastAttempted)
return failedAttempts < _p.failedAttempts;
else
return lastAttempted < _p.lastAttempted;
else
if (score == _p.score)
if (rating == _p.rating)
if (failedAttempts == _p.failedAttempts)
return id < _p.id;
else
return failedAttempts < _p.failedAttempts;
else
return rating < _p.rating;
else
return score < _p.score;
}
protected:
/// Used by isOffline() and (todo) for peer to emit session information.
std::weak_ptr<Session> m_session;
@ -109,6 +131,7 @@ class HostNodeTableHandler: public NodeTableEventHandler
* @brief The Host class
* Capabilities should be registered prior to startNetwork, since m_capabilities is not thread-safe.
*
* @todo exceptions when nodeTable not set (prior to start)
* @todo onNodeTableEvent: move peer-connection logic into ensurePeers
* @todo handshake: gracefully disconnect peer if peer already connected
* @todo abstract socket -> IPConnection
@ -116,6 +139,7 @@ class HostNodeTableHandler: public NodeTableEventHandler
* @todo handle conflict if addNode/requireNode called and Node already exists w/conflicting tcp or udp port
* @todo write host identifier to disk w/nodes
* @todo per-session keepalive/ping instead of broadcast; set ping-timeout via median-latency
* @todo configuration-management (NetworkPrefs+Keys+Topology)
*/
class Host: public Worker
{
@ -125,7 +149,7 @@ class Host: public Worker
public:
/// Start server, listening for connections on the given port.
Host(std::string const& _clientVersion, NetworkPreferences const& _n = NetworkPreferences());
Host(std::string const& _clientVersion, NetworkPreferences const& _n = NetworkPreferences(), bytesConstRef _restoreNetwork = bytesConstRef());
/// Will block on network process events.
virtual ~Host();
@ -158,10 +182,10 @@ public:
/// Get peer information.
PeerSessionInfos peers() const;
/// Get number of peers connected; equivalent to, but faster than, peers().size().
size_t peerCount() const { RecursiveGuard l(x_sessions); return m_peers.size(); }
/// Get number of peers connected.
size_t peerCount() const;
/// Get the address we're listening on currently.
std::string listenAddress() const { return m_tcpPublic.address().to_string(); }
@ -169,10 +193,7 @@ public:
unsigned short listenPort() const { return m_tcpPublic.port(); }
/// Serialise the set of known peers.
bytes saveNodes() const;
/// Deserialise the data and populate the set of known peers.
void restoreNodes(bytesConstRef _b);
bytes saveNetwork() const;
// 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 nodes() const { RecursiveGuard l(x_sessions); Peers ret; for (auto const& i: m_peers) ret.push_back(*i.second); return ret; }
@ -196,6 +217,9 @@ public:
protected:
void onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e);
/// Deserialise the data and populate the set of known peers.
void restoreNetwork(bytesConstRef _b);
private:
/// Populate m_peerAddresses with available public addresses.
void determinePublic(std::string const& _publicAddress, bool _upnp);
@ -226,13 +250,12 @@ private:
/// Shutdown network. Not thread-safe; to be called only by worker.
virtual void doneWorking();
/// Add node
void addNode(Node const& _node) { if (m_nodeTable) m_nodeTable->addNode(_node); }
/// Get or create host identifier (KeyPair).
KeyPair getHostIdentifier();
static KeyPair getNetworkAlias(bytesConstRef _b);
bytes m_restoreNetwork; ///< Set by constructor and used to set Host key and restore network peers & nodes.
bool m_run = false; ///< Whether network is running.
std::mutex x_runTimer; ///< Start/stop mutex.

3
libp2p/NodeTable.h

@ -161,6 +161,7 @@ public:
NodeEntry root() const { return NodeEntry(m_node, m_node.publicKey(), m_node.endpoint.udp); }
std::list<NodeId> nodes() const;
unsigned size() const { return m_nodes.size(); }
std::list<NodeEntry> state() const;
bool haveNode(NodeId _id) { Guard l(x_nodes); return m_nodes.count(_id); }
@ -347,7 +348,7 @@ struct Neighbours: RLPXDatagram<Neighbours>
void interpretRLP(RLP const& _r) { ipAddress = _r[0].toString(); port = _r[1].toInt<unsigned>(); node = h512(_r[2].toBytes()); }
};
Neighbours(bi::udp::endpoint _ep): RLPXDatagram<Neighbours>(_ep) {}
Neighbours(bi::udp::endpoint _ep): RLPXDatagram<Neighbours>(_ep), expiration(futureFromEpoch(std::chrono::seconds(30))) {}
Neighbours(bi::udp::endpoint _to, std::vector<std::shared_ptr<NodeEntry>> const& _nearest, unsigned _offset = 0, unsigned _limit = 0): RLPXDatagram<Neighbours>(_to), expiration(futureFromEpoch(std::chrono::seconds(30)))
{
auto limit = _limit ? std::min(_nearest.size(), (size_t)(_offset + _limit)) : _nearest.size();

4
libp2p/Session.cpp

@ -102,7 +102,7 @@ template <class T> vector<T> randomSelection(vector<T> const& _t, unsigned _n)
// TODO: P2P integration: replace w/asio post -> serviceNodesRequest()
void Session::ensureNodesRequested()
{
if (isOpen() && !m_weRequestedNodes)
if (isConnected() && !m_weRequestedNodes)
{
m_weRequestedNodes = true;
RLPStream s;
@ -310,7 +310,7 @@ bool Session::interpret(RLP const& _r)
// OK passed all our checks. Assume it's good.
addRating(1000);
m_server->addNode(Node(id, NodeIPEndpoint(bi::udp::endpoint(ep.address(), ep.port()), ep)));
m_server->addNode(id, ep.address().to_string(), ep.port(), ep.port());
clogS(NetTriviaDetail) << "New peer: " << ep << "(" << id .abridged()<< ")";
CONTINUE:;
LAMEPEER:;

2
libp2p/Session.h

@ -59,7 +59,7 @@ public:
void ping();
bool isOpen() const { return m_socket.is_open(); }
bool isConnected() const { return m_socket.is_open(); }
NodeId id() const;
unsigned socketId() const { return m_socket.native_handle(); }

13
libwebthree/WebThree.cpp

@ -35,9 +35,9 @@ using namespace dev::p2p;
using namespace dev::eth;
using namespace dev::shh;
WebThreeDirect::WebThreeDirect(std::string const& _clientVersion, std::string const& _dbPath, bool _forceClean, std::set<std::string> const& _interfaces, NetworkPreferences const& _n):
WebThreeDirect::WebThreeDirect(std::string const& _clientVersion, std::string const& _dbPath, bool _forceClean, std::set<std::string> const& _interfaces, NetworkPreferences const& _n, bytesConstRef _network):
m_clientVersion(_clientVersion),
m_net(_clientVersion, _n)
m_net(_clientVersion, _n, _network)
{
if (_dbPath.size())
Defaults::setDBPath(_dbPath);
@ -90,14 +90,9 @@ void WebThreeDirect::setIdealPeerCount(size_t _n)
return m_net.setIdealPeerCount(_n);
}
bytes WebThreeDirect::saveNodes()
bytes WebThreeDirect::saveNetwork()
{
return m_net.saveNodes();
}
void WebThreeDirect::restoreNodes(bytesConstRef _saved)
{
return m_net.restoreNodes(_saved);
return m_net.saveNetwork();
}
void WebThreeDirect::connect(std::string const& _seedHost, unsigned short _port)

13
libwebthree/WebThree.h

@ -63,10 +63,7 @@ public:
virtual void connect(std::string const& _seedHost, unsigned short _port) = 0;
/// Save peers
virtual dev::bytes saveNodes() = 0;
/// Restore peers
virtual void restoreNodes(bytesConstRef _saved) = 0;
virtual dev::bytes saveNetwork() = 0;
/// Sets the ideal number of peers.
virtual void setIdealPeerCount(size_t _n) = 0;
@ -106,7 +103,7 @@ class WebThreeDirect : public WebThreeNetworkFace
public:
/// Constructor for private instance. If there is already another process on the machine using @a _dbPath, then this will throw an exception.
/// ethereum() may be safely static_cast()ed to a eth::Client*.
WebThreeDirect(std::string const& _clientVersion, std::string const& _dbPath, bool _forceClean = false, std::set<std::string> const& _interfaces = {"eth", "shh"}, p2p::NetworkPreferences const& _n = p2p::NetworkPreferences());
WebThreeDirect(std::string const& _clientVersion, std::string const& _dbPath, bool _forceClean = false, std::set<std::string> const& _interfaces = {"eth", "shh"}, p2p::NetworkPreferences const& _n = p2p::NetworkPreferences(), bytesConstRef _network = bytesConstRef());
/// Destructor.
~WebThreeDirect();
@ -133,10 +130,10 @@ public:
void connect(std::string const& _seedHost, unsigned short _port = 30303) override;
/// Save peers
dev::bytes saveNodes() override;
dev::bytes saveNetwork() override;
/// Restore peers
void restoreNodes(bytesConstRef _saved) override;
// /// Restore peers
// void restoreNetwork(bytesConstRef _saved) override;
/// Sets the ideal number of peers.
void setIdealPeerCount(size_t _n) override;

9
neth/main.cpp

@ -415,13 +415,14 @@ int main(int argc, char** argv)
cout << credits();
NetworkPreferences netPrefs(listenPort, publicIP, upnp, useLocal);
auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp");
dev::WebThreeDirect web3(
"NEthereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM),
dbPath,
false,
mode == NodeMode::Full ? set<string>{"eth", "shh"} : set<string>(),
netPrefs
);
netPrefs,
&nodesState);
web3.setIdealPeerCount(peers);
eth::Client* c = mode == NodeMode::Full ? web3.ethereum() : nullptr;
@ -431,9 +432,7 @@ int main(int argc, char** argv)
c->setAddress(coinbase);
}
auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/nodeState.rlp");
web3.restoreNodes(&nodesState);
cout << "Address: " << endl << toHex(us.address().asArray()) << endl;
web3.startNetwork();
if (bootstrap)

11
test/net.cpp

@ -30,7 +30,7 @@ using namespace dev::p2p;
namespace ba = boost::asio;
namespace bi = ba::ip;
BOOST_AUTO_TEST_SUITE(p2p)
BOOST_AUTO_TEST_SUITE(net)
/**
* Only used for testing. Not useful beyond tests.
@ -190,6 +190,9 @@ BOOST_AUTO_TEST_CASE(kademlia)
node.populateAll();
clog << "NodeTable:\n" << *node.nodeTable.get() << endl;
auto nodes = node.nodeTable->nodes();
nodes.sort();
node.nodeTable->reset();
clog << "NodeTable:\n" << *node.nodeTable.get() << endl;
@ -199,6 +202,12 @@ BOOST_AUTO_TEST_CASE(kademlia)
node.nodeTable->join();
this_thread::sleep_for(chrono::milliseconds(2000));
clog << "NodeTable:\n" << *node.nodeTable.get() << endl;
BOOST_REQUIRE_EQUAL(node.nodeTable->size(), 8);
auto netNodes = node.nodeTable->nodes();
netNodes.sort();
}
BOOST_AUTO_TEST_CASE(test_udp_once)

37
test/peer.cpp

@ -50,6 +50,43 @@ BOOST_AUTO_TEST_CASE(host)
BOOST_REQUIRE_EQUAL(host2.peerCount(), host1.peerCount());
}
BOOST_AUTO_TEST_CASE(save_nodes)
{
std::list<Host*> hosts;
for (auto i:{0,1,2,3,4,5})
{
Host* h = new Host("Test", NetworkPreferences(30300 + i, "127.0.0.1", true, true));
// starting host is required so listenport is available
h->start();
while (!h->isStarted())
this_thread::sleep_for(chrono::milliseconds(2));
hosts.push_back(h);
}
Host& host = *hosts.front();
for (auto const& h: hosts)
host.addNode(h->id(), "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());
this_thread::sleep_for(chrono::milliseconds(1000));
bytes firstHostNetwork(host.saveNetwork());
bytes secondHostNetwork(host.saveNetwork());
BOOST_REQUIRE_EQUAL(sha3(firstHostNetwork), sha3(secondHostNetwork));
BOOST_CHECK_EQUAL(host.peerCount(), 5);
BOOST_CHECK_EQUAL(host2.peerCount(), 5);
RLP r(firstHostNetwork);
BOOST_REQUIRE(r.itemCount() == 3);
BOOST_REQUIRE(r[0].toInt<int>() == 1);
BOOST_REQUIRE_EQUAL(r[1].toBytes().size(), 32); // secret
BOOST_REQUIRE_EQUAL(r[2].itemCount(), 5);
}
BOOST_AUTO_TEST_SUITE_END()
int peerTest(int argc, char** argv)

19
third/MainWin.cpp

@ -114,7 +114,8 @@ Main::Main(QWidget *parent) :
connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved()));
m_web3.reset(new WebThreeDirect("Third", getDataDir() + "/Third", false, {"eth", "shh"}));
bytesConstRef networkConfig((byte*)m_networkConfig.data(), m_networkConfig.size())
m_web3.reset(new WebThreeDirect("Third", getDataDir() + "/Third", false, {"eth", "shh"}, NetworkPreferences(), networkConfig));
m_web3->connect(Host::pocHost());
m_server = unique_ptr<WebThreeStubServer>(new WebThreeStubServer(m_qwebConnector, *web3(), keysAsVector(m_myKeys)));
@ -377,10 +378,10 @@ void Main::writeSettings()
s.setValue("address", b);
s.setValue("url", ui->urlEdit->text());
bytes d = m_web3->saveNodes();
bytes d = m_web3->saveNetwork();
if (d.size())
m_nodes = QByteArray((char*)d.data(), (int)d.size());
s.setValue("peers", m_nodes);
m_networkConfig = QByteArray((char*)d.data(), (int)d.size());
s.setValue("peers", m_networkConfig);
s.setValue("geometry", saveGeometry());
s.setValue("windowState", saveState());
@ -409,7 +410,7 @@ void Main::readSettings(bool _skipGeometry)
}
}
ethereum()->setAddress(m_myKeys.back().address());
m_nodes = s.value("peers").toByteArray();
m_networkConfig = s.value("peers").toByteArray();
ui->urlEdit->setText(s.value("url", "about:blank").toString()); //http://gavwood.com/gavcoin.html
on_urlEdit_returnPressed();
}
@ -581,11 +582,9 @@ void Main::ensureNetwork()
web3()->startNetwork();
web3()->connect(defPeer);
}
else
if (!m_web3->peerCount())
m_web3->connect(defPeer);
if (m_nodes.size())
m_web3->restoreNodes(bytesConstRef((byte*)m_nodes.data(), m_nodes.size()));
// else
// if (!m_web3->peerCount())
// m_web3->connect(defPeer);
}
void Main::on_connect_triggered()

2
third/MainWin.h

@ -131,7 +131,7 @@ private:
unsigned m_currenciesFilter = (unsigned)-1;
unsigned m_balancesFilter = (unsigned)-1;
QByteArray m_nodes;
QByteArray m_networkConfig;
QStringList m_servers;
QNetworkAccessManager m_webCtrl;

Loading…
Cancel
Save