LCOV - code coverage report
Current view: top level - src - timedata.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 53 54 98.1 %
Date: 2022-04-21 14:51:19 Functions: 4 4 100.0 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 24 32 75.0 %

           Branch data     Line data    Source code
#       1                 :            : // Copyright (c) 2014-2021 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 <tinyformat.h>
#      15                 :            : #include <util/system.h>
#      16                 :            : #include <util/translation.h>
#      17                 :            : #include <warnings.h>
#      18                 :            : 
#      19                 :            : static Mutex g_timeoffset_mutex;
#      20                 :            : static int64_t nTimeOffset GUARDED_BY(g_timeoffset_mutex) = 0;
#      21                 :            : 
#      22                 :            : /**
#      23                 :            :  * "Never go to sea with two chronometers; take one or three."
#      24                 :            :  * Our three time sources are:
#      25                 :            :  *  - System clock
#      26                 :            :  *  - Median of other nodes clocks
#      27                 :            :  *  - The user (asking the user to fix the system clock if the first two disagree)
#      28                 :            :  */
#      29                 :            : int64_t GetTimeOffset()
#      30                 :     219401 : {
#      31                 :     219401 :     LOCK(g_timeoffset_mutex);
#      32                 :     219401 :     return nTimeOffset;
#      33                 :     219401 : }
#      34                 :            : 
#      35                 :            : int64_t GetAdjustedTime()
#      36                 :     219308 : {
#      37                 :     219308 :     return GetTime() + GetTimeOffset();
#      38                 :     219308 : }
#      39                 :            : 
#      40                 :        812 : #define BITCOIN_TIMEDATA_MAX_SAMPLES 200
#      41                 :            : 
#      42                 :            : static std::set<CNetAddr> g_sources;
#      43                 :            : static CMedianFilter<int64_t> g_time_offsets{BITCOIN_TIMEDATA_MAX_SAMPLES, 0};
#      44                 :            : static bool g_warning_emitted;
#      45                 :            : 
#      46                 :            : void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample)
#      47                 :        808 : {
#      48                 :        808 :     LOCK(g_timeoffset_mutex);
#      49                 :            :     // Ignore duplicates
#      50         [ -  + ]:        808 :     if (g_sources.size() == BITCOIN_TIMEDATA_MAX_SAMPLES)
#      51                 :          0 :         return;
#      52         [ +  + ]:        808 :     if (!g_sources.insert(ip).second)
#      53                 :        156 :         return;
#      54                 :            : 
#      55                 :            :     // Add data
#      56                 :        652 :     g_time_offsets.input(nOffsetSample);
#      57         [ +  - ]:        652 :     LogPrint(BCLog::NET, "added time data, samples %d, offset %+d (%+d minutes)\n", g_time_offsets.size(), nOffsetSample, nOffsetSample / 60);
#      58                 :            : 
#      59                 :            :     // There is a known issue here (see issue #4521):
#      60                 :            :     //
#      61                 :            :     // - The structure g_time_offsets 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 g_time_offsets 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                 :            :     //
#      76 [ +  + ][ +  + ]:        652 :     if (g_time_offsets.size() >= 5 && g_time_offsets.size() % 2 == 1) {
#      77                 :        196 :         int64_t nMedian = g_time_offsets.median();
#      78                 :        196 :         std::vector<int64_t> vSorted = g_time_offsets.sorted();
#      79                 :            :         // Only let other nodes change our time by so much
#      80                 :        196 :         int64_t max_adjustment = std::max<int64_t>(0, gArgs.GetIntArg("-maxtimeadjustment", DEFAULT_MAX_TIME_ADJUSTMENT));
#      81 [ +  - ][ +  + ]:        196 :         if (nMedian >= -max_adjustment && nMedian <= max_adjustment) {
#      82                 :        192 :             nTimeOffset = nMedian;
#      83                 :        192 :         } else {
#      84                 :          4 :             nTimeOffset = 0;
#      85                 :            : 
#      86         [ +  + ]:          4 :             if (!g_warning_emitted) {
#      87                 :            :                 // If nobody has a time different than ours but within 5 minutes of ours, give a warning
#      88                 :          2 :                 bool fMatch = false;
#      89         [ +  + ]:         10 :                 for (const int64_t nOffset : vSorted) {
#      90 [ +  + ][ +  - ]:         10 :                     if (nOffset != 0 && nOffset > -5 * 60 && nOffset < 5 * 60) fMatch = true;
#                 [ -  + ]
#      91                 :         10 :                 }
#      92                 :            : 
#      93         [ +  - ]:          2 :                 if (!fMatch) {
#      94                 :          2 :                     g_warning_emitted = true;
#      95                 :          2 :                     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);
#      96                 :          2 :                     SetMiscWarning(strMessage);
#      97                 :          2 :                     uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_WARNING);
#      98                 :          2 :                 }
#      99                 :          2 :             }
#     100                 :          4 :         }
#     101                 :            : 
#     102         [ +  - ]:        196 :         if (LogAcceptCategory(BCLog::NET)) {
#     103                 :        196 :             std::string log_message{"time data samples: "};
#     104         [ +  + ]:      19992 :             for (const int64_t n : vSorted) {
#     105                 :      19992 :                 log_message += strprintf("%+d  ", n);
#     106                 :      19992 :             }
#     107                 :        196 :             log_message += strprintf("|  median offset = %+d  (%+d minutes)", nTimeOffset, nTimeOffset / 60);
#     108         [ +  - ]:        196 :             LogPrint(BCLog::NET, "%s\n", log_message);
#     109                 :        196 :         }
#     110                 :        196 :     }
#     111                 :        652 : }
#     112                 :            : 
#     113                 :            : void TestOnlyResetTimeData()
#     114                 :          4 : {
#     115                 :          4 :     LOCK(g_timeoffset_mutex);
#     116                 :          4 :     nTimeOffset = 0;
#     117                 :          4 :     g_sources.clear();
#     118                 :          4 :     g_time_offsets = CMedianFilter<int64_t>{BITCOIN_TIMEDATA_MAX_SAMPLES, 0};
#     119                 :          4 :     g_warning_emitted = false;
#     120                 :          4 : }

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a