From 38aab0c5e389319115ec6ce2127174688e3c2656 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Thu, 16 May 2019 10:12:36 +0200 Subject: [PATCH] Add blocks conflicting with ChainLocks to block index (#2923) * Print hash of block which conflicts with a ChainLock * Allow specifying custom block status in `AddToBlockIndex` * Add blocks (headers) to block index even if they conflict with chainlocks --- src/chain.h | 2 ++ src/validation.cpp | 25 +++++++++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/chain.h b/src/chain.h index bff4f3c5fc820..ff72ff684cc58 100644 --- a/src/chain.h +++ b/src/chain.h @@ -158,6 +158,8 @@ enum BlockStatus: uint32_t { BLOCK_FAILED_VALID = 32, //!< stage after last reached validness failed BLOCK_FAILED_CHILD = 64, //!< descends from failed block BLOCK_FAILED_MASK = BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD, + + BLOCK_CONFLICT_CHAINLOCK = 128, //!< conflicts with chainlock system }; /** The block chain is a tree shaped structure starting with the diff --git a/src/validation.cpp b/src/validation.cpp index 822eb4c8ce9c2..f4095e2ec4e3b 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3074,7 +3074,7 @@ bool ResetBlockFailureFlags(CBlockIndex *pindex) { return true; } -CBlockIndex* AddToBlockIndex(const CBlockHeader& block) +CBlockIndex* AddToBlockIndex(const CBlockHeader& block, enum BlockStatus nStatus = BLOCK_VALID_TREE) { // Check for duplicate uint256 hash = block.GetHash(); @@ -3100,9 +3100,14 @@ CBlockIndex* AddToBlockIndex(const CBlockHeader& block) } pindexNew->nTimeMax = (pindexNew->pprev ? std::max(pindexNew->pprev->nTimeMax, pindexNew->nTime) : pindexNew->nTime); pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew); - pindexNew->RaiseValidity(BLOCK_VALID_TREE); - if (pindexBestHeader == NULL || pindexBestHeader->nChainWork < pindexNew->nChainWork) - pindexBestHeader = pindexNew; + if (nStatus & BLOCK_VALID_MASK) { + pindexNew->RaiseValidity(nStatus); + if (pindexBestHeader == NULL || pindexBestHeader->nChainWork < pindexNew->nChainWork) + pindexBestHeader = pindexNew; + } else { + pindexNew->RaiseValidity(BLOCK_VALID_TREE); // required validity level + pindexNew->nStatus |= nStatus; + } setDirtyBlockIndex.insert(pindexNew); @@ -3468,10 +3473,15 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state if (mi == mapBlockIndex.end()) return state.DoS(10, error("%s: prev block not found", __func__), 0, "bad-prevblk"); pindexPrev = (*mi).second; + assert(pindexPrev); + if (pindexPrev->nStatus & BLOCK_FAILED_MASK) return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk"); - assert(pindexPrev); + if (pindexPrev->nStatus & BLOCK_CONFLICT_CHAINLOCK) + // it's ok-ish, the other node is probably missing the latest chainlock + return state.DoS(10, error("%s: prev block %s conflicts with chainlock", __func__, block.hashPrevBlock.ToString()), REJECT_INVALID, "bad-prevblk-chainlock"); + if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, hash)) return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, state.GetRejectReason().c_str()); @@ -3479,7 +3489,10 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state)); if (llmq::chainLocksHandler->HasConflictingChainLock(pindexPrev->nHeight + 1, hash)) { - return state.DoS(10, error("%s: conflicting with chainlock", __func__), REJECT_INVALID, "bad-chainlock"); + if (pindex == NULL) { + AddToBlockIndex(block, BLOCK_CONFLICT_CHAINLOCK); + } + return state.DoS(10, error("%s: header %s conflicts with chainlock", __func__, hash.ToString()), REJECT_INVALID, "bad-chainlock"); } } if (pindex == NULL)