tests: Create or use existing properly initialized NodeContexts #20323

pull dongcarl wants to merge 2 commits into bitcoin:master from dongcarl:2020-10-chainman-fixes changing 4 files +88 −73
  1. dongcarl commented at 6:56 pm on November 5, 2020: member

    This is part 1/n of the effort to de-globalize ChainstateManager

    Reviewers: Looking for tested/Code-Review/plain-ACKs

    Context

    In many of our tests, we manually instantiate NodeContexts or ChainstateManagers in the test code, which is error prone. Instead, we should create or use existing references because:

    1. Before we de-globalize ChainstateManager, much of our code still acts on g_chainman (our global ChainstateManager), sometimes even when you’re calling a method on a specific instance of ChainstateManager! This means that we may act on two instances of ChainstateManager, which is most likely not what we want.
    2. Using existing references (initialized by the {Basic,}TestingSetup constructors) means that you’re acting on objects which are properly initialized, instead of “just initialized enough for this dang test to pass”. Also, they’re already there! It’s free!
    3. By acting on the right object, we also allow the review-only assertions in future commits of de-globalize ChainstateManager to work and demonstrate correctness.

    Some more detailed debugging notes can be found in the first commit, reproduced below:

     0Previously, the validation_chainstatemanager_tests test suite
     1instantiated its own duplicate ChainstateManager on which tests were
     2performed.
     3
     4This wasn't a problem for the specific actions performed in
     5that suite. However, the existence of this duplicate ChainstateManager
     6and the fact that many of our validation static functions reach for
     7g_chainman, ::Chain(state|)Active means we may end up acting on two
     8different CChainStates should we write more extensive tests in the
     9future.
    10
    11This change adds a new ChainTestingSetup which performs all
    12initialization previously done by TestingSetup except:
    13
    141. Mempool sanity check frequency setting
    152. ChainState initialization
    163. Genesis Activation
    174. {Ban,Conn,Peer}Man initialization
    18
    19Means that we will no longer need to initialize a duplicate
    20ChainstateManger in order to test the initialization codepaths of
    21CChainState and ChainstateManager.
    22
    23Lastly, this change has the additional benefit of allowing for
    24review-only assertions meant to show correctness to work in future work
    25de-globalizing g_chainman.
    26
    27In the test chainstatemanager_rebalance_caches, an additional
    28LoadGenesisBlock call is added as MaybeReblanaceCaches eventually calls
    29FlushBlockFile, which tries to access vinfoBlockFile[nLastBlockFile],
    30which is out of bounds when LoadGenesisBlock hasn't been called yet.
    31
    32-----
    33
    34Note for the future:
    35
    36In a previous version of this change, I put ChainTestingSetup between
    37BasicTestingSetup and TestingSetup such that TestingSetup inherited from
    38ChainTestingSetup.
    39
    40This was suboptimal, and showed how the class con/destructor inheritance
    41structure we have for these TestingSetup classes is probably not the
    42most suitable abstraction. In particular, for both TestingSetup and
    43ChainTestingSetup, we need to stop the scheduler first before anything
    44else. Otherwise classes depending on the scheduler may be referenced
    45by the scheduler after said classes are freed. This means that there's
    46no clear parallel between our teardown code and C++'s destructuring
    47order for class hierarchies.
    48
    49Future work should strive to coalesce (as much as possible) test and
    50non-test init codepaths and perhaps structure it in a more fail-proof
    51way.
    
  2. jnewbery commented at 7:38 pm on November 5, 2020: member
    Concept ACK. Thanks for moving ChainTestingSetup into validation_chainstatemanager_tests.cpp!
  3. practicalswift commented at 8:05 pm on November 5, 2020: contributor
    Concept ACK
  4. DrahtBot added the label GUI on Nov 5, 2020
  5. DrahtBot added the label Wallet on Nov 5, 2020
  6. dongcarl added the label Tests on Nov 5, 2020
  7. DrahtBot commented at 9:12 pm on November 5, 2020: 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:

    • #20228 (addrman: Make addrman a top-level component by jnewbery)
    • #20217 (net: Remove g_relay_txes by jnewbery)
    • #19064 (refactor: Cleanup thread ctor calls by hebasto)
    • #18731 (refactor: Make CCheckQueue RAII-styled by hebasto)

    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.

  8. ryanofsky approved
  9. ryanofsky commented at 4:22 pm on November 10, 2020: member
    Code review ACK 39387634834a1ef06e587b30fa42a781ce45e460. Obvious ACK. This is just test changes and the first 4 commits from #20158 with commit descriptions tweaked and improved
  10. in src/test/validation_chainstatemanager_tests.cpp:24 in 3938763483 outdated
    17@@ -15,15 +18,62 @@
    18 
    19 #include <boost/test/unit_test.hpp>
    20 
    21-BOOST_FIXTURE_TEST_SUITE(validation_chainstatemanager_tests, TestingSetup)
    22+struct ChainTestingSetup : public BasicTestingSetup {
    23+    boost::thread_group threadGroup;
    24+
    25+    explicit ChainTestingSetup(const std::string& chainName = CBaseChainParams::MAIN, const std::vector<const char*>& extra_args = {})
    


    jnewbery commented at 5:07 pm on November 10, 2020:
    You don’t need these ctor arguments. Just remove them and call BasicTestingSetup() (which will use the default arguments for its constructor).
  11. in src/test/validation_chainstatemanager_tests.cpp:29 in 3938763483 outdated
    25+    explicit ChainTestingSetup(const std::string& chainName = CBaseChainParams::MAIN, const std::vector<const char*>& extra_args = {})
    26+        : BasicTestingSetup(chainName, extra_args)
    27+    {
    28+        // Ideally we'd move all the RPC tests to the functional testing framework
    29+        // instead of unit tests, but for now we need these here.
    30+        RegisterAllCoreRPCCommands(tableRPC);
    


    jnewbery commented at 5:07 pm on November 10, 2020:
    Not needed. Remove.
  12. in src/test/validation_chainstatemanager_tests.cpp:31 in 3938763483 outdated
    27+    {
    28+        // Ideally we'd move all the RPC tests to the functional testing framework
    29+        // instead of unit tests, but for now we need these here.
    30+        RegisterAllCoreRPCCommands(tableRPC);
    31+
    32+        m_node.scheduler = MakeUnique<CScheduler>();
    


    jnewbery commented at 5:07 pm on November 10, 2020:
    I’d suggest moving this below the “We have to run…” comment, since it fits with the code there.
  13. in src/test/validation_chainstatemanager_tests.cpp:51 in 3938763483 outdated
    53+        if (m_node.scheduler) m_node.scheduler->stop();
    54+        threadGroup.interrupt_all();
    55+        threadGroup.join_all();
    56+        GetMainSignals().FlushBackgroundCallbacks();
    57+        GetMainSignals().UnregisterBackgroundSignalScheduler();
    58+        m_node.args = nullptr;
    


    jnewbery commented at 5:08 pm on November 10, 2020:
    Remove this line.

    dongcarl commented at 6:59 pm on November 10, 2020:
    I copied this from ~TestingSetup, is there a reason why this is needed there and not here?

    MarcoFalke commented at 7:11 pm on November 10, 2020:

    It’s a bit odd to have the low level code copied here, and require modifying src/test/validation_chainstatemanager_tests.cpp whenever the testing setup is upgraded.

    wouldn’t it be possible to simply keep using the TestingSetup here, like the tests did previously, and then do specific undo-hacks (hopefully less code) to unload the chainstates (and/or whatever else is required)


    jnewbery commented at 7:30 pm on November 10, 2020:
    oops. My mistake. This should be left. I was confusing it with the RPC registration/deregistration.

    dongcarl commented at 0:22 am on November 17, 2020:

    @MarcoFalke I assume you mean something like:

     0diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp
     1index 34e5723964..664405fc5e 100644
     2--- a/src/test/validation_chainstatemanager_tests.cpp
     3+++ b/src/test/validation_chainstatemanager_tests.cpp
     4@@ -17,48 +17,7 @@
     5 
     6 #include <boost/test/unit_test.hpp>
     7 
     8-struct ChainTestingSetup : public BasicTestingSetup {
     9-    boost::thread_group threadGroup;
    10-
    11-    explicit ChainTestingSetup()
    12-        : BasicTestingSetup()
    13-    {
    14-        // We have to run a scheduler thread to prevent ActivateBestChain
    15-        // from blocking due to queue overrun.
    16-        m_node.scheduler = MakeUnique<CScheduler>();
    17-        threadGroup.create_thread([&] { TraceThread("scheduler", [&] { m_node.scheduler->serviceQueue(); }); });
    18-        GetMainSignals().RegisterBackgroundSignalScheduler(*m_node.scheduler);
    19-
    20-        pblocktree.reset(new CBlockTreeDB(1 << 20, true));
    21-
    22-        m_node.mempool = MakeUnique<CTxMemPool>(&::feeEstimator);
    23-
    24-        m_node.chainman = &::g_chainman;
    25-
    26-        // Start script-checking threads. Set g_parallel_script_checks to true so they are used.
    27-        constexpr int script_check_threads = 2;
    28-        for (int i = 0; i < script_check_threads; ++i) {
    29-            threadGroup.create_thread([i]() { return ThreadScriptCheck(i); });
    30-        }
    31-        g_parallel_script_checks = true;
    32-    }
    33-    ~ChainTestingSetup() {
    34-        if (m_node.scheduler) m_node.scheduler->stop();
    35-        threadGroup.interrupt_all();
    36-        threadGroup.join_all();
    37-        GetMainSignals().FlushBackgroundCallbacks();
    38-        GetMainSignals().UnregisterBackgroundSignalScheduler();
    39-        m_node.args = nullptr;
    40-        UnloadBlockIndex(m_node.mempool.get(), *m_node.chainman);
    41-        m_node.mempool.reset();
    42-        m_node.scheduler.reset();
    43-        m_node.chainman->Reset();
    44-        m_node.chainman = nullptr;
    45-        pblocktree.reset();
    46-    }
    47-};
    48-
    49-BOOST_FIXTURE_TEST_SUITE(validation_chainstatemanager_tests, ChainTestingSetup)
    50+BOOST_FIXTURE_TEST_SUITE(validation_chainstatemanager_tests, TestingSetup)
    51 
    52 //! Basic tests for ChainstateManager.
    53 //!
    54@@ -68,6 +27,9 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
    55     ChainstateManager& manager = *m_node.chainman;
    56     CTxMemPool& mempool = *m_node.mempool;
    57 
    58+    UnloadBlockIndex(nullptr, manager);
    59+    manager.Reset();
    60+
    61     std::vector<CChainState*> chainstates;
    62     const CChainParams& chainparams = Params();
    63 
    64@@ -151,6 +113,9 @@ BOOST_AUTO_TEST_CASE(chainstatemanager_rebalance_caches)
    65     ChainstateManager& manager = *m_node.chainman;
    66     CTxMemPool& mempool = *m_node.mempool;
    67 
    68+    UnloadBlockIndex(nullptr, manager);
    69+    manager.Reset();
    70+
    71     size_t max_cache = 10000;
    72     manager.m_total_coinsdb_cache = max_cache;
    73     manager.m_total_coinstip_cache = max_cache;
    

    I found it hard to convince myself that UnloadBlockIndex and Reset cleanly resets everything exactly to before ActivateBestChain is run, which is why I thought repetition wasn’t such a bad thing here. Let me know if I’m missing anything though.

  14. in src/test/validation_chainstatemanager_tests.cpp:9 in 3938763483 outdated
    4@@ -5,6 +5,9 @@
    5 #include <chainparams.h>
    6 #include <consensus/validation.h>
    7 #include <random.h>
    8+#include <rpc/register.h>
    9+#include <rpc/server.h>
    


    jnewbery commented at 5:09 pm on November 10, 2020:
    Remove
  15. jnewbery commented at 5:11 pm on November 10, 2020: member

    utACK 39387634834a1ef06e587b30fa42a781ce45e460

    Some suggestions to remove unneeded code inline.

  16. MarcoFalke removed the label GUI on Nov 10, 2020
  17. MarcoFalke removed the label Wallet on Nov 10, 2020
  18. promag commented at 11:22 am on November 14, 2020: member
    Concept ACK.
  19. dongcarl force-pushed on Nov 16, 2020
  20. dongcarl commented at 5:35 pm on November 17, 2020: member

    Addressed a few comments.


    fuzz CI failing because of #20188 (comment).

  21. dongcarl force-pushed on Nov 24, 2020
  22. ryanofsky approved
  23. ryanofsky commented at 4:35 pm on December 1, 2020: member
    Code review ACK 1319b17e15dfd5a3a6bbf3c67b98fcce72c80812. Only changes since last review were suggested simplifications to ChainTestingSetup constructor
  24. ryanofsky commented at 4:38 pm on December 1, 2020: member
    Hopefully as a test-only cleanup PR with a lot of other changes building on top it (#20158), this can be merged soon
  25. MarcoFalke commented at 4:46 pm on December 1, 2020: member
    Reason I didn’t merge this is that this overlaps with the test changes here: #19425#pullrequestreview-534180561. Though there have been outstanding questions and those questions also apply to this pull (in the extent that they overlap).
  26. in src/test/validation_chainstatemanager_tests.cpp:170 in 43c880afbc outdated
    166@@ -122,6 +167,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager_rebalance_caches)
    167     {
    168         LOCK(::cs_main);
    169         c1.InitCoinsCache(1 << 23);
    170+        assert(c1.LoadGenesisBlock(Params()));
    


    ryanofsky commented at 5:17 pm on December 1, 2020:

    In commit “test: Add new ChainTestingSetup and use it” (43c880afbcafa9796c838518722594940af69b7d)

    Would suggest using BOOST_REQUIRE instead of assert or splitting as bool loaded = c1.LoadGenesisBlock(Params()); assert(loaded);. Writing code with side effects in an assert adds some ambiguity because behavior will depend on value of NDEBUG


    dongcarl commented at 6:24 pm on December 3, 2020:
    Oh! Didn’t know about NDEBUG… So when NDEBUG is set, the code inside assert(...) may be optimized out? Or is it the case that only the result isn’t checked/asserted?
  27. ryanofsky commented at 5:29 pm on December 1, 2020: member

    Reason I didn’t merge this is that this overlaps with the test changes here: #19425 (review). Though there have been outstanding questions and those questions also apply to this pull (in the extent that they overlap).

    Thanks. I guess I need to rebase #19425. I’ll check out the test changes too there and make updates if needed to make sure they are compatible with this PR.

    This PR just takes approach of having fewer duplicate disconnected state objects inside tests, so I don’t think there are real questions about it or major drawbacks. But if anyone has concerns or questions (even vague ones), it’d be good to post something so Carl can reply and this work doesn’t languish

  28. jnewbery commented at 11:31 am on December 4, 2020: member
    utACK 1319b17e15dfd5a3a6bbf3c67b98fcce72c80812
  29. dongcarl force-pushed on Dec 4, 2020
  30. dongcarl commented at 9:40 pm on December 4, 2020: member

    Pushed 1319b17e15dfd5a3a6bbf3c67b98fcce72c80812 -> 11fac8b2c8001e9aee9debb20df09473b9092b8c:

    1. Rebased over master for #20222
    2. Changed asserts in tests to BOOST_REQUIRE as recommended: #20323 (review)
    3. Extracted out testing app initialization and destruction logic into TestingAppInitSequence and TestingAppDestructionSequence to improve sync and decrease maintenance burden between ChainTestingSetup and TestingSetup to address: #20323 (review)

    In (3), ordering-wise, the script-checking thread initialization was moved up to before the chainstate gets initialized and RPC command registration was moved down. Neither of which should have any tangible effect on the correctness of initialization.

    I can also remove the bool chain_testing_only argument to TestingAppDestructionSequence as it’s a mostly idempotent sequence, somehow I like the self-documentation and symmetry. Let me know what seems better!

  31. jnewbery commented at 10:34 am on December 7, 2020: member

    I’ve had a quick look through the new branch and find the TestingAppInitSequence() and TestingAppDestructionSequence() less clear than the previous version. In general functions that take a bool argument which substantially changes the logic inside that function (in this case chain_testing_only), suggest that the abstraction may be wrong.

    Was there an actual problem with the previous branch, or are you just trying to reduce code duplication?

  32. in src/test/util/setup_common.cpp:188 in 11fac8b2c8 outdated
    232-    m_node.chainman->Reset();
    233-    m_node.chainman = nullptr;
    234+    if (!chain_testing_only) {
    235+        node.connman.reset();
    236+        node.banman.reset();
    237+    }
    


    MarcoFalke commented at 10:45 am on December 7, 2020:
    any reason for the modifications here? reset is idempotent , so doesn’t need to be guarded.
  33. in src/test/validation_chainstatemanager_tests.cpp:20 in 11fac8b2c8 outdated
    16@@ -15,15 +17,31 @@
    17 
    18 #include <boost/test/unit_test.hpp>
    19 
    20-BOOST_FIXTURE_TEST_SUITE(validation_chainstatemanager_tests, TestingSetup)
    21+struct ChainTestingSetup : public BasicTestingSetup {
    


    MarcoFalke commented at 10:47 am on December 7, 2020:
    Any reason to add this here and not to setup_common? Moving it to setup_common would allow removing the confusing TestingAppInitSequence declarations in the header. Also, it would allow other tests to use the ChainTestingSetup.
  34. in src/test/util/setup_common.cpp:147 in 11fac8b2c8 outdated
    178-    m_node.peerman = MakeUnique<PeerManager>(chainparams, *m_node.connman, m_node.banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool);
    179-    {
    180-        CConnman::Options options;
    181-        options.m_msgproc = m_node.peerman.get();
    182-        m_node.connman->Init(options);
    183+    if (!chain_testing_only) {
    


    MarcoFalke commented at 10:49 am on December 7, 2020:
    Agree with john that functions that have a large branch (and a boolean arg) are better split off into two functions
  35. MarcoFalke commented at 10:49 am on December 7, 2020: member
    left some comments
  36. DrahtBot added the label Needs rebase on Dec 7, 2020
  37. ryanofsky approved
  38. ryanofsky commented at 0:09 am on December 8, 2020: member

    Code review ACK 11fac8b2c8001e9aee9debb20df09473b9092b8c. Changes since last review are deduping test init functions and replacing asserts (thanks!).

    Other review suggestions for splitting up functions instead of using a bool arguments seem reasonable.

    Another idea (not sure whether it is good or applicable): an alternative to calling pairs of functions in constructors and destructors is to just add class members. Member constructors will run in containing class’s default constructor, and same with destructors. Seems like this would allow getting rid of the 4 one-line constructor/destructors.

  39. qt/test: [FIX] Add forgotten Context setting in RPCNestedTests 7e9e7fe567
  40. test: Add new ChainTestingSetup and use it
    Previously, the validation_chainstatemanager_tests test suite
    instantiated its own duplicate ChainstateManager on which tests were
    performed.
    
    This wasn't a problem for the specific actions performed in
    that suite. However, the existence of this duplicate ChainstateManager
    and the fact that many of our validation static functions reach for
    g_chainman, ::Chain(state|)Active means we may end up acting on two
    different CChainStates should we write more extensive tests in the
    future.
    
    This change adds a new ChainTestingSetup which performs all
    initialization previously done by TestingSetup except:
    
    1. RPC command registration
    2. ChainState initialization
    3. Genesis Activation
    4. {Ban,Conn,Peer}Man initialization
    
    Means that we will no longer need to initialize a duplicate
    ChainstateManger in order to test the initialization codepaths of
    CChainState and ChainstateManager.
    
    Lastly, this change has the additional benefit of allowing for
    review-only assertions meant to show correctness to work in future work
    de-globalizing g_chainman.
    
    In the test chainstatemanager_rebalance_caches, an additional
    LoadGenesisBlock call is added as MaybeReblanaceCaches eventually calls
    FlushBlockFile, which tries to access vinfoBlockFile[nLastBlockFile],
    which is out of bounds when LoadGenesisBlock hasn't been called yet.
    
    -----
    
    Note for the future:
    
    The class con/destructor inheritance structure we have for these
    TestingSetup classes is probably not the most suitable abstraction. In
    particular, for both TestingSetup and ChainTestingSetup, we need to stop
    the scheduler first before anything else. Otherwise classes depending on
    the scheduler may be referenced by the scheduler after said classes are
    freed. This means that there's no clear parallel between our teardown
    code and C++'s destructuring order for class hierarchies.
    
    Future work should strive to coalesce (as much as possible) test and
    non-test init codepaths and perhaps structure it in a more fail-proof
    way.
    81137c60fe
  41. dongcarl force-pushed on Dec 8, 2020
  42. dongcarl commented at 8:10 pm on December 8, 2020: member

    Thanks everyone for the reviews. The latest push 81137c6 is now rebased over #19485.

    This PR is intended to just move things around a bit for the rest of the ChainstateManager de-globalization to work properly. I believe we’ve gotten a bit stuck on the intricacies of these TestingSetup abstractions.

    Personally, I don’t particularly care how the abstraction works here. The TestingSetup classes and their inheritance hierarchy is a somewhat poor abstraction of how our initialization and de-initialization logic work. Therefore, I’d like to just fix this particular problem for now and move on.

    I do fully intend on coming back to the initialization codepaths later, most likely after having moved a couple of mutable statics into classes they logically belong in, and having a larger PR that coalesces and cleans all of this up.


    In this latest push I:

    1. Reverted back to my original solution of having this inheritance chain: TestingSetup -> ChainTestingSetup -> BasicTestingSetup. This has the advantage of not having to introduce any new functions. Compared to my last try at making this work, I now take advantage of the idempotency of our teardown sequence and have ~ChainTestingSetup teardown all application logic while ~TestingSetup inherits from it.
    2. Put ChainTestingSetup back in setup_common so that future tests can use it as requested here. (Sorry John, I knew you weren’t the biggest fan of this 😕)

    jnewbery: Was there an actual problem with the previous branch, or are you just trying to reduce code duplication?

    There wasn’t an actual problem with the previous branch, MarcoFalke brought up the concern that it was harder to maintain duplicate codepaths, so this previous push was a (perhaps poorly conceived) attempt at doing so. I agree w/re the bool argument and have since reverted to something similar to how I originally attempted this which avoids using a bool argument.

  43. DrahtBot removed the label Needs rebase on Dec 8, 2020
  44. ryanofsky approved
  45. ryanofsky commented at 10:09 pm on December 8, 2020: member

    Code review ACK 81137c60fe6234569e1c5e6760f3a6f016956944. This change is simpler after the rebase because wallet & bench commits are dropped.

    Along with the rebase, new test init functions were dropped again in response to #20323 (comment), which is fine. I think in the longer run more init code can be moved into RAII classes, and we won’t need these intricate initialization functions and class hierarchies (tests could just state their resource requirements as variable declarations).

  46. MarcoFalke commented at 6:57 am on December 9, 2020: member

    Thanks for shuffling this around for over a month

    ACK 81137c60fe looking excellent now 🐩

    Signature:

     0-----BEGIN PGP SIGNED MESSAGE-----
     1Hash: SHA512
     2
     3ACK 81137c60fe looking excellent now 🐩
     4-----BEGIN PGP SIGNATURE-----
     5
     6iQGzBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYAACgkQzit1aX5p
     7pUjLNQv9G0SWcw2rzItf1EIttkPPy6CX5BxM3WRp4MY+hW42LikQIcTm236LyD9t
     8/e4homRxM0DT1q6/JKin3RP4y1O4zpLswFaz8nNH7ScmLGyTNdb/HUDxLLNqnynb
     9TYZYpZP6Md/EWjCoF2kKEBlVmzUeehagq3L9gQ7udXTMZtMu2z1jP6v7/TLe6XxA
    10HqABCQn9BJYcD5dqHETg4TYBP2hG5bUnh5rmJWHnn0ifdEmnS4cbExtHCL9nxQpF
    111evmfgdk6nXzkkEllJsOm2tYVGhacW5Z483w/jFveBPmVJgduYmAO5mddMreqV/5
    12/1Gegw1YQnb6LmEyHhsD2POxlidXksNTOEAyghOwylFFPN8467R/LQEXr8ltstQ9
    13NnhkoCNVgSDBuzkdTB+n8S6gfQyTp2T3klrqr3GHJIPlRikRLGI5bOwtjtZsFkGX
    14j5508lSIANRoUKGv3nbfWL47l8he+dYMfCvpqkLWxRPqGT+MnIQV9aRKKxLcSFIb
    15czC392Ra
    16=hAKu
    17-----END PGP SIGNATURE-----
    

    Timestamp of file with hash 1fd492318f7f8e7f0f9f62fce5042d824a2c5c3fcb368e2027f02582ea8ed27e -

  47. MarcoFalke commented at 7:02 am on December 9, 2020: member
    1. Put ChainTestingSetup back in setup_common so that future tests can use it as requested here. (Sorry John, I knew you weren’t the biggest fan of this confused)

    Ok, let’s wait for @jnewbery ’s green light before merge

  48. jnewbery commented at 8:50 am on December 9, 2020: member
    ACK 81137c60fe6234569e1c5e6760f3a6f016956944
  49. MarcoFalke merged this on Dec 9, 2020
  50. MarcoFalke closed this on Dec 9, 2020

  51. sidhujag referenced this in commit d771bbd04b on Dec 9, 2020
  52. DrahtBot locked this on Feb 15, 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-07-01 13:12 UTC

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