KawPow WIP

This commit is contained in:
SChernykh 2020-05-24 23:57:41 +02:00
parent 07025dc41b
commit 22b937cc1c
88 changed files with 11004 additions and 8383 deletions

View file

@ -3,6 +3,7 @@ set(HEADERS_BASE
src/base/crypto/Algorithm.h
src/base/crypto/Coin.h
src/base/crypto/keccak.h
src/base/crypto/sha3.h
src/base/io/Console.h
src/base/io/Env.h
src/base/io/json/Json.h
@ -41,6 +42,7 @@ set(HEADERS_BASE
src/base/net/http/HttpListener.h
src/base/net/stratum/BaseClient.h
src/base/net/stratum/Client.h
src/base/net/stratum/EthStratumClient.h
src/base/net/stratum/Job.h
src/base/net/stratum/NetworkState.h
src/base/net/stratum/Pool.h
@ -69,6 +71,7 @@ set(SOURCES_BASE
src/base/crypto/Algorithm.cpp
src/base/crypto/Coin.cpp
src/base/crypto/keccak.cpp
src/base/crypto/sha3.cpp
src/base/io/Console.cpp
src/base/io/Env.cpp
src/base/io/json/Json.cpp
@ -91,6 +94,7 @@ set(SOURCES_BASE
src/base/net/http/Http.cpp
src/base/net/stratum/BaseClient.cpp
src/base/net/stratum/Client.cpp
src/base/net/stratum/EthStratumClient.cpp
src/base/net/stratum/Job.cpp
src/base/net/stratum/NetworkState.cpp
src/base/net/stratum/Pool.cpp

View file

@ -70,10 +70,6 @@ static AlgoName const algorithm_names[] = {
{ "cryptonight/rwz", "cn/rwz", Algorithm::CN_RWZ },
{ "cryptonight/zls", "cn/zls", Algorithm::CN_ZLS },
{ "cryptonight/double", "cn/double", Algorithm::CN_DOUBLE },
# ifdef XMRIG_ALGO_CN_GPU
{ "cryptonight/gpu", "cn/gpu", Algorithm::CN_GPU },
{ "cryptonight_gpu", nullptr, Algorithm::CN_GPU },
# endif
# ifdef XMRIG_ALGO_CN_LITE
{ "cryptonight-lite/0", "cn-lite/0", Algorithm::CN_LITE_0 },
{ "cryptonight-lite/1", "cn-lite/1", Algorithm::CN_LITE_1 },
@ -127,6 +123,10 @@ static AlgoName const algorithm_names[] = {
{ "astrobwt", nullptr, Algorithm::ASTROBWT_DERO },
{ "astrobwt/dero", nullptr, Algorithm::ASTROBWT_DERO },
# endif
# ifdef XMRIG_ALGO_KAWPOW
{ "kawpow", nullptr, Algorithm::KAWPOW_RVN },
{ "kawpow/rvn", nullptr, Algorithm::KAWPOW_RVN },
# endif
};
@ -238,6 +238,18 @@ size_t xmrig::Algorithm::l3() const
}
# endif
# ifdef XMRIG_ALGO_KAWPOW
if (f == KAWPOW) {
switch (m_id) {
case KAWPOW_RVN:
return 32768;
default:
break;
}
}
# endif
return 0;
}
@ -262,12 +274,6 @@ uint32_t xmrig::Algorithm::maxIntensity() const
}
# endif
# ifdef XMRIG_ALGO_CN_GPU
if (m_id == CN_GPU) {
return 1;
}
# endif
return 5;
}
@ -286,9 +292,6 @@ xmrig::Algorithm::Family xmrig::Algorithm::family(Id id)
case CN_RWZ:
case CN_ZLS:
case CN_DOUBLE:
# ifdef XMRIG_ALGO_CN_GPU
case CN_GPU:
# endif
return CN;
# ifdef XMRIG_ALGO_CN_LITE
@ -331,6 +334,11 @@ xmrig::Algorithm::Family xmrig::Algorithm::family(Id id)
return ASTROBWT;
# endif
# ifdef XMRIG_ALGO_KAWPOW
case KAWPOW_RVN:
return KAWPOW;
# endif
default:
break;
}

