forked from lthn/blockchain
time sync issues detection first impl
This commit is contained in:
parent
19daa91f08
commit
5995c0ca7f
4 changed files with 153 additions and 17 deletions
|
|
@ -21,6 +21,7 @@ using namespace epee;
|
|||
#include <sys/utsname.h>
|
||||
#endif
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
namespace tools
|
||||
{
|
||||
|
|
@ -588,4 +589,38 @@ std::string get_nix_version_display_string()
|
|||
return static_cast<uint64_t>(in.tellg());
|
||||
}
|
||||
|
||||
}
|
||||
int64_t get_ntp_time(const std::string& host_name)
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::asio::io_service io_service;
|
||||
boost::asio::ip::udp::resolver resolver(io_service);
|
||||
boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), host_name, "ntp");
|
||||
boost::asio::ip::udp::endpoint receiver_endpoint = *resolver.resolve(query);
|
||||
boost::asio::ip::udp::socket socket(io_service);
|
||||
socket.open(boost::asio::ip::udp::v4());
|
||||
|
||||
boost::array<unsigned char, 48> send_buf = { 010, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
socket.send_to(boost::asio::buffer(send_buf), receiver_endpoint);
|
||||
|
||||
boost::array<unsigned long, 1024> recv_buf;
|
||||
boost::asio::ip::udp::endpoint sender_endpoint;
|
||||
size_t len = socket.receive_from(boost::asio::buffer(recv_buf), sender_endpoint);
|
||||
|
||||
time_t time_recv = ntohl((time_t)recv_buf[4]);
|
||||
time_recv -= 2208988800U; //Unix time starts from 01/01/1970 == 2208988800U
|
||||
return time_recv;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG_PRINT_L2("get_ntp_time(): exception: " << e.what());
|
||||
return 0;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace tools
|
||||
|
|
|
|||
|
|
@ -333,4 +333,7 @@ namespace tools
|
|||
static std::function<void(void)> m_handler;
|
||||
static std::function<void(int, void*)> m_fatal_handler;
|
||||
};
|
||||
|
||||
|
||||
int64_t get_ntp_time(const std::string& host_name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,10 @@ namespace currency
|
|||
uint64_t get_max_seen_height();
|
||||
virtual size_t get_synchronized_connections_count();
|
||||
virtual size_t get_synchronizing_connections_count();
|
||||
|
||||
int64_t get_net_time_delta_median();
|
||||
bool add_time_delta_and_check_time_sync(int64_t delta);
|
||||
bool get_last_time_sync_difference(int64_t& last_median2local_time_difference, int64_t& last_ntp2local_time_difference); // returns true if differences in allowed bounds
|
||||
|
||||
private:
|
||||
//----------------- commands handlers ----------------------------------------------
|
||||
|
|
@ -108,6 +111,11 @@ namespace currency
|
|||
std::thread m_relay_que_thread;
|
||||
std::atomic<bool> m_want_stop;
|
||||
|
||||
std::deque<int64_t> m_time_deltas;
|
||||
std::mutex m_time_deltas_lock;
|
||||
int64_t m_last_median2local_time_difference;
|
||||
int64_t m_last_ntp2local_time_difference;
|
||||
|
||||
template<class t_parametr>
|
||||
bool post_notify(typename t_parametr::request& arg, currency_connection_context& context)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -12,26 +12,27 @@ namespace currency
|
|||
|
||||
//-----------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
t_currency_protocol_handler<t_core>::t_currency_protocol_handler(t_core& rcore, nodetool::i_p2p_endpoint<connection_context>* p_net_layout):m_core(rcore),
|
||||
m_p2p(p_net_layout),
|
||||
m_syncronized_connections_count(0),
|
||||
m_synchronized(false),
|
||||
m_have_been_synchronized(false),
|
||||
m_max_height_seen(0),
|
||||
m_core_inital_height(0),
|
||||
m_want_stop(false)
|
||||
|
||||
|
||||
t_currency_protocol_handler<t_core>::t_currency_protocol_handler(t_core& rcore, nodetool::i_p2p_endpoint<connection_context>* p_net_layout)
|
||||
: m_core(rcore)
|
||||
, m_p2p(p_net_layout)
|
||||
, m_syncronized_connections_count(0)
|
||||
, m_synchronized(false)
|
||||
, m_have_been_synchronized(false)
|
||||
, m_max_height_seen(0)
|
||||
, m_core_inital_height(0)
|
||||
, m_want_stop(false)
|
||||
, m_last_median2local_time_difference(0)
|
||||
, m_last_ntp2local_time_difference(0)
|
||||
{
|
||||
if(!m_p2p)
|
||||
m_p2p = &m_p2p_stub;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
t_currency_protocol_handler<t_core>::~t_currency_protocol_handler()
|
||||
{
|
||||
deinit();
|
||||
}
|
||||
template<class t_core>
|
||||
t_currency_protocol_handler<t_core>::~t_currency_protocol_handler()
|
||||
{
|
||||
deinit();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
bool t_currency_protocol_handler<t_core>::init(const boost::program_options::variables_map& vm)
|
||||
|
|
@ -121,7 +122,12 @@ namespace currency
|
|||
if(context.m_state == currency_connection_context::state_befor_handshake && !is_inital)
|
||||
return true;
|
||||
|
||||
context.m_time_delta = m_core.get_blockchain_storage().get_core_runtime_config().get_core_time() - hshd.core_time;
|
||||
uint64_t local_time = m_core.get_blockchain_storage().get_core_runtime_config().get_core_time();
|
||||
context.m_time_delta = local_time - hshd.core_time;
|
||||
|
||||
// for outgoing connections -- check time difference
|
||||
if (!context.m_is_income)
|
||||
add_time_delta_and_check_time_sync(context.m_time_delta);
|
||||
|
||||
if(context.m_state == currency_connection_context::state_synchronizing)
|
||||
return true;
|
||||
|
|
@ -751,6 +757,90 @@ namespace currency
|
|||
return epee::misc_utils::median(deltas);
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
#define TIME_SYNC_DELTA_RING_BUFFER_SIZE 8
|
||||
#define TIME_SYNC_DELTA_TO_LOCAL_MAX_DIFFERENCE (60 * 5) // max acceptable difference between time delta median among peers and local time (seconds)
|
||||
#define TIME_SYNC_NTP_TO_LOCAL_MAX_DIFFERENCE (60 * 5) // max acceptable difference between NTP time and local time (seconds)
|
||||
#define TIME_SYNC_NTP_SERVERS { "time.google.com", "0.pool.ntp.org", "1.pool.ntp.org", "2.pool.ntp.org", "3.pool.ntp.org" }
|
||||
#define TIME_SYNC_NTP_ATTEMPTS_COUNT 3 // max number of attempts when getting time from NTP server
|
||||
|
||||
static int64_t get_ntp_time()
|
||||
{
|
||||
static const std::vector<std::string> ntp_servers TIME_SYNC_NTP_SERVERS;
|
||||
|
||||
for (size_t att = 0; att < TIME_SYNC_NTP_ATTEMPTS_COUNT; ++att)
|
||||
{
|
||||
size_t i = 0;
|
||||
crypto::generate_random_bytes(sizeof(i), &i);
|
||||
const std::string& ntp_server = ntp_servers[i % ntp_servers.size()];
|
||||
LOG_PRINT_L3("NTP: trying to get time from " << ntp_server);
|
||||
int64_t time = tools::get_ntp_time(ntp_server);
|
||||
if (time > 0)
|
||||
{
|
||||
LOG_PRINT_L2("NTP: " << ntp_server << " responded with " << time << " (" << epee::misc_utils::get_time_str_v2(time) << ")");
|
||||
return time;
|
||||
}
|
||||
LOG_PRINT_L2("NTP: cannot get time from " << ntp_server);
|
||||
}
|
||||
|
||||
return 0; // smth went wrong
|
||||
}
|
||||
|
||||
template<class t_core>
|
||||
bool t_currency_protocol_handler<t_core>::add_time_delta_and_check_time_sync(int64_t time_delta)
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(m_time_deltas_lock);
|
||||
|
||||
m_time_deltas.push_back(time_delta);
|
||||
while (m_time_deltas.size() > TIME_SYNC_DELTA_RING_BUFFER_SIZE)
|
||||
m_time_deltas.pop_front();
|
||||
|
||||
if (m_time_deltas.size() < TIME_SYNC_DELTA_RING_BUFFER_SIZE)
|
||||
return true; // not enough data
|
||||
|
||||
std::vector<int64_t> time_deltas_copy(m_time_deltas.begin(), m_time_deltas.end());
|
||||
|
||||
int64_t m_last_median2local_time_difference = epee::misc_utils::median(time_deltas_copy);
|
||||
LOG_PRINT_MAGENTA("TIME: network time difference is " << m_last_median2local_time_difference << " (max is " << TIME_SYNC_DELTA_TO_LOCAL_MAX_DIFFERENCE << ")", LOG_LEVEL_2);
|
||||
if (std::abs(m_last_median2local_time_difference) > TIME_SYNC_DELTA_TO_LOCAL_MAX_DIFFERENCE)
|
||||
{
|
||||
int64_t ntp_time = get_ntp_time();
|
||||
if (ntp_time == 0)
|
||||
{
|
||||
// error geting ntp time
|
||||
LOG_PRINT_RED("TIME: network time difference is " << m_last_median2local_time_difference << " (max is " << TIME_SYNC_DELTA_TO_LOCAL_MAX_DIFFERENCE << ") but NTP servers did not respond", LOG_LEVEL_0);
|
||||
return false;
|
||||
}
|
||||
|
||||
// got ntp time correctly
|
||||
// update local time, because getting ntp time could be time consuming
|
||||
uint64_t local_time_2 = m_core.get_blockchain_storage().get_core_runtime_config().get_core_time();
|
||||
int64_t m_last_ntp2local_time_difference = local_time_2 - ntp_time;
|
||||
if (std::abs(m_last_ntp2local_time_difference) > TIME_SYNC_NTP_TO_LOCAL_MAX_DIFFERENCE)
|
||||
{
|
||||
// local time is out of sync
|
||||
LOG_PRINT_RED("TIME: network time difference is " << m_last_median2local_time_difference << " (max is " << TIME_SYNC_DELTA_TO_LOCAL_MAX_DIFFERENCE << "), NTP time difference is " <<
|
||||
m_last_ntp2local_time_difference << " (max is " << TIME_SYNC_NTP_TO_LOCAL_MAX_DIFFERENCE << ")", LOG_LEVEL_0);
|
||||
return false;
|
||||
}
|
||||
|
||||
// NTP time is OK
|
||||
LOG_PRINT_YELLOW("TIME: network time difference is " << m_last_median2local_time_difference << " (max is " << TIME_SYNC_DELTA_TO_LOCAL_MAX_DIFFERENCE << "), NTP time difference is " <<
|
||||
m_last_ntp2local_time_difference << " (max is " << TIME_SYNC_NTP_TO_LOCAL_MAX_DIFFERENCE << ")", LOG_LEVEL_1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
bool t_currency_protocol_handler<t_core>::get_last_time_sync_difference(int64_t& last_median2local_time_difference, int64_t& last_ntp2local_time_difference)
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(m_time_deltas_lock);
|
||||
last_median2local_time_difference = m_last_median2local_time_difference;
|
||||
last_ntp2local_time_difference = m_last_ntp2local_time_difference;
|
||||
|
||||
return !(std::abs(m_last_median2local_time_difference) > TIME_SYNC_DELTA_TO_LOCAL_MAX_DIFFERENCE && std::abs(m_last_ntp2local_time_difference) > TIME_SYNC_NTP_TO_LOCAL_MAX_DIFFERENCE);
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
int t_currency_protocol_handler<t_core>::handle_response_chain_entry(int command, NOTIFY_RESPONSE_CHAIN_ENTRY::request& arg, currency_connection_context& context)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue