protocol: add scoring system to drop peers that don't behave
This commit is contained in:
parent
4f401f6fca
commit
61f5001c3f
@ -43,7 +43,7 @@ namespace cryptonote
|
|||||||
{
|
{
|
||||||
cryptonote_connection_context(): m_state(state_before_handshake), m_remote_blockchain_height(0), m_last_response_height(0),
|
cryptonote_connection_context(): m_state(state_before_handshake), m_remote_blockchain_height(0), m_last_response_height(0),
|
||||||
m_last_request_time(boost::date_time::not_a_date_time), m_callback_request_count(0),
|
m_last_request_time(boost::date_time::not_a_date_time), m_callback_request_count(0),
|
||||||
m_last_known_hash(crypto::null_hash), m_pruning_seed(0), m_rpc_port(0), m_rpc_credits_per_hash(0), m_anchor(false) {}
|
m_last_known_hash(crypto::null_hash), m_pruning_seed(0), m_rpc_port(0), m_rpc_credits_per_hash(0), m_anchor(false), m_score(0) {}
|
||||||
|
|
||||||
enum state
|
enum state
|
||||||
{
|
{
|
||||||
@ -66,7 +66,7 @@ namespace cryptonote
|
|||||||
uint16_t m_rpc_port;
|
uint16_t m_rpc_port;
|
||||||
uint32_t m_rpc_credits_per_hash;
|
uint32_t m_rpc_credits_per_hash;
|
||||||
bool m_anchor;
|
bool m_anchor;
|
||||||
//size_t m_score; TODO: add score calculations
|
int32_t m_score;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::string get_protocol_state_string(cryptonote_connection_context::state s)
|
inline std::string get_protocol_state_string(cryptonote_connection_context::state s)
|
||||||
|
@ -148,6 +148,7 @@ namespace cryptonote
|
|||||||
void notify_new_stripe(cryptonote_connection_context &context, uint32_t stripe);
|
void notify_new_stripe(cryptonote_connection_context &context, uint32_t stripe);
|
||||||
void skip_unneeded_hashes(cryptonote_connection_context& context, bool check_block_queue) const;
|
void skip_unneeded_hashes(cryptonote_connection_context& context, bool check_block_queue) const;
|
||||||
bool request_txpool_complement(cryptonote_connection_context &context);
|
bool request_txpool_complement(cryptonote_connection_context &context);
|
||||||
|
void hit_score(cryptonote_connection_context &context, int32_t score);
|
||||||
|
|
||||||
t_core& m_core;
|
t_core& m_core;
|
||||||
|
|
||||||
@ -163,6 +164,7 @@ namespace cryptonote
|
|||||||
epee::math_helper::once_a_time_seconds<30> m_idle_peer_kicker;
|
epee::math_helper::once_a_time_seconds<30> m_idle_peer_kicker;
|
||||||
epee::math_helper::once_a_time_milliseconds<100> m_standby_checker;
|
epee::math_helper::once_a_time_milliseconds<100> m_standby_checker;
|
||||||
epee::math_helper::once_a_time_seconds<101> m_sync_search_checker;
|
epee::math_helper::once_a_time_seconds<101> m_sync_search_checker;
|
||||||
|
epee::math_helper::once_a_time_seconds<43> m_bad_peer_checker;
|
||||||
std::atomic<unsigned int> m_max_out_peers;
|
std::atomic<unsigned int> m_max_out_peers;
|
||||||
tools::PerformanceTimer m_sync_timer, m_add_timer;
|
tools::PerformanceTimer m_sync_timer, m_add_timer;
|
||||||
uint64_t m_last_add_end_time;
|
uint64_t m_last_add_end_time;
|
||||||
@ -183,6 +185,8 @@ namespace cryptonote
|
|||||||
double get_avg_block_size();
|
double get_avg_block_size();
|
||||||
boost::circular_buffer<size_t> m_avg_buffer = boost::circular_buffer<size_t>(10);
|
boost::circular_buffer<size_t> m_avg_buffer = boost::circular_buffer<size_t>(10);
|
||||||
|
|
||||||
|
boost::mutex m_bad_peer_check_lock;
|
||||||
|
|
||||||
template<class t_parameter>
|
template<class t_parameter>
|
||||||
bool post_notify(typename t_parameter::request& arg, cryptonote_connection_context& context)
|
bool post_notify(typename t_parameter::request& arg, cryptonote_connection_context& context)
|
||||||
{
|
{
|
||||||
|
@ -68,10 +68,11 @@
|
|||||||
#define BLOCK_QUEUE_FORCE_DOWNLOAD_NEAR_BLOCKS 1000
|
#define BLOCK_QUEUE_FORCE_DOWNLOAD_NEAR_BLOCKS 1000
|
||||||
#define REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD_STANDBY (5 * 1000000) // microseconds
|
#define REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD_STANDBY (5 * 1000000) // microseconds
|
||||||
#define REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD (30 * 1000000) // microseconds
|
#define REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD (30 * 1000000) // microseconds
|
||||||
#define IDLE_PEER_KICK_TIME (600 * 1000000) // microseconds
|
#define IDLE_PEER_KICK_TIME (240 * 1000000) // microseconds
|
||||||
#define PASSIVE_PEER_KICK_TIME (60 * 1000000) // microseconds
|
#define PASSIVE_PEER_KICK_TIME (60 * 1000000) // microseconds
|
||||||
#define DROP_ON_SYNC_WEDGE_THRESHOLD (30 * 1000000000ull) // nanoseconds
|
#define DROP_ON_SYNC_WEDGE_THRESHOLD (30 * 1000000000ull) // nanoseconds
|
||||||
#define LAST_ACTIVITY_STALL_THRESHOLD (2.0f) // seconds
|
#define LAST_ACTIVITY_STALL_THRESHOLD (2.0f) // seconds
|
||||||
|
#define DROP_PEERS_ON_SCORE -2
|
||||||
|
|
||||||
namespace cryptonote
|
namespace cryptonote
|
||||||
{
|
{
|
||||||
@ -142,6 +143,7 @@ namespace cryptonote
|
|||||||
m_core.get_short_chain_history(r.block_ids);
|
m_core.get_short_chain_history(r.block_ids);
|
||||||
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
|
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
|
||||||
r.prune = m_sync_pruned_blocks;
|
r.prune = m_sync_pruned_blocks;
|
||||||
|
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
|
||||||
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
|
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
|
||||||
post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
|
post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
|
||||||
MLOG_PEER_STATE("requesting chain");
|
MLOG_PEER_STATE("requesting chain");
|
||||||
@ -427,7 +429,7 @@ namespace cryptonote
|
|||||||
template<class t_core>
|
template<class t_core>
|
||||||
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& context)
|
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& context)
|
||||||
{
|
{
|
||||||
MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, "Received NOTIFY_NEW_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)");
|
MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, context << "Received NOTIFY_NEW_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)");
|
||||||
if(context.m_state != cryptonote_connection_context::state_normal)
|
if(context.m_state != cryptonote_connection_context::state_normal)
|
||||||
return 1;
|
return 1;
|
||||||
if(!is_synchronized()) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks
|
if(!is_synchronized()) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks
|
||||||
@ -487,6 +489,7 @@ namespace cryptonote
|
|||||||
m_core.get_short_chain_history(r.block_ids);
|
m_core.get_short_chain_history(r.block_ids);
|
||||||
r.prune = m_sync_pruned_blocks;
|
r.prune = m_sync_pruned_blocks;
|
||||||
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
|
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
|
||||||
|
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
|
||||||
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
|
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
|
||||||
post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
|
post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
|
||||||
MLOG_PEER_STATE("requesting chain");
|
MLOG_PEER_STATE("requesting chain");
|
||||||
@ -498,7 +501,7 @@ namespace cryptonote
|
|||||||
template<class t_core>
|
template<class t_core>
|
||||||
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_fluffy_block(int command, NOTIFY_NEW_FLUFFY_BLOCK::request& arg, cryptonote_connection_context& context)
|
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_fluffy_block(int command, NOTIFY_NEW_FLUFFY_BLOCK::request& arg, cryptonote_connection_context& context)
|
||||||
{
|
{
|
||||||
MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, "Received NOTIFY_NEW_FLUFFY_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)");
|
MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, context << "Received NOTIFY_NEW_FLUFFY_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)");
|
||||||
if(context.m_state != cryptonote_connection_context::state_normal)
|
if(context.m_state != cryptonote_connection_context::state_normal)
|
||||||
return 1;
|
return 1;
|
||||||
if(!is_synchronized()) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks
|
if(!is_synchronized()) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks
|
||||||
@ -765,6 +768,7 @@ namespace cryptonote
|
|||||||
m_core.get_short_chain_history(r.block_ids);
|
m_core.get_short_chain_history(r.block_ids);
|
||||||
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
|
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
|
||||||
r.prune = m_sync_pruned_blocks;
|
r.prune = m_sync_pruned_blocks;
|
||||||
|
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
|
||||||
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
|
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
|
||||||
post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
|
post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
|
||||||
MLOG_PEER_STATE("requesting chain");
|
MLOG_PEER_STATE("requesting chain");
|
||||||
@ -1029,6 +1033,7 @@ namespace cryptonote
|
|||||||
drop_connection(context, false, false);
|
drop_connection(context, false, false);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
|
||||||
MLOG_P2P_MESSAGE("-->>NOTIFY_RESPONSE_GET_OBJECTS: blocks.size()="
|
MLOG_P2P_MESSAGE("-->>NOTIFY_RESPONSE_GET_OBJECTS: blocks.size()="
|
||||||
<< rsp.blocks.size() << ", rsp.m_current_blockchain_height=" << rsp.current_blockchain_height
|
<< rsp.blocks.size() << ", rsp.m_current_blockchain_height=" << rsp.current_blockchain_height
|
||||||
<< ", missed_ids.size()=" << rsp.missed_ids.size());
|
<< ", missed_ids.size()=" << rsp.missed_ids.size());
|
||||||
@ -1666,6 +1671,7 @@ skip:
|
|||||||
bool t_cryptonote_protocol_handler<t_core>::kick_idle_peers()
|
bool t_cryptonote_protocol_handler<t_core>::kick_idle_peers()
|
||||||
{
|
{
|
||||||
MTRACE("Checking for idle peers...");
|
MTRACE("Checking for idle peers...");
|
||||||
|
std::vector<boost::uuids::uuid> idle_peers;
|
||||||
m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
|
m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
|
||||||
{
|
{
|
||||||
if (context.m_state == cryptonote_connection_context::state_synchronizing && context.m_last_request_time != boost::date_time::not_a_date_time)
|
if (context.m_state == cryptonote_connection_context::state_synchronizing && context.m_last_request_time != boost::date_time::not_a_date_time)
|
||||||
@ -1673,6 +1679,8 @@ skip:
|
|||||||
const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
|
const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
|
||||||
const boost::posix_time::time_duration dt = now - context.m_last_request_time;
|
const boost::posix_time::time_duration dt = now - context.m_last_request_time;
|
||||||
if (dt.total_microseconds() > IDLE_PEER_KICK_TIME)
|
if (dt.total_microseconds() > IDLE_PEER_KICK_TIME)
|
||||||
|
{
|
||||||
|
if (context.m_score-- >= 0)
|
||||||
{
|
{
|
||||||
MINFO(context << " kicking idle peer, last update " << (dt.total_microseconds() / 1.e6) << " seconds ago");
|
MINFO(context << " kicking idle peer, last update " << (dt.total_microseconds() / 1.e6) << " seconds ago");
|
||||||
LOG_PRINT_CCONTEXT_L2("requesting callback");
|
LOG_PRINT_CCONTEXT_L2("requesting callback");
|
||||||
@ -1681,9 +1689,25 @@ skip:
|
|||||||
++context.m_callback_request_count;
|
++context.m_callback_request_count;
|
||||||
m_p2p->request_callback(context);
|
m_p2p->request_callback(context);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
idle_peers.push_back(context.m_connection_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
for (const auto &uuid: idle_peers)
|
||||||
|
{
|
||||||
|
if (!m_p2p->for_connection(uuid, [&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t f)->bool{
|
||||||
|
MINFO(ctx << "dropping idle peer with negative score");
|
||||||
|
drop_connection(ctx, true, false);
|
||||||
|
return true;
|
||||||
|
}))
|
||||||
|
MDEBUG("Failed to find peer we wanted to drop");
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------
|
||||||
@ -2564,6 +2588,19 @@ skip:
|
|||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------
|
||||||
template<class t_core>
|
template<class t_core>
|
||||||
|
void t_cryptonote_protocol_handler<t_core>::hit_score(cryptonote_connection_context &context, int32_t score)
|
||||||
|
{
|
||||||
|
if (score <= 0)
|
||||||
|
{
|
||||||
|
MERROR("Negative score hit");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
context.m_score -= score;
|
||||||
|
if (context.m_score <= DROP_PEERS_ON_SCORE)
|
||||||
|
drop_connection_with_score(context, 5, false);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------
|
||||||
|
template<class t_core>
|
||||||
std::string t_cryptonote_protocol_handler<t_core>::get_peers_overview() const
|
std::string t_cryptonote_protocol_handler<t_core>::get_peers_overview() const
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
Loading…
Reference in New Issue
Block a user