View file

@ -56,7 +56,6 @@ public:
CN_RWZ, // "cn/rwz" CryptoNight variant 2 with 3/4 iterations and reversed shuffle operation (Graft).
CN_ZLS, // "cn/zls" CryptoNight variant 2 with 3/4 iterations (Zelerius).
CN_DOUBLE, // "cn/double" CryptoNight variant 2 with double iterations (X-CASH).
CN_GPU, // "cn/gpu" CryptoNight-GPU (Ryo).
CN_LITE_0, // "cn-lite/0" CryptoNight-Lite variant 0.
CN_LITE_1, // "cn-lite/1" CryptoNight-Lite variant 1.
CN_HEAVY_0, // "cn-heavy/0" CryptoNight-Heavy (4 MB).
@ -73,6 +72,7 @@ public:
AR2_CHUKWA, // "argon2/chukwa" Argon2id (Chukwa).
AR2_WRKZ, // "argon2/wrkz" Argon2id (WRKZ)
ASTROBWT_DERO, // "astrobwt" AstroBWT (Dero)
KAWPOW_RVN, // "kawpow/rvn" KawPow (RVN)
MAX
};
@ -84,7 +84,8 @@ public:
CN_PICO,
RANDOM_X,
ARGON2,
ASTROBWT
ASTROBWT,
KAWPOW
};
inline Algorithm() = default;

View file

@ -52,7 +52,10 @@ static CoinName const coin_names[] = {
{ "arqma", Coin::ARQMA },
{ "arq", Coin::ARQMA },
{ "dero", Coin::DERO },
{ "keva", Coin::KEVA }
{ "keva", Coin::KEVA },
{ "ravencoin", Coin::RAVEN },
{ "raven", Coin::RAVEN },
{ "rvn", Coin::RAVEN }
};
@ -75,6 +78,9 @@ xmrig::Algorithm::Id xmrig::Coin::algorithm(uint8_t blobVersion) const
case KEVA:
return (blobVersion >= 11) ? Algorithm::RX_KEVA : Algorithm::CN_R;
case RAVEN:
return Algorithm::KAWPOW_RVN;
case INVALID:
break;
}

View file

@ -42,7 +42,8 @@ public:
MONERO,
ARQMA,
DERO,
KEVA
KEVA,
RAVEN
};

258
src/base/crypto/sha3.cpp Normal file
View file

