2021-08-22 04:20:59 -06:00
/*
* This file is part of the Monero P2Pool < https : //github.com/SChernykh/p2pool>
2022-03-30 06:42:26 -06:00
* Copyright ( c ) 2021 - 2022 SChernykh < https : //github.com/SChernykh>
2021-08-22 04:20:59 -06: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 03:42:41 -06:00
# include "block_cache.h"
2022-02-17 12:03:47 -07:00
# include "json_rpc_request.h"
# include "json_parsers.h"
# include <rapidjson/document.h>
2021-08-22 04:20:59 -06: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 03:10:18 -07:00
static const char * seed_nodes [ ] = { " seeds.p2pool.io " , " " } ;
static const char * seed_nodes_mini [ ] = { " seeds-mini.p2pool.io " , " " } ;
2021-08-22 04:20:59 -06:00
static constexpr int DEFAULT_BACKLOG = 16 ;
static constexpr uint64_t DEFAULT_BAN_TIME = 600 ;
2022-05-04 07:53:01 -06:00
static constexpr size_t SEND_BUF_MIN_SIZE = 256 ;
2021-08-22 04:20:59 -06:00
# include "tcp_server.inl"
namespace p2pool {
P2PServer : : P2PServer ( p2pool * pool )
2021-08-26 15:27:05 -06:00
: TCPServer ( P2PClient : : allocate )
2021-08-22 04:20:59 -06:00
, m_pool ( pool )
2021-10-16 05:45:28 -06:00
, m_cache ( pool - > params ( ) . m_blockCache ? new BlockCache ( ) : nullptr )
2021-08-24 03:42:41 -06:00
, m_cacheLoaded ( false )
2021-09-07 04:56:22 -06:00
, m_initialPeerList ( pool - > params ( ) . m_p2pPeerList )
2022-03-24 11:30:23 -06:00
, m_cachedBlocks ( nullptr )
2022-03-17 09:14:29 -06:00
, m_rng ( RandomDeviceSeed : : instance )
2021-08-22 04:20:59 -06:00
, m_block ( new PoolBlock ( ) )
, m_timer { }
2021-10-08 10:02:04 -06:00
, m_timerCounter ( 0 )
2022-02-21 10:41:36 -07:00
, m_timerInterval ( 2 )
2021-08-22 04:20:59 -06:00
, m_peerListLastSaved ( 0 )
{
2022-03-17 09:14:29 -06:00
// Diffuse the initial state in case it has low quality
m_rng . discard ( 10000 ) ;
m_peerId = m_rng ( ) ;
2022-04-07 11:11:20 -06:00
const Params & params = pool - > params ( ) ;
set_max_outgoing_peers ( params . m_maxOutgoingPeers ) ;
set_max_incoming_peers ( params . m_maxIncomingPeers ) ;
2021-12-26 07:28:33 -07:00
2021-08-22 04:20:59 -06: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-27 09:26:42 -06:00
uv_mutex_init_checked ( & m_missingBlockRequestsLock ) ;
2021-08-24 03:42:41 -06:00
uv_rwlock_init_checked ( & m_cachedBlocksLock ) ;
2021-08-22 04:20:59 -06: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 07:46:15 -06:00
panic ( ) ;
2021-08-22 04:20:59 -06:00
}
m_broadcastAsync . data = this ;
m_broadcastQueue . reserve ( 2 ) ;
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 03:42:41 -06:00
if ( m_cache ) {
WriteLock lock ( m_cachedBlocksLock ) ;
m_cache - > load_all ( m_pool - > side_chain ( ) , * this ) ;
m_cacheLoaded = true ;
}
2021-08-22 04:20:59 -06:00
m_timer . data = this ;
2022-02-21 10:41:36 -07:00
err = uv_timer_start ( & m_timer , on_timer , 1000 , m_timerInterval * 1000 ) ;
2021-08-22 04:20:59 -06:00
if ( err ) {
LOGERR ( 1 , " failed to start timer, error " < < uv_err_name ( err ) ) ;
panic ( ) ;
}
2021-09-07 13:30:52 -06:00
load_peer_list ( ) ;
2022-04-07 11:11:20 -06:00
start_listening ( params . m_p2pAddresses ) ;
2021-08-22 04:20:59 -06:00
}
P2PServer : : ~ P2PServer ( )
{
uv_timer_stop ( & m_timer ) ;
2021-10-21 11:10:11 -06:00
uv_close ( reinterpret_cast < uv_handle_t * > ( & m_timer ) , nullptr ) ;
2021-08-22 04:20:59 -06:00
uv_close ( reinterpret_cast < uv_handle_t * > ( & m_broadcastAsync ) , nullptr ) ;
shutdown_tcp ( ) ;
uv_mutex_destroy ( & m_rngLock ) ;
uv_mutex_destroy ( & m_blockLock ) ;
uv_mutex_destroy ( & m_peerListLock ) ;
uv_mutex_destroy ( & m_broadcastLock ) ;
2021-08-27 09:26:42 -06:00
uv_mutex_destroy ( & m_missingBlockRequestsLock ) ;
2021-10-01 07:21:32 -06:00
clear_cached_blocks ( ) ;
2021-08-24 03:42:41 -06:00
uv_rwlock_destroy ( & m_cachedBlocksLock ) ;
2021-08-22 04:20:59 -06:00
delete m_block ;
2021-08-24 03:42:41 -06:00
delete m_cache ;
2022-06-07 11:40:13 -06:00
for ( const Broadcast * data : m_broadcastQueue ) {
delete data ;
}
2021-08-24 03:42:41 -06: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 11:30:23 -06: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 03:42:41 -06:00
}
2021-10-01 07:21:32 -06:00
void P2PServer : : clear_cached_blocks ( )
{
2022-03-24 11:30:23 -06:00
if ( ! m_cachedBlocks ) {
return ;
}
2021-10-01 07:21:32 -06:00
WriteLock lock ( m_cachedBlocksLock ) ;
2022-05-26 10:20:29 -06:00
// cppcheck-suppress identicalConditionAfterEarlyExit
2022-03-24 11:30:23 -06:00
if ( ! m_cachedBlocks ) {
return ;
}
for ( auto it : * m_cachedBlocks ) {
2021-10-01 07:21:32 -06:00
delete it . second ;
}
2022-03-24 11:30:23 -06:00
delete m_cachedBlocks ;
m_cachedBlocks = nullptr ;
2021-10-01 07:21:32 -06:00
}
2021-08-24 03:42:41 -06:00
void P2PServer : : store_in_cache ( const PoolBlock & block )
{
2021-08-24 05:46:38 -06:00
if ( m_cache & & block . m_verified & & ! block . m_invalid ) {
2021-08-24 03:42:41 -06:00
m_cache - > store ( block ) ;
}
2021-08-22 04:20:59 -06:00
}
void P2PServer : : connect_to_peers ( const std : : string & peer_list )
{
parse_address_list ( peer_list ,
2021-09-08 12:25:39 -06:00
[ this ] ( bool is_v6 , const std : : string & /*address*/ , std : : string ip , int port )
2021-08-22 04:20:59 -06:00
{
2021-09-08 12:25:39 -06:00
if ( resolve_host ( ip , is_v6 ) ) {
connect_to_peer ( is_v6 , ip . c_str ( ) , port ) ;
}
2021-08-22 04:20:59 -06: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 04:30:38 -06:00
const uint64_t cur_time = seconds_since_epoch ( ) ;
const uint64_t last_updated = m_pool - > side_chain ( ) . last_updated ( ) ;
2021-08-24 13:45:19 -06:00
2022-02-17 12:03:47 -07:00
bool has_good_peers = false ;
2022-04-07 08:48:01 -06:00
unordered_set < raw_ip > connected_clients ;
2021-08-22 04:20:59 -06:00
{
MutexLock lock ( m_clientsListLock ) ;
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-10-15 03:32:01 -06:00
bool disconnected = false ;
2021-08-25 03:14:23 -06:00
2021-09-08 12:36:21 -06:00
const int timeout = client - > m_handshakeComplete ? 300 : 10 ;
2021-08-25 03:14:23 -06:00
if ( cur_time > = client - > m_lastAlive + timeout ) {
2021-08-24 13:45:19 -06: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 ( ) ;
2021-10-15 03:32:01 -06:00
disconnected = true ;
2021-08-24 13:45:19 -06:00
}
2021-09-13 06:26:52 -06:00
if ( client - > m_handshakeComplete & & client - > m_lastBroadcastTimestamp ) {
2022-03-30 14:47:10 -06:00
// - Side chain is at least 15 minutes newer (last_updated >= client->m_lastBroadcastTimestamp + 900)
2021-09-13 06:26:52 -06: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 14:47:10 -06:00
if ( last_updated & & ( cur_time > = std : : max ( last_updated , client - > m_lastBlockrequestTimestamp ) + 10 ) & & ( last_updated > = client - > m_lastBroadcastTimestamp + 900 ) ) {
2022-03-23 04:30:38 -06:00
const uint64_t dt = last_updated - client - > m_lastBroadcastTimestamp ;
2021-09-13 06:26:52 -06: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 ( ) ;
2021-10-15 03:32:01 -06:00
disconnected = true ;
2021-09-13 06:26:52 -06:00
}
}
2021-10-15 03:32:01 -06:00
if ( ! disconnected ) {
2022-04-07 08:48:01 -06:00
connected_clients . insert ( client - > m_addr ) ;
2022-02-17 12:03:47 -07:00
if ( client - > m_handshakeComplete & & ! client - > m_handshakeInvalid & & ( client - > m_listenPort > = 0 ) ) {
has_good_peers = true ;
}
2021-10-15 03:32:01 -06:00
}
2021-08-22 04:20:59 -06:00
}
}
2021-10-15 03:32:01 -06: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 08:48:01 -06:00
if ( connected_clients . find ( p . m_addr ) ! = connected_clients . end ( ) ) {
2021-10-15 03:32:01 -06: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 12:03:47 -07: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 06:59:45 -07: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 12:03:47 -07:00
for ( uint32_t i = m_numConnections - m_numIncomingConnections ; ( i < N ) & & ! peer_list . empty ( ) ; ) {
2021-08-22 04:20:59 -06:00
const uint64_t k = get_random64 ( ) % peer_list . size ( ) ;
const Peer & peer = peer_list [ k ] ;
2022-04-07 08:48:01 -06: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 04:20:59 -06:00
+ + i ;
}
if ( k + 1 < peer_list . size ( ) ) {
peer_list [ k ] = peer_list . back ( ) ;
}
peer_list . pop_back ( ) ;
}
2021-10-08 10:02:04 -06:00
2022-02-17 12:03:47 -07:00
if ( ! has_good_peers & & ( ( m_timerCounter % 30 ) = = 0 ) ) {
2021-10-08 10:02:04 -06:00
LOGERR ( 1 , " no connections to other p2pool nodes, check your monerod/p2pool/network/firewall setup!!! " ) ;
2022-05-11 06:08:36 -06:00
load_peer_list ( ) ;
2022-02-17 12:03:47 -07:00
if ( m_peerListMonero . empty ( ) ) {
load_monerod_peer_list ( ) ;
}
2021-10-08 10:02:04 -06:00
}
2021-08-22 04:20:59 -06:00
}
void P2PServer : : update_peer_list ( )
{
2022-03-23 04:37:05 -06:00
const uint64_t cur_time = seconds_since_epoch ( ) ;
2021-08-22 04:20:59 -06:00
{
MutexLock lock ( m_clientsListLock ) ;
for ( P2PClient * client = static_cast < P2PClient * > ( m_connectedClientsList - > m_next ) ; client ! = m_connectedClientsList ; client = static_cast < P2PClient * > ( client - > m_next ) ) {
if ( ! client - > m_handshakeComplete | | ! client - > m_handshakeSolutionSent ) {
continue ;
}
2022-03-23 04:37:05 -06:00
if ( cur_time > = client - > m_nextOutgoingPeerListRequest ) {
2021-09-02 11:21:38 -06:00
// Send peer list requests at random intervals (60-120 seconds)
2022-03-23 04:37:05 -06:00
client - > m_nextOutgoingPeerListRequest = cur_time + ( 60 + ( get_random64 ( ) % 61 ) ) ;
2021-09-02 11:21:38 -06:00
2021-10-15 09:09:51 -06:00
const bool result = send ( client ,
2022-05-04 07:53:01 -06:00
[ ] ( void * buf , size_t buf_size )
2021-08-22 04:20:59 -06:00
{
LOGINFO ( 5 , " sending PEER_LIST_REQUEST " ) ;
2022-05-04 07:53:01 -06:00
if ( buf_size < SEND_BUF_MIN_SIZE ) {
return 0 ;
}
2021-08-22 04:20:59 -06:00
* reinterpret_cast < uint8_t * > ( buf ) = static_cast < uint8_t > ( MessageId : : PEER_LIST_REQUEST ) ;
return 1 ;
} ) ;
2021-10-15 09:09:51 -06:00
if ( result ) {
2022-02-21 10:46:53 -07:00
client - > m_lastPeerListRequestTime = std : : chrono : : high_resolution_clock : : now ( ) ;
2021-10-15 09:09:51 -06:00
+ + client - > m_peerListPendingRequests ;
}
2021-08-22 04:20:59 -06:00
}
}
}
}
void P2PServer : : save_peer_list_async ( )
{
2022-03-23 04:30:38 -06:00
const uint64_t cur_time = seconds_since_epoch ( ) ;
2021-08-22 04:20:59 -06: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 )
{
2021-08-24 03:42:41 -06:00
bkg_jobs_tracker . start ( " P2PServer::save_peer_list_async " ) ;
2021-08-22 04:20:59 -06:00
reinterpret_cast < Work * > ( req - > data ) - > server - > save_peer_list ( ) ;
} ,
[ ] ( uv_work_t * req , int /*status*/ )
{
delete reinterpret_cast < Work * > ( req - > data ) ;
2021-08-24 03:42:41 -06:00
bkg_jobs_tracker . stop ( " P2PServer::save_peer_list_async " ) ;
2021-08-22 04:20:59 -06:00
} ) ;
if ( err ) {
2021-10-21 02:12:57 -06:00
LOGERR ( 1 , " save_peer_list_async: uv_queue_work failed, error " < < uv_err_name ( err ) ) ;
2021-08-22 04:20:59 -06: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 11:21:38 -06:00
std : : vector < Peer > peer_list ;
2021-08-22 04:20:59 -06:00
{
MutexLock lock ( m_peerListLock ) ;
2021-09-02 11:21:38 -06:00
peer_list = m_peerList ;
}
2021-08-22 04:20:59 -06:00
2021-09-02 11:21:38 -06: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 04:20:59 -06:00
}
2021-09-02 11:21:38 -06: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 04:20:59 -06:00
}
}
}
f . close ( ) ;
2021-09-02 11:21:38 -06:00
LOGINFO ( 5 , " peer list saved ( " < < peer_list . size ( ) < < " peers) " ) ;
2022-03-23 04:30:38 -06:00
m_peerListLastSaved = seconds_since_epoch ( ) ;
2021-08-22 04:20:59 -06:00
}
2021-09-07 13:30:52 -06:00
void P2PServer : : load_peer_list ( )
2021-08-22 04:20:59 -06:00
{
2022-05-11 06:08:36 -06:00
size_t old_size ;
{
MutexLock lock ( m_peerListLock ) ;
old_size = m_peerList . size ( ) ;
}
2021-09-08 12:25:39 -06:00
std : : string saved_list ;
2021-08-22 04:20:59 -06:00
2021-12-30 03:10:18 -07: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 13:30:52 -06:00
addrinfo hints { } ;
hints . ai_family = AF_UNSPEC ;
hints . ai_socktype = SOCK_STREAM ;
2022-05-02 13:24:51 -06:00
hints . ai_flags = AI_ADDRCONFIG ;
2021-09-07 13:30:52 -06:00
addrinfo * result ;
2021-12-30 03:10:18 -07:00
const int err = getaddrinfo ( nodes [ i ] , nullptr , & hints , & result ) ;
2021-09-07 13:30:52 -06: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 12:16:04 -06:00
char buf [ 128 ] ;
2022-05-11 06:08:36 -06:00
buf [ 0 ] = ' \0 ' ;
2021-09-07 13:30:52 -06: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 02:03:06 -06:00
s < < ' [ ' < < addr_str < < " ]: " < < p2p_port < < ' \0 ' ;
2021-09-07 13:30:52 -06: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 02:03:06 -06:00
s < < addr_str < < ' : ' < < p2p_port < < ' \0 ' ;
2021-09-07 13:30:52 -06:00
}
}
if ( s . m_pos ) {
2022-05-10 12:16:04 -06:00
LOGINFO ( 4 , " added " < < static_cast < const char * > ( buf ) < < " from " < < nodes [ i ] ) ;
2021-09-07 13:30:52 -06:00
if ( ! saved_list . empty ( ) ) {
saved_list + = ' , ' ;
}
saved_list + = buf ;
}
}
freeaddrinfo ( result ) ;
}
else {
2021-12-30 03:10:18 -07:00
LOGWARN ( 3 , " getaddrinfo failed for " < < nodes [ i ] < < " : " < < gai_strerror ( err ) ) ;
2021-09-07 13:30:52 -06:00
}
}
2021-12-30 03:10:18 -07:00
} ;
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 13:30:52 -06:00
}
// Finally load peers from p2pool_peers.txt
2021-08-31 03:16:40 -06:00
std : : ifstream f ( saved_peer_list_file_name ) ;
if ( f . is_open ( ) ) {
std : : string address ;
while ( ! f . eof ( ) ) {
std : : getline ( f , address ) ;
if ( ! address . empty ( ) ) {
if ( ! saved_list . empty ( ) ) {
saved_list + = ' , ' ;
}
saved_list + = address ;
2021-08-22 04:20:59 -06:00
}
}
2021-08-31 03:16:40 -06:00
f . close ( ) ;
}
if ( saved_list . empty ( ) ) {
return ;
2021-08-22 04:20:59 -06: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 ;
if ( is_v6 ) {
sockaddr_in6 addr6 ;
const int err = uv_ip6_addr ( ip . c_str ( ) , port , & addr6 ) ;
if ( err ) {
LOGERR ( 1 , " failed to parse IPv6 address " < < ip < < " , error " < < uv_err_name ( err ) ) ;
return ;
}
p . m_isV6 = true ;
memcpy ( p . m_addr . data , & addr6 . sin6_addr , sizeof ( in6_addr ) ) ;
}
else {
sockaddr_in addr4 ;
const int err = uv_ip4_addr ( ip . c_str ( ) , port , & addr4 ) ;
if ( err ) {
LOGERR ( 1 , " failed to parse IPv4 address " < < ip < < " , error " < < uv_err_name ( err ) ) ;
return ;
}
p . m_isV6 = false ;
p . m_addr = { } ;
p . m_addr . data [ 10 ] = 0xFF ;
p . m_addr . data [ 11 ] = 0xFF ;
memcpy ( p . m_addr . data + 12 , & addr4 . sin_addr , sizeof ( in_addr ) ) ;
}
2021-08-23 15:12:52 -06: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 03:32:01 -06:00
p . m_port = port ;
p . m_numFailedConnections = 0 ;
2022-03-23 04:30:38 -06:00
p . m_lastSeen = seconds_since_epoch ( ) ;
2021-10-15 03:32:01 -06:00
2021-08-27 08:36:06 -06:00
if ( ! already_added & & ! is_banned ( p . m_addr ) ) {
2021-08-23 15:12:52 -06:00
m_peerList . push_back ( p ) ;
}
2021-08-22 04:20:59 -06:00
} ) ;
2021-08-31 03:16:40 -06:00
2022-02-17 12:03:47 -07: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-06-04 05:16:05 -06:00
JSONRPCRequest : : call ( params . m_host , params . m_rpcPort , " /get_peer_list " , params . m_rpcLogin ,
2022-02-17 12:03:47 -07:00
[ this ] ( const char * data , size_t size )
{
2022-05-10 12:16:04 -06:00
# define ERR_STR " / get_peer_list RPC request returned invalid JSON "
2022-02-17 12:03:47 -07:00
using namespace rapidjson ;
Document doc ;
if ( doc . Parse ( data , size ) . HasParseError ( ) ) {
2022-05-10 12:16:04 -06:00
LOGWARN ( 4 , ERR_STR " (parse error) " ) ;
2022-02-17 12:03:47 -07:00
return ;
}
if ( ! doc . IsObject ( ) ) {
2022-05-10 12:16:04 -06:00
LOGWARN ( 4 , ERR_STR " (not an object) " ) ;
2022-02-17 12:03:47 -07:00
return ;
}
if ( ! doc . HasMember ( " white_list " ) ) {
2022-05-10 12:16:04 -06:00
LOGWARN ( 4 , ERR_STR " ('white_list' not found) " ) ;
2022-02-17 12:03:47 -07:00
return ;
}
const auto & white_list = doc [ " white_list " ] ;
if ( ! white_list . IsArray ( ) ) {
2022-05-10 12:16:04 -06:00
LOGWARN ( 4 , ERR_STR " ('white_list' is not an array) " ) ;
2022-02-17 12:03:47 -07:00
return ;
}
2022-05-10 12:16:04 -06:00
# undef ERR_STR
2022-02-17 12:03:47 -07: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 ;
if ( strchr ( ip , ' : ' ) ) {
sockaddr_in6 addr6 ;
const int err = uv_ip6_addr ( ip , port , & addr6 ) ;
if ( err ) {
continue ;
}
p . m_isV6 = true ;
memcpy ( p . m_addr . data , & addr6 . sin6_addr , sizeof ( in6_addr ) ) ;
}
else {
sockaddr_in addr4 ;
const int err = uv_ip4_addr ( ip , port , & addr4 ) ;
if ( err ) {
continue ;
}
p . m_isV6 = false ;
p . m_addr = { } ;
p . m_addr . data [ 10 ] = 0xFF ;
p . m_addr . data [ 11 ] = 0xFF ;
memcpy ( p . m_addr . data + 12 , & addr4 . sin_addr , sizeof ( in_addr ) ) ;
}
p . m_port = port ;
p . m_numFailedConnections = 0 ;
if ( ! is_banned ( p . m_addr ) ) {
m_peerListMonero . push_back ( p ) ;
}
}
// Put recently active peers first in the list
std : : sort ( m_peerListMonero . begin ( ) , m_peerListMonero . end ( ) , [ ] ( const Peer & a , const Peer & b ) { return a . m_lastSeen > b . m_lastSeen ; } ) ;
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 04:20:59 -06:00
}
void P2PServer : : update_peer_in_list ( bool is_v6 , const raw_ip & ip , int port )
{
2022-03-23 04:30:38 -06:00
const uint64_t cur_time = seconds_since_epoch ( ) ;
2021-10-15 03:32:01 -06:00
2021-08-22 04:20:59 -06: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 03:32:01 -06:00
p . m_lastSeen = cur_time ;
2021-08-22 04:20:59 -06:00
return ;
}
}
2021-08-27 08:36:06 -06:00
if ( ! is_banned ( ip ) ) {
2021-10-15 03:32:01 -06:00
m_peerList . emplace_back ( Peer { is_v6 , ip , port , 0 , cur_time } ) ;
2021-08-27 08:36:06 -06:00
}
2021-08-22 04:20:59 -06: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 05:14:35 -06: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 ;
}
}
}
2021-08-22 04:20:59 -06:00
void P2PServer : : broadcast ( const PoolBlock & block )
{
2022-04-08 15:14:08 -06:00
MinerData miner_data = m_pool - > miner_data ( ) ;
2022-04-07 11:11:20 -06: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 15:41:05 -06:00
return ;
}
2022-04-07 11:11:20 -06: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 07:48:05 -06:00
return ;
}
2021-08-31 15:41:05 -06:00
Broadcast * data = new Broadcast ( ) ;
2021-08-22 04:20:59 -06:00
data - > blob . reserve ( block . m_mainChainData . size ( ) + block . m_sideChainData . size ( ) ) ;
data - > blob = block . m_mainChainData ;
data - > blob . insert ( data - > blob . end ( ) , block . m_sideChainData . begin ( ) , block . m_sideChainData . end ( ) ) ;
data - > pruned_blob . reserve ( block . m_mainChainData . size ( ) + block . m_sideChainData . size ( ) + 16 - block . m_mainChainOutputsBlobSize ) ;
data - > pruned_blob . assign ( block . m_mainChainData . begin ( ) , block . m_mainChainData . begin ( ) + block . m_mainChainOutputsOffset ) ;
// 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 ) ;
writeVarint ( block . m_mainChainOutputsBlobSize , data - > pruned_blob ) ;
data - > pruned_blob . insert ( data - > pruned_blob . end ( ) , block . m_mainChainData . begin ( ) + block . m_mainChainOutputsOffset + block . m_mainChainOutputsBlobSize , block . m_mainChainData . end ( ) ) ;
data - > pruned_blob . insert ( data - > pruned_blob . end ( ) , block . m_sideChainData . begin ( ) , block . m_sideChainData . end ( ) ) ;
data - > ancestor_hashes . reserve ( block . m_uncles . size ( ) + 1 ) ;
data - > ancestor_hashes = block . m_uncles ;
data - > ancestor_hashes . push_back ( block . m_parent ) ;
2021-08-24 03:42:41 -06:00
LOGINFO ( 5 , " Broadcasting block " < < block . m_sidechainId < < " (height " < < block . m_sidechainHeight < < " ): " < < data - > pruned_blob . size ( ) < < ' / ' < < data - > blob . size ( ) < < " bytes (pruned/full) " ) ;
2021-08-22 04:20:59 -06:00
{
MutexLock lock ( m_broadcastLock ) ;
m_broadcastQueue . push_back ( data ) ;
}
2021-08-23 15:09:59 -06:00
if ( uv_is_closing ( reinterpret_cast < uv_handle_t * > ( & m_broadcastAsync ) ) ) {
return ;
}
2021-08-22 04:20:59 -06: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 11:40:13 -06:00
for ( const Broadcast * data : broadcast_queue ) {
2021-08-22 04:20:59 -06: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 ) ) {
if ( ! client - > m_handshakeComplete | | ! client - > m_handshakeSolutionSent ) {
continue ;
}
for ( Broadcast * data : broadcast_queue ) {
2022-05-04 07:53:01 -06:00
send ( client , [ client , data ] ( void * buf , size_t buf_size ) - > size_t
{
2021-08-22 04:20:59 -06:00
uint8_t * p0 = reinterpret_cast < uint8_t * > ( buf ) ;
uint8_t * p = p0 ;
bool send_pruned = true ;
2021-10-17 02:48:09 -06: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 ;
break ;
2021-08-22 04:20:59 -06:00
}
}
if ( send_pruned ) {
2021-10-06 01:47:41 -06:00
LOGINFO ( 6 , " sending BLOCK_BROADCAST (pruned) to " < < log : : Gray ( ) < < static_cast < char * > ( client - > m_addrString ) ) ;
2021-08-22 04:20:59 -06:00
2022-04-08 14:34:37 -06:00
const uint32_t len = static_cast < uint32_t > ( data - > pruned_blob . size ( ) ) ;
2022-05-04 07:53:01 -06: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 14:34:37 -06:00
memcpy ( p , & len , sizeof ( uint32_t ) ) ;
2021-08-22 04:20:59 -06:00
p + = sizeof ( uint32_t ) ;
2022-04-08 14:34:37 -06:00
if ( len ) {
memcpy ( p , data - > pruned_blob . data ( ) , len ) ;
p + = len ;
}
2021-08-22 04:20:59 -06:00
}
else {
LOGINFO ( 5 , " sending BLOCK_BROADCAST (full) to " < < log : : Gray ( ) < < static_cast < char * > ( client - > m_addrString ) ) ;
2022-04-08 14:34:37 -06:00
const uint32_t len = static_cast < uint32_t > ( data - > blob . size ( ) ) ;
2022-05-04 07:53:01 -06: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 14:34:37 -06:00
memcpy ( p , & len , sizeof ( uint32_t ) ) ;
2021-08-22 04:20:59 -06:00
p + = sizeof ( uint32_t ) ;
2022-04-08 14:34:37 -06:00
if ( len ) {
memcpy ( p , data - > blob . data ( ) , len ) ;
p + = len ;
}
2021-08-22 04:20:59 -06:00
}
return p - p0 ;
2022-02-23 09:07:50 -07:00
} ) ;
2021-08-22 04:20:59 -06:00
}
}
}
uint64_t P2PServer : : get_random64 ( )
{
MutexLock lock ( m_rngLock ) ;
return m_rng ( ) ;
}
void P2PServer : : print_status ( )
{
2022-05-09 08:07:49 -06:00
MutexLock lock ( m_peerListLock ) ;
2021-08-22 04:20:59 -06:00
LOGINFO ( 0 , " status " < <
2022-05-09 08:07:49 -06:00
" \n Connections = " < < m_numConnections . load ( ) < < " ( " < < m_numIncomingConnections . load ( ) < < " incoming) " < <
2021-10-26 09:55:47 -06:00
" \n Peer list size = " < < m_peerList . size ( ) < <
2022-05-06 05:19:56 -06:00
" \n Uptime = " < < log : : Duration ( seconds_since_epoch ( ) - m_pool - > start_time ( ) )
2021-08-22 04:20:59 -06:00
) ;
}
2021-10-24 08:04:30 -06:00
void P2PServer : : show_peers ( )
{
MutexLock lock ( m_clientsListLock ) ;
2022-05-06 12:04:01 -06:00
size_t n = 0 ;
2021-10-24 08:04:30 -06: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 12:04:01 -06:00
+ + n ;
2021-10-24 08:04:30 -06:00
}
}
2022-05-06 12:04:01 -06:00
LOGINFO ( 0 , " Total: " < < n < < " peers " ) ;
2021-10-24 08:04:30 -06:00
}
2021-08-22 04:20:59 -06:00
void P2PServer : : on_timer ( )
{
2021-10-08 10:02:04 -06:00
+ + m_timerCounter ;
2021-09-07 04:56:22 -06:00
if ( ! m_initialPeerList . empty ( ) ) {
connect_to_peers ( m_initialPeerList ) ;
m_initialPeerList . clear ( ) ;
}
2021-08-24 03:42:41 -06:00
flush_cache ( ) ;
2021-08-22 04:20:59 -06:00
download_missing_blocks ( ) ;
update_peer_list ( ) ;
save_peer_list_async ( ) ;
2021-09-02 11:21:38 -06:00
update_peer_connections ( ) ;
2021-10-09 03:01:26 -06:00
check_zmq ( ) ;
2021-08-22 04:20:59 -06:00
}
2021-08-24 03:42:41 -06:00
void P2PServer : : flush_cache ( )
{
2021-11-01 04:29:59 -06:00
if ( ! m_cache | | ( ( m_timerCounter % 30 ) ! = 2 ) ) {
2021-08-24 03:42:41 -06: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 03:31:50 -06:00
const int err = uv_queue_work ( & m_loop , & work - > req ,
2021-08-24 03:42:41 -06:00
[ ] ( uv_work_t * req )
{
bkg_jobs_tracker . start ( " P2PServer::flush_cache " ) ;
reinterpret_cast < Work * > ( req - > data ) - > cache - > flush ( ) ;
} ,
[ ] ( uv_work_t * req , int )
{
delete reinterpret_cast < Work * > ( req - > data ) ;
bkg_jobs_tracker . stop ( " P2PServer::flush_cache " ) ;
} ) ;
if ( err ) {
LOGERR ( 1 , " flush_cache: uv_queue_work failed, error " < < uv_err_name ( err ) ) ;
2021-09-07 02:22:58 -06:00
delete work ;
2021-08-24 03:42:41 -06:00
}
}
2021-08-22 04:20:59 -06:00
void P2PServer : : download_missing_blocks ( )
{
std : : vector < hash > missing_blocks ;
m_pool - > side_chain ( ) . get_missing_blocks ( missing_blocks ) ;
if ( missing_blocks . empty ( ) ) {
2021-08-27 13:09:35 -06:00
MutexLock lock ( m_missingBlockRequestsLock ) ;
m_missingBlockRequests . clear ( ) ;
2021-08-22 04:20:59 -06: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 ) ) {
if ( ! client - > m_handshakeComplete | | ! client - > m_handshakeSolutionSent ) {
continue ;
}
clients . emplace_back ( client ) ;
}
2021-08-27 09:26:42 -06:00
if ( clients . empty ( ) ) {
return ;
}
2022-03-24 11:30:23 -06:00
ReadLock lock2 ( m_cachedBlocksLock ) ;
2021-08-22 04:20:59 -06:00
// Try to download each block from a random client
for ( const hash & id : missing_blocks ) {
2021-08-27 09:26:42 -06:00
P2PClient * client = clients [ get_random64 ( ) % clients . size ( ) ] ;
{
2022-03-24 11:30:23 -06:00
MutexLock lock3 ( m_missingBlockRequestsLock ) ;
2021-08-27 09:26:42 -06: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 ;
}
}
2022-03-24 11:30:23 -06: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 08:54:53 -07:00
const bool result = send ( client ,
2022-05-04 07:53:01 -06:00
[ & id ] ( void * buf , size_t buf_size ) - > size_t
2021-08-22 04:20:59 -06:00
{
2022-05-04 07:53:01 -06:00
LOGINFO ( 5 , " sending BLOCK_REQUEST for id = " < < id ) ;
if ( buf_size < SEND_BUF_MIN_SIZE ) {
return 0 ;
}
2021-08-22 04:20:59 -06: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 08:54:53 -07:00
if ( result ) {
+ + client - > m_blockPendingRequests ;
}
2021-08-22 04:20:59 -06:00
}
}
2021-10-09 03:01:26 -06:00
void P2PServer : : check_zmq ( )
{
if ( ( m_timerCounter % 30 ) ! = 0 ) {
return ;
}
2022-03-23 04:30:38 -06:00
const uint64_t cur_time = seconds_since_epoch ( ) ;
const uint64_t last_active = m_pool - > zmq_last_active ( ) ;
2021-10-09 03:01:26 -06: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 03:44:42 -06:00
m_pool - > restart_zmq ( ) ;
2021-10-09 03:01:26 -06:00
}
}
2021-08-22 04:20:59 -06:00
P2PServer : : P2PClient : : P2PClient ( )
: m_peerId ( 0 )
, m_expectedMessage ( MessageId : : HANDSHAKE_CHALLENGE )
, m_handshakeChallenge ( 0 )
, m_handshakeSolutionSent ( false )
, m_handshakeComplete ( false )
2021-08-29 09:26:30 -06:00
, m_handshakeInvalid ( false )
2021-08-22 04:20:59 -06:00
, m_listenPort ( - 1 )
2022-02-22 03:06:12 -07:00
, m_fastPeerListRequestCount ( 0 )
2022-03-23 04:30:38 -06:00
, m_prevIncomingPeerListRequest ( 0 )
2022-02-21 08:54:53 -07:00
, m_nextOutgoingPeerListRequest ( 0 )
2021-10-24 08:04:30 -06:00
, m_lastPeerListRequestTime { }
2021-10-15 09:09:51 -06:00
, m_peerListPendingRequests ( 0 )
2021-10-24 08:04:30 -06:00
, m_pingTime ( 0 )
2022-02-21 08:54:53 -07:00
, m_blockPendingRequests ( 0 )
2022-04-23 03:29:17 -06:00
, m_chainTipBlockRequest ( false )
2021-08-24 13:45:19 -06:00
, m_lastAlive ( 0 )
2021-09-13 06:26:52 -06:00
, m_lastBroadcastTimestamp ( 0 )
, m_lastBlockrequestTimestamp ( 0 )
2021-10-17 02:48:09 -06:00
, m_broadcastedHashes { }
2021-08-22 04:20:59 -06:00
{
}
P2PServer : : P2PClient : : ~ P2PClient ( )
{
}
void P2PServer : : P2PClient : : reset ( )
{
Client : : reset ( ) ;
m_peerId = 0 ;
m_expectedMessage = MessageId : : HANDSHAKE_CHALLENGE ;
m_handshakeChallenge = 0 ;
m_handshakeSolutionSent = false ;
m_handshakeComplete = false ;
2021-08-29 09:26:30 -06:00
m_handshakeInvalid = false ;
2021-08-22 04:20:59 -06:00
m_listenPort = - 1 ;
2022-02-22 03:06:12 -07:00
m_fastPeerListRequestCount = 0 ;
2022-03-23 04:30:38 -06:00
m_prevIncomingPeerListRequest = 0 ;
2022-02-21 08:54:53 -07:00
m_nextOutgoingPeerListRequest = 0 ;
2021-10-24 08:04:30 -06:00
m_lastPeerListRequestTime = { } ;
2021-10-15 09:09:51 -06:00
m_peerListPendingRequests = 0 ;
2021-10-24 08:04:30 -06:00
m_pingTime = 0 ;
2022-02-21 08:54:53 -07:00
m_blockPendingRequests = 0 ;
2022-04-23 03:29:17 -06:00
m_chainTipBlockRequest = false ;
2021-08-24 13:45:19 -06:00
m_lastAlive = 0 ;
2021-09-13 06:26:52 -06:00
m_lastBroadcastTimestamp = 0 ;
m_lastBlockrequestTimestamp = 0 ;
2021-08-22 04:20:59 -06:00
2021-10-17 02:48:09 -06:00
for ( hash & h : m_broadcastedHashes ) {
h = { } ;
}
m_broadcastedHashesIndex = 0 ;
2021-08-22 04:20:59 -06:00
}
bool P2PServer : : P2PClient : : on_connect ( )
{
2021-08-31 02:41:41 -06:00
P2PServer * server = static_cast < P2PServer * > ( m_owner ) ;
2021-12-26 07:28:33 -07:00
if ( ! server ) {
2021-12-26 06:59:45 -07:00
return false ;
}
2021-12-26 07:28:33 -07:00
if ( m_isIncoming & & ( server - > m_numIncomingConnections > server - > m_maxIncomingPeers ) ) {
2021-12-26 06:59:45 -07:00
LOGINFO ( 5 , " Connection from " < < log : : Gray ( ) < < static_cast < char * > ( m_addrString ) < < log : : NoColor ( ) < < " rejected (incoming connections limit was reached) " ) ;
return false ;
}
2021-08-31 02:41:41 -06:00
// Don't allow multiple connections to/from the same IP
// server->m_clientsListLock is already locked here
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 ) ) {
2021-08-31 09:23:20 -06:00
LOGINFO ( 5 , " peer " < < static_cast < char * > ( m_addrString ) < < " is already connected as " < < static_cast < char * > ( client - > m_addrString ) ) ;
2021-08-31 02:41:41 -06:00
return false ;
}
}
2022-03-23 04:30:38 -06:00
m_lastAlive = seconds_since_epoch ( ) ;
2021-08-22 04:20:59 -06: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 08:54:53 -07:00
uint32_t num_block_requests = 0 ;
2021-08-22 04:20:59 -06: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 09:09:51 -06: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 04:20:59 -06: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 09:09:51 -06: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 04:20:59 -06: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 08:54:53 -07: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 04:20:59 -06: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 08:54:53 -07: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 04:20:59 -06: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 08:54:53 -07: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 04:20:59 -06: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 14:34:37 -06:00
const uint32_t block_size = read_unaligned ( reinterpret_cast < uint32_t * > ( buf + 1 ) ) ;
2021-08-22 04:20:59 -06:00
if ( bytes_left > = 1 + sizeof ( uint32_t ) + block_size ) {
bytes_read = 1 + sizeof ( uint32_t ) + block_size ;
2022-02-21 08:54:53 -07:00
- - m_blockPendingRequests ;
2021-08-22 04:20:59 -06: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 :
2021-10-06 01:47:41 -06:00
LOGINFO ( 6 , " peer " < < log : : Gray ( ) < < static_cast < char * > ( m_addrString ) < < log : : NoColor ( ) < < " sent BLOCK_BROADCAST " ) ;
2021-08-22 04:20:59 -06:00
if ( bytes_left > = 1 + sizeof ( uint32_t ) ) {
2022-04-08 14:34:37 -06:00
const uint32_t block_size = read_unaligned ( reinterpret_cast < uint32_t * > ( buf + 1 ) ) ;
2021-08-22 04:20:59 -06:00
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 ) ) {
ban ( DEFAULT_BAN_TIME ) ;
server - > remove_peer_from_list ( this ) ;
return false ;
}
}
}
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 09:09:51 -06: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 04:20:59 -06:00
LOGINFO ( 5 , " peer " < < log : : Gray ( ) < < static_cast < char * > ( m_addrString ) < < log : : NoColor ( ) < < " sent PEER_LIST_RESPONSE " ) ;
if ( bytes_left > = 2 ) {
2021-10-21 07:55:00 -06:00
const uint32_t num_peers = buf [ 1 ] ;
2021-08-22 04:20:59 -06:00
if ( num_peers > PEER_LIST_RESPONSE_MAX_PEERS ) {
2021-08-24 13:45:19 -06:00
LOGWARN ( 5 , " peer " < < log : : Gray ( ) < < static_cast < char * > ( m_addrString ) < < log : : NoColor ( ) < < " sent too long peer list ( " < < num_peers < < ' ) ' ) ;
2021-08-22 04:20:59 -06:00
ban ( DEFAULT_BAN_TIME ) ;
server - > remove_peer_from_list ( this ) ;
return false ;
}
2021-10-21 07:55:00 -06:00
if ( bytes_left > = 2u + num_peers * 19u ) {
bytes_read = 2u + num_peers * 19u ;
2021-10-15 09:09:51 -06:00
2021-10-24 08:04:30 -06:00
using namespace std : : chrono ;
2022-02-21 10:46:53 -07:00
m_pingTime = duration_cast < milliseconds > ( high_resolution_clock : : now ( ) - m_lastPeerListRequestTime ) . count ( ) ;
2021-10-24 08:04:30 -06:00
2021-10-15 09:09:51 -06:00
- - m_peerListPendingRequests ;
2021-08-22 04:20:59 -06:00
if ( ! on_peer_list_response ( buf + 1 ) ) {
ban ( DEFAULT_BAN_TIME ) ;
server - > remove_peer_from_list ( this ) ;
return false ;
}
}
}
break ;
}
2021-08-24 13:45:19 -06:00
if ( bytes_read ) {
buf + = bytes_read ;
bytes_left - = bytes_read ;
2022-03-23 04:30:38 -06:00
m_lastAlive = seconds_since_epoch ( ) ;
2021-08-24 13:45:19 -06:00
}
2021-08-22 04:20:59 -06: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 08:17:20 -06:00
void P2PServer : : P2PClient : : on_read_failed ( int /*err*/ )
2021-09-07 01:53:38 -06:00
{
on_disconnected ( ) ;
}
void P2PServer : : P2PClient : : on_disconnected ( )
2021-09-06 08:17:20 -06:00
{
if ( ! m_handshakeComplete ) {
LOGWARN ( 5 , " peer " < < static_cast < char * > ( m_addrString ) < < " disconnected before finishing handshake " ) ;
ban ( DEFAULT_BAN_TIME ) ;
P2PServer * server = static_cast < P2PServer * > ( m_owner ) ;
if ( server ) {
server - > remove_peer_from_list ( this ) ;
}
}
}
2021-08-22 04:20:59 -06: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 07:53:01 -06:00
[ this , owner ] ( void * buf , size_t buf_size ) - > size_t
2021-08-22 04:20:59 -06:00
{
2022-05-04 07:53:01 -06:00
LOGINFO ( 5 , " sending HANDSHAKE_CHALLENGE " ) ;
if ( buf_size < SEND_BUF_MIN_SIZE ) {
return 0 ;
}
2021-08-22 04:20:59 -06: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 )
{
2021-08-24 03:42:41 -06:00
bkg_jobs_tracker . start ( " P2PServer::send_handshake_solution " ) ;
2021-08-22 04:20:59 -06: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 ;
2021-08-24 03:42:41 -06:00
bkg_jobs_tracker . stop ( " P2PServer::send_handshake_solution " ) ;
2021-08-22 04:20:59 -06: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 07:53:01 -06:00
[ work ] ( void * buf , size_t buf_size ) - > size_t
2021-08-22 04:20:59 -06:00
{
2022-05-04 07:53:01 -06:00
LOGINFO ( 5 , " sending HANDSHAKE_SOLUTION " ) ;
if ( buf_size < SEND_BUF_MIN_SIZE ) {
return 0 ;
}
2021-08-22 04:20:59 -06: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 09:26:30 -06:00
if ( work - > client - > m_handshakeComplete & & ! work - > client - > m_handshakeInvalid ) {
2021-08-22 04:20:59 -06:00
work - > client - > on_after_handshake ( p ) ;
}
return p - p0 ;
} ) ;
if ( result ) {
work - > client - > m_handshakeSolutionSent = true ;
2021-08-29 09:26:30 -06:00
2021-08-29 09:42:49 -06:00
if ( work - > client - > m_handshakeComplete & & work - > client - > m_handshakeInvalid ) {
2021-08-29 09:26:30 -06:00
work - > client - > ban ( DEFAULT_BAN_TIME ) ;
work - > server - > remove_peer_from_list ( work - > client ) ;
work - > client - > close ( ) ;
}
2021-08-22 04:20:59 -06: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 03:50:56 -06:00
[ & challenge , & solution_salt , & consensus_id , consensus_id_size ] ( int offset ) - > uint8_t
2021-08-22 04:20:59 -06: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 12:20:28 -06:00
LOGWARN ( 5 , " tried to connect to self at " < < static_cast < const char * > ( m_addrString ) ) ;
2021-08-22 04:20:59 -06: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 13:45:19 -06: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 04:20:59 -06: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 09:26:30 -06:00
m_handshakeInvalid = true ;
2021-08-22 04:20:59 -06:00
}
}
if ( ! check_handshake_solution ( solution , solution_salt ) ) {
LOGWARN ( 5 , " peer " < < static_cast < char * > ( m_addrString ) < < " handshake failed " ) ;
2021-08-29 09:26:30 -06:00
m_handshakeInvalid = true ;
2021-08-22 04:20:59 -06:00
}
m_handshakeComplete = true ;
2021-08-29 09:26:30 -06:00
if ( ! m_handshakeInvalid ) {
LOGINFO ( 5 , " peer " < < log : : Gray ( ) < < static_cast < char * > ( m_addrString ) < < log : : NoColor ( ) < < " handshake completed " ) ;
}
2021-08-22 04:20:59 -06:00
if ( m_handshakeSolutionSent ) {
2021-08-29 09:26:30 -06:00
if ( m_handshakeInvalid ) {
return false ;
}
2021-08-22 04:20:59 -06:00
return m_owner - > send ( this ,
2022-05-04 07:53:01 -06:00
[ this ] ( void * buf , size_t buf_size ) - > size_t
2021-08-22 04:20:59 -06:00
{
2022-05-04 07:53:01 -06:00
LOGINFO ( 5 , " sending LISTEN_PORT and BLOCK_REQUEST for the chain tip " ) ;
if ( buf_size < SEND_BUF_MIN_SIZE ) {
return 0 ;
}
2021-08-22 04:20:59 -06: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 )
{
LOGINFO ( 5 , " sending LISTEN_PORT " ) ;
* ( p + + ) = static_cast < uint8_t > ( MessageId : : LISTEN_PORT ) ;
const int32_t port = m_owner - > listen_port ( ) ;
memcpy ( p , & port , sizeof ( port ) ) ;
p + = sizeof ( port ) ;
LOGINFO ( 5 , " sending BLOCK_REQUEST for the chain tip " ) ;
* ( p + + ) = static_cast < uint8_t > ( MessageId : : BLOCK_REQUEST ) ;
hash empty ;
memcpy ( p , empty . h , HASH_SIZE ) ;
p + = HASH_SIZE ;
2021-09-13 06:26:52 -06:00
2022-02-21 08:54:53 -07:00
+ + m_blockPendingRequests ;
2022-04-23 03:29:17 -06:00
m_chainTipBlockRequest = true ;
2022-03-23 04:30:38 -06:00
m_lastBroadcastTimestamp = seconds_since_epoch ( ) ;
2021-08-22 04:20:59 -06: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 13:45:19 -06:00
LOGWARN ( 5 , " peer " < < static_cast < char * > ( m_addrString ) < < " sent an invalid listen port number " ) ;
2021-08-22 04:20:59 -06: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 04:30:38 -06:00
m_lastBlockrequestTimestamp = seconds_since_epoch ( ) ;
2021-09-13 06:26:52 -06:00
2021-08-22 04:20:59 -06: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-05-04 07:53:01 -06:00
[ & blob ] ( void * buf , size_t buf_size ) - > size_t
2021-08-22 04:20:59 -06:00
{
2022-05-04 07:53:01 -06:00
LOGINFO ( 5 , " sending BLOCK_RESPONSE " ) ;
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 04:20:59 -06:00
uint8_t * p0 = reinterpret_cast < uint8_t * > ( buf ) ;
uint8_t * p = p0 ;
* ( p + + ) = static_cast < uint8_t > ( MessageId : : BLOCK_RESPONSE ) ;
2022-04-08 14:34:37 -06:00
memcpy ( p , & len , sizeof ( uint32_t ) ) ;
2021-08-22 04:20:59 -06:00
p + = sizeof ( uint32_t ) ;
2022-04-08 14:34:37 -06:00
if ( len ) {
memcpy ( p , blob . data ( ) , len ) ;
p + = len ;
}
2021-08-22 04:20:59 -06: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 ) ;
const int result = server - > m_block - > deserialize ( buf , size , server - > m_pool - > side_chain ( ) ) ;
if ( result ! = 0 ) {
LOGWARN ( 3 , " peer " < < static_cast < char * > ( m_addrString ) < < " sent an invalid block, error " < < result ) ;
return false ;
}
2022-04-23 03:29:17 -06:00
if ( m_chainTipBlockRequest ) {
m_chainTipBlockRequest = false ;
const uint64_t peer_height = server - > m_block - > m_txinGenHeight ;
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 ;
}
}
2021-08-24 03:42:41 -06:00
return handle_incoming_block_async ( server - > m_block ) ;
2021-08-22 04:20:59 -06:00
}
bool P2PServer : : P2PClient : : on_block_broadcast ( const uint8_t * buf , uint32_t size )
{
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 ) ;
const int result = server - > m_block - > deserialize ( buf , size , server - > m_pool - > side_chain ( ) ) ;
if ( result ! = 0 ) {
LOGWARN ( 3 , " peer " < < static_cast < char * > ( m_addrString ) < < " sent an invalid block, error " < < result ) ;
return false ;
}
2021-10-17 02:48:09 -06:00
m_broadcastedHashes [ m_broadcastedHashesIndex . fetch_add ( 1 ) % array_size ( & P2PClient : : m_broadcastedHashes ) ] = server - > m_block - > m_sidechainId ;
2021-08-22 04:20:59 -06:00
2022-04-08 15:14:08 -06:00
MinerData miner_data = server - > m_pool - > miner_data ( ) ;
2021-08-31 15:11:58 -06:00
if ( server - > m_block - > m_prevId ! = miner_data . prev_id ) {
2021-08-24 09:19:10 -06:00
// This peer is mining on top of a different Monero block, investigate it
const uint64_t peer_height = server - > m_block - > m_txinGenHeight ;
2021-08-31 15:11:58 -06:00
const uint64_t our_height = miner_data . height ;
2021-08-24 09:19:10 -06:00
if ( peer_height < our_height ) {
if ( our_height - peer_height < 5 ) {
2021-08-31 01:58:57 -06:00
using namespace std : : chrono ;
2022-03-23 08:49:24 -06:00
const int64_t elapsed_ms = duration_cast < milliseconds > ( high_resolution_clock : : now ( ) - miner_data . time_received ) . count ( ) ;
2021-09-13 11:25:12 -06:00
if ( our_height - peer_height > 1 ) {
2021-08-31 01:58:57 -06: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 09:19:10 -06:00
}
else {
2022-04-23 03:29:17 -06:00
LOGWARN ( 4 , " peer " < < static_cast < char * > ( m_addrString ) < < " broadcasted an unreasonably stale block (mainchain height " < < peer_height < < " , expected >= " < < our_height < < ' ) ' ) ;
2021-08-24 09:19:10 -06:00
return false ;
}
}
else if ( peer_height > our_height ) {
2021-08-24 12:10:16 -06:00
if ( peer_height > = our_height + 2 ) {
2021-10-06 07:22:03 -06: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 12:10:16 -06:00
}
2021-08-24 09:19:10 -06:00
}
else {
2021-09-08 12:57:22 -06:00
LOGINFO ( 4 , " peer " < < static_cast < char * > ( m_addrString ) < < " is mining on an alternative mainchain tip (height " < < peer_height < < " ) " ) ;
2021-08-24 09:19:10 -06:00
}
2021-08-22 04:20:59 -06:00
}
server - > m_block - > m_wantBroadcast = true ;
2022-03-23 04:30:38 -06:00
m_lastBroadcastTimestamp = seconds_since_epoch ( ) ;
2021-09-13 06:26:52 -06:00
2021-08-24 03:42:41 -06:00
return handle_incoming_block_async ( server - > m_block ) ;
2021-08-22 04:20:59 -06:00
}
bool P2PServer : : P2PClient : : on_peer_list_request ( const uint8_t * )
{
P2PServer * server = static_cast < P2PServer * > ( m_owner ) ;
2022-03-23 04:30:38 -06:00
const uint64_t cur_time = seconds_since_epoch ( ) ;
2022-02-21 08:54:53 -07:00
// Allow peer list requests no more than once every 30 seconds
2022-03-23 04:30:38 -06:00
if ( cur_time - m_prevIncomingPeerListRequest < 30 ) {
2022-02-22 03:06:12 -07:00
+ + m_fastPeerListRequestCount ;
if ( m_fastPeerListRequestCount > = 3 ) {
2022-06-09 01:20:24 -06:00
LOGWARN ( 4 , " peer " < < static_cast < char * > ( m_addrString ) < < " is sending PEER_LIST_REQUEST too often " ) ;
2022-02-22 03:06:12 -07:00
return false ;
}
2022-02-21 08:54:53 -07:00
}
m_prevIncomingPeerListRequest = cur_time ;
2021-08-22 04:20:59 -06: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 03:32:01 -06: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 04:20:59 -06:00
for ( P2PClient * client = static_cast < P2PClient * > ( server - > m_connectedClientsList - > m_next ) ; client ! = server - > m_connectedClientsList ; client = static_cast < P2PClient * > ( client - > m_next ) ) {
2021-10-15 03:32:01 -06:00
if ( ( client - > m_listenPort < 0 ) | | ( client - > m_addr = = m_addr ) ) {
2021-08-22 04:20:59 -06:00
continue ;
}
2021-10-15 03:32:01 -06:00
const Peer p { client - > m_isV6 , client - > m_addr , client - > m_listenPort , 0 , 0 } ;
+ + n ;
2021-08-22 04:20:59 -06:00
2021-10-15 03:32:01 -06: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 04:20:59 -06:00
2021-10-15 03:32:01 -06:00
uint64_t k ;
umul128 ( server - > get_random64 ( ) , n , & k ) ;
if ( k < peers_to_send_target ) {
peers [ k ] = p ;
2021-08-22 04:20:59 -06:00
}
}
}
return server - > send ( this ,
2022-05-04 07:53:01 -06:00
[ & peers , num_selected_peers ] ( void * buf , size_t buf_size ) - > size_t
2021-08-22 04:20:59 -06:00
{
2022-05-04 07:53:01 -06:00
LOGINFO ( 5 , " sending PEER_LIST_RESPONSE " ) ;
if ( buf_size < SEND_BUF_MIN_SIZE + 2 + num_selected_peers * 19 ) {
return 0 ;
}
2021-08-22 04:20:59 -06: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 ;
} ) ;
}
bool P2PServer : : P2PClient : : on_peer_list_response ( const uint8_t * buf ) const
{
P2PServer * server = static_cast < P2PServer * > ( m_owner ) ;
2022-03-23 04:30:38 -06:00
const uint64_t cur_time = seconds_since_epoch ( ) ;
2021-08-22 04:20:59 -06:00
MutexLock lock ( server - > m_peerListLock ) ;
const uint32_t num_peers = * ( buf + + ) ;
for ( uint32_t i = 0 ; i < num_peers ; + + i ) {
const bool is_v6 = * ( buf + + ) ! = 0 ;
raw_ip ip ;
memcpy ( ip . data , buf , sizeof ( ip . data ) ) ;
buf + = sizeof ( ip . data ) ;
2021-10-21 07:55:00 -06:00
// Fill in default bytes for IPv4 addresses
if ( ! is_v6 ) {
memset ( ip . data , 0 , 10 ) ;
ip . data [ 10 ] = 0xFF ;
ip . data [ 11 ] = 0xFF ;
}
2021-08-22 04:20:59 -06:00
int port = 0 ;
memcpy ( & port , buf , 2 ) ;
buf + = 2 ;
bool already_added = false ;
2021-10-15 03:32:01 -06:00
for ( Peer & p : server - > m_peerList ) {
2021-08-22 04:20:59 -06:00
if ( ( p . m_isV6 = = is_v6 ) & & ( p . m_addr = = ip ) ) {
already_added = true ;
2021-10-15 03:32:01 -06:00
p . m_lastSeen = cur_time ;
2021-08-22 04:20:59 -06:00
break ;
}
}
2021-08-27 08:36:06 -06:00
if ( ! already_added & & ! server - > is_banned ( ip ) ) {
2021-10-15 03:32:01 -06:00
server - > m_peerList . emplace_back ( Peer { is_v6 , ip , port , 0 , cur_time } ) ;
2021-08-22 04:20:59 -06:00
}
}
return true ;
}
2021-08-24 03:42:41 -06:00
bool P2PServer : : P2PClient : : handle_incoming_block_async ( PoolBlock * block )
2021-08-22 04:20:59 -06:00
{
P2PServer * server = static_cast < P2PServer * > ( m_owner ) ;
2021-08-24 03:42:41 -06:00
if ( server - > m_pool - > side_chain ( ) . block_seen ( * block ) ) {
2021-08-25 01:38:47 -06:00
LOGINFO ( 6 , " block " < < block - > m_sidechainId < < " was received before, skipping it " ) ;
2021-08-22 04:20:59 -06:00
return true ;
}
struct Work
{
uv_work_t req ;
PoolBlock block ;
P2PClient * client ;
P2PServer * server ;
uint32_t client_reset_counter ;
2021-08-31 05:14:35 -06:00
raw_ip client_ip ;
2021-08-22 04:20:59 -06:00
std : : vector < hash > missing_blocks ;
} ;
2021-08-31 05:14:35 -06:00
Work * work = new Work { { } , * block , this , server , m_resetCounter . load ( ) , m_addr , { } } ;
2021-08-22 04:20:59 -06:00
work - > req . data = work ;
const int err = uv_queue_work ( & server - > m_loop , & work - > req ,
[ ] ( uv_work_t * req )
{
2021-08-24 03:42:41 -06:00
bkg_jobs_tracker . start ( " P2PServer::handle_incoming_block_async " ) ;
2021-08-22 04:20:59 -06:00
Work * work = reinterpret_cast < Work * > ( req - > data ) ;
2021-08-31 05:14:35 -06: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 04:20:59 -06: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 ;
2021-08-24 03:42:41 -06:00
bkg_jobs_tracker . stop ( " P2PServer::handle_incoming_block_async " ) ;
2021-08-22 04:20:59 -06: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 05:14:35 -06: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 04:20:59 -06: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 05:14:35 -06:00
LOGWARN ( 3 , " peer " < < static_cast < char * > ( m_addrString ) < < " banned for " < < DEFAULT_BAN_TIME < < " seconds " ) ;
2021-08-22 04:20:59 -06:00
}
2021-08-31 05:14:35 -06: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 04:20:59 -06: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 03:42:41 -06:00
if ( missing_blocks . empty ( ) ) {
return ;
}
P2PServer * server = static_cast < P2PServer * > ( m_owner ) ;
ReadLock lock ( server - > m_cachedBlocksLock ) ;
2021-08-22 04:20:59 -06:00
for ( const hash & id : missing_blocks ) {
2022-03-24 11:30:23 -06: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 03:42:41 -06:00
}
2021-08-22 04:20:59 -06:00
const bool result = m_owner - > send ( this ,
2022-05-04 07:53:01 -06:00
[ & id ] ( void * buf , size_t buf_size ) - > size_t
2021-08-22 04:20:59 -06:00
{
2022-05-04 07:53:01 -06:00
LOGINFO ( 5 , " sending BLOCK_REQUEST for id = " < < id ) ;
if ( buf_size < SEND_BUF_MIN_SIZE + 1 + HASH_SIZE ) {
return 0 ;
}
2021-08-22 04:20:59 -06: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 08:54:53 -07:00
+ + m_blockPendingRequests ;
2021-08-22 04:20:59 -06:00
}
}
} // namespace p2pool