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.inl199
1 files changed, 117 insertions, 82 deletions
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index 4652bf23e..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);
@@ -239,6 +239,8 @@ namespace cryptonote
cnx.connection_id = cntxt.m_connection_id;
+ cnx.height = cntxt.m_remote_blockchain_height;
+
connections.push_back(cnx);
return true;
@@ -256,6 +258,16 @@ namespace cryptonote
if(context.m_state == cryptonote_connection_context::state_synchronizing)
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_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 " << (unsigned)hshd.top_version << ", expected " << (unsigned)version);
+ return false;
+ }
+
+ context.m_remote_blockchain_height = hshd.current_height;
+
uint64_t target = m_core.get_target_blockchain_height();
if (target == 0)
target = m_core.get_current_blockchain_height();
@@ -285,7 +297,6 @@ namespace cryptonote
}
LOG_PRINT_L1("Remote blockchain height: " << hshd.current_height << ", id: " << hshd.top_id);
context.m_state = cryptonote_connection_context::state_synchronizing;
- context.m_remote_blockchain_height = hshd.current_height;
//let the socket to send response to handshake, but request callback, to let send request data after response
LOG_PRINT_CCONTEXT_L2("requesting callback");
++context.m_callback_request_count;
@@ -297,6 +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_hard_fork_version(hshd.current_height);
hshd.current_height +=1;
return true;
}
@@ -332,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;
}
}
@@ -347,8 +358,7 @@ namespace cryptonote
if(bvc.m_verifivation_failed)
{
LOG_PRINT_CCONTEXT_L0("Block verification failed, dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, true, false);
return 1;
}
if(bvc.m_added_to_main_chain)
@@ -401,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;
}
@@ -435,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;
}
@@ -450,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;
}
@@ -475,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;
}
@@ -493,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;
}
@@ -516,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;
}
@@ -537,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;
}
@@ -615,8 +618,7 @@ namespace cryptonote
if( bvc.m_verifivation_failed )
{
LOG_PRINT_CCONTEXT_L0("Block verification failed, dropping connection");
- m_p2p->drop_connection(context);
- m_block_queue.flush_spans(context.m_connection_id);
+ drop_connection(context, true, false);
return 1;
}
if( bvc.m_added_to_main_chain )
@@ -649,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;
}
@@ -670,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;
}
@@ -698,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;
}
}
@@ -710,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;
}
@@ -762,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)
@@ -789,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()
@@ -857,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;
}
@@ -880,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())
@@ -901,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;
}
@@ -922,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;
}
@@ -936,7 +925,8 @@ namespace cryptonote
}
{
- MLOG_YELLOW(el::Level::Debug, "Got NEW BLOCKS inside of " << __FUNCTION__ << ": size: " << arg.blocks.size());
+ MLOG_YELLOW(el::Level::Debug, context << " Got NEW BLOCKS inside of " << __FUNCTION__ << ": size: " << arg.blocks.size()
+ << ", blocks: " << start_height << " - " << (start_height + arg.blocks.size() - 1));
// add that new span to the block queue
const boost::posix_time::time_duration dt = now - context.m_last_request_time;
@@ -944,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
@@ -967,7 +959,6 @@ namespace cryptonote
uint64_t start_height;
std::list<cryptonote::block_complete_entry> blocks;
boost::uuids::uuid span_connection_id;
- m_block_queue.mark_last_block(previous_height - 1);
if (!m_block_queue.get_next_span(start_height, blocks, span_connection_id))
{
MDEBUG(context << " no next span found, going back to download");
@@ -975,9 +966,41 @@ namespace cryptonote
}
MDEBUG(context << " next span in the queue has blocks " << start_height << "-" << (start_height + blocks.size() - 1)
<< ", we need " << previous_height);
- if (previous_height < start_height || previous_height >= start_height + blocks.size())
+
+
+ block new_block;
+ if (!parse_and_validate_block_from_blob(blocks.front().block, new_block))
{
- MDEBUG(context << " this span is not what we need, going back to download");
+ 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;
}
@@ -1008,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");
@@ -1034,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");
@@ -1050,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");
@@ -1072,7 +1090,7 @@ namespace cryptonote
m_core.cleanup_handle_incoming_blocks();
- m_block_queue.mark_last_block(m_core.get_current_blockchain_height() - 1);
+ m_block_queue.remove_spans(span_connection_id, start_height);
if (m_core.get_current_blockchain_height() > previous_height)
{
@@ -1102,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;
@@ -1123,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());
@@ -1190,8 +1206,6 @@ skip:
template<class t_core>
bool t_cryptonote_protocol_handler<t_core>::request_missing_objects(cryptonote_connection_context& context, bool check_having_blocks, bool force_next_span)
{
- m_block_queue.mark_last_block(m_core.get_current_blockchain_height() - 1);
-
// flush stale spans
std::set<boost::uuids::uuid> live_connections;
m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool{
@@ -1297,8 +1311,13 @@ skip:
context.m_last_response_height = 0;
goto skip;
}
+ // take out blocks we already have
+ while (!context.m_needed_objects.empty() && m_core.have_block(context.m_needed_objects.front()))
+ {
+ context.m_needed_objects.pop_front();
+ }
const uint64_t first_block_height = context.m_last_response_height - context.m_needed_objects.size() + 1;
- span = m_block_queue.reserve_span(first_block_height, context.m_last_response_height, count_limit, context.m_connection_id);
+ span = m_block_queue.reserve_span(first_block_height, context.m_last_response_height, count_limit, context.m_connection_id, context.m_needed_objects);
MDEBUG(context << " span from " << first_block_height << ": " << span.first << "/" << span.second);
}
if (span.second == 0 && !force_next_span)
@@ -1349,8 +1368,6 @@ skip:
auto j = it++;
context.m_needed_objects.erase(j);
}
-
- m_block_queue.set_span_hashes(span.first, context.m_connection_id, hashes);
}
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
@@ -1373,10 +1390,9 @@ skip:
if (!start_from_current_chain)
{
- // we'll want to start off from where we are on the download side, which may not be added yet
- crypto::hash last_known_hash = m_block_queue.get_last_known_hash();
- if (last_known_hash != cryptonote::null_hash && r.block_ids.front() != last_known_hash)
- r.block_ids.push_front(last_known_hash);
+ // 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 != cryptonote::null_hash && r.block_ids.front() != context.m_last_known_hash)
+ r.block_ids.push_front(context.m_last_known_hash);
}
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
@@ -1453,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;
}
@@ -1466,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;
}
@@ -1479,8 +1492,7 @@ skip:
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;
@@ -1536,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>