@ -0,0 +1,258 @@
/* -------------------------------------------------------------------------
* Works when compiled for either 32-bit or 64-bit targets, optimized for
* 64 bit.
*
* Canonical implementation of Init/Update/Finalize for SHA-3 byte input.
*
* SHA3-256, SHA3-384, SHA-512 are implemented. SHA-224 can easily be added.
*
* Based on code from http://keccak.noekeon.org/ .
*
* I place the code that I wrote into public domain, free to use.
*
* I would appreciate if you give credits to this work if you used it to
* write or test * your code.
*
* Aug 2015. Andrey Jivsov. crypto@brainhub.org
* ---------------------------------------------------------------------- */
#include <cstdio>
#include <cstdint>
#include <cstring>
#include "sha3.h"
#include "base/crypto/keccak.h"
#define SHA3_ASSERT( x )
#if defined(_MSC_VER)
#define SHA3_TRACE( format, ...)
#define SHA3_TRACE_BUF( format, buf, l, ...)
#else
#define SHA3_TRACE(format, args...)
#define SHA3_TRACE_BUF(format, buf, l, args...)
#endif
/*
* This flag is used to configure "pure" Keccak, as opposed to NIST SHA3.
*/
#define SHA3_USE_KECCAK_FLAG 0x80000000
#define SHA3_CW(x) ((x) & (~SHA3_USE_KECCAK_FLAG))
#if defined(_MSC_VER)
#define SHA3_CONST(x) x
#else
#define SHA3_CONST(x) x##L
#endif
#define KECCAK_ROUNDS 24
/* *************************** Public Inteface ************************ */
/* For Init or Reset call these: */
sha3_return_t
sha3_Init(void *priv, unsigned bitSize) {
sha3_context *ctx = (sha3_context *) priv;
if( bitSize != 256 && bitSize != 384 && bitSize != 512 )
return SHA3_RETURN_BAD_PARAMS;
memset(ctx, 0, sizeof(*ctx));
ctx->capacityWords = 2 * bitSize / (8 * sizeof(uint64_t));
return SHA3_RETURN_OK;
}
void
sha3_Init256(void *priv)
{
sha3_Init(priv, 256);
}
void
sha3_Init384(void *priv)
{
sha3_Init(priv, 384);
}
void
sha3_Init512(void *priv)
{
sha3_Init(priv, 512);
}
SHA3_FLAGS
sha3_SetFlags(void *priv, SHA3_FLAGS flags)
{
sha3_context *ctx = (sha3_context *) priv;
flags = static_cast<SHA3_FLAGS>(static_cast<int>(flags) & SHA3_FLAGS_KECCAK);
ctx->capacityWords |= (flags == SHA3_FLAGS_KECCAK ? SHA3_USE_KECCAK_FLAG : 0);
return flags;
}
void
sha3_Update(void *priv, void const *bufIn, size_t len)
{
sha3_context *ctx = (sha3_context *) priv;
/* 0...7 -- how much is needed to have a word */
unsigned old_tail = (8 - ctx->byteIndex) & 7;
size_t words;
unsigned tail;
size_t i;
const uint8_t *buf = reinterpret_cast<const uint8_t*>(bufIn);
SHA3_TRACE_BUF("called to update with:", buf, len);
SHA3_ASSERT(ctx->byteIndex < 8);
SHA3_ASSERT(ctx->wordIndex < sizeof(ctx->s) / sizeof(ctx->s[0]));
if(len < old_tail) { /* have no complete word or haven't started
* the word yet */
SHA3_TRACE("because %d<%d, store it and return", (unsigned)len,
(unsigned)old_tail);
/* endian-independent code follows: */
while (len--)
ctx->saved |= (uint64_t) (*(buf++)) << ((ctx->byteIndex++) * 8);
SHA3_ASSERT(ctx->byteIndex < 8);
return;
}
if(old_tail) { /* will have one word to process */
SHA3_TRACE("completing one word with %d bytes", (unsigned)old_tail);
/* endian-independent code follows: */
len -= old_tail;
while (old_tail--)
ctx->saved |= (uint64_t) (*(buf++)) << ((ctx->byteIndex++) * 8);
/* now ready to add saved to the sponge */
ctx->s[ctx->wordIndex] ^= ctx->saved;
SHA3_ASSERT(ctx->byteIndex == 8);
ctx->byteIndex = 0;
ctx->saved = 0;
if(++ctx->wordIndex ==
(SHA3_KECCAK_SPONGE_WORDS - SHA3_CW(ctx->capacityWords))) {
xmrig::keccakf(ctx->s, KECCAK_ROUNDS);
ctx->wordIndex = 0;
}
}
/* now work in full words directly from input */
SHA3_ASSERT(ctx->byteIndex == 0);
words = len / sizeof(uint64_t);
tail = len - words * sizeof(uint64_t);
SHA3_TRACE("have %d full words to process", (unsigned)words);
for(i = 0; i < words; i++, buf += sizeof(uint64_t)) {
const uint64_t t = (uint64_t) (buf[0]) |
((uint64_t) (buf[1]) << 8 * 1) |
((uint64_t) (buf[2]) << 8 * 2) |
((uint64_t) (buf[3]) << 8 * 3) |
((uint64_t) (buf[4]) << 8 * 4) |
((uint64_t) (buf[5]) << 8 * 5) |
((uint64_t) (buf[6]) << 8 * 6) |
((uint64_t) (buf[7]) << 8 * 7);
#if defined(__x86_64__ ) || defined(__i386__)
SHA3_ASSERT(memcmp(&t, buf, 8) == 0);
#endif
ctx->s[ctx->wordIndex] ^= t;
if(++ctx->wordIndex ==
(SHA3_KECCAK_SPONGE_WORDS - SHA3_CW(ctx->capacityWords))) {
xmrig::keccakf(ctx->s, KECCAK_ROUNDS);
ctx->wordIndex = 0;
}
}
SHA3_TRACE("have %d bytes left to process, save them", (unsigned)tail);
/* finally, save the partial word */
SHA3_ASSERT(ctx->byteIndex == 0 && tail < 8);
while (tail--) {
SHA3_TRACE("Store byte %02x '%c'", *buf, *buf);
ctx->saved |= (uint64_t) (*(buf++)) << ((ctx->byteIndex++) * 8);
}
SHA3_ASSERT(ctx->byteIndex < 8);
SHA3_TRACE("Have saved=0x%016" PRIx64 " at the end", ctx->saved);
}
/* This is simply the 'update' with the padding block.
* The padding block is 0x01 || 0x00* || 0x80. First 0x01 and last 0x80
* bytes are always present, but they can be the same byte.
*/
void const *
sha3_Finalize(void *priv)
{
sha3_context *ctx = (sha3_context *) priv;
SHA3_TRACE("called with %d bytes in the buffer", ctx->byteIndex);
/* Append 2-bit suffix 01, per SHA-3 spec. Instead of 1 for padding we
* use 1<<2 below. The 0x02 below corresponds to the suffix 01.
* Overall, we feed 0, then 1, and finally 1 to start padding. Without
* M || 01, we would simply use 1 to start padding. */
uint64_t t;
if( ctx->capacityWords & SHA3_USE_KECCAK_FLAG ) {
/* Keccak version */
t = (uint64_t)(((uint64_t) 1) << (ctx->byteIndex * 8));
}
else {
/* SHA3 version */
t = (uint64_t)(((uint64_t)(0x02 | (1 << 2))) << ((ctx->byteIndex) * 8));
}
ctx->s[ctx->wordIndex] ^= ctx->saved ^ t;
ctx->s[SHA3_KECCAK_SPONGE_WORDS - SHA3_CW(ctx->capacityWords) - 1] ^=
SHA3_CONST(0x8000000000000000UL);
xmrig::keccakf(ctx->s, KECCAK_ROUNDS);
/* Return first bytes of the ctx->s. This conversion is not needed for
* little-endian platforms e.g. wrap with #if !defined(__BYTE_ORDER__)
* || !defined(__ORDER_LITTLE_ENDIAN__) || __BYTE_ORDER__!=__ORDER_LITTLE_ENDIAN__
* ... the conversion below ...
* #endif */
{
unsigned i;
for(i = 0; i < SHA3_KECCAK_SPONGE_WORDS; i++) {
const unsigned t1 = (uint32_t) ctx->s[i];
const unsigned t2 = (uint32_t) ((ctx->s[i] >> 16) >> 16);
ctx->sb[i * 8 + 0] = (uint8_t) (t1);
ctx->sb[i * 8 + 1] = (uint8_t) (t1 >> 8);
ctx->sb[i * 8 + 2] = (uint8_t) (t1 >> 16);
ctx->sb[i * 8 + 3] = (uint8_t) (t1 >> 24);
ctx->sb[i * 8 + 4] = (uint8_t) (t2);
ctx->sb[i * 8 + 5] = (uint8_t) (t2 >> 8);
ctx->sb[i * 8 + 6] = (uint8_t) (t2 >> 16);
ctx->sb[i * 8 + 7] = (uint8_t) (t2 >> 24);
}
}
SHA3_TRACE_BUF("Hash: (first 32 bytes)", ctx->sb, 256 / 8);
return (ctx->sb);
}
extern "C" sha3_return_t sha3_HashBuffer( unsigned bitSize, enum SHA3_FLAGS flags, const void *in, unsigned inBytes, void *out, unsigned outBytes ) {
sha3_return_t err;
sha3_context c;
err = sha3_Init(&c, bitSize);
if( err != SHA3_RETURN_OK )
return err;
if( sha3_SetFlags(&c, flags) != flags ) {
return SHA3_RETURN_BAD_PARAMS;
}
sha3_Update(&c, in, inBytes);
const void *h = sha3_Finalize(&c);
if(outBytes > bitSize/8)
outBytes = bitSize/8;
memcpy(out, h, outBytes);
return SHA3_RETURN_OK;
}

