aboutsummaryrefslogtreecommitdiff
path: root/src/node
diff options
context:
space:
mode:
authorstickies-v <stickies-v@protonmail.com>2024-03-07 11:23:00 +0000
committerstickies-v <stickies-v@protonmail.com>2024-04-10 17:01:27 +0200
commitee178dfcc1175e0af8163216c9c024f4bfc97965 (patch)
tree29d04d09dcc21862dcaf6627986a68b38f1e31bc /src/node
parent55361a15d1aa6984051441bce88112000688fb43 (diff)
downloadbitcoin-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.cpp69
-rw-r--r--src/node/timeoffsets.h39
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