validation: add to m_failed_blocks if found invalid during AcceptBlock

If we have accepted the block header but failed to accept the block
(because ContextualCheckBlock failed) we mark the header as BLOCK_FAILED_VALID.

Now, we also add this header to m_failed_blocks, so that we now don't
accept any headers building on a chain that includes the failed block
(and therefore will never be valid).

Before, we'd only do that if we accepted the block but failed while
connecting it.
This commit is contained in:
Martin Zumsande 2024-05-30 11:58:24 -04:00
parent ee61607a6a
commit 04be77be9b
3 changed files with 6 additions and 4 deletions

View file

@ -4481,6 +4481,7 @@ bool ChainstateManager::AcceptBlock(const std::shared_ptr<const CBlock>& pblock,
if (state.IsInvalid() && state.GetResult() != BlockValidationResult::BLOCK_MUTATED) { if (state.IsInvalid() && state.GetResult() != BlockValidationResult::BLOCK_MUTATED) {
pindex->nStatus |= BLOCK_FAILED_VALID; pindex->nStatus |= BLOCK_FAILED_VALID;
m_blockman.m_dirty_blockindex.insert(pindex); m_blockman.m_dirty_blockindex.insert(pindex);
m_failed_blocks.insert(pindex);
} }
LogError("%s: %s\n", __func__, state.ToString()); LogError("%s: %s\n", __func__, state.ToString());
return false; return false;

View file

@ -1046,10 +1046,11 @@ public:
/** /**
* In order to efficiently track invalidity of headers, we keep the set of * In order to efficiently track invalidity of headers, we keep the set of
* blocks which we tried to connect and found to be invalid here (ie which * blocks which were found to be invalid while connecting or accepting do disk
* were set to BLOCK_FAILED_VALID since the last restart). We can then * (ie which were set to BLOCK_FAILED_VALID since the last restart). We can then
* walk this set and check if a new header is a descendant of something in * walk this set and check if a new header is a descendant of something in
* this set, preventing us from having to walk m_block_index when we try * this set, preventing us from accepting headers building on invalid blocks into
* our blockindex and from having to walk m_block_index when we try
* to connect a bad block and fail. * to connect a bad block and fail.
* *
* While this is more complicated than marking everything which descends * While this is more complicated than marking everything which descends

View file

@ -75,7 +75,7 @@ class InvalidChainTest (BitcoinTestFramework):
block_time += 1 block_time += 1
block3 = create_block(block2a.sha256, create_coinbase(start_height + 3), block_time) block3 = create_block(block2a.sha256, create_coinbase(start_height + 3), block_time)
block3.solve() block3.solve()
node.submitheader(block3.serialize().hex()) # No error, we accept more headers building on a block we have marked as invalid. assert_raises_rpc_error(-25, 'bad-prevblk', lambda: node.submitheader(block3.serialize().hex()))
self.log.info("Test chain with an invalid block (found invalid before acceptance)") self.log.info("Test chain with an invalid block (found invalid before acceptance)")
# Create invalid block (too large) # Create invalid block (too large)