mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-11-11 06:28:31 +01:00
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.
This commit is contained in:
69
src/node/timeoffsets.cpp
Normal file
69
src/node/timeoffsets.cpp
Normal file
@@ -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;
|
||||
}
|
||||
39
src/node/timeoffsets.h
Normal file
39
src/node/timeoffsets.h
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user