Merge #12079: Improve prioritisetransaction test coverage
[bitcoinplatinum.git] / src / timedata.cpp
bloba803b2fc872d902fa238b4a225e78a35b6f0ef84
1 // Copyright (c) 2014-2017 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>
7 #endif
9 #include <timedata.h>
11 #include <netaddress.h>
12 #include <sync.h>
13 #include <ui_interface.h>
14 #include <util.h>
15 #include <utilstrencodings.h>
16 #include <warnings.h>
19 static CCriticalSection cs_nTimeOffset;
20 static int64_t nTimeOffset = 0;
22 /**
23 * "Never go to sea with two chronometers; take one or three."
24 * Our three time sources are:
25 * - System clock
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()
31 LOCK(cs_nTimeOffset);
32 return nTimeOffset;
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)
49 LOCK(cs_nTimeOffset);
50 // Ignore duplicates
51 static std::set<CNetAddr> setKnown;
52 if (setKnown.size() == BITCOIN_TIMEDATA_MAX_SAMPLES)
53 return;
54 if (!setKnown.insert(ip).second)
55 return;
57 // Add data
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
66 // oldest element.
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
74 // clock offset.
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;
88 else
90 nTimeOffset = 0;
92 static bool fDone;
93 if (!fDone)
95 // If nobody has a time different than ours but within 5 minutes of ours, give a warning
96 bool fMatch = false;
97 for (int64_t nOffset : vSorted)
98 if (nOffset != 0 && abs64(nOffset) < 5 * 60)
99 fMatch = true;
101 if (!fMatch)
103 fDone = true;
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);