Add global wallet address parser for DaemonClient.

This commit is contained in:
XMRig 2021-08-18 13:36:50 +07:00
parent d1033abbe5
commit 460d9c75c5
No known key found for this signature in database
GPG key ID: 446A53638BE94409
6 changed files with 110 additions and 117 deletions

View file

@ -1,12 +1,6 @@
/* XMRig /* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com> * Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org> * Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* 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 * 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 * it under the terms of the GNU General Public License as published by
@ -27,6 +21,7 @@
#include "3rdparty/rapidjson/fwd.h" #include "3rdparty/rapidjson/fwd.h"
#include "base/tools/Object.h"
#include <functional> #include <functional>
@ -46,6 +41,8 @@ class String;
class IClient class IClient
{ {
public: public:
XMRIG_DISABLE_COPY_MOVE(IClient)
enum Extension { enum Extension {
EXT_ALGO, EXT_ALGO,
EXT_NICEHASH, EXT_NICEHASH,
@ -57,6 +54,7 @@ public:
using Callback = std::function<void(const rapidjson::Value &result, bool success, uint64_t elapsed)>; using Callback = std::function<void(const rapidjson::Value &result, bool success, uint64_t elapsed)>;
IClient() = default;
virtual ~IClient() = default; virtual ~IClient() = default;
virtual bool disconnect() = 0; virtual bool disconnect() = 0;

View file

@ -1,12 +1,6 @@
/* XMRig /* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com> * Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org> * Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* 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 * 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 * it under the terms of the GNU General Public License as published by
@ -22,8 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "base/net/stratum/BaseClient.h" #include "base/net/stratum/BaseClient.h"
#include "3rdparty/fmt/core.h"
#include "3rdparty/rapidjson/document.h" #include "3rdparty/rapidjson/document.h"
#include "base/io/Env.h" #include "base/io/Env.h"
#include "base/io/log/Log.h" #include "base/io/log/Log.h"
@ -58,7 +52,7 @@ void xmrig::BaseClient::setPool(const Pool &pool)
m_user = Env::expand(pool.user()); m_user = Env::expand(pool.user());
m_password = Env::expand(pool.password()); m_password = Env::expand(pool.password());
m_rigId = Env::expand(pool.rigId()); m_rigId = Env::expand(pool.rigId());
m_tag = std::string(Tags::network()) + " " CYAN_BOLD_S + m_pool.url().data() + CLEAR; m_tag = fmt::format("{} " CYAN_BOLD("{}"), Tags::network(), m_pool.url().data());
} }

View file

@ -1,12 +1,6 @@
/* XMRig /* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com> * Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org> * Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* 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 * 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 * it under the terms of the GNU General Public License as published by

View file

@ -24,6 +24,9 @@
*/ */
#include <uv.h>
#include "base/net/stratum/DaemonClient.h" #include "base/net/stratum/DaemonClient.h"
#include "3rdparty/rapidjson/document.h" #include "3rdparty/rapidjson/document.h"
#include "3rdparty/rapidjson/error/en.h" #include "3rdparty/rapidjson/error/en.h"
@ -42,7 +45,6 @@
#include "base/tools/Cvt.h" #include "base/tools/Cvt.h"
#include "base/tools/Timer.h" #include "base/tools/Timer.h"
#include "base/tools/cryptonote/Signatures.h" #include "base/tools/cryptonote/Signatures.h"
#include "base/tools/cryptonote/WalletAddress.h"
#include "net/JobResult.h" #include "net/JobResult.h"
@ -181,12 +183,28 @@ int64_t xmrig::DaemonClient::submit(const JobResult &result)
void xmrig::DaemonClient::connect() void xmrig::DaemonClient::connect()
{ {
if ((m_pool.algorithm() == Algorithm::ASTROBWT_DERO) || (m_pool.coin() == Coin::DERO)) { auto connectError = [this](const char *message) {
m_apiVersion = API_DERO; if (!isQuiet()) {
LOG_ERR("%s " RED("connect error: ") RED_BOLD("\"%s\""), tag(), message);
} }
retry();
};
setState(ConnectingState); setState(ConnectingState);
if (!m_walletAddress.isValid()) {
return connectError("Invalid wallet address.");
}
if (!m_coin.isValid() && !m_pool.algorithm().isValid()) {
return connectError("Invalid algorithm.");
}
if ((m_pool.algorithm() == Algorithm::ASTROBWT_DERO) || (m_coin == Coin::DERO)) {
m_apiVersion = API_DERO;
}
if (m_pool.zmq_port() >= 0) { if (m_pool.zmq_port() >= 0) {
m_dns = Dns::resolve(m_pool.host(), this); m_dns = Dns::resolve(m_pool.host(), this);
} }
@ -203,6 +221,20 @@ void xmrig::DaemonClient::connect(const Pool &pool)
} }
void xmrig::DaemonClient::setPool(const Pool &pool)
{
BaseClient::setPool(pool);
m_walletAddress.decode(m_user);
m_coin = pool.coin().isValid() ? pool.coin() : m_walletAddress.coin();
if (!m_coin.isValid() && pool.algorithm() == Algorithm::RX_WOW) {
m_coin = Coin::WOWNERO;
}
}
void xmrig::DaemonClient::onHttpData(const HttpData &data) void xmrig::DaemonClient::onHttpData(const HttpData &data)
{ {
if (data.status != 200) { if (data.status != 200) {
@ -219,7 +251,7 @@ void xmrig::DaemonClient::onHttpData(const HttpData &data)
rapidjson::Document doc; rapidjson::Document doc;
if (doc.Parse(data.body.c_str()).HasParseError()) { if (doc.Parse(data.body.c_str()).HasParseError()) {
if (!isQuiet()) { if (!isQuiet()) {
LOG_ERR("[%s:%d] JSON decode failed: \"%s\"", m_pool.host().data(), m_pool.port(), rapidjson::GetParseError_En(doc.GetParseError())); LOG_ERR("%s " RED("JSON decode failed: ") RED_BOLD("\"%s\""), tag(), rapidjson::GetParseError_En(doc.GetParseError()));
} }
return retry(); return retry();
@ -284,7 +316,7 @@ void xmrig::DaemonClient::onTimer(const Timer *)
} }
void xmrig::DaemonClient::onResolved(const DnsRecords& records, int status, const char* error) void xmrig::DaemonClient::onResolved(const DnsRecords &records, int status, const char* error)
{ {
m_dns.reset(); m_dns.reset();
@ -297,14 +329,14 @@ void xmrig::DaemonClient::onResolved(const DnsRecords& records, int status, cons
return; return;
} }
if (m_ZMQSocket) {
delete m_ZMQSocket;
}
const auto& record = records.get(); delete m_ZMQSocket;
const auto &record = records.get();
m_ip = record.ip(); m_ip = record.ip();
uv_connect_t* req = new uv_connect_t; auto req = new uv_connect_t;
req->data = m_storage.ptr(m_key); req->data = m_storage.ptr(m_key);
m_ZMQSocket = new uv_tcp_t; m_ZMQSocket = new uv_tcp_t;
@ -329,26 +361,26 @@ bool xmrig::DaemonClient::isOutdated(uint64_t height, const char *hash) const
bool xmrig::DaemonClient::parseJob(const rapidjson::Value &params, int *code) bool xmrig::DaemonClient::parseJob(const rapidjson::Value &params, int *code)
{ {
auto jobError = [this, code](const char *message) {
if (!isQuiet()) {
LOG_ERR("%s " RED("job error: ") RED_BOLD("\"%s\""), tag(), message);
}
*code = 1;
return false;
};
Job job(false, m_pool.algorithm(), String()); Job job(false, m_pool.algorithm(), String());
String blocktemplate = Json::getString(params, kBlocktemplateBlob); String blocktemplate = Json::getString(params, kBlocktemplateBlob);
if (blocktemplate.isNull()) { if (blocktemplate.isNull()) {
LOG_ERR("Empty block template received from daemon"); return jobError("Empty block template received from daemon.");
*code = 1;
return false;
} }
Coin pool_coin = m_pool.coin(); if (!m_blocktemplate.Init(blocktemplate, m_coin)) {
return jobError("Invalid block template received from daemon.");
if (!pool_coin.isValid() && (m_pool.algorithm() == Algorithm::RX_WOW)) {
pool_coin = Coin::WOWNERO;
}
if (!m_blocktemplate.Init(blocktemplate, pool_coin)) {
LOG_ERR("Invalid block template received from daemon");
*code = 2;
return false;
} }
# ifdef XMRIG_PROXY_PROJECT # ifdef XMRIG_PROXY_PROJECT
@ -368,29 +400,21 @@ bool xmrig::DaemonClient::parseJob(const rapidjson::Value &params, int *code)
if (m_blocktemplate.has_miner_signature) { if (m_blocktemplate.has_miner_signature) {
if (m_pool.spendSecretKey().isEmpty()) { if (m_pool.spendSecretKey().isEmpty()) {
LOG_ERR("Secret spend key is not set"); return jobError("Secret spend key is not set.");
*code = 4;
return false;
} }
if (m_pool.spendSecretKey().size() != 64) { if (m_pool.spendSecretKey().size() != 64) {
LOG_ERR("Secret spend key has invalid length. It must be 64 hex characters."); return jobError("Secret spend key has invalid length. It must be 64 hex characters.");
*code = 5;
return false;
} }
uint8_t secret_spendkey[32]; uint8_t secret_spendkey[32];
if (!Cvt::fromHex(secret_spendkey, 32, m_pool.spendSecretKey(), 64)) { if (!Cvt::fromHex(secret_spendkey, 32, m_pool.spendSecretKey(), 64)) {
LOG_ERR("Secret spend key is not a valid hex data."); return jobError("Secret spend key is not a valid hex data.");
*code = 6;
return false;
} }
uint8_t public_spendkey[32]; uint8_t public_spendkey[32];
if (!secret_key_to_public_key(secret_spendkey, public_spendkey)) { if (!secret_key_to_public_key(secret_spendkey, public_spendkey)) {
LOG_ERR("Secret spend key is invalid."); return jobError("Secret spend key is invalid.");
*code = 7;
return false;
} }
# ifdef XMRIG_PROXY_PROJECT # ifdef XMRIG_PROXY_PROJECT
@ -401,35 +425,24 @@ bool xmrig::DaemonClient::parseJob(const rapidjson::Value &params, int *code)
uint8_t public_viewkey[32]; uint8_t public_viewkey[32];
if (!secret_key_to_public_key(secret_viewkey, public_viewkey)) { if (!secret_key_to_public_key(secret_viewkey, public_viewkey)) {
LOG_ERR("Secret view key is invalid."); return jobError("Secret view key is invalid.");
*code = 8;
return false;
} }
uint8_t derivation[32]; uint8_t derivation[32];
if (!generate_key_derivation(m_blocktemplate.raw_blob.data() + m_blocktemplate.tx_pubkey_index, secret_viewkey, derivation)) { if (!generate_key_derivation(m_blocktemplate.raw_blob.data() + m_blocktemplate.tx_pubkey_index, secret_viewkey, derivation)) {
LOG_ERR("Failed to generate key derivation for miner signature."); return jobError("Failed to generate key derivation for miner signature.");
*code = 9;
return false;
} }
WalletAddress user_address; if (!m_walletAddress.decode(m_pool.user())) {
if (!user_address.decode(m_pool.user())) { return jobError("Invalid wallet address.");
LOG_ERR("Invalid wallet address.");
*code = 10;
return false;
} }
if (memcmp(user_address.spendKey(), public_spendkey, sizeof(public_spendkey)) != 0) { if (memcmp(m_walletAddress.spendKey(), public_spendkey, sizeof(public_spendkey)) != 0) {
LOG_ERR("Wallet address and spend key don't match."); return jobError("Wallet address and spend key don't match.");
*code = 11;
return false;
} }
if (memcmp(user_address.viewKey(), public_viewkey, sizeof(public_viewkey)) != 0) { if (memcmp(m_walletAddress.viewKey(), public_viewkey, sizeof(public_viewkey)) != 0) {
LOG_ERR("Wallet address and view key don't match."); return jobError("Wallet address and view key don't match.");
*code = 12;
return false;
} }
uint8_t eph_secret_key[32]; uint8_t eph_secret_key[32];
@ -444,8 +457,8 @@ bool xmrig::DaemonClient::parseJob(const rapidjson::Value &params, int *code)
Cvt::toHex(m_blockhashingblob.data() + offset * 2, kBlobReserveSize * 2, Cvt::randomBytes(kBlobReserveSize).data(), kBlobReserveSize); Cvt::toHex(m_blockhashingblob.data() + offset * 2, kBlobReserveSize * 2, Cvt::randomBytes(kBlobReserveSize).data(), kBlobReserveSize);
} }
if (pool_coin.isValid()) { if (m_coin.isValid()) {
job.setAlgorithm(pool_coin.algorithm(m_blocktemplate.major_version)); job.setAlgorithm(m_coin.algorithm(m_blocktemplate.major_version));
} }
if (!job.setBlob(m_blockhashingblob)) { if (!job.setBlob(m_blockhashingblob)) {
@ -594,7 +607,6 @@ void xmrig::DaemonClient::send(const char *path)
void xmrig::DaemonClient::setState(SocketState state) void xmrig::DaemonClient::setState(SocketState state)
{ {
assert(m_state != state);
if (m_state == state) { if (m_state == state) {
return; return;
} }
@ -735,11 +747,10 @@ void xmrig::DaemonClient::ZMQRead(ssize_t nread, const uv_buf_t* buf)
m_ZMQConnectionState = ZMQ_GREETING_2; m_ZMQConnectionState = ZMQ_GREETING_2;
break; break;
} }
else {
LOG_ERR("%s " RED("ZMQ handshake failed: invalid greeting format"), tag()); LOG_ERR("%s " RED("ZMQ handshake failed: invalid greeting format"), tag());
ZMQClose(); ZMQClose();
} }
}
return; return;
case ZMQ_GREETING_2: case ZMQ_GREETING_2:
@ -751,10 +762,10 @@ void xmrig::DaemonClient::ZMQRead(ssize_t nread, const uv_buf_t* buf)
ZMQWrite(kZMQHandshake, sizeof(kZMQHandshake) - 1); ZMQWrite(kZMQHandshake, sizeof(kZMQHandshake) - 1);
break; break;
} }
else {
LOG_ERR("%s " RED("ZMQ handshake failed: invalid greeting format 2"), tag()); LOG_ERR("%s " RED("ZMQ handshake failed: invalid greeting format 2"), tag());
ZMQClose(); ZMQClose();
}
} }
return; return;

View file

@ -1,13 +1,7 @@
/* XMRig /* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com> * Copyright (c) 2019 Howard Chu <https://github.com/hyc>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org> * Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones> * Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2019 Howard Chu <https://github.com/hyc>
* 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 * 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 * it under the terms of the GNU General Public License as published by
@ -27,21 +21,25 @@
#define XMRIG_DAEMONCLIENT_H #define XMRIG_DAEMONCLIENT_H
#include <uv.h>
#include "base/kernel/interfaces/IDnsListener.h" #include "base/kernel/interfaces/IDnsListener.h"
#include "base/kernel/interfaces/IHttpListener.h" #include "base/kernel/interfaces/IHttpListener.h"
#include "base/kernel/interfaces/ITimerListener.h" #include "base/kernel/interfaces/ITimerListener.h"
#include "base/net/stratum/BaseClient.h" #include "base/net/stratum/BaseClient.h"
#include "base/tools/Object.h"
#include "base/tools/cryptonote/BlockTemplate.h"
#include "base/net/tools/Storage.h" #include "base/net/tools/Storage.h"
#include "base/tools/cryptonote/BlockTemplate.h"
#include "base/tools/cryptonote/WalletAddress.h"
#include <memory> #include <memory>
using uv_buf_t = struct uv_buf_t;
using uv_connect_t = struct uv_connect_s;
using uv_handle_t = struct uv_handle_s;
using uv_stream_t = struct uv_stream_s;
using uv_tcp_t = struct uv_tcp_s;
namespace xmrig { namespace xmrig {
@ -62,10 +60,11 @@ protected:
int64_t submit(const JobResult &result) override; int64_t submit(const JobResult &result) override;
void connect() override; void connect() override;
void connect(const Pool &pool) override; void connect(const Pool &pool) override;
void setPool(const Pool &pool) override;
void onHttpData(const HttpData &data) override; void onHttpData(const HttpData &data) override;
void onTimer(const Timer *timer) override; void onTimer(const Timer *timer) override;
void onResolved(const DnsRecords& records, int status, const char* error) override; void onResolved(const DnsRecords &records, int status, const char* error) override;
inline bool hasExtension(Extension) const noexcept override { return false; } inline bool hasExtension(Extension) const noexcept override { return false; }
inline const char *mode() const override { return "daemon"; } inline const char *mode() const override { return "daemon"; }
@ -92,18 +91,19 @@ private:
API_DERO, API_DERO,
} m_apiVersion = API_MONERO; } m_apiVersion = API_MONERO;
BlockTemplate m_blocktemplate;
Coin m_coin;
std::shared_ptr<IHttpListener> m_httpListener; std::shared_ptr<IHttpListener> m_httpListener;
String m_currentJobId;
String m_blocktemplateStr;
String m_blockhashingblob; String m_blockhashingblob;
String m_blocktemplateRequestHash;
String m_blocktemplateStr;
String m_currentJobId;
String m_prevHash; String m_prevHash;
String m_tlsFingerprint; String m_tlsFingerprint;
String m_tlsVersion; String m_tlsVersion;
Timer *m_timer; Timer *m_timer;
uint64_t m_blocktemplateRequestHeight = 0; uint64_t m_blocktemplateRequestHeight = 0;
String m_blocktemplateRequestHash; WalletAddress m_walletAddress;
BlockTemplate m_blocktemplate;
private: private:
static inline DaemonClient* getClient(void* data) { return m_storage.get(data); } static inline DaemonClient* getClient(void* data) { return m_storage.get(data); }

View file

@ -190,10 +190,6 @@ bool xmrig::Pool::isEnabled() const
} }
# endif # endif
if (m_mode == MODE_DAEMON && (!algorithm().isValid() && !coin().isValid())) {
return false;
}
return m_flags.test(FLAG_ENABLED) && isValid(); return m_flags.test(FLAG_ENABLED) && isValid();
} }