Compare commits

...

3 Commits

Author SHA1 Message Date
Martin Zumsande 0cb1f9e221
Merge 04b943b63c into b510893d00 2025-10-08 15:59:34 +00:00
Martin Zumsande 04b943b63c validation: call CheckForkWarningConditions during IBD, and at startup
The existing IBD check was added at a time when CheckForkWarningConditions
did also sophisticated fork detection that could lead to false positives
during IBD (55ed3f1475).

The fork detection logic doesn't exist anymore
(since fa62304c97), so the IBD check is no
longer necessary.

Displaying the log at startup will help node operators diagnose the
problem better.
2025-10-08 11:58:46 -04:00
Martin Zumsande 419ff388b9 p2p: Add warning message when receiving headers for blocks cached as invalid
Currently, if database corruption leads to a block being marked as
invalid incorrectly, we can get stuck in an infinite headerssync
loop with no indication what went wrong or how to fix it.
With the added log message, users will receive an explicit warning after each
failed headerssync attempt with an outbound peer.
2025-10-08 11:57:47 -04:00
2 changed files with 10 additions and 5 deletions

View File

@ -2956,6 +2956,12 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
state, &pindexLast)}; state, &pindexLast)};
if (!processed) { if (!processed) {
if (state.IsInvalid()) { if (state.IsInvalid()) {
if (!pfrom.IsInboundConn() && state.GetResult() == BlockValidationResult::BLOCK_CACHED_INVALID) {
LogWarning("Header received from peer=%i was previously marked as invalid. "
"If this happens with all peers, database corruption is likely and "
"-reindex may be necessary to recover.",
pfrom.GetId());
}
MaybePunishNodeForBlock(pfrom.GetId(), state, via_compact_block, "invalid header received"); MaybePunishNodeForBlock(pfrom.GetId(), state, via_compact_block, "invalid header received");
return; return;
} }

View File

@ -2023,15 +2023,12 @@ void Chainstate::CheckForkWarningConditions()
{ {
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
// Before we get past initial download, we cannot reliably alert about forks if (this->GetRole() == ChainstateRole::BACKGROUND) {
// (we assume we don't get stuck on a fork before finishing our initial sync)
// Also not applicable to the background chainstate
if (m_chainman.IsInitialBlockDownload() || this->GetRole() == ChainstateRole::BACKGROUND) {
return; return;
} }
if (m_chainman.m_best_invalid && m_chainman.m_best_invalid->nChainWork > m_chain.Tip()->nChainWork + (GetBlockProof(*m_chain.Tip()) * 6)) { if (m_chainman.m_best_invalid && m_chainman.m_best_invalid->nChainWork > m_chain.Tip()->nChainWork + (GetBlockProof(*m_chain.Tip()) * 6)) {
LogPrintf("%s: Warning: Found invalid chain at least ~6 blocks longer than our best chain.\nChain state database corruption likely.\n", __func__); LogWarning("Found invalid chain at least ~6 blocks longer than our best chain. Chain state database corruption likely.");
m_chainman.GetNotifications().warningSet( m_chainman.GetNotifications().warningSet(
kernel::Warning::LARGE_WORK_INVALID_CHAIN, kernel::Warning::LARGE_WORK_INVALID_CHAIN,
_("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.")); _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade."));
@ -4674,6 +4671,8 @@ bool Chainstate::LoadChainTip()
/*verification_progress=*/m_chainman.GuessVerificationProgress(tip)); /*verification_progress=*/m_chainman.GuessVerificationProgress(tip));
} }
CheckForkWarningConditions();
return true; return true;
} }