Merge xmrig v6.14.0 into master
This commit is contained in:
commit
74f39ac947
47 changed files with 6885 additions and 170 deletions
|
@ -6,8 +6,8 @@
|
|||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
|
||||
* Copyright 2019 jtgrassie <https://github.com/jtgrassie>
|
||||
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
* Copyright 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright 2016-2021 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
|
||||
|
@ -53,6 +53,7 @@
|
|||
#include "base/net/tools/NetBuffer.h"
|
||||
#include "base/tools/Chrono.h"
|
||||
#include "base/tools/Cvt.h"
|
||||
#include "base/tools/cryptonote/BlobReader.h"
|
||||
#include "net/JobResult.h"
|
||||
|
||||
|
||||
|
@ -83,7 +84,8 @@ static const char *states[] = {
|
|||
xmrig::Client::Client(int id, const char *agent, IClientListener *listener) :
|
||||
BaseClient(id, listener),
|
||||
m_agent(agent),
|
||||
m_sendBuf(1024)
|
||||
m_sendBuf(1024),
|
||||
m_tempBuf(256)
|
||||
{
|
||||
m_reader.setListener(this);
|
||||
m_key = m_storage.add(this);
|
||||
|
@ -200,11 +202,16 @@ int64_t xmrig::Client::submit(const JobResult &result)
|
|||
const char *nonce = result.nonce;
|
||||
const char *data = result.result;
|
||||
# else
|
||||
char *nonce = m_sendBuf.data();
|
||||
char *data = m_sendBuf.data() + 16;
|
||||
char *nonce = m_tempBuf.data();
|
||||
char *data = m_tempBuf.data() + 16;
|
||||
char *signature = m_tempBuf.data() + 88;
|
||||
|
||||
Cvt::toHex(nonce, sizeof(uint32_t) * 2 + 1, reinterpret_cast<const uint8_t *>(&result.nonce), sizeof(uint32_t));
|
||||
Cvt::toHex(data, 65, result.result(), 32);
|
||||
|
||||
if (result.minerSignature()) {
|
||||
Cvt::toHex(signature, 129, result.minerSignature(), 64);
|
||||
}
|
||||
# endif
|
||||
|
||||
Document doc(kObjectType);
|
||||
|
@ -216,6 +223,16 @@ int64_t xmrig::Client::submit(const JobResult &result)
|
|||
params.AddMember("nonce", StringRef(nonce), allocator);
|
||||
params.AddMember("result", StringRef(data), allocator);
|
||||
|
||||
# ifndef XMRIG_PROXY_PROJECT
|
||||
if (result.minerSignature()) {
|
||||
params.AddMember("sig", StringRef(signature), allocator);
|
||||
}
|
||||
# else
|
||||
if (result.sig) {
|
||||
params.AddMember("sig", StringRef(result.sig), allocator);
|
||||
}
|
||||
# endif
|
||||
|
||||
if (has<EXT_ALGO>() && result.algorithm.isValid()) {
|
||||
params.AddMember("algo", StringRef(result.algorithm.shortName()), allocator);
|
||||
}
|
||||
|
@ -429,6 +446,8 @@ bool xmrig::Client::parseJob(const rapidjson::Value ¶ms, int *code)
|
|||
return false;
|
||||
}
|
||||
|
||||
job.setSigKey(Json::getString(params, "sig_key"));
|
||||
|
||||
m_job.setClientId(m_rpcId);
|
||||
|
||||
if (m_job != job) {
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
|
||||
* Copyright 2019 jtgrassie <https://github.com/jtgrassie>
|
||||
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
* Copyright 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright 2016-2021 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
|
||||
|
@ -137,6 +137,7 @@ private:
|
|||
std::bitset<EXT_MAX> m_extensions;
|
||||
std::shared_ptr<DnsRequest> m_dns;
|
||||
std::vector<char> m_sendBuf;
|
||||
std::vector<char> m_tempBuf;
|
||||
String m_rpcId;
|
||||
Tls *m_tls = nullptr;
|
||||
uint64_t m_expire = 0;
|
||||
|
|
|
@ -31,12 +31,18 @@
|
|||
#include "base/io/json/JsonRequest.h"
|
||||
#include "base/io/log/Log.h"
|
||||
#include "base/kernel/interfaces/IClientListener.h"
|
||||
#include "base/net/dns/Dns.h"
|
||||
#include "base/net/dns/DnsRecords.h"
|
||||
#include "base/net/http/Fetch.h"
|
||||
#include "base/net/http/HttpData.h"
|
||||
#include "base/net/http/HttpListener.h"
|
||||
#include "base/net/stratum/SubmitResult.h"
|
||||
#include "base/net/tools/NetBuffer.h"
|
||||
#include "base/tools/bswap_64.h"
|
||||
#include "base/tools/Cvt.h"
|
||||
#include "base/tools/Timer.h"
|
||||
#include "base/tools/cryptonote/Signatures.h"
|
||||
#include "base/tools/cryptonote/WalletAddress.h"
|
||||
#include "net/JobResult.h"
|
||||
|
||||
|
||||
|
@ -46,7 +52,11 @@
|
|||
|
||||
namespace xmrig {
|
||||
|
||||
static const char *kBlocktemplateBlob = "blocktemplate_blob";
|
||||
|
||||
Storage<DaemonClient> DaemonClient::m_storage;
|
||||
|
||||
|
||||
static const char* kBlocktemplateBlob = "blocktemplate_blob";
|
||||
static const char *kGetHeight = "/getheight";
|
||||
static const char *kGetInfo = "/getinfo";
|
||||
static const char *kHash = "hash";
|
||||
|
@ -55,6 +65,12 @@ static const char *kJsonRPC = "/json_rpc";
|
|||
|
||||
static constexpr size_t kBlobReserveSize = 8;
|
||||
|
||||
static const char kZMQGreeting[64] = { -1, 0, 0, 0, 0, 0, 0, 0, 0, 127, 3, 0, 'N', 'U', 'L', 'L' };
|
||||
static constexpr size_t kZMQGreetingSize1 = 11;
|
||||
|
||||
static const char kZMQHandshake[] = "\4\x19\5READY\xbSocket-Type\0\0\0\3SUB";
|
||||
static const char kZMQSubscribe[] = "\0\x18\1json-minimal-chain_main";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -63,12 +79,25 @@ xmrig::DaemonClient::DaemonClient(int id, IClientListener *listener) :
|
|||
{
|
||||
m_httpListener = std::make_shared<HttpListener>(this);
|
||||
m_timer = new Timer(this);
|
||||
m_key = m_storage.add(this);
|
||||
}
|
||||
|
||||
|
||||
xmrig::DaemonClient::~DaemonClient()
|
||||
{
|
||||
delete m_timer;
|
||||
delete m_ZMQSocket;
|
||||
}
|
||||
|
||||
|
||||
void xmrig::DaemonClient::deleteLater()
|
||||
{
|
||||
if (m_pool.zmq_port() >= 0) {
|
||||
ZMQClose(true);
|
||||
}
|
||||
else {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -94,16 +123,36 @@ bool xmrig::DaemonClient::isTLS() const
|
|||
|
||||
int64_t xmrig::DaemonClient::submit(const JobResult &result)
|
||||
{
|
||||
if (result.jobId != (m_blocktemplate.data() + m_blocktemplate.size() - 32)) {
|
||||
if (result.jobId != m_currentJobId) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *data = (m_apiVersion == API_DERO) ? m_blockhashingblob.data() : m_blocktemplate.data();
|
||||
char *data = (m_apiVersion == API_DERO) ? m_blockhashingblob.data() : m_blocktemplateStr.data();
|
||||
|
||||
const size_t sig_offset = m_job.nonceOffset() + m_job.nonceSize();
|
||||
|
||||
# ifdef XMRIG_PROXY_PROJECT
|
||||
memcpy(data + 78, result.nonce, 8);
|
||||
|
||||
memcpy(data + m_job.nonceOffset() * 2, result.nonce, 8);
|
||||
|
||||
if (m_blocktemplate.has_miner_signature && result.sig) {
|
||||
memcpy(data + sig_offset * 2, result.sig, 64 * 2);
|
||||
memcpy(data + m_blocktemplate.tx_pubkey_index * 2, result.sig_data, 32 * 2);
|
||||
memcpy(data + m_blocktemplate.eph_public_key_index * 2, result.sig_data + 32 * 2, 32 * 2);
|
||||
}
|
||||
|
||||
if (result.extra_nonce >= 0) {
|
||||
Cvt::toHex(data + m_blocktemplate.tx_extra_nonce_index * 2, 8, reinterpret_cast<const uint8_t*>(&result.extra_nonce), 4);
|
||||
}
|
||||
|
||||
# else
|
||||
Cvt::toHex(data + 78, 8, reinterpret_cast<const uint8_t *>(&result.nonce), 4);
|
||||
|
||||
Cvt::toHex(data + m_job.nonceOffset() * 2, 8, reinterpret_cast<const uint8_t*>(&result.nonce), 4);
|
||||
|
||||
if (m_blocktemplate.has_miner_signature) {
|
||||
Cvt::toHex(data + sig_offset * 2, 128, result.minerSignature(), 64);
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
using namespace rapidjson;
|
||||
|
@ -111,11 +160,11 @@ int64_t xmrig::DaemonClient::submit(const JobResult &result)
|
|||
|
||||
Value params(kArrayType);
|
||||
if (m_apiVersion == API_DERO) {
|
||||
params.PushBack(m_blocktemplate.toJSON(), doc.GetAllocator());
|
||||
params.PushBack(m_blocktemplateStr.toJSON(), doc.GetAllocator());
|
||||
params.PushBack(m_blockhashingblob.toJSON(), doc.GetAllocator());
|
||||
}
|
||||
else {
|
||||
params.PushBack(m_blocktemplate.toJSON(), doc.GetAllocator());
|
||||
params.PushBack(m_blocktemplateStr.toJSON(), doc.GetAllocator());
|
||||
}
|
||||
|
||||
JsonRequest::create(doc, m_sequence, "submitblock", params);
|
||||
|
@ -137,7 +186,13 @@ void xmrig::DaemonClient::connect()
|
|||
}
|
||||
|
||||
setState(ConnectingState);
|
||||
getBlockTemplate();
|
||||
|
||||
if (m_pool.zmq_port() >= 0) {
|
||||
m_dns = Dns::resolve(m_pool.host(), this);
|
||||
}
|
||||
else {
|
||||
getBlockTemplate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -216,7 +271,7 @@ void xmrig::DaemonClient::onHttpData(const HttpData &data)
|
|||
void xmrig::DaemonClient::onTimer(const Timer *)
|
||||
{
|
||||
if (m_state == ConnectingState) {
|
||||
getBlockTemplate();
|
||||
connect();
|
||||
}
|
||||
else if (m_state == ConnectedState) {
|
||||
if (m_apiVersion == API_DERO) {
|
||||
|
@ -229,6 +284,43 @@ void xmrig::DaemonClient::onTimer(const Timer *)
|
|||
}
|
||||
|
||||
|
||||
void xmrig::DaemonClient::onResolved(const DnsRecords& records, int status, const char* error)
|
||||
{
|
||||
m_dns.reset();
|
||||
|
||||
if (status < 0 && records.isEmpty()) {
|
||||
if (!isQuiet()) {
|
||||
LOG_ERR("%s " RED("DNS error: ") RED_BOLD("\"%s\""), tag(), error);
|
||||
}
|
||||
|
||||
retry();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_ZMQSocket) {
|
||||
delete m_ZMQSocket;
|
||||
}
|
||||
|
||||
const auto& record = records.get();
|
||||
m_ip = record.ip();
|
||||
|
||||
uv_connect_t* req = new uv_connect_t;
|
||||
req->data = m_storage.ptr(m_key);
|
||||
|
||||
m_ZMQSocket = new uv_tcp_t;
|
||||
m_ZMQSocket->data = m_storage.ptr(m_key);
|
||||
|
||||
uv_tcp_init(uv_default_loop(), m_ZMQSocket);
|
||||
uv_tcp_nodelay(m_ZMQSocket, 1);
|
||||
|
||||
# ifndef WIN32
|
||||
uv_tcp_keepalive(m_ZMQSocket, 1, 60);
|
||||
# endif
|
||||
|
||||
uv_tcp_connect(req, m_ZMQSocket, record.addr(m_pool.zmq_port()), onZMQConnect);
|
||||
}
|
||||
|
||||
|
||||
bool xmrig::DaemonClient::isOutdated(uint64_t height, const char *hash) const
|
||||
{
|
||||
return m_job.height() != height || m_prevHash != hash;
|
||||
|
@ -241,31 +333,136 @@ bool xmrig::DaemonClient::parseJob(const rapidjson::Value ¶ms, int *code)
|
|||
|
||||
String blocktemplate = Json::getString(params, kBlocktemplateBlob);
|
||||
|
||||
if (blocktemplate.isNull()) {
|
||||
LOG_ERR("Empty block template received from daemon");
|
||||
*code = 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
Coin pool_coin = m_pool.coin();
|
||||
|
||||
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
|
||||
const size_t k = m_blocktemplate.miner_tx_prefix_begin_index;
|
||||
job.setMinerTx(
|
||||
m_blocktemplate.raw_blob.data() + k,
|
||||
m_blocktemplate.raw_blob.data() + m_blocktemplate.miner_tx_prefix_end_index,
|
||||
m_blocktemplate.eph_public_key_index - k,
|
||||
m_blocktemplate.tx_pubkey_index - k,
|
||||
m_blocktemplate.tx_extra_nonce_index - k,
|
||||
m_blocktemplate.tx_extra_nonce_size,
|
||||
m_blocktemplate.miner_tx_merkle_tree_branch
|
||||
);
|
||||
# endif
|
||||
|
||||
m_blockhashingblob = Json::getString(params, "blockhashing_blob");
|
||||
|
||||
if (m_blocktemplate.has_miner_signature) {
|
||||
if (m_pool.spendSecretKey().isEmpty()) {
|
||||
LOG_ERR("Secret spend key is not set");
|
||||
*code = 4;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_pool.spendSecretKey().size() != 64) {
|
||||
LOG_ERR("Secret spend key has invalid length. It must be 64 hex characters.");
|
||||
*code = 5;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t secret_spendkey[32];
|
||||
if (!Cvt::fromHex(secret_spendkey, 32, m_pool.spendSecretKey(), 64)) {
|
||||
LOG_ERR("Secret spend key is not a valid hex data.");
|
||||
*code = 6;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t public_spendkey[32];
|
||||
if (!secret_key_to_public_key(secret_spendkey, public_spendkey)) {
|
||||
LOG_ERR("Secret spend key is invalid.");
|
||||
*code = 7;
|
||||
return false;
|
||||
}
|
||||
|
||||
# ifdef XMRIG_PROXY_PROJECT
|
||||
job.setSpendSecretKey(secret_spendkey);
|
||||
# else
|
||||
uint8_t secret_viewkey[32];
|
||||
derive_view_secret_key(secret_spendkey, secret_viewkey);
|
||||
|
||||
uint8_t public_viewkey[32];
|
||||
if (!secret_key_to_public_key(secret_viewkey, public_viewkey)) {
|
||||
LOG_ERR("Secret view key is invalid.");
|
||||
*code = 8;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t derivation[32];
|
||||
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.");
|
||||
*code = 9;
|
||||
return false;
|
||||
}
|
||||
|
||||
WalletAddress user_address;
|
||||
if (!user_address.Decode(m_pool.user())) {
|
||||
LOG_ERR("Invalid wallet address.");
|
||||
*code = 10;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memcmp(user_address.public_spend_key, public_spendkey, sizeof(public_spendkey)) != 0) {
|
||||
LOG_ERR("Wallet address and spend key don't match.");
|
||||
*code = 11;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memcmp(user_address.public_view_key, public_viewkey, sizeof(public_viewkey)) != 0) {
|
||||
LOG_ERR("Wallet address and view key don't match.");
|
||||
*code = 12;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t eph_secret_key[32];
|
||||
derive_secret_key(derivation, 0, secret_spendkey, eph_secret_key);
|
||||
|
||||
job.setEphemeralKeys(m_blocktemplate.raw_blob.data() + m_blocktemplate.eph_public_key_index, eph_secret_key);
|
||||
# endif
|
||||
}
|
||||
|
||||
if (m_apiVersion == API_DERO) {
|
||||
const uint64_t offset = Json::getUint64(params, "reserved_offset");
|
||||
Cvt::toHex(m_blockhashingblob.data() + offset * 2, kBlobReserveSize * 2, Cvt::randomBytes(kBlobReserveSize).data(), kBlobReserveSize);
|
||||
}
|
||||
|
||||
if (m_pool.coin().isValid()) {
|
||||
uint8_t blobVersion = 0;
|
||||
Cvt::fromHex(&blobVersion, 1, m_blockhashingblob.data(), 2);
|
||||
job.setAlgorithm(m_pool.coin().algorithm(blobVersion));
|
||||
if (pool_coin.isValid()) {
|
||||
job.setAlgorithm(pool_coin.algorithm(m_blocktemplate.major_version));
|
||||
}
|
||||
|
||||
if (blocktemplate.isNull() || !job.setBlob(m_blockhashingblob)) {
|
||||
*code = 4;
|
||||
if (!job.setBlob(m_blockhashingblob)) {
|
||||
*code = 3;
|
||||
return false;
|
||||
}
|
||||
|
||||
job.setSeedHash(Json::getString(params, "seed_hash"));
|
||||
job.setHeight(Json::getUint64(params, kHeight));
|
||||
job.setDiff(Json::getUint64(params, "difficulty"));
|
||||
job.setId(blocktemplate.data() + blocktemplate.size() - 32);
|
||||
|
||||
m_job = std::move(job);
|
||||
m_blocktemplate = std::move(blocktemplate);
|
||||
m_prevHash = Json::getString(params, "prev_hash");
|
||||
m_currentJobId = Cvt::toHex(Cvt::randomBytes(4));
|
||||
job.setId(m_currentJobId);
|
||||
|
||||
m_job = std::move(job);
|
||||
m_blocktemplateStr = std::move(blocktemplate);
|
||||
m_prevHash = Json::getString(params, "prev_hash");
|
||||
|
||||
if (m_apiVersion == API_DERO) {
|
||||
// Truncate to 32 bytes to have the same data as in get_info RPC
|
||||
|
@ -315,8 +512,19 @@ bool xmrig::DaemonClient::parseResponse(int64_t id, const rapidjson::Value &resu
|
|||
return true;
|
||||
}
|
||||
|
||||
if (handleSubmitResponse(id)) {
|
||||
getBlockTemplate();
|
||||
const char* error_msg = nullptr;
|
||||
|
||||
if ((m_apiVersion == API_DERO) && result.HasMember("status")) {
|
||||
error_msg = result["status"].GetString();
|
||||
if (!error_msg || (strlen(error_msg) == 0) || (strcmp(error_msg, "OK") == 0)) {
|
||||
error_msg = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (handleSubmitResponse(id, error_msg)) {
|
||||
if (error_msg || (m_pool.zmq_port() < 0)) {
|
||||
getBlockTemplate();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -368,6 +576,10 @@ void xmrig::DaemonClient::retry()
|
|||
setState(ConnectingState);
|
||||
}
|
||||
|
||||
if ((m_ZMQConnectionState != ZMQ_NOT_CONNECTED) && (m_ZMQConnectionState != ZMQ_DISCONNECTING)) {
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(m_ZMQSocket), onZMQClose);
|
||||
}
|
||||
|
||||
m_timer->stop();
|
||||
m_timer->start(m_retryPause, 0);
|
||||
}
|
||||
|
@ -395,8 +607,10 @@ void xmrig::DaemonClient::setState(SocketState state)
|
|||
m_failures = 0;
|
||||
m_listener->onLoginSuccess(this);
|
||||
|
||||
const uint64_t interval = std::max<uint64_t>(20, m_pool.pollInterval());
|
||||
m_timer->start(interval, interval);
|
||||
if (m_pool.zmq_port() < 0) {
|
||||
const uint64_t interval = std::max<uint64_t>(20, m_pool.pollInterval());
|
||||
m_timer->start(interval, interval);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -409,3 +623,282 @@ void xmrig::DaemonClient::setState(SocketState state)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void xmrig::DaemonClient::onZMQConnect(uv_connect_t* req, int status)
|
||||
{
|
||||
DaemonClient* client = getClient(req->data);
|
||||
delete req;
|
||||
|
||||
if (!client) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (status < 0) {
|
||||
LOG_ERR("%s " RED("ZMQ connect error: ") RED_BOLD("\"%s\""), client->tag(), uv_strerror(status));
|
||||
client->retry();
|
||||
return;
|
||||
}
|
||||
|
||||
client->ZMQConnected();
|
||||
}
|
||||
|
||||
|
||||
void xmrig::DaemonClient::onZMQRead(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
|
||||
{
|
||||
DaemonClient* client = getClient(stream->data);
|
||||
if (client) {
|
||||
client->ZMQRead(nread, buf);
|
||||
}
|
||||
|
||||
NetBuffer::release(buf);
|
||||
}
|
||||
|
||||
|
||||
void xmrig::DaemonClient::onZMQClose(uv_handle_t* handle)
|
||||
{
|
||||
DaemonClient* client = getClient(handle->data);
|
||||
if (client) {
|
||||
# ifdef APP_DEBUG
|
||||
LOG_DEBUG(CYAN("tcp-zmq://%s:%u") BLACK_BOLD(" disconnected"), client->m_pool.host().data(), client->m_pool.zmq_port());
|
||||
# endif
|
||||
client->m_ZMQConnectionState = ZMQ_NOT_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void xmrig::DaemonClient::onZMQShutdown(uv_handle_t* handle)
|
||||
{
|
||||
DaemonClient* client = getClient(handle->data);
|
||||
if (client) {
|
||||
# ifdef APP_DEBUG
|
||||
LOG_DEBUG(CYAN("tcp-zmq://%s:%u") BLACK_BOLD(" shutdown"), client->m_pool.host().data(), client->m_pool.zmq_port());
|
||||
# endif
|
||||
client->m_ZMQConnectionState = ZMQ_NOT_CONNECTED;
|
||||
m_storage.remove(client->m_key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void xmrig::DaemonClient::ZMQConnected()
|
||||
{
|
||||
# ifdef APP_DEBUG
|
||||
LOG_DEBUG(CYAN("tcp-zmq://%s:%u") BLACK_BOLD(" connected"), m_pool.host().data(), m_pool.zmq_port());
|
||||
# endif
|
||||
|
||||
m_ZMQConnectionState = ZMQ_GREETING_1;
|
||||
m_ZMQSendBuf.reserve(256);
|
||||
m_ZMQRecvBuf.reserve(256);
|
||||
|
||||
if (ZMQWrite(kZMQGreeting, kZMQGreetingSize1)) {
|
||||
uv_read_start(reinterpret_cast<uv_stream_t*>(m_ZMQSocket), NetBuffer::onAlloc, onZMQRead);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool xmrig::DaemonClient::ZMQWrite(const char* data, size_t size)
|
||||
{
|
||||
m_ZMQSendBuf.assign(data, data + size);
|
||||
|
||||
uv_buf_t buf;
|
||||
buf.base = m_ZMQSendBuf.data();
|
||||
buf.len = static_cast<uint32_t>(m_ZMQSendBuf.size());
|
||||
|
||||
const int rc = uv_try_write(reinterpret_cast<uv_stream_t*>(m_ZMQSocket), &buf, 1);
|
||||
|
||||
if (static_cast<size_t>(rc) == buf.len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG_ERR("%s " RED("ZMQ write failed, rc = %d"), tag(), rc);
|
||||
ZMQClose();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void xmrig::DaemonClient::ZMQRead(ssize_t nread, const uv_buf_t* buf)
|
||||
{
|
||||
if (nread <= 0) {
|
||||
LOG_ERR("%s " RED("ZMQ read failed, nread = %" PRId64), tag(), nread);
|
||||
ZMQClose();
|
||||
return;
|
||||
}
|
||||
|
||||
m_ZMQRecvBuf.insert(m_ZMQRecvBuf.end(), buf->base, buf->base + nread);
|
||||
|
||||
do {
|
||||
switch (m_ZMQConnectionState) {
|
||||
case ZMQ_GREETING_1:
|
||||
if (m_ZMQRecvBuf.size() >= kZMQGreetingSize1) {
|
||||
if ((m_ZMQRecvBuf[0] == -1) && (m_ZMQRecvBuf[9] == 127) && (m_ZMQRecvBuf[10] == 3)) {
|
||||
ZMQWrite(kZMQGreeting + kZMQGreetingSize1, sizeof(kZMQGreeting) - kZMQGreetingSize1);
|
||||
m_ZMQConnectionState = ZMQ_GREETING_2;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
LOG_ERR("%s " RED("ZMQ handshake failed: invalid greeting format"), tag());
|
||||
ZMQClose();
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
case ZMQ_GREETING_2:
|
||||
if (m_ZMQRecvBuf.size() >= sizeof(kZMQGreeting)) {
|
||||
if (memcmp(m_ZMQRecvBuf.data() + 12, kZMQGreeting + 12, 20) == 0) {
|
||||
m_ZMQConnectionState = ZMQ_HANDSHAKE;
|
||||
m_ZMQRecvBuf.erase(m_ZMQRecvBuf.begin(), m_ZMQRecvBuf.begin() + sizeof(kZMQGreeting));
|
||||
|
||||
ZMQWrite(kZMQHandshake, sizeof(kZMQHandshake) - 1);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
LOG_ERR("%s " RED("ZMQ handshake failed: invalid greeting format 2"), tag());
|
||||
ZMQClose();
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
case ZMQ_HANDSHAKE:
|
||||
if (m_ZMQRecvBuf.size() >= 2) {
|
||||
if (m_ZMQRecvBuf[0] != 4) {
|
||||
LOG_ERR("%s " RED("ZMQ handshake failed: invalid handshake format"), tag());
|
||||
ZMQClose();
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t size = static_cast<unsigned char>(m_ZMQRecvBuf[1]);
|
||||
if (size < 18) {
|
||||
LOG_ERR("%s " RED("ZMQ handshake failed: invalid handshake size"), tag());
|
||||
ZMQClose();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_ZMQRecvBuf.size() < size + 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (memcmp(m_ZMQRecvBuf.data() + 2, kZMQHandshake + 2, 18) != 0) {
|
||||
LOG_ERR("%s " RED("ZMQ handshake failed: invalid handshake data"), tag());
|
||||
ZMQClose();
|
||||
return;
|
||||
}
|
||||
|
||||
ZMQWrite(kZMQSubscribe, sizeof(kZMQSubscribe) - 1);
|
||||
|
||||
m_ZMQConnectionState = ZMQ_CONNECTED;
|
||||
m_ZMQRecvBuf.erase(m_ZMQRecvBuf.begin(), m_ZMQRecvBuf.begin() + size + 2);
|
||||
|
||||
getBlockTemplate();
|
||||
break;
|
||||
}
|
||||
return;
|
||||
|
||||
case ZMQ_CONNECTED:
|
||||
ZMQParse();
|
||||
return;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
|
||||
void xmrig::DaemonClient::ZMQParse()
|
||||
{
|
||||
# ifdef APP_DEBUG
|
||||
std::vector<char> msg;
|
||||
# endif
|
||||
|
||||
size_t msg_size = 0;
|
||||
|
||||
char* data = m_ZMQRecvBuf.data();
|
||||
size_t avail = m_ZMQRecvBuf.size();
|
||||
bool more;
|
||||
|
||||
do {
|
||||
if (avail < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
more = (data[0] & 1) != 0;
|
||||
const bool long_size = (data[0] & 2) != 0;
|
||||
const bool command = (data[0] & 4) != 0;
|
||||
|
||||
++data;
|
||||
--avail;
|
||||
|
||||
uint64_t size = 0;
|
||||
if (long_size)
|
||||
{
|
||||
if (avail < sizeof(uint64_t)) {
|
||||
return;
|
||||
}
|
||||
size = bswap_64(*((uint64_t*)data));
|
||||
data += sizeof(uint64_t);
|
||||
avail -= sizeof(uint64_t);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (avail < sizeof(uint8_t)) {
|
||||
return;
|
||||
}
|
||||
size = static_cast<uint8_t>(*data);
|
||||
++data;
|
||||
--avail;
|
||||
}
|
||||
|
||||
if (size > 1024U - msg_size)
|
||||
{
|
||||
LOG_ERR("%s " RED("ZMQ message is too large, size = %" PRIu64 " bytes"), tag(), size);
|
||||
ZMQClose();
|
||||
return;
|
||||
}
|
||||
|
||||
if (avail < size) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!command) {
|
||||
# ifdef APP_DEBUG
|
||||
msg.insert(msg.end(), data, data + size);
|
||||
# endif
|
||||
|
||||
msg_size += size;
|
||||
}
|
||||
|
||||
data += size;
|
||||
avail -= size;
|
||||
} while (more);
|
||||
|
||||
m_ZMQRecvBuf.erase(m_ZMQRecvBuf.begin(), m_ZMQRecvBuf.begin() + (data - m_ZMQRecvBuf.data()));
|
||||
|
||||
# ifdef APP_DEBUG
|
||||
LOG_DEBUG(CYAN("tcp-zmq://%s:%u") BLACK_BOLD(" read ") CYAN_BOLD("%zu") BLACK_BOLD(" bytes") " %s", m_pool.host().data(), m_pool.zmq_port(), msg.size(), msg.data());
|
||||
# endif
|
||||
|
||||
getBlockTemplate();
|
||||
}
|
||||
|
||||
|
||||
bool xmrig::DaemonClient::ZMQClose(bool shutdown)
|
||||
{
|
||||
if ((m_ZMQConnectionState == ZMQ_NOT_CONNECTED) || (m_ZMQConnectionState == ZMQ_DISCONNECTING)) {
|
||||
if (shutdown) {
|
||||
m_storage.remove(m_key);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
m_ZMQConnectionState = ZMQ_DISCONNECTING;
|
||||
|
||||
if (uv_is_closing(reinterpret_cast<uv_handle_t*>(m_ZMQSocket)) == 0) {
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(m_ZMQSocket), shutdown ? onZMQShutdown : onZMQClose);
|
||||
if (!shutdown) {
|
||||
retry();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -27,10 +27,16 @@
|
|||
#define XMRIG_DAEMONCLIENT_H
|
||||
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
|
||||
#include "base/kernel/interfaces/IDnsListener.h"
|
||||
#include "base/kernel/interfaces/IHttpListener.h"
|
||||
#include "base/kernel/interfaces/ITimerListener.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 <memory>
|
||||
|
@ -39,7 +45,10 @@
|
|||
namespace xmrig {
|
||||
|
||||
|
||||
class DaemonClient : public BaseClient, public ITimerListener, public IHttpListener
|
||||
class DnsRequest;
|
||||
|
||||
|
||||
class DaemonClient : public BaseClient, public IDnsListener, public ITimerListener, public IHttpListener
|
||||
{
|
||||
public:
|
||||
XMRIG_DISABLE_COPY_MOVE_DEFAULT(DaemonClient)
|
||||
|
@ -56,6 +65,7 @@ protected:
|
|||
|
||||
void onHttpData(const HttpData &data) override;
|
||||
void onTimer(const Timer *timer) override;
|
||||
void onResolved(const DnsRecords& records, int status, const char* error) override;
|
||||
|
||||
inline bool hasExtension(Extension) const noexcept override { return false; }
|
||||
inline const char *mode() const override { return "daemon"; }
|
||||
|
@ -63,7 +73,7 @@ protected:
|
|||
inline const char *tlsVersion() const override { return m_tlsVersion; }
|
||||
inline int64_t send(const rapidjson::Value &, Callback) override { return -1; }
|
||||
inline int64_t send(const rapidjson::Value &) override { return -1; }
|
||||
inline void deleteLater() override { delete this; }
|
||||
void deleteLater() override;
|
||||
inline void tick(uint64_t) override {}
|
||||
|
||||
private:
|
||||
|
@ -83,7 +93,8 @@ private:
|
|||
} m_apiVersion = API_MONERO;
|
||||
|
||||
std::shared_ptr<IHttpListener> m_httpListener;
|
||||
String m_blocktemplate;
|
||||
String m_currentJobId;
|
||||
String m_blocktemplateStr;
|
||||
String m_blockhashingblob;
|
||||
String m_prevHash;
|
||||
String m_tlsFingerprint;
|
||||
|
@ -91,6 +102,40 @@ private:
|
|||
Timer *m_timer;
|
||||
uint64_t m_blocktemplateRequestHeight = 0;
|
||||
String m_blocktemplateRequestHash;
|
||||
|
||||
BlockTemplate m_blocktemplate;
|
||||
|
||||
private:
|
||||
static inline DaemonClient* getClient(void* data) { return m_storage.get(data); }
|
||||
|
||||
uintptr_t m_key = 0;
|
||||
static Storage<DaemonClient> m_storage;
|
||||
|
||||
static void onZMQConnect(uv_connect_t* req, int status);
|
||||
static void onZMQRead(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
|
||||
static void onZMQClose(uv_handle_t* handle);
|
||||
static void onZMQShutdown(uv_handle_t* handle);
|
||||
|
||||
void ZMQConnected();
|
||||
bool ZMQWrite(const char* data, size_t size);
|
||||
void ZMQRead(ssize_t nread, const uv_buf_t* buf);
|
||||
void ZMQParse();
|
||||
bool ZMQClose(bool shutdown = false);
|
||||
|
||||
std::shared_ptr<DnsRequest> m_dns;
|
||||
uv_tcp_t* m_ZMQSocket = nullptr;
|
||||
|
||||
enum {
|
||||
ZMQ_NOT_CONNECTED,
|
||||
ZMQ_GREETING_1,
|
||||
ZMQ_GREETING_2,
|
||||
ZMQ_HANDSHAKE,
|
||||
ZMQ_CONNECTED,
|
||||
ZMQ_DISCONNECTING,
|
||||
} m_ZMQConnectionState = ZMQ_NOT_CONNECTED;
|
||||
|
||||
std::vector<char> m_ZMQSendBuf;
|
||||
std::vector<char> m_ZMQRecvBuf;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
|
||||
* Copyright 2018 Lee Clagett <https://github.com/vtnerd>
|
||||
* 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>
|
||||
* Copyright 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright 2016-2021 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
|
||||
|
@ -32,6 +32,9 @@
|
|||
#include "base/net/stratum/Job.h"
|
||||
#include "base/tools/Buffer.h"
|
||||
#include "base/tools/Cvt.h"
|
||||
#include "base/tools/cryptonote/BlockTemplate.h"
|
||||
#include "base/tools/cryptonote/Signatures.h"
|
||||
#include "base/crypto/keccak.h"
|
||||
|
||||
|
||||
xmrig::Job::Job(bool nicehash, const Algorithm &algorithm, const String &clientId) :
|
||||
|
@ -141,6 +144,50 @@ void xmrig::Job::setDiff(uint64_t diff)
|
|||
}
|
||||
|
||||
|
||||
void xmrig::Job::setSigKey(const char *sig_key)
|
||||
{
|
||||
constexpr const size_t size = 64;
|
||||
|
||||
if (!sig_key || strlen(sig_key) != size * 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
# ifndef XMRIG_PROXY_PROJECT
|
||||
const auto buf = Cvt::fromHex(sig_key, size * 2);
|
||||
if (buf.size() == size) {
|
||||
setEphemeralKeys(buf.data(), buf.data() + 32);
|
||||
}
|
||||
# else
|
||||
m_rawSigKey = sig_key;
|
||||
# endif
|
||||
}
|
||||
|
||||
|
||||
uint32_t xmrig::Job::getNumTransactions() const
|
||||
{
|
||||
if (m_algorithm.family() > Algorithm::RANDOM_X) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t num_transactions = 0;
|
||||
|
||||
// Monero (and some other coins) has the number of transactions encoded as varint in the end of hashing blob
|
||||
const size_t expected_tx_offset = (m_algorithm == Algorithm::RX_WOW) ? 141 : 75;
|
||||
|
||||
if ((m_size > expected_tx_offset) && (m_size <= expected_tx_offset + 4)) {
|
||||
for (size_t i = expected_tx_offset, k = 0; i < m_size; ++i, k += 7) {
|
||||
const uint8_t b = m_blob[i];
|
||||
num_transactions |= static_cast<uint32_t>(b & 0x7F) << k;
|
||||
if ((b & 0x80) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return num_transactions;
|
||||
}
|
||||
|
||||
|
||||
void xmrig::Job::copy(const Job &other)
|
||||
{
|
||||
m_algorithm = other.m_algorithm;
|
||||
|
@ -161,6 +208,7 @@ void xmrig::Job::copy(const Job &other)
|
|||
|
||||
# ifdef XMRIG_PROXY_PROJECT
|
||||
m_rawSeedHash = other.m_rawSeedHash;
|
||||
m_rawSigKey = other.m_rawSigKey;
|
||||
|
||||
memcpy(m_rawBlob, other.m_rawBlob, sizeof(m_rawBlob));
|
||||
memcpy(m_rawTarget, other.m_rawTarget, sizeof(m_rawTarget));
|
||||
|
@ -169,6 +217,24 @@ void xmrig::Job::copy(const Job &other)
|
|||
# ifdef XMRIG_FEATURE_BENCHMARK
|
||||
m_benchSize = other.m_benchSize;
|
||||
# endif
|
||||
|
||||
# ifdef XMRIG_PROXY_PROJECT
|
||||
memcpy(m_spendSecretKey, other.m_spendSecretKey, sizeof(m_spendSecretKey));
|
||||
memcpy(m_viewSecretKey, other.m_viewSecretKey, sizeof(m_viewSecretKey));
|
||||
memcpy(m_spendPublicKey, other.m_spendPublicKey, sizeof(m_spendPublicKey));
|
||||
memcpy(m_viewPublicKey, other.m_viewPublicKey, sizeof(m_viewPublicKey));
|
||||
m_minerTxPrefix = other.m_minerTxPrefix;
|
||||
m_minerTxEphPubKeyOffset = other.m_minerTxEphPubKeyOffset;
|
||||
m_minerTxPubKeyOffset = other.m_minerTxPubKeyOffset;
|
||||
m_minerTxExtraNonceOffset = other.m_minerTxExtraNonceOffset;
|
||||
m_minerTxExtraNonceSize = other.m_minerTxExtraNonceSize;
|
||||
m_minerTxMerkleTreeBranch = other.m_minerTxMerkleTreeBranch;
|
||||
# else
|
||||
memcpy(m_ephPublicKey, other.m_ephPublicKey, sizeof(m_ephPublicKey));
|
||||
memcpy(m_ephSecretKey, other.m_ephSecretKey, sizeof(m_ephSecretKey));
|
||||
# endif
|
||||
|
||||
m_hasMinerSignature = other.m_hasMinerSignature;
|
||||
}
|
||||
|
||||
|
||||
|
@ -196,6 +262,7 @@ void xmrig::Job::move(Job &&other)
|
|||
|
||||
# ifdef XMRIG_PROXY_PROJECT
|
||||
m_rawSeedHash = std::move(other.m_rawSeedHash);
|
||||
m_rawSigKey = std::move(other.m_rawSigKey);
|
||||
|
||||
memcpy(m_rawBlob, other.m_rawBlob, sizeof(m_rawBlob));
|
||||
memcpy(m_rawTarget, other.m_rawTarget, sizeof(m_rawTarget));
|
||||
|
@ -204,4 +271,115 @@ void xmrig::Job::move(Job &&other)
|
|||
# ifdef XMRIG_FEATURE_BENCHMARK
|
||||
m_benchSize = other.m_benchSize;
|
||||
# endif
|
||||
|
||||
# ifdef XMRIG_PROXY_PROJECT
|
||||
memcpy(m_spendSecretKey, other.m_spendSecretKey, sizeof(m_spendSecretKey));
|
||||
memcpy(m_viewSecretKey, other.m_viewSecretKey, sizeof(m_viewSecretKey));
|
||||
memcpy(m_spendPublicKey, other.m_spendPublicKey, sizeof(m_spendPublicKey));
|
||||
memcpy(m_viewPublicKey, other.m_viewPublicKey, sizeof(m_viewPublicKey));
|
||||
|
||||
m_minerTxPrefix = std::move(other.m_minerTxPrefix);
|
||||
m_minerTxEphPubKeyOffset = other.m_minerTxEphPubKeyOffset;
|
||||
m_minerTxPubKeyOffset = other.m_minerTxPubKeyOffset;
|
||||
m_minerTxExtraNonceOffset = other.m_minerTxExtraNonceOffset;
|
||||
m_minerTxExtraNonceSize = other.m_minerTxExtraNonceSize;
|
||||
m_minerTxMerkleTreeBranch = std::move(other.m_minerTxMerkleTreeBranch);
|
||||
# else
|
||||
memcpy(m_ephPublicKey, other.m_ephPublicKey, sizeof(m_ephPublicKey));
|
||||
memcpy(m_ephSecretKey, other.m_ephSecretKey, sizeof(m_ephSecretKey));
|
||||
# endif
|
||||
|
||||
m_hasMinerSignature = other.m_hasMinerSignature;
|
||||
}
|
||||
|
||||
|
||||
#ifdef XMRIG_PROXY_PROJECT
|
||||
|
||||
|
||||
void xmrig::Job::setSpendSecretKey(const uint8_t *key)
|
||||
{
|
||||
m_hasMinerSignature = true;
|
||||
memcpy(m_spendSecretKey, key, sizeof(m_spendSecretKey));
|
||||
|
||||
derive_view_secret_key(m_spendSecretKey, m_viewSecretKey);
|
||||
secret_key_to_public_key(m_spendSecretKey, m_spendPublicKey);
|
||||
secret_key_to_public_key(m_viewSecretKey, m_viewPublicKey);
|
||||
}
|
||||
|
||||
|
||||
void xmrig::Job::setMinerTx(const uint8_t *begin, const uint8_t *end, size_t minerTxEphPubKeyOffset, size_t minerTxPubKeyOffset, size_t minerTxExtraNonceOffset, size_t minerTxExtraNonceSize, const Buffer &minerTxMerkleTreeBranch)
|
||||
{
|
||||
m_minerTxPrefix.assign(begin, end);
|
||||
m_minerTxEphPubKeyOffset = minerTxEphPubKeyOffset;
|
||||
m_minerTxPubKeyOffset = minerTxPubKeyOffset;
|
||||
m_minerTxExtraNonceOffset = minerTxExtraNonceOffset;
|
||||
m_minerTxExtraNonceSize = minerTxExtraNonceSize;
|
||||
m_minerTxMerkleTreeBranch = minerTxMerkleTreeBranch;
|
||||
}
|
||||
|
||||
|
||||
void xmrig::Job::setExtraNonceInMinerTx(uint32_t extra_nonce)
|
||||
{
|
||||
memcpy(m_minerTxPrefix.data() + m_minerTxExtraNonceOffset, &extra_nonce, std::min(m_minerTxExtraNonceSize, sizeof(uint32_t)));
|
||||
}
|
||||
|
||||
|
||||
void xmrig::Job::generateSignatureData(String &signatureData) const
|
||||
{
|
||||
uint8_t* eph_public_key = m_minerTxPrefix.data() + m_minerTxEphPubKeyOffset;
|
||||
uint8_t* txkey_pub = m_minerTxPrefix.data() + m_minerTxPubKeyOffset;
|
||||
|
||||
uint8_t txkey_sec[32];
|
||||
|
||||
generate_keys(txkey_pub, txkey_sec);
|
||||
|
||||
uint8_t derivation[32];
|
||||
|
||||
generate_key_derivation(m_viewPublicKey, txkey_sec, derivation);
|
||||
derive_public_key(derivation, 0, m_spendPublicKey, eph_public_key);
|
||||
|
||||
uint8_t buf[32 * 3] = {};
|
||||
memcpy(buf, txkey_pub, 32);
|
||||
memcpy(buf + 32, eph_public_key, 32);
|
||||
|
||||
generate_key_derivation(txkey_pub, m_viewSecretKey, derivation);
|
||||
derive_secret_key(derivation, 0, m_spendSecretKey, buf + 64);
|
||||
|
||||
signatureData = Cvt::toHex(buf, sizeof(buf));
|
||||
}
|
||||
|
||||
void xmrig::Job::generateHashingBlob(String &blob) const
|
||||
{
|
||||
uint8_t root_hash[32];
|
||||
const uint8_t* p = m_minerTxPrefix.data();
|
||||
BlockTemplate::CalculateRootHash(p, p + m_minerTxPrefix.size(), m_minerTxMerkleTreeBranch, root_hash);
|
||||
|
||||
uint64_t root_hash_offset = nonceOffset() + nonceSize();
|
||||
|
||||
if (m_hasMinerSignature) {
|
||||
root_hash_offset += BlockTemplate::SIGNATURE_SIZE + 2 /* vote */;
|
||||
}
|
||||
|
||||
blob = rawBlob();
|
||||
Cvt::toHex(blob.data() + root_hash_offset * 2, 64, root_hash, BlockTemplate::HASH_SIZE);
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
void xmrig::Job::generateMinerSignature(const uint8_t* blob, size_t size, uint8_t* out_sig) const
|
||||
{
|
||||
uint8_t tmp[kMaxBlobSize];
|
||||
memcpy(tmp, blob, size);
|
||||
|
||||
// Fill signature with zeros
|
||||
memset(tmp + nonceOffset() + nonceSize(), 0, BlockTemplate::SIGNATURE_SIZE);
|
||||
|
||||
uint8_t prefix_hash[32];
|
||||
xmrig::keccak(tmp, static_cast<int>(size), prefix_hash, sizeof(prefix_hash));
|
||||
xmrig::generate_signature(prefix_hash, m_ephPublicKey, m_ephSecretKey, out_sig);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
|
||||
* Copyright 2018 Lee Clagett <https://github.com/vtnerd>
|
||||
* 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>
|
||||
* Copyright 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright 2016-2021 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
|
||||
|
@ -63,6 +63,7 @@ public:
|
|||
bool setSeedHash(const char *hash);
|
||||
bool setTarget(const char *target);
|
||||
void setDiff(uint64_t diff);
|
||||
void setSigKey(const char *sig_key);
|
||||
|
||||
inline bool isNicehash() const { return m_nicehash; }
|
||||
inline bool isValid() const { return (m_size > 0 && m_diff > 0) || !m_poolWallet.isEmpty(); }
|
||||
|
@ -82,7 +83,7 @@ public:
|
|||
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 nonceMask() const { return isNicehash() ? 0xFFFFFFULL : (nonceSize() == sizeof(uint64_t) ? (-1ULL >> (extraNonce().size() * 4)): 0xFFFFFFFFULL); }
|
||||
inline uint64_t nonceMask() const { return isNicehash() ? 0xFFFFFFULL : (nonceSize() == sizeof(uint64_t) ? (static_cast<uint64_t>(-1LL) >> (extraNonce().size() * 4)) : 0xFFFFFFFFULL); }
|
||||
inline uint64_t target() const { return m_target; }
|
||||
inline uint8_t *blob() { return m_blob; }
|
||||
inline uint8_t fixedByte() const { return *(m_blob + 42); }
|
||||
|
@ -102,6 +103,7 @@ public:
|
|||
inline const char *rawBlob() const { return m_rawBlob; }
|
||||
inline const char *rawTarget() const { return m_rawTarget; }
|
||||
inline const String &rawSeedHash() const { return m_rawSeedHash; }
|
||||
inline const String &rawSigKey() const { return m_rawSigKey; }
|
||||
# endif
|
||||
|
||||
static inline uint64_t toDiff(uint64_t target) { return target ? (0xFFFFFFFFFFFFFFFFULL / target) : 0; }
|
||||
|
@ -116,6 +118,29 @@ public:
|
|||
inline void setBenchSize(uint32_t size) { m_benchSize = size; }
|
||||
# endif
|
||||
|
||||
# ifdef XMRIG_PROXY_PROJECT
|
||||
void setSpendSecretKey(const uint8_t* key);
|
||||
void setMinerTx(const uint8_t* begin, const uint8_t* end, size_t minerTxEphPubKeyOffset, size_t minerTxPubKeyOffset, size_t minerTxExtraNonceOffset, size_t minerTxExtraNonceSize, const Buffer& minerTxMerkleTreeBranch);
|
||||
void setExtraNonceInMinerTx(uint32_t extra_nonce);
|
||||
void generateSignatureData(String& signatureData) const;
|
||||
void generateHashingBlob(String& blob) const;
|
||||
# else
|
||||
inline const uint8_t* ephSecretKey() const { return m_hasMinerSignature ? m_ephSecretKey : nullptr; }
|
||||
|
||||
inline void setEphemeralKeys(const uint8_t *pub_key, const uint8_t *sec_key)
|
||||
{
|
||||
m_hasMinerSignature = true;
|
||||
memcpy(m_ephPublicKey, pub_key, sizeof(m_ephSecretKey));
|
||||
memcpy(m_ephSecretKey, sec_key, sizeof(m_ephSecretKey));
|
||||
}
|
||||
|
||||
void generateMinerSignature(const uint8_t* blob, size_t size, uint8_t* out_sig) const;
|
||||
# endif
|
||||
|
||||
inline bool hasMinerSignature() const { return m_hasMinerSignature; }
|
||||
|
||||
uint32_t getNumTransactions() const;
|
||||
|
||||
private:
|
||||
void copy(const Job &other);
|
||||
void move(Job &&other);
|
||||
|
@ -139,8 +164,27 @@ private:
|
|||
char m_rawBlob[kMaxBlobSize * 2 + 8]{};
|
||||
char m_rawTarget[24]{};
|
||||
String m_rawSeedHash;
|
||||
String m_rawSigKey;
|
||||
|
||||
// Miner signatures
|
||||
uint8_t m_spendSecretKey[32]{};
|
||||
uint8_t m_viewSecretKey[32]{};
|
||||
uint8_t m_spendPublicKey[32]{};
|
||||
uint8_t m_viewPublicKey[32]{};
|
||||
mutable Buffer m_minerTxPrefix;
|
||||
size_t m_minerTxEphPubKeyOffset = 0;
|
||||
size_t m_minerTxPubKeyOffset = 0;
|
||||
size_t m_minerTxExtraNonceOffset = 0;
|
||||
size_t m_minerTxExtraNonceSize = 0;
|
||||
Buffer m_minerTxMerkleTreeBranch;
|
||||
# else
|
||||
// Miner signatures
|
||||
uint8_t m_ephPublicKey[32]{};
|
||||
uint8_t m_ephSecretKey[32]{};
|
||||
# endif
|
||||
|
||||
bool m_hasMinerSignature = false;
|
||||
|
||||
# ifdef XMRIG_FEATURE_BENCHMARK
|
||||
uint32_t m_benchSize = 0;
|
||||
# endif
|
||||
|
|
|
@ -66,6 +66,7 @@ const char *Pool::kAlgo = "algo";
|
|||
const char *Pool::kCoin = "coin";
|
||||
const char *Pool::kDaemon = "daemon";
|
||||
const char *Pool::kDaemonPollInterval = "daemon-poll-interval";
|
||||
const char *Pool::kDaemonZMQPort = "daemon-zmq-port";
|
||||
const char *Pool::kEnabled = "enabled";
|
||||
const char *Pool::kFingerprint = "tls-fingerprint";
|
||||
const char *Pool::kKeepalive = "keepalive";
|
||||
|
@ -78,6 +79,7 @@ const char *Pool::kSubmitToOrigin = "submit-to-origin";
|
|||
const char *Pool::kTls = "tls";
|
||||
const char *Pool::kUrl = "url";
|
||||
const char *Pool::kUser = "user";
|
||||
const char *Pool::kSpendSecretKey = "spend-secret-key";
|
||||
const char *Pool::kNicehashHost = "nicehash.com";
|
||||
|
||||
|
||||
|
@ -92,12 +94,13 @@ 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) :
|
||||
xmrig::Pool::Pool(const char *host, uint16_t port, const char *user, const char *password, const char* spendSecretKey, 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_spendSecretKey(spendSecretKey),
|
||||
m_pollInterval(kDefaultPollInterval),
|
||||
m_url(host, port, tls)
|
||||
{
|
||||
|
@ -115,15 +118,17 @@ xmrig::Pool::Pool(const rapidjson::Value &object) :
|
|||
return;
|
||||
}
|
||||
|
||||
m_user = Json::getString(object, kUser);
|
||||
m_password = Json::getString(object, kPass);
|
||||
m_rigId = Json::getString(object, kRigId);
|
||||
m_fingerprint = Json::getString(object, kFingerprint);
|
||||
m_pollInterval = Json::getUint64(object, kDaemonPollInterval, kDefaultPollInterval);
|
||||
m_algorithm = Json::getString(object, kAlgo);
|
||||
m_coin = Json::getString(object, kCoin);
|
||||
m_daemon = Json::getString(object, kSelfSelect);
|
||||
m_proxy = Json::getValue(object, kSOCKS5);
|
||||
m_user = Json::getString(object, kUser);
|
||||
m_spendSecretKey = Json::getString(object, kSpendSecretKey);
|
||||
m_password = Json::getString(object, kPass);
|
||||
m_rigId = Json::getString(object, kRigId);
|
||||
m_fingerprint = Json::getString(object, kFingerprint);
|
||||
m_pollInterval = Json::getUint64(object, kDaemonPollInterval, kDefaultPollInterval);
|
||||
m_algorithm = Json::getString(object, kAlgo);
|
||||
m_coin = Json::getString(object, kCoin);
|
||||
m_daemon = Json::getString(object, kSelfSelect);
|
||||
m_proxy = Json::getValue(object, kSOCKS5);
|
||||
m_zmqPort = Json::getInt(object, kDaemonZMQPort, m_zmqPort);
|
||||
|
||||
m_flags.set(FLAG_ENABLED, Json::getBool(object, kEnabled, true));
|
||||
m_flags.set(FLAG_NICEHASH, Json::getBool(object, kNicehash) || m_url.host().contains(kNicehashHost));
|
||||
|
@ -270,6 +275,10 @@ rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const
|
|||
obj.AddMember(StringRef(kUrl), url().toJSON(), allocator);
|
||||
obj.AddMember(StringRef(kUser), m_user.toJSON(), allocator);
|
||||
|
||||
if (!m_spendSecretKey.isEmpty()) {
|
||||
obj.AddMember(StringRef(kSpendSecretKey), m_spendSecretKey.toJSON(), allocator);
|
||||
}
|
||||
|
||||
if (m_mode != MODE_DAEMON) {
|
||||
obj.AddMember(StringRef(kPass), m_password.toJSON(), allocator);
|
||||
obj.AddMember(StringRef(kRigId), m_rigId.toJSON(), allocator);
|
||||
|
@ -294,6 +303,7 @@ rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const
|
|||
|
||||
if (m_mode == MODE_DAEMON) {
|
||||
obj.AddMember(StringRef(kDaemonPollInterval), m_pollInterval, allocator);
|
||||
obj.AddMember(StringRef(kDaemonZMQPort), m_zmqPort, allocator);
|
||||
}
|
||||
else {
|
||||
obj.AddMember(StringRef(kSelfSelect), m_daemon.url().toJSON(), allocator);
|
||||
|
@ -329,6 +339,9 @@ void xmrig::Pool::print() const
|
|||
LOG_NOTICE("url: %s", url().data());
|
||||
LOG_DEBUG ("host: %s", host().data());
|
||||
LOG_DEBUG ("port: %d", static_cast<int>(port()));
|
||||
if (m_zmqPort >= 0) {
|
||||
LOG_DEBUG("zmq-port: %d", m_zmqPort);
|
||||
}
|
||||
LOG_DEBUG ("user: %s", m_user.data());
|
||||
LOG_DEBUG ("pass: %s", m_password.data());
|
||||
LOG_DEBUG ("rig-id %s", m_rigId.data());
|
||||
|
|
|
@ -73,6 +73,8 @@ public:
|
|||
static const char *kTls;
|
||||
static const char *kUrl;
|
||||
static const char *kUser;
|
||||
static const char* kSpendSecretKey;
|
||||
static const char* kDaemonZMQPort;
|
||||
static const char *kNicehashHost;
|
||||
|
||||
constexpr static int kKeepAliveTimeout = 60;
|
||||
|
@ -80,7 +82,7 @@ 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 *host, uint16_t port, const char *user, const char *password, const char* spendSecretKey, int keepAlive, bool nicehash, bool tls, Mode mode);
|
||||
Pool(const char *url);
|
||||
Pool(const rapidjson::Value &object);
|
||||
|
||||
|
@ -103,10 +105,12 @@ public:
|
|||
inline const String &rigId() const { return m_rigId; }
|
||||
inline const String &url() const { return m_url.url(); }
|
||||
inline const String &user() const { return !m_user.isNull() ? m_user : kDefaultUser; }
|
||||
inline const String &spendSecretKey() const { return m_spendSecretKey; }
|
||||
inline const Url &daemon() const { return m_daemon; }
|
||||
inline int keepAlive() const { return m_keepAlive; }
|
||||
inline Mode mode() const { return m_mode; }
|
||||
inline uint16_t port() const { return m_url.port(); }
|
||||
inline int zmq_port() const { return m_zmqPort; }
|
||||
inline uint64_t pollInterval() const { return m_pollInterval; }
|
||||
inline void setAlgo(const Algorithm &algorithm) { m_algorithm = algorithm; }
|
||||
inline void setPassword(const String &password) { m_password = password; }
|
||||
|
@ -155,9 +159,11 @@ private:
|
|||
String m_password;
|
||||
String m_rigId;
|
||||
String m_user;
|
||||
String m_spendSecretKey;
|
||||
uint64_t m_pollInterval = kDefaultPollInterval;
|
||||
Url m_daemon;
|
||||
Url m_url;
|
||||
int m_zmqPort = -1;
|
||||
|
||||
# ifdef XMRIG_FEATURE_BENCHMARK
|
||||
std::shared_ptr<BenchConfig> m_benchmark;
|
||||
|
|
|
@ -60,7 +60,7 @@ public:
|
|||
# ifdef XMRIG_FEATURE_BENCHMARK
|
||||
inline bool isBenchmark() const { return !!m_benchmark; }
|
||||
# else
|
||||
inline constexpr bool isBenchmark() const { return false; }
|
||||
inline constexpr static bool isBenchmark() { return false; }
|
||||
# endif
|
||||
|
||||
inline const std::vector<Pool> &data() const { return m_data; }
|
||||
|
|
|
@ -61,7 +61,8 @@ xmrig::BenchClient::BenchClient(const std::shared_ptr<BenchConfig> &benchmark, I
|
|||
|
||||
# ifdef XMRIG_FEATURE_HTTP
|
||||
if (m_benchmark->isSubmit()) {
|
||||
m_mode = ONLINE_BENCH;
|
||||
m_mode = ONLINE_BENCH;
|
||||
m_token = m_benchmark->token();
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -350,6 +351,11 @@ void xmrig::BenchClient::send(Request request)
|
|||
# endif
|
||||
|
||||
FetchRequest req(HTTP_POST, m_ip, BenchConfig::kApiPort, "/1/benchmark", doc, BenchConfig::kApiTLS, true);
|
||||
|
||||
if (!m_token.isEmpty()) {
|
||||
req.headers.insert({ "Authorization", fmt::format("Bearer {}", m_token)});
|
||||
}
|
||||
|
||||
fetch(tag(), std::move(req), m_httpListener);
|
||||
}
|
||||
break;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue