diff options
author | Pieter Wuille <pieter.wuille@gmail.com> | 2013-11-18 01:25:17 +0100 |
---|---|---|
committer | Pieter Wuille <pieter.wuille@gmail.com> | 2013-12-08 14:51:37 +0100 |
commit | b2864d2fb35fa85e32c76e111f8900598e0bb69d (patch) | |
tree | e34d33bf5a9309ce4e60ba1e1889a5bf1b6c7beb /src/main.cpp | |
parent | 70370ae502df8756f3a067a00ccd61b9fc819581 (diff) |
Add main-specific node state
Diffstat (limited to 'src/main.cpp')
-rw-r--r-- | src/main.cpp | 102 |
1 files changed, 90 insertions, 12 deletions
diff --git a/src/main.cpp b/src/main.cpp index 25201c7367..d130e9705e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -153,17 +153,66 @@ void SyncWithWallets(const uint256 &hash, const CTransaction &tx, const CBlock * // Registration of network node signals. // -int static GetHeight() +namespace { +// Maintain validation-specific state about nodes, protected by cs_main, instead +// by CNode's own locks. This simplifies asynchronous operation, where +// processing of incoming data is done after the ProcessMessage call returns, +// and we're no longer holding the node's locks. +struct CNodeState { + int nMisbehavior; + bool fShouldBan; + std::string name; + + CNodeState() { + nMisbehavior = 0; + fShouldBan = false; + } +}; + +map<NodeId, CNodeState> mapNodeState; + +// Requires cs_main. +CNodeState *State(NodeId pnode) { + map<NodeId, CNodeState>::iterator it = mapNodeState.find(pnode); + if (it == mapNodeState.end()) + return NULL; + return &it->second; +} + +int GetHeight() { LOCK(cs_main); return chainActive.Height(); } +void InitializeNode(NodeId nodeid, const CNode *pnode) { + LOCK(cs_main); + CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second; + state.name = pnode->addrName; +} + +void FinalizeNode(NodeId nodeid) { + LOCK(cs_main); + mapNodeState.erase(nodeid); +} +} + +bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) { + LOCK(cs_main); + CNodeState *state = State(nodeid); + if (state == NULL) + return false; + stats.nMisbehavior = state->nMisbehavior; + return true; +} + void RegisterNodeSignals(CNodeSignals& nodeSignals) { nodeSignals.GetHeight.connect(&GetHeight); nodeSignals.ProcessMessages.connect(&ProcessMessages); nodeSignals.SendMessages.connect(&SendMessages); + nodeSignals.InitializeNode.connect(&InitializeNode); + nodeSignals.FinalizeNode.connect(&FinalizeNode); } void UnregisterNodeSignals(CNodeSignals& nodeSignals) @@ -171,6 +220,8 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals) nodeSignals.GetHeight.disconnect(&GetHeight); nodeSignals.ProcessMessages.disconnect(&ProcessMessages); nodeSignals.SendMessages.disconnect(&SendMessages); + nodeSignals.InitializeNode.disconnect(&InitializeNode); + nodeSignals.FinalizeNode.disconnect(&FinalizeNode); } ////////////////////////////////////////////////////////////////////////////// @@ -2915,6 +2966,23 @@ bool static AlreadyHave(const CInv& inv) } +void Misbehaving(NodeId pnode, int howmuch) +{ + if (howmuch == 0) + return; + + CNodeState *state = State(pnode); + if (state == NULL) + return; + + state->nMisbehavior += howmuch; + if (state->nMisbehavior >= GetArg("-banscore", 100)) + { + LogPrintf("Misbehaving: %s (%d -> %d) BAN THRESHOLD EXCEEDED\n", state->name.c_str(), state->nMisbehavior-howmuch, state->nMisbehavior); + state->fShouldBan = true; + } else + LogPrintf("Misbehaving: %s (%d -> %d)\n", state->name.c_str(), state->nMisbehavior-howmuch, state->nMisbehavior); +} void static ProcessGetData(CNode* pfrom) { @@ -3048,7 +3116,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) if (pfrom->nVersion != 0) { pfrom->PushMessage("reject", strCommand, REJECT_DUPLICATE, string("Duplicate version message")); - pfrom->Misbehaving(1); + Misbehaving(pfrom->GetId(), 1); return false; } @@ -3153,7 +3221,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) else if (pfrom->nVersion == 0) { // Must have a version message before anything else - pfrom->Misbehaving(1); + Misbehaving(pfrom->GetId(), 1); return false; } @@ -3174,7 +3242,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) return true; if (vAddr.size() > 1000) { - pfrom->Misbehaving(20); + Misbehaving(pfrom->GetId(), 20); return error("message addr size() = %"PRIszu"", vAddr.size()); } @@ -3237,7 +3305,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) vRecv >> vInv; if (vInv.size() > MAX_INV_SZ) { - pfrom->Misbehaving(20); + Misbehaving(pfrom->GetId(), 20); return error("message inv size() = %"PRIszu"", vInv.size()); } @@ -3288,7 +3356,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) vRecv >> vInv; if (vInv.size() > MAX_INV_SZ) { - pfrom->Misbehaving(20); + Misbehaving(pfrom->GetId(), 20); return error("message getdata size() = %"PRIszu"", vInv.size()); } @@ -3461,7 +3529,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) pfrom->PushMessage("reject", strCommand, state.GetRejectCode(), state.GetRejectReason(), inv.hash); if (nDoS > 0) - pfrom->Misbehaving(nDoS); + Misbehaving(pfrom->GetId(), nDoS); } } @@ -3488,7 +3556,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) pfrom->PushMessage("reject", strCommand, state.GetRejectCode(), state.GetRejectReason(), inv.hash); if (nDoS > 0) - pfrom->Misbehaving(nDoS); + Misbehaving(pfrom->GetId(), nDoS); } } @@ -3631,7 +3699,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) // This isn't a Misbehaving(100) (immediate ban) because the // peer might be an older or different implementation with // a different signature key, etc. - pfrom->Misbehaving(10); + Misbehaving(pfrom->GetId(), 10); } } } @@ -3644,7 +3712,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) if (!filter.IsWithinSizeConstraints()) // There is no excuse for sending a too-large filter - pfrom->Misbehaving(100); + Misbehaving(pfrom->GetId(), 100); else { LOCK(pfrom->cs_filter); @@ -3665,13 +3733,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) // and thus, the maximum size any matched object can have) in a filteradd message if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE) { - pfrom->Misbehaving(100); + Misbehaving(pfrom->GetId(), 100); } else { LOCK(pfrom->cs_filter); if (pfrom->pfilter) pfrom->pfilter->insert(vData); else - pfrom->Misbehaving(100); + Misbehaving(pfrom->GetId(), 100); } } @@ -3936,6 +4004,16 @@ bool SendMessages(CNode* pto, bool fSendTrickle) if (!lockMain) return true; + if (State(pto->GetId())->fShouldBan) { + if (pto->addr.IsLocal()) + LogPrintf("Warning: not banning local node %s!\n", pto->addr.ToString().c_str()); + else { + pto->fDisconnect = true; + CNode::Ban(pto->addr); + } + State(pto->GetId())->fShouldBan = false; + } + // Start block sync if (pto->fStartSync && !fImporting && !fReindex) { pto->fStartSync = false; |