Skip to content

Commit 7202d9d

Browse files
committed
Merge pull request #3276 from sipa/nodestate
Add main-specific node state & move ban score
2 parents 70370ae + b2864d2 commit 7202d9d

File tree

8 files changed

+158
-48
lines changed

8 files changed

+158
-48
lines changed

src/init.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ void Shutdown()
120120
GenerateBitcoins(false, NULL, 0);
121121
#endif
122122
StopNode();
123+
UnregisterNodeSignals(GetNodeSignals());
123124
{
124125
LOCK(cs_main);
125126
#ifdef ENABLE_WALLET

src/main.cpp

Lines changed: 90 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -153,24 +153,75 @@ void SyncWithWallets(const uint256 &hash, const CTransaction &tx, const CBlock *
153153
// Registration of network node signals.
154154
//
155155

156-
int static GetHeight()
156+
namespace {
157+
// Maintain validation-specific state about nodes, protected by cs_main, instead
158+
// by CNode's own locks. This simplifies asynchronous operation, where
159+
// processing of incoming data is done after the ProcessMessage call returns,
160+
// and we're no longer holding the node's locks.
161+
struct CNodeState {
162+
int nMisbehavior;
163+
bool fShouldBan;
164+
std::string name;
165+
166+
CNodeState() {
167+
nMisbehavior = 0;
168+
fShouldBan = false;
169+
}
170+
};
171+
172+
map<NodeId, CNodeState> mapNodeState;
173+
174+
// Requires cs_main.
175+
CNodeState *State(NodeId pnode) {
176+
map<NodeId, CNodeState>::iterator it = mapNodeState.find(pnode);
177+
if (it == mapNodeState.end())
178+
return NULL;
179+
return &it->second;
180+
}
181+
182+
int GetHeight()
157183
{
158184
LOCK(cs_main);
159185
return chainActive.Height();
160186
}
161187

188+
void InitializeNode(NodeId nodeid, const CNode *pnode) {
189+
LOCK(cs_main);
190+
CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second;
191+
state.name = pnode->addrName;
192+
}
193+
194+
void FinalizeNode(NodeId nodeid) {
195+
LOCK(cs_main);
196+
mapNodeState.erase(nodeid);
197+
}
198+
}
199+
200+
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
201+
LOCK(cs_main);
202+
CNodeState *state = State(nodeid);
203+
if (state == NULL)
204+
return false;
205+
stats.nMisbehavior = state->nMisbehavior;
206+
return true;
207+
}
208+
162209
void RegisterNodeSignals(CNodeSignals& nodeSignals)
163210
{
164211
nodeSignals.GetHeight.connect(&GetHeight);
165212
nodeSignals.ProcessMessages.connect(&ProcessMessages);
166213
nodeSignals.SendMessages.connect(&SendMessages);
214+
nodeSignals.InitializeNode.connect(&InitializeNode);
215+
nodeSignals.FinalizeNode.connect(&FinalizeNode);
167216
}
168217

169218
void UnregisterNodeSignals(CNodeSignals& nodeSignals)
170219
{
171220
nodeSignals.GetHeight.disconnect(&GetHeight);
172221
nodeSignals.ProcessMessages.disconnect(&ProcessMessages);
173222
nodeSignals.SendMessages.disconnect(&SendMessages);
223+
nodeSignals.InitializeNode.disconnect(&InitializeNode);
224+
nodeSignals.FinalizeNode.disconnect(&FinalizeNode);
174225
}
175226

176227
//////////////////////////////////////////////////////////////////////////////
@@ -2915,6 +2966,23 @@ bool static AlreadyHave(const CInv& inv)
29152966
}
29162967

29172968

