This will be used primarily by the addr time refactor (https://github.com/bitcoin/bitcoin/pull/24697) to make addr relay time type safe. However, it can also be used in other places, and can be reviewed independently, so I split it up.
Add mockable clock type #25101
pull MarcoFalke wants to merge 1 commits into bitcoin:master from MarcoFalke:2205-mock-clock-😃 changing 4 files +33 −17-
MarcoFalke commented at 11:10 AM on May 10, 2022: member
- MarcoFalke added the label Refactoring on May 10, 2022
-
MarcoFalke commented at 11:12 AM on May 10, 2022: member
Naming discussion welcome. Previous naming thread at #24697 (review)
-
DrahtBot commented at 7:18 PM on May 10, 2022: member
<!--e57a25ab6845829454e8d69fc972939a-->
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
<!--174a7506f384e20aa4161008e828411d-->
Conflicts
No conflicts as of last run.
-
in src/util/time.h:64 in fa66cf13a5 outdated
57 | @@ -43,7 +58,10 @@ inline double CountSecondsDouble(SecondsDouble t) { return t.count(); } 58 | 59 | /** 60 | * DEPRECATED 61 | - * Use either GetTimeSeconds (not mockable) or GetTime<T> (mockable) 62 | + * Use either: 63 | + * - std::chrono::sytem_clock::now() or Now<std::chrono::system_clock>() for system time 64 | + * - std::chrono::steady_clock::now() or Now<std::chrono::steady_clock>() for steady time 65 | + * - NodeClock::now() or Now<NodeClock>() for mockable system time
ajtowns commented at 10:17 PM on May 10, 2022:Doesn't
Now<>()want a timepoint type, rather than a clock? Should beNow<NodeSeconds>()orNow<SteadyMilliseconds>(), no?
MarcoFalke commented at 6:04 PM on May 11, 2022:Good catch, reworked doxygen string
in src/util/time.h:93 in fa66cf13a5 outdated
87 | @@ -70,7 +88,10 @@ std::chrono::seconds GetMockTime(); 88 | 89 | /** Return system time (or mocked time, if set) */ 90 | template <typename T> 91 | -T GetTime(); 92 | +T GetTime() 93 | +{ 94 | + return std::chrono::duration_cast<T>(NodeClock::now().time_since_epoch());
ajtowns commented at 10:19 PM on May 10, 2022:return Now<std::chrono::time_point<NodeClock, T>>().time_since_epoch()?
MarcoFalke commented at 6:04 PM on May 11, 2022:Yes, makes sense to use the casting feature of
Now.MarcoFalke force-pushed on May 11, 2022MarcoFalke force-pushed on May 11, 2022in src/util/time.h:44 in fa201cc1b8 outdated
42 | - * This helper is used to convert durations before passing them over an 43 | + * This helper is used to convert durations/time_points before passing them over an 44 | * interface that doesn't support std::chrono (e.g. RPC, debug log, or the GUI) 45 | */ 46 | +template <typename Clock> 47 | +constexpr int64_t count_seconds(std::chrono::time_point<Clock, std::chrono::seconds> t)
ajtowns commented at 6:26 PM on May 11, 2022:Should this be called
seconds_since_epoch(or the camelcase equivalent) perhaps? Looking back through #24697 it doesn't seem like it's just a temporary that will go away, so might be worth clearly distinguishing something that's working with a timepoint vs a duration.At least as far as #24697 is concerned, this is effectively implementing the behaviour of
NodeClock::to_time_tso it's a bit funny that you explicitly deleted it above then reimplemented it here :)
MarcoFalke commented at 6:41 PM on May 11, 2022:Is
time_tusing more than 32-bits on all platforms? Also rounding/truncation is implementation defined. So it seems best to avoid.Also, I expect count_milliseconds to be added in the future, which
to_time_tcan't handle either.seconds_since_epochsounds good, will change.
MarcoFalke commented at 7:23 PM on May 11, 2022:Actually I think it is fine to silently do a cast inside the function. Similar to how it is fine to do a silent cast in
Now.So I'll be pushing a version of this that takes the duration as a template parameter.
MarcoFalke force-pushed on May 11, 2022in src/util/time.h:46 in fa0f3ffd31 outdated
44 | * interface that doesn't support std::chrono (e.g. RPC, debug log, or the GUI) 45 | */ 46 | +template <typename Duration, typename Timepoint> 47 | +constexpr int64_t TicksSinceEpoch(Timepoint t) 48 | +{ 49 | + return std::chrono::time_point_cast<Duration>(t).time_since_epoch().count();
ajtowns commented at 8:09 PM on May 11, 2022:Add a
static_assert(std::is_integral_v<typename Duration::rep>)or have the return type betypename Duration::rep?
MarcoFalke commented at 5:45 AM on May 12, 2022:Good catch. Used
autoreturn typeMarcoFalke force-pushed on May 12, 2022MarcoFalke force-pushed on May 12, 2022MarcoFalke commented at 8:29 AM on May 12, 2022: memberRebased for changes in
src/bitcoin-cli.cpp.in src/util/time.h:63 in fab086650e outdated
57 | @@ -48,7 +58,11 @@ inline double CountSecondsDouble(SecondsDouble t) { return t.count(); } 58 | 59 | /** 60 | * DEPRECATED 61 | - * Use either GetTimeSeconds (not mockable) or GetTime<T> (mockable) 62 | + * Use either ClockType::now() or Now<TimePointType>() if a cast is needed. 63 | + * ClockType is 64 | + * - std::chrono::sytem_clock for system time
jonatack commented at 4:07 PM on May 16, 2022:s/sytem/system/
Between system_clock, steady_clock, and NodeClock, which would you see used for the CNodeStats?
ajtowns commented at 6:58 PM on May 16, 2022:I think
NodeClockfor everything except for really short waits, likeThreadMessageHandler(which is alreadysteady_clock).system_clockonly for implementingNodeClockand logging?
MarcoFalke commented at 8:42 AM on May 17, 2022:thx, fixed typo
jonatack commented at 4:09 PM on May 16, 2022: memberConcept ACK / Edit: light code review, debug build, and tested running bitcoind locally on this branch
in src/util/time.h:18 in fab086650e outdated
13 | @@ -14,6 +14,16 @@ 14 | 15 | using namespace std::chrono_literals; 16 | 17 | +/** Mockable clock in the context of tests, otherwise the system clock */ 18 | +struct NodeClock : std::chrono::system_clock {
ajtowns commented at 5:26 PM on May 16, 2022:Newline before
{? Isn't it better to put inpublicexplicitly?
jonatack commented at 7:05 PM on May 16, 2022:Public in structs might be unneeded, as access is public by default in structs / private by default in classes, and because https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c8-use-class-rather-than-struct-if-any-member-is-non-public
ajtowns commented at 7:28 PM on May 16, 2022:Yeah, it's definitely unneeded, just seems clearer for people to have it there explicitly? Seems like we usually have an explicit
publicwhen inheriting astructfrom some otherstruct.
jonatack commented at 7:34 PM on May 16, 2022:Yes, good point re inheriting.
MarcoFalke commented at 8:43 AM on May 17, 2022:Thx, added
publicinheritanceajtowns commented at 5:27 PM on May 16, 2022: memberLooks good to me
MarcoFalke force-pushed on May 17, 2022in src/util/time.h:29 in fa207814f1 outdated
24 | +}; 25 | +using NodeSeconds = std::chrono::time_point<NodeClock, std::chrono::seconds>; 26 | + 27 | using SteadySeconds = std::chrono::time_point<std::chrono::steady_clock, std::chrono::seconds>; 28 | using SteadyMilliseconds = std::chrono::time_point<std::chrono::steady_clock, std::chrono::milliseconds>; 29 | using SteadyMicroseconds = std::chrono::time_point<std::chrono::steady_clock, std::chrono::microseconds>;
jonatack commented at 3:51 PM on May 17, 2022:Note:
SteadyMicrosecondsis currently unused and untested.
MarcoFalke commented at 3:57 PM on May 17, 2022:Not sure how to test it or how to make it used. It was added in case someone wants to use it, but I am happy to remove it and let someone add it later if it gets used.
MarcoFalke commented at 5:38 PM on May 18, 2022:side note: It can be tested in the
// Check that steady time and system time changes after a sleeptest case.in src/util/time.h:23 in fa207814f1 outdated
18 | +struct NodeClock : public std::chrono::system_clock { 19 | + using time_point = std::chrono::time_point<NodeClock>; 20 | + /** Return current system time or mocked time, if set */ 21 | + static time_point now() noexcept; 22 | + static std::time_t to_time_t(const time_point&) = delete; // unused 23 | + static time_point from_time_t(std::time_t) = delete; // unused
jonatack commented at 3:54 PM on May 17, 2022:
MarcoFalke commented at 3:58 PM on May 17, 2022:I am not touching de-/con-structors, so I guess no?
jonatack commented at 6:15 PM on May 17, 2022:Right, the intention here is to delete the
to_time_tandfrom_time_tclass members inherited fromstd::chrono::system_clock, so IIUC, we don't care here about copy constructor deletion implicitly suppressing move constructor and move assignment operators.Verified these are deleted in the same way they are declared per https://en.cppreference.com/w/cpp/chrono/system_clock/to_time_t and https://en.cppreference.com/w/cpp/chrono/system_clock/from_time_t.
ajtowns commented at 9:47 PM on May 17, 2022:You don't normally instantiate instances of clock types, all the methods on them are static / class methods, so constructors/destructors/copying don't matter?
MarcoFalke commented at 5:03 PM on May 18, 2022:right. They don't matter and as I mentioned before, I am not touching them at all, so I fail to understand what the issue is.
See also:
(not meaningful, but compiles fine)
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index eeecbe5ea9..c6fd1ec548 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -1483,6 +1483,17 @@ BOOST_AUTO_TEST_CASE(gettime) BOOST_AUTO_TEST_CASE(util_time_GetTime) { +{ +auto c1{NodeClock{}}; +auto c3{c1}; +auto c2{std::move(c1)}; +} +{ +auto c1{std::chrono::system_clock{}}; +auto c3{c1}; +auto c2{std::move(c1)}; +} + SetMockTime(111); // Check that mock time does not change after a sleep for (const auto& num_sleep : {0ms, 1ms}) {
jonatack commented at 5:39 PM on May 18, 2022:I think the last three comments agree, but I'm not sure :) I did want to ask to make sure and check my assumptions. Thanks for the replies.
jonatack commented at 8:28 AM on May 20, 2022:Continuing with that test code snippet, verified these don't compile as expected.
test/util_tests.cpp:1487:25: error: attempt to use a deleted function auto c1{NodeClock{}.to_time_t(std::chrono::system_clock::now())}; ^ ./util/time.h:22:24: note: 'to_time_t' has been explicitly marked deleted here static std::time_t to_time_t(const time_point&) = delete; // unusedtest/util_tests.cpp:1487:25: error: attempt to use a deleted function auto c1{NodeClock{}.from_time_t(std::chrono::system_clock{})}; ^ ./util/time.h:23:23: note: 'from_time_t' has been explicitly marked deleted here static time_point from_time_t(std::time_t) = delete; // unusedjonatack commented at 3:55 PM on May 17, 2022: memberACK fa207814f126feeb47b4a1271142dc86f5ce678d
Am running mainnet and signet nodes with this branch today.
DrahtBot added the label Needs rebase on May 18, 2022Add mockable clock type and TicksSinceEpoch helper fa305fd92cMarcoFalke force-pushed on May 18, 2022MarcoFalke commented at 5:04 PM on May 18, 2022: memberRebased. Should be trivial to re-review
jonatack commented at 5:32 PM on May 18, 2022: memberACK fa305fd92c0a5a91831be3ccec0a5ef962a5fbcb per
git range-diff 7b3343f fa20781 fa305fdDrahtBot removed the label Needs rebase on May 18, 2022ajtowns commented at 3:53 AM on May 20, 2022: memberACK fa305fd92c0a5a91831be3ccec0a5ef962a5fbcb
fanquake merged this on May 20, 2022fanquake closed this on May 20, 2022MarcoFalke deleted the branch on May 20, 2022sidhujag referenced this in commit d148a072ea on May 28, 2022DrahtBot locked this on May 20, 2023
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: 2026-04-13 18:13 UTC
This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me