|
@ -237,7 +237,7 @@ void EthereumHost::maintainBlocks(h256 const& _currentHash) |
|
|
|
|
|
|
|
|
void EthereumHost::onPeerStatus(EthereumPeer* _peer) |
|
|
void EthereumHost::onPeerStatus(EthereumPeer* _peer) |
|
|
{ |
|
|
{ |
|
|
Guard l(x_sync); |
|
|
RecursiveGuard l(x_sync); |
|
|
if (_peer->m_genesisHash != m_chain.genesisHash()) |
|
|
if (_peer->m_genesisHash != m_chain.genesisHash()) |
|
|
_peer->disable("Invalid genesis hash"); |
|
|
_peer->disable("Invalid genesis hash"); |
|
|
else if (_peer->m_protocolVersion != protocolVersion() && _peer->m_protocolVersion != c_oldProtocolVersion) |
|
|
else if (_peer->m_protocolVersion != protocolVersion() && _peer->m_protocolVersion != c_oldProtocolVersion) |
|
@ -252,12 +252,13 @@ void EthereumHost::onPeerStatus(EthereumPeer* _peer) |
|
|
{ |
|
|
{ |
|
|
if (_peer->m_protocolVersion != protocolVersion()) |
|
|
if (_peer->m_protocolVersion != protocolVersion()) |
|
|
estimatePeerHashes(_peer); |
|
|
estimatePeerHashes(_peer); |
|
|
else if (_peer->m_latestBlockNumber > m_chain.number()) |
|
|
|
|
|
_peer->m_expectedHashes = (unsigned)_peer->m_latestBlockNumber - m_chain.number() + 1000; |
|
|
|
|
|
else |
|
|
else |
|
|
_peer->m_expectedHashes = 1000; |
|
|
{ |
|
|
if (m_hashMan.chainSize() < _peer->m_expectedHashes) |
|
|
if (_peer->m_latestBlockNumber > m_chain.number()) |
|
|
m_hashMan.resetToRange(m_chain.number() + 1, _peer->m_expectedHashes); |
|
|
_peer->m_expectedHashes = (unsigned)_peer->m_latestBlockNumber - m_chain.number(); |
|
|
|
|
|
if (m_hashMan.chainSize() < _peer->m_expectedHashes) |
|
|
|
|
|
m_hashMan.resetToRange(m_chain.number() + 1, _peer->m_expectedHashes); |
|
|
|
|
|
} |
|
|
continueSync(_peer); |
|
|
continueSync(_peer); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -267,7 +268,7 @@ void EthereumHost::estimatePeerHashes(EthereumPeer* _peer) |
|
|
BlockInfo block = m_chain.info(); |
|
|
BlockInfo block = m_chain.info(); |
|
|
time_t lastBlockTime = (block.hash() == m_chain.genesisHash()) ? 1428192000 : (time_t)block.timestamp; |
|
|
time_t lastBlockTime = (block.hash() == m_chain.genesisHash()) ? 1428192000 : (time_t)block.timestamp; |
|
|
time_t now = time(0); |
|
|
time_t now = time(0); |
|
|
unsigned blockCount = 1000; |
|
|
unsigned blockCount = 30000; |
|
|
if (lastBlockTime > now) |
|
|
if (lastBlockTime > now) |
|
|
clog(NetWarn) << "Clock skew? Latest block is in the future"; |
|
|
clog(NetWarn) << "Clock skew? Latest block is in the future"; |
|
|
else |
|
|
else |
|
@ -285,7 +286,7 @@ void EthereumHost::noteRude(p2p::NodeId const& _id, std::string const& _client) |
|
|
|
|
|
|
|
|
void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) |
|
|
void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) |
|
|
{ |
|
|
{ |
|
|
Guard l(x_sync); |
|
|
RecursiveGuard l(x_sync); |
|
|
assert(_peer->m_asking == Asking::Nothing); |
|
|
assert(_peer->m_asking == Asking::Nothing); |
|
|
onPeerHashes(_peer, _hashes, false); |
|
|
onPeerHashes(_peer, _hashes, false); |
|
|
} |
|
|
} |
|
@ -294,13 +295,23 @@ void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool |
|
|
{ |
|
|
{ |
|
|
if (_hashes.empty()) |
|
|
if (_hashes.empty()) |
|
|
{ |
|
|
{ |
|
|
onPeerDoneHashes(_peer, true); |
|
|
_peer->m_hashSub.doneFetch(); |
|
|
|
|
|
continueSync(); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool syncByNumber = _peer->m_syncHashNumber; |
|
|
|
|
|
if (!syncByNumber && _peer->m_syncHash != m_syncingLatestHash) |
|
|
|
|
|
{ |
|
|
|
|
|
// Obsolete hashes, discard
|
|
|
|
|
|
continueSync(_peer); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
unsigned knowns = 0; |
|
|
unsigned knowns = 0; |
|
|
unsigned unknowns = 0; |
|
|
unsigned unknowns = 0; |
|
|
h256s neededBlocks; |
|
|
h256s neededBlocks; |
|
|
bool syncByNumber = !m_syncingLatestHash; |
|
|
unsigned firstNumber = _peer->m_syncHashNumber - _hashes.size(); |
|
|
for (unsigned i = 0; i < _hashes.size(); ++i) |
|
|
for (unsigned i = 0; i < _hashes.size(); ++i) |
|
|
{ |
|
|
{ |
|
|
_peer->addRating(1); |
|
|
_peer->addRating(1); |
|
@ -330,8 +341,11 @@ void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool |
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
knowns++; |
|
|
knowns++; |
|
|
|
|
|
|
|
|
if (!syncByNumber) |
|
|
if (!syncByNumber) |
|
|
m_syncingLatestHash = h; |
|
|
m_syncingLatestHash = h; |
|
|
|
|
|
else |
|
|
|
|
|
_peer->m_hashSub.noteHash(firstNumber + i, 1); |
|
|
} |
|
|
} |
|
|
if (syncByNumber) |
|
|
if (syncByNumber) |
|
|
{ |
|
|
{ |
|
@ -377,13 +391,14 @@ void EthereumHost::onPeerDoneHashes(EthereumPeer* _peer, bool _localChain) |
|
|
{ |
|
|
{ |
|
|
m_man.resetToChain(m_hashes); |
|
|
m_man.resetToChain(m_hashes); |
|
|
m_hashes.clear(); |
|
|
m_hashes.clear(); |
|
|
|
|
|
m_hashMan.reset(m_chain.number() + 1); |
|
|
} |
|
|
} |
|
|
continueSync(); |
|
|
continueSync(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) |
|
|
void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) |
|
|
{ |
|
|
{ |
|
|
Guard l(x_sync); |
|
|
RecursiveGuard l(x_sync); |
|
|
assert(_peer->m_asking == Asking::Nothing); |
|
|
assert(_peer->m_asking == Asking::Nothing); |
|
|
unsigned itemCount = _r.itemCount(); |
|
|
unsigned itemCount = _r.itemCount(); |
|
|
clog(NetMessageSummary) << "Blocks (" << dec << itemCount << "entries)" << (itemCount ? "" : ": NoMoreBlocks"); |
|
|
clog(NetMessageSummary) << "Blocks (" << dec << itemCount << "entries)" << (itemCount ? "" : ": NoMoreBlocks"); |
|
@ -393,6 +408,7 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) |
|
|
// Got to this peer's latest block - just give up.
|
|
|
// Got to this peer's latest block - just give up.
|
|
|
clog(NetNote) << "Finishing blocks fetch..."; |
|
|
clog(NetNote) << "Finishing blocks fetch..."; |
|
|
// NOTE: need to notify of giving up on chain-hashes, too, altering state as necessary.
|
|
|
// NOTE: need to notify of giving up on chain-hashes, too, altering state as necessary.
|
|
|
|
|
|
_peer->m_sub.doneFetch(); |
|
|
_peer->setIdle(); |
|
|
_peer->setIdle(); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
@ -459,7 +475,7 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) |
|
|
|
|
|
|
|
|
void EthereumHost::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) |
|
|
void EthereumHost::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) |
|
|
{ |
|
|
{ |
|
|
Guard l(x_sync); |
|
|
RecursiveGuard l(x_sync); |
|
|
if (isSyncing_UNSAFE()) |
|
|
if (isSyncing_UNSAFE()) |
|
|
{ |
|
|
{ |
|
|
clog(NetMessageSummary) << "Ignoring new hashes since we're already downloading."; |
|
|
clog(NetMessageSummary) << "Ignoring new hashes since we're already downloading."; |
|
@ -471,7 +487,7 @@ void EthereumHost::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) |
|
|
|
|
|
|
|
|
void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) |
|
|
void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) |
|
|
{ |
|
|
{ |
|
|
Guard l(x_sync); |
|
|
RecursiveGuard l(x_sync); |
|
|
if (isSyncing_UNSAFE()) |
|
|
if (isSyncing_UNSAFE()) |
|
|
{ |
|
|
{ |
|
|
clog(NetMessageSummary) << "Ignoring new blocks since we're already downloading."; |
|
|
clog(NetMessageSummary) << "Ignoring new blocks since we're already downloading."; |
|
@ -558,6 +574,17 @@ void EthereumHost::onPeerTransactions(EthereumPeer* _peer, RLP const& _r) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void EthereumHost::onPeerAborting(EthereumPeer* _peer) |
|
|
|
|
|
{ |
|
|
|
|
|
RecursiveGuard l(x_sync); |
|
|
|
|
|
if (_peer->isSyncing()) |
|
|
|
|
|
{ |
|
|
|
|
|
_peer->setIdle(); |
|
|
|
|
|
_peer->setRude(); |
|
|
|
|
|
continueSync(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
void EthereumHost::continueSync() |
|
|
void EthereumHost::continueSync() |
|
|
{ |
|
|
{ |
|
|
clog(NetAllDetail) << "Getting help with downloading hashes and blocks"; |
|
|
clog(NetAllDetail) << "Getting help with downloading hashes and blocks"; |
|
@ -571,22 +598,37 @@ void EthereumHost::continueSync() |
|
|
void EthereumHost::continueSync(EthereumPeer* _peer) |
|
|
void EthereumHost::continueSync(EthereumPeer* _peer) |
|
|
{ |
|
|
{ |
|
|
assert(_peer->m_asking == Asking::Nothing); |
|
|
assert(_peer->m_asking == Asking::Nothing); |
|
|
bool otherPeerSync = false; |
|
|
bool otherPeerV60Sync = false; |
|
|
|
|
|
bool otherPeerV61Sync = false; |
|
|
if (m_needSyncHashes && peerShouldGrabChain(_peer)) |
|
|
if (m_needSyncHashes && peerShouldGrabChain(_peer)) |
|
|
{ |
|
|
{ |
|
|
foreachPeer([&](EthereumPeer* _p) |
|
|
foreachPeer([&](EthereumPeer* _p) |
|
|
{ |
|
|
{ |
|
|
if (_p != _peer && _p->m_asking == Asking::Hashes && _p->m_protocolVersion != protocolVersion()) |
|
|
if (_p != _peer && _p->m_asking == Asking::Hashes) |
|
|
otherPeerSync = true; // Already have a peer downloading hash chain with old protocol, do nothing
|
|
|
{ |
|
|
|
|
|
if (_p->m_protocolVersion != protocolVersion()) |
|
|
|
|
|
otherPeerV60Sync = true; // Already have a peer downloading hash chain with old protocol, do nothing
|
|
|
|
|
|
else |
|
|
|
|
|
otherPeerV61Sync = true; // Already have a peer downloading hash chain with V61+ protocol, join if supported
|
|
|
|
|
|
} |
|
|
}); |
|
|
}); |
|
|
if (otherPeerSync) |
|
|
if (otherPeerV60Sync && !m_hashes.empty()) |
|
|
{ |
|
|
{ |
|
|
/// Downloading from other peer with v60 protocol, nothing else we can do
|
|
|
/// Downloading from other peer with v60 protocol, nothing else we can do
|
|
|
_peer->setIdle(); |
|
|
_peer->setIdle(); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
if (_peer->m_protocolVersion == protocolVersion() && !m_syncingLatestHash) |
|
|
if (otherPeerV61Sync && _peer->m_protocolVersion != protocolVersion()) |
|
|
|
|
|
{ |
|
|
|
|
|
/// Downloading from other peer with v61+ protocol which this peer does not support,
|
|
|
|
|
|
_peer->setIdle(); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
if (_peer->m_protocolVersion == protocolVersion() && !m_hashMan.isComplete()) |
|
|
|
|
|
{ |
|
|
|
|
|
m_syncingV61 = true; |
|
|
_peer->requestHashes(); /// v61+ and not catching up to a particular hash
|
|
|
_peer->requestHashes(); /// v61+ and not catching up to a particular hash
|
|
|
|
|
|
} |
|
|
else |
|
|
else |
|
|
{ |
|
|
{ |
|
|
// Restart/continue sync in single peer mode
|
|
|
// Restart/continue sync in single peer mode
|
|
@ -595,7 +637,14 @@ void EthereumHost::continueSync(EthereumPeer* _peer) |
|
|
m_syncingLatestHash =_peer->m_latestHash; |
|
|
m_syncingLatestHash =_peer->m_latestHash; |
|
|
m_syncingTotalDifficulty = _peer->m_totalDifficulty; |
|
|
m_syncingTotalDifficulty = _peer->m_totalDifficulty; |
|
|
} |
|
|
} |
|
|
_peer->requestHashes(m_syncingLatestHash); |
|
|
if (_peer->m_totalDifficulty >= m_syncingTotalDifficulty) |
|
|
|
|
|
{ |
|
|
|
|
|
_peer->requestHashes(m_syncingLatestHash); |
|
|
|
|
|
m_syncingV61 = false; |
|
|
|
|
|
m_estimatedHashes = _peer->m_expectedHashes; |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
_peer->setIdle(); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
else if (m_needSyncBlocks && peerShouldGrabBlocks(_peer)) // Check if this peer can help with downloading blocks
|
|
|
else if (m_needSyncBlocks && peerShouldGrabBlocks(_peer)) // Check if this peer can help with downloading blocks
|
|
@ -655,3 +704,12 @@ bool EthereumHost::isSyncing_UNSAFE() const |
|
|
}); |
|
|
}); |
|
|
return syncing; |
|
|
return syncing; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
HashChainStatus EthereumHost::status() |
|
|
|
|
|
{ |
|
|
|
|
|
RecursiveGuard l(x_sync); |
|
|
|
|
|
if (m_syncingV61) |
|
|
|
|
|
return HashChainStatus { static_cast<unsigned>(m_hashMan.chainSize()), static_cast<unsigned>(m_hashMan.gotCount()), false }; |
|
|
|
|
|
return HashChainStatus { m_estimatedHashes, static_cast<unsigned>(m_hashes.size()), true }; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|