LCOV - code coverage report
Current view: top level - src - timedata.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 43 44 97.7 %
Date: 2020-09-26 01:30:44 Functions: 5 5 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2014-2020 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.
       4             : 
       5             : #if defined(HAVE_CONFIG_H)
       6             : #include <config/bitcoin-config.h>
       7             : #endif
       8             : 
       9             : #include <timedata.h>
      10             : 
      11             : #include <netaddress.h>
      12             : #include <node/ui_interface.h>
      13             : #include <sync.h>
      14             : #include <util/system.h>
      15             : #include <util/translation.h>
      16             : #include <warnings.h>
      17             : 
      18         640 : static Mutex g_timeoffset_mutex;
      19             : static int64_t nTimeOffset GUARDED_BY(g_timeoffset_mutex) = 0;
      20             : 
      21             : /**
      22             :  * "Never go to sea with two chronometers; take one or three."
      23             :  * Our three time sources are:
      24             :  *  - System clock
      25             :  *  - Median of other nodes clocks
      26             :  *  - The user (asking the user to fix the system clock if the first two disagree)
      27             :  */
      28     1466674 : int64_t GetTimeOffset()
      29             : {
      30     1466674 :     LOCK(g_timeoffset_mutex);
      31     1466674 :     return nTimeOffset;
      32     1466674 : }
      33             : 
      34     1466627 : int64_t GetAdjustedTime()
      35             : {
      36     1466627 :     return GetTime() + GetTimeOffset();
      37             : }
      38             : 
      39         102 : static int64_t abs64(int64_t n)
      40             : {
      41         102 :     return (n >= 0 ? n : -n);
      42             : }
      43             : 
      44             : #define BITCOIN_TIMEDATA_MAX_SAMPLES 200
      45             : 
      46         898 : void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample)
      47             : {
      48         898 :     LOCK(g_timeoffset_mutex);
      49             :     // Ignore duplicates
      50         898 :     static std::set<CNetAddr> setKnown;
      51         898 :     if (setKnown.size() == BITCOIN_TIMEDATA_MAX_SAMPLES)
      52           0 :         return;
      53         898 :     if (!setKnown.insert(ip).second)
      54         398 :         return;
      55             : 
      56             :     // Add data
      57         500 :     static CMedianFilter<int64_t> vTimeOffsets(BITCOIN_TIMEDATA_MAX_SAMPLES, 0);
      58         500 :     vTimeOffsets.input(nOffsetSample);
      59         500 :     LogPrint(BCLog::NET, "added time data, samples %d, offset %+d (%+d minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample / 60);
      60             : 
      61             :     // There is a known issue here (see issue #4521):
      62             :     //
      63             :     // - The structure vTimeOffsets contains up to 200 elements, after which
      64             :     // any new element added to it will not increase its size, replacing the
      65             :     // oldest element.
      66             :     //
      67             :     // - The condition to update nTimeOffset includes checking whether the
      68             :     // number of elements in vTimeOffsets is odd, which will never happen after
      69             :     // there are 200 elements.
      70             :     //
      71             :     // But in this case the 'bug' is protective against some attacks, and may
      72             :     // actually explain why we've never seen attacks which manipulate the
      73             :     // clock offset.
      74             :     //
      75             :     // So we should hold off on fixing this and clean it up as part of
      76             :     // a timing cleanup that strengthens it in a number of other ways.
      77             :     //
      78         500 :     if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1) {
      79          98 :         int64_t nMedian = vTimeOffsets.median();
      80          98 :         std::vector<int64_t> vSorted = vTimeOffsets.sorted();
      81             :         // Only let other nodes change our time by so much
      82          98 :         if (abs64(nMedian) <= std::max<int64_t>(0, gArgs.GetArg("-maxtimeadjustment", DEFAULT_MAX_TIME_ADJUSTMENT))) {
      83          96 :             nTimeOffset = nMedian;
      84          96 :         } else {
      85           2 :             nTimeOffset = 0;
      86             : 
      87             :             static bool fDone;
      88           2 :             if (!fDone) {
      89             :                 // If nobody has a time different than ours but within 5 minutes of ours, give a warning
      90             :                 bool fMatch = false;
      91           6 :                 for (const int64_t nOffset : vSorted) {
      92           5 :                     if (nOffset != 0 && abs64(nOffset) < 5 * 60) fMatch = true;
      93             :                 }
      94             : 
      95           1 :                 if (!fMatch) {
      96           1 :                     fDone = true;
      97           1 :                     bilingual_str 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);
      98           1 :                     SetMiscWarning(strMessage);
      99           1 :                     uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_WARNING);
     100           1 :                 }
     101           1 :             }
     102             :         }
     103             : 
     104          98 :         if (LogAcceptCategory(BCLog::NET)) {
     105       10094 :             for (const int64_t n : vSorted) {
     106        9996 :                 LogPrint(BCLog::NET, "%+d  ", n); /* Continued */
     107        9996 :             }
     108          98 :             LogPrint(BCLog::NET, "|  "); /* Continued */
     109          98 :             LogPrint(BCLog::NET, "nTimeOffset = %+d  (%+d minutes)\n", nTimeOffset, nTimeOffset / 60);
     110             :         }
     111          98 :     }
     112         898 : }

Generated by: LCOV version 1.15