2022-12-24 20:49:50 -03:00
// Copyright (c) 2014-2022 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>
2022-06-14 04:38:51 -04:00
# include <node/interface_ui.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
2022-04-20 03:10:13 -04:00
static GlobalMutex g_timeoffset_mutex ;
2020-06-06 09:41:02 -04:00
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 ;
}
2022-08-05 09:12:58 -04:00
NodeClock : : time_point GetAdjustedTime ( )
2014-06-19 09:08:37 -04:00
{
2022-08-05 09:12:58 -04:00
return NodeClock : : now ( ) + std : : chrono : : seconds { GetTimeOffset ( ) } ;
2014-06-19 09:08:37 -04:00
}
2015-08-11 10:57:52 -03:00
# define BITCOIN_TIMEDATA_MAX_SAMPLES 200
2021-01-18 10:34:03 -03:00
static std : : set < CNetAddr > g_sources ;
static CMedianFilter < int64_t > g_time_offsets { BITCOIN_TIMEDATA_MAX_SAMPLES , 0 } ;
static bool g_warning_emitted ;
2021-01-18 10:27:00 -03:00
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
2021-01-18 10:34:03 -03:00
if ( g_sources . size ( ) = = BITCOIN_TIMEDATA_MAX_SAMPLES )
2015-08-11 10:57:52 -03:00
return ;
2021-01-18 10:34:03 -03:00
if ( ! g_sources . insert ( ip ) . second )
2014-06-19 09:08:37 -04:00
return ;
// Add data
2021-01-18 10:34:03 -03:00
g_time_offsets . input ( nOffsetSample ) ;
LogPrint ( BCLog : : NET , " added time data, samples %d, offset %+d (%+d minutes) \n " , g_time_offsets . size ( ) , nOffsetSample , nOffsetSample / 60 ) ;
2014-07-24 13:00:24 -04:00
// There is a known issue here (see issue #4521):
//
2021-01-18 10:34:03 -03:00
// - The structure g_time_offsets contains up to 200 elements, after which
2014-07-24 13:00:24 -04:00
// any new element added to it will not increase its size, replacing the
// oldest element.
//
// - The condition to update nTimeOffset includes checking whether the
2021-01-18 10:34:03 -03:00
// number of elements in g_time_offsets is odd, which will never happen after
2014-07-24 13:00:24 -04:00
// 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.
//
2021-01-18 10:34:03 -03:00
if ( g_time_offsets . size ( ) > = 5 & & g_time_offsets . size ( ) % 2 = = 1 ) {
int64_t nMedian = g_time_offsets . median ( ) ;
std : : vector < int64_t > vSorted = g_time_offsets . sorted ( ) ;
2014-06-19 09:08:37 -04:00
// Only let other nodes change our time by so much
2019-08-22 21:40:41 -04:00
int64_t max_adjustment = std : : max < int64_t > ( 0 , gArgs . GetIntArg ( " -maxtimeadjustment " , DEFAULT_MAX_TIME_ADJUSTMENT ) ) ;
2020-10-12 21:36:51 -03:00
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 ;
2021-01-18 10:34:03 -03:00
if ( ! g_warning_emitted ) {
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 ) {
2021-01-18 10:34:03 -03:00
g_warning_emitted = 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
2022-05-24 13:52:49 -04:00
if ( LogAcceptCategory ( BCLog : : NET , BCLog : : Level : : Debug ) ) {
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
}
}
2021-01-18 10:27:00 -03:00
void TestOnlyResetTimeData ( )
{
LOCK ( g_timeoffset_mutex ) ;
nTimeOffset = 0 ;
2021-01-18 10:34:03 -03:00
g_sources . clear ( ) ;
g_time_offsets = CMedianFilter < int64_t > { BITCOIN_TIMEDATA_MAX_SAMPLES , 0 } ;
g_warning_emitted = false ;
2021-01-18 10:27:00 -03:00
}