-
Notifications
You must be signed in to change notification settings - Fork 38.7k
Ensure nStatus is set properly for all invalid blocks #12407
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
Ensure nStatus is set properly for all invalid blocks #12407
Conversation
|
Hm: this changeset is failing tests that initially transmit a block with unexpected witness data (which gets rejected) and then retransmit without witness data for expected acceptance, but we get hung up on an existing Is it worth special-casing out Is the bookkeeping this PR wants to do even worth it? I guess we could just lump long invalid forks in with long headers-only forks, but that doesn't seem great either... |
|
You can only mark a block as invalid when fPossibleCorruption is not set in the validation status. |
fe6c253 to
5ed8fe9
Compare
|
Ah good point, thanks @sipa. That seems to have fixed it. |
5ed8fe9 to
7bd2d85
Compare
dcousens
left a comment
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.
utACK 7bd2d85906f12661efb9e0747d8bbd30530d149d
7bd2d85 to
869f981
Compare
|
I've rebased this changeset, removing the code that's now in #12431 as well as the semi-related log statement. I've also DRY'd up parts of validation which set This change should only be merged after #12431 since this will exercise the bug that PR fixes. |
869f981 to
6af17e4
Compare
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.
Slight utACK 6af17e40890651e5e5f5968a1a131c6a48ce998c. Slight because I don't know all the implications of adding the new InvalidBlockFound calls.
New test code looks great.
I'd find the main commit ("Do the proper InvalidateBlock bookkeeping for DoSy blocks") easier to understand if it were split up, with the actual behavior change in ProcessNewBlock in one commit, and all the documentation/assertlock/DRY cleanup stuff in a different commit or set of commits.
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.
In commit "[tests] Add utility for generating bad coinbase transactions"
I think:
(r.index, tip for r, tip in zip(rpc_connections, tips))would be clearer than:
(rpc_connections[i].index, tip for i, tip in enumerate(tips))but you should ignore this suggestion if you prefer enumerate.
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.
Agree, will do.
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.
In commit "[tests] Add utility for generating bad coinbase transactions"
Could drop kwargs assignment with
return create_coinbase(*args, **kwargs. txin=CTxIn(...))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.
Ah yep, that's better.
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.
Ah, Python 3.4 doesn't support this syntax (which is what we run on Travis). Will have to revert this.
src/validation.cpp
Outdated
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.
In commit "Do the proper InvalidateBlock bookkeeping for DoSy blocks"
Duplicating the CorruptionPossible check here seems unnecessarily confusing and fragile to me, though perhaps there's an advantage I'm not seeing.
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.
Agree in hindsight that this was overly paranoid. Will remove.
6af17e4 to
7d6e014
Compare
jamesob
left a comment
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.
@ryanofsky thanks very much for the review and good feedback. I've incorporated your recommendations and split out the last commit into two: one for the actual behavioral change and one for the cleanup.
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.
Ah yep, that's better.
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.
Agree, will do.
src/validation.cpp
Outdated
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.
Agree in hindsight that this was overly paranoid. Will remove.
7d6e014 to
bdfe29e
Compare
src/validation.cpp
Outdated
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.
This now happens in the InvalidBlockFound call above.
|
Needs rebase to fix travis (sorry) |
bdfe29e to
a12ce0d
Compare
|
Rebased. |
|
Slight re-utACK a12ce0dde462911bb702070d31ed28ba32353a05. Again someone more knowledgeable than me should review safety of adding new Changes since last review were rebase, python cleanups, adding CorruptionPossible log print, and some suggestions from the last review. You may want to update PR description since it will become part of git history if this is merged. |
f98b543 Only call NotifyBlockTip when the active chain changes (James O'Beirne) 152b7fb [tests] Add a (failing) test for waitforblockheight (James O'Beirne) Pull request description: This is a subset of the more controversial #12407, but this also adds a test demonstrating the bug. In InvalidateBlock, we're calling NotifyBlockTip with the now-invalid block's prev regardless of what chain the ancestor block is on. This could create numerous issues, but it at least screws up `waitforblockheight` (or anything else relying on `rpc/blockchain.cpp:latestblock`) when InvalidateBlock is called on a block not in chainActive, which can happen via RPC. Only call NotifyBlockTip when the block being marked invalid is on the active chain. Tree-SHA512: 9a54fe5e8c7eb489daf5df4483c0986129e871e2ca931a456ba869ecb5d5a8d4f7bd27ccc9e711e9292c9ed79ddef896c85d0e81fc76883503e327995b0e914f
src/validation.cpp
Outdated
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.
Why log this unconditionally? I think it may be trivial to cause someone's logfile to be filled with these.
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.
Yep, that's a good point. I'll change this into a comment.
c478e41 to
06a7c1e
Compare
|
Thanks @ryanofsky and @sipa for the re-review. I've incorporated @sipa's change (remove unconditional log in
|
b3eec70 to
16d75a0
Compare
|
Any hope of a concept ACK/NACK on this from @sipa @TheBlueMatt @sdaftuar? |
src/validation.cpp
Outdated
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.
The usual convention for method documentation in this project is to add the comment in the class definition, not above the implementation. This makes it easier to read the API documentation in one place when looking at the class.
That said, as both are in the .cpp file for this class I don't think that's much of an issue here.
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.
Fixed, thanks.
|
Needs rebase |
Also adds a small logging clarification for `sync_blocks`. Includes feedback from @ryanofsky.
…blocks Ensure that we mark any block which merits a DoS response as invalid, as well as its associated chain tip. This will become important for detecting and warning about long invalid forks.
When we receive a block which causes a DoS response, ensure that we mark its status as "invalid" in `mapBlockIndex`. This is necessary for detecting and warning about forks which are invalid but long.
79f4e5f to
ba1e6a0
Compare
Consolidate BLOCK_FAILED_VALID nStatus updates to use InvalidBlockFound. Clean up InvalidBlockFound for a defensive early exit if called when corruption is possible.
ba1e6a0 to
29bd480
Compare
|
Rebased and addressed @laanwj's feedback. |
| Needs rebase |
|
Closing this; isn't getting much traction and no point in rebasing if that's the case. |
Summary: f98b543 Only call NotifyBlockTip when the active chain changes (James O'Beirne) 152b7fb [tests] Add a (failing) test for waitforblockheight (James O'Beirne) Pull request description: This is a subset of the more controversial bitcoin/bitcoin#12407, but this also adds a test demonstrating the bug. In InvalidateBlock, we're calling NotifyBlockTip with the now-invalid block's prev regardless of what chain the ancestor block is on. This could create numerous issues, but it at least screws up `waitforblockheight` (or anything else relying on `rpc/blockchain.cpp:latestblock`) when InvalidateBlock is called on a block not in chainActive, which can happen via RPC. Only call NotifyBlockTip when the block being marked invalid is on the active chain. Tree-SHA512: 9a54fe5e8c7eb489daf5df4483c0986129e871e2ca931a456ba869ecb5d5a8d4f7bd27ccc9e711e9292c9ed79ddef896c85d0e81fc76883503e327995b0e914f Backport of Core PR12431 https://github.com/bitcoin/bitcoin/pull/12431/files Completes T680 Test Plan: ``` make check test_runner.py ``` Reviewers: #bitcoin_abc, deadalnix Reviewed By: #bitcoin_abc, deadalnix Differential Revision: https://reviews.bitcoinabc.org/D3748
f98b543 Only call NotifyBlockTip when the active chain changes (James O'Beirne) 152b7fb [tests] Add a (failing) test for waitforblockheight (James O'Beirne) Pull request description: This is a subset of the more controversial bitcoin#12407, but this also adds a test demonstrating the bug. In InvalidateBlock, we're calling NotifyBlockTip with the now-invalid block's prev regardless of what chain the ancestor block is on. This could create numerous issues, but it at least screws up `waitforblockheight` (or anything else relying on `rpc/blockchain.cpp:latestblock`) when InvalidateBlock is called on a block not in chainActive, which can happen via RPC. Only call NotifyBlockTip when the block being marked invalid is on the active chain. Tree-SHA512: 9a54fe5e8c7eb489daf5df4483c0986129e871e2ca931a456ba869ecb5d5a8d4f7bd27ccc9e711e9292c9ed79ddef896c85d0e81fc76883503e327995b0e914f
Summary: f98b54352 Only call NotifyBlockTip when the active chain changes (James O'Beirne) 152b7fb25 [tests] Add a (failing) test for waitforblockheight (James O'Beirne) Pull request description: This is a subset of the more controversial bitcoin/bitcoin#12407, but this also adds a test demonstrating the bug. In InvalidateBlock, we're calling NotifyBlockTip with the now-invalid block's prev regardless of what chain the ancestor block is on. This could create numerous issues, but it at least screws up `waitforblockheight` (or anything else relying on `rpc/blockchain.cpp:latestblock`) when InvalidateBlock is called on a block not in chainActive, which can happen via RPC. Only call NotifyBlockTip when the block being marked invalid is on the active chain. Tree-SHA512: 9a54fe5e8c7eb489daf5df4483c0986129e871e2ca931a456ba869ecb5d5a8d4f7bd27ccc9e711e9292c9ed79ddef896c85d0e81fc76883503e327995b0e914f Backport of Core PR12431 https://github.com/bitcoin/bitcoin/pull/12431/files Completes T680 Test Plan: ``` make check test_runner.py ``` Reviewers: #bitcoin_abc, deadalnix Reviewed By: #bitcoin_abc, deadalnix Differential Revision: https://reviews.bitcoinabc.org/D3748
Summary: f98b54352 Only call NotifyBlockTip when the active chain changes (James O'Beirne) 152b7fb25 [tests] Add a (failing) test for waitforblockheight (James O'Beirne) Pull request description: This is a subset of the more controversial bitcoin/bitcoin#12407, but this also adds a test demonstrating the bug. In InvalidateBlock, we're calling NotifyBlockTip with the now-invalid block's prev regardless of what chain the ancestor block is on. This could create numerous issues, but it at least screws up `waitforblockheight` (or anything else relying on `rpc/blockchain.cpp:latestblock`) when InvalidateBlock is called on a block not in chainActive, which can happen via RPC. Only call NotifyBlockTip when the block being marked invalid is on the active chain. Tree-SHA512: 9a54fe5e8c7eb489daf5df4483c0986129e871e2ca931a456ba869ecb5d5a8d4f7bd27ccc9e711e9292c9ed79ddef896c85d0e81fc76883503e327995b0e914f Backport of Core PR12431 https://github.com/bitcoin/bitcoin/pull/12431/files Completes T680 Test Plan: ``` make check test_runner.py ``` Reviewers: #bitcoin_abc, deadalnix Reviewed By: #bitcoin_abc, deadalnix Differential Revision: https://reviews.bitcoinabc.org/D3748
Summary: f98b54352 Only call NotifyBlockTip when the active chain changes (James O'Beirne) 152b7fb25 [tests] Add a (failing) test for waitforblockheight (James O'Beirne) Pull request description: This is a subset of the more controversial bitcoin/bitcoin#12407, but this also adds a test demonstrating the bug. In InvalidateBlock, we're calling NotifyBlockTip with the now-invalid block's prev regardless of what chain the ancestor block is on. This could create numerous issues, but it at least screws up `waitforblockheight` (or anything else relying on `rpc/blockchain.cpp:latestblock`) when InvalidateBlock is called on a block not in chainActive, which can happen via RPC. Only call NotifyBlockTip when the block being marked invalid is on the active chain. Tree-SHA512: 9a54fe5e8c7eb489daf5df4483c0986129e871e2ca931a456ba869ecb5d5a8d4f7bd27ccc9e711e9292c9ed79ddef896c85d0e81fc76883503e327995b0e914f Backport of Core PR12431 https://github.com/bitcoin/bitcoin/pull/12431/files Completes T680 Test Plan: ``` make check test_runner.py ``` Reviewers: #bitcoin_abc, deadalnix Reviewed By: #bitcoin_abc, deadalnix Differential Revision: https://reviews.bitcoinabc.org/D3748
In trying to fix the fork warning code (
validation.cpp:CheckForkWarningConditions*), it became apparent that we are marking some (but not all) invalid blocks as invalid (vianStatus) when they are received and subsequently dropped. The fact that we never mark some invalid blocks as such prevents us from e.g. detecting and warning on invalid chains with significant work.This change has
ProcessNewBlockcallInvalidateBlockon the invalid block to do the expected bookkeeping inmapBlockIndexbefore dropping the block.This change also consolidates the setting of CBlockIndex's
nStatus |= BLOCK_FAILED_VALIDto a single function (InvalidBlockFound) since there's peripheral bookkeeping (e.g.g_failed_blocks.insert()) that we want to do consistently but is duplicated in some places or not done in other cases when it apparently should be.One such replacement with InvalidBlockFound ensures addition of invalid blocks to
g_failed_blocksand so (in theory) reduces CPU burden when being spammed with descendants of an invalid block, since we no longer have to walkmapBlockIndexto determine its invalidity. Based on reading usage ofg_failed_blocksI can't tell if this savings is real, but in any case it seems worthwhile to keep that set consistent (i.e. 1-1 with blocks marked BLOCK_FAILED_VALID since last restart).