Bitcoin Core  27.99.0
P2P Digital Currency
timedata.cpp
Go to the documentation of this file.
1 // Copyright (c) 2014-2022 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #if defined(HAVE_CONFIG_H)
7 #endif
8 
9 #include <timedata.h>
10 
11 #include <common/args.h>
12 #include <logging.h>
13 #include <netaddress.h>
14 #include <node/interface_ui.h>
15 #include <sync.h>
16 #include <tinyformat.h>
17 #include <util/translation.h>
18 #include <warnings.h>
19 
21 static int64_t nTimeOffset GUARDED_BY(g_timeoffset_mutex) = 0;
22 
30 int64_t GetTimeOffset()
31 {
33  return nTimeOffset;
34 }
35 
36 #define BITCOIN_TIMEDATA_MAX_SAMPLES 200
37 
38 static std::set<CNetAddr> g_sources;
40 static bool g_warning_emitted;
41 
42 void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample)
43 {
45  // Ignore duplicates
47  return;
48  if (!g_sources.insert(ip).second)
49  return;
50 
51  // Add data
52  g_time_offsets.input(nOffsetSample);
53  LogPrint(BCLog::NET, "added time data, samples %d, offset %+d (%+d minutes)\n", g_time_offsets.size(), nOffsetSample, nOffsetSample / 60);
54 
55  // There is a known issue here (see issue #4521):
56  //
57  // - The structure g_time_offsets contains up to 200 elements, after which
58  // any new element added to it will not increase its size, replacing the
59  // oldest element.
60  //
61  // - The condition to update nTimeOffset includes checking whether the
62  // number of elements in g_time_offsets is odd, which will never happen after
63  // there are 200 elements.
64  //
65  // But in this case the 'bug' is protective against some attacks, and may
66  // actually explain why we've never seen attacks which manipulate the
67  // clock offset.
68  //
69  // So we should hold off on fixing this and clean it up as part of
70  // a timing cleanup that strengthens it in a number of other ways.
71  //
72  if (g_time_offsets.size() >= 5 && g_time_offsets.size() % 2 == 1) {
73  int64_t nMedian = g_time_offsets.median();
74  std::vector<int64_t> vSorted = g_time_offsets.sorted();
75  // Only let other nodes change our time by so much
76  int64_t max_adjustment = std::max<int64_t>(0, gArgs.GetIntArg("-maxtimeadjustment", DEFAULT_MAX_TIME_ADJUSTMENT));
77  if (nMedian >= -max_adjustment && nMedian <= max_adjustment) {
78  nTimeOffset = nMedian;
79  } else {
80  nTimeOffset = 0;
81 
82  if (!g_warning_emitted) {
83  // If nobody has a time different than ours but within 5 minutes of ours, give a warning
84  bool fMatch = false;
85  for (const int64_t nOffset : vSorted) {
86  if (nOffset != 0 && nOffset > -5 * 60 && nOffset < 5 * 60) fMatch = true;
87  }
88 
89  if (!fMatch) {
90  g_warning_emitted = true;
91  bilingual_str strMessage = strprintf(_("Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly."), PACKAGE_NAME);
92  SetMiscWarning(strMessage);
93  uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_WARNING);
94  }
95  }
96  }
97 
99  std::string log_message{"time data samples: "};
100  for (const int64_t n : vSorted) {
101  log_message += strprintf("%+d ", n);
102  }
103  log_message += strprintf("| median offset = %+d (%+d minutes)", nTimeOffset, nTimeOffset / 60);
104  LogPrint(BCLog::NET, "%s\n", log_message);
105  }
106  }
107 }
108 
110 {
112  nTimeOffset = 0;
113  g_sources.clear();
115  g_warning_emitted = false;
116 }
ArgsManager gArgs
Definition: args.cpp:41
#define PACKAGE_NAME
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
Definition: args.cpp:480
Median filter over a stream of values.
Definition: timedata.h:23
Network address.
Definition: netaddress.h:112
Different type to mark Mutex at global scope.
Definition: sync.h:140
static CService ip(uint32_t i)
CClientUIInterface uiInterface
#define LogPrint(category,...)
Definition: logging.h:264
static bool LogAcceptCategory(BCLog::LogFlags category, BCLog::Level level)
Return true if log accepts specified category, at the specified level.
Definition: logging.h:210
@ NET
Definition: logging.h:41
Bilingual messages:
Definition: translation.h:18
#define LOCK(cs)
Definition: sync.h:257
static CMedianFilter< int64_t > g_time_offsets
Definition: timedata.cpp:39
int64_t GetTimeOffset()
"Never go to sea with two chronometers; take one or three." Our three time sources are:
Definition: timedata.cpp:30
void TestOnlyResetTimeData()
Reset the internal state of GetTimeOffset() and AddTimeData().
Definition: timedata.cpp:109
static GlobalMutex g_timeoffset_mutex
Definition: timedata.cpp:20
#define BITCOIN_TIMEDATA_MAX_SAMPLES
Definition: timedata.cpp:36
static std::set< CNetAddr > g_sources
Definition: timedata.cpp:38
void AddTimeData(const CNetAddr &ip, int64_t nOffsetSample)
Definition: timedata.cpp:42
static int64_t nTimeOffset GUARDED_BY(g_timeoffset_mutex)=0
static bool g_warning_emitted
Definition: timedata.cpp:40
static const int64_t DEFAULT_MAX_TIME_ADJUSTMENT
Definition: timedata.h:13
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1162
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:74
void SetMiscWarning(const bilingual_str &warning)
Definition: warnings.cpp:23