@ -38,7 +38,7 @@ EthereumPeer::EthereumPeer(Session* _s, HostCapabilityFace* _h):
Capability ( _s , _h ) ,
m_sub ( host ( ) - > m_man )
{
setGrabbing ( Grabb ing : : State ) ;
setAsking ( Ask ing : : State , Syncing : : Don e ) ;
sendStatus ( ) ;
}
@ -75,13 +75,19 @@ void EthereumPeer::startInitialSync()
sealAndSend ( s ) ;
}
host ( ) - > noteHave PeerState ( this ) ;
host ( ) - > notePeerStateChanged ( this ) ;
}
void EthereumPeer : : tryGrabbingHashChain ( )
{
if ( m_asking ! = Asking : : Nothing )
{
clogS ( NetAllDetail ) < < " Can't synced with this peer - outstanding asks. " ;
return ;
}
// if already done this, then ignore.
if ( m_grabbing ! = Grabbing : : State )
if ( m_syncing = = Syncing : : Don e )
{
clogS ( NetAllDetail ) < < " Already synced with this peer. " ;
return ;
@ -95,7 +101,7 @@ void EthereumPeer::tryGrabbingHashChain()
if ( td > = m_totalDifficulty )
{
clogS ( NetAllDetail ) < < " No. Our chain is better. " ;
setGrabbing ( Grabb ing : : Nothing ) ;
setAsking ( Ask ing : : Nothing , Syncing : : Done ) ;
return ; // All good - we have the better chain.
}
@ -103,8 +109,8 @@ void EthereumPeer::tryGrabbingHashChain()
{
clogS ( NetAllDetail ) < < " Yes. Their chain is better. " ;
host ( ) - > updateGrabbing ( Grabb ing: : Hashes ) ;
setGrabbing ( Grabb ing : : Hashes ) ;
host ( ) - > updateGrabbing ( Ask ing: : Hashes ) ;
setAsking ( Ask ing : : Hashes , Syncing : : Executing ) ;
RLPStream s ;
prep ( s ) . appendList ( 3 ) ;
s < < GetBlockHashesPacket < < m_latestHash < < c_maxHashesAsk ;
@ -118,10 +124,10 @@ void EthereumPeer::giveUpOnFetch()
clogS ( NetNote ) < < " Finishing fetch... " ;
// a bit overkill given that the other nodes may yet have the needed blocks, but better to be safe than sorry.
if ( m_grabbing = = Grabbing : : Chain | | m_grabbing = = Grabb ing : : ChainHelper )
if ( m_asking = = Asking : : Blocks | | m_asking = = Ask ing : : ChainHelper )
{
host ( ) - > noteDoneBlocks ( this ) ;
setGrabbing ( Grabb ing : : Nothing ) ;
setAsking ( Ask ing : : Nothing ) ;
}
// NOTE: need to notify of giving up on chain-hashes, too, altering state as necessary.
@ -163,12 +169,11 @@ bool EthereumPeer::interpret(RLP const& _r)
{
clogS ( NetMessageSummary ) < < " Transactions ( " < < dec < < ( _r . itemCount ( ) - 1 ) < < " entries) " ;
addRating ( _r . itemCount ( ) - 1 ) ;
lock_guard < recursive_mutex > l ( host ( ) - > m_incomingLock ) ;
RecursiveGuard l ( m_incomingLock ) ;
Guard l ( x_knownTransactions ) ;
for ( unsigned i = 1 ; i < _r . itemCount ( ) ; + + i )
{
host ( ) - > addIncomingTransaction ( _r [ i ] . data ( ) . toBytes ( ) ) ;
lock_guard < mutex > l ( x_knownTransactions ) ;
m_incomingTransactions . push_back ( _r [ i ] . data ( ) . toBytes ( ) ) ;
m_knownTransactions . insert ( sha3 ( _r [ i ] . data ( ) ) ) ;
}
break ;
@ -193,7 +198,7 @@ bool EthereumPeer::interpret(RLP const& _r)
{
clogS ( NetMessageSummary ) < < " BlockHashes ( " < < dec < < ( _r . itemCount ( ) - 1 ) < < " entries) " < < ( _r . itemCount ( ) - 1 ? " " : " : NoMoreHashes " ) ;
if ( m_grabbing ! = Grabb ing : : Hashes )
if ( m_asking ! = Ask ing : : Hashes )
{
cwarn < < " Peer giving us hashes when we didn't ask for them. " ;
break ;
@ -247,21 +252,62 @@ bool EthereumPeer::interpret(RLP const& _r)
if ( _r . itemCount ( ) = = 1 )
{
// Couldn't get any from last batch - probably got to this peer's latest block - just give up.
if ( m_grabbing = = Grabbing : : Chain | | m_grabbing = = Grabb ing : : ChainHelper )
if ( m_asking = = Asking : : Blocks | | m_asking = = Ask ing : : ChainHelper )
giveUpOnFetch ( ) ;
break ;
}
unsigned used = 0 ;
unsigned success = 0 ;
unsigned got = 0 ;
unsigned bad = 0 ;
unsigned unknown = 0 ;
unsigned future = 0 ;
for ( unsigned i = 1 ; i < _r . itemCount ( ) ; + + i )
{
auto h = BlockInfo : : headerHash ( _r [ i ] . data ( ) ) ;
m_sub . noteBlock ( h ) ;
if ( host ( ) - > noteBlock ( h , _r [ i ] . data ( ) ) )
used + + ;
Guard l ( x_knownBlocks ) ;
m_knownBlocks . insert ( h ) ;
{
Guard l ( x_knownBlocks ) ;
m_knownBlocks . insert ( h ) ;
}
switch ( host ( ) - > m_bq . import ( _r [ i ] . data ( ) , host ( ) - > m_chain ) )
{
case ImportResult : : Success :
success + + ;
break ;
case ImportResult : : Malformed :
bad + + ;
break ;
case ImportResult : : FutureTime :
future + + ;
break ;
case ImportResult : : AlreadyInChain :
case ImportResult : : AlreadyKnown :
got + + ;
break ;
case ImportResult : : UnknownParent :
unknown + + ;
break ;
}
}
if ( unknown & & m_asking = = Asking : : Nothing )
{
// TODO: kick off resync.
}
if ( bad )
{
// TODO: punish peer
}
addRating ( used ) ;
unsigned knownParents = 0 ;
unsigned unknownParents = 0 ;
@ -286,7 +332,7 @@ bool EthereumPeer::interpret(RLP const& _r)
}
}
clogS ( NetMessageSummary ) < < dec < < knownParents < < " known parents, " < < unknownParents < < " unknown, " < < used < < " used. " ;
if ( m_grabbing = = Grabbing : : Chain | | m_grabbing = = Grabb ing : : ChainHelper )
if ( m_asking = = Asking : : Blocks | | m_asking = = Ask ing : : ChainHelper )
continueGettingChain ( ) ;
break ;
}
@ -298,20 +344,18 @@ bool EthereumPeer::interpret(RLP const& _r)
void EthereumPeer : : ensureGettingChain ( )
{
if ( m_grabbing = = Grabbing : : ChainHelper )
if ( m_helping )
return ; // Already asked & waiting for some.
// Switch to ChainHelper otherwise, unless we're already the Chain grabber.
if ( m_grabbing ! = Grabbing : : Chain )
setGrabbing ( Grabbing : : ChainHelper ) ;
// Help otherwise, unless we're already the Chain grabber.
setHelping ( true ) ;
continueGettingChain ( ) ;
}
void EthereumPeer : : continueGettingChain ( )
{
// If we're getting the hashes already, then we shouldn't be asking for the chain.
if ( m_grabbing = = Grabb ing : : Hashes )
if ( m_asking = = Ask ing : : Hashes )
return ;
auto blocks = m_sub . nextFetch ( c_maxBlocksAsk ) ;
@ -329,8 +373,24 @@ void EthereumPeer::continueGettingChain()
giveUpOnFetch ( ) ;
}
void EthereumPeer : : setGrabbing ( Grabbing _g )
/*
* Possible asking / syncing states for two peers :
* state / presync
* presync hashes
* presync chain ( transiently )
* presync + chain
* presync nothing
* hashes nothing
* chain hashes
* presync chain ( transiently )
* presync + chain
* presync nothing
*/
void EthereumPeer : : setAsking ( Asking _a , Syncing _s )
{
m_grabbing = _g ;
session ( ) - > addNote ( " grab " , _g = = Grabbing : : Nothing ? " nothing " : _g = = Grabbing : : State ? " state " : _g = = Grabbing : : Hashes ? " hashes " : _g = = Grabbing : : Chain ? " chain " : _g = = Grabbing : : ChainHelper ? " chainhelper " : " ? " ) ;
m_asking = _a ;
m_syncing = _s ;
session ( ) - > addNote ( " ask " , _a = = Asking : : Nothing ? " nothing " : _a = = Asking : : State ? " state " : _a = = Asking : : Hashes ? " hashes " : _a = = Asking : : Blocks ? " blocks " : " ? " ) ;
session ( ) - > addNote ( " sync " , _s = = Syncing : : Done ? " done " : _s = = Syncing : : Waiting ? " wait " : _s = = Syncing : : Executing ? " exec " : " ? " ) ;
}