mirror of
https://github.com/xmrig/xmrig.git
synced 2024-10-30 13:07:46 +00:00
Added support for solo mining with miner signatures (Wownero)
This commit is contained in:
parent
29f2dd4b9e
commit
a136790bee
20 changed files with 200 additions and 41 deletions
|
@ -11,7 +11,7 @@ option(WITH_ARGON2 "Enable Argon2 algorithms family" ON)
|
||||||
option(WITH_ASTROBWT "Enable AstroBWT algorithms family" ON)
|
option(WITH_ASTROBWT "Enable AstroBWT algorithms family" ON)
|
||||||
option(WITH_KAWPOW "Enable KawPow algorithms family" ON)
|
option(WITH_KAWPOW "Enable KawPow algorithms family" ON)
|
||||||
option(WITH_HTTP "Enable HTTP protocol support (client/server)" ON)
|
option(WITH_HTTP "Enable HTTP protocol support (client/server)" ON)
|
||||||
option(WITH_DEBUG_LOG "Enable debug log output" ON)
|
option(WITH_DEBUG_LOG "Enable debug log output" OFF)
|
||||||
option(WITH_TLS "Enable OpenSSL support" ON)
|
option(WITH_TLS "Enable OpenSSL support" ON)
|
||||||
option(WITH_ASM "Enable ASM PoW implementations" ON)
|
option(WITH_ASM "Enable ASM PoW implementations" ON)
|
||||||
option(WITH_MSR "Enable MSR mod & 1st-gen Ryzen fix" ON)
|
option(WITH_MSR "Enable MSR mod & 1st-gen Ryzen fix" ON)
|
||||||
|
|
|
@ -85,9 +85,10 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline int32_t nonceOffset() const { return currentJob().nonceOffset(); }
|
||||||
|
inline size_t nonceSize() const { return currentJob().nonceSize(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline int32_t nonceOffset() const { return currentJob().nonceOffset(); }
|
|
||||||
inline size_t nonceSize() const { return currentJob().nonceSize(); }
|
|
||||||
inline uint64_t nonceMask() const { return m_nonce_mask[index()]; }
|
inline uint64_t nonceMask() const { return m_nonce_mask[index()]; }
|
||||||
|
|
||||||
inline void save(const Job &job, uint32_t reserveCount, Nonce::Backend backend)
|
inline void save(const Job &job, uint32_t reserveCount, Nonce::Backend backend)
|
||||||
|
|
|
@ -274,10 +274,16 @@ void xmrig::CpuWorker<N>::start()
|
||||||
|
|
||||||
bool valid = true;
|
bool valid = true;
|
||||||
|
|
||||||
|
uint8_t miner_signature_saved[64];
|
||||||
|
uint8_t* miner_signature_ptr = m_job.blob() + m_job.nonceOffset() + m_job.nonceSize();
|
||||||
|
|
||||||
# ifdef XMRIG_ALGO_RANDOMX
|
# ifdef XMRIG_ALGO_RANDOMX
|
||||||
if (job.algorithm().family() == Algorithm::RANDOM_X) {
|
if (job.algorithm().family() == Algorithm::RANDOM_X) {
|
||||||
if (first) {
|
if (first) {
|
||||||
first = false;
|
first = false;
|
||||||
|
if (job.hasMinerSignature()) {
|
||||||
|
job.generateMinerSignature(m_job.currentJob().timestamp() + *m_job.nonce(), miner_signature_ptr);
|
||||||
|
}
|
||||||
randomx_calculate_hash_first(m_vm, tempHash, m_job.blob(), job.size());
|
randomx_calculate_hash_first(m_vm, tempHash, m_job.blob(), job.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,6 +291,10 @@ void xmrig::CpuWorker<N>::start()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (job.hasMinerSignature()) {
|
||||||
|
memcpy(miner_signature_saved, miner_signature_ptr, sizeof(miner_signature_saved));
|
||||||
|
job.generateMinerSignature(m_job.currentJob().timestamp() + *m_job.nonce(), miner_signature_ptr);
|
||||||
|
}
|
||||||
randomx_calculate_hash_next(m_vm, tempHash, m_job.blob(), job.size(), m_hash);
|
randomx_calculate_hash_next(m_vm, tempHash, m_job.blob(), job.size(), m_hash);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -319,7 +329,7 @@ void xmrig::CpuWorker<N>::start()
|
||||||
else
|
else
|
||||||
# endif
|
# endif
|
||||||
if (value < job.target()) {
|
if (value < job.target()) {
|
||||||
JobResults::submit(job, current_job_nonces[i], m_hash + (i * 32));
|
JobResults::submit(job, current_job_nonces[i], m_hash + (i * 32), miner_signature_saved);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_count += N;
|
m_count += N;
|
||||||
|
|
|
@ -56,7 +56,8 @@ static CoinName const coin_names[] = {
|
||||||
{ "ravencoin", Coin::RAVEN },
|
{ "ravencoin", Coin::RAVEN },
|
||||||
{ "raven", Coin::RAVEN },
|
{ "raven", Coin::RAVEN },
|
||||||
{ "rvn", Coin::RAVEN },
|
{ "rvn", Coin::RAVEN },
|
||||||
{ "conceal", Coin::CONCEAL }
|
{ "conceal", Coin::CONCEAL },
|
||||||
|
{ "wownero", Coin::WOWNERO }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -85,6 +86,9 @@ xmrig::Algorithm::Id xmrig::Coin::algorithm(uint8_t blobVersion) const
|
||||||
case CONCEAL:
|
case CONCEAL:
|
||||||
return Algorithm::CN_CCX;
|
return Algorithm::CN_CCX;
|
||||||
|
|
||||||
|
case WOWNERO:
|
||||||
|
return Algorithm::RX_WOW;
|
||||||
|
|
||||||
case INVALID:
|
case INVALID:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,8 @@ public:
|
||||||
DERO,
|
DERO,
|
||||||
KEVA,
|
KEVA,
|
||||||
RAVEN,
|
RAVEN,
|
||||||
CONCEAL
|
CONCEAL,
|
||||||
|
WOWNERO
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -181,6 +181,9 @@ void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const ch
|
||||||
case IConfig::PasswordKey: /* --pass */
|
case IConfig::PasswordKey: /* --pass */
|
||||||
return add(doc, Pools::kPools, Pool::kPass, arg);
|
return add(doc, Pools::kPools, Pool::kPass, arg);
|
||||||
|
|
||||||
|
case IConfig::SpendSecretKey: /* --spend-secret-key */
|
||||||
|
return add(doc, Pools::kPools, Pool::kSpendSecretKey, arg);
|
||||||
|
|
||||||
case IConfig::RigIdKey: /* --rig-id */
|
case IConfig::RigIdKey: /* --rig-id */
|
||||||
return add(doc, Pools::kPools, Pool::kRigId, arg);
|
return add(doc, Pools::kPools, Pool::kRigId, arg);
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,7 @@ public:
|
||||||
SubmitToOriginKey = 1052,
|
SubmitToOriginKey = 1052,
|
||||||
DnsIPv6Key = 1053,
|
DnsIPv6Key = 1053,
|
||||||
DnsTtlKey = 1054,
|
DnsTtlKey = 1054,
|
||||||
|
SpendSecretKey = 1055,
|
||||||
|
|
||||||
// xmrig common
|
// xmrig common
|
||||||
CPUPriorityKey = 1021,
|
CPUPriorityKey = 1021,
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "base/net/stratum/SubmitResult.h"
|
#include "base/net/stratum/SubmitResult.h"
|
||||||
#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 "net/JobResult.h"
|
#include "net/JobResult.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -94,11 +95,11 @@ bool xmrig::DaemonClient::isTLS() const
|
||||||
|
|
||||||
int64_t xmrig::DaemonClient::submit(const JobResult &result)
|
int64_t xmrig::DaemonClient::submit(const JobResult &result)
|
||||||
{
|
{
|
||||||
if (result.jobId != (m_blocktemplate.data() + m_blocktemplate.size() - 32)) {
|
if (result.jobId != (m_blocktemplateStr.data() + m_blocktemplateStr.size() - 32)) {
|
||||||
return -1;
|
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();
|
||||||
|
|
||||||
# ifdef XMRIG_PROXY_PROJECT
|
# ifdef XMRIG_PROXY_PROJECT
|
||||||
memcpy(data + 78, result.nonce, 8);
|
memcpy(data + 78, result.nonce, 8);
|
||||||
|
@ -106,16 +107,21 @@ int64_t xmrig::DaemonClient::submit(const JobResult &result)
|
||||||
Cvt::toHex(data + 78, 8, reinterpret_cast<const uint8_t *>(&result.nonce), 4);
|
Cvt::toHex(data + 78, 8, reinterpret_cast<const uint8_t *>(&result.nonce), 4);
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
if (m_blocktemplate.has_miner_signature) {
|
||||||
|
const size_t sig_offset = m_job.nonceOffset() + m_job.nonceSize();
|
||||||
|
Cvt::toHex(data + sig_offset * 2, 128, result.minerSignature(), 64);
|
||||||
|
}
|
||||||
|
|
||||||
using namespace rapidjson;
|
using namespace rapidjson;
|
||||||
Document doc(kObjectType);
|
Document doc(kObjectType);
|
||||||
|
|
||||||
Value params(kArrayType);
|
Value params(kArrayType);
|
||||||
if (m_apiVersion == API_DERO) {
|
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());
|
params.PushBack(m_blockhashingblob.toJSON(), doc.GetAllocator());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
params.PushBack(m_blocktemplate.toJSON(), doc.GetAllocator());
|
params.PushBack(m_blocktemplateStr.toJSON(), doc.GetAllocator());
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonRequest::create(doc, m_sequence, "submitblock", params);
|
JsonRequest::create(doc, m_sequence, "submitblock", params);
|
||||||
|
@ -263,9 +269,53 @@ bool xmrig::DaemonClient::parseJob(const rapidjson::Value ¶ms, int *code)
|
||||||
job.setDiff(Json::getUint64(params, "difficulty"));
|
job.setDiff(Json::getUint64(params, "difficulty"));
|
||||||
job.setId(blocktemplate.data() + blocktemplate.size() - 32);
|
job.setId(blocktemplate.data() + blocktemplate.size() - 32);
|
||||||
|
|
||||||
m_job = std::move(job);
|
Coin pool_coin = m_pool.coin();
|
||||||
m_blocktemplate = std::move(blocktemplate);
|
|
||||||
m_prevHash = Json::getString(params, "prev_hash");
|
if ((pool_coin == Coin::INVALID) && (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");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_blocktemplate.has_miner_signature) {
|
||||||
|
if (m_pool.spendSecretKey().isEmpty()) {
|
||||||
|
LOG_ERR("Secret spend key is not set");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_pool.spendSecretKey().size() != 64) {
|
||||||
|
LOG_ERR("Secret spend key has invalid length. It must be 64 hex characters.");
|
||||||
|
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.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t secret_viewkey[32];
|
||||||
|
derive_view_secret_key(secret_spendkey, secret_viewkey);
|
||||||
|
|
||||||
|
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.");
|
||||||
|
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);
|
||||||
|
job.setTimestamp(m_blocktemplate.timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_job = std::move(job);
|
||||||
|
m_blocktemplateStr = std::move(blocktemplate);
|
||||||
|
m_prevHash = Json::getString(params, "prev_hash");
|
||||||
|
|
||||||
if (m_apiVersion == API_DERO) {
|
if (m_apiVersion == API_DERO) {
|
||||||
// Truncate to 32 bytes to have the same data as in get_info RPC
|
// Truncate to 32 bytes to have the same data as in get_info RPC
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#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/Object.h"
|
||||||
|
#include "base/tools/cryptonote/BlockTemplate.h"
|
||||||
|
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -83,7 +84,7 @@ private:
|
||||||
} m_apiVersion = API_MONERO;
|
} m_apiVersion = API_MONERO;
|
||||||
|
|
||||||
std::shared_ptr<IHttpListener> m_httpListener;
|
std::shared_ptr<IHttpListener> m_httpListener;
|
||||||
String m_blocktemplate;
|
String m_blocktemplateStr;
|
||||||
String m_blockhashingblob;
|
String m_blockhashingblob;
|
||||||
String m_prevHash;
|
String m_prevHash;
|
||||||
String m_tlsFingerprint;
|
String m_tlsFingerprint;
|
||||||
|
@ -91,6 +92,8 @@ private:
|
||||||
Timer *m_timer;
|
Timer *m_timer;
|
||||||
uint64_t m_blocktemplateRequestHeight = 0;
|
uint64_t m_blocktemplateRequestHeight = 0;
|
||||||
String m_blocktemplateRequestHash;
|
String m_blocktemplateRequestHash;
|
||||||
|
|
||||||
|
BlockTemplate m_blocktemplate;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,8 @@
|
||||||
#include "base/net/stratum/Job.h"
|
#include "base/net/stratum/Job.h"
|
||||||
#include "base/tools/Buffer.h"
|
#include "base/tools/Buffer.h"
|
||||||
#include "base/tools/Cvt.h"
|
#include "base/tools/Cvt.h"
|
||||||
|
#include "base/tools/cryptonote/Signatures.h"
|
||||||
|
#include "base/crypto/keccak.h"
|
||||||
|
|
||||||
|
|
||||||
xmrig::Job::Job(bool nicehash, const Algorithm &algorithm, const String &clientId) :
|
xmrig::Job::Job(bool nicehash, const Algorithm &algorithm, const String &clientId) :
|
||||||
|
@ -169,6 +171,13 @@ void xmrig::Job::copy(const Job &other)
|
||||||
# ifdef XMRIG_FEATURE_BENCHMARK
|
# ifdef XMRIG_FEATURE_BENCHMARK
|
||||||
m_benchSize = other.m_benchSize;
|
m_benchSize = other.m_benchSize;
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
m_hasMinerSignature = other.m_hasMinerSignature;
|
||||||
|
|
||||||
|
memcpy(m_ephPublicKey, other.m_ephPublicKey, sizeof(m_ephPublicKey));
|
||||||
|
memcpy(m_ephSecretKey, other.m_ephSecretKey, sizeof(m_ephSecretKey));
|
||||||
|
|
||||||
|
m_timestamp = other.m_timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -204,4 +213,27 @@ void xmrig::Job::move(Job &&other)
|
||||||
# ifdef XMRIG_FEATURE_BENCHMARK
|
# ifdef XMRIG_FEATURE_BENCHMARK
|
||||||
m_benchSize = other.m_benchSize;
|
m_benchSize = other.m_benchSize;
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
m_hasMinerSignature = other.m_hasMinerSignature;
|
||||||
|
|
||||||
|
memcpy(m_ephPublicKey, other.m_ephPublicKey, sizeof(m_ephPublicKey));
|
||||||
|
memcpy(m_ephSecretKey, other.m_ephSecretKey, sizeof(m_ephSecretKey));
|
||||||
|
|
||||||
|
m_timestamp = other.m_timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void xmrig::Job::generateMinerSignature(uint64_t data, uint8_t* sig) const
|
||||||
|
{
|
||||||
|
uint8_t sig_data[16];
|
||||||
|
int k = sizeof(sig_data);
|
||||||
|
do {
|
||||||
|
sig_data[--k] = "0123456789"[data % 10];
|
||||||
|
data /= 10;
|
||||||
|
} while (data);
|
||||||
|
|
||||||
|
uint8_t prefix_hash[32];
|
||||||
|
xmrig::keccak(sig_data + k, sizeof(sig_data) - k, prefix_hash, sizeof(prefix_hash));
|
||||||
|
|
||||||
|
xmrig::generate_signature(prefix_hash, m_ephPublicKey, m_ephSecretKey, sig);
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,6 +116,21 @@ public:
|
||||||
inline void setBenchSize(uint32_t size) { m_benchSize = size; }
|
inline void setBenchSize(uint32_t size) { m_benchSize = size; }
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
inline const uint8_t* ephSecretKey() const { return m_hasMinerSignature ? m_ephSecretKey : nullptr; }
|
||||||
|
inline uint64_t timestamp() const { return m_timestamp; }
|
||||||
|
|
||||||
|
inline void setEphemeralKeys(uint8_t* pub_key, uint8_t* sec_key)
|
||||||
|
{
|
||||||
|
m_hasMinerSignature = true;
|
||||||
|
memcpy(m_ephPublicKey, pub_key, sizeof(m_ephSecretKey));
|
||||||
|
memcpy(m_ephSecretKey, sec_key, sizeof(m_ephSecretKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setTimestamp(uint64_t timestamp) { m_timestamp = timestamp; }
|
||||||
|
|
||||||
|
inline bool hasMinerSignature() const { return m_hasMinerSignature; }
|
||||||
|
void generateMinerSignature(uint64_t data, uint8_t* sig) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void copy(const Job &other);
|
void copy(const Job &other);
|
||||||
void move(Job &&other);
|
void move(Job &&other);
|
||||||
|
@ -144,6 +159,11 @@ private:
|
||||||
# ifdef XMRIG_FEATURE_BENCHMARK
|
# ifdef XMRIG_FEATURE_BENCHMARK
|
||||||
uint32_t m_benchSize = 0;
|
uint32_t m_benchSize = 0;
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
bool m_hasMinerSignature = false;
|
||||||
|
uint8_t m_ephPublicKey[32]{};
|
||||||
|
uint8_t m_ephSecretKey[32]{};
|
||||||
|
uint64_t m_timestamp = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,7 @@ const char *Pool::kSubmitToOrigin = "submit-to-origin";
|
||||||
const char *Pool::kTls = "tls";
|
const char *Pool::kTls = "tls";
|
||||||
const char *Pool::kUrl = "url";
|
const char *Pool::kUrl = "url";
|
||||||
const char *Pool::kUser = "user";
|
const char *Pool::kUser = "user";
|
||||||
|
const char *Pool::kSpendSecretKey = "spend-secret-key";
|
||||||
const char *Pool::kNicehashHost = "nicehash.com";
|
const char *Pool::kNicehashHost = "nicehash.com";
|
||||||
|
|
||||||
|
|
||||||
|
@ -92,12 +93,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_keepAlive(keepAlive),
|
||||||
m_mode(mode),
|
m_mode(mode),
|
||||||
m_flags(1 << FLAG_ENABLED),
|
m_flags(1 << FLAG_ENABLED),
|
||||||
m_password(password),
|
m_password(password),
|
||||||
m_user(user),
|
m_user(user),
|
||||||
|
m_spendSecretKey(spendSecretKey),
|
||||||
m_pollInterval(kDefaultPollInterval),
|
m_pollInterval(kDefaultPollInterval),
|
||||||
m_url(host, port, tls)
|
m_url(host, port, tls)
|
||||||
{
|
{
|
||||||
|
@ -115,15 +117,16 @@ xmrig::Pool::Pool(const rapidjson::Value &object) :
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_user = Json::getString(object, kUser);
|
m_user = Json::getString(object, kUser);
|
||||||
m_password = Json::getString(object, kPass);
|
m_spendSecretKey = Json::getString(object, kSpendSecretKey);
|
||||||
m_rigId = Json::getString(object, kRigId);
|
m_password = Json::getString(object, kPass);
|
||||||
m_fingerprint = Json::getString(object, kFingerprint);
|
m_rigId = Json::getString(object, kRigId);
|
||||||
m_pollInterval = Json::getUint64(object, kDaemonPollInterval, kDefaultPollInterval);
|
m_fingerprint = Json::getString(object, kFingerprint);
|
||||||
m_algorithm = Json::getString(object, kAlgo);
|
m_pollInterval = Json::getUint64(object, kDaemonPollInterval, kDefaultPollInterval);
|
||||||
m_coin = Json::getString(object, kCoin);
|
m_algorithm = Json::getString(object, kAlgo);
|
||||||
m_daemon = Json::getString(object, kSelfSelect);
|
m_coin = Json::getString(object, kCoin);
|
||||||
m_proxy = Json::getValue(object, kSOCKS5);
|
m_daemon = Json::getString(object, kSelfSelect);
|
||||||
|
m_proxy = Json::getValue(object, kSOCKS5);
|
||||||
|
|
||||||
m_flags.set(FLAG_ENABLED, Json::getBool(object, kEnabled, true));
|
m_flags.set(FLAG_ENABLED, Json::getBool(object, kEnabled, true));
|
||||||
m_flags.set(FLAG_NICEHASH, Json::getBool(object, kNicehash) || m_url.host().contains(kNicehashHost));
|
m_flags.set(FLAG_NICEHASH, Json::getBool(object, kNicehash) || m_url.host().contains(kNicehashHost));
|
||||||
|
@ -270,6 +273,10 @@ rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const
|
||||||
obj.AddMember(StringRef(kUrl), url().toJSON(), allocator);
|
obj.AddMember(StringRef(kUrl), url().toJSON(), allocator);
|
||||||
obj.AddMember(StringRef(kUser), m_user.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) {
|
if (m_mode != MODE_DAEMON) {
|
||||||
obj.AddMember(StringRef(kPass), m_password.toJSON(), allocator);
|
obj.AddMember(StringRef(kPass), m_password.toJSON(), allocator);
|
||||||
obj.AddMember(StringRef(kRigId), m_rigId.toJSON(), allocator);
|
obj.AddMember(StringRef(kRigId), m_rigId.toJSON(), allocator);
|
||||||
|
|
|
@ -71,6 +71,7 @@ public:
|
||||||
static const char *kTls;
|
static const char *kTls;
|
||||||
static const char *kUrl;
|
static const char *kUrl;
|
||||||
static const char *kUser;
|
static const char *kUser;
|
||||||
|
static const char* kSpendSecretKey;
|
||||||
static const char *kNicehashHost;
|
static const char *kNicehashHost;
|
||||||
|
|
||||||
constexpr static int kKeepAliveTimeout = 60;
|
constexpr static int kKeepAliveTimeout = 60;
|
||||||
|
@ -78,7 +79,7 @@ public:
|
||||||
constexpr static uint64_t kDefaultPollInterval = 1000;
|
constexpr static uint64_t kDefaultPollInterval = 1000;
|
||||||
|
|
||||||
Pool() = default;
|
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 char *url);
|
||||||
Pool(const rapidjson::Value &object);
|
Pool(const rapidjson::Value &object);
|
||||||
|
|
||||||
|
@ -101,6 +102,7 @@ public:
|
||||||
inline const String &rigId() const { return m_rigId; }
|
inline const String &rigId() const { return m_rigId; }
|
||||||
inline const String &url() const { return m_url.url(); }
|
inline const String &url() const { return m_url.url(); }
|
||||||
inline const String &user() const { return !m_user.isNull() ? m_user : kDefaultUser; }
|
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 const Url &daemon() const { return m_daemon; }
|
||||||
inline int keepAlive() const { return m_keepAlive; }
|
inline int keepAlive() const { return m_keepAlive; }
|
||||||
inline Mode mode() const { return m_mode; }
|
inline Mode mode() const { return m_mode; }
|
||||||
|
@ -149,6 +151,7 @@ private:
|
||||||
String m_password;
|
String m_password;
|
||||||
String m_rigId;
|
String m_rigId;
|
||||||
String m_user;
|
String m_user;
|
||||||
|
String m_spendSecretKey;
|
||||||
uint64_t m_pollInterval = kDefaultPollInterval;
|
uint64_t m_pollInterval = kDefaultPollInterval;
|
||||||
Url m_daemon;
|
Url m_daemon;
|
||||||
Url m_url;
|
Url m_url;
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
namespace xmrig {
|
namespace xmrig {
|
||||||
|
|
||||||
|
|
||||||
bool CBlockTemplate::Init(const String& blockTemplate)
|
bool BlockTemplate::Init(const String& blockTemplate, Coin coin)
|
||||||
{
|
{
|
||||||
raw_blob = Cvt::fromHex(blockTemplate);
|
raw_blob = Cvt::fromHex(blockTemplate);
|
||||||
|
|
||||||
|
@ -41,6 +41,12 @@ bool CBlockTemplate::Init(const String& blockTemplate)
|
||||||
ar(prev_id);
|
ar(prev_id);
|
||||||
ar(nonce);
|
ar(nonce);
|
||||||
|
|
||||||
|
// Wownero block template has miner signature starting from version 19
|
||||||
|
has_miner_signature = (coin == Coin::WOWNERO) && (major_version >= 19);
|
||||||
|
if (has_miner_signature) {
|
||||||
|
ar(miner_signature);
|
||||||
|
}
|
||||||
|
|
||||||
// Miner transaction begin
|
// Miner transaction begin
|
||||||
// Prefix begin
|
// Prefix begin
|
||||||
miner_tx_prefix_begin_index = ar.index();
|
miner_tx_prefix_begin_index = ar.index();
|
||||||
|
@ -108,7 +114,7 @@ bool CBlockTemplate::Init(const String& blockTemplate)
|
||||||
ar(num_hashes);
|
ar(num_hashes);
|
||||||
|
|
||||||
hashes.resize((num_hashes + 1) * HASH_SIZE);
|
hashes.resize((num_hashes + 1) * HASH_SIZE);
|
||||||
CalculateMinerTxHash(hashes.data());
|
//CalculateMinerTxHash(hashes.data());
|
||||||
|
|
||||||
for (uint64_t i = 1; i <= num_hashes; ++i) {
|
for (uint64_t i = 1; i <= num_hashes; ++i) {
|
||||||
uint8_t h[HASH_SIZE];
|
uint8_t h[HASH_SIZE];
|
||||||
|
@ -116,14 +122,14 @@ bool CBlockTemplate::Init(const String& blockTemplate)
|
||||||
memcpy(hashes.data() + i * HASH_SIZE, h, HASH_SIZE);
|
memcpy(hashes.data() + i * HASH_SIZE, h, HASH_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
CalculateMerkleTreeHash(hashes.data(), num_hashes + 1, root_hash);
|
//CalculateMerkleTreeHash(hashes.data(), num_hashes + 1, root_hash);
|
||||||
CalculateHashingBlob();
|
//CalculateHashingBlob();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CBlockTemplate::CalculateMinerTxHash(uint8_t* hash)
|
void BlockTemplate::CalculateMinerTxHash(uint8_t* hash)
|
||||||
{
|
{
|
||||||
uint8_t hashes[HASH_SIZE * 3];
|
uint8_t hashes[HASH_SIZE * 3];
|
||||||
|
|
||||||
|
@ -147,7 +153,7 @@ void CBlockTemplate::CalculateMinerTxHash(uint8_t* hash)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void CBlockTemplate::CalculateMerkleTreeHash(const uint8_t* hashes, size_t count, uint8_t* root_hash)
|
void BlockTemplate::CalculateMerkleTreeHash(const uint8_t* hashes, size_t count, uint8_t* root_hash)
|
||||||
{
|
{
|
||||||
if (count == 1) {
|
if (count == 1) {
|
||||||
memcpy(root_hash, hashes, HASH_SIZE);
|
memcpy(root_hash, hashes, HASH_SIZE);
|
||||||
|
@ -180,7 +186,7 @@ void CBlockTemplate::CalculateMerkleTreeHash(const uint8_t* hashes, size_t count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CBlockTemplate::CalculateHashingBlob()
|
void BlockTemplate::CalculateHashingBlob()
|
||||||
{
|
{
|
||||||
hashingBlob.clear();
|
hashingBlob.clear();
|
||||||
hashingBlob.reserve(miner_tx_prefix_begin_index + HASH_SIZE + 3);
|
hashingBlob.reserve(miner_tx_prefix_begin_index + HASH_SIZE + 3);
|
||||||
|
@ -194,9 +200,6 @@ void CBlockTemplate::CalculateHashingBlob()
|
||||||
k >>= 7;
|
k >>= 7;
|
||||||
}
|
}
|
||||||
hashingBlob.emplace_back(static_cast<uint8_t>(k));
|
hashingBlob.emplace_back(static_cast<uint8_t>(k));
|
||||||
|
|
||||||
for (int i = 0; i < hashingBlob.size(); ++i)
|
|
||||||
printf("%02x", hashingBlob[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#define XMRIG_BLOCKTEMPLATE_H
|
#define XMRIG_BLOCKTEMPLATE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "base/crypto/Coin.h"
|
||||||
#include "base/tools/Buffer.h"
|
#include "base/tools/Buffer.h"
|
||||||
#include "base/tools/String.h"
|
#include "base/tools/String.h"
|
||||||
|
|
||||||
|
@ -29,11 +30,12 @@
|
||||||
namespace xmrig {
|
namespace xmrig {
|
||||||
|
|
||||||
|
|
||||||
struct CBlockTemplate
|
struct BlockTemplate
|
||||||
{
|
{
|
||||||
enum {
|
enum {
|
||||||
HASH_SIZE = 32,
|
HASH_SIZE = 32,
|
||||||
KEY_SIZE = 32,
|
KEY_SIZE = 32,
|
||||||
|
SIGNATURE_SIZE = 64,
|
||||||
NONCE_SIZE = 4,
|
NONCE_SIZE = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -50,6 +52,9 @@ struct CBlockTemplate
|
||||||
uint8_t prev_id[HASH_SIZE];
|
uint8_t prev_id[HASH_SIZE];
|
||||||
uint8_t nonce[NONCE_SIZE];
|
uint8_t nonce[NONCE_SIZE];
|
||||||
|
|
||||||
|
bool has_miner_signature;
|
||||||
|
uint8_t miner_signature[SIGNATURE_SIZE];
|
||||||
|
|
||||||
// Miner tx
|
// Miner tx
|
||||||
uint64_t tx_version;
|
uint64_t tx_version;
|
||||||
uint64_t unlock_time;
|
uint64_t unlock_time;
|
||||||
|
@ -72,7 +77,7 @@ struct CBlockTemplate
|
||||||
|
|
||||||
Buffer hashingBlob;
|
Buffer hashingBlob;
|
||||||
|
|
||||||
bool Init(const String& blockTemplate);
|
bool Init(const String& blockTemplate, Coin coin);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void CalculateMinerTxHash(uint8_t* hash);
|
void CalculateMinerTxHash(uint8_t* hash);
|
||||||
|
|
|
@ -96,6 +96,7 @@ static const option options[] = {
|
||||||
{ "pause-on-active", 1, nullptr, IConfig::PauseOnActiveKey },
|
{ "pause-on-active", 1, nullptr, IConfig::PauseOnActiveKey },
|
||||||
{ "dns-ipv6", 0, nullptr, IConfig::DnsIPv6Key },
|
{ "dns-ipv6", 0, nullptr, IConfig::DnsIPv6Key },
|
||||||
{ "dns-ttl", 1, nullptr, IConfig::DnsTtlKey },
|
{ "dns-ttl", 1, nullptr, IConfig::DnsTtlKey },
|
||||||
|
{ "spend-secret-key", 1, nullptr, IConfig::SpendSecretKey },
|
||||||
# ifdef XMRIG_FEATURE_BENCHMARK
|
# ifdef XMRIG_FEATURE_BENCHMARK
|
||||||
{ "stress", 0, nullptr, IConfig::StressKey },
|
{ "stress", 0, nullptr, IConfig::StressKey },
|
||||||
{ "bench", 1, nullptr, IConfig::BenchKey },
|
{ "bench", 1, nullptr, IConfig::BenchKey },
|
||||||
|
|
|
@ -43,7 +43,7 @@ class JobResult
|
||||||
public:
|
public:
|
||||||
JobResult() = delete;
|
JobResult() = delete;
|
||||||
|
|
||||||
inline JobResult(const Job &job, uint64_t nonce, const uint8_t *result, const uint8_t* header_hash = nullptr, const uint8_t *mix_hash = nullptr) :
|
inline JobResult(const Job &job, uint64_t nonce, const uint8_t *result, const uint8_t* header_hash = nullptr, const uint8_t *mix_hash = nullptr, const uint8_t* miner_signature = nullptr) :
|
||||||
algorithm(job.algorithm()),
|
algorithm(job.algorithm()),
|
||||||
clientId(job.clientId()),
|
clientId(job.clientId()),
|
||||||
jobId(job.id()),
|
jobId(job.id()),
|
||||||
|
@ -61,6 +61,10 @@ public:
|
||||||
if (mix_hash) {
|
if (mix_hash) {
|
||||||
memcpy(m_mixHash, mix_hash, sizeof(m_mixHash));
|
memcpy(m_mixHash, mix_hash, sizeof(m_mixHash));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (miner_signature) {
|
||||||
|
memcpy(m_minerSignature, miner_signature, sizeof(m_minerSignature));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline JobResult(const Job &job) :
|
inline JobResult(const Job &job) :
|
||||||
|
@ -80,6 +84,8 @@ public:
|
||||||
inline const uint8_t *headerHash() const { return m_headerHash; }
|
inline const uint8_t *headerHash() const { return m_headerHash; }
|
||||||
inline const uint8_t *mixHash() const { return m_mixHash; }
|
inline const uint8_t *mixHash() const { return m_mixHash; }
|
||||||
|
|
||||||
|
inline const uint8_t *minerSignature() const { return m_minerSignature; }
|
||||||
|
|
||||||
const Algorithm algorithm;
|
const Algorithm algorithm;
|
||||||
const String clientId;
|
const String clientId;
|
||||||
const String jobId;
|
const String jobId;
|
||||||
|
@ -92,6 +98,8 @@ private:
|
||||||
uint8_t m_result[32] = { 0 };
|
uint8_t m_result[32] = { 0 };
|
||||||
uint8_t m_headerHash[32] = { 0 };
|
uint8_t m_headerHash[32] = { 0 };
|
||||||
uint8_t m_mixHash[32] = { 0 };
|
uint8_t m_mixHash[32] = { 0 };
|
||||||
|
|
||||||
|
uint8_t m_minerSignature[64] = { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -341,6 +341,12 @@ void xmrig::JobResults::submit(const Job &job, uint32_t nonce, const uint8_t *re
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void xmrig::JobResults::submit(const Job& job, uint32_t nonce, const uint8_t* result, const uint8_t* miner_signature)
|
||||||
|
{
|
||||||
|
submit(JobResult(job, nonce, result, nullptr, nullptr, miner_signature));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void xmrig::JobResults::submit(const JobResult &result)
|
void xmrig::JobResults::submit(const JobResult &result)
|
||||||
{
|
{
|
||||||
assert(handler != nullptr);
|
assert(handler != nullptr);
|
||||||
|
|
|
@ -46,6 +46,7 @@ public:
|
||||||
static void setListener(IJobResultListener *listener, bool hwAES);
|
static void setListener(IJobResultListener *listener, bool hwAES);
|
||||||
static void stop();
|
static void stop();
|
||||||
static void submit(const Job &job, uint32_t nonce, const uint8_t *result);
|
static void submit(const Job &job, uint32_t nonce, const uint8_t *result);
|
||||||
|
static void submit(const Job& job, uint32_t nonce, const uint8_t* result, const uint8_t* miner_signature);
|
||||||
static void submit(const JobResult &result);
|
static void submit(const JobResult &result);
|
||||||
|
|
||||||
# if defined(XMRIG_FEATURE_OPENCL) || defined(XMRIG_FEATURE_CUDA)
|
# if defined(XMRIG_FEATURE_OPENCL) || defined(XMRIG_FEATURE_CUDA)
|
||||||
|
|
|
@ -77,9 +77,9 @@ xmrig::DonateStrategy::DonateStrategy(Controller *controller, IStrategyListener
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifdef XMRIG_FEATURE_TLS
|
# ifdef XMRIG_FEATURE_TLS
|
||||||
m_pools.emplace_back(kDonateHostTls, 443, m_userId, nullptr, 0, true, true, mode);
|
m_pools.emplace_back(kDonateHostTls, 443, m_userId, nullptr, nullptr, 0, true, true, mode);
|
||||||
# endif
|
# endif
|
||||||
m_pools.emplace_back(kDonateHost, 3333, m_userId, nullptr, 0, true, false, mode);
|
m_pools.emplace_back(kDonateHost, 3333, m_userId, nullptr, nullptr, 0, true, false, mode);
|
||||||
|
|
||||||
if (m_pools.size() > 1) {
|
if (m_pools.size() > 1) {
|
||||||
m_strategy = new FailoverStrategy(m_pools, 10, 2, this, true);
|
m_strategy = new FailoverStrategy(m_pools, 10, 2, this, true);
|
||||||
|
@ -259,7 +259,7 @@ xmrig::IClient *xmrig::DonateStrategy::createProxy()
|
||||||
const IClient *client = strategy->client();
|
const IClient *client = strategy->client();
|
||||||
m_tls = client->hasExtension(IClient::EXT_TLS);
|
m_tls = client->hasExtension(IClient::EXT_TLS);
|
||||||
|
|
||||||
Pool pool(client->pool().proxy().isValid() ? client->pool().host() : client->ip(), client->pool().port(), m_userId, client->pool().password(), 0, true, client->isTLS(), Pool::MODE_POOL);
|
Pool pool(client->pool().proxy().isValid() ? client->pool().host() : client->ip(), client->pool().port(), m_userId, client->pool().password(), nullptr, 0, true, client->isTLS(), Pool::MODE_POOL);
|
||||||
pool.setAlgo(client->pool().algorithm());
|
pool.setAlgo(client->pool().algorithm());
|
||||||
pool.setProxy(client->pool().proxy());
|
pool.setProxy(client->pool().proxy());
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue