-
Notifications
You must be signed in to change notification settings - Fork 37.7k
Fix block index inconsistency in InvalidateBlock() #16849
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix block index inconsistency in InvalidateBlock() #16849
Conversation
See #16444 (comment) for additional background. |
// Instead, consider only non-active-chain blocks that have at | ||
// least as much work as where we expect the new tip to end up. | ||
if (!m_chain.Contains(candidate) && | ||
!CBlockIndexWorkComparator()(candidate, pindex->pprev) && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't this potentially omit candidate
s with equal work as pindex->pprev
(depending on nSequenceId/pointer address)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this exactly matches the test in CheckBlockIndex()
:
Line 4604 in 1985c4e
if (!CBlockIndexWorkComparator()(pindex, m_chain.Tip()) && pindexFirstNeverProcessed == nullptr) { |
Previously, we could release cs_main while leaving the block index in a state that would fail CheckBlockIndex, because setBlockIndexCandidates was not being fully populated before releasing cs_main.
bfd4fde
to
2a4e60b
Compare
The only remaining case I've thought of that is unaddressed is if a new block were to arrive while InvalidateBlock() is running that (a) builds off a chain tip that is not being invalidated and (b) has less work than the current tip at the time the block is received, then we might still end up in a state that is temporarily inconsistent. I left in the old code that cleans up before returning as a belt-and-suspenders to ensure that this case is handled the same as before. As this is an essentially unobservable bug (outside of travis) to begin with, I'm not sure it would be worth fixing this any further beyond documenting the situation. |
ACK 2a4e60b. Ran tests, reviewed code, inspected behavior while manually testing |
2a4e60b Fix block index inconsistency in InvalidateBlock() (Suhas Daftuar) Pull request description: Previously, we could release `cs_main` while leaving the block index in a state that would fail `CheckBlockIndex()`, because `setBlockIndexCandidates` was not being fully populated before releasing `cs_main`. ACKs for top commit: TheBlueMatt: utACK 2a4e60b. I also discovered another issue in InvalidateBlock while reviewing, see #16856. Sjors: ACK 2a4e60b. Tested on top of #16899. Also tested `invalidateblock` with `-checkblockindex=1`. fjahr: ACK 2a4e60b. Ran tests, reviewed code, inspected behavior while manually testing `invalidateblock`. Tree-SHA512: ced12f9dfff0d413258c709921543fb154789898165590b30d1ee0cdc72863382f189744f7669a7c924d3689a1cc623efdf4e5ae3efc60054572c1e6826de612
2a4e60b Fix block index inconsistency in InvalidateBlock() (Suhas Daftuar) Pull request description: Previously, we could release `cs_main` while leaving the block index in a state that would fail `CheckBlockIndex()`, because `setBlockIndexCandidates` was not being fully populated before releasing `cs_main`. ACKs for top commit: TheBlueMatt: utACK 2a4e60b. I also discovered another issue in InvalidateBlock while reviewing, see bitcoin#16856. Sjors: ACK 2a4e60b. Tested on top of bitcoin#16899. Also tested `invalidateblock` with `-checkblockindex=1`. fjahr: ACK 2a4e60b. Ran tests, reviewed code, inspected behavior while manually testing `invalidateblock`. Tree-SHA512: ced12f9dfff0d413258c709921543fb154789898165590b30d1ee0cdc72863382f189744f7669a7c924d3689a1cc623efdf4e5ae3efc60054572c1e6826de612
Summary: Future [[bitcoin/bitcoin#16849 | PR16849]] (D7204) introduces locking `m_cs_chainstate` to their version of `InvalidateBlock`. Our codepath for that is shared by `ParkBlock`, `InvalidateBlock` and `FinalizeBlock`, so having all three be members of `CChainState` (`FinalizeBlock` already is) makes sense. Also made `UnwindBlock` private since it's not supposed to be called by just anyone, rather by stuff that knows what they're doing -, and moved `FinalizeBlock` implementation to be closer to the other two since that makes more sense. Test Plan: cmake .. -DCMAKE_BUILD_TYPE=Debug -GNinja ninja check check-functional Reviewers: #bitcoin_abc, deadalnix Reviewed By: #bitcoin_abc, deadalnix Differential Revision: https://reviews.bitcoinabc.org/D7203
Summary: Fix block index inconsistency in InvalidateBlock() (Suhas Daftuar) Pull request description: Previously, we could release `cs_main` while leaving the block index in a state that would fail `CheckBlockIndex()`, because `setBlockIndexCandidates` was not being fully populated before releasing `cs_main`. --- Note: Because of the way our version of "InvalidateBlock" is in the codepath for Park, Invalidate and FinalizeBlock, the lock for m_cs_chainstate needs to appear in additional places. Backport of Core [[bitcoin/bitcoin#16849 | PR16849]] Depends on D6956 Test Plan: cmake -DCMAKE_BUILD_TYPE=Debug -DNinja ninja check check-functional Reviewers: #bitcoin_abc, deadalnix Reviewed By: #bitcoin_abc, deadalnix Subscribers: deadalnix Differential Revision: https://reviews.bitcoinabc.org/D7204
2a4e60b Fix block index inconsistency in InvalidateBlock() (Suhas Daftuar) Pull request description: Previously, we could release `cs_main` while leaving the block index in a state that would fail `CheckBlockIndex()`, because `setBlockIndexCandidates` was not being fully populated before releasing `cs_main`. ACKs for top commit: TheBlueMatt: utACK 2a4e60b. I also discovered another issue in InvalidateBlock while reviewing, see bitcoin#16856. Sjors: ACK 2a4e60b. Tested on top of bitcoin#16899. Also tested `invalidateblock` with `-checkblockindex=1`. fjahr: ACK 2a4e60b. Ran tests, reviewed code, inspected behavior while manually testing `invalidateblock`. Tree-SHA512: ced12f9dfff0d413258c709921543fb154789898165590b30d1ee0cdc72863382f189744f7669a7c924d3689a1cc623efdf4e5ae3efc60054572c1e6826de612
2a4e60b Fix block index inconsistency in InvalidateBlock() (Suhas Daftuar) Pull request description: Previously, we could release `cs_main` while leaving the block index in a state that would fail `CheckBlockIndex()`, because `setBlockIndexCandidates` was not being fully populated before releasing `cs_main`. ACKs for top commit: TheBlueMatt: utACK 2a4e60b. I also discovered another issue in InvalidateBlock while reviewing, see bitcoin#16856. Sjors: ACK 2a4e60b. Tested on top of bitcoin#16899. Also tested `invalidateblock` with `-checkblockindex=1`. fjahr: ACK 2a4e60b. Ran tests, reviewed code, inspected behavior while manually testing `invalidateblock`. Tree-SHA512: ced12f9dfff0d413258c709921543fb154789898165590b30d1ee0cdc72863382f189744f7669a7c924d3689a1cc623efdf4e5ae3efc60054572c1e6826de612
Previously, we could release
cs_main
while leaving the block index in a statethat would fail
CheckBlockIndex()
, becausesetBlockIndexCandidates
was not beingfully populated before releasing
cs_main
.