From 82ca50d234b981d219c3ef075b80ceaef70227d0 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 6 May 2015 22:21:34 +0200 Subject: [PATCH] NewBlockHashes packet, basic implementation. --- alethzero/Main.ui | 74 +++++++++++++++++++----------------- alethzero/MainWin.cpp | 1 + eth/main.cpp | 4 +- libethereum/EthereumHost.cpp | 51 +++++++++++++++---------- libethereum/EthereumHost.h | 4 +- libethereum/EthereumPeer.cpp | 34 ++++++++--------- libethereum/EthereumPeer.h | 2 +- libp2p/Host.cpp | 3 +- libp2p/Host.h | 2 + libwebthree/WebThree.cpp | 5 +++ libwebthree/WebThree.h | 5 +++ mix/Web3Server.cpp | 6 +++ 12 files changed, 114 insertions(+), 77 deletions(-) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index f28f5b5fc..736af8684 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -256,6 +256,19 @@ + + + + + + + + + + Automatic + + + @@ -266,16 +279,6 @@ - - - - 1 - - - 5 - - - @@ -289,20 +292,21 @@ - - - - - + + - + Public IP + + + + Automatic - + Ideal &Peers @@ -312,21 +316,7 @@ - - - - Automatic - - - - - - - Public IP - - - - + &Client Name @@ -336,13 +326,30 @@ - + + + + 1 + + + 5 + + + + Anonymous + + + + true + + + @@ -1751,7 +1758,6 @@ font-size: 14pt verbosity tabWidget urlEdit - idealPeers listenIP port transactionQueue diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 42951279b..62515f171 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1774,6 +1774,7 @@ void Main::on_net_triggered() ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : h256()); web3()->startNetwork(); ui->downloadView->setDownloadMan(ethereum()->downloadMan()); + ui->enode->setText(QString::fromStdString(web3()->enode())); } else { diff --git a/eth/main.cpp b/eth/main.cpp index 985e74e59..801ee1a0f 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -407,6 +407,7 @@ void doFarm(MinerType _m, string const& _remote, unsigned _recheckPeriod) int main(int argc, char** argv) { +#if 0 cout << "\x1b[30mEthBlack\x1b[0m" << endl; cout << "\x1b[90mEthCoal\x1b[0m" << endl; cout << "\x1b[37mEthGray\x1b[0m" << endl; @@ -472,7 +473,7 @@ int main(int argc, char** argv) cout << "\x1b[4;35mEthPurpleU\x1b[0m" << endl; cout << "\x1b[4;36mEthCyanU\x1b[0m" << endl; cout << "\x1b[4;37mEthWhiteU\x1b[0m" << endl; - +#endif // Init defaults Defaults::get(); @@ -1051,6 +1052,7 @@ int main(int argc, char** argv) cout << "Transaction Signer: " << sigKey.address() << endl; cout << "Mining Benefactor: " << coinbase << endl; web3.startNetwork(); + cout << "Node ID: " << web3.enode() << endl; if (bootstrap) web3.addNode(p2p::NodeId(), Host::pocHost()); diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index 340ae417f..5744f75fa 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -189,7 +189,7 @@ void EthereumHost::maintainTransactions() for (auto const& i: ts) { bool unsent = !m_transactionsSent.count(i.first); - for (auto const& p: randomSelection(100, [&](EthereumPeer* p) { return p->m_requireTransactions || (unsent && !p->m_knownTransactions.count(i.first)); })) + for (auto const& p: randomSelection(0, [&](EthereumPeer* p) { return p->m_requireTransactions || (unsent && !p->m_knownTransactions.count(i.first)); }).second) peerTransactions[p].push_back(i.first); } for (auto const& t: ts) @@ -218,28 +218,28 @@ void EthereumHost::maintainTransactions() } } -std::vector> EthereumHost::randomSelection(unsigned _percent, std::function const& _allow) +pair>, vector>> EthereumHost::randomSelection(unsigned _percent, std::function const& _allow) { - std::vector> candidates; - candidates.reserve(peerSessions().size()); + pair>, vector>> ret; + ret.second.reserve(peerSessions().size()); for (auto const& j: peerSessions()) { auto pp = j.first->cap(); if (_allow(pp.get())) - candidates.push_back(pp); + ret.second.push_back(pp); } - std::vector> ret; - for (unsigned i = (peerSessions().size() * _percent + 99) / 100; i-- && candidates.size();) + ret.second.reserve((peerSessions().size() * _percent + 99) / 100); + for (unsigned i = (peerSessions().size() * _percent + 99) / 100; i-- && ret.second.size();) { - unsigned n = rand() % candidates.size(); - ret.push_back(std::move(candidates[n])); - candidates.erase(candidates.begin() + n); + unsigned n = rand() % ret.second.size(); + ret.first.push_back(std::move(ret.second[n])); + ret.second.erase(ret.second.begin() + n); } return ret; } -void EthereumHost::maintainBlocks(h256 _currentHash) +void EthereumHost::maintainBlocks(h256 const& _currentHash) { // Send any new blocks. auto detailsFrom = m_chain.details(m_latestBlockSent); @@ -253,17 +253,28 @@ void EthereumHost::maintainBlocks(h256 _currentHash) h256s blocks = get<0>(m_chain.treeRoute(m_latestBlockSent, _currentHash, false, false, true)); - for (auto const& p: randomSelection(100, [&](EthereumPeer* p){return !p->m_knownBlocks.count(_currentHash); })) + auto s = randomSelection(0, [&](EthereumPeer* p){ ETH_GUARDED(p->x_knownBlocks) return !p->m_knownBlocks.count(_currentHash); return false; }); + for (shared_ptr const& p: s.first) for (auto const& b: blocks) - if (!p->m_knownBlocks.count(b)) - { - RLPStream ts; - p->prep(ts, NewBlockPacket, 2).appendRaw(m_chain.block(b), 1).append(m_chain.details(b).totalDifficulty); + { + RLPStream ts; + p->prep(ts, NewBlockPacket, 2).appendRaw(m_chain.block(b), 1).append(m_chain.details(b).totalDifficulty); - Guard l(p->x_knownBlocks); - p->sealAndSend(ts); - p->m_knownBlocks.clear(); - } + Guard l(p->x_knownBlocks); + p->sealAndSend(ts); + p->m_knownBlocks.clear(); + } + for (shared_ptr const& p: s.second) + { + RLPStream ts; + p->prep(ts, NewBlockHashesPacket, blocks.size()); + for (auto const& b: blocks) + ts.append(b); + + Guard l(p->x_knownBlocks); + p->sealAndSend(ts); + p->m_knownBlocks.clear(); + } } m_latestBlockSent = _currentHash; } diff --git a/libethereum/EthereumHost.h b/libethereum/EthereumHost.h index c2fffcd82..baa850b5c 100644 --- a/libethereum/EthereumHost.h +++ b/libethereum/EthereumHost.h @@ -80,7 +80,7 @@ public: void noteNewBlocks() { m_newBlocks = true; } private: - std::vector> randomSelection(unsigned _percent = 25, std::function const& _allow = [](EthereumPeer const*){ return true; }); + std::pair>, std::vector>> randomSelection(unsigned _percent = 25, std::function const& _allow = [](EthereumPeer const*){ return true; }); /// Session is tell us that we may need (re-)syncing with the peer. void noteNeedsSyncing(EthereumPeer* _who); @@ -92,7 +92,7 @@ private: void doWork(); void maintainTransactions(); - void maintainBlocks(h256 _currentBlock); + void maintainBlocks(h256 const& _currentBlock); /// Get a bunch of needed blocks. /// Removes them from our list of needed blocks. diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index a3327bbf8..c550bd4f7 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -559,37 +559,33 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) default:; } - Guard l(x_knownBlocks); - m_knownBlocks.insert(h); + ETH_GUARDED(x_knownBlocks) + m_knownBlocks.insert(h); } break; } -/* case NewBlockHashesPacket: + case NewBlockHashesPacket: { - clog(NetMessageSummary) << "NewBlock: " << h; - if (_r.itemCount() == 1) - disable("NewBlock without any data fields."); - else if (host()->isSyncing()) + clog(NetMessageSummary) << "NewBlockHashes"; + if (host()->isSyncing()) clog(NetMessageSummary) << "Ignoring since we're already downloading."; else { unsigned knowns = 0; unsigned unknowns = 0; + unsigned itemCount = _r.itemCount(); for (unsigned i = 0; i < itemCount; ++i) { addRating(1); auto h = _r[i].toHash(); + ETH_GUARDED(x_knownBlocks) + m_knownBlocks.insert(h); auto status = host()->m_bq.blockStatus(h); if (status == QueueStatus::Importing || status == QueueStatus::Ready || host()->m_chain.isKnown(h)) - { - clog(NetMessageSummary) << "block hash ready:" << h << ". Start blocks download..."; - transition(Asking::Blocks); - return true; - } + knowns++; else if (status == QueueStatus::Bad) { cwarn << "block hash bad!" << h << ". Bailing..."; - transition(Asking::Nothing); return true; } else if (status == QueueStatus::Unknown) @@ -599,14 +595,18 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) } else knowns++; - m_syncingLastReceivedHash = h; } - clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns; now at" << m_syncingLastReceivedHash; - transition(Asking::Blocks); + clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns"; + if (unknowns > 0) + { + host()->m_man.resetToChain(m_syncingNeededBlocks); + host()->changeSyncer(this); + transition(Asking::Blocks); + } return true; } break; - }*/ + } default: return false; } diff --git a/libethereum/EthereumPeer.h b/libethereum/EthereumPeer.h index a80d5dadd..75ebab02f 100644 --- a/libethereum/EthereumPeer.h +++ b/libethereum/EthereumPeer.h @@ -129,7 +129,7 @@ private: /// This is built as we ask for hashes. Once no more hashes are given, we present this to the /// host who initialises the DownloadMan and m_sub becomes active for us to begin asking for blocks. h256s m_syncingNeededBlocks; ///< The blocks that we should download from this peer. - h256 m_syncingLastReceivedHash; ///< Hash more recently received from peer. + h256 m_syncingLastReceivedHash; ///< Hash most recently received from peer. h256 m_syncingLatestHash; ///< Peer's latest block's hash, as of the current sync. u256 m_syncingTotalDifficulty; ///< Peer's latest block's total difficulty, as of the current sync. diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 78c1102c1..d47f1764e 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -413,7 +413,6 @@ void Host::requirePeer(NodeId const& _n, NodeIPEndpoint const& _endpoint) // create or update m_peers entry shared_ptr p; ETH_RECURSIVE_GUARDED(x_sessions) - { if (m_peers.count(_n)) { p = m_peers[_n]; @@ -425,7 +424,6 @@ void Host::requirePeer(NodeId const& _n, NodeIPEndpoint const& _endpoint) p.reset(new Peer(node)); m_peers[_n] = p; } - } connect(p); } else if (m_nodeTable) @@ -438,6 +436,7 @@ void Host::requirePeer(NodeId const& _n, NodeIPEndpoint const& _endpoint) t->async_wait([this, _n](boost::system::error_code const& _ec) { if (!_ec && m_nodeTable) + // FIXME RACE CONDITION (use weak_ptr or mutex). if (auto n = m_nodeTable->node(_n)) requirePeer(n.id, n.endpoint); }); diff --git a/libp2p/Host.h b/libp2p/Host.h index 375481c38..ea47b58b4 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -135,6 +135,8 @@ public: // TODO: P2P this should be combined with peers into a HostStat object of some kind; coalesce data, as it's only used for status information. Peers getPeers() const { RecursiveGuard l(x_sessions); Peers ret; for (auto const& i: m_peers) ret.push_back(*i.second); return ret; } + NetworkPreferences const& networkPreferences() const { return m_netPrefs; } + void setNetworkPreferences(NetworkPreferences const& _p, bool _dropPeers = false) { m_dropPeers = _dropPeers; auto had = isStarted(); if (had) stop(); m_netPrefs = _p; if (had) start(); } /// Start network. @threadsafe diff --git a/libwebthree/WebThree.cpp b/libwebthree/WebThree.cpp index a520190ee..606126e43 100644 --- a/libwebthree/WebThree.cpp +++ b/libwebthree/WebThree.cpp @@ -72,6 +72,11 @@ WebThreeDirect::~WebThreeDirect() m_ethereum.reset(); } +p2p::NetworkPreferences const& WebThreeDirect::networkPreferences() const +{ + return m_net.networkPreferences(); +} + void WebThreeDirect::setNetworkPreferences(p2p::NetworkPreferences const& _n, bool _dropPeers) { auto had = isNetworkStarted(); diff --git a/libwebthree/WebThree.h b/libwebthree/WebThree.h index 90a4aa3c2..ece83abb8 100644 --- a/libwebthree/WebThree.h +++ b/libwebthree/WebThree.h @@ -73,6 +73,7 @@ public: virtual bool haveNetwork() const = 0; + virtual p2p::NetworkPreferences const& networkPreferences() const = 0; virtual void setNetworkPreferences(p2p::NetworkPreferences const& _n, bool _dropPeers) = 0; virtual p2p::NodeId id() const = 0; @@ -88,6 +89,8 @@ public: /// Is network working? there may not be any peers yet. virtual bool isNetworkStarted() const = 0; + + std::string enode() const { return "enode://" + toHex(id().ref()) + "@" + (networkPreferences().publicIPAddress.empty() ? "127.0.0.1" : networkPreferences().publicIPAddress) + ":" + toString(networkPreferences().listenPort); } }; @@ -164,6 +167,8 @@ public: bool haveNetwork() const override { return m_net.haveNetwork(); } + p2p::NetworkPreferences const& networkPreferences() const override; + void setNetworkPreferences(p2p::NetworkPreferences const& _n, bool _dropPeers = false) override; p2p::NodeId id() const override { return m_net.id(); } diff --git a/mix/Web3Server.cpp b/mix/Web3Server.cpp index 4acb262df..7edc73060 100644 --- a/mix/Web3Server.cpp +++ b/mix/Web3Server.cpp @@ -70,6 +70,12 @@ class EmptyNetwork : public dev::WebThreeNetworkFace return false; } + p2p::NetworkPreferences const& networkPreferences() const override + { + static const p2p::NetworkPreferences c_ret; + return c_ret; + } + void setNetworkPreferences(p2p::NetworkPreferences const& _n, bool _dropPeers) override { (void)_n;