From 01eecf58b631d9ee44ffde98d1d511a76dfb4652 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 10 Oct 2014 16:50:51 +0200 Subject: [PATCH 01/29] More network fixes. --- alethzero/Main.ui | 34 +++++++++++++++++ alethzero/MainWin.cpp | 26 ++++++++++++- libdevcrypto/MemoryDB.h | 2 +- libdevcrypto/TrieDB.h | 2 +- libp2p/Common.cpp | 5 +++ libp2p/Common.h | 20 +++++++++- libp2p/Host.cpp | 47 ++++++++++++++--------- libp2p/Host.h | 23 ++++++----- libp2p/Session.cpp | 85 +++++++++++++++++++++++++++-------------- libp2p/Session.h | 9 ++++- libwebthree/WebThree.h | 5 +++ 11 files changed, 196 insertions(+), 62 deletions(-) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index 5e86ee59a..5a6eb6f32 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -1480,6 +1480,40 @@ font-size: 14pt + + + QDockWidget::DockWidgetFeatureMask + + + Nodes + + + 2 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + + + + &Quit diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 7d3fe4085..77384d7ea 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -750,11 +750,33 @@ void Main::refreshBalances() void Main::refreshNetwork() { auto ps = web3()->peers(); - ui->peerCount->setText(QString::fromStdString(toString(ps.size())) + " peer(s)"); ui->peers->clear(); for (PeerInfo const& i: ps) - ui->peers->addItem(QString("[%7] %3 ms - %1:%2 - %4 %5 %6").arg(i.host.c_str()).arg(i.port).arg(chrono::duration_cast(i.lastPing).count()).arg(i.clientVersion.c_str()).arg(QString::fromStdString(toString(i.caps))).arg(QString::fromStdString(toString(i.notes))).arg(i.socket)); + ui->peers->addItem(QString("[%8 %7] %3 ms - %1:%2 - %4 %5 %6") + .arg(QString::fromStdString(i.host)) + .arg(i.port) + .arg(chrono::duration_cast(i.lastPing).count()) + .arg(QString::fromStdString(i.clientVersion)) + .arg(QString::fromStdString(toString(i.caps))) + .arg(QString::fromStdString(toString(i.notes))) + .arg(i.socket) + .arg(QString::fromStdString(i.id.abridged()))); + + auto ns = web3()->nodes(); + ui->nodes->clear(); + for (p2p::Node const& i: ns) + ui->nodes->addItem(QString("[%1%3] %2 - ( =%5s | /%4s | %6 | %7x ) - *%8 $%9") + .arg(QString::fromStdString(i.id.abridged())) + .arg(QString::fromStdString(toString(i.address))) + .arg(i.id == web3()->id() ? " self" : i.isOffline() ? "" : " PEER") + .arg(i.secondsSinceLastAttempted()) + .arg(i.secondsSinceLastConnected()) + .arg(QString::fromStdString(reasonOf(i.lastDisconnect))) + .arg(i.failedAttempts) + .arg(i.rating) + .arg((int)i.idOrigin) + ); } void Main::refreshAll() diff --git a/libdevcrypto/MemoryDB.h b/libdevcrypto/MemoryDB.h index 59435d3bf..446a947ec 100644 --- a/libdevcrypto/MemoryDB.h +++ b/libdevcrypto/MemoryDB.h @@ -32,7 +32,7 @@ namespace dev namespace eth { -struct DBChannel: public LogChannel { static const char* name() { return "TDB"; } static const int verbosity = 12; }; +struct DBChannel: public LogChannel { static const char* name() { return "TDB"; } static const int verbosity = 18; }; #define dbdebug clog(DBChannel) diff --git a/libdevcrypto/TrieDB.h b/libdevcrypto/TrieDB.h index 16e2684fc..3dd76899a 100644 --- a/libdevcrypto/TrieDB.h +++ b/libdevcrypto/TrieDB.h @@ -42,7 +42,7 @@ namespace dev namespace eth { -struct TrieDBChannel: public LogChannel { static const char* name() { return "-T-"; } static const int verbosity = 6; }; +struct TrieDBChannel: public LogChannel { static const char* name() { return "-T-"; } static const int verbosity = 17; }; #define tdebug clog(TrieDBChannel) struct InvalidTrie: virtual dev::Exception {}; diff --git a/libp2p/Common.cpp b/libp2p/Common.cpp index 540f285c1..8a3b27ef0 100644 --- a/libp2p/Common.cpp +++ b/libp2p/Common.cpp @@ -64,7 +64,12 @@ std::string p2p::reasonOf(DisconnectReason _r) case TooManyPeers: return "Peer had too many connections."; case DuplicatePeer: return "Peer was already connected."; case IncompatibleProtocol: return "Peer protocol versions are incompatible."; + case NullIdentity: return "Null identity given."; case ClientQuit: return "Peer is exiting."; + case UnexpectedIdentity: return "Unexpected identity given."; + case LocalIdentity: return "Connected to ourselves."; + case UserReason: return "Subprotocol reason."; + case NoDisconnect: return "(No disconnect has happened.)"; default: return "Unknown reason."; } } diff --git a/libp2p/Common.h b/libp2p/Common.h index 7ef25ca6e..04154c9a0 100644 --- a/libp2p/Common.h +++ b/libp2p/Common.h @@ -87,9 +87,27 @@ enum DisconnectReason NullIdentity, ClientQuit, UnexpectedIdentity, - UserReason = 0x10 + LocalIdentity, + UserReason = 0x10, + NoDisconnect = 0xffff }; +inline bool isPermanentProblem(DisconnectReason _r) +{ + switch (_r) + { + case DisconnectRequested: + case DuplicatePeer: + case IncompatibleProtocol: + case NullIdentity: + case UnexpectedIdentity: + case LocalIdentity: + return true; + default: + return false; + } +} + /// @returns the string form of the given disconnection reason. std::string reasonOf(DisconnectReason _r); diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index bb9901428..82de1727e 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -66,7 +66,6 @@ Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bool m_key(KeyPair::create()) { populateAddresses(); - m_lastPeersRequest = chrono::steady_clock::time_point::min(); clog(NetNote) << "Id:" << id().abridged(); if (_start) start(); @@ -112,7 +111,6 @@ void Host::start() if (!m_public.address().is_unspecified() && (m_nodes.empty() || m_nodes[m_nodesList[0]]->id != id())) noteNode(id(), m_public, Origin::Perfect, false); - m_lastPeersRequest = chrono::steady_clock::time_point::min(); clog(NetNote) << "Id:" << id().abridged(); for (auto const& h: m_capabilities) @@ -349,6 +347,10 @@ shared_ptr Host::noteNode(NodeId _id, bi::tcp::endpoint const& _a, Origin { RecursiveGuard l(x_peers); cnote << "Node:" << _id.abridged() << _a << (_ready ? "ready" : "used") << _oldId.abridged() << (m_nodes.count(_id) ? "[have]" : "[NEW]"); + if (!_a.port()) + { + cwarn << "PORT IS INVALID!"; + } unsigned i; if (!m_nodes.count(_id)) { @@ -367,7 +369,7 @@ shared_ptr Host::noteNode(NodeId _id, bi::tcp::endpoint const& _a, Origin m_nodesList.push_back(_id); m_nodes[_id] = make_shared(); } - m_nodes[_id]->address = m_public; + m_nodes[_id]->address = _a; m_nodes[_id]->index = i; m_nodes[_id]->id = _id; m_nodes[_id]->idOrigin = _o; @@ -390,6 +392,8 @@ shared_ptr Host::noteNode(NodeId _id, bi::tcp::endpoint const& _a, Origin cnote << m_nodes[_id]->index << ":" << m_ready; + m_hadNewNodes = true; + return m_nodes[_id]; } @@ -398,7 +402,8 @@ Nodes Host::potentialPeers(RangeMask const& _known) RecursiveGuard l(x_peers); Nodes ret; - for (auto i: m_ready - (m_private + _known)) + auto ns = (m_netPrefs.localNetworking ? _known : (m_private + _known)).inverted(); + for (auto i: ns) ret.push_back(*m_nodes[m_nodesList[i]]); return ret; } @@ -494,7 +499,7 @@ void Host::connect(bi::tcp::endpoint const& _ep) void Node::connect(Host* _h) { - clog(NetConnect) << "Attempting connection to node" << id.abridged() << "@" << address; + clog(NetConnect) << "Attempting connection to node" << id.abridged() << "@" << address << "from" << _h->id().abridged(); _h->m_ready -= index; bi::tcp::socket* s = new bi::tcp::socket(_h->m_ioService); s->async_connect(address, [=](boost::system::error_code const& ec) @@ -566,23 +571,16 @@ void Host::growPeers() else { ensureAccepting(); - if (chrono::steady_clock::now() > m_lastPeersRequest + chrono::seconds(10)) - requestPeers(); + requestNodes(); } } } -void Host::requestPeers() +void Host::requestNodes() { - RLPStream s; - bytes b; - Session::prep(s, GetPeersPacket).swapOut(b); - seal(b); for (auto const& i: m_peers) if (auto p = i.second.lock()) - if (p->isOpen()) - p->send(&b); - m_lastPeersRequest = chrono::steady_clock::now(); + p->ensureNodesRequested(); } void Host::prunePeers() @@ -637,6 +635,16 @@ void Host::doWork() { growPeers(); prunePeers(); + + if (m_hadNewNodes) + { + for (auto p: m_peers) + if (auto pp = p.second.lock()) + pp->serviceNodesRequest(); + + m_hadNewNodes = false; + } + m_ioService.poll(); } @@ -667,7 +675,7 @@ bytes Host::saveNodes() const nodes << n.address.port() << n.id << (int)n.idOrigin << std::chrono::duration_cast(n.lastConnected.time_since_epoch()).count() << std::chrono::duration_cast(n.lastAttempted.time_since_epoch()).count() - << n.failedAttempts << n.lastDisconnect << n.score << n.rating; + << n.failedAttempts << (unsigned)n.lastDisconnect << n.score << n.rating; count++; } } @@ -686,7 +694,11 @@ void Host::restoreNodes(bytesConstRef _b) switch (r[0].toInt()) { case 0: + { + auto oldId = id(); m_key = KeyPair(r[1].toHash()); + noteNode(id(), m_public, Origin::Perfect, false, oldId); + for (auto i: r[2]) { bi::tcp::endpoint ep; @@ -702,11 +714,12 @@ void Host::restoreNodes(bytesConstRef _b) n->lastConnected = chrono::system_clock::time_point(chrono::seconds(i[4].toInt())); n->lastAttempted = chrono::system_clock::time_point(chrono::seconds(i[5].toInt())); n->failedAttempts = i[6].toInt(); - n->lastDisconnect = (int)i[7].toInt(); + n->lastDisconnect = (DisconnectReason)i[7].toInt(); n->score = (int)i[8].toInt(); n->rating = (int)i[9].toInt(); } } + } default:; } else diff --git a/libp2p/Host.h b/libp2p/Host.h index 723cc5cba..43a5afb25 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -67,16 +67,19 @@ struct Node std::chrono::system_clock::time_point lastConnected; std::chrono::system_clock::time_point lastAttempted; unsigned failedAttempts = 0; - int lastDisconnect = -1; ///< Reason for disconnect that happened last. + DisconnectReason lastDisconnect = NoDisconnect; ///< Reason for disconnect that happened last. - Origin idOrigin = Origin::Unknown; ///< Thirdparty + Origin idOrigin = Origin::Unknown; ///< How did we get to know this node's id? - bool offline() const { return lastDisconnect == -1 || lastAttempted > lastConnected; } + int secondsSinceLastConnected() const { return lastConnected == std::chrono::system_clock::time_point() ? -1 : (int)std::chrono::duration_cast(std::chrono::system_clock::now() - lastConnected).count(); } + int secondsSinceLastAttempted() const { return lastAttempted == std::chrono::system_clock::time_point() ? -1 : (int)std::chrono::duration_cast(std::chrono::system_clock::now() - lastAttempted).count(); } + + bool isOffline() const { return lastDisconnect == -1 || lastAttempted > lastConnected; } bool operator<(Node const& _n) const { - if (offline() != _n.offline()) - return offline(); - else if (offline()) + if (isOffline() != _n.isOffline()) + return isOffline(); + else if (isOffline()) if (lastAttempted == _n.lastAttempted) return failedAttempts < _n.failedAttempts; else @@ -165,6 +168,8 @@ public: /// Deserialise the data and populate the set of known peers. void restoreNodes(bytesConstRef _b); + Nodes nodes() const { RecursiveGuard l(x_peers); Nodes ret; for (auto const& i: m_nodes) ret.push_back(*i.second); return ret; } + void setNetworkPreferences(NetworkPreferences const& _p) { stop(); m_netPrefs = _p; start(); } void start(); @@ -194,7 +199,7 @@ private: std::shared_ptr noteNode(NodeId _id, bi::tcp::endpoint const& _a, Origin _o, bool _ready, NodeId _oldId = h256()); Nodes potentialPeers(RangeMask const& _known); - void requestPeers(); + void requestNodes(); std::string m_clientVersion; ///< Our version string. @@ -211,6 +216,8 @@ private: bi::tcp::endpoint m_public; ///< Our public listening endpoint. KeyPair m_key; ///< Our unique ID. + bool m_hadNewNodes = false; + mutable RecursiveMutex x_peers; /// The nodes to which we are currently connected. @@ -227,8 +234,6 @@ private: RangeMask m_ready; ///< Indices into m_nodesList over to which nodes we are not currently connected, connecting or otherwise ignoring. RangeMask m_private; ///< Indices into m_nodesList over to which nodes are private. - std::chrono::steady_clock::time_point m_lastPeersRequest; ///< Last time we asked for some peers - don't want to do this too often. TODO: peers should be pushed, not polled. - unsigned m_idealPeerCount = 5; ///< Ideal number of peers to be connected to. // Our addresses. diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 65517c0d1..d647d97dc 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -62,8 +62,8 @@ Session::Session(Host* _s, bi::tcp::socket _socket, std::shared_ptr const& Session::~Session() { - if (id()) - m_server->noteNode(id(), m_manualEndpoint, Origin::Unknown, true); + if (id() && !isPermanentProblem(m_node->lastDisconnect)) + m_server->m_ready += m_node->index; // Read-chain finished for one reason or another. for (auto& i: m_capabilities) @@ -125,6 +125,47 @@ template vector randomSelection(vector const& _t, unsigned _n) return ret; } +void Session::ensureNodesRequested() +{ + if (isOpen() && !m_weRequestedNodes) + { + m_weRequestedNodes = true; + RLPStream s; + sealAndSend(prep(s, GetPeersPacket)); + } +} + +void Session::serviceNodesRequest() +{ + if (!m_theyRequestedNodes) + return; + + auto peers = m_server->potentialPeers(m_knownNodes); + if (peers.empty()) + { + addNote("peers", "requested"); + return; + } + + // note this should cost them... + RLPStream s; + prep(s, PeersPacket, min(10, peers.size())); + auto rs = randomSelection(peers, 10); + for (auto const& i: rs) + { + clogS(NetTriviaDetail) << "Sending peer " << i.id.abridged() << i.address; + if (i.address.address().is_v4()) + s.appendList(3) << bytesConstRef(i.address.address().to_v4().to_bytes().data(), 4) << i.address.port() << i.id; + else// if (i.second.address().is_v6()) - assumed + s.appendList(3) << bytesConstRef(i.address.address().to_v6().to_bytes().data(), 16) << i.address.port() << i.id; + m_knownNodes.extendAll(i.index); + m_knownNodes.unionWith(i.index); + } + sealAndSend(s); + m_theyRequestedNodes = false; + addNote("peers", "done"); +} + bool Session::interpret(RLP const& _r) { clogS(NetRight) << _r; @@ -136,7 +177,7 @@ bool Session::interpret(RLP const& _r) case HelloPacket: { if (m_node) - m_node->lastDisconnect = -1; + m_node->lastDisconnect = NoDisconnect; m_protocolVersion = _r[1].toInt(); auto clientVersion = _r[2].toString(); @@ -152,6 +193,14 @@ bool Session::interpret(RLP const& _r) clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "]" << id.abridged() << showbase << capslog.str() << dec << listenPort; + if (m_server->id() == id) + { + // Already connected. + clogS(NetWarn) << "Connected to ourself under a false pretext. We were told this peer was id" << m_info.id.abridged(); + disconnect(LocalIdentity); + return false; + } + if (m_server->havePeer(id)) { // Already connected. @@ -221,27 +270,13 @@ bool Session::interpret(RLP const& _r) case GetPeersPacket: { clogS(NetTriviaSummary) << "GetPeers"; - auto peers = m_server->potentialPeers(m_knownNodes); - if (peers.empty()) - break; - RLPStream s; - prep(s, PeersPacket, min(10, peers.size())); - auto rs = randomSelection(peers, 10); - for (auto const& i: rs) - { - clogS(NetTriviaDetail) << "Sending peer " << i.id.abridged() << i.address; - if (i.address.address().is_v4()) - s.appendList(3) << bytesConstRef(i.address.address().to_v4().to_bytes().data(), 4) << i.address.port() << i.id; - else// if (i.second.address().is_v6()) - assumed - s.appendList(3) << bytesConstRef(i.address.address().to_v6().to_bytes().data(), 16) << i.address.port() << i.id; - m_knownNodes.extendAll(i.index); - m_knownNodes.unionWith(i.index); - } - sealAndSend(s); + m_theyRequestedNodes = true; + serviceNodesRequest(); break; } case PeersPacket: clogS(NetTriviaSummary) << "Peers (" << dec << (_r.itemCount() - 1) << " entries)"; + m_weRequestedNodes = false; for (unsigned i = 1; i < _r.itemCount(); ++i) { bi::address peerAddress; @@ -329,12 +364,6 @@ void Session::ping() m_ping = std::chrono::steady_clock::now(); } -void Session::getPeers() -{ - RLPStream s; - sealAndSend(prep(s, GetPeersPacket)); -} - RLPStream& Session::prep(RLPStream& _s, PacketType _id, unsigned _args) { return prep(_s).appendList(_args + 1).append((unsigned)_id); @@ -449,7 +478,7 @@ void Session::dropped() catch (...) {} } -void Session::disconnect(int _reason) +void Session::disconnect(DisconnectReason _reason) { clogS(NetConnect) << "Disconnecting (reason:" << reasonOf((DisconnectReason)_reason) << ")"; @@ -481,8 +510,6 @@ void Session::start() << m_server->id(); sealAndSend(s); ping(); - getPeers(); - doRead(); } diff --git a/libp2p/Session.h b/libp2p/Session.h index ff05be81b..e76edd8b1 100644 --- a/libp2p/Session.h +++ b/libp2p/Session.h @@ -55,7 +55,7 @@ public: virtual ~Session(); void start(); - void disconnect(int _reason); + void disconnect(DisconnectReason _reason); void ping(); @@ -82,6 +82,9 @@ public: PeerInfo const& info() const { return m_info; } + void ensureNodesRequested(); + void serviceNodesRequest(); + private: void dropped(); void doRead(); @@ -89,7 +92,6 @@ private: void writeImpl(bytes& _buffer); void write(); - void getPeers(); bool interpret(RLP const& _r); /// @returns true iff the _msg forms a valid message for sending or receiving on the network. @@ -110,6 +112,9 @@ private: bi::tcp::endpoint m_manualEndpoint; bool m_force = false; /// If true, ignore IDs being different. This could open you up to MitM attacks. + bool m_theyRequestedNodes = false; + bool m_weRequestedNodes = false; + std::chrono::steady_clock::time_point m_ping; std::chrono::steady_clock::time_point m_connect; std::chrono::steady_clock::time_point m_disconnect; diff --git a/libwebthree/WebThree.h b/libwebthree/WebThree.h index fd0991eaa..32bbe0b31 100644 --- a/libwebthree/WebThree.h +++ b/libwebthree/WebThree.h @@ -108,6 +108,11 @@ public: void setNetworkPreferences(p2p::NetworkPreferences const& _n) { auto had = haveNetwork(); if (had) stopNetwork(); m_net.setNetworkPreferences(_n); if (had) startNetwork(); } + p2p::NodeId id() const { return m_net.id(); } + + /// Gets the nodes. + p2p::Nodes nodes() const { return m_net.nodes(); } + /// Start the network subsystem. void startNetwork() { m_net.start(); } From 5d2238d179c0da4f7b88feee263649d0d67453e3 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 10 Oct 2014 17:03:46 +0200 Subject: [PATCH 02/29] Manage dead nodes. --- alethzero/MainWin.cpp | 5 +++-- libp2p/Host.cpp | 11 ++++------- libp2p/Host.h | 1 + libp2p/Session.cpp | 25 ++++++++++++++++--------- 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 77384d7ea..f55bf2d9f 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -766,10 +766,11 @@ void Main::refreshNetwork() auto ns = web3()->nodes(); ui->nodes->clear(); for (p2p::Node const& i: ns) - ui->nodes->addItem(QString("[%1%3] %2 - ( =%5s | /%4s | %6 | %7x ) - *%8 $%9") + if (!i.dead) + ui->nodes->addItem(QString("[%1%3] %2 - ( =%5s | /%4s | %6 | %7x ) - *%8 $%9") .arg(QString::fromStdString(i.id.abridged())) .arg(QString::fromStdString(toString(i.address))) - .arg(i.id == web3()->id() ? " self" : i.isOffline() ? "" : " PEER") + .arg(i.id == web3()->id() ? " self" : i.isOffline() ? " ripe" : " ----") .arg(i.secondsSinceLastAttempted()) .arg(i.secondsSinceLastConnected()) .arg(QString::fromStdString(reasonOf(i.lastDisconnect))) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 82de1727e..44fa137e5 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -354,24 +354,21 @@ shared_ptr Host::noteNode(NodeId _id, bi::tcp::endpoint const& _a, Origin unsigned i; if (!m_nodes.count(_id)) { - shared_ptr old; if (m_nodes.count(_oldId)) { - old = m_nodes[_oldId]; - i = old->index; + i = m_nodes[_oldId]->index; m_nodes.erase(_oldId); m_nodesList[i] = _id; - m_nodes[id()] = make_shared(); } else { i = m_nodesList.size(); m_nodesList.push_back(_id); - m_nodes[_id] = make_shared(); } + m_nodes[_id] = make_shared(); + m_nodes[_id]->id = _id; m_nodes[_id]->address = _a; m_nodes[_id]->index = i; - m_nodes[_id]->id = _id; m_nodes[_id]->idOrigin = _o; } else @@ -665,7 +662,7 @@ bytes Host::saveNodes() const for (auto const& i: m_nodes) { Node const& n = *(i.second); - if (n.id != id() && !isPrivateAddress(n.address.address())) + if (!n.dead && n.id != id() && !isPrivateAddress(n.address.address())) { nodes.appendList(10); if (n.address.address().is_v4()) diff --git a/libp2p/Host.h b/libp2p/Host.h index 43a5afb25..a7beb8c35 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -64,6 +64,7 @@ struct Node bi::tcp::endpoint address; ///< As reported from the node itself. int score = 0; ///< All time cumulative. int rating = 0; ///< Trending. + bool dead = false; ///< If true, we believe this node is permanently dead - forget all about it. std::chrono::system_clock::time_point lastConnected; std::chrono::system_clock::time_point lastAttempted; unsigned failedAttempts = 0; diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index d647d97dc..3f224a72d 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -62,7 +62,7 @@ Session::Session(Host* _s, bi::tcp::socket _socket, std::shared_ptr const& Session::~Session() { - if (id() && !isPermanentProblem(m_node->lastDisconnect)) + if (id() && (!m_node || (!isPermanentProblem(m_node->lastDisconnect) && !m_node->dead))) m_server->m_ready += m_node->index; // Read-chain finished for one reason or another. @@ -201,14 +201,6 @@ bool Session::interpret(RLP const& _r) return false; } - if (m_server->havePeer(id)) - { - // Already connected. - clogS(NetWarn) << "Already connected to a peer with id" << id.abridged(); - disconnect(DuplicatePeer); - return false; - } - if (m_node && m_node->id != id) { if (m_force || m_node->idOrigin <= Origin::SelfThird) @@ -220,6 +212,21 @@ bool Session::interpret(RLP const& _r) disconnect(UnexpectedIdentity); return false; } + + if (m_server->havePeer(id)) + { + m_node->dead = true; + disconnect(DuplicatePeer); + return false; + } + } + + if (m_server->havePeer(id)) + { + // Already connected. + clogS(NetWarn) << "Already connected to a peer with id" << id.abridged(); + disconnect(DuplicatePeer); + return false; } if (!id) From 23021abbe25744b87b4fb8240059a91c4f25f2ba Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 10 Oct 2014 17:22:31 +0200 Subject: [PATCH 03/29] Eth stores past peers and its own ID. --- eth/main.cpp | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 4e790709e..95d1c21fa 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #if ETH_JSONRPC @@ -166,6 +167,13 @@ string pretty(h160 _a, dev::eth::State _st) return ns; } +bool g_exit = false; + +void sighandler(int) +{ + g_exit = true; +} + int main(int argc, char** argv) { unsigned short listenPort = 30303; @@ -316,6 +324,9 @@ int main(int argc, char** argv) c->setAddress(coinbase); } + auto nodesState = contents(dbPath + "/nodeState.rlp"); + web3.restoreNodes(&nodesState); + cout << "Address: " << endl << toHex(us.address().asArray()) << endl; web3.startNetwork(); @@ -334,11 +345,15 @@ int main(int argc, char** argv) } #endif + signal(SIGABRT, &sighandler); + signal(SIGTERM, &sighandler); + signal(SIGINT, &sighandler); + if (interactive) { string logbuf; string l; - while (true) + while (!g_exit) { g_logPost = [](std::string const& a, char const*) { cout << "\r \r" << a << endl << "Press Enter" << flush; }; cout << logbuf << "Press Enter" << flush; @@ -764,7 +779,7 @@ int main(int argc, char** argv) unsigned n =c->blockChain().details().number; if (mining) c->startMining(); - while (true) + while (!g_exit) { if ( c->isMining() &&c->blockChain().details().number - n == mining) c->stopMining(); @@ -772,9 +787,10 @@ int main(int argc, char** argv) } } else - while (true) + while (!g_exit) this_thread::sleep_for(chrono::milliseconds(1000)); + writeFile(dbPath + "/nodeState.rlp", web3.saveNodes()); return 0; } From b7c9bed067c4714ff317ef994073843424141bc5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 10 Oct 2014 17:35:37 +0200 Subject: [PATCH 04/29] Throw exception for invalid instruction prior to determining gas. --- libevm/VM.h | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 109 insertions(+), 3 deletions(-) diff --git a/libevm/VM.h b/libevm/VM.h index 456e949c7..401e30baf 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -188,8 +188,116 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con break; } - default: + case Instruction::ADD: + case Instruction::MUL: + case Instruction::SUB: + case Instruction::DIV: + case Instruction::SDIV: + case Instruction::MOD: + case Instruction::SMOD: + case Instruction::EXP: + case Instruction::NEG: + case Instruction::LT: + case Instruction::GT: + case Instruction::SLT: + case Instruction::SGT: + case Instruction::EQ: + case Instruction::NOT: + case Instruction::AND: + case Instruction::OR: + case Instruction::XOR: + case Instruction::BYTE: + case Instruction::ADDMOD: + case Instruction::MULMOD: + case Instruction::ADDRESS: + case Instruction::ORIGIN: + case Instruction::CALLER: + case Instruction::CALLVALUE: + case Instruction::CALLDATALOAD: + case Instruction::CALLDATASIZE: + case Instruction::CODESIZE: + case Instruction::EXTCODESIZE: + case Instruction::GASPRICE: + case Instruction::PREVHASH: + case Instruction::COINBASE: + case Instruction::TIMESTAMP: + case Instruction::NUMBER: + case Instruction::DIFFICULTY: + case Instruction::GASLIMIT: + case Instruction::PUSH1: + case Instruction::PUSH2: + case Instruction::PUSH3: + case Instruction::PUSH4: + case Instruction::PUSH5: + case Instruction::PUSH6: + case Instruction::PUSH7: + case Instruction::PUSH8: + case Instruction::PUSH9: + case Instruction::PUSH10: + case Instruction::PUSH11: + case Instruction::PUSH12: + case Instruction::PUSH13: + case Instruction::PUSH14: + case Instruction::PUSH15: + case Instruction::PUSH16: + case Instruction::PUSH17: + case Instruction::PUSH18: + case Instruction::PUSH19: + case Instruction::PUSH20: + case Instruction::PUSH21: + case Instruction::PUSH22: + case Instruction::PUSH23: + case Instruction::PUSH24: + case Instruction::PUSH25: + case Instruction::PUSH26: + case Instruction::PUSH27: + case Instruction::PUSH28: + case Instruction::PUSH29: + case Instruction::PUSH30: + case Instruction::PUSH31: + case Instruction::PUSH32: + case Instruction::POP: + case Instruction::DUP1: + case Instruction::DUP2: + case Instruction::DUP3: + case Instruction::DUP4: + case Instruction::DUP5: + case Instruction::DUP6: + case Instruction::DUP7: + case Instruction::DUP8: + case Instruction::DUP9: + case Instruction::DUP10: + case Instruction::DUP11: + case Instruction::DUP12: + case Instruction::DUP13: + case Instruction::DUP14: + case Instruction::DUP15: + case Instruction::DUP16: + case Instruction::SWAP1: + case Instruction::SWAP2: + case Instruction::SWAP3: + case Instruction::SWAP4: + case Instruction::SWAP5: + case Instruction::SWAP6: + case Instruction::SWAP7: + case Instruction::SWAP8: + case Instruction::SWAP9: + case Instruction::SWAP10: + case Instruction::SWAP11: + case Instruction::SWAP12: + case Instruction::SWAP13: + case Instruction::SWAP14: + case Instruction::SWAP15: + case Instruction::SWAP16: + case Instruction::JUMP: + case Instruction::JUMPI: + case Instruction::PC: + case Instruction::MSIZE: + case Instruction::GAS: + case Instruction::JUMPDEST: break; + default: + BOOST_THROW_EXCEPTION(BadInstruction()); } newTempSize = (newTempSize + 31) / 32 * 32; @@ -669,8 +777,6 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con } case Instruction::STOP: return bytesConstRef(); - default: - BOOST_THROW_EXCEPTION(BadInstruction()); } } if (_steps == (uint64_t)-1) From 8b1652bbf3482f70530c77f9e9b3e0acd81af289 Mon Sep 17 00:00:00 2001 From: sveneh Date: Sat, 11 Oct 2014 00:01:54 +0200 Subject: [PATCH 05/29] cleanup build file. Start some modularisation. --- CMakeLists.txt | 103 ++++++++++++++------------------ cmake/EthCompilerSettings.cmake | 44 ++++++++++++++ 2 files changed, 88 insertions(+), 59 deletions(-) create mode 100644 cmake/EthCompilerSettings.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index e623c7319..08a6295e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,38 +1,58 @@ # cmake global -project(ethereum) cmake_minimum_required(VERSION 2.8.9) -set(CMAKE_AUTOMOC ON) -cmake_policy(SET CMP0015 NEW) + +project(ethereum) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + + +###################################################################################################### # user defined, defaults # Normally, set(...CACHE...) creates cache variables, but does not modify them. +function(createDefaultCacheConfig) + set(HEADLESS OFF CACHE BOOL "Do not compile GUI (AlethZero)") + set(LANGUAGES OFF CACHE BOOL "Limit build to Serpent/LLL tools") + set(VMTRACE OFF CACHE BOOL "VM tracing and run-time checks (useful for cross-implementation VM debugging)") + set(PARANOIA OFF CACHE BOOL "Additional run-time checks") +endfunction() -set(HEADLESS OFF CACHE BOOL "Do not compile GUI (AlethZero)") -set(LANGUAGES OFF CACHE BOOL "Limit build to Serpent/LLL tools") -set(VMTRACE OFF CACHE BOOL "VM tracing and run-time checks (useful for cross-implementation VM debugging)") -set(PARANOIA OFF CACHE BOOL "Additional run-time checks") -if (LANGUAGES) - add_definitions(-DETH_LANGUAGES) -endif () +# propagates CMake configuration options to the compiler +function(configureProject) + if (LANGUAGES) + add_definitions(-DETH_LANGUAGES) + endif () -if (PARANOIA) - if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - add_definitions(-DETH_PARANOIA) - else () - message(FATAL_ERROR "Paranoia requires debug.") + if (PARANOIA) + if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + add_definitions(-DETH_PARANOIA) + else () + message(FATAL_ERROR "Paranoia requires debug.") + endif () endif () -endif () -if (VMTRACE) - if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - add_definitions(-DETH_VMTRACE) - else () - message(FATAL_ERROR "VM tracing requires debug.") + if (VMTRACE) + if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + add_definitions(-DETH_VMTRACE) + else () + message(FATAL_ERROR "VM tracing requires debug.") + endif () endif () -endif () -message("LANGUAGES: ${LANGUAGES}; VMTRACE: ${VMTRACE}; PARANOIA: ${PARANOIA}; HEADLESS: ${HEADLESS}") + message("LANGUAGES: ${LANGUAGES}; VMTRACE: ${VMTRACE}; PARANOIA: ${PARANOIA}; HEADLESS: ${HEADLESS}") +endfunction() + +###################################################################################################### + + +set(CMAKE_AUTOMOC ON) +cmake_policy(SET CMP0015 NEW) + + +createDefaultCacheConfig() +configureProject() + # Default TARGET_PLATFORM to "linux". set(TARGET_PLATFORM CACHE STRING "linux") @@ -49,44 +69,9 @@ endif () # set(CMAKE_BUILD_TYPE RelWithDebInfo) # endif() -# Initialize CXXFLAGS -set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -DSHAREDLIB") -set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DETH_DEBUG") -set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE") -set(CMAKE_CXX_FLAGS_RELEASE "-O4 -DNDEBUG -DETH_RELEASE") -set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_DEBUG") - -# Windows -if ("${TARGET_PLATFORM}" STREQUAL "w64") - set(CMAKE_SYSTEM_NAME Windows) - - set(CMAKE_CXX_LIBRARY_ARCHITECTURE x86_64-w64-mingw32) - set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) - set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++) - set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) - set(CMAKE_AR x86_64-w64-mingw32-ar) - set(CMAKE_RANLIB x86_64-w64-mingw32-ranlib) - - set(CMAKE_EXECUTABLE_SUFFIX .exe) - set(CMAKE_FIND_ROOT_PATH - /usr/x86_64-w64-mingw32 - ) +include(EthCompilerSettings) - include_directories(/usr/x86_64-w64-mingw32/include/cryptopp) - - set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) - - set(CMAKE_INSTALL_PREFIX /usr/x86_64-w64-mingw32) - set(ETH_BUILD_PLATFORM "windows") - set(ETH_STATIC 1) -else () - set(ETH_BUILD_PLATFORM ${CMAKE_SYSTEM_NAME}) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") - set(ETH_SHARED 1) -endif() # Set build platform; to be written to BuildInfo.h if (CMAKE_COMPILER_IS_MINGW) diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake new file mode 100644 index 000000000..7404e924b --- /dev/null +++ b/cmake/EthCompilerSettings.cmake @@ -0,0 +1,44 @@ +# Set necessary compile and link flags + + +# Initialize CXXFLAGS +set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -DSHAREDLIB") +set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DETH_DEBUG") +set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE") +set(CMAKE_CXX_FLAGS_RELEASE "-O4 -DNDEBUG -DETH_RELEASE") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_DEBUG") + +# Windows +if ("${TARGET_PLATFORM}" STREQUAL "w64") + set(CMAKE_SYSTEM_NAME Windows) + + set(CMAKE_CXX_LIBRARY_ARCHITECTURE x86_64-w64-mingw32) + set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) + set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++) + set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) + set(CMAKE_AR x86_64-w64-mingw32-ar) + set(CMAKE_RANLIB x86_64-w64-mingw32-ranlib) + + set(CMAKE_EXECUTABLE_SUFFIX .exe) + + set(CMAKE_FIND_ROOT_PATH + /usr/x86_64-w64-mingw32 + ) + + include_directories(/usr/x86_64-w64-mingw32/include/cryptopp) + + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + + set(CMAKE_INSTALL_PREFIX /usr/x86_64-w64-mingw32) + set(ETH_BUILD_PLATFORM "windows") + set(ETH_STATIC 1) +else () + set(ETH_BUILD_PLATFORM ${CMAKE_SYSTEM_NAME}) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") + set(ETH_SHARED 1) +endif() + + + From 7920f04f3082579dbf8f84d905c3a86157c1866f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 11 Oct 2014 13:57:55 +0200 Subject: [PATCH 06/29] Better drop off semantics. --- libp2p/Capability.cpp | 8 +-- libp2p/Capability.h | 2 +- libp2p/Host.cpp | 31 ++++++---- libp2p/Session.cpp | 132 ++++++++++++++++++------------------------ libp2p/Session.h | 50 +++++++++------- 5 files changed, 110 insertions(+), 113 deletions(-) diff --git a/libp2p/Capability.cpp b/libp2p/Capability.cpp index 2dbfd76a8..dfa1ab546 100644 --- a/libp2p/Capability.cpp +++ b/libp2p/Capability.cpp @@ -53,14 +53,14 @@ void Capability::sealAndSend(RLPStream& _s) m_session->sealAndSend(_s); } -void Capability::sendDestroy(bytes& _msg) +void Capability::send(bytesConstRef _msg) { - m_session->sendDestroy(_msg); + m_session->send(_msg); } -void Capability::send(bytesConstRef _msg) +void Capability::send(bytes&& _msg) { - m_session->send(_msg); + m_session->send(move(_msg)); } void Capability::addRating(unsigned _r) diff --git a/libp2p/Capability.h b/libp2p/Capability.h index bd2ab7a95..04b116aa8 100644 --- a/libp2p/Capability.h +++ b/libp2p/Capability.h @@ -52,7 +52,7 @@ protected: RLPStream& prep(RLPStream& _s, unsigned _id, unsigned _args = 0); void sealAndSend(RLPStream& _s); - void sendDestroy(bytes& _msg); + void send(bytes&& _msg); void send(bytesConstRef _msg); void addRating(unsigned _r); diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 44fa137e5..2c93e64e0 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -497,6 +497,8 @@ void Host::connect(bi::tcp::endpoint const& _ep) void Node::connect(Host* _h) { clog(NetConnect) << "Attempting connection to node" << id.abridged() << "@" << address << "from" << _h->id().abridged(); + lastAttempted = std::chrono::system_clock::now(); + failedAttempts++; _h->m_ready -= index; bi::tcp::socket* s = new bi::tcp::socket(_h->m_ioService); s->async_connect(address, [=](boost::system::error_code const& ec) @@ -504,14 +506,11 @@ void Node::connect(Host* _h) if (ec) { clog(NetConnect) << "Connection refused to node" << id.abridged() << "@" << address << "(" << ec.message() << ")"; - failedAttempts++; - lastAttempted = std::chrono::system_clock::now(); _h->m_ready += index; } else { clog(NetConnect) << "Connected to" << id.abridged() << "@" << address; - failedAttempts = 0; lastConnected = std::chrono::system_clock::now(); auto p = make_shared(_h, std::move(*s), _h->node(id), true); // true because we don't care about ids matched for now. Once we have permenant IDs this will matter a lot more and we can institute a safer mechanism. p->start(); @@ -534,14 +533,24 @@ bool Host::havePeer(NodeId _id) const return !!m_peers.count(_id); } -unsigned cumulativeFallback(unsigned _failed) +unsigned cumulativeFallback(unsigned _failed, DisconnectReason _r) { - if (_failed < 5) - return _failed * 5; - else if (_failed < 15) - return 25 + (_failed - 5) * 10; - else - return 25 + 100 + (_failed - 15) * 20; + switch (_r) + { + case BadProtocol: + return 30 * (_failed + 1); + case UselessPeer: + case TooManyPeers: + case ClientQuit: + return 15 * (_failed + 1); + default: + if (_failed < 5) + return _failed * 5; + else if (_failed < 15) + return 25 + (_failed - 5) * 10; + else + return 25 + 100 + (_failed - 15) * 20; + } } void Host::growPeers() @@ -555,7 +564,7 @@ void Host::growPeers() toTry -= m_private; set ns; for (auto i: toTry) - if (chrono::system_clock::now() > m_nodes[m_nodesList[i]]->lastAttempted + chrono::seconds(cumulativeFallback(m_nodes[m_nodesList[i]]->failedAttempts))) + if (chrono::system_clock::now() > m_nodes[m_nodesList[i]]->lastAttempted + chrono::seconds(cumulativeFallback(m_nodes[m_nodesList[i]]->failedAttempts, m_nodes[m_nodesList[i]]->lastDisconnect))) ns.insert(*m_nodes[m_nodesList[i]]); if (ns.size()) diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 3f224a72d..7c0d291c4 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -42,7 +42,6 @@ Session::Session(Host* _s, bi::tcp::socket _socket, bi::tcp::endpoint const& _ma m_node(nullptr), m_manualEndpoint(_manual) { - m_disconnect = std::chrono::steady_clock::time_point::max(); m_connect = std::chrono::steady_clock::now(); m_info = PeerInfo({NodeId(), "?", m_manualEndpoint.address().to_string(), m_manualEndpoint.port(), std::chrono::steady_clock::duration(0), CapDescSet(), 0, map()}); @@ -55,15 +54,15 @@ Session::Session(Host* _s, bi::tcp::socket _socket, std::shared_ptr const& m_manualEndpoint(_n->address), m_force(_force) { - m_disconnect = std::chrono::steady_clock::time_point::max(); m_connect = std::chrono::steady_clock::now(); m_info = PeerInfo({m_node->id, "?", _n->address.address().to_string(), _n->address.port(), std::chrono::steady_clock::duration(0), CapDescSet(), 0, map()}); } Session::~Session() { - if (id() && (!m_node || (!isPermanentProblem(m_node->lastDisconnect) && !m_node->dead))) - m_server->m_ready += m_node->index; + if (m_node) + if (id() && !isPermanentProblem(m_node->lastDisconnect) && !m_node->dead) + m_server->m_ready += m_node->index; // Read-chain finished for one reason or another. for (auto& i: m_capabilities) @@ -176,9 +175,6 @@ bool Session::interpret(RLP const& _r) { case HelloPacket: { - if (m_node) - m_node->lastDisconnect = NoDisconnect; - m_protocolVersion = _r[1].toInt(); auto clientVersion = _r[2].toString(); auto caps = _r[3].toVector(); @@ -198,7 +194,7 @@ bool Session::interpret(RLP const& _r) // Already connected. clogS(NetWarn) << "Connected to ourself under a false pretext. We were told this peer was id" << m_info.id.abridged(); disconnect(LocalIdentity); - return false; + return true; } if (m_node && m_node->id != id) @@ -210,14 +206,14 @@ bool Session::interpret(RLP const& _r) { clogS(NetWarn) << "Connected to node, but their ID has changed since last time. This could indicate a MitM attack. Disconnecting."; disconnect(UnexpectedIdentity); - return false; + return true; } if (m_server->havePeer(id)) { m_node->dead = true; disconnect(DuplicatePeer); - return false; + return true; } } @@ -226,13 +222,13 @@ bool Session::interpret(RLP const& _r) // Already connected. clogS(NetWarn) << "Already connected to a peer with id" << id.abridged(); disconnect(DuplicatePeer); - return false; + return true; } if (!id) { disconnect(NullIdentity); - return false; + return true; } m_node = m_server->noteNode(id, bi::tcp::endpoint(m_socket.remote_endpoint().address(), listenPort), Origin::Self, false, !m_node || m_node->id == id ? NodeId() : m_node->id); @@ -242,7 +238,7 @@ bool Session::interpret(RLP const& _r) if (m_protocolVersion != m_server->protocolVersion()) { disconnect(IncompatibleProtocol); - return false; + return true; } m_info = PeerInfo({id, clientVersion, m_socket.remote_endpoint().address().to_string(), listenPort, std::chrono::steady_clock::duration(), _r[3].toSet(), (unsigned)m_socket.native_handle(), map() }); @@ -252,16 +248,13 @@ bool Session::interpret(RLP const& _r) case DisconnectPacket: { string reason = "Unspecified"; + auto r = (DisconnectReason)_r[1].toInt(); if (_r[1].isInt()) - reason = reasonOf((DisconnectReason)_r[1].toInt()); + reason = reasonOf(r); clogS(NetMessageSummary) << "Disconnect (reason: " << reason << ")"; - if (m_socket.is_open()) - clogS(NetNote) << "Closing " << m_socket.remote_endpoint(); - else - clogS(NetNote) << "Remote closed."; - m_socket.close(); - return false; + drop(DisconnectRequested); + return true; } case PingPacket: { @@ -294,7 +287,7 @@ bool Session::interpret(RLP const& _r) else { disconnect(BadProtocol); - return false; + return true; } auto ep = bi::tcp::endpoint(peerAddress, _r[i][1].toInt()); NodeId id = _r[i][2].toHash(); @@ -356,10 +349,11 @@ bool Session::interpret(RLP const& _r) } } } - catch (...) + catch (std::exception const& _e) { + clogS(NetWarn) << "Peer causing an exception:" << _e.what(); disconnect(BadProtocol); - return false; + return true; } return true; } @@ -386,7 +380,7 @@ void Session::sealAndSend(RLPStream& _s) bytes b; _s.swapOut(b); m_server->seal(b); - sendDestroy(b); + send(move(b)); } bool Session::checkPacket(bytesConstRef _msg) @@ -404,42 +398,26 @@ bool Session::checkPacket(bytesConstRef _msg) return true; } -void Session::sendDestroy(bytes& _msg) +void Session::send(bytesConstRef _msg) { - clogS(NetLeft) << RLP(bytesConstRef(&_msg).cropped(8)); - - if (!checkPacket(bytesConstRef(&_msg))) - { - clogS(NetWarn) << "INVALID PACKET CONSTRUCTED!"; - } - - bytes buffer = bytes(std::move(_msg)); - writeImpl(buffer); + send(_msg.toBytes()); } -void Session::send(bytesConstRef _msg) +void Session::send(bytes&& _msg) { - clogS(NetLeft) << RLP(_msg.cropped(8)); - - if (!checkPacket(_msg)) - { - clogS(NetWarn) << "INVALID PACKET CONSTRUCTED!"; - } + clogS(NetLeft) << RLP(bytesConstRef(&_msg).cropped(8)); - bytes buffer = bytes(_msg.toBytes()); - writeImpl(buffer); -} + if (!checkPacket(bytesConstRef(&_msg))) + clogS(NetWarn) << "INVALID PACKET CONSTRUCTED!"; -void Session::writeImpl(bytes& _buffer) -{ // cerr << (void*)this << " writeImpl" << endl; if (!m_socket.is_open()) return; bool doWrite = false; { - lock_guard l(m_writeLock); - m_writeQueue.push_back(_buffer); + Guard l(x_writeQueue); + m_writeQueue.push_back(_msg); doWrite = (m_writeQueue.size() == 1); } @@ -453,18 +431,16 @@ void Session::write() auto self(shared_from_this()); ba::async_write(m_socket, ba::buffer(bytes), [this, self](boost::system::error_code ec, std::size_t /*length*/) { -// cerr << (void*)this << " write.callback" << endl; - // must check queue, as write callback can occur following dropped() if (ec) { clogS(NetWarn) << "Error sending: " << ec.message(); - dropped(); + drop(TCPError); return; } else { - lock_guard l(m_writeLock); + Guard l(x_writeQueue); m_writeQueue.pop_front(); if (m_writeQueue.empty()) return; @@ -473,37 +449,43 @@ void Session::write() }); } -void Session::dropped() +void Session::drop(DisconnectReason _reason) { -// cerr << (void*)this << " dropped" << endl; + if (m_dropped) + return; + cerr << (void*)this << " dropped" << endl; if (m_socket.is_open()) try { - clogS(NetConnect) << "Closing " << m_socket.remote_endpoint(); + clogS(NetConnect) << "Closing " << m_socket.remote_endpoint() << "(" << reasonOf(_reason) << ")"; m_socket.close(); } catch (...) {} -} - -void Session::disconnect(DisconnectReason _reason) -{ - clogS(NetConnect) << "Disconnecting (reason:" << reasonOf((DisconnectReason)_reason) << ")"; if (m_node) + { + if (_reason != m_node->lastDisconnect || _reason == NoDisconnect || _reason == ClientQuit || _reason == DisconnectRequested) + m_node->failedAttempts = 0; m_node->lastDisconnect = _reason; + if (_reason == BadProtocol) + { + m_node->rating /= 2; + m_node->score /= 2; + } + } + m_dropped = true; +} +void Session::disconnect(DisconnectReason _reason) +{ + clogS(NetConnect) << "Disconnecting (our reason:" << reasonOf(_reason) << ")"; if (m_socket.is_open()) { - if (m_disconnect == chrono::steady_clock::time_point::max()) - { - RLPStream s; - prep(s, DisconnectPacket, 1) << _reason; - sealAndSend(s); - m_disconnect = chrono::steady_clock::now(); - } - else - dropped(); + RLPStream s; + prep(s, DisconnectPacket, 1) << (int)_reason; + sealAndSend(s); } + drop(_reason); } void Session::start() @@ -523,7 +505,7 @@ void Session::start() void Session::doRead() { // ignore packets received while waiting to disconnect - if (chrono::steady_clock::now() - m_disconnect > chrono::seconds(0)) + if (m_dropped) return; auto self(shared_from_this()); @@ -534,7 +516,7 @@ void Session::doRead() { // got here with length of 1241... clogS(NetWarn) << "Error reading: " << ec.message(); - dropped(); + drop(TCPError); } else if (ec && length == 0) { @@ -575,8 +557,8 @@ void Session::doRead() RLP r(data.cropped(8)); if (!interpret(r)) { - // error - dropped(); + // error - bad protocol + disconnect(BadProtocol); return; } } @@ -589,12 +571,12 @@ void Session::doRead() catch (Exception const& _e) { clogS(NetWarn) << "ERROR: " << diagnostic_information(_e); - dropped(); + drop(BadProtocol); } catch (std::exception const& _e) { clogS(NetWarn) << "ERROR: " << _e.what(); - dropped(); + drop(BadProtocol); } } }); diff --git a/libp2p/Session.h b/libp2p/Session.h index e76edd8b1..289abca26 100644 --- a/libp2p/Session.h +++ b/libp2p/Session.h @@ -30,6 +30,7 @@ #include #include #include +#include #include "Common.h" namespace dev @@ -72,7 +73,7 @@ public: static RLPStream& prep(RLPStream& _s, PacketType _t, unsigned _args = 0); static RLPStream& prep(RLPStream& _s); void sealAndSend(RLPStream& _s); - void sendDestroy(bytes& _msg); + void send(bytes&& _msg); void send(bytesConstRef _msg); int rating() const; @@ -86,43 +87,48 @@ public: void serviceNodesRequest(); private: - void dropped(); + /// Drop the connection for the reason @a _r. + void drop(DisconnectReason _r); + + /// Perform a read on the socket. void doRead(); - void doWrite(std::size_t length); + + /// The void writeImpl(bytes& _buffer); + + /// Perform a single round of the write operation. This could end up calling itself asynchronously. void write(); + /// Interpret an incoming message. bool interpret(RLP const& _r); /// @returns true iff the _msg forms a valid message for sending or receiving on the network. static bool checkPacket(bytesConstRef _msg); - Host* m_server; + Host* m_server; ///< The host that owns us. Never null. - std::mutex m_writeLock; - std::deque m_writeQueue; + mutable bi::tcp::socket m_socket; ///< Socket for the peer's connection. Mutable to ask for native_handle(). + Mutex x_writeQueue; ///< Mutex for the write queue. + std::deque m_writeQueue; ///< The write queue. + std::array m_data; ///< Data buffer for the write queue. + bytes m_incoming; ///< The incoming read queue of bytes. - mutable bi::tcp::socket m_socket; ///< Mutable to ask for native_handle(). - std::array m_data; - PeerInfo m_info; + PeerInfo m_info; ///< Dyanamic information about this peer. - bytes m_incoming; - unsigned m_protocolVersion; - std::shared_ptr m_node; - bi::tcp::endpoint m_manualEndpoint; - bool m_force = false; /// If true, ignore IDs being different. This could open you up to MitM attacks. + unsigned m_protocolVersion = 0; ///< The protocol version of the peer. + std::shared_ptr m_node; ///< The Node object. Might be null if we constructed using a bare address/port. + bi::tcp::endpoint m_manualEndpoint; ///< The endpoint as specified by the constructor. + bool m_force = false; ///< If true, ignore IDs being different. This could open you up to MitM attacks. + bool m_dropped = false; ///< If true, we've already divested ourselves of this peer. We're just waiting for the reads & writes to fail before the shared_ptr goes OOS and the destructor kicks in. - bool m_theyRequestedNodes = false; - bool m_weRequestedNodes = false; + bool m_theyRequestedNodes = false; ///< Has the peer requested nodes from us without receiveing an answer from us? + bool m_weRequestedNodes = false; ///< Have we requested nodes from the peer and not received an answer yet? - std::chrono::steady_clock::time_point m_ping; - std::chrono::steady_clock::time_point m_connect; - std::chrono::steady_clock::time_point m_disconnect; + std::chrono::steady_clock::time_point m_ping; ///< Time point of last ping. + std::chrono::steady_clock::time_point m_connect; ///< Time point of connection. - std::map> m_capabilities; + std::map> m_capabilities; ///< The peer's capability set. RangeMask m_knownNodes; ///< Nodes we already know about as indices into Host's nodesList. These shouldn't be resent to peer. - - bool m_willBeDeleted = false; ///< True if we already posted a deleter on the strand. }; } From 2e972be64082be766e06ea9ef645e1137f8ad50f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 11 Oct 2014 15:44:24 +0200 Subject: [PATCH 07/29] Efforts to make reconnect timing strategy more expansive and consistent. --- libp2p/Host.cpp | 39 +++++++++++++++++++++------------------ libp2p/Host.h | 5 +++-- libp2p/Session.cpp | 13 ++++++++----- libp2p/Session.h | 3 --- 4 files changed, 32 insertions(+), 28 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 2c93e64e0..b3b8cdbc1 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -506,6 +506,7 @@ void Node::connect(Host* _h) if (ec) { clog(NetConnect) << "Connection refused to node" << id.abridged() << "@" << address << "(" << ec.message() << ")"; + lastDisconnect = TCPError; _h->m_ready += index; } else @@ -533,26 +534,33 @@ bool Host::havePeer(NodeId _id) const return !!m_peers.count(_id); } -unsigned cumulativeFallback(unsigned _failed, DisconnectReason _r) +unsigned Node::fallbackSeconds() const { - switch (_r) + switch (lastDisconnect) { case BadProtocol: - return 30 * (_failed + 1); + return 30 * (failedAttempts + 1); case UselessPeer: case TooManyPeers: case ClientQuit: - return 15 * (_failed + 1); + return 15 * (failedAttempts + 1); + case NoDisconnect: + return 0; default: - if (_failed < 5) - return _failed * 5; - else if (_failed < 15) - return 25 + (_failed - 5) * 10; + if (failedAttempts < 5) + return failedAttempts * 5; + else if (failedAttempts < 15) + return 25 + (failedAttempts - 5) * 10; else - return 25 + 100 + (_failed - 15) * 20; + return 25 + 100 + (failedAttempts - 15) * 20; } } +bool Node::shouldReconnect() const +{ + return chrono::system_clock::now() > lastAttempted + chrono::seconds(fallbackSeconds()); +} + void Host::growPeers() { RecursiveGuard l(x_peers); @@ -564,7 +572,7 @@ void Host::growPeers() toTry -= m_private; set ns; for (auto i: toTry) - if (chrono::system_clock::now() > m_nodes[m_nodesList[i]]->lastAttempted + chrono::seconds(cumulativeFallback(m_nodes[m_nodesList[i]]->failedAttempts, m_nodes[m_nodesList[i]]->lastDisconnect))) + if (m_nodes[m_nodesList[i]]->shouldReconnect()) ns.insert(*m_nodes[m_nodesList[i]]); if (ns.size()) @@ -577,18 +585,13 @@ void Host::growPeers() else { ensureAccepting(); - requestNodes(); + for (auto const& i: m_peers) + if (auto p = i.second.lock()) + p->ensureNodesRequested(); } } } -void Host::requestNodes() -{ - for (auto const& i: m_peers) - if (auto p = i.second.lock()) - p->ensureNodesRequested(); -} - void Host::prunePeers() { RecursiveGuard l(x_peers); diff --git a/libp2p/Host.h b/libp2p/Host.h index a7beb8c35..52e4af6be 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -75,6 +75,9 @@ struct Node int secondsSinceLastConnected() const { return lastConnected == std::chrono::system_clock::time_point() ? -1 : (int)std::chrono::duration_cast(std::chrono::system_clock::now() - lastConnected).count(); } int secondsSinceLastAttempted() const { return lastAttempted == std::chrono::system_clock::time_point() ? -1 : (int)std::chrono::duration_cast(std::chrono::system_clock::now() - lastAttempted).count(); } + unsigned fallbackSeconds() const; + bool shouldReconnect() const; + bool isOffline() const { return lastDisconnect == -1 || lastAttempted > lastConnected; } bool operator<(Node const& _n) const { @@ -200,8 +203,6 @@ private: std::shared_ptr noteNode(NodeId _id, bi::tcp::endpoint const& _a, Origin _o, bool _ready, NodeId _oldId = h256()); Nodes potentialPeers(RangeMask const& _known); - void requestNodes(); - std::string m_clientVersion; ///< Our version string. NetworkPreferences m_netPrefs; ///< Network settings. diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 7c0d291c4..79b84111a 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -249,12 +249,15 @@ bool Session::interpret(RLP const& _r) { string reason = "Unspecified"; auto r = (DisconnectReason)_r[1].toInt(); - if (_r[1].isInt()) + if (!_r[1].isInt()) + drop(BadProtocol); + else + { reason = reasonOf(r); - - clogS(NetMessageSummary) << "Disconnect (reason: " << reason << ")"; - drop(DisconnectRequested); - return true; + clogS(NetMessageSummary) << "Disconnect (reason: " << reason << ")"; + drop(DisconnectRequested); + } + break; } case PingPacket: { diff --git a/libp2p/Session.h b/libp2p/Session.h index 289abca26..f76162cca 100644 --- a/libp2p/Session.h +++ b/libp2p/Session.h @@ -93,9 +93,6 @@ private: /// Perform a read on the socket. void doRead(); - /// The - void writeImpl(bytes& _buffer); - /// Perform a single round of the write operation. This could end up calling itself asynchronously. void write(); From a775c54adf368b902c645437e32d6b188395822d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 11 Oct 2014 16:06:40 +0200 Subject: [PATCH 08/29] UX fixes to nodes view. --- alethzero/MainWin.cpp | 7 +++---- libp2p/Host.cpp | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index f55bf2d9f..e9dcf0ff6 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -767,14 +767,13 @@ void Main::refreshNetwork() ui->nodes->clear(); for (p2p::Node const& i: ns) if (!i.dead) - ui->nodes->addItem(QString("[%1%3] %2 - ( =%5s | /%4s | %6 | %7x ) - *%8 $%9") + ui->nodes->addItem(QString("[%1%3] %2 - ( =%5s | /%4s%6 ) - *%7 $%8") .arg(QString::fromStdString(i.id.abridged())) .arg(QString::fromStdString(toString(i.address))) - .arg(i.id == web3()->id() ? " self" : i.isOffline() ? " ripe" : " ----") + .arg(i.id == web3()->id() ? " self" : i.isOffline() ? QString::number(i.fallbackSeconds() - i.secondsSinceLastAttempted()) + "s" : " ----") .arg(i.secondsSinceLastAttempted()) .arg(i.secondsSinceLastConnected()) - .arg(QString::fromStdString(reasonOf(i.lastDisconnect))) - .arg(i.failedAttempts) + .arg(i.lastDisconnect == NoDisconnect ? QString("") : (" | " + QString::fromStdString(reasonOf(i.lastDisconnect)) + " | " + QString::number(i.failedAttempts) + "x")) .arg(i.rating) .arg((int)i.idOrigin) ); diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index b3b8cdbc1..85b0af81e 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -507,6 +507,7 @@ void Node::connect(Host* _h) { clog(NetConnect) << "Connection refused to node" << id.abridged() << "@" << address << "(" << ec.message() << ")"; lastDisconnect = TCPError; + lastAttempted = std::chrono::system_clock::now(); _h->m_ready += index; } else From 33ec3ca35d76207dd5e170472d693e64d186519e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 11 Oct 2014 18:51:04 +0200 Subject: [PATCH 09/29] Pinging, stake disconnecting and better UI. --- alethzero/MainWin.cpp | 11 +++++++---- libdevcore/Common.cpp | 2 +- libp2p/Common.h | 2 +- libp2p/Host.cpp | 9 +++++++++ libp2p/Host.h | 6 ++++-- libp2p/Session.cpp | 6 ++++-- libp2p/Session.h | 7 ++++--- 7 files changed, 30 insertions(+), 13 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index e9dcf0ff6..3964f0e6f 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -750,6 +750,9 @@ void Main::refreshBalances() void Main::refreshNetwork() { auto ps = web3()->peers(); + + map clients; + ui->peerCount->setText(QString::fromStdString(toString(ps.size())) + " peer(s)"); ui->peers->clear(); for (PeerInfo const& i: ps) @@ -757,7 +760,7 @@ void Main::refreshNetwork() .arg(QString::fromStdString(i.host)) .arg(i.port) .arg(chrono::duration_cast(i.lastPing).count()) - .arg(QString::fromStdString(i.clientVersion)) + .arg(clients[i.id] = QString::fromStdString(i.clientVersion)) .arg(QString::fromStdString(toString(i.caps))) .arg(QString::fromStdString(toString(i.notes))) .arg(i.socket) @@ -767,13 +770,13 @@ void Main::refreshNetwork() ui->nodes->clear(); for (p2p::Node const& i: ns) if (!i.dead) - ui->nodes->addItem(QString("[%1%3] %2 - ( =%5s | /%4s%6 ) - *%7 $%8") + ui->nodes->addItem(QString("[%1 %3] %2 - ( =%5s | /%4s%6 ) - *%7 $%8") .arg(QString::fromStdString(i.id.abridged())) .arg(QString::fromStdString(toString(i.address))) - .arg(i.id == web3()->id() ? " self" : i.isOffline() ? QString::number(i.fallbackSeconds() - i.secondsSinceLastAttempted()) + "s" : " ----") + .arg(i.id == web3()->id() ? "self" : i.isOffline() ? i.secondsSinceLastAttempted() > -1 ? "retry-" + QString::number(i.fallbackSeconds() - i.secondsSinceLastAttempted()) + "s" : "session-fail" : clients[i.id]) .arg(i.secondsSinceLastAttempted()) .arg(i.secondsSinceLastConnected()) - .arg(i.lastDisconnect == NoDisconnect ? QString("") : (" | " + QString::fromStdString(reasonOf(i.lastDisconnect)) + " | " + QString::number(i.failedAttempts) + "x")) + .arg(i.isOffline() ? " | " + QString::fromStdString(reasonOf(i.lastDisconnect)) + " | " + QString::number(i.failedAttempts) + "x" : "") .arg(i.rating) .arg((int)i.idOrigin) ); diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index b67e3e62c..41b75f5ec 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.7.2"; +char const* Version = "0.7.3"; } diff --git a/libp2p/Common.h b/libp2p/Common.h index 04154c9a0..7c2c61156 100644 --- a/libp2p/Common.h +++ b/libp2p/Common.h @@ -88,6 +88,7 @@ enum DisconnectReason ClientQuit, UnexpectedIdentity, LocalIdentity, + PingTimeout, UserReason = 0x10, NoDisconnect = 0xffff }; @@ -96,7 +97,6 @@ inline bool isPermanentProblem(DisconnectReason _r) { switch (_r) { - case DisconnectRequested: case DuplicatePeer: case IncompatibleProtocol: case NullIdentity: diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 85b0af81e..73808633a 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -655,6 +655,15 @@ void Host::doWork() m_hadNewNodes = false; } + if (chrono::steady_clock::now() - m_lastPing > chrono::seconds(30)) // ping every 30s. + { + for (auto p: m_peers) + if (auto pp = p.second.lock()) + if (chrono::steady_clock::now() - pp->m_lastReceived > chrono::seconds(30)) + pp->disconnect(PingTimeout); + pingAll(); + } + m_ioService.poll(); } diff --git a/libp2p/Host.h b/libp2p/Host.h index 52e4af6be..ca546390c 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -78,7 +78,7 @@ struct Node unsigned fallbackSeconds() const; bool shouldReconnect() const; - bool isOffline() const { return lastDisconnect == -1 || lastAttempted > lastConnected; } + bool isOffline() const { return lastAttempted > lastConnected; } bool operator<(Node const& _n) const { if (isOffline() != _n.isOffline()) @@ -121,7 +121,7 @@ class Host: public Worker { friend class Session; friend class HostCapabilityFace; - friend class Node; + friend struct Node; public: /// Start server, listening for connections on the given port. @@ -245,6 +245,8 @@ private: // Our capabilities. std::map> m_capabilities; ///< Each of the capabilities we support. + std::chrono::steady_clock::time_point m_lastPing; ///< Time we sent the last ping to all peers. + bool m_accepting = false; }; diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 79b84111a..20d50025d 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -42,7 +42,7 @@ Session::Session(Host* _s, bi::tcp::socket _socket, bi::tcp::endpoint const& _ma m_node(nullptr), m_manualEndpoint(_manual) { - m_connect = std::chrono::steady_clock::now(); + m_lastReceived = m_connect = std::chrono::steady_clock::now(); m_info = PeerInfo({NodeId(), "?", m_manualEndpoint.address().to_string(), m_manualEndpoint.port(), std::chrono::steady_clock::duration(0), CapDescSet(), 0, map()}); } @@ -54,7 +54,7 @@ Session::Session(Host* _s, bi::tcp::socket _socket, std::shared_ptr const& m_manualEndpoint(_n->address), m_force(_force) { - m_connect = std::chrono::steady_clock::now(); + m_lastReceived = m_connect = std::chrono::steady_clock::now(); m_info = PeerInfo({m_node->id, "?", _n->address.address().to_string(), _n->address.port(), std::chrono::steady_clock::duration(0), CapDescSet(), 0, map()}); } @@ -167,6 +167,8 @@ void Session::serviceNodesRequest() bool Session::interpret(RLP const& _r) { + m_lastReceived = chrono::steady_clock::now(); + clogS(NetRight) << _r; try // Generic try-catch block designed to capture RLP format errors - TODO: give decent diagnostics, make a bit more specific over what is caught. { diff --git a/libp2p/Session.h b/libp2p/Session.h index f76162cca..e8de1c398 100644 --- a/libp2p/Session.h +++ b/libp2p/Session.h @@ -39,7 +39,7 @@ namespace dev namespace p2p { -class Node; +struct Node; /** * @brief The Session class @@ -121,8 +121,9 @@ private: bool m_theyRequestedNodes = false; ///< Has the peer requested nodes from us without receiveing an answer from us? bool m_weRequestedNodes = false; ///< Have we requested nodes from the peer and not received an answer yet? - std::chrono::steady_clock::time_point m_ping; ///< Time point of last ping. - std::chrono::steady_clock::time_point m_connect; ///< Time point of connection. + std::chrono::steady_clock::time_point m_connect; ///< Time point of connection. + std::chrono::steady_clock::time_point m_ping; ///< Time point of last ping. + std::chrono::steady_clock::time_point m_lastReceived; ///< Time point of last message. std::map> m_capabilities; ///< The peer's capability set. RangeMask m_knownNodes; ///< Nodes we already know about as indices into Host's nodesList. These shouldn't be resent to peer. From 692cb38006f8d22061e6a256ce3a430bc2f8d0d2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 11 Oct 2014 18:53:25 +0200 Subject: [PATCH 10/29] Remember last ping time. --- libp2p/Host.cpp | 1 + libqethereum/QEthereum.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 73808633a..2e870ba33 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -673,6 +673,7 @@ void Host::pingAll() for (auto& i: m_peers) if (auto j = i.second.lock()) j->ping(); + m_lastPing = chrono::steady_clock::now(); } bytes Host::saveNodes() const diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index a244b9c9b..89cd71792 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -396,7 +396,7 @@ static QString toJson(dev::eth::Transaction const& _bi) v["from"] = toQJS(_bi.sender()); v["gas"] = (int)_bi.gas; v["gasPrice"] = toQJS(_bi.gasPrice); - v["nonce"] = toQJS(_bi.nonce); + v["nonce"] = (int)_bi.nonce; v["value"] = toQJS(_bi.value); return QString::fromUtf8(QJsonDocument(v).toJson()); From 0652e3ed4f6cfee20c42626d8a530f6bb8d54fa1 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 11 Oct 2014 19:22:38 +0200 Subject: [PATCH 11/29] Fix a previous bad fix. --- eth/main.cpp | 71 +++++++++++++++++++++--------------------- libethereum/Client.cpp | 37 +++++++++++++--------- libethereum/State.cpp | 9 +----- libp2p/Host.cpp | 2 ++ libp2p/Session.cpp | 2 +- 5 files changed, 62 insertions(+), 59 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 95d1c21fa..b5e8eb736 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -630,46 +630,47 @@ int main(int argc, char** argv) try { e.setup(&r); + + OnOpFunc oof; + if (format == "pretty") + oof = [&](uint64_t steps, Instruction instr, bigint newMemSize, bigint gasCost, void* vvm, void const* vextVM) + { + dev::eth::VM* vm = (VM*)vvm; + dev::eth::ExtVM const* ext = (ExtVM const*)vextVM; + f << endl << " STACK" << endl; + for (auto i: vm->stack()) + f << (h256)i << endl; + f << " MEMORY" << endl << dev::memDump(vm->memory()); + f << " STORAGE" << endl; + for (auto const& i: ext->state().storage(ext->myAddress)) + f << showbase << hex << i.first << ": " << i.second << endl; + f << dec << ext->depth << " | " << ext->myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm->curPC() << " : " << dev::eth::instructionInfo(instr).name << " | " << dec << vm->gas() << " | -" << dec << gasCost << " | " << newMemSize << "x32"; + }; + else if (format == "standard") + oof = [&](uint64_t, Instruction instr, bigint, bigint, void* vvm, void const* vextVM) + { + dev::eth::VM* vm = (VM*)vvm; + dev::eth::ExtVM const* ext = (ExtVM const*)vextVM; + f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl; + }; + else if (format == "standard+") + oof = [&](uint64_t, Instruction instr, bigint, bigint, void* vvm, void const* vextVM) + { + dev::eth::VM* vm = (VM*)vvm; + dev::eth::ExtVM const* ext = (ExtVM const*)vextVM; + if (instr == Instruction::STOP || instr == Instruction::RETURN || instr == Instruction::SUICIDE) + for (auto const& i: ext->state().storage(ext->myAddress)) + f << toHex(dev::toCompactBigEndian(i.first, 1)) << " " << toHex(dev::toCompactBigEndian(i.second, 1)) << endl; + f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl; + }; + e.go(oof); + e.finalize(oof); } catch(Exception const& _e) { + // TODO: a bit more information here. this is probably quite worrying as the transaction is already in the blockchain. cwarn << diagnostic_information(_e); } - - OnOpFunc oof; - if (format == "pretty") - oof = [&](uint64_t steps, Instruction instr, bigint newMemSize, bigint gasCost, void* vvm, void const* vextVM) - { - dev::eth::VM* vm = (VM*)vvm; - dev::eth::ExtVM const* ext = (ExtVM const*)vextVM; - f << endl << " STACK" << endl; - for (auto i: vm->stack()) - f << (h256)i << endl; - f << " MEMORY" << endl << dev::memDump(vm->memory()); - f << " STORAGE" << endl; - for (auto const& i: ext->state().storage(ext->myAddress)) - f << showbase << hex << i.first << ": " << i.second << endl; - f << dec << ext->depth << " | " << ext->myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm->curPC() << " : " << dev::eth::instructionInfo(instr).name << " | " << dec << vm->gas() << " | -" << dec << gasCost << " | " << newMemSize << "x32"; - }; - else if (format == "standard") - oof = [&](uint64_t, Instruction instr, bigint, bigint, void* vvm, void const* vextVM) - { - dev::eth::VM* vm = (VM*)vvm; - dev::eth::ExtVM const* ext = (ExtVM const*)vextVM; - f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl; - }; - else if (format == "standard+") - oof = [&](uint64_t, Instruction instr, bigint, bigint, void* vvm, void const* vextVM) - { - dev::eth::VM* vm = (VM*)vvm; - dev::eth::ExtVM const* ext = (ExtVM const*)vextVM; - if (instr == Instruction::STOP || instr == Instruction::RETURN || instr == Instruction::SUICIDE) - for (auto const& i: ext->state().storage(ext->myAddress)) - f << toHex(dev::toCompactBigEndian(i.first, 1)) << " " << toHex(dev::toCompactBigEndian(i.second, 1)) << endl; - f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl; - }; - e.go(oof); - e.finalize(oof); } } else if (c && cmd == "inspect") diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index d22f7d873..717e2684c 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -323,23 +323,30 @@ void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _ bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) { - State temp; - Transaction t; -// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); + bytes out; + try { - ReadGuard l(x_stateDB); - temp = m_postMine; - t.nonce = temp.transactionsFrom(toAddress(_secret)); + State temp; + Transaction t; + // cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); + { + ReadGuard l(x_stateDB); + temp = m_postMine; + t.nonce = temp.transactionsFrom(toAddress(_secret)); + } + t.value = _value; + t.gasPrice = _gasPrice; + t.gas = _gas; + t.receiveAddress = _dest; + t.data = _data; + t.sign(_secret); + u256 gasUsed = temp.execute(t.data, &out, false); + (void)gasUsed; // TODO: do something with gasused which it returns. + } + catch (...) + { + // TODO: Some sort of notification of failure. } - t.value = _value; - t.gasPrice = _gasPrice; - t.gas = _gas; - t.receiveAddress = _dest; - t.data = _data; - t.sign(_secret); - bytes out; - u256 gasUsed = temp.execute(t.data, &out, false); - (void)gasUsed; // TODO: do something with gasused which it returns. return out; } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 105df0172..3fed4ae23 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -1054,14 +1054,7 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit) Manifest ms; Executive e(*this, &ms); - try - { - e.setup(_rlp); - } - catch (Exception const & _e) - { - cwarn << diagnostic_information(_e); - } + e.setup(_rlp); u256 startGasUsed = gasUsed(); diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 2e870ba33..84a8766ea 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -346,6 +346,8 @@ void Host::populateAddresses() shared_ptr Host::noteNode(NodeId _id, bi::tcp::endpoint const& _a, Origin _o, bool _ready, NodeId _oldId) { RecursiveGuard l(x_peers); + if (_a.port() < 30300 && _a.port() > 30303) + cwarn << "Wierd port being recorded!"; cnote << "Node:" << _id.abridged() << _a << (_ready ? "ready" : "used") << _oldId.abridged() << (m_nodes.count(_id) ? "[have]" : "[NEW]"); if (!_a.port()) { diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 20d50025d..119881c24 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -40,7 +40,7 @@ Session::Session(Host* _s, bi::tcp::socket _socket, bi::tcp::endpoint const& _ma m_server(_s), m_socket(std::move(_socket)), m_node(nullptr), - m_manualEndpoint(_manual) + m_manualEndpoint(_manual) // NOTE: the port on this shouldn't be used if it's zero. { m_lastReceived = m_connect = std::chrono::steady_clock::now(); From 51994f72a0410a91dbb2134150832e5e19518c4a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 11 Oct 2014 19:24:39 +0200 Subject: [PATCH 12/29] Don't save peers with odd ports for now. --- libp2p/Host.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 84a8766ea..b216d8f5b 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -687,7 +687,7 @@ bytes Host::saveNodes() const for (auto const& i: m_nodes) { Node const& n = *(i.second); - if (!n.dead && n.id != id() && !isPrivateAddress(n.address.address())) + if (!n.dead && n.address.port() > 0 && n.address.port() >= 30300 && n.address.port() <= 30305 && n.id != id() && !isPrivateAddress(n.address.address())) { nodes.appendList(10); if (n.address.address().is_v4()) From 3ac0eb089b04adb3f88f9a3e6ccd1e42b2b98853 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 11 Oct 2014 19:59:22 +0200 Subject: [PATCH 13/29] Kill old database (invalid transactions in there). --- libethcore/CommonEth.cpp | 4 ++-- libp2p/Session.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index 1526da1b0..40a86dba4 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -34,8 +34,8 @@ namespace dev namespace eth { -const unsigned c_protocolVersion = 34; -const unsigned c_databaseVersion = 2; +const unsigned c_protocolVersion = 35; +const unsigned c_databaseVersion = 3; static const vector> g_units = { diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 119881c24..a144d398f 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -44,7 +44,7 @@ Session::Session(Host* _s, bi::tcp::socket _socket, bi::tcp::endpoint const& _ma { m_lastReceived = m_connect = std::chrono::steady_clock::now(); - m_info = PeerInfo({NodeId(), "?", m_manualEndpoint.address().to_string(), m_manualEndpoint.port(), std::chrono::steady_clock::duration(0), CapDescSet(), 0, map()}); + m_info = PeerInfo({NodeId(), "?", m_manualEndpoint.address().to_string(), 0, std::chrono::steady_clock::duration(0), CapDescSet(), 0, map()}); } Session::Session(Host* _s, bi::tcp::socket _socket, std::shared_ptr const& _n, bool _force): @@ -317,7 +317,7 @@ bool Session::interpret(RLP const& _r) // See if it's any better that ours or not... // This could be the public address of a known node. // SECURITY: remove this in beta - it's only for lazy connections and presents an easy attack vector. - if (m_server->m_nodes.count(id) && isPrivateAddress(m_server->m_nodes.at(id)->address.address())) + if (m_server->m_nodes.count(id) && isPrivateAddress(m_server->m_nodes.at(id)->address.address()) && ep.port() != 0) // Update address if the node if we now have a public IP for it. m_server->m_nodes[id]->address = ep; goto CONTINUE; From 61b786b70a716460ddb8a43767379451c9c339b9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 11 Oct 2014 20:02:18 +0200 Subject: [PATCH 14/29] Avoid listening to peers telling us of wierd ports. --- libp2p/Session.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index a144d398f..42a3dff89 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -326,6 +326,11 @@ bool Session::interpret(RLP const& _r) if (!ep.port()) goto CONTINUE; // Zero port? Don't think so. + // TODO: PoC-7: + // Technically fine, but ignore for now to avoid peers passing on incoming ports until we can be sure that doesn't happen any more. + if (ep.port() < 30300 || ep.port() > 30305) + goto CONTINUE; // Wierd port. + // Avoid our random other addresses that they might end up giving us. for (auto i: m_server->m_addresses) if (ep.address() == i && ep.port() == m_server->listenPort()) From 86127f382071d16b32e19ab8d667b509da43b8e0 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 11 Oct 2014 20:16:44 +0200 Subject: [PATCH 15/29] Avoid trying to connect to obviously private ports. --- libp2p/Host.cpp | 3 ++- libp2p/Session.cpp | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index b216d8f5b..b15d6ca40 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -687,7 +687,8 @@ bytes Host::saveNodes() const for (auto const& i: m_nodes) { Node const& n = *(i.second); - if (!n.dead && n.address.port() > 0 && n.address.port() >= 30300 && n.address.port() <= 30305 && n.id != id() && !isPrivateAddress(n.address.address())) + // TODO: PoC-7: Figure out why it ever shares these ports.//n.address.port() >= 30300 && n.address.port() <= 30305 && + if (!n.dead && n.address.port() > 0 && n.address.port() < 49152 && n.id != id() && !isPrivateAddress(n.address.address())) { nodes.appendList(10); if (n.address.address().is_v4()) diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 42a3dff89..3860b34c3 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -326,10 +326,13 @@ bool Session::interpret(RLP const& _r) if (!ep.port()) goto CONTINUE; // Zero port? Don't think so. + if (ep.port() >= 49152) + goto CONTINUE; // Private port according to IANA. + // TODO: PoC-7: // Technically fine, but ignore for now to avoid peers passing on incoming ports until we can be sure that doesn't happen any more. - if (ep.port() < 30300 || ep.port() > 30305) - goto CONTINUE; // Wierd port. +// if (ep.port() < 30300 || ep.port() > 30305) +// goto CONTINUE; // Wierd port. // Avoid our random other addresses that they might end up giving us. for (auto i: m_server->m_addresses) From e27922258dfca9f1d8784f3054fa56eb6b802d28 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 11 Oct 2014 20:18:52 +0200 Subject: [PATCH 16/29] Avoid noting nodes with obviously bad listen ports. --- libp2p/Host.cpp | 9 ++++++++- libp2p/Host.h | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index b15d6ca40..6b4deed0c 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -343,11 +343,18 @@ void Host::populateAddresses() #endif } -shared_ptr Host::noteNode(NodeId _id, bi::tcp::endpoint const& _a, Origin _o, bool _ready, NodeId _oldId) +shared_ptr Host::noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId) { RecursiveGuard l(x_peers); if (_a.port() < 30300 && _a.port() > 30303) cwarn << "Wierd port being recorded!"; + + if (_a.port() >= 49152) + { + cwarn << "Private port being recorded - setting to 0"; + _a = bi::tcp::endpoint(_a.address(), 0); + } + cnote << "Node:" << _id.abridged() << _a << (_ready ? "ready" : "used") << _oldId.abridged() << (m_nodes.count(_id) ? "[have]" : "[NEW]"); if (!_a.port()) { diff --git a/libp2p/Host.h b/libp2p/Host.h index ca546390c..c981edc29 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -200,7 +200,7 @@ private: /// This won't touch alter the blockchain. virtual void doWork(); - std::shared_ptr noteNode(NodeId _id, bi::tcp::endpoint const& _a, Origin _o, bool _ready, NodeId _oldId = h256()); + std::shared_ptr noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId = h256()); Nodes potentialPeers(RangeMask const& _known); std::string m_clientVersion; ///< Our version string. From f11a4bb9737fcb835b93caa9159dd632b0a9ca3f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 11 Oct 2014 20:26:05 +0200 Subject: [PATCH 17/29] Avoid duplicate nodes with different IDs. --- libp2p/Host.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 6b4deed0c..d1ffa0999 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -356,10 +356,16 @@ shared_ptr Host::noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, boo } cnote << "Node:" << _id.abridged() << _a << (_ready ? "ready" : "used") << _oldId.abridged() << (m_nodes.count(_id) ? "[have]" : "[NEW]"); - if (!_a.port()) - { - cwarn << "PORT IS INVALID!"; - } + + // First check for another node with the same connection credentials, and put it in oldId if found. + if (!_oldId) + for (pair> const& n: m_nodes) + if (n.second->address == _a && n.second->id != _id) + { + _oldId = n.second->id; + break; + } + unsigned i; if (!m_nodes.count(_id)) { From 76402e82fa00ca2cd18df69780cf52b6e583b223 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 11 Oct 2014 20:29:17 +0200 Subject: [PATCH 18/29] Bump to P2P protocol version 2. --- libp2p/Host.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index d1ffa0999..aed95a099 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -142,7 +142,7 @@ void Host::stop() unsigned Host::protocolVersion() const { - return 1; + return 2; } void Host::registerPeer(std::shared_ptr _s, CapDescs const& _caps) From be72db117e0f0e30cc15f484598a8a7c93fc3286 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 11 Oct 2014 20:35:01 +0200 Subject: [PATCH 19/29] Fix ping timeout. --- libp2p/Host.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index aed95a099..7ce453839 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -674,7 +674,7 @@ void Host::doWork() { for (auto p: m_peers) if (auto pp = p.second.lock()) - if (chrono::steady_clock::now() - pp->m_lastReceived > chrono::seconds(30)) + if (chrono::steady_clock::now() - pp->m_lastReceived > chrono::seconds(60)) pp->disconnect(PingTimeout); pingAll(); } From 7b48050a049f7d920083d2aeac74353bbc6bfc9b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 11 Oct 2014 20:36:46 +0200 Subject: [PATCH 20/29] Avoid public/private IP kludge. --- libp2p/Session.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 3860b34c3..2c0a6d87b 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -313,6 +313,7 @@ bool Session::interpret(RLP const& _r) // check that it's not us or one we already know: if (m_server->m_nodes.count(id)) { + /* MEH. Far from an ideal solution. Leave alone for now. // Already got this node. // See if it's any better that ours or not... // This could be the public address of a known node. @@ -320,6 +321,7 @@ bool Session::interpret(RLP const& _r) if (m_server->m_nodes.count(id) && isPrivateAddress(m_server->m_nodes.at(id)->address.address()) && ep.port() != 0) // Update address if the node if we now have a public IP for it. m_server->m_nodes[id]->address = ep; + */ goto CONTINUE; } From fb28639d5522b27ffe941f79e6a4dac6c10b80c3 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 11 Oct 2014 21:04:45 +0200 Subject: [PATCH 21/29] Fix NewBlock transmission. --- libethereum/EthereumHost.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index 8e92fa9e6..ee5105cd6 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -189,20 +189,14 @@ void EthereumHost::maintainBlocks(h256 _currentHash) // If we've finished our initial sync send any new blocks. if (!isSyncing() && m_chain.isKnown(m_latestBlockSent) && m_chain.details(m_latestBlockSent).totalDifficulty < m_chain.details(_currentHash).totalDifficulty) { - // TODO: clean up - h256s hs; - hs.push_back(_currentHash); - bytes bs; - for (auto h: hs) - bs += m_chain.block(h); - clog(NetMessageSummary) << "Sending" << hs.size() << "new blocks (current is" << _currentHash << ", was" << m_latestBlockSent << ")"; + clog(NetMessageSummary) << "Sending a new block (current is" << _currentHash << ", was" << m_latestBlockSent << ")"; for (auto j: peers()) { auto p = j->cap(); RLPStream ts; - p->prep(ts, NewBlockPacket, hs.size()).appendRaw(bs, hs.size()); + p->prep(ts, NewBlockPacket, 2).appendRaw(m_chain.block(), 1).append(m_chain.details().totalDifficulty); Guard l(p->x_knownBlocks); if (!p->m_knownBlocks.count(_currentHash)) From 492cbd80b9eae736df86e4b74a57a8123a5d4bcf Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 12 Oct 2014 19:20:38 +0200 Subject: [PATCH 22/29] Better management of peers that alter their ID. --- README.md | 6 +++-- alethzero/MainWin.cpp | 56 +++++++++++++++++++++++-------------------- libp2p/Host.cpp | 2 +- 3 files changed, 35 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 7529fed50..371b82097 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,11 @@ By Gav Wood, 2014. -Based on a design by Vitalik Buterin. +[![Build ++Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20master%20branch/builds/-1) master [![Build ++Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20branch/builds/-1) develop -Contributors, builders and testers include Eric Lombrozo (cross-compilation), Tim Hughes (MSVC compilation & Dagger testing), Alex Leverington (Clang & Mac building), Marko Simovic (CI) and several others. +Ethereum is based on a design in an original whitepaper by Vitalik Buterin. This implementation is based on the formal specification of a refinement of that idea detailed in the 'yellow paper' by Gavin Wood. Contributors, builders and testers include Alex Leverington (Clang & Mac building, client multiplexing), Tim Hughes (MSVC compilation & Dagger testing), Caktux (ongoing CI), Christoph Jentzsch (tests), Christian Reissweiner (Solidity), Marek Kotewicz (external JS & JSON-RPC), Eric Lombrozo (MinGW32 cross-compilation), Marko Simovic (original CI), and several others. ### Building diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 3964f0e6f..1da6b7d9a 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -751,35 +751,39 @@ void Main::refreshNetwork() { auto ps = web3()->peers(); - map clients; ui->peerCount->setText(QString::fromStdString(toString(ps.size())) + " peer(s)"); ui->peers->clear(); - for (PeerInfo const& i: ps) - ui->peers->addItem(QString("[%8 %7] %3 ms - %1:%2 - %4 %5 %6") - .arg(QString::fromStdString(i.host)) - .arg(i.port) - .arg(chrono::duration_cast(i.lastPing).count()) - .arg(clients[i.id] = QString::fromStdString(i.clientVersion)) - .arg(QString::fromStdString(toString(i.caps))) - .arg(QString::fromStdString(toString(i.notes))) - .arg(i.socket) - .arg(QString::fromStdString(i.id.abridged()))); - - auto ns = web3()->nodes(); ui->nodes->clear(); - for (p2p::Node const& i: ns) - if (!i.dead) - ui->nodes->addItem(QString("[%1 %3] %2 - ( =%5s | /%4s%6 ) - *%7 $%8") - .arg(QString::fromStdString(i.id.abridged())) - .arg(QString::fromStdString(toString(i.address))) - .arg(i.id == web3()->id() ? "self" : i.isOffline() ? i.secondsSinceLastAttempted() > -1 ? "retry-" + QString::number(i.fallbackSeconds() - i.secondsSinceLastAttempted()) + "s" : "session-fail" : clients[i.id]) - .arg(i.secondsSinceLastAttempted()) - .arg(i.secondsSinceLastConnected()) - .arg(i.isOffline() ? " | " + QString::fromStdString(reasonOf(i.lastDisconnect)) + " | " + QString::number(i.failedAttempts) + "x" : "") - .arg(i.rating) - .arg((int)i.idOrigin) - ); + + if (web3()->haveNetwork()) + { + map clients; + for (PeerInfo const& i: ps) + ui->peers->addItem(QString("[%8 %7] %3 ms - %1:%2 - %4 %5 %6") + .arg(QString::fromStdString(i.host)) + .arg(i.port) + .arg(chrono::duration_cast(i.lastPing).count()) + .arg(clients[i.id] = QString::fromStdString(i.clientVersion)) + .arg(QString::fromStdString(toString(i.caps))) + .arg(QString::fromStdString(toString(i.notes))) + .arg(i.socket) + .arg(QString::fromStdString(i.id.abridged()))); + + auto ns = web3()->nodes(); + for (p2p::Node const& i: ns) + if (!i.dead) + ui->nodes->insertItem(i.isOffline() ? ui->nodes->count() : 0, QString("[%1 %3] %2 - ( =%5s | /%4s%6 ) - *%7 $%8") + .arg(QString::fromStdString(i.id.abridged())) + .arg(QString::fromStdString(toString(i.address))) + .arg(i.id == web3()->id() ? "self" : i.isOffline() ? i.secondsSinceLastAttempted() > -1 ? i.secondsSinceLastAttempted() < (int)i.fallbackSeconds() ? "retry-" + QString::number(i.fallbackSeconds() - i.secondsSinceLastAttempted()) + "s" : "retrying..." : "session-fail" : clients[i.id]) + .arg(i.secondsSinceLastAttempted()) + .arg(i.secondsSinceLastConnected()) + .arg(i.isOffline() ? " | " + QString::fromStdString(reasonOf(i.lastDisconnect)) + " | " + QString::number(i.failedAttempts) + "x" : "") + .arg(i.rating) + .arg((int)i.idOrigin) + ); + } } void Main::refreshAll() @@ -973,7 +977,7 @@ void Main::timerEvent(QTimerEvent*) if (interval / 100 % 2 == 0) refreshMining(); - if (interval / 100 % 2 == 0 && m_webThree->ethereum()->isSyncing()) + if ((interval / 100 % 2 == 0 && m_webThree->ethereum()->isSyncing()) || interval == 1000) ui->downloadView->update(); if (m_logChanged) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 7ce453839..ea89b5613 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -382,7 +382,6 @@ shared_ptr Host::noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, boo } m_nodes[_id] = make_shared(); m_nodes[_id]->id = _id; - m_nodes[_id]->address = _a; m_nodes[_id]->index = i; m_nodes[_id]->idOrigin = _o; } @@ -391,6 +390,7 @@ shared_ptr Host::noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, boo i = m_nodes[_id]->index; m_nodes[_id]->idOrigin = max(m_nodes[_id]->idOrigin, _o); } + m_nodes[_id]->address = _a; m_ready.extendAll(i); m_private.extendAll(i); if (_ready) From ee947b562ee8094cff00f1c9c7fc09591bc2a7ea Mon Sep 17 00:00:00 2001 From: sveneh Date: Sun, 12 Oct 2014 19:22:57 +0200 Subject: [PATCH 23/29] refactor C++11 detection, BuildFile.h generation --- CMakeLists.txt | 65 ++++++++++++++++----------------- cmake/EthCompilerSettings.cmake | 15 ++++++++ 2 files changed, 46 insertions(+), 34 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 08a6295e6..04c795ad1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,8 +39,31 @@ function(configureProject) message(FATAL_ERROR "VM tracing requires debug.") endif () endif () +endfunction() + - message("LANGUAGES: ${LANGUAGES}; VMTRACE: ${VMTRACE}; PARANOIA: ${PARANOIA}; HEADLESS: ${HEADLESS}") +function(createBuildInfo) + # Set build platform; to be written to BuildInfo.h + if (CMAKE_COMPILER_IS_MINGW) + set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/mingw") + elseif (CMAKE_COMPILER_IS_MSYS) + set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/msys") + elseif (CMAKE_COMPILER_IS_GNUCXX) + set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/g++") + elseif (CMAKE_COMPILER_IS_MSVC) + set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/msvc") + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/clang") + else () + set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/unknown") + endif () + + # Generate header file containing useful build information + add_custom_target(BuildInfo.h ALL COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/BuildInfo.sh ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_BUILD_TYPE} ${ETH_BUILD_PLATFORM}) + include_directories(${CMAKE_CURRENT_BINARY_DIR}) + + set(CMAKE_INCLUDE_CURRENT_DIR ON) + set(SRC_LIST BuildInfo.h) endfunction() ###################################################################################################### @@ -52,6 +75,7 @@ cmake_policy(SET CMP0015 NEW) createDefaultCacheConfig() configureProject() +message("-- LANGUAGES: ${LANGUAGES}; VMTRACE: ${VMTRACE}; PARANOIA: ${PARANOIA}; HEADLESS: ${HEADLESS}") # Default TARGET_PLATFORM to "linux". @@ -71,40 +95,14 @@ endif () include(EthCompilerSettings) +message("-- CXXFLAGS: ${CMAKE_CXX_FLAGS}") + -# Set build platform; to be written to BuildInfo.h -if (CMAKE_COMPILER_IS_MINGW) - set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/mingw") -elseif (CMAKE_COMPILER_IS_MSYS) - set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/msys") -elseif (CMAKE_COMPILER_IS_GNUCXX) - set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/g++") -elseif (CMAKE_COMPILER_IS_MSVC) - set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/msvc") -elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/clang") -else () - set(ETH_BUILD_PLATFORM "${ETH_BUILD_PLATFORM}/unknown") -endif () -message("CXXFLAGS: ${CMAKE_CXX_FLAGS}") #add_definitions("-DETH_BUILD_TYPE=${ETH_BUILD_TYPE}") #add_definitions("-DETH_BUILD_PLATFORM=${ETH_BUILD_PLATFORM}") -# C++11 check and activation -if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") - execute_process( - COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) - if (NOT (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7)) - message(FATAL_ERROR "${PROJECT_NAME} requires g++ 4.7 or greater.") - endif () -elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") -else () - message(FATAL_ERROR "Your C++ compiler does not support C++11.") -endif () - if("${TARGET_PLATFORM}" STREQUAL "w64") # set(MINIUPNPC_LS /usr/x86_64-w64-mingw32/lib/libminiupnpc.a) set(LEVELDB_LS leveldb) @@ -300,15 +298,16 @@ if(JSONRPC_ID) include_directories(${JSONRPC_ID}) endif() -# Generate header file containing useful build information -add_custom_target(BuildInfo.h ALL COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/BuildInfo.sh ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_BUILD_TYPE} ${ETH_BUILD_PLATFORM}) -include_directories(${CMAKE_CURRENT_BINARY_DIR}) + + if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") link_directories(/usr/local/lib) include_directories(/usr/local/include) endif() +createBuildInfo() + add_subdirectory(libdevcore) add_subdirectory(libevmface) add_subdirectory(liblll) @@ -359,8 +358,6 @@ if (NOT LANGUAGES) endif() endif() -set(CMAKE_INCLUDE_CURRENT_DIR ON) -set(SRC_LIST BuildInfo.h) enable_testing() add_test(NAME alltests WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/test COMMAND testeth) diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake index 7404e924b..6103970c4 100644 --- a/cmake/EthCompilerSettings.cmake +++ b/cmake/EthCompilerSettings.cmake @@ -1,6 +1,21 @@ # Set necessary compile and link flags +# C++11 check and activation +if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") + execute_process( + COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) + if (NOT (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7)) + message(FATAL_ERROR "${PROJECT_NAME} requires g++ 4.7 or greater.") + endif () +elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") +else () + message(FATAL_ERROR "Your C++ compiler does not support C++11.") +endif () + + + # Initialize CXXFLAGS set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -DSHAREDLIB") set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DETH_DEBUG") From d74db4083c29bf5cd7520f18336bb87ad10d07ca Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 12 Oct 2014 20:57:25 +0200 Subject: [PATCH 24/29] Move Dagger to ProofOfWork and refactor in preparation for ARPoW. --- alethzero/MainWin.cpp | 1 - libethcore/BlockInfo.cpp | 4 +- libethcore/Dagger.h | 84 --------------- libethcore/{Dagger.cpp => ProofOfWork.cpp} | 97 ++--------------- libethcore/ProofOfWork.h | 117 +++++++++++++++++++++ libethcore/_libethcore.cpp | 2 +- libethereum/BlockChain.cpp | 2 +- libethereum/Client.h | 1 - libethereum/State.cpp | 3 +- libethereum/State.h | 4 +- libp2p/Session.cpp | 2 + libqethereum/QEthereum.cpp | 1 - libqethereum/QmlEthereum.cpp | 1 - test/dagger.cpp | 14 +-- third/MainWin.cpp | 1 - 15 files changed, 141 insertions(+), 193 deletions(-) delete mode 100644 libethcore/Dagger.h rename libethcore/{Dagger.cpp => ProofOfWork.cpp} (50%) create mode 100644 libethcore/ProofOfWork.h diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 1da6b7d9a..235da2230 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index f6d5731b3..536f684f2 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -24,7 +24,7 @@ #include #include #include -#include "Dagger.h" +#include "ProofOfWork.h" #include "Exceptions.h" #include "BlockInfo.h" using namespace std; @@ -99,7 +99,7 @@ void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce) } // check it hashes according to proof of work or that it's the genesis block. - if (_checkNonce && parentHash && !Dagger::verify(headerHashWithoutNonce(), nonce, difficulty)) + if (_checkNonce && parentHash && !ProofOfWork::verify(headerHashWithoutNonce(), nonce, difficulty)) BOOST_THROW_EXCEPTION(InvalidBlockNonce(headerHashWithoutNonce(), nonce, difficulty)); if (gasUsed > gasLimit) diff --git a/libethcore/Dagger.h b/libethcore/Dagger.h deleted file mode 100644 index c32ef38be..000000000 --- a/libethcore/Dagger.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file Dagger.h - * @author Gav Wood - * @date 2014 - * - * Dagger algorithm. Or not. - */ - -#pragma once - -#include -#include "CommonEth.h" - -#define FAKE_DAGGER 1 - -namespace dev -{ -namespace eth -{ - -struct MineInfo -{ - void combine(MineInfo const& _m) { requirement = std::max(requirement, _m.requirement); best = std::min(best, _m.best); hashes += _m.hashes; completed = completed || _m.completed; } - double requirement = 0; - double best = 1e99; - unsigned hashes = 0; - bool completed = false; -}; - -#if FAKE_DAGGER - -class Dagger -{ -public: - static h256 eval(h256 const& _root, h256 const& _nonce) { h256 b[2] = { _root, _nonce }; return sha3(bytesConstRef((byte const*)&b[0], 64)); } - static bool verify(h256 const& _root, h256 const& _nonce, u256 const& _difficulty) { return (bigint)(u256)eval(_root, _nonce) <= (bigint(1) << 256) / _difficulty; } - - MineInfo mine(h256& o_solution, h256 const& _root, u256 const& _difficulty, unsigned _msTimeout = 100, bool _continue = true, bool _turbo = false); - - h256 m_last; -}; - -#else - -/// Functions are not re-entrant. If you want to multi-thread, then use different classes for each thread. -class Dagger -{ -public: - Dagger(); - ~Dagger(); - - static u256 bound(u256 const& _difficulty); - static h256 eval(h256 const& _root, u256 const& _nonce); - static bool verify(h256 const& _root, u256 const& _nonce, u256 const& _difficulty); - - bool mine(u256& o_solution, h256 const& _root, u256 const& _difficulty, unsigned _msTimeout = 100, bool const& _continue = bool(true)); - -private: - - static h256 node(h256 const& _root, h256 const& _xn, uint_fast32_t _L, uint_fast32_t _i); - - h256 m_root; - u256 m_nonce; -}; - -#endif - -} -} diff --git a/libethcore/Dagger.cpp b/libethcore/ProofOfWork.cpp similarity index 50% rename from libethcore/Dagger.cpp rename to libethcore/ProofOfWork.cpp index 956557b64..7d3916fd3 100644 --- a/libethcore/Dagger.cpp +++ b/libethcore/ProofOfWork.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file Dagger.cpp +/** @file ProofOfWork.cpp * @author Gav Wood * @date 2014 */ @@ -28,7 +28,7 @@ #include #include #include -#include "Dagger.h" +#include "ProofOfWork.h" using namespace std; using namespace std::chrono; @@ -37,88 +37,8 @@ namespace dev namespace eth { -#if FAKE_DAGGER - -MineInfo Dagger::mine(h256& o_solution, h256 const& _root, u256 const& _difficulty, unsigned _msTimeout, bool _continue, bool _turbo) -{ - MineInfo ret; - static std::mt19937_64 s_eng((time(0) + (unsigned)m_last)); - u256 s = (m_last = h256::random(s_eng)); - - bigint d = (bigint(1) << 256) / _difficulty; - ret.requirement = log2((double)d); - - // 2^ 0 32 64 128 256 - // [--------*-------------------------] - // - // evaluate until we run out of time - auto startTime = steady_clock::now(); - if (!_turbo) - this_thread::sleep_for(chrono::milliseconds(_msTimeout * 90 / 100)); - for (; (steady_clock::now() - startTime) < milliseconds(_msTimeout) && _continue; s++, ret.hashes++) - { - o_solution = (h256)s; - auto e = (bigint)(u256)eval(_root, o_solution); - ret.best = min(ret.best, log2((double)e)); - if (e <= d) - { - ret.completed = true; - break; - } - } - - if (ret.completed) - assert(verify(_root, o_solution, _difficulty)); - - return ret; -} - -#else - -Dagger::Dagger() -{ -} - -Dagger::~Dagger() -{ -} - -u256 Dagger::bound(u256 const& _difficulty) -{ - return (u256)((bigint(1) << 256) / _difficulty); -} - -bool Dagger::verify(h256 const& _root, u256 const& _nonce, u256 const& _difficulty) -{ - return eval(_root, _nonce) < bound(_difficulty); -} - -bool Dagger::mine(u256& o_solution, h256 const& _root, u256 const& _difficulty, unsigned _msTimeout, bool const& _continue) -{ - // restart search if root has changed - if (m_root != _root) - { - m_root = _root; - m_nonce = 0; - } - - // compute bound - u256 const b = bound(_difficulty); - - // evaluate until we run out of time - for (auto startTime = steady_clock::now(); (steady_clock::now() - startTime) < milliseconds(_msTimeout) && _continue; m_nonce += 1) - { - if (eval(_root, m_nonce) < b) - { - o_solution = m_nonce; - return true; - } - } - return false; -} - template -inline void update(_T& _sha, u256 const& _value) +static inline void update(_T& _sha, u256 const& _value) { int i = 0; for (u256 v = _value; v; ++i, v >>= 8) {} @@ -129,7 +49,7 @@ inline void update(_T& _sha, u256 const& _value) } template -inline void update(_T& _sha, h256 const& _value) +static inline void update(_T& _sha, h256 const& _value) { int i = 0; byte const* data = _value.data(); @@ -138,14 +58,14 @@ inline void update(_T& _sha, h256 const& _value) } template -inline h256 get(_T& _sha) +static inline h256 get(_T& _sha) { h256 ret; _sha.TruncatedFinal(&ret[0], 32); return ret; } -h256 Dagger::node(h256 const& _root, h256 const& _xn, uint_fast32_t _L, uint_fast32_t _i) +h256 DaggerEvaluator::node(h256 const& _root, h256 const& _xn, uint_fast32_t _L, uint_fast32_t _i) { if (_L == _i) return _root; @@ -166,9 +86,9 @@ h256 Dagger::node(h256 const& _root, h256 const& _xn, uint_fast32_t _L, uint_fas return get(bsha); } -h256 Dagger::eval(h256 const& _root, u256 const& _nonce) +h256 DaggerEvaluator::eval(h256 const& _root, h256 const& _nonce) { - h256 extranonce = _nonce >> 26; // with xn = floor(n / 2^26) -> assuming this is with xn = floor(N / 2^26) + h256 extranonce = (u256)_nonce >> 26; // with xn = floor(n / 2^26) -> assuming this is with xn = floor(N / 2^26) CryptoPP::SHA3_256 bsha; for (uint_fast32_t k = 0; k < 4; ++k) { @@ -185,7 +105,6 @@ h256 Dagger::eval(h256 const& _root, u256 const& _nonce) return get(bsha); } -#endif } } #endif diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h new file mode 100644 index 000000000..d942d06f7 --- /dev/null +++ b/libethcore/ProofOfWork.h @@ -0,0 +1,117 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file ProofOfWork.h + * @author Gav Wood + * @date 2014 + * + * ProofOfWork algorithm. Or not. + */ + +#pragma once + +#include +#include +#include +#include +#include "CommonEth.h" + +#define FAKE_DAGGER 1 + +namespace dev +{ +namespace eth +{ + +struct MineInfo +{ + void combine(MineInfo const& _m) { requirement = std::max(requirement, _m.requirement); best = std::min(best, _m.best); hashes += _m.hashes; completed = completed || _m.completed; } + double requirement = 0; + double best = 1e99; + unsigned hashes = 0; + bool completed = false; +}; + +template +class ProofOfWorkEngine: public Evaluator +{ +public: + static bool verify(h256 const& _root, h256 const& _nonce, u256 const& _difficulty) { return (bigint)(u256)Evaluator::eval(_root, _nonce) <= (bigint(1) << 256) / _difficulty; } + + inline MineInfo mine(h256& o_solution, h256 const& _root, u256 const& _difficulty, unsigned _msTimeout = 100, bool _continue = true, bool _turbo = false); + +protected: + h256 m_last; +}; + +class SHA3Evaluator +{ +public: + static h256 eval(h256 const& _root, h256 const& _nonce) { h256 b[2] = { _root, _nonce }; return sha3(bytesConstRef((byte const*)&b[0], 64)); } +}; + +// TODO: class ARPoWEvaluator + +class DaggerEvaluator +{ +public: + static h256 eval(h256 const& _root, h256 const& _nonce); + +private: + static h256 node(h256 const& _root, h256 const& _xn, uint_fast32_t _L, uint_fast32_t _i); +}; + +using SHA3ProofOfWork = ProofOfWorkEngine; + +using ProofOfWork = SHA3ProofOfWork; + +template +MineInfo ProofOfWorkEngine::mine(h256& o_solution, h256 const& _root, u256 const& _difficulty, unsigned _msTimeout, bool _continue, bool _turbo) +{ + MineInfo ret; + static std::mt19937_64 s_eng((time(0) + (unsigned)m_last)); + u256 s = (m_last = h256::random(s_eng)); + + bigint d = (bigint(1) << 256) / _difficulty; + ret.requirement = log2((double)d); + + // 2^ 0 32 64 128 256 + // [--------*-------------------------] + // + // evaluate until we run out of time + auto startTime = std::chrono::steady_clock::now(); + if (!_turbo) + std::this_thread::sleep_for(std::chrono::milliseconds(_msTimeout * 90 / 100)); + for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; s++, ret.hashes++) + { + o_solution = (h256)s; + auto e = (bigint)(u256)Evaluator::eval(_root, o_solution); + ret.best = std::min(ret.best, log2((double)e)); + if (e <= d) + { + ret.completed = true; + break; + } + } + + if (ret.completed) + assert(verify(_root, o_solution, _difficulty)); + + return ret; +} + +} +} diff --git a/libethcore/_libethcore.cpp b/libethcore/_libethcore.cpp index 477034b9e..93eaf0d16 100644 --- a/libethcore/_libethcore.cpp +++ b/libethcore/_libethcore.cpp @@ -2,6 +2,6 @@ #include "All.h" #include "BlockInfo.cpp" #include "CommonEth.cpp" -#include "Dagger.cpp" +#include "ProofOfWork.cpp" #include "Exceptions.cpp" #endif diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 8e0619a43..d8c588118 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include "State.h" #include "Defaults.h" diff --git a/libethereum/Client.h b/libethereum/Client.h index e7bbc1ca3..8ec65c199 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -31,7 +31,6 @@ #include #include #include -#include #include #include "BlockChain.h" #include "TransactionQueue.h" diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 3fed4ae23..8f2794c12 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include "BlockChain.h" #include "Defaults.h" @@ -837,7 +836,7 @@ MineInfo State::mine(unsigned _msTimeout, bool _turbo) m_currentBlock.difficulty = m_currentBlock.calculateDifficulty(m_previousBlock); // TODO: Miner class that keeps dagger between mine calls (or just non-polling mining). - auto ret = m_dagger.mine(/*out*/m_currentBlock.nonce, m_currentBlock.headerHashWithoutNonce(), m_currentBlock.difficulty, _msTimeout, true, _turbo); + auto ret = m_pow.mine(/*out*/m_currentBlock.nonce, m_currentBlock.headerHashWithoutNonce(), m_currentBlock.difficulty, _msTimeout, true, _turbo); if (!ret.completed) m_currentBytes.clear(); diff --git a/libethereum/State.h b/libethereum/State.h index c73fc95dc..6914b9f5e 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include "TransactionQueue.h" @@ -322,7 +322,7 @@ private: Address m_ourAddress; ///< Our address (i.e. the address to which fees go). - Dagger m_dagger; + ProofOfWork m_pow; u256 m_blockReward; diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 2c0a6d87b..733c5259c 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -234,6 +234,8 @@ bool Session::interpret(RLP const& _r) } m_node = m_server->noteNode(id, bi::tcp::endpoint(m_socket.remote_endpoint().address(), listenPort), Origin::Self, false, !m_node || m_node->id == id ? NodeId() : m_node->id); + if (m_node->isOffline()) + m_node->lastConnected = chrono::system_clock::now(); m_knownNodes.extendAll(m_node->index); m_knownNodes.unionWith(m_node->index); diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index 89cd71792..e85d381f8 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include diff --git a/libqethereum/QmlEthereum.cpp b/libqethereum/QmlEthereum.cpp index 89578a29a..a7ed3df4d 100644 --- a/libqethereum/QmlEthereum.cpp +++ b/libqethereum/QmlEthereum.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/test/dagger.cpp b/test/dagger.cpp index 555c5d776..9422b6a96 100644 --- a/test/dagger.cpp +++ b/test/dagger.cpp @@ -17,12 +17,12 @@ /** @file dagger.cpp * @author Gav Wood * @date 2014 - * Dagger test functions. + * ProofOfWork test functions. */ #include #include -#include +#include using namespace std; using namespace std::chrono; using namespace dev; @@ -30,20 +30,20 @@ using namespace dev::eth; int daggerTest() { - cnote << "Testing Dagger..."; + cnote << "Testing ProofOfWork..."; // Test dagger { auto s = steady_clock::now(); - cout << hex << Dagger().eval((h256)(u256)1, (h256)(u256)0); + cout << hex << ProofOfWork().eval((h256)(u256)1, (h256)(u256)0); cout << " " << dec << duration_cast(steady_clock::now() - s).count() << " ms" << endl; - cout << hex << Dagger().eval((h256)(u256)1, (h256)(u256)1); + cout << hex << ProofOfWork().eval((h256)(u256)1, (h256)(u256)1); cout << " " << dec << duration_cast(steady_clock::now() - s).count() << " ms" << endl; } { auto s = steady_clock::now(); - cout << hex << Dagger().eval((h256)(u256)1, (h256)(u256)0); + cout << hex << ProofOfWork().eval((h256)(u256)1, (h256)(u256)0); cout << " " << dec << duration_cast(steady_clock::now() - s).count() << " ms" << endl; - cout << hex << Dagger().eval((h256)(u256)1, (h256)(u256)1); + cout << hex << ProofOfWork().eval((h256)(u256)1, (h256)(u256)1); cout << " " << dec << duration_cast(steady_clock::now() - s).count() << " ms" << endl; } return 0; diff --git a/third/MainWin.cpp b/third/MainWin.cpp index 399fc8396..d21077f86 100644 --- a/third/MainWin.cpp +++ b/third/MainWin.cpp @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include From 459b0c534c0f0b4a5722336fa47d7e0547941687 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 12 Oct 2014 21:28:35 +0200 Subject: [PATCH 25/29] More node list UX nicities. --- alethzero/MainWin.cpp | 4 ++-- libp2p/Session.cpp | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 235da2230..249f3b4cc 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -772,10 +772,10 @@ void Main::refreshNetwork() auto ns = web3()->nodes(); for (p2p::Node const& i: ns) if (!i.dead) - ui->nodes->insertItem(i.isOffline() ? ui->nodes->count() : 0, QString("[%1 %3] %2 - ( =%5s | /%4s%6 ) - *%7 $%8") + ui->nodes->insertItem(clients.count(i.id) ? 0 : ui->nodes->count(), QString("[%1 %3] %2 - ( =%5s | /%4s%6 ) - *%7 $%8") .arg(QString::fromStdString(i.id.abridged())) .arg(QString::fromStdString(toString(i.address))) - .arg(i.id == web3()->id() ? "self" : i.isOffline() ? i.secondsSinceLastAttempted() > -1 ? i.secondsSinceLastAttempted() < (int)i.fallbackSeconds() ? "retry-" + QString::number(i.fallbackSeconds() - i.secondsSinceLastAttempted()) + "s" : "retrying..." : "session-fail" : clients[i.id]) + .arg(i.id == web3()->id() ? "self" : clients.count(i.id) ? clients[i.id] : i.secondsSinceLastAttempted() == -1 ? "session-fail" : i.secondsSinceLastAttempted() >= (int)i.fallbackSeconds() ? "retrying..." : "retry-" + QString::number(i.fallbackSeconds() - i.secondsSinceLastAttempted()) + "s") .arg(i.secondsSinceLastAttempted()) .arg(i.secondsSinceLastConnected()) .arg(i.isOffline() ? " | " + QString::fromStdString(reasonOf(i.lastDisconnect)) + " | " + QString::number(i.failedAttempts) + "x" : "") diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 733c5259c..1ab4ca123 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -61,8 +61,12 @@ Session::Session(Host* _s, bi::tcp::socket _socket, std::shared_ptr const& Session::~Session() { if (m_node) + { if (id() && !isPermanentProblem(m_node->lastDisconnect) && !m_node->dead) m_server->m_ready += m_node->index; + else + m_node->lastConnected = m_node->lastAttempted - chrono::seconds(1); + } // Read-chain finished for one reason or another. for (auto& i: m_capabilities) From 88d4907c5c1e177182fe81f5a9d7720f6086dbfb Mon Sep 17 00:00:00 2001 From: sveneh Date: Sun, 12 Oct 2014 21:44:33 +0200 Subject: [PATCH 26/29] refactored external library detection TODO this is not proper CMake way, needs further refactoring --- CMakeLists.txt | 212 +------------------------- cmake/EthDependenciesDeprecated.cmake | 208 +++++++++++++++++++++++++ 2 files changed, 213 insertions(+), 207 deletions(-) create mode 100644 cmake/EthDependenciesDeprecated.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 04c795ad1..3620e1a3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,214 +97,11 @@ endif () include(EthCompilerSettings) message("-- CXXFLAGS: ${CMAKE_CXX_FLAGS}") - - - #add_definitions("-DETH_BUILD_TYPE=${ETH_BUILD_TYPE}") #add_definitions("-DETH_BUILD_PLATFORM=${ETH_BUILD_PLATFORM}") -if("${TARGET_PLATFORM}" STREQUAL "w64") -# set(MINIUPNPC_LS /usr/x86_64-w64-mingw32/lib/libminiupnpc.a) - set(LEVELDB_LS leveldb) - set(CRYPTOPP_LS cryptopp) - set(CRYPTOPP_ID /usr/x86_64-w64-mingw32/include/cryptopp) -else() - # Look for available Crypto++ version and if it is >= 5.6.2 - find_path(ID cryptlib.h - ../cryptopp/src - ../../cryptopp/src - /usr/include/cryptopp - /usr/include/crypto++ - /usr/local/include/cryptopp - /usr/local/include/crypto++ - /opt/local/include/cryptopp - /opt/local/include/crypto++ - ) - find_library(LS NAMES cryptoppeth cryptopp - ../cryptopp/src/../target/build/release - ../../cryptopp/src/../target/build/release - PATHS - /usr/lib - /usr/local/lib - /opt/local/lib - ) - - if (ID AND LS) - message(STATUS "Found Crypto++: ${ID}, ${LS}") - set(_CRYPTOPP_VERSION_HEADER ${ID}/config.h) - if(EXISTS ${_CRYPTOPP_VERSION_HEADER}) - file(STRINGS ${_CRYPTOPP_VERSION_HEADER} _CRYPTOPP_VERSION REGEX "^#define CRYPTOPP_VERSION[ \t]+[0-9]+$") - string(REGEX REPLACE "^#define CRYPTOPP_VERSION[ \t]+([0-9]+)" "\\1" _CRYPTOPP_VERSION ${_CRYPTOPP_VERSION}) - if(${_CRYPTOPP_VERSION} LESS 562) - message(FATAL_ERROR "Crypto++ version found is smaller than 5.6.2.") - else() - set(CRYPTOPP_ID ${ID} CACHE FILEPATH "") - set(CRYPTOPP_LS ${LS} CACHE FILEPATH "") - message(STATUS "Crypto++ found and version greater or equal to 5.6.2") - endif() - endif() - else() - message(STATUS "Crypto++ Not Found: ${CRYPTOPP_ID}, ${CRYPTOPP_LS}") - endif() - find_path( LEVELDB_ID leveldb/db.h - /usr/include - /usr/local/include - ) - if ( LEVELDB_ID STREQUAL "LEVELDB_ID-NOTFOUND" ) - message(FATAL_ERROR "Failed to find the LevelDB headers") - else () - message(STATUS "Found LevelDB Headers") - - # Check for accessory dev libraries leveldb and miniupnpc - find_library( LEVELDB_LS NAMES leveldb - PATHS - /usr/lib - /usr/local/lib - /opt/local/lib - /usr/lib/*/ - ) - if ( LEVELDB_LS STREQUAL "LEVELDB_LS-NOTFOUND" ) - message(FATAL_ERROR "Failed to find the LevelDB Library!") - else () - message(STATUS "Found LevelDB Library: ${LEVELDB_LS}") - add_definitions(-DETH_LEVELDB) - endif () - endif () - - find_path( PYTHON_ID pyconfig.h - ${PYTHON_INCLUDE_DIR} - /usr/include/python2.7 - /usr/local/include/python2.7 - ) - if ( PYTHON_ID STREQUAL "PYTHON_ID-NOTFOUND" ) - message(STATUS "Failed to find the Python-2.7 headers") - else () - message(STATUS "Found Python-2.7 Headers: ${PYTHON_ID}") - - # Check for accessory dev libraries leveldb and miniupnpc - find_library( PYTHON_LS NAMES python2.7 - PATHS - /usr/lib - /usr/local/lib - /opt/local/lib - /usr/lib/*/ - ) - if ( PYTHON_LS STREQUAL "PYTHON_LS-NOTFOUND" ) - message(STATUS "Failed to find the Python-2.7 Library!") - set(PYTHON_ID) - set(PYTHON_LS) - else () - message(STATUS "Found Python-2.7 Library: ${PYTHON_LS}") - add_definitions(-DETH_PYTHON) - endif () - endif () - - find_path( MINIUPNPC_ID miniupnpc/miniwget.h - /usr/include - /usr/local/include - ) - if ( MINIUPNPC_ID ) - message(STATUS "Found miniupnpc headers") - - find_library( MINIUPNPC_LS NAMES miniupnpc - PATHS - /usr/lib - /usr/local/lib - /opt/local/lib - /usr/lib/*/ - ) - if ( MINIUPNPC_LS ) - message(STATUS "Found miniupnpc library: ${MINIUPNPC_LS}") - add_definitions(-DETH_MINIUPNPC) - else () - message(STATUS "Failed to find the miniupnpc library!") - endif () - else () - message(STATUS "Failed to find the miniupnpc headers!") - endif () - - find_path( JSONRPC_ID jsonrpc/rpc.h - /usr/include - /usr/local/include - ) - if ( JSONRPC_ID ) - message(STATUS "Found jsonrpc headers") - find_library( JSONRPC_LS NAMES jsonrpc - PATHS - /usr/lib - /usr/local/lib - /opt/local/lib - /usr/lib/*/ - ) - if ( JSONRPC_LS ) - message(STATUS "Found jsonrpc library: ${JSONRPC_LS}") - add_definitions(-DETH_JSONRPC) - else () - message(STATUS "Failed to find the jsonrpc library!") - endif () - else () - message(STATUS "Failed to find the jsonrpc headers!") - endif () - - find_path( READLINE_ID readline/readline.h - /usr/include - /usr/local/include - ) - if ( READLINE_ID ) - message(STATUS "Found readline headers") - find_library( READLINE_LS NAMES readline - PATHS - /usr/lib - /usr/local/lib - /opt/local/lib - /usr/lib/*/ - ) - if ( READLINE_LS ) - message(STATUS "Found readline library: ${READLINE_LS}") - add_definitions(-DETH_READLINE) - else () - message(STATUS "Failed to find the readline library!") - endif () - else () - message(STATUS "Failed to find the readline headers!") - endif () - - if (LANGUAGES) - find_package(Boost 1.53 REQUIRED COMPONENTS thread date_time) - else() - find_package(Boost 1.53 REQUIRED COMPONENTS thread date_time system regex) - endif() - - set(QTQML 1) -endif() - -if(CRYPTOPP_ID) - include_directories(${CRYPTOPP_ID}) -endif() -if(PYTHON_ID) - include_directories(${PYTHON_ID}) -endif() -if(MINIUPNPC_ID) - include_directories(${MINIUPNPC_ID}) -endif() -if(LEVELDB_ID) - include_directories(${LEVELDB_ID}) -endif() -if(READLINE_ID) - include_directories(${READLINE_ID}) -endif() -if(JSONRPC_ID) - include_directories(${JSONRPC_ID}) -endif() - - - - -if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - link_directories(/usr/local/lib) - include_directories(/usr/local/include) -endif() +include(EthDependenciesDeprecated) createBuildInfo() @@ -313,10 +110,11 @@ add_subdirectory(libevmface) add_subdirectory(liblll) add_subdirectory(libserpent) if(NOT APPLE) -if(PYTHON_LS) -add_subdirectory(libpyserpent) -endif() + if(PYTHON_LS) + add_subdirectory(libpyserpent) + endif() endif() + add_subdirectory(lllc) add_subdirectory(sc) if (NOT LANGUAGES) diff --git a/cmake/EthDependenciesDeprecated.cmake b/cmake/EthDependenciesDeprecated.cmake new file mode 100644 index 000000000..d1c51f6c4 --- /dev/null +++ b/cmake/EthDependenciesDeprecated.cmake @@ -0,0 +1,208 @@ +# search for and configure dependencies + +# deprecated. TODO will rewrite to proper CMake packages + + + +if("${TARGET_PLATFORM}" STREQUAL "w64") +# set(MINIUPNPC_LS /usr/x86_64-w64-mingw32/lib/libminiupnpc.a) + set(LEVELDB_LS leveldb) + set(CRYPTOPP_LS cryptopp) + set(CRYPTOPP_ID /usr/x86_64-w64-mingw32/include/cryptopp) +else() + # Look for available Crypto++ version and if it is >= 5.6.2 + find_path(ID cryptlib.h + ../cryptopp/src + ../../cryptopp/src + /usr/include/cryptopp + /usr/include/crypto++ + /usr/local/include/cryptopp + /usr/local/include/crypto++ + /opt/local/include/cryptopp + /opt/local/include/crypto++ + ) + find_library(LS NAMES cryptoppeth cryptopp + ../cryptopp/src/../target/build/release + ../../cryptopp/src/../target/build/release + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + ) + + if (ID AND LS) + message(STATUS "Found Crypto++: ${ID}, ${LS}") + set(_CRYPTOPP_VERSION_HEADER ${ID}/config.h) + if(EXISTS ${_CRYPTOPP_VERSION_HEADER}) + file(STRINGS ${_CRYPTOPP_VERSION_HEADER} _CRYPTOPP_VERSION REGEX "^#define CRYPTOPP_VERSION[ \t]+[0-9]+$") + string(REGEX REPLACE "^#define CRYPTOPP_VERSION[ \t]+([0-9]+)" "\\1" _CRYPTOPP_VERSION ${_CRYPTOPP_VERSION}) + if(${_CRYPTOPP_VERSION} LESS 562) + message(FATAL_ERROR "Crypto++ version found is smaller than 5.6.2.") + else() + set(CRYPTOPP_ID ${ID} CACHE FILEPATH "") + set(CRYPTOPP_LS ${LS} CACHE FILEPATH "") + message(STATUS "Crypto++ found and version greater or equal to 5.6.2") + endif() + endif() + else() + message(STATUS "Crypto++ Not Found: ${CRYPTOPP_ID}, ${CRYPTOPP_LS}") + endif() + + find_path( LEVELDB_ID leveldb/db.h + /usr/include + /usr/local/include + ) + if ( LEVELDB_ID STREQUAL "LEVELDB_ID-NOTFOUND" ) + message(FATAL_ERROR "Failed to find the LevelDB headers") + else () + message(STATUS "Found LevelDB Headers") + + # Check for accessory dev libraries leveldb and miniupnpc + find_library( LEVELDB_LS NAMES leveldb + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + /usr/lib/*/ + ) + if ( LEVELDB_LS STREQUAL "LEVELDB_LS-NOTFOUND" ) + message(FATAL_ERROR "Failed to find the LevelDB Library!") + else () + message(STATUS "Found LevelDB Library: ${LEVELDB_LS}") + add_definitions(-DETH_LEVELDB) + endif () + endif () + + find_path( PYTHON_ID pyconfig.h + ${PYTHON_INCLUDE_DIR} + /usr/include/python2.7 + /usr/local/include/python2.7 + ) + if ( PYTHON_ID STREQUAL "PYTHON_ID-NOTFOUND" ) + message(STATUS "Failed to find the Python-2.7 headers") + else () + message(STATUS "Found Python-2.7 Headers: ${PYTHON_ID}") + + # Check for accessory dev libraries leveldb and miniupnpc + find_library( PYTHON_LS NAMES python2.7 + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + /usr/lib/*/ + ) + if ( PYTHON_LS STREQUAL "PYTHON_LS-NOTFOUND" ) + message(STATUS "Failed to find the Python-2.7 Library!") + set(PYTHON_ID) + set(PYTHON_LS) + else () + message(STATUS "Found Python-2.7 Library: ${PYTHON_LS}") + add_definitions(-DETH_PYTHON) + endif () + endif () + + find_path( MINIUPNPC_ID miniupnpc/miniwget.h + /usr/include + /usr/local/include + ) + if ( MINIUPNPC_ID ) + message(STATUS "Found miniupnpc headers") + + find_library( MINIUPNPC_LS NAMES miniupnpc + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + /usr/lib/*/ + ) + if ( MINIUPNPC_LS ) + message(STATUS "Found miniupnpc library: ${MINIUPNPC_LS}") + add_definitions(-DETH_MINIUPNPC) + else () + message(STATUS "Failed to find the miniupnpc library!") + endif () + else () + message(STATUS "Failed to find the miniupnpc headers!") + endif () + + find_path( JSONRPC_ID jsonrpc/rpc.h + /usr/include + /usr/local/include + ) + if ( JSONRPC_ID ) + message(STATUS "Found jsonrpc headers") + find_library( JSONRPC_LS NAMES jsonrpc + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + /usr/lib/*/ + ) + if ( JSONRPC_LS ) + message(STATUS "Found jsonrpc library: ${JSONRPC_LS}") + add_definitions(-DETH_JSONRPC) + else () + message(STATUS "Failed to find the jsonrpc library!") + endif () + else () + message(STATUS "Failed to find the jsonrpc headers!") + endif () + + find_path( READLINE_ID readline/readline.h + /usr/include + /usr/local/include + ) + if ( READLINE_ID ) + message(STATUS "Found readline headers") + find_library( READLINE_LS NAMES readline + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + /usr/lib/*/ + ) + if ( READLINE_LS ) + message(STATUS "Found readline library: ${READLINE_LS}") + add_definitions(-DETH_READLINE) + else () + message(STATUS "Failed to find the readline library!") + endif () + else () + message(STATUS "Failed to find the readline headers!") + endif () + + if (LANGUAGES) + find_package(Boost 1.53 REQUIRED COMPONENTS thread date_time) + else() + find_package(Boost 1.53 REQUIRED COMPONENTS thread date_time system regex) + endif() + + set(QTQML 1) +endif() + +if(CRYPTOPP_ID) + include_directories(${CRYPTOPP_ID}) +endif() +if(PYTHON_ID) + include_directories(${PYTHON_ID}) +endif() +if(MINIUPNPC_ID) + include_directories(${MINIUPNPC_ID}) +endif() +if(LEVELDB_ID) + include_directories(${LEVELDB_ID}) +endif() +if(READLINE_ID) + include_directories(${READLINE_ID}) +endif() +if(JSONRPC_ID) + include_directories(${JSONRPC_ID}) +endif() + + + + +if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + link_directories(/usr/local/lib) + include_directories(/usr/local/include) +endif() From 35e6e895bf4c7d2328531dfa374294ce9aba67f8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 13 Oct 2014 11:11:18 +0300 Subject: [PATCH 27/29] Minor crash fix. --- alethzero/MainWin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 249f3b4cc..8d69727f8 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1740,9 +1740,9 @@ void Main::on_debugStepBack_triggered() void Main::on_debugStepBackOut_triggered() { - if (ui->debugTimeline->value() > 0) + if (ui->debugTimeline->value() > 0 && m_history.size() > 0) { - auto ls = m_history[ui->debugTimeline->value()].levels.size(); + auto ls = m_history[min(ui->debugTimeline->value(), m_history.size() - 1)].levels.size(); int l = ui->debugTimeline->value(); for (; l > 0 && m_history[l].levels.size() >= ls; --l) {} ui->debugTimeline->setValue(l); From 0c2aaac471e8852bc46b4378ee9337377b8a408e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 13 Oct 2014 11:46:25 +0300 Subject: [PATCH 28/29] Thread-safety fix for BlockChain. --- libethereum/BlockChain.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index d8c588118..c0b127913 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -428,6 +428,7 @@ h256s BlockChain::treeRoute(h256 _from, h256 _to, h256* o_common, bool _pre, boo void BlockChain::checkConsistency() { + WriteGuard l(x_details); m_details.clear(); ldb::Iterator* it = m_db->NewIterator(m_readOptions); for (it->SeekToFirst(); it->Valid(); it->Next()) From 344e0ecaa90d2fe02d8cea144ac27ac5b07bf191 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 13 Oct 2014 12:14:55 +0300 Subject: [PATCH 29/29] Windows build fix. Threading fix. --- libethcore/All.h | 2 +- libethereum/BlockChain.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libethcore/All.h b/libethcore/All.h index 4a6747ff0..7a1ca8f51 100644 --- a/libethcore/All.h +++ b/libethcore/All.h @@ -2,7 +2,7 @@ #include "BlockInfo.h" #include "CommonEth.h" -#include "Dagger.h" +#include "ProofOfWork.h" #include "CryptoHeaders.h" #include "Exceptions.h" diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index c0b127913..6f0af911c 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -428,8 +428,10 @@ h256s BlockChain::treeRoute(h256 _from, h256 _to, h256* o_common, bool _pre, boo void BlockChain::checkConsistency() { - WriteGuard l(x_details); - m_details.clear(); + { + WriteGuard l(x_details); + m_details.clear(); + } ldb::Iterator* it = m_db->NewIterator(m_readOptions); for (it->SeekToFirst(); it->Valid(); it->Next()) if (it->key().size() == 32)