Util: Allow scheduler to be mocked #18037

pull amitiuttarwar wants to merge 5 commits into bitcoin:master from amitiuttarwar:2020-01-mock-scheduler changing 13 files +134 −19
  1. amitiuttarwar commented at 5:52 am on January 31, 2020: contributor

    This PR is to support functional tests by allowing the scheduler to be mocked via the RPC.

    It adds a MockForward method to the scheduler class that iterates through the task queue and reschedules them to be delta_seconds sooner.

    This is currently used to support functional testing of the “unbroadcast” set tracking in #18038. If this patch is accepted, it would also be useful to simplify the code in #16698.

  2. amitiuttarwar commented at 5:52 am on January 31, 2020: contributor

    Some relevant info about the analysis of the cost (maintenance burden) vs benefit (supporting a better tested & simpler codebase) of these changes

    pros:

    • these changes add a function to the scheduler with unit test coverage
    • the function would only be used when running regtest
    • intent is for this to support easier functional testing for other features
    • currently, two explicit use cases

    cons:

    • all code adds maintenance burden
    • c++ code specifically to support testing should only be added when necessary
    • the scheduler mock is not required for functionally testing the current use cases. workarounds are possible

    explanation of the two use cases & workarounds.

    1. #18038 uses the mock to trigger the next attempt at initial broadcast, which is scheduled for every 10 minutes. Alternatively, the REATTEMPT_BROADCAST_INTERVAL constant that indicates scheduler frequency could be defined as a chain param and made more frequent for regtest (thanks @MarcoFalke for the suggestion).
    2. In PR #16698, specifically commit baf7de22108eb9081ddc700067b72409efbc382e, the mock would allow deleting some of the c++ code (but still be testable.) In the patch right now, the scheduler periodically calls MaybeResendWalletTxs which calls ResubmitWalletTransactionsToMempool which uses nNextResend to track time. nNextResend implements a mockable time so can be tested from the functional tests. If the scheduler mock is supported, the scheduler could directly invoke the resubmit function & drop the member var to maintain time tracking.
  3. fanquake added the label Utils/log/libs on Jan 31, 2020
  4. JeremyRubin commented at 6:09 am on January 31, 2020: contributor

    utACK 58c4c19.

    This seems like a generally useful test harness, and the code looks basically correct to me. I think the pointer to the scheduler is a little crass, but it isn’t a bad option considering the scheduler is created as a static in init.cpp (someone can clean it up later if they make the schedule a non static).

    The time delta technically could underflow, but I don’t think that’s the base time being subtracted from is a time point (and we’re far from the unix epoch time). If this weren’t just testing harness, it might be worth it to check for underflow, but since we’d basically be having to actively try to shoot ourselves in the foot during a test to get an underflow this usage is fine.

    Great work!

  5. fanquake commented at 6:24 am on January 31, 2020: member

    Concept ACK.

    Looks like there’s an issue with the new mockforward unit test, as most of the Travis instances are failing:

    0test/scheduler_tests.cpp(158): Entering test case "mockforward"
    1test/scheduler_tests.cpp(188): error: in "scheduler_tests/mockforward": check num_tasks == 1 has failed [3 != 1]
    2test/scheduler_tests.cpp(191): error: in "scheduler_tests/mockforward": check counter == 2 has failed [0 != 2]
    3test/scheduler_tests.cpp(197): error: in "scheduler_tests/mockforward": check delta > 2*60 && delta < 3*60 has failed
    4test/scheduler_tests.cpp(158): Leaving test case "mockforward"; testing time: 6321us
    5test/scheduler_tests.cpp(13): Leaving test suite "scheduler_tests"; testing time: 146946us
    
  6. DrahtBot commented at 8:40 am on January 31, 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:

    • #18038 (P2P: Mempool tracks locally submitted transactions to improve privacy by amitiuttarwar)
    • #17997 (refactor: Remove mempool global from net by MarcoFalke)
    • #17037 (Testschains: Many regtests with different genesis and default datadir by jtimon)
    • #17032 (Tests: Chainparams: Make regtest almost fully customizable by jtimon)
    • #16770 (Chainparams: Rename IsTestChain() to AllowAcceptNonstd() by jtimon)
    • #16365 (Log RPC parameters (arguments) if -debug=rpcparams by LarryRuane)

    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. MarcoFalke commented at 9:12 am on January 31, 2020: member

    No objection, but some observations:

    • In light of the test failures on some platforms, we obviously need to make sure this is doing the right thing. Timestamp handling isn’t obviously trivial especially in combination with condition variables. See also the numerous scheduler crashed that no one can explain: #16307, #16027, #14200, …

    • “Mocking” code so that tests run the mocked code and production runs a different code might defeat the whole point of having the tests in the first place. Tests (especially functional tests) are supposed to test the production code (paths) as closely as possible.

    So my personal preference would be to go with some minimally invasive and simple approach like the chainparam. But if everyone else likes this mock approach because it could be used for other testing needs as well, then I won’t object having this merged.

  8. in src/rpc/misc.cpp:384 in 58c4c1943e outdated
    379+            RPCResults{},
    380+            RPCExamples{""},
    381+        }.Check(request);
    382+
    383+    if (!Params().MineBlocksOnDemand())
    384+        throw std::runtime_error("mockscheduler for regression testing (-regtest mode) only");
    


    kristapsk commented at 4:56 pm on February 1, 2020:
    nit: “mockscheduler is for regression testing (-regtest mode) only”?
  9. in src/scheduler.cpp:125 in 5c9d5bed72 outdated
    120+        boost::unique_lock<boost::mutex> lock(newTaskMutex);
    121+
    122+        // use temp_queue to maintain updated schedule
    123+        std::multimap<boost::chrono::system_clock::time_point, Function> temp_queue;
    124+
    125+        for (const auto& element : taskQueue){
    


    promag commented at 11:56 pm on February 2, 2020:

    5c9d5bed7205161d6870d199d223af37efe66179

    nit, space before {.

  10. in src/node/context.h:13 in 58c4c1943e outdated
    10@@ -11,6 +11,7 @@
    11 class BanMan;
    12 class CConnman;
    13 class CTxMemPool;
    14+class CScheduler;
    


    promag commented at 0:04 am on February 3, 2020:

    58c4c1943e082060f38054ed4738478635ab9c31

    nit, keep sorted.

  11. in src/rpc/misc.cpp:13 in 58c4c1943e outdated
     9 #include <outputtype.h>
    10 #include <rpc/blockchain.h>
    11 #include <rpc/server.h>
    12 #include <rpc/util.h>
    13 #include <script/descriptor.h>
    14+#include <scheduler.h>
    


    promag commented at 0:05 am on February 3, 2020:

    58c4c1943e082060f38054ed4738478635ab9c31

    nit, keep sorted.

  12. in src/rpc/misc.cpp:19 in 58c4c1943e outdated
    14+#include <scheduler.h>
    15 #include <util/check.h>
    16 #include <util/strencodings.h>
    17 #include <util/system.h>
    18 #include <util/validation.h>
    19+#include <init.h>
    


    promag commented at 0:08 am on February 3, 2020:

    58c4c1943e082060f38054ed4738478635ab9c31

    Why is this included?


    amitiuttarwar commented at 3:05 am on February 5, 2020:
    good catch. was left over from a previous iteration
  13. in src/rpc/misc.cpp:388 in 58c4c1943e outdated
    383+    if (!Params().MineBlocksOnDemand())
    384+        throw std::runtime_error("mockscheduler for regression testing (-regtest mode) only");
    385+
    386+    RPCTypeCheck(request.params, {UniValue::VNUM});
    387+
    388+    g_rpc_node->scheduler->MockForward(boost::chrono::seconds(request.params[0].get_int64()));
    


    promag commented at 0:11 am on February 3, 2020:

    58c4c1943e082060f38054ed4738478635ab9c31

    Maybe check delta_time > 0?

  14. promag commented at 0:13 am on February 3, 2020: member

    Concept ACK.

    Some minor comments otherwise change LGTM.

  15. in src/test/scheduler_tests.cpp:183 in ca57312e5b outdated
    178+    // bump the scheduler forward 5 minutes
    179+    scheduler.MockForward(boost::chrono::seconds(5*60));
    180+
    181+    // finish up
    182+    MicroSleep(600);
    183+    scheduler.stop(false);
    


    promag commented at 0:19 am on February 3, 2020:

    ca57312e5b0dc9d28766369b963395f1690e0b4f

    Maybe change this to:

    0scheduler.scheduleFromNow([&]{ scheduler.stop(false); }, 1);
    

    and remove the sleep above.


    amitiuttarwar commented at 3:09 am on February 5, 2020:

    clever. thank you!

    lets see if travis likes it 🤞🏽


    amitiuttarwar commented at 5:43 am on February 5, 2020:
    yay! looking good. only travis failure seemed unrelated.
  16. amitiuttarwar force-pushed on Feb 5, 2020
  17. amitiuttarwar force-pushed on Feb 5, 2020
  18. amitiuttarwar commented at 5:00 pm on February 5, 2020: contributor

    I addressed review comments & tests are now passing CI. Added checks in RPC function & scheduler function to ensure reasonable values / no underflow.

    This PR has received 3 ACKs - utACK from @JeremyRubin & concept ACKs from @promag @fanquake. Would appreciate re-review 🙏🏽

  19. JeremyRubin commented at 6:39 pm on February 5, 2020: contributor
    re-utACK ecb0ad5
  20. JeremyRubin added this to the "General Testing" column in a project

  21. in src/rpc/misc.cpp:605 in ecb0ad52a0 outdated
    599@@ -570,6 +600,7 @@ static const CRPCCommand commands[] =
    600 
    601     /* Not shown in help */
    602     { "hidden",             "setmocktime",            &setmocktime,            {"timestamp"}},
    603+    { "hidden",             "mockscheduler",          &mockscheduler,          {"delta_time"}},
    


    promag commented at 6:51 pm on February 5, 2020:
    Follow up, would be cool to skip this when !regtest and in mockscheduler would be assert(Params().MineBlocksOnDemand()).

    JeremyRubin commented at 2:14 am on February 6, 2020:
    I think it’s reasonable for @amitiuttarwar to just copy exactly what setmocktime is doing in this regard.

    ajtowns commented at 7:35 pm on February 6, 2020:
    Huh? static const commands[]= will get done prior to working out what chain is in use, so you’d have to do a much more serious rework to remove it from the list of rpcs entirely.

    sipa commented at 10:31 pm on February 6, 2020:
    It’s a hidden RPC so I don’t think this matters much.

    promag commented at 10:48 pm on February 6, 2020:
    @ajtowns I was thinking that CRPCTable::execute could take into account some CRPCCommand flag and then it would result in RPC_METHOD_NOT_FOUND.
  22. promag commented at 6:54 pm on February 5, 2020: member
    @amitiuttarwar sure, will review later.
  23. in src/scheduler.cpp:126 in ecb0ad52a0 outdated
    121+
    122+        // use temp_queue to maintain updated schedule
    123+        std::multimap<boost::chrono::system_clock::time_point, Function> temp_queue;
    124+
    125+        for (const auto& element : taskQueue) {
    126+            boost::chrono::system_clock::time_point new_time = std::max(boost::chrono::system_clock::now() + delta_seconds, element.first) - delta_seconds;
    


    promag commented at 0:26 am on February 6, 2020:

    What’s the problem of doing

    0temp_queue.emplace_hint(temp_queue.cend(), element.first - delta_seconds, element.second);
    

    Looks fine to me since wait_until returns when system time is later than that absolute time.

    Didn’t check the case for boost < 1.50.


    JeremyRubin commented at 2:26 am on February 6, 2020:
    element.first - delta_seconds may underflow, so std::max prevents underflow.

    promag commented at 8:27 pm on February 6, 2020:
    Underflow how? You mean be less than current time?

    amitiuttarwar commented at 8:31 pm on February 6, 2020:

    if element.first - delta_seconds < now everything will process fine (as in the previous version you reviewed)

    but if delta_seconds > element.first then there could be an underflow. seems highly unlikely because element.first is a time point, but doesn’t hurt to have this guarantee


    sipa commented at 10:26 pm on February 6, 2020:

    This looks equivalent to

    0std::max(boost::chrono::system_clock::now(), element.first - delta_seconds);
    

    Also perhaps you only want to invoke now() once and cache it rather than querying it for every queue element.


    JeremyRubin commented at 11:11 pm on February 6, 2020:

    @sipa that misses the point above. if delta_seconds > element.first, it underflows and then it can be greater than now().

    I guess equivalently, if delta_seconds is too large, now() + delta_seconds may overflow… but that seems less likely because we don’t know if this system_clock::now() which feeds into the queue is set to start at time 0 on startup.

    Note also that caching now(), were emplace hint not used, would mean that the tmp queue would potentially be unstable ordered w.r.t. jobs with the same timeout.


    sipa commented at 11:28 pm on February 6, 2020:

    if delta_seconds > element.first, it underflows and then it can be greater than now().

    According to https://en.cppreference.com/w/cpp/chrono/duration, the representation type for the standard clock values is signed, so underflow should not be any issue (or at least not more than we need to worry about the clock overflowing in the first place).

    Note also that caching now(), were emplace hint not used, would mean that the tmp queue would potentially be unstable ordered w.r.t. jobs with the same timeout.

    If that’s a concern, it already is. There is no guarantee that subsequent calls to now() will be strictly increasing.


    amitiuttarwar commented at 1:10 am on February 7, 2020:
    RE: underflow / overflow- the intent is to ensure delta_seconds is reasonable. I’m thinking of asserting the value is between 0 & 3600 from both this MockForward method & the mockscheduler rpc method. and reverting to the original temp_queue.emplace_hint(temp_queue.cend(), element.first - delta_seconds, element.second)

    JeremyRubin commented at 1:13 am on February 7, 2020:
    Ah – note that it’s boost and not std… I think that the seconds duration is guaranteed to be signed 64, but I couldn’t find anything on system_clock’s duration. Good catch on the non steady adjustable clock of system_clock, I had missed that. Seems like a general thing that our scheduler should be on a monotonic hardware clock rather than something that adjusting the system date could adjust (which would be another way to do this patch – just fast forward the system time).

    sipa commented at 1:40 am on February 7, 2020:
    Even with a monotonic clock there is no guarantee that subsequent requests to now() are strictly increasing (they’ll be monotonically increasing, but that’s not enough to guarantee a stable sorting order absent hints).

    amitiuttarwar commented at 5:15 pm on February 7, 2020:

    reverted to original (element.first - delta_seconds), but added checks in MockForward and mockscheduler that delta_seconds is between 0 and 3600.

    which means we no longer invoke now() =P

    lmk if there are any further concerns


    promag commented at 5:22 pm on February 7, 2020:
    lgtm
  24. in src/test/scheduler_tests.cpp:163 in ecb0ad52a0 outdated
    154@@ -155,4 +155,45 @@ BOOST_AUTO_TEST_CASE(singlethreadedscheduler_ordered)
    155     BOOST_CHECK_EQUAL(counter2, 100);
    156 }
    157 
    158+BOOST_AUTO_TEST_CASE(mockforward)
    159+{
    160+    CScheduler scheduler;
    161+
    162+    int counter{0};
    163+    CScheduler::Function dummy = [&counter](){counter++;};
    


    promag commented at 0:30 am on February 6, 2020:
    nit, you can drop ().

    JeremyRubin commented at 2:16 am on February 6, 2020:

    I think this is a style preference (plus it’s in tests) so it’s whatever.

    For whatever reason, I prefer this form when it’s a function that should be called multiple times (as dummy is) and the no () form when it’s more akin to a std::bind for a call-once thing.


    amitiuttarwar commented at 5:13 pm on February 7, 2020:
    updated
  25. in src/test/scheduler_tests.cpp:182 in ecb0ad52a0 outdated
    177+
    178+    // bump the scheduler forward 5 minutes
    179+    scheduler.MockForward(boost::chrono::seconds(5*60));
    180+
    181+    // ensure scheduler has chance to process all tasks queued for before 1 ms from now.
    182+    scheduler.scheduleFromNow([&]{ scheduler.stop(false); }, 1);
    


    promag commented at 0:31 am on February 6, 2020:
    nit, just capture &scheduler.

    amitiuttarwar commented at 0:48 am on February 6, 2020:
    I’m curious- is this for style or is there a difference in behavior? from what I can tell the behavior should be the same? docs: “& (implicitly capture the used automatic variables by reference)” compiler explorer: https://godbolt.org/z/QfeAVF

    JeremyRubin commented at 2:23 am on February 6, 2020:

    I think & is perfectly clear, it’s just for style.

    I agree in principle if a lambda is multiple lines and has arguments it’s usually better to explicitly capture, but I think implicit capture is totally reasonable here.


    promag commented at 9:03 am on February 6, 2020:
    Yes, should be same, however in L163 you already explicitly capture &counter so I though you would like to do the same here.

    amitiuttarwar commented at 5:12 pm on February 7, 2020:
    updated
  26. promag commented at 0:34 am on February 6, 2020: member
    FWIW there’s no coverage for mockscheduler RPC, just a simple call in the test framework would be nice.
  27. JeremyRubin commented at 2:32 am on February 6, 2020: contributor
    @promag I think it’s reasonable that the mockscheduler RPC doesn’t have coverage presently – @amitiuttarwar has a larger project that this testing harness was extracted from as a reviewable chunk, a later PR will be using it extensively to test rebroadcasting logic (see #18038). I think it’s reasonable that the coverage in RPC tests lives there & there isn’t a separate one just testing the testing rpc, but feel free to disagree.
  28. laanwj added this to the "Blockers" column in a project

  29. JeremyRubin moved this from the "General Testing" to the "Rebroadcasting" column in a project

  30. JeremyRubin moved this from the "Rebroadcasting" to the "Ready to Merge" column in a project

  31. amitiuttarwar commented at 8:15 pm on February 6, 2020: contributor

    thanks for review @promag!

    RE testing mockscheduler RPC- as @JeremyRubin mentioned, my next PR uses it here , so the happy path will be tested. But if you prefer separate explicit test coverage, I can add.

    I’ll incorporate style nits if I push & invalidate current ACKs

  32. in src/rpc/misc.cpp:382 in ecb0ad52a0 outdated
    377+            },
    378+            RPCResults{},
    379+            RPCExamples{""},
    380+        }.Check(request);
    381+
    382+    if (!Params().MineBlocksOnDemand()) {
    


    sipa commented at 10:30 pm on February 6, 2020:
    I realize this is copied from setmocktime, but it feels very strange to use MineBlocksOnDemand to gate time mocking. Perhaps it’s worth adding a separate chainparams property for time mocking, and then using it for both setmocktime and mockscheduler.

    JeremyRubin commented at 3:29 am on February 7, 2020:
    @sipa what would you think about just abstracting out a new function named AllowMockableTime() and having it call MineBlocksOnDemand – that way someone can clean up the logic later, I’m sure we’re doing other weird things like this that could also be fixed.

    JeremyRubin commented at 3:30 am on February 7, 2020:
    Or just making it the responsibility of follow up work, I don’t think it’s that bad (if someone reviewed using MineBlocksOnDemand for this once… it should still be fine now)

    amitiuttarwar commented at 5:19 pm on February 7, 2020:
    I agree that using MineBlocksOnDemand felt weird. Added m_is_mockable_chain to chainparams & implemented for mockscheduler. If it looks okay I’ll do a follow up PR to use that for mocktime.
  33. amitiuttarwar force-pushed on Feb 7, 2020
  34. amitiuttarwar commented at 6:19 pm on February 7, 2020: contributor

    changes:

    • mockscheduler rpc updated to use new m_is_mockable_chain chainparams property instead of MineBlocksOnDemand
    • added checks to mockscheduler and MockForward methods to ensure delta_seconds is within acceptable range

    other comments:

    • considered adding functional test to test mockscheduler rpc, but testing the success case would require actually invoking something scheduled from the c++ code, making it look extremely similar to the PR that provides context for & builds on this one. link to test. So I don’t think it makes sense to test independently.

    So I believe all existing review comments are addressed.

    This PR is ready for review :)

  35. amitiuttarwar commented at 7:01 pm on February 7, 2020: contributor

    s390x travis build is failing with “Disk space is too low!” error. everything else is green

    appveyor wallet_resendwallettransactions.py failed, seems unlikely that its related but not impossible since MaybeResendWalletTxs is called by the scheduler. investigating.

  36. in src/scheduler.cpp:119 in 69468a9373 outdated
    113@@ -114,6 +114,28 @@ void CScheduler::scheduleFromNow(CScheduler::Function f, int64_t deltaMilliSecon
    114     schedule(f, boost::chrono::system_clock::now() + boost::chrono::milliseconds(deltaMilliSeconds));
    115 }
    116 
    117+void CScheduler::MockForward(boost::chrono::seconds delta_seconds)
    118+{
    119+    assert(delta_seconds.count() > 0 && delta_seconds.count() < 3600);
    


    MarcoFalke commented at 9:47 pm on February 9, 2020:

    In commit 69468a93737ed9d4a38e04bdce20778ce8191810:

    Could add a comment why 3600? Also, why not use a named compile time constant like boost::chrono::hours{1}?


    amitiuttarwar commented at 0:00 am on February 12, 2020:
    addressed in follow up
  37. in src/scheduler.h:58 in 69468a9373 outdated
    54@@ -55,6 +55,11 @@ class CScheduler
    55     // need more accurate scheduling, don't use this method.
    56     void scheduleEvery(Function f, int64_t deltaMilliSeconds);
    57 
    58+    // Regtest only- mock the scheduler to fast forward in time
    


    MarcoFalke commented at 9:50 pm on February 9, 2020:
    0    /**
    1     * Mock the scheduler to fast forward in time
    

    This is not limited to regtest. It can be called in unit tests as well, or in #17037 testchains.


    amitiuttarwar commented at 0:00 am on February 12, 2020:
    addressed in follow up
  38. in src/test/scheduler_tests.cpp:176 in 3679f096c2 outdated
    171+    // check taskQueue
    172+    boost::chrono::system_clock::time_point first, last;
    173+    size_t num_tasks = scheduler.getQueueInfo(first, last);
    174+    BOOST_CHECK(num_tasks == 3);
    175+
    176+    boost::thread scheduler_thread(std::bind(&CScheduler::serviceQueue, &scheduler));
    


    MarcoFalke commented at 10:07 pm on February 9, 2020:

    in commit 3679f096c2ef52fa8673e5cd4064154a1889fa12

    No features of boost::thread are needed here, so you might as well use a plain std thread

    0    std::thread scheduler_thread([&]() { scheduler.serviceQueue(); });
    

    amitiuttarwar commented at 11:56 pm on February 11, 2020:
    addressed in follow up
  39. in src/test/scheduler_tests.cpp:187 in 3679f096c2 outdated
    182+    scheduler.scheduleFromNow([&scheduler]{ scheduler.stop(false); }, 1);
    183+    scheduler_thread.join();
    184+
    185+    // check that the queue only has one job remaining
    186+    num_tasks = scheduler.getQueueInfo(first, last);
    187+    BOOST_CHECK(num_tasks == 1);
    


    MarcoFalke commented at 10:08 pm on February 9, 2020:

    in commit 3679f096c2ef52fa8673e5cd4064154a1889fa12:

    0    BOOST_CHECK_EQUAL(num_tasks, 1);
    

    amitiuttarwar commented at 7:48 pm on February 10, 2020:
    yup. using boost_check_equal was causing a warning I didn’t understand, but after pushing I realized I just need to cast to size_t.

    amitiuttarwar commented at 11:56 pm on February 11, 2020:
    addressed in follow up
  40. in src/chainparams.cpp:235 in 3392d690cf outdated
    231@@ -231,7 +232,7 @@ class CTestNetParams : public CChainParams {
    232         fDefaultConsistencyChecks = false;
    233         fRequireStandard = false;
    234         m_is_test_chain = true;
    235-
    236+        m_is_mockable_chain = false;
    


    MarcoFalke commented at 10:13 pm on February 9, 2020:

    In commit 3392d690cfb338e1a9a9d7347710c0744e4486d5:

    this should be true, otherwise one has to change this in the source code when wanting to test on testnet. While there is an argument for test params to be as close to main params as possible, I think this does not apply to params that have been introduced for primarily testing purposes. (See also my m_is_test_chain, which turned out to be too general and people prefer a per-parameter toggle).

    So I think this should be true to not hinder testing on testnet.


    amitiuttarwar commented at 7:58 pm on February 10, 2020:
    hmmm, well if we want m_is_mockable_chain to be true on testnet, wouldn’t it be better not to introduce the param and use the m_is_test_chain instead?

    amitiuttarwar commented at 8:03 pm on February 10, 2020:
    Although, conceptually, I don’t know if I’m convinced. Mocking time seems useful for increasing automated test coverage, but running the node on testnet simulating closer to mainnet makes sense. But I feel pretty indifferent since even if time is allowed to be mocked on testnet, a user doesn’t have to invoke it. And there’s no concern around attack because its testnet. Mostly just trying to move the PR forward.

    MarcoFalke commented at 8:19 pm on February 10, 2020:
    Feel free to ignore, this can be handled in the follow-up

    amitiuttarwar commented at 0:01 am on February 12, 2020:
    not addressed, but noted as open question in the follow up https://github.com/amitiuttarwar/bitcoin/pull/2#issuecomment-584885826. going to resolve here.
  41. in src/rpc/misc.cpp:373 in cf04e02bbe outdated
    367@@ -366,6 +368,32 @@ static UniValue setmocktime(const JSONRPCRequest& request)
    368     return NullUniValue;
    369 }
    370 
    371+static UniValue mockscheduler(const JSONRPCRequest& request)
    372+{
    373+        RPCHelpMan{"mockscheduler",
    


    MarcoFalke commented at 10:16 pm on February 9, 2020:

    in commit cf04e02bbe14257a1513b029231cb6a21c9766ac:

    0    RPCHelpMan{"mockscheduler",
    

    Excessive whitespace?


    amitiuttarwar commented at 8:16 pm on February 10, 2020:
    hmm, I’m seeing the same amount of whitespace on the other RPCHelpMan calls in rpc/misc & rpc/net & wallet/rpcwallet. Are you seeing inconsistency? Is there something I’m missing?

    MarcoFalke commented at 8:23 pm on February 10, 2020:
    Feel free to ignore this, but we haven’t re-formatted them in b6fb617aaaad5f9cdd7f2ad2825b253ca792055d because they are still in flux.

    amitiuttarwar commented at 11:55 pm on February 11, 2020:
    addressed in follow up
  42. in src/rpc/misc.cpp:396 in cf04e02bbe outdated
    387+    int64_t delta_seconds = request.params[0].get_int64();
    388+    if ((delta_seconds <= 0) || (delta_seconds > 3600)) {
    389+        throw std::runtime_error("delta_time must be between 0 and 3600 seconds (1 hr)");
    390+    }
    391+
    392+    g_rpc_node->scheduler->MockForward(boost::chrono::seconds(delta_seconds));
    


    MarcoFalke commented at 10:20 pm on February 9, 2020:

    in commit cf04e02bbe14257a1513b029231cb6a21c9766ac:

    Would be nice to protect against null pointer dereference. See EnsureMemPool


    amitiuttarwar commented at 11:55 pm on February 11, 2020:
    addressed in follow up
  43. MarcoFalke approved
  44. MarcoFalke commented at 10:21 pm on February 9, 2020: member

    ACK cf04e02bbe14257a1513b029231cb6a21c9766ac only some style nits 🔵

    Signature:

     0-----BEGIN PGP SIGNED MESSAGE-----
     1Hash: SHA512
     2
     3ACK cf04e02bbe14257a1513b029231cb6a21c9766ac only some style nits 🔵
     4-----BEGIN PGP SIGNATURE-----
     5
     6iQGzBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYAACgkQzit1aX5p
     7pUgrVAwAzQPXXwQxaHhiRYtQO0W21qQLUyCF92Bvjtq2RMMQnmkrQZ8sIeyFkka9
     8Mm0FDE2e0eU4en2Xw4CK/7yFsWUxlOMx8vrOlzYttO9htkmVT95Rnm7HOuAShvav
     9lcuEloyfjMe0bKAR+X/X51/roJhf+WSGrKsEFI8C+FV/bu/AbOOxlLEFiW9v6Wo3
    1083aqh74lXb5B3Bf4aZJRSTAJhlUE9XNlMH664laqefks2HXyseZpvomRd/w90NX/
    11VC9UzgeTUnSqUAGd278nFFAf1J5tqIfnE37USY1EokaZw4Yc8zsdYOYHUK1ZklEw
    12ZHIF3WPRln9OaR7kLfWtHslQUnCo1797qP2ouWAVpgRVXl63cNmjMqRGJErGZtXK
    1323bKPE3D1CgEdb+dO422dKlbiI4Nsdg0pkwnAR/z+KLBwCu+oov2KF3kPhwVdQfq
    14pUNQMn/cS7X9QP7bHxQOlAnpl4ijuBJfbV+wqU+0fY/WfclKyM/20u7IFecoZFOz
    15CYu4fn+Z
    16=NQgO
    17-----END PGP SIGNATURE-----
    

    Timestamp of file with hash 6c8ec4d2d3fd87097e17c0ce53d45761554026de152c054c527f36f2fdc7f39b -

  45. in src/init.cpp:1273 in cf04e02bbe outdated
    1268@@ -1269,6 +1269,9 @@ bool AppInitMain(NodeContext& node)
    1269     CScheduler::Function serviceLoop = std::bind(&CScheduler::serviceQueue, &scheduler);
    1270     threadGroup.create_thread(std::bind(&TraceThread<CScheduler::Function>, "scheduler", serviceLoop));
    1271 
    1272+    assert(!node.scheduler);
    1273+    node.scheduler = &scheduler;
    


    MarcoFalke commented at 7:42 pm on February 10, 2020:
    The same should be done in src/test/util/setup_common.cpp, no?

    amitiuttarwar commented at 11:55 pm on February 11, 2020:
    addressed in follow up
  46. amitiuttarwar commented at 11:55 pm on February 11, 2020: contributor

    Thank you for the review @MarcoFalke ! I addressed your concerns in a commit (with one open question), currently opened as a PR on my fork: https://github.com/amitiuttarwar/bitcoin/pull/2, will make as a follow up PR if this one gets accepted.

    Tried to investigate the appveyor failure and cannot see how it could possibly be related to my changes.

  47. MarcoFalke commented at 1:57 am on February 12, 2020: member

    I’d prefer to fixup the style fixes you want to make into the commits in this pull or not do them at all. Splitting them into a separate pull only causes noise in the git history and on GitHub.

    Rationale is that we generally discourage style-only pull requests.

  48. amitiuttarwar force-pushed on Feb 12, 2020
  49. amitiuttarwar force-pushed on Feb 12, 2020
  50. amitiuttarwar commented at 8:06 pm on February 12, 2020: contributor

    incorporated style updates & made NodeContext.scheduler a unique_ptr instead of raw pointer.

    update: Travis build failing on my new test. Working on debugging.

  51. MarcoFalke commented at 2:12 pm on February 13, 2020: member

    Looks like travis fails with the boost exception “invalid argument” (https://github.com/bitcoin/bitcoin/pull/18037#issuecomment-580650220)

     0Running 3 test cases...
     1
     2Test cases order is shuffled using seed: 902768437
     3
     4Entering test module "Bitcoin Core Test Suite"
     5
     6test/scheduler_tests.cpp(11): Entering test suite "scheduler_tests"
     7
     8test/scheduler_tests.cpp(112): Entering test case "singlethreadedscheduler_ordered"
     9
    10test/scheduler_tests.cpp(112): Leaving test case "singlethreadedscheduler_ordered"; testing time: 6488us
    11
    12test/scheduler_tests.cpp(38): Entering test case "manythreads"
    13
    14test/scheduler_tests.cpp(38): Leaving test case "manythreads"; testing time: 11938us
    15
    16test/scheduler_tests.cpp(156): Entering test case "mockforward"
    17
    18terminate called after throwing an instance of 'boost::wrapexcept<boost::condition_error>'
    19
    20  what():  boost::condition_variable::do_wait_until failed in pthread_cond_timedwait: Invalid argument
    21
    22unknown location(0): fatal error: in "scheduler_tests/mockforward": signal: SIGABRT (application abort requested)
    23
    24test/scheduler_tests.cpp(172): last checkpoint
    25
    26test/scheduler_tests.cpp(156): Leaving test case "mockforward"; testing time: 455us
    27
    28test/scheduler_tests.cpp(11): Leaving test suite "scheduler_tests"; testing time: 18977us
    29
    30Leaving test module "Bitcoin Core Test Suite"; testing time: 19091us
    31
    32*** 1 failure is detected in the test module "Bitcoin Core Test Suite"
    
  52. amitiuttarwar commented at 3:40 pm on February 13, 2020: contributor
    yup :( I’m investigating.
  53. in src/scheduler.h:58 in db45f73ab9 outdated
    54@@ -55,6 +55,11 @@ class CScheduler
    55     // need more accurate scheduling, don't use this method.
    56     void scheduleEvery(Function f, int64_t deltaMilliSeconds);
    57 
    58+    // Mock the scheduler to fast forward in time.
    


    MarcoFalke commented at 4:28 pm on February 13, 2020:

    style-nit in commit 3f5cebe47b:

    Using /** will make this a doxygen comment. I know that the other functions don’t use doxygen comment, but for new code we should aim for that.

  54. in src/init.cpp:1271 in db45f73ab9 outdated
    1263@@ -1265,16 +1264,19 @@ bool AppInitMain(NodeContext& node)
    1264         }
    1265     }
    1266 
    1267+    assert(!node.scheduler);
    1268+    node.scheduler = MakeUnique<CScheduler>();
    1269+
    1270     // Start the lightweight task scheduler thread
    1271-    CScheduler::Function serviceLoop = std::bind(&CScheduler::serviceQueue, &scheduler);
    1272+    CScheduler::Function serviceLoop = std::bind(&CScheduler::serviceQueue, node.scheduler.get());
    


    MarcoFalke commented at 4:39 pm on February 13, 2020:

    style-nit in commit 047c1fd23ab7f281af7acd238f3bbb441817686c:

    As you are changing this line anyway, might as well get rid of the std::bind mess

    0CScheduler::Function serviceLoop = [&] { node.scheduler->serviceQueue(); };
    
  55. in src/init.cpp:162 in db45f73ab9 outdated
    156@@ -157,7 +157,6 @@ NODISCARD static bool CreatePidFile()
    157 static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle;
    158 
    159 static boost::thread_group threadGroup;
    160-static CScheduler scheduler;
    161 
    162 void Interrupt(NodeContext& node)
    163 {
    


    MarcoFalke commented at 4:43 pm on February 13, 2020:

    style-nit in commit 047c1fd:

    It should be safe and a bit cleaner to reset the scheduler unique_ptr at the end of void Shutdown(NodeContext& node).

  56. in src/test/util/setup_common.cpp:106 in db45f73ab9 outdated
    102@@ -103,10 +103,12 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
    103     g_rpc_node = &m_node;
    104     RegisterAllCoreRPCCommands(tableRPC);
    105 
    106+    g_rpc_node->scheduler = MakeUnique<CScheduler>();
    


    MarcoFalke commented at 4:46 pm on February 13, 2020:

    style-nit in commit 047c1fd23ab7f281af7acd238f3bbb441817686c:

    g_rpc_node might go away (#17548), and using m_node directly would be cleaner code anyway.


    MarcoFalke commented at 3:11 am on February 17, 2020:
    Also, the pointer should probably be reset in ~TestingSetup

    amitiuttarwar commented at 7:56 pm on February 17, 2020:

    yeah totally. do you think the lack of reset could have somehow caused the failure here? I’ll push shortly and observe, but still trying to fill in my conceptual understanding.

    not directly related, but another thing I’m wondering is why the scheduler thread isn’t interrupted here

  57. in src/test/util/setup_common.cpp:110 in db45f73ab9 outdated
    107+
    108     // We have to run a scheduler thread to prevent ActivateBestChain
    109     // from blocking due to queue overrun.
    110-    threadGroup.create_thread(std::bind(&CScheduler::serviceQueue, &scheduler));
    111-    GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
    112+    threadGroup.create_thread(std::bind(&CScheduler::serviceQueue, g_rpc_node->scheduler.get()));
    


    MarcoFalke commented at 4:48 pm on February 13, 2020:

    style-nit in commit 047c1fd23ab7f281af7acd238f3bbb441817686c:

    Same here

    0    threadGroup.create_thread([&] { m_node.scheduler->serviceQueue(); });
    
  58. MarcoFalke approved
  59. MarcoFalke commented at 4:49 pm on February 13, 2020: member

    ACK db45f73ab93e207f792fb5bb11ca1ec2885d8a91 , only some style changes 🖊

    Signature:

     0-----BEGIN PGP SIGNED MESSAGE-----
     1Hash: SHA512
     2
     3ACK db45f73ab93e207f792fb5bb11ca1ec2885d8a91 , only some style changes 🖊
     4-----BEGIN PGP SIGNATURE-----
     5
     6iQGzBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYEACgkQzit1aX5p
     7pUhXZwwAnlRWgEGarDT3ZkLJNksVg2V3EkG8VEMRyDGnmkUYCRNaeemikKnzxvI7
     8rrqKckkaYGyZvYqLhgodn+OG+EoZOh3DBrRljH1jdl9DjsNp5VcNVoVV2SHqsdrp
     9qfoJeMwuzCqo9XYluZ5pKvJCyXYu+JbKIkhojeLRO4G8G6xfR6vejRDRXeG8wnEL
    10KBkFHveCBBsem3JXwjTgj2uxRLzArVg0x2/shMDMpCsDyWdTn+6ngrTWulAyt5qB
    11QjlwhCvJ7jyiAp8ymQU0aiRIg7OERYvNbNLxtc3S/DKmMeUq9Tyb1xCQW+y3iD/j
    12x3kQi0jSief82PhqT4FhdjZPDhu2PbZlVg/M4zghsUiLOA6B/s1M2g8qaqC7OjrW
    13ucC9PFUen/W0eNl7IIE/SBQ8IfYyDpw/Kz32o7fv/dwUlYUM8qXi6KxYIpplS1OG
    14pn/Zzh3vdyC6cqPJS0q67+0Crv5at3ac3xx8dF5dTuT5+LHcztXyhANVpJl/y7xt
    15oXFK3lOi
    16=G9JB
    17-----END PGP SIGNATURE-----
    

    Timestamp of file with hash 1ac115fc816927e857fea47e64737b58665a1508da322004b7d0622a653ebbbf -

  60. [util] allow scheduler to be mocked
    Add MockForward method to the scheduler that mimics going into the future by rescheduling all items on the taskQueue to be sooner.
    a6f63598ad
  61. [test] unit test for new MockForward scheduler method 1cd43e83c6
  62. [test] add chainparams property to indicate chain allows time mocking 930d837542
  63. amitiuttarwar force-pushed on Feb 17, 2020
  64. [lib] add scheduler to node context
    - also update test setup & access point in denial of service test
    7c8b6e5b52
  65. [rpc] expose ability to mock scheduler via the rpc 8bca30ea17
  66. amitiuttarwar force-pushed on Feb 17, 2020
  67. MarcoFalke commented at 1:00 am on February 18, 2020: member

    ACK 8bca30ea17cd4c1dacee28eaa27e5fa3493b021d, only change is some style fixups 🕓

    Signature:

     0-----BEGIN PGP SIGNED MESSAGE-----
     1Hash: SHA512
     2
     3ACK 8bca30ea17cd4c1dacee28eaa27e5fa3493b021d, only change is some style fixups 🕓
     4-----BEGIN PGP SIGNATURE-----
     5
     6iQGzBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYAACgkQzit1aX5p
     7pUjeVAv/YuSt6tTjGv6SeqSUSmrURxHQKmaO8WtGS57M8zxKiQLp2IlBrXaccECP
     8ktwXi7z+OxVlfaw/acuEoFZn5kIUjOC19D7tIegGh6qIWJxVYcT2cDghEG3JfTFD
     9H+gDfpx6+JUjJcXybDwrc0jeOpva0aR6WOV/BBv+JuaOM0G2SXZPFS+DeUkSWGez
    108gMhSY4FE1sjGxtYSyhdtlHpROL1qX22joa8kdgVplJIuQJOmn8TGjI/4s4Xu6j7
    115Afa60Iqnbqb9paSMyEEi7XPhjOPKtLYWwB/K+itYjvbipaz4uw4yd5+YfMdYy45
    12F/KSW9+7bYCSGE+ggEUQykrR60CYVPJay5WbwfDs0UdZhKmfyjlbx/iysTx63uKs
    134PKeLZoNCJynQA+nodf1vrXuA8nxJgfYdhDP8bWnUCMdcP84FKPdrG7r3v2x6fBt
    14MeCCRSOXPNEAFtu59xnZw9mc+Dctx5EUyznhy5ybp/3QCUlM9DhxvTbx0H7sFzDo
    15BTRQiIFP
    16=2pAG
    17-----END PGP SIGNATURE-----
    

    Timestamp of file with hash 0370e988925c0bd1dc04b6ff2d771181e26d2b0eb3b28b69eb3c0a0976243393 -

  68. MarcoFalke referenced this in commit 36f42e1bf4 on Feb 18, 2020
  69. MarcoFalke merged this on Feb 18, 2020
  70. MarcoFalke closed this on Feb 18, 2020

  71. fanquake removed this from the "Blockers" column in a project

  72. sidhujag referenced this in commit 2fc510301e on Feb 18, 2020
  73. jonasschnelli commented at 5:39 pm on February 19, 2020: contributor

    This PR seems to have made bitcoinbuilds.org pretty unhappy:

    0  what():  boost::condition_variable::do_wait_until failed in pthread_cond_timedwait: Invalid argument
    1unknown location(0): fatal error: in "scheduler_tests/mockforward": signal: SIGABRT (application abort requested)
    2test/scheduler_tests.cpp(172): last checkpoint
    

    Example build: https://bitcoinbuilds.org/index.php?job=5c006a9e-b8e6-4932-a6a8-3ead3d1fc188

    Any ideas why we see a SIGABRT?

    I think it happens at std::thread scheduler_thread([&]() { scheduler.serviceQueue(); }); in the scheduler tests.

  74. MarcoFalke commented at 6:02 pm on February 19, 2020: member
  75. jonasschnelli commented at 6:05 pm on February 19, 2020: contributor
    @MarcoFalke: I guess you where trying to refer to #18174. Looking into that now…
  76. jonasschnelli commented at 6:26 pm on February 19, 2020: contributor

    Master (Linux 64 depends tests) fails when using ccache cache (seems to be reproducible 100%): https://bitcoinbuilds.org/index.php?job=c1d3a0f5-7d47-40e6-9c9b-cac397c5ff30

    Master succeeds when clearing the ccache cache (but keeping the dependency cache): https://bitcoinbuilds.org/index.php?job=f28f0356-d431-4428-832b-49bc870042f5

  77. MarcoFalke referenced this in commit 96488e6784 on Mar 5, 2020
  78. deadalnix referenced this in commit e589af8c33 on Jun 10, 2020
  79. deadalnix referenced this in commit d2d2c37a9c on Jun 10, 2020
  80. deadalnix referenced this in commit 1919fb1f2e on Jun 10, 2020
  81. deadalnix referenced this in commit a4d6e33212 on Jun 10, 2020
  82. deadalnix referenced this in commit 09741cfffa on Jun 10, 2020
  83. ftrader referenced this in commit f21f90f588 on Aug 17, 2020
  84. ftrader referenced this in commit 41f7f4a62f on Aug 17, 2020
  85. sidhujag referenced this in commit 990a3ee8c8 on Nov 10, 2020
  86. Fabcien referenced this in commit aa3561df33 on Jan 5, 2021
  87. PastaPastaPasta referenced this in commit 023cda03c2 on Jun 27, 2021
  88. PastaPastaPasta referenced this in commit 653269009c on Jun 28, 2021
  89. PastaPastaPasta referenced this in commit 98b287fb52 on Jun 29, 2021
  90. kittywhiskers referenced this in commit 43f4443668 on Jan 9, 2022
  91. kittywhiskers referenced this in commit 31e8208de9 on Jan 11, 2022
  92. kittywhiskers referenced this in commit 09a517b6c0 on Jan 25, 2022
  93. 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-12-19 03:12 UTC

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