]>
Commit | Line | Data |
---|---|---|
14f888ca | 1 | // Copyright (c) 2014 The Bitcoin developers |
fa94b9d5 | 2 | // Distributed under the MIT software license, see the accompanying |
14f888ca WL |
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 | ||
fa94b9d5 MF |
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 | */ | |
14f888ca WL |
27 | int64_t GetTimeOffset() |
28 | { | |
29 | LOCK(cs_nTimeOffset); | |
30 | return nTimeOffset; | |
31 | } | |
32 | ||
33 | int64_t GetAdjustedTime() | |
34 | { | |
35 | return GetTime() + GetTimeOffset(); | |
36 | } | |
37 | ||
ad49c256 WL |
38 | static int64_t abs64(int64_t n) |
39 | { | |
40 | return (n >= 0 ? n : -n); | |
41 | } | |
42 | ||
14f888ca WL |
43 | void AddTimeData(const CNetAddr& ip, int64_t nTime) |
44 | { | |
45 | int64_t nOffsetSample = nTime - GetTime(); | |
46 | ||
47 | LOCK(cs_nTimeOffset); | |
48 | // Ignore duplicates | |
49 | static set<CNetAddr> setKnown; | |
50 | if (!setKnown.insert(ip).second) | |
51 | return; | |
52 | ||
53 | // Add data | |
54 | static CMedianFilter<int64_t> vTimeOffsets(200,0); | |
55 | vTimeOffsets.input(nOffsetSample); | |
56 | LogPrintf("Added time data, samples %d, offset %+d (%+d minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample/60); | |
93659379 WL |
57 | |
58 | // There is a known issue here (see issue #4521): | |
59 | // | |
60 | // - The structure vTimeOffsets contains up to 200 elements, after which | |
61 | // any new element added to it will not increase its size, replacing the | |
62 | // oldest element. | |
63 | // | |
64 | // - The condition to update nTimeOffset includes checking whether the | |
65 | // number of elements in vTimeOffsets is odd, which will never happen after | |
66 | // there are 200 elements. | |
67 | // | |
68 | // But in this case the 'bug' is protective against some attacks, and may | |
69 | // actually explain why we've never seen attacks which manipulate the | |
70 | // clock offset. | |
71 | // | |
72 | // So we should hold off on fixing this and clean it up as part of | |
73 | // a timing cleanup that strengthens it in a number of other ways. | |
74 | // | |
14f888ca WL |
75 | if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1) |
76 | { | |
77 | int64_t nMedian = vTimeOffsets.median(); | |
78 | std::vector<int64_t> vSorted = vTimeOffsets.sorted(); | |
79 | // Only let other nodes change our time by so much | |
80 | if (abs64(nMedian) < 70 * 60) | |
81 | { | |
82 | nTimeOffset = nMedian; | |
83 | } | |
84 | else | |
85 | { | |
86 | nTimeOffset = 0; | |
87 | ||
88 | static bool fDone; | |
89 | if (!fDone) | |
90 | { | |
91 | // If nobody has a time different than ours but within 5 minutes of ours, give a warning | |
92 | bool fMatch = false; | |
93 | BOOST_FOREACH(int64_t nOffset, vSorted) | |
94 | if (nOffset != 0 && abs64(nOffset) < 5 * 60) | |
95 | fMatch = true; | |
96 | ||
97 | if (!fMatch) | |
98 | { | |
99 | fDone = true; | |
2b410c2f | 100 | 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 |
101 | strMiscWarning = strMessage; |
102 | LogPrintf("*** %s\n", strMessage); | |
103 | uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_WARNING); | |
104 | } | |
105 | } | |
106 | } | |
107 | if (fDebug) { | |
108 | BOOST_FOREACH(int64_t n, vSorted) | |
109 | LogPrintf("%+d ", n); | |
110 | LogPrintf("| "); | |
111 | } | |
112 | LogPrintf("nTimeOffset = %+d (%+d minutes)\n", nTimeOffset, nTimeOffset/60); | |
113 | } | |
114 | } |