This commit is contained in:
MoneroOcean 2020-06-10 18:14:06 -07:00
commit 0ada4ca4ac
150 changed files with 12300 additions and 8764 deletions

View file

@ -0,0 +1,90 @@
/* XMRig
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "base/net/stratum/AutoClient.h"
#include "3rdparty/rapidjson/document.h"
#include "base/io/json/Json.h"
xmrig::AutoClient::AutoClient(int id, const char *agent, IClientListener *listener) :
EthStratumClient(id, agent, listener)
{
}
bool xmrig::AutoClient::handleResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error)
{
if (m_mode == DEFAULT_MODE) {
return Client::handleResponse(id, result, error);
}
return EthStratumClient::handleResponse(id, result, error);
}
bool xmrig::AutoClient::parseLogin(const rapidjson::Value &result, int *code)
{
if (result.HasMember("job")) {
return Client::parseLogin(result, code);
}
setRpcId(Json::getString(result, "id"));
if (rpcId().isNull()) {
*code = 1;
return false;
}
const Algorithm algo(Json::getString(result, "algo"));
if (algo.family() != Algorithm::KAWPOW) {
*code = 6;
return false;
}
try {
setExtraNonce(Json::getValue(result, "extra_nonce"));
} catch (const std::exception &ex) {
*code = 6;
return false;
}
m_mode = ETH_MODE;
setAlgo(algo);
return true;
}
int64_t xmrig::AutoClient::submit(const JobResult &result)
{
if (m_mode == DEFAULT_MODE) {
return Client::submit(result);
}
return EthStratumClient::submit(result);
}
void xmrig::AutoClient::parseNotification(const char *method, const rapidjson::Value &params, const rapidjson::Value &error)
{
if (m_mode == DEFAULT_MODE) {
return Client::parseNotification(method, params, error);
}
return EthStratumClient::parseNotification(method, params, error);
}

View file

@ -0,0 +1,61 @@
/* XMRig
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef XMRIG_AUTOCLIENT_H
#define XMRIG_AUTOCLIENT_H
#include "base/net/stratum/EthStratumClient.h"
#include <utility>
namespace xmrig {
class AutoClient : public EthStratumClient
{
public:
XMRIG_DISABLE_COPY_MOVE_DEFAULT(AutoClient)
AutoClient(int id, const char *agent, IClientListener *listener);
~AutoClient() override = default;
protected:
inline void login() override { Client::login(); }
bool handleResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error) override;
bool parseLogin(const rapidjson::Value &result, int *code) override;
int64_t submit(const JobResult &result) override;
void parseNotification(const char *method, const rapidjson::Value &params, const rapidjson::Value &error) override;
private:
enum Mode {
DEFAULT_MODE,
ETH_MODE
};
Mode m_mode = DEFAULT_MODE;
};
} /* namespace xmrig */
#endif /* XMRIG_AUTOCLIENT_H */

View file

@ -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;
}

View file

@ -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; }
@ -83,7 +84,7 @@ protected:
inline bool isQuiet() const { return m_quiet || m_failures >= m_retries; }
bool handleResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error);
virtual bool handleResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error);
bool handleSubmitResponse(int64_t id, const char *error = nullptr);
bool m_quiet = false;
@ -96,6 +97,7 @@ protected:
SocketState m_state = UnconnectedState;
std::map<int64_t, SendResult> m_callbacks;
std::map<int64_t, SubmitResult> m_results;
std::string m_tag;
String m_ip;
String m_password;
String m_rigId;

View file

@ -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 &params, 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 &params, int *code)
}
if (!isQuiet()) {
LOG_WARN("[%s] duplicate job received, reconnect", url());
LOG_WARN("%s " YELLOW("duplicate job received, reconnect"), tag());
}
close();
@ -449,23 +445,6 @@ bool xmrig::Client::parseJob(const rapidjson::Value &params, int *code)
}
bool xmrig::Client::parseLogin(const rapidjson::Value &result, int *code)
{
m_rpcId = result["id"].GetString();
if (m_rpcId.isNull()) {
*code = 1;
return false;
}
parseExtensions(result);
const bool rc = parseJob(result["job"], code);
m_jobs = 0;
return rc;
}
bool xmrig::Client::send(BIO *bio)
{
# ifdef XMRIG_FEATURE_TLS
@ -500,10 +479,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 +493,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 +508,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 +529,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;
@ -633,6 +612,23 @@ void xmrig::Client::handshake()
}
bool xmrig::Client::parseLogin(const rapidjson::Value &result, int *code)
{
setRpcId(Json::getString(result, "id"));
if (rpcId().isNull()) {
*code = 1;
return false;
}
parseExtensions(result);
const bool rc = parseJob(result["job"], code);
m_jobs = 0;
return rc;
}
void xmrig::Client::login()
{
using namespace rapidjson;
@ -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 &params, const rapidjson::Value &error)
void xmrig::Client::parseNotification(const char *method, const rapidjson::Value &params, 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();
@ -821,7 +819,11 @@ void xmrig::Client::parseResponse(int64_t id, const rapidjson::Value &result, co
m_failures = 0;
m_listener->onLoginSuccess(this);
m_listener->onJobReceived(this, m_job, result["job"]);
if (m_job.isValid()) {
m_listener->onJobReceived(this, m_job, result["job"]);
}
return;
}
@ -840,10 +842,9 @@ void xmrig::Client::ping()
void xmrig::Client::read(ssize_t nread, const uv_buf_t *buf)
{
const auto size = static_cast<size_t>(nread);
if (nread < 0) {
if (!isQuiet()) {
LOG_ERR("[%s] read error: \"%s\"", url(), uv_strerror(static_cast<int>(nread)));
LOG_ERR("%s " RED("read error: ") RED_BOLD("\"%s\""), tag(), uv_strerror(static_cast<int>(nread)));
}
close();
@ -972,7 +973,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 +981,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 +989,6 @@ void xmrig::Client::onConnect(uv_connect_t *req, int status)
}
if (client->state() == ConnectedState) {
LOG_ERR("[%s] already connected", client->url());
return;
}

View file

@ -81,18 +81,28 @@ protected:
void onResolved(const Dns &dns, int status) override;
inline bool hasExtension(Extension extension) const noexcept override { return m_extensions.test(extension); }
inline const char *mode() const override { return "pool"; }
inline void onLine(char *line, size_t size) override { parse(line, size); }
inline bool hasExtension(Extension extension) const noexcept override { return m_extensions.test(extension); }
inline const char *mode() const override { return "pool"; }
inline void onLine(char *line, size_t size) override { parse(line, size); }
inline const char *agent() const { return m_agent; }
inline const char *url() const { return m_pool.url(); }
inline const String &rpcId() const { return m_rpcId; }
inline void setRpcId(const char *id) { m_rpcId = id; }
virtual bool parseLogin(const rapidjson::Value &result, int *code);
virtual void login();
virtual void parseNotification(const char* method, const rapidjson::Value& params, const rapidjson::Value& error);
bool close();
virtual void onClose();
private:
class Socks5;
class Tls;
bool close();
bool isCriticalError(const char *message);
bool parseJob(const rapidjson::Value &params, int *code);
bool parseLogin(const rapidjson::Value &result, int *code);
bool send(BIO *bio);
bool verifyAlgorithm(const Algorithm &algorithm, const char *algo) const;
bool write(const uv_buf_t &buf);
@ -100,11 +110,8 @@ private:
int64_t send(size_t size);
void connect(sockaddr *addr);
void handshake();
void login();
void onClose();
void parse(char *line, size_t len);
void parseExtensions(const rapidjson::Value &result);
void parseNotification(const char *method, const rapidjson::Value &params, const rapidjson::Value &error);
void parseResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error);
void ping();
void read(ssize_t nread, const uv_buf_t *buf);
@ -112,7 +119,6 @@ private:
void setState(SocketState state);
void startTimeout();
inline const char *url() const { return m_pool.url(); }
inline SocketState state() const { return m_state; }
inline uv_stream_t *stream() const { return reinterpret_cast<uv_stream_t *>(m_socket); }
inline void setExtension(Extension ext, bool enable) noexcept { m_extensions.set(ext, enable); }

View file

@ -0,0 +1,369 @@
/* XMRig
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cinttypes>
#include <iomanip>
#include <sstream>
#include <stdexcept>
#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 "net/JobResult.h"
xmrig::EthStratumClient::EthStratumClient(int id, const char *agent, IClientListener *listener) :
Client(id, agent, listener)
{
}
int64_t xmrig::EthStratumClient::submit(const JobResult& result)
{
# ifndef XMRIG_PROXY_PROJECT
if ((m_state != ConnectedState) || !m_authorized) {
return -1;
}
# endif
if (result.diff == 0) {
LOG_ERR("%s " RED("result.diff is 0"), tag());
close();
return -1;
}
using namespace rapidjson;
Document doc(kObjectType);
auto& allocator = doc.GetAllocator();
Value params(kArrayType);
params.PushBack(m_pool.user().toJSON(), allocator);
params.PushBack(result.jobId.toJSON(), allocator);
std::stringstream s;
s << "0x" << std::hex << std::setw(16) << std::setfill('0') << result.nonce;
params.PushBack(Value(s.str().c_str(), allocator), allocator);
s.str(std::string());
s << "0x";
for (size_t i = 0; i < 32; ++i) {
const uint32_t k = result.headerHash()[i];
s << std::hex << std::setw(2) << std::setfill('0') << k;
}
params.PushBack(Value(s.str().c_str(), allocator), allocator);
s.str(std::string());
s << "0x";
for (size_t i = 0; i < 32; ++i) {
const uint32_t k = result.mixHash()[i];
s << std::hex << std::setw(2) << std::setfill('0') << k;
}
params.PushBack(Value(s.str().c_str(), allocator), allocator);
JsonRequest::create(doc, m_sequence, "mining.submit", params);
uint64_t actual_diff = ethash_swap_u64(*((uint64_t*)result.result()));
actual_diff = actual_diff ? (uint64_t(-1) / actual_diff) : 0;
# ifdef XMRIG_PROXY_PROJECT
m_results[m_sequence] = SubmitResult(m_sequence, result.diff, actual_diff, result.id, 0);
# else
m_results[m_sequence] = SubmitResult(m_sequence, result.diff, actual_diff, 0, result.backend);
# endif
return send(doc);
}
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()) {
const uint64_t elapsed = Chrono::steadyMSecs() - it->second.ts;
if (error.IsArray() || error.IsObject() || error.IsString()) {
it->second.callback(error, false, elapsed);
}
else {
it->second.callback(result, true, elapsed);
}
m_callbacks.erase(it);
return true;
}
return handleSubmitResponse(id, errorMessage(error));
}
void xmrig::EthStratumClient::parseNotification(const char *method, const rapidjson::Value &params, const rapidjson::Value &)
{
if (strcmp(method, "mining.set_target") == 0) {
return;
}
if (strcmp(method, "mining.notify") == 0) {
if (!params.IsArray()) {
LOG_ERR("%s " RED("invalid mining.notify notification: params is not an array"), tag());
return;
}
auto arr = params.GetArray();
if (arr.Size() < 6) {
LOG_ERR("%s " RED("invalid mining.notify notification: params array has wrong size"), tag());
return;
}
Job job;
job.setId(arr[0].GetString());
auto algo = m_pool.algorithm();
if (!algo.isValid()) {
algo = m_pool.coin().algorithm();
}
job.setAlgorithm(algo);
job.setExtraNonce(m_extraNonce.second);
std::stringstream s;
// header hash (32 bytes)
s << arr[1].GetString();
// nonce template (8 bytes)
for (uint64_t i = 0, k = m_extraNonce.first; i < sizeof(m_extraNonce.first); ++i, k >>= 8) {
s << std::hex << std::setw(2) << std::setfill('0') << (k & 0xFF);
}
std::string blob = s.str();
// zeros up to 76 bytes
blob.resize(76 * 2, '0');
job.setBlob(blob.c_str());
std::string target_str = arr[3].GetString();
target_str.resize(16, '0');
const uint64_t target = strtoull(target_str.c_str(), nullptr, 16);
job.setDiff(Job::toDiff(target));
job.setHeight(arr[5].GetUint64());
bool ok = true;
m_listener->onVerifyAlgorithm(this, algo, &ok);
if (!ok) {
if (!isQuiet()) {
LOG_ERR("[%s] incompatible/disabled algorithm \"%s\" detected, reconnect", url(), algo.shortName());
}
close();
return;
}
if (m_job != job) {
m_job = std::move(job);
// Workaround for nanopool.org, mining.notify received before mining.authorize response.
if (!m_authorized) {
m_authorized = true;
m_listener->onLoginSuccess(this);
}
m_listener->onJobReceived(this, m_job, params);
}
else {
if (!isQuiet()) {
LOG_WARN("%s " YELLOW("duplicate job received, reconnect"), tag());
}
close();
}
}
}
void xmrig::EthStratumClient::setExtraNonce(const rapidjson::Value &nonce)
{
if (!nonce.IsString()) {
throw std::runtime_error("invalid mining.subscribe response: extra nonce is not a string");
}
const char *s = nonce.GetString();
size_t len = nonce.GetStringLength();
// Skip "0x"
if ((len >= 2) && (s[0] == '0') && (s[1] == 'x')) {
s += 2;
len -= 2;
}
if (len & 1) {
throw std::runtime_error("invalid mining.subscribe response: extra nonce has an odd number of hex chars");
}
if (len > 8) {
throw std::runtime_error("Invalid mining.subscribe response: extra nonce is too long");
}
std::string extra_nonce_str(s);
extra_nonce_str.resize(16, '0');
LOG_DEBUG("[%s] extra nonce set to %s", url(), s);
m_extraNonce = { std::stoull(extra_nonce_str, nullptr, 16), s };
}
const char *xmrig::EthStratumClient::errorMessage(const rapidjson::Value &error) const
{
if (error.IsArray() && error.GetArray().Size() > 1) {
auto &value = error.GetArray()[1];
if (value.IsString()) {
return value.GetString();
}
}
if (error.IsString()) {
return error.GetString();
}
if (error.IsObject()) {
return Json::getString(error, "message");
}
return nullptr;
}
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)
{
try {
if (!success) {
const auto message = errorMessage(result);
if (message) {
throw std::runtime_error(message);
}
throw std::runtime_error("mining.authorize call failed");
}
if (!result.IsBool()) {
throw std::runtime_error("invalid mining.authorize response: result is not a boolean");
}
if (!result.GetBool()) {
throw std::runtime_error("login failed");
}
} catch (const std::exception &ex) {
LOG_ERR("%s " RED_BOLD("%s"), tag(), ex.what());
close();
return;
}
LOG_DEBUG("[%s] login succeeded", url());
if (!m_authorized) {
m_authorized = true;
m_listener->onLoginSuccess(this);
}
}
void xmrig::EthStratumClient::onSubscribeResponse(const rapidjson::Value &result, bool success, uint64_t)
{
if (!success) {
return;
}
try {
if (!result.IsArray()) {
throw std::runtime_error("invalid mining.subscribe response: result is not an array");
}
if (result.GetArray().Size() <= 1) {
throw std::runtime_error("invalid mining.subscribe response: result array is too short");
}
setExtraNonce(result.GetArray()[1]);
} catch (const std::exception &ex) {
LOG_ERR("%s " RED("%s"), tag(), ex.what());
m_extraNonce = { 0, {} };
}
}
void xmrig::EthStratumClient::subscribe()
{
using namespace rapidjson;
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); });
}

View file

@ -0,0 +1,65 @@
/* XMRig
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef XMRIG_ETHSTRATUMCLIENT_H
#define XMRIG_ETHSTRATUMCLIENT_H
#include "base/net/stratum/Client.h"
#include <utility>
namespace xmrig {
class EthStratumClient : public Client
{
public:
XMRIG_DISABLE_COPY_MOVE_DEFAULT(EthStratumClient)
EthStratumClient(int id, const char *agent, IClientListener *listener);
~EthStratumClient() override = default;
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 setExtraNonce(const rapidjson::Value &nonce);
private:
const char *errorMessage(const rapidjson::Value &error) 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 subscribe();
bool m_authorized = false;
std::pair<uint64_t, String> m_extraNonce{};
};
} /* namespace xmrig */
#endif /* XMRIG_ETHSTRATUMCLIENT_H */

View file

@ -71,14 +71,17 @@ public:
inline const String &extraNonce() const { return m_extraNonce; }
inline const String &id() const { return m_id; }
inline const String &poolWallet() const { return m_poolWallet; }
inline const uint32_t *nonce() const { return reinterpret_cast<const uint32_t*>(m_blob + 39); }
inline const uint32_t *nonce() const { return reinterpret_cast<const uint32_t*>(m_blob + nonceOffset()); }
inline const uint8_t *blob() const { return m_blob; }
inline int32_t nonceOffset() const { return (algorithm().family() == Algorithm::KAWPOW) ? 32 : 39; }
inline size_t nonceSize() const { return (algorithm().family() == Algorithm::KAWPOW) ? 8 : 4; }
inline size_t size() const { return m_size; }
inline uint32_t *nonce() { return reinterpret_cast<uint32_t*>(m_blob + 39); }
inline uint32_t *nonce() { return reinterpret_cast<uint32_t*>(m_blob + nonceOffset()); }
inline uint32_t backend() const { return m_backend; }
inline uint64_t diff() const { return m_diff; }
inline uint64_t height() const { return m_height; }
inline uint64_t target() const { return m_target; }
inline uint8_t *blob() { return m_blob; }
inline uint8_t fixedByte() const { return *(m_blob + 42); }
inline uint8_t index() const { return m_index; }
inline void reset() { m_size = 0; m_diff = 0; }
@ -98,7 +101,6 @@ public:
inline const String &rawSeedHash() const { return m_rawSeedHash; }
# endif
static inline uint32_t *nonce(uint8_t *blob) { return reinterpret_cast<uint32_t*>(blob + 39); }
static inline uint64_t toDiff(uint64_t target) { return target ? (0xFFFFFFFFFFFFFFFFULL / target) : 0; }
inline bool operator!=(const Job &other) const { return !isEqual(other); }

View file

@ -118,12 +118,12 @@ void xmrig::NetworkState::onActive(IStrategy *strategy, IClient *client)
}
void xmrig::NetworkState::onJob(IStrategy *strategy, IClient *client, const Job &job)
void xmrig::NetworkState::onJob(IStrategy *strategy, IClient *client, const Job &job, const rapidjson::Value &params)
{
m_algorithm = job.algorithm();
m_diff = job.diff();
StrategyProxy::onJob(strategy, client, job);
StrategyProxy::onJob(strategy, client, job, params);
}