2969+
void Misbehaving(NodeId pnode, int howmuch)
2970+
{
2971+
if (howmuch == 0)
2972+
return;
2973+
2974+
CNodeState *state = State(pnode);
2975+
if (state == NULL)
2976+
return;
2977+
2978+
state->nMisbehavior += howmuch;
2979+
if (state->nMisbehavior >= GetArg("-banscore", 100))
2980+
{
2981+
LogPrintf("Misbehaving: %s (%d -> %d) BAN THRESHOLD EXCEEDED\n", state->name.c_str(), state->nMisbehavior-howmuch, state->nMisbehavior);
2982+
state->fShouldBan = true;
2983+
} else
2984+
LogPrintf("Misbehaving: %s (%d -> %d)\n", state->name.c_str(), state->nMisbehavior-howmuch, state->nMisbehavior);
2985+
}
29182986

29192987
void static ProcessGetData(CNode* pfrom)
29202988
{
@@ -3048,7 +3116,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
30483116
if (pfrom->nVersion != 0)
30493117
{
30503118
pfrom->PushMessage("reject", strCommand, REJECT_DUPLICATE, string("Duplicate version message"));
3051-
pfrom->Misbehaving(1);
3119+
Misbehaving(pfrom->GetId(), 1);
30523120
return false;
30533121
}
30543122

@@ -3153,7 +3221,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
31533221
else if (pfrom->nVersion == 0)
31543222
{
31553223
// Must have a version message before anything else
3156-
pfrom->Misbehaving(1);
3224+
Misbehaving(pfrom->GetId(), 1);
31573225
return false;
31583226
}
31593227

@@ -3174,7 +3242,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
31743242
return true;
31753243
if (vAddr.size() > 1000)
31763244
{
3177-
pfrom->Misbehaving(20);
3245+
Misbehaving(pfrom->GetId(), 20);
31783246
return error("message addr size() = %"PRIszu"", vAddr.size());
31793247
}
31803248

@@ -3237,7 +3305,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
32373305
vRecv >> vInv;
32383306
if (vInv.size() > MAX_INV_SZ)
32393307
{
3240-
pfrom->Misbehaving(20);
3308+
Misbehaving(pfrom->GetId(), 20);
32413309
return error("message inv size() = %"PRIszu"", vInv.size());
32423310
}
32433311

@@ -3288,7 +3356,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
32883356
vRecv >> vInv;
32893357
if (vInv.size() > MAX_INV_SZ)
32903358
{
3291-
pfrom->Misbehaving(20);
3359+
Misbehaving(pfrom->GetId(), 20);
32923360
return error("message getdata size() = %"PRIszu"", vInv.size());
32933361
}
32943362

@@ -3461,7 +3529,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
34613529
pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),
34623530
state.GetRejectReason(), inv.hash);
34633531
if (nDoS > 0)
3464-
pfrom->Misbehaving(nDoS);
3532+
Misbehaving(pfrom->GetId(), nDoS);
34653533
}
34663534
}
34673535

@@ -3488,7 +3556,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
34883556
pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),
34893557
state.GetRejectReason(), inv.hash);
34903558
if (nDoS > 0)
3491-
pfrom->Misbehaving(nDoS);
3559+
Misbehaving(pfrom->GetId(), nDoS);
34923560
}
34933561
}
34943562

@@ -3631,7 +3699,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
36313699
// This isn't a Misbehaving(100) (immediate ban) because the
36323700
// peer might be an older or different implementation with
36333701
// a different signature key, etc.
3634-
pfrom->Misbehaving(10);
3702+
Misbehaving(pfrom->GetId(), 10);
36353703
}
36363704
}
36373705
}
@@ -3644,7 +3712,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
36443712

36453713
if (!filter.IsWithinSizeConstraints())
36463714
// There is no excuse for sending a too-large filter
3647-
pfrom->Misbehaving(100);
3715+
Misbehaving(pfrom->GetId(), 100);
36483716
else
36493717
{
36503718
LOCK(pfrom->cs_filter);
@@ -3665,13 +3733,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
36653733
// and thus, the maximum size any matched object can have) in a filteradd message
36663734
if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE)
36673735
{
3668-
pfrom->Misbehaving(100);
3736+
Misbehaving(pfrom->GetId(), 100);
36693737
} else {
36703738
LOCK(pfrom->cs_filter);
36713739
if (pfrom->pfilter)
36723740
pfrom->pfilter->insert(vData);
36733741
else
3674-
pfrom->Misbehaving(100);
3742+
Misbehaving(pfrom->GetId(), 100);
36753743
}
36763744
}
36773745

