]>
Commit | Line | Data |
---|---|---|
14f888ca WL |
1 | // Copyright (c) 2014 The Bitcoin developers |
2 | // Distributed under the MIT/X11 software license, see the accompanying | |
3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | |
4 | ||
5 | #include "timedata.h" | |
6 | ||
7 | #include "netbase.h" | |
8 | #include "sync.h" | |
9 | #include "ui_interface.h" | |
10 | #include "util.h" | |
ad49c256 | 11 | #include "utilstrencodings.h" |
14f888ca WL |
12 | |
13 | #include <boost/foreach.hpp> | |
14 | ||
15 | using namespace std; | |
16 | ||
17 | static CCriticalSection cs_nTimeOffset; | |
18 | static int64_t nTimeOffset = 0; | |
19 | ||
20 | // | |
21 | // "Never go to sea with two chronometers; take one or three." | |
22 | // Our three time sources are: | |
23 | // - System clock | |
24 | // - Median of other nodes clocks | |
25 | // - The user (asking the user to fix the system clock if the first two disagree) | |
26 | // | |
27 | // | |
28 | int64_t GetTimeOffset() | |
29 | { | |
30 | LOCK(cs_nTimeOffset); | |
31 | return nTimeOffset; | |
32 | } | |
33 | ||
34 | int64_t GetAdjustedTime() | |
35 | { | |
36 | return GetTime() + GetTimeOffset(); | |
37 | } | |
38 | ||
ad49c256 WL |
39 | static int64_t abs64(int64_t n) |
40 | { | |
41 | return (n >= 0 ? n : -n); | |
42 | } | |
43 | ||
14f888ca WL |
44 | void AddTimeData(const CNetAddr& ip, int64_t nTime) |
45 | { | |
46 | int64_t nOffsetSample = nTime - GetTime(); | |
47 | ||
48 | LOCK(cs_nTimeOffset); | |
49 | // Ignore duplicates | |
50 | static set<CNetAddr> setKnown; | |
51 | if (!setKnown.insert(ip).second) | |
52 | return; | |
53 | ||
54 | // Add data | |
55 | static CMedianFilter<int64_t> vTimeOffsets(200,0); | |
56 | vTimeOffsets.input(nOffsetSample); | |
57 | LogPrintf("Added time data, samples %d, offset %+d (%+d minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample/60); | |
93659379 WL |
58 | |
59 | // There is a known issue here (see issue #4521): | |
60 | // | |
61 | // - The structure vTimeOffsets contains up to 200 elements, after which | |
62 | // any new element added to it will not increase its size, replacing the | |
63 | // oldest element. | |
64 | // | |
65 | // - The condition to update nTimeOffset includes checking whether the | |
66 | // number of elements in vTimeOffsets is odd, which will never happen after | |
67 | // there are 200 elements. | |
68 | // | |
69 | // But in this case the 'bug' is protective against some attacks, and may | |
70 | // actually explain why we've never seen attacks which manipulate the | |
71 | // clock offset. | |
72 | // | |
73 | // So we should hold off on fixing this and clean it up as part of | |
74 | // a timing cleanup that strengthens it in a number of other ways. | |
75 | // | |
14f888ca WL |
76 | if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1) |
77 | { | |
78 | int64_t nMedian = vTimeOffsets.median(); | |
79 | std::vector<int64_t> vSorted = vTimeOffsets.sorted(); | |
80 | // Only let other nodes change our time by so much | |
81 | if (abs64(nMedian) < 70 * 60) | |
82 | { | |
83 | nTimeOffset = nMedian; | |
84 | } | |
85 | else | |
86 | { | |
87 | nTimeOffset = 0; | |
88 | ||
89 | static bool fDone; | |
90 | if (!fDone) | |
91 | { | |
92 | // If nobody has a time different than ours but within 5 minutes of ours, give a warning | |
93 | bool fMatch = false; | |
94 | BOOST_FOREACH(int64_t nOffset, vSorted) | |
95 | if (nOffset != 0 && abs64(nOffset) < 5 * 60) | |
96 | fMatch = true; | |
97 | ||
98 | if (!fMatch) | |
99 | { | |
100 | fDone = true; | |
2b410c2f | 101 | string strMessage = _("Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly."); |
14f888ca WL |
102 | strMiscWarning = strMessage; |
103 | LogPrintf("*** %s\n", strMessage); | |
104 | uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_WARNING); | |
105 | } | |
106 | } | |
107 | } | |
108 | if (fDebug) { | |
109 | BOOST_FOREACH(int64_t n, vSorted) | |
110 | LogPrintf("%+d ", n); | |
111 | LogPrintf("| "); | |
112 | } | |
113 | LogPrintf("nTimeOffset = %+d (%+d minutes)\n", nTimeOffset, nTimeOffset/60); | |
114 | } | |
115 | } |