aboutsummaryrefslogtreecommitdiff
path: root/src/cryptonote_protocol
diff options
context:
space:
mode:
Diffstat (limited to 'src/cryptonote_protocol')
-rw-r--r--src/cryptonote_protocol/block_queue.cpp2
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.h2
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl171
3 files changed, 102 insertions, 73 deletions
diff --git a/src/cryptonote_protocol/block_queue.cpp b/src/cryptonote_protocol/block_queue.cpp
index 610637637..4f760582b 100644
--- a/src/cryptonote_protocol/block_queue.cpp
+++ b/src/cryptonote_protocol/block_queue.cpp
@@ -189,6 +189,8 @@ std::pair<uint64_t, uint64_t> block_queue::reserve_span(uint64_t first_block_hei
++i;
++span_length;
}
+ if (span_length == 0)
+ return std::make_pair(0, 0);
MDEBUG("Reserving span " << span_start_height << " - " << (span_start_height + span_length - 1) << " for " << connection_id);
add_blocks(span_start_height, span_length, connection_id, time);
set_span_hashes(span_start_height, connection_id, hashes);
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h
index dcee03f66..f30aebf3a 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h
@@ -130,6 +130,8 @@ namespace cryptonote
size_t get_synchronizing_connections_count();
bool on_connection_synchronized();
bool should_download_next_span(cryptonote_connection_context& context) const;
+ void drop_connection(cryptonote_connection_context &context, bool add_fail, bool flush_all_spans);
+
t_core& m_core;
nodetool::p2p_endpoint_stub<connection_context> m_p2p_stub;
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index b5a307208..5b3b059a4 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -209,10 +209,10 @@ namespace cryptonote
cnx.support_flags = support_flags;
cnx.recv_count = cntxt.m_recv_cnt;
- cnx.recv_idle_time = timestamp - cntxt.m_last_recv;
+ cnx.recv_idle_time = timestamp - std::max(cntxt.m_started, cntxt.m_last_recv);
cnx.send_count = cntxt.m_send_cnt;
- cnx.send_idle_time = timestamp - cntxt.m_last_send;
+ cnx.send_idle_time = timestamp - std::max(cntxt.m_started, cntxt.m_last_send);
cnx.state = get_protocol_state_string(cntxt.m_state);
@@ -259,10 +259,10 @@ namespace cryptonote
return true;
// from v6, if the peer advertises a top block version, reject if it's not what it should be (will only work if no voting)
- const uint8_t version = m_core.get_blockchain_storage().get_ideal_hard_fork_version(hshd.current_height - 1);
+ const uint8_t version = m_core.get_ideal_hard_fork_version(hshd.current_height - 1);
if (version >= 6 && version != hshd.top_version)
{
- LOG_DEBUG_CC(context, "Ignoring due to wrong top version (" << hshd.top_version << ", expected " << version);
+ LOG_DEBUG_CC(context, "Ignoring due to wrong top version " << (unsigned)hshd.top_version << ", expected " << (unsigned)version);
return false;
}
@@ -308,7 +308,7 @@ namespace cryptonote
bool t_cryptonote_protocol_handler<t_core>::get_payload_sync_data(CORE_SYNC_DATA& hshd)
{
m_core.get_blockchain_top(hshd.current_height, hshd.top_id);
- hshd.top_version = m_core.get_blockchain_storage().get_hard_fork_version(hshd.current_height);
+ hshd.top_version = m_core.get_hard_fork_version(hshd.current_height);
hshd.current_height +=1;
return true;
}
@@ -344,10 +344,9 @@ namespace cryptonote
if(tvc.m_verifivation_failed)
{
LOG_PRINT_CCONTEXT_L1("Block verification failed: transaction verification failed, dropping connection");
- m_p2p->drop_connection(context);
+ drop_connection(context, false, false);
m_core.cleanup_handle_incoming_blocks();
m_core.resume_mine();
- m_block_queue.flush_spans(context.m_connection_id);
return 1;
}
}
@@ -359,9 +358,7 @@ namespace cryptonote
if(bvc.m_verifivation_failed)
{
LOG_PRINT_CCONTEXT_L0("Block verification failed, dropping connection");
- m_p2p->drop_connection(context);
- m_p2p->add_host_fail(context.m_remote_address);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, true, false);
return 1;
}
if(bvc.m_added_to_main_chain)
@@ -414,8 +411,7 @@ namespace cryptonote
<< ", dropping connection"
);
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
m_core.resume_mine();
return 1;
}
@@ -448,8 +444,7 @@ namespace cryptonote
<< ", dropping connection"
);
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
m_core.resume_mine();
return 1;
}
@@ -463,8 +458,7 @@ namespace cryptonote
<< ", dropping connection"
);
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
m_core.resume_mine();
return 1;
}
@@ -488,8 +482,7 @@ namespace cryptonote
<< "dropping connection"
);
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
m_core.resume_mine();
return 1;
}
@@ -506,8 +499,7 @@ namespace cryptonote
if(!m_core.handle_incoming_tx(tx_blob, tvc, true, true, false) || tvc.m_verifivation_failed)
{
LOG_PRINT_CCONTEXT_L1("Block verification failed: transaction verification failed, dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
m_core.resume_mine();
return 1;
}
@@ -529,8 +521,7 @@ namespace cryptonote
<< ", dropping connection"
);
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
m_core.resume_mine();
return 1;
}
@@ -550,8 +541,7 @@ namespace cryptonote
<< ", dropping connection"
);
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
m_core.resume_mine();
return 1;
}
@@ -628,9 +618,7 @@ namespace cryptonote
if( bvc.m_verifivation_failed )
{
LOG_PRINT_CCONTEXT_L0("Block verification failed, dropping connection");
- m_p2p->drop_connection(context);
- m_p2p->add_host_fail(context.m_remote_address);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, true, false);
return 1;
}
if( bvc.m_added_to_main_chain )
@@ -663,8 +651,7 @@ namespace cryptonote
);
m_core.resume_mine();
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
@@ -684,8 +671,7 @@ namespace cryptonote
if (!m_core.get_block_by_hash(arg.block_hash, b))
{
LOG_ERROR_CCONTEXT("failed to find block: " << arg.block_hash << ", dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
@@ -712,8 +698,7 @@ namespace cryptonote
<< ", dropping connection"
);
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
}
@@ -724,16 +709,14 @@ namespace cryptonote
{
LOG_ERROR_CCONTEXT("Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX, "
<< "failed to get requested transactions");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
if (!missed.empty() || txs.size() != txids.size())
{
LOG_ERROR_CCONTEXT("Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX, "
<< missed.size() << " requested transactions not found" << ", dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
@@ -776,8 +759,7 @@ namespace cryptonote
if(tvc.m_verifivation_failed)
{
LOG_PRINT_CCONTEXT_L1("Tx verification failed, dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
if(tvc.m_should_be_relayed)
@@ -803,8 +785,7 @@ namespace cryptonote
if(!m_core.handle_get_objects(arg, rsp, context))
{
LOG_ERROR_CCONTEXT("failed to handle request NOTIFY_REQUEST_GET_OBJECTS, dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
LOG_PRINT_CCONTEXT_L2("-->>NOTIFY_RESPONSE_GET_OBJECTS: blocks.size()=" << rsp.blocks.size() << ", txs.size()=" << rsp.txs.size()
@@ -871,8 +852,7 @@ namespace cryptonote
{
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_HAVE_OBJECTS: arg.m_current_blockchain_height=" << arg.current_blockchain_height
<< " < m_last_response_height=" << context.m_last_response_height << ", dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
@@ -894,16 +874,14 @@ namespace cryptonote
{
LOG_ERROR_CCONTEXT("sent wrong block: failed to parse and validate block: "
<< epee::string_tools::buff_to_hex_nodelimer(block_entry.block) << ", dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
if (b.miner_tx.vin.size() != 1 || b.miner_tx.vin.front().type() != typeid(txin_gen))
{
LOG_ERROR_CCONTEXT("sent wrong block: block: miner tx does not have exactly one txin_gen input"
<< epee::string_tools::buff_to_hex_nodelimer(block_entry.block) << ", dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
if (start_height == std::numeric_limits<uint64_t>::max())
@@ -915,16 +893,14 @@ namespace cryptonote
{
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(block_entry.block))
<< " wasn't requested, dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
if(b.tx_hashes.size() != block_entry.txs.size())
{
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(block_entry.block))
<< ", tx_hashes.size()=" << b.tx_hashes.size() << " mismatch with block_complete_entry.m_txs.size()=" << block_entry.txs.size() << ", dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
@@ -936,8 +912,7 @@ namespace cryptonote
{
MERROR("returned not all requested objects (context.m_requested_objects.size()="
<< context.m_requested_objects.size() << "), dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
@@ -959,6 +934,8 @@ namespace cryptonote
MDEBUG(context << " adding span: " << arg.blocks.size() << " at height " << start_height << ", " << dt.total_microseconds()/1e6 << " seconds, " << (rate/1e3) << " 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);
+ context.m_last_known_hash = cryptonote::get_blob_hash(arg.blocks.back().block);
+
if (m_core.get_test_drop_download() && m_core.get_test_drop_download_height()) { // DISCARD BLOCKS for testing
// We try to lock the sync lock. If we can, it means no other thread is
@@ -990,6 +967,43 @@ namespace cryptonote
MDEBUG(context << " next span in the queue has blocks " << start_height << "-" << (start_height + blocks.size() - 1)
<< ", we need " << previous_height);
+
+ block new_block;
+ if (!parse_and_validate_block_from_blob(blocks.front().block, new_block))
+ {
+ MERROR("Failed to parse block, but it should already have been parsed");
+ break;
+ }
+ bool parent_known = m_core.have_block(new_block.prev_id);
+ if (!parent_known)
+ {
+ // it could be:
+ // - later in the current chain
+ // - later in an alt chain
+ // - orphan
+ // if it was requested, then it'll be resolved later, otherwise it's an orphan
+ bool parent_requested = false;
+ m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool{
+ if (context.m_requested_objects.find(new_block.prev_id) != context.m_requested_objects.end())
+ {
+ parent_requested = true;
+ return false;
+ }
+ return true;
+ });
+ if (!parent_requested)
+ {
+ LOG_ERROR_CCONTEXT("Got block with unknown parent which was not requested - dropping connection");
+ // in case the peer had dropped beforehand, remove the span anyway so other threads can wake up and get it
+ m_block_queue.remove_spans(span_connection_id, start_height);
+ return 1;
+ }
+
+ // parent was requested, so we wait for it to be retrieved
+ MINFO(context << " parent was requested, we'll get back to it");
+ break;
+ }
+
const boost::posix_time::ptime start = boost::posix_time::microsec_clock::universal_time();
m_core.prepare_handle_incoming_blocks(blocks);
@@ -1017,8 +1031,7 @@ namespace cryptonote
if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
LOG_ERROR_CCONTEXT("transaction verification failed on NOTIFY_RESPONSE_GET_OBJECTS, tx_id = "
<< epee::string_tools::pod_to_hex(get_blob_hash(*it)) << ", dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id, true);
+ drop_connection(context, false, true);
return true;
}))
LOG_ERROR_CCONTEXT("span connection id not found");
@@ -1043,9 +1056,7 @@ namespace cryptonote
{
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");
- m_p2p->drop_connection(context);
- m_p2p->add_host_fail(context.m_remote_address);
- m_block_queue.flush_spans(context.m_connection_id, true);
+ drop_connection(context, true, true);
return true;
}))
LOG_ERROR_CCONTEXT("span connection id not found");
@@ -1059,9 +1070,7 @@ namespace cryptonote
{
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");
- m_p2p->drop_connection(context);
- m_p2p->add_host_fail(context.m_remote_address);
- m_block_queue.flush_spans(context.m_connection_id, true);
+ drop_connection(context, true, true);
return true;
}))
LOG_ERROR_CCONTEXT("span connection id not found");
@@ -1111,8 +1120,7 @@ skip:
if (!request_missing_objects(context, true, force_next_span))
{
LOG_ERROR_CCONTEXT("Failed to request missing objects, dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
return 1;
@@ -1132,8 +1140,7 @@ skip:
if(!m_core.find_blockchain_supplement(arg.block_ids, r))
{
LOG_ERROR_CCONTEXT("Failed to handle NOTIFY_REQUEST_CHAIN.");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
LOG_PRINT_CCONTEXT_L2("-->>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());
@@ -1462,9 +1469,7 @@ skip:
if(!arg.m_block_ids.size())
{
LOG_ERROR_CCONTEXT("sent empty m_block_ids, dropping connection");
- m_p2p->drop_connection(context);
- m_p2p->add_host_fail(context.m_remote_address);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, true, false);
return 1;
}
@@ -1475,8 +1480,7 @@ skip:
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_CHAIN_ENTRY, with m_total_height=" << arg.total_height
<< ", m_start_height=" << arg.start_height
<< ", m_block_ids.size()=" << arg.m_block_ids.size());
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
@@ -1484,13 +1488,11 @@ skip:
{
context.m_needed_objects.push_back(bl_id);
}
- context.m_last_known_hash = context.m_needed_objects.back();
if (!request_missing_objects(context, false))
{
LOG_ERROR_CCONTEXT("Failed to request missing objects, dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, false, false);
return 1;
}
return 1;
@@ -1546,6 +1548,29 @@ skip:
m_core.on_transaction_relayed(*tx_blob_it);
return relay_post_notify<NOTIFY_NEW_TRANSACTIONS>(arg, exclude_context);
}
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
+ void t_cryptonote_protocol_handler<t_core>::drop_connection(cryptonote_connection_context &context, bool add_fail, bool flush_all_spans)
+ {
+ if (add_fail)
+ m_p2p->add_host_fail(context.m_remote_address);
+ m_p2p->drop_connection(context);
+
+ uint64_t target = 0;
+ m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags) {
+ if (cntxt.m_state >= cryptonote_connection_context::state_synchronizing && cntxt.m_connection_id != context.m_connection_id)
+ target = std::max(target, cntxt.m_remote_blockchain_height);
+ return true;
+ });
+ const uint64_t previous_target = m_core.get_target_blockchain_height();
+ if (target < previous_target)
+ {
+ MINFO("Target height decreasing from " << previous_target << " to " << target);
+ m_core.set_target_blockchain_height(target);
+ }
+
+ m_block_queue.flush_spans(context.m_connection_id, flush_all_spans);
+ }
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>