@@ -3936,6 +4004,16 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
39364004
if (!lockMain)
39374005
return true;
39384006

4007+
if (State(pto->GetId())->fShouldBan) {
4008+
if (pto->addr.IsLocal())
4009+
LogPrintf("Warning: not banning local node %s!\n", pto->addr.ToString().c_str());
4010+
else {
4011+
pto->fDisconnect = true;
4012+
CNode::Ban(pto->addr);
4013+
}
4014+
State(pto->GetId())->fShouldBan = false;
4015+
}
4016+
39394017
// Start block sync
39404018
if (pto->fStartSync && !fImporting && !fReindex) {
39414019
pto->fStartSync = false;

src/main.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ class CTxUndo;
110110
class CScriptCheck;
111111
class CValidationState;
112112
class CWalletInterface;
113+
struct CNodeStateStats;
113114

114115
struct CBlockTemplate;
115116

@@ -182,6 +183,8 @@ CBlockIndex * InsertBlockIndex(uint256 hash);
182183
bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType);
183184
/** Abort with a message */
184185
bool AbortNode(const std::string &msg);
186+
/** Get statistics from node state */
187+
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats);
185188

186189
/** (try to) add transaction to memory pool **/
187190
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
@@ -194,6 +197,10 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
194197

195198

196199

200+
struct CNodeStateStats {
201+
int nMisbehavior;
202+
};
203+
197204
struct CDiskBlockPos
198205
{
199206
int nFile;

src/net.cpp

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ CCriticalSection cs_setservAddNodeAddresses;
8080
vector<std::string> vAddedNodes;
8181
CCriticalSection cs_vAddedNodes;
8282

83+
NodeId nLastNodeId = 0;
84+
CCriticalSection cs_nLastNodeId;
85+
8386
static CSemaphore *semOutbound = NULL;
8487

8588
// Signals for message handling
@@ -581,35 +584,21 @@ bool CNode::IsBanned(CNetAddr ip)
581584
return fResult;
582585
}
583586

584-
bool CNode::Misbehaving(int howmuch)
585-
{
586-
if (addr.IsLocal())
587+
bool CNode::Ban(const CNetAddr &addr) {
588+
int64_t banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban
587589
{
588-
LogPrintf("Warning: Local node %s misbehaving (delta: %d)!\n", addrName.c_str(), howmuch);
589-
return false;
590+
LOCK(cs_setBanned);
591+
if (setBanned[addr] < banTime)
592+
setBanned[addr] = banTime;
590593
}
591-
592-
nMisbehavior += howmuch;
593-
if (nMisbehavior >= GetArg("-banscore", 100))
594-
{
595-
int64_t banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban
596-
LogPrintf("Misbehaving: %s (%d -> %d) DISCONNECTING\n", addr.ToString().c_str(), nMisbehavior-howmuch, nMisbehavior);
597-
{
598-
LOCK(cs_setBanned);
599-
if (setBanned[addr] < banTime)
600-
setBanned[addr] = banTime;
601-
}
602-
CloseSocketDisconnect();
603-
return true;
604-
} else
605-
LogPrintf("Misbehaving: %s (%d -> %d)\n", addr.ToString().c_str(), nMisbehavior-howmuch, nMisbehavior);
606-
return false;
594+
return true;
607595
}
608596

609597
#undef X
610598
#define X(name) stats.name = name
611599
void CNode::copyStats(CNodeStats &stats)
612600
{
601+
stats.nodeid = this->GetId();
613602
X(nServices);
614603
X(nLastSend);
615604
X(nLastRecv);
@@ -619,7 +608,6 @@ void CNode::copyStats(CNodeStats &stats)
619608
X(cleanSubVer);
620609
X(fInbound);
621610
X(nStartingHeight);
622-
X(nMisbehavior);
623611
X(nSendBytes);
624612
X(nRecvBytes);
625613
stats.fSyncNode = (this == pnodeSync);

0 commit comments

Comments
 (0)