View file

@ -54,7 +54,7 @@ public:
protected:
void onActive(IStrategy *strategy, IClient *client) override;
void onJob(IStrategy *strategy, IClient *client, const Job &job) override;
void onJob(IStrategy *strategy, IClient *client, const Job &job, const rapidjson::Value &params) override;
void onPause(IStrategy *strategy) override;
void onResultAccepted(IStrategy *strategy, IClient *client, const SubmitResult &result, const char *error) override;

View file

@ -38,6 +38,11 @@
#include "base/kernel/Platform.h"
#include "base/net/stratum/Client.h"
#ifdef XMRIG_ALGO_KAWPOW
# include "base/net/stratum/AutoClient.h"
# include "base/net/stratum/EthStratumClient.h"
#endif
#ifdef XMRIG_FEATURE_HTTP
# include "base/net/stratum/DaemonClient.h"
@ -80,6 +85,20 @@ xmrig::Pool::Pool(const char *url) :
}
xmrig::Pool::Pool(const char *host, uint16_t port, const char *user, const char *password, int keepAlive, bool nicehash, bool tls, Mode mode) :
m_keepAlive(keepAlive),
m_mode(mode),
m_flags(1 << FLAG_ENABLED),
m_password(password),
m_user(user),
m_pollInterval(kDefaultPollInterval),
m_url(host, port, tls)
{
m_flags.set(FLAG_NICEHASH, nicehash);
m_flags.set(FLAG_TLS, tls);
}
xmrig::Pool::Pool(const rapidjson::Value &object) :
m_flags(1 << FLAG_ENABLED),
m_pollInterval(kDefaultPollInterval),
@ -120,19 +139,6 @@ xmrig::Pool::Pool(const rapidjson::Value &object) :
}
xmrig::Pool::Pool(const char *host, uint16_t port, const char *user, const char *password, int keepAlive, bool nicehash, bool tls) :
m_keepAlive(keepAlive),
m_flags(1 << FLAG_ENABLED),
m_password(password),
m_user(user),
m_pollInterval(kDefaultPollInterval),
m_url(host, port, tls)
{
m_flags.set(FLAG_NICEHASH, nicehash);
m_flags.set(FLAG_TLS, tls);
}
bool xmrig::Pool::isEnabled() const
{
# ifndef XMRIG_FEATURE_TLS
@ -185,7 +191,15 @@ xmrig::IClient *xmrig::Pool::createClient(int id, IClientListener *listener) con
IClient *client = nullptr;
if (m_mode == MODE_POOL) {
client = new Client(id, Platform::userAgent(), listener);
# ifdef XMRIG_ALGO_KAWPOW
if ((m_algorithm.family() == Algorithm::KAWPOW) || (m_coin == Coin::RAVEN)) {
client = new EthStratumClient(id, Platform::userAgent(), listener);
}
else
# endif
{
client = new Client(id, Platform::userAgent(), listener);
}
}
# ifdef XMRIG_FEATURE_HTTP
else if (m_mode == MODE_DAEMON) {
@ -195,6 +209,11 @@ xmrig::IClient *xmrig::Pool::createClient(int id, IClientListener *listener) con
client = new SelfSelectClient(id, Platform::userAgent(), listener);
}
# endif
# ifdef XMRIG_ALGO_KAWPOW
else if (m_mode == MODE_AUTO_ETH) {
client = new AutoClient(id, Platform::userAgent(), listener);
}
# endif
assert(client != nullptr);

View file

@ -49,7 +49,8 @@ public:
enum Mode {
MODE_POOL,
MODE_DAEMON,
MODE_SELF_SELECT
MODE_SELF_SELECT,
MODE_AUTO_ETH
};
static const String kDefaultPassword;
@ -76,16 +77,9 @@ public:
constexpr static uint64_t kDefaultPollInterval = 1000;
Pool() = default;
Pool(const char *host, uint16_t port, const char *user, const char *password, int keepAlive, bool nicehash, bool tls, Mode mode);
Pool(const char *url);
Pool(const rapidjson::Value &object);
Pool(const char *host,
uint16_t port,
const char *user = nullptr,
const char *password = nullptr,
int keepAlive = 0,
bool nicehash = false,
bool tls = false
);
inline bool isNicehash() const { return m_flags.test(FLAG_NICEHASH); }
inline bool isTLS() const { return m_flags.test(FLAG_TLS) || m_url.isTLS(); }

View file

@ -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; }

