mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-17 21:32:00 +01:00
Merge 17718660b8c95d1c12124ba2f38baf286a3bddf2 into 5f4422d68dc3530c353af1f87499de1c864b60ad
This commit is contained in:
commit
24f42ee0bc
@ -117,4 +117,41 @@ BOOST_AUTO_TEST_CASE(num_chain_tx_max)
|
|||||||
BOOST_CHECK_EQUAL(block_index.m_chain_tx_count, std::numeric_limits<uint64_t>::max());
|
BOOST_CHECK_EQUAL(block_index.m_chain_tx_count, std::numeric_limits<uint64_t>::max());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(invalidate_block, TestChain100Setup)
|
||||||
|
{
|
||||||
|
const CChain& active{*WITH_LOCK(Assert(m_node.chainman)->GetMutex(), return &Assert(m_node.chainman)->ActiveChain())};
|
||||||
|
|
||||||
|
// Check BlockStatus when doing InvalidateBlock()
|
||||||
|
BlockValidationState state;
|
||||||
|
auto* orig_tip = active.Tip();
|
||||||
|
int height_to_invalidate = orig_tip->nHeight - 10;
|
||||||
|
auto* tip_to_invalidate = active[height_to_invalidate];
|
||||||
|
m_node.chainman->ActiveChainstate().InvalidateBlock(state, tip_to_invalidate);
|
||||||
|
|
||||||
|
// tip_to_invalidate just got invalidated, so it's BLOCK_FAILED_VALID
|
||||||
|
WITH_LOCK(::cs_main, assert(tip_to_invalidate->nStatus & BLOCK_FAILED_VALID));
|
||||||
|
WITH_LOCK(::cs_main, assert((tip_to_invalidate->nStatus & BLOCK_FAILED_CHILD) == 0));
|
||||||
|
|
||||||
|
// check all ancestors of block are validated up to BLOCK_VALID_TRANSACTIONS and are not invalid
|
||||||
|
auto pindex = tip_to_invalidate->pprev;
|
||||||
|
while (pindex) {
|
||||||
|
WITH_LOCK(::cs_main, assert(pindex->IsValid(BLOCK_VALID_TRANSACTIONS)));
|
||||||
|
WITH_LOCK(::cs_main, assert((pindex->nStatus & BLOCK_FAILED_MASK) == 0));
|
||||||
|
pindex = pindex->pprev;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check all descendants of block are BLOCK_FAILED_CHILD
|
||||||
|
pindex = orig_tip;
|
||||||
|
while (pindex && pindex != tip_to_invalidate) {
|
||||||
|
WITH_LOCK(::cs_main, assert((pindex->nStatus & BLOCK_FAILED_VALID) == 0));
|
||||||
|
WITH_LOCK(::cs_main, assert(pindex->nStatus & BLOCK_FAILED_CHILD));
|
||||||
|
pindex = pindex->pprev;
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't mark already invalidated block (orig_tip is BLOCK_FAILED_CHILD) with BLOCK_FAILED_VALID again
|
||||||
|
m_node.chainman->ActiveChainstate().InvalidateBlock(state, orig_tip);
|
||||||
|
WITH_LOCK(::cs_main, assert(orig_tip->nStatus & BLOCK_FAILED_CHILD));
|
||||||
|
WITH_LOCK(::cs_main, assert((orig_tip->nStatus & BLOCK_FAILED_VALID) == 0));
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
@ -3747,7 +3747,7 @@ bool Chainstate::InvalidateBlock(BlockValidationState& state, CBlockIndex* pinde
|
|||||||
m_blockman.m_dirty_blockindex.insert(invalid_walk_tip);
|
m_blockman.m_dirty_blockindex.insert(invalid_walk_tip);
|
||||||
setBlockIndexCandidates.erase(invalid_walk_tip);
|
setBlockIndexCandidates.erase(invalid_walk_tip);
|
||||||
setBlockIndexCandidates.insert(invalid_walk_tip->pprev);
|
setBlockIndexCandidates.insert(invalid_walk_tip->pprev);
|
||||||
if (invalid_walk_tip->pprev == to_mark_failed && (to_mark_failed->nStatus & BLOCK_FAILED_VALID)) {
|
if (invalid_walk_tip == to_mark_failed->pprev && (to_mark_failed->nStatus & BLOCK_FAILED_VALID)) {
|
||||||
// We only want to mark the last disconnected block as BLOCK_FAILED_VALID; its children
|
// We only want to mark the last disconnected block as BLOCK_FAILED_VALID; its children
|
||||||
// need to be BLOCK_FAILED_CHILD instead.
|
// need to be BLOCK_FAILED_CHILD instead.
|
||||||
to_mark_failed->nStatus = (to_mark_failed->nStatus ^ BLOCK_FAILED_VALID) | BLOCK_FAILED_CHILD;
|
to_mark_failed->nStatus = (to_mark_failed->nStatus ^ BLOCK_FAILED_VALID) | BLOCK_FAILED_CHILD;
|
||||||
@ -3779,11 +3779,13 @@ bool Chainstate::InvalidateBlock(BlockValidationState& state, CBlockIndex* pinde
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark pindex (or the last disconnected block) as invalid, even when it never was in the main chain
|
// Mark pindex as invalid if it never was in the main chain
|
||||||
to_mark_failed->nStatus |= BLOCK_FAILED_VALID;
|
if (!pindex_was_in_chain && !(pindex->nStatus & BLOCK_FAILED_MASK)) {
|
||||||
m_blockman.m_dirty_blockindex.insert(to_mark_failed);
|
pindex->nStatus |= BLOCK_FAILED_VALID;
|
||||||
setBlockIndexCandidates.erase(to_mark_failed);
|
m_blockman.m_dirty_blockindex.insert(pindex);
|
||||||
m_chainman.m_failed_blocks.insert(to_mark_failed);
|
setBlockIndexCandidates.erase(pindex);
|
||||||
|
m_chainman.m_failed_blocks.insert(pindex);
|
||||||
|
}
|
||||||
|
|
||||||
// If any new blocks somehow arrived while we were disconnecting
|
// If any new blocks somehow arrived while we were disconnecting
|
||||||
// (above), then the pre-calculation of what should go into
|
// (above), then the pre-calculation of what should go into
|
||||||
@ -3826,8 +3828,9 @@ void Chainstate::SetBlockFailureFlags(CBlockIndex* invalid_block)
|
|||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
|
|
||||||
for (auto& [_, block_index] : m_blockman.m_block_index) {
|
for (auto& [_, block_index] : m_blockman.m_block_index) {
|
||||||
if (block_index.GetAncestor(invalid_block->nHeight) == invalid_block && !(block_index.nStatus & BLOCK_FAILED_MASK)) {
|
if (invalid_block != &block_index && block_index.GetAncestor(invalid_block->nHeight) == invalid_block) {
|
||||||
block_index.nStatus |= BLOCK_FAILED_CHILD;
|
block_index.nStatus = (block_index.nStatus & ~BLOCK_FAILED_VALID) | BLOCK_FAILED_CHILD;
|
||||||
|
m_blockman.m_dirty_blockindex.insert(&block_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user