73
src/base/crypto/sha3.h Normal file
View file

@ -0,0 +1,73 @@
#ifndef SHA3_H
#define SHA3_H
/* -------------------------------------------------------------------------
* Works when compiled for either 32-bit or 64-bit targets, optimized for
* 64 bit.
*
* Canonical implementation of Init/Update/Finalize for SHA-3 byte input.
*
* SHA3-256, SHA3-384, SHA-512 are implemented. SHA-224 can easily be added.
*
* Based on code from http://keccak.noekeon.org/ .
*
* I place the code that I wrote into public domain, free to use.
*
* I would appreciate if you give credits to this work if you used it to
* write or test * your code.
*
* Aug 2015. Andrey Jivsov. crypto@brainhub.org
* ---------------------------------------------------------------------- */
/* 'Words' here refers to uint64_t */
#define SHA3_KECCAK_SPONGE_WORDS \
(((1600)/8/*bits to byte*/)/sizeof(uint64_t))
typedef struct sha3_context_ {
uint64_t saved; /* the portion of the input message that we
* didn't consume yet */
union { /* Keccak's state */
uint64_t s[SHA3_KECCAK_SPONGE_WORDS];
uint8_t sb[SHA3_KECCAK_SPONGE_WORDS * 8];
};
unsigned byteIndex; /* 0..7--the next byte after the set one
* (starts from 0; 0--none are buffered) */
unsigned wordIndex; /* 0..24--the next word to integrate input
* (starts from 0) */
unsigned capacityWords; /* the double size of the hash output in
* words (e.g. 16 for Keccak 512) */
} sha3_context;
enum SHA3_FLAGS {
SHA3_FLAGS_NONE=0,
SHA3_FLAGS_KECCAK=1
};
enum SHA3_RETURN {
SHA3_RETURN_OK=0,
SHA3_RETURN_BAD_PARAMS=1
};
typedef enum SHA3_RETURN sha3_return_t;
/* For Init or Reset call these: */
sha3_return_t sha3_Init(void *priv, unsigned bitSize);
void sha3_Init256(void *priv);
void sha3_Init384(void *priv);
void sha3_Init512(void *priv);
enum SHA3_FLAGS sha3_SetFlags(void *priv, enum SHA3_FLAGS);
void sha3_Update(void *priv, void const *bufIn, size_t len);
void const *sha3_Finalize(void *priv);
/* Single-call hashing */
#ifdef __cplusplus
extern "C"
#endif
sha3_return_t sha3_HashBuffer(
unsigned bitSize, /* 256, 384, 512 */
enum SHA3_FLAGS flags, /* SHA3_FLAGS_NONE or SHA3_FLAGS_KECCAK */
const void *in, unsigned inBytes,
void *out, unsigned outBytes ); /* up to bitSize/8; truncation OK */
#endif

