Mining interface followups, reduce cs_main locking, test rpc bug fix #30335

pull Sjors wants to merge 5 commits into bitcoin:master from Sjors:2024/06/mining-interface-followups changing 3 files +18 −16
  1. Sjors commented at 11:38 am on June 25, 2024: member

    Followups from #30200

    Fixes:

    • std::unique_ptr needs #include <memory> (noticed while working on #30332, which has fewer includes than its parent PR that I originally tested with)
    • Drop lock from createNewBlock that was spuriously added
    • Have testBlockValidity hold cs_main instead of caller (also fixes a race condition in test-only code)

    Refactor:

    • Use CHECK_NONFATAL to avoid single-use symbol (refactor)
    • move output argument state to the end of testBlockValidity, see #30200 (review)
  2. DrahtBot commented at 11:38 am on June 25, 2024: contributor

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

    Code Coverage

    For detailed information about the code coverage, see the test coverage report.

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK AngusP, itornaza, ryanofsky
    Stale ACK tdb3

    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:

    • #29432 (Stratum v2 Template Provider (take 3) by Sjors)

    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. Sjors force-pushed on Jun 25, 2024
  4. in src/interfaces/mining.h:48 in 22fe97a5cc outdated
    44@@ -44,6 +45,7 @@ class Mining
    45      * @returns a block template
    46      */
    47     virtual std::unique_ptr<node::CBlockTemplate> createNewBlock(const CScript& script_pub_key, bool use_mempool = true) = 0;
    48+
    


    Sjors commented at 11:44 am on June 25, 2024:
    Added blank line here for consistency.
  5. itornaza approved
  6. itornaza commented at 6:09 pm on June 25, 2024: contributor

    tested ACK 22fe97a5cc612f438ec6280757487934501bf527

    Manually validated all instances of testBlockValidity in the entire code base are having their parameter list updated with state as their last output parameter using good old git grep -n testBlockValidity. Now, the interface can be used with the libmultiprocess code generator!

    As for the standard testing, I got the pr from upstream, built and run all unit and functional tests including the entire extended test harness and all tests pass.

    (Special thanks for incorporating that empty line, it makes eyeballing of different methods pretty easier to spot even for people with poorer eyesight!)

  7. AngusP approved
  8. AngusP commented at 9:14 pm on June 25, 2024: contributor
    Tested ACK 22fe97a5cc612f438ec6280757487934501bf527
  9. tdb3 approved
  10. tdb3 commented at 11:42 pm on June 25, 2024: contributor

    ACK 22fe97a5cc612f438ec6280757487934501bf527

    Changes look straightforward. Took a quick look at the other interface functions in mining.h, and the function arguments look to all now be in the in/inout/out order. Also manually ran getblocktemplate RPC on signet and on regtest (after broadcasting a few transactions). All looked well.

  11. in src/rpc/mining.cpp:390 in 22fe97a5cc outdated
    389@@ -390,7 +390,7 @@ static RPCHelpMan generateblock()
    390         LOCK(cs_main);
    


    maflcko commented at 8:07 am on June 26, 2024:
    What is this lock used for?

    maflcko commented at 8:12 am on June 26, 2024:
    Same in line 374

    AngusP commented at 9:45 am on June 26, 2024:

    It is also acquired within miner.testBlockValidity (and in miner.createNewBlock) so maybe is now unnecessary outside the Miner interface?

    https://github.com/bitcoin/bitcoin/blob/a9716c53f05082d6d89ebea51a46d4404efb12d7/src/node/interfaces.cpp#L873-L877


    Sjors commented at 10:28 am on June 26, 2024:
    I pushed 1f0559e9954253c23af7ee9b49e57eb3d7a45bea to drop it from createNewBlock. Will look at the other occurances too.

    maflcko commented at 10:42 am on June 26, 2024:

    I pushed 1f0559e to drop it from createNewBlock. Will look at the other occurances too.

    The commit referenced in this commit message is wrong.


    Sjors commented at 10:56 am on June 26, 2024:

    The lock at line 390 has been there from the introduction of the generateblock RPC call in #17693. I don’t see any discussion of it in the reviews.

    I think it’s because assert(pindexPrev && pindexPrev == chainstate.m_chain.Tip()); inside of TestBlockValidity. Added 18d6b0f86769f89738a3b08aa8152a8479cef5d4 to explain that, and also make testBlockValidity require the lock. @maflcko I fixed the commit reference. Still looking at the other lock you mentioned.


    Sjors commented at 11:26 am on June 26, 2024:

    Actually that assert isn’t the problem, it merely checks that the chainman().ActiveChainstate() and chainman().ActiveChain().Tip() that we passed in match.

    The problem is deeper down the call stack, where TestBlockValidity calls ConnectBlock. That takes a viewNew argument which is chainstate.CoinsTip(), and our proposed block (pindex), and then it does assert(hashPrevBlock == view.GetBestBlock()); where hashPrevBlock = pindex->pprev. In other words, if our proposed block no longer points to the tip it crashes.


    Sjors commented at 11:46 am on June 26, 2024:

    Pushed c8343e29a66082b37c37ee0ff8f7433b97eea9b1 to deal with this (replaces https://github.com/bitcoin/bitcoin/commit/18d6b0f86769f89738a3b08aa8152a8479cef5d4). This drops both locks from the RPC code.

    An alternative that would actually prevent the tip from updating, rather than fail the RPC call, is to hold the lock even longer. But callers need to handle failure anyway since testBlockValidity can fail for other reasons.

    Also note that with the original two separate LOCK(cs_main) calls the tip could have been updated before testBlockValidity anyway, so this is probably a bug fix.


    maflcko commented at 12:44 pm on June 26, 2024:

    probably a bug fix.

    In test-only code. But seems fine to fix, if the fix is correct.


    ryanofsky commented at 1:29 pm on June 26, 2024:

    re: #30335 (review)

    What is this lock used for?

    Marking this thread resolved as the lock is now removed in later commit c8343e29a66082b37c37ee0ff8f7433b97eea9b1

  12. maflcko commented at 8:19 am on June 26, 2024: member

    CHECK_NONFATAL can be used to write shorter code and not pollute the scope with single-use symbols. That is:

    0    std::optional<uint256> maybe_tip{miner.getTipHash()};
    1    CHECK_NONFATAL(maybe_tip);
    2    uint256 tip{maybe_tip.value()};
    

    can be:

    0    uint256 tip{CHECK_NONFATAL(miner.getTipHash()).value()};
    
  13. Add missing include for mining interface
    Needed for std::unique_ptr
    83a9bef0e2
  14. refactor: testBlockValidity make out argument last 75ce7637ad
  15. Sjors force-pushed on Jun 26, 2024
  16. Sjors force-pushed on Jun 26, 2024
  17. in src/node/interfaces.cpp:873 in 18d6b0f867 outdated
    869@@ -870,9 +870,10 @@ class MinerImpl : public Mining
    870         return context()->mempool->GetTransactionsUpdated();
    871     }
    872 
    873-    bool testBlockValidity(BlockValidationState& state, const CBlock& block, bool check_merkle_root) override
    874+    bool testBlockValidity(const CBlock& block, bool check_merkle_root, BlockValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) override
    


    maflcko commented at 11:07 am on June 26, 2024:
    Lock annotations in the cpp file will be ignored by the compiler, because it usually only sees the .h file.

    Sjors commented at 11:23 am on June 26, 2024:

    I initially added it only to the header, but that resulted in:

    0node/interfaces.cpp:875:9: warning: calling function 'AssertLockHeldInternal<AnnotatedMixin<std::recursive_mutex>>' requires holding mutex 'cs_main' exclusively [-Wthread-safety-analysis]
    1        AssertLockHeld(cs_main);
    2        ^
    

    Should I add it in both? Or declare the override first (which would need a new header).


    maflcko commented at 11:25 am on June 26, 2024:
    Well, I don’t even understand the big picture. Isn’t the point of interfaces to have (possibly) multiple processes? How would one even take and release a lock in another process?

    Sjors commented at 11:34 am on June 26, 2024:
    Good point, it doesn’t make sense to require the lock. Will try something else.
  18. Sjors force-pushed on Jun 26, 2024
  19. in src/node/interfaces.cpp:878 in c8343e29a6 outdated
    876-        LOCK(::cs_main);
    877-        return TestBlockValidity(state, chainman().GetParams(), chainman().ActiveChainstate(), block, chainman().ActiveChain().Tip(), /*fCheckPOW=*/false, check_merkle_root);
    878+        LOCK(cs_main);
    879+        CBlockIndex* tip{chainman().ActiveChain().Tip()};
    880+        // Fail if the tip updated before the lock was taken
    881+        if (block.hashPrevBlock != tip->GetBlockHash()) return false;
    


    maflcko commented at 12:08 pm on June 26, 2024:
    state will be valid, no? So this may be confusing?

    maflcko commented at 12:10 pm on June 26, 2024:
    just a nit, because it only affects test-only code, but wanted to leave the comment.

    ryanofsky commented at 1:39 pm on June 26, 2024:

    In commit “Have testBlockValidity hold cs_main instead of caller” (c8343e29a66082b37c37ee0ff8f7433b97eea9b1)

    re: #30335 (review)

    state will be valid, no? So this may be confusing?

    It seems like it would be better to do something like:

    0if (block.hashPrevBlock != tip->GetBlockHash()) {
    1    state.Error("Block does not connect to current chain tip.")
    2    return false;
    3}
    

    Sjors commented at 7:00 am on June 27, 2024:
    Taken
  20. in src/node/interfaces.cpp:878 in c8343e29a6 outdated
    871@@ -872,8 +872,12 @@ class MinerImpl : public Mining
    872 
    873     bool testBlockValidity(const CBlock& block, bool check_merkle_root, BlockValidationState& state) override
    874     {
    875-        LOCK(::cs_main);
    876-        return TestBlockValidity(state, chainman().GetParams(), chainman().ActiveChainstate(), block, chainman().ActiveChain().Tip(), /*fCheckPOW=*/false, check_merkle_root);
    877+        LOCK(cs_main);
    878+        CBlockIndex* tip{chainman().ActiveChain().Tip()};
    879+        // Fail if the tip updated before the lock was taken
    880+        if (block.hashPrevBlock != tip->GetBlockHash()) return false;
    


    AngusP commented at 12:20 pm on June 26, 2024:

    nit: In the RPC error you’ll give state.ToString() as the failure reason, but if this tip check fails that’ll be the default BLOCK_RESULT_UNSET.

    better suggestion #30335 (review) Seems correct to fail if the tip has updated to avoid building a fork on an older block, but I can’t see a BlockValidationResult that would make sense here other than maybe stretching the meaning of BLOCK_INVALID_HEADER – perhaps you could add another that only makes sense in a templating context like BLOCK_NOT_TIP (or wrap BlockValidationState in something like BlockTemplateValidationState allowing for other template-specific reults but that might be too messy?)


    AngusP commented at 12:24 pm on June 26, 2024:
    Currently if this happens as you said #30335 (review) it looks like we’d have crashed which is fun
  21. in src/node/interfaces.cpp:884 in 1e4918b8f3 outdated
    880@@ -881,7 +881,6 @@ class MinerImpl : public Mining
    881         BlockAssembler::Options options;
    882         ApplyArgsManOptions(gArgs, options);
    883 
    884-        LOCK(::cs_main);
    


    ryanofsky commented at 1:32 pm on June 26, 2024:

    In commit “Drop unneeded lock from createNewBlock” (1e4918b8f3af20577acdc9f201af44153e29bcb3)

    Commit message could mention the reason the lock is not required in CreateNewBlock, which is just that CreateNewBlock already locks cs_main internally.


    Sjors commented at 7:01 am on June 27, 2024:
    Reworded
  22. ryanofsky approved
  23. ryanofsky commented at 1:44 pm on June 26, 2024: contributor

    Code review ACK c8343e29a66082b37c37ee0ff8f7433b97eea9b1

    Nice changes getting rid of some over-broad and recursive uses of cs_main.

  24. DrahtBot requested review from AngusP on Jun 26, 2024
  25. DrahtBot requested review from tdb3 on Jun 26, 2024
  26. DrahtBot requested review from itornaza on Jun 26, 2024
  27. ryanofsky commented at 1:47 pm on June 26, 2024: contributor
    It would be good to mention that the are some changes to cs_main locking (including a potential bugfix) in the PR description, otherwise this should be a refactoring with no changes in behavior.
  28. Sjors renamed this:
    Mining interface followups
    Mining interface followups, reduce cs_main locking, test rpc bug fix
    on Jun 27, 2024
  29. Drop unneeded lock from createNewBlock
    This was added in 4bf2e361da1964f7c278b4939967a0e5afde20b0, but
    BlockAssembler::CreateNewBlock already locks cs_main internally.
    5fb2b70489
  30. refactor: use CHECK_NONFATAL to avoid single-use symbol f6dc6db44d
  31. Have testBlockValidity hold cs_main instead of caller
    The goal of interfaces is to eventually run in their own process,
    so we can't use EXCLUSIVE_LOCKS_REQUIRED in their declaration.
    
    However TestBlockValidaty will crash (in its call to ConnectBlock)
    if the tip changes from under the proposed block.
    
    Have the testBlockValidity implementation  hold the lock instead,
    and non-fatally check for this condition.
    a74b0f93ef
  32. Sjors force-pushed on Jun 27, 2024
  33. Sjors commented at 7:04 am on June 27, 2024: member
    Addressed feedback and expanded PR description.
  34. AngusP approved
  35. AngusP commented at 1:50 pm on June 27, 2024: contributor
    Code Review ACK a74b0f93efa1d9eaf5abc2f6591c44a632aec6ed
  36. DrahtBot requested review from ryanofsky on Jun 27, 2024
  37. itornaza approved
  38. itornaza commented at 6:45 pm on June 27, 2024: contributor

    Tested ACK a74b0f93efa1d9eaf5abc2f6591c44a632aec6ed

    Code reviewed and validated all the initial refactor and appended fix changes as they were discovered during the course of this PR.

    Cleaned up and rebuilt this commit running the unit, functional and extended tests that all pass.

  39. ryanofsky approved
  40. ryanofsky commented at 8:56 pm on June 27, 2024: contributor
    Code review ACK a74b0f93efa1d9eaf5abc2f6591c44a632aec6ed. Just new error string is added since last review, and a commit message was updated
  41. ryanofsky merged this on Jun 27, 2024
  42. ryanofsky closed this on Jun 27, 2024

  43. Sjors deleted the branch on Jun 28, 2024
  44. in src/rpc/mining.cpp:666 in a74b0f93ef
    662@@ -667,9 +663,7 @@ static RPCHelpMan getblocktemplate()
    663     ChainstateManager& chainman = EnsureChainman(node);
    664     Mining& miner = EnsureMining(node);
    665     LOCK(cs_main);
    666-    std::optional<uint256> maybe_tip{miner.getTipHash()};
    667-    CHECK_NONFATAL(maybe_tip);
    668-    uint256 tip{maybe_tip.value()};
    669+    uint256 tip{CHECK_NONFATAL(miner.getTipHash()).value()};
    


    maflcko commented at 7:20 am on June 28, 2024:
    nit: The same can be done below where tip is assigned again.

    Sjors commented at 8:57 am on June 28, 2024:
    Added to #30356.
  45. ryanofsky referenced this in commit ef19a193fc on Jul 18, 2024
  46. Theschorpioen approved

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: 2024-11-23 09:12 UTC

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