Skip to content

Commit 6407c0e

Browse files
committed
Merge bitcoin/bitcoin#25101: Add mockable clock type
fa305fd Add mockable clock type and TicksSinceEpoch helper (MarcoFalke) Pull request description: This will be used primarily by the addr time refactor (bitcoin/bitcoin#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. ACKs for top commit: jonatack: ACK fa305fd per `git range-diff 7b3343f fa20781 fa305fd` ajtowns: ACK fa305fd Tree-SHA512: da00200126833c1f55b1b1e68f596eab5c9254e82b188ad17779c08ffd685e198a7c5270791b4b69a858dc6ba4e051fe0c8b445d203d356d0c884f6365ee1cfe
2 parents 0de3694 + fa305fd commit 6407c0e

File tree

4 files changed

+33
-17
lines changed

4 files changed

+33
-17
lines changed

src/bitcoin-cli.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
// trivial to get the mocked time from the server, nor is it needed for now, so
4545
// just use a plain system_clock.
4646
using CliClock = std::chrono::system_clock;
47-
using CliSeconds = std::chrono::time_point<CliClock, std::chrono::seconds>;
4847

4948
const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
5049
UrlDecodeFn* const URL_DECODE = urlDecode;
@@ -470,7 +469,7 @@ class NetinfoRequestHandler : public BaseRequestHandler
470469
if (networkinfo["version"].getInt<int>() < 209900) {
471470
throw std::runtime_error("-netinfo requires bitcoind server to be running v0.21.0 and up");
472471
}
473-
const int64_t time_now{count_seconds(Now<CliSeconds>())};
472+
const int64_t time_now{TicksSinceEpoch<std::chrono::seconds>(CliClock::now())};
474473

475474
// Count peer connection totals, and if DetailsRequested(), store peer data in a vector of structs.
476475
for (const UniValue& peer : batch[ID_PEERINFO]["result"].getValues()) {

src/test/util_tests.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1488,8 +1488,12 @@ BOOST_AUTO_TEST_CASE(util_time_GetTime)
14881488
for (const auto& num_sleep : {0ms, 1ms}) {
14891489
UninterruptibleSleep(num_sleep);
14901490
BOOST_CHECK_EQUAL(111, GetTime()); // Deprecated time getter
1491+
BOOST_CHECK_EQUAL(111, Now<NodeSeconds>().time_since_epoch().count());
1492+
BOOST_CHECK_EQUAL(111, TicksSinceEpoch<std::chrono::seconds>(NodeClock::now()));
1493+
BOOST_CHECK_EQUAL(111, TicksSinceEpoch<SecondsDouble>(Now<NodeSeconds>()));
14911494
BOOST_CHECK_EQUAL(111, GetTime<std::chrono::seconds>().count());
14921495
BOOST_CHECK_EQUAL(111000, GetTime<std::chrono::milliseconds>().count());
1496+
BOOST_CHECK_EQUAL(111000, TicksSinceEpoch<std::chrono::milliseconds>(NodeClock::now()));
14931497
BOOST_CHECK_EQUAL(111000000, GetTime<std::chrono::microseconds>().count());
14941498
}
14951499

src/util/time.cpp

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,20 +66,16 @@ bool ChronoSanityCheck()
6666
return true;
6767
}
6868

69-
template <typename T>
70-
T GetTime()
69+
NodeClock::time_point NodeClock::now() noexcept
7170
{
7271
const std::chrono::seconds mocktime{nMockTime.load(std::memory_order_relaxed)};
7372
const auto ret{
7473
mocktime.count() ?
7574
mocktime :
76-
std::chrono::duration_cast<T>(std::chrono::system_clock::now().time_since_epoch())};
75+
std::chrono::system_clock::now().time_since_epoch()};
7776
assert(ret > 0s);
78-
return ret;
79-
}
80-
template std::chrono::seconds GetTime();
81-
template std::chrono::milliseconds GetTime();
82-
template std::chrono::microseconds GetTime();
77+
return time_point{ret};
78+
};
8379

8480
template <typename T>
8581
static T GetSystemTime()

src/util/time.h

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,16 @@
1414

1515
using namespace std::chrono_literals;
1616

17+
/** Mockable clock in the context of tests, otherwise the system clock */
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
24+
};
25+
using NodeSeconds = std::chrono::time_point<NodeClock, std::chrono::seconds>;
26+
1727
using SteadySeconds = std::chrono::time_point<std::chrono::steady_clock, std::chrono::seconds>;
1828
using SteadyMilliseconds = std::chrono::time_point<std::chrono::steady_clock, std::chrono::milliseconds>;
1929
using SteadyMicroseconds = std::chrono::time_point<std::chrono::steady_clock, std::chrono::microseconds>;
@@ -30,10 +40,10 @@ void UninterruptibleSleep(const std::chrono::microseconds& n);
3040
* This helper is used to convert durations/time_points before passing them over an
3141
* interface that doesn't support std::chrono (e.g. RPC, debug log, or the GUI)
3242
*/
33-
template <typename Clock>
34-
constexpr int64_t count_seconds(std::chrono::time_point<Clock, std::chrono::seconds> t)
43+
template <typename Duration, typename Timepoint>
44+
constexpr auto TicksSinceEpoch(Timepoint t)
3545
{
36-
return t.time_since_epoch().count();
46+
return std::chrono::time_point_cast<Duration>(t).time_since_epoch().count();
3747
}
3848
constexpr int64_t count_seconds(std::chrono::seconds t) { return t.count(); }
3949
constexpr int64_t count_milliseconds(std::chrono::milliseconds t) { return t.count(); }
@@ -48,7 +58,11 @@ inline double CountSecondsDouble(SecondsDouble t) { return t.count(); }
4858

4959
/**
5060
* DEPRECATED
51-
* Use either GetTimeSeconds (not mockable) or GetTime<T> (mockable)
61+
* Use either ClockType::now() or Now<TimePointType>() if a cast is needed.
62+
* ClockType is
63+
* - std::chrono::steady_clock for steady time
64+
* - std::chrono::system_clock for system time
65+
* - NodeClock for mockable system time
5266
*/
5367
int64_t GetTime();
5468

@@ -71,9 +85,6 @@ void SetMockTime(std::chrono::seconds mock_time_in);
7185
/** For testing */
7286
std::chrono::seconds GetMockTime();
7387

74-
/** Return system time (or mocked time, if set) */
75-
template <typename T>
76-
T GetTime();
7788
/**
7889
* Return the current time point cast to the given precicion. Only use this
7990
* when an exact precicion is needed, otherwise use T::clock::now() directly.
@@ -83,6 +94,12 @@ T Now()
8394
{
8495
return std::chrono::time_point_cast<typename T::duration>(T::clock::now());
8596
}
97+
/** DEPRECATED, see GetTime */
98+
template <typename T>
99+
T GetTime()
100+
{
101+
return Now<std::chrono::time_point<NodeClock, T>>().time_since_epoch();
102+
}
86103

87104
/**
88105
* ISO 8601 formatting is preferred. Use the FormatISO8601{DateTime,Date}

0 commit comments

Comments
 (0)