add lightweight block propagation ("fluffy blocks")

Added a new command to the P2P protocol definitions to allow querying for support flags.

Implemented handling of new support flags command in net_node. Changed for_each callback template to include support flags. Updated print_connections command to show peer support flags.

Added p2p constant for signaling fluffy block support.

Added get_pool_transaction function to cryptnote_core.

Added new commands to cryptonote protocol for relaying fluffy blocks.

Implemented handling of fluffy block command in cryptonote protocol.

Enabled fluffy block support in node initial configuration.

Implemented get_testnet function in cryptonote_core.

Made it so that fluffy blocks only run on testnet.
This commit is contained in:
Dion Ahmetaj 2016-10-26 15:00:08 -04:00
parent d51f1af75f
commit d61bd8187e
11 changed files with 492 additions and 11 deletions

View file

@ -111,6 +111,9 @@
#define P2P_IP_FAILS_BEFORE_BLOCK 10 #define P2P_IP_FAILS_BEFORE_BLOCK 10
#define P2P_IDLE_CONNECTION_KILL_INTERVAL (5*60) //5 minutes #define P2P_IDLE_CONNECTION_KILL_INTERVAL (5*60) //5 minutes
#define P2P_SUPPORT_FLAG_FLUFFY_BLOCKS 0x01
#define P2P_SUPPORT_FLAGS P2P_SUPPORT_FLAG_FLUFFY_BLOCKS
#define ALLOW_DEBUG_COMMANDS #define ALLOW_DEBUG_COMMANDS
#define CRYPTONOTE_NAME "bitmonero" #define CRYPTONOTE_NAME "bitmonero"

View file

