diff --git a/src/base/kernel/interfaces/IClient.h b/src/base/kernel/interfaces/IClient.h index 8a8776ba..456d603d 100644 --- a/src/base/kernel/interfaces/IClient.h +++ b/src/base/kernel/interfaces/IClient.h @@ -64,6 +64,7 @@ public: virtual bool isEnabled() const = 0; virtual bool isTLS() const = 0; virtual const char *mode() const = 0; + virtual const char *tag() const = 0; virtual const char *tlsFingerprint() const = 0; virtual const char *tlsVersion() const = 0; virtual const Job &job() const = 0; diff --git a/src/base/net/stratum/BaseClient.cpp b/src/base/net/stratum/BaseClient.cpp index 6072a666..12b7ca76 100644 --- a/src/base/net/stratum/BaseClient.cpp +++ b/src/base/net/stratum/BaseClient.cpp @@ -26,6 +26,8 @@ #include "base/net/stratum/BaseClient.h" #include "3rdparty/rapidjson/document.h" #include "base/io/Env.h" +#include "base/io/log/Log.h" +#include "base/io/log/Tags.h" #include "base/kernel/interfaces/IClientListener.h" #include "base/net/stratum/SubmitResult.h" @@ -56,6 +58,7 @@ void xmrig::BaseClient::setPool(const Pool &pool) m_user = Env::expand(pool.user()); m_password = Env::expand(pool.password()); m_rigId = Env::expand(pool.rigId()); + m_tag = std::string(Tags::network()) + " " CYAN_BOLD_S + m_pool.url().data() + CLEAR; } diff --git a/src/base/net/stratum/BaseClient.h b/src/base/net/stratum/BaseClient.h index 03b3895c..0a87fedb 100644 --- a/src/base/net/stratum/BaseClient.h +++ b/src/base/net/stratum/BaseClient.h @@ -49,6 +49,7 @@ public: protected: inline bool isEnabled() const override { return m_enabled; } + inline const char *tag() const override { return m_tag.c_str(); } inline const Job &job() const override { return m_job; } inline const Pool &pool() const override { return m_pool; } inline const String &ip() const override { return m_ip; } @@ -96,6 +97,7 @@ protected: SocketState m_state = UnconnectedState; std::map m_callbacks; std::map m_results; + std::string m_tag; String m_ip; String m_password; String m_rigId; diff --git a/src/base/net/stratum/Client.cpp b/src/base/net/stratum/Client.cpp index 81574016..8240e4e3 100644 --- a/src/base/net/stratum/Client.cpp +++ b/src/base/net/stratum/Client.cpp @@ -161,7 +161,7 @@ int64_t xmrig::Client::send(const rapidjson::Value &obj) const size_t size = buffer.GetSize(); if (size > kMaxSendBufferSize) { - LOG_ERR("[%s] send failed: \"max send buffer size exceeded: %zu\"", url(), size); + LOG_ERR("%s " RED("send failed: ") RED_BOLD("\"max send buffer size exceeded: %zu\""), tag(), size); close(); return -1; @@ -307,7 +307,7 @@ void xmrig::Client::onResolved(const Dns &dns, int status) if (status < 0 && dns.isEmpty()) { if (!isQuiet()) { - LOG_ERR("[%s] DNS error: \"%s\"", url(), uv_strerror(status)); + LOG_ERR("%s " RED("DNS error: ") RED_BOLD("\"%s\""), tag(), uv_strerror(status)); } return reconnect(); @@ -420,10 +420,6 @@ bool xmrig::Client::parseJob(const rapidjson::Value ¶ms, int *code) } if (m_pool.mode() != Pool::MODE_SELF_SELECT && job.algorithm().family() == Algorithm::RANDOM_X && !job.setSeedHash(Json::getString(params, "seed_hash"))) { - if (!isQuiet()) { - LOG_ERR("[%s] failed to parse field \"seed_hash\" required by RandomX", url(), algo); - } - *code = 7; return false; } @@ -441,7 +437,7 @@ bool xmrig::Client::parseJob(const rapidjson::Value ¶ms, int *code) } if (!isQuiet()) { - LOG_WARN("[%s] duplicate job received, reconnect", url()); + LOG_WARN("%s " YELLOW("duplicate job received, reconnect"), tag()); } close(); @@ -500,10 +496,10 @@ bool xmrig::Client::verifyAlgorithm(const Algorithm &algorithm, const char *algo if (!algorithm.isValid()) { if (!isQuiet()) { if (algo == nullptr) { - LOG_ERR("[%s] unknown algorithm, make sure you set \"algo\" or \"coin\" option", url(), algo); + LOG_ERR("%s " RED("unknown algorithm, make sure you set \"algo\" or \"coin\" option"), tag(), algo); } else { - LOG_ERR("[%s] unsupported algorithm \"%s\" detected, reconnect", url(), algo); + LOG_ERR("%s " RED("unsupported algorithm ") RED_BOLD("\"%s\" ") RED("detected, reconnect"), tag(), algo); } } @@ -514,7 +510,7 @@ bool xmrig::Client::verifyAlgorithm(const Algorithm &algorithm, const char *algo m_listener->onVerifyAlgorithm(this, algorithm, &ok); if (!ok && !isQuiet()) { - LOG_ERR("[%s] incompatible/disabled algorithm \"%s\" detected, reconnect", url(), algorithm.shortName()); + LOG_ERR("%s " RED("incompatible/disabled algorithm ") RED_BOLD("\"%s\" ") RED("detected, reconnect"), tag(), algorithm.shortName()); } return ok; @@ -529,7 +525,7 @@ bool xmrig::Client::write(const uv_buf_t &buf) } if (!isQuiet()) { - LOG_ERR("[%s] write error: \"%s\"", url(), uv_strerror(rc)); + LOG_ERR("%s " RED("write error: ") RED_BOLD("\"%s\""), tag(), uv_strerror(rc)); } close(); @@ -550,7 +546,7 @@ int xmrig::Client::resolve(const String &host) if (!m_dns->resolve(host)) { if (!isQuiet()) { - LOG_ERR("[%s:%u] getaddrinfo error: \"%s\"", host.data(), m_pool.port(), uv_strerror(m_dns->status())); + LOG_ERR("%s " RED("getaddrinfo error: ") RED_BOLD("\"%s\""), tag(), uv_strerror(m_dns->status())); } return 1; @@ -644,7 +640,7 @@ void xmrig::Client::login() Value params(kObjectType); params.AddMember("login", m_user.toJSON(), allocator); params.AddMember("pass", m_password.toJSON(), allocator); - params.AddMember("agent", StringRef(m_agent), allocator); + params.AddMember("agent", StringRef(m_agent), allocator); if (!m_rigId.isNull()) { params.AddMember("rigid", m_rigId.toJSON(), allocator); @@ -684,7 +680,7 @@ void xmrig::Client::parse(char *line, size_t len) if (len < 32 || line[0] != '{') { if (!isQuiet()) { - LOG_ERR("[%s] JSON decode failed", url()); + LOG_ERR("%s " RED("JSON decode failed"), tag()); } return; @@ -693,7 +689,7 @@ void xmrig::Client::parse(char *line, size_t len) rapidjson::Document doc; if (doc.ParseInsitu(line).HasParseError()) { if (!isQuiet()) { - LOG_ERR("[%s] JSON decode failed: \"%s\"", url(), rapidjson::GetParseError_En(doc.GetParseError())); + LOG_ERR("%s " RED("JSON decode failed: ") RED_BOLD("\"%s\""), tag(), rapidjson::GetParseError_En(doc.GetParseError())); } return; @@ -703,13 +699,28 @@ void xmrig::Client::parse(char *line, size_t len) return; } - const rapidjson::Value &id = doc["id"]; + const auto &id = Json::getValue(doc, "id"); + const auto &error = Json::getValue(doc, "error"); + if (id.IsInt64()) { - parseResponse(id.GetInt64(), doc["result"], doc["error"]); + return parseResponse(id.GetInt64(), Json::getValue(doc, "result"), error); } - else { - parseNotification(doc["method"].GetString(), doc["params"], doc["error"]); + + const char *method = Json::getString(doc, "method"); + if (!method) { + return; } + + if (error.IsObject()) { + if (!isQuiet()) { + LOG_ERR("%s " RED("error: ") RED_BOLD("\"%s\"") RED(", code: ") RED_BOLD("%d"), + tag(), Json::getString(error, "message"), Json::getInt(error, "code")); + } + + return; + } + + parseNotification(method, Json::getValue(doc, "params"), error); } @@ -755,19 +766,8 @@ void xmrig::Client::parseExtensions(const rapidjson::Value &result) } -void xmrig::Client::parseNotification(const char *method, const rapidjson::Value ¶ms, const rapidjson::Value &error) +void xmrig::Client::parseNotification(const char *method, const rapidjson::Value ¶ms, const rapidjson::Value &) { - if (error.IsObject()) { - if (!isQuiet()) { - LOG_ERR("[%s] error: \"%s\", code: %d", url(), error["message"].GetString(), error["code"].GetInt()); - } - return; - } - - if (!method) { - return; - } - if (strcmp(method, "job") == 0) { int code = -1; if (parseJob(params, &code)) { @@ -779,8 +779,6 @@ void xmrig::Client::parseNotification(const char *method, const rapidjson::Value return; } - - LOG_WARN("[%s] unsupported method: \"%s\"", url(), method); } @@ -794,7 +792,7 @@ void xmrig::Client::parseResponse(int64_t id, const rapidjson::Value &result, co const char *message = error["message"].GetString(); if (!handleSubmitResponse(id, message) && !isQuiet()) { - LOG_ERR("[%s] error: " RED_BOLD("\"%s\"") RED_S ", code: %d", url(), message, error["code"].GetInt()); + LOG_ERR("%s " RED("error: ") RED_BOLD("\"%s\"") RED(", code: ") RED_BOLD("%d"), tag(), message, Json::getInt(error, "code")); } if (m_id == 1 || isCriticalError(message)) { @@ -812,7 +810,7 @@ void xmrig::Client::parseResponse(int64_t id, const rapidjson::Value &result, co int code = -1; if (!parseLogin(result, &code)) { if (!isQuiet()) { - LOG_ERR("[%s] login error code: %d", url(), code); + LOG_ERR("%s " RED("login error code: ") RED_BOLD("%d"), tag(), code); } close(); @@ -840,10 +838,9 @@ void xmrig::Client::ping() void xmrig::Client::read(ssize_t nread, const uv_buf_t *buf) { const auto size = static_cast(nread); - if (nread < 0) { if (!isQuiet()) { - LOG_ERR("[%s] read error: \"%s\"", url(), uv_strerror(static_cast(nread))); + LOG_ERR("%s " RED("read error: ") RED_BOLD("\"%s\""), tag(), uv_strerror(static_cast(nread))); } close(); @@ -972,7 +969,7 @@ void xmrig::Client::onConnect(uv_connect_t *req, int status) if (status < 0) { if (!client->isQuiet()) { - LOG_ERR("[%s] connect error: \"%s\"", client->url(), uv_strerror(status)); + LOG_ERR("%s " RED("connect error: ") RED_BOLD("\"%s\""), client->tag(), uv_strerror(status)); } if (client->state() == ReconnectingState || client->state() == ClosingState) { @@ -980,10 +977,6 @@ void xmrig::Client::onConnect(uv_connect_t *req, int status) } if (client->state() != ConnectingState) { - if (!client->isQuiet()) { - LOG_ERR("[%s] connect error: \"invalid state: %d\"", client->url(), client->state()); - } - return; } @@ -992,8 +985,6 @@ void xmrig::Client::onConnect(uv_connect_t *req, int status) } if (client->state() == ConnectedState) { - LOG_ERR("[%s] already connected", client->url()); - return; } diff --git a/src/base/net/stratum/EthStratumClient.cpp b/src/base/net/stratum/EthStratumClient.cpp index 52ffe35e..e87b0841 100644 --- a/src/base/net/stratum/EthStratumClient.cpp +++ b/src/base/net/stratum/EthStratumClient.cpp @@ -1,11 +1,4 @@ /* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2019 jtgrassie * Copyright 2018-2020 SChernykh * Copyright 2016-2020 XMRig , * @@ -24,58 +17,32 @@ */ #include -#include #include +#include +#include + +#include "base/net/stratum/EthStratumClient.h" #include "3rdparty/libethash/endian.h" #include "3rdparty/rapidjson/document.h" #include "3rdparty/rapidjson/error/en.h" #include "3rdparty/rapidjson/stringbuffer.h" #include "3rdparty/rapidjson/writer.h" - #include "base/io/json/Json.h" #include "base/io/json/JsonRequest.h" #include "base/io/log/Log.h" #include "base/kernel/interfaces/IClientListener.h" -#include "base/net/stratum/EthStratumClient.h" - #include "net/JobResult.h" -namespace xmrig { - -EthStratumClient::EthStratumClient(int id, const char *agent, IClientListener *listener) : +xmrig::EthStratumClient::EthStratumClient(int id, const char *agent, IClientListener *listener) : Client(id, agent, listener) { } -void EthStratumClient::login() -{ - using namespace rapidjson; - m_results.clear(); - - Document doc(kObjectType); - auto& allocator = doc.GetAllocator(); - - Value params(kArrayType); - params.PushBack(StringRef(agent()), allocator); - - JsonRequest::create(doc, m_sequence, "mining.subscribe", params); - - send(doc, [this](const rapidjson::Value& result, bool success, uint64_t elapsed) { OnSubscribeResponse(result, success, elapsed); }); -} - - -void EthStratumClient::onClose() -{ - m_authorized = false; - Client::onClose(); -} - - -int64_t EthStratumClient::submit(const JobResult& result) +int64_t xmrig::EthStratumClient::submit(const JobResult& result) { # ifndef XMRIG_PROXY_PROJECT if ((m_state != ConnectedState) || !m_authorized) { @@ -100,7 +67,7 @@ int64_t EthStratumClient::submit(const JobResult& result) std::stringstream s; s << "0x" << std::hex << std::setw(16) << std::setfill('0') << result.nonce; - params.PushBack(rapidjson::Value(s.str().c_str(), allocator), allocator); + params.PushBack(Value(s.str().c_str(), allocator), allocator); s.str(std::string()); s << "0x"; @@ -108,7 +75,7 @@ int64_t EthStratumClient::submit(const JobResult& result) const uint32_t k = result.headerHash()[i]; s << std::hex << std::setw(2) << std::setfill('0') << k; } - params.PushBack(rapidjson::Value(s.str().c_str(), allocator), allocator); + params.PushBack(Value(s.str().c_str(), allocator), allocator); s.str(std::string()); s << "0x"; @@ -116,7 +83,7 @@ int64_t EthStratumClient::submit(const JobResult& result) const uint32_t k = result.mixHash()[i]; s << std::hex << std::setw(2) << std::setfill('0') << k; } - params.PushBack(rapidjson::Value(s.str().c_str(), allocator), allocator); + params.PushBack(Value(s.str().c_str(), allocator), allocator); JsonRequest::create(doc, m_sequence, "mining.submit", params); @@ -133,7 +100,23 @@ int64_t EthStratumClient::submit(const JobResult& result) } -bool EthStratumClient::handleResponse(int64_t id, const rapidjson::Value& result, const rapidjson::Value& error) +void xmrig::EthStratumClient::login() +{ + m_results.clear(); + + subscribe(); + authorize(); +} + + +void xmrig::EthStratumClient::onClose() +{ + m_authorized = false; + Client::onClose(); +} + + +bool xmrig::EthStratumClient::handleResponse(int64_t id, const rapidjson::Value& result, const rapidjson::Value& error) { auto it = m_callbacks.find(id); if (it != m_callbacks.end()) { @@ -164,43 +147,10 @@ bool EthStratumClient::handleResponse(int64_t id, const rapidjson::Value& result } -void EthStratumClient::parseNotification(const char* method, const rapidjson::Value& params, const rapidjson::Value& error) +void xmrig::EthStratumClient::parseNotification(const char *method, const rapidjson::Value ¶ms, const rapidjson::Value &) { - if (error.IsObject()) { - if (!isQuiet()) { - LOG_ERR("[%s] error: \"%s\", code: %d", url(), error["message"].GetString(), error["code"].GetInt()); - } - return; - } - - if (!method) { - return; - } - if (strcmp(method, "mining.set_target") == 0) { - if (!params.IsArray()) { - LOG_ERR("Invalid mining.set_target notification: params is not an array"); - return; - } - - if (params.GetArray().Size() != 1) { - LOG_ERR("Invalid mining.set_target notification: params array has wrong size"); - return; - } - - auto& new_target = params.GetArray()[0]; - if (!new_target.IsString()) { - LOG_ERR("Invalid mining.set_target notification: target is not a string"); - return; - } - - std::string new_target_str = new_target.GetString(); - new_target_str.resize(16, '0'); - - m_target = std::stoull(new_target_str, nullptr, 16); - LOG_DEBUG("Target set to %016" PRIX64, m_target); - - return; + return setTarget(params); } if (strcmp(method, "mining.notify") == 0) { @@ -265,7 +215,7 @@ void EthStratumClient::parseNotification(const char* method, const rapidjson::Va } else { if (!isQuiet()) { - LOG_WARN("[%s] duplicate job received, reconnect", url()); + LOG_WARN("%s " YELLOW("duplicate job received, reconnect"), tag()); } disconnect(); } @@ -273,7 +223,7 @@ void EthStratumClient::parseNotification(const char* method, const rapidjson::Va } -bool EthStratumClient::disconnect() +bool xmrig::EthStratumClient::disconnect() { m_authorized = false; @@ -281,7 +231,73 @@ bool EthStratumClient::disconnect() } -void EthStratumClient::OnSubscribeResponse(const rapidjson::Value& result, bool success, uint64_t elapsed) +uint64_t xmrig::EthStratumClient::target(const rapidjson::Value ¶ms) const +{ + if (!params.IsArray()) { + throw std::runtime_error("invalid mining.set_target notification: params is not an array"); + } + + if (params.GetArray().Size() != 1) { + throw std::runtime_error("invalid mining.set_target notification: params array has wrong size"); + } + + auto &new_target = params.GetArray()[0]; + if (!new_target.IsString()) { + throw std::runtime_error("invalid mining.set_target notification: target is not a string"); + } + + std::string new_target_str = new_target.GetString(); + new_target_str.resize(16, '0'); + + return std::stoull(new_target_str, nullptr, 16); +} + + +void xmrig::EthStratumClient::authorize() +{ + using namespace rapidjson; + + Document doc(kObjectType); + auto &allocator = doc.GetAllocator(); + + Value params(kArrayType); + params.PushBack(m_pool.user().toJSON(), allocator); + params.PushBack(m_pool.password().toJSON(), allocator); + + JsonRequest::create(doc, m_sequence, "mining.authorize", params); + + send(doc, [this](const rapidjson::Value& result, bool success, uint64_t elapsed) { onAuthorizeResponse(result, success, elapsed); }); +} + + +void xmrig::EthStratumClient::onAuthorizeResponse(const rapidjson::Value& result, bool success, uint64_t elapsed) +{ + if (!success) { + LOG_ERR("mining.authorize call failed"); + disconnect(); + return; + } + + if (!result.IsBool()) { + LOG_ERR("Invalid mining.authorize response: result is not a boolean"); + disconnect(); + return; + } + + if (!result.GetBool()) { + LOG_ERR("Login failed"); + disconnect(); + return; + } + + LOG_DEBUG("Login succeeded"); + + m_authorized = true; + m_listener->onLoginSuccess(this); +} + + +void xmrig::EthStratumClient::onSubscribeResponse(const rapidjson::Value& result, bool success, uint64_t elapsed) { if (!success) { return; @@ -327,49 +343,34 @@ void EthStratumClient::OnSubscribeResponse(const rapidjson::Value& result, bool m_extraNonce = std::stoull(extra_nonce_str, nullptr, 16); LOG_DEBUG("Extra nonce set to %s", s); +} + +void xmrig::EthStratumClient::setTarget(const rapidjson::Value ¶ms) +{ + try { + m_target = target(params); + } catch (const std::exception &ex) { + LOG_ERR("%s " RED("%s"), tag(), ex.what()); + + return; + } + + LOG_DEBUG("[%s] target set to %016" PRIX64, url(), m_target); +} + + +void xmrig::EthStratumClient::subscribe() +{ using namespace rapidjson; Document doc(kObjectType); - auto& allocator = doc.GetAllocator(); + auto &allocator = doc.GetAllocator(); Value params(kArrayType); + params.PushBack(StringRef(agent()), allocator); - const char* user = m_pool.user().data(); - const char* pass = m_pool.password().data(); - - params.PushBack(StringRef(user), allocator); - params.PushBack(StringRef(pass), allocator); - - JsonRequest::create(doc, m_sequence, "mining.authorize", params); - - send(doc, [this](const rapidjson::Value& result, bool success, uint64_t elapsed) { OnAuthorizeResponse(result, success, elapsed); }); -} - -void EthStratumClient::OnAuthorizeResponse(const rapidjson::Value& result, bool success, uint64_t elapsed) -{ - if (!success) { - LOG_ERR("mining.authorize call failed"); - disconnect(); - return; - } - - if (!result.IsBool()) { - LOG_ERR("Invalid mining.authorize response: result is not a boolean"); - disconnect(); - return; - } - - if (!result.GetBool()) { - LOG_ERR("Login failed"); - disconnect(); - return; - } - - LOG_DEBUG("Login succeeded"); - - m_authorized = true; - m_listener->onLoginSuccess(this); -} + JsonRequest::create(doc, m_sequence, "mining.subscribe", params); + send(doc, [this](const rapidjson::Value& result, bool success, uint64_t elapsed) { onSubscribeResponse(result, success, elapsed); }); } diff --git a/src/base/net/stratum/EthStratumClient.h b/src/base/net/stratum/EthStratumClient.h index 289716ce..f4f40f9b 100644 --- a/src/base/net/stratum/EthStratumClient.h +++ b/src/base/net/stratum/EthStratumClient.h @@ -1,11 +1,4 @@ /* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2019 jtgrassie * Copyright 2018-2020 SChernykh * Copyright 2016-2020 XMRig , * @@ -43,25 +36,29 @@ public: EthStratumClient(int id, const char *agent, IClientListener *listener); - void login() override; - void onClose() override; +protected: protected: int64_t submit(const JobResult& result) override; + void login() override; + void onClose() override; bool handleResponse(int64_t id, const rapidjson::Value& result, const rapidjson::Value& error) override; - void parseNotification(const char* method, const rapidjson::Value& params, const rapidjson::Value& error) override; + void parseNotification(const char *method, const rapidjson::Value ¶ms, const rapidjson::Value &error) override; bool disconnect() override; private: - void OnSubscribeResponse(const rapidjson::Value& result, bool success, uint64_t elapsed); - void OnAuthorizeResponse(const rapidjson::Value& result, bool success, uint64_t elapsed); + uint64_t target(const rapidjson::Value ¶ms) const; + void authorize(); + void onAuthorizeResponse(const rapidjson::Value& result, bool success, uint64_t elapsed); + void onSubscribeResponse(const rapidjson::Value& result, bool success, uint64_t elapsed); + void setTarget(const rapidjson::Value ¶ms); + void subscribe(); - bool m_authorized = false; - - uint64_t m_target = 0; - uint64_t m_extraNonce = 0; + bool m_authorized = false; + uint64_t m_target = 0; + uint64_t m_extraNonce = 0; }; diff --git a/src/base/net/stratum/SelfSelectClient.h b/src/base/net/stratum/SelfSelectClient.h index c54cf8df..b02e5212 100644 --- a/src/base/net/stratum/SelfSelectClient.h +++ b/src/base/net/stratum/SelfSelectClient.h @@ -55,6 +55,7 @@ protected: inline bool isEnabled() const override { return m_client->isEnabled(); } inline bool isTLS() const override { return m_client->isTLS(); } inline const char *mode() const override { return m_client->mode(); } + inline const char *tag() const override { return m_client->tag(); } inline const char *tlsFingerprint() const override { return m_client->tlsFingerprint(); } inline const char *tlsVersion() const override { return m_client->tlsVersion(); } inline const Job &job() const override { return m_job; }