Skip to content

Commit

Permalink
Merge pull request #191 Improvements in P2P and routines
Browse files Browse the repository at this point in the history
Initial select dandelion stems only when we have peers
Select from outgoing connections preferably supporting Dandelion
Add 'print_dandelion' command to daemon
Separate on idle routine workers
  • Loading branch information
aivve authored Mar 13, 2022
2 parents 76f2a33 + 01d32f1 commit eed4f35
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 44 deletions.
34 changes: 30 additions & 4 deletions src/CryptoNoteProtocol/CryptoNoteProtocolHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,11 @@ CryptoNoteProtocolHandler::CryptoNoteProtocolHandler(const Currency& currency, S
m_p2p(p_net_layout),
m_synchronized(false),
m_stop(false),
m_init_select_dandelion_called(false),
m_observedHeight(0),
m_peersCount(0),
m_dandelionStemSelectInterval(CryptoNote::parameters::DANDELION_EPOCH),
m_dandelionStemFluffInterval(CryptoNote::parameters::DANDELION_STEM_EMBARGO),
logger(log, "protocol"),
m_stemPool() {

Expand All @@ -79,6 +82,16 @@ size_t CryptoNoteProtocolHandler::getPeerCount() const {
return m_peersCount;
}

void CryptoNoteProtocolHandler::printDandelions() const {
if (m_dandelion_stem.size() == 0)
std::cout << "No dandelion connections" << ENDL;
std::stringstream ss;
for (const auto& d : m_dandelion_stem) {
ss << Common::ipAddressToString(d.m_remote_ip) << ":" << d.m_remote_port << std::endl;
}
std::cout << ss.str();
}

void CryptoNoteProtocolHandler::set_p2p_endpoint(IP2pEndpoint* p2p) {
if (p2p)
m_p2p = p2p;
Expand Down Expand Up @@ -634,13 +647,15 @@ int CryptoNoteProtocolHandler::processObjects(CryptoNoteConnectionContext& conte
}

bool CryptoNoteProtocolHandler::select_dandelion_stem() {
m_dandelion_stem.clear();
m_init_select_dandelion_called = true;

//TODO: select from outgoing connections preferably supporting Dandelion: context.version >= P2P_VERSION_4)
m_dandelion_stem.clear();

std::vector<CryptoNoteConnectionContext> alive_peers;
m_p2p->for_each_connection([&](const CryptoNoteConnectionContext& ctx, PeerIdType peer_id) {
if ((ctx.m_state == CryptoNoteConnectionContext::state_normal || ctx.m_state == CryptoNoteConnectionContext::state_synchronizing) && !ctx.m_is_income) {
if ((ctx.m_state == CryptoNoteConnectionContext::state_normal ||
ctx.m_state == CryptoNoteConnectionContext::state_synchronizing) &&
!ctx.m_is_income && ctx.version >= P2P_VERSION_4) {
alive_peers.push_back(ctx);
}
});
Expand Down Expand Up @@ -693,7 +708,18 @@ bool CryptoNoteProtocolHandler::fluffStemPool() {
}

bool CryptoNoteProtocolHandler::on_idle() {
return m_core.on_idle();
try {
m_core.on_idle();
// We don't have peers yet to select dandelion stems
if (m_init_select_dandelion_called) {
m_dandelionStemSelectInterval.call(std::bind(&CryptoNoteProtocolHandler::select_dandelion_stem, this));
}
m_dandelionStemFluffInterval.call(std::bind(&CryptoNoteProtocolHandler::fluffStemPool, this));
} catch (std::exception& e) {
logger(DEBUGGING) << "exception in on_idle: " << e.what();
}

return true;
}

int CryptoNoteProtocolHandler::doPushLiteBlock(NOTIFY_NEW_LITE_BLOCK::request arg, CryptoNoteConnectionContext &context,
Expand Down
5 changes: 5 additions & 0 deletions src/CryptoNoteProtocol/CryptoNoteProtocolHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ namespace CryptoNote
void requestMissingPoolTransactions(const CryptoNoteConnectionContext& context);
bool select_dandelion_stem();
bool fluffStemPool();
void printDandelions() const override;

std::atomic<bool> m_init_select_dandelion_called;

private:
//----------------- commands handlers ----------------------------------------------
Expand Down Expand Up @@ -193,6 +196,8 @@ namespace CryptoNote
std::atomic<size_t> m_peersCount;
Tools::ObserverManager<ICryptoNoteProtocolObserver> m_observerManager;

OnceInInterval m_dandelionStemSelectInterval;
OnceInInterval m_dandelionStemFluffInterval;
std::vector<CryptoNoteConnectionContext> m_dandelion_stem;

StemPool m_stemPool;
Expand Down
1 change: 1 addition & 0 deletions src/CryptoNoteProtocol/ICryptoNoteProtocolQuery.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class ICryptoNoteProtocolQuery {
virtual size_t getPeerCount() const = 0;
virtual bool isSynchronized() const = 0;
virtual bool getConnections(std::vector<CryptoNoteConnectionContext>& connections) const = 0;
virtual void printDandelions() const = 0;
};

} //namespace CryptoNote
7 changes: 7 additions & 0 deletions src/Daemon/DaemonCommandsHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ DaemonCommandsHandler::DaemonCommandsHandler(CryptoNote::Core& core, CryptoNote:
m_consoleHandler.setHandler("help", boost::bind(&DaemonCommandsHandler::help, this, boost::arg<1>()), "Show this help");
m_consoleHandler.setHandler("print_pl", boost::bind(&DaemonCommandsHandler::print_pl, this, boost::arg<1>()), "Print peer list");
m_consoleHandler.setHandler("print_cn", boost::bind(&DaemonCommandsHandler::print_cn, this, boost::arg<1>()), "Print connections");
m_consoleHandler.setHandler("print_dandelion", boost::bind(&DaemonCommandsHandler::print_dand, this, boost::arg<1>()), "Print current dandelion connections");
m_consoleHandler.setHandler("print_bc", boost::bind(&DaemonCommandsHandler::print_bc, this, boost::arg<1>()), "Print blockchain info in a given blocks range, print_bc <begin_height> [<end_height>]");
m_consoleHandler.setHandler("height", boost::bind(&DaemonCommandsHandler::print_height, this, boost::arg<1>()), "Print blockchain height");
//m_consoleHandler.setHandler("print_bci", boost::bind(&DaemonCommandsHandler::print_bci, this, boost::arg<1>()));
Expand Down Expand Up @@ -202,6 +203,12 @@ bool DaemonCommandsHandler::print_cn(const std::vector<std::string>& args)
return true;
}
//--------------------------------------------------------------------------------
bool DaemonCommandsHandler::print_dand(const std::vector<std::string>& args)
{
protocolQuery.printDandelions();
return true;
}
//--------------------------------------------------------------------------------
bool DaemonCommandsHandler::print_bc(const std::vector<std::string> &args) {
if (!args.size()) {
std::cout << "need block index parameter" << ENDL;
Expand Down
1 change: 1 addition & 0 deletions src/Daemon/DaemonCommandsHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class DaemonCommandsHandler
bool print_cn(const std::vector<std::string>& args);
bool print_bc(const std::vector<std::string>& args);
bool print_bci(const std::vector<std::string>& args);
bool print_dand(const std::vector<std::string>& args);
bool print_height(const std::vector<std::string>& args);
bool set_log(const std::vector<std::string>& args);
bool print_block(const std::vector<std::string>& args);
Expand Down
83 changes: 46 additions & 37 deletions src/P2p/NetNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
#include <algorithm>
#include <chrono>
#include <fstream>
#include <future>
#include <thread>

#include <boost/bind.hpp>
Expand Down Expand Up @@ -237,16 +236,15 @@ namespace CryptoNote
logger(log, "node_server"),
m_stopEvent(m_dispatcher),
m_idleTimer(m_dispatcher),
m_connTimer(m_dispatcher),
m_timedSyncTimer(m_dispatcher),
m_timeoutTimer(m_dispatcher),
m_stop(false),
// intervals
m_peer_handshake_idle_maker_interval(CryptoNote::P2P_DEFAULT_HANDSHAKE_INTERVAL),
m_connections_maker_interval(1),
m_peerlist_store_interval(60*30, false),
m_gray_peerlist_housekeeping_interval(CryptoNote::P2P_DEFAULT_HANDSHAKE_INTERVAL),
m_dandelionStemSelectInterval(CryptoNote::parameters::DANDELION_EPOCH),
m_dandelionStemFluffInterval(CryptoNote::parameters::DANDELION_STEM_EMBARGO)
m_gray_peerlist_housekeeping_interval(CryptoNote::P2P_DEFAULT_HANDSHAKE_INTERVAL)
{
}

Expand Down Expand Up @@ -600,6 +598,7 @@ namespace CryptoNote
logger(INFO) << "Starting NodeServer...";

m_workingContextGroup.spawn(std::bind(&NodeServer::acceptLoop, this));
m_workingContextGroup.spawn(std::bind(&NodeServer::connectionWorker, this));
m_workingContextGroup.spawn(std::bind(&NodeServer::onIdle, this));
m_workingContextGroup.spawn(std::bind(&NodeServer::timedSyncLoop, this));
m_workingContextGroup.spawn(std::bind(&NodeServer::timeoutLoop, this));
Expand Down Expand Up @@ -993,68 +992,74 @@ namespace CryptoNote

return false;
}
//-----------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------
bool NodeServer::connections_maker()
{
if (!connect_to_peerlist(m_exclusive_peers)) {
if (!m_exclusive_peers.empty() && !connect_to_peerlist(m_exclusive_peers)) {
return false;
}

if (!m_exclusive_peers.empty()) {
return true;
}

if(!m_peerlist.get_white_peers_count() && m_seed_nodes.size()) {
if (!m_peerlist.get_white_peers_count() && m_seed_nodes.size()) {
size_t try_count = 0;
size_t current_index = Random::randomValue<size_t>() % m_seed_nodes.size();
while(true) {
if(try_to_connect_and_handshake_with_new_peer(m_seed_nodes[current_index], true))

while (true) {
if (try_to_connect_and_handshake_with_new_peer(m_seed_nodes[current_index], true))
break;

if(++try_count > m_seed_nodes.size()) {
if (++try_count > m_seed_nodes.size()) {
logger(ERROR) << "Failed to connect to any of seed peers, continuing without seeds";
break;
}
if(++current_index >= m_seed_nodes.size())
if (++current_index >= m_seed_nodes.size())
current_index = 0;
}
}

if (!connect_to_peerlist(m_priority_peers)) return false;
if (!m_priority_peers.empty() && !connect_to_peerlist(m_priority_peers)) return false;

size_t expected_white_connections = (m_config.m_net_config.connections_count * CryptoNote::P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT) / 100;

size_t conn_count = get_outgoing_connections_count();
if(conn_count < m_config.m_net_config.connections_count)
if (conn_count < m_config.m_net_config.connections_count)
{
if(conn_count < expected_white_connections)
if (conn_count < expected_white_connections)
{
//start from anchor list
if (!make_expected_connections_count(anchor, P2P_DEFAULT_ANCHOR_CONNECTIONS_COUNT))
return false;
//start from white list
if(!make_expected_connections_count(white, expected_white_connections))
if (!make_expected_connections_count(white, expected_white_connections))
return false;
//and then do grey list
if(!make_expected_connections_count(gray, m_config.m_net_config.connections_count))
if (!make_expected_connections_count(gray, m_config.m_net_config.connections_count))
return false;
} else
}
else
{
//start from grey list
if(!make_expected_connections_count(gray, m_config.m_net_config.connections_count))
if (!make_expected_connections_count(gray, m_config.m_net_config.connections_count))
return false;
//and then do white list
if(!make_expected_connections_count(white, m_config.m_net_config.connections_count))
if (!make_expected_connections_count(white, m_config.m_net_config.connections_count))
return false;
}
}

// Now we have peers to select dandelion stems
if (!m_payload_handler.m_init_select_dandelion_called) {
m_payload_handler.select_dandelion_stem();
}

return true;
}

//-----------------------------------------------------------------------------------

bool NodeServer::make_expected_connections_count(PeerType peer_type, size_t expected_connections)
{
std::vector<AnchorPeerlistEntry> apl;
Expand Down Expand Up @@ -1097,20 +1102,6 @@ namespace CryptoNote
return count;
}

//-----------------------------------------------------------------------------------
bool NodeServer::idle_worker() {
try {
m_connections_maker_interval.call(std::bind(&NodeServer::connections_maker, this));
m_dandelionStemSelectInterval.call([&]() { return m_payload_handler.select_dandelion_stem(); });
m_dandelionStemFluffInterval.call([&]() { return m_payload_handler.fluffStemPool(); });
m_peerlist_store_interval.call(std::bind(&NodeServer::store_config, this));
m_gray_peerlist_housekeeping_interval.call(std::bind(&NodeServer::gray_peerlist_housekeeping, this));
} catch (std::exception& e) {
logger(DEBUGGING) << "exception in idle_worker: " << e.what();
}
return true;
}

//-----------------------------------------------------------------------------------
bool NodeServer::fix_time_delta(std::vector<PeerlistEntry>& local_peerlist, time_t local_time, int64_t& delta)
{
Expand Down Expand Up @@ -1502,18 +1493,36 @@ namespace CryptoNote
try {
while (!m_stop) {
m_payload_handler.on_idle();
idle_worker();
m_peerlist_store_interval.call(std::bind(&NodeServer::store_config, this));
m_gray_peerlist_housekeeping_interval.call(std::bind(&NodeServer::gray_peerlist_housekeeping, this));
m_idleTimer.sleep(std::chrono::seconds(1));
}
} catch (System::InterruptedException&) {
logger(DEBUGGING) << "onIdle() is interrupted";
} catch (std::exception& e) {
logger(TRACE) << "Exception in onIdle: " << e.what();
logger(DEBUGGING) << "Exception in onIdle: " << e.what();
}

logger(DEBUGGING) << "onIdle finished";
}

void NodeServer::connectionWorker() {
logger(DEBUGGING) << "connectionWorker started";

try {
while (!m_stop) {
m_connections_maker_interval.call(std::bind(&NodeServer::connections_maker, this));
m_connTimer.sleep(std::chrono::seconds(1));
}
} catch (System::InterruptedException&) {
logger(DEBUGGING) << "connectionWorker() is interrupted";
} catch (std::exception& e) {
logger(DEBUGGING) << "Exception in connectionWorker: " << e.what();
}

logger(DEBUGGING) << "connectionWorker finished";
}

void NodeServer::timeoutLoop() {
try {
while (!m_stop) {
Expand Down
5 changes: 2 additions & 3 deletions src/P2p/NetNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,6 @@ namespace CryptoNote
bool is_addr_recently_failed(const uint32_t address_ip);
bool handleConfig(const NetNodeConfig& config);
bool append_net_address(std::vector<NetworkAddress>& nodes, const std::string& addr);
bool idle_worker();
bool handle_remote_peerlist(const std::vector<PeerlistEntry>& peerlist, time_t local_time, const CryptoNoteConnectionContext& context);
bool get_local_node_data(basic_node_data& node_data);

Expand Down Expand Up @@ -226,6 +225,7 @@ namespace CryptoNote
void connectionHandler(const boost::uuids::uuid& connectionId, P2pConnectionContext& connection);
void writeHandler(P2pConnectionContext& ctx);
void onIdle();
void connectionWorker();
void timedSyncLoop();
void timeoutLoop();

Expand Down Expand Up @@ -256,6 +256,7 @@ namespace CryptoNote
System::ContextGroup m_workingContextGroup;
System::Event m_stopEvent;
System::Timer m_idleTimer;
System::Timer m_connTimer;
System::Timer m_timeoutTimer;
System::TcpListener m_listener;
Logging::LoggerRef logger;
Expand All @@ -268,8 +269,6 @@ namespace CryptoNote
OnceInInterval m_connections_maker_interval;
OnceInInterval m_peerlist_store_interval;
OnceInInterval m_gray_peerlist_housekeeping_interval;
OnceInInterval m_dandelionStemSelectInterval;
OnceInInterval m_dandelionStemFluffInterval;
System::Timer m_timedSyncTimer;

std::string m_bind_ip;
Expand Down

0 comments on commit eed4f35

Please sign in to comment.