@ -916,6 +916,11 @@ namespace cryptonote
return true; return true;
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool core::get_pool_transaction(const crypto::hash &id, transaction& tx) const
{
return m_mempool.get_transaction(id, tx);
}
//-----------------------------------------------------------------------------------------------
bool core::get_pool_transactions_and_spent_keys_info(std::vector<tx_info>& tx_infos, std::vector<spent_key_image_info>& key_image_infos) const bool core::get_pool_transactions_and_spent_keys_info(std::vector<tx_info>& tx_infos, std::vector<spent_key_image_info>& key_image_infos) const
{ {
return m_mempool.get_transactions_and_spent_keys_info(tx_infos, key_image_infos); return m_mempool.get_transactions_and_spent_keys_info(tx_infos, key_image_infos);

View file

@ -380,6 +380,13 @@ namespace cryptonote
*/ */
bool get_pool_transactions(std::list<transaction>& txs) const; bool get_pool_transactions(std::list<transaction>& txs) const;
/**
* @copydoc tx_memory_pool::get_transaction
*
* @note see tx_memory_pool::get_transaction
*/
bool get_pool_transaction(const crypto::hash& id, transaction& tx) const;
/** /**
* @copydoc tx_memory_pool::get_pool_transactions_and_spent_keys_info * @copydoc tx_memory_pool::get_pool_transactions_and_spent_keys_info
* *
@ -612,6 +619,13 @@ namespace cryptonote
*/ */
std::pair<uint64_t, uint64_t> get_coinbase_tx_sum(const uint64_t start_offset, const size_t count); std::pair<uint64_t, uint64_t> get_coinbase_tx_sum(const uint64_t start_offset, const size_t count);
/**
* @brief get whether we're on testnet or not
*
* @return are we on testnet?
*/
bool get_testnet() const { return m_testnet; };
private: private:
/** /**

View file

@ -70,6 +70,8 @@ namespace cryptonote
uint64_t avg_upload; uint64_t avg_upload;
uint64_t current_upload; uint64_t current_upload;
uint32_t support_flags;
BEGIN_KV_SERIALIZE_MAP() BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(incoming) KV_SERIALIZE(incoming)
KV_SERIALIZE(localhost) KV_SERIALIZE(localhost)
@ -87,6 +89,7 @@ namespace cryptonote
KV_SERIALIZE(current_download) KV_SERIALIZE(current_download)
KV_SERIALIZE(avg_upload) KV_SERIALIZE(avg_upload)
KV_SERIALIZE(current_upload) KV_SERIALIZE(current_upload)
KV_SERIALIZE(support_flags)
END_KV_SERIALIZE_MAP() END_KV_SERIALIZE_MAP()
}; };
@ -224,4 +227,48 @@ namespace cryptonote
}; };
}; };
/************************************************************************/
/* */
/************************************************************************/
struct NOTIFY_NEW_FLUFFY_BLOCK
{
const static int ID = BC_COMMANDS_POOL_BASE + 8;
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_REQUEST_FLUFFY_MISSING_TX
{
const static int ID = BC_COMMANDS_POOL_BASE + 9;
struct request
{
block_complete_entry b;
uint64_t current_blockchain_height;
std::vector<size_t> missing_tx_indices;
uint32_t hop;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(b)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(missing_tx_indices)
KV_SERIALIZE(hop)
KV_SERIALIZE(current_blockchain_height)
END_KV_SERIALIZE_MAP()
};
};
} }

View file

@ -91,6 +91,8 @@ namespace cryptonote
HANDLE_NOTIFY_T2(NOTIFY_RESPONSE_GET_OBJECTS, &cryptonote_protocol_handler::handle_response_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_REQUEST_CHAIN, &cryptonote_protocol_handler::handle_request_chain)
HANDLE_NOTIFY_T2(NOTIFY_RESPONSE_CHAIN_ENTRY, &cryptonote_protocol_handler::handle_response_chain_entry) HANDLE_NOTIFY_T2(NOTIFY_RESPONSE_CHAIN_ENTRY, &cryptonote_protocol_handler::handle_response_chain_entry)
HANDLE_NOTIFY_T2(NOTIFY_NEW_FLUFFY_BLOCK, &cryptonote_protocol_handler::handle_notify_new_fluffy_block)
HANDLE_NOTIFY_T2(NOTIFY_REQUEST_FLUFFY_MISSING_TX, &cryptonote_protocol_handler::handle_request_fluffy_missing_tx)
END_INVOKE_MAP2() END_INVOKE_MAP2()
bool on_idle(); bool on_idle();
@ -115,7 +117,8 @@ namespace cryptonote
int handle_response_get_objects(int command, NOTIFY_RESPONSE_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(int command, NOTIFY_REQUEST_CHAIN::request& arg, cryptonote_connection_context& context);
int handle_response_chain_entry(int command, NOTIFY_RESPONSE_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);
int handle_notify_new_fluffy_block(int command, NOTIFY_NEW_FLUFFY_BLOCK::request& arg, cryptonote_connection_context& context);
int handle_request_fluffy_missing_tx(int command, NOTIFY_REQUEST_FLUFFY_MISSING_TX::request& arg, cryptonote_connection_context& context);
//----------------- i_bc_protocol_layout --------------------------------------- //----------------- i_bc_protocol_layout ---------------------------------------
virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context); virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context);

View file

