Bitcoin Core  0.20.99
P2P Digital Currency
timedata.cpp
Go to the documentation of this file.
1 // Copyright (c) 2014-2020 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 <netaddress.h>
12 #include <node/ui_interface.h>
13 #include <sync.h>
14 #include <util/system.h>
15 #include <util/translation.h>
16 #include <warnings.h>
17 
19 static int64_t nTimeOffset GUARDED_BY(g_timeoffset_mutex) = 0;
20 
28 int64_t GetTimeOffset()
29 {
30  LOCK(g_timeoffset_mutex);
31  return nTimeOffset;
32 }
33 
34 int64_t GetAdjustedTime()
35 {
36  return GetTime() + GetTimeOffset();
37 }
38 
39 static int64_t abs64(int64_t n)
40 {
41  return (n >= 0 ? n : -n);
42 }
43 
44 #define BITCOIN_TIMEDATA_MAX_SAMPLES 200
45 
46 void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample)
47 {
48  LOCK(g_timeoffset_mutex);
49  // Ignore duplicates
50  static std::set<CNetAddr> setKnown;
51  if (setKnown.size() == BITCOIN_TIMEDATA_MAX_SAMPLES)
52  return;
53  if (!setKnown.insert(ip).second)
54  return;
55 
56  // Add data
58  vTimeOffsets.input(nOffsetSample);
59  LogPrint(BCLog::NET, "added time data, samples %d, offset %+d (%+d minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample / 60);
60 
61  // There is a known issue here (see issue #4521):
62  //
63  // - The structure vTimeOffsets contains up to 200 elements, after which
64  // any new element added to it will not increase its size, replacing the
65  // oldest element.
66  //
67  // - The condition to update nTimeOffset includes checking whether the
68  // number of elements in vTimeOffsets is odd, which will never happen after
69  // there are 200 elements.
70  //
71  // But in this case the 'bug' is protective against some attacks, and may
72  // actually explain why we've never seen attacks which manipulate the
73  // clock offset.
74  //
75  // So we should hold off on fixing this and clean it up as part of
76  // a timing cleanup that strengthens it in a number of other ways.
77  //
78  if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1) {
79  int64_t nMedian = vTimeOffsets.median();
80  std::vector<int64_t> vSorted = vTimeOffsets.sorted();
81  // Only let other nodes change our time by so much
82  if (abs64(nMedian) <= std::max<int64_t>(0, gArgs.GetArg("-maxtimeadjustment", DEFAULT_MAX_TIME_ADJUSTMENT))) {
83  nTimeOffset = nMedian;
84  } else {
85  nTimeOffset = 0;
86 
87  static bool fDone;
88  if (!fDone) {
89  // If nobody has a time different than ours but within 5 minutes of ours, give a warning
90  bool fMatch = false;
91  for (const int64_t nOffset : vSorted) {
92  if (nOffset != 0 && abs64(nOffset) < 5 * 60) fMatch = true;
93  }
94 
95  if (!fMatch) {
96  fDone = true;
97  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);
98  SetMiscWarning(strMessage);
99  uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_WARNING);
100  }
101  }
102  }
103 
105  for (const int64_t n : vSorted) {
106  LogPrint(BCLog::NET, "%+d ", n); /* Continued */
107  }
108  LogPrint(BCLog::NET, "| "); /* Continued */
109  LogPrint(BCLog::NET, "nTimeOffset = %+d (%+d minutes)\n", nTimeOffset, nTimeOffset / 60);
110  }
111  }
112 }
#define LogPrint(category,...)
Definition: logging.h:182
Bilingual messages:
Definition: translation.h:16
#define BITCOIN_TIMEDATA_MAX_SAMPLES
Definition: timedata.cpp:44
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1164
static int64_t abs64(int64_t n)
Definition: timedata.cpp:39
void SetMiscWarning(const bilingual_str &warning)
Definition: warnings.cpp:20
Median filter over a stream of values.
Definition: timedata.h:22
#define PACKAGE_NAME
int64_t GetTimeOffset()
"Never go to sea with two chronometers; take one or three." Our three time sources are: ...
Definition: timedata.cpp:28
std::vector< T > sorted() const
Definition: timedata.h:67
void input(T value)
Definition: timedata.h:37
static int64_t nTimeOffset GUARDED_BY(g_timeoffset_mutex)=0
#define LOCK(cs)
Definition: sync.h:226
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:57
static bool LogAcceptCategory(BCLog::LogFlags category)
Return true if log accepts specified category.
Definition: logging.h:153
IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96))
Definition: netaddress.h:31
static Mutex g_timeoffset_mutex
Definition: timedata.cpp:18
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: system.cpp:380
int64_t GetAdjustedTime()
Definition: timedata.cpp:34
ArgsManager gArgs
Definition: system.cpp:77
CClientUIInterface uiInterface
void AddTimeData(const CNetAddr &ip, int64_t nOffsetSample)
Definition: timedata.cpp:46
int64_t GetTime()
Return system time (or mocked time, if set)
Definition: time.cpp:23
int size() const
Definition: timedata.h:62
static const int64_t DEFAULT_MAX_TIME_ADJUSTMENT
Definition: timedata.h:13
T median() const
Definition: timedata.h:49