From 548c91ebb6785e181b01c3d9f3a9e62b33080931 Mon Sep 17 00:00:00 2001 From: Nik Bougalis Date: Tue, 26 Sep 2023 17:35:31 -0700 Subject: [PATCH] Eliminate the built-in SNTP support (fixes #4207): (#4628) --- Builds/CMake/RippledCore.cmake | 3 - Builds/levelization/results/ordering.txt | 1 - cfg/rippled-example.cfg | 19 - cfg/rippled-reporting.cfg | 19 - src/ripple/app/main/Application.cpp | 3 - src/ripple/app/main/Main.cpp | 4 +- src/ripple/app/misc/NetworkOPs.cpp | 18 +- src/ripple/beast/clock/abstract_clock.h | 2 +- src/ripple/core/Config.h | 8 +- src/ripple/core/TimeKeeper.h | 120 +++--- src/ripple/core/impl/Config.cpp | 32 +- src/ripple/core/impl/SNTPClock.cpp | 491 ----------------------- src/ripple/core/impl/SNTPClock.h | 47 --- src/ripple/core/impl/TimeKeeper.cpp | 124 ------ src/test/jtx/ManualTimeKeeper.h | 41 +- src/test/jtx/impl/ManualTimeKeeper.cpp | 95 ----- src/test/overlay/compression_test.cpp | 21 +- 17 files changed, 124 insertions(+), 924 deletions(-) delete mode 100644 src/ripple/core/impl/SNTPClock.cpp delete mode 100644 src/ripple/core/impl/SNTPClock.h delete mode 100644 src/ripple/core/impl/TimeKeeper.cpp delete mode 100644 src/test/jtx/impl/ManualTimeKeeper.cpp diff --git a/Builds/CMake/RippledCore.cmake b/Builds/CMake/RippledCore.cmake index 87d6484288f..8d2ff6cbaef 100644 --- a/Builds/CMake/RippledCore.cmake +++ b/Builds/CMake/RippledCore.cmake @@ -568,9 +568,7 @@ target_sources (rippled PRIVATE src/ripple/core/impl/JobQueue.cpp src/ripple/core/impl/LoadEvent.cpp src/ripple/core/impl/LoadMonitor.cpp - src/ripple/core/impl/SNTPClock.cpp src/ripple/core/impl/SociDB.cpp - src/ripple/core/impl/TimeKeeper.cpp src/ripple/core/impl/Workers.cpp src/ripple/core/Pg.cpp #[===============================[ @@ -929,7 +927,6 @@ if (tests) src/test/jtx/impl/AMMTest.cpp src/test/jtx/impl/Env.cpp src/test/jtx/impl/JSONRPCClient.cpp - src/test/jtx/impl/ManualTimeKeeper.cpp src/test/jtx/impl/TestHelpers.cpp src/test/jtx/impl/WSClient.cpp src/test/jtx/impl/acctdelete.cpp diff --git a/Builds/levelization/results/ordering.txt b/Builds/levelization/results/ordering.txt index 7a4f4404321..832b548e5de 100644 --- a/Builds/levelization/results/ordering.txt +++ b/Builds/levelization/results/ordering.txt @@ -173,7 +173,6 @@ test.nodestore > test.unit_test test.overlay > ripple.app test.overlay > ripple.basics test.overlay > ripple.beast -test.overlay > ripple.core test.overlay > ripple.overlay test.overlay > ripple.peerfinder test.overlay > ripple.protocol diff --git a/cfg/rippled-example.cfg b/cfg/rippled-example.cfg index 6e1d553a970..e21197eed5a 100644 --- a/cfg/rippled-example.cfg +++ b/cfg/rippled-example.cfg @@ -463,19 +463,6 @@ # # # -# [sntp_servers] -# -# IP address or domain of NTP servers to use for time synchronization. -# -# These NTP servers are suitable for rippled servers located in the United -# States: -# time.windows.com -# time.apple.com -# time.nist.gov -# pool.ntp.org -# -# -# # [max_transactions] # # Configure the maximum number of transactions to have in the job queue @@ -1704,12 +1691,6 @@ advisory_delete=0 [debug_logfile] /var/log/rippled/debug.log -[sntp_servers] -time.windows.com -time.apple.com -time.nist.gov -pool.ntp.org - # To use the XRP test network # (see https://xrpl.org/connect-your-rippled-to-the-xrp-test-net.html), # use the following [ips] section: diff --git a/cfg/rippled-reporting.cfg b/cfg/rippled-reporting.cfg index f09c17ae637..632a8a7800e 100644 --- a/cfg/rippled-reporting.cfg +++ b/cfg/rippled-reporting.cfg @@ -450,19 +450,6 @@ # # # -# [sntp_servers] -# -# IP address or domain of NTP servers to use for time synchronization. -# -# These NTP servers are suitable for rippled servers located in the United -# States: -# time.windows.com -# time.apple.com -# time.nist.gov -# pool.ntp.org -# -# -# # [max_transactions] # # Configure the maximum number of transactions to have in the job queue @@ -1662,12 +1649,6 @@ advisory_delete=0 [debug_logfile] /var/log/rippled-reporting/debug.log -[sntp_servers] -time.windows.com -time.apple.com -time.nist.gov -pool.ntp.org - # To use the XRP test network # (see https://xrpl.org/connect-your-rippled-to-the-xrp-test-net.html), # use the following [ips] section: diff --git a/src/ripple/app/main/Application.cpp b/src/ripple/app/main/Application.cpp index 14b816e4564..8fcbb8a971c 100644 --- a/src/ripple/app/main/Application.cpp +++ b/src/ripple/app/main/Application.cpp @@ -1175,9 +1175,6 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) // Optionally turn off logging to console. logs_->silent(config_->silent()); - if (!config_->standalone()) - timeKeeper_->run(config_->SNTP_SERVERS); - if (!initRelationalDatabase() || !initNodeStore()) return false; diff --git a/src/ripple/app/main/Main.cpp b/src/ripple/app/main/Main.cpp index 80ac40132d5..a998640c01c 100644 --- a/src/ripple/app/main/Main.cpp +++ b/src/ripple/app/main/Main.cpp @@ -803,10 +803,8 @@ run(int argc, char** argv) if (vm.count("debug")) setDebugLogSink(logs->makeSink("Debug", beast::severities::kTrace)); - auto timeKeeper = make_TimeKeeper(logs->journal("TimeKeeper")); - auto app = make_Application( - std::move(config), std::move(logs), std::move(timeKeeper)); + std::move(config), std::move(logs), std::make_unique()); if (!app->setup(vm)) return -1; diff --git a/src/ripple/app/misc/NetworkOPs.cpp b/src/ripple/app/misc/NetworkOPs.cpp index 4e91a9d32f6..cd7fe3861ec 100644 --- a/src/ripple/app/misc/NetworkOPs.cpp +++ b/src/ripple/app/misc/NetworkOPs.cpp @@ -739,11 +739,10 @@ class NetworkOPsImp final : public NetworkOPs sPeerStatus, // Peer status changes. sConsensusPhase, // Consensus phase sBookChanges, // Per-ledger order book changes - - sLastEntry = sBookChanges // as this name implies, any new entry - // must be ADDED ABOVE this one + sLastEntry // Any new entry must be ADDED ABOVE this one }; - std::array mStreamMaps; + + std::array mStreamMaps; ServerFeeSummary mLastFeeSummary; @@ -2614,13 +2613,10 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) lpClosed->fees().accountReserve(0).decimalXRP(); l[jss::reserve_inc_xrp] = lpClosed->fees().increment.decimalXRP(); - auto const nowOffset = app_.timeKeeper().nowOffset(); - if (std::abs(nowOffset.count()) >= 60) - l[jss::system_time_offset] = nowOffset.count(); - - auto const closeOffset = app_.timeKeeper().closeOffset(); - if (std::abs(closeOffset.count()) >= 60) - l[jss::close_time_offset] = closeOffset.count(); + if (auto const closeOffset = app_.timeKeeper().closeOffset(); + std::abs(closeOffset.count()) >= 60) + l[jss::close_time_offset] = + static_cast(closeOffset.count()); #if RIPPLED_REPORTING std::int64_t const dbAge = diff --git a/src/ripple/beast/clock/abstract_clock.h b/src/ripple/beast/clock/abstract_clock.h index e543d6d7bb4..128ab82b4bd 100644 --- a/src/ripple/beast/clock/abstract_clock.h +++ b/src/ripple/beast/clock/abstract_clock.h @@ -70,7 +70,7 @@ class abstract_clock abstract_clock(abstract_clock const&) = default; /** Returns the current time. */ - virtual time_point + [[nodiscard]] virtual time_point now() const = 0; }; diff --git a/src/ripple/core/Config.h b/src/ripple/core/Config.h index 48bc9681e46..a9acd4c6b2b 100644 --- a/src/ripple/core/Config.h +++ b/src/ripple/core/Config.h @@ -149,9 +149,11 @@ class Config : public BasicConfig bool nodeToShard = false; bool ELB_SUPPORT = false; - std::vector IPS; // Peer IPs from rippled.cfg. - std::vector IPS_FIXED; // Fixed Peer IPs from rippled.cfg. - std::vector SNTP_SERVERS; // SNTP servers from rippled.cfg. + // Entries from [ips] config stanza + std::vector IPS; + + // Entries from [ips_fixed] config stanza + std::vector IPS_FIXED; enum StartUpType { FRESH, NORMAL, LOAD, LOAD_FILE, REPLAY, NETWORK }; StartUpType START_UP = NORMAL; diff --git a/src/ripple/core/TimeKeeper.h b/src/ripple/core/TimeKeeper.h index ebc6c1f1ab0..55970ec8227 100644 --- a/src/ripple/core/TimeKeeper.h +++ b/src/ripple/core/TimeKeeper.h @@ -22,73 +22,99 @@ #include #include -#include -#include -#include +#include namespace ripple { /** Manages various times used by the server. */ class TimeKeeper : public beast::abstract_clock { -public: - virtual ~TimeKeeper() = default; - - /** Launch the internal thread. +private: + std::atomic closeOffset_{}; - The internal thread synchronizes local network time - using the provided list of SNTP servers. - */ - virtual void - run(std::vector const& servers) = 0; - - /** Returns the estimate of wall time, in network time. + // 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( + when.time_since_epoch() - days(10957))); + } - The network time is wall time adjusted for the Ripple - epoch, the beginning of January 1st, 2000 UTC. Each server - can compute a different value for network time. Other - servers value for network time is not directly observable, - but good guesses can be made by looking at validators' - positions on close times. +public: + virtual ~TimeKeeper() = default; - Servers compute network time by adjusting a local wall - clock using SNTP and then adjusting for the epoch. - */ - virtual time_point - now() const override = 0; + /** Returns the current time, using the server's clock. - /** Returns the close time, in network time. + 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. - Close time is the time the network would agree that - a ledger closed, if a ledger closed right now. + 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. - The close time represents the notional "center" - of the network. Each server assumes its clock - is correct, and tries to pull the close time towards - its measure of network time. + @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. */ - virtual time_point - closeTime() const = 0; + [[nodiscard]] time_point + now() const override + { + return adjust(std::chrono::system_clock::now()); + } - /** Adjust the close time. + /** Returns the predicted close time, in network time. - This is called in response to received validations. + 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. */ - virtual void - adjustCloseTime(std::chrono::duration amount) = 0; + [[nodiscard]] time_point + closeTime() const + { + return now() + closeOffset_.load(); + } // This may return a negative value - virtual std::chrono::duration - nowOffset() const = 0; - - // This may return a negative value - virtual std::chrono::duration - closeOffset() const = 0; + [[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(); + } }; -extern std::unique_ptr -make_TimeKeeper(beast::Journal j); - } // namespace ripple #endif diff --git a/src/ripple/core/impl/Config.cpp b/src/ripple/core/impl/Config.cpp index f835ca8df04..2f26b8ba525 100644 --- a/src/ripple/core/impl/Config.cpp +++ b/src/ripple/core/impl/Config.cpp @@ -206,14 +206,10 @@ parseIniFile(std::string const& strInput, const bool bTrim) IniFileSections::mapped_type* getIniFileSection(IniFileSections& secSource, std::string const& strSection) { - IniFileSections::iterator it; - IniFileSections::mapped_type* smtResult; - it = secSource.find(strSection); - if (it == secSource.end()) - smtResult = nullptr; - else - smtResult = &(it->second); - return smtResult; + if (auto it = secSource.find(strSection); it != secSource.end()) + return &(it->second); + + return nullptr; } bool @@ -223,22 +219,21 @@ getSingleSection( std::string& strValue, beast::Journal j) { - IniFileSections::mapped_type* pmtEntries = - getIniFileSection(secSource, strSection); - bool bSingle = pmtEntries && 1 == pmtEntries->size(); + auto const pmtEntries = getIniFileSection(secSource, strSection); - if (bSingle) + if (pmtEntries && pmtEntries->size() == 1) { strValue = (*pmtEntries)[0]; + return true; } - else if (pmtEntries) + + if (pmtEntries) { - JLOG(j.warn()) << boost::str( - boost::format("Section [%s]: requires 1 line not %d lines.") % - strSection % pmtEntries->size()); + JLOG(j.warn()) << "Section '" << strSection << "': requires 1 line not " + << pmtEntries->size() << " lines."; } - return bSingle; + return false; } //------------------------------------------------------------------------------ @@ -461,9 +456,6 @@ Config::loadFromString(std::string const& fileContents) if (auto s = getIniFileSection(secConfig, SECTION_IPS_FIXED)) IPS_FIXED = *s; - if (auto s = getIniFileSection(secConfig, SECTION_SNTP)) - SNTP_SERVERS = *s; - // if the user has specified ip:port then replace : with a space. { auto replaceColons = [](std::vector& strVec) { diff --git a/src/ripple/core/impl/SNTPClock.cpp b/src/ripple/core/impl/SNTPClock.cpp deleted file mode 100644 index 8651dcbe5a4..00000000000 --- a/src/ripple/core/impl/SNTPClock.cpp +++ /dev/null @@ -1,491 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ripple { - -static uint8_t SNTPQueryData[48] = { - 0x1B, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - -using namespace std::chrono_literals; -// NTP query frequency - 4 minutes -auto constexpr NTP_QUERY_FREQUENCY = 4min; - -// NTP minimum interval to query same servers - 3 minutes -auto constexpr NTP_MIN_QUERY = 3min; - -// NTP sample window (should be odd) -#define NTP_SAMPLE_WINDOW 9 - -// NTP timestamp constant -auto constexpr NTP_UNIX_OFFSET = 0x83AA7E80s; - -// NTP timestamp validity -auto constexpr NTP_TIMESTAMP_VALID = (NTP_QUERY_FREQUENCY + NTP_MIN_QUERY) * 2; - -// SNTP packet offsets -#define NTP_OFF_INFO 0 -#define NTP_OFF_ROOTDELAY 1 -#define NTP_OFF_ROOTDISP 2 -#define NTP_OFF_REFERENCEID 3 -#define NTP_OFF_REFTS_INT 4 -#define NTP_OFF_REFTS_FRAC 5 -#define NTP_OFF_ORGTS_INT 6 -#define NTP_OFF_ORGTS_FRAC 7 -#define NTP_OFF_RECVTS_INT 8 -#define NTP_OFF_RECVTS_FRAC 9 -#define NTP_OFF_XMITTS_INT 10 -#define NTP_OFF_XMITTS_FRAC 11 - -class SNTPClientImp : public SNTPClock -{ -private: - template - using sys_time = std::chrono::time_point; - - using sys_seconds = sys_time; - - struct Query - { - bool replied; - sys_seconds sent; - std::uint32_t nonce; - - explicit Query(sys_seconds j = sys_seconds::max()) - : replied(false), sent(j) - { - } - }; - - beast::Journal const j_; - std::mutex mutable mutex_; - std::thread thread_; - boost::asio::io_service io_service_; - std::optional work_; - - std::map queries_; - boost::asio::ip::udp::socket socket_; - boost::asio::basic_waitable_timer timer_; - boost::asio::ip::udp::resolver resolver_; - std::vector> servers_; - std::chrono::seconds offset_; - sys_seconds lastUpdate_; - std::deque offsets_; - std::vector buf_; - boost::asio::ip::udp::endpoint ep_; - -public: - using error_code = boost::system::error_code; - - explicit SNTPClientImp(beast::Journal j) - : j_(j) - , work_(io_service_) - , socket_(io_service_) - , timer_(io_service_) - , resolver_(io_service_) - , offset_(0) - , lastUpdate_(sys_seconds::max()) - , buf_(256) - { - } - - ~SNTPClientImp() override - { - if (thread_.joinable()) - { - error_code ec; - timer_.cancel(ec); - socket_.cancel(ec); - work_ = std::nullopt; - thread_.join(); - } - } - - //-------------------------------------------------------------------------- - - void - run(const std::vector& servers) override - { - std::vector::const_iterator it = servers.begin(); - - if (it == servers.end()) - { - JLOG(j_.info()) << "SNTP: no server specified"; - return; - } - - { - std::lock_guard lock(mutex_); - for (auto const& item : servers) - servers_.emplace_back(item, sys_seconds::max()); - } - queryAll(); - - using namespace boost::asio; - socket_.open(ip::udp::v4()); - socket_.bind(ep_); - socket_.async_receive_from( - buffer(buf_, 256), - ep_, - std::bind( - &SNTPClientImp::onRead, - this, - std::placeholders::_1, - std::placeholders::_2)); - timer_.expires_from_now(NTP_QUERY_FREQUENCY); - timer_.async_wait( - std::bind(&SNTPClientImp::onTimer, this, std::placeholders::_1)); - - thread_ = std::thread(&SNTPClientImp::doRun, this); - } - - time_point - now() const override - { - std::lock_guard lock(mutex_); - using namespace std::chrono; - auto const when = time_point_cast(clock_type::now()); - if ((lastUpdate_ == sys_seconds::max()) || - ((lastUpdate_ + NTP_TIMESTAMP_VALID) < - time_point_cast(clock_type::now()))) - return when; - return when + offset_; - } - - duration - offset() const override - { - std::lock_guard lock(mutex_); - return offset_; - } - - //-------------------------------------------------------------------------- - - void - doRun() - { - beast::setCurrentThreadName("rippled: SNTPClock"); - io_service_.run(); - } - - void - onTimer(error_code const& ec) - { - using namespace boost::asio; - if (ec == error::operation_aborted) - return; - if (ec) - { - JLOG(j_.error()) << "SNTPClock::onTimer: " << ec.message(); - return; - } - - doQuery(); - timer_.expires_from_now(NTP_QUERY_FREQUENCY); - timer_.async_wait( - std::bind(&SNTPClientImp::onTimer, this, std::placeholders::_1)); - } - - void - onRead(error_code const& ec, std::size_t bytes_xferd) - { - using namespace boost::asio; - using namespace std::chrono; - if (ec == error::operation_aborted) - return; - - // VFALCO Should we return on any error? - /* - if (ec) - return; - */ - - if (!ec) - { - JLOG(j_.trace()) << "SNTP: Packet from " << ep_; - std::lock_guard lock(mutex_); - auto const query = queries_.find(ep_); - if (query == queries_.end()) - { - JLOG(j_.debug()) << "SNTP: Reply from " << ep_ - << " found without matching query"; - } - else if (query->second.replied) - { - JLOG(j_.debug()) << "SNTP: Duplicate response from " << ep_; - } - else - { - query->second.replied = true; - - if (time_point_cast(clock_type::now()) > - (query->second.sent + 1s)) - { - JLOG(j_.warn()) << "SNTP: Late response from " << ep_; - } - else if (bytes_xferd < 48) - { - JLOG(j_.warn()) << "SNTP: Short reply from " << ep_ << " (" - << bytes_xferd << ") " << buf_.size(); - } - else if ( - reinterpret_cast( - &buf_[0])[NTP_OFF_ORGTS_FRAC] != query->second.nonce) - { - JLOG(j_.warn()) - << "SNTP: Reply from " << ep_ << "had wrong nonce"; - } - else - { - processReply(); - } - } - } - - socket_.async_receive_from( - buffer(buf_, 256), - ep_, - std::bind( - &SNTPClientImp::onRead, - this, - std::placeholders::_1, - std::placeholders::_2)); - } - - //-------------------------------------------------------------------------- - - void - addServer(std::string const& server) - { - std::lock_guard lock(mutex_); - servers_.push_back(std::make_pair(server, sys_seconds::max())); - } - - void - queryAll() - { - while (doQuery()) - { - } - } - - bool - doQuery() - { - std::lock_guard lock(mutex_); - auto best = servers_.end(); - - for (auto iter = servers_.begin(), end = best; iter != end; ++iter) - if ((best == end) || (iter->second == sys_seconds::max()) || - (iter->second < best->second)) - best = iter; - - if (best == servers_.end()) - { - JLOG(j_.trace()) << "SNTP: No server to query"; - return false; - } - - using namespace std::chrono; - auto now = time_point_cast(clock_type::now()); - - if ((best->second != sys_seconds::max()) && - ((best->second + NTP_MIN_QUERY) >= now)) - { - JLOG(j_.trace()) << "SNTP: All servers recently queried"; - return false; - } - - best->second = now; - - boost::asio::ip::udp::resolver::query query( - boost::asio::ip::udp::v4(), best->first, "ntp"); - resolver_.async_resolve( - query, - std::bind( - &SNTPClientImp::resolveComplete, - this, - std::placeholders::_1, - std::placeholders::_2)); - JLOG(j_.trace()) << "SNTPClock: Resolve pending for " << best->first; - return true; - } - - void - resolveComplete( - error_code const& ec, - boost::asio::ip::udp::resolver::iterator it) - { - using namespace boost::asio; - if (ec == error::operation_aborted) - return; - if (ec) - { - JLOG(j_.trace()) << "SNTPClock::resolveComplete: " << ec.message(); - return; - } - - assert(it != ip::udp::resolver::iterator()); - - auto sel = it; - int i = 1; - - while (++it != ip::udp::resolver::iterator()) - { - if (rand_int(i++) == 0) - sel = it; - } - - if (sel != ip::udp::resolver::iterator()) - { - std::lock_guard lock(mutex_); - Query& query = queries_[*sel]; - using namespace std::chrono; - auto now = time_point_cast(clock_type::now()); - - if ((query.sent == now) || ((query.sent + 1s) == now)) - { - // This can happen if the same IP address is reached through - // multiple names - JLOG(j_.trace()) << "SNTP: Redundant query suppressed"; - return; - } - - query.replied = false; - query.sent = now; - query.nonce = rand_int(); - // The following line of code will overflow at 2036-02-07 06:28:16 - // UTC - // due to the 32 bit cast. - reinterpret_cast( - SNTPQueryData)[NTP_OFF_XMITTS_INT] = - static_cast( - (time_point_cast(clock_type::now()) + - NTP_UNIX_OFFSET) - .time_since_epoch() - .count()); - reinterpret_cast( - SNTPQueryData)[NTP_OFF_XMITTS_FRAC] = query.nonce; - socket_.async_send_to( - buffer(SNTPQueryData, 48), - *sel, - std::bind( - &SNTPClientImp::onSend, - this, - std::placeholders::_1, - std::placeholders::_2)); - } - } - - void - onSend(error_code const& ec, std::size_t) - { - if (ec == boost::asio::error::operation_aborted) - return; - - if (ec) - { - JLOG(j_.warn()) << "SNTPClock::onSend: " << ec.message(); - return; - } - } - - void - processReply() - { - using namespace std::chrono; - assert(buf_.size() >= 48); - std::uint32_t* recvBuffer = - reinterpret_cast(&buf_.front()); - - unsigned info = ntohl(recvBuffer[NTP_OFF_INFO]); - auto timev = seconds{ntohl(recvBuffer[NTP_OFF_RECVTS_INT])}; - unsigned stratum = (info >> 16) & 0xff; - - if ((info >> 30) == 3) - { - JLOG(j_.info()) << "SNTP: Alarm condition " << ep_; - return; - } - - if ((stratum == 0) || (stratum > 14)) - { - JLOG(j_.info()) << "SNTP: Unreasonable stratum (" << stratum - << ") from " << ep_; - return; - } - - using namespace std::chrono; - auto now = time_point_cast(clock_type::now()); - timev -= now.time_since_epoch(); - timev -= NTP_UNIX_OFFSET; - - // add offset to list, replacing oldest one if appropriate - offsets_.push_back(timev); - - if (offsets_.size() >= NTP_SAMPLE_WINDOW) - offsets_.pop_front(); - - lastUpdate_ = now; - - // select median time - auto offsetList = offsets_; - std::sort(offsetList.begin(), offsetList.end()); - auto j = offsetList.size(); - auto it = std::next(offsetList.begin(), j / 2); - offset_ = *it; - - if ((j % 2) == 0) - offset_ = (offset_ + (*--it)) / 2; - - // debounce: small corrections likely - // do more harm than good - if ((offset_ == -1s) || (offset_ == 1s)) - offset_ = 0s; - - if (timev != 0s || offset_ != 0s) - { - JLOG(j_.trace()) << "SNTP: Offset is " << timev.count() - << ", new system offset is " << offset_.count(); - } - } -}; - -//------------------------------------------------------------------------------ - -std::unique_ptr -make_SNTPClock(beast::Journal j) -{ - return std::make_unique(j); -} - -} // namespace ripple diff --git a/src/ripple/core/impl/SNTPClock.h b/src/ripple/core/impl/SNTPClock.h deleted file mode 100644 index b63cac53da5..00000000000 --- a/src/ripple/core/impl/SNTPClock.h +++ /dev/null @@ -1,47 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_NET_SNTPCLOCK_H_INCLUDED -#define RIPPLE_NET_SNTPCLOCK_H_INCLUDED - -#include -#include -#include -#include -#include -#include - -namespace ripple { - -/** A clock based on system_clock and adjusted for SNTP. */ -class SNTPClock : public beast::abstract_clock -{ -public: - virtual void - run(std::vector const& servers) = 0; - - virtual duration - offset() const = 0; -}; - -extern std::unique_ptr make_SNTPClock(beast::Journal); - -} // namespace ripple - -#endif diff --git a/src/ripple/core/impl/TimeKeeper.cpp b/src/ripple/core/impl/TimeKeeper.cpp deleted file mode 100644 index d1b07f53f44..00000000000 --- a/src/ripple/core/impl/TimeKeeper.cpp +++ /dev/null @@ -1,124 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include -#include -#include -#include -#include - -namespace ripple { - -class TimeKeeperImpl : public TimeKeeper -{ -private: - beast::Journal const j_; - std::mutex mutable mutex_; - std::chrono::duration closeOffset_; - std::unique_ptr clock_; - - // Adjust system_clock::time_point for NetClock epoch - static time_point - adjust(std::chrono::system_clock::time_point when) - { - return time_point(std::chrono::duration_cast( - when.time_since_epoch() - days(10957))); - } - -public: - explicit TimeKeeperImpl(beast::Journal j) - : j_(j), closeOffset_{}, clock_(make_SNTPClock(j)) - { - } - - void - run(std::vector const& servers) override - { - clock_->run(servers); - } - - time_point - now() const override - { - std::lock_guard lock(mutex_); - return adjust(clock_->now()); - } - - time_point - closeTime() const override - { - std::lock_guard lock(mutex_); - return adjust(clock_->now()) + closeOffset_; - } - - void - adjustCloseTime(std::chrono::duration amount) override - { - using namespace std::chrono; - auto const s = amount.count(); - std::lock_guard lock(mutex_); - // Take large offsets, ignore small offsets, - // push the close time towards our wall time. - if (s > 1) - closeOffset_ += seconds((s + 3) / 4); - else if (s < -1) - closeOffset_ += seconds((s - 3) / 4); - else - closeOffset_ = (closeOffset_ * 3) / 4; - if (closeOffset_.count() != 0) - { - if (std::abs(closeOffset_.count()) < 60) - { - JLOG(j_.info()) << "TimeKeeper: Close time offset now " - << closeOffset_.count(); - } - else - { - JLOG(j_.warn()) << "TimeKeeper: Large close time offset = " - << closeOffset_.count(); - } - } - } - - std::chrono::duration - nowOffset() const override - { - using namespace std::chrono; - using namespace std; - lock_guard lock(mutex_); - return duration_cast>(clock_->offset()); - } - - std::chrono::duration - closeOffset() const override - { - std::lock_guard lock(mutex_); - return closeOffset_; - } -}; - -//------------------------------------------------------------------------------ - -std::unique_ptr -make_TimeKeeper(beast::Journal j) -{ - return std::make_unique(j); -} - -} // namespace ripple diff --git a/src/test/jtx/ManualTimeKeeper.h b/src/test/jtx/ManualTimeKeeper.h index 838f2c1398f..f3adb29b5f0 100644 --- a/src/test/jtx/ManualTimeKeeper.h +++ b/src/test/jtx/ManualTimeKeeper.h @@ -21,45 +21,30 @@ #define RIPPLE_TEST_MANUALTIMEKEEPER_H_INCLUDED #include -#include +#include namespace ripple { namespace test { class ManualTimeKeeper : public TimeKeeper { -public: - ManualTimeKeeper(); - - void - run(std::vector const& servers) override; +private: + std::atomic now_{}; - time_point - now() const override; +public: + ManualTimeKeeper() = default; time_point - closeTime() const override; + now() const override + { + return now_.load(); + } void - adjustCloseTime(std::chrono::duration amount) override; - - std::chrono::duration - nowOffset() const override; - - std::chrono::duration - closeOffset() const override; - - void - set(time_point now); - -private: - // Adjust system_clock::time_point for NetClock epoch - static time_point - adjust(std::chrono::system_clock::time_point when); - - std::mutex mutable mutex_; - std::chrono::duration closeOffset_; - time_point now_; + set(time_point now) + { + now_.store(now); + } }; } // namespace test diff --git a/src/test/jtx/impl/ManualTimeKeeper.cpp b/src/test/jtx/impl/ManualTimeKeeper.cpp deleted file mode 100644 index 72ceaa30bc0..00000000000 --- a/src/test/jtx/impl/ManualTimeKeeper.cpp +++ /dev/null @@ -1,95 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2015 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include - -namespace ripple { -namespace test { - -using namespace std::chrono_literals; - -ManualTimeKeeper::ManualTimeKeeper() : closeOffset_{}, now_(0s) -{ -} - -void -ManualTimeKeeper::run(std::vector const& servers) -{ -} - -auto -ManualTimeKeeper::now() const -> time_point -{ - std::lock_guard lock(mutex_); - return now_; -} - -auto -ManualTimeKeeper::closeTime() const -> time_point -{ - std::lock_guard lock(mutex_); - return now_ + closeOffset_; -} - -void -ManualTimeKeeper::adjustCloseTime(std::chrono::duration amount) -{ - // Copied from TimeKeeper::adjustCloseTime - using namespace std::chrono; - auto const s = amount.count(); - std::lock_guard lock(mutex_); - // Take large offsets, ignore small offsets, - // push the close time towards our wall time. - if (s > 1) - closeOffset_ += seconds((s + 3) / 4); - else if (s < -1) - closeOffset_ += seconds((s - 3) / 4); - else - closeOffset_ = (closeOffset_ * 3) / 4; -} - -std::chrono::duration -ManualTimeKeeper::nowOffset() const -{ - return {}; -} - -std::chrono::duration -ManualTimeKeeper::closeOffset() const -{ - std::lock_guard lock(mutex_); - return closeOffset_; -} - -void -ManualTimeKeeper::set(time_point now) -{ - std::lock_guard lock(mutex_); - now_ = now; -} - -auto -ManualTimeKeeper::adjust(std::chrono::system_clock::time_point when) - -> time_point -{ - return time_point(std::chrono::duration_cast( - when.time_since_epoch() - days(10957))); -} -} // namespace test -} // namespace ripple diff --git a/src/test/overlay/compression_test.cpp b/src/test/overlay/compression_test.cpp index 3b61b2b3a09..81f21258e30 100644 --- a/src/test/overlay/compression_test.cpp +++ b/src/test/overlay/compression_test.cpp @@ -20,9 +20,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -227,8 +227,7 @@ class compression_test : public beast::unit_test::suite auto transaction = std::make_shared(); transaction->set_rawtransaction(usdTxBlob); transaction->set_status(protocol::tsNEW); - auto tk = make_TimeKeeper(logs.journal("TimeKeeper")); - transaction->set_receivetimestamp(tk->now().time_since_epoch().count()); + transaction->set_receivetimestamp(rand_int()); transaction->set_deferred(true); return transaction; @@ -263,19 +262,23 @@ class compression_test : public beast::unit_test::suite ledgerData->set_error(protocol::TMReplyError::reNO_LEDGER); ledgerData->mutable_nodes()->Reserve(n); uint256 parentHash(0); + + NetClock::duration const resolution{10}; + NetClock::time_point ct{resolution}; + for (int i = 0; i < n; i++) { LedgerInfo info; - auto tk = make_TimeKeeper(logs.journal("TimeKeeper")); info.seq = i; - info.parentCloseTime = tk->now(); + info.parentCloseTime = ct; info.hash = ripple::sha512Half(i); info.txHash = ripple::sha512Half(i + 1); info.accountHash = ripple::sha512Half(i + 2); info.parentHash = parentHash; info.drops = XRPAmount(10); - info.closeTimeResolution = tk->now().time_since_epoch(); - info.closeTime = tk->now(); + info.closeTimeResolution = resolution; + info.closeTime = ct; + ct += resolution; parentHash = ledgerHash(info); Serializer nData; ripple::addRaw(info, nData); @@ -341,7 +344,7 @@ class compression_test : public beast::unit_test::suite Serializer s1; st.add(s1); list->set_signature(s1.data(), s1.size()); - list->set_blob(strHex(s.getString())); + list->set_blob(strHex(s.slice())); return list; } @@ -375,7 +378,7 @@ class compression_test : public beast::unit_test::suite st.add(s1); auto& blob = *list->add_blobs(); blob.set_signature(s1.data(), s1.size()); - blob.set_blob(strHex(s.getString())); + blob.set_blob(strHex(s.slice())); return list; }