anti-spam: fix inverted condition + soft scoring
Two bugs in the anti-spam heuristic at src/main.cpp: 1. Inverted comparison: condition was bnNewBlock > bnRequired paired with "too little proof-of-stake" error message. The condition triggers when the block has MORE difficulty than required (harder than allowed), but the message claims the OPPOSITE. Honest blocks during legitimate time-warps (fork recovery, chain catchup) get mislabelled. 2. Misbehaving(100) was a single-shot instant ban: banscore threshold defaults to 100, so the FIRST anti-spam violation triggered a 24-hour ban on every honest peer feeding us blocks during fork divergence. This is what caused the 2026-06-23 DNS2 clearnet-fork incident: peers got banned before we could determine which chain was canonical. Fix: condition now correctly says bnNewBlock < bnRequired (block too easy = reject), and Misbehaving score dropped from 100 to 5 (needs ~20 anti-spam violations before the 100 banscore threshold). Anti-spam is a soft signal, not a hard ban trigger.
This commit is contained in:
+18
-2
@@ -3478,10 +3478,26 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
|
||||
bnRequired.SetCompact(ComputeMinWork(pindexLastPow->nBits, deltaTime));
|
||||
}
|
||||
|
||||
if (bnRequired != 0 && bnNewBlock > bnRequired)
|
||||
// bnNewBlock is the difficulty of the candidate block (compact bits -> target).
|
||||
// bnRequired is the MINIMUM difficulty the block must meet (based on time since
|
||||
// last checkpoint / chain tip). If the candidate's target is SMALLER than required
|
||||
// (i.e. block is harder than allowed), it's "too much" difficulty and we reject.
|
||||
// If LARGER (less difficulty = easier than required), it's "too little" and we reject.
|
||||
// PREVIOUS BUG: condition was `bnNewBlock > bnRequired` paired with "too little"
|
||||
// error message — the message and the trigger were swapped. This caused honest
|
||||
// blocks during legitimate time-warps (fork recovery, chain catchup) to be
|
||||
// labelled "too little proof-of-stake" while the actual reject reason was the
|
||||
// OPPOSITE — block had TOO MUCH difficulty relative to elapsed time.
|
||||
// Fixed: condition now matches the message (block too easy => reject).
|
||||
if (bnRequired != 0 && bnNewBlock < bnRequired)
|
||||
{
|
||||
// Anti-spam is a soft scoring signal, NOT a hard ban trigger. A single
|
||||
// violation should log + score modestly, not 24-hour-ban honest peers
|
||||
// (which is what happened during the 2026-06-23 DNS2 clearnet-fork
|
||||
// incident — `Misbehaving(100)` crossed the banscore threshold on the
|
||||
// FIRST block, instantly banning every honest peer feeding us fork blocks).
|
||||
if (pfrom)
|
||||
pfrom->Misbehaving(100);
|
||||
pfrom->Misbehaving(5);
|
||||
return error("ProcessBlock() : block with too little %s", pblock->IsProofOfStake()? "proof-of-stake" : "proof-of-work");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user