-
Notifications
You must be signed in to change notification settings - Fork 38.7k
locks and docs in ATMP and CheckInputsFromMempoolAndCache #20834
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
Conversation
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.
Concept ACK.
I think you could update the PR description to say that CIFMAC also does:
CheckInputScripts() to cache signature and script validity against current tip consensus rules.
in order for script caching to work, and that you're retaining that check and moving it into the calling function (ConsensusScriptChecks()).
|
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. Great PR description, really informative. Is there anything in particular you'd recommend a reviewer do to assure themselves that removing this code doesn't cause any problems beyond the usual building, running tests etc? |
maflcko
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.
Approach ACK. The code indeed doesn't seem to do anything.
|
@michaelfolkson good question. You could go line-by-line in the function and verify that what I said in the description is true, i.e. that each one is done earlier in ATMP. And then you can also look at what |
|
This code was added in commit b014668, specifically in response to this review comment: #10192 (comment). The code was added here: #10192 (comment) before the change to per-txout db and later rebased: #10192 (comment). I believe the reasoning is as follows:
I'm not sure we really need this. We could move these checks to immediately after the coins are fetched from CCoinsViewMempool. At that point we're basically adding duplicate code to ensure that there isn't a bug in CCoinsViewMempool, which itself is only a few lines of code. We may as well just move CCoinsViewMempool into validation.cpp as suggested in the original PR by @sdaftuar:
Another interesting thing to note is that at the time this was introduced, the mempool lock was not held for the duration of ATMP (e.g. it'd be released after this block: Lines 528 to 572 in b014668
|
|
I'm pretty skeptical of this change. I think the OP downplays the consensus risk if a bug is introduced in the CCoinsViewMempool or the mempool (which CCoinsViewMempool relies on). I also took a quick look at #20833, and it seems to make that code much higher risk if we would be turning CCoinsViewMempool into something consensus critical and then make a bunch of changes to it. Is there a method for implementing #20833 that does not require this? (I was going to suggest looking at what I proposed in #16401, which faced the same issue, but now I suspect there may be a |
|
@jnewbery @sdaftuar Thanks for your input and for digging into things! I agree that a bug here would be awful as we could potentially cache incorrect script checks, affecting consensus. I think these lines from CIFMAC are a nice sanity check: const CTransactionRef& txFrom = m_pool.get(txin.prevout.hash);
if (txFrom) {
assert(txFrom->GetHash() == txin.prevout.hash);
assert(txFrom->vout.size() > txin.prevout.n);
assert(txFrom->vout[txin.prevout.n] == coin.out);
} else {
const Coin& coinFromDisk = ::ChainstateActive().CoinsTip().AccessCoin(txin.prevout);
assert(!coinFromDisk.IsSpent());
assert(coinFromDisk.out == coin.out);
}The main issues are with them being so late in ATMP.
I've moved
Yes exactly, this cleanup came up while I was trying to figure out conflicting transactions. I did a light rebase of #20833 on top of this and this condition needs to be added, but otherwise it still works. |
|
I like the way this is going. CCoinsViewMempool should live in validation.cpp and be considered consensus critical since script caching was introduced. Making that clear by reflecting it in the code structure, rather than working around it by double checking the results returned from CCoinsViewCache seems like an improvement. As far as I'm aware, CTxMemPool is not consensus critical, since any bugs in there would not cause us to incorrectly validate a block. Making the boundary between consensus-critical and non-consensus-critical code clearer is a good goal and fits with the current direction of the project (eg see #20158). It'd be nice to eventually have ChainstateActive expose a GetCoin() method that returns a coin from the UTXO set or mempool so that callers (rpc, rest, etc) don't need to concern themselves with locking cs_main/mempool.cs and setting the coins view. After that happens, CCoinsViewMempool can exist just in validation.cpp and not be exposed in the header. |
|
Concept NACK. I think the current structure of using CIFMAC to encapsulate the consensus requirements of the script cache is better than spreading the checks out across validation, where it is less clear why these checks exist and what they protect against. Moreover, I don't believe this change is necessary (or desired) for #20833, as I commented here: #20833 (comment) |
747ae56 to
89da5ed
Compare
|
@sdaftuar Thanks for your thorough review - I'm no longer removing CIFMAC. I think the lock annotations are still helpful, though, and in general would like to update the documentation to clarify what this function does. |
|
Concept ACK for updating locks and docs |
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.
utACK 89da5ed578b4839c426151960594bd4a9bf6d4f7
This is a definite improvement to the documentation/naming.
It's not clear to me why we want CheckInputsFromMempoolAndCache() to be a separate function from ConsensusScriptChecks(). It means that the documentation is split out over three places - the ConsensusScriptChecks() declaration ("Re-run the script checks, using consensus flags, and try to cache the result in the scriptcache..."), the ConsensusScriptChecks() function body ("Check again against the current block tip's script verification flags to cache our script execution flags. This is, of course, useless...") and the CheckInputsFromMempoolAndCache() function comment ("Checks to avoid mempool polluting consensus critical paths ..."). It would be much clearer if the code from CheckInputsFromMempoolAndCache() was brought into ConsensusScriptChecks() and fully documented in one place.
Maybe there's a reason that the code is structured this way and the intent is to call CheckInputsFromMempoolAndCache() from more than one place. If not, then I think a future PR could consolidate them. In any case, this PR is an improvement and stands on its own.
Note that
Somewhere we should draw a line between mempool validation and block validation; our philosophy has long been to not allow mistakes during mempool validation to cause block validation errors, because we have had historical bugs that have cropped up over the years that could have either caused consensus splits or invalid blocks to be mined. (One example that I recall is #6077, which could have broken consensus; I heard stories that prior to my time working on this project, there were prior bugs that allowed invalid transactions in the mempool, which is the motivation for Script caching of course is a huge performance win, justifying a desire to have mempool validation interact with block validation. So an important part of how we use mempool validation to speed up block validation is designing a system that is robust to differences in mempool vs block validation (the script cache design itself tries to address many of these concerns, in comparison with prior attempts to cache validation success). And in particular, finding a way to draw the line between mempool and block validation so that any future bugs introduced in mempool validation would not result in a consensus split is also very important. Drawing this line at CIFMAC seems to have held up pretty well. At the least, mempool logic was refactored in preparation for package validation back in #16400 (which is when So while we could move this consensus critical function into the At a higher level: I really think that we should have a very high bar for refactoring or otherwise changing consensus-critical code -- which CIFMAC most certainly is (as the interface to the script cache), and this PR didn't seem to acknowledge when first opened. Sometimes we'll have to modify consensus critical code to fix a bug or implement a feature, and we'll take that review burden and effort when necessary, but when unnecessary I think the cost/benefit of changing consensus code tilts strongly towards not making changes. As for the current version of this PR: @glozow thank you for taking the feedback! At first glance it looks much better to me as just doc changes and lock annotations -- will take a closer look. |
sdaftuar
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.
Concept ACK -- just a couple small questions.
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.
Interestingly, PolicyScriptChecks doesn't itself need the mempool, so on its face this seems slightly strange. I can understand that the semantics may be easiest to reason about if we try to enforce that cs_main and the mempool.cs locks are held throughout mempool acceptance, so no objection to that idea conceptually. But it's not clear to me if there's some better idiom to express this? As it is, if the caller unlocked the mempool in between calls to these internal functions and then relocked before making the next call, the annotations would not catch that, but I think our understanding is that we want to prevent that from happening.
Anyway, if we go down this route, is it worth adding these lock annotations to the CheckFeeRate helper function inside MemPoolTest as well? I think that's the only one that would be left un-annotated, otherwise.
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 added annotations to CheckFeeRate for now.
In my mind, I think of MemPoolAccept class as one "validation session" on top of current Tip and mempool, so would want to assert that it holds cs_main, pool.cs for the entirety of AcceptSingleTransaction. Don't know how to do that though 😅 not familiar
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 non-static functions need EXCLUSIVE_LOCKS_REQUIRED in any header files which include them as well - EXCLUSIVE_LOCKS_REQUIRED will be ignored by call-sites if its only set in the definitions and not all declarations.
89da5ed to
479f6f7
Compare
479f6f7 to
8027938
Compare
We should already have the mempool lock when entering CheckInputsFromMempoolAndCache
8027938 to
2f463f5
Compare
|
utACK 2f463f5 |
|
🕵️ @sipa has been requested to review this pull request as specified in the REVIEWERS file. |
maflcko
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.
cr ACK 2f463f5
| /** | ||
| * Checks to avoid mempool polluting consensus critical paths since cached | ||
| * signature and script validity results will be reused if we validate this | ||
| * transaction again during block validation. |
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 " [doc] for CheckInputsFromMempoolAndCache ":
Could make sense to refer to g_scriptExecutionCache to clarify this has nothing to do with the schnorr-cache and ecdsa-cache?
|
|
||
| // Check equivalence for available inputs. | ||
| // If the Coin is available, there are 2 possibilities: | ||
| // it is available in our current ChainstateActive UTXO set, |
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 " lock annotations for MemPoolAccept functions ":
ChainstateActive is deprecated, so to make @dongcarl 's life easier it might be best to not add new references to it
| // it is available in our current ChainstateActive UTXO set, | |
| // it is available in our current active UTXO set, |
|
utACK 2f463f5 |
fanquake
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.
ACK 2f463f5
Summary: > This is a very small PR that adds some lock annotations to clarify that, now, the `pool.cs` lock is held throughout tx validation for mempool. The comments in `CheckInputsFromMempoolAndCache` were unclear/outdated so I updated those as well. This is a backport of [[bitcoin/bitcoin#20834 | core#20834]] Notes: the `PolicyScriptChecks` and `CheckFeeRate` methods don't exist in our codebase, they are part of `PreChecks`. See D8203. Test Plan: With clang and debug: `ninja all check-all` With clang and TSAN: `ninja check check-functional` Reviewers: #bitcoin_abc, Fabien Reviewed By: #bitcoin_abc, Fabien Subscribers: Fabien Differential Revision: https://reviews.bitcoinabc.org/D11767
This is a very small PR that adds some lock annotations to clarify that, now, the
pool.cslock is held throughout tx validation for mempool. The comments inCheckInputsFromMempoolAndCachewere unclear/outdated so I updated those as well.This PR is a cleanup. It removes unnecessary code that doesn't do much.