GhostRider algorithm (Raptoreum) support
This commit is contained in:
parent
5156ff11a8
commit
ceaebfd877
67 changed files with 72022 additions and 177 deletions
|
@ -34,6 +34,16 @@
|
|||
#include "base/kernel/interfaces/IClientListener.h"
|
||||
#include "net/JobResult.h"
|
||||
|
||||
#ifdef XMRIG_ALGO_GHOSTRIDER
|
||||
#include <cmath>
|
||||
|
||||
extern "C" {
|
||||
#include "crypto/ghostrider/sph_sha2.h"
|
||||
}
|
||||
|
||||
#include "base/tools/Cvt.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
xmrig::EthStratumClient::EthStratumClient(int id, const char *agent, IClientListener *listener) :
|
||||
|
@ -66,29 +76,53 @@ int64_t xmrig::EthStratumClient::submit(const JobResult& result)
|
|||
params.PushBack(m_pool.user().toJSON(), allocator);
|
||||
params.PushBack(result.jobId.toJSON(), allocator);
|
||||
|
||||
std::stringstream s;
|
||||
s << "0x" << std::hex << std::setw(16) << std::setfill('0') << result.nonce;
|
||||
params.PushBack(Value(s.str().c_str(), allocator), allocator);
|
||||
# ifdef XMRIG_ALGO_GHOSTRIDER
|
||||
if (m_pool.algorithm().id() == Algorithm::GHOSTRIDER_RTM) {
|
||||
params.PushBack(Value("00000000000000000000000000000000", static_cast<uint32_t>(m_extraNonce2Size * 2)), allocator);
|
||||
params.PushBack(Value(m_ntime.data(), allocator), allocator);
|
||||
|
||||
s.str(std::string());
|
||||
s << "0x";
|
||||
for (size_t i = 0; i < 32; ++i) {
|
||||
const uint32_t k = result.headerHash()[i];
|
||||
s << std::hex << std::setw(2) << std::setfill('0') << k;
|
||||
std::stringstream s;
|
||||
s << std::hex << std::setw(8) << std::setfill('0') << result.nonce;
|
||||
params.PushBack(Value(s.str().c_str(), allocator), allocator);
|
||||
}
|
||||
params.PushBack(Value(s.str().c_str(), allocator), allocator);
|
||||
else
|
||||
# endif
|
||||
{
|
||||
std::stringstream s;
|
||||
s << "0x" << std::hex << std::setw(16) << std::setfill('0') << result.nonce;
|
||||
params.PushBack(Value(s.str().c_str(), allocator), allocator);
|
||||
|
||||
s.str(std::string());
|
||||
s << "0x";
|
||||
for (size_t i = 0; i < 32; ++i) {
|
||||
const uint32_t k = result.mixHash()[i];
|
||||
s << std::hex << std::setw(2) << std::setfill('0') << k;
|
||||
s.str(std::string());
|
||||
s << "0x";
|
||||
for (size_t i = 0; i < 32; ++i) {
|
||||
const uint32_t k = result.headerHash()[i];
|
||||
s << std::hex << std::setw(2) << std::setfill('0') << k;
|
||||
}
|
||||
params.PushBack(Value(s.str().c_str(), allocator), allocator);
|
||||
|
||||
s.str(std::string());
|
||||
s << "0x";
|
||||
for (size_t i = 0; i < 32; ++i) {
|
||||
const uint32_t k = result.mixHash()[i];
|
||||
s << std::hex << std::setw(2) << std::setfill('0') << k;
|
||||
}
|
||||
params.PushBack(Value(s.str().c_str(), allocator), allocator);
|
||||
}
|
||||
params.PushBack(Value(s.str().c_str(), allocator), allocator);
|
||||
|
||||
JsonRequest::create(doc, m_sequence, "mining.submit", params);
|
||||
|
||||
uint64_t actual_diff = ethash_swap_u64(*((uint64_t*)result.result()));
|
||||
uint64_t actual_diff;
|
||||
|
||||
# ifdef XMRIG_ALGO_GHOSTRIDER
|
||||
if (result.algorithm == Algorithm::GHOSTRIDER_RTM) {
|
||||
actual_diff = reinterpret_cast<const uint64_t*>(result.result())[3];
|
||||
}
|
||||
else
|
||||
# endif
|
||||
{
|
||||
actual_diff = ethash_swap_u64(*((uint64_t*)result.result()));
|
||||
}
|
||||
|
||||
actual_diff = actual_diff ? (uint64_t(-1) / actual_diff) : 0;
|
||||
|
||||
# ifdef XMRIG_PROXY_PROJECT
|
||||
|
@ -161,6 +195,33 @@ void xmrig::EthStratumClient::parseNotification(const char *method, const rapidj
|
|||
setExtraNonce(arr[0]);
|
||||
}
|
||||
|
||||
# ifdef XMRIG_ALGO_GHOSTRIDER
|
||||
if (strcmp(method, "mining.set_difficulty") == 0) {
|
||||
if (!params.IsArray()) {
|
||||
LOG_ERR("%s " RED("invalid mining.set_difficulty notification: params is not an array"), tag());
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_pool.algorithm().id() != Algorithm::GHOSTRIDER_RTM) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto arr = params.GetArray();
|
||||
|
||||
if (arr.Empty()) {
|
||||
LOG_ERR("%s " RED("invalid mining.set_difficulty notification: params array is empty"), tag());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!arr[0].IsDouble()) {
|
||||
LOG_ERR("%s " RED("invalid mining.set_difficulty notification: difficulty is not a number"), tag());
|
||||
return;
|
||||
}
|
||||
|
||||
m_nextDifficulty = static_cast<uint64_t>(ceil(arr[0].GetDouble() * 65536.0));
|
||||
}
|
||||
# endif
|
||||
|
||||
if (strcmp(method, "mining.notify") == 0) {
|
||||
if (!params.IsArray()) {
|
||||
LOG_ERR("%s " RED("invalid mining.notify notification: params is not an array"), tag());
|
||||
|
@ -169,44 +230,152 @@ void xmrig::EthStratumClient::parseNotification(const char *method, const rapidj
|
|||
|
||||
auto arr = params.GetArray();
|
||||
|
||||
if (arr.Size() < 6) {
|
||||
auto algo = m_pool.algorithm();
|
||||
if (!algo.isValid()) {
|
||||
algo = m_pool.coin().algorithm();
|
||||
}
|
||||
|
||||
const size_t min_arr_size = (algo.id() == Algorithm::GHOSTRIDER_RTM) ? 8 : 6;
|
||||
|
||||
if (arr.Size() < min_arr_size) {
|
||||
LOG_ERR("%s " RED("invalid mining.notify notification: params array has wrong size"), tag());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!arr[0].IsString()) {
|
||||
LOG_ERR("%s " RED("invalid mining.notify notification: invalid job id"), tag());
|
||||
return;
|
||||
}
|
||||
|
||||
Job job;
|
||||
job.setId(arr[0].GetString());
|
||||
|
||||
auto algo = m_pool.algorithm();
|
||||
if (!algo.isValid()) {
|
||||
algo = m_pool.coin().algorithm();
|
||||
}
|
||||
|
||||
job.setAlgorithm(algo);
|
||||
job.setExtraNonce(m_extraNonce.second);
|
||||
|
||||
std::stringstream s;
|
||||
|
||||
// header hash (32 bytes)
|
||||
s << arr[1].GetString();
|
||||
# ifdef XMRIG_ALGO_GHOSTRIDER
|
||||
if (algo.id() == Algorithm::GHOSTRIDER_RTM) {
|
||||
// Raptoreum uses Bitcoin's Stratum protocol
|
||||
// https://en.bitcoinwiki.org/wiki/Stratum_mining_protocol#mining.notify
|
||||
|
||||
// nonce template (8 bytes)
|
||||
for (uint64_t i = 0, k = m_extraNonce.first; i < sizeof(m_extraNonce.first); ++i, k >>= 8) {
|
||||
s << std::hex << std::setw(2) << std::setfill('0') << (k & 0xFF);
|
||||
if (!arr[1].IsString() || !arr[2].IsString() || !arr[3].IsString() || !arr[4].IsArray() || !arr[5].IsString() || !arr[6].IsString() || !arr[7].IsString()) {
|
||||
LOG_ERR("%s " RED("invalid mining.notify notification: invalid param array"), tag());
|
||||
return;
|
||||
}
|
||||
|
||||
// Version
|
||||
s << arr[5].GetString();
|
||||
|
||||
// Previous block hash
|
||||
s << arr[1].GetString();
|
||||
|
||||
// Merkle tree root
|
||||
std::string blob = arr[2].GetString();
|
||||
blob += m_extraNonce.second;
|
||||
blob.append(m_extraNonce2Size * 2, '0');
|
||||
blob += arr[3].GetString();
|
||||
|
||||
uint8_t merkle_root[64];
|
||||
|
||||
Buffer buf = Cvt::fromHex(blob.c_str(), blob.length());
|
||||
|
||||
// Get height from coinbase
|
||||
{
|
||||
uint8_t* p = buf.data() + 32;
|
||||
uint8_t* m = p + 128;
|
||||
|
||||
while ((p < m) && (*p != 0xff)) ++p;
|
||||
while ((p < m) && (*p == 0xff)) ++p;
|
||||
|
||||
if ((p < m) && (*(p - 1) == 0xff) && (*(p - 2) == 0xff)) {
|
||||
uint32_t height = *reinterpret_cast<uint16_t*>(p + 2);
|
||||
switch (*(p + 1)) {
|
||||
case 4:
|
||||
height += *reinterpret_cast<uint16_t*>(p + 4) * 0x10000UL;
|
||||
break;
|
||||
case 3:
|
||||
height += *(p + 4) * 0x10000UL;
|
||||
break;
|
||||
}
|
||||
job.setHeight(height);
|
||||
}
|
||||
else {
|
||||
job.setHeight(0);
|
||||
}
|
||||
}
|
||||
|
||||
sha256d(merkle_root, buf.data(), static_cast<int>(buf.size()));
|
||||
|
||||
auto merkle_branches = arr[4].GetArray();
|
||||
for (int i = 0, n = merkle_branches.Size(); i < n; ++i) {
|
||||
auto& b = merkle_branches[i];
|
||||
buf = b.IsString() ? Cvt::fromHex(b.GetString(), b.GetStringLength()) : Buffer();
|
||||
if (buf.size() != 32) {
|
||||
LOG_ERR("%s " RED("invalid mining.notify notification: param 4 is invalid"), tag());
|
||||
return;
|
||||
}
|
||||
memcpy(merkle_root + 32, buf.data(), 32);
|
||||
sha256d(merkle_root, merkle_root, 64);
|
||||
}
|
||||
|
||||
s << Cvt::toHex(merkle_root, 32);
|
||||
|
||||
// ntime
|
||||
m_ntime = arr[7].GetString();
|
||||
s << m_ntime;
|
||||
|
||||
// nbits
|
||||
s << arr[6].GetString();
|
||||
|
||||
blob = s.str();
|
||||
|
||||
if (blob.size() != 76 * 2) {
|
||||
LOG_ERR("%s " RED("invalid mining.notify notification: invalid blob size"), tag());
|
||||
return;
|
||||
}
|
||||
|
||||
// zeros up to 80 bytes
|
||||
blob.resize(80 * 2, '0');
|
||||
|
||||
// Invert byte order (no idea why, but it's done in Bitcoin's Stratum)
|
||||
buf = Cvt::fromHex(blob.c_str(), blob.length());
|
||||
for (size_t i = 0; i < 80; i += sizeof(uint32_t)) {
|
||||
uint32_t& k = *reinterpret_cast<uint32_t*>(buf.data() + i);
|
||||
if ((i < 36) || (i >= 68)) {
|
||||
k = ethash_swap_u32(k);
|
||||
}
|
||||
}
|
||||
blob = Cvt::toHex(buf.data(), buf.size());
|
||||
|
||||
job.setBlob(blob.c_str());
|
||||
job.setDiff(m_nextDifficulty);
|
||||
}
|
||||
else
|
||||
# endif
|
||||
{
|
||||
// header hash (32 bytes)
|
||||
s << arr[1].GetString();
|
||||
|
||||
std::string blob = s.str();
|
||||
// nonce template (8 bytes)
|
||||
for (uint64_t i = 0, k = m_extraNonce.first; i < sizeof(m_extraNonce.first); ++i, k >>= 8) {
|
||||
s << std::hex << std::setw(2) << std::setfill('0') << (k & 0xFF);
|
||||
}
|
||||
|
||||
// zeros up to 76 bytes
|
||||
blob.resize(76 * 2, '0');
|
||||
job.setBlob(blob.c_str());
|
||||
std::string blob = s.str();
|
||||
|
||||
std::string target_str = arr[3].GetString();
|
||||
target_str.resize(16, '0');
|
||||
const uint64_t target = strtoull(target_str.c_str(), nullptr, 16);
|
||||
job.setDiff(Job::toDiff(target));
|
||||
// zeros up to 76 bytes
|
||||
blob.resize(76 * 2, '0');
|
||||
job.setBlob(blob.c_str());
|
||||
|
||||
job.setHeight(arr[5].GetUint64());
|
||||
std::string target_str = arr[3].GetString();
|
||||
target_str.resize(16, '0');
|
||||
const uint64_t target = strtoull(target_str.c_str(), nullptr, 16);
|
||||
job.setDiff(Job::toDiff(target));
|
||||
|
||||
job.setHeight(arr[5].GetUint64());
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
m_listener->onVerifyAlgorithm(this, algo, &ok);
|
||||
|
@ -356,11 +525,19 @@ void xmrig::EthStratumClient::onSubscribeResponse(const rapidjson::Value &result
|
|||
throw std::runtime_error("invalid mining.subscribe response: result is not an array");
|
||||
}
|
||||
|
||||
if (result.GetArray().Size() <= 1) {
|
||||
auto arr = result.GetArray();
|
||||
|
||||
if (arr.Size() <= 1) {
|
||||
throw std::runtime_error("invalid mining.subscribe response: result array is too short");
|
||||
}
|
||||
|
||||
setExtraNonce(result.GetArray()[1]);
|
||||
setExtraNonce(arr[1]);
|
||||
|
||||
# ifdef XMRIG_ALGO_GHOSTRIDER
|
||||
if ((arr.Size() > 2) && (arr[2].IsUint())) {
|
||||
m_extraNonce2Size = arr[2].GetUint();
|
||||
}
|
||||
# endif
|
||||
|
||||
if (m_pool.isNicehash()) {
|
||||
using namespace rapidjson;
|
||||
|
|
|
@ -57,6 +57,12 @@ private:
|
|||
|
||||
bool m_authorized = false;
|
||||
std::pair<uint64_t, String> m_extraNonce{};
|
||||
|
||||
# ifdef XMRIG_ALGO_GHOSTRIDER
|
||||
uint64_t m_extraNonce2Size = 0;
|
||||
uint64_t m_nextDifficulty = 0;
|
||||
String m_ntime;
|
||||
# endif
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ public:
|
|||
inline const String &poolWallet() const { return m_poolWallet; }
|
||||
inline const uint32_t *nonce() const { return reinterpret_cast<const uint32_t*>(m_blob + nonceOffset()); }
|
||||
inline const uint8_t *blob() const { return m_blob; }
|
||||
inline int32_t nonceOffset() const { return (algorithm().family() == Algorithm::KAWPOW) ? 32 : 39; }
|
||||
inline int32_t nonceOffset() const { auto f = algorithm().family(); return (f == Algorithm::KAWPOW) ? 32 : ((f == Algorithm::GHOSTRIDER) ? 76 : 39); }
|
||||
inline size_t nonceSize() const { return (algorithm().family() == Algorithm::KAWPOW) ? 8 : 4; }
|
||||
inline size_t size() const { return m_size; }
|
||||
inline uint32_t *nonce() { return reinterpret_cast<uint32_t*>(m_blob + nonceOffset()); }
|
||||
|
|
|
@ -219,7 +219,8 @@ xmrig::IClient *xmrig::Pool::createClient(int id, IClientListener *listener) con
|
|||
|
||||
if (m_mode == MODE_POOL) {
|
||||
# ifdef XMRIG_ALGO_KAWPOW
|
||||
if ((m_algorithm.family() == Algorithm::KAWPOW) || (m_coin == Coin::RAVEN)) {
|
||||
const uint32_t f = m_algorithm.family();
|
||||
if ((f == Algorithm::KAWPOW) || (f == Algorithm::GHOSTRIDER) || (m_coin == Coin::RAVEN)) {
|
||||
client = new EthStratumClient(id, Platform::userAgent(), listener);
|
||||
}
|
||||
else
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue