aboutsummaryrefslogtreecommitdiff
path: root/src/cryptonote_protocol/cryptonote_protocol_handler.inl
diff options
context:
space:
mode:
Diffstat (limited to 'src/cryptonote_protocol/cryptonote_protocol_handler.inl')
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl117
1 files changed, 102 insertions, 15 deletions
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index 25b14d903..e2598e382 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -141,6 +141,7 @@ namespace cryptonote
{
NOTIFY_REQUEST_CHAIN::request r = {};
context.m_needed_objects.clear();
+ context.m_expect_height = m_core.get_current_blockchain_height();
m_core.get_short_chain_history(r.block_ids);
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
r.prune = m_sync_pruned_blocks;
@@ -425,7 +426,7 @@ namespace cryptonote
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
- bool t_cryptonote_protocol_handler<t_core>::get_payload_sync_data(blobdata& data)
+ bool t_cryptonote_protocol_handler<t_core>::get_payload_sync_data(epee::byte_slice& data)
{
CORE_SYNC_DATA hsd = {};
get_payload_sync_data(hsd);
@@ -493,6 +494,7 @@ namespace cryptonote
context.m_needed_objects.clear();
context.m_state = cryptonote_connection_context::state_synchronizing;
NOTIFY_REQUEST_CHAIN::request r = {};
+ context.m_expect_height = m_core.get_current_blockchain_height();
m_core.get_short_chain_history(r.block_ids);
r.prune = m_sync_pruned_blocks;
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
@@ -773,6 +775,7 @@ namespace cryptonote
context.m_needed_objects.clear();
context.m_state = cryptonote_connection_context::state_synchronizing;
NOTIFY_REQUEST_CHAIN::request r = {};
+ context.m_expect_height = m_core.get_current_blockchain_height();
m_core.get_short_chain_history(r.block_ids);
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
r.prune = m_sync_pruned_blocks;
@@ -1168,7 +1171,16 @@ namespace cryptonote
return 1;
}
if (start_height == std::numeric_limits<uint64_t>::max())
+ {
start_height = boost::get<txin_gen>(b.miner_tx.vin[0]).height;
+ if (start_height > context.m_expect_height)
+ {
+ LOG_ERROR_CCONTEXT("sent block ahead of expected height, dropping connection");
+ drop_connection(context, false, false);
+ ++m_sync_bad_spans_downloaded;
+ return 1;
+ }
+ }
auto req_it = context.m_requested_objects.find(block_hash);
if(req_it == context.m_requested_objects.end())
@@ -1257,7 +1269,7 @@ namespace cryptonote
const boost::posix_time::time_duration dt = now - request_time;
const float rate = size * 1e6 / (dt.total_microseconds() + 1);
MDEBUG(context << " adding span: " << arg.blocks.size() << " at height " << start_height << ", " << dt.total_microseconds()/1e6 << " seconds, " << (rate/1024) << " kB/s, size now " << (m_block_queue.get_data_size() + blocks_size) / 1048576.f << " MB");
- m_block_queue.add_blocks(start_height, arg.blocks, context.m_connection_id, rate, blocks_size);
+ m_block_queue.add_blocks(start_height, arg.blocks, context.m_connection_id, context.m_remote_address, rate, blocks_size);
const crypto::hash last_block_hash = cryptonote::get_block_hash(b);
context.m_last_known_hash = last_block_hash;
@@ -1358,7 +1370,8 @@ namespace cryptonote
uint64_t start_height;
std::vector<cryptonote::block_complete_entry> blocks;
boost::uuids::uuid span_connection_id;
- if (!m_block_queue.get_next_span(start_height, blocks, span_connection_id))
+ epee::net_utils::network_address span_origin;
+ if (!m_block_queue.get_next_span(start_height, blocks, span_connection_id, span_origin))
{
MDEBUG(context << " no next span found, going back to download");
break;
@@ -1456,6 +1469,7 @@ namespace cryptonote
if (!m_core.prepare_handle_incoming_blocks(blocks, pblocks))
{
LOG_ERROR_CCONTEXT("Failure in prepare_handle_incoming_blocks");
+ drop_connections(span_origin);
return 1;
}
if (!pblocks.empty() && pblocks.size() != blocks.size())
@@ -1495,6 +1509,7 @@ namespace cryptonote
{
if(tvc[i].m_verifivation_failed)
{
+ drop_connections(span_origin);
if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
cryptonote::transaction tx;
crypto::hash txid;
@@ -1536,6 +1551,7 @@ namespace cryptonote
if(bvc.m_verifivation_failed)
{
+ drop_connections(span_origin);
if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
LOG_PRINT_CCONTEXT_L1("Block verification failed, dropping connection");
drop_connection_with_score(context, bvc.m_bad_pow ? P2P_IP_FAILS_BEFORE_BLOCK : 1, true);
@@ -1555,6 +1571,7 @@ namespace cryptonote
}
if(bvc.m_marked_as_orphaned)
{
+ drop_connections(span_origin);
if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
LOG_PRINT_CCONTEXT_L1("Block received at sync phase was marked as orphaned, dropping connection");
drop_connection(context, true, true);
@@ -1709,6 +1726,7 @@ skip:
LOG_PRINT_CCONTEXT_L2("requesting callback");
context.m_last_request_time = boost::date_time::not_a_date_time;
context.m_expect_response = 0;
+ context.m_expect_height = 0;
context.m_state = cryptonote_connection_context::state_standby; // we'll go back to adding, then (if we can't), download
++context.m_callback_request_count;
m_p2p->request_callback(context);
@@ -1808,6 +1826,16 @@ skip:
LOG_ERROR_CCONTEXT("Failed to handle NOTIFY_REQUEST_CHAIN.");
return 1;
}
+ if (r.m_block_ids.size() >= 2)
+ {
+ cryptonote::block b;
+ if (!m_core.get_block_by_hash(r.m_block_ids[1], b))
+ {
+ LOG_ERROR_CCONTEXT("Failed to handle NOTIFY_REQUEST_CHAIN: first block not found");
+ return 1;
+ }
+ r.first_block = cryptonote::block_to_blob(b);
+ }
MLOG_P2P_MESSAGE("-->>NOTIFY_RESPONSE_CHAIN_ENTRY: m_start_height=" << r.start_height << ", m_total_height=" << r.total_height << ", m_block_ids.size()=" << r.m_block_ids.size());
post_notify<NOTIFY_RESPONSE_CHAIN_ENTRY>(r, context);
return 1;
@@ -1992,7 +2020,7 @@ skip:
if (local_stripe == 0)
return false;
// don't request pre-bulletprooof pruned blocks, we can't reconstruct their weight (yet)
- static const uint64_t bp_fork_height = m_core.get_earliest_ideal_height_for_version(HF_VERSION_SMALLER_BP);
+ static const uint64_t bp_fork_height = m_core.get_earliest_ideal_height_for_version(HF_VERSION_SMALLER_BP + 1);
if (first_block_height < bp_fork_height)
return false;
// assumes the span size is less or equal to the stripe size
@@ -2173,7 +2201,7 @@ skip:
const uint64_t first_block_height = context.m_last_response_height - context.m_needed_objects.size() + 1;
static const uint64_t bp_fork_height = m_core.get_earliest_ideal_height_for_version(8);
bool sync_pruned_blocks = m_sync_pruned_blocks && first_block_height >= bp_fork_height && m_core.get_blockchain_pruning_seed();
- span = m_block_queue.reserve_span(first_block_height, context.m_last_response_height, count_limit, context.m_connection_id, sync_pruned_blocks, m_core.get_blockchain_pruning_seed(), context.m_pruning_seed, context.m_remote_blockchain_height, context.m_needed_objects);
+ span = m_block_queue.reserve_span(first_block_height, context.m_last_response_height, count_limit, context.m_connection_id, context.m_remote_address, sync_pruned_blocks, m_core.get_blockchain_pruning_seed(), context.m_pruning_seed, context.m_remote_blockchain_height, context.m_needed_objects);
MDEBUG(context << " span from " << first_block_height << ": " << span.first << "/" << span.second);
if (span.second > 0)
{
@@ -2254,6 +2282,7 @@ skip:
}
}
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
+ context.m_expect_height = span.first;
context.m_expect_response = NOTIFY_RESPONSE_GET_OBJECTS::ID;
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_GET_OBJECTS: blocks.size()=" << req.blocks.size()
<< "requested blocks count=" << count << " / " << count_limit << " from " << span.first << ", first hash " << req.blocks.front());
@@ -2309,8 +2338,8 @@ skip:
uint64_t start_height;
std::vector<cryptonote::block_complete_entry> blocks;
boost::uuids::uuid span_connection_id;
- bool filled = false;
- if (m_block_queue.get_next_span(start_height, blocks, span_connection_id, filled) && filled)
+ epee::net_utils::network_address span_origin;
+ if (m_block_queue.get_next_span(start_height, blocks, span_connection_id, span_origin, true))
{
LOG_DEBUG_CC(context, "No other thread is adding blocks, resuming");
MLOG_PEER_STATE("will try to add blocks next");
@@ -2326,6 +2355,7 @@ skip:
{//we have to fetch more objects ids, request blockchain entry
NOTIFY_REQUEST_CHAIN::request r = {};
+ context.m_expect_height = m_core.get_current_blockchain_height();
m_core.get_short_chain_history(r.block_ids);
CHECK_AND_ASSERT_MES(!r.block_ids.empty(), false, "Short chain history is empty");
@@ -2333,7 +2363,10 @@ skip:
{
// we'll want to start off from where we are on that peer, which may not be added yet
if (context.m_last_known_hash != crypto::null_hash && r.block_ids.front() != context.m_last_known_hash)
+ {
+ context.m_expect_height = std::numeric_limits<uint64_t>::max();
r.block_ids.push_front(context.m_last_known_hash);
+ }
}
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
@@ -2475,6 +2508,12 @@ skip:
return 1;
}
context.m_expect_response = 0;
+ if (arg.start_height + 1 > context.m_expect_height) // we expect an overlapping block
+ {
+ LOG_ERROR_CCONTEXT("Got NOTIFY_RESPONSE_CHAIN_ENTRY past expected height, dropping connection");
+ drop_connection(context, true, false);
+ return 1;
+ }
context.m_last_request_time = boost::date_time::not_a_date_time;
@@ -2500,7 +2539,7 @@ skip:
}
MDEBUG(context << "first block hash " << arg.m_block_ids.front() << ", last " << arg.m_block_ids.back());
- if (arg.total_height >= CRYPTONOTE_MAX_BLOCK_NUMBER || arg.m_block_ids.size() >= CRYPTONOTE_MAX_BLOCK_NUMBER)
+ if (arg.total_height >= CRYPTONOTE_MAX_BLOCK_NUMBER || arg.m_block_ids.size() > BLOCKS_IDS_SYNCHRONIZING_MAX_COUNT)
{
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_CHAIN_ENTRY, with total_height=" << arg.total_height << " and block_ids=" << arg.m_block_ids.size());
drop_connection(context, false, false);
@@ -2522,8 +2561,19 @@ skip:
return 1;
}
+ std::unordered_set<crypto::hash> hashes;
+ for (const auto &h: arg.m_block_ids)
+ {
+ if (!hashes.insert(h).second)
+ {
+ LOG_ERROR_CCONTEXT("sent duplicate block, dropping connection");
+ drop_connection(context, true, false);
+ return 1;
+ }
+ }
+
uint64_t n_use_blocks = m_core.prevalidate_block_hashes(arg.start_height, arg.m_block_ids, arg.m_block_weights);
- if (n_use_blocks + HASH_OF_HASHES_STEP <= arg.m_block_ids.size())
+ if (n_use_blocks == 0 || n_use_blocks + HASH_OF_HASHES_STEP <= arg.m_block_ids.size())
{
LOG_ERROR_CCONTEXT("Most blocks are invalid, dropping connection");
drop_connection(context, true, false);
@@ -2532,8 +2582,15 @@ skip:
context.m_needed_objects.clear();
uint64_t added = 0;
+ std::unordered_set<crypto::hash> blocks_found;
for (size_t i = 0; i < arg.m_block_ids.size(); ++i)
{
+ if (!blocks_found.insert(arg.m_block_ids[i]).second)
+ {
+ LOG_ERROR_CCONTEXT("Duplicate blocks in chain entry response, dropping connection");
+ drop_connection(context, true, false);
+ return 1;
+ }
const uint64_t block_weight = arg.m_block_weights.empty() ? 0 : arg.m_block_weights[i];
context.m_needed_objects.push_back(std::make_pair(arg.m_block_ids[i], block_weight));
if (++added == n_use_blocks)
@@ -2586,15 +2643,15 @@ skip:
// send fluffy ones first, we want to encourage people to run that
if (!fluffyConnections.empty())
{
- std::string fluffyBlob;
- epee::serialization::store_t_to_binary(fluffy_arg, fluffyBlob);
- m_p2p->relay_notify_to_list(NOTIFY_NEW_FLUFFY_BLOCK::ID, epee::strspan<uint8_t>(fluffyBlob), std::move(fluffyConnections));
+ epee::byte_slice fluffyBlob;
+ epee::serialization::store_t_to_binary(fluffy_arg, fluffyBlob, 32 * 1024);
+ m_p2p->relay_notify_to_list(NOTIFY_NEW_FLUFFY_BLOCK::ID, epee::to_span(fluffyBlob), std::move(fluffyConnections));
}
if (!fullConnections.empty())
{
- std::string fullBlob;
- epee::serialization::store_t_to_binary(arg, fullBlob);
- m_p2p->relay_notify_to_list(NOTIFY_NEW_BLOCK::ID, epee::strspan<uint8_t>(fullBlob), std::move(fullConnections));
+ epee::byte_slice fullBlob;
+ epee::serialization::store_t_to_binary(arg, fullBlob, 128 * 1024);
+ m_p2p->relay_notify_to_list(NOTIFY_NEW_BLOCK::ID, epee::to_span(fullBlob), std::move(fullConnections));
}
return true;
@@ -2714,6 +2771,13 @@ skip:
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
+ bool t_cryptonote_protocol_handler<t_core>::is_busy_syncing()
+ {
+ const boost::unique_lock<boost::mutex> sync{m_sync_lock, boost::try_to_lock};
+ return !sync.owns_lock();
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
void t_cryptonote_protocol_handler<t_core>::drop_connection_with_score(cryptonote_connection_context &context, unsigned score, bool flush_all_spans)
{
LOG_DEBUG_CC(context, "dropping connection id " << context.m_connection_id << " (pruning seed " <<
@@ -2735,6 +2799,29 @@ skip:
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
+ void t_cryptonote_protocol_handler<t_core>::drop_connections(const epee::net_utils::network_address address)
+ {
+ MWARNING("dropping connections to " << address.str());
+
+ m_p2p->add_host_fail(address, 5);
+
+ std::vector<boost::uuids::uuid> drop;
+ m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags) {
+ if (address.is_same_host(cntxt.m_remote_address))
+ drop.push_back(cntxt.m_connection_id);
+ return true;
+ });
+ for (const boost::uuids::uuid &id: drop)
+ {
+ m_block_queue.flush_spans(id, true);
+ m_p2p->for_connection(id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
+ drop_connection(context, true, false);
+ return true;
+ });
+ }
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
void t_cryptonote_protocol_handler<t_core>::on_connection_close(cryptonote_connection_context &context)
{
uint64_t target = 0;