From bd0494c9c4b7584fef108b4af29e9ca5677ded0d Mon Sep 17 00:00:00 2001 From: Genoil Date: Mon, 11 Apr 2016 23:31:49 +0200 Subject: [PATCH] stratum failover --- ethminer/MinerAux.h | 81 ++++++++++++++++++++++++++------- libstratum/EthStratumClient.cpp | 74 ++++++++++++++++++++++++------ libstratum/EthStratumClient.h | 32 +++++++++---- 3 files changed, 148 insertions(+), 39 deletions(-) diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index a5b97e78e..93a23d293 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -120,10 +120,23 @@ public: m_farmURL = argv[++i]; m_activeFarmURL = m_farmURL; } - else if ((arg == "-FF" || arg == "--farm-failover") && i + 1 < argc) + else if ((arg == "-FF" || arg == "-FS" || arg == "--farm-failover" || arg == "--stratum-failover") && i + 1 < argc) { - mode = OperationMode::Farm; - m_farmFailOverURL = argv[++i]; + string url = argv[++i]; + if (mode == OperationMode::Stratum) + { + size_t p = url.find_last_of(":"); + if (p > 0) + { + m_farmFailOverURL = url.substr(0, p); + if (p + 1 <= url.length()) + m_fport = url.substr(p + 1); + } + else + { + m_farmFailOverURL = url; + } + } } else if (arg == "--farm-recheck" && i + 1 < argc) try { @@ -168,6 +181,14 @@ public: if (p + 1 <= userpass.length()) m_pass = userpass.substr(p+1); } + else if ((arg == "-FO" || arg == "--failover-userpass") && i + 1 < argc) + { + string userpass = string(argv[++i]); + size_t p = userpass.find_first_of(":"); + m_fuser = userpass.substr(0, p); + if (p + 1 <= userpass.length()) + m_fpass = userpass.substr(p + 1); + } else if ((arg == "-u" || arg == "--user") && i + 1 < argc) { m_user = string(argv[++i]); @@ -180,6 +201,18 @@ public: { m_port = string(argv[++i]); } + else if ((arg == "-fu" || arg == "--failover-user") && i + 1 < argc) + { + m_fuser = string(argv[++i]); + } + else if ((arg == "-fp" || arg == "--failover-pass") && i + 1 < argc) + { + m_fpass = string(argv[++i]); + } + else if ((arg == "-fo" || arg == "--failover-port") && i + 1 < argc) + { + m_fport = string(argv[++i]); + } #endif else if (arg == "--opencl-platform" && i + 1 < argc) try { @@ -536,11 +569,11 @@ public: doBenchmark(m_minerType, m_phoneHome, m_benchmarkWarmup, m_benchmarkTrial, m_benchmarkTrials); else if (mode == OperationMode::Farm) doFarm(m_minerType, m_activeFarmURL, m_farmRecheckPeriod); - else if (mode == OperationMode::Simulation) + else if (mode == OperationMode::Simulation) doSimulation(m_minerType); #if ETH_STRATUM || !ETH_TRUE else if (mode == OperationMode::Stratum) - doStratum(m_minerType, m_farmRecheckPeriod, m_farmURL, m_port, m_user, m_pass); + doStratum(); #endif } @@ -922,9 +955,13 @@ private: if (m_farmFailOverURL != "") { m_farmRetries++; - if (m_farmRetries >= m_maxFarmRetries) + if (m_farmRetries > m_maxFarmRetries) { - if (_remote == m_farmURL) { + if (_remote == "exit") + { + m_running = false; + } + else if (_remote == m_farmURL) { _remote = m_farmFailOverURL; prpc = &rpcFailover; } @@ -934,10 +971,7 @@ private: } m_farmRetries = 0; } - if (_remote == "exit") - { - m_running = false; - } + } } #endif @@ -945,7 +979,7 @@ private: } #if ETH_STRATUM || !ETH_TRUE - void doStratum(MinerType _m, unsigned _recheckPeriod, string const & host, string const & port, string const & user, string const & pass) + void doStratum() { map::SealerDescriptor> sealers; sealers["cpu"] = GenericFarm::SealerDescriptor{ &EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); } }; @@ -956,8 +990,18 @@ private: sealers["cuda"] = GenericFarm::SealerDescriptor{ &EthashCUDAMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCUDAMiner(ci); } }; #endif GenericFarm f; - EthStratumClient client(&f, _m, host, port, user, pass); - + EthStratumClient client(&f, m_minerType, m_farmURL, m_port, m_user, m_pass, m_maxFarmRetries); + if (m_farmFailOverURL != "") + { + if (m_fuser != "") + { + client.setFailover(m_farmFailOverURL, m_fport, m_fuser, m_fpass); + } + else + { + client.setFailover(m_farmFailOverURL, m_fport); + } + } f.setSealers(sealers); f.onSolutionFound([&](EthashProofOfWork::Solution sol) @@ -966,7 +1010,7 @@ private: return false; }); - while (true) + while (client.isRunning()) { auto mp = f.miningProgress(); f.resetMiningProgress(); @@ -977,7 +1021,7 @@ private: else minelog << "Waiting for work package..."; } - this_thread::sleep_for(chrono::milliseconds(_recheckPeriod)); + this_thread::sleep_for(chrono::milliseconds(m_farmRecheckPeriod)); } } #endif @@ -1027,6 +1071,8 @@ private: /// Farm params string m_farmURL = "http://127.0.0.1:8545"; string m_farmFailOverURL = ""; + + string m_activeFarmURL = m_farmURL; unsigned m_farmRetries = 0; unsigned m_maxFarmRetries = 3; @@ -1037,6 +1083,9 @@ private: string m_user; string m_pass; string m_port; + string m_fuser = ""; + string m_fpass = ""; + string m_fport = ""; #endif }; diff --git a/libstratum/EthStratumClient.cpp b/libstratum/EthStratumClient.cpp index 8cf8f98b9..71eb4fd31 100644 --- a/libstratum/EthStratumClient.cpp +++ b/libstratum/EthStratumClient.cpp @@ -4,18 +4,23 @@ using boost::asio::ip::tcp; -EthStratumClient::EthStratumClient(GenericFarm * f, MinerType m, string const & host, string const & port, string const & user, string const & pass) +EthStratumClient::EthStratumClient(GenericFarm * f, MinerType m, string const & host, string const & port, string const & user, string const & pass, int const & retries) : m_socket(m_io_service) { m_minerType = m; - m_host = host; - m_port = port; - m_user = user; - m_pass = pass; + m_primary.host = host; + m_primary.port = port; + m_primary.user = user; + m_primary.pass = pass; + + p_active = &m_primary; + m_authorized = false; m_connected = false; m_precompute = true; m_pending = 0; + m_maxRetries = retries; + p_farm = f; connect(); } @@ -25,22 +30,37 @@ EthStratumClient::~EthStratumClient() } +void EthStratumClient::setFailover(string const & host, string const & port) +{ + setFailover(host, port, p_active->user, p_active->pass); +} + +void EthStratumClient::setFailover(string const & host, string const & port, string const & user, string const & pass) +{ + m_failover.host = host; + m_failover.port = port; + m_failover.user = user; + m_failover.pass = pass; +} + void EthStratumClient::connect() { tcp::resolver r(m_io_service); - tcp::resolver::query q(m_host, m_port); + tcp::resolver::query q(p_active->host, p_active->port); r.async_resolve(q, boost::bind(&EthStratumClient::resolve_handler, this, boost::asio::placeholders::error, boost::asio::placeholders::iterator)); - cnote << "Connecting to stratum server " << m_host +":"+m_port; + cnote << "Connecting to stratum server " << p_active->host + ":" + p_active->port; boost::thread t(boost::bind(&boost::asio::io_service::run, &m_io_service)); } +#define BOOST_ASIO_ENABLE_CANCELIO + void EthStratumClient::reconnect() { /* @@ -50,13 +70,36 @@ void EthStratumClient::reconnect() p_farm->stop(); } */ - m_socket.close(); m_io_service.reset(); + m_socket.close(); m_authorized = false; m_connected = false; + + if (!m_failover.host.empty()) + { + m_retries++; + + if (m_retries > m_maxRetries) + { + if (m_failover.host == "exit") { + disconnect(); + return; + } + else if (p_active == &m_primary) + { + p_active = &m_failover; + } + else { + p_active = &m_primary; + } + m_retries = 0; + } + } + cnote << "Reconnecting in 3 seconds..."; boost::asio::deadline_timer timer(m_io_service, boost::posix_time::seconds(3)); timer.wait(); + connect(); } @@ -64,6 +107,7 @@ void EthStratumClient::disconnect() { cnote << "Disconnecting"; m_connected = false; + m_running = false; if (p_farm->isMining()) { cnote << "Stopping farm"; @@ -83,7 +127,7 @@ void EthStratumClient::resolve_handler(const boost::system::error_code& ec, tcp: } else { - cerr << "Could not resolve host" << m_host + ":" + m_port + ", " << ec.message(); + cerr << "Could not resolve host" << p_active->host + ":" + p_active->port + ", " << ec.message(); reconnect(); } } @@ -93,7 +137,7 @@ void EthStratumClient::connect_handler(const boost::system::error_code& ec, tcp: if (!ec) { m_connected = true; - cnote << "Connected to stratum server " << m_host << ":" << m_port; + cnote << "Connected to stratum server " << p_active->host << ":" << p_active->port; if (!p_farm->isMining()) { cnote << "Starting farm"; @@ -114,7 +158,7 @@ void EthStratumClient::connect_handler(const boost::system::error_code& ec, tcp: } else { - cwarn << "Could not connect to stratum server " << m_host << ":" << m_port << ", " << ec.message(); + cwarn << "Could not connect to stratum server " << p_active->host << ":" << p_active->port << ", " << ec.message(); reconnect(); } @@ -199,7 +243,7 @@ void EthStratumClient::processReponse(Json::Value& responseObject) case 1: cnote << "Subscribed to stratum server"; - os << "{\"id\": 2, \"method\": \"mining.authorize\", \"params\": [\"" << m_user << "\",\"" << m_pass << "\"]}\n"; + os << "{\"id\": 2, \"method\": \"mining.authorize\", \"params\": [\"" << p_active->user << "\",\"" << p_active->pass << "\"]}\n"; async_write(m_socket, m_requestBuffer, boost::bind(&EthStratumClient::handleResponse, this, @@ -212,7 +256,7 @@ void EthStratumClient::processReponse(Json::Value& responseObject) disconnect(); return; } - cnote << "Authorized worker " << m_user; + cnote << "Authorized worker " << p_active->user; break; case 4: if (responseObject.get("result", false).asBool()) @@ -284,7 +328,7 @@ void EthStratumClient::processReponse(Json::Value& responseObject) bool EthStratumClient::submit(EthashProofOfWork::Solution solution) { - cnote << "Solution found; Submitting to" << m_host << "..."; + cnote << "Solution found; Submitting to" << p_active->host << "..."; cnote << " Nonce:" << "0x"+solution.nonce.hex(); cnote << " Mixhash:" << "0x" + solution.mixHash.hex(); cnote << " Header-hash:" << "0x" + m_current.headerHash.hex(); @@ -293,7 +337,7 @@ bool EthStratumClient::submit(EthashProofOfWork::Solution solution) { cnote << " Ethash: " << "0x" + h256(EthashAux::eval(m_current.seedHash, m_current.headerHash, solution.nonce).value).hex(); if (EthashAux::eval(m_current.seedHash, m_current.headerHash, solution.nonce).value < m_current.boundary) { - string json = "{\"id\": 4, \"method\": \"mining.submit\", \"params\": [\"" + m_user + "\",\"" + m_job + "\",\"0x" + solution.nonce.hex() + "\",\"0x" + m_current.headerHash.hex() + "\",\"0x" + solution.mixHash.hex() + "\"]}\n"; + string json = "{\"id\": 4, \"method\": \"mining.submit\", \"params\": [\"" + p_active->user + "\",\"" + m_job + "\",\"0x" + solution.nonce.hex() + "\",\"0x" + m_current.headerHash.hex() + "\",\"0x" + solution.mixHash.hex() + "\"]}\n"; std::ostream os(&m_requestBuffer); os << json; diff --git a/libstratum/EthStratumClient.h b/libstratum/EthStratumClient.h index 447356f79..9afb59120 100644 --- a/libstratum/EthStratumClient.h +++ b/libstratum/EthStratumClient.h @@ -17,12 +17,23 @@ using boost::asio::ip::tcp; using namespace dev; using namespace dev::eth; +typedef struct { + string host; + string port; + string user; + string pass; +} cred_t; + class EthStratumClient { public: - EthStratumClient(GenericFarm * f, MinerType m, string const & host, string const & port, string const & user, string const & pass); + EthStratumClient(GenericFarm * f, MinerType m, string const & host, string const & port, string const & user, string const & pass, int const & retries); ~EthStratumClient(); + void setFailover(string const & host, string const & port); + void setFailover(string const & host, string const & port, string const & user, string const & pass); + + bool isRunning() { return m_running; } bool isConnected() { return m_connected; } h256 currentHeaderHash() { return m_current.headerHash; } bool current() { return m_current; } @@ -40,13 +51,18 @@ private: void processReponse(Json::Value& responseObject); MinerType m_minerType; - string m_host; - string m_port; - string m_user; - string m_pass; - bool m_authorized; - bool m_connected; - bool m_precompute; + + cred_t * p_active; + cred_t m_primary; + cred_t m_failover; + + bool m_authorized; + bool m_connected; + bool m_precompute; + bool m_running = true; + + int m_retries = 0; + int m_maxRetries; boost::mutex m_mtx; int m_pending;