checkqueue: make the queue non-optional for CCheckQueueControl and drop legacy locking macro usage #32467

pull theuni wants to merge 5 commits into bitcoin:master from theuni:checkqueue_control_mandatory changing 7 files +41 −41
  1. theuni commented at 1:12 am on May 10, 2025: member

    As part of an effort to cleanup our threading primitives and add safe SharedMutex/SharedLock impls, I’d like to get rid of the last of our legacy ENTER_CRITICAL_SECTION/LEAVE_CRITICAL_SECTION usage. This, along with a follow-up after fixing REVERSE_LOCK will allow us to do that.

    This replaces the old macros with an RAII lock, while simplifying CCheckQueueControl. It now requires a CCheckQueue, and optionality is handled externally. In the case of validation, it is wrapped in a std::optional.

    It also adds an LOCK_ARGS macro for UniqueLock initialization which may be helpful elsewhere.

  2. DrahtBot commented at 1:12 am on May 10, 2025: contributor

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/32467.

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK fjahr, ryanofsky, TheCharlatan
    Approach ACK hebasto

    If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #32575 (refactor: Split multithreaded case out of CheckInputScripts by fjahr)
    • #32317 (kernel: Separate UTXO set access from validation functions by TheCharlatan)
    • #32080 (OP_CHECKCONTRACTVERIFY by bigspider)

    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.

  3. hebasto commented at 9:18 am on May 10, 2025: member
    Concept ACK.
  4. laanwj added the label Validation on May 10, 2025
  5. fjahr commented at 3:38 pm on May 10, 2025: contributor
    Concept ACK
  6. in src/checkqueue.h:218 in c820fe5585 outdated
    215 public:
    216     CCheckQueueControl() = delete;
    217     CCheckQueueControl(const CCheckQueueControl&) = delete;
    218     CCheckQueueControl& operator=(const CCheckQueueControl&) = delete;
    219-    explicit CCheckQueueControl(CCheckQueue<T> * const pqueueIn) : pqueue(pqueueIn), fDone(false)
    220+    explicit CCheckQueueControl(CCheckQueue<T>& pqueueIn) : pqueue(pqueueIn), fDone(false)
    


    TheCharlatan commented at 7:16 pm on May 10, 2025:

    Nit: s/pqueue/queue/

    The relevant lines are touched already, so maybe just do it in the same commit?


    fjahr commented at 8:17 pm on May 12, 2025:
    double-nit: maybe m_queue

    theuni commented at 8:53 pm on May 13, 2025:
    Done.
  7. in src/checkqueue.h:219 in 5aca850c20 outdated
    218     CCheckQueueControl& operator=(const CCheckQueueControl&) = delete;
    219-    explicit CCheckQueueControl(CCheckQueue<T>& pqueueIn) : pqueue(pqueueIn), fDone(false)
    220-    {
    221-        ENTER_CRITICAL_SECTION(pqueue.m_control_mutex);
    222-    }
    223+    explicit CCheckQueueControl(CCheckQueue<T>& pqueueIn) : pqueue(pqueueIn), m_lock(IN_PLACE_LOCK(pqueueIn.m_control_mutex)), fDone(false) {}
    


    TheCharlatan commented at 6:42 pm on May 11, 2025:
    I think it would be nice if we could get some kind of locking warning here if a second CCheckQueueControl is created from the same CCheckQueue, instead of just deadlocking. Tried coming up with a combination of LOCK and UNLOCK_FUNCTION annotation, but could not find something that actually worked.

    theuni commented at 8:43 pm on May 13, 2025:

    Yeah, I had hoped for the same :(

    The problem here (as usual with these annotations) is aliasing.

    As a simplified example:

    0CCheckQueueControl<CScriptCheck> control(m_chainman.GetCheckQueue());
    1CCheckQueueControl<CScriptCheck> control2(m_chainman.GetCheckQueue());
    

    Here, clang has no idea that &control.m_lock.m_control_mutex == &control2.m_lock.m_control_mutex.

    The only alternative, really, would be something like:

     0diff --git a/src/checkqueue.h b/src/checkqueue.h
     1index ade793ab392..5249e040d24 100644
     2--- a/src/checkqueue.h
     3+++ b/src/checkqueue.h
     4@@ -188,6 +188,11 @@ public:
     5         }
     6     }
     7
     8+    UniqueLock<Mutex> TryLock()
     9+    {
    10+        return {IN_PLACE_TRY_LOCK(m_control_mutex)};
    11+    }
    12+
    13     ~CCheckQueue()
    14     {
    15         WITH_LOCK(m_mutex, m_request_stop = true);
    16@@ -209,13 +214,14 @@ class CCheckQueueControl
    17 {
    18 private:
    19     CCheckQueue<T, R>& pqueue;
    20+    UniqueLock<Mutex> m_lock;
    21     bool fDone;
    22
    23 public:
    24     CCheckQueueControl() = delete;
    25     CCheckQueueControl(const CCheckQueueControl&) = delete;
    26     CCheckQueueControl& operator=(const CCheckQueueControl&) = delete;
    27-    explicit CCheckQueueControl(CCheckQueue<T>& pqueueIn) : pqueue(pqueueIn), fDone(false)
    28+    explicit CCheckQueueControl(CCheckQueue<T>& pqueueIn, UniqueLock<Mutex>&& lock) : pqueue(pqueueIn), m_lock(std::move(lock)), fDone(false)
    29     {
    30         ENTER_CRITICAL_SECTION(pqueue.m_control_mutex);
    31     }
    32diff --git a/src/sync.h b/src/sync.h
    33index b22956ef1ab..db4fd977cee 100644
    34--- a/src/sync.h
    35+++ b/src/sync.h
    36@@ -193,6 +193,8 @@ public:
    37             Enter(pszName, pszFile, nLine);
    38     }
    39
    40+    UniqueLock(UniqueLock&&) = default;
    41+
    42     ~UniqueLock() UNLOCK_FUNCTION()
    43     {
    44         if (Base::owns_lock())
    45@@ -260,6 +262,7 @@ inline MutexType* MaybeCheckNotHeld(MutexType* m) LOCKS_EXCLUDED(m) LOCK_RETURNE
    46     UniqueLock criticalblock2(MaybeCheckNotHeld(cs2), #cs2, __FILE__, __LINE__)
    47 #define TRY_LOCK(cs, name) UniqueLock name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__, true)
    48 #define WAIT_LOCK(cs, name) UniqueLock name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
    49+#define IN_PLACE_TRY_LOCK(cs) MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__, true
    50
    51 #define ENTER_CRITICAL_SECTION(cs)                            \
    52     {                                                         \
    53diff --git a/src/validation.cpp b/src/validation.cpp
    54index 3fa7afe3090..d690191b38e 100644
    55--- a/src/validation.cpp
    56+++ b/src/validation.cpp
    57@@ -2612,7 +2612,10 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
    58     // doesn't invalidate pointers into the vector, and keep txsdata in scope
    59     // for as long as `control`.
    60     std::optional<CCheckQueueControl<CScriptCheck>> control;
    61-    if (fScriptChecks && parallel_script_checks) control.emplace(m_chainman.GetCheckQueue());
    62+    auto& queue = m_chainman.GetCheckQueue();
    63+    auto queue_lock = queue.TryLock();
    64+    assert(queue_lock);
    65+    if (fScriptChecks && parallel_script_checks) control.emplace(m_chainman.GetCheckQueue(), std::move(queue_lock));
    66
    67     std::vector<PrecomputedTransactionData> txsdata(block.vtx.size());
    

    Unfortunately, try_lock is allowed to fail spuriously, so that’s not safe :(


    ryanofsky commented at 5:57 pm on May 19, 2025:

    re: #32467 (review)

    Following seems to prevent duplicate locking. Error message is:

    0src/bench/checkqueue.cpp:60:42: error: acquiring mutex 'queue.m_control_mutex' that is already held [-Werror,-Wthread-safety-analysis]
    1   60 |         CCheckQueueControl<PrevectorJob> control2(queue);
    2      |                                          ^
    3src/bench/checkqueue.cpp:59:42: note: mutex acquired here
    4   59 |         CCheckQueueControl<PrevectorJob> control(queue);
    5      |                                          ^
    61 error generated.
    
     0--- a/src/bench/checkqueue.cpp
     1+++ b/src/bench/checkqueue.cpp
     2@@ -57,6 +57,7 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::Bench& bench)
     3     bench.minEpochIterations(10).batch(BATCH_SIZE * BATCHES).unit("job").run([&] {
     4         // Make insecure_rand here so that each iteration is identical.
     5         CCheckQueueControl<PrevectorJob> control(queue);
     6+        CCheckQueueControl<PrevectorJob> control2(queue);
     7         for (auto vChecks : vBatches) {
     8             control.Add(std::move(vChecks));
     9         }
    10--- a/src/checkqueue.h
    11+++ b/src/checkqueue.h
    12@@ -205,7 +205,7 @@ public:
    13  * queue is finished before continuing.
    14  */
    15 template <typename T, typename R = std::remove_cvref_t<decltype(std::declval<T>()().value())>>
    16-class CCheckQueueControl
    17+class SCOPED_LOCKABLE CCheckQueueControl
    18 {
    19 private:
    20     CCheckQueue<T, R>& m_queue;
    21@@ -216,7 +216,7 @@ public:
    22     CCheckQueueControl() = delete;
    23     CCheckQueueControl(const CCheckQueueControl&) = delete;
    24     CCheckQueueControl& operator=(const CCheckQueueControl&) = delete;
    25-    explicit CCheckQueueControl(CCheckQueue<T>& queueIn) : m_queue(queueIn), m_lock(IN_PLACE_LOCK(queueIn.m_control_mutex)), fDone(false) {}
    26+    explicit CCheckQueueControl(CCheckQueue<T>& queueIn) EXCLUSIVE_LOCK_FUNCTION(queueIn.m_control_mutex) : m_queue(queueIn), m_lock(IN_PLACE_LOCK(queueIn.m_control_mutex)), fDone(false) {}
    27 
    28     std::optional<R> Complete()
    29     {
    30@@ -230,7 +230,7 @@ public:
    31         m_queue.Add(std::move(vChecks));
    32     }
    33 
    34-    ~CCheckQueueControl()
    35+    ~CCheckQueueControl() UNLOCK_FUNCTION()
    36     {
    37         if (!fDone)
    38             Complete();
    

    theuni commented at 6:50 pm on May 19, 2025:

    Nice! I guess it manages to see through the references after all. My testing shows that:

    0    auto& queue = m_chainman.GetCheckQueue();
    1    CCheckQueueControl<CScriptCheck> control(queue);
    2    CCheckQueueControl<CScriptCheck> control2(queue)
    
    0    CCheckQueueControl<CScriptCheck> control(m_chainman.GetCheckQueue());
    1    CCheckQueueControl<CScriptCheck> control2(m_chainman.GetCheckQueue());
    

    Both of those indeed work.

    I suppose I came to the conclusion that the SCOPED_LOCKABLE approach didn’t help because neither of the above work when using a std::optional. So it won’t actually work in the validation case.

    But still better than nothing. Will add. Thanks!

  8. TheCharlatan approved
  9. TheCharlatan commented at 6:43 pm on May 11, 2025: contributor
    ACK 5aca850c205a20a0f198827f9797fb8053f2b3dd
  10. DrahtBot requested review from fjahr on May 11, 2025
  11. DrahtBot requested review from hebasto on May 11, 2025
  12. fjahr commented at 8:17 pm on May 12, 2025: contributor
    Code review ACK 5aca850c205a20a0f198827f9797fb8053f2b3dd
  13. theuni force-pushed on May 13, 2025
  14. theuni commented at 8:53 pm on May 13, 2025: member
    Updated to address @TheCharlatan’s nit.
  15. TheCharlatan approved
  16. TheCharlatan commented at 8:46 am on May 14, 2025: contributor
    ACK da5d55227e6aead8a9fbb85e967801cfcd4283ce
  17. fjahr commented at 9:14 am on May 14, 2025: contributor
    re-ACK da5d55227e6aead8a9fbb85e967801cfcd4283ce
  18. in src/validation.cpp:2686 in bcde915301 outdated
    2681@@ -2680,7 +2682,8 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
    2682                               tx_state.GetRejectReason(), tx_state.GetDebugMessage());
    2683                 break;
    2684             }
    2685-            control.Add(std::move(vChecks));
    2686+            if (control)
    2687+                control->Add(std::move(vChecks));
    


    ryanofsky commented at 5:05 pm on May 19, 2025:

    In commit “validation: only create a CCheckQueueControl if it’s actually going to be used” (bcde9153012b2ce3e9ff5b7cd1c6f9866453e727)

    Developer notes want single-line if or multiple line if with braces, not multiline if without braces.

    • If an if only has a single-statement then-clause, it can appear on the same line as the if, without braces. In every other case, braces are required, and the then and else clauses must appear correctly indented on a new line.
  19. in src/validation.cpp:2685 in bcde915301 outdated
    2681@@ -2680,7 +2682,8 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
    2682                               tx_state.GetRejectReason(), tx_state.GetDebugMessage());
    2683                 break;
    2684             }
    2685-            control.Add(std::move(vChecks));
    2686+            if (control)
    


    ryanofsky commented at 5:08 pm on May 19, 2025:

    In commit “validation: only create a CCheckQueueControl if it’s actually going to be used” (bcde9153012b2ce3e9ff5b7cd1c6f9866453e727)

    Seems like it would be good to change parallel_script_checks ? &vChecks : nullptr on line 2679 above to control ? &vChecks : nullptr to be checking for the control condition consistently in this function.

    IMO, it would also be nice to have a comment here saying that if control is unset, checks were already performed in the CheckInputScripts call. Otherwise it looks like they are being skipped here.


    theuni commented at 10:09 pm on May 19, 2025:

    Mmm, this is kinda awkward either way. It’d be better imo to pass the actual optional<CCheckQueueControl>& as an argument to CheckInputScripts, but that makes this much more complicated for a bunch of reasons.

    I pushed an additional commit to try to make this a little easier to read. Please let me know what you think. If it’s over-complicating what’s otherwise a pretty trivial PR, I can remove it.

  20. in src/sync.h:263 in da5d55227e outdated
    259@@ -260,6 +260,7 @@ inline MutexType* MaybeCheckNotHeld(MutexType* m) LOCKS_EXCLUDED(m) LOCK_RETURNE
    260     UniqueLock criticalblock2(MaybeCheckNotHeld(cs2), #cs2, __FILE__, __LINE__)
    261 #define TRY_LOCK(cs, name) UniqueLock name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__, true)
    262 #define WAIT_LOCK(cs, name) UniqueLock name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
    263+#define IN_PLACE_LOCK(cs) MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__
    


    ryanofsky commented at 5:29 pm on May 19, 2025:

    In commit “validation: use a lock for CCheckQueueControl” (da5d55227e6aead8a9fbb85e967801cfcd4283ce)

    Something like LOCK_ARGS might be a better name for this macro than than IN_PLACE_LOCK, because it expands to a list of 4 arguments, not a lock. Also, TRY_LOCK and WAIT_LOCK above could be deduplicated and written using LOCK_ARGS.

    I don’t think there is a close parallel between IN_PLACE_LOCK and std::in_place other than that they both get used as constructor arguments. IN_PLACE_LOCK isn’t being used to help construct objects in place inside a larger std::any/std::optional/std::variant object like std::in_place is


    theuni commented at 10:10 pm on May 19, 2025:
    Done. I wasn’t sure if __LINE__ would work correctly when called from another macro, but it seems to do the right thing :)
  21. ryanofsky approved
  22. ryanofsky commented at 6:00 pm on May 19, 2025: contributor
    Code review ACK da5d55227e6aead8a9fbb85e967801cfcd4283ce. This looks good and is a nice improvement. Left some suggestions below I think it could be good to follow up on, though
  23. threading: add LOCK_ARGS macro
    This is useful for initializing locks in a constructor.
    11fed833b3
  24. validation: only create a CCheckQueueControl if it's actually going to be used
    This will allow CCheckQueueControl to require a CCheckQueue.
    4c8c90b556
  25. validation: make CCheckQueueControl's CCheckQueue non-optional
    This simplifies the construction logic and will allow the constructor and
    destructor to lock and unlock uncondiationally.
    c3b0e6c7f4
  26. validation: use a lock for CCheckQueueControl
    Uses an RAII lock for the exact same behavior as the old critical sections.
    
    Co-authored-by: Ryan Ofsky <ryan@ofsky.org>
    1a37507895
  27. theuni force-pushed on May 19, 2025
  28. theuni commented at 10:12 pm on May 19, 2025: member
    Updated to resolve @ryanofsky’s comments. I added a new comment to (hopefully) clarify the CheckInputScripts calling.
  29. hebasto commented at 3:36 pm on May 20, 2025: member

    Approach ACK 833dc7b9e3672b9a9033d02802ac60a48d4a8b3c, I have reviewed the code and it looks OK. Still testing.

    It also adds an IN_PLACE_LOCK macro for UniqueLock initialization which may be helpful elsewhere.

    Update the macro name in the PR description?

  30. in src/validation.cpp:2681 in 833dc7b9e3 outdated
    2679-            if (fScriptChecks && !CheckInputScripts(tx, tx_state, view, flags, fCacheResults, fCacheResults, txsdata[i], m_chainman.m_validation_cache, parallel_script_checks ? &vChecks : nullptr)) {
    2680+            // If CheckInputScripts is called with a pointer to a checks vector, the resulting checks are appended to it. In that case
    2681+            // they need to be added to control which runs them asynchronously. Otherwise, CheckInputScripts runs the checks before returning.
    2682+            if (control) {
    2683+                std::vector<CScriptCheck> vChecks;
    2684+                Assert(CheckInputScripts(tx, tx_state, view, flags, fCacheResults, fCacheResults, txsdata[i], m_chainman.m_validation_cache, &vChecks));
    


    ryanofsky commented at 3:41 pm on May 20, 2025:

    In commit “validation: clean up and clarify CheckInputScripts logic” (833dc7b9e3672b9a9033d02802ac60a48d4a8b3c)

    Not important, but I think it is not ideal for CheckInputScripts return value to be handled inconsistently and sometimes abort. It makes it more difficult for CheckInputScripts to change in the future (to add checks or shift between delayed and upfront checking) if one caller is making stronger assumptions than the other callers about how it works and what it may return. Would suggest treating both cases here more similarly:

     0--- a/src/validation.cpp
     1+++ b/src/validation.cpp
     2@@ -2673,14 +2673,18 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
     3         if (!tx.IsCoinBase() && fScriptChecks)
     4         {
     5             bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
     6+            bool tx_ok;
     7             TxValidationState tx_state;
     8             // If CheckInputScripts is called with a pointer to a checks vector, the resulting checks are appended to it. In that case
     9             // they need to be added to control which runs them asynchronously. Otherwise, CheckInputScripts runs the checks before returning.
    10             if (control) {
    11                 std::vector<CScriptCheck> vChecks;
    12-                Assert(CheckInputScripts(tx, tx_state, view, flags, fCacheResults, fCacheResults, txsdata[i], m_chainman.m_validation_cache, &vChecks));
    13+                tx_ok = CheckInputScripts(tx, tx_state, view, flags, fCacheResults, fCacheResults, txsdata[i], m_chainman.m_validation_cache, &vChecks);
    14                 control->Add(std::move(vChecks));
    15-            } else if (!CheckInputScripts(tx, tx_state, view, flags, fCacheResults, fCacheResults, txsdata[i], m_chainman.m_validation_cache)) {
    16+            } else {
    17+                tx_ok = CheckInputScripts(tx, tx_state, view, flags, fCacheResults, fCacheResults, txsdata[i], m_chainman.m_validation_cache);
    18+            }
    19+            if (!tx_ok) {
    20                 // Any transaction validation failure in ConnectBlock is a block consensus failure
    21                 state.Invalid(BlockValidationResult::BLOCK_CONSENSUS,
    22                               tx_state.GetRejectReason(), tx_state.GetDebugMessage());
    

    theuni commented at 4:02 pm on May 20, 2025:

    Yeah, I had the same thought but I guess I came to a different conclusion. I figured if a false return only has meaning in the sync code-path, the true return should be enforced in the async as well. That way if someone ever tries to add a return false in the batched case, we’d catch it right away in testing.

    Edit: Everything about the way CheckInputScripts is called is ugly, btw. It makes a bunch of non-obvious assumptions (like !vChecks basically implies it’s a mempool check), and has the potential to do unexpected things on single-core machines. That’s been true for ages, but I still think it’d be good to refactor it to be more sane. Just not as a part of this PR.


    ryanofsky commented at 4:30 pm on May 20, 2025:

    That way if someone ever tries to add a return false in the batched case, we’d catch it right away in testing.

    Catch what though? Catch CheckInputScripts detecting an invalid input and returning false like someone would reasonably expect it to? There aren’t warnings or any indication inside CheckInputScripts saying that returning false may crash the program. So I don’t think it’s hard to imagine someone optimizing CheckInputScripts or refactoring or just adding a new check that returns false. They could even write test code that triggers the check but bypasses this particular call path. And the check could avoid initially causing errors in production because it would normally pass. But at some point later the check could be triggered and cause crashes, and the diff I suggested above might be the logical fix.

    Perhaps this is not realistic, but naively to me it would seem safest to handle CheckInputScripts failing in ConnectBlock by treating the block as invalid (as the code is currently doing) rather than crashing.

    If it is also important to ensure that CheckInputScripts returns true when CheckQueue::HasThreads is true, it seems like it would be safer to check for that with an Assume+LogWarning rather than an Assert.

    I’m not sure about this and maybe I am thinking about it in the wrong way, but that’s my logic here.


    theuni commented at 6:29 pm on May 20, 2025:
    Ok, yes, thank you for walking through that. I agree. Pushed with a slight change (only adding to the queue if tx_ok).

    fjahr commented at 8:38 pm on May 20, 2025:

    This whole conversation reminded me that I really wanted to split up CheckInputScripts after interacting with it for the batch validation stuff. I will open a draft of that for conceptual feedback.

    EDIT: See #32575

  31. ryanofsky approved
  32. ryanofsky commented at 3:44 pm on May 20, 2025: contributor

    Code review ACK 833dc7b9e3672b9a9033d02802ac60a48d4a8b3c. Main changes since last review were adding lock annotations and a new commit to clarify CheckInputScripts.

    I definitely think the new commit 833dc7b9e3672b9a9033d02802ac60a48d4a8b3c is good and makes code less confusing. I left one suggestion about it, but it is not important.

  33. DrahtBot requested review from TheCharlatan on May 20, 2025
  34. DrahtBot requested review from hebasto on May 20, 2025
  35. validation: clean up and clarify CheckInputScripts logic
    CheckInputScripts behaves differently depending on whether or not it was called
    with a vector for checks. Make this difference clear by calling it differently
    depending on whether or not control exists. Though more verbose, it should be
    more straightforward to understand what's happening this way.
    
    Also remove parallel_script_checks, as `if(control)` is a better test.
    
    Co-authored-by: Ryan Ofsky <ryan@ofsky.org>
    fd290730f5
  36. theuni force-pushed on May 20, 2025
  37. fjahr commented at 8:38 pm on May 20, 2025: contributor

    re-ACK fd290730f530a8b76a9607392f49830697cdd7c5

    CI failure looks unrelated.

  38. DrahtBot requested review from ryanofsky on May 20, 2025
  39. DrahtBot added the label CI failed on May 20, 2025
  40. DrahtBot removed the label CI failed on May 21, 2025
  41. ryanofsky approved
  42. ryanofsky commented at 6:22 pm on May 21, 2025: contributor
    Code review ACK fd290730f530a8b76a9607392f49830697cdd7c5, just removing assert since last review. Thanks for considering all the comments and feedback!
  43. in src/sync.h:261 in 11fed833b3 outdated
    257@@ -258,8 +258,9 @@ inline MutexType* MaybeCheckNotHeld(MutexType* m) LOCKS_EXCLUDED(m) LOCK_RETURNE
    258 #define LOCK2(cs1, cs2)                                               \
    259     UniqueLock criticalblock1(MaybeCheckNotHeld(cs1), #cs1, __FILE__, __LINE__); \
    260     UniqueLock criticalblock2(MaybeCheckNotHeld(cs2), #cs2, __FILE__, __LINE__)
    261-#define TRY_LOCK(cs, name) UniqueLock name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__, true)
    262-#define WAIT_LOCK(cs, name) UniqueLock name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
    263+#define LOCK_ARGS(cs) MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__
    


    davidgumberg commented at 0:08 am on May 22, 2025:

    In commit 11fed833b3ed6d5c96957de5addc4f903b2cee6c (threading: add LOCK_ARGS macro):


    Not blocking: LOCK_ARGS would also be useful for LOCK and LOCK2 above, and it would make the differences among the four locking macros more obvious.

  44. TheCharlatan approved
  45. TheCharlatan commented at 8:39 am on May 22, 2025: contributor
    Re-ACK fd290730f530a8b76a9607392f49830697cdd7c5
  46. fanquake merged this on May 22, 2025
  47. fanquake closed this on May 22, 2025

  48. in src/validation.cpp:2683 in fd290730f5
    2681+            // If CheckInputScripts is called with a pointer to a checks vector, the resulting checks are appended to it. In that case
    2682+            // they need to be added to control which runs them asynchronously. Otherwise, CheckInputScripts runs the checks before returning.
    2683+            if (control) {
    2684+                std::vector<CScriptCheck> vChecks;
    2685+                tx_ok = CheckInputScripts(tx, tx_state, view, flags, fCacheResults, fCacheResults, txsdata[i], m_chainman.m_validation_cache, &vChecks);
    2686+                if (tx_ok) control->Add(std::move(vChecks));
    


    mzumsande commented at 7:38 pm on May 22, 2025:
    just noting that CheckInputScripts() will always return true in the parallel validation case where control is set (it doesn’t do any validation after all), so this logic could be simpler / tx_ok isn’t really necessary.

    fjahr commented at 7:44 pm on May 22, 2025:
    Hopefully this is soon obsolete with #32575 :)

    theuni commented at 8:13 pm on May 22, 2025:

    @mzumsande See the (hidden) discussion here: #32467 (review)

    This was mostly added to prevent future footguns if an early false return is ever added. But yeah, it’s meaningless and confusing as-is, and prompted @fjahr’s PR above :)

  49. mzumsande commented at 7:42 pm on May 22, 2025: contributor
    post-merge code review ACK fd290730f530a8b76a9607392f49830697cdd7c5
  50. in src/validation.cpp:2614 in fd290730f5
    2610@@ -2612,7 +2611,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
    2611     // doesn't invalidate pointers into the vector, and keep txsdata in scope
    2612     // for as long as `control`.
    2613     std::optional<CCheckQueueControl<CScriptCheck>> control;
    2614-    if (fScriptChecks && parallel_script_checks) control.emplace(m_chainman.GetCheckQueue());
    2615+    if (auto& queue = m_chainman.GetCheckQueue(); queue.HasThreads() && fScriptChecks) control.emplace(queue);
    


    davidgumberg commented at 9:22 pm on May 22, 2025:

    Dumb question: Is there a reason why the order was changed here between HasThreads() and fSCriptChecks? Is it because HasThreads() is cheap and the line is more readible with the check next to the initializer?

    Edit: yeah that’s a silly question, the order never mattered here before since checking both values had no side effects or performance cost. The order here makes sense and is legible.


    theuni commented at 9:51 pm on May 22, 2025:
    Yep, no reason other than I thought it was more readable that way.
  51. davidgumberg commented at 9:30 pm on May 22, 2025: contributor

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2025-05-26 00:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me