interfaces: refactor: move Mining and BlockTemplate implementation to miner #32378

pull ismaelsadeeq wants to merge 5 commits into bitcoin:master from ismaelsadeeq:04-2025-refactor-mining-interface changing 3 files +174 −132
  1. ismaelsadeeq commented at 1:48 pm on April 29, 2025: member

    Motivation

    In Internal interface guidelines

    It’s stated that

    Interface method definitions should wrap existing functionality instead of implementing new functionality. Any substantial new node or wallet functionality should be implemented in src/node/ or src/wallet/ and just exposed in src/interfaces/ instead of being implemented there, so it can be more modular and accessible to unit tests.

    However the some methods in the newly added BlockTemplateImpl and MinerImpl classes partially enforces this guideline, as the implementations of the submitSolution, waitNext, and waitTipChanged methods reside within the class itself.

    What the PR Does

    This PR introduces a simple refactor by moving certain method implementations from BlockTemplateImpl into the miner module. It introduces three new functions:

    1. Remove rundundant coinbase fee check in waitNext

    2. AddMerkleRootAndCoinbase: Computes the block’s Merkle root, inserts the coinbase transaction, and sets the Merkle root in the block. This function is called by submitSolution before the block is submitted for processing.

    3. WaitAndCreateNewBlock: Returns a new block template either when transaction fees reach a certain threshold or when a new tip is detected. If a timeout is reached, it returns nullptr. The waitNext method in BlockTemplateImpl now simply wraps this function.

    4. Move GetTip implementation to miner.

    5. WaitTipChanged: Returns the tip when the chain it changes, or nullopt if a timeout or interrupt occurs. The waitTipChanged method in MinerImpl now calls GetTip after invoking ChainTipChanged, and returns the tip.

    Behavior Change

    • We now only Assert for a valid chainman and notifications pointer once.
  2. DrahtBot commented at 1:48 pm on April 29, 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/32378.

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK Sjors, ryanofsky, achow101
    Stale ACK musaHaruna

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

    LLM Linter (✨ experimental)

    Possible typos and grammar issues:

    then -> from [incorrect comparison]

  3. DrahtBot added the label interfaces on Apr 29, 2025
  4. ismaelsadeeq renamed this:
    interfaces: move `Mining` and `BlockTemplate` implementation to miner
    interfaces: refactor: move `Mining` and `BlockTemplate` implementation to miner
    on Apr 29, 2025
  5. in src/node/miner.cpp:453 in a5145ba0fc outdated
    448@@ -446,4 +449,94 @@ void AddMerkleRootAndCoinbase(CBlock& block, CTransactionRef coinbase, uint32_t
    449     block.nNonce = nonce;
    450     block.hashMerkleRoot = BlockMerkleRoot(block);
    451 }
    452+
    453+std::optional<std::unique_ptr<CBlockTemplate>> WaitNext(NodeContext& node, const uint256& prev_block_hash, const std::vector<CAmount>& tx_fees, const BlockWaitOptions& options, const BlockAssembler::Options& assemble_options)
    


    ryanofsky commented at 3:09 pm on April 29, 2025:

    In commit “interfaces: refactor: move waitNext implementation to miner” (a5145ba0fc3339392ff71bf20613812e0d8c8efc)

    This change generally looks good, but I would suggest tweaking this commit and the next one to pass Chainman& and KernelNotification& parameters directly instead of NodeContext& because NodeContext exposes a lot of node state that this code shouldn’t need access to and also brings in dependencies this code shouldn’t need to depend on.


    ismaelsadeeq commented at 4:45 pm on April 29, 2025:

    Thanks for taking a look I’ve taken your suggestion with the addition of CTxMemPool* as a parameter to WaitNext. I think it’s best to pass it as well, to make the method self contained and allow for testing with a custom mempool.

    Also, if I use the mempool pointer in the active chainstate not the node, a miner test fails. This happens because in TestPackageSelection, we construct a new mempool and update the node interfaces’ mempool pointer, but we don’t update the raw pointer stored in the active chainstate.

  6. DrahtBot added the label CI failed on Apr 29, 2025
  7. DrahtBot commented at 3:22 pm on April 29, 2025: contributor

    🚧 At least one of the CI tasks failed. Task tidy: https://github.com/bitcoin/bitcoin/runs/41351512028 LLM reason (✨ experimental): The CI failure was caused by clang-tidy generating errors due to an unused using-declaration in testnet4_miner_tests.cpp.

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

  8. ismaelsadeeq force-pushed on Apr 29, 2025
  9. ismaelsadeeq commented at 4:47 pm on April 29, 2025: member
  10. DrahtBot removed the label CI failed on Apr 29, 2025
  11. in src/node/miner.h:239 in d11db291d4 outdated
    233@@ -232,6 +234,10 @@ void ApplyArgsManOptions(const ArgsManager& gArgs, BlockAssembler::Options& opti
    234 
    235 /* Compute the block's merkle root, insert the coinbase transaction and the merkle root into the block */
    236 void AddMerkleRootAndCoinbase(CBlock& block, CTransactionRef coinbase, uint32_t version, uint32_t timestamp, uint32_t nonce);
    237+
    238+/* Return a new block template when fees rise to a certain threshold or after a new tip; return nullopt if timeout is reached. */
    239+std::optional<std::unique_ptr<CBlockTemplate>> WaitNext(ChainstateManager& chainman, KernelNotifications& kernel_notifications, CTxMemPool* mempool, const uint256& prev_block_hash,
    


    ryanofsky commented at 8:24 pm on May 8, 2025:

    In commit “interfaces: refactor: move waitNext implementation to miner” (d11db291d492785125dc0971ed8eaf0a4c981932)

    Would be better to return std::unique_ptr<CBlockTemplate> instead of std::optional<std::unique_ptr<CBlockTemplate>> here because unique_ptr is already nullable.

    Also node::WaitNext is kind of a vague name. Maybe a name like WaitAndCreateNewBlock could be more descriptive. Or maybe something like CreateNextBlock or CreateUpdatedBlock. Could be other ideas.


    ismaelsadeeq commented at 4:37 pm on May 9, 2025:
    Fixed
  12. in src/node/miner.h:243 in c8a3fabe40 outdated
    237@@ -238,6 +238,9 @@ void AddMerkleRootAndCoinbase(CBlock& block, CTransactionRef coinbase, uint32_t
    238 /* Return a new block template when fees rise to a certain threshold or after a new tip; return nullopt if timeout is reached. */
    239 std::optional<std::unique_ptr<CBlockTemplate>> WaitNext(ChainstateManager& chainman, KernelNotifications& kernel_notifications, CTxMemPool* mempool, const uint256& prev_block_hash,
    240                                                         const std::vector<CAmount>& tx_fees, const BlockWaitOptions& options, const BlockAssembler::Options& assemble_options);
    241+
    242+/* Waits for the connected tip to change until timeout has elapsed. During node initialization, this will wait until the tip is connected (regardless of `timeout`). */
    243+bool ChainTipChanged(ChainstateManager& chainman, KernelNotifications& kernel_notifications, const uint256& current_tip, MillisecondsDouble& timeout);
    


    ryanofsky commented at 8:54 pm on May 8, 2025:

    In commit “interfaces: refactor: move waitTipChanged implementation to miner” (c8a3fabe4090fa2b9a0e8cef73ed5365e8221ad6)

    I think name ChainTipChanged could be a little misleading since this returns a bool and you might think it returns true when the tip has changed, false otherwise. But in reality it returns true whether or not this tip has changed (after the timeout), and the only case it returns false is when the node is shutting down.

    To be less confusing I think it would be good to rename this and return the actual tip instead of a bool. Could do:

     0```diff
     1--- a/src/node/interfaces.cpp
     2+++ b/src/node/interfaces.cpp
     3@@ -974,7 +974,7 @@ public:
     4 
     5     std::optional<BlockRef> waitTipChanged(uint256 current_tip, MillisecondsDouble timeout) override
     6     {
     7-        if (ChainTipChanged(chainman(), notifications(), current_tip, timeout)) return getTip();
     8+        if (WaitTipChanged(chainman(), notifications(), current_tip, timeout)) return getTip();
     9         return {};
    10     }
    11 
    12--- a/src/node/miner.cpp
    13+++ b/src/node/miner.cpp
    14@@ -539,7 +539,7 @@ std::optional<std::unique_ptr<CBlockTemplate>> WaitNext(ChainstateManager& chain
    15     return std::nullopt;
    16 }
    17 
    18-bool ChainTipChanged(ChainstateManager& chainman, KernelNotifications& kernel_notifications, const uint256& current_tip, MillisecondsDouble& timeout)
    19+std::optional<uint256> WaitTipChanged(ChainstateManager& chainman, KernelNotifications& kernel_notifications, const uint256& current_tip, MillisecondsDouble& timeout)
    20 {
    21     Assume(timeout >= 0ms); // No internal callers should use a negative timeout
    22     if (timeout < 0ms) timeout = 0ms;
    23@@ -554,16 +554,14 @@ bool ChainTipChanged(ChainstateManager& chainman, KernelNotifications& kernel_no
    24         kernel_notifications.m_tip_block_cv.wait(lock, [&]() EXCLUSIVE_LOCKS_REQUIRED(kernel_notifications.m_tip_block_mutex) {
    25             return kernel_notifications.TipBlock() || chainman.m_interrupt;
    26         });
    27-        if (chainman.m_interrupt) return false;
    28+        if (chainman.m_interrupt) return {};
    29         // At this point TipBlock is set, so continue to wait until it is
    30         // different then `current_tip` provided by caller.
    31         kernel_notifications.m_tip_block_cv.wait_until(lock, deadline, [&]() EXCLUSIVE_LOCKS_REQUIRED(kernel_notifications.m_tip_block_mutex) {
    32             return Assume(kernel_notifications.TipBlock()) != current_tip || chainman.m_interrupt;
    33         });
    34+        if (chainman.m_interrupt) return {};
    35+        return Assume(kernel_notifications.TipBlock());
    36     }
    37-
    38-    if (chainman.m_interrupt) return false;
    39-
    40-    return true;
    41 }
    42 } // namespace node
    43--- a/src/node/miner.h
    44+++ b/src/node/miner.h
    45@@ -239,8 +239,8 @@ void AddMerkleRootAndCoinbase(CBlock& block, CTransactionRef coinbase, uint32_t
    46 std::optional<std::unique_ptr<CBlockTemplate>> WaitNext(ChainstateManager& chainman, KernelNotifications& kernel_notifications, CTxMemPool* mempool, const uint256& prev_block_hash,
    47                                                         const std::vector<CAmount>& tx_fees, const BlockWaitOptions& options, const BlockAssembler::Options& assemble_options);
    48 
    49-/* Waits for the connected tip to change until timeout has elapsed. During node initialization, this will wait until the tip is connected (regardless of `timeout`). */
    50-bool ChainTipChanged(ChainstateManager& chainman, KernelNotifications& kernel_notifications, const uint256& current_tip, MillisecondsDouble& timeout);
    51+/* Waits for the connected tip to change until timeout has elapsed. During node initialization, this will wait until the tip is connected (regardless of `timeout`). Returns the current tip hash, or nullopt if the node is shutting down. */
    52+std::optional<uint256> WaitTipChanged(ChainstateManager& chainman, KernelNotifications& kernel_notifications, const uint256& current_tip, MillisecondsDouble& timeout);
    53 } // namespace node
    54 
    55 #endif // BITCOIN_NODE_MINER_H
    

    ismaelsadeeq commented at 4:37 pm on May 9, 2025:
    Taken, thanks
  13. ryanofsky approved
  14. ryanofsky commented at 8:55 pm on May 8, 2025: contributor

    Code review ACK c8a3fabe4090fa2b9a0e8cef73ed5365e8221ad6

    Thanks for the cleanup! This change should make the node interfaces.cpp more managable and organize code better. I left some suggestions for renames and API tweaks but they are not very important.

  15. ismaelsadeeq force-pushed on May 9, 2025
  16. ismaelsadeeq commented at 4:38 pm on May 9, 2025: member
    Forced pushed to address recent comments see c8a3fabe..31e3808d
  17. in src/node/miner.h:233 in d3f4e64d41 outdated
    228@@ -229,6 +229,9 @@ void RegenerateCommitments(CBlock& block, ChainstateManager& chainman);
    229 
    230 /** Apply -blockmintxfee and -blockmaxweight options from ArgsManager to BlockAssembler options. */
    231 void ApplyArgsManOptions(const ArgsManager& gArgs, BlockAssembler::Options& options);
    232+
    233+/* Compute the block's merkle root, insert the coinbase transaction and the merkle root into the block */
    


    Sjors commented at 12:08 pm on May 13, 2025:

    In d3f4e64d416aa29d4448dffb4d47e52997b40271 “interfaces: refactor: move submitSolution implementation to miner”: maybe say “insert or replace”

    It’s unlikely for vtx to be empty, since we we add a coinbase during template creation.

    More importantly, it’s possible to call submitSolution() multiple times, with each call updating the coinbase. This could happen as a race condition or because the first solution was somehow incorrect.


    ismaelsadeeq commented at 3:22 pm on May 13, 2025:
    Done
  18. in src/node/miner.h:240 in 497996c3e5 outdated
    233@@ -232,6 +234,10 @@ void ApplyArgsManOptions(const ArgsManager& gArgs, BlockAssembler::Options& opti
    234 
    235 /* Compute the block's merkle root, insert the coinbase transaction and the merkle root into the block */
    236 void AddMerkleRootAndCoinbase(CBlock& block, CTransactionRef coinbase, uint32_t version, uint32_t timestamp, uint32_t nonce);
    237+
    238+/* Return a new block template when fees rise to a certain threshold or after a new tip; return nullopt if timeout is reached. */
    239+std::unique_ptr<CBlockTemplate> WaitAndCreateNewBlock(ChainstateManager& chainman, KernelNotifications& kernel_notifications, CTxMemPool* mempool, const uint256& prev_block_hash,
    240+                                                      const std::vector<CAmount>& tx_fees, const BlockWaitOptions& options, const BlockAssembler::Options& assemble_options);
    


    Sjors commented at 12:12 pm on May 13, 2025:

    In 497996c3e572c8992d34e54fd13d92984e9ec21c “interfaces: refactor: move waitNext implementation to miner” nit, a little less wide:

     0diff --git a/src/node/miner.h b/src/node/miner.h
     1index e20cab0d08..04b12f065e 100644
     2--- a/src/node/miner.h
     3+++ b/src/node/miner.h
     4@@ -235,9 +235,17 @@ void ApplyArgsManOptions(const ArgsManager& gArgs, BlockAssembler::Options& opti
     5 /* Compute the block's merkle root, insert the coinbase transaction and the merkle root into the block */
     6 void AddMerkleRootAndCoinbase(CBlock& block, CTransactionRef coinbase, uint32_t version, uint32_t timestamp, uint32_t nonce);
     7
     8-/* Return a new block template when fees rise to a certain threshold or after a new tip; return nullopt if timeout is reached. */
     9-std::unique_ptr<CBlockTemplate> WaitAndCreateNewBlock(ChainstateManager& chainman, KernelNotifications& kernel_notifications, CTxMemPool* mempool, const uint256& prev_block_hash,
    10-                                                      const std::vector<CAmount>& tx_fees, const BlockWaitOptions& options, const BlockAssembler::Options& assemble_options);
    11+/**
    12+ * Return a new block template when fees rise to a certain threshold or after a
    13+ * new tip; return nullopt if timeout is reached.
    14+ */
    15+std::unique_ptr<CBlockTemplate> WaitAndCreateNewBlock(ChainstateManager& chainman,
    16+                                                      KernelNotifications& kernel_notifications,
    17+                                                      CTxMemPool* mempool,
    18+                                                      const uint256& prev_block_hash,
    19+                                                      const std::vector<CAmount>& tx_fees,
    20+                                                      const BlockWaitOptions& options,
    21+                                                      const BlockAssembler::Options& assemble_options);
    22
    23 /* Waits for the connected tip to change until timeout has elapsed. During node initialization, this will wait until the tip is connected (regardless of `timeout`).
    

    Sjors commented at 12:21 pm on May 13, 2025:

    In the same commit, it’s better to pass you should pass the CBlockTemplate as an argument rather than tx_fees. With cluster mempool we might overhaul the way we do this fee calculation. Even without that, we might add a helper method to CBlockTemplate to get the total fees. In both cases I’d rather not have to change the function signature.

    (if you do this, you can also drop the prev_block_hash argument)


    ismaelsadeeq commented at 3:22 pm on May 13, 2025:
    Done!
  19. in src/node/interfaces.cpp:980 in 31e3808df9 outdated
     998-        if (chainman().m_interrupt) return {};
     999-
    1000-        // Must release m_tip_block_mutex before getTip() locks cs_main, to
    1001-        // avoid deadlocks.
    1002-        return getTip();
    1003+        if (WaitTipChanged(chainman(), notifications(), current_tip, timeout)) return getTip();
    


    Sjors commented at 12:31 pm on May 13, 2025:

    In 31e3808df9c59d36a07cad07df89ae1bf9e63000 “interfaces: refactor: move waitTipChanged implementation to miner”: this neatly solves the deadlock issue, but I think we should preserve that comment.

    Additionally we should explain why getTip() is called here, ignoring the block hash returned by WaitTipChanged. Perhaps the latter should just return a boolean?


    Sjors commented at 12:33 pm on May 13, 2025:

    Regarding the latter, I see @ryanofsky’s point: #32378 (review)

    But we should still explain why we ignore the result.


    ismaelsadeeq commented at 3:22 pm on May 13, 2025:
    Added the comment as requested.
  20. Sjors commented at 12:32 pm on May 13, 2025: member

    Concept ACK

    Mostly happy with 31e3808df9c59d36a07cad07df89ae1bf9e63000

  21. ismaelsadeeq force-pushed on May 13, 2025
  22. interfaces: remove redundant coinbase fee check in `waitNext`
    - vTxFees now does not include the negative coinbase fee,
      hence this check can be removed.
    02d4bc776b
  23. interfaces: refactor: move `submitSolution` implementation to miner
    - Create a new function `AddMerkleRootAndCoinbase` that compute the
      block's merkle root, insert the coinbase transaction and the merkle
      root into the block.
    e6c2f4ce7a
  24. interfaces: refactor: move `waitNext` implementation to miner
    - We now assert for a valid chainman and notifications once when
     invoking WaitAndCreateNewBlock function.
    720f201e65
  25. ismaelsadeeq force-pushed on May 13, 2025
  26. DrahtBot added the label CI failed on May 13, 2025
  27. DrahtBot commented at 3:23 pm on May 13, 2025: contributor

    🚧 At least one of the CI tasks failed. Task lint: https://github.com/bitcoin/bitcoin/runs/42145841028 LLM reason (✨ experimental): The CI failure is due to a lint check identifying trailing whitespace in src/node/interfaces.cpp.

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

  28. ismaelsadeeq force-pushed on May 13, 2025
  29. ismaelsadeeq commented at 3:29 pm on May 13, 2025: member

    Force-pushed to address recent comments by @Sjors:

    1. Added an explanation for why we ignore the result of WaitTipChanged.
    2. Clarified the comment for AddMerkleRootAndCoinbase.
    3. Shortened line lengths for improved readability.

    Additionally, in the recent push, I added a commit that deletes the coinbase fee check during block template total fees computation in waitNext. This check is redundant after #31897.

  30. DrahtBot removed the label CI failed on May 13, 2025
  31. musaHaruna commented at 8:08 pm on May 13, 2025: none

    Code review ACK 5134492

    Code review: After reading through internal-interface-guidelines, the new code change adheres to interface guideline and correctly abracts away implementation details to the appropraite files. Naming of function is very descriptive which is good.

    I compiled each commit successfully and ran all mining related functional test successfully. To make sure the code refactor is not breaking functionalities

  32. DrahtBot requested review from ryanofsky on May 13, 2025
  33. DrahtBot requested review from Sjors on May 13, 2025
  34. Sjors commented at 8:05 am on May 14, 2025: member

    I still found the comment a bit confusing: #32378 (review)

    Maybe it’s better to also move the GetTip() implementation to the miner, so we call it from the WaitTipChanged implementation. See https://github.com/Sjors/bitcoin/commits/2025/05/interface/

    If you then squash the last commit into 51344920ebe1772d8dd3bece789a6510d774ab59, the result is a smaller change to the waitTipChanged body, see 2dae1cb16e3e32aa477713b88adcfbb6251cc779. And it preserves the comment about deadlocks.

  35. interfaces: move getTip implementation to miner c39ca9d4f7
  36. interfaces: refactor: move `waitTipChanged` implementation to miner
    - This commit creates a function `WaitTipChanged` that waits for the connected
      tip to change until timeout elapsed.
    
    - This function is now used by `waitTipChanged`
    
    Co-authored-by: Ryan Ofsky <ryan@ofsky.org>
    62fc42d475
  37. ismaelsadeeq force-pushed on May 14, 2025
  38. ismaelsadeeq commented at 1:02 pm on May 14, 2025: member

    @Sjors I’ve taken your suggestion in this push 0d774ab59..62fc42d475

    If the GetTip method from the mining interface isn’t going to be used by the TP, it can be deleted as well?

  39. Sjors approved
  40. Sjors commented at 1:16 pm on May 14, 2025: member

    ACK 62fc42d475df4f23bd93313f95ee7b7eb0d4683f

    We could do another round of interface pruning like #31196 closer to the v30 branch-off.

    Although getTip() isn’t used by the TP (anymore), it does seem generally useful and trivial to maintain. But we can decide later if that’s a good enough reason.

  41. DrahtBot requested review from musaHaruna on May 14, 2025
  42. in src/node/interfaces.cpp:1018 in 02d4bc776b outdated
    1014@@ -1015,16 +1015,12 @@ class BlockTemplateImpl : public BlockTemplate
    1015                 if (current_fees == -1) {
    1016                     current_fees = 0;
    1017                     for (CAmount fee : m_block_template->vTxFees) {
    1018-                        // Skip coinbase
    


    ryanofsky commented at 4:10 pm on May 14, 2025:

    In commit “interfaces: remove redundant coinbase fee check in waitNext” (02d4bc776bbe002ee624ec2c09d7c3f981be1b17)

    Might be help to mention #31897 in the commit description to clarify what “now does not include” refers to

  43. in src/node/miner.h:245 in 720f201e65 outdated
    240+ * new tip; return nullopt if timeout is reached.
    241+ */
    242+std::unique_ptr<CBlockTemplate> WaitAndCreateNewBlock(ChainstateManager& chainman,
    243+                                                      KernelNotifications& kernel_notifications,
    244+                                                      CTxMemPool* mempool,
    245+                                                      const std::unique_ptr<CBlockTemplate>& block_template,
    


    ryanofsky commented at 4:16 pm on May 14, 2025:

    In commit “interfaces: refactor: move waitNext implementation to miner” (720f201e652885b9e0aec8e62a1bf9590052b320)

    Would be good to change const std::unique_ptr<CBlockTemplate>& block_template to just const CBlockTemplate& block_template since it doesn’t look like it’s allowed to be null.


    ismaelsadeeq commented at 5:26 pm on May 14, 2025:
    yeah it is not, I will do if I have to retouch.
  44. in src/node/miner.cpp:575 in 62fc42d475
    570+            return Assume(kernel_notifications.TipBlock()) != current_tip || chainman.m_interrupt;
    571+        });
    572+    }
    573+    if (chainman.m_interrupt) return {};
    574+
    575+    // Must release m_tip_block_mutex before getTip() locks cs_main, to
    


    ryanofsky commented at 4:22 pm on May 14, 2025:

    In commit “interfaces: refactor: move waitTipChanged implementation to miner” (62fc42d475df4f23bd93313f95ee7b7eb0d4683f)

    Not sure, but I think it might be a good idea to drop the 4th commit c39ca9d4f7bc9ca155692ac949be2e61c0598a97 and instead change the 5th commit 62fc42d475df4f23bd93313f95ee7b7eb0d4683f to use the kernel_notifications.TipBlock() consistently instead switching to chainman.ActiveChain().Tip() at the end:

     0--- a/src/node/miner.cpp
     1+++ b/src/node/miner.cpp
     2@@ -554,6 +554,7 @@ std::optional<BlockRef> WaitTipChanged(ChainstateManager& chainman, KernelNotifi
     3     if (timeout < 0ms) timeout = 0ms;
     4     if (timeout > std::chrono::years{100}) timeout = std::chrono::years{100}; // Upper bound to avoid UB in std::chrono
     5     auto deadline{std::chrono::steady_clock::now() + timeout};
     6+    uint256 new_tip;
     7     {
     8         WAIT_LOCK(kernel_notifications.m_tip_block_mutex, lock);
     9         // For callers convenience, wait longer than the provided timeout
    10@@ -569,11 +570,12 @@ std::optional<BlockRef> WaitTipChanged(ChainstateManager& chainman, KernelNotifi
    11         kernel_notifications.m_tip_block_cv.wait_until(lock, deadline, [&]() EXCLUSIVE_LOCKS_REQUIRED(kernel_notifications.m_tip_block_mutex) {
    12             return Assume(kernel_notifications.TipBlock()) != current_tip || chainman.m_interrupt;
    13         });
    14+        if (chainman.m_interrupt) return {};
    15+        new_tip = *kernel_notifications.TipBlock();
    16     }
    17-    if (chainman.m_interrupt) return {};
    18 
    19-    // Must release m_tip_block_mutex before getTip() locks cs_main, to
    20-    // avoid deadlocks.
    21-    return GetTip(chainman);
    22+    // Must release m_tip_block_mutex before locking cs_main to avoid deadlocks.
    23+    LOCK(::cs_main);
    24+    return BlockRef{new_tip, Assert(chainman.m_blockman.LookupBlockIndex(new_tip))->nHeight};
    25 }
    26 } // namespace node
    

    Could also s/getTip/GetTip()/ in this comment if keeping current code


    Sjors commented at 5:13 pm on May 14, 2025:

    As long as getTip() is in the interface it seems consistent with the rest of this PR to move the implementation, so no need to drop c39ca9d4f7bc9ca155692ac949be2e61c0598a97?

    Moving the implementation might also allow use to annotate the cs_main lock? (I wasn’t sure how to deal with it)

    Meanwhile your suggestion can be still be used in the 5th commit.


    ismaelsadeeq commented at 5:27 pm on May 14, 2025:
    I will do if I will retouch as well.

    ryanofsky commented at 5:31 pm on May 14, 2025:

    re: #32378 (review)

    As long as getTip() is in the interface it seems consistent with the rest of this PR to move the implementation, so no need to drop c39ca9d?

    Yes that’s fine since it’s possible the function could be used other places. I just suggested dropping the commit to shrink the PR since getTip method is already pretty simple and doesn’t necessarily need to to be split up. But any approach, including current approach seems pretty good to me, just wanted to raise this idea.

    Moving the implementation might also allow use to annotate the cs_main lock? (I wasn’t sure how to deal with it)

    Makes sense if there are other callers of GetTip function they could probably benefit from lock annotations that getTip wouldn’t provide (since there probably isn’t a good solution for annotating virtual methods).

  45. ryanofsky approved
  46. ryanofsky commented at 4:41 pm on May 14, 2025: contributor
    Code review ACK 62fc42d475df4f23bd93313f95ee7b7eb0d4683f. Lots of suggest suggest changes made since last review, altering function names and signatures and also adding new commit to drop negative fee handling. I like the idea of making the wait function return a BlockRef, that is clearer than what I suggested. Left some comments below but they are not important and this looks good as-is
  47. achow101 commented at 7:43 pm on May 14, 2025: member
    ACK 62fc42d475df4f23bd93313f95ee7b7eb0d4683f
  48. achow101 merged this on May 14, 2025
  49. achow101 closed this on May 14, 2025

  50. ismaelsadeeq deleted the branch on May 14, 2025

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-30 12:12 UTC

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