1 // Copyright (c) 2014-2016 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.
5 #if defined(HAVE_CONFIG_H)
6 #include <config/bitcoin-config.h>
11 #include <netaddress.h>
13 #include <ui_interface.h>
15 #include <utilstrencodings.h>
19 static CCriticalSection cs_nTimeOffset
;
20 static int64_t nTimeOffset
= 0;
23 * "Never go to sea with two chronometers; take one or three."
24 * Our three time sources are:
26 * - Median of other nodes clocks
27 * - The user (asking the user to fix the system clock if the first two disagree)
29 int64_t GetTimeOffset()
35 int64_t GetAdjustedTime()
37 return GetTime() + GetTimeOffset();
40 static int64_t abs64(int64_t n
)
42 return (n
>= 0 ? n
: -n
);
45 #define BITCOIN_TIMEDATA_MAX_SAMPLES 200
47 void AddTimeData(const CNetAddr
& ip
, int64_t nOffsetSample
)
51 static std::set
<CNetAddr
> setKnown
;
52 if (setKnown
.size() == BITCOIN_TIMEDATA_MAX_SAMPLES
)
54 if (!setKnown
.insert(ip
).second
)
58 static CMedianFilter
<int64_t> vTimeOffsets(BITCOIN_TIMEDATA_MAX_SAMPLES
, 0);
59 vTimeOffsets
.input(nOffsetSample
);
60 LogPrint(BCLog::NET
,"added time data, samples %d, offset %+d (%+d minutes)\n", vTimeOffsets
.size(), nOffsetSample
, nOffsetSample
/60);
62 // There is a known issue here (see issue #4521):
64 // - The structure vTimeOffsets contains up to 200 elements, after which
65 // any new element added to it will not increase its size, replacing the
68 // - The condition to update nTimeOffset includes checking whether the
69 // number of elements in vTimeOffsets is odd, which will never happen after
70 // there are 200 elements.
72 // But in this case the 'bug' is protective against some attacks, and may
73 // actually explain why we've never seen attacks which manipulate the
76 // So we should hold off on fixing this and clean it up as part of
77 // a timing cleanup that strengthens it in a number of other ways.
79 if (vTimeOffsets
.size() >= 5 && vTimeOffsets
.size() % 2 == 1)
81 int64_t nMedian
= vTimeOffsets
.median();
82 std::vector
<int64_t> vSorted
= vTimeOffsets
.sorted();
83 // Only let other nodes change our time by so much
84 if (abs64(nMedian
) <= std::max
<int64_t>(0, gArgs
.GetArg("-maxtimeadjustment", DEFAULT_MAX_TIME_ADJUSTMENT
)))
86 nTimeOffset
= nMedian
;
95 // If nobody has a time different than ours but within 5 minutes of ours, give a warning
97 for (int64_t nOffset
: vSorted
)
98 if (nOffset
!= 0 && abs64(nOffset
) < 5 * 60)
104 std::string 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
));
105 SetMiscWarning(strMessage
);
106 uiInterface
.ThreadSafeMessageBox(strMessage
, "", CClientUIInterface::MSG_WARNING
);
111 if (LogAcceptCategory(BCLog::NET
)) {
112 for (int64_t n
: vSorted
) {
113 LogPrint(BCLog::NET
, "%+d ", n
);
115 LogPrint(BCLog::NET
, "| ");
117 LogPrint(BCLog::NET
, "nTimeOffset = %+d (%+d minutes)\n", nTimeOffset
, nTimeOffset
/60);