mirror of
https://github.com/XRPLF/rippled.git
synced 2026-04-29 15:37:57 +00:00
103 lines
3.1 KiB
C++
103 lines
3.1 KiB
C++
#ifndef XRPL_CORE_TIMEKEEPER_H_INCLUDED
|
|
#define XRPL_CORE_TIMEKEEPER_H_INCLUDED
|
|
|
|
#include <xrpl/basics/chrono.h>
|
|
#include <xrpl/beast/clock/abstract_clock.h>
|
|
|
|
#include <atomic>
|
|
|
|
namespace xrpl {
|
|
|
|
/** Manages various times used by the server. */
|
|
class TimeKeeper : public beast::abstract_clock<NetClock>
|
|
{
|
|
private:
|
|
std::atomic<std::chrono::seconds> closeOffset_{};
|
|
|
|
// Adjust system_clock::time_point for NetClock epoch
|
|
static constexpr time_point
|
|
adjust(std::chrono::system_clock::time_point when)
|
|
{
|
|
return time_point(std::chrono::duration_cast<duration>(
|
|
when.time_since_epoch() - epoch_offset));
|
|
}
|
|
|
|
public:
|
|
virtual ~TimeKeeper() = default;
|
|
|
|
/** Returns the current time, using the server's clock.
|
|
|
|
It's possible for servers to have a different value for network
|
|
time, especially if they do not use some external mechanism for
|
|
time synchronization (e.g. NTP or SNTP). This is fine.
|
|
|
|
This estimate is not directly visible to other servers over the
|
|
protocol, but it is possible for them to make an educated guess
|
|
if this server publishes proposals or validations.
|
|
|
|
@note The network time is adjusted for the "Ripple epoch" which
|
|
was arbitrarily defined as 2000-01-01T00:00:00Z by Arthur
|
|
Britto and David Schwartz during early development of the
|
|
code. No rationale has been provided for this curious and
|
|
annoying, but otherwise unimportant, choice.
|
|
*/
|
|
[[nodiscard]] time_point
|
|
now() const override
|
|
{
|
|
return adjust(std::chrono::system_clock::now());
|
|
}
|
|
|
|
/** Returns the predicted close time, in network time.
|
|
|
|
The predicted close time represents the notional "center" of the
|
|
network. Each server assumes that its clock is correct and tries
|
|
to pull the close time towards its measure of network time.
|
|
*/
|
|
[[nodiscard]] time_point
|
|
closeTime() const
|
|
{
|
|
return now() + closeOffset_.load();
|
|
}
|
|
|
|
// This may return a negative value
|
|
[[nodiscard]] std::chrono::seconds
|
|
closeOffset() const
|
|
{
|
|
return closeOffset_.load();
|
|
}
|
|
|
|
/** Adjust the close time, based on the network's view of time. */
|
|
std::chrono::seconds
|
|
adjustCloseTime(std::chrono::seconds by)
|
|
{
|
|
using namespace std::chrono_literals;
|
|
|
|
auto offset = closeOffset_.load();
|
|
|
|
if (by == 0s && offset == 0s)
|
|
return offset;
|
|
|
|
// The close time adjustment is serialized externally to this
|
|
// code. The compare/exchange only serves as a weak check and
|
|
// should not fail. Even if it does, it's safe to simply just
|
|
// skip the adjustment.
|
|
closeOffset_.compare_exchange_strong(offset, [by, offset]() {
|
|
// Ignore small offsets and push the close time
|
|
// towards our wall time.
|
|
if (by > 1s)
|
|
return offset + ((by + 3s) / 4);
|
|
|
|
if (by < -1s)
|
|
return offset + ((by - 3s) / 4);
|
|
|
|
return (offset * 3) / 4;
|
|
}());
|
|
|
|
return closeOffset_.load();
|
|
}
|
|
};
|
|
|
|
} // namespace xrpl
|
|
|
|
#endif
|