2021-08-22 10:20:59 +00:00
/*
* This file is part of the Monero P2Pool < https : //github.com/SChernykh/p2pool>
2022-03-30 12:42:26 +00:00
* Copyright ( c ) 2021 - 2022 SChernykh < https : //github.com/SChernykh>
2021-08-22 10:20:59 +00:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , version 3.
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "common.h"
# include "p2p_server.h"
# include "p2pool.h"
# include "params.h"
# include "keccak.h"
# include "side_chain.h"
# include "pool_block.h"
2021-08-24 09:42:41 +00:00
# include "block_cache.h"
2022-02-17 19:03:47 +00:00
# include "json_rpc_request.h"
# include "json_parsers.h"
2022-11-04 06:47:07 +00:00
# include "block_template.h"
2022-02-17 19:03:47 +00:00
# include <rapidjson/document.h>
2021-08-22 10:20:59 +00:00
# include <fstream>
# include <numeric>
static constexpr char log_category_prefix [ ] = " P2PServer " ;
static constexpr char saved_peer_list_file_name [ ] = " p2pool_peers.txt " ;
2021-12-30 10:10:18 +00:00
static const char * seed_nodes [ ] = { " seeds.p2pool.io " , " " } ;
static const char * seed_nodes_mini [ ] = { " seeds-mini.p2pool.io " , " " } ;
2021-08-22 10:20:59 +00:00
static constexpr int DEFAULT_BACKLOG = 16 ;
static constexpr uint64_t DEFAULT_BAN_TIME = 600 ;
2022-05-04 13:53:01 +00:00
static constexpr size_t SEND_BUF_MIN_SIZE = 256 ;
2021-08-22 10:20:59 +00:00
# include "tcp_server.inl"
namespace p2pool {
P2PServer : : P2PServer ( p2pool * pool )
2021-08-26 21:27:05 +00:00
: TCPServer ( P2PClient : : allocate )
2021-08-22 10:20:59 +00:00
, m_pool ( pool )
2021-10-16 11:45:28 +00:00
, m_cache ( pool - > params ( ) . m_blockCache ? new BlockCache ( ) : nullptr )
2021-08-24 09:42:41 +00:00
, m_cacheLoaded ( false )
2021-09-07 10:56:22 +00:00
, m_initialPeerList ( pool - > params ( ) . m_p2pPeerList )
2022-03-24 17:30:23 +00:00
, m_cachedBlocks ( nullptr )
2022-03-17 15:14:29 +00:00
, m_rng ( RandomDeviceSeed : : instance )
2021-08-22 10:20:59 +00:00
, m_block ( new PoolBlock ( ) )
2022-07-10 08:24:03 +00:00
, m_blockDeserializeResult ( 0 )
2021-08-22 10:20:59 +00:00
, m_timer { }
2021-10-08 16:02:04 +00:00
, m_timerCounter ( 0 )
2022-02-21 17:41:36 +00:00
, m_timerInterval ( 2 )
2021-08-22 10:20:59 +00:00
, m_peerListLastSaved ( 0 )
2022-07-10 08:24:03 +00:00
, m_lookForMissingBlocks ( true )
2022-09-13 08:51:15 +00:00
, m_fastestPeer ( nullptr )
2021-08-22 10:20:59 +00:00
{
2022-07-10 08:24:03 +00:00
m_blockDeserializeBuf . reserve ( 131072 ) ;
2022-03-17 15:14:29 +00:00
// Diffuse the initial state in case it has low quality
m_rng . discard ( 10000 ) ;
m_peerId = m_rng ( ) ;
2022-04-07 17:11:20 +00:00
const Params & params = pool - > params ( ) ;
2022-08-31 14:37:33 +00:00
if ( ! params . m_socks5Proxy . empty ( ) ) {
parse_address_list ( params . m_socks5Proxy ,
[ this ] ( bool is_v6 , const std : : string & /*address*/ , const std : : string & ip , int port )
{
if ( ! str_to_ip ( is_v6 , ip . c_str ( ) , m_socks5ProxyIP ) ) {
panic ( ) ;
}
m_socks5ProxyV6 = is_v6 ;
m_socks5ProxyPort = port ;
} ) ;
m_socks5Proxy = params . m_socks5Proxy ;
}
2022-04-07 17:11:20 +00:00
set_max_outgoing_peers ( params . m_maxOutgoingPeers ) ;
set_max_incoming_peers ( params . m_maxIncomingPeers ) ;
2021-12-26 14:28:33 +00:00
2021-08-22 10:20:59 +00:00
uv_mutex_init_checked ( & m_rngLock ) ;
uv_mutex_init_checked ( & m_blockLock ) ;
uv_mutex_init_checked ( & m_peerListLock ) ;
uv_mutex_init_checked ( & m_broadcastLock ) ;
2021-08-24 09:42:41 +00:00
uv_rwlock_init_checked ( & m_cachedBlocksLock ) ;
2022-08-31 14:37:33 +00:00
uv_mutex_init_checked ( & m_connectToPeersLock ) ;
2021-08-22 10:20:59 +00:00
int err = uv_async_init ( & m_loop , & m_broadcastAsync , on_broadcast ) ;
if ( err ) {
LOGERR ( 1 , " uv_async_init failed, error " < < uv_err_name ( err ) ) ;
2022-05-23 13:46:15 +00:00
panic ( ) ;
2021-08-22 10:20:59 +00:00
}
m_broadcastAsync . data = this ;
m_broadcastQueue . reserve ( 2 ) ;
2022-08-31 14:37:33 +00:00
err = uv_async_init ( & m_loop , & m_connectToPeersAsync , on_connect_to_peers ) ;
if ( err ) {
LOGERR ( 1 , " uv_async_init failed, error " < < uv_err_name ( err ) ) ;
panic ( ) ;
}
m_connectToPeersAsync . data = this ;
err = uv_async_init ( & m_loop , & m_showPeersAsync , on_show_peers ) ;
if ( err ) {
LOGERR ( 1 , " uv_async_init failed, error " < < uv_err_name ( err ) ) ;
panic ( ) ;
}
m_showPeersAsync . data = this ;
2021-08-22 10:20:59 +00:00
err = uv_timer_init ( & m_loop , & m_timer ) ;
if ( err ) {
LOGERR ( 1 , " failed to create timer, error " < < uv_err_name ( err ) ) ;
panic ( ) ;
}
2021-08-24 09:42:41 +00:00
if ( m_cache ) {
WriteLock lock ( m_cachedBlocksLock ) ;
m_cache - > load_all ( m_pool - > side_chain ( ) , * this ) ;
m_cacheLoaded = true ;
}
2021-08-22 10:20:59 +00:00
m_timer . data = this ;
2022-02-21 17:41:36 +00:00
err = uv_timer_start ( & m_timer , on_timer , 1000 , m_timerInterval * 1000 ) ;
2021-08-22 10:20:59 +00:00
if ( err ) {
LOGERR ( 1 , " failed to start timer, error " < < uv_err_name ( err ) ) ;
panic ( ) ;
}
2021-09-07 19:30:52 +00:00
load_peer_list ( ) ;
2022-04-07 17:11:20 +00:00
start_listening ( params . m_p2pAddresses ) ;
2021-08-22 10:20:59 +00:00
}
P2PServer : : ~ P2PServer ( )
{
shutdown_tcp ( ) ;
uv_mutex_destroy ( & m_rngLock ) ;
uv_mutex_destroy ( & m_blockLock ) ;
uv_mutex_destroy ( & m_peerListLock ) ;
uv_mutex_destroy ( & m_broadcastLock ) ;
2021-10-01 13:21:32 +00:00
clear_cached_blocks ( ) ;
2021-08-24 09:42:41 +00:00
uv_rwlock_destroy ( & m_cachedBlocksLock ) ;
2021-08-22 10:20:59 +00:00
2022-08-31 14:37:33 +00:00
uv_mutex_destroy ( & m_connectToPeersLock ) ;
2021-08-22 10:20:59 +00:00
delete m_block ;
2021-08-24 09:42:41 +00:00
delete m_cache ;
2022-06-07 17:40:13 +00:00
for ( const Broadcast * data : m_broadcastQueue ) {
delete data ;
}
2021-08-24 09:42:41 +00:00
}
void P2PServer : : add_cached_block ( const PoolBlock & block )
{
if ( m_cacheLoaded ) {
LOGERR ( 1 , " add_cached_block can only be called on startup. Fix the code! " ) ;
return ;
}
2022-03-24 17:30:23 +00:00
if ( ! m_cachedBlocks ) {
m_cachedBlocks = new unordered_map < hash , PoolBlock * > ( ) ;
}
if ( m_cachedBlocks - > find ( block . m_sidechainId ) = = m_cachedBlocks - > end ( ) ) {
PoolBlock * new_block = new PoolBlock ( block ) ;
m_cachedBlocks - > insert ( { new_block - > m_sidechainId , new_block } ) ;
}
2021-08-24 09:42:41 +00:00
}
2021-10-01 13:21:32 +00:00
void P2PServer : : clear_cached_blocks ( )
{
2022-03-24 17:30:23 +00:00
if ( ! m_cachedBlocks ) {
return ;
}
2021-10-01 13:21:32 +00:00
WriteLock lock ( m_cachedBlocksLock ) ;
2022-05-26 16:20:29 +00:00
// cppcheck-suppress identicalConditionAfterEarlyExit
2022-03-24 17:30:23 +00:00
if ( ! m_cachedBlocks ) {
return ;
}
for ( auto it : * m_cachedBlocks ) {
2021-10-01 13:21:32 +00:00
delete it . second ;
}
2022-03-24 17:30:23 +00:00
delete m_cachedBlocks ;
m_cachedBlocks = nullptr ;
2021-10-01 13:21:32 +00:00
}
2021-08-24 09:42:41 +00:00
void P2PServer : : store_in_cache ( const PoolBlock & block )
{
2021-08-24 11:46:38 +00:00
if ( m_cache & & block . m_verified & & ! block . m_invalid ) {
2021-08-24 09:42:41 +00:00
m_cache - > store ( block ) ;
}
2021-08-22 10:20:59 +00:00
}
2022-08-31 14:37:33 +00:00
void P2PServer : : connect_to_peers_async ( const char * peer_list )
{
{
MutexLock lock ( m_connectToPeersLock ) ;
if ( ! m_connectToPeersData . empty ( ) ) {
m_connectToPeersData . append ( 1 , ' , ' ) ;
}
m_connectToPeersData . append ( peer_list ) ;
}
if ( ! uv_is_closing ( reinterpret_cast < uv_handle_t * > ( & m_connectToPeersAsync ) ) ) {
uv_async_send ( & m_connectToPeersAsync ) ;
}
}
void P2PServer : : on_connect_to_peers ( uv_async_t * handle )
{
P2PServer * server = reinterpret_cast < P2PServer * > ( handle - > data ) ;
std : : string peer_list ;
{
MutexLock lock ( server - > m_connectToPeersLock ) ;
peer_list = std : : move ( server - > m_connectToPeersData ) ;
}
if ( ! peer_list . empty ( ) ) {
server - > connect_to_peers ( peer_list ) ;
}
}
2021-08-22 10:20:59 +00:00
void P2PServer : : connect_to_peers ( const std : : string & peer_list )
{
parse_address_list ( peer_list ,
2021-09-08 18:25:39 +00:00
[ this ] ( bool is_v6 , const std : : string & /*address*/ , std : : string ip , int port )
2021-08-22 10:20:59 +00:00
{
2022-09-04 16:10:14 +00:00
if ( ! m_pool - > params ( ) . m_dns | | resolve_host ( ip , is_v6 ) ) {
2021-09-08 18:25:39 +00:00
connect_to_peer ( is_v6 , ip . c_str ( ) , port ) ;
}
2021-08-22 10:20:59 +00:00
} ) ;
}
void P2PServer : : on_connect_failed ( bool is_v6 , const raw_ip & ip , int port )
{
MutexLock lock ( m_peerListLock ) ;
for ( auto it = m_peerList . begin ( ) ; it ! = m_peerList . end ( ) ; + + it ) {
if ( ( it - > m_isV6 = = is_v6 ) & & ( it - > m_port = = port ) & & ( it - > m_addr = = ip ) ) {
+ + it - > m_numFailedConnections ;
if ( it - > m_numFailedConnections > = 10 ) {
m_peerList . erase ( it ) ;
}
return ;
}
}
}
void P2PServer : : update_peer_connections ( )
{
2022-03-23 10:30:38 +00:00
const uint64_t cur_time = seconds_since_epoch ( ) ;
const uint64_t last_updated = m_pool - > side_chain ( ) . last_updated ( ) ;
2021-08-24 19:45:19 +00:00
2022-02-17 19:03:47 +00:00
bool has_good_peers = false ;
2022-09-13 08:51:15 +00:00
m_fastestPeer = nullptr ;
2022-02-17 19:03:47 +00:00
2022-04-07 14:48:01 +00:00
unordered_set < raw_ip > connected_clients ;
2021-08-22 10:20:59 +00:00
{
MutexLock lock ( m_clientsListLock ) ;
2022-07-10 08:24:03 +00:00
2021-08-22 10:20:59 +00:00
connected_clients . reserve ( m_numConnections ) ;
for ( P2PClient * client = static_cast < P2PClient * > ( m_connectedClientsList - > m_next ) ; client ! = m_connectedClientsList ; client = static_cast < P2PClient * > ( client - > m_next ) ) {
2021-09-08 18:36:21 +00:00
const int timeout = client - > m_handshakeComplete ? 300 : 10 ;
2022-08-31 14:37:33 +00:00
if ( ( cur_time > = client - > m_lastAlive + timeout ) & & ( client - > m_socks5ProxyState = = Client : : Socks5ProxyState : : Default ) ) {
2021-08-24 19:45:19 +00:00
const uint64_t idle_time = static_cast < uint64_t > ( cur_time - client - > m_lastAlive ) ;
LOGWARN ( 5 , " peer " < < static_cast < char * > ( client - > m_addrString ) < < " has been idle for " < < idle_time < < " seconds, disconnecting " ) ;
client - > close ( ) ;
2022-07-10 08:24:03 +00:00
continue ;
2021-08-24 19:45:19 +00:00
}
2021-09-13 12:26:52 +00:00
if ( client - > m_handshakeComplete & & client - > m_lastBroadcastTimestamp ) {
2022-03-30 20:47:10 +00:00
// - Side chain is at least 15 minutes newer (last_updated >= client->m_lastBroadcastTimestamp + 900)
2021-09-13 12:26:52 +00:00
// - It's been at least 10 seconds since side chain updated (cur_time >= last_updated + 10)
// - It's been at least 10 seconds since the last block request (peer is not syncing)
// - Peer should have sent a broadcast by now
2022-03-30 20:47:10 +00:00
if ( last_updated & & ( cur_time > = std : : max ( last_updated , client - > m_lastBlockrequestTimestamp ) + 10 ) & & ( last_updated > = client - > m_lastBroadcastTimestamp + 900 ) ) {
2022-03-23 10:30:38 +00:00
const uint64_t dt = last_updated - client - > m_lastBroadcastTimestamp ;
2021-09-13 12:26:52 +00:00
LOGWARN ( 5 , " peer " < < static_cast < char * > ( client - > m_addrString ) < < " is not broadcasting blocks (last update " < < dt < < " seconds ago) " ) ;
client - > ban ( DEFAULT_BAN_TIME ) ;
remove_peer_from_list ( client ) ;
client - > close ( ) ;
2022-07-10 08:24:03 +00:00
continue ;
2021-09-13 12:26:52 +00:00
}
}
2021-10-15 09:32:01 +00:00
2022-07-10 08:24:03 +00:00
connected_clients . insert ( client - > m_addr ) ;
if ( client - > is_good ( ) ) {
has_good_peers = true ;
2022-09-13 08:51:15 +00:00
if ( ( client - > m_pingTime > = 0 ) & & ( ! m_fastestPeer | | ( m_fastestPeer - > m_pingTime > client - > m_pingTime ) ) ) {
m_fastestPeer = client ;
}
2021-10-15 09:32:01 +00:00
}
2021-08-22 10:20:59 +00:00
}
}
2021-10-15 09:32:01 +00:00
std : : vector < Peer > peer_list ;
{
MutexLock lock ( m_peerListLock ) ;
if ( ( m_timerCounter % 30 ) = = 1 ) {
// Update last seen time for currently connected peers
for ( Peer & p : m_peerList ) {
2022-04-07 14:48:01 +00:00
if ( connected_clients . find ( p . m_addr ) ! = connected_clients . end ( ) ) {
2021-10-15 09:32:01 +00:00
p . m_lastSeen = cur_time ;
}
}
// Remove all peers that weren't seen for more than 1 hour
m_peerList . erase ( std : : remove_if ( m_peerList . begin ( ) , m_peerList . end ( ) , [ cur_time ] ( const Peer & p ) { return p . m_lastSeen + 3600 < cur_time ; } ) , m_peerList . end ( ) ) ;
}
peer_list = m_peerList ;
}
2022-02-17 19:03:47 +00:00
uint32_t N = m_maxOutgoingPeers ;
// Special case: when we can't find p2pool peers, scan through monerod peers (try 25 peers at a time)
if ( ! has_good_peers & & ! m_peerListMonero . empty ( ) ) {
LOGINFO ( 3 , " Scanning monerod peers, " < < m_peerListMonero . size ( ) < < " left " ) ;
for ( uint32_t i = 0 ; ( i < 25 ) & & ! m_peerListMonero . empty ( ) ; + + i ) {
peer_list . push_back ( m_peerListMonero . back ( ) ) ;
m_peerListMonero . pop_back ( ) ;
}
N = static_cast < uint32_t > ( peer_list . size ( ) ) ;
}
2021-12-26 13:59:45 +00:00
// Try to have at least N outgoing connections (N defaults to 10, can be set via --out-peers command line parameter)
2022-02-17 19:03:47 +00:00
for ( uint32_t i = m_numConnections - m_numIncomingConnections ; ( i < N ) & & ! peer_list . empty ( ) ; ) {
2021-08-22 10:20:59 +00:00
const uint64_t k = get_random64 ( ) % peer_list . size ( ) ;
const Peer & peer = peer_list [ k ] ;
2022-04-07 14:48:01 +00:00
if ( ( connected_clients . find ( peer . m_addr ) = = connected_clients . end ( ) ) & & connect_to_peer ( peer . m_isV6 , peer . m_addr , peer . m_port ) ) {
2021-08-22 10:20:59 +00:00
+ + i ;
}
if ( k + 1 < peer_list . size ( ) ) {
peer_list [ k ] = peer_list . back ( ) ;
}
peer_list . pop_back ( ) ;
}
2021-10-08 16:02:04 +00:00
2022-09-04 16:10:14 +00:00
if ( ! has_good_peers & & ( ( m_timerCounter % 10 ) = = 0 ) ) {
2021-10-08 16:02:04 +00:00
LOGERR ( 1 , " no connections to other p2pool nodes, check your monerod/p2pool/network/firewall setup!!! " ) ;
2022-05-11 12:08:36 +00:00
load_peer_list ( ) ;
2022-02-17 19:03:47 +00:00
if ( m_peerListMonero . empty ( ) ) {
load_monerod_peer_list ( ) ;
}
2021-10-08 16:02:04 +00:00
}
2021-08-22 10:20:59 +00:00
}
void P2PServer : : update_peer_list ( )
{
2022-03-23 10:37:05 +00:00
const uint64_t cur_time = seconds_since_epoch ( ) ;
2021-08-22 10:20:59 +00:00
2022-07-10 08:24:03 +00:00
MutexLock lock ( m_clientsListLock ) ;
2021-08-22 10:20:59 +00:00
2022-07-10 08:24:03 +00:00
for ( P2PClient * client = static_cast < P2PClient * > ( m_connectedClientsList - > m_next ) ; client ! = m_connectedClientsList ; client = static_cast < P2PClient * > ( client - > m_next ) ) {
if ( client - > is_good ( ) & & ( cur_time > = client - > m_nextOutgoingPeerListRequest ) ) {
2022-09-13 08:51:15 +00:00
send_peer_list_request ( client , cur_time ) ;
}
}
}
2022-05-04 13:53:01 +00:00
2022-09-13 08:51:15 +00:00
void P2PServer : : send_peer_list_request ( P2PClient * client , uint64_t cur_time )
{
// Send peer list requests at random intervals (60-120 seconds)
client - > m_nextOutgoingPeerListRequest = cur_time + ( 60 + ( get_random64 ( ) % 61 ) ) ;
2022-05-04 13:53:01 +00:00
2022-09-13 08:51:15 +00:00
const bool result = send ( client ,
2022-09-13 09:12:08 +00:00
[ client ] ( void * buf , size_t buf_size )
2022-09-13 08:51:15 +00:00
{
2022-09-13 09:12:08 +00:00
LOGINFO ( 5 , " sending PEER_LIST_REQUEST to " < < static_cast < char * > ( client - > m_addrString ) ) ;
2021-10-15 15:09:51 +00:00
2022-09-13 08:51:15 +00:00
if ( buf_size < SEND_BUF_MIN_SIZE ) {
return 0 ;
2021-08-22 10:20:59 +00:00
}
2022-09-13 08:51:15 +00:00
* reinterpret_cast < uint8_t * > ( buf ) = static_cast < uint8_t > ( MessageId : : PEER_LIST_REQUEST ) ;
return 1 ;
} ) ;
if ( result ) {
client - > m_lastPeerListRequestTime = std : : chrono : : high_resolution_clock : : now ( ) ;
+ + client - > m_peerListPendingRequests ;
2021-08-22 10:20:59 +00:00
}
}
void P2PServer : : save_peer_list_async ( )
{
2022-03-23 10:30:38 +00:00
const uint64_t cur_time = seconds_since_epoch ( ) ;
2021-08-22 10:20:59 +00:00
if ( cur_time < m_peerListLastSaved + 300 ) {
return ;
}
struct Work
{
uv_work_t req ;
P2PServer * server ;
} ;
Work * work = new Work { } ;
work - > req . data = work ;
work - > server = this ;
const int err = uv_queue_work ( & m_loop , & work - > req ,
[ ] ( uv_work_t * req )
{
2022-11-04 09:14:49 +00:00
BACKGROUND_JOB_START ( P2PServer : : save_peer_list_async ) ;
2021-08-22 10:20:59 +00:00
reinterpret_cast < Work * > ( req - > data ) - > server - > save_peer_list ( ) ;
} ,
[ ] ( uv_work_t * req , int /*status*/ )
{
delete reinterpret_cast < Work * > ( req - > data ) ;
2022-11-04 09:14:49 +00:00
BACKGROUND_JOB_STOP ( P2PServer : : save_peer_list_async ) ;
2021-08-22 10:20:59 +00:00
} ) ;
if ( err ) {
2021-10-21 08:12:57 +00:00
LOGERR ( 1 , " save_peer_list_async: uv_queue_work failed, error " < < uv_err_name ( err ) ) ;
2021-08-22 10:20:59 +00:00
delete work ;
}
}
void P2PServer : : save_peer_list ( )
{
std : : ofstream f ( saved_peer_list_file_name , std : : ios : : binary ) ;
if ( ! f . is_open ( ) ) {
LOGERR ( 1 , " failed to save peer list " ) ;
return ;
}
2021-09-02 17:21:38 +00:00
std : : vector < Peer > peer_list ;
2021-08-22 10:20:59 +00:00
{
MutexLock lock ( m_peerListLock ) ;
2021-09-02 17:21:38 +00:00
peer_list = m_peerList ;
}
2021-08-22 10:20:59 +00:00
2021-09-02 17:21:38 +00:00
for ( const Peer & p : peer_list ) {
const char * addr_str ;
char addr_str_buf [ 64 ] ;
if ( p . m_isV6 ) {
in6_addr addr { } ;
memcpy ( addr . s6_addr , p . m_addr . data , sizeof ( addr . s6_addr ) ) ;
addr_str = inet_ntop ( AF_INET6 , & addr , addr_str_buf , sizeof ( addr_str_buf ) ) ;
if ( addr_str ) {
f < < ' [ ' < < addr_str < < " ]: " < < p . m_port < < ' \n ' ;
2021-08-22 10:20:59 +00:00
}
2021-09-02 17:21:38 +00:00
}
else {
in_addr addr { } ;
memcpy ( & addr . s_addr , p . m_addr . data + 12 , sizeof ( addr . s_addr ) ) ;
addr_str = inet_ntop ( AF_INET , & addr , addr_str_buf , sizeof ( addr_str_buf ) ) ;
if ( addr_str ) {
f < < addr_str < < ' : ' < < p . m_port < < ' \n ' ;
2021-08-22 10:20:59 +00:00
}
}
}
2022-09-13 16:26:01 +00:00
f . flush ( ) ;
2021-08-22 10:20:59 +00:00
f . close ( ) ;
2021-09-02 17:21:38 +00:00
LOGINFO ( 5 , " peer list saved ( " < < peer_list . size ( ) < < " peers) " ) ;
2022-03-23 10:30:38 +00:00
m_peerListLastSaved = seconds_since_epoch ( ) ;
2021-08-22 10:20:59 +00:00
}
2021-09-07 19:30:52 +00:00
void P2PServer : : load_peer_list ( )
2021-08-22 10:20:59 +00:00
{
2022-05-11 12:08:36 +00:00
size_t old_size ;
{
MutexLock lock ( m_peerListLock ) ;
old_size = m_peerList . size ( ) ;
}
2021-09-08 18:25:39 +00:00
std : : string saved_list ;
2021-08-22 10:20:59 +00:00
2021-12-30 10:10:18 +00:00
// Load peers from seed nodes if we're on the default or mini sidechain
auto load_from_seed_nodes = [ & saved_list ] ( const char * * nodes , int p2p_port ) {
for ( size_t i = 0 ; nodes [ i ] [ 0 ] ; + + i ) {
LOGINFO ( 4 , " loading peers from " < < nodes [ i ] ) ;
2021-09-07 19:30:52 +00:00
addrinfo hints { } ;
hints . ai_family = AF_UNSPEC ;
hints . ai_socktype = SOCK_STREAM ;
2022-05-02 19:24:51 +00:00
hints . ai_flags = AI_ADDRCONFIG ;
2021-09-07 19:30:52 +00:00
addrinfo * result ;
2021-12-30 10:10:18 +00:00
const int err = getaddrinfo ( nodes [ i ] , nullptr , & hints , & result ) ;
2021-09-07 19:30:52 +00:00
if ( err = = 0 ) {
for ( addrinfo * r = result ; r ! = NULL ; r = r - > ai_next ) {
const char * addr_str ;
char addr_str_buf [ 64 ] ;
2022-05-10 18:16:04 +00:00
char buf [ 128 ] ;
2022-05-11 12:08:36 +00:00
buf [ 0 ] = ' \0 ' ;
2021-09-07 19:30:52 +00:00
log : : Stream s ( buf ) ;
if ( r - > ai_family = = AF_INET6 ) {
addr_str = inet_ntop ( AF_INET6 , & reinterpret_cast < sockaddr_in6 * > ( r - > ai_addr ) - > sin6_addr , addr_str_buf , sizeof ( addr_str_buf ) ) ;
if ( addr_str ) {
2021-09-18 08:03:06 +00:00
s < < ' [ ' < < addr_str < < " ]: " < < p2p_port < < ' \0 ' ;
2021-09-07 19:30:52 +00:00
}
}
else {
addr_str = inet_ntop ( AF_INET , & reinterpret_cast < sockaddr_in * > ( r - > ai_addr ) - > sin_addr , addr_str_buf , sizeof ( addr_str_buf ) ) ;
if ( addr_str ) {
2021-09-18 08:03:06 +00:00
s < < addr_str < < ' : ' < < p2p_port < < ' \0 ' ;
2021-09-07 19:30:52 +00:00
}
}
if ( s . m_pos ) {
2022-05-10 18:16:04 +00:00
LOGINFO ( 4 , " added " < < static_cast < const char * > ( buf ) < < " from " < < nodes [ i ] ) ;
2021-09-07 19:30:52 +00:00
if ( ! saved_list . empty ( ) ) {
saved_list + = ' , ' ;
}
saved_list + = buf ;
}
}
freeaddrinfo ( result ) ;
}
else {
2021-12-30 10:10:18 +00:00
LOGWARN ( 3 , " getaddrinfo failed for " < < nodes [ i ] < < " : " < < gai_strerror ( err ) ) ;
2021-09-07 19:30:52 +00:00
}
}
2021-12-30 10:10:18 +00:00
} ;
2022-09-04 16:10:14 +00:00
if ( m_pool - > params ( ) . m_dns ) {
if ( m_pool - > side_chain ( ) . is_default ( ) ) {
load_from_seed_nodes ( seed_nodes , DEFAULT_P2P_PORT ) ;
}
else if ( m_pool - > side_chain ( ) . is_mini ( ) ) {
load_from_seed_nodes ( seed_nodes_mini , DEFAULT_P2P_PORT_MINI ) ;
}
2021-09-07 19:30:52 +00:00
}
// Finally load peers from p2pool_peers.txt
2021-08-31 09:16:40 +00:00
std : : ifstream f ( saved_peer_list_file_name ) ;
if ( f . is_open ( ) ) {
std : : string address ;
2022-09-13 16:26:01 +00:00
while ( f . good ( ) ) {
2021-08-31 09:16:40 +00:00
std : : getline ( f , address ) ;
if ( ! address . empty ( ) ) {
if ( ! saved_list . empty ( ) ) {
saved_list + = ' , ' ;
}
saved_list + = address ;
2021-08-22 10:20:59 +00:00
}
}
2021-08-31 09:16:40 +00:00
f . close ( ) ;
}
if ( saved_list . empty ( ) ) {
return ;
2021-08-22 10:20:59 +00:00
}
MutexLock lock ( m_peerListLock ) ;
parse_address_list ( saved_list ,
[ this ] ( bool is_v6 , const std : : string & /*address*/ , const std : : string & ip , int port )
{
Peer p ;
2022-08-31 14:37:33 +00:00
if ( ! str_to_ip ( is_v6 , ip . c_str ( ) , p . m_addr ) ) {
return ;
2021-08-22 10:20:59 +00:00
}
2022-08-31 14:37:33 +00:00
p . m_isV6 = is_v6 ;
2021-08-23 21:12:52 +00:00
bool already_added = false ;
for ( const Peer & peer : m_peerList ) {
if ( ( peer . m_isV6 = = p . m_isV6 ) & & ( peer . m_addr = = p . m_addr ) ) {
already_added = true ;
break ;
}
}
2021-10-15 09:32:01 +00:00
p . m_port = port ;
p . m_numFailedConnections = 0 ;
2022-03-23 10:30:38 +00:00
p . m_lastSeen = seconds_since_epoch ( ) ;
2021-10-15 09:32:01 +00:00
2021-08-27 14:36:06 +00:00
if ( ! already_added & & ! is_banned ( p . m_addr ) ) {
2021-08-23 21:12:52 +00:00
m_peerList . push_back ( p ) ;
}
2021-08-22 10:20:59 +00:00
} ) ;
2021-08-31 09:16:40 +00:00
2022-02-17 19:03:47 +00:00
LOGINFO ( 4 , " peer list loaded ( " < < ( m_peerList . size ( ) - old_size ) < < " peers) " ) ;
}
void P2PServer : : load_monerod_peer_list ( )
{
const Params & params = m_pool - > params ( ) ;
2022-08-31 14:37:33 +00:00
JSONRPCRequest : : call ( params . m_host , params . m_rpcPort , " /get_peer_list " , params . m_rpcLogin , m_socks5Proxy ,
2022-02-17 19:03:47 +00:00
[ this ] ( const char * data , size_t size )
{
2022-05-10 18:16:04 +00:00
# define ERR_STR " / get_peer_list RPC request returned invalid JSON "
2022-02-17 19:03:47 +00:00
using namespace rapidjson ;
Document doc ;
if ( doc . Parse ( data , size ) . HasParseError ( ) ) {
2022-05-10 18:16:04 +00:00
LOGWARN ( 4 , ERR_STR " (parse error) " ) ;
2022-02-17 19:03:47 +00:00
return ;
}
if ( ! doc . IsObject ( ) ) {
2022-05-10 18:16:04 +00:00
LOGWARN ( 4 , ERR_STR " (not an object) " ) ;
2022-02-17 19:03:47 +00:00
return ;
}
if ( ! doc . HasMember ( " white_list " ) ) {
2022-05-10 18:16:04 +00:00
LOGWARN ( 4 , ERR_STR " ('white_list' not found) " ) ;
2022-02-17 19:03:47 +00:00
return ;
}
const auto & white_list = doc [ " white_list " ] ;
if ( ! white_list . IsArray ( ) ) {
2022-05-10 18:16:04 +00:00
LOGWARN ( 4 , ERR_STR " ('white_list' is not an array) " ) ;
2022-02-17 19:03:47 +00:00
return ;
}
2022-05-10 18:16:04 +00:00
# undef ERR_STR
2022-02-17 19:03:47 +00:00
const int port = m_pool - > side_chain ( ) . is_mini ( ) ? DEFAULT_P2P_PORT_MINI : DEFAULT_P2P_PORT ;
const SizeType n = white_list . Size ( ) ;
m_peerListMonero . clear ( ) ;
m_peerListMonero . reserve ( n ) ;
for ( SizeType i = 0 ; i < n ; + + i ) {
auto & v = white_list [ i ] ;
const char * ip ;
uint64_t last_seen ;
if ( ! parseValue ( v , " host " , ip ) | | ! parseValue ( v , " last_seen " , last_seen ) ) {
continue ;
}
Peer p ;
p . m_lastSeen = last_seen ;
2022-08-31 14:37:33 +00:00
p . m_isV6 = ( strchr ( ip , ' : ' ) ! = 0 ) ;
2022-02-17 19:03:47 +00:00
2022-08-31 14:37:33 +00:00
if ( ! str_to_ip ( p . m_isV6 , ip , p . m_addr ) ) {
continue ;
2022-02-17 19:03:47 +00:00
}
p . m_port = port ;
p . m_numFailedConnections = 0 ;
if ( ! is_banned ( p . m_addr ) ) {
m_peerListMonero . push_back ( p ) ;
}
}
2022-08-31 14:37:33 +00:00
// Put recently active peers last in the list (it will be scanned backwards)
std : : sort ( m_peerListMonero . begin ( ) , m_peerListMonero . end ( ) , [ ] ( const Peer & a , const Peer & b ) { return a . m_lastSeen < b . m_lastSeen ; } ) ;
2022-02-17 19:03:47 +00:00
LOGINFO ( 4 , " monerod peer list loaded ( " < < m_peerListMonero . size ( ) < < " peers) " ) ;
} ,
[ ] ( const char * data , size_t size )
{
if ( size > 0 ) {
LOGWARN ( 4 , " /get_peer_list RPC request failed: error " < < log : : const_buf ( data , size ) ) ;
}
} , & m_loop ) ;
2021-08-22 10:20:59 +00:00
}
void P2PServer : : update_peer_in_list ( bool is_v6 , const raw_ip & ip , int port )
{
2022-03-23 10:30:38 +00:00
const uint64_t cur_time = seconds_since_epoch ( ) ;
2021-10-15 09:32:01 +00:00
2021-08-22 10:20:59 +00:00
MutexLock lock ( m_peerListLock ) ;
for ( Peer & p : m_peerList ) {
if ( ( p . m_isV6 = = is_v6 ) & & ( p . m_addr = = ip ) ) {
p . m_port = port ;
p . m_numFailedConnections = 0 ;
2021-10-15 09:32:01 +00:00
p . m_lastSeen = cur_time ;
2021-08-22 10:20:59 +00:00
return ;
}
}
2021-08-27 14:36:06 +00:00
if ( ! is_banned ( ip ) ) {
2021-10-15 09:32:01 +00:00
m_peerList . emplace_back ( Peer { is_v6 , ip , port , 0 , cur_time } ) ;
2021-08-27 14:36:06 +00:00
}
2021-08-22 10:20:59 +00:00
}
void P2PServer : : remove_peer_from_list ( P2PClient * client )
{
MutexLock lock ( m_peerListLock ) ;
for ( auto it = m_peerList . begin ( ) ; it ! = m_peerList . end ( ) ; + + it ) {
const Peer & p = * it ;
if ( ( p . m_isV6 = = client - > m_isV6 ) & & ( p . m_port = = client - > m_listenPort ) & & ( p . m_addr = = client - > m_addr ) ) {
m_peerList . erase ( it ) ;
return ;
}
}
}
2021-08-31 11:14:35 +00:00
void P2PServer : : remove_peer_from_list ( const raw_ip & ip )
{
MutexLock lock ( m_peerListLock ) ;
for ( auto it = m_peerList . begin ( ) ; it ! = m_peerList . end ( ) ; + + it ) {
const Peer & p = * it ;
if ( p . m_addr = = ip ) {
m_peerList . erase ( it ) ;
return ;
}
}
}
2022-11-09 10:17:35 +00:00
void P2PServer : : broadcast ( const PoolBlock & block , const PoolBlock * parent )
2021-08-22 10:20:59 +00:00
{
2022-04-08 21:14:08 +00:00
MinerData miner_data = m_pool - > miner_data ( ) ;
2022-04-07 17:11:20 +00:00
if ( block . m_txinGenHeight + 2 < miner_data . height ) {
LOGWARN ( 3 , " Trying to broadcast a stale block " < < block . m_sidechainId < < " (mainchain height " < < block . m_txinGenHeight < < " , current height is " < < miner_data . height < < ' ) ' ) ;
2021-08-31 21:41:05 +00:00
return ;
}
2022-04-07 17:11:20 +00:00
if ( block . m_txinGenHeight > miner_data . height + 2 ) {
LOGWARN ( 3 , " Trying to broadcast a block " < < block . m_sidechainId < < " ahead on mainchain (mainchain height " < < block . m_txinGenHeight < < " , current height is " < < miner_data . height < < ' ) ' ) ;
2021-09-13 13:48:05 +00:00
return ;
}
2021-08-31 21:41:05 +00:00
Broadcast * data = new Broadcast ( ) ;
2021-08-22 10:20:59 +00:00
2022-09-30 12:37:32 +00:00
int outputs_offset , outputs_blob_size ;
const std : : vector < uint8_t > mainchain_data = block . serialize_mainchain_data ( nullptr , nullptr , & outputs_offset , & outputs_blob_size ) ;
2022-10-04 13:44:57 +00:00
const std : : vector < uint8_t > sidechain_data = block . serialize_sidechain_data ( ) ;
2022-09-30 12:37:32 +00:00
2022-10-04 13:44:57 +00:00
data - > blob . reserve ( mainchain_data . size ( ) + sidechain_data . size ( ) ) ;
2022-09-30 12:37:32 +00:00
data - > blob = mainchain_data ;
2022-10-04 13:44:57 +00:00
data - > blob . insert ( data - > blob . end ( ) , sidechain_data . begin ( ) , sidechain_data . end ( ) ) ;
2021-08-22 10:20:59 +00:00
2022-10-04 13:44:57 +00:00
data - > pruned_blob . reserve ( mainchain_data . size ( ) + sidechain_data . size ( ) + 16 - outputs_blob_size ) ;
2022-09-30 12:37:32 +00:00
data - > pruned_blob . assign ( mainchain_data . begin ( ) , mainchain_data . begin ( ) + outputs_offset ) ;
2021-08-22 10:20:59 +00:00
// 0 outputs in the pruned blob
data - > pruned_blob . push_back ( 0 ) ;
const uint64_t total_reward = std : : accumulate ( block . m_outputs . begin ( ) , block . m_outputs . end ( ) , 0ULL ,
[ ] ( uint64_t a , const PoolBlock : : TxOutput & b )
{
return a + b . m_reward ;
} ) ;
writeVarint ( total_reward , data - > pruned_blob ) ;
2022-09-30 12:37:32 +00:00
writeVarint ( outputs_blob_size , data - > pruned_blob ) ;
2021-08-22 10:20:59 +00:00
2022-09-30 12:37:32 +00:00
data - > pruned_blob . insert ( data - > pruned_blob . end ( ) , mainchain_data . begin ( ) + outputs_offset + outputs_blob_size , mainchain_data . end ( ) ) ;
2022-11-09 10:17:35 +00:00
const size_t N = block . m_transactions . size ( ) ;
2022-11-09 14:29:53 +00:00
if ( ( N > 1 ) & & parent & & ( parent - > m_transactions . size ( ) > 1 ) ) {
2022-11-09 10:17:35 +00:00
unordered_map < hash , size_t > parent_transactions ;
parent_transactions . reserve ( parent - > m_transactions . size ( ) ) ;
for ( size_t i = 1 ; i < parent - > m_transactions . size ( ) ; + + i ) {
parent_transactions . emplace ( parent - > m_transactions [ i ] , i ) ;
}
// Reserve 1 additional byte per transaction to be ready for the worst case (all transactions are different in the parent block)
data - > compact_blob . reserve ( data - > pruned_blob . capacity ( ) + ( N - 1 ) ) ;
// Copy pruned_blob without the transaction list
data - > compact_blob . assign ( data - > pruned_blob . begin ( ) , data - > pruned_blob . end ( ) - ( N - 1 ) * HASH_SIZE ) ;
// Process transaction hashes one by one
size_t num_found = 0 ;
for ( size_t i = 1 ; i < N ; + + i ) {
const hash & tx = block . m_transactions [ i ] ;
auto it = parent_transactions . find ( tx ) ;
if ( it ! = parent_transactions . end ( ) ) {
writeVarint ( it - > second , data - > compact_blob ) ;
+ + num_found ;
}
else {
data - > compact_blob . push_back ( 0 ) ;
data - > compact_blob . insert ( data - > compact_blob . end ( ) , tx . h , tx . h + HASH_SIZE ) ;
}
}
LOGINFO ( 6 , " compact blob: " < < num_found < < ' / ' < < ( N - 1 ) < < " transactions were found in the parent block " ) ;
data - > compact_blob . insert ( data - > compact_blob . end ( ) , sidechain_data . begin ( ) , sidechain_data . end ( ) ) ;
}
2022-10-04 13:44:57 +00:00
data - > pruned_blob . insert ( data - > pruned_blob . end ( ) , sidechain_data . begin ( ) , sidechain_data . end ( ) ) ;
2021-08-22 10:20:59 +00:00
data - > ancestor_hashes . reserve ( block . m_uncles . size ( ) + 1 ) ;
data - > ancestor_hashes = block . m_uncles ;
data - > ancestor_hashes . push_back ( block . m_parent ) ;
2022-11-09 10:17:35 +00:00
LOGINFO ( 5 , " Broadcasting block " < < block . m_sidechainId < < " (height " < < block . m_sidechainHeight < < " ): " < < data - > compact_blob . size ( ) < < ' / ' < < data - > pruned_blob . size ( ) < < ' / ' < < data - > blob . size ( ) < < " bytes (compact/pruned/full) " ) ;
2021-08-22 10:20:59 +00:00
{
MutexLock lock ( m_broadcastLock ) ;
m_broadcastQueue . push_back ( data ) ;
}
2021-08-23 21:09:59 +00:00
if ( uv_is_closing ( reinterpret_cast < uv_handle_t * > ( & m_broadcastAsync ) ) ) {
return ;
}
2021-08-22 10:20:59 +00:00
const int err = uv_async_send ( & m_broadcastAsync ) ;
if ( err ) {
LOGERR ( 1 , " uv_async_send failed, error " < < uv_err_name ( err ) ) ;
bool found = false ;
{
MutexLock lock ( m_broadcastLock ) ;
auto it = std : : find ( m_broadcastQueue . begin ( ) , m_broadcastQueue . end ( ) , data ) ;
if ( it ! = m_broadcastQueue . end ( ) ) {
found = true ;
m_broadcastQueue . erase ( it ) ;
}
}
if ( found ) {
delete data ;
}
}
}
void P2PServer : : on_broadcast ( )
{
std : : vector < Broadcast * > broadcast_queue ;
broadcast_queue . reserve ( 2 ) ;
{
MutexLock lock ( m_broadcastLock ) ;
broadcast_queue = m_broadcastQueue ;
m_broadcastQueue . clear ( ) ;
}
if ( broadcast_queue . empty ( ) ) {
return ;
}
ON_SCOPE_LEAVE ( [ & broadcast_queue ] ( )
{
2022-06-07 17:40:13 +00:00
for ( const Broadcast * data : broadcast_queue ) {
2021-08-22 10:20:59 +00:00
delete data ;
}
} ) ;
MutexLock lock ( m_clientsListLock ) ;
for ( P2PClient * client = static_cast < P2PClient * > ( m_connectedClientsList - > m_next ) ; client ! = m_connectedClientsList ; client = static_cast < P2PClient * > ( client - > m_next ) ) {
2022-08-31 14:37:33 +00:00
if ( ! client - > is_good ( ) ) {
2021-08-22 10:20:59 +00:00
continue ;
}
for ( Broadcast * data : broadcast_queue ) {
2022-05-04 13:53:01 +00:00
send ( client , [ client , data ] ( void * buf , size_t buf_size ) - > size_t
{
2021-08-22 10:20:59 +00:00
uint8_t * p0 = reinterpret_cast < uint8_t * > ( buf ) ;
uint8_t * p = p0 ;
bool send_pruned = true ;
2022-11-09 18:03:58 +00:00
bool send_compact = ( client - > m_protocolVersion > = PROTOCOL_VERSION_1_1 ) & & ! data - > compact_blob . empty ( ) & & ( data - > compact_blob . size ( ) < data - > pruned_blob . size ( ) ) ;
2021-10-17 08:48:09 +00:00
const hash * a = client - > m_broadcastedHashes ;
const hash * b = client - > m_broadcastedHashes + array_size ( & P2PClient : : m_broadcastedHashes ) ;
for ( const hash & id : data - > ancestor_hashes ) {
if ( std : : find ( a , b , id ) = = b ) {
send_pruned = false ;
2022-11-09 18:03:58 +00:00
send_compact = false ;
2021-10-17 08:48:09 +00:00
break ;
2021-08-22 10:20:59 +00:00
}
}
if ( send_pruned ) {
2022-11-09 18:03:58 +00:00
LOGINFO ( 6 , " sending BLOCK_BROADCAST ( " < < ( send_compact ? " compact " : " pruned " ) < < " ) to " < < log : : Gray ( ) < < static_cast < char * > ( client - > m_addrString ) ) ;
const std : : vector < uint8_t > & blob = send_compact ? data - > compact_blob : data - > pruned_blob ;
2021-08-22 10:20:59 +00:00
2022-11-09 18:03:58 +00:00
const uint32_t len = static_cast < uint32_t > ( blob . size ( ) ) ;
2022-05-04 13:53:01 +00:00
if ( buf_size < SEND_BUF_MIN_SIZE + 1 + sizeof ( uint32_t ) + len ) {
return 0 ;
}
2022-11-09 18:03:58 +00:00
* ( p + + ) = static_cast < uint8_t > ( send_compact ? MessageId : : BLOCK_BROADCAST_COMPACT : MessageId : : BLOCK_BROADCAST ) ;
2022-05-04 13:53:01 +00:00
2022-04-08 20:34:37 +00:00
memcpy ( p , & len , sizeof ( uint32_t ) ) ;
2021-08-22 10:20:59 +00:00
p + = sizeof ( uint32_t ) ;
2022-04-08 20:34:37 +00:00
if ( len ) {
2022-11-09 18:03:58 +00:00
memcpy ( p , blob . data ( ) , len ) ;
2022-04-08 20:34:37 +00:00
p + = len ;
}
2021-08-22 10:20:59 +00:00
}
else {
LOGINFO ( 5 , " sending BLOCK_BROADCAST (full) to " < < log : : Gray ( ) < < static_cast < char * > ( client - > m_addrString ) ) ;
2022-04-08 20:34:37 +00:00
const uint32_t len = static_cast < uint32_t > ( data - > blob . size ( ) ) ;
2022-05-04 13:53:01 +00:00
if ( buf_size < SEND_BUF_MIN_SIZE + 1 + sizeof ( uint32_t ) + len ) {
return 0 ;
}
* ( p + + ) = static_cast < uint8_t > ( MessageId : : BLOCK_BROADCAST ) ;
2022-04-08 20:34:37 +00:00
memcpy ( p , & len , sizeof ( uint32_t ) ) ;
2021-08-22 10:20:59 +00:00
p + = sizeof ( uint32_t ) ;
2022-04-08 20:34:37 +00:00
if ( len ) {
memcpy ( p , data - > blob . data ( ) , len ) ;
p + = len ;
}
2021-08-22 10:20:59 +00:00
}
return p - p0 ;
2022-02-23 16:07:50 +00:00
} ) ;
2021-08-22 10:20:59 +00:00
}
}
}
uint64_t P2PServer : : get_random64 ( )
{
MutexLock lock ( m_rngLock ) ;
return m_rng ( ) ;
}
void P2PServer : : print_status ( )
{
2022-05-09 14:07:49 +00:00
MutexLock lock ( m_peerListLock ) ;
2021-08-22 10:20:59 +00:00
LOGINFO ( 0 , " status " < <
2022-05-09 14:07:49 +00:00
" \n Connections = " < < m_numConnections . load ( ) < < " ( " < < m_numIncomingConnections . load ( ) < < " incoming) " < <
2021-10-26 15:55:47 +00:00
" \n Peer list size = " < < m_peerList . size ( ) < <
2022-05-06 11:19:56 +00:00
" \n Uptime = " < < log : : Duration ( seconds_since_epoch ( ) - m_pool - > start_time ( ) )
2021-08-22 10:20:59 +00:00
) ;
}
2022-08-31 14:37:33 +00:00
void P2PServer : : show_peers_async ( )
{
if ( ! uv_is_closing ( reinterpret_cast < uv_handle_t * > ( & m_showPeersAsync ) ) ) {
uv_async_send ( & m_showPeersAsync ) ;
}
}
2021-10-24 14:04:30 +00:00
void P2PServer : : show_peers ( )
{
MutexLock lock ( m_clientsListLock ) ;
2022-05-06 18:04:01 +00:00
size_t n = 0 ;
2021-10-24 14:04:30 +00:00
for ( P2PClient * client = static_cast < P2PClient * > ( m_connectedClientsList - > m_next ) ; client ! = m_connectedClientsList ; client = static_cast < P2PClient * > ( client - > m_next ) ) {
if ( client - > m_listenPort > = 0 ) {
LOGINFO ( 0 , ( client - > m_isIncoming ? " I " : " O " ) < < client - > m_pingTime < < " ms \t " < < static_cast < char * > ( client - > m_addrString ) ) ;
2022-05-06 18:04:01 +00:00
+ + n ;
2021-10-24 14:04:30 +00:00
}
}
2022-05-06 18:04:01 +00:00
LOGINFO ( 0 , " Total: " < < n < < " peers " ) ;
2021-10-24 14:04:30 +00:00
}
2022-10-28 12:06:26 +00:00
int P2PServer : : listen_port ( ) const
{
const Params & params = m_pool - > params ( ) ;
return params . m_p2pExternalPort ? params . m_p2pExternalPort : m_listenPort ;
}
2022-11-09 14:29:53 +00:00
int P2PServer : : deserialize_block ( const uint8_t * buf , uint32_t size , bool compact )
2022-07-10 08:24:03 +00:00
{
int result ;
if ( ( m_blockDeserializeBuf . size ( ) = = size ) & & ( memcmp ( m_blockDeserializeBuf . data ( ) , buf , size ) = = 0 ) ) {
m_block - > reset_offchain_data ( ) ;
result = m_blockDeserializeResult ;
}
else {
2022-11-09 14:29:53 +00:00
result = m_block - > deserialize ( buf , size , m_pool - > side_chain ( ) , & m_loop , compact ) ;
2022-07-10 08:24:03 +00:00
m_blockDeserializeBuf . assign ( buf , buf + size ) ;
m_blockDeserializeResult = result ;
m_lookForMissingBlocks = true ;
}
return result ;
}
2021-08-22 10:20:59 +00:00
void P2PServer : : on_timer ( )
{
2021-10-08 16:02:04 +00:00
+ + m_timerCounter ;
2021-09-07 10:56:22 +00:00
if ( ! m_initialPeerList . empty ( ) ) {
connect_to_peers ( m_initialPeerList ) ;
m_initialPeerList . clear ( ) ;
}
2021-08-24 09:42:41 +00:00
flush_cache ( ) ;
2021-08-22 10:20:59 +00:00
download_missing_blocks ( ) ;
update_peer_list ( ) ;
save_peer_list_async ( ) ;
2021-09-02 17:21:38 +00:00
update_peer_connections ( ) ;
2021-10-09 09:01:26 +00:00
check_zmq ( ) ;
2022-11-04 06:47:07 +00:00
check_block_template ( ) ;
2021-08-22 10:20:59 +00:00
}
2021-08-24 09:42:41 +00:00
void P2PServer : : flush_cache ( )
{
2021-11-01 10:29:59 +00:00
if ( ! m_cache | | ( ( m_timerCounter % 30 ) ! = 2 ) ) {
2021-08-24 09:42:41 +00:00
return ;
}
struct Work
{
uv_work_t req ;
BlockCache * cache ;
} ;
Work * work = new Work { } ;
work - > req . data = work ;
work - > cache = m_cache ;
2021-08-25 09:31:50 +00:00
const int err = uv_queue_work ( & m_loop , & work - > req ,
2021-08-24 09:42:41 +00:00
[ ] ( uv_work_t * req )
{
2022-11-04 09:14:49 +00:00
BACKGROUND_JOB_START ( P2PServer : : flush_cache ) ;
2021-08-24 09:42:41 +00:00
reinterpret_cast < Work * > ( req - > data ) - > cache - > flush ( ) ;
} ,
[ ] ( uv_work_t * req , int )
{
delete reinterpret_cast < Work * > ( req - > data ) ;
2022-11-04 09:14:49 +00:00
BACKGROUND_JOB_STOP ( P2PServer : : flush_cache ) ;
2021-08-24 09:42:41 +00:00
} ) ;
if ( err ) {
LOGERR ( 1 , " flush_cache: uv_queue_work failed, error " < < uv_err_name ( err ) ) ;
2021-09-07 08:22:58 +00:00
delete work ;
2021-08-24 09:42:41 +00:00
}
}
2021-08-22 10:20:59 +00:00
void P2PServer : : download_missing_blocks ( )
{
2022-07-10 08:24:03 +00:00
if ( ! m_lookForMissingBlocks ) {
return ;
}
2021-08-22 10:20:59 +00:00
std : : vector < hash > missing_blocks ;
m_pool - > side_chain ( ) . get_missing_blocks ( missing_blocks ) ;
if ( missing_blocks . empty ( ) ) {
2022-07-10 08:24:03 +00:00
m_lookForMissingBlocks = false ;
2021-08-27 19:09:35 +00:00
m_missingBlockRequests . clear ( ) ;
2021-08-22 10:20:59 +00:00
return ;
}
MutexLock lock ( m_clientsListLock ) ;
if ( m_numConnections = = 0 ) {
return ;
}
std : : vector < P2PClient * > clients ;
clients . reserve ( m_numConnections ) ;
for ( P2PClient * client = static_cast < P2PClient * > ( m_connectedClientsList - > m_next ) ; client ! = m_connectedClientsList ; client = static_cast < P2PClient * > ( client - > m_next ) ) {
2022-07-10 08:24:03 +00:00
if ( client - > is_good ( ) ) {
clients . emplace_back ( client ) ;
2021-08-22 10:20:59 +00:00
}
}
2021-08-27 15:26:42 +00:00
if ( clients . empty ( ) ) {
return ;
}
2022-03-24 17:30:23 +00:00
ReadLock lock2 ( m_cachedBlocksLock ) ;
2021-08-22 10:20:59 +00:00
// Try to download each block from a random client
for ( const hash & id : missing_blocks ) {
2021-08-27 15:26:42 +00:00
P2PClient * client = clients [ get_random64 ( ) % clients . size ( ) ] ;
2022-09-13 08:51:15 +00:00
const uint64_t truncated_block_id = * reinterpret_cast < const uint64_t * > ( id . h ) ;
if ( ! m_missingBlockRequests . insert ( { client - > m_peerId , truncated_block_id } ) . second ) {
// We already asked this peer about this block
// Don't try to ask another peer, leave it for another timer tick
continue ;
2021-08-27 15:26:42 +00:00
}
2022-03-24 17:30:23 +00:00
if ( m_cachedBlocks ) {
auto it = m_cachedBlocks - > find ( id ) ;
if ( it ! = m_cachedBlocks - > end ( ) ) {
LOGINFO ( 5 , " using cached block for id = " < < id ) ;
client - > handle_incoming_block_async ( it - > second ) ;
continue ;
}
}
2022-02-21 15:54:53 +00:00
const bool result = send ( client ,
2022-09-13 09:12:08 +00:00
[ & id , client ] ( void * buf , size_t buf_size ) - > size_t
2021-08-22 10:20:59 +00:00
{
2022-09-13 09:12:08 +00:00
LOGINFO ( 5 , " sending BLOCK_REQUEST for id = " < < id < < " to " < < static_cast < char * > ( client - > m_addrString ) ) ;
2022-05-04 13:53:01 +00:00
if ( buf_size < SEND_BUF_MIN_SIZE ) {
return 0 ;
}
2021-08-22 10:20:59 +00:00
uint8_t * p0 = reinterpret_cast < uint8_t * > ( buf ) ;
uint8_t * p = p0 ;
* ( p + + ) = static_cast < uint8_t > ( MessageId : : BLOCK_REQUEST ) ;
memcpy ( p , id . h , HASH_SIZE ) ;
p + = HASH_SIZE ;
return p - p0 ;
} ) ;
2022-02-21 15:54:53 +00:00
if ( result ) {
+ + client - > m_blockPendingRequests ;
}
2021-08-22 10:20:59 +00:00
}
}
2021-10-09 09:01:26 +00:00
void P2PServer : : check_zmq ( )
{
2022-07-10 08:24:03 +00:00
if ( ( m_timerCounter % 30 ) ! = 3 ) {
2021-10-09 09:01:26 +00:00
return ;
}
2022-03-23 10:30:38 +00:00
const uint64_t cur_time = seconds_since_epoch ( ) ;
const uint64_t last_active = m_pool - > zmq_last_active ( ) ;
2021-10-09 09:01:26 +00:00
if ( cur_time > = last_active + 300 ) {
const uint64_t dt = static_cast < uint64_t > ( cur_time - last_active ) ;
LOGERR ( 1 , " no ZMQ messages received from monerod in the last " < < dt < < " seconds, check your monerod/p2pool/network/firewall setup!!! " ) ;
2022-05-11 09:44:42 +00:00
m_pool - > restart_zmq ( ) ;
2021-10-09 09:01:26 +00:00
}
}
2022-11-04 06:47:07 +00:00
void P2PServer : : check_block_template ( )
{
if ( ! m_pool - > side_chain ( ) . precalcFinished ( ) ) {
return ;
}
// Force update block template every 30 seconds after the initial sync is done
if ( seconds_since_epoch ( ) > = m_pool - > block_template ( ) . last_updated ( ) + 30 ) {
LOGINFO ( 4 , " block template is 30 seconds old, updating it " ) ;
m_pool - > update_block_template_async ( ) ;
}
}
2021-08-22 10:20:59 +00:00
P2PServer : : P2PClient : : P2PClient ( )
: m_peerId ( 0 )
, m_expectedMessage ( MessageId : : HANDSHAKE_CHALLENGE )
, m_handshakeChallenge ( 0 )
, m_handshakeSolutionSent ( false )
, m_handshakeComplete ( false )
2021-08-29 15:26:30 +00:00
, m_handshakeInvalid ( false )
2021-08-22 10:20:59 +00:00
, m_listenPort ( - 1 )
2022-02-22 10:06:12 +00:00
, m_fastPeerListRequestCount ( 0 )
2022-03-23 10:30:38 +00:00
, m_prevIncomingPeerListRequest ( 0 )
2022-02-21 15:54:53 +00:00
, m_nextOutgoingPeerListRequest ( 0 )
2021-10-24 14:04:30 +00:00
, m_lastPeerListRequestTime { }
2021-10-15 15:09:51 +00:00
, m_peerListPendingRequests ( 0 )
2022-11-09 18:03:58 +00:00
, m_protocolVersion ( PROTOCOL_VERSION_1_0 )
2022-09-13 08:51:15 +00:00
, m_pingTime ( - 1 )
2022-02-21 15:54:53 +00:00
, m_blockPendingRequests ( 0 )
2022-04-23 09:29:17 +00:00
, m_chainTipBlockRequest ( false )
2021-08-24 19:45:19 +00:00
, m_lastAlive ( 0 )
2021-09-13 12:26:52 +00:00
, m_lastBroadcastTimestamp ( 0 )
, m_lastBlockrequestTimestamp ( 0 )
2021-10-17 08:48:09 +00:00
, m_broadcastedHashes { }
2021-08-22 10:20:59 +00:00
{
}
2022-10-07 14:02:08 +00:00
void P2PServer : : on_shutdown ( )
{
uv_timer_stop ( & m_timer ) ;
uv_close ( reinterpret_cast < uv_handle_t * > ( & m_timer ) , nullptr ) ;
uv_close ( reinterpret_cast < uv_handle_t * > ( & m_broadcastAsync ) , nullptr ) ;
uv_close ( reinterpret_cast < uv_handle_t * > ( & m_connectToPeersAsync ) , nullptr ) ;
uv_close ( reinterpret_cast < uv_handle_t * > ( & m_showPeersAsync ) , nullptr ) ;
}
2021-08-22 10:20:59 +00:00
P2PServer : : P2PClient : : ~ P2PClient ( )
{
}
void P2PServer : : P2PClient : : reset ( )
{
2022-09-13 08:51:15 +00:00
P2PServer * server = static_cast < P2PServer * > ( m_owner ) ;
if ( server & & ( server - > m_fastestPeer = = this ) ) {
server - > m_fastestPeer = nullptr ;
}
2021-08-22 10:20:59 +00:00
Client : : reset ( ) ;
m_peerId = 0 ;
m_expectedMessage = MessageId : : HANDSHAKE_CHALLENGE ;
m_handshakeChallenge = 0 ;
m_handshakeSolutionSent = false ;
m_handshakeComplete = false ;
2021-08-29 15:26:30 +00:00
m_handshakeInvalid = false ;
2021-08-22 10:20:59 +00:00
m_listenPort = - 1 ;
2022-02-22 10:06:12 +00:00
m_fastPeerListRequestCount = 0 ;
2022-03-23 10:30:38 +00:00
m_prevIncomingPeerListRequest = 0 ;
2022-02-21 15:54:53 +00:00
m_nextOutgoingPeerListRequest = 0 ;
2021-10-24 14:04:30 +00:00
m_lastPeerListRequestTime = { } ;
2021-10-15 15:09:51 +00:00
m_peerListPendingRequests = 0 ;
2022-11-09 18:03:58 +00:00
m_protocolVersion = PROTOCOL_VERSION_1_0 ;
2022-09-13 08:51:15 +00:00
m_pingTime = - 1 ;
2022-02-21 15:54:53 +00:00
m_blockPendingRequests = 0 ;
2022-04-23 09:29:17 +00:00
m_chainTipBlockRequest = false ;
2021-08-24 19:45:19 +00:00
m_lastAlive = 0 ;
2021-09-13 12:26:52 +00:00
m_lastBroadcastTimestamp = 0 ;
m_lastBlockrequestTimestamp = 0 ;
2021-08-22 10:20:59 +00:00
2021-10-17 08:48:09 +00:00
for ( hash & h : m_broadcastedHashes ) {
h = { } ;
}
m_broadcastedHashesIndex = 0 ;
2021-08-22 10:20:59 +00:00
}
bool P2PServer : : P2PClient : : on_connect ( )
{
2021-08-31 08:41:41 +00:00
P2PServer * server = static_cast < P2PServer * > ( m_owner ) ;
2021-12-26 14:28:33 +00:00
if ( ! server ) {
2021-12-26 13:59:45 +00:00
return false ;
}
2021-12-26 14:28:33 +00:00
if ( m_isIncoming & & ( server - > m_numIncomingConnections > server - > m_maxIncomingPeers ) ) {
2021-12-26 13:59:45 +00:00
LOGINFO ( 5 , " Connection from " < < log : : Gray ( ) < < static_cast < char * > ( m_addrString ) < < log : : NoColor ( ) < < " rejected (incoming connections limit was reached) " ) ;
return false ;
}
2022-08-31 14:37:33 +00:00
// Don't allow multiple connections to/from the same IP (except localhost)
2021-08-31 08:41:41 +00:00
// server->m_clientsListLock is already locked here
2022-08-31 14:37:33 +00:00
if ( ! m_addr . is_localhost ( ) ) {
for ( P2PClient * client = static_cast < P2PClient * > ( server - > m_connectedClientsList - > m_next ) ; client ! = server - > m_connectedClientsList ; client = static_cast < P2PClient * > ( client - > m_next ) ) {
if ( ( client ! = this ) & & ( client - > m_addr = = m_addr ) ) {
LOGINFO ( 5 , " peer " < < static_cast < char * > ( m_addrString ) < < " is already connected as " < < static_cast < char * > ( client - > m_addrString ) ) ;
return false ;
}
2021-08-31 08:41:41 +00:00
}
}
2022-03-23 10:30:38 +00:00
m_lastAlive = seconds_since_epoch ( ) ;
2021-08-22 10:20:59 +00:00
return send_handshake_challenge ( ) ;
}
bool P2PServer : : P2PClient : : on_read ( char * data , uint32_t size )
{
P2PServer * server = static_cast < P2PServer * > ( m_owner ) ;
if ( ! server ) {
return false ;
}
if ( ( data ! = m_readBuf + m_numRead ) | | ( data + size > m_readBuf + sizeof ( m_readBuf ) ) ) {
LOGERR ( 1 , " peer " < < static_cast < char * > ( m_addrString ) < < " invalid data pointer or size in on_read() " ) ;
ban ( DEFAULT_BAN_TIME ) ;
server - > remove_peer_from_list ( this ) ;
return false ;
}
m_numRead + = size ;
uint8_t * buf_begin = reinterpret_cast < uint8_t * > ( m_readBuf ) ;
uint8_t * buf = buf_begin ;
uint32_t bytes_left = m_numRead ;
2022-02-21 15:54:53 +00:00
uint32_t num_block_requests = 0 ;
2021-08-22 10:20:59 +00:00
uint32_t bytes_read ;
do {
MessageId id = static_cast < MessageId > ( buf [ 0 ] ) ;
// Peer must complete the handshake challenge before sending any other messages
if ( ! m_handshakeComplete & & ( id ! = m_expectedMessage ) ) {
LOGWARN ( 5 , " peer " < < static_cast < char * > ( m_addrString ) < < " didn't send handshake messages first " ) ;
ban ( DEFAULT_BAN_TIME ) ;
server - > remove_peer_from_list ( this ) ;
return false ;
}
bytes_read = 0 ;
switch ( id )
{
case MessageId : : HANDSHAKE_CHALLENGE :
2021-10-15 15:09:51 +00:00
if ( m_handshakeComplete ) {
LOGWARN ( 4 , " peer " < < log : : Gray ( ) < < static_cast < char * > ( m_addrString ) < < log : : NoColor ( ) < < " sent an unexpected HANDSHAKE_CHALLENGE " ) ;
ban ( DEFAULT_BAN_TIME ) ;
server - > remove_peer_from_list ( this ) ;
return false ;
}
2021-08-22 10:20:59 +00:00
LOGINFO ( 5 , " peer " < < log : : Gray ( ) < < static_cast < char * > ( m_addrString ) < < log : : NoColor ( ) < < " sent HANDSHAKE_CHALLENGE " ) ;
if ( bytes_left > = 1 + CHALLENGE_SIZE + sizeof ( uint64_t ) ) {
bytes_read = 1 + CHALLENGE_SIZE + sizeof ( uint64_t ) ;
if ( ! on_handshake_challenge ( buf + 1 ) ) {
ban ( DEFAULT_BAN_TIME ) ;
server - > remove_peer_from_list ( this ) ;
return false ;
}
m_expectedMessage = MessageId : : HANDSHAKE_SOLUTION ;
}
break ;
case MessageId : : HANDSHAKE_SOLUTION :
2021-10-15 15:09:51 +00:00
if ( m_handshakeComplete ) {
LOGWARN ( 4 , " peer " < < log : : Gray ( ) < < static_cast < char * > ( m_addrString ) < < log : : NoColor ( ) < < " sent an unexpected HANDSHAKE_SOLUTION " ) ;
ban ( DEFAULT_BAN_TIME ) ;
server - > remove_peer_from_list ( this ) ;
return false ;
}
2021-08-22 10:20:59 +00:00
LOGINFO ( 5 , " peer " < < log : : Gray ( ) < < static_cast < char * > ( m_addrString ) < < log : : NoColor ( ) < < " sent HANDSHAKE_SOLUTION " ) ;
if ( bytes_left > = 1 + HASH_SIZE + CHALLENGE_SIZE ) {
bytes_read = 1 + HASH_SIZE + CHALLENGE_SIZE ;
if ( ! on_handshake_solution ( buf + 1 ) ) {
ban ( DEFAULT_BAN_TIME ) ;
server - > remove_peer_from_list ( this ) ;
return false ;
}
}
break ;
case MessageId : : LISTEN_PORT :
2022-02-21 15:54:53 +00:00
if ( m_listenPort > = 0 ) {
LOGWARN ( 4 , " peer " < < static_cast < char * > ( m_addrString ) < < " sent an unexpected LISTEN_PORT " ) ;
ban ( DEFAULT_BAN_TIME ) ;
server - > remove_peer_from_list ( this ) ;
return false ;
}
2021-08-22 10:20:59 +00:00
LOGINFO ( 5 , " peer " < < log : : Gray ( ) < < static_cast < char * > ( m_addrString ) < < log : : NoColor ( ) < < " sent LISTEN_PORT " ) ;
if ( bytes_left > = 1 + sizeof ( int32_t ) ) {
bytes_read = 1 + sizeof ( int32_t ) ;
if ( ! on_listen_port ( buf + 1 ) ) {
ban ( DEFAULT_BAN_TIME ) ;
server - > remove_peer_from_list ( this ) ;
return false ;
}
}
break ;
case MessageId : : BLOCK_REQUEST :
2022-02-21 15:54:53 +00:00
+ + num_block_requests ;
if ( num_block_requests > 100 ) {
LOGWARN ( 4 , " peer " < < log : : Gray ( ) < < static_cast < char * > ( m_addrString ) < < log : : NoColor ( ) < < " sent too many BLOCK_REQUEST messages at once " ) ;
ban ( DEFAULT_BAN_TIME ) ;
server - > remove_peer_from_list ( this ) ;
return false ;
}
2021-08-22 10:20:59 +00:00
LOGINFO ( 5 , " peer " < < log : : Gray ( ) < < static_cast < char * > ( m_addrString ) < < log : : NoColor ( ) < < " sent BLOCK_REQUEST " ) ;
if ( bytes_left > = 1 + HASH_SIZE ) {
bytes_read = 1 + HASH_SIZE ;
if ( ! on_block_request ( buf + 1 ) ) {
ban ( DEFAULT_BAN_TIME ) ;
server - > remove_peer_from_list ( this ) ;
return false ;
}
}
break ;
case MessageId : : BLOCK_RESPONSE :
2022-02-21 15:54:53 +00:00
if ( m_blockPendingRequests < = 0 ) {
LOGWARN ( 4 , " peer " < < log : : Gray ( ) < < static_cast < char * > ( m_addrString ) < < log : : NoColor ( ) < < " sent an unexpected BLOCK_RESPONSE " ) ;
ban ( DEFAULT_BAN_TIME ) ;
server - > remove_peer_from_list ( this ) ;
return false ;
}
2021-08-22 10:20:59 +00:00
LOGINFO ( 5 , " peer " < < log : : Gray ( ) < < static_cast < char * > ( m_addrString ) < < log : : NoColor ( ) < < " sent BLOCK_RESPONSE " ) ;
if ( bytes_left > = 1 + sizeof ( uint32_t ) ) {
2022-04-08 20:34:37 +00:00
const uint32_t block_size = read_unaligned ( reinterpret_cast < uint32_t * > ( buf + 1 ) ) ;
2021-08-22 10:20:59 +00:00
if ( bytes_left > = 1 + sizeof ( uint32_t ) + block_size ) {
bytes_read = 1 + sizeof ( uint32_t ) + block_size ;
2022-02-21 15:54:53 +00:00
- - m_blockPendingRequests ;
2021-08-22 10:20:59 +00:00
if ( ! on_block_response ( buf + 1 + sizeof ( uint32_t ) , block_size ) ) {
ban ( DEFAULT_BAN_TIME ) ;
server - > remove_peer_from_list ( this ) ;
return false ;
}
}
}
break ;
case MessageId : : BLOCK_BROADCAST :
2022-11-09 18:03:58 +00:00
case MessageId : : BLOCK_BROADCAST_COMPACT :
{
const bool compact = ( id = = MessageId : : BLOCK_BROADCAST_COMPACT ) ;
LOGINFO ( 6 , " peer " < < log : : Gray ( ) < < static_cast < char * > ( m_addrString ) < < log : : NoColor ( ) < < " sent " < < ( compact ? " BLOCK_BROADCAST_COMPACT " : " BLOCK_BROADCAST " ) ) ;
if ( bytes_left > = 1 + sizeof ( uint32_t ) ) {
const uint32_t block_size = read_unaligned ( reinterpret_cast < uint32_t * > ( buf + 1 ) ) ;
if ( bytes_left > = 1 + sizeof ( uint32_t ) + block_size ) {
bytes_read = 1 + sizeof ( uint32_t ) + block_size ;
if ( ! on_block_broadcast ( buf + 1 + sizeof ( uint32_t ) , block_size , compact ) ) {
ban ( DEFAULT_BAN_TIME ) ;
server - > remove_peer_from_list ( this ) ;
return false ;
}
2021-08-22 10:20:59 +00:00
}
}
}
break ;
case MessageId : : PEER_LIST_REQUEST :
LOGINFO ( 5 , " peer " < < log : : Gray ( ) < < static_cast < char * > ( m_addrString ) < < log : : NoColor ( ) < < " sent PEER_LIST_REQUEST " ) ;
if ( bytes_left > = 1 ) {
bytes_read = 1 ;
if ( ! on_peer_list_request ( buf + 1 ) ) {
ban ( DEFAULT_BAN_TIME ) ;
server - > remove_peer_from_list ( this ) ;
return false ;
}
}
break ;
case MessageId : : PEER_LIST_RESPONSE :
2021-10-15 15:09:51 +00:00
if ( m_peerListPendingRequests < = 0 ) {
LOGWARN ( 4 , " peer " < < log : : Gray ( ) < < static_cast < char * > ( m_addrString ) < < log : : NoColor ( ) < < " sent an unexpected PEER_LIST_RESPONSE " ) ;
ban ( DEFAULT_BAN_TIME ) ;
server - > remove_peer_from_list ( this ) ;
return false ;
}
2021-08-22 10:20:59 +00:00
LOGINFO ( 5 , " peer " < < log : : Gray ( ) < < static_cast < char * > ( m_addrString ) < < log : : NoColor ( ) < < " sent PEER_LIST_RESPONSE " ) ;
if ( bytes_left > = 2 ) {
2021-10-21 13:55:00 +00:00
const uint32_t num_peers = buf [ 1 ] ;
2021-08-22 10:20:59 +00:00
if ( num_peers > PEER_LIST_RESPONSE_MAX_PEERS ) {
2021-08-24 19:45:19 +00:00
LOGWARN ( 5 , " peer " < < log : : Gray ( ) < < static_cast < char * > ( m_addrString ) < < log : : NoColor ( ) < < " sent too long peer list ( " < < num_peers < < ' ) ' ) ;
2021-08-22 10:20:59 +00:00
ban ( DEFAULT_BAN_TIME ) ;
server - > remove_peer_from_list ( this ) ;
return false ;
}
2021-10-21 13:55:00 +00:00
if ( bytes_left > = 2u + num_peers * 19u ) {
bytes_read = 2u + num_peers * 19u ;
2021-10-15 15:09:51 +00:00
2021-10-24 14:04:30 +00:00
using namespace std : : chrono ;
2022-09-13 08:51:15 +00:00
m_pingTime = std : : max < int64_t > ( duration_cast < milliseconds > ( high_resolution_clock : : now ( ) - m_lastPeerListRequestTime ) . count ( ) , 0 ) ;
2021-10-24 14:04:30 +00:00
2021-10-15 15:09:51 +00:00
- - m_peerListPendingRequests ;
2021-08-22 10:20:59 +00:00
if ( ! on_peer_list_response ( buf + 1 ) ) {
ban ( DEFAULT_BAN_TIME ) ;
server - > remove_peer_from_list ( this ) ;
return false ;
}
}
}
break ;
}
2021-08-24 19:45:19 +00:00
if ( bytes_read ) {
buf + = bytes_read ;
bytes_left - = bytes_read ;
2022-03-23 10:30:38 +00:00
m_lastAlive = seconds_since_epoch ( ) ;
2021-08-24 19:45:19 +00:00
}
2021-08-22 10:20:59 +00:00
} while ( bytes_read & & bytes_left ) ;
// Move the possible unfinished message to the beginning of m_readBuf to free up more space for reading
if ( buf ! = buf_begin ) {
m_numRead = static_cast < uint32_t > ( buf_begin + m_numRead - buf ) ;
if ( m_numRead > 0 ) {
memmove ( m_readBuf , buf , m_numRead ) ;
}
}
return true ;
}
2021-09-06 14:17:20 +00:00
void P2PServer : : P2PClient : : on_read_failed ( int /*err*/ )
2021-09-07 07:53:38 +00:00
{
on_disconnected ( ) ;
}
void P2PServer : : P2PClient : : on_disconnected ( )
2021-09-06 14:17:20 +00:00
{
2022-09-13 08:51:15 +00:00
P2PServer * server = static_cast < P2PServer * > ( m_owner ) ;
if ( server & & ( server - > m_fastestPeer = = this ) ) {
server - > m_fastestPeer = nullptr ;
}
2022-09-13 14:14:54 +00:00
m_pingTime = - 1 ;
2021-09-06 14:17:20 +00:00
if ( ! m_handshakeComplete ) {
LOGWARN ( 5 , " peer " < < static_cast < char * > ( m_addrString ) < < " disconnected before finishing handshake " ) ;
ban ( DEFAULT_BAN_TIME ) ;
if ( server ) {
server - > remove_peer_from_list ( this ) ;
}
}
}
2021-08-22 10:20:59 +00:00
bool P2PServer : : P2PClient : : send_handshake_challenge ( )
{
P2PServer * owner = static_cast < P2PServer * > ( m_owner ) ;
m_handshakeChallenge = owner - > get_random64 ( ) ;
return owner - > send ( this ,
2022-05-04 13:53:01 +00:00
[ this , owner ] ( void * buf , size_t buf_size ) - > size_t
2021-08-22 10:20:59 +00:00
{
2022-09-13 09:12:08 +00:00
LOGINFO ( 5 , " sending HANDSHAKE_CHALLENGE to " < < static_cast < char * > ( m_addrString ) ) ;
2022-05-04 13:53:01 +00:00
if ( buf_size < SEND_BUF_MIN_SIZE ) {
return 0 ;
}
2021-08-22 10:20:59 +00:00
uint8_t * p0 = reinterpret_cast < uint8_t * > ( buf ) ;
uint8_t * p = p0 ;
* ( p + + ) = static_cast < uint8_t > ( MessageId : : HANDSHAKE_CHALLENGE ) ;
uint64_t k = m_handshakeChallenge ;
for ( int i = 0 ; i < CHALLENGE_SIZE ; + + i ) {
* ( p + + ) = k & 0xFF ;
k > > = 8 ;
}
k = owner - > get_peerId ( ) ;
memcpy ( p , & k , sizeof ( uint64_t ) ) ;
p + = sizeof ( uint64_t ) ;
return p - p0 ;
} ) ;
}
void P2PServer : : P2PClient : : send_handshake_solution ( const uint8_t ( & challenge ) [ CHALLENGE_SIZE ] )
{
P2PServer * server = static_cast < P2PServer * > ( m_owner ) ;
struct Work
{
uv_work_t req ;
P2PClient * client ;
P2PServer * server ;
uint32_t reset_counter ;
uint8_t challenge [ CHALLENGE_SIZE ] ;
uint64_t salt ;
uint8_t solution_salt [ CHALLENGE_SIZE ] ;
hash solution ;
} ;
Work * work = new Work { } ;
work - > req . data = work ;
work - > client = this ;
work - > server = server ;
work - > reset_counter = m_resetCounter . load ( ) ;
memcpy ( work - > challenge , challenge , CHALLENGE_SIZE ) ;
work - > salt = server - > get_random64 ( ) ;
const int err = uv_queue_work ( & server - > m_loop , & work - > req ,
[ ] ( uv_work_t * req )
{
2022-11-04 09:14:49 +00:00
BACKGROUND_JOB_START ( P2PServer : : send_handshake_solution ) ;
2021-08-22 10:20:59 +00:00
Work * work = reinterpret_cast < Work * > ( req - > data ) ;
const std : : vector < uint8_t > & consensus_id = work - > server - > m_pool - > side_chain ( ) . consensus_id ( ) ;
const int consensus_id_size = static_cast < int > ( consensus_id . size ( ) ) ;
for ( size_t iter = 1 ; ; + + iter , + + work - > salt ) {
uint64_t k = work - > salt ;
for ( size_t i = 0 ; i < CHALLENGE_SIZE ; + + i ) {
work - > solution_salt [ i ] = k & 0xFF ;
k > > = 8 ;
}
keccak_custom (
[ work , & consensus_id , consensus_id_size ] ( int offset ) - > uint8_t
{
if ( offset < CHALLENGE_SIZE ) {
return work - > challenge [ offset ] ;
}
offset - = CHALLENGE_SIZE ;
if ( offset < consensus_id_size ) {
return consensus_id [ offset ] ;
}
return work - > solution_salt [ offset - consensus_id_size ] ;
} , CHALLENGE_SIZE * 2 + static_cast < int > ( consensus_id . size ( ) ) , work - > solution . h , HASH_SIZE ) ;
// We might've been disconnected while working on the challenge, do nothing in this case
if ( work - > client - > m_resetCounter . load ( ) ! = work - > reset_counter ) {
return ;
}
if ( work - > client - > m_isIncoming ) {
// This is an incoming connection, so it must do PoW, not us
return ;
}
uint64_t * value = reinterpret_cast < uint64_t * > ( work - > solution . h ) ;
uint64_t high ;
umul128 ( value [ HASH_SIZE / sizeof ( uint64_t ) - 1 ] , CHALLENGE_DIFFICULTY , & high ) ;
if ( high = = 0 ) {
LOGINFO ( 5 , " found handshake challenge solution after " < < iter < < " iterations " ) ;
return ;
}
}
} ,
[ ] ( uv_work_t * req , int )
{
Work * work = reinterpret_cast < Work * > ( req - > data ) ;
ON_SCOPE_LEAVE (
[ work ] ( )
{
delete work ;
2022-11-04 09:14:49 +00:00
BACKGROUND_JOB_STOP ( P2PServer : : send_handshake_solution ) ;
2021-08-22 10:20:59 +00:00
} ) ;
// We might've been disconnected while working on the challenge, do nothing in this case
if ( work - > client - > m_resetCounter . load ( ) ! = work - > reset_counter ) {
return ;
}
const bool result = work - > server - > send ( work - > client ,
2022-05-04 13:53:01 +00:00
[ work ] ( void * buf , size_t buf_size ) - > size_t
2021-08-22 10:20:59 +00:00
{
2022-09-13 09:12:08 +00:00
LOGINFO ( 5 , " sending HANDSHAKE_SOLUTION to " < < static_cast < char * > ( work - > client - > m_addrString ) ) ;
2022-05-04 13:53:01 +00:00
if ( buf_size < SEND_BUF_MIN_SIZE ) {
return 0 ;
}
2021-08-22 10:20:59 +00:00
uint8_t * p0 = reinterpret_cast < uint8_t * > ( buf ) ;
uint8_t * p = p0 ;
* ( p + + ) = static_cast < uint8_t > ( MessageId : : HANDSHAKE_SOLUTION ) ;
memcpy ( p , work - > solution . h , HASH_SIZE ) ;
p + = HASH_SIZE ;
memcpy ( p , work - > solution_salt , CHALLENGE_SIZE ) ;
p + = CHALLENGE_SIZE ;
2021-08-29 15:26:30 +00:00
if ( work - > client - > m_handshakeComplete & & ! work - > client - > m_handshakeInvalid ) {
2021-08-22 10:20:59 +00:00
work - > client - > on_after_handshake ( p ) ;
}
return p - p0 ;
} ) ;
if ( result ) {
work - > client - > m_handshakeSolutionSent = true ;
2021-08-29 15:26:30 +00:00
2021-08-29 15:42:49 +00:00
if ( work - > client - > m_handshakeComplete & & work - > client - > m_handshakeInvalid ) {
2021-08-29 15:26:30 +00:00
work - > client - > ban ( DEFAULT_BAN_TIME ) ;
work - > server - > remove_peer_from_list ( work - > client ) ;
work - > client - > close ( ) ;
}
2021-08-22 10:20:59 +00:00
}
else {
work - > client - > close ( ) ;
}
} ) ;
if ( err ) {
LOGERR ( 1 , " send_handshake_solution: uv_queue_work failed, error " < < uv_err_name ( err ) ) ;
delete work ;
}
}
bool P2PServer : : P2PClient : : check_handshake_solution ( const hash & solution , const uint8_t ( & solution_salt ) [ CHALLENGE_SIZE ] )
{
P2PServer * owner = static_cast < P2PServer * > ( m_owner ) ;
const std : : vector < uint8_t > & consensus_id = owner - > m_pool - > side_chain ( ) . consensus_id ( ) ;
const int consensus_id_size = static_cast < int > ( consensus_id . size ( ) ) ;
uint8_t challenge [ CHALLENGE_SIZE ] ;
uint64_t k = m_handshakeChallenge ;
for ( size_t i = 0 ; i < CHALLENGE_SIZE ; + + i ) {
challenge [ i ] = k & 0xFF ;
k > > = 8 ;
}
hash check { } ;
keccak_custom (
2021-09-05 09:50:56 +00:00
[ & challenge , & solution_salt , & consensus_id , consensus_id_size ] ( int offset ) - > uint8_t
2021-08-22 10:20:59 +00:00
{
if ( offset < CHALLENGE_SIZE ) {
return challenge [ offset ] ;
}
offset - = CHALLENGE_SIZE ;
if ( offset < consensus_id_size ) {
return consensus_id [ offset ] ;
}
return solution_salt [ offset - consensus_id_size ] ;
} , CHALLENGE_SIZE * 2 + static_cast < int > ( consensus_id . size ( ) ) , check . h , HASH_SIZE ) ;
return solution = = check ;
}
bool P2PServer : : P2PClient : : on_handshake_challenge ( const uint8_t * buf )
{
P2PServer * server = static_cast < P2PServer * > ( m_owner ) ;
uint8_t challenge [ CHALLENGE_SIZE ] ;
memcpy ( challenge , buf , CHALLENGE_SIZE ) ;
uint64_t peer_id ;
memcpy ( & peer_id , buf + CHALLENGE_SIZE , sizeof ( uint64_t ) ) ;
if ( peer_id = = server - > get_peerId ( ) ) {
2021-09-05 18:20:28 +00:00
LOGWARN ( 5 , " tried to connect to self at " < < static_cast < const char * > ( m_addrString ) ) ;
2021-08-22 10:20:59 +00:00
return false ;
}
m_peerId = peer_id ;
bool same_peer = false ;
{
MutexLock lock ( server - > m_clientsListLock ) ;
for ( const P2PClient * client = static_cast < P2PClient * > ( server - > m_connectedClientsList - > m_next ) ; client ! = server - > m_connectedClientsList ; client = static_cast < P2PClient * > ( client - > m_next ) ) {
if ( ( client ! = this ) & & ( client - > m_peerId = = peer_id ) ) {
2021-08-24 19:45:19 +00:00
LOGWARN ( 5 , " tried to connect to the same peer twice: current connection " < < static_cast < const char * > ( client - > m_addrString ) < < " , new connection " < < static_cast < const char * > ( m_addrString ) ) ;
2021-08-22 10:20:59 +00:00
same_peer = true ;
break ;
}
}
}
if ( same_peer ) {
close ( ) ;
return true ;
}
send_handshake_solution ( challenge ) ;
return true ;
}
bool P2PServer : : P2PClient : : on_handshake_solution ( const uint8_t * buf )
{
hash solution ;
uint8_t solution_salt [ CHALLENGE_SIZE ] ;
memcpy ( & solution , buf , HASH_SIZE ) ;
memcpy ( solution_salt , buf + HASH_SIZE , CHALLENGE_SIZE ) ;
// Check that incoming connection provided enough PoW
if ( m_isIncoming ) {
uint64_t * value = reinterpret_cast < uint64_t * > ( solution . h ) ;
uint64_t high ;
umul128 ( value [ HASH_SIZE / sizeof ( uint64_t ) - 1 ] , CHALLENGE_DIFFICULTY , & high ) ;
if ( high ) {
LOGWARN ( 5 , " peer " < < static_cast < char * > ( m_addrString ) < < " handshake doesn't have enough PoW " ) ;
2021-08-29 15:26:30 +00:00
m_handshakeInvalid = true ;
2021-08-22 10:20:59 +00:00
}
}
if ( ! check_handshake_solution ( solution , solution_salt ) ) {
LOGWARN ( 5 , " peer " < < static_cast < char * > ( m_addrString ) < < " handshake failed " ) ;
2021-08-29 15:26:30 +00:00
m_handshakeInvalid = true ;
2021-08-22 10:20:59 +00:00
}
m_handshakeComplete = true ;
2021-08-29 15:26:30 +00:00
if ( ! m_handshakeInvalid ) {
LOGINFO ( 5 , " peer " < < log : : Gray ( ) < < static_cast < char * > ( m_addrString ) < < log : : NoColor ( ) < < " handshake completed " ) ;
}
2021-08-22 10:20:59 +00:00
if ( m_handshakeSolutionSent ) {
2021-08-29 15:26:30 +00:00
if ( m_handshakeInvalid ) {
return false ;
}
2021-08-22 10:20:59 +00:00
return m_owner - > send ( this ,
2022-05-04 13:53:01 +00:00
[ this ] ( void * buf , size_t buf_size ) - > size_t
2021-08-22 10:20:59 +00:00
{
2022-09-13 09:12:08 +00:00
LOGINFO ( 5 , " sending LISTEN_PORT and BLOCK_REQUEST for the chain tip to " < < static_cast < char * > ( m_addrString ) ) ;
2022-05-04 13:53:01 +00:00
if ( buf_size < SEND_BUF_MIN_SIZE ) {
return 0 ;
}
2021-08-22 10:20:59 +00:00
uint8_t * p0 = reinterpret_cast < uint8_t * > ( buf ) ;
uint8_t * p = p0 ;
on_after_handshake ( p ) ;
return p - p0 ;
} ) ;
}
return true ;
}
void P2PServer : : P2PClient : : on_after_handshake ( uint8_t * & p )
{
2022-09-13 09:12:08 +00:00
LOGINFO ( 5 , " sending LISTEN_PORT to " < < static_cast < char * > ( m_addrString ) ) ;
2021-08-22 10:20:59 +00:00
* ( p + + ) = static_cast < uint8_t > ( MessageId : : LISTEN_PORT ) ;
const int32_t port = m_owner - > listen_port ( ) ;
memcpy ( p , & port , sizeof ( port ) ) ;
p + = sizeof ( port ) ;
2022-09-13 09:12:08 +00:00
LOGINFO ( 5 , " sending BLOCK_REQUEST for the chain tip to " < < static_cast < char * > ( m_addrString ) ) ;
2021-08-22 10:20:59 +00:00
* ( p + + ) = static_cast < uint8_t > ( MessageId : : BLOCK_REQUEST ) ;
hash empty ;
memcpy ( p , empty . h , HASH_SIZE ) ;
p + = HASH_SIZE ;
2021-09-13 12:26:52 +00:00
2022-02-21 15:54:53 +00:00
+ + m_blockPendingRequests ;
2022-04-23 09:29:17 +00:00
m_chainTipBlockRequest = true ;
2022-03-23 10:30:38 +00:00
m_lastBroadcastTimestamp = seconds_since_epoch ( ) ;
2021-08-22 10:20:59 +00:00
}
bool P2PServer : : P2PClient : : on_listen_port ( const uint8_t * buf )
{
int32_t port ;
memcpy ( & port , buf , sizeof ( port ) ) ;
if ( ( port < 0 ) | | ( port > = 65536 ) ) {
2021-08-24 19:45:19 +00:00
LOGWARN ( 5 , " peer " < < static_cast < char * > ( m_addrString ) < < " sent an invalid listen port number " ) ;
2021-08-22 10:20:59 +00:00
return false ;
}
m_listenPort = port ;
static_cast < P2PServer * > ( m_owner ) - > update_peer_in_list ( m_isV6 , m_addr , port ) ;
return true ;
}
bool P2PServer : : P2PClient : : on_block_request ( const uint8_t * buf )
{
2022-03-23 10:30:38 +00:00
m_lastBlockrequestTimestamp = seconds_since_epoch ( ) ;
2021-09-13 12:26:52 +00:00
2021-08-22 10:20:59 +00:00
hash id ;
memcpy ( id . h , buf , HASH_SIZE ) ;
P2PServer * server = static_cast < P2PServer * > ( m_owner ) ;
std : : vector < uint8_t > blob ;
if ( ! server - > m_pool - > side_chain ( ) . get_block_blob ( id , blob ) & & ! id . empty ( ) ) {
LOGWARN ( 5 , " got a request for block with id " < < id < < " but couldn't find it " ) ;
}
return server - > send ( this ,
2022-09-13 09:12:08 +00:00
[ this , & blob ] ( void * buf , size_t buf_size ) - > size_t
2021-08-22 10:20:59 +00:00
{
2022-09-13 09:12:08 +00:00
LOGINFO ( 5 , " sending BLOCK_RESPONSE to " < < static_cast < char * > ( m_addrString ) ) ;
2022-05-04 13:53:01 +00:00
const uint32_t len = static_cast < uint32_t > ( blob . size ( ) ) ;
if ( buf_size < SEND_BUF_MIN_SIZE + 1 + sizeof ( uint32_t ) + len ) {
return 0 ;
}
2021-08-22 10:20:59 +00:00
uint8_t * p0 = reinterpret_cast < uint8_t * > ( buf ) ;
uint8_t * p = p0 ;
* ( p + + ) = static_cast < uint8_t > ( MessageId : : BLOCK_RESPONSE ) ;
2022-04-08 20:34:37 +00:00
memcpy ( p , & len , sizeof ( uint32_t ) ) ;
2021-08-22 10:20:59 +00:00
p + = sizeof ( uint32_t ) ;
2022-04-08 20:34:37 +00:00
if ( len ) {
memcpy ( p , blob . data ( ) , len ) ;
p + = len ;
}
2021-08-22 10:20:59 +00:00
return p - p0 ;
} ) ;
}
bool P2PServer : : P2PClient : : on_block_response ( const uint8_t * buf , uint32_t size )
{
if ( ! size ) {
LOGINFO ( 5 , " peer " < < log : : Gray ( ) < < static_cast < char * > ( m_addrString ) < < log : : NoColor ( ) < < " sent an empty block response " ) ;
return true ;
}
P2PServer * server = static_cast < P2PServer * > ( m_owner ) ;
MutexLock lock ( server - > m_blockLock ) ;
2022-11-09 14:29:53 +00:00
const int result = server - > deserialize_block ( buf , size , false ) ;
2021-08-22 10:20:59 +00:00
if ( result ! = 0 ) {
LOGWARN ( 3 , " peer " < < static_cast < char * > ( m_addrString ) < < " sent an invalid block, error " < < result ) ;
return false ;
}
2022-04-23 09:29:17 +00:00
if ( m_chainTipBlockRequest ) {
m_chainTipBlockRequest = false ;
2022-07-10 08:24:03 +00:00
const uint64_t peer_height = server - > get_block ( ) - > m_txinGenHeight ;
2022-04-23 09:29:17 +00:00
const uint64_t our_height = server - > m_pool - > miner_data ( ) . height ;
if ( peer_height + 2 < our_height ) {
LOGWARN ( 4 , " peer " < < static_cast < char * > ( m_addrString ) < < " is mining on top of a stale block (mainchain height " < < peer_height < < " , expected >= " < < our_height < < ' ) ' ) ;
return false ;
}
2022-09-13 08:51:15 +00:00
2022-11-01 15:07:13 +00:00
const uint64_t cur_time = seconds_since_epoch ( ) ;
if ( cur_time > = m_nextOutgoingPeerListRequest ) {
server - > send_peer_list_request ( this , cur_time ) ;
}
2022-04-23 09:29:17 +00:00
}
2022-11-02 17:41:16 +00:00
const SideChain & side_chain = server - > m_pool - > side_chain ( ) ;
const uint64_t max_time_delta = side_chain . precalcFinished ( ) ? ( side_chain . block_time ( ) * side_chain . chain_window_size ( ) * 4 ) : 0 ;
return handle_incoming_block_async ( server - > get_block ( ) , max_time_delta ) ;
2021-08-22 10:20:59 +00:00
}
2022-11-09 18:03:58 +00:00
bool P2PServer : : P2PClient : : on_block_broadcast ( const uint8_t * buf , uint32_t size , bool compact )
2021-08-22 10:20:59 +00:00
{
if ( ! size ) {
LOGWARN ( 3 , " peer " < < static_cast < char * > ( m_addrString ) < < " broadcasted an empty block " ) ;
return false ;
}
P2PServer * server = static_cast < P2PServer * > ( m_owner ) ;
MutexLock lock ( server - > m_blockLock ) ;
2022-11-09 18:03:58 +00:00
const int result = server - > deserialize_block ( buf , size , compact ) ;
2021-08-22 10:20:59 +00:00
if ( result ! = 0 ) {
LOGWARN ( 3 , " peer " < < static_cast < char * > ( m_addrString ) < < " sent an invalid block, error " < < result ) ;
return false ;
}
2022-07-10 08:24:03 +00:00
const PoolBlock * block = server - > get_block ( ) ;
m_broadcastedHashes [ m_broadcastedHashesIndex . fetch_add ( 1 ) % array_size ( & P2PClient : : m_broadcastedHashes ) ] = block - > m_sidechainId ;
2021-08-22 10:20:59 +00:00
2022-04-08 21:14:08 +00:00
MinerData miner_data = server - > m_pool - > miner_data ( ) ;
2021-08-31 21:11:58 +00:00
2022-07-10 08:24:03 +00:00
if ( block - > m_prevId ! = miner_data . prev_id ) {
2021-08-24 15:19:10 +00:00
// This peer is mining on top of a different Monero block, investigate it
2022-07-10 08:24:03 +00:00
const uint64_t peer_height = block - > m_txinGenHeight ;
2021-08-31 21:11:58 +00:00
const uint64_t our_height = miner_data . height ;
2021-08-24 15:19:10 +00:00
if ( peer_height < our_height ) {
if ( our_height - peer_height < 5 ) {
2021-08-31 07:58:57 +00:00
using namespace std : : chrono ;
2022-03-23 14:49:24 +00:00
const int64_t elapsed_ms = duration_cast < milliseconds > ( high_resolution_clock : : now ( ) - miner_data . time_received ) . count ( ) ;
2021-09-13 17:25:12 +00:00
if ( our_height - peer_height > 1 ) {
2021-08-31 07:58:57 +00:00
LOGWARN ( 5 , " peer " < < static_cast < char * > ( m_addrString ) < < " broadcasted a stale block ( " < < elapsed_ms < < " ms late, mainchain height " < < peer_height < < " , expected >= " < < our_height < < " ), ignoring it " ) ;
return true ;
}
else {
LOGINFO ( 5 , " peer " < < static_cast < char * > ( m_addrString ) < < " broadcasted a stale block ( " < < elapsed_ms < < " ms late, mainchain height " < < peer_height < < " , expected >= " < < our_height < < " ) " ) ;
}
2021-08-24 15:19:10 +00:00
}
else {
2022-04-23 09:29:17 +00:00
LOGWARN ( 4 , " peer " < < static_cast < char * > ( m_addrString ) < < " broadcasted an unreasonably stale block (mainchain height " < < peer_height < < " , expected >= " < < our_height < < ' ) ' ) ;
2021-08-24 15:19:10 +00:00
return false ;
}
}
else if ( peer_height > our_height ) {
2021-08-24 18:10:16 +00:00
if ( peer_height > = our_height + 2 ) {
2021-10-06 13:22:03 +00:00
LOGWARN ( 3 , " peer " < < static_cast < char * > ( m_addrString ) < < " is ahead on mainchain (height " < < peer_height < < " , your height " < < our_height < < " ). Is your monerod stuck or lagging? " ) ;
2021-08-24 18:10:16 +00:00
}
2021-08-24 15:19:10 +00:00
}
else {
2021-09-08 18:57:22 +00:00
LOGINFO ( 4 , " peer " < < static_cast < char * > ( m_addrString ) < < " is mining on an alternative mainchain tip (height " < < peer_height < < " ) " ) ;
2021-08-24 15:19:10 +00:00
}
2021-08-22 10:20:59 +00:00
}
2022-07-10 08:24:03 +00:00
block - > m_wantBroadcast = true ;
2021-08-22 10:20:59 +00:00
2022-03-23 10:30:38 +00:00
m_lastBroadcastTimestamp = seconds_since_epoch ( ) ;
2021-09-13 12:26:52 +00:00
2022-11-02 17:41:16 +00:00
return handle_incoming_block_async ( block , 1800 ) ;
2021-08-22 10:20:59 +00:00
}
bool P2PServer : : P2PClient : : on_peer_list_request ( const uint8_t * )
{
P2PServer * server = static_cast < P2PServer * > ( m_owner ) ;
2022-03-23 10:30:38 +00:00
const uint64_t cur_time = seconds_since_epoch ( ) ;
2022-11-09 18:03:58 +00:00
const bool first = ( m_prevIncomingPeerListRequest = = 0 ) ;
2022-02-21 15:54:53 +00:00
// Allow peer list requests no more than once every 30 seconds
2022-03-23 10:30:38 +00:00
if ( cur_time - m_prevIncomingPeerListRequest < 30 ) {
2022-02-22 10:06:12 +00:00
+ + m_fastPeerListRequestCount ;
if ( m_fastPeerListRequestCount > = 3 ) {
2022-06-09 07:20:24 +00:00
LOGWARN ( 4 , " peer " < < static_cast < char * > ( m_addrString ) < < " is sending PEER_LIST_REQUEST too often " ) ;
2022-02-22 10:06:12 +00:00
return false ;
}
2022-02-21 15:54:53 +00:00
}
m_prevIncomingPeerListRequest = cur_time ;
2021-08-22 10:20:59 +00:00
Peer peers [ PEER_LIST_RESPONSE_MAX_PEERS ] ;
uint32_t num_selected_peers = 0 ;
{
MutexLock lock ( server - > m_clientsListLock ) ;
// Send every 4th peer on average, selected at random
2021-10-15 09:32:01 +00:00
const uint32_t peers_to_send_target = std : : min < uint32_t > ( PEER_LIST_RESPONSE_MAX_PEERS , std : : max < uint32_t > ( 1 , server - > m_numConnections / 4 ) ) ;
uint32_t n = 0 ;
2021-08-22 10:20:59 +00:00
for ( P2PClient * client = static_cast < P2PClient * > ( server - > m_connectedClientsList - > m_next ) ; client ! = server - > m_connectedClientsList ; client = static_cast < P2PClient * > ( client - > m_next ) ) {
2022-08-31 14:37:33 +00:00
if ( ! client - > is_good ( ) | | ( client - > m_addr = = m_addr ) ) {
2021-08-22 10:20:59 +00:00
continue ;
}
2021-10-15 09:32:01 +00:00
const Peer p { client - > m_isV6 , client - > m_addr , client - > m_listenPort , 0 , 0 } ;
+ + n ;
2021-08-22 10:20:59 +00:00
2021-10-15 09:32:01 +00:00
// Use https://en.wikipedia.org/wiki/Reservoir_sampling algorithm
if ( num_selected_peers < peers_to_send_target ) {
peers [ num_selected_peers + + ] = p ;
continue ;
}
2021-08-22 10:20:59 +00:00
2021-10-15 09:32:01 +00:00
uint64_t k ;
umul128 ( server - > get_random64 ( ) , n , & k ) ;
if ( k < peers_to_send_target ) {
peers [ k ] = p ;
2021-08-22 10:20:59 +00:00
}
}
}
2022-11-09 18:03:58 +00:00
// Protocol version message:
// - IPv4 address = 255.255.255.255
// - port = 65535
// - first 12 bytes of the 16-byte raw IP address are ignored by older clients if it's IPv4
// - use first 4 bytes of the 16-byte raw IP address to send supported protocol version
if ( first ) {
LOGINFO ( 5 , " sending protocol version " < < ( SUPPORTED_PROTOCOL_VERSION > > 16 ) < < ' . ' < < ( SUPPORTED_PROTOCOL_VERSION & 0xFFFF ) < < " to peer " < < log : : Gray ( ) < < static_cast < char * > ( m_addrString ) ) ;
peers [ 0 ] = { } ;
* reinterpret_cast < uint32_t * > ( peers [ 0 ] . m_addr . data ) = SUPPORTED_PROTOCOL_VERSION ;
* reinterpret_cast < uint32_t * > ( peers [ 0 ] . m_addr . data + 12 ) = 0xFFFFFFFFU ;
peers [ 0 ] . m_port = 0xFFFF ;
if ( num_selected_peers = = 0 ) {
num_selected_peers = 1 ;
}
}
2021-08-22 10:20:59 +00:00
return server - > send ( this ,
2022-09-13 09:12:08 +00:00
[ this , & peers , num_selected_peers ] ( void * buf , size_t buf_size ) - > size_t
2021-08-22 10:20:59 +00:00
{
2022-09-13 09:12:08 +00:00
LOGINFO ( 5 , " sending PEER_LIST_RESPONSE to " < < static_cast < char * > ( m_addrString ) ) ;
2022-05-04 13:53:01 +00:00
if ( buf_size < SEND_BUF_MIN_SIZE + 2 + num_selected_peers * 19 ) {
return 0 ;
}
2021-08-22 10:20:59 +00:00
uint8_t * p0 = reinterpret_cast < uint8_t * > ( buf ) ;
uint8_t * p = p0 ;
* ( p + + ) = static_cast < uint8_t > ( MessageId : : PEER_LIST_RESPONSE ) ;
* ( p + + ) = static_cast < uint8_t > ( num_selected_peers ) ;
// 19 bytes per peer
for ( uint32_t i = 0 ; i < num_selected_peers ; + + i ) {
const Peer & peer = peers [ i ] ;
* ( p + + ) = peer . m_isV6 ? 1 : 0 ;
memcpy ( p , peer . m_addr . data , sizeof ( peer . m_addr . data ) ) ;
p + = sizeof ( peer . m_addr . data ) ;
memcpy ( p , & peer . m_port , 2 ) ;
p + = 2 ;
}
return p - p0 ;
} ) ;
}
2022-11-09 18:03:58 +00:00
bool P2PServer : : P2PClient : : on_peer_list_response ( const uint8_t * buf )
2021-08-22 10:20:59 +00:00
{
P2PServer * server = static_cast < P2PServer * > ( m_owner ) ;
2022-03-23 10:30:38 +00:00
const uint64_t cur_time = seconds_since_epoch ( ) ;
2021-08-22 10:20:59 +00:00
MutexLock lock ( server - > m_peerListLock ) ;
const uint32_t num_peers = * ( buf + + ) ;
for ( uint32_t i = 0 ; i < num_peers ; + + i ) {
2022-11-08 15:23:31 +00:00
bool is_v6 = * ( buf + + ) ! = 0 ;
2021-08-22 10:20:59 +00:00
raw_ip ip ;
memcpy ( ip . data , buf , sizeof ( ip . data ) ) ;
buf + = sizeof ( ip . data ) ;
2022-11-09 18:03:58 +00:00
int port = 0 ;
memcpy ( & port , buf , 2 ) ;
buf + = 2 ;
2022-11-08 15:23:31 +00:00
// Treat IPv4-mapped addresses as regular IPv4 addresses
if ( is_v6 & & ip . is_ipv4_prefix ( ) ) {
is_v6 = false ;
}
2021-10-21 13:55:00 +00:00
if ( ! is_v6 ) {
2022-11-08 15:23:31 +00:00
const uint32_t b = ip . data [ 12 ] ;
if ( ( b = = 0 ) | | ( b > = 224 ) ) {
// Ignore 0.0.0.0/8 (special-purpose range for "this network") and 224.0.0.0/3 (IP multicast and reserved ranges)
2022-11-09 18:03:58 +00:00
// Check for protocol version message
if ( ( * reinterpret_cast < uint32_t * > ( ip . data + 12 ) = = 0xFFFFFFFFU ) & & ( port = = 0xFFFF ) ) {
m_protocolVersion = * reinterpret_cast < uint32_t * > ( ip . data ) ;
LOGINFO ( 5 , " peer " < < log : : Gray ( ) < < static_cast < char * > ( m_addrString ) < < log : : NoColor ( ) < < " supports protocol version " < < ( m_protocolVersion > > 16 ) < < ' . ' < < ( m_protocolVersion & 0xFFFF ) ) ;
}
2022-11-08 15:23:31 +00:00
continue ;
}
// Fill in default bytes for IPv4 addresses
2021-10-21 13:55:00 +00:00
memset ( ip . data , 0 , 10 ) ;
ip . data [ 10 ] = 0xFF ;
ip . data [ 11 ] = 0xFF ;
}
2021-08-22 10:20:59 +00:00
bool already_added = false ;
2021-10-15 09:32:01 +00:00
for ( Peer & p : server - > m_peerList ) {
2021-08-22 10:20:59 +00:00
if ( ( p . m_isV6 = = is_v6 ) & & ( p . m_addr = = ip ) ) {
already_added = true ;
2021-10-15 09:32:01 +00:00
p . m_lastSeen = cur_time ;
2021-08-22 10:20:59 +00:00
break ;
}
}
2021-08-27 14:36:06 +00:00
if ( ! already_added & & ! server - > is_banned ( ip ) ) {
2021-10-15 09:32:01 +00:00
server - > m_peerList . emplace_back ( Peer { is_v6 , ip , port , 0 , cur_time } ) ;
2021-08-22 10:20:59 +00:00
}
}
return true ;
}
2022-11-02 17:41:16 +00:00
bool P2PServer : : P2PClient : : handle_incoming_block_async ( const PoolBlock * block , uint64_t max_time_delta )
2021-08-22 10:20:59 +00:00
{
P2PServer * server = static_cast < P2PServer * > ( m_owner ) ;
2022-11-03 14:20:38 +00:00
SideChain & side_chain = server - > m_pool - > side_chain ( ) ;
2021-08-22 10:20:59 +00:00
2022-11-02 17:41:16 +00:00
// Limit system clock difference between connected peers
2022-11-03 15:14:56 +00:00
// Check only new blocks (not added to side_chain yet)
if ( max_time_delta & & ! side_chain . find_block ( block - > m_sidechainId ) ) {
2022-11-03 12:52:29 +00:00
static hash prev_checked_block ;
2022-11-03 15:14:56 +00:00
const bool is_new = ( block - > m_sidechainId ! = prev_checked_block ) ;
prev_checked_block = block - > m_sidechainId ;
2022-11-03 14:20:38 +00:00
2022-11-03 15:14:56 +00:00
const uint64_t t = time ( nullptr ) ;
const uint32_t failed = ( ( block - > m_timestamp + max_time_delta < t ) | | ( block - > m_timestamp > t + max_time_delta ) ) ? 1 : 0 ;
2022-11-02 17:41:16 +00:00
2022-11-03 15:14:56 +00:00
static uint32_t failed_history = 0 ;
if ( is_new ) {
2022-11-03 12:52:29 +00:00
failed_history = ( failed_history < < 1 ) | failed ;
2022-11-03 15:14:56 +00:00
}
2022-11-02 17:41:16 +00:00
2022-11-03 15:14:56 +00:00
if ( failed ) {
if ( is_new ) {
2022-11-03 20:19:48 +00:00
int64_t dt = static_cast < int64_t > ( block - > m_timestamp - t ) ;
char sign = ' + ' ;
if ( dt < 0 ) {
sign = ' - ' ;
dt = - dt ;
}
2022-11-03 12:52:29 +00:00
LOGWARN ( 4 , " peer " < < static_cast < char * > ( m_addrString )
2022-11-03 15:14:56 +00:00
< < " sent a block " < < block - > m_sidechainId < < " (mined by " < < block - > m_minerWallet < < " ) with an invalid timestamp " < < block - > m_timestamp
2022-11-03 20:19:48 +00:00
< < " ( " < < sign < < dt < < " seconds) " ) ;
2022-11-03 12:52:29 +00:00
uint32_t failed_checks = 0 ;
for ( uint32_t k = 1 ; k ! = 0 ; k < < = 1 ) {
if ( failed_history & k ) {
+ + failed_checks ;
}
}
if ( failed_checks > 16 ) {
2022-11-03 20:19:48 +00:00
LOGWARN ( 1 , " Your system clock might be invalid: " < < failed_checks < < " of 32 last blocks were rejected due to high timestamp diff " ) ;
2022-11-03 12:52:29 +00:00
}
}
2022-11-03 15:14:56 +00:00
return true ;
2022-11-02 17:41:16 +00:00
}
}
2022-11-03 14:20:38 +00:00
if ( side_chain . block_seen ( * block ) ) {
2022-11-02 11:49:12 +00:00
LOGINFO ( 6 , " block " < < block - > m_sidechainId < < " (nonce " < < block - > m_nonce < < " , extra_nonce " < < block - > m_extraNonce < < " ) was received before, skipping it " ) ;
2021-08-22 10:20:59 +00:00
return true ;
}
struct Work
{
uv_work_t req ;
PoolBlock block ;
P2PClient * client ;
P2PServer * server ;
uint32_t client_reset_counter ;
2021-08-31 11:14:35 +00:00
raw_ip client_ip ;
2021-08-22 10:20:59 +00:00
std : : vector < hash > missing_blocks ;
} ;
2021-08-31 11:14:35 +00:00
Work * work = new Work { { } , * block , this , server , m_resetCounter . load ( ) , m_addr , { } } ;
2021-08-22 10:20:59 +00:00
work - > req . data = work ;
const int err = uv_queue_work ( & server - > m_loop , & work - > req ,
[ ] ( uv_work_t * req )
{
2022-11-04 09:14:49 +00:00
BACKGROUND_JOB_START ( P2PServer : : handle_incoming_block_async ) ;
2021-08-22 10:20:59 +00:00
Work * work = reinterpret_cast < Work * > ( req - > data ) ;
2021-08-31 11:14:35 +00:00
work - > client - > handle_incoming_block ( work - > server - > m_pool , work - > block , work - > client_reset_counter , work - > client_ip , work - > missing_blocks ) ;
2021-08-22 10:20:59 +00:00
} ,
[ ] ( uv_work_t * req , int /*status*/ )
{
Work * work = reinterpret_cast < Work * > ( req - > data ) ;
work - > client - > post_handle_incoming_block ( work - > client_reset_counter , work - > missing_blocks ) ;
delete work ;
2022-11-04 09:14:49 +00:00
BACKGROUND_JOB_STOP ( P2PServer : : handle_incoming_block_async ) ;
2021-08-22 10:20:59 +00:00
} ) ;
if ( err ! = 0 ) {
LOGERR ( 1 , " handle_incoming_block_async: uv_queue_work failed, error " < < uv_err_name ( err ) ) ;
delete work ;
return false ;
}
return true ;
}
2021-08-31 11:14:35 +00:00
void P2PServer : : P2PClient : : handle_incoming_block ( p2pool * pool , PoolBlock & block , const uint32_t reset_counter , const raw_ip & addr , std : : vector < hash > & missing_blocks )
2021-08-22 10:20:59 +00:00
{
if ( ! pool - > side_chain ( ) . add_external_block ( block , missing_blocks ) ) {
// Client sent bad data, disconnect and ban it
if ( reset_counter = = m_resetCounter . load ( ) ) {
close ( ) ;
2021-08-31 11:14:35 +00:00
LOGWARN ( 3 , " peer " < < static_cast < char * > ( m_addrString ) < < " banned for " < < DEFAULT_BAN_TIME < < " seconds " ) ;
2021-08-22 10:20:59 +00:00
}
2021-08-31 11:14:35 +00:00
else {
const log : : hex_buf addr_hex ( addr . data , sizeof ( addr . data ) ) ;
LOGWARN ( 3 , " IP " < < addr_hex < < " banned for " < < DEFAULT_BAN_TIME < < " seconds " ) ;
}
P2PServer * server = pool - > p2p_server ( ) ;
server - > ban ( addr , DEFAULT_BAN_TIME ) ;
server - > remove_peer_from_list ( addr ) ;
2021-08-22 10:20:59 +00:00
}
}
void P2PServer : : P2PClient : : post_handle_incoming_block ( const uint32_t reset_counter , std : : vector < hash > & missing_blocks )
{
// We might have been disconnected while side_chain was adding the block
// In this case we can't send BLOCK_REQUEST messages on this connection anymore
if ( reset_counter ! = m_resetCounter . load ( ) ) {
return ;
}
2021-08-24 09:42:41 +00:00
if ( missing_blocks . empty ( ) ) {
return ;
}
P2PServer * server = static_cast < P2PServer * > ( m_owner ) ;
2022-09-13 08:51:15 +00:00
// If the initial sync is not finished yet, try to ask the fastest peer too
P2PClient * c = server - > m_fastestPeer ;
if ( c & & ( c ! = this ) & & ! server - > m_pool - > side_chain ( ) . precalcFinished ( ) ) {
2022-09-13 09:12:08 +00:00
LOGINFO ( 5 , " peer " < < static_cast < char * > ( c - > m_addrString ) < < " is faster, sending BLOCK_REQUEST to it too " ) ;
2022-09-13 08:51:15 +00:00
c - > post_handle_incoming_block ( c - > m_resetCounter . load ( ) , missing_blocks ) ;
}
2021-08-24 09:42:41 +00:00
ReadLock lock ( server - > m_cachedBlocksLock ) ;
2021-08-22 10:20:59 +00:00
for ( const hash & id : missing_blocks ) {
2022-03-24 17:30:23 +00:00
if ( server - > m_cachedBlocks ) {
auto it = server - > m_cachedBlocks - > find ( id ) ;
if ( it ! = server - > m_cachedBlocks - > end ( ) ) {
LOGINFO ( 5 , " using cached block for id = " < < id ) ;
handle_incoming_block_async ( it - > second ) ;
continue ;
}
2021-08-24 09:42:41 +00:00
}
2022-09-13 08:51:15 +00:00
const bool result = server - > send ( this ,
2022-09-13 09:12:08 +00:00
[ this , & id ] ( void * buf , size_t buf_size ) - > size_t
2021-08-22 10:20:59 +00:00
{
2022-09-13 09:12:08 +00:00
LOGINFO ( 5 , " sending BLOCK_REQUEST for id = " < < id < < " to " < < static_cast < char * > ( m_addrString ) ) ;
2022-05-04 13:53:01 +00:00
if ( buf_size < SEND_BUF_MIN_SIZE + 1 + HASH_SIZE ) {
return 0 ;
}
2021-08-22 10:20:59 +00:00
uint8_t * p0 = reinterpret_cast < uint8_t * > ( buf ) ;
uint8_t * p = p0 ;
* ( p + + ) = static_cast < uint8_t > ( MessageId : : BLOCK_REQUEST ) ;
memcpy ( p , id . h , HASH_SIZE ) ;
p + = HASH_SIZE ;
return p - p0 ;
} ) ;
if ( ! result ) {
return ;
}
2022-02-21 15:54:53 +00:00
+ + m_blockPendingRequests ;
2021-08-22 10:20:59 +00:00
}
}
} // namespace p2pool