@ -276,10 +276,6 @@ struct CNodeState {
const CService address ;
const CService address ;
//! Whether we have a fully established connection.
//! Whether we have a fully established connection.
bool fCurrentlyConnected ;
bool fCurrentlyConnected ;
//! Accumulated misbehaviour score for this peer.
int nMisbehavior ;
//! Whether this peer should be disconnected and marked as discouraged (unless it has the noban permission).
bool m_should_discourage ;
//! The best known block we know this peer has announced.
//! The best known block we know this peer has announced.
const CBlockIndex * pindexBestKnownBlock ;
const CBlockIndex * pindexBestKnownBlock ;
//! The hash of the last unknown block this peer has announced.
//! The hash of the last unknown block this peer has announced.
@ -432,8 +428,6 @@ struct CNodeState {
: address ( addrIn ) , m_is_inbound ( is_inbound ) , m_is_manual_connection ( is_manual )
: address ( addrIn ) , m_is_inbound ( is_inbound ) , m_is_manual_connection ( is_manual )
{
{
fCurrentlyConnected = false ;
fCurrentlyConnected = false ;
nMisbehavior = 0 ;
m_should_discourage = false ;
pindexBestKnownBlock = nullptr ;
pindexBestKnownBlock = nullptr ;
hashLastUnknownBlock . SetNull ( ) ;
hashLastUnknownBlock . SetNull ( ) ;
pindexLastCommonBlock = nullptr ;
pindexLastCommonBlock = nullptr ;
@ -485,6 +479,13 @@ struct Peer {
/** Same id as the CNode object for this peer */
/** Same id as the CNode object for this peer */
const NodeId m_id { 0 } ;
const NodeId m_id { 0 } ;
/** Protects misbehavior data members */
Mutex m_misbehavior_mutex ;
/** Accumulated misbehavior score for this peer */
int nMisbehavior GUARDED_BY ( m_misbehavior_mutex ) { 0 } ;
/** Whether this peer should be disconnected and marked as discouraged (unless it has the noban permission). */
bool m_should_discourage GUARDED_BY ( m_misbehavior_mutex ) { false } ;
Peer ( NodeId id ) : m_id ( id ) { }
Peer ( NodeId id ) : m_id ( id ) { }
} ;
} ;
@ -907,7 +908,11 @@ void PeerLogicValidation::ReattemptInitialBroadcast(CScheduler& scheduler) const
void PeerLogicValidation : : FinalizeNode ( NodeId nodeid , bool & fUpdateConnectionTime ) {
void PeerLogicValidation : : FinalizeNode ( NodeId nodeid , bool & fUpdateConnectionTime ) {
fUpdateConnectionTime = false ;
fUpdateConnectionTime = false ;
LOCK ( cs_main ) ;
LOCK ( cs_main ) ;
int misbehavior { 0 } ;
{
{
PeerRef peer = GetPeerRef ( nodeid ) ;
assert ( peer ! = nullptr ) ;
misbehavior = WITH_LOCK ( peer - > m_misbehavior_mutex , return peer - > nMisbehavior ) ;
LOCK ( g_peer_mutex ) ;
LOCK ( g_peer_mutex ) ;
g_peer_map . erase ( nodeid ) ;
g_peer_map . erase ( nodeid ) ;
}
}
@ -917,7 +922,7 @@ void PeerLogicValidation::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTim
if ( state - > fSyncStarted )
if ( state - > fSyncStarted )
nSyncStarted - - ;
nSyncStarted - - ;
if ( state- > nM isbehavior = = 0 & & state - > fCurrentlyConnected ) {
if ( m isbehavior = = 0 & & state - > fCurrentlyConnected ) {
fUpdateConnectionTime = true ;
fUpdateConnectionTime = true ;
}
}
@ -947,17 +952,23 @@ void PeerLogicValidation::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTim
}
}
bool GetNodeStateStats ( NodeId nodeid , CNodeStateStats & stats ) {
bool GetNodeStateStats ( NodeId nodeid , CNodeStateStats & stats ) {
LOCK ( cs_main ) ;
{
CNodeState * state = State ( nodeid ) ;
LOCK ( cs_main ) ;
if ( state = = nullptr )
CNodeState * state = State ( nodeid ) ;
return false ;
if ( state = = nullptr )
stats . nMisbehavior = state - > nMisbehavior ;
return false ;
stats . nSyncHeight = state - > pindexBestKnownBlock ? state - > pindexBestKnownBlock - > nHeight : - 1 ;
stats . nSyncHeight = state - > pindexBestKnownBlock ? state - > pindexBestKnownBlock - > nHeight : - 1 ;
stats . nCommonHeight = state - > pindexLastCommonBlock ? state - > pindexLastCommonBlock - > nHeight : - 1 ;
stats . nCommonHeight = state - > pindexLastCommonBlock ? state - > pindexLastCommonBlock - > nHeight : - 1 ;
for ( const QueuedBlock & queue : state - > vBlocksInFlight ) {
for ( const QueuedBlock & queue : state - > vBlocksInFlight ) {
if ( queue . pindex )
if ( queue . pindex )
stats . vHeightInFlight . push_back ( queue . pindex - > nHeight ) ;
stats . vHeightInFlight . push_back ( queue . pindex - > nHeight ) ;
}
}
}
PeerRef peer = GetPeerRef ( nodeid ) ;
if ( peer = = nullptr ) return false ;
stats . nMisbehavior = WITH_LOCK ( peer - > m_misbehavior_mutex , return peer - > nMisbehavior ) ;
return true ;
return true ;
}
}
@ -1101,21 +1112,21 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
* Increment peer ' s misbehavior score . If the new value > = DISCOURAGEMENT_THRESHOLD , mark the node
* Increment peer ' s misbehavior score . If the new value > = DISCOURAGEMENT_THRESHOLD , mark the node
* to be discouraged , meaning the peer might be disconnected and added to the discouragement filter .
* to be discouraged , meaning the peer might be disconnected and added to the discouragement filter .
*/
*/
void Misbehaving ( const NodeId pnode , const int howmuch , const std : : string & message ) EXCLUSIVE_LOCKS_REQUIRED ( cs_main )
void Misbehaving ( const NodeId pnode , const int howmuch , const std : : string & message )
{
{
assert ( howmuch > 0 ) ;
assert ( howmuch > 0 ) ;
CNodeState* const state = State ( pnode ) ;
PeerRef peer = GetPeerRef ( pnode ) ;
if ( state = = nullptr ) return ;
if ( peer = = nullptr ) return ;
state - > nMisbehavior + = howmuch ;
LOCK ( peer - > m_misbehavior_mutex ) ;
peer - > nMisbehavior + = howmuch ;
const std : : string message_prefixed = message . empty ( ) ? " " : ( " : " + message ) ;
const std : : string message_prefixed = message . empty ( ) ? " " : ( " : " + message ) ;
if ( state - > nMisbehavior > = DISCOURAGEMENT_THRESHOLD & & state - > nMisbehavior - howmuch < DISCOURAGEMENT_THRESHOLD )
if ( peer - > nMisbehavior > = DISCOURAGEMENT_THRESHOLD & & peer - > nMisbehavior - howmuch < DISCOURAGEMENT_THRESHOLD ) {
{
LogPrint ( BCLog : : NET , " Misbehaving: peer=%d (%d -> %d) DISCOURAGE THRESHOLD EXCEEDED%s \n " , pnode , peer - > nMisbehavior - howmuch , peer - > nMisbehavior , message_prefixed ) ;
LogPrint ( BCLog : : NET , " Misbehaving: peer=%d (%d -> %d) DISCOURAGE THRESHOLD EXCEEDED%s \n " , pnode , state - > nMisbehavior - howmuch , state - > nMisbehavior , message_prefixed ) ;
peer - > m_should_discourage = true ;
state - > m_should_discourage = true ;
} else {
} else {
LogPrint ( BCLog : : NET , " Misbehaving: peer=%d (%d -> %d)%s \n " , pnode , state- > nMisbehavior - howmuch , state - > nMisbehavior , message_prefixed ) ;
LogPrint ( BCLog : : NET , " Misbehaving: peer=%d (%d -> %d)%s \n " , pnode , peer- > nMisbehavior - howmuch , peer - > nMisbehavior , message_prefixed ) ;
}
}
}
}
@ -1137,7 +1148,6 @@ static bool MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& s
case BlockValidationResult : : BLOCK_CONSENSUS :
case BlockValidationResult : : BLOCK_CONSENSUS :
case BlockValidationResult : : BLOCK_MUTATED :
case BlockValidationResult : : BLOCK_MUTATED :
if ( ! via_compact_block ) {
if ( ! via_compact_block ) {
LOCK ( cs_main ) ;
Misbehaving ( nodeid , 100 , message ) ;
Misbehaving ( nodeid , 100 , message ) ;
return true ;
return true ;
}
}
@ -1161,18 +1171,12 @@ static bool MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& s
case BlockValidationResult : : BLOCK_INVALID_HEADER :
case BlockValidationResult : : BLOCK_INVALID_HEADER :
case BlockValidationResult : : BLOCK_CHECKPOINT :
case BlockValidationResult : : BLOCK_CHECKPOINT :
case BlockValidationResult : : BLOCK_INVALID_PREV :
case BlockValidationResult : : BLOCK_INVALID_PREV :
{
Misbehaving ( nodeid , 100 , message ) ;
LOCK ( cs_main ) ;
Misbehaving ( nodeid , 100 , message ) ;
}
return true ;
return true ;
// Conflicting (but not necessarily invalid) data or different policy:
// Conflicting (but not necessarily invalid) data or different policy:
case BlockValidationResult : : BLOCK_MISSING_PREV :
case BlockValidationResult : : BLOCK_MISSING_PREV :
{
// TODO: Handle this much more gracefully (10 DoS points is super arbitrary)
// TODO: Handle this much more gracefully (10 DoS points is super arbitrary)
Misbehaving ( nodeid , 10 , message ) ;
LOCK ( cs_main ) ;
Misbehaving ( nodeid , 10 , message ) ;
}
return true ;
return true ;
case BlockValidationResult : : BLOCK_RECENT_CONSENSUS_CHANGE :
case BlockValidationResult : : BLOCK_RECENT_CONSENSUS_CHANGE :
case BlockValidationResult : : BLOCK_TIME_FUTURE :
case BlockValidationResult : : BLOCK_TIME_FUTURE :
@ -1196,11 +1200,8 @@ static bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state,
break ;
break ;
// The node is providing invalid data:
// The node is providing invalid data:
case TxValidationResult : : TX_CONSENSUS :
case TxValidationResult : : TX_CONSENSUS :
{
Misbehaving ( nodeid , 100 , message ) ;
LOCK ( cs_main ) ;
return true ;
Misbehaving ( nodeid , 100 , message ) ;
return true ;
}
// Conflicting (but not necessarily invalid) data or different policy:
// Conflicting (but not necessarily invalid) data or different policy:
case TxValidationResult : : TX_RECENT_CONSENSUS_CHANGE :
case TxValidationResult : : TX_RECENT_CONSENSUS_CHANGE :
case TxValidationResult : : TX_INPUTS_NOT_STANDARD :
case TxValidationResult : : TX_INPUTS_NOT_STANDARD :
@ -1847,7 +1848,6 @@ inline void static SendBlockTransactions(const CBlock& block, const BlockTransac
BlockTransactions resp ( req ) ;
BlockTransactions resp ( req ) ;
for ( size_t i = 0 ; i < req . indexes . size ( ) ; i + + ) {
for ( size_t i = 0 ; i < req . indexes . size ( ) ; i + + ) {
if ( req . indexes [ i ] > = block . vtx . size ( ) ) {
if ( req . indexes [ i ] > = block . vtx . size ( ) ) {
LOCK ( cs_main ) ;
Misbehaving ( pfrom . GetId ( ) , 100 , " getblocktxn with out-of-bounds tx indices " ) ;
Misbehaving ( pfrom . GetId ( ) , 100 , " getblocktxn with out-of-bounds tx indices " ) ;
return ;
return ;
}
}
@ -2368,7 +2368,6 @@ void ProcessMessage(
// Each connection can only send one version message
// Each connection can only send one version message
if ( pfrom . nVersion ! = 0 )
if ( pfrom . nVersion ! = 0 )
{
{
LOCK ( cs_main ) ;
Misbehaving ( pfrom . GetId ( ) , 1 , " redundant version message " ) ;
Misbehaving ( pfrom . GetId ( ) , 1 , " redundant version message " ) ;
return ;
return ;
}
}
@ -2528,7 +2527,6 @@ void ProcessMessage(
if ( pfrom . nVersion = = 0 ) {
if ( pfrom . nVersion = = 0 ) {
// Must have a version message before anything else
// Must have a version message before anything else
LOCK ( cs_main ) ;
Misbehaving ( pfrom . GetId ( ) , 1 , " non-version message before version handshake " ) ;
Misbehaving ( pfrom . GetId ( ) , 1 , " non-version message before version handshake " ) ;
return ;
return ;
}
}
@ -2595,7 +2593,6 @@ void ProcessMessage(
if ( ! pfrom . fSuccessfullyConnected ) {
if ( ! pfrom . fSuccessfullyConnected ) {
// Must have a verack message before anything else
// Must have a verack message before anything else
LOCK ( cs_main ) ;
Misbehaving ( pfrom . GetId ( ) , 1 , " non-verack message before version handshake " ) ;
Misbehaving ( pfrom . GetId ( ) , 1 , " non-verack message before version handshake " ) ;
return ;
return ;
}
}
@ -2609,7 +2606,6 @@ void ProcessMessage(
}
}
if ( vAddr . size ( ) > MAX_ADDR_TO_SEND )
if ( vAddr . size ( ) > MAX_ADDR_TO_SEND )
{
{
LOCK ( cs_main ) ;
Misbehaving ( pfrom . GetId ( ) , 20 , strprintf ( " addr message size = %u " , vAddr . size ( ) ) ) ;
Misbehaving ( pfrom . GetId ( ) , 20 , strprintf ( " addr message size = %u " , vAddr . size ( ) ) ) ;
return ;
return ;
}
}
@ -2688,7 +2684,6 @@ void ProcessMessage(
vRecv > > vInv ;
vRecv > > vInv ;
if ( vInv . size ( ) > MAX_INV_SZ )
if ( vInv . size ( ) > MAX_INV_SZ )
{
{
LOCK ( cs_main ) ;
Misbehaving ( pfrom . GetId ( ) , 20 , strprintf ( " inv message size = %u " , vInv . size ( ) ) ) ;
Misbehaving ( pfrom . GetId ( ) , 20 , strprintf ( " inv message size = %u " , vInv . size ( ) ) ) ;
return ;
return ;
}
}
@ -2764,7 +2759,6 @@ void ProcessMessage(
vRecv > > vInv ;
vRecv > > vInv ;
if ( vInv . size ( ) > MAX_INV_SZ )
if ( vInv . size ( ) > MAX_INV_SZ )
{
{
LOCK ( cs_main ) ;
Misbehaving ( pfrom . GetId ( ) , 20 , strprintf ( " getdata message size = %u " , vInv . size ( ) ) ) ;
Misbehaving ( pfrom . GetId ( ) , 20 , strprintf ( " getdata message size = %u " , vInv . size ( ) ) ) ;
return ;
return ;
}
}
@ -3489,7 +3483,6 @@ void ProcessMessage(
// Bypass the normal CBlock deserialization, as we don't want to risk deserializing 2000 full blocks.
// Bypass the normal CBlock deserialization, as we don't want to risk deserializing 2000 full blocks.
unsigned int nCount = ReadCompactSize ( vRecv ) ;
unsigned int nCount = ReadCompactSize ( vRecv ) ;
if ( nCount > MAX_HEADERS_RESULTS ) {
if ( nCount > MAX_HEADERS_RESULTS ) {
LOCK ( cs_main ) ;
Misbehaving ( pfrom . GetId ( ) , 20 , strprintf ( " headers message size = %u " , nCount ) ) ;
Misbehaving ( pfrom . GetId ( ) , 20 , strprintf ( " headers message size = %u " , nCount ) ) ;
return ;
return ;
}
}
@ -3691,7 +3684,6 @@ void ProcessMessage(
if ( ! filter . IsWithinSizeConstraints ( ) )
if ( ! filter . IsWithinSizeConstraints ( ) )
{
{
// There is no excuse for sending a too-large filter
// There is no excuse for sending a too-large filter
LOCK ( cs_main ) ;
Misbehaving ( pfrom . GetId ( ) , 100 , " too-large bloom filter " ) ;
Misbehaving ( pfrom . GetId ( ) , 100 , " too-large bloom filter " ) ;
}
}
else if ( pfrom . m_tx_relay ! = nullptr )
else if ( pfrom . m_tx_relay ! = nullptr )
@ -3725,7 +3717,6 @@ void ProcessMessage(
}
}
}
}
if ( bad ) {
if ( bad ) {
LOCK ( cs_main ) ;
Misbehaving ( pfrom . GetId ( ) , 100 , " bad filteradd message " ) ;
Misbehaving ( pfrom . GetId ( ) , 100 , " bad filteradd message " ) ;
}
}
return ;
return ;
@ -3811,15 +3802,17 @@ void ProcessMessage(
bool PeerLogicValidation : : MaybeDiscourageAndDisconnect ( CNode & pnode )
bool PeerLogicValidation : : MaybeDiscourageAndDisconnect ( CNode & pnode )
{
{
const NodeId peer_id { pnode . GetId ( ) } ;
const NodeId peer_id { pnode . GetId ( ) } ;
PeerRef peer = GetPeerRef ( peer_id ) ;
if ( peer = = nullptr ) return false ;
{
{
LOCK ( cs_main ) ;
LOCK ( peer - > m_misbehavior_mutex ) ;
CNodeState & state = * State ( peer_id ) ;
// There's nothing to do if the m_should_discourage flag isn't set
// There's nothing to do if the m_should_discourage flag isn't set
if ( ! state. m_should_discourage ) return false ;
if ( ! peer- > m_should_discourage ) return false ;
state. m_should_discourage = false ;
peer- > m_should_discourage = false ;
} // cs_main
} // peer.m_misbehavior_mutex
if ( pnode . HasPermission ( PF_NOBAN ) ) {
if ( pnode . HasPermission ( PF_NOBAN ) ) {
// We never disconnect or discourage peers for bad behavior if they have the NOBAN permission flag
// We never disconnect or discourage peers for bad behavior if they have the NOBAN permission flag