Skip to content

Commit 40a0481

Browse files
committed
Merge #19472: [net processing] Reduce cs_main scope in MaybeDiscourageAndDisconnect()
655b195 [net processing] Continue SendMessages processing if not disconnecting peer (John Newbery) a49781e [net processing] Only call MaybeDiscourageAndDisconnect from SendMessages (John Newbery) a1d5a42 [net processing] Fix bad indentation in SendMessages() (John Newbery) 1a1c23f [net processing] Change cs_main TRY_LOCK to LOCK in SendMessages() (John Newbery) Pull request description: The motivation for this PR is to reduce the scope of cs_main locking in misbehavior logic. It is the first set of commits from a larger branch to move the misbehavior data out of CNodeState and into a new struct that doesn't take cs_main. There are some very minor behavior changes in this branch, such as: - Not checking for discouragement/disconnect in `ProcessMessages()` (and instead relying on the following check in `SendMessages()`) - Checking for discouragement/disconnect as the first action in `SendMessages()` (and not doing ping message sending first) - Continuing through `SendMessages()` if `MaybeDiscourageAndDisconnect()` doesn't disconnect the peer (rather than dropping out of `SendMessages()` ACKs for top commit: jonatack: re-ACK 655b195 per `git range-diff 505b4ed f54af5e 655b195`, code/commit messages review, a bit of code history, and debug build. MarcoFalke: ACK 655b195 only some style-nits 🚁 promag: Code review ACK 655b195. ariard: Code Review ACK 655b195 Tree-SHA512: fd6d7bc6bb789f5fb7771fb6a45f61a8faba32af93b766554f562144f9631d15c9cc849a383e71743ef73e610b4ee14853666f6fbf08a3ae35176d48c76c65d3
2 parents 007e15d + 655b195 commit 40a0481

File tree

2 files changed

+78
-63
lines changed

2 files changed

+78
-63
lines changed

src/net_processing.cpp

Lines changed: 77 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3716,32 +3716,49 @@ void ProcessMessage(
37163716
return;
37173717
}
37183718

3719+
/** Maybe disconnect a peer and discourage future connections from its address.
3720+
*
3721+
* @param[in] pnode The node to check.
3722+
* @return True if the peer was marked for disconnection in this function
3723+
*/
37193724
bool PeerLogicValidation::MaybeDiscourageAndDisconnect(CNode& pnode)
37203725
{
3721-
AssertLockHeld(cs_main);
3722-
CNodeState &state = *State(pnode.GetId());
3726+
NodeId peer_id{pnode.GetId()};
3727+
{
3728+
LOCK(cs_main);
3729+
CNodeState &state = *State(peer_id);
3730+
3731+
// There's nothing to do if the m_should_discourage flag isn't set
3732+
if (!state.m_should_discourage) return false;
37233733

3724-
if (state.m_should_discourage) {
3734+
// Reset m_should_discourage
37253735
state.m_should_discourage = false;
3726-
if (pnode.HasPermission(PF_NOBAN)) {
3727-
LogPrintf("Warning: not punishing whitelisted peer %s!\n", pnode.addr.ToString());
3728-
} else if (pnode.m_manual_connection) {
3729-
LogPrintf("Warning: not punishing manually-connected peer %s!\n", pnode.addr.ToString());
3730-
} else if (pnode.addr.IsLocal()) {
3731-
// Disconnect but don't discourage this local node
3732-
LogPrintf("Warning: disconnecting but not discouraging local peer %s!\n", pnode.addr.ToString());
3733-
pnode.fDisconnect = true;
3734-
} else {
3735-
// Disconnect and discourage all nodes sharing the address
3736-
LogPrintf("Disconnecting and discouraging peer %s!\n", pnode.addr.ToString());
3737-
if (m_banman) {
3738-
m_banman->Discourage(pnode.addr);
3739-
}
3740-
connman->DisconnectNode(pnode.addr);
3741-
}
3736+
} // cs_main
3737+
3738+
if (pnode.HasPermission(PF_NOBAN)) {
3739+
// Peer has the NOBAN permission flag - log but don't disconnect
3740+
LogPrintf("Warning: not punishing noban peer %d!\n", peer_id);
3741+
return false;
3742+
}
3743+
3744+
if (pnode.m_manual_connection) {
3745+
// Peer is a manual connection - log but don't disconnect
3746+
LogPrintf("Warning: not punishing manually connected peer %d!\n", peer_id);
3747+
return false;
3748+
}
3749+
3750+
if (pnode.addr.IsLocal()) {
3751+
// Peer is on a local address. Disconnect this peer, but don't discourage the local address
3752+
LogPrintf("Warning: disconnecting but not discouraging local peer %d!\n", peer_id);
3753+
pnode.fDisconnect = true;
37423754
return true;
37433755
}
3744-
return false;
3756+
3757+
// Normal case: Disconnect the peer and discourage all nodes sharing the address
3758+
LogPrintf("Disconnecting and discouraging peer %d!\n", peer_id);
3759+
if (m_banman) m_banman->Discourage(pnode.addr);
3760+
connman->DisconnectNode(pnode.addr);
3761+
return true;
37453762
}
37463763

37473764
bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& interruptMsgProc)
@@ -3834,9 +3851,6 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
38343851
LogPrint(BCLog::NET, "%s(%s, %u bytes): Unknown exception caught\n", __func__, SanitizeString(msg_type), nMessageSize);
38353852
}
38363853

