diff options
author | stickies-v <stickies-v@protonmail.com> | 2024-03-07 11:23:00 +0000 |
---|---|---|
committer | stickies-v <stickies-v@protonmail.com> | 2024-04-10 17:01:27 +0200 |
commit | ee178dfcc1175e0af8163216c9c024f4bfc97965 (patch) | |
tree | 29d04d09dcc21862dcaf6627986a68b38f1e31bc /src/node | |
parent | 55361a15d1aa6984051441bce88112000688fb43 (diff) | |
download | bitcoin-ee178dfcc1175e0af8163216c9c024f4bfc97965.tar.xz |
Add TimeOffsets helper class
This helper class is an alternative to CMedianFilter, but without a
lot of the special logic and exceptions that we needed while it was
still used for consensus.
Diffstat (limited to 'src/node')
-rw-r--r-- | src/node/timeoffsets.cpp | 69 | ||||
-rw-r--r-- | src/node/timeoffsets.h | 39 |
2 files changed, 108 insertions, 0 deletions
diff --git a/src/node/timeoffsets.cpp b/src/node/timeoffsets.cpp new file mode 100644 index 0000000000..62f527be8a --- /dev/null +++ b/src/node/timeoffsets.cpp @@ -0,0 +1,69 @@ +// Copyright (c) 2024-present The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <logging.h> +#include <node/interface_ui.h> +#include <node/timeoffsets.h> +#include <sync.h> +#include <tinyformat.h> +#include <util/time.h> +#include <util/translation.h> +#include <warnings.h> + +#include <algorithm> +#include <chrono> +#include <cstdint> +#include <deque> +#include <limits> +#include <optional> + +using namespace std::chrono_literals; + +void TimeOffsets::Add(std::chrono::seconds offset) +{ + LOCK(m_mutex); + + if (m_offsets.size() >= MAX_SIZE) { + m_offsets.pop_front(); + } + m_offsets.push_back(offset); + LogDebug(BCLog::NET, "Added time offset %+ds, total samples %d\n", + Ticks<std::chrono::seconds>(offset), m_offsets.size()); +} + +std::chrono::seconds TimeOffsets::Median() const +{ + LOCK(m_mutex); + + // Only calculate the median if we have 5 or more offsets + if (m_offsets.size() < 5) return 0s; + + auto sorted_copy = m_offsets; + std::sort(sorted_copy.begin(), sorted_copy.end()); + return sorted_copy[sorted_copy.size() / 2]; // approximate median is good enough, keep it simple +} + +bool TimeOffsets::WarnIfOutOfSync() const +{ + // when median == std::numeric_limits<int64_t>::min(), calling std::chrono::abs is UB + auto median{std::max(Median(), std::chrono::seconds(std::numeric_limits<int64_t>::min() + 1))}; + if (std::chrono::abs(median) <= WARN_THRESHOLD) { + SetMedianTimeOffsetWarning(std::nullopt); + uiInterface.NotifyAlertChanged(); + return false; + } + + bilingual_str msg{strprintf(_( + "Your computer's date and time appear to be more than %d minutes out of sync with the network, " + "this may lead to consensus failure. After you've confirmed your computer's clock, this message " + "should no longer appear when you restart your node. Without a restart, it should stop showing " + "automatically after you've connected to a sufficient number of new outbound peers, which may " + "take some time. You can inspect the `timeoffset` field of the `getpeerinfo` and `getnetworkinfo` " + "RPC methods to get more info." + ), Ticks<std::chrono::minutes>(WARN_THRESHOLD))}; + LogWarning("%s\n", msg.original); + SetMedianTimeOffsetWarning(msg); + uiInterface.NotifyAlertChanged(); + return true; +} diff --git a/src/node/timeoffsets.h b/src/node/timeoffsets.h new file mode 100644 index 0000000000..2b12584e12 --- /dev/null +++ b/src/node/timeoffsets.h @@ -0,0 +1,39 @@ +// Copyright (c) 2024-present The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_NODE_TIMEOFFSETS_H +#define BITCOIN_NODE_TIMEOFFSETS_H + +#include <sync.h> + +#include <chrono> +#include <cstddef> +#include <deque> + +class TimeOffsets +{ + //! Maximum number of timeoffsets stored. + static constexpr size_t MAX_SIZE{50}; + //! Minimum difference between system and network time for a warning to be raised. + static constexpr std::chrono::minutes WARN_THRESHOLD{10}; + + mutable Mutex m_mutex; + /** The observed time differences between our local clock and those of our outbound peers. A + * positive offset means our peer's clock is ahead of our local clock. */ + std::deque<std::chrono::seconds> m_offsets GUARDED_BY(m_mutex){}; + +public: + /** Add a new time offset sample. */ + void Add(std::chrono::seconds offset) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + + /** Compute and return the median of the collected time offset samples. The median is returned + * as 0 when there are less than 5 samples. */ + std::chrono::seconds Median() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + + /** Raise warnings if the median time offset exceeds the warnings threshold. Returns true if + * warnings were raised. */ + bool WarnIfOutOfSync() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); +}; + +#endif // BITCOIN_NODE_TIMEOFFSETS_H |