2021-12-30 19:36:57 +02:00
// Copyright (c) 2014-2021 The Bitcoin Core developers
2014-10-31 08:43:19 +08:00
// Distributed under the MIT software license, see the accompanying
2014-06-19 15:08:37 +02:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2015-12-09 10:53:12 +00:00
# if defined(HAVE_CONFIG_H)
2017-11-10 13:57:53 +13:00
# include <config/bitcoin-config.h>
2015-12-09 10:53:12 +00:00
# endif
2017-11-10 13:57:53 +13:00
# include <timedata.h>
2014-06-19 15:08:37 +02:00
2017-11-10 13:57:53 +13:00
# include <netaddress.h>
2020-06-19 18:14:17 -04:00
# include <node/ui_interface.h>
2017-11-10 13:57:53 +13:00
# include <sync.h>
2021-09-21 22:33:05 +02:00
# include <tinyformat.h>
2018-10-22 15:51:11 -07:00
# include <util/system.h>
2019-06-17 10:56:52 +03:00
# include <util/translation.h>
2017-11-10 13:57:53 +13:00
# include <warnings.h>
2014-06-19 15:08:37 +02:00
2020-06-06 16:41:02 +03:00
static Mutex g_timeoffset_mutex ;
static int64_t nTimeOffset GUARDED_BY ( g_timeoffset_mutex ) = 0 ;
2014-06-19 15:08:37 +02:00
2014-10-31 08:43:19 +08: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 15:08:37 +02:00
int64_t GetTimeOffset ( )
{
2020-06-06 16:41:02 +03:00
LOCK ( g_timeoffset_mutex ) ;
2014-06-19 15:08:37 +02:00
return nTimeOffset ;
}
int64_t GetAdjustedTime ( )
{
return GetTime ( ) + GetTimeOffset ( ) ;
}
2015-08-11 15:57:52 +02:00
# define BITCOIN_TIMEDATA_MAX_SAMPLES 200
2021-01-18 14:34:03 +01: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 14:27:00 +01:00
2014-12-15 11:06:15 +01:00
void AddTimeData ( const CNetAddr & ip , int64_t nOffsetSample )
2014-06-19 15:08:37 +02:00
{
2020-06-06 16:41:02 +03:00
LOCK ( g_timeoffset_mutex ) ;
2014-06-19 15:08:37 +02:00
// Ignore duplicates
2021-01-18 14:34:03 +01:00
if ( g_sources . size ( ) = = BITCOIN_TIMEDATA_MAX_SAMPLES )
2015-08-11 15:57:52 +02:00
return ;
2021-01-18 14:34:03 +01:00
if ( ! g_sources . insert ( ip ) . second )
2014-06-19 15:08:37 +02:00
return ;
// Add data
2021-01-18 14:34:03 +01: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 19:00:24 +02:00
// There is a known issue here (see issue #4521):
//
2021-01-18 14:34:03 +01:00
// - The structure g_time_offsets contains up to 200 elements, after which
2014-07-24 19:00:24 +02: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 14:34:03 +01:00
// number of elements in g_time_offsets is odd, which will never happen after
2014-07-24 19:00:24 +02: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 14:34:03 +01: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 15:08:37 +02: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 17:36:51 -07:00
if ( nMedian > = - max_adjustment & & nMedian < = max_adjustment ) {
2014-06-19 15:08:37 +02:00
nTimeOffset = nMedian ;
2020-06-07 14:00:28 +03:00
} else {
2014-06-19 15:08:37 +02:00
nTimeOffset = 0 ;
2021-01-18 14:34:03 +01:00
if ( ! g_warning_emitted ) {
2014-06-19 15:08:37 +02:00
// If nobody has a time different than ours but within 5 minutes of ours, give a warning
bool fMatch = false ;
2020-06-07 14:00:28 +03:00
for ( const int64_t nOffset : vSorted ) {
2020-10-12 17:36:51 -07:00
if ( nOffset ! = 0 & & nOffset > - 5 * 60 & & nOffset < 5 * 60 ) fMatch = true ;
2020-06-07 14:00:28 +03:00
}
2014-06-19 15:08:37 +02:00
2020-06-07 14:00:28 +03:00
if ( ! fMatch ) {
2021-01-18 14:34:03 +01:00
g_warning_emitted = true ;
2020-04-11 18:47:17 +03: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 12:14:32 +03:00
SetMiscWarning ( strMessage ) ;
2014-06-19 15:08:37 +02:00
uiInterface . ThreadSafeMessageBox ( strMessage , " " , CClientUIInterface : : MSG_WARNING ) ;
}
}
}
2016-12-25 20:19:40 +00:00
2022-05-24 19:52:49 +02:00
if ( LogAcceptCategory ( BCLog : : NET , BCLog : : Level : : Debug ) ) {
2021-09-21 22:33:05 +02:00
std : : string log_message { " time data samples: " } ;
2018-06-18 07:58:28 +02:00
for ( const int64_t n : vSorted ) {
2021-09-21 22:33:05 +02:00
log_message + = strprintf ( " %+d " , n ) ;
2016-12-25 20:19:40 +00:00
}
2021-09-21 22:33:05 +02:00
log_message + = strprintf ( " | median offset = %+d (%+d minutes) " , nTimeOffset , nTimeOffset / 60 ) ;
LogPrint ( BCLog : : NET , " %s \n " , log_message ) ;
2016-12-25 20:19:40 +00:00
}
2014-06-19 15:08:37 +02:00
}
}
2021-01-18 14:27:00 +01:00
void TestOnlyResetTimeData ( )
{
LOCK ( g_timeoffset_mutex ) ;
nTimeOffset = 0 ;
2021-01-18 14:34:03 +01:00
g_sources . clear ( ) ;
g_time_offsets = CMedianFilter < int64_t > { BITCOIN_TIMEDATA_MAX_SAMPLES , 0 } ;
g_warning_emitted = false ;
2021-01-18 14:27:00 +01:00
}