diff --git a/Builds/VisualStudio2013/RippleD.vcxproj b/Builds/VisualStudio2013/RippleD.vcxproj index 741f68e994..b9cf2c0ab7 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj +++ b/Builds/VisualStudio2013/RippleD.vcxproj @@ -2071,13 +2071,13 @@ ..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories) ..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories) - + True True ..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories) ..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories) - + True @@ -2085,6 +2085,12 @@ ..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories) ..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories) + + True + True + ..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories) + ..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories) + @@ -2121,6 +2127,8 @@ ..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories) ..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories) + + diff --git a/Builds/VisualStudio2013/RippleD.vcxproj.filters b/Builds/VisualStudio2013/RippleD.vcxproj.filters index c8afd1126e..f102266f88 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2013/RippleD.vcxproj.filters @@ -2805,15 +2805,18 @@ ripple\core\impl - + ripple\core\impl - + ripple\core\impl ripple\core\impl + + ripple\core\impl + ripple\core @@ -2850,6 +2853,9 @@ ripple\core\tests + + ripple\core + ripple\crypto diff --git a/src/ripple/app/ledger/Ledger.cpp b/src/ripple/app/ledger/Ledger.cpp index 8584a22d81..6e9c157898 100644 --- a/src/ripple/app/ledger/Ledger.cpp +++ b/src/ripple/app/ledger/Ledger.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -223,7 +224,7 @@ Ledger::Ledger (open_ledger_t, Ledger const& prevLedger) // VFALCO Remove this call to getApp if (prevLedger.info_.closeTime == 0) info_.closeTime = roundCloseTime ( - getApp().getOPs ().getCloseTimeNC (), info_.closeTimeResolution); + getApp().timeKeeper().closeTime().time_since_epoch().count(), info_.closeTimeResolution); else info_.closeTime = prevLedger.info_.closeTime + info_.closeTimeResolution; diff --git a/src/ripple/app/ledger/impl/LedgerConsensusImp.cpp b/src/ripple/app/ledger/impl/LedgerConsensusImp.cpp index 13f51a2a6b..656ba703a4 100644 --- a/src/ripple/app/ledger/impl/LedgerConsensusImp.cpp +++ b/src/ripple/app/ledger/impl/LedgerConsensusImp.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -721,7 +722,7 @@ void LedgerConsensusImp::statePreClose () if (mHaveCorrectLCL && getCloseAgree(mPreviousLedger->info())) { // we can use consensus timing - sinceClose = 1000 * (getApp().getOPs ().getCloseTimeNC () + sinceClose = 1000 * (getApp().timeKeeper().closeTime().time_since_epoch().count() - mPreviousLedger->info().closeTime); idleInterval = 2 * mPreviousLedger->info().closeTimeResolution; @@ -731,7 +732,7 @@ void LedgerConsensusImp::statePreClose () else { // Use the time we saw the last ledger close - sinceClose = 1000 * (getApp().getOPs ().getCloseTimeNC () + sinceClose = 1000 * (getApp().timeKeeper().closeTime().time_since_epoch().count() - consensus_.getLastCloseTime ()); idleInterval = LEDGER_IDLE_INTERVAL; } @@ -1041,7 +1042,7 @@ void LedgerConsensusImp::accept (std::shared_ptr set) { // Build validation auto v = std::make_shared (newLCLHash, - consensus_.validationTimestamp (getApp().getOPs ().getNetworkTimeNC ()), + consensus_.validationTimestamp (getApp().timeKeeper().now().time_since_epoch().count()), mValPublic, mProposing); v->setFieldU32 (sfLedgerSequence, newLCL->info().seq); addLoad(v); // Our network load @@ -1195,7 +1196,8 @@ void LedgerConsensusImp::accept (std::shared_ptr set) WriteLog (lsINFO, LedgerConsensus) << "Our close offset is estimated at " << offset << " (" << closeCount << ")"; - getApp().getOPs ().closeTimeOffset (offset); + getApp().timeKeeper().adjustCloseTime( + std::chrono::seconds(offset)); } } @@ -1280,7 +1282,7 @@ void LedgerConsensusImp::addDisputedTransaction ( protocol::TMTransaction msg; msg.set_rawtransaction (& (tx.front ()), tx.size ()); msg.set_status (protocol::tsNEW); - msg.set_receivetimestamp (getApp().getOPs ().getNetworkTimeNC ()); + msg.set_receivetimestamp (getApp().timeKeeper().now().time_since_epoch().count()); getApp ().overlay ().foreach (send_always ( std::make_shared ( msg, protocol::mtTRANSACTION))); @@ -1355,7 +1357,7 @@ void LedgerConsensusImp::statusChange (protocol::NodeEvent event, Ledger& ledger s.set_newevent (event); s.set_ledgerseq (ledger.info().seq); - s.set_networktime (getApp().getOPs ().getNetworkTimeNC ()); + s.set_networktime (getApp().timeKeeper().now().time_since_epoch().count()); s.set_ledgerhashprevious(ledger.info().parentHash.begin (), std::decay_t::bytes); s.set_ledgerhash (ledger.getHash ().begin (), @@ -1650,7 +1652,7 @@ void LedgerConsensusImp::closeLedger () checkOurValidation (); state_ = State::establish; mConsensusStartTime = std::chrono::steady_clock::now (); - mCloseTime = getApp().getOPs ().getCloseTimeNC (); + mCloseTime = getApp().timeKeeper().closeTime().time_since_epoch().count(); consensus_.setLastCloseTime (mCloseTime); statusChange (protocol::neCLOSING_LEDGER, *mPreviousLedger); ledgerMaster_.applyHeldTransactions (); @@ -1682,7 +1684,7 @@ void LedgerConsensusImp::checkOurValidation () } auto v = std::make_shared (mPreviousLedger->getHash (), - consensus_.validationTimestamp (getApp().getOPs ().getNetworkTimeNC ()), + consensus_.validationTimestamp (getApp().timeKeeper().now().time_since_epoch().count()), mValPublic, false); addLoad(v); v->setTrusted (); diff --git a/src/ripple/app/ledger/impl/LedgerMaster.cpp b/src/ripple/app/ledger/impl/LedgerMaster.cpp index ecf6438008..45e5e47708 100644 --- a/src/ripple/app/ledger/impl/LedgerMaster.cpp +++ b/src/ripple/app/ledger/impl/LedgerMaster.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -172,7 +173,8 @@ public: return 999999; } - std::int64_t ret = getApp().getOPs().getCloseTimeNC(); + // VFALCO int widening? + std::int64_t ret = getApp().timeKeeper().closeTime().time_since_epoch().count(); ret -= static_cast (pubClose); ret = (ret > 0) ? ret : 0; @@ -189,7 +191,7 @@ public: return 999999; } - std::int64_t ret = getApp().getOPs().getCloseTimeNC(); + std::int64_t ret = getApp().timeKeeper().closeTime().time_since_epoch().count(); ret -= static_cast (valClose); ret = (ret > 0) ? ret : 0; @@ -1170,7 +1172,7 @@ public: if (!standalone_) { // don't pathfind with a ledger that's more than 60 seconds old - std::int64_t age = getApp().getOPs().getCloseTimeNC(); + std::int64_t age = getApp().timeKeeper().closeTime().time_since_epoch().count(); age -= static_cast (lastLedger->info().closeTime); if (age > 60) { diff --git a/src/ripple/app/main/Application.cpp b/src/ripple/app/main/Application.cpp index 4873923c7d..f4dce25d08 100644 --- a/src/ripple/app/main/Application.cpp +++ b/src/ripple/app/main/Application.cpp @@ -50,10 +50,10 @@ #include #include #include -#include #include +#include +#include #include -#include #include #include #include @@ -259,6 +259,8 @@ public: beast::Journal m_journal; Application::MutexType m_masterMutex; + std::unique_ptr timeKeeper_; + // Required by the SHAMapStore TransactionMaster m_txMaster; @@ -289,7 +291,6 @@ public: std::unique_ptr m_networkOPs; std::unique_ptr m_deprecatedUNL; std::unique_ptr serverHandler_; - std::unique_ptr m_sntpClient; std::unique_ptr m_validators; std::unique_ptr m_amendmentTable; std::unique_ptr mFeeTrack; @@ -333,6 +334,9 @@ public: , m_journal (m_logs.journal("Application")) + , timeKeeper_ (make_TimeKeeper( + deprecatedLogs().journal("TimeKeeper"))) + , m_nodeStoreScheduler (*this) , m_shaMapStore (make_SHAMapStore (setup_SHAMapStore ( @@ -403,9 +407,6 @@ public: , serverHandler_ (make_ServerHandler (*m_networkOPs, get_io_service (), *m_jobQueue, *m_networkOPs, *m_resourceManager, *m_collectorManager)) - , m_sntpClient (make_SNTPClient( - deprecatedLogs().journal("SNTPClient"))) - , m_validators (Validators::make_Manager(*this, get_io_service(), m_logs.journal("UVL"), getConfig ())) @@ -470,6 +471,12 @@ public: return family_; } + TimeKeeper& + timeKeeper() + { + return *timeKeeper_; + } + JobQueue& getJobQueue () { return *m_jobQueue; @@ -625,10 +632,6 @@ public: { return mTxnDB != nullptr; } - bool getSystemTimeOffset (int& offset) - { - return m_sntpClient->getOffset (offset); - } DatabaseCon& getTxnDB () { @@ -724,7 +727,7 @@ public: } if (!getConfig ().RUN_STANDALONE) - m_sntpClient->init (getConfig ().SNTP_SERVERS); + timeKeeper_->run(getConfig ().SNTP_SERVERS); if (!initSqliteDbs ()) { @@ -1139,7 +1142,7 @@ bool ApplicationImp::loadOldLedger ( std::uint32_t seq = 1; - std::uint32_t closeTime = getApp().getOPs().getCloseTimeNC (); + auto closeTime = getApp().timeKeeper().closeTime().time_since_epoch().count(); std::uint32_t closeTimeResolution = 30; bool closeTimeEstimated = false; std::uint64_t totalDrops = 0; diff --git a/src/ripple/app/main/Application.h b/src/ripple/app/main/Application.h index 4afd9a1393..9dc4a86f11 100644 --- a/src/ripple/app/main/Application.h +++ b/src/ripple/app/main/Application.h @@ -60,6 +60,7 @@ class PathRequests; class PendingSaves; class AccountIDCache; class STLedgerEntry; +class TimeKeeper; class TransactionMaster; class Validations; @@ -93,6 +94,7 @@ public: virtual boost::asio::io_service& getIOService () = 0; virtual CollectorManager& getCollectorManager () = 0; virtual shamap::Family& family() = 0; + virtual TimeKeeper& timeKeeper() = 0; virtual JobQueue& getJobQueue () = 0; virtual NodeCache& getTempNodeCache () = 0; virtual CachedSLEs& cachedSLEs() = 0; @@ -132,7 +134,6 @@ public: // virtual DatabaseCon& getWalletDB () = 0; - virtual bool getSystemTimeOffset (int& offset) = 0; virtual bool isShutdown () = 0; virtual bool running () = 0; virtual void setup () = 0; diff --git a/src/ripple/app/misc/NetworkOPs.cpp b/src/ripple/app/misc/NetworkOPs.cpp index ab99c57949..ef2750857b 100644 --- a/src/ripple/app/misc/NetworkOPs.cpp +++ b/src/ripple/app/misc/NetworkOPs.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -128,7 +129,6 @@ public: , m_clusterTimer (this) , mConsensus (make_Consensus ()) , m_ledgerMaster (ledgerMaster) - , mCloseTimeOffset (0) , mLastLoadBase (256) , mLastLoadFactor (256) , m_job_queue (job_queue) @@ -139,21 +139,7 @@ public: ~NetworkOPsImp() override = default; - // Network information. - // Our best estimate of wall time in seconds from 1/1/2000. - std::uint32_t getNetworkTimeNC () const override; - - // Our best estimate of current ledger close time. - std::uint32_t getCloseTimeNC () const override; -private: - std::uint32_t getCloseTimeNC (int& offset) const; - public: - void closeTimeOffset (int) override; - - /** On return the offset param holds the System time offset in seconds. - */ - boost::posix_time::ptime getNetworkTimePT(int& offset) const; OperatingMode getOperatingMode () const override { return mMode; @@ -461,8 +447,6 @@ private: LedgerMaster& m_ledgerMaster; InboundLedger::pointer mAcquiringLedger; - int mCloseTimeOffset; - SubInfoMapType mSubAccount; SubInfoMapType mSubRTAccount; @@ -592,7 +576,7 @@ void NetworkOPsImp::processClusterTimer () { bool synced = (m_ledgerMaster.getValidatedLedgerAge() <= 240); ClusterNodeStatus us("", synced ? getApp().getFeeTrack().getLocalFee() : 0, - getNetworkTimeNC()); + getApp().timeKeeper().now().time_since_epoch().count()); auto& unl = getApp().getUNL(); if (!unl.nodeUpdate(getApp().getLocalCredentials().getNodePublic(), us)) { @@ -652,56 +636,6 @@ std::string NetworkOPsImp::strOperatingMode () const return paStatusToken[mMode]; } -boost::posix_time::ptime NetworkOPsImp::getNetworkTimePT (int& offset) const -{ - offset = 0; - getApp().getSystemTimeOffset (offset); - - if (std::abs (offset) >= 60) - m_journal.warning << "Large system time offset (" << offset << ")."; - - // VFALCO TODO Replace this with a beast call - return boost::posix_time::microsec_clock::universal_time () + - boost::posix_time::seconds (offset); -} - -std::uint32_t NetworkOPsImp::getNetworkTimeNC () const -{ - int offset; - return iToSeconds (getNetworkTimePT (offset)); -} - -std::uint32_t NetworkOPsImp::getCloseTimeNC () const -{ - int offset; - return getCloseTimeNC (offset); -} - -std::uint32_t NetworkOPsImp::getCloseTimeNC (int& offset) const -{ - return iToSeconds (getNetworkTimePT (offset) + - boost::posix_time::seconds (mCloseTimeOffset)); -} - -void NetworkOPsImp::closeTimeOffset (int offset) -{ - // take large offsets, ignore small offsets, push towards our wall time - if (offset > 1) - mCloseTimeOffset += (offset + 3) / 4; - else if (offset < -1) - mCloseTimeOffset += (offset - 3) / 4; - else - mCloseTimeOffset = (mCloseTimeOffset * 3) / 4; - - if (mCloseTimeOffset != 0) - { - m_journal.info << "Close time offset now " << mCloseTimeOffset; - - if (std::abs (mCloseTimeOffset) >= 60) - m_journal.warning << "Large close time offset (" << mCloseTimeOffset << ")."; - } -} - void NetworkOPsImp::submitTransaction (Job&, STTx::pointer iTrans) { if (isNeedNetworkLedger ()) @@ -1044,7 +978,7 @@ void NetworkOPsImp::apply (std::unique_lock& batchLock) e.transaction->getSTransaction()->add (s); tx.set_rawtransaction (&s.getData().front(), s.getLength()); tx.set_status (protocol::tsCURRENT); - tx.set_receivetimestamp (getApp().getOPs().getNetworkTimeNC()); + tx.set_receivetimestamp (getApp().timeKeeper().now().time_since_epoch().count()); // FIXME: This should be when we received it getApp().overlay().foreach (send_if_not ( std::make_shared (tx, protocol::mtTRANSACTION), @@ -1198,7 +1132,7 @@ void NetworkOPsImp::tryStartConsensus () // check if the ledger is good enough to go to omFULL // Note: Do not go to omFULL if we don't have the previous ledger // check if the ledger is bad enough to go to omCONNECTED -- TODO - if (getApp().getOPs ().getNetworkTimeNC () < + if (getApp().timeKeeper().now().time_since_epoch().count() < m_ledgerMaster.getCurrentLedger ()->info().closeTime) { setMode (omFULL); @@ -1401,7 +1335,7 @@ void NetworkOPsImp::switchLastClosedLedger ( protocol::TMStatusChange s; s.set_newevent (protocol::neSWITCHED_LEDGER); s.set_ledgerseq (newLCL->info().seq); - s.set_networktime (getApp().getOPs ().getNetworkTimeNC ()); + s.set_networktime (getApp().timeKeeper().now().time_since_epoch().count()); uint256 hash = newLCL->info().parentHash; s.set_ledgerhashprevious (hash.begin (), hash.size ()); hash = newLCL->getHash (); @@ -2063,22 +1997,24 @@ Json::Value NetworkOPsImp::getServerInfo (bool human, bool admin) lpClosed->getReserveInc () * baseFee / baseRef)) / SYSTEM_CURRENCY_PARTS; - int offset; - std::uint32_t closeTime (getCloseTimeNC (offset)); - if (std::abs (offset) >= 60) - l[jss::system_time_offset] = offset; + auto const nowOffset = getApp().timeKeeper().nowOffset(); + if (std::abs (nowOffset.count()) >= 60) + l[jss::system_time_offset] = nowOffset.count(); + auto const closeOffset = getApp().timeKeeper().closeOffset(); + if (std::abs (closeOffset.count()) >= 60) + l[jss::close_time_offset] = closeOffset.count(); + + // VFALCO How do we fix this? + /* std::uint32_t lCloseTime (lpClosed->info().closeTime); - if (std::abs (mCloseTimeOffset) >= 60) - l[jss::close_time_offset] = mCloseTimeOffset; - if (lCloseTime <= closeTime) { std::uint32_t age = closeTime - lCloseTime; - if (age < 1000000) l[jss::age] = Json::UInt (age); } + */ } if (valid) diff --git a/src/ripple/app/misc/NetworkOPs.h b/src/ripple/app/misc/NetworkOPs.h index 52dde31d40..4b3fd56ffd 100644 --- a/src/ripple/app/misc/NetworkOPs.h +++ b/src/ripple/app/misc/NetworkOPs.h @@ -101,12 +101,6 @@ public: // Network information // - // Our best estimate of wall time in seconds from 1/1/2000 - virtual std::uint32_t getNetworkTimeNC () const = 0; - // Our best estimate of current ledger close time - virtual std::uint32_t getCloseTimeNC () const = 0; - virtual void closeTimeOffset (int) = 0; - virtual OperatingMode getOperatingMode () const = 0; virtual std::string strOperatingMode () const = 0; diff --git a/src/ripple/app/misc/UniqueNodeList.cpp b/src/ripple/app/misc/UniqueNodeList.cpp index ecc1a5fbdf..8c236f86af 100644 --- a/src/ripple/app/misc/UniqueNodeList.cpp +++ b/src/ripple/app/misc/UniqueNodeList.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -695,7 +696,7 @@ UniqueNodeListImp::getClusterStatus() std::uint32_t UniqueNodeListImp::getClusterFee() { - int thresh = getApp().getOPs().getNetworkTimeNC() - 90; + auto const thresh = getApp().timeKeeper().now().time_since_epoch().count() - 90; std::vector fees; { @@ -723,7 +724,7 @@ void UniqueNodeListImp::addClusterStatus (Json::Value& obj) ScopedUNLLockType sl (mUNLLock); if (m_clusterNodes.size() > 1) // nodes other than us { - int now = getApp().getOPs().getNetworkTimeNC(); + auto const now = getApp().timeKeeper().now().time_since_epoch().count(); std::uint32_t ref = getApp().getFeeTrack().getLoadBase(); Json::Value& nodes = (obj[jss::cluster] = Json::objectValue); diff --git a/src/ripple/app/misc/Validations.cpp b/src/ripple/app/misc/Validations.cpp index 03358098a2..5a9d43d591 100644 --- a/src/ripple/app/misc/Validations.cpp +++ b/src/ripple/app/misc/Validations.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include // #include #include @@ -86,7 +87,7 @@ private: if (!val->isTrusted() && getApp().getUNL().nodeInUNL (signer)) val->setTrusted(); - std::uint32_t now = getApp().getOPs().getCloseTimeNC(); + auto const now = getApp().timeKeeper().closeTime().time_since_epoch().count(); std::uint32_t valClose = val->getSignTime(); if ((now > (valClose - LEDGER_EARLY_INTERVAL)) && (now < (valClose + LEDGER_VAL_INTERVAL))) @@ -176,7 +177,8 @@ private: if (set) { - std::uint32_t now = getApp().getOPs ().getNetworkTimeNC (); + auto const now = + getApp().timeKeeper().now().time_since_epoch().count(); for (auto& it: *set) { bool isTrusted = it.second->isTrusted (); @@ -304,7 +306,8 @@ private: std::list getCurrentTrustedValidations () { - std::uint32_t cutoff = getApp().getOPs ().getNetworkTimeNC () - LEDGER_VAL_INTERVAL; + // VFALCO LEDGER_VAL_INTERVAL should be a NetClock::duration + auto const cutoff = getApp().timeKeeper().now().time_since_epoch().count() - LEDGER_VAL_INTERVAL; std::list ret; @@ -339,7 +342,7 @@ private: LedgerToValidationCounter getCurrentValidations ( uint256 currentLedger, uint256 priorLedger) { - std::uint32_t cutoff = getApp().getOPs ().getNetworkTimeNC () - LEDGER_VAL_INTERVAL; + auto const cutoff = getApp().timeKeeper().now().time_since_epoch().count() - LEDGER_VAL_INTERVAL; bool valCurrentLedger = currentLedger.isNonZero (); bool valPriorLedger = priorLedger.isNonZero (); diff --git a/src/ripple/core/TimeKeeper.h b/src/ripple/core/TimeKeeper.h new file mode 100644 index 0000000000..963ac8aa2e --- /dev/null +++ b/src/ripple/core/TimeKeeper.h @@ -0,0 +1,100 @@ +//------------------------------------------------------------------------------ +/* + 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_CORE_TIMEKEEPER_H_INCLUDED +#define RIPPLE_CORE_TIMEKEEPER_H_INCLUDED + +#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. + + 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. + + The network time is wall time adjusted for the Ripple + epoch, the beginning of January 1st, 2000. 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. + + Servers compute network time by adjusting a local wall + clock using SNTP and then adjusting for the epoch. + */ + virtual + time_point + now() const = 0; + + /** Returns the close time, in network time. + + Close time is the time the network would agree that + a ledger closed, if a ledger closed right now. + + 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. + */ + virtual + time_point + closeTime() const = 0; + + /** Adjust the close time. + + This is called in response to received validations. + */ + virtual + void + adjustCloseTime (duration amount) = 0; + + virtual + duration + nowOffset() const = 0; + + virtual + duration + closeOffset() const = 0; + +}; + +extern +std::unique_ptr +make_TimeKeeper(beast::Journal j); + +} // ripple + +#endif diff --git a/src/ripple/core/impl/SNTPClient.cpp b/src/ripple/core/impl/SNTPClock.cpp similarity index 73% rename from src/ripple/core/impl/SNTPClient.cpp rename to src/ripple/core/impl/SNTPClock.cpp index 90ab29d5c6..990ada97e5 100644 --- a/src/ripple/core/impl/SNTPClient.cpp +++ b/src/ripple/core/impl/SNTPClock.cpp @@ -21,11 +21,12 @@ #include #include #include -#include +#include #include #include #include #include +#include #include #include #include // @@ -69,7 +70,7 @@ static uint8_t SNTPQueryData[48] = #define NTP_OFF_XMITTS_FRAC 11 class SNTPClientImp - : public SNTPClient + : public SNTPClock { private: struct Query @@ -78,7 +79,7 @@ private: time_t sent; // VFALCO time_t, really? std::uint32_t nonce; - Query (time_t j = (time_t) -1) + Query (time_t j = time_t(-1)) : replied (false) , sent (j) { @@ -86,7 +87,7 @@ private: }; beast::Journal j_; - std::mutex mutex_; + std::mutex mutable mutex_; std::thread thread_; boost::asio::io_service io_service_; boost::optional< @@ -114,9 +115,45 @@ public: , timer_ (io_service_) , resolver_ (io_service_) , offset_ (0) - , lastUpdate_ ((time_t) -1) + , lastUpdate_ (time_t(-1)) , buf_ (256) { + } + + ~SNTPClientImp () + { + if (thread_.joinable()) + { + error_code ec; + timer_.cancel(ec); + socket_.cancel(ec); + work_ = boost::none; + 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, time_t(-1)); + } + queryAll(); + using namespace boost::asio; socket_.open (ip::udp::v4 ()); socket_.async_receive_from (buffer (buf_, 256), @@ -129,25 +166,38 @@ public: timer_.async_wait(std::bind( &SNTPClientImp::onTimer, this, beast::asio::placeholders::error)); - thread_ = std::thread(&SNTPClientImp::run, this); + + // VFALCO Is it correct to launch the thread + // here after queuing I/O? + // + thread_ = std::thread(&SNTPClientImp::doRun, this); } - ~SNTPClientImp () + time_point + now() const override { - error_code ec; - timer_.cancel(ec); - socket_.cancel(ec); - work_ = boost::none; - thread_.join(); + std::lock_guard lock (mutex_); + auto const when = clock_type::now(); + if ((lastUpdate_ == (time_t)-1) || + ((lastUpdate_ + NTP_TIMESTAMP_VALID) < time(nullptr))) + return when; + return when + std::chrono::seconds(offset_); } - - void run () + + duration + offset() const override { - setCallingThreadName("SNTPClient"); - io_service_.run(); + std::lock_guard lock (mutex_); + return std::chrono::seconds(offset_); } //-------------------------------------------------------------------------- + + void doRun () + { + setCallingThreadName("SNTPClock"); + io_service_.run(); + } void onTimer (error_code const& ec) @@ -158,7 +208,7 @@ public: if (ec) { JLOG(j_.error) << - "SNTPClient::onTimer: " << ec.message(); + "SNTPClock::onTimer: " << ec.message(); return; } @@ -190,29 +240,41 @@ public: 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 (nullptr) > (query->second.sent + 1)) + { JLOG(j_.warning) << "SNTP: Late response from " << ep_; + } else if (bytes_xferd < 48) + { JLOG(j_.warning) << "SNTP: Short reply from " << ep_ << " (" << bytes_xferd << ") " << buf_.size (); + } else if (reinterpret_cast( &buf_[0])[NTP_OFF_ORGTS_FRAC] != query->second.nonce) + { JLOG(j_.warning) << "SNTP: Reply from " << ep_ << "had wrong nonce"; + } else + { processReply (); + } } } @@ -224,26 +286,10 @@ public: //-------------------------------------------------------------------------- - void init (const std::vector& servers) - { - std::vector::const_iterator it = servers.begin (); - - if (it == servers.end ()) - { - JLOG(j_.info) << - "SNTP: no server specified"; - return; - } - - for (auto const& it : servers) - addServer (it); - queryAll (); - } - void addServer (std::string const& server) { std::lock_guard lock (mutex_); - servers_.push_back (std::make_pair (server, (time_t) - 1)); + servers_.push_back (std::make_pair (server, time_t(-1))); } void queryAll () @@ -253,27 +299,15 @@ public: } } - bool getOffset (int& offset) - { - std::lock_guard lock (mutex_); - - if ((lastUpdate_ == (time_t) - 1) || ((lastUpdate_ + NTP_TIMESTAMP_VALID) < time (nullptr))) - return false; - - offset = offset_; - return true; - } - bool doQuery () { - std::lock_guard lock (mutex_); std::vector< std::pair >::iterator best = servers_.end (); - for (std::vector< std::pair >::iterator it = servers_.begin (), end = best; - it != end; ++it) - if ((best == end) || (it->second == (time_t) - 1) || (it->second < best->second)) - best = it; + for (auto iter = servers_.begin (), end = best; + iter != end; ++iter) + if ((best == end) || (iter->second == time_t(-1)) || (iter->second < best->second)) + best = iter; if (best == servers_.end ()) { @@ -284,7 +318,7 @@ public: time_t now = time (nullptr); - if ((best->second != (time_t) - 1) && ((best->second + NTP_MIN_QUERY) >= now)) + if ((best->second != time_t(-1)) && ((best->second + NTP_MIN_QUERY) >= now)) { JLOG(j_.trace) << "SNTP: All servers recently queried"; @@ -300,44 +334,53 @@ public: beast::asio::placeholders::error, beast::asio::placeholders::iterator)); JLOG(j_.trace) << - "SNTP: Resolve pending for " << best->first; + "SNTPClock: Resolve pending for " << best->first; return true; } - void resolveComplete (const error_code& error, boost::asio::ip::udp::resolver::iterator it) + void resolveComplete (error_code const& ec, + boost::asio::ip::udp::resolver::iterator it) { - if (!error) + using namespace boost::asio; + if (ec == error::operation_aborted) + return; + if (ec) { - boost::asio::ip::udp::resolver::iterator sel = it; - int i = 1; + JLOG(j_.trace) << + "SNTPClock::resolveComplete: " << ec.message(); + return; + } - while (++it != boost::asio::ip::udp::resolver::iterator ()) - if ((rand () % ++i) == 0) - sel = it; + ip::udp::resolver::iterator sel = it; + int i = 1; - if (sel != boost::asio::ip::udp::resolver::iterator ()) + while (++it != ip::udp::resolver::iterator()) + if ((rand () % ++i) == 0) + sel = it; + + if (sel != ip::udp::resolver::iterator ()) + { + std::lock_guard lock (mutex_); + Query& query = queries_[*sel]; + time_t now = time (nullptr); + + if ((query.sent == now) || ((query.sent + 1) == now)) { - std::lock_guard lock (mutex_); - Query& query = queries_[*sel]; - time_t now = time (nullptr); - - if ((query.sent == now) || ((query.sent + 1) == 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; - random_fill (&query.nonce); - reinterpret_cast (SNTPQueryData)[NTP_OFF_XMITTS_INT] = static_cast (time (nullptr)) + NTP_UNIX_OFFSET; - reinterpret_cast (SNTPQueryData)[NTP_OFF_XMITTS_FRAC] = query.nonce; - socket_.async_send_to (boost::asio::buffer (SNTPQueryData, 48), *sel, - std::bind (&SNTPClientImp::onSend, this, - beast::asio::placeholders::error, beast::asio::placeholders::bytes_transferred)); + // 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; + random_fill (&query.nonce); + reinterpret_cast (SNTPQueryData)[NTP_OFF_XMITTS_INT] = static_cast (time (nullptr)) + NTP_UNIX_OFFSET; + reinterpret_cast (SNTPQueryData)[NTP_OFF_XMITTS_FRAC] = query.nonce; + socket_.async_send_to(buffer(SNTPQueryData, 48), + *sel, std::bind (&SNTPClientImp::onSend, this, + beast::asio::placeholders::error, + beast::asio::placeholders::bytes_transferred)); } } @@ -349,7 +392,7 @@ public: if (ec) { JLOG(j_.warning) << - "SNTPClient::onSend: " << ec.message(); + "SNTPClock::onSend: " << ec.message(); return; } } @@ -414,8 +457,8 @@ public: //------------------------------------------------------------------------------ -std::unique_ptr -make_SNTPClient (beast::Journal j) +std::unique_ptr +make_SNTPClock (beast::Journal j) { return std::make_unique(j); } diff --git a/src/ripple/core/impl/SNTPClient.h b/src/ripple/core/impl/SNTPClock.h similarity index 71% rename from src/ripple/core/impl/SNTPClient.h rename to src/ripple/core/impl/SNTPClock.h index 05b34c17e1..f766211431 100644 --- a/src/ripple/core/impl/SNTPClient.h +++ b/src/ripple/core/impl/SNTPClock.h @@ -17,29 +17,36 @@ */ //============================================================================== -#ifndef RIPPLE_NET_SNTPCLIENT_H_INCLUDED -#define RIPPLE_NET_SNTPCLIENT_H_INCLUDED +#ifndef RIPPLE_NET_SNTPCLOCK_H_INCLUDED +#define RIPPLE_NET_SNTPCLOCK_H_INCLUDED +#include #include +#include #include #include #include namespace ripple { -class SNTPClient +/** A clock based on system_clock and adjusted for SNTP. */ +class SNTPClock + : public beast::abstract_clock< + std::chrono::system_clock> { public: - virtual ~SNTPClient() = default; - virtual void init (std::vector const& servers) = 0; - virtual void addServer (std::string const& mServer) = 0; - virtual void queryAll () = 0; - virtual bool getOffset (int& offset) = 0; + virtual + void + run (std::vector const& servers) = 0; + + virtual + duration + offset() const = 0; }; extern -std::unique_ptr -make_SNTPClient (beast::Journal); +std::unique_ptr +make_SNTPClock (beast::Journal); } // ripple diff --git a/src/ripple/core/impl/TimeKeeper.cpp b/src/ripple/core/impl/TimeKeeper.cpp new file mode 100644 index 0000000000..735ba99cc8 --- /dev/null +++ b/src/ripple/core/impl/TimeKeeper.cpp @@ -0,0 +1,133 @@ +//------------------------------------------------------------------------------ +/* + 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 + +namespace ripple { + +class TimeKeeperImpl : public TimeKeeper +{ +private: + beast::Journal j_; + std::mutex mutable mutex_; + 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) + , clock_ (make_SNTPClock(j)) + { + } + + void + run (std::vector< + std::string> 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( + NetClock::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_.warning) << + "TimeKeeper: Large close time offset = " << + closeOffset_.count(); + } + } + } + + duration + nowOffset() const override + { + std::lock_guard lock(mutex_); + return std::chrono::duration_cast( + clock_->offset()); + } + + duration + closeOffset() const override + { + std::lock_guard lock(mutex_); + return closeOffset_; + } +}; + +//------------------------------------------------------------------------------ + +std::unique_ptr +make_TimeKeeper (beast::Journal j) +{ + return std::make_unique(j); +} + +} // ripple diff --git a/src/ripple/ledger/ReadView.h b/src/ripple/ledger/ReadView.h index c2eb8d7248..0d21b422e5 100644 --- a/src/ripple/ledger/ReadView.h +++ b/src/ripple/ledger/ReadView.h @@ -66,25 +66,30 @@ struct Fees /** Information about the notional ledger backing the view. */ struct LedgerInfo { - // Fields for all ledgers + // + // For all ledgers + // + bool open = true; LedgerIndex seq = 0; std::uint32_t parentCloseTime = 0; - // Fields for closed ledgers + // + // For closed ledgers + // + // Closed means "tx set already determined" uint256 hash = zero; uint256 txHash = zero; uint256 accountHash = zero; uint256 parentHash = zero; - - //uint256 stateHash; std::uint64_t drops = 0; // If validated is false, it means "not yet validated." // Once validated is true, it will never be set false at a later time. - mutable - bool validated = false; + // VFALCO TODO Make this not mutable + bool mutable validated = false; + bool accepted = false; // flags indicating how this ledger close took place int closeFlags = 0; @@ -103,7 +108,6 @@ struct LedgerInfo static std::uint32_t const sLCF_NoConsensusTime = 1; - inline bool getCloseAgree (LedgerInfo const& info) { diff --git a/src/ripple/overlay/impl/PeerImp.cpp b/src/ripple/overlay/impl/PeerImp.cpp index b61256df67..96cf13632a 100644 --- a/src/ripple/overlay/impl/PeerImp.cpp +++ b/src/ripple/overlay/impl/PeerImp.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -1144,7 +1145,7 @@ PeerImp::onMessage (std::shared_ptr const& m) set.set_hops(set.hops() + 1); // VFALCO Magic numbers are bad - if ((set.closetime() + 180) < getApp().getOPs().getCloseTimeNC()) + if ((set.closetime() + 180) < getApp().timeKeeper().closeTime().time_since_epoch().count()) return; auto const type = publicKeyType( @@ -1231,7 +1232,7 @@ PeerImp::onMessage (std::shared_ptr const& m) p_journal_.trace << "Status: Change"; if (!m->has_networktime ()) - m->set_networktime (getApp().getOPs ().getNetworkTimeNC ()); + m->set_networktime (getApp().timeKeeper().now().time_since_epoch().count()); if (!last_status_.has_newstatus () || m->has_newstatus ()) last_status_ = *m; @@ -1410,7 +1411,7 @@ void PeerImp::onMessage (std::shared_ptr const& m) { error_code ec; - std::uint32_t closeTime = getApp().getOPs().getCloseTimeNC(); + auto const closeTime = getApp().timeKeeper().closeTime().time_since_epoch().count(); if (m->has_hops() && ! slot_->cluster()) m->set_hops(m->hops() + 1); diff --git a/src/ripple/overlay/impl/TMHello.cpp b/src/ripple/overlay/impl/TMHello.cpp index 1184b39bbd..e650103638 100644 --- a/src/ripple/overlay/impl/TMHello.cpp +++ b/src/ripple/overlay/impl/TMHello.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -116,7 +117,7 @@ buildHello (uint256 const& sharedValue, Application& app) h.set_protoversion (to_packed (BuildInfo::getCurrentProtocol())); h.set_protoversionmin (to_packed (BuildInfo::getMinimumProtocol())); h.set_fullversion (BuildInfo::getFullVersionString ()); - h.set_nettime (app.getOPs ().getNetworkTimeNC ()); + h.set_nettime (app.timeKeeper().now().time_since_epoch().count()); h.set_nodepublic (app.getLocalCredentials ().getNodePublic ( ).humanNodePublic ()); h.set_nodeproof (&vchSig[0], vchSig.size ()); @@ -300,7 +301,7 @@ verifyHello (protocol::TMHello const& h, uint256 const& sharedValue, beast::Journal journal, Application& app) { std::pair result = { {}, false }; - std::uint32_t const ourTime = app.getOPs().getNetworkTimeNC(); + auto const ourTime = app.timeKeeper().now().time_since_epoch().count(); std::uint32_t const minTime = ourTime - clockToleranceDeltaSeconds; std::uint32_t const maxTime = ourTime + clockToleranceDeltaSeconds; diff --git a/src/ripple/unity/core.cpp b/src/ripple/unity/core.cpp index 1ec0cce05b..fce87d135f 100644 --- a/src/ripple/unity/core.cpp +++ b/src/ripple/unity/core.cpp @@ -26,7 +26,8 @@ #include #include #include -#include +#include +#include #include #include