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.inl579
1 files changed, 506 insertions, 73 deletions
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index 6dfc9fbc5..79578a34e 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -2,7 +2,7 @@
/// @author rfree (current maintainer/user in monero.cc project - most of code is from CryptoNote)
/// @brief This is the orginal cryptonote protocol network-events handler, modified by us
-// Copyright (c) 2014-2016, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
@@ -37,20 +37,19 @@
#include <boost/interprocess/detail/atomic.hpp>
#include <list>
+#include <unordered_map>
-#include "cryptonote_core/cryptonote_format_utils.h"
+#include "cryptonote_basic/cryptonote_format_utils.h"
#include "profile_tools.h"
-#include "../../contrib/otshell_utils/utils.hpp"
#include "../../src/p2p/network_throttle-detail.hpp"
-#include "../../src/p2p/data_logger.hpp"
-using namespace nOT::nUtils;
-namespace cryptonote
-{
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "net.cn"
+#define MLOG_P2P_MESSAGE(x) MCINFO("net.p2p.msg", context << x)
-// static
-// template<class t_core> std::ofstream t_cryptonote_protocol_handler<t_core>::m_logreq("logreq.txt"); // static
+namespace cryptonote
+{
@@ -59,7 +58,8 @@ namespace cryptonote
t_cryptonote_protocol_handler<t_core>::t_cryptonote_protocol_handler(t_core& rcore, nodetool::i_p2p_endpoint<connection_context>* p_net_layout):m_core(rcore),
m_p2p(p_net_layout),
m_syncronized_connections_count(0),
- m_synchronized(false)
+ m_synchronized(false),
+ m_stopping(false)
{
if(!m_p2p)
@@ -75,8 +75,6 @@ namespace cryptonote
template<class t_core>
bool t_cryptonote_protocol_handler<t_core>::deinit()
{
-
-
return true;
}
//------------------------------------------------------------------------------------------------------------------------
@@ -126,6 +124,7 @@ namespace cryptonote
ss << std::setw(30) << std::left << "Remote Host"
<< std::setw(20) << "Peer id"
+ << std::setw(20) << "Support Flags"
<< std::setw(30) << "Recv/Sent (inactive,sec)"
<< std::setw(25) << "State"
<< std::setw(20) << "Livetime(sec)"
@@ -136,7 +135,7 @@ namespace cryptonote
<< ENDL;
uint32_t ip;
- m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id)
+ m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags)
{
bool local_ip = false;
ip = ntohl(cntxt.m_remote_ip);
@@ -147,6 +146,7 @@ namespace cryptonote
ss << std::setw(30) << std::left << std::string(cntxt.m_is_income ? " [INC]":"[OUT]") +
epee::string_tools::get_ip_string_from_int32(cntxt.m_remote_ip) + ":" + std::to_string(cntxt.m_remote_port)
<< std::setw(20) << std::hex << peer_id
+ << std::setw(20) << std::hex << support_flags
<< std::setw(30) << std::to_string(cntxt.m_recv_cnt)+ "(" + std::to_string(time(NULL) - cntxt.m_last_recv) + ")" + "/" + std::to_string(cntxt.m_send_cnt) + "(" + std::to_string(time(NULL) - cntxt.m_last_send) + ")"
<< std::setw(25) << get_protocol_state_string(cntxt.m_state)
<< std::setw(20) << std::to_string(time(NULL) - cntxt.m_started)
@@ -186,7 +186,7 @@ namespace cryptonote
{
std::list<connection_info> connections;
- m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id)
+ m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags)
{
connection_info cnx;
auto timestamp = time(NULL);
@@ -199,6 +199,8 @@ namespace cryptonote
std::stringstream peer_id_str;
peer_id_str << std::hex << peer_id;
peer_id_str >> cnx.peer_id;
+
+ cnx.support_flags = support_flags;
cnx.recv_count = cntxt.m_recv_cnt;
cnx.recv_idle_time = timestamp - cntxt.m_last_recv;
@@ -263,27 +265,33 @@ namespace cryptonote
if(context.m_state == cryptonote_connection_context::state_synchronizing)
return true;
- if(m_core.have_block(hshd.top_id) && !(hshd.current_height < m_core.get_target_blockchain_height()))
+ uint64_t target = m_core.get_target_blockchain_height();
+ if (target == 0)
+ target = m_core.get_current_blockchain_height();
+
+ if(m_core.have_block(hshd.top_id))
{
context.m_state = cryptonote_connection_context::state_normal;
- if(is_inital)
+ if(is_inital && target == m_core.get_current_blockchain_height())
on_connection_synchronized();
return true;
}
+ if (hshd.current_height > target)
+ {
/* As I don't know if accessing hshd from core could be a good practice,
I prefer pushing target height to the core at the same time it is pushed to the user.
Nz. */
m_core.set_target_blockchain_height(static_cast<int64_t>(hshd.current_height));
-
int64_t diff = static_cast<int64_t>(hshd.current_height) - static_cast<int64_t>(m_core.get_current_blockchain_height());
int64_t max_block_height = max(static_cast<int64_t>(hshd.current_height),static_cast<int64_t>(m_core.get_current_blockchain_height()));
int64_t last_block_v1 = 1009826;
int64_t diff_v2 = max_block_height > last_block_v1 ? min(abs(diff), max_block_height - last_block_v1) : 0;
- LOG_PRINT_CCONTEXT_YELLOW("Sync data returned unknown top block: " << m_core.get_current_blockchain_height() << " -> " << hshd.current_height
- << " [" << std::abs(diff) << " blocks (" << ((abs(diff) - diff_v2) / (24 * 60 * 60 / DIFFICULTY_TARGET_V1)) + (diff_v2 / (24 * 60 * 60 / DIFFICULTY_TARGET_V2)) << " days) "
+ MCLOG(is_inital ? el::Level::Info : el::Level::Debug, "global", context << "Sync data returned a new top block candidate: " << m_core.get_current_blockchain_height() << " -> " << hshd.current_height
+ << " [Your node is " << std::abs(diff) << " blocks (" << ((abs(diff) - diff_v2) / (24 * 60 * 60 / DIFFICULTY_TARGET_V1)) + (diff_v2 / (24 * 60 * 60 / DIFFICULTY_TARGET_V2)) << " days) "
<< (0 <= diff ? std::string("behind") : std::string("ahead"))
- << "] " << ENDL << "SYNCHRONIZATION started", (is_inital ? LOG_LEVEL_0:LOG_LEVEL_1));
+ << "] " << ENDL << "SYNCHRONIZATION started");
+ }
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;
@@ -314,7 +322,7 @@ namespace cryptonote
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)
{
- LOG_PRINT_CCONTEXT_L2("NOTIFY_NEW_BLOCK (hop " << arg.hop << ")");
+ MLOG_P2P_MESSAGE("Received NOTIFY_NEW_BLOCK (hop " << arg.hop << ", " << arg.b.txs.size() << " txes)");
if(context.m_state != cryptonote_connection_context::state_normal)
return 1;
m_core.pause_mine();
@@ -324,7 +332,7 @@ namespace cryptonote
for(auto tx_blob_it = arg.b.txs.begin(); tx_blob_it!=arg.b.txs.end();tx_blob_it++)
{
cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
- m_core.handle_incoming_tx(*tx_blob_it, tvc, true, true);
+ m_core.handle_incoming_tx(*tx_blob_it, tvc, true, true, false);
if(tvc.m_verifivation_failed)
{
LOG_PRINT_CCONTEXT_L1("Block verification failed: transaction verification failed, dropping connection");
@@ -363,16 +371,370 @@ namespace cryptonote
}
//------------------------------------------------------------------------------------------------------------------------
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)
+ {
+ MLOG_P2P_MESSAGE("Received NOTIFY_NEW_FLUFFY_BLOCK (height " << arg.current_blockchain_height << ", hop " << arg.hop << ", " << arg.b.txs.size() << " txes)");
+ if(context.m_state != cryptonote_connection_context::state_normal)
+ return 1;
+
+ m_core.pause_mine();
+
+ block new_block;
+ transaction miner_tx;
+ if(parse_and_validate_block_from_blob(arg.b.block, new_block))
+ {
+ // This is a second notification, we must have asked for some missing tx
+ if(!context.m_requested_objects.empty())
+ {
+ // What we asked for != to what we received ..
+ if(context.m_requested_objects.size() != arg.b.txs.size())
+ {
+ LOG_ERROR_CCONTEXT
+ (
+ "NOTIFY_NEW_FLUFFY_BLOCK -> request/response mismatch, "
+ << "block = " << epee::string_tools::pod_to_hex(get_blob_hash(arg.b.block))
+ << ", requested = " << context.m_requested_objects.size()
+ << ", received = " << new_block.tx_hashes.size()
+ << ", dropping connection"
+ );
+
+ m_p2p->drop_connection(context);
+ m_core.resume_mine();
+ return 1;
+ }
+ }
+
+ std::list<blobdata> have_tx;
+
+ // Instead of requesting missing transactions by hash like BTC,
+ // we do it by index (thanks to a suggestion from moneromooo) because
+ // we're way cooler .. and also because they're smaller than hashes.
+ //
+ // Also, remember to pepper some whitespace changes around to bother
+ // moneromooo ... only because I <3 him.
+ std::vector<size_t> need_tx_indices;
+
+ transaction tx;
+ crypto::hash tx_hash;
+
+ for(auto& tx_blob: arg.b.txs)
+ {
+ if(parse_and_validate_tx_from_blob(tx_blob, tx))
+ {
+ try
+ {
+ if(!get_transaction_hash(tx, tx_hash))
+ {
+ LOG_PRINT_CCONTEXT_L1
+ (
+ "NOTIFY_NEW_FLUFFY_BLOCK: get_transaction_hash failed"
+ << ", dropping connection"
+ );
+
+ m_p2p->drop_connection(context);
+ m_core.resume_mine();
+ return 1;
+ }
+ }
+ catch(...)
+ {
+ LOG_PRINT_CCONTEXT_L1
+ (
+ "NOTIFY_NEW_FLUFFY_BLOCK: get_transaction_hash failed"
+ << ", exception thrown"
+ << ", dropping connection"
+ );
+
+ m_p2p->drop_connection(context);
+ m_core.resume_mine();
+ return 1;
+ }
+
+ // hijacking m_requested objects in connection context to patch up
+ // a possible DOS vector pointed out by @monero-moo where peers keep
+ // sending (0...n-1) transactions.
+ // If requested objects is not empty, then we must have asked for
+ // some missing transacionts, make sure that they're all there.
+ //
+ // Can I safely re-use this field? I think so, but someone check me!
+ if(!context.m_requested_objects.empty())
+ {
+ auto req_tx_it = context.m_requested_objects.find(tx_hash);
+ if(req_tx_it == context.m_requested_objects.end())
+ {
+ LOG_ERROR_CCONTEXT
+ (
+ "Peer sent wrong transaction (NOTIFY_NEW_FLUFFY_BLOCK): "
+ << "transaction with id = " << tx_hash << " wasn't requested, "
+ << "dropping connection"
+ );
+
+ m_p2p->drop_connection(context);
+ m_core.resume_mine();
+ return 1;
+ }
+
+ context.m_requested_objects.erase(req_tx_it);
+ }
+
+ // we might already have the tx that the peer
+ // sent in our pool, so don't verify again..
+ if(!m_core.get_pool_transaction(tx_hash, tx))
+ {
+ MDEBUG("Incoming tx " << tx_hash << " not in pool, adding");
+ cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
+ 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_core.resume_mine();
+ return 1;
+ }
+
+ //
+ // future todo:
+ // tx should only not be added to pool if verification failed, but
+ // maybe in the future could not be added for other reasons
+ // according to monero-moo so keep track of these separately ..
+ //
+ }
+ }
+ else
+ {
+ LOG_ERROR_CCONTEXT
+ (
+ "sent wrong tx: failed to parse and validate transaction: "
+ << epee::string_tools::buff_to_hex_nodelimer(tx_blob)
+ << ", dropping connection"
+ );
+
+ m_p2p->drop_connection(context);
+ m_core.resume_mine();
+ return 1;
+ }
+ }
+
+ // The initial size equality check could have been fooled if the sender
+ // gave us the number of transactions we asked for, but not the right
+ // ones. This check make sure the transactions we asked for were the
+ // ones we received.
+ if(context.m_requested_objects.size())
+ {
+ MERROR
+ (
+ "NOTIFY_NEW_FLUFFY_BLOCK: peer sent the number of transaction requested"
+ << ", but not the actual transactions requested"
+ << ", context.m_requested_objects.size() = " << context.m_requested_objects.size()
+ << ", dropping connection"
+ );
+
+ m_p2p->drop_connection(context);
+ m_core.resume_mine();
+ return 1;
+ }
+
+ size_t tx_idx = 0;
+ for(auto& tx_hash: new_block.tx_hashes)
+ {
+ if(m_core.get_pool_transaction(tx_hash, tx))
+ {
+ have_tx.push_back(tx_to_blob(tx));
+ }
+ else
+ {
+ std::vector<crypto::hash> tx_ids;
+ std::list<transaction> txes;
+ std::list<crypto::hash> missing;
+ tx_ids.push_back(tx_hash);
+ if (m_core.get_transactions(tx_ids, txes, missing) && missing.empty())
+ {
+ if (txes.size() == 1)
+ {
+ have_tx.push_back(tx_to_blob(txes.front()));
+ }
+ else
+ {
+ MERROR("1 tx requested, none not found, but " << txes.size() << " returned");
+ m_core.resume_mine();
+ return 1;
+ }
+ }
+ else
+ {
+ MDEBUG("Tx " << tx_hash << " not found in pool");
+ need_tx_indices.push_back(tx_idx);
+ }
+ }
+
+ ++tx_idx;
+ }
+
+ if(!need_tx_indices.empty()) // drats, we don't have everything..
+ {
+ // request non-mempool txs
+ MDEBUG("We are missing " << need_tx_indices.size() << " txes for this fluffy block");
+ for (auto txidx: need_tx_indices)
+ MDEBUG(" tx " << new_block.tx_hashes[txidx]);
+ NOTIFY_REQUEST_FLUFFY_MISSING_TX::request missing_tx_req;
+ missing_tx_req.block_hash = get_block_hash(new_block);
+ missing_tx_req.hop = arg.hop;
+ missing_tx_req.current_blockchain_height = arg.current_blockchain_height;
+ missing_tx_req.missing_tx_indices = std::move(need_tx_indices);
+
+ m_core.resume_mine();
+ post_notify<NOTIFY_REQUEST_FLUFFY_MISSING_TX>(missing_tx_req, context);
+ }
+ else // whoo-hoo we've got em all ..
+ {
+ MDEBUG("We have all needed txes for this fluffy block");
+
+ block_complete_entry b;
+ b.block = arg.b.block;
+ b.txs = have_tx;
+
+ std::list<block_complete_entry> blocks;
+ blocks.push_back(b);
+ m_core.prepare_handle_incoming_blocks(blocks);
+
+ block_verification_context bvc = boost::value_initialized<block_verification_context>();
+ m_core.handle_incoming_block(arg.b.block, bvc); // got block from handle_notify_new_block
+ m_core.cleanup_handle_incoming_blocks(true);
+ m_core.resume_mine();
+
+ if( bvc.m_verifivation_failed )
+ {
+ LOG_PRINT_CCONTEXT_L0("Block verification failed, dropping connection");
+ m_p2p->drop_connection(context);
+ return 1;
+ }
+ if( bvc.m_added_to_main_chain )
+ {
+ ++arg.hop;
+ //TODO: Add here announce protocol usage
+ NOTIFY_NEW_BLOCK::request reg_arg = AUTO_VAL_INIT(reg_arg);
+ reg_arg.hop = arg.hop;
+ reg_arg.current_blockchain_height = arg.current_blockchain_height;
+ reg_arg.b = b;
+ relay_block(reg_arg, context);
+ }
+ else if( bvc.m_marked_as_orphaned )
+ {
+ context.m_state = cryptonote_connection_context::state_synchronizing;
+ NOTIFY_REQUEST_CHAIN::request r = boost::value_initialized<NOTIFY_REQUEST_CHAIN::request>();
+ m_core.get_short_chain_history(r.block_ids);
+ LOG_PRINT_CCONTEXT_L2("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
+ post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
+ }
+ }
+ }
+ else
+ {
+ LOG_ERROR_CCONTEXT
+ (
+ "sent wrong block: failed to parse and validate block: "
+ << epee::string_tools::buff_to_hex_nodelimer(arg.b.block)
+ << ", dropping connection"
+ );
+
+ m_core.resume_mine();
+ m_p2p->drop_connection(context);
+
+ return 1;
+ }
+
+ return 1;
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
+ int t_cryptonote_protocol_handler<t_core>::handle_request_fluffy_missing_tx(int command, NOTIFY_REQUEST_FLUFFY_MISSING_TX::request& arg, cryptonote_connection_context& context)
+ {
+ MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_FLUFFY_MISSING_TX (" << arg.missing_tx_indices.size() << " txes), block hash " << arg.block_hash);
+
+ std::list<std::pair<cryptonote::blobdata, block>> local_blocks;
+ std::list<cryptonote::blobdata> local_txs;
+
+ block b;
+ 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);
+ return 1;
+ }
+
+ for (auto txidx: arg.missing_tx_indices)
+ MDEBUG(" tx " << b.tx_hashes[txidx]);
+
+ std::vector<crypto::hash> txids;
+ NOTIFY_NEW_FLUFFY_BLOCK::request fluffy_response;
+ fluffy_response.b.block = t_serializable_object_to_blob(b);
+ fluffy_response.current_blockchain_height = arg.current_blockchain_height;
+ fluffy_response.hop = arg.hop;
+ for(auto& tx_idx: arg.missing_tx_indices)
+ {
+ if(tx_idx < b.tx_hashes.size())
+ {
+ txids.push_back(b.tx_hashes[tx_idx]);
+ }
+ else
+ {
+ LOG_ERROR_CCONTEXT
+ (
+ "Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX"
+ << ", request is asking for a tx whose index is out of bounds "
+ << ", tx index = " << tx_idx << ", block tx count " << b.tx_hashes.size()
+ << ", block_height = " << arg.current_blockchain_height
+ << ", dropping connection"
+ );
+
+ m_p2p->drop_connection(context);
+ return 1;
+ }
+ }
+
+ std::list<cryptonote::transaction> txs;
+ std::list<crypto::hash> missed;
+ if (!m_core.get_transactions(txids, txs, missed))
+ {
+ LOG_ERROR_CCONTEXT("Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX, "
+ << "failed to get requested transactions");
+ m_p2p->drop_connection(context);
+ 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);
+ return 1;
+ }
+
+ for(auto& tx: txs)
+ {
+ fluffy_response.b.txs.push_back(t_serializable_object_to_blob(tx));
+ }
+
+ LOG_PRINT_CCONTEXT_L2
+ (
+ "-->>NOTIFY_RESPONSE_FLUFFY_MISSING_TX: "
+ << ", txs.size()=" << fluffy_response.b.txs.size()
+ << ", rsp.current_blockchain_height=" << fluffy_response.current_blockchain_height
+ );
+
+ post_notify<NOTIFY_NEW_FLUFFY_BLOCK>(fluffy_response, context);
+ return 1;
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_transactions(int command, NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& context)
{
- LOG_PRINT_CCONTEXT_L2("NOTIFY_NEW_TRANSACTIONS");
+ MLOG_P2P_MESSAGE("Received NOTIFY_NEW_TRANSACTIONS (" << arg.txs.size() << " txes)");
if(context.m_state != cryptonote_connection_context::state_normal)
return 1;
for(auto tx_blob_it = arg.txs.begin(); tx_blob_it!=arg.txs.end();)
{
cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
- m_core.handle_incoming_tx(*tx_blob_it, tvc, false, true);
+ m_core.handle_incoming_tx(*tx_blob_it, tvc, false, true, false);
if(tvc.m_verifivation_failed)
{
LOG_PRINT_CCONTEXT_L1("Tx verification failed, dropping connection");
@@ -397,7 +759,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_request_get_objects(int command, NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote_connection_context& context)
{
- LOG_PRINT_CCONTEXT_L2("NOTIFY_REQUEST_GET_OBJECTS");
+ MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_GET_OBJECTS (" << arg.blocks.size() << " blocks, " << arg.txs.size() << " txes)");
NOTIFY_RESPONSE_GET_OBJECTS::request rsp;
if(!m_core.handle_get_objects(arg, rsp, context))
{
@@ -437,7 +799,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_response_get_objects(int command, NOTIFY_RESPONSE_GET_OBJECTS::request& arg, cryptonote_connection_context& context)
{
- LOG_PRINT_CCONTEXT_L2("NOTIFY_RESPONSE_GET_OBJECTS");
+ MLOG_P2P_MESSAGE("Received NOTIFY_RESPONSE_GET_OBJECTS (" << arg.blocks.size() << " blocks, " << arg.txs.size() << " txes)");
// calculate size of request - mainly for logging/debug
size_t size = 0;
@@ -482,21 +844,29 @@ namespace cryptonote
context.m_remote_blockchain_height = arg.current_blockchain_height;
size_t count = 0;
- BOOST_FOREACH(const block_complete_entry& block_entry, arg.blocks)
+ std::vector<crypto::hash> block_hashes;
+ block_hashes.reserve(arg.blocks.size());
+ for(const block_complete_entry& block_entry: arg.blocks)
{
+ if (m_stopping)
+ {
+ return 1;
+ }
+
++count;
block b;
if(!parse_and_validate_block_from_blob(block_entry.block, b))
{
- LOG_ERROR_CCONTEXT("sent wrong block: failed to parse and validate block: \r\n"
- << epee::string_tools::buff_to_hex_nodelimer(block_entry.block) << "\r\n dropping connection");
+ 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);
return 1;
}
//to avoid concurrency in core between connections, suspend connections which delivered block later then first one
+ const crypto::hash block_hash = get_block_hash(b);
if(count == 2)
{
- if(m_core.have_block(get_block_hash(b)))
+ if(m_core.have_block(block_hash))
{
context.m_state = cryptonote_connection_context::state_idle;
context.m_needed_objects.clear();
@@ -506,7 +876,7 @@ namespace cryptonote
}
}
- auto req_it = context.m_requested_objects.find(get_block_hash(b));
+ auto req_it = context.m_requested_objects.find(block_hash);
if(req_it == context.m_requested_objects.end())
{
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(block_entry.block))
@@ -523,40 +893,74 @@ namespace cryptonote
}
context.m_requested_objects.erase(req_it);
+ block_hashes.push_back(block_hash);
}
if(context.m_requested_objects.size())
{
- LOG_PRINT_CCONTEXT_RED("returned not all requested objects (context.m_requested_objects.size()="
- << context.m_requested_objects.size() << "), dropping connection", LOG_LEVEL_0);
+ MERROR("returned not all requested objects (context.m_requested_objects.size()="
+ << context.m_requested_objects.size() << "), dropping connection");
m_p2p->drop_connection(context);
return 1;
}
{
- m_core.pause_mine();
- epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler(
- boost::bind(&t_core::resume_mine, &m_core));
-
- LOG_PRINT_CCONTEXT_YELLOW( "Got NEW BLOCKS inside of " << __FUNCTION__ << ": size: " << arg.blocks.size() , LOG_LEVEL_1);
+ MLOG_YELLOW(el::Level::Debug, "Got NEW BLOCKS inside of " << __FUNCTION__ << ": size: " << arg.blocks.size());
if (m_core.get_test_drop_download() && m_core.get_test_drop_download_height()) { // DISCARD BLOCKS for testing
- uint64_t previous_height = m_core.get_current_blockchain_height();
+ // we lock all the rest to avoid having multiple connections redo a lot
+ // of the same work, and one of them doing it for nothing: subsequent
+ // connections will wait until the current one's added its blocks, then
+ // will add any extra it has, if any
+ CRITICAL_REGION_LOCAL(m_sync_lock);
+
+ m_core.pause_mine();
+ epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler(
+ boost::bind(&t_core::resume_mine, &m_core));
+
+ const uint64_t previous_height = m_core.get_current_blockchain_height();
+
+ // dismiss what another connection might already have done (likely everything)
+ uint64_t top_height;
+ crypto::hash top_hash;
+ if (m_core.get_blockchain_top(top_height, top_hash)) {
+ uint64_t dismiss = 1;
+ for (const auto &h: block_hashes) {
+ if (top_hash == h) {
+ LOG_DEBUG_CC(context, "Found current top block in synced blocks, dismissing "
+ << dismiss << "/" << arg.blocks.size() << " blocks");
+ while (dismiss--)
+ arg.blocks.pop_front();
+ break;
+ }
+ ++dismiss;
+ }
+ }
+
+ if (arg.blocks.empty())
+ goto skip;
m_core.prepare_handle_incoming_blocks(arg.blocks);
- BOOST_FOREACH(const block_complete_entry& block_entry, arg.blocks)
+
+ for(const block_complete_entry& block_entry: arg.blocks)
{
+ if (m_stopping)
+ {
+ m_core.cleanup_handle_incoming_blocks();
+ return 1;
+ }
+
// process transactions
TIME_MEASURE_START(transactions_process_time);
- BOOST_FOREACH(auto& tx_blob, block_entry.txs)
+ for(auto& tx_blob: block_entry.txs)
{
tx_verification_context tvc = AUTO_VAL_INIT(tvc);
- m_core.handle_incoming_tx(tx_blob, tvc, true, true);
+ m_core.handle_incoming_tx(tx_blob, tvc, true, true, false);
if(tvc.m_verifivation_failed)
{
- LOG_ERROR_CCONTEXT("transaction verification failed on NOTIFY_RESPONSE_GET_OBJECTS, \r\ntx_id = "
+ LOG_ERROR_CCONTEXT("transaction verification failed on NOTIFY_RESPONSE_GET_OBJECTS, tx_id = "
<< epee::string_tools::pod_to_hex(get_blob_hash(tx_blob)) << ", dropping connection");
m_p2p->drop_connection(context);
m_core.cleanup_handle_incoming_blocks();
@@ -592,20 +996,18 @@ namespace cryptonote
TIME_MEASURE_FINISH(block_process_time);
LOG_PRINT_CCONTEXT_L2("Block process time: " << block_process_time + transactions_process_time << "(" << transactions_process_time << "/" << block_process_time << ")ms");
- epee::net_utils::data_logger::get_instance().add_data("calc_time", block_process_time + transactions_process_time);
- epee::net_utils::data_logger::get_instance().add_data("block_processing", 1);
-
} // each download block
m_core.cleanup_handle_incoming_blocks();
if (m_core.get_current_blockchain_height() > previous_height)
{
- LOG_PRINT_CCONTEXT_YELLOW( "Synced " << m_core.get_current_blockchain_height() << "/" << m_core.get_target_blockchain_height() , LOG_LEVEL_0);
+ MGINFO_YELLOW(context << " Synced " << m_core.get_current_blockchain_height() << "/" << m_core.get_target_blockchain_height());
}
} // if not DISCARD BLOCK
}
+skip:
request_missing_objects(context, true);
return 1;
}
@@ -619,11 +1021,12 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_request_chain(int command, NOTIFY_REQUEST_CHAIN::request& arg, cryptonote_connection_context& context)
{
- LOG_PRINT_CCONTEXT_L2("NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << arg.block_ids.size());
+ MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_CHAIN (" << arg.block_ids.size() << " blocks");
NOTIFY_RESPONSE_CHAIN_ENTRY::request r;
if(!m_core.find_blockchain_supplement(arg.block_ids, r))
{
LOG_ERROR_CCONTEXT("Failed to handle NOTIFY_REQUEST_CHAIN.");
+ m_p2p->drop_connection(context);
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());
@@ -651,7 +1054,7 @@ namespace cryptonote
auto it = context.m_needed_objects.begin();
const size_t count_limit = m_core.get_block_sync_size();
- _note_c("net/req-calc" , "Setting count_limit: " << count_limit);
+ MDEBUG("Setting count_limit: " << count_limit);
while(it != context.m_needed_objects.end() && count < count_limit)
{
if( !(check_having_blocks && m_core.have_block(*it)))
@@ -693,7 +1096,7 @@ namespace cryptonote
<< "\r\non connection [" << epee::net_utils::print_connection_context_short(context)<< "]");
context.m_state = cryptonote_connection_context::state_normal;
- LOG_PRINT_CCONTEXT_GREEN(" SYNCHRONIZED OK", LOG_LEVEL_0);
+ MGINFO_GREEN("SYNCHRONIZED OK");
on_connection_synchronized();
}
return true;
@@ -705,13 +1108,10 @@ namespace cryptonote
bool val_expected = false;
if(m_synchronized.compare_exchange_strong(val_expected, true))
{
- LOG_PRINT_L0(ENDL << "**********************************************************************" << ENDL
+ MGINFO_YELLOW(ENDL << "**********************************************************************" << ENDL
<< "You are now synchronized with the network. You may now start monero-wallet-cli." << ENDL
<< ENDL
- << "Please note, that the blockchain will be saved only after you quit the daemon with \"exit\" command or if you use \"save\" command." << ENDL
- << "Otherwise, you will possibly need to synchronize the blockchain again." << ENDL
- << ENDL
- << "Use \"help\" command to see the list of available commands." << ENDL
+ << "Use the \"help\" command to see the list of available commands." << ENDL
<< "**********************************************************************");
m_core.on_synchronized();
}
@@ -733,7 +1133,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_response_chain_entry(int command, NOTIFY_RESPONSE_CHAIN_ENTRY::request& arg, cryptonote_connection_context& context)
{
- LOG_PRINT_CCONTEXT_L2("NOTIFY_RESPONSE_CHAIN_ENTRY: m_block_ids.size()=" << arg.m_block_ids.size()
+ MLOG_P2P_MESSAGE("Received NOTIFY_RESPONSE_CHAIN_ENTRY: m_block_ids.size()=" << arg.m_block_ids.size()
<< ", m_start_height=" << arg.start_height << ", m_total_height=" << arg.total_height);
if(!arg.m_block_ids.size())
@@ -757,13 +1157,13 @@ namespace cryptonote
context.m_last_response_height = arg.start_height + arg.m_block_ids.size()-1;
if(context.m_last_response_height > context.m_remote_blockchain_height)
{
- LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_CHAIN_ENTRY, with \r\nm_total_height=" << arg.total_height
- << "\r\nm_start_height=" << arg.start_height
- << "\r\nm_block_ids.size()=" << arg.m_block_ids.size());
+ 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);
}
- BOOST_FOREACH(auto& bl_id, arg.m_block_ids)
+ for(auto& bl_id: arg.m_block_ids)
{
if(!m_core.have_block(bl_id))
context.m_needed_objects.push_back(bl_id);
@@ -776,26 +1176,59 @@ namespace cryptonote
template<class t_core>
bool t_cryptonote_protocol_handler<t_core>::relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context)
{
- return relay_post_notify<NOTIFY_NEW_BLOCK>(arg, exclude_context);
+ NOTIFY_NEW_FLUFFY_BLOCK::request fluffy_arg = AUTO_VAL_INIT(fluffy_arg);
+ fluffy_arg.hop = arg.hop;
+ fluffy_arg.current_blockchain_height = arg.current_blockchain_height;
+ std::list<blobdata> fluffy_txs;
+ fluffy_arg.b = arg.b;
+ fluffy_arg.b.txs = fluffy_txs;
+
+ // pre-serialize them
+ std::string fullBlob, fluffyBlob;
+ epee::serialization::store_t_to_binary(arg, fullBlob);
+ epee::serialization::store_t_to_binary(fluffy_arg, fluffyBlob);
+
+ // sort peers between fluffy ones and others
+ std::list<boost::uuids::uuid> fullConnections, fluffyConnections;
+ m_p2p->for_each_connection([this, &arg, &fluffy_arg, &exclude_context, &fullConnections, &fluffyConnections](connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)
+ {
+ if (peer_id && exclude_context.m_connection_id != context.m_connection_id)
+ {
+ if(m_core.get_testnet() && (support_flags & P2P_SUPPORT_FLAG_FLUFFY_BLOCKS))
+ {
+ LOG_DEBUG_CC(context, "PEER SUPPORTS FLUFFY BLOCKS - RELAYING THIN/COMPACT WHATEVER BLOCK");
+ fluffyConnections.push_back(context.m_connection_id);
+ }
+ else
+ {
+ LOG_DEBUG_CC(context, "PEER DOESN'T SUPPORT FLUFFY BLOCKS - RELAYING FULL BLOCK");
+ fullConnections.push_back(context.m_connection_id);
+ }
+ }
+ return true;
+ });
+
+ // send fluffy ones first, we want to encourage people to run that
+ m_p2p->relay_notify_to_list(NOTIFY_NEW_FLUFFY_BLOCK::ID, fluffyBlob, fluffyConnections);
+ m_p2p->relay_notify_to_list(NOTIFY_NEW_BLOCK::ID, fullBlob, fullConnections);
+
+ return 1;
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
bool t_cryptonote_protocol_handler<t_core>::relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& exclude_context)
{
+ // no check for success, so tell core they're relayed unconditionally
+ for(auto tx_blob_it = arg.txs.begin(); tx_blob_it!=arg.txs.end(); ++tx_blob_it)
+ m_core.on_transaction_relayed(*tx_blob_it);
return relay_post_notify<NOTIFY_NEW_TRANSACTIONS>(arg, exclude_context);
}
- /// @deprecated
- template<class t_core> std::ofstream& t_cryptonote_protocol_handler<t_core>::get_logreq() const {
- static std::ofstream * logreq=NULL;
- if (!logreq) {
- LOG_PRINT_RED("LOG OPENED",LOG_LEVEL_0);
- logreq = new std::ofstream("logreq.txt"); // leak mem (singleton)
- *logreq << "Opened log" << std::endl;
- }
- LOG_PRINT_YELLOW("LOG USED",LOG_LEVEL_0);
- (*logreq) << "log used" << std::endl;
- return *logreq;
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
+ void t_cryptonote_protocol_handler<t_core>::stop()
+ {
+ m_stopping = true;
+ m_core.stop();
}
-
} // namespace