Line data Source code
1 : // Copyright (c) 2014-2017 The Bitcoin developers 2 : // Copyright (c) 2017-2021 The PIVX Core developers 3 : // Distributed under the MIT software license, see the accompanying 4 : // file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 : 6 : #if defined(HAVE_CONFIG_H) 7 : #include "config/pivx-config.h" 8 : #endif 9 : 10 : #include "timedata.h" 11 : 12 : #include "chainparams.h" 13 : #include "guiinterface.h" 14 : #include "netaddress.h" 15 : #include "sync.h" 16 : #include "util/system.h" 17 : #include "warnings.h" 18 : 19 : 20 : static RecursiveMutex cs_nTimeOffset; 21 : static int64_t nTimeOffset = 0; 22 : 23 : /** 24 : * "Never go to sea with two chronometers; take one or three." 25 : * Our three time sources are: 26 : * - System clock 27 : * - Median of other nodes clocks 28 : * - The user (asking the user to fix the system clock if the first two disagree) 29 : */ 30 5996678 : int64_t GetTimeOffset() 31 : { 32 5996678 : LOCK(cs_nTimeOffset); 33 5996678 : return nTimeOffset; 34 : } 35 : 36 5995455 : int64_t GetAdjustedTime() 37 : { 38 5995455 : return GetTime() + GetTimeOffset(); 39 : } 40 : 41 : #define BITCOIN_TIMEDATA_MAX_SAMPLES 200 42 : 43 1360 : void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample, int nOffsetLimit) 44 : { 45 2720 : LOCK(cs_nTimeOffset); 46 : // Ignore duplicates (Except on regtest where all nodes have the same ip) 47 1360 : static std::set<CNetAddr> setKnown; 48 1360 : if (setKnown.size() == BITCOIN_TIMEDATA_MAX_SAMPLES) 49 0 : return; 50 1360 : if (!Params().IsRegTestNet() && !setKnown.insert(ip).second) 51 : return; 52 : 53 : // Add data 54 1360 : static CMedianFilter<int64_t> vTimeOffsets(BITCOIN_TIMEDATA_MAX_SAMPLES, 0); 55 1360 : vTimeOffsets.input(nOffsetSample); 56 1360 : LogPrintf("Added time data, samples %d, offset %+d (%+d minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample / 60); 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 : // 75 1360 : if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1) { 76 460 : int64_t nMedian = vTimeOffsets.median(); 77 920 : std::vector<int64_t> vSorted = vTimeOffsets.sorted(); 78 : // Only let other nodes change our time by so much 79 460 : if (abs64(nMedian) < nOffsetLimit) { 80 458 : nTimeOffset = nMedian; 81 916 : SetMiscWarning(""); 82 : } else { 83 2 : nTimeOffset = (nMedian > 0 ? 1 : -1) * nOffsetLimit; 84 4 : std::string strMessage = strprintf(_("Warning: Please check that your computer's date and time are correct! If your clock is wrong %s will not work properly."), PACKAGE_NAME); 85 2 : SetMiscWarning(strMessage); 86 2 : LogPrintf("*** %s\n", strMessage); 87 4 : uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_ERROR); 88 : } 89 460 : if (!gArgs.GetBoolArg("-shrinkdebugfile", g_logger->DefaultShrinkDebugFile())) { 90 5740 : for (int64_t n : vSorted) 91 5288 : LogPrintf("%+d ", n); /* Continued */ 92 452 : LogPrintf("| "); /* Continued */ 93 : } 94 460 : LogPrintf("nTimeOffset = %+d\n", nTimeOffset); 95 : } 96 : } 97 : 98 : // Time Protocol V2 99 : // Timestamp for time protocol V2: slot duration 15 seconds 100 0 : int64_t GetTimeSlot(const int64_t nTime) 101 : { 102 0 : const int slotLen = Params().GetConsensus().nTimeSlotLength; 103 0 : return (nTime / slotLen) * slotLen; 104 : } 105 : 106 0 : int64_t GetCurrentTimeSlot() 107 : { 108 0 : return GetTimeSlot(GetAdjustedTime()); 109 : }