@ -37,6 +37,7 @@
#include <boost/interprocess/detail/atomic.hpp> #include <boost/interprocess/detail/atomic.hpp>
#include <list> #include <list>
#include <unordered_map>
#include "cryptonote_core/cryptonote_format_utils.h" #include "cryptonote_core/cryptonote_format_utils.h"
#include "profile_tools.h" #include "profile_tools.h"
@ -124,6 +125,7 @@ namespace cryptonote
ss << std::setw(30) << std::left << "Remote Host" ss << std::setw(30) << std::left << "Remote Host"
<< std::setw(20) << "Peer id" << std::setw(20) << "Peer id"
<< std::setw(20) << "Support Flags"
<< std::setw(30) << "Recv/Sent (inactive,sec)" << std::setw(30) << "Recv/Sent (inactive,sec)"
<< std::setw(25) << "State" << std::setw(25) << "State"
<< std::setw(20) << "Livetime(sec)" << std::setw(20) << "Livetime(sec)"
@ -134,7 +136,7 @@ namespace cryptonote
<< ENDL; << ENDL;
uint32_t ip; 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; bool local_ip = false;
ip = ntohl(cntxt.m_remote_ip); ip = ntohl(cntxt.m_remote_ip);
@ -145,6 +147,7 @@ namespace cryptonote
ss << std::setw(30) << std::left << std::string(cntxt.m_is_income ? " [INC]":"[OUT]") + 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) 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 << 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(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(25) << get_protocol_state_string(cntxt.m_state)
<< std::setw(20) << std::to_string(time(NULL) - cntxt.m_started) << std::setw(20) << std::to_string(time(NULL) - cntxt.m_started)
@ -184,7 +187,7 @@ namespace cryptonote
{ {
std::list<connection_info> connections; 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; connection_info cnx;
auto timestamp = time(NULL); auto timestamp = time(NULL);
@ -198,6 +201,8 @@ namespace cryptonote
peer_id_str << std::hex << peer_id; peer_id_str << std::hex << peer_id;
peer_id_str >> cnx.peer_id; peer_id_str >> cnx.peer_id;
cnx.support_flags = support_flags;
cnx.recv_count = cntxt.m_recv_cnt; cnx.recv_count = cntxt.m_recv_cnt;
cnx.recv_idle_time = timestamp - cntxt.m_last_recv; cnx.recv_idle_time = timestamp - cntxt.m_last_recv;
@ -361,6 +366,312 @@ namespace cryptonote
} }
//------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------
template<class t_core> 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)
{
LOG_PRINT_CCONTEXT_L2("NOTIFY_NEW_FLUFFY_BLOCK (hop " << arg.hop << ")");
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 seccond 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;
BOOST_FOREACH(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))
{
cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
if(!m_core.handle_incoming_tx(tx_blob, tvc, true, true) || 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: \r\n"
<< epee::string_tools::buff_to_hex_nodelimer(tx_blob)
<< "\r\n 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())
{
LOG_PRINT_CCONTEXT_RED
(
"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", LOG_LEVEL_0
);
m_p2p->drop_connection(context);
m_core.resume_mine();
return 1;
}
size_t tx_idx = 0;
BOOST_FOREACH(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
{
need_tx_indices.push_back(tx_idx);
}
++tx_idx;
}
if(!need_tx_indices.empty()) // drats, we don't have everything..
{
// request non-mempool txs
NOTIFY_REQUEST_FLUFFY_MISSING_TX::request missing_tx_req;
missing_tx_req.b = arg.b;
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 ..
{
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.block = b.block;
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: \r\n"
<< epee::string_tools::buff_to_hex_nodelimer(arg.b.block)
<< "\r\n 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)
{
LOG_PRINT_CCONTEXT_L2("NOTIFY_REQUEST_FLUFFY_MISSING_TX");
std::list<block> local_blocks;
std::list<transaction> local_txs;
if(!m_core.get_blocks(arg.current_blockchain_height - 1, 1, local_blocks, local_txs))
{
LOG_ERROR_CCONTEXT
(
"Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX"
<< ", get_blocks( start_offset = " << (arg.current_blockchain_height - 1) << " ) failed"
<< ", dropping connection"
);
m_p2p->drop_connection(context);
return 1;
}
NOTIFY_NEW_FLUFFY_BLOCK::request fluffy_response;
fluffy_response.b = arg.b;
fluffy_response.current_blockchain_height = m_core.get_current_blockchain_height();
fluffy_response.hop = arg.hop;
size_t local_txs_count = local_txs.size();
BOOST_FOREACH(auto& tx_idx, arg.missing_tx_indices)
{
if(tx_idx < local_txs_count)
{
fluffy_response.b.txs.push_back(t_serializable_object_to_blob( *(std::next(local_txs.begin(), 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_height = " << arg.current_blockchain_height
<< ", dropping connection"
);
m_p2p->drop_connection(context);
return 1;
}
}
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) 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"); LOG_PRINT_CCONTEXT_L2("NOTIFY_NEW_TRANSACTIONS");
@ -774,7 +1085,28 @@ namespace cryptonote
template<class t_core> template<class t_core>
bool t_cryptonote_protocol_handler<t_core>::relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context) 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;
m_p2p->for_each_connection([this, &arg, &fluffy_arg](connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags)
{
if(m_core.get_testnet() && support_flags & P2P_SUPPORT_FLAG_FLUFFY_BLOCKS)
{
LOG_PRINT_YELLOW("PEER SUPPORTS FLUFFY BLOCKS - RELAYING THIN/COMPACT WHATEVER BLOCK", LOG_LEVEL_1);
return post_notify<NOTIFY_NEW_FLUFFY_BLOCK>(fluffy_arg, cntxt);
}
else
{
LOG_PRINT_YELLOW("PEER DOESN'T SUPPORT FLUFFY BLOCKS - RELAYING FULL BLOCK", LOG_LEVEL_1);
return post_notify<NOTIFY_NEW_BLOCK>(arg, cntxt);
}
});
return 1;
} }
//------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------
template<class t_core> template<class t_core>

View file

@ -404,6 +404,7 @@ bool t_rpc_command_executor::print_connections() {
tools::msg_writer() << std::setw(30) << std::left << "Remote Host" tools::msg_writer() << std::setw(30) << std::left << "Remote Host"
<< std::setw(20) << "Peer id" << std::setw(20) << "Peer id"
<< std::setw(20) << "Support Flags"
<< std::setw(30) << "Recv/Sent (inactive,sec)" << std::setw(30) << "Recv/Sent (inactive,sec)"
<< std::setw(25) << "State" << std::setw(25) << "State"
<< std::setw(20) << "Livetime(sec)" << std::setw(20) << "Livetime(sec)"
@ -422,6 +423,7 @@ bool t_rpc_command_executor::print_connections() {
//<< std::setw(30) << std::left << in_out //<< std::setw(30) << std::left << in_out
<< std::setw(30) << std::left << address << std::setw(30) << std::left << address
<< std::setw(20) << info.peer_id << std::setw(20) << info.peer_id
<< std::setw(20) << info.support_flags
<< std::setw(30) << std::to_string(info.recv_count) + "(" + std::to_string(info.recv_idle_time) + ")/" + std::to_string(info.send_count) + "(" + std::to_string(info.send_idle_time) + ")" << std::setw(30) << std::to_string(info.recv_count) + "(" + std::to_string(info.recv_idle_time) + ")/" + std::to_string(info.send_count) + "(" + std::to_string(info.send_idle_time) + ")"
<< std::setw(25) << info.state << std::setw(25) << info.state
<< std::setw(20) << info.live_time << std::setw(20) << info.live_time

View file

@ -63,6 +63,7 @@ namespace nodetool
struct p2p_connection_context_t: base_type //t_payload_net_handler::connection_context //public net_utils::connection_context_base struct p2p_connection_context_t: base_type //t_payload_net_handler::connection_context //public net_utils::connection_context_base
{ {
peerid_type peer_id; peerid_type peer_id;
uint32_t support_flags;
}; };
template<class t_payload_net_handler> template<class t_payload_net_handler>
@ -146,6 +147,7 @@ namespace nodetool
HANDLE_INVOKE_T2(COMMAND_REQUEST_NETWORK_STATE, &node_server::handle_get_network_state) HANDLE_INVOKE_T2(COMMAND_REQUEST_NETWORK_STATE, &node_server::handle_get_network_state)
HANDLE_INVOKE_T2(COMMAND_REQUEST_PEER_ID, &node_server::handle_get_peer_id) HANDLE_INVOKE_T2(COMMAND_REQUEST_PEER_ID, &node_server::handle_get_peer_id)
#endif #endif
HANDLE_INVOKE_T2(COMMAND_REQUEST_SUPPORT_FLAGS, &node_server::handle_get_support_flags)
CHAIN_INVOKE_MAP_TO_OBJ_FORCE_CONTEXT(m_payload_handler, typename t_payload_net_handler::connection_context&) CHAIN_INVOKE_MAP_TO_OBJ_FORCE_CONTEXT(m_payload_handler, typename t_payload_net_handler::connection_context&)
END_INVOKE_MAP2() END_INVOKE_MAP2()
@ -158,6 +160,7 @@ namespace nodetool
int handle_get_network_state(int command, COMMAND_REQUEST_NETWORK_STATE::request& arg, COMMAND_REQUEST_NETWORK_STATE::response& rsp, p2p_connection_context& context); int handle_get_network_state(int command, COMMAND_REQUEST_NETWORK_STATE::request& arg, COMMAND_REQUEST_NETWORK_STATE::response& rsp, p2p_connection_context& context);
int handle_get_peer_id(int command, COMMAND_REQUEST_PEER_ID::request& arg, COMMAND_REQUEST_PEER_ID::response& rsp, p2p_connection_context& context); int handle_get_peer_id(int command, COMMAND_REQUEST_PEER_ID::request& arg, COMMAND_REQUEST_PEER_ID::response& rsp, p2p_connection_context& context);
#endif #endif
int handle_get_support_flags(int command, COMMAND_REQUEST_SUPPORT_FLAGS::request& arg, COMMAND_REQUEST_SUPPORT_FLAGS::response& rsp, p2p_connection_context& context);
bool init_config(); bool init_config();
bool make_default_config(); bool make_default_config();
bool store_config(); bool store_config();
@ -174,7 +177,7 @@ namespace nodetool
virtual bool invoke_notify_to_peer(int command, const std::string& req_buff, const epee::net_utils::connection_context_base& context); virtual bool invoke_notify_to_peer(int command, const std::string& req_buff, const epee::net_utils::connection_context_base& context);
virtual bool drop_connection(const epee::net_utils::connection_context_base& context); virtual bool drop_connection(const epee::net_utils::connection_context_base& context);
virtual void request_callback(const epee::net_utils::connection_context_base& context); virtual void request_callback(const epee::net_utils::connection_context_base& context);
virtual void for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&, peerid_type)> f); virtual void for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&, peerid_type, uint32_t)> f);
virtual bool add_ip_fail(uint32_t address); virtual bool add_ip_fail(uint32_t address);
//----------------- i_connection_filter -------------------------------------------------------- //----------------- i_connection_filter --------------------------------------------------------
virtual bool is_remote_ip_allowed(uint32_t adress); virtual bool is_remote_ip_allowed(uint32_t adress);
@ -204,6 +207,7 @@ namespace nodetool
bool is_addr_connected(const net_address& peer); bool is_addr_connected(const net_address& peer);
template<class t_callback> template<class t_callback>
bool try_ping(basic_node_data& node_data, p2p_connection_context& context, t_callback cb); bool try_ping(basic_node_data& node_data, p2p_connection_context& context, t_callback cb);
bool try_get_support_flags(const p2p_connection_context& context, std::function<void(p2p_connection_context&, const uint32_t&)> f);
bool make_expected_connections_count(bool white_list, size_t expected_connections); bool make_expected_connections_count(bool white_list, size_t expected_connections);
void cache_connect_fail_info(const net_address& addr); void cache_connect_fail_info(const net_address& addr);
bool is_addr_recently_failed(const net_address& addr); bool is_addr_recently_failed(const net_address& addr);
@ -240,10 +244,12 @@ namespace nodetool
{ {
network_config m_net_config; network_config m_net_config;
uint64_t m_peer_id; uint64_t m_peer_id;
uint32_t m_support_flags;
BEGIN_KV_SERIALIZE_MAP() BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(m_net_config) KV_SERIALIZE(m_net_config)
KV_SERIALIZE(m_peer_id) KV_SERIALIZE(m_peer_id)
KV_SERIALIZE(m_support_flags)
END_KV_SERIALIZE_MAP() END_KV_SERIALIZE_MAP()
}; };

View file

@ -158,6 +158,7 @@ namespace nodetool
m_config.m_net_config.connection_timeout = P2P_DEFAULT_CONNECTION_TIMEOUT; m_config.m_net_config.connection_timeout = P2P_DEFAULT_CONNECTION_TIMEOUT;
m_config.m_net_config.ping_connection_timeout = P2P_DEFAULT_PING_CONNECTION_TIMEOUT; m_config.m_net_config.ping_connection_timeout = P2P_DEFAULT_PING_CONNECTION_TIMEOUT;
m_config.m_net_config.send_peerlist_sz = P2P_DEFAULT_PEERS_IN_HANDSHAKE; m_config.m_net_config.send_peerlist_sz = P2P_DEFAULT_PEERS_IN_HANDSHAKE;
m_config.m_support_flags = P2P_SUPPORT_FLAGS;
m_first_connection_maker_call = true; m_first_connection_maker_call = true;
CATCH_ENTRY_L0("node_server::init_config", false); CATCH_ENTRY_L0("node_server::init_config", false);
@ -165,10 +166,10 @@ namespace nodetool
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
template<class t_payload_net_handler> template<class t_payload_net_handler>
void node_server<t_payload_net_handler>::for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&, peerid_type)> f) void node_server<t_payload_net_handler>::for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&, peerid_type, uint32_t)> f)
{ {
m_net_server.get_config_object().foreach_connection([&](p2p_connection_context& cntx){ m_net_server.get_config_object().foreach_connection([&](p2p_connection_context& cntx){
return f(cntx, cntx.peer_id); return f(cntx, cntx.peer_id, cntx.support_flags);
}); });
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
@ -730,6 +731,13 @@ namespace nodetool
LOG_PRINT_CC_L1(context_, "COMMAND_HANDSHAKE Failed"); LOG_PRINT_CC_L1(context_, "COMMAND_HANDSHAKE Failed");
m_net_server.get_config_object().close(context_.m_connection_id); m_net_server.get_config_object().close(context_.m_connection_id);
} }
else
{
try_get_support_flags(context_, [](p2p_connection_context& flags_context, const uint32_t& support_flags)
{
flags_context.support_flags = support_flags;
});
}
return hsh_result; return hsh_result;
} }
@ -1219,6 +1227,13 @@ namespace nodetool
return 1; return 1;
} }
#endif #endif
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
int node_server<t_payload_net_handler>::handle_get_support_flags(int command, COMMAND_REQUEST_SUPPORT_FLAGS::request& arg, COMMAND_REQUEST_SUPPORT_FLAGS::response& rsp, p2p_connection_context& context)
{
rsp.support_flags = m_config.m_support_flags;
return 1;
}
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
template<class t_payload_net_handler> template<class t_payload_net_handler>
void node_server<t_payload_net_handler>::request_callback(const epee::net_utils::connection_context_base& context) void node_server<t_payload_net_handler>::request_callback(const epee::net_utils::connection_context_base& context)
@ -1338,6 +1353,32 @@ namespace nodetool
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
template<class t_payload_net_handler> template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::try_get_support_flags(const p2p_connection_context& context, std::function<void(p2p_connection_context&, const uint32_t&)> f)
{
COMMAND_REQUEST_SUPPORT_FLAGS::request support_flags_request;
bool r = epee::net_utils::async_invoke_remote_command2<typename COMMAND_REQUEST_SUPPORT_FLAGS::response>
(
context.m_connection_id,
COMMAND_REQUEST_SUPPORT_FLAGS::ID,
support_flags_request,
m_net_server.get_config_object(),
[=](int code, const typename COMMAND_REQUEST_SUPPORT_FLAGS::response& rsp, p2p_connection_context& context_)
{
if(code < 0)
{
LOG_PRINT_CC_RED(context_, "COMMAND_REQUEST_SUPPORT_FLAGS invoke failed. (" << code << ", " << epee::levin::get_err_descr(code) << ")", LOG_LEVEL_1);
return;
}
f(context_, rsp.support_flags);
},
P2P_DEFAULT_HANDSHAKE_INVOKE_TIMEOUT
);
return r;
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
int node_server<t_payload_net_handler>::handle_timed_sync(int command, typename COMMAND_TIMED_SYNC::request& arg, typename COMMAND_TIMED_SYNC::response& rsp, p2p_connection_context& context) int node_server<t_payload_net_handler>::handle_timed_sync(int command, typename COMMAND_TIMED_SYNC::request& arg, typename COMMAND_TIMED_SYNC::response& rsp, p2p_connection_context& context)
{ {
if(!m_payload_handler.process_payload_sync_data(arg.payload_data, context, false)) if(!m_payload_handler.process_payload_sync_data(arg.payload_data, context, false))
@ -1411,6 +1452,11 @@ namespace nodetool
}); });
} }
try_get_support_flags(context, [](p2p_connection_context& flags_context, const uint32_t& support_flags)
{
flags_context.support_flags = support_flags;
});
//fill response //fill response
m_peerlist.get_peerlist_head(rsp.local_peerlist); m_peerlist.get_peerlist_head(rsp.local_peerlist);
get_local_node_data(rsp.node_data); get_local_node_data(rsp.node_data);

