-
Notifications
You must be signed in to change notification settings - Fork 38.6k
Rewrite DoS interface between validation and net_processing #15141
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
Rewrite DoS interface between validation and net_processing #15141
Conversation
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
|
Concept ACK |
|
Concept ACK; I'll review for changes in behavior for specific validation reasons later. |
|
Concept ACK |
jnewbery
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.
I've reviewed a5415e8. A few nits/questions inline.
src/validation.cpp
Outdated
| // failed). | ||
| if (GetBlockWeight(block) > MAX_BLOCK_WEIGHT) { | ||
| return state.DoS(100, false, REJECT_INVALID, "bad-blk-weight", false, strprintf("%s : weight limit failed", __func__)); | ||
| // We can call this a consensus failure as any data-providers who provided |
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 seems entirely obvious and not requiring a comment to me, which makes me think there's some subtlety I've missed. Is this just saying that if we receive a block with witness data, it should be valid-according-to-BIP141?
Pedantic nit: I'd also avoid talking about 'data-providers' in validation.cpp. After this PR, validation should be unconcerned with data-providers and only be validating blocks based on the block data.
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 comment is contrasting a CONSENSUS failure from a RECENT_CONSENSUS_CHANGE -- I think in @TheBlueMatt's original PR he had some validation failures marked as RECENT_CONSENSUS_CHANGE, but eventually we decided to switch them all out (and reserve RECENT_CONSENSUS_CHANGE as something we might do in the future).
I think I agree with you philosophically that validation ought not be very concerned with 'data providers', but I think the ValidationReasons interface is also driven by the needs of net_processing, so sometimes we may need to explain reasons that maybe don't make sense in a totally neutral validation library because our application requires it. RECENT_CONSENSUS_CHANGE is one such possible example (though we're not using it in this PR and I am not sure we ever will); the BLOCK_INVALID_HEADER enum I added is another (net_processing needs to be able to distinguish some headers failures from others, in order to maintain the current ban behavior).
Anyway I'll update this comment to be clearer.
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 think this comment is justifying upgrading the (at the time recent) segwit test from a RECENT_CONSENSUS_CHANGE to just CONSENSUS_CHANGE, the reason being that either you've got an old client that didn't provide segwit data -- in which case this test won't trigger because the bad-blk-length test will already have failed -- or it is providing segwit data but doing it wrong, in which case there's no reason to use the more forgiving RECENT version. So I think just dropping the comment (now that segwit isn't recent) is fine, fwiw.
ajtowns
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.
Looks good to me; haven't fully looked through "Use new reason-based DoS/disconnect logic instead of state.nDoS" though.
| } | ||
| bool CorruptionPossible() const { | ||
| return corruptionPossible; | ||
| } |
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.
Maybe having inline bool CorruptionPossible() const { return reason == BLOCK_MUTATED; } would make for nicer code elsewhere?
| // Only the witness is missing, so the transaction itself may be fine. | ||
| state.Invalid(ValidationInvalidReason::TX_WITNESS_MUTATED, false, | ||
| state.GetRejectCode(), state.GetRejectReason(), state.GetDebugMessage()); | ||
| state.SetCorruptionPossible(); |
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 change isn't a clean refactor -- !state.CorruptionPossible() would have returned false after this, but its replacement in this commit (ie, state.GetReason() != BLOCK_MUTATED) will return true. I think this is okay though, since CorruptionPossible() is only checked for block updates, and this just deals with mempool tx's, and the uses of state.CorruptionPossible() that this would have effected were already changed to state.GetReason() != TX_WITNESS_MUTATED in an earlier commit.
| // "checked-status" (in the CBlock?). CBlock should be able to | ||
| // check its own merkle root and cache that check. | ||
| if (state.CorruptionPossible()) | ||
| if (state.GetReason() == ValidationInvalidReason::BLOCK_MUTATED) |
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.
Seems like this change could be squashed into "Remove references to CValidationState's DoS and CorruptionPossible" ?
ryanofsky
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.
Started reviewing this, but IMO, the way this PR is structured makes it difficult to verify that it doesn't unintentionally change behavior.
I think a nicer way to write this would be to have one commit adding empty ValidationInvalidReason, MayResultInDisconnect, and MaybePunishNode definitions, and adding a state.Invalid() overload taking an optional ValidationInvalidReason argument. Then have a sequence of small followup commits which each add a few enum values at a time, passing them through state.Invalid() and translating them into Misbehaving() calls, where each commit is self contained and is deals with related reasons so it is easy to spot and understand changes in behavior.
If this is a bad idea, or too much work, I'd be ok with trying to review this PR as it is, but I wanted to suggest something to be able to have more confidence in it, and to maybe make it easier to find other reviewers.
- a5415e8 Add useful-for-dos "reason" field to CValidationState (1/8)
- 33213ad Add functions to convert CValidationInterface's reason to DoS info (2/8)
- 6bdc449 Use new reason-based DoS/disconnect logic instead of state.nDoS (3/8)
- 963699d Use state reason field to check for collisions in cmpctblocks (4/8)
- 06e4247 Prep for scripted-diff by removing some \ns which annoy sed. (5/8)
- 8131896 scripted-diff: Remove DoS calls to CValidationState (6/8)
- 6ee2c45 Remove references to CValidationState's DoS and CorruptionPossible (7/8)
- 94874dd Update some comments in validation.cpp as we arent doing DoS there (8/8)
src/consensus/tx_verify.cpp
Outdated
| // Basic checks that don't depend on any context | ||
| if (tx.vin.empty()) | ||
| return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty"); | ||
| return state.DoS(10, ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-vin-empty"); |
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 "Add useful-for-dos "reason" field to CValidationState" (a5415e8)
Note: word-diff is useful here to review new function arguments:
git log -p -n1 -U0 --word-diff-regex=. a5415e85caaf2f5a77d6bae9574bb6d21139ee34| fSpendsCoinbase, nSigOpsCost, lp); | ||
| unsigned int nSize = entry.GetTxSize(); | ||
|
|
||
| // Check that the transaction doesn't have an excessive number of |
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 "Add useful-for-dos "reason" field to CValidationState" (a5415e8):
Why remove this 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.
Good question.
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.
Note that MAX_BLOCK_SIGOPS has been renamed / replaced by MAX_STANDARD_TX_SIGOPS_COST as part of SegWit in 2b1f6f9. In addition to this comment, MAX_BLOCK_SIGOPS is also still mentioned in the function test framework. But that doesn't explain why the comment can be removed.
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 think this comment is not very helpful. It was originally added in #4150, and in the review on that PR people complained that the phrasing in this comment is confusing ("invalid rather than merely non-standard" - huh?).
If reviewers prefer it, then I can just improve this comment rather than delete it -- it just seems to me like the code reads just fine on its own.
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.
MAX_BLOCK_SIGOPS is replaced by MAX_BLOCK_SIGOPS_COST (which is just multiplied by the witness scale factor of 4) as part of segwit. MAX_STANDARD_TX_SIGOPS_COST is just a separate rule at the relay/mempool level saying "you have to use at least 5 tx's to hit the sigop limit".
I agree that the comment's just confusing given how we understand "invalid" (breaks consensus rules) vs "non-standard" (not interesting for mempool/relay, but not too strongly punished either).
src/validation.cpp
Outdated
| if (state.GetReason() == ValidationInvalidReason::TX_MISSING_INPUTS) { | ||
| // CheckTxInputs may return MISSING_INPUTS but we can't return that, as | ||
| // it's not defined for a block, so we reset the reason flag to CONSENSUS here. | ||
| state.DoS(state.GetDoS(), ValidationInvalidReason::CONSENSUS, false, |
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 "Add useful-for-dos "reason" field to CValidationState" (a5415e8)
This seems like it is doubling the state.nDoS level, in addition to updating the reason enum:
bitcoin/src/consensus/validation.h
Line 96 in a5415e8
| nDoS += level; |
Would suggest replacing this change something more straightforward like state.UpdateReason(ValidationInvalidReason::CONSENSUS)
src/validation.cpp
Outdated
| // but we can't return that, as it's not defined for a block, so | ||
| // we reset the reason flag to CONSENSUS here. | ||
| // (note that this may not be the case until we add additional | ||
| // soft-fork flags to our script flags, in which case we need to |
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 "Add useful-for-dos "reason" field to CValidationState" (a5415e8)
Extra space on this line
src/validation.cpp
Outdated
| // soft-fork flags to our script flags, in which case we need to | ||
| // be careful to differentiate RECENT_CONSENSUS_CHANGE and | ||
| // CONSENSUS) | ||
| state.DoS(state.GetDoS(), ValidationInvalidReason::CONSENSUS, false, |
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 "Add useful-for-dos "reason" field to CValidationState" (a5415e8)
This also seems to double state.nDoS.
src/validation.cpp
Outdated
| if (!Consensus::CheckTxInputs(tx, state, view, pindex->nHeight, txfee)) { | ||
| if (state.GetReason() == ValidationInvalidReason::TX_MISSING_INPUTS) { | ||
| // CheckTxInputs may return MISSING_INPUTS but we can't return that, as | ||
| // it's not defined for a block, so we reset the reason flag to CONSENSUS 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.
In commit "Add useful-for-dos "reason" field to CValidationState" (a5415e8)
Is there a check for the requirement that MISSING_INPUTS is not used for a block? I would expect to see an assert(reason != MISSING_INPUTS) or assert(ValidForBlock(reason)) or something like that somewhere.
| // Check transactions | ||
| for (const auto& tx : block.vtx) | ||
| if (!CheckTransaction(*tx, state, true)) | ||
| return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(), |
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 "Add useful-for-dos "reason" field to CValidationState" (a5415e8)
Note: I guess this line used to set state.corruptionPossible = false but no longer does.
bitcoin/src/consensus/validation.h
Lines 54 to 58 in cebe910
| bool Invalid(bool ret = false, | |
| unsigned int _chRejectCode=0, const std::string &_strRejectReason="", | |
| const std::string &_strDebugMessage="") { | |
| return DoS(0, ret, _chRejectCode, _strRejectReason, false, _strDebugMessage); | |
| } |
New way seems 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.
So if I understand this correctly:
state.Invalid()just callsstate.DoS() withlevel=0andcorruptionIn=false` (default).CheckTransaction()can currently fail in various ways, calling:state.DoSwith:level10 or 100: why isn't this higher level a problem?corruptionInnot specified (so defaults tofalse)
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.
level 10 or 100: why isn't this higher level a problem?
@Sjors I don't understand your question -- can you rephrase?
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.
If I understand correctly: the higher level (ie, changing the 10's to 100's in 96cedc8 - the "clean up banning levels" commit) isn't a problem because these failures are all consensus ones, so any reasonable implementation shouldn't be making them. (Except for immature coinbase and missing inputs at the mempool level which are downgraded elsewhere)
| State(it->second.first)->rejects.push_back(reject); | ||
| if (nDoS > 0 && it->second.second) | ||
| Misbehaving(it->second.first, nDoS); | ||
| MaybePunishNode(/*nodeid=*/ it->second.first, state, /*via_compact_block=*/ !it->second.second); |
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 "Use state reason field to check for collisions in cmpctblocks" (963699d)
Since the mapBlockSource bool is now being passed as !via_compact_block, it seems like the field description should mention something about setting it based on whether the source was a compact or full block:
bitcoin/src/net_processing.cpp
Lines 104 to 105 in 6bdc449
| * Set mapBlockSource[hash].second to false if the node should not be | |
| * punished if the block is invalid. |
src/test/txvalidation_tests.cpp
Outdated
| int nDoS; | ||
| BOOST_CHECK_EQUAL(state.IsInvalid(nDoS), true); | ||
| BOOST_CHECK_EQUAL(nDoS, 100); | ||
| BOOST_CHECK_EQUAL(state.IsInvalid(), true); |
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.
We checked state.IsInvalid() a couple of lines earlier, so this addition is redundant.
FWIW, I've had a go at redoing the patchset to try to make the (potential) functionality changes more clear: https://github.com/ajtowns/bitcoin/commits/201901-dosreasons This has (I think) all the behaviour changes first: before introducing the new reason field, along with checks that the implied DoS value for each reason matches the actual DoS values presented/used: which then allows dropping the instance variables: Then the code is changed to use reasons directly: And the now obsolete DoS/etc stuff is dropped: That leaves a couple more things: but finally ends up with the same code as this PR (minus the latest commit anyway). Anyway I think this approach might be easier to review? It could also allow splitting the PR into two -- one making the changes to DoS behaviour but not changing the way DoS works; followed by a second PR that actually adds the Reasons and refactors but doesn't change behaviour. (Proof of concept only: bunches of these commits should probably be combined, commit messages need improvement, and I think I lost a bunch of authorship info) EDIT: I've added an extra commit prior to the DoS->Invalid refactor, namely "5b15205883 Allow use of state.Invalid() for all reasons" that avoids assertions that Invalid() is only used for DoS-level-0 problems failing. That just leaves one test failure in the intermediate commits; feature_block.py fails after the changing the DoS levels but before adding the "reason" code. I think this is due to lowering |
|
Thanks all for the review so far! I'd started taking a stab at rewriting this; I'll continue with my approach to see how it ends up but @ajtowns thank you for your help -- @ryanofsky if you have any thoughts on @ajtowns's rework please let me know, happy to adapt his breakdown and include here if that approach looks good. |
Took a quick look, and I think ajtowns's refactor is great. It's a slightly different approach than I suggested in that the 32747d0746d91a8f63e39cedfb232f8c36b33bc6 commit which starts using reason codes is done all at once instead of incrementally as reasons are added, so it requires a little bit of grepping to verify, but this is easy to do and I think it's a huge improvement. I think it would be best to use ajtown's branch here, unless you've done a lot of work on your own already or see problems I'm missing. |
|
Concept ACK, I will take a closer look once the code is updated per comments above I guess. |
a642744 to
7e0090c
Compare
|
I have redone this along the lines of @ajtowns branch, and cleaned up each commit (I think!) so that each one should be logically correct, pass tests, etc. I've saved the original version of this PR here: https://github.com/sdaftuar/bitcoin/commits/15141.original The diff between the two is pretty small (just some formatting changes that were getting tedious to resolve, and I removed a couple lines that some reviewers had commented on as being unnecessary): Also if this version is not actually easier to review I'm happy to go back to the original or try another approach. |
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.
Started review (will update list below with progress).
- 59ff8e6 Remove redundant state.Invalid() call after CheckTransaction() (1/27)
- e7edc15 drop obsolete comment (2/27)
- f3fd64c [refactor] stateDummy -> orphan_state (3/27)
- 4159f7c [refactor] Use maybepunish etc (4/27)
- bfa94c7 Update comment to reference MaybePunishNode (5/27)
- 70906c5 [refactor] drop IsInvalid(nDoSOut) (6/27)
- 858bae6 set nDoS rather than bumping it (7/27)
- 96cedc8 Clean up banning levels (8/27)
- 6e27c50 === end of functionality changes (9/27)
- ac3873e [refactor] Add useful-for-dos "reason" field to CValidationState (10/27)
- bee1d4f TX_MISSING_INPUTS now has a DoS score of 0 (11/27)
- 95d7de9 ==== start switch to reasons (12/27)
- 6e3332a [refactor] Drop redundant nDoS, corruptionPossible, SetCorruptionPossible (13/27)
- c558eba LookupBlockIndex -> CACHED_INVALID (14/27)
- 8ed1801 CorruptionPossible -> TX_WITNESS_MUTATED (15/27)
- 3048533 CorruptionPossible -> BLOCK_MUTATED (16/27)
- 3466993 [refactor] Use Reasons directly instead of DoS codes (17/27)
- 9dd6fc1 Fix handling of invalid headers (18/27)
- 5e85f54 ==== drop nDoS info (19/27)
- e5f43f3 Allow use of state.Invalid() for all reasons (20/27)
- 5507fea [refactor] Prep for scripted-diff by removing some \ns which annoy sed. (21/27)
- c664daf scripted-diff: Remove DoS calls to CValidationState (22/27)
- 8e4590e [refactor] Drop unused state.DoS(), state.GetDoS(), state.CorruptionPossible() (23/27)
- f494f78 ==== cleanup (24/27)
- 9b7978e [refactor] Update some comments in validation.cpp as we arent doing DoS there (25/27)
- 99d9689 [refactor] swap if/else order (26/27)
- 7682566 nit: reason -> m_reason (27/27)
src/net_processing.cpp
Outdated
| static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool via_compact_block, const std::string& message = "") { | ||
| int nDoS = state.GetDoS(); | ||
| if (nDoS > 0 && !via_compact_block) { | ||
| LOCK(cs_main); |
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 "[refactor] Use maybepunish etc" (8226bed)
Note: This acquires lock recursively in PeerLogicValidation::BlockChecked. Seems fine, but just wanted to note it wasn't happening before.
7e0090c to
4e1ae68
Compare
|
I addressed @ryanofsky's comments so far (which rewrote the git history, since one of the commit messages changed, so I also squashed in a comment change as well). Previous version of this PR is now here: https://github.com/sdaftuar/bitcoin/commits/15141.1. |
|
This needs a simple rebase, but can I get concept ACK/NACK from more reviewers on whether the reworked form of this PR (which broke things up into many more commits) is preferable compared to the original formulation? |
|
I haven't reviewed the last few commits yet (only up to "[refactor] Use Reasons directly instead of DoS codes"), but so far the structure is very clear. Concept ACK on that. |
fd047f7 to
7682566
Compare
|
One overall comment: it seems there is a subset of |
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.
Mostly finished reviewing this, just a few more commits left: #15141 (review)
src/consensus/tx_verify.cpp
Outdated
| // Basic checks that don't depend on any context | ||
| if (tx.vin.empty()) | ||
| return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty"); | ||
| return state.DoS(100, false, REJECT_INVALID, "bad-txns-vin-empty"); |
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 "Clean up banning levels" (96cedc8)
Note: this is "Txn with empty vin/vout or null prevouts move from 10 DoS points to 100"
src/consensus/tx_verify.cpp
Outdated
| return state.DoS(100, false, REJECT_INVALID, "bad-txns-vin-empty"); | ||
| if (tx.vout.empty()) | ||
| return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty"); | ||
| return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-empty"); |
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 "Clean up banning levels" (96cedc8)
Note: this is "Txn with empty vin/vout or null prevouts move from 10 DoS points to 100"
src/consensus/tx_verify.cpp
Outdated
| for (const auto& txin : tx.vin) | ||
| if (txin.prevout.IsNull()) | ||
| return state.DoS(10, false, REJECT_INVALID, "bad-txns-prevout-null"); | ||
| return state.DoS(100, false, REJECT_INVALID, "bad-txns-prevout-null"); |
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 "Clean up banning levels" (96cedc8)
Note: this is "Txn with empty vin/vout or null prevouts move from 10 DoS points to 100"
src/consensus/tx_verify.cpp
Outdated
| return state.Invalid(false, | ||
| REJECT_INVALID, "bad-txns-premature-spend-of-coinbase", | ||
| return state.DoS(100, false, | ||
| REJECT_INVALID, "bad-txns-premature-spend-of-coinbase", false, |
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 "Clean up banning levels" (96cedc8)
Note: this is "Inclusion of a premature coinbase spend now results in a ban"
src/validation.cpp
Outdated
| if (setConflicts.count(hashAncestor)) | ||
| { | ||
| return state.DoS(10, false, | ||
| return state.DoS(100, false, |
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 "Clean up banning levels" (96cedc8)
Note: this is "Loose transactions with a dependency loop now result in a ban instead of 10 DoS points"
src/validation.cpp
Outdated
| for (const auto& tx : block.vtx) { | ||
| if (!IsFinalTx(*tx, nHeight, nLockTimeCutoff)) { | ||
| return state.DoS(10, false, REJECT_INVALID, "bad-txns-nonfinal", false, "non-final transaction"); | ||
| return state.DoS(100, false, REJECT_INVALID, "bad-txns-nonfinal", false, "non-final transaction"); |
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 "Clean up banning levels" (96cedc8)
Note: this is "Inclusion of non-final transactions in a block now results in a ban"
src/validation.cpp
Outdated
| !CheckInputs(tx, stateDummy, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, false, txdata)) { | ||
| // Only the witness is missing, so the transaction itself may be fine. | ||
| state.SetCorruptionPossible(); | ||
| state.DoS(0, ValidationInvalidReason::TX_WITNESS_MUTATED, false, |
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 "[refactor] Add useful-for-dos "reason" field to CValidationState" (ac3873e)
Passing state.GetDoS() instead of 0 might make it clearer behavior isn't changing.
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 agree that this is confusing. IMO, even better than passing in state.GetDoS() to state.DoS() would be:
state.Invalid(ValidationInvalidReason::TX_WITNESS_MUTATED, false, state.GetRejectCode(), state.GetRejectReason(), state.GetDebugMessage());
state.SetCorruptionPossible();
src/consensus/validation.h
Outdated
| case ValidationInvalidReason::RECENT_CONSENSUS_CHANGE: | ||
| case ValidationInvalidReason::BLOCK_BAD_TIME: | ||
| case ValidationInvalidReason::TX_NOT_STANDARD: | ||
| case ValidationInvalidReason::TX_MISSING_INPUTS: |
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 "TX_MISSING_INPUTS now has a DoS score of 0" (bee1d4f)
Not sure, but it seems like it might be nice to have a comment here saying TX_MISSING_INPUTS reason will change to CONSENSUS if the transaction is included in a block, and lead to a higher dos score in that case.
src/net_processing.cpp
Outdated
| if (!ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast, &first_invalid_header)) { | ||
| if (state.IsInvalid()) { | ||
| if (punish_duplicate_invalid && LookupBlockIndex(first_invalid_header.GetHash())) { | ||
| if (punish_duplicate_invalid && state.GetReason() == ValidationInvalidReason::CACHED_INVALID) { |
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 "LookupBlockIndex -> CACHED_INVALID" (c558eba)
Note: behavior should be unchanged here because ProcessNewBlockHeaders calls AcceptBlockHeader which sets CACHED_INVALID if a header is already known and has BLOCK_FAILED_MASK is set. If the first invalid header is invalid for a different reason the check shouldn't trigger either before or after this change.
fdd7683 to
0ff1c2a
Compare
|
utACK 0ff1c2a
EDIT: Copy-paste error above. The only change was dropping the Remove redundant state.Invalid() call after CheckTransaction() commit. |
ryanofsky
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.
|
thanks for addressing my comment, and sorry for holding this up last-minute |
| // Check for non-standard witness in P2WSH | ||
| if (tx.HasWitness() && fRequireStandard && !IsWitnessStandard(tx, view)) | ||
| return state.DoS(0, false, REJECT_NONSTANDARD, "bad-witness-nonstandard", true); | ||
| return state.Invalid(ValidationInvalidReason::TX_WITNESS_MUTATED, false, REJECT_NONSTANDARD, "bad-witness-nonstandard"); |
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.
@TheBlueMatt I was tracking down our use of TX_WITNESS_MUTATED and the introduction of it here seems like a bug -- any idea why we did this? TX_NOT_STANDARD seems more correct, and actually I think now that we should rename TX_WITNESS_MUTATED to TX_WITNESS_STRIPPED to make it clear how we use it.
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.
It was my understanding that this could trigger in case the witness was malleated by a third part (making it nonstandard), which was the original definition for WITNESS_MUTATED.
This is a rebase of #11639 with some fixes for the last few comments which were not yet addressed.
The original PR text, with some strikethroughs of text that is no longer correct:
Note: The change to ban all peers for consensus violations is actually NOT the change I'd like to make -- I'd prefer to only ban outbound peers in those situations. The current behavior is a bit of a mess, however, and so in the interests of advancing this PR I tried to keep the changes to a minimum. I plan to revisit the behavior in a followup PR.
EDIT: One reviewer suggested I add some additional context for this PR: