diff options
Diffstat (limited to 'xmrstak/misc/executor.cpp')
-rw-r--r-- | xmrstak/misc/executor.cpp | 420 |
1 files changed, 250 insertions, 170 deletions
diff --git a/xmrstak/misc/executor.cpp b/xmrstak/misc/executor.cpp index b469dc2..931e2aa 100644 --- a/xmrstak/misc/executor.cpp +++ b/xmrstak/misc/executor.cpp @@ -39,6 +39,7 @@ #include <string> #include <cmath> #include <algorithm> +#include <functional> #include <assert.h> #include <time.h> @@ -58,23 +59,17 @@ void executor::push_timed_event(ex_event&& ev, size_t sec) void executor::ex_clock_thd() { - size_t iSwitchPeriod = sec_to_ticks(iDevDonatePeriod); - size_t iDevPortion = (size_t)floor(((double)iSwitchPeriod) * fDevDonationLevel); - - //No point in bothering with less than 10 sec - if(iDevPortion < sec_to_ticks(10)) - iDevPortion = 0; - - //Add 2 seconds to compensate for connect - if(iDevPortion != 0) - iDevPortion += sec_to_ticks(2); - + size_t tick = 0; while (true) { std::this_thread::sleep_for(std::chrono::milliseconds(size_t(iTickTime))); push_event(ex_event(EV_PERF_TICK)); + //Eval pool choice every fourth tick + if((tick++ & 0x03) == 0) + push_event(ex_event(EV_EVAL_POOL_CHOICE)); + // Service timed events std::unique_lock<std::mutex> lck(timed_event_mutex); std::list<timed_event>::iterator ev = lTimedEvents.begin(); @@ -90,49 +85,190 @@ void executor::ex_clock_thd() ev++; } lck.unlock(); + } +} + +bool executor::get_live_pools(std::vector<jpsock*>& eval_pools, bool is_dev) +{ + size_t limit = jconf::inst()->GetGiveUpLimit(); + size_t wait = jconf::inst()->GetNetRetry(); - if(iDevPortion == 0) + if(limit == 0 || is_dev) limit = (-1); //No limit = limit of 2^64-1 + + size_t pool_count = 0; + size_t over_limit = 0; + for(jpsock& pool : pools) + { + if(pool.is_dev_pool() != is_dev) continue; - iSwitchPeriod--; - if(iSwitchPeriod == 0) - { - push_event(ex_event(EV_SWITCH_POOL, usr_pool_id)); - iSwitchPeriod = sec_to_ticks(iDevDonatePeriod); - } - else if(iSwitchPeriod == iDevPortion) + // Only eval live pools + size_t num, dtime; + if(pool.get_disconnects(num, dtime)) + set_timestamp(); + + if(dtime == 0 || (dtime >= wait && num <= limit)) + eval_pools.emplace_back(&pool); + + pool_count++; + if(num > limit) + over_limit++; + } + + if(eval_pools.size() == 0) + { + if(!is_dev) { - push_event(ex_event(EV_SWITCH_POOL, dev_pool_id)); + if(xmrstak::globalStates::inst().pool_id != invalid_pool_id) + { + printer::inst()->print_msg(L0, "All pools are dead. Idling..."); + auto work = xmrstak::miner_work(); + xmrstak::pool_data dat; + xmrstak::globalStates::inst().switch_work(work, dat); + } + + if(over_limit == pool_count) + { + printer::inst()->print_msg(L0, "All pools are over give up limit. Exitting."); + exit(0); + } + + return false; } + else + return get_live_pools(eval_pools, false); } + + return true; } -void executor::sched_reconnect() +/* + * This event is called by the timer and whenever something relevant happens. + * The job here is to decide if we want to connect, disconnect, or switch jobs (or do nothing) + */ +void executor::eval_pool_choice() { - iReconnectAttempts++; - size_t iLimit = jconf::inst()->GetGiveUpLimit(); - if(iLimit != 0 && iReconnectAttempts > iLimit) + std::vector<jpsock*> eval_pools; + eval_pools.reserve(pools.size()); + + bool dev_time = is_dev_time(); + if(!get_live_pools(eval_pools, dev_time)) + return; + + size_t running = 0; + for(jpsock* pool : eval_pools) { - printer::inst()->print_msg(L0, "Give up limit reached. Exitting."); - exit(0); + if(pool->is_running()) + running++; } - long long unsigned int rt = jconf::inst()->GetNetRetry(); - printer::inst()->print_msg(L1, "Pool connection lost. Waiting %lld s before retry (attempt %llu).", - rt, int_port(iReconnectAttempts)); + // Special case - if we are without a pool, connect to all find a live pool asap + if(running == 0) + { + if(dev_time) + printer::inst()->print_msg(L1, "Fast-connecting to dev pool ..."); - auto work = xmrstak::miner_work(); - xmrstak::pool_data dat; + for(jpsock* pool : eval_pools) + { + if(pool->can_connect()) + { + if(!dev_time) + printer::inst()->print_msg(L1, "Fast-connecting to %s pool ...", pool->get_pool_addr()); + std::string error; + if(!pool->connect(error)) + log_socket_error(pool, std::move(error)); + } + } + + return; + } + + std::sort(eval_pools.begin(), eval_pools.end(), [](jpsock* a, jpsock* b) { return b->get_pool_weight(true) < a->get_pool_weight(true); }); + jpsock* goal = eval_pools[0]; - xmrstak::globalStates::inst().switch_work(work, dat); + if(goal->get_pool_id() != xmrstak::globalStates::inst().pool_id) + { + if(!goal->is_running() && goal->can_connect()) + { + if(dev_time) + printer::inst()->print_msg(L1, "Connecting to dev pool ..."); + else + printer::inst()->print_msg(L1, "Connecting to %s pool ...", goal->get_pool_addr()); + + std::string error; + if(!goal->connect(error)) + log_socket_error(goal, std::move(error)); + return; + } + + if(goal->is_logged_in()) + { + pool_job oPoolJob; + if(!goal->get_current_job(oPoolJob)) + { + goal->disconnect(); + return; + } - push_timed_event(ex_event(EV_RECONNECT, usr_pool_id), rt); + size_t prev_pool_id = current_pool_id; + current_pool_id = goal->get_pool_id(); + on_pool_have_job(current_pool_id, oPoolJob); + + jpsock* prev_pool = pick_pool_by_id(prev_pool_id); + if(prev_pool == nullptr || (!prev_pool->is_dev_pool() && !goal->is_dev_pool())) + reset_stats(); + + if(goal->is_dev_pool() && (prev_pool != nullptr && !prev_pool->is_dev_pool())) + last_usr_pool_id = prev_pool_id; + else + last_usr_pool_id = invalid_pool_id; + + return; + } + } + else + { + /* All is good - but check if we can do better */ + std::sort(eval_pools.begin(), eval_pools.end(), [](jpsock* a, jpsock* b) { return b->get_pool_weight(false) < a->get_pool_weight(false); }); + jpsock* goal2 = eval_pools[0]; + + if(goal->get_pool_id() != goal2->get_pool_id()) + { + if(!goal2->is_running() && goal2->can_connect()) + { + printer::inst()->print_msg(L1, "Background-connect to %s pool ...", goal2->get_pool_addr()); + std::string error; + if(!goal2->connect(error)) + log_socket_error(goal2, std::move(error)); + return; + } + } + } + + if(!dev_time) + { + for(jpsock& pool : pools) + { + if(goal->is_logged_in() && pool.is_running() && pool.get_pool_id() != goal->get_pool_id()) + pool.disconnect(true); + + if(pool.is_dev_pool() && pool.is_running()) + pool.disconnect(true); + } + } } -void executor::log_socket_error(std::string&& sError) +void executor::log_socket_error(jpsock* pool, std::string&& sError) { + std::string pool_name; + pool_name.reserve(128); + pool_name.append("[").append(pool->get_pool_addr()).append("] "); + sError.insert(0, pool_name); + vSocketLog.emplace_back(std::move(sError)); printer::inst()->print_msg(L1, "SOCKET ERROR - %s", vSocketLog.back().msg.c_str()); + + push_event(ex_event(EV_EVAL_POOL_CHOICE)); } void executor::log_result_error(std::string&& sError) @@ -172,70 +308,48 @@ jpsock* executor::pick_pool_by_id(size_t pool_id) if(pool_id == invalid_pool_id) return nullptr; - if(pool_id == dev_pool_id) - return dev_pool; - else - return usr_pool; + for(jpsock& pool : pools) + if(pool.get_pool_id() == pool_id) + return &pool; + + return nullptr; } void executor::on_sock_ready(size_t pool_id) { jpsock* pool = pick_pool_by_id(pool_id); + + if(pool->is_dev_pool()) + printer::inst()->print_msg(L1, "Dev pool connected. Logging in..."); + else + printer::inst()->print_msg(L1, "Pool %s connected. Logging in...", pool->get_pool_addr()); - if(pool_id == dev_pool_id) - { - if(::jconf::inst()->IsCurrencyMonero()) - { - if(!pool->cmd_login("", "")) - pool->disconnect(); - } - else - { - if(!pool->cmd_login("WmsvqXDu7Fw5eAEZr1euJH3ycad55NxFd82PfhLR9Zi1Nq5S74zk63EA8fyMS8BQNR94os9N9aah87inKkumNJ7G2d7qTpRLN", "x")) - pool->disconnect(); - } - - current_pool_id = dev_pool_id; - printer::inst()->print_msg(L1, "Dev pool logged in. Switching work."); - return; - } - - printer::inst()->print_msg(L1, "Connected. Logging in..."); - - if (!pool->cmd_login(jconf::inst()->GetWalletAddress(), jconf::inst()->GetPoolPwd())) + if(!pool->cmd_login()) { if(!pool->have_sock_error()) { - log_socket_error(pool->get_call_error()); + log_socket_error(pool, pool->get_call_error()); pool->disconnect(); } } - else - { - iReconnectAttempts = 0; - reset_stats(); - } } -void executor::on_sock_error(size_t pool_id, std::string&& sError) +void executor::on_sock_error(size_t pool_id, std::string&& sError, bool silent) { jpsock* pool = pick_pool_by_id(pool_id); - if(pool_id == dev_pool_id) - { - pool->disconnect(); - - if(current_pool_id != dev_pool_id) - return; + pool->disconnect(); + + if(pool_id == current_pool_id) + current_pool_id = invalid_pool_id; - printer::inst()->print_msg(L1, "Dev pool connection error. Switching work."); - on_switch_pool(usr_pool_id); + if(silent) return; - } - log_socket_error(std::move(sError)); - pool->disconnect(); - sched_reconnect(); + if(!pool->is_dev_pool()) + log_socket_error(pool, std::move(sError)); + else + printer::inst()->print_msg(L1, "Dev pool socket error - mining on user pool..."); } void executor::on_pool_have_job(size_t pool_id, pool_job& oPoolJob) @@ -245,9 +359,8 @@ void executor::on_pool_have_job(size_t pool_id, pool_job& oPoolJob) jpsock* pool = pick_pool_by_id(pool_id); - xmrstak::miner_work oWork(oPoolJob.sJobID, oPoolJob.bWorkBlob, oPoolJob.iWorkLen, oPoolJob.iTarget, - pool_id != dev_pool_id && ::jconf::inst()->NiceHashMode(), pool_id); - + xmrstak::miner_work oWork(oPoolJob.sJobID, oPoolJob.bWorkBlob, oPoolJob.iWorkLen, oPoolJob.iTarget, pool->is_nicehash(), pool_id); + xmrstak::pool_data dat; dat.iSavedNonce = oPoolJob.iSavedNonce; dat.pool_id = pool_id; @@ -261,7 +374,7 @@ void executor::on_pool_have_job(size_t pool_id, pool_job& oPoolJob) prev_pool->save_nonce(dat.iSavedNonce); } - if(pool_id == dev_pool_id) + if(pool->is_dev_pool()) return; if(iPoolDiff != pool->get_current_diff()) @@ -270,17 +383,22 @@ void executor::on_pool_have_job(size_t pool_id, pool_job& oPoolJob) printer::inst()->print_msg(L2, "Difficulty changed. Now: %llu.", int_port(iPoolDiff)); } - if(dat.pool_id == pool_id) - printer::inst()->print_msg(L3, "New block detected."); + if(dat.pool_id != pool_id) + { + if(dat.pool_id == invalid_pool_id) + printer::inst()->print_msg(L2, "Pool logged in."); + else + printer::inst()->print_msg(L2, "Pool switched."); + } else - printer::inst()->print_msg(L3, "Pool switched."); + printer::inst()->print_msg(L3, "New block detected."); } void executor::on_miner_result(size_t pool_id, job_result& oResult) { jpsock* pool = pick_pool_by_id(pool_id); - if(pool_id == dev_pool_id) + if(pool->is_dev_pool()) { //Ignore errors silently if(pool->is_running() && pool->is_logged_in()) @@ -331,64 +449,6 @@ void executor::on_miner_result(size_t pool_id, job_result& oResult) } } -void executor::on_reconnect(size_t pool_id) -{ - jpsock* pool = pick_pool_by_id(pool_id); - - std::string error; - if(pool_id == dev_pool_id) - return; - - printer::inst()->print_msg(L1, "Connecting to pool %s ...", jconf::inst()->GetPoolAddress()); - - if(!pool->connect(jconf::inst()->GetPoolAddress(), error)) - { - log_socket_error(std::move(error)); - sched_reconnect(); - } -} - -void executor::on_switch_pool(size_t pool_id) -{ - if(pool_id == current_pool_id) - return; - - jpsock* pool = pick_pool_by_id(pool_id); - if(pool_id == dev_pool_id) - { - std::string error; - - // If it fails, it fails, we carry on on the usr pool - // as we never receive further events - printer::inst()->print_msg(L1, "Connecting to dev pool..."); - std::string dev_pool_addr; - if(::jconf::inst()->IsCurrencyMonero()) - dev_pool_addr = jconf::inst()->GetTlsSetting() ? "donate.xmr-stak.net:6666" : "donate.xmr-stak.net:3333"; - else - dev_pool_addr = jconf::inst()->GetTlsSetting() ? "mine.aeon-pool.com:443" : "mine.aeon-pool.com:5555"; - if(!pool->connect(dev_pool_addr.c_str(), error)) - printer::inst()->print_msg(L1, "Error connecting to dev pool. Staying with user pool."); - } - else - { - printer::inst()->print_msg(L1, "Switching back to user pool."); - - current_pool_id = pool_id; - pool_job oPoolJob; - - if(!pool->get_current_job(oPoolJob)) - { - pool->disconnect(); - return; - } - - on_pool_have_job(current_pool_id, oPoolJob); - - if(dev_pool->is_running()) - push_timed_event(ex_event(EV_DEV_POOL_EXIT), 5); - } -} - void executor::ex_main() { assert(1000 % iTickTime == 0); @@ -406,15 +466,36 @@ void executor::ex_main() telem = new xmrstak::telemetry(pvThreads->size()); - current_pool_id = usr_pool_id; - usr_pool = new jpsock(usr_pool_id, jconf::inst()->GetTlsSetting()); - dev_pool = new jpsock(dev_pool_id, jconf::inst()->GetTlsSetting()); + set_timestamp(); + size_t pc = jconf::inst()->GetPoolCount(); + bool tls = true; + for(size_t i=0; i < pc; i++) + { + jconf::pool_cfg cfg; + jconf::inst()->GetPoolConfig(i, cfg); + if(!cfg.tls) tls = false; + pools.emplace_back(i+1, cfg.sPoolAddr, cfg.sWalletAddr, cfg.sPasswd, cfg.weight, false, cfg.tls, cfg.tls_fingerprint, cfg.nicehash); + } + + if(jconf::inst()->IsCurrencyMonero()) + { + if(tls) + pools.emplace_front(0, "donate.xmr-stak.net:6666", "", "", 0.0, true, true, "", false); + else + pools.emplace_front(0, "donate.xmr-stak.net:3333", "", "", 0.0, true, false, "", false); + } + else + { + if(tls) + pools.emplace_front(0, "donate.xmr-stak.net:7777", "", "", 0.0, true, true, "", false); + else + pools.emplace_front(0, "donate.xmr-stak.net:4444", "", "", 0.0, true, false, "", false); + } ex_event ev; std::thread clock_thd(&executor::ex_clock_thd, this); - //This will connect us to the pool for the first time - push_event(ex_event(EV_RECONNECT, usr_pool_id)); + eval_pool_choice(); // Place the default success result at position 0, it needs to // be here even if our first result is a failure @@ -435,7 +516,7 @@ void executor::ex_main() break; case EV_SOCK_ERROR: - on_sock_error(ev.iPoolId, std::move(ev.sSocketError)); + on_sock_error(ev.iPoolId, std::move(ev.oSocketError.sSocketError), ev.oSocketError.silent); break; case EV_POOL_HAVE_JOB: @@ -446,16 +527,8 @@ void executor::ex_main() on_miner_result(ev.iPoolId, ev.oJobResult); break; - case EV_RECONNECT: - on_reconnect(ev.iPoolId); - break; - - case EV_SWITCH_POOL: - on_switch_pool(ev.iPoolId); - break; - - case EV_DEV_POOL_EXIT: - dev_pool->disconnect(); + case EV_EVAL_POOL_CHOICE: + eval_pool_choice(); break; case EV_PERF_TICK: @@ -486,7 +559,7 @@ void executor::ex_main() if(normal && fHighestHps < fHps) fHighestHps = fHps; } - break; + break; case EV_USR_HASHRATE: case EV_USR_RESULTS: @@ -672,11 +745,13 @@ void executor::connection_report(std::string& out) out.reserve(512); - jpsock* pool = pick_pool_by_id(dev_pool_id + 1); + jpsock* pool = pick_pool_by_id(current_pool_id); + if(pool != nullptr && pool->is_dev_pool()) + pool = pick_pool_by_id(last_usr_pool_id); out.append("CONNECTION REPORT\n"); - out.append("Pool address : ").append(jconf::inst()->GetPoolAddress()).append(1, '\n'); - if (pool->is_running() && pool->is_logged_in()) + out.append("Pool address : ").append(pool != nullptr ? pool->get_pool_addr() : "<not connected>").append(1, '\n'); + if(pool != nullptr && pool->is_running() && pool->is_logged_in()) out.append("Connected since : ").append(time_format(date, sizeof(date), tPoolConnTime)).append(1, '\n'); else out.append("Connected since : <not connected>\n"); @@ -833,9 +908,12 @@ void executor::http_connection_report(std::string& out) snprintf(buffer, sizeof(buffer), sHtmlCommonHeader, "Connection Report", "Connection Report"); out.append(buffer); - jpsock* pool = pick_pool_by_id(dev_pool_id + 1); + jpsock* pool = pick_pool_by_id(current_pool_id); + if(pool != nullptr && pool->is_dev_pool()) + pool = pick_pool_by_id(last_usr_pool_id); + const char* cdate = "not connected"; - if (pool->is_running() && pool->is_logged_in()) + if (pool != nullptr && pool->is_running() && pool->is_logged_in()) cdate = time_format(date, sizeof(date), tPoolConnTime); size_t n_calls = iPoolCallTimes.size(); @@ -848,7 +926,7 @@ void executor::http_connection_report(std::string& out) } snprintf(buffer, sizeof(buffer), sHtmlConnectionBodyHigh, - jconf::inst()->GetPoolAddress(), + pool != nullptr ? pool->get_pool_addr() : "not connected", cdate, ping_time); out.append(buffer); @@ -918,10 +996,12 @@ void executor::http_json_report(std::string& out) for(size_t i=1; i < ln; i++) iTotalRes += vMineResults[i].count; - jpsock* pool = pick_pool_by_id(dev_pool_id + 1); + jpsock* pool = pick_pool_by_id(current_pool_id); + if(pool != nullptr && pool->is_dev_pool()) + pool = pick_pool_by_id(last_usr_pool_id); size_t iConnSec = 0; - if(pool->is_running() && pool->is_logged_in()) + if(pool != nullptr && pool->is_running() && pool->is_logged_in()) { using namespace std::chrono; iConnSec = duration_cast<seconds>(system_clock::now() - tPoolConnTime).count(); @@ -973,7 +1053,7 @@ void executor::http_json_report(std::string& out) int_port(iPoolDiff), int_port(iGoodRes), int_port(iTotalRes), fAvgResTime, int_port(iPoolHashes), int_port(iTopDiff[0]), int_port(iTopDiff[1]), int_port(iTopDiff[2]), int_port(iTopDiff[3]), int_port(iTopDiff[4]), int_port(iTopDiff[5]), int_port(iTopDiff[6]), int_port(iTopDiff[7]), int_port(iTopDiff[8]), int_port(iTopDiff[9]), - res_error.c_str(), jconf::inst()->GetPoolAddress(), int_port(iConnSec), int_port(iPoolPing), cn_error.c_str()); + res_error.c_str(), pool != nullptr ? pool->get_pool_addr() : "not connected", int_port(iConnSec), int_port(iPoolPing), cn_error.c_str()); out = std::string(bigbuf.get(), bigbuf.get() + bb_len); } |