protocol: request txpool contents when synced
A newly synced Alice sends a (typically quite small) list of txids in the local tpxool to a random peer Bob, who then uses the existing tx relay system to send Alice any tx in his txpool which is not in the list Alice sent
This commit is contained in:
parent
d1cf16364f
commit
054b4c7f41
|
@ -1946,6 +1946,12 @@ namespace cryptonote
|
||||||
{
|
{
|
||||||
m_blockchain_storage.flush_invalid_blocks();
|
m_blockchain_storage.flush_invalid_blocks();
|
||||||
}
|
}
|
||||||
|
//-----------------------------------------------------------------------------------------------
|
||||||
|
bool core::get_txpool_complement(const std::vector<crypto::hash> &hashes, std::vector<cryptonote::blobdata> &txes)
|
||||||
|
{
|
||||||
|
return m_mempool.get_complement(hashes, txes);
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------------------------
|
||||||
bool core::update_blockchain_pruning()
|
bool core::update_blockchain_pruning()
|
||||||
{
|
{
|
||||||
return m_blockchain_storage.update_blockchain_pruning();
|
return m_blockchain_storage.update_blockchain_pruning();
|
||||||
|
|
|
@ -864,6 +864,15 @@ namespace cryptonote
|
||||||
*/
|
*/
|
||||||
void flush_invalid_blocks();
|
void flush_invalid_blocks();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief returns the set of transactions in the txpool which are not in the argument
|
||||||
|
*
|
||||||
|
* @param hashes hashes of transactions to exclude from the result
|
||||||
|
*
|
||||||
|
* @return true iff success, false otherwise
|
||||||
|
*/
|
||||||
|
bool get_txpool_complement(const std::vector<crypto::hash> &hashes, std::vector<cryptonote::blobdata> &txes);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -594,6 +594,39 @@ namespace cryptonote
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------
|
||||||
|
bool tx_memory_pool::get_complement(const std::vector<crypto::hash> &hashes, std::vector<cryptonote::blobdata> &txes) const
|
||||||
|
{
|
||||||
|
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||||
|
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||||
|
|
||||||
|
m_blockchain.for_all_txpool_txes([this, &hashes, &txes](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata*) {
|
||||||
|
const auto relay_method = meta.get_relay_method();
|
||||||
|
if (relay_method != relay_method::block && relay_method != relay_method::fluff)
|
||||||
|
return true;
|
||||||
|
const auto i = std::find(hashes.begin(), hashes.end(), txid);
|
||||||
|
if (i == hashes.end())
|
||||||
|
{
|
||||||
|
cryptonote::blobdata bd;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!m_blockchain.get_txpool_tx_blob(txid, bd, cryptonote::relay_category::broadcasted))
|
||||||
|
{
|
||||||
|
MERROR("Failed to get blob for txpool transaction " << txid);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
txes.emplace_back(std::move(bd));
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
MERROR("Failed to get blob for txpool transaction " << txid << ": " << e.what());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}, false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
void tx_memory_pool::on_idle()
|
void tx_memory_pool::on_idle()
|
||||||
{
|
{
|
||||||
m_remove_stuck_tx_interval.do_call([this](){return remove_stuck_transactions();});
|
m_remove_stuck_tx_interval.do_call([this](){return remove_stuck_transactions();});
|
||||||
|
|
|
@ -441,6 +441,11 @@ namespace cryptonote
|
||||||
*/
|
*/
|
||||||
bool get_transaction_info(const crypto::hash &txid, tx_details &td) const;
|
bool get_transaction_info(const crypto::hash &txid, tx_details &td) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get transactions not in the passed set
|
||||||
|
*/
|
||||||
|
bool get_complement(const std::vector<crypto::hash> &hashes, std::vector<cryptonote::blobdata> &txes) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -353,5 +353,23 @@ namespace cryptonote
|
||||||
};
|
};
|
||||||
typedef epee::misc_utils::struct_init<request_t> request;
|
typedef epee::misc_utils::struct_init<request_t> request;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/************************************************************************/
|
||||||
|
/* */
|
||||||
|
/************************************************************************/
|
||||||
|
struct NOTIFY_GET_TXPOOL_COMPLEMENT
|
||||||
|
{
|
||||||
|
const static int ID = BC_COMMANDS_POOL_BASE + 10;
|
||||||
|
|
||||||
|
struct request_t
|
||||||
|
{
|
||||||
|
std::vector<crypto::hash> hashes;
|
||||||
|
|
||||||
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
|
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(hashes)
|
||||||
|
END_KV_SERIALIZE_MAP()
|
||||||
|
};
|
||||||
|
typedef epee::misc_utils::struct_init<request_t> request;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,6 +92,7 @@ namespace cryptonote
|
||||||
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_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)
|
HANDLE_NOTIFY_T2(NOTIFY_REQUEST_FLUFFY_MISSING_TX, &cryptonote_protocol_handler::handle_request_fluffy_missing_tx)
|
||||||
|
HANDLE_NOTIFY_T2(NOTIFY_GET_TXPOOL_COMPLEMENT, &cryptonote_protocol_handler::handle_notify_get_txpool_complement)
|
||||||
END_INVOKE_MAP2()
|
END_INVOKE_MAP2()
|
||||||
|
|
||||||
bool on_idle();
|
bool on_idle();
|
||||||
|
@ -127,6 +128,7 @@ namespace cryptonote
|
||||||
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_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);
|
int handle_request_fluffy_missing_tx(int command, NOTIFY_REQUEST_FLUFFY_MISSING_TX::request& arg, cryptonote_connection_context& context);
|
||||||
|
int handle_notify_get_txpool_complement(int command, NOTIFY_GET_TXPOOL_COMPLEMENT::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);
|
||||||
|
@ -147,6 +149,7 @@ namespace cryptonote
|
||||||
int try_add_next_blocks(cryptonote_connection_context &context);
|
int try_add_next_blocks(cryptonote_connection_context &context);
|
||||||
void notify_new_stripe(cryptonote_connection_context &context, uint32_t stripe);
|
void notify_new_stripe(cryptonote_connection_context &context, uint32_t stripe);
|
||||||
void skip_unneeded_hashes(cryptonote_connection_context& context, bool check_block_queue) const;
|
void skip_unneeded_hashes(cryptonote_connection_context& context, bool check_block_queue) const;
|
||||||
|
bool request_txpool_complement(cryptonote_connection_context &context);
|
||||||
|
|
||||||
t_core& m_core;
|
t_core& m_core;
|
||||||
|
|
||||||
|
@ -156,6 +159,7 @@ namespace cryptonote
|
||||||
std::atomic<bool> m_synchronized;
|
std::atomic<bool> m_synchronized;
|
||||||
std::atomic<bool> m_stopping;
|
std::atomic<bool> m_stopping;
|
||||||
std::atomic<bool> m_no_sync;
|
std::atomic<bool> m_no_sync;
|
||||||
|
std::atomic<bool> m_ask_for_txpool_complement;
|
||||||
boost::mutex m_sync_lock;
|
boost::mutex m_sync_lock;
|
||||||
block_queue m_block_queue;
|
block_queue m_block_queue;
|
||||||
epee::math_helper::once_a_time_seconds<30> m_idle_peer_kicker;
|
epee::math_helper::once_a_time_seconds<30> m_idle_peer_kicker;
|
||||||
|
|
|
@ -83,6 +83,7 @@ namespace cryptonote
|
||||||
m_p2p(p_net_layout),
|
m_p2p(p_net_layout),
|
||||||
m_syncronized_connections_count(0),
|
m_syncronized_connections_count(0),
|
||||||
m_synchronized(offline),
|
m_synchronized(offline),
|
||||||
|
m_ask_for_txpool_complement(true),
|
||||||
m_stopping(false),
|
m_stopping(false),
|
||||||
m_no_sync(false)
|
m_no_sync(false)
|
||||||
|
|
||||||
|
@ -885,6 +886,34 @@ namespace cryptonote
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------
|
||||||
template<class t_core>
|
template<class t_core>
|
||||||
|
int t_cryptonote_protocol_handler<t_core>::handle_notify_get_txpool_complement(int command, NOTIFY_GET_TXPOOL_COMPLEMENT::request& arg, cryptonote_connection_context& context)
|
||||||
|
{
|
||||||
|
MLOG_P2P_MESSAGE("Received NOTIFY_GET_TXPOOL_COMPLEMENT (" << arg.hashes.size() << " txes)");
|
||||||
|
|
||||||
|
std::vector<std::pair<cryptonote::blobdata, block>> local_blocks;
|
||||||
|
std::vector<cryptonote::blobdata> local_txs;
|
||||||
|
|
||||||
|
std::vector<cryptonote::blobdata> txes;
|
||||||
|
if (!m_core.get_txpool_complement(arg.hashes, txes))
|
||||||
|
{
|
||||||
|
LOG_ERROR_CCONTEXT("failed to get txpool complement");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
NOTIFY_NEW_TRANSACTIONS::request new_txes;
|
||||||
|
new_txes.txs = std::move(txes);
|
||||||
|
|
||||||
|
MLOG_P2P_MESSAGE
|
||||||
|
(
|
||||||
|
"-->>NOTIFY_NEW_TRANSACTIONS: "
|
||||||
|
<< ", txs.size()=" << new_txes.txs.size()
|
||||||
|
);
|
||||||
|
|
||||||
|
post_notify<NOTIFY_NEW_TRANSACTIONS>(new_txes, 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)
|
||||||
{
|
{
|
||||||
MLOG_P2P_MESSAGE("Received NOTIFY_NEW_TRANSACTIONS (" << arg.txs.size() << " txes)");
|
MLOG_P2P_MESSAGE("Received NOTIFY_NEW_TRANSACTIONS (" << arg.txs.size() << " txes)");
|
||||||
|
@ -2201,6 +2230,27 @@ skip:
|
||||||
}
|
}
|
||||||
m_core.safesyncmode(true);
|
m_core.safesyncmode(true);
|
||||||
m_p2p->clear_used_stripe_peers();
|
m_p2p->clear_used_stripe_peers();
|
||||||
|
|
||||||
|
// ask for txpool complement from any suitable node if we did not yet
|
||||||
|
val_expected = true;
|
||||||
|
if (m_ask_for_txpool_complement.compare_exchange_strong(val_expected, false))
|
||||||
|
{
|
||||||
|
m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
|
||||||
|
{
|
||||||
|
if(context.m_state < cryptonote_connection_context::state_synchronizing)
|
||||||
|
{
|
||||||
|
MDEBUG(context << "not ready, ignoring");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!request_txpool_complement(context))
|
||||||
|
{
|
||||||
|
MERROR(context << "Failed to request txpool complement");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------
|
||||||
|
@ -2354,6 +2404,21 @@ skip:
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------
|
||||||
template<class t_core>
|
template<class t_core>
|
||||||
|
bool t_cryptonote_protocol_handler<t_core>::request_txpool_complement(cryptonote_connection_context &context)
|
||||||
|
{
|
||||||
|
NOTIFY_GET_TXPOOL_COMPLEMENT::request r = {};
|
||||||
|
if (!m_core.get_pool_transaction_hashes(r.hashes, false))
|
||||||
|
{
|
||||||
|
MERROR("Failed to get txpool hashes");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
MLOG_P2P_MESSAGE("-->>NOTIFY_GET_TXPOOL_COMPLEMENT: hashes.size()=" << r.hashes.size() );
|
||||||
|
post_notify<NOTIFY_GET_TXPOOL_COMPLEMENT>(r, context);
|
||||||
|
MLOG_PEER_STATE("requesting txpool complement");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------
|
||||||
|
template<class t_core>
|
||||||
std::string t_cryptonote_protocol_handler<t_core>::get_peers_overview() const
|
std::string t_cryptonote_protocol_handler<t_core>::get_peers_overview() const
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
@ -2463,7 +2528,10 @@ skip:
|
||||||
MINFO("Target height decreasing from " << previous_target << " to " << target);
|
MINFO("Target height decreasing from " << previous_target << " to " << target);
|
||||||
m_core.set_target_blockchain_height(target);
|
m_core.set_target_blockchain_height(target);
|
||||||
if (target == 0 && context.m_state > cryptonote_connection_context::state_before_handshake && !m_stopping)
|
if (target == 0 && context.m_state > cryptonote_connection_context::state_before_handshake && !m_stopping)
|
||||||
|
{
|
||||||
MCWARNING("global", "monerod is now disconnected from the network");
|
MCWARNING("global", "monerod is now disconnected from the network");
|
||||||
|
m_ask_for_txpool_complement = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_block_queue.flush_spans(context.m_connection_id, false);
|
m_block_queue.flush_spans(context.m_connection_id, false);
|
||||||
|
|
|
@ -110,5 +110,7 @@ namespace tests
|
||||||
bool pad_transactions() const { return false; }
|
bool pad_transactions() const { return false; }
|
||||||
uint32_t get_blockchain_pruning_seed() const { return 0; }
|
uint32_t get_blockchain_pruning_seed() const { return 0; }
|
||||||
bool prune_blockchain(uint32_t pruning_seed) const { return true; }
|
bool prune_blockchain(uint32_t pruning_seed) const { return true; }
|
||||||
|
bool get_txpool_complement(const std::vector<crypto::hash> &hashes, std::vector<cryptonote::blobdata> &txes) { return false; }
|
||||||
|
bool get_pool_transaction_hashes(std::vector<crypto::hash>& txs, bool include_unrelayed_txes = true) const { return false; }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,8 @@ public:
|
||||||
bool prune_blockchain(uint32_t pruning_seed = 0) { return true; }
|
bool prune_blockchain(uint32_t pruning_seed = 0) { return true; }
|
||||||
bool is_within_compiled_block_hash_area(uint64_t height) const { return false; }
|
bool is_within_compiled_block_hash_area(uint64_t height) const { return false; }
|
||||||
bool has_block_weights(uint64_t height, uint64_t nblocks) const { return false; }
|
bool has_block_weights(uint64_t height, uint64_t nblocks) const { return false; }
|
||||||
|
bool get_txpool_complement(const std::vector<crypto::hash> &hashes, std::vector<cryptonote::blobdata> &txes) { return false; }
|
||||||
|
bool get_pool_transaction_hashes(std::vector<crypto::hash>& txs, bool include_unrelayed_txes = true) const { return false; }
|
||||||
void stop() {}
|
void stop() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue