aboutsummaryrefslogtreecommitdiff
path: root/src/cryptonote_protocol
diff options
context:
space:
mode:
Diffstat (limited to 'src/cryptonote_protocol')
-rw-r--r--src/cryptonote_protocol/blobdatatype.h10
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_defs.h152
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.h107
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl474
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler_common.h37
5 files changed, 780 insertions, 0 deletions
diff --git a/src/cryptonote_protocol/blobdatatype.h b/src/cryptonote_protocol/blobdatatype.h
new file mode 100644
index 000000000..23111f048
--- /dev/null
+++ b/src/cryptonote_protocol/blobdatatype.h
@@ -0,0 +1,10 @@
+// Copyright (c) 2012-2013 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#pragma once
+
+namespace cryptonote
+{
+ typedef std::string blobdata;
+}
diff --git a/src/cryptonote_protocol/cryptonote_protocol_defs.h b/src/cryptonote_protocol/cryptonote_protocol_defs.h
new file mode 100644
index 000000000..d646a7f6f
--- /dev/null
+++ b/src/cryptonote_protocol/cryptonote_protocol_defs.h
@@ -0,0 +1,152 @@
+// Copyright (c) 2012-2013 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#pragma once
+
+#include <list>
+#include "serialization/keyvalue_serialization.h"
+#include "cryptonote_core/cryptonote_basic.h"
+#include "cryptonote_protocol/blobdatatype.h"
+namespace cryptonote
+{
+
+
+#define BC_COMMANDS_POOL_BASE 2000
+
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ struct block_complete_entry
+ {
+ blobdata block;
+ std::list<blobdata> txs;
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(block)
+ KV_SERIALIZE(txs)
+ END_KV_SERIALIZE_MAP()
+ };
+
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ struct NOTIFY_NEW_BLOCK
+ {
+ const static int ID = BC_COMMANDS_POOL_BASE + 1;
+
+ struct request
+ {
+ block_complete_entry b;
+ uint64_t current_blockchain_height;
+ uint32_t hop;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(b)
+ KV_SERIALIZE(current_blockchain_height)
+ KV_SERIALIZE(hop)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ struct NOTIFY_NEW_TRANSACTIONS
+ {
+ const static int ID = BC_COMMANDS_POOL_BASE + 2;
+
+ struct request
+ {
+ std::list<blobdata> txs;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(txs)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ struct NOTIFY_REQUEST_GET_OBJECTS
+ {
+ const static int ID = BC_COMMANDS_POOL_BASE + 3;
+
+ struct request
+ {
+ std::list<crypto::hash> txs;
+ std::list<crypto::hash> blocks;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_CONTAINER_POD_AS_BLOB(txs)
+ KV_SERIALIZE_CONTAINER_POD_AS_BLOB(blocks)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
+ struct NOTIFY_RESPONSE_GET_OBJECTS
+ {
+ const static int ID = BC_COMMANDS_POOL_BASE + 4;
+
+ struct request
+ {
+ std::list<blobdata> txs;
+ std::list<block_complete_entry> blocks;
+ std::list<crypto::hash> missed_ids;
+ uint64_t current_blockchain_height;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(txs)
+ KV_SERIALIZE(blocks)
+ KV_SERIALIZE_CONTAINER_POD_AS_BLOB(missed_ids)
+ KV_SERIALIZE(current_blockchain_height)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
+
+ struct CORE_SYNC_DATA
+ {
+ uint64_t current_height;
+ crypto::hash top_id;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(current_height)
+ KV_SERIALIZE_VAL_POD_AS_BLOB(top_id)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct NOTIFY_REQUEST_CHAIN
+ {
+ const static int ID = BC_COMMANDS_POOL_BASE + 6;
+
+ struct request
+ {
+ std::list<crypto::hash> block_ids; /*IDs of the first 10 blocks are sequential, next goes with pow(2,n) offset, like 2, 4, 8, 16, 32, 64 and so on, and the last one is always genesis block */
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_CONTAINER_POD_AS_BLOB(block_ids)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
+ struct NOTIFY_RESPONSE_CHAIN_ENTRY
+ {
+ const static int ID = BC_COMMANDS_POOL_BASE + 7;
+
+ struct request
+ {
+ uint64_t start_height;
+ uint64_t total_height;
+ std::list<crypto::hash> m_block_ids;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(start_height)
+ KV_SERIALIZE(total_height)
+ KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_block_ids)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
+}
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h
new file mode 100644
index 000000000..f599cf40f
--- /dev/null
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h
@@ -0,0 +1,107 @@
+// Copyright (c) 2012-2013 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#pragma once
+
+#include <boost/program_options/variables_map.hpp>
+
+#include "storages/levin_abstract_invoke2.h"
+#include "warnings.h"
+#include "cryptonote_protocol_defs.h"
+#include "cryptonote_protocol_handler_common.h"
+#include "cryptonote_core/connection_context.h"
+#include "cryptonote_core/cryptonote_stat_info.h"
+#include "cryptonote_core/verification_context.h"
+
+PUSH_WARNINGS
+DISABLE_VS_WARNINGS(4355)
+
+namespace cryptonote
+{
+
+ template<class t_core>
+ class t_cryptonote_protocol_handler: public i_cryptonote_protocol
+ {
+ public:
+ typedef cryptonote_connection_context connection_context;
+ typedef core_stat_info stat_info;
+ typedef t_cryptonote_protocol_handler<t_core> cryptonote_protocol_handler;
+ typedef CORE_SYNC_DATA payload_type;
+
+ t_cryptonote_protocol_handler(t_core& rcore, nodetool::i_p2p_endpoint<connection_context>* p_net_layout);
+
+ BEGIN_INVOKE_MAP2(cryptonote_protocol_handler)
+ HANDLE_NOTIFY_T2(NOTIFY_NEW_BLOCK, &cryptonote_protocol_handler::handle_notify_new_block)
+ HANDLE_NOTIFY_T2(NOTIFY_NEW_TRANSACTIONS, &cryptonote_protocol_handler::handle_notify_new_transactions)
+ HANDLE_NOTIFY_T2(NOTIFY_REQUEST_GET_OBJECTS, &cryptonote_protocol_handler::handle_request_get_objects)
+ HANDLE_NOTIFY_T2(NOTIFY_RESPONSE_GET_OBJECTS, &cryptonote_protocol_handler::handle_response_get_objects)
+ HANDLE_NOTIFY_T2(NOTIFY_REQUEST_CHAIN, &cryptonote_protocol_handler::handle_request_chain)
+ HANDLE_NOTIFY_T2(NOTIFY_RESPONSE_CHAIN_ENTRY, &cryptonote_protocol_handler::handle_response_chain_entry)
+ END_INVOKE_MAP2()
+
+ bool on_idle();
+ bool init(const boost::program_options::variables_map& vm);
+ bool deinit();
+ void set_p2p_endpoint(nodetool::i_p2p_endpoint<connection_context>* p2p);
+ //bool process_handshake_data(const blobdata& data, cryptonote_connection_context& context);
+ bool process_payload_sync_data(const CORE_SYNC_DATA& hshd, cryptonote_connection_context& context, bool is_inital);
+ bool get_payload_sync_data(blobdata& data);
+ bool get_payload_sync_data(CORE_SYNC_DATA& hshd);
+ bool get_stat_info(core_stat_info& stat_inf);
+ bool on_callback(cryptonote_connection_context& context);
+ t_core& get_core(){return m_core;}
+
+
+ private:
+ //----------------- commands handlers ----------------------------------------------
+ int handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& context);
+ int handle_notify_new_transactions(int command, NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& context);
+ int handle_request_get_objects(int command, NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote_connection_context& context);
+ int handle_response_get_objects(int command, NOTIFY_RESPONSE_GET_OBJECTS::request& arg, cryptonote_connection_context& context);
+ int handle_request_chain(int command, NOTIFY_REQUEST_CHAIN::request& arg, cryptonote_connection_context& context);
+// int handle_request_chain_entry(int command, NOTIFY_REQUEST_CHAIN_ENTRY::request& arg, cryptonote_connection_context& context);
+ int handle_response_chain_entry(int command, NOTIFY_RESPONSE_CHAIN_ENTRY::request& arg, cryptonote_connection_context& context);
+
+
+ //----------------- i_bc_protocol_layout ---------------------------------------
+ virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context);
+ virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& exclude_context);
+ //----------------------------------------------------------------------------------
+ //bool get_payload_sync_data(HANDSHAKE_DATA::request& hshd, cryptonote_connection_context& context);
+ bool request_missing_objects(cryptonote_connection_context& context, bool check_having_blocks);
+ size_t get_synchronizing_connections_count();
+ bool on_connection_synchronized();
+ t_core& m_core;
+
+ nodetool::p2p_endpoint_stub<connection_context> m_p2p_stub;
+ nodetool::i_p2p_endpoint<connection_context>* m_p2p;
+ std::atomic<uint32_t> m_syncronized_connections_count;
+ //std::atomic<uint32_t> m_syncronizing_connections_count;
+ std::atomic<bool> m_welcome_showed;
+
+
+ template<class t_parametr>
+ bool post_notify(typename t_parametr::request& arg, cryptonote_connection_context& context)
+ {
+ LOG_PRINT_L2("[" << net_utils::print_connection_context_short(context) << "] post " << typeid(t_parametr).name() << " -->");
+ std::string blob;
+ epee::serialization::store_t_to_binary(arg, blob);
+ return m_p2p->invoke_notify_to_peer(t_parametr::ID, blob, context);
+ }
+
+ template<class t_parametr>
+ bool relay_post_notify(typename t_parametr::request& arg, cryptonote_connection_context& exlude_context)
+ {
+ LOG_PRINT_L2("[" << net_utils::print_connection_context_short(exlude_context) << "] post relay " << typeid(t_parametr).name() << " -->");
+ std::string arg_buff;
+ epee::serialization::store_t_to_binary(arg, arg_buff);
+ return m_p2p->relay_notify_to_all(t_parametr::ID, arg_buff, exlude_context);
+ }
+ };
+}
+
+
+#include "cryptonote_protocol_handler.inl"
+
+POP_WARNINGS
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
new file mode 100644
index 000000000..9c9668071
--- /dev/null
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -0,0 +1,474 @@
+// Copyright (c) 2012-2013 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <boost/interprocess/detail/atomic.hpp>
+#include "cryptonote_core/cryptonote_format_utils.h"
+#include "profile_tools.h"
+namespace cryptonote
+{
+
+ //-----------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
+ 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_welcome_showed(false)
+
+ {
+ if(!m_p2p)
+ m_p2p = &m_p2p_stub;
+ }
+ //-----------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
+ bool t_cryptonote_protocol_handler<t_core>::init(const boost::program_options::variables_map& vm)
+ {
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
+ bool t_cryptonote_protocol_handler<t_core>::deinit()
+ {
+
+
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
+ void t_cryptonote_protocol_handler<t_core>::set_p2p_endpoint(nodetool::i_p2p_endpoint<connection_context>* p2p)
+ {
+ if(p2p)
+ m_p2p = p2p;
+ else
+ m_p2p = &m_p2p_stub;
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
+ bool t_cryptonote_protocol_handler<t_core>::on_callback(cryptonote_connection_context& context)
+ {
+ LOG_PRINT_CCONTEXT_L2("callback fired");
+ CHECK_AND_ASSERT_MES_CC( context.m_callback_request_count > 0, false, "false callback fired, but context.m_callback_request_count=" << context.m_callback_request_count);
+ --context.m_callback_request_count;
+
+ if(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);
+ }
+
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
+ bool t_cryptonote_protocol_handler<t_core>::get_stat_info(core_stat_info& stat_inf)
+ {
+ return m_core.get_stat_info(stat_inf);
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
+ bool t_cryptonote_protocol_handler<t_core>::process_payload_sync_data(const CORE_SYNC_DATA& hshd, cryptonote_connection_context& context, bool is_inital)
+ {
+ if(context.m_state == cryptonote_connection_context::state_befor_handshake && !is_inital)
+ return true;
+
+ if(context.m_state == cryptonote_connection_context::state_synchronizing)
+ return true;
+
+ if(m_core.have_block(hshd.top_id))
+ {
+ context.m_state = cryptonote_connection_context::state_normal;
+ if(is_inital)
+ on_connection_synchronized();
+ return true;
+ }
+
+ LOG_PRINT_CCONTEXT_BLUE("Sync data returned unknown top block " << "["<< m_core.get_current_blockchain_height() << "->" << hshd.current_height << "] " << hshd.top_id << ", set SYNCHRONIZATION mode", LOG_LEVEL_0);
+ 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;
+ m_p2p->request_callback(context);
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ /* template<class t_core>
+ bool t_cryptonote_protocol_handler<t_core>::process_handshake_data(const blobdata& data, cryptonote_connection_context& context)
+ {
+ CORE_SYNC_DATA hsd = boost::value_initialized<CORE_SYNC_DATA>();
+ StorageNamed::load_struct_from_storage_buff(hsd, data);
+ return process_handshake_data(hsd, context);
+ }*/
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
+ 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.current_height +=1;
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
+ bool t_cryptonote_protocol_handler<t_core>::get_payload_sync_data(blobdata& data)
+ {
+ CORE_SYNC_DATA hsd = boost::value_initialized<CORE_SYNC_DATA>();
+ get_payload_sync_data(hsd);
+ epee::serialization::store_t_to_binary(hsd, data);
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ 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 << ")");
+ if(context.m_state != cryptonote_connection_context::state_normal)
+ return 1;
+
+ 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);
+ if(tvc.m_verifivation_failed)
+ {
+ LOG_PRINT_CCONTEXT_L0("Block verification failed: transaction verification failed, dropping connection");
+ m_p2p->drop_connection(context);
+ return 1;
+ }
+ }
+
+
+ block_verification_context bvc = boost::value_initialized<block_verification_context>();
+ m_core.pause_mine();
+ m_core.handle_incoming_block(arg.b.block, bvc);
+ 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
+ relay_block(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);
+ }
+
+ 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");
+ 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);
+ if(tvc.m_verifivation_failed)
+ {
+ LOG_PRINT_CCONTEXT_L0("Tx verification failed, dropping connection");
+ m_p2p->drop_connection(context);
+ return 1;
+ }
+ if(tvc.m_should_be_relayed)
+ ++tx_blob_it;
+ else
+ arg.txs.erase(tx_blob_it++);
+ }
+
+ if(arg.txs.size())
+ {
+ //TODO: add announce usage here
+ relay_transactions(arg, context);
+ }
+
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ 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");
+ NOTIFY_RESPONSE_GET_OBJECTS::request rsp;
+ 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);
+ }
+ LOG_PRINT_CCONTEXT_L2("-->>NOTIFY_RESPONSE_GET_OBJECTS: blocks.size()=" << rsp.blocks.size() << ", txs.size()=" << rsp.txs.size()
+ << ", rsp.m_current_blockchain_height=" << rsp.current_blockchain_height << ", missed_ids.size()=" << rsp.missed_ids.size());
+ post_notify<NOTIFY_RESPONSE_GET_OBJECTS>(rsp, context);
+ return 1;
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ 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");
+ if(context.m_last_response_height > arg.current_blockchain_height)
+ {
+ 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);
+ return 1;
+ }
+
+ context.m_remote_blockchain_height = arg.current_blockchain_height;
+
+ BOOST_FOREACH(const block_complete_entry& block_entry, arg.blocks)
+ {
+ 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"
+ << string_tools::buff_to_hex_nodelimer(block_entry.block) << "\r\n dropping connection");
+ m_p2p->drop_connection(context);
+ return 1;
+ }
+
+ auto req_it = context.m_requested_objects.find(get_block_hash(b));
+ if(req_it == context.m_requested_objects.end())
+ {
+ LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << string_tools::pod_to_hex(get_blob_hash(block_entry.block))
+ << " wasn't requested, dropping connection");
+ m_p2p->drop_connection(context);
+ return 1;
+ }
+ if(b.tx_hashes.size() != block_entry.txs.size())
+ {
+ LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << 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);
+ return 1;
+ }
+
+ context.m_requested_objects.erase(req_it);
+ }
+
+ 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);
+ m_p2p->drop_connection(context);
+ return 1;
+ }
+
+ {
+ m_core.pause_mine();
+ misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler(
+ boost::bind(&t_core::resume_mine, &m_core));
+
+ BOOST_FOREACH(const block_complete_entry& block_entry, arg.blocks)
+ {
+ //process transactions
+ TIME_MEASURE_START(transactions_process_time);
+ BOOST_FOREACH(auto& tx_blob, block_entry.txs)
+ {
+ tx_verification_context tvc = AUTO_VAL_INIT(tvc);
+ m_core.handle_incoming_tx(tx_blob, tvc, true);
+ if(tvc.m_verifivation_failed)
+ {
+ LOG_ERROR_CCONTEXT("transaction verification failed on NOTIFY_RESPONSE_GET_OBJECTS, \r\ntx_id = "
+ << string_tools::pod_to_hex(get_blob_hash(tx_blob)) << ", dropping connection");
+ m_p2p->drop_connection(context);
+ return 1;
+ }
+ }
+ TIME_MEASURE_FINISH(transactions_process_time);
+
+ //process block
+ TIME_MEASURE_START(block_process_time);
+ block_verification_context bvc = boost::value_initialized<block_verification_context>();
+
+ m_core.handle_incoming_block(block_entry.block, bvc, false);
+
+ if(bvc.m_verifivation_failed)
+ {
+ LOG_PRINT_CCONTEXT_L0("Block verification failed, dropping connection");
+ m_p2p->drop_connection(context);
+ return 1;
+ }
+ if(bvc.m_marked_as_orphaned)
+ {
+ LOG_PRINT_CCONTEXT_L0("Block received at sync phase was marked as orphaned, dropping connection");
+ m_p2p->drop_connection(context);
+ return 1;
+ }
+
+ 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");
+ }
+ }
+
+ request_missing_objects(context, true);
+ return 1;
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
+ bool t_cryptonote_protocol_handler<t_core>::on_idle()
+ {
+ return m_core.on_idle();
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ 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());
+ 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.");
+ 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());
+ post_notify<NOTIFY_RESPONSE_CHAIN_ENTRY>(r, context);
+ return 1;
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
+ bool t_cryptonote_protocol_handler<t_core>::request_missing_objects(cryptonote_connection_context& context, bool check_having_blocks)
+ {
+ if(context.m_needed_objects.size())
+ {
+ //we know objects that we need, request this objects
+ NOTIFY_REQUEST_GET_OBJECTS::request req;
+ size_t count = 0;
+ auto it = context.m_needed_objects.begin();
+
+ while(it != context.m_needed_objects.end() && count < BLOCKS_SYNCHRONIZING_DEFAULT_COUNT)
+ {
+ if( !(check_having_blocks && m_core.have_block(*it)))
+ {
+ req.blocks.push_back(*it);
+ ++count;
+ context.m_requested_objects.insert(*it);
+ }
+ context.m_needed_objects.erase(it++);
+ }
+ LOG_PRINT_CCONTEXT_L2("-->>NOTIFY_REQUEST_GET_OBJECTS: blocks.size()=" << req.blocks.size() << ", txs.size()=" << req.txs.size());
+ post_notify<NOTIFY_REQUEST_GET_OBJECTS>(req, context);
+ }else if(context.m_last_response_height < context.m_remote_blockchain_height-1)
+ {//we have to fetch more objects ids, request blockchain entry
+
+ 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
+ {
+ CHECK_AND_ASSERT_MES(context.m_last_response_height == context.m_remote_blockchain_height-1
+ && !context.m_needed_objects.size()
+ && !context.m_requested_objects.size(), false, "request_missing_blocks final condition failed!"
+ << "\r\nm_last_response_height=" << context.m_last_response_height
+ << "\r\nm_remote_blockchain_height=" << context.m_remote_blockchain_height
+ << "\r\nm_needed_objects.size()=" << context.m_needed_objects.size()
+ << "\r\nm_requested_objects.size()=" << context.m_requested_objects.size()
+ << "\r\non connection [" << net_utils::print_connection_context_short(context)<< "]");
+
+ context.m_state = cryptonote_connection_context::state_normal;
+ LOG_PRINT_CCONTEXT_GREEN(" SYNCHRONIZED OK", LOG_LEVEL_0);
+ if( true/*get_synchronizing_connections_count() == 0 && !m_welcome_showed*/)
+ {
+ on_connection_synchronized();
+ }
+ }
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
+ bool t_cryptonote_protocol_handler<t_core>::on_connection_synchronized()
+ {
+ bool val_expected = false;
+ if(m_welcome_showed.compare_exchange_strong(val_expected, true))
+ {
+ LOG_PRINT_L0(ENDL << "**********************************************************************" << ENDL
+ << "You are now synchronized with the network. You may now start simplewallet." << 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
+ << "**********************************************************************");
+ m_core.on_synchronized();
+ }
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
+ size_t t_cryptonote_protocol_handler<t_core>::get_synchronizing_connections_count()
+ {
+ size_t count = 0;
+ m_p2p->for_each_connection([&](cryptonote_connection_context& context)->bool{
+ if(context.m_state == cryptonote_connection_context::state_synchronizing)
+ ++count;
+ return true;
+ });
+ return count;
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ 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()
+ << ", m_start_height=" << arg.start_height << ", m_total_height=" << arg.total_height);
+
+ if(!arg.m_block_ids.size())
+ {
+ LOG_ERROR_CCONTEXT("sent empty m_block_ids, dropping connection");
+ m_p2p->drop_connection(context);
+ return 1;
+ }
+
+ if(!m_core.have_block(arg.m_block_ids.front()))
+ {
+ LOG_ERROR_CCONTEXT("sent m_block_ids starting from unknown id: "
+ << string_tools::pod_to_hex(arg.m_block_ids.front()) << " , dropping connection");
+ m_p2p->drop_connection(context);
+ return 1;
+ }
+
+ context.m_remote_blockchain_height = arg.total_height;
+ 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());
+ m_p2p->drop_connection(context);
+ }
+
+ BOOST_FOREACH(auto& bl_id, arg.m_block_ids)
+ {
+ if(!m_core.have_block(bl_id))
+ context.m_needed_objects.push_back(bl_id);
+ }
+
+ request_missing_objects(context, false);
+ return 1;
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ 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);
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
+ bool t_cryptonote_protocol_handler<t_core>::relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& exclude_context)
+ {
+ return relay_post_notify<NOTIFY_NEW_TRANSACTIONS>(arg, exclude_context);
+ }
+}
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler_common.h b/src/cryptonote_protocol/cryptonote_protocol_handler_common.h
new file mode 100644
index 000000000..f1ced5050
--- /dev/null
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler_common.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2012-2013 The Cryptonote developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#pragma once
+
+#include "p2p/net_node_common.h"
+#include "cryptonote_protocol/cryptonote_protocol_defs.h"
+#include "cryptonote_core/connection_context.h"
+namespace cryptonote
+{
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ struct i_cryptonote_protocol
+ {
+ virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context)=0;
+ virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& exclude_context)=0;
+ //virtual bool request_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote_connection_context& context)=0;
+ };
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ struct cryptonote_protocol_stub: public i_cryptonote_protocol
+ {
+ virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context)
+ {
+ return false;
+ }
+ virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& exclude_context)
+ {
+ return false;
+ }
+
+ };
+}