View file

@ -49,7 +49,7 @@ namespace nodetool
virtual bool drop_connection(const epee::net_utils::connection_context_base& context)=0; virtual bool drop_connection(const epee::net_utils::connection_context_base& context)=0;
virtual void request_callback(const epee::net_utils::connection_context_base& context)=0; virtual void request_callback(const epee::net_utils::connection_context_base& context)=0;
virtual uint64_t get_connections_count()=0; virtual uint64_t get_connections_count()=0;
virtual void for_each_connection(std::function<bool(t_connection_context&, peerid_type)> f)=0; virtual void for_each_connection(std::function<bool(t_connection_context&, peerid_type, uint32_t)> f)=0;
virtual bool block_ip(uint32_t adress, time_t seconds = 0)=0; virtual bool block_ip(uint32_t adress, time_t seconds = 0)=0;
virtual bool unblock_ip(uint32_t adress)=0; virtual bool unblock_ip(uint32_t adress)=0;
virtual std::map<uint32_t, time_t> get_blocked_ips()=0; virtual std::map<uint32_t, time_t> get_blocked_ips()=0;
@ -79,7 +79,7 @@ namespace nodetool
{ {
} }
virtual void for_each_connection(std::function<bool(t_connection_context&,peerid_type)> f) virtual void for_each_connection(std::function<bool(t_connection_context&,peerid_type,uint32_t)> f)
{ {
} }

View file

@ -332,6 +332,29 @@ namespace nodetool
}; };
}; };
/************************************************************************/
/* */
/************************************************************************/
struct COMMAND_REQUEST_SUPPORT_FLAGS
{
const static int ID = P2P_COMMANDS_POOL_BASE + 7;
struct request
{
BEGIN_KV_SERIALIZE_MAP()
END_KV_SERIALIZE_MAP()
};
struct response
{
uint32_t support_flags;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(support_flags)
END_KV_SERIALIZE_MAP()
};
};
#endif #endif