@ -68,13 +68,10 @@ DownloadMan& BlockChainSync::downloadMan()
void BlockChainSync : : abortSync ( )
{
DEV_INVARIANT_CHECK ;
host ( ) . foreachPeer ( [ this ] ( EthereumPeer * _p ) { onPeerAborting ( _p ) ; return true ; } ) ;
downloadMan ( ) . resetToChain ( h256s ( ) ) ;
DEV_INVARIANT_CHECK ;
}
void BlockChainSync : : onPeerStatus ( EthereumPeer * _peer )
void BlockChainSync : : onPeerStatus ( std : : shared_ptr < EthereumPeer > _peer )
{
RecursiveGuard l ( x_sync ) ;
DEV_INVARIANT_CHECK ;
@ -111,7 +108,7 @@ unsigned BlockChainSync::estimatedHashes() const
return blockCount ;
}
void BlockChainSync : : requestBlocks ( EthereumPeer * _peer )
void BlockChainSync : : requestBlocks ( std : : shared_ptr < EthereumPeer > _peer )
{
if ( host ( ) . bq ( ) . knownFull ( ) )
{
@ -130,7 +127,14 @@ void BlockChainSync::requestBlocks(EthereumPeer* _peer)
}
}
void BlockChainSync : : onPeerBlocks ( EthereumPeer * _peer , RLP const & _r )
void BlockChainSync : : logNewBlock ( h256 const & _h )
{
if ( m_state = = SyncState : : NewBlocks )
clog ( NetNote ) < < " NewBlock: " < < _h ;
m_knownNewHashes . erase ( _h ) ;
}
void BlockChainSync : : onPeerBlocks ( std : : shared_ptr < EthereumPeer > _peer , RLP const & _r )
{
RecursiveGuard l ( x_sync ) ;
DEV_INVARIANT_CHECK ;
@ -138,7 +142,7 @@ void BlockChainSync::onPeerBlocks(EthereumPeer* _peer, RLP const& _r)
clog ( NetMessageSummary ) < < " Blocks ( " < < dec < < itemCount < < " entries) " < < ( itemCount ? " " : " : NoMoreBlocks " ) ;
_peer - > setIdle ( ) ;
if ( m_state ! = SyncState : : Blocks & & m_state ! = SyncState : : NewBlocks )
if ( m_state ! = SyncState : : Blocks & & m_state ! = SyncState : : NewBlocks & & m_state ! = SyncState : : Waiting )
clog ( NetWarn ) < < " Unexpected Blocks received! " ;
if ( m_state = = SyncState : : Waiting )
{
@ -173,14 +177,17 @@ void BlockChainSync::onPeerBlocks(EthereumPeer* _peer, RLP const& _r)
{
case ImportResult : : Success :
success + + ;
logNewBlock ( h ) ;
break ;
case ImportResult : : Malformed :
case ImportResult : : BadChain :
logNewBlock ( h ) ;
_peer - > disable ( " Malformed block received. " ) ;
return ;
case ImportResult : : FutureTimeKnown :
logNewBlock ( h ) ;
future + + ;
break ;
case ImportResult : : AlreadyInChain :
@ -194,6 +201,7 @@ void BlockChainSync::onPeerBlocks(EthereumPeer* _peer, RLP const& _r)
case ImportResult : : UnknownParent :
{
unknown + + ;
logNewBlock ( h ) ;
if ( m_state = = SyncState : : NewBlocks )
{
BlockInfo bi ;
@ -241,12 +249,11 @@ void BlockChainSync::onPeerBlocks(EthereumPeer* _peer, RLP const& _r)
DEV_INVARIANT_CHECK ;
}
void BlockChainSync : : onPeerNewBlock ( EthereumPeer * _peer , RLP const & _r )
void BlockChainSync : : onPeerNewBlock ( std : : shared_ptr < EthereumPeer > _peer , RLP const & _r )
{
DEV_INVARIANT_CHECK ;
RecursiveGuard l ( x_sync ) ;
auto h = BlockInfo : : headerHash ( _r [ 0 ] . data ( ) ) ;
clog ( NetMessageSummary ) < < " NewBlock: " < < h ;
if ( _r . itemCount ( ) ! = 2 )
_peer - > disable ( " NewBlock without 2 data fields. " ) ;
@ -256,6 +263,7 @@ void BlockChainSync::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r)
{
case ImportResult : : Success :
_peer - > addRating ( 100 ) ;
logNewBlock ( h ) ;
break ;
case ImportResult : : FutureTimeKnown :
//TODO: Rating dependent on how far in future it is.
@ -263,6 +271,7 @@ void BlockChainSync::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r)
case ImportResult : : Malformed :
case ImportResult : : BadChain :
logNewBlock ( h ) ;
_peer - > disable ( " Malformed block received. " ) ;
return ;
@ -272,6 +281,7 @@ void BlockChainSync::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r)
case ImportResult : : FutureTimeUnknown :
case ImportResult : : UnknownParent :
logNewBlock ( h ) ;
clog ( NetMessageSummary ) < < " Received block with no known parent. Resyncing... " ;
resetSyncFor ( _peer , h , _r [ 1 ] . toInt < u256 > ( ) ) ;
break ;
@ -309,17 +319,17 @@ SyncStatus PV60Sync::status() const
return res ;
}
void PV60Sync : : setState ( EthereumPeer * _peer , SyncState _s , bool _isSyncing , bool _needHelp )
void PV60Sync : : setState ( std : : shared_ptr < EthereumPeer > _peer , SyncState _s , bool _isSyncing , bool _needHelp )
{
bool changedState = ( m_state ! = _s ) ;
m_state = _s ;
if ( _isSyncing ! = ( m_syncer = = _peer ) | | ( _isSyncing & & changedState ) )
if ( _isSyncing ! = ( m_syncer . lock ( ) = = _peer ) | | ( _isSyncing & & changedState ) )
changeSyncer ( _isSyncing ? _peer : nullptr , _needHelp ) ;
else if ( _s = = SyncState : : Idle )
changeSyncer ( nullptr , _needHelp ) ;
assert ( ! ! m_syncer | | _s = = SyncState : : Idle ) ;
assert ( isSyncing ( ) | | _s = = SyncState : : Idle ) ;
}
void PV60Sync : : resetSync ( )
@ -335,32 +345,33 @@ void PV60Sync::restartSync()
resetSync ( ) ;
host ( ) . bq ( ) . clear ( ) ;
if ( isSyncing ( ) )
transition ( m_syncer , SyncState : : Idle ) ;
transition ( m_syncer . lock ( ) , SyncState : : Idle ) ;
}
void PV60Sync : : completeSync ( )
{
if ( isSyncing ( ) )
transition ( m_syncer , SyncState : : Idle ) ;
transition ( m_syncer . lock ( ) , SyncState : : Idle ) ;
}
void PV60Sync : : pauseSync ( )
{
if ( isSyncing ( ) )
setState ( m_syncer , SyncState : : Waiting , true ) ;
setState ( m_syncer . lock ( ) , SyncState : : Waiting , true ) ;
}
void PV60Sync : : continueSync ( )
{
transition ( m_syncer , SyncState : : Blocks ) ;
if ( isSyncing ( ) )
transition ( m_syncer . lock ( ) , SyncState : : Blocks ) ;
}
void PV60Sync : : onNewPeer ( EthereumPeer * _peer )
void PV60Sync : : onNewPeer ( std : : shared_ptr < EthereumPeer > _peer )
{
setNeedsSyncing ( _peer , _peer - > m_latestHash , _peer - > m_totalDifficulty ) ;
}
void PV60Sync : : transition ( EthereumPeer * _peer , SyncState _s , bool _force , bool _needHelp )
void PV60Sync : : transition ( std : : shared_ptr < EthereumPeer > _peer , SyncState _s , bool _force , bool _needHelp )
{
clog ( NetMessageSummary ) < < " Transition! " < < EthereumHost : : stateName ( _s ) < < " from " < < EthereumHost : : stateName ( m_state ) < < " , " < < ( isSyncing ( _peer ) ? " syncing " : " holding " ) < < ( needsSyncing ( _peer ) ? " & needed " : " " ) ;
@ -404,13 +415,13 @@ void PV60Sync::transition(EthereumPeer* _peer, SyncState _s, bool _force, bool _
}
if ( shouldGrabBlocks ( _peer ) )
{
clog ( NetNote ) < < " Difficulty of hashchain HIGHER. Grabbing " < < m_syncingNeededBlocks . size ( ) < < " blocks [latest now " < < m_syncingLatestHash < < " , was " < < host ( ) . latestBlockSent ( ) < < " ] " ;
clog ( NetMessageDetail ) < < " Difficulty of hashchain HIGHER. Grabbing " < < m_syncingNeededBlocks . size ( ) < < " blocks [latest now " < < m_syncingLatestHash < < " , was " < < host ( ) . latestBlockSent ( ) < < " ] " ;
downloadMan ( ) . resetToChain ( m_syncingNeededBlocks ) ;
resetSync ( ) ;
}
else
{
clog ( NetNote ) < < " Difficulty of hashchain not HIGHER. Ignoring. " ;
clog ( NetMessageDetail ) < < " Difficulty of hashchain not HIGHER. Ignoring. " ;
resetSync ( ) ;
setState ( _peer , SyncState : : Idle , false ) ;
return ;
@ -451,10 +462,10 @@ void PV60Sync::transition(EthereumPeer* _peer, SyncState _s, bool _force, bool _
}
else if ( _s = = SyncState : : Idle )
{
host ( ) . foreachPeer ( [ this ] ( EthereumPeer * _p ) { _p - > setIdle ( ) ; return true ; } ) ;
host ( ) . foreachPeer ( [ this ] ( std : : shared_ptr < EthereumPeer > _p ) { _p - > setIdle ( ) ; return true ; } ) ;
if ( m_state = = SyncState : : Blocks | | m_state = = SyncState : : NewBlocks )
{
clog ( NetNote ) < < " Finishing blocks fetch... " ;
clog ( NetMessageDetail ) < < " Finishing blocks fetch... " ;
// a bit overkill given that the other nodes may yet have the needed blocks, but better to be safe than sorry.
if ( isSyncing ( _peer ) )
@ -467,7 +478,7 @@ void PV60Sync::transition(EthereumPeer* _peer, SyncState _s, bool _force, bool _
}
else if ( m_state = = SyncState : : Hashes )
{
clog ( NetNote ) < < " Finishing hashes fetch... " ;
clog ( NetMessageDetail ) < < " Finishing hashes fetch... " ;
setState ( _peer , SyncState : : Idle , false ) ;
}
// Otherwise it's fine. We don't care if it's Nothing->Nothing.
@ -478,12 +489,12 @@ void PV60Sync::transition(EthereumPeer* _peer, SyncState _s, bool _force, bool _
clog ( NetWarn ) < < " Invalid state transition: " < < EthereumHost : : stateName ( _s ) < < " from " < < EthereumHost : : stateName ( m_state ) < < " , " < < ( isSyncing ( _peer ) ? " syncing " : " holding " ) < < ( needsSyncing ( _peer ) ? " & needed " : " " ) ;
}
void PV60Sync : : resetSyncFor ( EthereumPeer * _peer , h256 const & _latestHash , u256 const & _td )
void PV60Sync : : resetSyncFor ( std : : shared_ptr < EthereumPeer > _peer , h256 const & _latestHash , u256 const & _td )
{
setNeedsSyncing ( _peer , _latestHash , _td ) ;
}
void PV60Sync : : setNeedsSyncing ( EthereumPeer * _peer , h256 const & _latestHash , u256 const & _td )
void PV60Sync : : setNeedsSyncing ( std : : shared_ptr < EthereumPeer > _peer , h256 const & _latestHash , u256 const & _td )
{
_peer - > m_latestHash = _latestHash ;
_peer - > m_totalDifficulty = _td ;
@ -494,17 +505,17 @@ void PV60Sync::setNeedsSyncing(EthereumPeer* _peer, h256 const& _latestHash, u25
_peer - > session ( ) - > addNote ( " sync " , string ( isSyncing ( _peer ) ? " ongoing " : " holding " ) + ( needsSyncing ( _peer ) ? " & needed " : " " ) ) ;
}
bool PV60Sync : : needsSyncing ( EthereumPeer * _peer ) const
bool PV60Sync : : needsSyncing ( std : : shared_ptr < EthereumPeer > _peer ) const
{
return ! ! _peer - > m_latestHash ;
}
bool PV60Sync : : isSyncing ( EthereumPeer * _peer ) const
bool PV60Sync : : isSyncing ( std : : shared_ptr < EthereumPeer > _peer ) const
{
return m_syncer = = _peer ;
return m_syncer . lock ( ) = = _peer ;
}
bool PV60Sync : : shouldGrabBlocks ( EthereumPeer * _peer ) const
bool PV60Sync : : shouldGrabBlocks ( std : : shared_ptr < EthereumPeer > _peer ) const
{
auto td = _peer - > m_totalDifficulty ;
auto lh = _peer - > m_latestHash ;
@ -513,7 +524,7 @@ bool PV60Sync::shouldGrabBlocks(EthereumPeer* _peer) const
if ( m_syncingNeededBlocks . empty ( ) )
return false ;
clog ( NetNote ) < < " Should grab blocks? " < < td < < " vs " < < ctd < < " ; " < < m_syncingNeededBlocks . size ( ) < < " blocks, ends " < < m_syncingNeededBlocks . back ( ) ;
clog ( NetMessageDetail ) < < " Should grab blocks? " < < td < < " vs " < < ctd < < " ; " < < m_syncingNeededBlocks . size ( ) < < " blocks, ends " < < m_syncingNeededBlocks . back ( ) ;
if ( td < ctd | | ( td = = ctd & & host ( ) . chain ( ) . currentHash ( ) = = lh ) )
return false ;
@ -521,7 +532,7 @@ bool PV60Sync::shouldGrabBlocks(EthereumPeer* _peer) const
return true ;
}
void PV60Sync : : attemptSync ( EthereumPeer * _peer )
void PV60Sync : : attemptSync ( std : : shared_ptr < EthereumPeer > _peer )
{
if ( m_state ! = SyncState : : Idle )
{
@ -556,7 +567,7 @@ void PV60Sync::attemptSync(EthereumPeer* _peer)
}
}
void PV60Sync : : noteNeedsSyncing ( EthereumPeer * _peer )
void PV60Sync : : noteNeedsSyncing ( std : : shared_ptr < EthereumPeer > _peer )
{
// if already downloading hash-chain, ignore.
if ( isSyncing ( ) )
@ -570,7 +581,7 @@ void PV60Sync::noteNeedsSyncing(EthereumPeer* _peer)
attemptSync ( _peer ) ;
}
void PV60Sync : : changeSyncer ( EthereumPeer * _syncer , bool _needHelp )
void PV60Sync : : changeSyncer ( std : : shared_ptr < EthereumPeer > _syncer , bool _needHelp )
{
if ( _syncer )
clog ( NetAllDetail ) < < " Changing syncer to " < < _syncer - > session ( ) - > socketId ( ) ;
@ -581,9 +592,9 @@ void PV60Sync::changeSyncer(EthereumPeer* _syncer, bool _needHelp)
if ( isSyncing ( ) )
{
if ( _needHelp & & ( m_state = = SyncState : : Blocks | | m_state = = SyncState : : NewBlocks ) )
host ( ) . foreachPeer ( [ & ] ( EthereumPeer * _p )
host ( ) . foreachPeer ( [ & ] ( std : : shared_ptr < EthereumPeer > _p )
{
clog ( NetNote ) < < " Getting help with downloading blocks " ;
clog ( NetMessageDetail ) < < " Getting help with downloading blocks " ;
if ( _p ! = _syncer & & _p - > m_asking = = Asking : : Nothing )
transition ( _p , m_state ) ;
return true ;
@ -592,7 +603,7 @@ void PV60Sync::changeSyncer(EthereumPeer* _syncer, bool _needHelp)
else
{
// start grabbing next hash chain if there is one.
host ( ) . foreachPeer ( [ this ] ( EthereumPeer * _p )
host ( ) . foreachPeer ( [ this ] ( std : : shared_ptr < EthereumPeer > _p )
{
attemptSync ( _p ) ;
return ! isSyncing ( ) ;
@ -601,24 +612,24 @@ void PV60Sync::changeSyncer(EthereumPeer* _syncer, bool _needHelp)
{
if ( m_state ! = SyncState : : Idle )
setState ( _syncer , SyncState : : Idle ) ;
clog ( NetNote ) < < " No more peers to sync with. " ;
clog ( NetMessageDetail ) < < " No more peers to sync with. " ;
}
}
assert ( ! ! m_syncer | | m_state = = SyncState : : Idle ) ;
assert ( isSyncing ( ) | | m_state = = SyncState : : Idle ) ;
}
void PV60Sync : : peerDoneBlocks ( EthereumPeer * _peer )
void PV60Sync : : peerDoneBlocks ( std : : shared_ptr < EthereumPeer > _peer )
{
noteDoneBlocks ( _peer , false ) ;
}
void PV60Sync : : noteDoneBlocks ( EthereumPeer * _peer , bool _clemency )
void PV60Sync : : noteDoneBlocks ( std : : shared_ptr < EthereumPeer > _peer , bool _clemency )
{
resetNeedsSyncing ( _peer ) ;
if ( downloadMan ( ) . isComplete ( ) )
{
// Done our chain-get.
clog ( NetNote ) < < " Chain download complete. " ;
clog ( NetMessageDetail ) < < " Chain download complete. " ;
// 1/100th for each useful block hash.
_peer - > addRating ( downloadMan ( ) . chainSize ( ) / 100 ) ;
downloadMan ( ) . reset ( ) ;
@ -643,7 +654,7 @@ void PV60Sync::noteDoneBlocks(EthereumPeer* _peer, bool _clemency)
_peer - > m_sub . doneFetch ( ) ;
}
void PV60Sync : : onPeerHashes ( EthereumPeer * _peer , h256s const & _hashes )
void PV60Sync : : onPeerHashes ( std : : shared_ptr < EthereumPeer > _peer , h256s const & _hashes )
{
RecursiveGuard l ( x_sync ) ;
DEV_INVARIANT_CHECK ;
@ -698,11 +709,11 @@ void PV60Sync::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes)
DEV_INVARIANT_CHECK ;
}
void PV60Sync : : onPeerNewHashes ( EthereumPeer * _peer , h256s const & _hashes )
void PV60Sync : : onPeerNewHashes ( std : : shared_ptr < EthereumPeer > _peer , h256s const & _hashes )
{
RecursiveGuard l ( x_sync ) ;
DEV_INVARIANT_CHECK ;
if ( isSyncing ( ) )
if ( isSyncing ( ) & & ( m_state ! = SyncState : : NewBlocks | | isSyncing ( _peer ) ) )
{
clog ( NetMessageSummary ) < < " Ignoring since we're already downloading. " ;
return ;
@ -734,43 +745,55 @@ void PV60Sync::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes)
clog ( NetMessageSummary ) < < knowns < < " knowns, " < < unknowns < < " unknowns " ;
if ( unknowns > 0 )
{
clog ( NetNote ) < < " Not syncing and new block hash discovered: syncing without help. " ;
downloadMan ( ) . resetToChain ( m_syncingNeededBlocks ) ;
if ( m_state = = SyncState : : NewBlocks )
{
clog ( NetMessageDetail ) < < " Downloading new blocks and seeing new hashes. Trying grabbing blocks " ;
_peer - > requestBlocks ( m_syncingNeededBlocks ) ;
}
else
{
clog ( NetMessageDetail ) < < " Not syncing and new block hash discovered: syncing without help. " ;
downloadMan ( ) . resetToChain ( m_syncingNeededBlocks ) ;
transition ( _peer , SyncState : : NewBlocks , false , false ) ;
}
for ( auto const & h : m_syncingNeededBlocks )
if ( ! m_knownNewHashes . count ( h ) )
{
m_knownNewHashes . insert ( h ) ;
clog ( NetNote ) < < " NewHash: " < < h ;
}
resetSync ( ) ;
transition ( _peer , SyncState : : NewBlocks , false , false ) ;
}
DEV_INVARIANT_CHECK ;
}
void PV60Sync : : abortSync ( EthereumPeer * _peer )
void PV60Sync : : abortSync ( )
{
// Can't check invariants here since the peers is already removed from the list and the state is not updated yet.
if ( isSyncing ( _peer ) )
{
host ( ) . foreachPeer ( [ this ] ( EthereumPeer * _p ) { _p - > setIdle ( ) ; return true ; } ) ;
transition ( _peer , SyncState : : Idle , true ) ;
}
host ( ) . foreachPeer ( [ this ] ( std : : shared_ptr < EthereumPeer > _p ) { _p - > setIdle ( ) ; return true ; } ) ;
setState ( std : : shared_ptr < EthereumPeer > ( ) , SyncState : : Idle , false , true ) ;
DEV_INVARIANT_CHECK ;
}
void PV60Sync : : onPeerAborting ( EthereumPeer * _peer )
void PV60Sync : : onPeerAborting ( )
{
RecursiveGuard l ( x_sync ) ;
// Can't check invariants here since the peers is already removed from the list and the state is not updated yet.
abortSync ( _peer ) ;
if ( m_syncer . expired ( ) )
abortSync ( ) ;
DEV_INVARIANT_CHECK ;
}
bool PV60Sync : : invariants ( ) const
{
if ( m_state = = SyncState : : Idle & & ! ! m_syncer )
if ( m_state = = SyncState : : Idle & & isSyncing ( ) )
return false ;
if ( m_state ! = SyncState : : Idle & & ! m_syncer )
if ( m_state ! = SyncState : : Idle & & ! isSyncing ( ) )
return false ;
if ( m_state = = SyncState : : Hashes )
{
bool hashes = false ;
host ( ) . foreachPeer ( [ & ] ( EthereumPeer * _p ) { if ( _p - > m_asking = = Asking : : Hashes ) hashes = true ; return ! hashes ; } ) ;
host ( ) . foreachPeer ( [ & ] ( std : : shared_ptr < EthereumPeer > _p ) { if ( _p - > m_asking = = Asking : : Hashes ) hashes = true ; return ! hashes ; } ) ;
if ( ! hashes )
return false ;
if ( ! m_syncingLatestHash )
@ -781,7 +804,7 @@ bool PV60Sync::invariants() const
if ( m_state = = SyncState : : Blocks | | m_state = = SyncState : : NewBlocks )
{
bool blocks = false ;
host ( ) . foreachPeer ( [ & ] ( EthereumPeer * _p ) { if ( _p - > m_asking = = Asking : : Blocks ) blocks = true ; return ! blocks ; } ) ;
host ( ) . foreachPeer ( [ & ] ( std : : shared_ptr < EthereumPeer > _p ) { if ( _p - > m_asking = = Asking : : Blocks ) blocks = true ; return ! blocks ; } ) ;
if ( ! blocks )
return false ;
if ( downloadMan ( ) . isComplete ( ) )
@ -790,7 +813,7 @@ bool PV60Sync::invariants() const
if ( m_state = = SyncState : : Idle )
{
bool busy = false ;
host ( ) . foreachPeer ( [ & ] ( EthereumPeer * _p ) { if ( _p - > m_asking ! = Asking : : Nothing & & _p - > m_asking ! = Asking : : State ) busy = true ; return ! busy ; } ) ;
host ( ) . foreachPeer ( [ & ] ( std : : shared_ptr < EthereumPeer > _p ) { if ( _p - > m_asking ! = Asking : : Nothing & & _p - > m_asking ! = Asking : : State ) busy = true ; return ! busy ; } ) ;
if ( busy )
return false ;
}