cut the validation <-> txmempool circular dependency 2/2 #22677

pull glozow wants to merge 5 commits into bitcoin:master from glozow:2021-08-circular-dep changing 5 files +70 −55
  1. glozow commented at 4:30 pm on August 10, 2021: member

    Remove 2 circular dependencies: validation - txmempool and validation - policy/rbf - txmempool

    Validation should depend on txmempool (e.g. CChainstateManager has a mempool and we often need to know what’s in our mempool to validate transactions), but txmempool is a data structure that shouldn’t really need to know about chain state.

    • Changes removeForReorg() to be parameterized by a callable that returns true/false (i.e. whether the transaction should be removed due to being now immature or nonfinal) instead of a CChainState. The mempool really shouldn’t need to know about coinbase maturity or lockpoints, it just needs to know which entries to remove.
  2. DrahtBot added the label Mempool on Aug 10, 2021
  3. DrahtBot added the label P2P on Aug 10, 2021
  4. DrahtBot added the label Validation on Aug 10, 2021
  5. JeremyRubin commented at 5:48 pm on August 10, 2021: contributor

    Hmm I’m mildly concept NACK on this refactoring; removeForReorg really feels like internal mempool functionality.

    Another tactic to remove the module links would be to make removeForReorg generic to any T ChainState class. Then you don’t need to have the specifics of the implementation of T known within mempool.

    (Circular deps within .cpp are not that bad IMO)

  6. DrahtBot commented at 6:51 pm on August 10, 2021: member

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

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #22282 (refactor: CheckFinalTx pass by reference instead of pointer by klementtan)
    • #10443 (Add fee_est tool for debugging fee estimation code by ryanofsky)

    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.

  7. fanquake commented at 2:44 am on August 11, 2021: member
     0validation.cpp:338:25: error: calling function 'TestLockPointValidity' requires holding mutex 'cs_main' exclusively [-Werror,-Wthread-safety-analysis]
     1        bool validLP =  TestLockPointValidity(m_chain, &lp);
     2                        ^
     3validation.cpp:339:41: error: calling function 'CoinsTip' requires holding mutex 'cs_main' exclusively [-Werror,-Wthread-safety-analysis]
     4        CCoinsViewMemPool view_mempool(&CoinsTip(), pool);
     5                                        ^
     6validation.cpp:340:14: error: calling function 'CheckFinalTx' requires holding mutex 'cs_main' exclusively [-Werror,-Wthread-safety-analysis]
     7        if (!CheckFinalTx(m_chain.Tip(), tx, flags)
     8             ^
     9validation.cpp:350:36: error: calling function 'CoinsTip' requires holding mutex 'cs_main' exclusively [-Werror,-Wthread-safety-analysis]
    10                const Coin &coin = CoinsTip().AccessCoin(txin.prevout);
    11                                   ^
    12validation.cpp:5113:5: error: calling function 'AssertLockHeldInternal<AnnotatedMixin<std::__1::recursive_mutex> >' requires holding mutex 'cs_main' exclusively [-Werror,-Wthread-safety-analysis]
    13    AssertLockHeld(::cs_main);
    14    ^
    15./sync.h:81:28: note: expanded from macro 'AssertLockHeld'
    16#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
    17                           ^
    18validation.cpp:5117:10: error: calling function 'check' requires holding mutex 'cs_main' exclusively [-Werror,-Wthread-safety-analysis]
    19    pool.check();
    20         ^
    21validation.cpp:5119:41: error: calling function 'CoinsTip' requires holding mutex 'cs_main' exclusively [-Werror,-Wthread-safety-analysis]
    22    CCoinsViewCache& active_coins_tip = CoinsTip();
    23                                        ^
    247 errors generated.
    
  8. glozow commented at 10:06 am on August 11, 2021: member

    removeForReorg really feels like internal mempool functionality. Another tactic to remove the module links would be to make removeForReorg generic to any T ChainState class. Then you don’t need to have the specifics of the implementation of T known within mempool.

    Yeah, I see this. Perhaps the function could instead be parametrized by tip, coins cache, etc?

  9. glozow force-pushed on Aug 18, 2021
  10. glozow commented at 8:34 pm on August 18, 2021: member
    I’ve pushed a version that splits out the finality checking part of removeForReorg (parts that require validation functions CheckSequenceLocks and CheckFinalTx) into validation, but leaves most of it in txmempool. Perhaps a better separation?
  11. JeremyRubin commented at 9:30 pm on August 18, 2021: contributor

    i don’t think so :/

    edit: it still feels like an abstraction layer leak, the for loop is inner functionality. Have you given parametrizing by CChainState. a try?

  12. glozow commented at 8:43 am on August 19, 2021: member
    @JeremyRubin CChainState is what it’s currently parametrized by - it’s what causes the dependency on validation.h
  13. glozow force-pushed on Aug 19, 2021
  14. glozow commented at 2:01 pm on August 19, 2021: member
    Ok new approach. I added something similar to the CConnman.ForEachNode so we can pass in a lambda that captures what we need from chainstate. Validation isn’t looking through mapTx anymore. The mempool gets a callable object and applies it to the entries internally.
  15. glozow force-pushed on Aug 19, 2021
  16. JeremyRubin commented at 9:24 pm on August 19, 2021: contributor
    i meant template paramterized by a generic ChainStateProvider type, that way it’s clean depedency wise.. will check out the new approach later.
  17. glozow referenced this in commit 3a2d809801 on Aug 20, 2021
  18. glozow referenced this in commit b001b9f6de on Aug 24, 2021
  19. fanquake referenced this in commit 81f4a3e84d on Aug 31, 2021
  20. michaelfolkson commented at 4:05 pm on September 2, 2021: contributor

    What’s the latest on this PR? Am I right in thinking that an approach hasn’t been settled on to avoid the circular dependency and that #22675 should be reviewed instead?

    edit: I guess this is just a RFC and draft PR so it is here in case an alternative approach is sketched out.

  21. mjdietzx referenced this in commit c7a696a86b on Sep 2, 2021
  22. glozow force-pushed on Sep 10, 2021
  23. glozow renamed this:
    [RFC] cut the validation <-> txmempool circular dependency
    cut the validation <-> txmempool circular dependency
    on Sep 10, 2021
  24. glozow force-pushed on Sep 10, 2021
  25. glozow marked this as ready for review on Sep 10, 2021
  26. glozow commented at 1:31 pm on September 10, 2021: member
    Fixed the CI issue. Ready for review.
  27. in src/txmempool.cpp:565 in ab3fef71ed outdated
    561@@ -563,39 +562,11 @@ void CTxMemPool::removeRecursive(const CTransaction &origTx, MemPoolRemovalReaso
    562         RemoveStaged(setAllRemoves, false, reason);
    563 }
    564 
    565-void CTxMemPool::removeForReorg(CChainState& active_chainstate, int flags)
    566+void CTxMemPool::removeForReorg(const setEntries& txToRemove)
    


    jnewbery commented at 3:35 pm on September 22, 2021:
    I wonder if this function should be made more generic, into RemoveWithDescendants(const setEntries& txToRemove, MemPoolRemovalReason reason), and then be called with MemPoolRemovalReason::REORG when removing transactions for a reorg. That’d deduplicate some of the code above in removeRecursive().

    glozow commented at 8:21 pm on September 29, 2021:
    Agree about consolidating duplicate code, but I don’t think it helps much with this PR - maybe for a followup?
  28. in src/validation.cpp:377 in ab3fef71ed outdated
    374+    {
    375+        AssertLockHeld(cs_main);
    376+        AssertLockHeld(m_mempool->cs);
    377+        const CTransaction& tx = it->GetTx();
    378+        LockPoints lp = it->GetLockPoints();
    379+        bool validLP =  TestLockPointValidity(m_chain, &lp);
    


    jnewbery commented at 3:44 pm on September 22, 2021:
    TestLockPointValidity() can now be static in validation.cpp, since it’s not used outside of that translation unit.
  29. in src/txmempool.cpp:633 in ab3fef71ed outdated
    575-        CCoinsViewMemPool view_mempool(&active_chainstate.CoinsTip(), *this);
    576-        if (!CheckFinalTx(active_chainstate.m_chain.Tip(), tx, flags)
    577-            || !CheckSequenceLocks(active_chainstate.m_chain.Tip(), view_mempool, tx, flags, &lp, validLP)) {
    578-            // Note if CheckSequenceLocks fails the LockPoints may still be invalid
    579-            // So it's critical that we remove the tx and not depend on the LockPoints.
    580-            txToRemove.insert(it);
    


    jnewbery commented at 3:46 pm on September 22, 2021:
    This line has now been replaced by return true; in the lambda, which means that the if (!validLP) conditional below is not executed if we enter this branch. Is that intentional? If so, can you justify why it’s safe to make that change?

    glozow commented at 8:17 pm on September 29, 2021:
    Good catch, switched it to be updating a bool should_remove and returning at the end instead :)
  30. in src/txmempool.cpp:731 in ab3fef71ed outdated
    654-void CTxMemPool::check(CChainState& active_chainstate) const
    655+void CTxMemPool::check() const
    656 {
    657     if (m_check_ratio == 0) return;
    658-
    659     if (GetRand(m_check_ratio) >= 1) return;
    


    jnewbery commented at 3:49 pm on September 22, 2021:
    This seems like a behaviour change. Since CTxMemPool::check() is now called by CChainState::CheckMempool(), which itself has if (GetRand(check_ratio) >= 1) return;, then these checks will only get run 1/n^2 times.

    glozow commented at 8:18 pm on September 29, 2021:
    keeping check_ratio checking inside the mempool function now
  31. in src/net_processing.cpp:2301 in ab3fef71ed outdated
    2287@@ -2288,7 +2288,7 @@ void PeerManagerImpl::ProcessOrphanTx(std::set<uint256>& orphan_work_set)
    2288             break;
    2289         }
    2290     }
    2291-    m_mempool.check(m_chainman.ActiveChainstate());
    


    jnewbery commented at 4:07 pm on September 22, 2021:

    It’d be nice to remove these calls to mempool.check() from net_processing. It shouldn’t be the client’s responsibility to call into validation/mempool to check its invariants.

    The diff is really easy:

     0iff --git a/src/net_processing.cpp b/src/net_processing.cpp
     1index 80655c61e7..636b4d1102 100644
     2--- a/src/net_processing.cpp
     3+++ b/src/net_processing.cpp
     4@@ -2288,7 +2288,6 @@ void PeerManagerImpl::ProcessOrphanTx(std::set<uint256>& orphan_work_set)
     5             break;
     6         }
     7     }
     8-    m_mempool.check(m_chainman.ActiveChainstate());
     9 }
    10 
    11 bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& peer,
    12@@ -3250,7 +3249,6 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
    13         const TxValidationState& state = result.m_state;
    14 
    15         if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
    16-            m_mempool.check(m_chainman.ActiveChainstate());
    17             // As this version of the transaction was acceptable, we can forget about any
    18             // requests for it.
    19             m_txrequest.ForgetTxHash(tx.GetHash());
    20diff --git a/src/validation.cpp b/src/validation.cpp
    21index 2a66d96f22..8f1f33782b 100644
    22--- a/src/validation.cpp
    23+++ b/src/validation.cpp
    24@@ -1041,7 +1041,9 @@ static MempoolAcceptResult AcceptToMemoryPoolWithTime(const CChainParams& chainp
    25 MempoolAcceptResult AcceptToMemoryPool(CChainState& active_chainstate, CTxMemPool& pool, const CTransactionRef& tx,
    26                                        bool bypass_limits, bool test_accept)
    27 {
    28-    return AcceptToMemoryPoolWithTime(Params(), pool, active_chainstate, tx, GetTime(), bypass_limits, test_accept);
    29+    auto ret = AcceptToMemoryPoolWithTime(Params(), pool, active_chainstate, tx, GetTime(), bypass_limits, test_accept);
    30+    pool.check(active_chainstate);
    31+    return ret;
    32 }
    33 
    34 PackageMempoolAcceptResult ProcessNewPackage(CChainState& active_chainstate, CTxMemPool& pool,
    

    branch here: https://github.com/jnewbery/bitcoin/tree/2021-09-no-mempool-check-in-net-processing

    That’s a slight behaviour change since check() will get called a little more often, so it doesn’t fit inside this PR, but by doing it first, this PR wouldn’t need to touch net_processing. Thoughts?


    glozow commented at 8:20 pm on September 29, 2021:

    Didn’t end up taking this change, though I tried to at first, because I agree that it should be the mempool, or at the very least, chainstate manager’s job to sanity check the mempool, not net processing.

    The problem is that we call ATMP from the reorg code, and we shouldn’t call check() then because the mempool can temporarily be in a state where not all inputs are available from the chainstate coins cache. This causes the check() assertions to fail.


    jnewbery commented at 3:18 pm on September 30, 2021:

    The problem is that we call ATMP from the reorg code, and we shouldn’t call check() then because the mempool can temporarily be in a state where not all inputs are available from the chainstate coins cache. This causes the check() assertions to fail.

    Yes, I’d forgotten that ATMP could be called while the mempool is in an inconsistent state.

    The fix is to only call check() after ATMP has been called from outside validation. I have a branch that implements a ChainstateManager.ProcessTransaction() interface method which does exactly that: https://github.com/jnewbery/bitcoin/tree/2021-09-process-transaction. I’ll probably go ahead and PR that soon unless you think it should wait until after this PR.

  32. jnewbery commented at 4:15 pm on September 22, 2021: member

    Concept ACK!

    I’ve left a few comments inline. Another couple of comments on the git history:

    1.

    Commit 3 ([mempool] split CTxMemPool::check into contextual and internal parts) claims to be no behaviour change, but the new internal check() method is not called by external check(CChainState& active_chainstate) method. That is restored in a later commit, but it should be included in commit 3 to make the commits hygenic (and the later commit MOVEONLY: contextual mempool check to validation would be more move-only)

    2.

    It’d be nice if the MOVEONLY: contextual mempool check to validation commit had fewer non-move changes so that using git diff --color-moved=dimmed-zebra --color-moved-ws=ignore-all-space would obviously show that the code really is just moving. Are you able to rename variables inside check(), so that the changes are minimal in the move. Same for the MOVEONLY: filtering nonfinal/immature transactions to validation commit.

  33. glozow force-pushed on Sep 29, 2021
  34. glozow force-pushed on Sep 30, 2021
  35. glozow force-pushed on Sep 30, 2021
  36. glozow commented at 12:49 pm on September 30, 2021: member

    I’ve changed the circular dependency-breaking to be as minimal as possible. The check() function is now parametrized by a coins cache and spend height rather than chainstate. The removeForReorg() function now takes a callable object to apply to each mempool entry, removing the ones for which it returns true.

    I’ve also written a bench for these 2 functions and taken the opportunity to speed check() up by eliminating the need to check mempool entries more than once. My bench results show a 35% speedup. Hopefully the performance improvement + circular dependency break is good enough to motivate these changes.

    Bench at commit when the benchmark is first introduced: image

    Bench at HEAD of this PR: image

  37. glozow removed the label P2P on Sep 30, 2021
  38. glozow added the label Refactoring on Sep 30, 2021
  39. in src/validation.cpp:360 in 48a5b1b3eb outdated
    372+        bool should_remove = false;
    373+        AssertLockHeld(m_mempool->cs);
    374+        AssertLockHeld(::cs_main);
    375+        const CTransaction& tx = it->GetTx();
    376+        LockPoints lp = it->GetLockPoints();
    377+        bool validLP = TestLockPointValidity(m_chain, &lp);
    


    jnewbery commented at 3:13 pm on September 30, 2021:
    TestLockPointValidity() can now be static since it’s not called from outside this translation unit.

    glozow commented at 12:32 pm on October 1, 2021:
    Done
  40. glozow force-pushed on Oct 1, 2021
  41. glozow commented at 11:44 am on October 1, 2021: member
    Rebased, addressed @jnewbery’s comment, and separated the benches because it’s a bit misleading to group them.
  42. glozow force-pushed on Oct 1, 2021
  43. glozow renamed this:
    cut the validation <-> txmempool circular dependency
    cut the validation <-> txmempool circular dependency 2/2
    on Oct 1, 2021
  44. glozow commented at 4:09 pm on October 1, 2021: member
    Split the PR up - first half is in #23157.
  45. glozow force-pushed on Oct 25, 2021
  46. glozow commented at 1:44 pm on October 25, 2021: member
    Rebased
  47. mjdietzx commented at 1:50 am on October 29, 2021: contributor

    Code review ACK b5de6cc10bfbc8174936c3e8ae9418dedfb60000

    Very nicely done as usual. I also did some light testing - built locally, unit tests pass, also ran the functional tests I added in #22867 and those still pass ✅

  48. theStack approved
  49. theStack commented at 3:17 pm on November 12, 2021: member

    Code-review ACK b5de6cc10bfbc8174936c3e8ae9418dedfb60000

    TIL that lambda captures can also be used to define new variables/constant, rather than just capturing existing ones (as done for flags).

  50. MarcoFalke commented at 4:08 pm on November 12, 2021: member
    Needs rebase?
  51. glozow commented at 4:23 pm on November 15, 2021: member
    Thanks @MarcoFalke! silent merge conflict with #23211. Need to rethink approach since it’s no longer possible to modify lockpoints from outside txmempool…
  52. MarcoFalke commented at 4:33 pm on November 15, 2021: member
    That was a move-only, so can be reverted if needed. Maybe a struct update_lock_points; forward decl is enough?
  53. glozow commented at 4:47 pm on November 15, 2021: member

    That was a move-only, so can be reverted if needed. Maybe a struct update_lock_points; forward decl is enough?

    Forward decl isn’t enough because we need the constructor in order to call update_lock_points(lp).

    Currently, I’m leaning towards splitting removeForReorg into 2 loops: CheckLockPoints (leave inside txmempool) and RemoveNonFinalAndPremature (move to validation). There shouldn’t be a performance penalty.

    Reverting is also an option. I’m currently trying to figure out whether that’s better. AFAICT, the update_* structs help provide an interface to modifying mempool entries while keeping the txiter type const (txmempool passes txiters and setEntriess to outside callers pretty freely). But since all modifications to entries should be done through txmempool’s public member functions, perhaps it’s better for them to be private. Will investigate further.

  54. MOVEONLY: TestLockPointValidity to txmempool 1b3a11e126
  55. [mempool] only update lockpoints for non-removed entries
    Each entry's lockpoints are independent of one another, so there isn't
    any reason to update lockpoints for entries that will be removed.
    Separating the loops also allows us to move validation logic out and
    leave lockpoints in txmempool.
    bedf246f1e
  56. [refactor] put finality and maturity checking into a lambda
    No behavior change.
    bb9078ed51
  57. [mempool] always assert coin spent
    This is an extremely cheap function (just checks that the coin CTxOut
    isn't null) that doesn't need to be gated on check_ratio.
    64e4963c63
  58. Break validation <-> txmempool circular dependency
    No behavior change.
    
    Parameterize removeForReorg using a CChain and callable that
    encapsulates validation logic.  The mempool shouldn't need to know a
    bunch of details about coinbase maturity and lock finality. Instead,
    just pass in a callable function that says true/false. Breaks circular
    dependency by removing txmempool's dependency on validation.
    a64078e385
  59. glozow force-pushed on Nov 30, 2021
  60. glozow commented at 12:30 pm on November 30, 2021: member
    Rebased. If you have time, please take another look @mjdietzx @theStack @MarcoFalke?
  61. laanwj commented at 5:52 pm on November 30, 2021: member
    Code review ACK a64078e38563ef3ac5e5ec20c07569441c87eeee
  62. in src/txmempool.h:17 in 1b3a11e126 outdated
    13@@ -14,6 +14,7 @@
    14 #include <utility>
    15 #include <vector>
    16 
    17+#include <chain.h>
    


    theStack commented at 10:27 am on December 1, 2021:
    nit: could use the forward-declaration class CChain; instead to reduce header dependencies

    glozow commented at 2:57 pm on December 2, 2021:
    taken in #23649
  63. theStack approved
  64. theStack commented at 10:37 am on December 1, 2021: member
    re-ACK a64078e38563ef3ac5e5ec20c07569441c87eeee
  65. mjdietzx commented at 2:53 pm on December 1, 2021: contributor
    reACK a64078e38563ef3ac5e5ec20c07569441c87eeee
  66. MarcoFalke merged this on Dec 1, 2021
  67. MarcoFalke closed this on Dec 1, 2021

  68. in src/txmempool.cpp:672 in bedf246f1e outdated
    670     setEntries setAllRemoves;
    671     for (txiter it : txToRemove) {
    672         CalculateDescendants(it, setAllRemoves);
    673     }
    674     RemoveStaged(setAllRemoves, false, MemPoolRemovalReason::REORG);
    675+    auto chain = active_chainstate.m_chain;
    


    MarcoFalke commented at 5:19 pm on December 1, 2021:

    bedf246f1e2497a3641093c6e8fa11fb34dddac4:

    Is this creating a copy of a vector holding 1kk elements for no reason?


    glozow commented at 11:16 am on December 2, 2021:
    woop, should have declared as auto&. The good thing is it’s removed in the last commit?
  69. in src/txmempool.cpp:675 in bedf246f1e outdated
    673     }
    674     RemoveStaged(setAllRemoves, false, MemPoolRemovalReason::REORG);
    675+    auto chain = active_chainstate.m_chain;
    676+    for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
    677+        LockPoints lp = it->GetLockPoints();
    678+        if (!TestLockPointValidity(chain, &lp)) {
    


    MarcoFalke commented at 5:20 pm on December 1, 2021:
    unrelated: Seems a bit confusing to pass a pointer here. Usually this means the memory it points to will be modified. However, in this case lp can be const.

    MarcoFalke commented at 3:39 pm on December 3, 2021:

    Actually bedf246f1e2497a3641093c6e8fa11fb34dddac4 is wrong.

    CheckSequenceLocks modifies lp, so dropping it and using a fresh lp here from GetLockPoints is illegal.


    glozow commented at 5:44 pm on December 3, 2021:
    Oof, that’s not good. Can be fixed by moving update_lock_points back to txmempool.h and updating lockpoints within the lambda (original approach in b5de6cc10bfbc8174936c3e8ae9418dedfb60000). Should I open a pull with that?

    hebasto commented at 7:30 pm on December 29, 2021:

    Actually bedf246 is wrong.

    CheckSequenceLocks modifies lp, so dropping it and using a fresh lp here from GetLockPoints is illegal.

    #23897 aims to make it less fragile in the future.

  70. in src/txmempool.cpp:645 in bedf246f1e outdated
    641@@ -642,7 +642,7 @@ void CTxMemPool::removeForReorg(CChainState& active_chainstate, int flags)
    642     for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
    643         const CTransaction& tx = it->GetTx();
    644         LockPoints lp = it->GetLockPoints();
    645-        bool validLP =  TestLockPointValidity(active_chainstate.m_chain, &lp);
    646+        const bool validLP = TestLockPointValidity(active_chainstate.m_chain, &lp);
    


    MarcoFalke commented at 5:21 pm on December 1, 2021:
    nit: Could use {} instead of = to enable more compile time checks.
  71. in src/validation.cpp:360 in a64078e385
    355+        bool should_remove = false;
    356+        AssertLockHeld(m_mempool->cs);
    357+        AssertLockHeld(::cs_main);
    358+        const CTransaction& tx = it->GetTx();
    359+        LockPoints lp = it->GetLockPoints();
    360+        bool validLP = TestLockPointValidity(m_chain, &lp);
    


    MarcoFalke commented at 5:39 pm on December 1, 2021:
    why add a const first and then remove it again?
  72. in src/validation.cpp:375 in a64078e385
    370+                if (it2 != m_mempool->mapTx.end())
    371+                    continue;
    372+                const Coin &coin = CoinsTip().AccessCoin(txin.prevout);
    373+                assert(!coin.IsSpent());
    374+                unsigned int nMemPoolHeight = m_chain.Tip()->nHeight + 1;
    375+                if (coin.IsSpent() || (coin.IsCoinBase() && ((signed long)nMemPoolHeight) - coin.nHeight < COINBASE_MATURITY)) {
    


    MarcoFalke commented at 5:42 pm on December 1, 2021:
    unrelated, but it seems a bit odd to have an integer and cast it three times for no reason. int->unsigned->signed long

    glozow commented at 12:07 pm on December 2, 2021:
    Done in #23649
  73. MarcoFalke commented at 5:42 pm on December 1, 2021: member
    left comments
  74. glozow deleted the branch on Dec 2, 2021
  75. sidhujag referenced this in commit 5409965454 on Dec 2, 2021
  76. fanquake referenced this in commit ffe414bd9a on Dec 3, 2021
  77. MarcoFalke added the label Bug on Dec 3, 2021
  78. MarcoFalke removed the label Refactoring on Dec 3, 2021
  79. MarcoFalke commented at 3:40 pm on December 3, 2021: member
    This is not refactoring, but introducing a bug: #22677 (review)
  80. MarcoFalke referenced this in commit c09b41dc66 on Dec 15, 2021
  81. RandyMcMillan referenced this in commit 0d88113a46 on Dec 23, 2021
  82. MarcoFalke referenced this in commit 75a227e39e on Jan 3, 2022
  83. sidhujag referenced this in commit f76bc09f0e on Jan 4, 2022
  84. Fabcien referenced this in commit bd99a74d3e on Nov 10, 2022
  85. Fabcien referenced this in commit 848f2f48c2 on Nov 10, 2022
  86. Fabcien referenced this in commit 7ebe2bd935 on Nov 10, 2022
  87. Fabcien referenced this in commit 93a3ae2a01 on Nov 10, 2022
  88. Fabcien referenced this in commit d470c5fe05 on Nov 10, 2022
  89. DrahtBot locked this on Dec 29, 2022

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-06-26 16:12 UTC

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