View file

@ -24,6 +24,7 @@
#include "base/net/stratum/strategies/FailoverStrategy.h"
#include "3rdparty/rapidjson/document.h"
#include "base/kernel/interfaces/IClient.h"
#include "base/kernel/interfaces/IStrategyListener.h"
#include "base/kernel/Platform.h"
@ -96,7 +97,7 @@ void xmrig::FailoverStrategy::resume()
return;
}
m_listener->onJob(this, active(), active()->job());
m_listener->onJob(this, active(), active()->job(), rapidjson::Value(rapidjson::kNullType));
}
@ -164,10 +165,10 @@ void xmrig::FailoverStrategy::onLogin(IClient *client, rapidjson::Document &doc,
}
void xmrig::FailoverStrategy::onJobReceived(IClient *client, const Job &job, const rapidjson::Value &)
void xmrig::FailoverStrategy::onJobReceived(IClient *client, const Job &job, const rapidjson::Value &params)
{
if (m_active == client->id()) {
m_listener->onJob(this, client, job);
m_listener->onJob(this, client, job, params);
}
}

View file

@ -24,6 +24,7 @@
#include "base/net/stratum/strategies/SinglePoolStrategy.h"
#include "3rdparty/rapidjson/document.h"
#include "base/kernel/interfaces/IClient.h"
#include "base/kernel/interfaces/IStrategyListener.h"
#include "base/kernel/Platform.h"
@ -65,7 +66,7 @@ void xmrig::SinglePoolStrategy::resume()
return;
}
m_listener->onJob(this, m_client, m_client->job());
m_listener->onJob(this, m_client, m_client->job(), rapidjson::Value(rapidjson::kNullType));
}
@ -104,9 +105,9 @@ void xmrig::SinglePoolStrategy::onClose(IClient *, int)
}
void xmrig::SinglePoolStrategy::onJobReceived(IClient *client, const Job &job, const rapidjson::Value &)
void xmrig::SinglePoolStrategy::onJobReceived(IClient *client, const Job &job, const rapidjson::Value &params)
{
m_listener->onJob(this, client, job);
m_listener->onJob(this, client, job, params);
}

View file

@ -43,9 +43,9 @@ protected:
m_listener->onActive(strategy, client);
}
inline void onJob(IStrategy *strategy, IClient *client, const Job &job) override
inline void onJob(IStrategy *strategy, IClient *client, const Job &job, const rapidjson::Value &params) override
{
m_listener->onJob(strategy, client, job);
m_listener->onJob(strategy, client, job, params);
}
inline void onLogin(IStrategy *strategy, IClient *client, rapidjson::Document &doc, rapidjson::Value &params) override