View file

@ -83,7 +83,7 @@ protected:
inline bool isQuiet() const { return m_quiet || m_failures >= m_retries; }
bool handleResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error);
virtual bool handleResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error);
bool handleSubmitResponse(int64_t id, const char *error = nullptr);
bool m_quiet = false;

View file

@ -85,11 +85,19 @@ protected:
inline const char *mode() const override { return "pool"; }
inline void onLine(char *line, size_t size) override { parse(line, size); }
inline const char* agent() const { return m_agent; }
inline const char* url() const { return m_pool.url(); }
virtual void login();
virtual void parseNotification(const char* method, const rapidjson::Value& params, const rapidjson::Value& error);
bool close();
virtual void onClose();
private:
class Socks5;
class Tls;
bool close();
bool isCriticalError(const char *message);
bool parseJob(const rapidjson::Value &params, int *code);
bool parseLogin(const rapidjson::Value &result, int *code);
@ -100,11 +108,8 @@ private:
int64_t send(size_t size);
void connect(sockaddr *addr);
void handshake();
void login();
void onClose();
void parse(char *line, size_t len);
void parseExtensions(const rapidjson::Value &result);
void parseNotification(const char *method, const rapidjson::Value &params, const rapidjson::Value &error);
void parseResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error);
void ping();
void read(ssize_t nread, const uv_buf_t *buf);
@ -112,7 +117,6 @@ private:
void setState(SocketState state);
void startTimeout();
inline const char *url() const { return m_pool.url(); }
inline SocketState state() const { return m_state; }
inline uv_stream_t *stream() const { return reinterpret_cast<uv_stream_t *>(m_socket); }
inline void setExtension(Extension ext, bool enable) noexcept { m_extensions.set(ext, enable); }