3837-
LOCK(cs_main);
3838-
MaybeDiscourageAndDisconnect(*pfrom);
3839-
38403854
return fMoreWork;
38413855
}
38423856

@@ -3999,48 +4013,49 @@ class CompareInvMempoolOrder
39994013
bool PeerLogicValidation::SendMessages(CNode* pto)
40004014
{
40014015
const Consensus::Params& consensusParams = Params().GetConsensus();
4002-
{
4003-
// Don't send anything until the version handshake is complete
4004-
if (!pto->fSuccessfullyConnected || pto->fDisconnect)
4005-
return true;
40064016

4007-
// If we get here, the outgoing message serialization version is set and can't change.
4008-
const CNetMsgMaker msgMaker(pto->GetSendVersion());
4017+
// We must call MaybeDiscourageAndDisconnect first, to ensure that we'll
4018+
// disconnect misbehaving peers even before the version handshake is complete.
4019+
if (MaybeDiscourageAndDisconnect(*pto)) return true;
40094020

4010-
//
4011-
// Message: ping
4012-
//
4013-
bool pingSend = false;
4014-
if (pto->fPingQueued) {
4015-
// RPC ping request by user
4016-
pingSend = true;
4017-
}
4018-
if (pto->nPingNonceSent == 0 && pto->m_ping_start.load() + PING_INTERVAL < GetTime<std::chrono::microseconds>()) {
4019-
// Ping automatically sent as a latency probe & keepalive.
4020-
pingSend = true;
4021-
}
4022-
if (pingSend) {
4023-
uint64_t nonce = 0;
4024-
while (nonce == 0) {
4025-
GetRandBytes((unsigned char*)&nonce, sizeof(nonce));
4026-
}
4027-
pto->fPingQueued = false;
4028-
pto->m_ping_start = GetTime<std::chrono::microseconds>();
4029-
if (pto->nVersion > BIP0031_VERSION) {
4030-
pto->nPingNonceSent = nonce;
4031-
connman->PushMessage(pto, msgMaker.Make(NetMsgType::PING, nonce));
4032-
} else {
4033-
// Peer is too old to support ping command with nonce, pong will never arrive.
4034-
pto->nPingNonceSent = 0;
4035-
connman->PushMessage(pto, msgMaker.Make(NetMsgType::PING));
4036-
}
4037-
}
4021+
// Don't send anything until the version handshake is complete
4022+
if (!pto->fSuccessfullyConnected || pto->fDisconnect)
4023+
return true;
40384024

4039-
TRY_LOCK(cs_main, lockMain);
4040-
if (!lockMain)
4041-
return true;
4025+
// If we get here, the outgoing message serialization version is set and can't change.
4026+
const CNetMsgMaker msgMaker(pto->GetSendVersion());
40424027

4043-
if (MaybeDiscourageAndDisconnect(*pto)) return true;
4028+
//
4029+
// Message: ping
4030+
//
4031+
bool pingSend = false;
4032+
if (pto->fPingQueued) {
4033+
// RPC ping request by user
4034+
pingSend = true;
4035+
}
4036+
if (pto->nPingNonceSent == 0 && pto->m_ping_start.load() + PING_INTERVAL < GetTime<std::chrono::microseconds>()) {
4037+
// Ping automatically sent as a latency probe & keepalive.
4038+
pingSend = true;
4039+
}
4040+
if (pingSend) {
4041+
uint64_t nonce = 0;
4042+
while (nonce == 0) {
4043+
GetRandBytes((unsigned char*)&nonce, sizeof(nonce));
4044+
}
4045+
pto->fPingQueued = false;
4046+
pto->m_ping_start = GetTime<std::chrono::microseconds>();
4047+
if (pto->nVersion > BIP0031_VERSION) {
4048+
pto->nPingNonceSent = nonce;
4049+
connman->PushMessage(pto, msgMaker.Make(NetMsgType::PING, nonce));
4050+
} else {
4051+
// Peer is too old to support ping command with nonce, pong will never arrive.
4052+
pto->nPingNonceSent = 0;
4053+
connman->PushMessage(pto, msgMaker.Make(NetMsgType::PING));
4054+
}
4055+
}
4056+
4057+
{
4058+
LOCK(cs_main);
40444059

40454060
CNodeState &state = *State(pto->GetId());
40464061

@@ -4602,7 +4617,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
46024617
pto->m_tx_relay->nextSendTimeFeeFilter = timeNow + GetRandInt(MAX_FEEFILTER_CHANGE_DELAY) * 1000000;
46034618
}
46044619
}
4605-
}
4620+
} // release cs_main
46064621
return true;
46074622
}
46084623

src/net_processing.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class PeerLogicValidation final : public CValidationInterface, public NetEventsI
3434
ChainstateManager& m_chainman;
3535
CTxMemPool& m_mempool;
3636

37-
bool MaybeDiscourageAndDisconnect(CNode& pnode) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
37+
bool MaybeDiscourageAndDisconnect(CNode& pnode);
3838

3939
public:
4040
PeerLogicValidation(CConnman* connman, BanMan* banman, CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool);

0 commit comments

Comments
 (0)