diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index 33f95695b..4609fddb6 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -81,6 +81,7 @@ void EthereumHost::reset() m_hashMan.reset(m_chain.number() + 1); m_needSyncBlocks = true; m_needSyncHashes = true; + m_syncingNewHashes = false; m_syncingLatestHash = h256(); m_syncingTotalDifficulty = 0; m_latestBlockSent = h256(); @@ -88,6 +89,14 @@ void EthereumHost::reset() m_hashes.clear(); } +void EthereumHost::resetSyncTo(h256 const& _h) +{ + m_needSyncHashes = true; + m_needSyncBlocks = true; + m_syncingLatestHash = _h; + m_syncingNewHashes = false; +} + void EthereumHost::doWork() { bool netChange = ensureInitialised(); @@ -366,8 +375,13 @@ void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool } if (_complete) { + clog(NetMessageSummary) << "Start new blocks download..."; m_needSyncBlocks = true; - continueSync(); + m_syncingNewHashes = true; + m_man.resetToChain(m_hashes); + m_hashes.clear(); + m_hashMan.reset(m_chain.number() + 1); + continueSync(_peer); } else if (syncByNumber && m_hashMan.isComplete()) { @@ -425,6 +439,7 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) unsigned unknown = 0; unsigned got = 0; unsigned repeated = 0; + h256 lastUnknown; for (unsigned i = 0; i < itemCount; ++i) { @@ -453,6 +468,7 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) break; case ImportResult::UnknownParent: + lastUnknown = h; unknown++; break; @@ -467,6 +483,13 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) } clog(NetMessageSummary) << dec << success << "imported OK," << unknown << "with unknown parents," << future << "with future timestamps," << got << " already known," << repeated << " repeats received."; + + if (m_syncingNewHashes && unknown > 0) + { + _peer->m_latestHash = lastUnknown; + resetSyncTo(lastUnknown); + } + continueSync(_peer); } @@ -486,7 +509,7 @@ void EthereumHost::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) { RecursiveGuard l(x_sync); - if (isSyncing_UNSAFE() || _peer->isConversing()) + if ((isSyncing_UNSAFE() || _peer->isConversing()) && !m_syncingNewHashes) { clog(NetMessageSummary) << "Ignoring new blocks since we're already downloading."; return; @@ -526,9 +549,7 @@ void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) clog(NetMessageSummary) << "Received block with no known parent. Resyncing..."; _peer->m_latestHash = h; _peer->m_totalDifficulty = difficulty; - m_needSyncHashes = true; - m_needSyncBlocks = true; - m_syncingLatestHash = h; + resetSyncTo(h);; sync = true; } } @@ -646,7 +667,7 @@ void EthereumHost::continueSync(EthereumPeer* _peer) { _peer->requestHashes(m_syncingLatestHash); m_syncingV61 = false; - m_estimatedHashes = _peer->m_expectedHashes; + m_estimatedHashes = _peer->m_expectedHashes - (_peer->m_protocolVersion == protocolVersion() ? 0 : c_chainReorgSize); } else _peer->setIdle(); @@ -658,6 +679,7 @@ void EthereumHost::continueSync(EthereumPeer* _peer) { // Done our chain-get. m_needSyncBlocks = false; + m_syncingNewHashes = false; clog(NetNote) << "Chain download complete."; // 1/100th for each useful block hash. _peer->addRating(m_man.chainSize() / 100); //TODO: what about other peers? @@ -742,6 +764,6 @@ HashChainStatus EthereumHost::status() RecursiveGuard l(x_sync); if (m_syncingV61) return HashChainStatus { static_cast(m_hashMan.chainSize()), static_cast(m_hashMan.gotCount()), false }; - return HashChainStatus { m_estimatedHashes > 0 ? m_estimatedHashes - c_chainReorgSize : 0, static_cast(m_hashes.size()), m_estimatedHashes > 0 }; + return HashChainStatus { m_estimatedHashes > 0 ? m_estimatedHashes : 0, static_cast(m_hashes.size()), m_estimatedHashes > 0 }; } diff --git a/libethereum/EthereumHost.h b/libethereum/EthereumHost.h index 17684fea1..392e234f3 100644 --- a/libethereum/EthereumHost.h +++ b/libethereum/EthereumHost.h @@ -97,6 +97,7 @@ private: void foreachPeerPtr(std::function)> const& _f) const; void foreachPeer(std::function const& _f) const; bool isSyncing_UNSAFE() const; + void resetSyncTo(h256 const& _h); /// Sync with the BlockChain. It might contain one of our mined blocks, we might have new candidates from the network. void doWork(); @@ -151,6 +152,7 @@ private: bool m_needSyncBlocks = true; ///< Indicates if we still need to download some blocks h256 m_syncingLatestHash; ///< Latest block's hash, as of the current sync. u256 m_syncingTotalDifficulty; ///< Latest block's total difficulty, as of the current sync. + bool m_syncingNewHashes = false; ///< True if currently downloading hashes received with NewHashes h256s m_hashes; ///< List of hashes with unknown block numbers. Used for PV60 chain downloading and catching up to a particular unknown unsigned m_estimatedHashes = 0; ///< Number of estimated hashes for the last peer over PV60. Used for status reporting only. bool m_syncingV61 = false; ///< True if recent activity was over pv61+. Used for status reporting only. diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index f4cceebf2..628b59767 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -61,17 +61,22 @@ ReputationManager::ReputationManager() void ReputationManager::noteRude(Session const& _s, std::string const& _sub) { - m_nodes[make_pair(_s.id(), _s.info().clientVersion)].subs[_sub].isRude = true; + DEV_WRITE_GUARDED(x_nodes) + m_nodes[make_pair(_s.id(), _s.info().clientVersion)].subs[_sub].isRude = true; } bool ReputationManager::isRude(Session const& _s, std::string const& _sub) const { - auto nit = m_nodes.find(make_pair(_s.id(), _s.info().clientVersion)); - if (nit == m_nodes.end()) - return false; - auto sit = nit->second.subs.find(_sub); - bool ret = sit == nit->second.subs.end() ? false : sit->second.isRude; - return _sub.empty() ? ret : (ret || isRude(_s)); + DEV_READ_GUARDED(x_nodes) + { + auto nit = m_nodes.find(make_pair(_s.id(), _s.info().clientVersion)); + if (nit == m_nodes.end()) + return false; + auto sit = nit->second.subs.find(_sub); + bool ret = sit == nit->second.subs.end() ? false : sit->second.isRude; + return _sub.empty() ? ret : (ret || isRude(_s)); + } + return false; } Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bytesConstRef _restoreNetwork): diff --git a/libp2p/Host.h b/libp2p/Host.h index 132dd379a..b32c495cb 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -99,6 +99,7 @@ public: private: std::unordered_map, Reputation> m_nodes; ///< Nodes that were impolite while syncing. We avoid syncing from these if possible. + SharedMutex mutable x_nodes; }; /**