View file

@ -0,0 +1,353 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 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>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cinttypes>
#include <sstream>
#include <iomanip>
#include "3rdparty/libethash/endian.h"
#include "3rdparty/rapidjson/document.h"
#include "3rdparty/rapidjson/error/en.h"
#include "3rdparty/rapidjson/stringbuffer.h"
#include "3rdparty/rapidjson/writer.h"
#include "base/io/json/Json.h"
#include "base/io/json/JsonRequest.h"
#include "base/io/log/Log.h"
#include "base/kernel/interfaces/IClientListener.h"
#include "base/net/stratum/EthStratumClient.h"
#include "net/JobResult.h"
namespace xmrig {
EthStratumClient::EthStratumClient(int id, const char *agent, IClientListener *listener) :
Client(id, agent, listener)
{
}
void EthStratumClient::login()
{
using namespace rapidjson;
m_results.clear();
Document doc(kObjectType);
auto& allocator = doc.GetAllocator();
Value params(kArrayType);
params.PushBack(StringRef(agent()), allocator);
JsonRequest::create(doc, m_sequence, "mining.subscribe", params);
send(doc, [this](const rapidjson::Value& result, bool success, uint64_t elapsed) { OnSubscribeResponse(result, success, elapsed); });
}
void EthStratumClient::onClose()
{
m_authorized = false;
Client::onClose();
}
int64_t EthStratumClient::submit(const JobResult& result)
{
# ifndef XMRIG_PROXY_PROJECT
if ((m_state != ConnectedState) || !m_authorized) {
return -1;
}
# endif
if (result.diff == 0) {
disconnect();
return -1;
}
using namespace rapidjson;
Document doc(kObjectType);
auto& allocator = doc.GetAllocator();
Value params(kArrayType);
params.PushBack(StringRef(m_pool.user().data()), allocator);
params.PushBack(StringRef(result.jobId.data()), allocator);
std::stringstream s;
s << "0x" << std::hex << std::setw(16) << std::setfill('0') << result.nonce;
params.PushBack(rapidjson::Value(s.str().c_str(), allocator), allocator);
s.str(std::string());
s << "0x";
for (size_t i = 0; i < 32; ++i) {
const uint32_t k = result.headerHash()[i];
s << std::hex << std::setw(2) << std::setfill('0') << k;
}
params.PushBack(rapidjson::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(rapidjson::Value(s.str().c_str(), allocator), allocator);
JsonRequest::create(doc, m_sequence, "mining.submit", params);
uint64_t actual_diff = ethash_swap_u64(*((uint64_t*)result.result()));
actual_diff = actual_diff ? (uint64_t(-1) / actual_diff) : 0;
# ifdef XMRIG_PROXY_PROJECT
m_results[m_sequence] = SubmitResult(m_sequence, result.diff, actual_diff, result.id, 0);
# else
m_results[m_sequence] = SubmitResult(m_sequence, result.diff, actual_diff, 0, result.backend);
# endif
return send(doc);
}
bool EthStratumClient::handleResponse(int64_t id, const rapidjson::Value& result, const rapidjson::Value& error)
{
auto it = m_callbacks.find(id);
if (it != m_callbacks.end()) {
const uint64_t elapsed = Chrono::steadyMSecs() - it->second.ts;
if (error.IsObject()) {
it->second.callback(error, false, elapsed);
}
else {
it->second.callback(result, true, elapsed);
}
m_callbacks.erase(it);
return true;
}
const char* err = nullptr;
if (error.IsArray() && error.GetArray().Size() > 1) {
auto& value = error.GetArray()[1];
if (value.IsString()) {
err = value.GetString();
}
}
handleSubmitResponse(id, err);
return false;
}
void EthStratumClient::parseNotification(const char* method, const rapidjson::Value& params, const rapidjson::Value& error)
{
if (error.IsObject()) {
if (!isQuiet()) {
LOG_ERR("[%s] error: \"%s\", code: %d", url(), error["message"].GetString(), error["code"].GetInt());
}
return;
}
if (!method) {
return;
}
if (strcmp(method, "mining.set_target") == 0) {
if (!params.IsArray()) {
LOG_ERR("Invalid mining.set_target notification: params is not an array");
return;
}
if (params.GetArray().Size() != 1) {
LOG_ERR("Invalid mining.set_target notification: params array has wrong size");
return;
}
auto& new_target = params.GetArray()[0];
if (!new_target.IsString()) {
LOG_ERR("Invalid mining.set_target notification: target is not a string");
return;
}
std::string new_target_str = new_target.GetString();
new_target_str.resize(16, '0');
m_target = std::stoull(new_target_str, nullptr, 16);
LOG_DEBUG("Target set to %016" PRIX64, m_target);
return;
}
if (strcmp(method, "mining.notify") == 0) {
if (!params.IsArray()) {
LOG_ERR("Invalid mining.notify notification: params is not an array");
return;
}
auto arr = params.GetArray();
if (arr.Size() < 6) {
LOG_ERR("Invalid mining.notify notification: params array has wrong size");
return;
}
Job job;
job.setId(arr[0].GetString());
Algorithm algo = m_pool.algorithm();
if (algo == Algorithm::INVALID) {
algo = m_pool.coin().algorithm(0);
}
job.setAlgorithm(algo);
std::stringstream s;
// header hash (32 bytes)
s << arr[1].GetString();
// nonce template (8 bytes)
for (uint64_t i = 0, k = m_extraNonce; i < sizeof(m_extraNonce); ++i, k >>= 8) {
s << std::hex << std::setw(2) << std::setfill('0') << (k & 0xFF);
}
std::string blob = s.str();
// zeros up to 76 bytes
blob.resize(76 * 2, '0');
job.setBlob(blob.c_str());
std::string target_str = arr[3].GetString();
target_str.resize(16, '0');
const uint64_t target = strtoull(target_str.c_str(), nullptr, 16);
job.setDiff(job.toDiff(target));
job.setHeight(arr[5].GetUint64());
m_listener->onJobReceived(this, job, params);
}
}
bool EthStratumClient::disconnect()
{
m_authorized = false;
return Client::disconnect();
}
void EthStratumClient::OnSubscribeResponse(const rapidjson::Value& result, bool success, uint64_t elapsed)
{
if (!success) {
return;
}
if (!result.IsArray()) {
LOG_ERR("Invalid mining.subscribe response: result is not an array");
return;
}
if (result.GetArray().Size() <= 1) {
LOG_ERR("Invalid mining.subscribe response: result array is too short");
return;
}
auto& extra_nonce = result.GetArray()[1];
if (!extra_nonce.IsString()) {
LOG_ERR("Invalid mining.subscribe response: extra nonce is not a string");
return;
}
const char* s = extra_nonce.GetString();
size_t len = extra_nonce.GetStringLength();
// Skip "0x"
if ((len >= 2) && (s[0] == '0') && (s[1] == 'x')) {
s += 2;
len -= 2;
}
if (len & 1) {
LOG_ERR("Invalid mining.subscribe response: extra nonce has an odd number of hex chars");
return;
}
if (len > 8) {
LOG_ERR("Invalid mining.subscribe response: extra nonce is too long");
return;
}
std::string extra_nonce_str(s);
extra_nonce_str.resize(16, '0');
m_extraNonce = std::stoull(extra_nonce_str, nullptr, 16);
LOG_DEBUG("Extra nonce set to %s", s);
using namespace rapidjson;
Document doc(kObjectType);
auto& allocator = doc.GetAllocator();
Value params(kArrayType);
const char* user = m_pool.user().data();
const char* pass = m_pool.password().data();
params.PushBack(StringRef(user), allocator);
params.PushBack(StringRef(pass), allocator);
JsonRequest::create(doc, m_sequence, "mining.authorize", params);
send(doc, [this](const rapidjson::Value& result, bool success, uint64_t elapsed) { OnAuthorizeResponse(result, success, elapsed); });
}
void EthStratumClient::OnAuthorizeResponse(const rapidjson::Value& result, bool success, uint64_t elapsed)
{
if (!success) {
disconnect();
return;
}
if (!result.IsBool()) {
LOG_ERR("Invalid mining.authorize response: result is not a boolean");
disconnect();
return;
}
if (!result.GetBool()) {
LOG_ERR("Login failed");
disconnect();
return;
}
LOG_DEBUG("Login succeeded");
m_authorized = true;
}
}

View file

@ -0,0 +1,71 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 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>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef XMRIG_ETHSTRATUMCLIENT_H
#define XMRIG_ETHSTRATUMCLIENT_H
#include "base/net/stratum/Client.h"
namespace xmrig {
class IClientListener;
class EthStratumClient : public Client
{
public:
XMRIG_DISABLE_COPY_MOVE_DEFAULT(EthStratumClient)
EthStratumClient(int id, const char *agent, IClientListener *listener);
void login() override;
void onClose() override;
protected:
int64_t submit(const JobResult& result) override;
bool handleResponse(int64_t id, const rapidjson::Value& result, const rapidjson::Value& error) override;
void parseNotification(const char* method, const rapidjson::Value& params, const rapidjson::Value& error) override;
bool disconnect() override;
private:
void OnSubscribeResponse(const rapidjson::Value& result, bool success, uint64_t elapsed);
void OnAuthorizeResponse(const rapidjson::Value& result, bool success, uint64_t elapsed);
bool m_authorized = false;
uint64_t m_target = 0;
uint64_t m_extraNonce = 0;
};
} /* namespace xmrig */
#endif /* XMRIG_ETHSTRATUMCLIENT_H */

View file

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

View file

@ -37,6 +37,7 @@
#include "base/io/log/Log.h"
#include "base/kernel/Platform.h"
#include "base/net/stratum/Client.h"
#include "base/net/stratum/EthStratumClient.h"
#ifdef XMRIG_FEATURE_HTTP
@ -185,7 +186,12 @@ xmrig::IClient *xmrig::Pool::createClient(int id, IClientListener *listener) con
IClient *client = nullptr;
if (m_mode == MODE_POOL) {
client = new Client(id, Platform::userAgent(), listener);
if ((m_algorithm.family() == Algorithm::KAWPOW) || (m_coin == Coin::RAVEN)) {
client = new EthStratumClient(id, Platform::userAgent(), listener);
}
else {
client = new Client(id, Platform::userAgent(), listener);
}
}
# ifdef XMRIG_FEATURE_HTTP
else if (m_mode == MODE_DAEMON) {