8e5162fb9eff3e61a154e8ae310f1ea1f7d328c9
[novacoin.git] / src / timedata.cpp
1 #include "timedata.h"
2 #include "netbase.h"
3 #include "sync.h"
4 #include "interface.h"
5
6 #include <climits>
7
8 static CCriticalSection cs_nTimeOffset;
9 static uint32_t NOVACOIN_TIMEDATA_MAX_SAMPLES = 200;
10
11 // Trusted NTP offset or median of NTP samples.
12 extern int64_t nNtpOffset;
13
14 // Median of time samples given by other nodes.
15 static int64_t nNodesOffset = std::numeric_limits<int64_t>::max();
16
17 //
18 // "Never go to sea with two chronometers; take one or three."
19 // Our three time sources are:
20 //  - System clock
21 //  - Median of other nodes clocks
22 //  - The user (asking the user to fix the system clock if the first two disagree)
23 //
24
25 // Select time offset:
26 int64_t GetTimeOffset()
27 {
28     LOCK(cs_nTimeOffset);
29     // If NTP and system clock are in agreement within 40 minutes, then use NTP.
30     if (std::abs(nNtpOffset) < 40 * 60)
31         return nNtpOffset;
32
33     // If not, then choose between median peer time and system clock.
34     if (std::abs(nNodesOffset) < 70 * 60)
35         return nNodesOffset;
36
37     return 0;
38 }
39
40 int64_t GetNodesOffset()
41 {
42         return nNodesOffset;
43 }
44
45 int64_t GetAdjustedTime()
46 {
47     return GetTime() + GetTimeOffset();
48 }
49
50 void AddTimeData(const CNetAddr& ip, int64_t nTime)
51 {
52     int64_t nOffsetSample = nTime - GetTime();
53
54     LOCK(cs_nTimeOffset);
55     // Ignore duplicates
56     static std::set<CNetAddr> setKnown;
57     if (setKnown.size() == NOVACOIN_TIMEDATA_MAX_SAMPLES)
58         return;
59     if (!setKnown.insert(ip).second)
60         return;
61
62     // Add data
63     static CMedianFilter<int64_t> vTimeOffsets(NOVACOIN_TIMEDATA_MAX_SAMPLES,0);
64     vTimeOffsets.input(nOffsetSample);
65     printf("Added time data, samples %d, offset %+" PRId64 " (%+" PRId64 " minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample/60);
66     if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1)
67     {
68         int64_t nMedian = vTimeOffsets.median();
69         std::vector<int64_t> vSorted = vTimeOffsets.sorted();
70         // Only let other nodes change our time by so much
71         if (std::abs(nMedian) < 70 * 60)
72         {
73             nNodesOffset = nMedian;
74         }
75         else
76         {
77             nNodesOffset = std::numeric_limits<int64_t>::max();
78
79             static bool fDone;
80             if (!fDone)
81             {
82                 bool fMatch = false;
83
84                 // If nobody has a time different than ours but within 5 minutes of ours, give a warning
85                 for (int64_t nOffset : vSorted)
86                     if (nOffset != 0 && std::abs(nOffset) < 5 * 60)
87                         fMatch = true;
88
89                 if (!fMatch)
90                 {
91                     fDone = true;
92                     std::string strMessage = _("Warning: Please check that your computer's date and time are correct! If your clock is wrong NovaCoin will not work properly.");
93                     strMiscWarning = strMessage;
94                     printf("*** %s\n", strMessage.c_str());
95                     uiInterface.ThreadSafeMessageBox(strMessage+" ", std::string("NovaCoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION);
96                 }
97             }
98         }
99         if (fDebug) {
100             for (int64_t n : vSorted)
101                 printf("%+" PRId64 "  ", n);
102             printf("|  ");
103         }
104         if (nNodesOffset != std::numeric_limits<int64_t>::max())
105             printf("nNodesOffset = %+" PRId64 "  (%+" PRId64 " minutes)\n", nNodesOffset, nNodesOffset/60);
106     }
107 }