2020-01-14 16:17:38 -03:00
// Copyright (c) 2014-2020 The Bitcoin Core developers
2014-10-30 21:43:19 -03:00
// Distributed under the MIT software license, see the accompanying
2014-06-19 09:08:37 -04:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2015-12-09 07:53:12 -03:00
# if defined(HAVE_CONFIG_H)
2017-11-09 21:57:53 -03:00
# include <config/bitcoin-config.h>
2015-12-09 07:53:12 -03:00
# endif
2017-11-09 21:57:53 -03:00
# include <timedata.h>
2014-06-19 09:08:37 -04:00
2017-11-09 21:57:53 -03:00
# include <netaddress.h>
2020-06-19 18:14:17 -04:00
# include <node/ui_interface.h>
2017-11-09 21:57:53 -03:00
# include <sync.h>
2021-09-21 17:33:05 -03:00
# include <tinyformat.h>
2018-10-22 19:51:11 -03:00
# include <util/system.h>
2019-06-17 03:56:52 -04:00
# include <util/translation.h>
2017-11-09 21:57:53 -03:00
# include <warnings.h>
2014-06-19 09:08:37 -04:00
2020-06-06 09:41:02 -04:00
static Mutex g_timeoffset_mutex ;
static int64_t nTimeOffset GUARDED_BY ( g_timeoffset_mutex ) = 0 ;
2014-06-19 09:08:37 -04:00
2014-10-30 21:43:19 -03:00
/**
* " Never go to sea with two chronometers; take one or three. "
* Our three time sources are :
* - System clock
* - Median of other nodes clocks
* - The user ( asking the user to fix the system clock if the first two disagree )
*/
2014-06-19 09:08:37 -04:00
int64_t GetTimeOffset ( )
{
2020-06-06 09:41:02 -04:00
LOCK ( g_timeoffset_mutex ) ;
2014-06-19 09:08:37 -04:00
return nTimeOffset ;
}
int64_t GetAdjustedTime ( )
{
return GetTime ( ) + GetTimeOffset ( ) ;
}
2015-08-11 10:57:52 -03:00
# define BITCOIN_TIMEDATA_MAX_SAMPLES 200
2014-12-15 07:06:15 -03:00
void AddTimeData ( const CNetAddr & ip , int64_t nOffsetSample )
2014-06-19 09:08:37 -04:00
{
2020-06-06 09:41:02 -04:00
LOCK ( g_timeoffset_mutex ) ;
2014-06-19 09:08:37 -04:00
// Ignore duplicates
2017-01-27 05:43:41 -03:00
static std : : set < CNetAddr > setKnown ;
2015-08-11 10:57:52 -03:00
if ( setKnown . size ( ) = = BITCOIN_TIMEDATA_MAX_SAMPLES )
return ;
2014-06-19 09:08:37 -04:00
if ( ! setKnown . insert ( ip ) . second )
return ;
// Add data
2015-08-11 10:57:52 -03:00
static CMedianFilter < int64_t > vTimeOffsets ( BITCOIN_TIMEDATA_MAX_SAMPLES , 0 ) ;
2014-06-19 09:08:37 -04:00
vTimeOffsets . input ( nOffsetSample ) ;
2020-06-07 07:00:28 -04:00
LogPrint ( BCLog : : NET , " added time data, samples %d, offset %+d (%+d minutes) \n " , vTimeOffsets . size ( ) , nOffsetSample , nOffsetSample / 60 ) ;
2014-07-24 13:00:24 -04:00
// There is a known issue here (see issue #4521):
//
// - The structure vTimeOffsets contains up to 200 elements, after which
// any new element added to it will not increase its size, replacing the
// oldest element.
//
// - The condition to update nTimeOffset includes checking whether the
// number of elements in vTimeOffsets is odd, which will never happen after
// there are 200 elements.
//
// But in this case the 'bug' is protective against some attacks, and may
// actually explain why we've never seen attacks which manipulate the
// clock offset.
//
// So we should hold off on fixing this and clean it up as part of
// a timing cleanup that strengthens it in a number of other ways.
//
2020-06-07 07:00:28 -04:00
if ( vTimeOffsets . size ( ) > = 5 & & vTimeOffsets . size ( ) % 2 = = 1 ) {
2014-06-19 09:08:37 -04:00
int64_t nMedian = vTimeOffsets . median ( ) ;
std : : vector < int64_t > vSorted = vTimeOffsets . sorted ( ) ;
// Only let other nodes change our time by so much
2020-10-12 21:36:51 -03:00
int64_t max_adjustment = std : : max < int64_t > ( 0 , gArgs . GetArg ( " -maxtimeadjustment " , DEFAULT_MAX_TIME_ADJUSTMENT ) ) ;
if ( nMedian > = - max_adjustment & & nMedian < = max_adjustment ) {
2014-06-19 09:08:37 -04:00
nTimeOffset = nMedian ;
2020-06-07 07:00:28 -04:00
} else {
2014-06-19 09:08:37 -04:00
nTimeOffset = 0 ;
static bool fDone ;
2020-06-07 07:00:28 -04:00
if ( ! fDone ) {
2014-06-19 09:08:37 -04:00
// If nobody has a time different than ours but within 5 minutes of ours, give a warning
bool fMatch = false ;
2020-06-07 07:00:28 -04:00
for ( const int64_t nOffset : vSorted ) {
2020-10-12 21:36:51 -03:00
if ( nOffset ! = 0 & & nOffset > - 5 * 60 & & nOffset < 5 * 60 ) fMatch = true ;
2020-06-07 07:00:28 -04:00
}
2014-06-19 09:08:37 -04:00
2020-06-07 07:00:28 -04:00
if ( ! fMatch ) {
2014-06-19 09:08:37 -04:00
fDone = true ;
2020-04-11 11:47:17 -04:00
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 ) ;
2020-06-10 05:14:32 -04:00
SetMiscWarning ( strMessage ) ;
2014-06-19 09:08:37 -04:00
uiInterface . ThreadSafeMessageBox ( strMessage , " " , CClientUIInterface : : MSG_WARNING ) ;
}
}
}
2016-12-25 17:19:40 -03:00
if ( LogAcceptCategory ( BCLog : : NET ) ) {
2021-09-21 17:33:05 -03:00
std : : string log_message { " time data samples: " } ;
2018-06-18 01:58:28 -04:00
for ( const int64_t n : vSorted ) {
2021-09-21 17:33:05 -03:00
log_message + = strprintf ( " %+d " , n ) ;
2016-12-25 17:19:40 -03:00
}
2021-09-21 17:33:05 -03:00
log_message + = strprintf ( " | median offset = %+d (%+d minutes) " , nTimeOffset , nTimeOffset / 60 ) ;
LogPrint ( BCLog : : NET , " %s \n " , log_message ) ;
2016-12-25 17:19:40 -03:00
}
2014-06-19 09:08:37 -04:00
}
}