mirror of
https://github.com/xmrig/xmrig.git
synced 2025-01-11 05:14:40 +00:00
Merge branch 'evo' into beta
This commit is contained in:
commit
f6d58c7d46
56 changed files with 1160 additions and 440 deletions
|
@ -1,3 +1,12 @@
|
|||
# v4.4.0-beta
|
||||
- [#1068](https://github.com/xmrig/xmrig/pull/1068) Added support for `self-select` stratum protocol extension.
|
||||
- [#1240](https://github.com/xmrig/xmrig/pull/1240) Sync with latest RandomX code.
|
||||
- [#1241](https://github.com/xmrig/xmrig/issues/1241) Fixed regression with colors on old Windows systems.
|
||||
- [#1243](https://github.com/xmrig/xmrig/pull/1243) Fixed incorrect OpenCL memory size detection in some cases.
|
||||
- [#1247](https://github.com/xmrig/xmrig/pull/1247) Fixed ARM64 RandomX code alignment.
|
||||
- [#1248](https://github.com/xmrig/xmrig/pull/1248) Fixed RandomX code cache cleanup on iOS/Darwin.
|
||||
|
||||
|
||||
# v4.3.1-beta
|
||||
- Fixed regression in v4.3.0, miner didn't create `cn` mining profile with default config example.
|
||||
|
||||
|
|
|
@ -9,9 +9,7 @@
|
|||
[![GitHub stars](https://img.shields.io/github/stars/xmrig/xmrig.svg)](https://github.com/xmrig/xmrig/stargazers)
|
||||
[![GitHub forks](https://img.shields.io/github/forks/xmrig/xmrig.svg)](https://github.com/xmrig/xmrig/network)
|
||||
|
||||
XMRig is a high performance RandomX and CryptoNight CPU miner, with official support for Windows.
|
||||
|
||||
* This is the **CPU-mining** version, there is also a [NVIDIA GPU version](https://github.com/xmrig/xmrig-nvidia) and [AMD GPU version]( https://github.com/xmrig/xmrig-amd).
|
||||
XMRig High performance, open source, cross platform RandomX, CryptoNight and Argon2 CPU/GPU miner, with official support for Windows
|
||||
|
||||
<img src="doc/screenshot.png" width="808" >
|
||||
|
||||
|
@ -30,6 +28,8 @@ XMRig is a high performance RandomX and CryptoNight CPU miner, with official sup
|
|||
## Usage
|
||||
The preferred way to configure the miner is the [JSON config file](src/config.json) as it is more flexible and human friendly. The command line interface does not cover all features, such as mining profiles for different algorithms. Important options can be changed during runtime without miner restart by editing the config file or executing API calls.
|
||||
|
||||
* **[xmrig.com/wizard](https://xmrig.com/wizard)** helps you create initial configuration for the miner.
|
||||
|
||||
### Command line options
|
||||
```
|
||||
Network:
|
||||
|
|
|
@ -54,6 +54,8 @@ if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
|||
|
||||
#set(CMAKE_C_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -gdwarf-2")
|
||||
|
||||
add_definitions(/DHAVE_BUILTIN_CLEAR_CACHE)
|
||||
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
|
||||
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Ox /Ot /Oi /MT /GL")
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
*/
|
||||
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <cinttypes>
|
||||
#include <cstdio>
|
||||
#include <uv.h>
|
||||
|
||||
|
||||
|
@ -59,10 +59,10 @@ inline static const char *asmName(Assembly::Id assembly)
|
|||
#endif
|
||||
|
||||
|
||||
static void print_memory(Config *) {
|
||||
static void print_memory(Config *config) {
|
||||
# ifdef _WIN32
|
||||
Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") "%s",
|
||||
"HUGE PAGES", VirtualMemory::isHugepagesAvailable() ? GREEN_BOLD("permission granted") : RED_BOLD("unavailable"));
|
||||
"HUGE PAGES", config->cpu().isHugePages() ? (VirtualMemory::isHugepagesAvailable() ? GREEN_BOLD("permission granted") : RED_BOLD("unavailable")) : RED_BOLD("disabled"));
|
||||
# endif
|
||||
}
|
||||
|
||||
|
|
|
@ -132,6 +132,8 @@ xmrig::OclDevice::OclDevice(uint32_t index, cl_device_id id, cl_platform_id plat
|
|||
m_board(OclLib::getString(id, 0x4038 /* CL_DEVICE_BOARD_NAME_AMD */)),
|
||||
m_name(OclLib::getString(id, CL_DEVICE_NAME)),
|
||||
m_vendor(OclLib::getString(id, CL_DEVICE_VENDOR)),
|
||||
m_maxMemoryAlloc(OclLib::getUlong(id, CL_DEVICE_MAX_MEM_ALLOC_SIZE)),
|
||||
m_globalMemory(OclLib::getUlong(id, CL_DEVICE_GLOBAL_MEM_SIZE)),
|
||||
m_computeUnits(OclLib::getUint(id, CL_DEVICE_MAX_COMPUTE_UNITS, 1)),
|
||||
m_index(index)
|
||||
{
|
||||
|
@ -155,24 +157,6 @@ xmrig::OclDevice::OclDevice(uint32_t index, cl_device_id id, cl_platform_id plat
|
|||
}
|
||||
|
||||
|
||||
size_t xmrig::OclDevice::freeMemSize() const
|
||||
{
|
||||
return std::min(maxMemAllocSize(), globalMemSize());
|
||||
}
|
||||
|
||||
|
||||
size_t xmrig::OclDevice::globalMemSize() const
|
||||
{
|
||||
return OclLib::getUlong(id(), CL_DEVICE_GLOBAL_MEM_SIZE);
|
||||
}
|
||||
|
||||
|
||||
size_t xmrig::OclDevice::maxMemAllocSize() const
|
||||
{
|
||||
return OclLib::getUlong(id(), CL_DEVICE_MAX_MEM_ALLOC_SIZE);
|
||||
}
|
||||
|
||||
|
||||
xmrig::String xmrig::OclDevice::printableName() const
|
||||
{
|
||||
const size_t size = m_board.size() + m_name.size() + 64;
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "backend/opencl/wrappers/OclVendor.h"
|
||||
#include "base/tools/String.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using cl_device_id = struct _cl_device_id *;
|
||||
using cl_platform_id = struct _cl_platform_id *;
|
||||
|
@ -62,9 +63,6 @@ public:
|
|||
OclDevice() = delete;
|
||||
OclDevice(uint32_t index, cl_device_id id, cl_platform_id platform);
|
||||
|
||||
size_t freeMemSize() const;
|
||||
size_t globalMemSize() const;
|
||||
size_t maxMemAllocSize() const;
|
||||
String printableName() const;
|
||||
uint32_t clock() const;
|
||||
void generate(const Algorithm &algorithm, OclThreads &threads) const;
|
||||
|
@ -78,6 +76,9 @@ public:
|
|||
inline OclVendor vendorId() const { return m_vendorId; }
|
||||
inline Type type() const { return m_type; }
|
||||
inline uint32_t computeUnits() const { return m_computeUnits; }
|
||||
inline size_t freeMemSize() const { return std::min(maxMemAllocSize(), globalMemSize()); }
|
||||
inline size_t globalMemSize() const { return m_globalMemory; }
|
||||
inline size_t maxMemAllocSize() const { return m_maxMemoryAlloc; }
|
||||
inline uint32_t index() const { return m_index; }
|
||||
|
||||
# ifdef XMRIG_FEATURE_API
|
||||
|
@ -90,6 +91,8 @@ private:
|
|||
const String m_board;
|
||||
const String m_name;
|
||||
const String m_vendor;
|
||||
const size_t m_maxMemoryAlloc = 0;
|
||||
const size_t m_globalMemory = 0;
|
||||
const uint32_t m_computeUnits = 1;
|
||||
const uint32_t m_index = 0;
|
||||
OclVendor m_vendorId = OCL_VENDOR_UNKNOWN;
|
||||
|
|
|
@ -41,6 +41,7 @@ set(HEADERS_BASE
|
|||
src/base/net/stratum/strategies/FailoverStrategy.h
|
||||
src/base/net/stratum/strategies/SinglePoolStrategy.h
|
||||
src/base/net/stratum/SubmitResult.h
|
||||
src/base/net/stratum/Url.h
|
||||
src/base/net/tools/RecvBuf.h
|
||||
src/base/net/tools/Storage.h
|
||||
src/base/tools/Arguments.h
|
||||
|
@ -78,6 +79,7 @@ set(SOURCES_BASE
|
|||
src/base/net/stratum/Pools.cpp
|
||||
src/base/net/stratum/strategies/FailoverStrategy.cpp
|
||||
src/base/net/stratum/strategies/SinglePoolStrategy.cpp
|
||||
src/base/net/stratum/Url.cpp
|
||||
src/base/tools/Arguments.cpp
|
||||
src/base/tools/Buffer.cpp
|
||||
src/base/tools/String.cpp
|
||||
|
@ -137,6 +139,7 @@ if (WITH_HTTP)
|
|||
src/base/net/http/HttpResponse.h
|
||||
src/base/net/http/HttpServer.h
|
||||
src/base/net/stratum/DaemonClient.h
|
||||
src/base/net/stratum/SelfSelectClient.h
|
||||
src/base/net/tools/TcpServer.h
|
||||
)
|
||||
|
||||
|
@ -152,6 +155,7 @@ if (WITH_HTTP)
|
|||
src/base/net/http/HttpResponse.cpp
|
||||
src/base/net/http/HttpServer.cpp
|
||||
src/base/net/stratum/DaemonClient.cpp
|
||||
src/base/net/stratum/SelfSelectClient.cpp
|
||||
src/base/net/tools/TcpServer.cpp
|
||||
)
|
||||
|
||||
|
|
|
@ -49,6 +49,8 @@ xmrig::ConsoleLog::ConsoleLog()
|
|||
uv_tty_set_mode(m_tty, UV_TTY_MODE_NORMAL);
|
||||
|
||||
# ifdef WIN32
|
||||
m_stream = reinterpret_cast<uv_stream_t*>(m_tty);
|
||||
|
||||
HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
|
||||
if (handle != INVALID_HANDLE_VALUE) {
|
||||
DWORD mode = 0;
|
||||
|
@ -67,14 +69,26 @@ xmrig::ConsoleLog::~ConsoleLog()
|
|||
}
|
||||
|
||||
|
||||
void xmrig::ConsoleLog::print(int, const char *line, size_t, size_t, bool colors)
|
||||
void xmrig::ConsoleLog::print(int, const char *line, size_t, size_t size, bool colors)
|
||||
{
|
||||
if (!m_tty || Log::colors != colors) {
|
||||
return;
|
||||
}
|
||||
|
||||
# ifdef _WIN32
|
||||
uv_buf_t buf = uv_buf_init(const_cast<char *>(line), static_cast<unsigned int>(size));
|
||||
|
||||
if (!isWritable()) {
|
||||
fputs(line, stdout);
|
||||
fflush(stdout);
|
||||
}
|
||||
else {
|
||||
uv_try_write(m_stream, &buf, 1);
|
||||
}
|
||||
# else
|
||||
fputs(line, stdout);
|
||||
fflush(stdout);
|
||||
# endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -83,3 +97,15 @@ bool xmrig::ConsoleLog::isSupported() const
|
|||
const uv_handle_type type = uv_guess_handle(1);
|
||||
return type == UV_TTY || type == UV_NAMED_PIPE;
|
||||
}
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
bool xmrig::ConsoleLog::isWritable() const
|
||||
{
|
||||
if (!m_stream || uv_is_writable(m_stream) != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isSupported();
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -53,6 +53,12 @@ private:
|
|||
bool isSupported() const;
|
||||
|
||||
uv_tty_t *m_tty = nullptr;
|
||||
|
||||
# ifdef _WIN32
|
||||
bool isWritable() const;
|
||||
|
||||
uv_stream_t *m_stream = nullptr;
|
||||
# endif
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -183,6 +183,9 @@ void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const ch
|
|||
case IConfig::FingerprintKey: /* --tls-fingerprint */
|
||||
return add(doc, kPools, "tls-fingerprint", arg);
|
||||
|
||||
case IConfig::SelfSelectKey: /* --self-select */
|
||||
return add(doc, kPools, "self-select", arg);
|
||||
|
||||
case IConfig::LogFileKey: /* --log-file */
|
||||
return set(doc, "log-file", arg);
|
||||
|
||||
|
|
|
@ -26,7 +26,10 @@
|
|||
#define XMRIG_ICLIENT_H
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include "rapidjson/fwd.h"
|
||||
|
||||
|
||||
#include <functional>
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
@ -51,31 +54,35 @@ public:
|
|||
EXT_MAX
|
||||
};
|
||||
|
||||
using Callback = std::function<void(const rapidjson::Value &result, bool success, uint64_t elapsed)>;
|
||||
|
||||
virtual ~IClient() = default;
|
||||
|
||||
virtual bool disconnect() = 0;
|
||||
virtual bool hasExtension(Extension extension) const noexcept = 0;
|
||||
virtual bool isEnabled() const = 0;
|
||||
virtual bool isTLS() const = 0;
|
||||
virtual const char *mode() const = 0;
|
||||
virtual const char *tlsFingerprint() const = 0;
|
||||
virtual const char *tlsVersion() const = 0;
|
||||
virtual const Job &job() const = 0;
|
||||
virtual const Pool &pool() const = 0;
|
||||
virtual const String &ip() const = 0;
|
||||
virtual int id() const = 0;
|
||||
virtual int64_t submit(const JobResult &result) = 0;
|
||||
virtual void connect() = 0;
|
||||
virtual void connect(const Pool &pool) = 0;
|
||||
virtual void deleteLater() = 0;
|
||||
virtual void setAlgo(const Algorithm &algo) = 0;
|
||||
virtual void setEnabled(bool enabled) = 0;
|
||||
virtual void setPool(const Pool &pool) = 0;
|
||||
virtual void setQuiet(bool quiet) = 0;
|
||||
virtual void setRetries(int retries) = 0;
|
||||
virtual void setRetryPause(uint64_t ms) = 0;
|
||||
virtual void tick(uint64_t now) = 0;
|
||||
|
||||
virtual bool disconnect() = 0;
|
||||
virtual bool hasExtension(Extension extension) const noexcept = 0;
|
||||
virtual bool isEnabled() const = 0;
|
||||
virtual bool isTLS() const = 0;
|
||||
virtual const char *mode() const = 0;
|
||||
virtual const char *tlsFingerprint() const = 0;
|
||||
virtual const char *tlsVersion() const = 0;
|
||||
virtual const Job &job() const = 0;
|
||||
virtual const Pool &pool() const = 0;
|
||||
virtual const String &ip() const = 0;
|
||||
virtual int id() const = 0;
|
||||
virtual int64_t send(const rapidjson::Value &obj, Callback callback) = 0;
|
||||
virtual int64_t send(const rapidjson::Value &obj) = 0;
|
||||
virtual int64_t sequence() const = 0;
|
||||
virtual int64_t submit(const JobResult &result) = 0;
|
||||
virtual void connect() = 0;
|
||||
virtual void connect(const Pool &pool) = 0;
|
||||
virtual void deleteLater() = 0;
|
||||
virtual void setAlgo(const Algorithm &algo) = 0;
|
||||
virtual void setEnabled(bool enabled) = 0;
|
||||
virtual void setPool(const Pool &pool) = 0;
|
||||
virtual void setQuiet(bool quiet) = 0;
|
||||
virtual void setRetries(int retries) = 0;
|
||||
virtual void setRetryPause(uint64_t ms) = 0;
|
||||
virtual void tick(uint64_t now) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#define XMRIG_ICLIENTLISTENER_H
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
#include "rapidjson/fwd.h"
|
||||
|
|
|
@ -72,6 +72,7 @@ public:
|
|||
ProxyDonateKey = 1017,
|
||||
DaemonKey = 1018,
|
||||
DaemonPollKey = 1019,
|
||||
SelfSelectKey = 1028,
|
||||
|
||||
// xmrig common
|
||||
CPUPriorityKey = 1021,
|
||||
|
|
|
@ -78,9 +78,7 @@ private:
|
|||
|
||||
|
||||
xmrig::HttpClient::HttpClient(int method, const String &url, IHttpListener *listener, const char *data, size_t size) :
|
||||
HttpContext(HTTP_RESPONSE, listener),
|
||||
m_quiet(false),
|
||||
m_port(0)
|
||||
HttpContext(HTTP_RESPONSE, listener)
|
||||
{
|
||||
this->method = method;
|
||||
this->url = url;
|
||||
|
@ -127,7 +125,7 @@ void xmrig::HttpClient::onResolved(const Dns &dns, int status)
|
|||
|
||||
sockaddr *addr = dns.get().addr(m_port);
|
||||
|
||||
uv_connect_t *req = new uv_connect_t;
|
||||
auto req = new uv_connect_t;
|
||||
req->data = this;
|
||||
|
||||
uv_tcp_connect(req, m_tcp, addr, onConnect);
|
||||
|
@ -140,7 +138,7 @@ void xmrig::HttpClient::handshake()
|
|||
headers.insert({ "Connection", "close" });
|
||||
headers.insert({ "User-Agent", Platform::userAgent() });
|
||||
|
||||
if (body.size()) {
|
||||
if (!body.empty()) {
|
||||
headers.insert({ "Content-Length", std::to_string(body.size()) });
|
||||
}
|
||||
|
||||
|
@ -169,14 +167,14 @@ void xmrig::HttpClient::read(const char *data, size_t size)
|
|||
|
||||
void xmrig::HttpClient::write(const std::string &header)
|
||||
{
|
||||
ClientWriteBaton *baton = new ClientWriteBaton(header, std::move(body));
|
||||
auto baton = new ClientWriteBaton(header, std::move(body));
|
||||
uv_write(&baton->req, stream(), baton->bufs, baton->count(), ClientWriteBaton::onWrite);
|
||||
}
|
||||
|
||||
|
||||
void xmrig::HttpClient::onConnect(uv_connect_t *req, int status)
|
||||
{
|
||||
HttpClient *client = static_cast<HttpClient *>(req->data);
|
||||
auto client = static_cast<HttpClient *>(req->data);
|
||||
if (!client) {
|
||||
delete req;
|
||||
return;
|
||||
|
@ -205,7 +203,7 @@ void xmrig::HttpClient::onConnect(uv_connect_t *req, int status)
|
|||
},
|
||||
[](uv_stream_t *tcp, ssize_t nread, const uv_buf_t *buf)
|
||||
{
|
||||
HttpClient *client = static_cast<HttpClient*>(tcp->data);
|
||||
auto client = static_cast<HttpClient*>(tcp->data);
|
||||
|
||||
if (nread >= 0) {
|
||||
client->read(buf->base, static_cast<size_t>(nread));
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "base/net/http/HttpContext.h"
|
||||
#include "base/kernel/interfaces/IDnsListener.h"
|
||||
#include "base/tools/Object.h"
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
@ -41,6 +42,8 @@ class String;
|
|||
class HttpClient : public HttpContext, public IDnsListener
|
||||
{
|
||||
public:
|
||||
XMRIG_DISABLE_COPY_MOVE_DEFAULT(HttpClient);
|
||||
|
||||
HttpClient(int method, const String &url, IHttpListener *listener, const char *data = nullptr, size_t size = 0);
|
||||
~HttpClient() override;
|
||||
|
||||
|
@ -57,13 +60,13 @@ protected:
|
|||
virtual void read(const char *data, size_t size);
|
||||
virtual void write(const std::string &header);
|
||||
|
||||
bool m_quiet;
|
||||
bool m_quiet = false;
|
||||
|
||||
private:
|
||||
static void onConnect(uv_connect_t *req, int status);
|
||||
|
||||
Dns *m_dns;
|
||||
uint16_t m_port;
|
||||
uint16_t m_port = 0;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -136,7 +136,7 @@ void xmrig::HttpContext::closeAll()
|
|||
|
||||
int xmrig::HttpContext::onHeaderField(http_parser *parser, const char *at, size_t length)
|
||||
{
|
||||
HttpContext *ctx = static_cast<HttpContext*>(parser->data);
|
||||
auto ctx = static_cast<HttpContext*>(parser->data);
|
||||
|
||||
if (ctx->m_wasHeaderValue) {
|
||||
if (!ctx->m_lastHeaderField.empty()) {
|
||||
|
@ -155,7 +155,7 @@ int xmrig::HttpContext::onHeaderField(http_parser *parser, const char *at, size_
|
|||
|
||||
int xmrig::HttpContext::onHeaderValue(http_parser *parser, const char *at, size_t length)
|
||||
{
|
||||
HttpContext *ctx = static_cast<HttpContext*>(parser->data);
|
||||
auto ctx = static_cast<HttpContext*>(parser->data);
|
||||
|
||||
if (!ctx->m_wasHeaderValue) {
|
||||
ctx->m_lastHeaderValue = std::string(at, length);
|
||||
|
@ -185,7 +185,7 @@ void xmrig::HttpContext::attach(http_parser_settings *settings)
|
|||
settings->on_header_value = onHeaderValue;
|
||||
|
||||
settings->on_headers_complete = [](http_parser* parser) -> int {
|
||||
HttpContext *ctx = static_cast<HttpContext*>(parser->data);
|
||||
auto ctx = static_cast<HttpContext*>(parser->data);
|
||||
ctx->status = parser->status_code;
|
||||
|
||||
if (parser->type == HTTP_REQUEST) {
|
||||
|
@ -208,7 +208,7 @@ void xmrig::HttpContext::attach(http_parser_settings *settings)
|
|||
|
||||
settings->on_message_complete = [](http_parser *parser) -> int
|
||||
{
|
||||
HttpContext *ctx = static_cast<HttpContext*>(parser->data);
|
||||
auto ctx = static_cast<HttpContext*>(parser->data);
|
||||
ctx->m_listener->onHttpData(*ctx);
|
||||
ctx->m_listener = nullptr;
|
||||
|
||||
|
|
|
@ -28,15 +28,16 @@
|
|||
#define XMRIG_HTTPCONTEXT_H
|
||||
|
||||
|
||||
typedef struct http_parser http_parser;
|
||||
typedef struct http_parser_settings http_parser_settings;
|
||||
typedef struct uv_connect_s uv_connect_t;
|
||||
typedef struct uv_handle_s uv_handle_t;
|
||||
typedef struct uv_stream_s uv_stream_t;
|
||||
typedef struct uv_tcp_s uv_tcp_t;
|
||||
using http_parser = struct http_parser;
|
||||
using http_parser_settings = struct http_parser_settings;
|
||||
using uv_connect_t = struct uv_connect_s;
|
||||
using uv_handle_t = struct uv_handle_s;
|
||||
using uv_stream_t = struct uv_stream_s;
|
||||
using uv_tcp_t = struct uv_tcp_s;
|
||||
|
||||
|
||||
#include "base/net/http/HttpData.h"
|
||||
#include "base/tools/Object.h"
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
@ -48,6 +49,8 @@ class IHttpListener;
|
|||
class HttpContext : public HttpData
|
||||
{
|
||||
public:
|
||||
XMRIG_DISABLE_COPY_MOVE_DEFAULT(HttpContext)
|
||||
|
||||
HttpContext(int parser_type, IHttpListener *listener);
|
||||
virtual ~HttpContext();
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
*/
|
||||
|
||||
|
||||
#include <assert.h>
|
||||
#include <cassert>
|
||||
#include <openssl/ssl.h>
|
||||
#include <uv.h>
|
||||
|
||||
|
|
|
@ -28,10 +28,10 @@
|
|||
#define XMRIG_HTTPSCLIENT_H
|
||||
|
||||
|
||||
typedef struct bio_st BIO;
|
||||
typedef struct ssl_ctx_st SSL_CTX;
|
||||
typedef struct ssl_st SSL;
|
||||
typedef struct x509_st X509;
|
||||
using BIO = struct bio_st;
|
||||
using SSL_CTX = struct ssl_ctx_st;
|
||||
using SSL = struct ssl_st;
|
||||
using X509 = struct x509_st;
|
||||
|
||||
|
||||
#include "base/net/http/HttpClient.h"
|
||||
|
@ -44,6 +44,8 @@ namespace xmrig {
|
|||
class HttpsClient : public HttpClient
|
||||
{
|
||||
public:
|
||||
XMRIG_DISABLE_COPY_MOVE_DEFAULT(HttpsClient)
|
||||
|
||||
HttpsClient(int method, const String &url, IHttpListener *listener, const char *data, size_t size, const String &fingerprint);
|
||||
~HttpsClient() override;
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "base/kernel/interfaces/IClientListener.h"
|
||||
#include "base/net/stratum/BaseClient.h"
|
||||
#include "base/net/stratum/SubmitResult.h"
|
||||
#include "rapidjson/document.h"
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
@ -36,18 +37,38 @@ int64_t BaseClient::m_sequence = 1;
|
|||
|
||||
|
||||
xmrig::BaseClient::BaseClient(int id, IClientListener *listener) :
|
||||
m_quiet(false),
|
||||
m_listener(listener),
|
||||
m_id(id),
|
||||
m_retries(5),
|
||||
m_failures(0),
|
||||
m_state(UnconnectedState),
|
||||
m_retryPause(5000),
|
||||
m_enabled(true)
|
||||
m_id(id)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool xmrig::BaseClient::handleResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error)
|
||||
{
|
||||
if (id == 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool xmrig::BaseClient::handleSubmitResponse(int64_t id, const char *error)
|
||||
{
|
||||
auto it = m_results.find(id);
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "base/kernel/interfaces/IClient.h"
|
||||
#include "base/net/stratum/Job.h"
|
||||
#include "base/net/stratum/Pool.h"
|
||||
#include "base/tools/Chrono.h"
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
@ -46,11 +47,13 @@ class BaseClient : public IClient
|
|||
public:
|
||||
BaseClient(int id, IClientListener *listener);
|
||||
|
||||
protected:
|
||||
inline bool isEnabled() const override { return m_enabled; }
|
||||
inline const Job &job() const override { return m_job; }
|
||||
inline const Pool &pool() const override { return m_pool; }
|
||||
inline const String &ip() const override { return m_ip; }
|
||||
inline int id() const override { return m_id; }
|
||||
inline int64_t sequence() const override { return m_sequence; }
|
||||
inline void setAlgo(const Algorithm &algo) override { m_pool.setAlgo(algo); }
|
||||
inline void setEnabled(bool enabled) override { m_enabled = enabled; }
|
||||
inline void setPool(const Pool &pool) override { if (pool.isValid()) { m_pool = pool; } }
|
||||
|
@ -68,26 +71,36 @@ protected:
|
|||
ReconnectingState
|
||||
};
|
||||
|
||||
struct SendResult
|
||||
{
|
||||
inline SendResult(Callback &&callback) : callback(callback), ts(Chrono::steadyMSecs()) {}
|
||||
|
||||
Callback callback;
|
||||
const uint64_t ts;
|
||||
};
|
||||
|
||||
inline bool isQuiet() const { return m_quiet || m_failures >= m_retries; }
|
||||
|
||||
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;
|
||||
bool m_quiet = false;
|
||||
IClientListener *m_listener;
|
||||
int m_id;
|
||||
int m_retries;
|
||||
int64_t m_failures;
|
||||
int m_retries = 5;
|
||||
int64_t m_failures = 0;
|
||||
Job m_job;
|
||||
Pool m_pool;
|
||||
SocketState m_state;
|
||||
SocketState m_state = UnconnectedState;
|
||||
std::map<int64_t, SendResult> m_callbacks;
|
||||
std::map<int64_t, SubmitResult> m_results;
|
||||
String m_ip;
|
||||
uint64_t m_retryPause;
|
||||
uint64_t m_retryPause = 5000;
|
||||
|
||||
static int64_t m_sequence;
|
||||
|
||||
private:
|
||||
bool m_enabled;
|
||||
bool m_enabled = true;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
|
||||
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright 2019 jtgrassie <https://github.com/jtgrassie>
|
||||
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
|
@ -22,11 +23,11 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <cassert>
|
||||
#include <cinttypes>
|
||||
#include <iterator>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
|
||||
|
||||
|
@ -136,6 +137,41 @@ const char *xmrig::Client::tlsVersion() const
|
|||
}
|
||||
|
||||
|
||||
int64_t xmrig::Client::send(const rapidjson::Value &obj, Callback callback)
|
||||
{
|
||||
assert(obj["id"] == sequence());
|
||||
|
||||
m_callbacks.insert({ sequence(), std::move(callback) });
|
||||
|
||||
return send(obj);
|
||||
}
|
||||
|
||||
|
||||
int64_t xmrig::Client::send(const rapidjson::Value &obj)
|
||||
{
|
||||
using namespace rapidjson;
|
||||
|
||||
Value value;
|
||||
|
||||
StringBuffer buffer(nullptr, 512);
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
obj.Accept(writer);
|
||||
|
||||
const size_t size = buffer.GetSize();
|
||||
if (size > (sizeof(m_sendBuf) - 2)) {
|
||||
LOG_ERR("[%s] send failed: \"send buffer overflow: %zu > %zu\"", url(), size, (sizeof(m_sendBuf) - 2));
|
||||
close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(m_sendBuf, buffer.GetString(), size);
|
||||
m_sendBuf[size] = '\n';
|
||||
m_sendBuf[size + 1] = '\0';
|
||||
|
||||
return send(size + 1);
|
||||
}
|
||||
|
||||
|
||||
int64_t xmrig::Client::submit(const JobResult &result)
|
||||
{
|
||||
# ifndef XMRIG_PROXY_PROJECT
|
||||
|
@ -320,9 +356,23 @@ bool xmrig::Client::parseJob(const rapidjson::Value ¶ms, int *code)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!job.setBlob(params["blob"].GetString())) {
|
||||
*code = 4;
|
||||
return false;
|
||||
# ifdef XMRIG_FEATURE_HTTP
|
||||
if (m_pool.mode() == Pool::MODE_SELF_SELECT) {
|
||||
job.setExtraNonce(Json::getString(params, "extra_nonce"));
|
||||
job.setPoolWallet(Json::getString(params, "pool_wallet"));
|
||||
|
||||
if (job.extraNonce().isNull() || job.poolWallet().isNull()) {
|
||||
*code = 4;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
# endif
|
||||
{
|
||||
if (!job.setBlob(params["blob"].GetString())) {
|
||||
*code = 4;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!job.setTarget(params["target"].GetString())) {
|
||||
|
@ -345,7 +395,7 @@ bool xmrig::Client::parseJob(const rapidjson::Value ¶ms, int *code)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (job.algorithm().family() == Algorithm::RANDOM_X && !job.setSeedHash(Json::getString(params, "seed_hash"))) {
|
||||
if (m_pool.mode() != Pool::MODE_SELF_SELECT && job.algorithm().family() == Algorithm::RANDOM_X && !job.setSeedHash(Json::getString(params, "seed_hash"))) {
|
||||
if (!isQuiet()) {
|
||||
LOG_ERR("[%s] failed to parse field \"seed_hash\" required by RandomX", url(), algo);
|
||||
}
|
||||
|
@ -473,29 +523,6 @@ int xmrig::Client::resolve(const String &host)
|
|||
}
|
||||
|
||||
|
||||
int64_t xmrig::Client::send(const rapidjson::Document &doc)
|
||||
{
|
||||
using namespace rapidjson;
|
||||
|
||||
StringBuffer buffer(nullptr, 512);
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
doc.Accept(writer);
|
||||
|
||||
const size_t size = buffer.GetSize();
|
||||
if (size > (sizeof(m_sendBuf) - 2)) {
|
||||
LOG_ERR("[%s] send failed: \"send buffer overflow: %zu > %zu\"", url(), size, (sizeof(m_sendBuf) - 2));
|
||||
close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(m_sendBuf, buffer.GetString(), size);
|
||||
m_sendBuf[size] = '\n';
|
||||
m_sendBuf[size + 1] = '\0';
|
||||
|
||||
return send(size + 1);
|
||||
}
|
||||
|
||||
|
||||
int64_t xmrig::Client::send(size_t size)
|
||||
{
|
||||
LOG_DEBUG("[%s] send (%d bytes): \"%.*s\"", url(), size, static_cast<int>(size) - 1, m_sendBuf);
|
||||
|
@ -719,6 +746,10 @@ void xmrig::Client::parseNotification(const char *method, const rapidjson::Value
|
|||
|
||||
void xmrig::Client::parseResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error)
|
||||
{
|
||||
if (handleResponse(id, result, error)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (error.IsObject()) {
|
||||
const char *message = error["message"].GetString();
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
|
||||
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright 2019 jtgrassie <https://github.com/jtgrassie>
|
||||
* Copyright 2016-2019 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
|
@ -40,10 +41,11 @@
|
|||
#include "base/net/stratum/SubmitResult.h"
|
||||
#include "base/net/tools/RecvBuf.h"
|
||||
#include "base/net/tools/Storage.h"
|
||||
#include "base/tools/Object.h"
|
||||
#include "crypto/common/Algorithm.h"
|
||||
|
||||
|
||||
typedef struct bio_st BIO;
|
||||
using BIO = struct bio_st;
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
@ -56,6 +58,8 @@ class JobResult;
|
|||
class Client : public BaseClient, public IDnsListener, public ILineListener
|
||||
{
|
||||
public:
|
||||
XMRIG_DISABLE_COPY_MOVE_DEFAULT(Client)
|
||||
|
||||
constexpr static uint64_t kConnectTimeout = 20 * 1000;
|
||||
constexpr static uint64_t kResponseTimeout = 20 * 1000;
|
||||
|
||||
|
@ -73,6 +77,8 @@ protected:
|
|||
bool isTLS() const override;
|
||||
const char *tlsFingerprint() const override;
|
||||
const char *tlsVersion() const override;
|
||||
int64_t send(const rapidjson::Value &obj, Callback callback) override;
|
||||
int64_t send(const rapidjson::Value &obj) override;
|
||||
int64_t submit(const JobResult &result) override;
|
||||
void connect() override;
|
||||
void connect(const Pool &pool) override;
|
||||
|
@ -95,7 +101,6 @@ private:
|
|||
bool send(BIO *bio);
|
||||
bool verifyAlgorithm(const Algorithm &algorithm, const char *algo) const;
|
||||
int resolve(const String &host);
|
||||
int64_t send(const rapidjson::Document &doc);
|
||||
int64_t send(size_t size);
|
||||
void connect(sockaddr *addr);
|
||||
void handshake();
|
||||
|
|
|
@ -27,9 +27,10 @@
|
|||
#define XMRIG_DAEMONCLIENT_H
|
||||
|
||||
|
||||
#include "base/net/stratum/BaseClient.h"
|
||||
#include "base/kernel/interfaces/ITimerListener.h"
|
||||
#include "base/kernel/interfaces/IHttpListener.h"
|
||||
#include "base/kernel/interfaces/ITimerListener.h"
|
||||
#include "base/net/stratum/BaseClient.h"
|
||||
#include "base/tools/Object.h"
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
@ -38,6 +39,8 @@ namespace xmrig {
|
|||
class DaemonClient : public BaseClient, public ITimerListener, public IHttpListener
|
||||
{
|
||||
public:
|
||||
XMRIG_DISABLE_COPY_MOVE_DEFAULT(DaemonClient)
|
||||
|
||||
DaemonClient(int id, IClientListener *listener);
|
||||
~DaemonClient() override;
|
||||
|
||||
|
@ -51,12 +54,14 @@ protected:
|
|||
void onHttpData(const HttpData &data) override;
|
||||
void onTimer(const Timer *timer) override;
|
||||
|
||||
inline bool hasExtension(Extension) const noexcept override { return false; }
|
||||
inline const char *mode() const override { return "daemon"; }
|
||||
inline const char *tlsFingerprint() const override { return m_tlsFingerprint; }
|
||||
inline const char *tlsVersion() const override { return m_tlsVersion; }
|
||||
inline void deleteLater() override { delete this; }
|
||||
inline void tick(uint64_t) override {}
|
||||
inline bool hasExtension(Extension) const noexcept override { return false; }
|
||||
inline const char *mode() const override { return "daemon"; }
|
||||
inline const char *tlsFingerprint() const override { return m_tlsFingerprint; }
|
||||
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; }
|
||||
inline void tick(uint64_t) override {}
|
||||
|
||||
private:
|
||||
bool isOutdated(uint64_t height, const char *hash) const;
|
||||
|
|
|
@ -152,16 +152,18 @@ void xmrig::Job::setDiff(uint64_t diff)
|
|||
|
||||
void xmrig::Job::copy(const Job &other)
|
||||
{
|
||||
m_algorithm = other.m_algorithm;
|
||||
m_nicehash = other.m_nicehash;
|
||||
m_size = other.m_size;
|
||||
m_clientId = other.m_clientId;
|
||||
m_id = other.m_id;
|
||||
m_diff = other.m_diff;
|
||||
m_height = other.m_height;
|
||||
m_target = other.m_target;
|
||||
m_index = other.m_index;
|
||||
m_seed = other.m_seed;
|
||||
m_algorithm = other.m_algorithm;
|
||||
m_nicehash = other.m_nicehash;
|
||||
m_size = other.m_size;
|
||||
m_clientId = other.m_clientId;
|
||||
m_id = other.m_id;
|
||||
m_diff = other.m_diff;
|
||||
m_height = other.m_height;
|
||||
m_target = other.m_target;
|
||||
m_index = other.m_index;
|
||||
m_seed = other.m_seed;
|
||||
m_extraNonce = other.m_extraNonce;
|
||||
m_poolWallet = other.m_poolWallet;
|
||||
|
||||
memcpy(m_blob, other.m_blob, sizeof(m_blob));
|
||||
|
||||
|
|
|
@ -58,28 +58,32 @@ public:
|
|||
bool setTarget(const char *target);
|
||||
void setDiff(uint64_t diff);
|
||||
|
||||
inline bool isNicehash() const { return m_nicehash; }
|
||||
inline bool isValid() const { return m_size > 0 && m_diff > 0; }
|
||||
inline bool setId(const char *id) { return m_id = id; }
|
||||
inline const Algorithm &algorithm() const { return m_algorithm; }
|
||||
inline const Buffer &seed() const { return m_seed; }
|
||||
inline const String &clientId() const { return m_clientId; }
|
||||
inline const String &id() const { return m_id; }
|
||||
inline const uint32_t *nonce() const { return reinterpret_cast<const uint32_t*>(m_blob + 39); }
|
||||
inline const uint8_t *blob() const { return m_blob; }
|
||||
inline size_t size() const { return m_size; }
|
||||
inline uint32_t *nonce() { return reinterpret_cast<uint32_t*>(m_blob + 39); }
|
||||
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; }
|
||||
inline void setAlgorithm(const char *algo) { m_algorithm = algo; }
|
||||
inline void setClientId(const String &id) { m_clientId = id; }
|
||||
inline void setHeight(uint64_t height) { m_height = height; }
|
||||
inline void setIndex(uint8_t index) { m_index = index; }
|
||||
inline bool isNicehash() const { return m_nicehash; }
|
||||
inline bool isValid() const { return m_size > 0 && m_diff > 0; }
|
||||
inline bool setId(const char *id) { return m_id = id; }
|
||||
inline const Algorithm &algorithm() const { return m_algorithm; }
|
||||
inline const Buffer &seed() const { return m_seed; }
|
||||
inline const String &clientId() const { return m_clientId; }
|
||||
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 const uint8_t *blob() const { return m_blob; }
|
||||
inline size_t size() const { return m_size; }
|
||||
inline uint32_t *nonce() { return reinterpret_cast<uint32_t*>(m_blob + 39); }
|
||||
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; }
|
||||
inline void setAlgorithm(const char *algo) { m_algorithm = algo; }
|
||||
inline void setClientId(const String &id) { m_clientId = id; }
|
||||
inline void setExtraNonce(const String &extraNonce) { m_extraNonce = extraNonce; }
|
||||
inline void setHeight(uint64_t height) { m_height = height; }
|
||||
inline void setIndex(uint8_t index) { m_index = index; }
|
||||
inline void setPoolWallet(const String &poolWallet) { m_poolWallet = poolWallet; }
|
||||
|
||||
# ifdef XMRIG_PROXY_PROJECT
|
||||
inline char *rawBlob() { return m_rawBlob; }
|
||||
|
@ -103,7 +107,9 @@ private:
|
|||
Buffer m_seed;
|
||||
size_t m_size = 0;
|
||||
String m_clientId;
|
||||
String m_extraNonce;
|
||||
String m_id;
|
||||
String m_poolWallet;
|
||||
uint64_t m_diff = 0;
|
||||
uint64_t m_height = 0;
|
||||
uint64_t m_target = 0;
|
||||
|
|
|
@ -24,24 +24,23 @@
|
|||
*/
|
||||
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
#include "base/io/json/Json.h"
|
||||
#include "base/net/stratum/Pool.h"
|
||||
#include "base/io/json/Json.h"
|
||||
#include "base/io/log/Log.h"
|
||||
#include "base/kernel/Platform.h"
|
||||
#include "base/net/stratum/Client.h"
|
||||
#include "rapidjson/document.h"
|
||||
|
||||
|
||||
#ifdef APP_DEBUG
|
||||
# include "base/io/log/Log.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define strncasecmp _strnicmp
|
||||
#ifdef XMRIG_FEATURE_HTTP
|
||||
# include "base/net/stratum/DaemonClient.h"
|
||||
# include "base/net/stratum/SelfSelectClient.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -57,6 +56,7 @@ static const char *kKeepalive = "keepalive";
|
|||
static const char *kNicehash = "nicehash";
|
||||
static const char *kPass = "pass";
|
||||
static const char *kRigId = "rig-id";
|
||||
static const char *kSelfSelect = "self-select";
|
||||
static const char *kTls = "tls";
|
||||
static const char *kUrl = "url";
|
||||
static const char *kUser = "user";
|
||||
|
@ -64,54 +64,23 @@ static const char *kUser = "user";
|
|||
const String Pool::kDefaultPassword = "x";
|
||||
const String Pool::kDefaultUser = "x";
|
||||
|
||||
static const char kStratumTcp[] = "stratum+tcp://";
|
||||
static const char kStratumSsl[] = "stratum+ssl://";
|
||||
|
||||
#ifdef XMRIG_FEATURE_HTTP
|
||||
static const char kDaemonHttp[] = "daemon+http://";
|
||||
static const char kDaemonHttps[] = "daemon+https://";
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
xmrig::Pool::Pool() :
|
||||
m_keepAlive(0),
|
||||
m_flags(0),
|
||||
m_port(kDefaultPort),
|
||||
m_pollInterval(kDefaultPollInterval)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Parse url.
|
||||
*
|
||||
* Valid urls:
|
||||
* example.com
|
||||
* example.com:3333
|
||||
* stratum+tcp://example.com
|
||||
* stratum+tcp://example.com:3333
|
||||
*
|
||||
* @param url
|
||||
*/
|
||||
xmrig::Pool::Pool(const char *url) :
|
||||
m_keepAlive(0),
|
||||
m_flags(1),
|
||||
m_port(kDefaultPort),
|
||||
m_pollInterval(kDefaultPollInterval)
|
||||
m_flags(1 << FLAG_ENABLED),
|
||||
m_pollInterval(kDefaultPollInterval),
|
||||
m_url(url)
|
||||
{
|
||||
parse(url);
|
||||
}
|
||||
|
||||
|
||||
xmrig::Pool::Pool(const rapidjson::Value &object) :
|
||||
m_keepAlive(0),
|
||||
m_flags(1),
|
||||
m_port(kDefaultPort),
|
||||
m_pollInterval(kDefaultPollInterval)
|
||||
m_flags(1 << FLAG_ENABLED),
|
||||
m_pollInterval(kDefaultPollInterval),
|
||||
m_url(Json::getString(object, kUrl))
|
||||
{
|
||||
if (!parse(Json::getString(object, kUrl))) {
|
||||
if (!m_url.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -122,11 +91,18 @@ xmrig::Pool::Pool(const rapidjson::Value &object) :
|
|||
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_flags.set(FLAG_ENABLED, Json::getBool(object, kEnabled, true));
|
||||
m_flags.set(FLAG_NICEHASH, Json::getBool(object, kNicehash));
|
||||
m_flags.set(FLAG_TLS, Json::getBool(object, kTls, m_flags.test(FLAG_TLS)));
|
||||
m_flags.set(FLAG_DAEMON, Json::getBool(object, kDaemon, m_flags.test(FLAG_DAEMON)));
|
||||
m_flags.set(FLAG_TLS, Json::getBool(object, kTls) || m_url.isTLS());
|
||||
|
||||
if (m_daemon.isValid()) {
|
||||
m_mode = MODE_SELF_SELECT;
|
||||
}
|
||||
else if (Json::getBool(object, kDaemon)) {
|
||||
m_mode = MODE_DAEMON;
|
||||
}
|
||||
|
||||
const rapidjson::Value &keepalive = Json::getValue(object, kKeepalive);
|
||||
if (keepalive.IsInt()) {
|
||||
|
@ -140,21 +116,12 @@ xmrig::Pool::Pool(const rapidjson::Value &object) :
|
|||
|
||||
xmrig::Pool::Pool(const char *host, uint16_t port, const char *user, const char *password, int keepAlive, bool nicehash, bool tls) :
|
||||
m_keepAlive(keepAlive),
|
||||
m_flags(1),
|
||||
m_host(host),
|
||||
m_flags(1 << FLAG_ENABLED),
|
||||
m_password(password),
|
||||
m_user(user),
|
||||
m_port(port),
|
||||
m_pollInterval(kDefaultPollInterval)
|
||||
m_pollInterval(kDefaultPollInterval),
|
||||
m_url(host, port, tls)
|
||||
{
|
||||
const size_t size = m_host.size() + 8;
|
||||
assert(size > 8);
|
||||
|
||||
char *url = new char[size]();
|
||||
snprintf(url, size - 1, "%s:%d", m_host.data(), m_port);
|
||||
|
||||
m_url = url;
|
||||
|
||||
m_flags.set(FLAG_NICEHASH, nicehash);
|
||||
m_flags.set(FLAG_TLS, tls);
|
||||
}
|
||||
|
@ -169,12 +136,18 @@ bool xmrig::Pool::isEnabled() const
|
|||
# endif
|
||||
|
||||
# ifndef XMRIG_FEATURE_HTTP
|
||||
if (isDaemon()) {
|
||||
if (m_mode == MODE_DAEMON) {
|
||||
return false;
|
||||
}
|
||||
# endif
|
||||
|
||||
if (isDaemon() && (!algorithm().isValid() && !coin().isValid())) {
|
||||
# ifndef XMRIG_FEATURE_HTTP
|
||||
if (m_mode == MODE_SELF_SELECT) {
|
||||
return false;
|
||||
}
|
||||
# endif
|
||||
|
||||
if (m_mode == MODE_DAEMON && (!algorithm().isValid() && !coin().isValid())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -186,79 +159,43 @@ bool xmrig::Pool::isEqual(const Pool &other) const
|
|||
{
|
||||
return (m_flags == other.m_flags
|
||||
&& m_keepAlive == other.m_keepAlive
|
||||
&& m_port == other.m_port
|
||||
&& m_algorithm == other.m_algorithm
|
||||
&& m_coin == other.m_coin
|
||||
&& m_mode == other.m_mode
|
||||
&& m_fingerprint == other.m_fingerprint
|
||||
&& m_host == other.m_host
|
||||
&& m_password == other.m_password
|
||||
&& m_rigId == other.m_rigId
|
||||
&& m_url == other.m_url
|
||||
&& m_user == other.m_user
|
||||
&& m_pollInterval == other.m_pollInterval
|
||||
&& m_daemon == other.m_daemon
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
bool xmrig::Pool::parse(const char *url)
|
||||
xmrig::IClient *xmrig::Pool::createClient(int id, IClientListener *listener) const
|
||||
{
|
||||
assert(url != nullptr);
|
||||
if (url == nullptr) {
|
||||
return false;
|
||||
IClient *client = nullptr;
|
||||
|
||||
if (m_mode == MODE_POOL) {
|
||||
client = new Client(id, Platform::userAgent(), listener);
|
||||
}
|
||||
# ifdef XMRIG_FEATURE_HTTP
|
||||
else if (m_mode == MODE_DAEMON) {
|
||||
client = new DaemonClient(id, listener);
|
||||
}
|
||||
else if (m_mode == MODE_SELF_SELECT) {
|
||||
client = new SelfSelectClient(id, Platform::userAgent(), listener);
|
||||
}
|
||||
# endif
|
||||
|
||||
assert(client != nullptr);
|
||||
|
||||
if (client) {
|
||||
client->setPool(*this);
|
||||
}
|
||||
|
||||
const char *p = strstr(url, "://");
|
||||
const char *base = url;
|
||||
|
||||
if (p) {
|
||||
if (strncasecmp(url, kStratumTcp, sizeof(kStratumTcp) - 1) == 0) {
|
||||
m_flags.set(FLAG_DAEMON, false);
|
||||
m_flags.set(FLAG_TLS, false);
|
||||
}
|
||||
else if (strncasecmp(url, kStratumSsl, sizeof(kStratumSsl) - 1) == 0) {
|
||||
m_flags.set(FLAG_DAEMON, false);
|
||||
m_flags.set(FLAG_TLS, true);
|
||||
}
|
||||
# ifdef XMRIG_FEATURE_HTTP
|
||||
else if (strncasecmp(url, kDaemonHttps, sizeof(kDaemonHttps) - 1) == 0) {
|
||||
m_flags.set(FLAG_DAEMON, true);
|
||||
m_flags.set(FLAG_TLS, true);
|
||||
}
|
||||
else if (strncasecmp(url, kDaemonHttp, sizeof(kDaemonHttp) - 1) == 0) {
|
||||
m_flags.set(FLAG_DAEMON, true);
|
||||
m_flags.set(FLAG_TLS, false);
|
||||
}
|
||||
# endif
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
base = p + 3;
|
||||
}
|
||||
|
||||
if (!strlen(base) || *base == '/') {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_url = url;
|
||||
if (base[0] == '[') {
|
||||
return parseIPv6(base);
|
||||
}
|
||||
|
||||
const char *port = strchr(base, ':');
|
||||
if (!port) {
|
||||
m_host = base;
|
||||
return true;
|
||||
}
|
||||
|
||||
const size_t size = static_cast<size_t>(port++ - base + 1);
|
||||
char *host = new char[size]();
|
||||
memcpy(host, base, size - 1);
|
||||
|
||||
m_host = host;
|
||||
m_port = static_cast<uint16_t>(strtol(port, nullptr, 10));
|
||||
|
||||
return true;
|
||||
return client;
|
||||
}
|
||||
|
||||
|
||||
|
@ -272,10 +209,10 @@ rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const
|
|||
|
||||
obj.AddMember(StringRef(kAlgo), m_algorithm.toJSON(), allocator);
|
||||
obj.AddMember(StringRef(kCoin), m_coin.toJSON(), allocator);
|
||||
obj.AddMember(StringRef(kUrl), m_url.toJSON(), allocator);
|
||||
obj.AddMember(StringRef(kUrl), url().toJSON(), allocator);
|
||||
obj.AddMember(StringRef(kUser), m_user.toJSON(), allocator);
|
||||
|
||||
if (!isDaemon()) {
|
||||
if (m_mode != MODE_DAEMON) {
|
||||
obj.AddMember(StringRef(kPass), m_password.toJSON(), allocator);
|
||||
obj.AddMember(StringRef(kRigId), m_rigId.toJSON(), allocator);
|
||||
|
||||
|
@ -294,22 +231,44 @@ rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const
|
|||
obj.AddMember(StringRef(kEnabled), m_flags.test(FLAG_ENABLED), allocator);
|
||||
obj.AddMember(StringRef(kTls), isTLS(), allocator);
|
||||
obj.AddMember(StringRef(kFingerprint), m_fingerprint.toJSON(), allocator);
|
||||
obj.AddMember(StringRef(kDaemon), m_flags.test(FLAG_DAEMON), allocator);
|
||||
obj.AddMember(StringRef(kDaemon), m_mode == MODE_DAEMON, allocator);
|
||||
|
||||
if (isDaemon()) {
|
||||
if (m_mode == MODE_DAEMON) {
|
||||
obj.AddMember(StringRef(kDaemonPollInterval), m_pollInterval, allocator);
|
||||
}
|
||||
else {
|
||||
obj.AddMember(StringRef(kSelfSelect), m_daemon.url().toJSON(), allocator);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
std::string xmrig::Pool::printableName() const
|
||||
{
|
||||
std::string out(CSI "1;" + std::to_string(isEnabled() ? (isTLS() ? 32 : 36) : 31) + "m" + url().data() + CLEAR);
|
||||
|
||||
if (m_coin.isValid()) {
|
||||
out += std::string(" coin ") + WHITE_BOLD_S + m_coin.name() + CLEAR;
|
||||
}
|
||||
else {
|
||||
out += std::string(" algo ") + WHITE_BOLD_S + (m_algorithm.isValid() ? m_algorithm.shortName() : "auto") + CLEAR;
|
||||
}
|
||||
|
||||
if (m_mode == MODE_SELF_SELECT) {
|
||||
out += std::string(" self-select ") + CSI "1;" + std::to_string(m_daemon.isTLS() ? 32 : 36) + "m" + m_daemon.url().data() + CLEAR;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
#ifdef APP_DEBUG
|
||||
void xmrig::Pool::print() const
|
||||
{
|
||||
LOG_NOTICE("url: %s", m_url.data());
|
||||
LOG_DEBUG ("host: %s", m_host.data());
|
||||
LOG_DEBUG ("port: %d", static_cast<int>(m_port));
|
||||
LOG_NOTICE("url: %s", url().data());
|
||||
LOG_DEBUG ("host: %s", host().data());
|
||||
LOG_DEBUG ("port: %d", static_cast<int>(port()));
|
||||
LOG_DEBUG ("user: %s", m_user.data());
|
||||
LOG_DEBUG ("pass: %s", m_password.data());
|
||||
LOG_DEBUG ("rig-id %s", m_rigId.data());
|
||||
|
@ -318,26 +277,3 @@ void xmrig::Pool::print() const
|
|||
LOG_DEBUG ("keepAlive: %d", m_keepAlive);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool xmrig::Pool::parseIPv6(const char *addr)
|
||||
{
|
||||
const char *end = strchr(addr, ']');
|
||||
if (!end) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *port = strchr(end, ':');
|
||||
if (!port) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t size = static_cast<size_t>(end - addr);
|
||||
char *host = new char[size]();
|
||||
memcpy(host, addr + 1, size - 1);
|
||||
|
||||
m_host = host;
|
||||
m_port = static_cast<uint16_t>(strtol(port + 1, nullptr, 10));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#include <vector>
|
||||
|
||||
|
||||
#include "base/tools/String.h"
|
||||
#include "base/net/stratum/Url.h"
|
||||
#include "crypto/common/Coin.h"
|
||||
#include "rapidjson/fwd.h"
|
||||
|
||||
|
@ -39,15 +39,17 @@
|
|||
namespace xmrig {
|
||||
|
||||
|
||||
class IClient;
|
||||
class IClientListener;
|
||||
|
||||
|
||||
class Pool
|
||||
{
|
||||
public:
|
||||
enum Flags {
|
||||
FLAG_ENABLED,
|
||||
FLAG_NICEHASH,
|
||||
FLAG_TLS,
|
||||
FLAG_DAEMON,
|
||||
FLAG_MAX
|
||||
enum Mode {
|
||||
MODE_POOL,
|
||||
MODE_DAEMON,
|
||||
MODE_SELF_SELECT
|
||||
};
|
||||
|
||||
static const String kDefaultPassword;
|
||||
|
@ -57,7 +59,7 @@ public:
|
|||
constexpr static uint16_t kDefaultPort = 3333;
|
||||
constexpr static uint64_t kDefaultPollInterval = 1000;
|
||||
|
||||
Pool();
|
||||
Pool() = default;
|
||||
Pool(const char *url);
|
||||
Pool(const rapidjson::Value &object);
|
||||
Pool(const char *host,
|
||||
|
@ -69,20 +71,21 @@ public:
|
|||
bool tls = false
|
||||
);
|
||||
|
||||
inline bool isDaemon() const { return m_flags.test(FLAG_DAEMON); }
|
||||
inline bool isNicehash() const { return m_flags.test(FLAG_NICEHASH); }
|
||||
inline bool isTLS() const { return m_flags.test(FLAG_TLS); }
|
||||
inline bool isValid() const { return !m_host.isNull() && m_port > 0; }
|
||||
inline bool isValid() const { return m_url.isValid(); }
|
||||
inline const Algorithm &algorithm() const { return m_algorithm; }
|
||||
inline const Coin &coin() const { return m_coin; }
|
||||
inline const String &fingerprint() const { return m_fingerprint; }
|
||||
inline const String &host() const { return m_host; }
|
||||
inline const String &host() const { return m_url.host(); }
|
||||
inline const String &password() const { return !m_password.isNull() ? m_password : kDefaultPassword; }
|
||||
inline const String &rigId() const { return m_rigId; }
|
||||
inline const String &url() const { return m_url; }
|
||||
inline const String &url() const { return m_url.url(); }
|
||||
inline const String &user() const { return !m_user.isNull() ? m_user : kDefaultUser; }
|
||||
inline const Url &daemon() const { return m_daemon; }
|
||||
inline int keepAlive() const { return m_keepAlive; }
|
||||
inline uint16_t port() const { return m_port; }
|
||||
inline Mode mode() const { return m_mode; }
|
||||
inline uint16_t port() const { return m_url.port(); }
|
||||
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; }
|
||||
|
@ -94,31 +97,37 @@ public:
|
|||
|
||||
bool isEnabled() const;
|
||||
bool isEqual(const Pool &other) const;
|
||||
bool parse(const char *url);
|
||||
IClient *createClient(int id, IClientListener *listener) const;
|
||||
rapidjson::Value toJSON(rapidjson::Document &doc) const;
|
||||
std::string printableName() const;
|
||||
|
||||
# ifdef APP_DEBUG
|
||||
void print() const;
|
||||
# endif
|
||||
|
||||
private:
|
||||
enum Flags {
|
||||
FLAG_ENABLED,
|
||||
FLAG_NICEHASH,
|
||||
FLAG_TLS,
|
||||
FLAG_MAX
|
||||
};
|
||||
|
||||
inline void setKeepAlive(bool enable) { setKeepAlive(enable ? kKeepAliveTimeout : 0); }
|
||||
inline void setKeepAlive(int keepAlive) { m_keepAlive = keepAlive >= 0 ? keepAlive : 0; }
|
||||
|
||||
bool parseIPv6(const char *addr);
|
||||
|
||||
Algorithm m_algorithm;
|
||||
Coin m_coin;
|
||||
int m_keepAlive;
|
||||
std::bitset<FLAG_MAX> m_flags;
|
||||
int m_keepAlive = 0;
|
||||
Mode m_mode = MODE_POOL;
|
||||
std::bitset<FLAG_MAX> m_flags = 0;
|
||||
String m_fingerprint;
|
||||
String m_host;
|
||||
String m_password;
|
||||
String m_rigId;
|
||||
String m_url;
|
||||
String m_user;
|
||||
uint16_t m_port;
|
||||
uint64_t m_pollInterval;
|
||||
uint64_t m_pollInterval = kDefaultPollInterval;
|
||||
Url m_daemon;
|
||||
Url m_url;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ xmrig::IStrategy *xmrig::Pools::createStrategy(IStrategyListener *listener) cons
|
|||
}
|
||||
}
|
||||
|
||||
FailoverStrategy *strategy = new FailoverStrategy(retryPause(), retries(), listener);
|
||||
auto strategy = new FailoverStrategy(retryPause(), retries(), listener);
|
||||
for (const Pool &pool : m_data) {
|
||||
if (pool.isEnabled()) {
|
||||
strategy->add(pool);
|
||||
|
@ -135,13 +135,7 @@ void xmrig::Pools::print() const
|
|||
{
|
||||
size_t i = 1;
|
||||
for (const Pool &pool : m_data) {
|
||||
Log::print(GREEN_BOLD(" * ") WHITE_BOLD("POOL #%-7zu") CSI "1;%dm%s" CLEAR " %s " WHITE_BOLD("%s"),
|
||||
i,
|
||||
(pool.isEnabled() ? (pool.isTLS() ? 32 : 36) : 31),
|
||||
pool.url().data(),
|
||||
pool.coin().isValid() ? "coin" : "algo",
|
||||
pool.coin().isValid() ? pool.coin().name() : (pool.algorithm().isValid() ? pool.algorithm().shortName() : "auto")
|
||||
);
|
||||
Log::print(GREEN_BOLD(" * ") WHITE_BOLD("POOL #%-7zu") "%s", i, pool.printableName().c_str());
|
||||
|
||||
i++;
|
||||
}
|
||||
|
|
302
src/base/net/stratum/SelfSelectClient.cpp
Normal file
302
src/base/net/stratum/SelfSelectClient.cpp
Normal file
|
@ -0,0 +1,302 @@
|
|||
/* 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 2018-2019 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright 2019 jtgrassie <https://github.com/jtgrassie>
|
||||
* Copyright 2016-2019 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 "base/net/stratum/SelfSelectClient.h"
|
||||
#include "3rdparty/http-parser/http_parser.h"
|
||||
#include "base/io/json/Json.h"
|
||||
#include "base/io/json/JsonRequest.h"
|
||||
#include "base/io/log/Log.h"
|
||||
#include "base/net/http/HttpClient.h"
|
||||
#include "base/net/stratum/Client.h"
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/error/en.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include "rapidjson/writer.h"
|
||||
|
||||
|
||||
#ifdef XMRIG_FEATURE_TLS
|
||||
# include "base/net/http/HttpsClient.h"
|
||||
#endif
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
||||
static const char *kBlob = "blob";
|
||||
static const char *kBlockhashingBlob = "blockhashing_blob";
|
||||
static const char *kBlocktemplateBlob = "blocktemplate_blob";
|
||||
static const char *kDifficulty = "difficulty";
|
||||
static const char *kHeight = "height";
|
||||
static const char *kId = "id";
|
||||
static const char *kJobId = "job_id";
|
||||
static const char *kNextSeedHash = "next_seed_hash";
|
||||
static const char *kPrevHash = "prev_hash";
|
||||
static const char *kSeedHash = "seed_hash";
|
||||
|
||||
static const char * const required_fields[] = { kBlocktemplateBlob, kBlockhashingBlob, kHeight, kDifficulty, kPrevHash };
|
||||
|
||||
} /* namespace xmrig */
|
||||
|
||||
|
||||
xmrig::SelfSelectClient::SelfSelectClient(int id, const char *agent, IClientListener *listener) :
|
||||
m_listener(listener)
|
||||
{
|
||||
m_client = new Client(id, agent, this);
|
||||
}
|
||||
|
||||
|
||||
xmrig::SelfSelectClient::~SelfSelectClient()
|
||||
{
|
||||
delete m_client;
|
||||
}
|
||||
|
||||
|
||||
void xmrig::SelfSelectClient::tick(uint64_t now)
|
||||
{
|
||||
m_client->tick(now);
|
||||
|
||||
if (m_state == RetryState) {
|
||||
if (Chrono::steadyMSecs() - m_timestamp < m_retryPause) {
|
||||
return;
|
||||
}
|
||||
|
||||
getBlockTemplate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void xmrig::SelfSelectClient::onJobReceived(IClient *, const Job &job, const rapidjson::Value &)
|
||||
{
|
||||
m_job = job;
|
||||
|
||||
getBlockTemplate();
|
||||
}
|
||||
|
||||
|
||||
void xmrig::SelfSelectClient::onLogin(IClient *, rapidjson::Document &doc, rapidjson::Value ¶ms)
|
||||
{
|
||||
params.AddMember("mode", "self-select", doc.GetAllocator());
|
||||
|
||||
m_listener->onLogin(this, doc, params);
|
||||
}
|
||||
|
||||
|
||||
bool xmrig::SelfSelectClient::parseResponse(int64_t id, rapidjson::Value &result, const rapidjson::Value &error)
|
||||
{
|
||||
if (id == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (error.IsObject()) {
|
||||
LOG_ERR("[%s] error: " RED_BOLD("\"%s\"") RED_S ", code: %d", pool().daemon().url().data(), Json::getString(error, "message"), Json::getInt(error, "code"));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!result.IsObject()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto field : required_fields) {
|
||||
if (!result.HasMember(field)) {
|
||||
LOG_ERR("[%s] required field " RED_BOLD("\"%s\"") RED_S " not found", pool().daemon().url().data(), field);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_job.setBlob(result[kBlockhashingBlob].GetString())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_job.setHeight(Json::getUint64(result, kHeight));
|
||||
m_job.setSeedHash(Json::getString(result, kSeedHash));
|
||||
|
||||
submitBlockTemplate(result);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void xmrig::SelfSelectClient::getBlockTemplate()
|
||||
{
|
||||
setState(WaitState);
|
||||
|
||||
using namespace rapidjson;
|
||||
Document doc(kObjectType);
|
||||
auto &allocator = doc.GetAllocator();
|
||||
|
||||
Value params(kObjectType);
|
||||
params.AddMember("wallet_address", m_job.poolWallet().toJSON(), allocator);
|
||||
params.AddMember("extra_nonce", m_job.extraNonce().toJSON(), allocator);
|
||||
|
||||
JsonRequest::create(doc, m_sequence++, "getblocktemplate", params);
|
||||
|
||||
send(HTTP_POST, "/json_rpc", doc);
|
||||
}
|
||||
|
||||
|
||||
void xmrig::SelfSelectClient::retry()
|
||||
{
|
||||
setState(RetryState);
|
||||
}
|
||||
|
||||
|
||||
void xmrig::SelfSelectClient::send(int method, const char *url, const char *data, size_t size)
|
||||
{
|
||||
LOG_DEBUG("[%s] " MAGENTA_BOLD("\"%s %s\"") BLACK_BOLD_S " send (%zu bytes): \"%.*s\"",
|
||||
pool().daemon().url().data(),
|
||||
http_method_str(static_cast<http_method>(method)),
|
||||
url,
|
||||
size,
|
||||
static_cast<int>(size),
|
||||
data);
|
||||
|
||||
HttpClient *client;
|
||||
# ifdef XMRIG_FEATURE_TLS
|
||||
if (pool().daemon().isTLS()) {
|
||||
client = new HttpsClient(method, url, this, data, size, String());
|
||||
}
|
||||
else
|
||||
# endif
|
||||
{
|
||||
client = new HttpClient(method, url, this, data, size);
|
||||
}
|
||||
|
||||
client->setQuiet(isQuiet());
|
||||
client->connect(pool().daemon().host(), pool().daemon().port());
|
||||
}
|
||||
|
||||
|
||||
void xmrig::SelfSelectClient::send(int method, const char *url, const rapidjson::Document &doc)
|
||||
{
|
||||
using namespace rapidjson;
|
||||
|
||||
StringBuffer buffer(nullptr, 512);
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
doc.Accept(writer);
|
||||
|
||||
send(method, url, buffer.GetString(), buffer.GetSize());
|
||||
}
|
||||
|
||||
|
||||
void xmrig::SelfSelectClient::setState(State state)
|
||||
{
|
||||
if (m_state == state) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case IdleState:
|
||||
m_timestamp = 0;
|
||||
m_failures = 0;
|
||||
break;
|
||||
|
||||
case WaitState:
|
||||
m_timestamp = Chrono::steadyMSecs();
|
||||
break;
|
||||
|
||||
case RetryState:
|
||||
m_timestamp = Chrono::steadyMSecs();
|
||||
|
||||
if (m_failures > m_retries) {
|
||||
m_listener->onClose(this, static_cast<int>(m_failures));
|
||||
}
|
||||
|
||||
m_failures++;
|
||||
break;
|
||||
}
|
||||
|
||||
m_state = state;
|
||||
}
|
||||
|
||||
|
||||
void xmrig::SelfSelectClient::submitBlockTemplate(rapidjson::Value &result)
|
||||
{
|
||||
using namespace rapidjson;
|
||||
Document doc(kObjectType);
|
||||
auto &allocator = doc.GetAllocator();
|
||||
|
||||
Value params(kObjectType);
|
||||
params.AddMember(StringRef(kId), m_job.clientId().toJSON(), allocator);
|
||||
params.AddMember(StringRef(kJobId), m_job.id().toJSON(), allocator);
|
||||
params.AddMember(StringRef(kBlob), result[kBlocktemplateBlob], allocator);
|
||||
params.AddMember(StringRef(kHeight), m_job.height(), allocator);
|
||||
params.AddMember(StringRef(kDifficulty), result[kDifficulty], allocator);
|
||||
params.AddMember(StringRef(kPrevHash), result[kPrevHash], allocator);
|
||||
params.AddMember(StringRef(kSeedHash), result[kSeedHash], allocator);
|
||||
params.AddMember(StringRef(kNextSeedHash), result[kNextSeedHash], allocator);
|
||||
|
||||
JsonRequest::create(doc, sequence(), "block_template", params);
|
||||
|
||||
send(doc, [this](const rapidjson::Value &result, bool success, uint64_t elapsed) {
|
||||
if (!success) {
|
||||
if (!isQuiet()) {
|
||||
LOG_ERR("[%s] error: " RED_BOLD("\"%s\"") RED_S ", code: %d", pool().daemon().url().data(), Json::getString(result, "message"), Json::getInt(result, "code"));
|
||||
}
|
||||
|
||||
return retry();
|
||||
}
|
||||
|
||||
if (!m_active) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_failures > m_retries) {
|
||||
m_listener->onLoginSuccess(this);
|
||||
}
|
||||
|
||||
setState(IdleState);
|
||||
m_listener->onJobReceived(this, m_job, rapidjson::Value{});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void xmrig::SelfSelectClient::onHttpData(const HttpData &data)
|
||||
{
|
||||
if (data.status != HTTP_STATUS_OK) {
|
||||
return retry();
|
||||
}
|
||||
|
||||
LOG_DEBUG("[%s] received (%d bytes): \"%.*s\"", pool().daemon().url().data(), static_cast<int>(data.body.size()), static_cast<int>(data.body.size()), data.body.c_str());
|
||||
|
||||
rapidjson::Document doc;
|
||||
if (doc.Parse(data.body.c_str()).HasParseError()) {
|
||||
if (!isQuiet()) {
|
||||
LOG_ERR("[%s] JSON decode failed: \"%s\"", pool().daemon().url().data(), rapidjson::GetParseError_En(doc.GetParseError()));
|
||||
}
|
||||
|
||||
return retry();
|
||||
}
|
||||
|
||||
const int64_t id = Json::getInt64(doc, "id", -1);
|
||||
if (id > 0 && m_sequence - id != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!parseResponse(id, doc["result"], Json::getObject(doc, "error"))) {
|
||||
retry();
|
||||
}
|
||||
}
|
123
src/base/net/stratum/SelfSelectClient.h
Normal file
123
src/base/net/stratum/SelfSelectClient.h
Normal file
|
@ -0,0 +1,123 @@
|
|||
/* 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 2018-2019 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright 2019 jtgrassie <https://github.com/jtgrassie>
|
||||
* Copyright 2016-2019 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_SELFSELECTCLIENT_H
|
||||
#define XMRIG_SELFSELECTCLIENT_H
|
||||
|
||||
|
||||
#include "base/kernel/interfaces/IClient.h"
|
||||
#include "base/kernel/interfaces/IClientListener.h"
|
||||
#include "base/kernel/interfaces/IHttpListener.h"
|
||||
#include "base/net/stratum/Job.h"
|
||||
#include "base/tools/Object.h"
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
||||
|
||||
class SelfSelectClient : public IClient, public IClientListener, public IHttpListener
|
||||
{
|
||||
public:
|
||||
XMRIG_DISABLE_COPY_MOVE_DEFAULT(SelfSelectClient)
|
||||
|
||||
SelfSelectClient(int id, const char *agent, IClientListener *listener);
|
||||
~SelfSelectClient() override;
|
||||
|
||||
protected:
|
||||
// IClient
|
||||
inline bool disconnect() override { return m_client->disconnect(); }
|
||||
inline bool hasExtension(Extension extension) const noexcept override { return m_client->hasExtension(extension); }
|
||||
inline bool isEnabled() const override { return m_client->isEnabled(); }
|
||||
inline bool isTLS() const override { return m_client->isTLS(); }
|
||||
inline const char *mode() const override { return m_client->mode(); }
|
||||
inline const char *tlsFingerprint() const override { return m_client->tlsFingerprint(); }
|
||||
inline const char *tlsVersion() const override { return m_client->tlsVersion(); }
|
||||
inline const Job &job() const override { return m_client->job(); }
|
||||
inline const Pool &pool() const override { return m_client->pool(); }
|
||||
inline const String &ip() const override { return m_client->ip(); }
|
||||
inline int id() const override { return m_client->id(); }
|
||||
inline int64_t send(const rapidjson::Value &obj, Callback callback) override { return m_client->send(obj, callback); }
|
||||
inline int64_t send(const rapidjson::Value &obj) override { return m_client->send(obj); }
|
||||
inline int64_t sequence() const override { return m_client->sequence(); }
|
||||
inline int64_t submit(const JobResult &result) override { return m_client->submit(result); }
|
||||
inline void connect() override { m_client->connect(); }
|
||||
inline void connect(const Pool &pool) override { m_client->connect(pool); }
|
||||
inline void deleteLater() override { m_client->deleteLater(); }
|
||||
inline void setAlgo(const Algorithm &algo) override { m_client->setAlgo(algo); }
|
||||
inline void setEnabled(bool enabled) override { m_client->setEnabled(enabled); }
|
||||
inline void setPool(const Pool &pool) override { m_client->setPool(pool); }
|
||||
inline void setQuiet(bool quiet) override { m_client->setQuiet(quiet); m_quiet = quiet; }
|
||||
inline void setRetries(int retries) override { m_client->setRetries(retries); m_retries = retries; }
|
||||
inline void setRetryPause(uint64_t ms) override { m_client->setRetryPause(ms); m_retryPause = ms; }
|
||||
|
||||
void tick(uint64_t now) override;
|
||||
|
||||
// IClientListener
|
||||
inline void onClose(IClient *, int failures) override { m_listener->onClose(this, failures); setState(IdleState); m_active = false; }
|
||||
inline void onLoginSuccess(IClient *) override { m_listener->onLoginSuccess(this); setState(IdleState); m_active = true; }
|
||||
inline void onResultAccepted(IClient *, const SubmitResult &result, const char *error) override { m_listener->onResultAccepted(this, result, error); }
|
||||
inline void onVerifyAlgorithm(const IClient *, const Algorithm &algorithm, bool *ok) override { m_listener->onVerifyAlgorithm(this, algorithm, ok); }
|
||||
|
||||
void onJobReceived(IClient *, const Job &job, const rapidjson::Value ¶ms) override;
|
||||
void onLogin(IClient *, rapidjson::Document &doc, rapidjson::Value ¶ms) override;
|
||||
|
||||
// IHttpListener
|
||||
void onHttpData(const HttpData &data) override;
|
||||
|
||||
private:
|
||||
enum State {
|
||||
IdleState,
|
||||
WaitState,
|
||||
RetryState
|
||||
};
|
||||
|
||||
inline bool isQuiet() const { return m_quiet || m_failures >= m_retries; }
|
||||
|
||||
bool parseResponse(int64_t id, rapidjson::Value &result, const rapidjson::Value &error);
|
||||
void getBlockTemplate();
|
||||
void retry();
|
||||
void send(int method, const char *url, const char *data = nullptr, size_t size = 0);
|
||||
void send(int method, const char *url, const rapidjson::Document &doc);
|
||||
void setState(State state);
|
||||
void submitBlockTemplate(rapidjson::Value &result);
|
||||
|
||||
bool m_active = false;
|
||||
bool m_quiet = false;
|
||||
IClient *m_client;
|
||||
IClientListener *m_listener;
|
||||
int m_retries = 5;
|
||||
int64_t m_failures = 0;
|
||||
int64_t m_sequence = 1;
|
||||
Job m_job;
|
||||
State m_state = IdleState;
|
||||
uint64_t m_retryPause = 5000;
|
||||
uint64_t m_timestamp = 0;
|
||||
};
|
||||
|
||||
|
||||
} /* namespace xmrig */
|
||||
|
||||
|
||||
#endif /* XMRIG_SELFSELECTCLIENT_H */
|
|
@ -35,34 +35,26 @@ namespace xmrig {
|
|||
class SubmitResult
|
||||
{
|
||||
public:
|
||||
inline SubmitResult() :
|
||||
reqId(0),
|
||||
seq(0),
|
||||
actualDiff(0),
|
||||
diff(0),
|
||||
elapsed(0),
|
||||
m_start(0)
|
||||
{}
|
||||
SubmitResult() = default;
|
||||
|
||||
inline SubmitResult(int64_t seq, uint64_t diff, uint64_t actualDiff, int64_t reqId = 0) :
|
||||
reqId(reqId),
|
||||
seq(seq),
|
||||
actualDiff(actualDiff),
|
||||
diff(diff),
|
||||
elapsed(0),
|
||||
m_start(Chrono::steadyMSecs())
|
||||
{}
|
||||
|
||||
inline void done() { elapsed = Chrono::steadyMSecs() - m_start; }
|
||||
|
||||
int64_t reqId;
|
||||
int64_t seq;
|
||||
uint64_t actualDiff;
|
||||
uint64_t diff;
|
||||
uint64_t elapsed;
|
||||
int64_t reqId = 0;
|
||||
int64_t seq = 0;
|
||||
uint64_t actualDiff = 0;
|
||||
uint64_t diff = 0;
|
||||
uint64_t elapsed = 0;
|
||||
|
||||
private:
|
||||
uint64_t m_start;
|
||||
uint64_t m_start = 0;
|
||||
};
|
||||
|
||||
|
||||
|
|
163
src/base/net/stratum/Url.cpp
Normal file
163
src/base/net/stratum/Url.cpp
Normal file
|
@ -0,0 +1,163 @@
|
|||
/* 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-2019 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
|
||||
* Copyright 2018-2019 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright 2019 Howard Chu <https://github.com/hyc>
|
||||
* Copyright 2016-2019 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 "base/net/stratum/Url.h"
|
||||
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define strncasecmp _strnicmp
|
||||
#endif
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
||||
static const char kStratumTcp[] = "stratum+tcp://";
|
||||
static const char kStratumSsl[] = "stratum+ssl://";
|
||||
|
||||
#ifdef XMRIG_FEATURE_HTTP
|
||||
static const char kDaemonHttp[] = "daemon+http://";
|
||||
static const char kDaemonHttps[] = "daemon+https://";
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
xmrig::Url::Url(const char *url)
|
||||
{
|
||||
parse(url);
|
||||
}
|
||||
|
||||
|
||||
xmrig::Url::Url(const char *host, uint16_t port, bool tls, Scheme scheme) :
|
||||
m_tls(tls),
|
||||
m_scheme(scheme),
|
||||
m_host(host),
|
||||
m_port(port)
|
||||
{
|
||||
const size_t size = m_host.size() + 8;
|
||||
assert(size > 8);
|
||||
|
||||
char *url = new char[size]();
|
||||
snprintf(url, size - 1, "%s:%d", m_host.data(), m_port);
|
||||
|
||||
m_url = url;
|
||||
}
|
||||
|
||||
|
||||
bool xmrig::Url::isEqual(const Url &other) const
|
||||
{
|
||||
return (m_tls == other.m_tls && m_scheme == other.m_scheme && m_host == other.m_host && m_url == other.m_url && m_port == other.m_port);
|
||||
}
|
||||
|
||||
|
||||
bool xmrig::Url::parse(const char *url)
|
||||
{
|
||||
if (url == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *p = strstr(url, "://");
|
||||
const char *base = url;
|
||||
|
||||
if (p) {
|
||||
if (strncasecmp(url, kStratumTcp, sizeof(kStratumTcp) - 1) == 0) {
|
||||
m_scheme = STRATUM;
|
||||
m_tls = false;
|
||||
}
|
||||
else if (strncasecmp(url, kStratumSsl, sizeof(kStratumSsl) - 1) == 0) {
|
||||
m_scheme = STRATUM;
|
||||
m_tls = true;
|
||||
}
|
||||
# ifdef XMRIG_FEATURE_HTTP
|
||||
else if (strncasecmp(url, kDaemonHttps, sizeof(kDaemonHttps) - 1) == 0) {
|
||||
m_scheme = DAEMON;
|
||||
m_tls = true;
|
||||
}
|
||||
else if (strncasecmp(url, kDaemonHttp, sizeof(kDaemonHttp) - 1) == 0) {
|
||||
m_scheme = DAEMON;
|
||||
m_tls = false;
|
||||
}
|
||||
# endif
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
base = p + 3;
|
||||
}
|
||||
|
||||
if (!strlen(base) || *base == '/') {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_url = url;
|
||||
if (base[0] == '[') {
|
||||
return parseIPv6(base);
|
||||
}
|
||||
|
||||
const char *port = strchr(base, ':');
|
||||
if (!port) {
|
||||
m_host = base;
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto size = static_cast<size_t>(port++ - base + 1);
|
||||
char *host = new char[size]();
|
||||
memcpy(host, base, size - 1);
|
||||
|
||||
m_host = host;
|
||||
m_port = static_cast<uint16_t>(strtol(port, nullptr, 10));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool xmrig::Url::parseIPv6(const char *addr)
|
||||
{
|
||||
const char *end = strchr(addr, ']');
|
||||
if (!end) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *port = strchr(end, ':');
|
||||
if (!port) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto size = static_cast<size_t>(end - addr);
|
||||
char *host = new char[size]();
|
||||
memcpy(host, addr + 1, size - 1);
|
||||
|
||||
m_host = host;
|
||||
m_port = static_cast<uint16_t>(strtol(port + 1, nullptr, 10));
|
||||
|
||||
return true;
|
||||
}
|
77
src/base/net/stratum/Url.h
Normal file
77
src/base/net/stratum/Url.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
/* 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 2018-2019 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright 2019 Howard Chu <https://github.com/hyc>
|
||||
* Copyright 2016-2019 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_URL_H
|
||||
#define XMRIG_URL_H
|
||||
|
||||
|
||||
#include "base/tools/String.h"
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
||||
|
||||
class Url
|
||||
{
|
||||
public:
|
||||
enum Scheme {
|
||||
UNSPECIFIED,
|
||||
STRATUM,
|
||||
DAEMON
|
||||
};
|
||||
|
||||
Url() = default;
|
||||
Url(const char *url);
|
||||
Url(const char *host, uint16_t port, bool tls = false, Scheme scheme = UNSPECIFIED);
|
||||
|
||||
inline bool isTLS() const { return m_tls; }
|
||||
inline bool isValid() const { return !m_host.isNull() && m_port > 0; }
|
||||
inline const String &host() const { return m_host; }
|
||||
inline const String &url() const { return m_url; }
|
||||
inline Scheme scheme() const { return m_scheme; }
|
||||
inline uint16_t port() const { return m_port; }
|
||||
|
||||
inline bool operator!=(const Url &other) const { return !isEqual(other); }
|
||||
inline bool operator==(const Url &other) const { return isEqual(other); }
|
||||
|
||||
bool isEqual(const Url &other) const;
|
||||
rapidjson::Value toJSON(rapidjson::Document &doc) const;
|
||||
|
||||
private:
|
||||
bool parse(const char *url);
|
||||
bool parseIPv6(const char *addr);
|
||||
|
||||
bool m_tls = false;
|
||||
Scheme m_scheme = UNSPECIFIED;
|
||||
String m_host;
|
||||
String m_url;
|
||||
uint16_t m_port = 3333;
|
||||
};
|
||||
|
||||
|
||||
} /* namespace xmrig */
|
||||
|
||||
|
||||
#endif /* XMRIG_URL_H */
|
|
@ -23,15 +23,10 @@
|
|||
*/
|
||||
|
||||
|
||||
#include "base/net/stratum/strategies/FailoverStrategy.h"
|
||||
#include "base/kernel/interfaces/IClient.h"
|
||||
#include "base/kernel/interfaces/IStrategyListener.h"
|
||||
#include "base/kernel/Platform.h"
|
||||
#include "base/net/stratum/Client.h"
|
||||
#include "base/net/stratum/strategies/FailoverStrategy.h"
|
||||
|
||||
|
||||
#ifdef XMRIG_FEATURE_HTTP
|
||||
# include "base/net/stratum/DaemonClient.h"
|
||||
#endif
|
||||
|
||||
|
||||
xmrig::FailoverStrategy::FailoverStrategy(const std::vector<Pool> &pools, int retryPause, int retries, IStrategyListener *listener, bool quiet) :
|
||||
|
@ -69,16 +64,8 @@ xmrig::FailoverStrategy::~FailoverStrategy()
|
|||
|
||||
void xmrig::FailoverStrategy::add(const Pool &pool)
|
||||
{
|
||||
const int id = static_cast<int>(m_pools.size());
|
||||
IClient *client = pool.createClient(static_cast<int>(m_pools.size()), this);
|
||||
|
||||
# ifdef XMRIG_FEATURE_HTTP
|
||||
IClient *client = !pool.isDaemon() ? static_cast<IClient *>(new Client(id, Platform::userAgent(), this))
|
||||
: static_cast<IClient *>(new DaemonClient(id, this));
|
||||
# else
|
||||
IClient *client = new Client(id, Platform::userAgent(), this);
|
||||
# endif
|
||||
|
||||
client->setPool(pool);
|
||||
client->setRetries(m_retries);
|
||||
client->setRetryPause(m_retryPause * 1000);
|
||||
client->setQuiet(m_quiet);
|
||||
|
@ -123,8 +110,8 @@ void xmrig::FailoverStrategy::setAlgo(const Algorithm &algo)
|
|||
|
||||
void xmrig::FailoverStrategy::stop()
|
||||
{
|
||||
for (size_t i = 0; i < m_pools.size(); ++i) {
|
||||
m_pools[i]->disconnect();
|
||||
for (auto &pool : m_pools) {
|
||||
pool->disconnect();
|
||||
}
|
||||
|
||||
m_index = 0;
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "base/kernel/interfaces/IClientListener.h"
|
||||
#include "base/kernel/interfaces/IStrategy.h"
|
||||
#include "base/net/stratum/Pool.h"
|
||||
#include "base/tools/Object.h"
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
@ -44,6 +45,8 @@ class IStrategyListener;
|
|||
class FailoverStrategy : public IStrategy, public IClientListener
|
||||
{
|
||||
public:
|
||||
XMRIG_DISABLE_COPY_MOVE_DEFAULT(FailoverStrategy)
|
||||
|
||||
FailoverStrategy(const std::vector<Pool> &pool, int retryPause, int retries, IStrategyListener *listener, bool quiet = false);
|
||||
FailoverStrategy(int retryPause, int retries, IStrategyListener *listener, bool quiet = false);
|
||||
~FailoverStrategy() override;
|
||||
|
|
|
@ -23,33 +23,18 @@
|
|||
*/
|
||||
|
||||
|
||||
#include "base/net/stratum/strategies/SinglePoolStrategy.h"
|
||||
#include "base/kernel/interfaces/IClient.h"
|
||||
#include "base/kernel/interfaces/IStrategyListener.h"
|
||||
#include "base/kernel/Platform.h"
|
||||
#include "base/net/stratum/Client.h"
|
||||
#include "base/net/stratum/strategies/SinglePoolStrategy.h"
|
||||
|
||||
|
||||
#ifdef XMRIG_FEATURE_HTTP
|
||||
# include "base/net/stratum/DaemonClient.h"
|
||||
#endif
|
||||
#include "base/net/stratum/Pool.h"
|
||||
|
||||
|
||||
xmrig::SinglePoolStrategy::SinglePoolStrategy(const Pool &pool, int retryPause, int retries, IStrategyListener *listener, bool quiet) :
|
||||
m_active(false),
|
||||
m_listener(listener)
|
||||
{
|
||||
# ifdef XMRIG_FEATURE_HTTP
|
||||
if (!pool.isDaemon()) {
|
||||
m_client = new Client(0, Platform::userAgent(), this);
|
||||
}
|
||||
else {
|
||||
m_client = new DaemonClient(0, this);
|
||||
}
|
||||
# else
|
||||
m_client = new Client(0, Platform::userAgent(), this);
|
||||
# endif
|
||||
|
||||
m_client->setPool(pool);
|
||||
m_client = pool.createClient(0, this);
|
||||
m_client->setRetries(retries);
|
||||
m_client->setRetryPause(retryPause * 1000);
|
||||
m_client->setQuiet(quiet);
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "base/kernel/interfaces/IClientListener.h"
|
||||
#include "base/kernel/interfaces/IStrategy.h"
|
||||
#include "base/tools/Object.h"
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
@ -41,6 +42,8 @@ class Pool;
|
|||
class SinglePoolStrategy : public IStrategy, public IClientListener
|
||||
{
|
||||
public:
|
||||
XMRIG_DISABLE_COPY_MOVE_DEFAULT(SinglePoolStrategy)
|
||||
|
||||
SinglePoolStrategy(const Pool &pool, int retryPause, int retries, IStrategyListener *listener, bool quiet = false);
|
||||
~SinglePoolStrategy() override;
|
||||
|
||||
|
|
|
@ -54,7 +54,8 @@
|
|||
"enabled": true,
|
||||
"tls": false,
|
||||
"tls-fingerprint": null,
|
||||
"daemon": false
|
||||
"daemon": false,
|
||||
"self-select": null
|
||||
}
|
||||
],
|
||||
"print-time": 60,
|
||||
|
|
|
@ -152,6 +152,7 @@ public:
|
|||
reply.AddMember("ua", StringRef(Platform::userAgent()), allocator);
|
||||
reply.AddMember("cpu", Cpu::toJSON(doc), allocator);
|
||||
reply.AddMember("donate_level", controller->config()->pools().donateLevel(), allocator);
|
||||
reply.AddMember("paused", !enabled, allocator);
|
||||
|
||||
Value algo(kArrayType);
|
||||
|
||||
|
|
|
@ -88,7 +88,8 @@ R"===(
|
|||
"enabled": true,
|
||||
"tls": false,
|
||||
"tls-fingerprint": null,
|
||||
"daemon": false
|
||||
"daemon": false,
|
||||
"self-select": null
|
||||
}
|
||||
],
|
||||
"print-time": 60,
|
||||
|
|
|
@ -56,6 +56,7 @@ static const option options[] = {
|
|||
{ "http-no-restricted", 0, nullptr, IConfig::HttpRestrictedKey },
|
||||
{ "daemon", 0, nullptr, IConfig::DaemonKey },
|
||||
{ "daemon-poll-interval", 1, nullptr, IConfig::DaemonPollKey },
|
||||
{ "self-select", 1, nullptr, IConfig::SelfSelectKey },
|
||||
# endif
|
||||
{ "av", 1, nullptr, IConfig::AVKey },
|
||||
{ "background", 0, nullptr, IConfig::BackgroundKey },
|
||||
|
|
|
@ -62,6 +62,7 @@ static inline const std::string &usage()
|
|||
# ifdef XMRIG_FEATURE_HTTP
|
||||
u += " --daemon use daemon RPC instead of pool for solo mining\n";
|
||||
u += " --daemon-poll-interval=N daemon poll interval in milliseconds (default: 1000)\n";
|
||||
u += " --self-select=URL self-select block templates from URL\n";
|
||||
# endif
|
||||
|
||||
u += " -r, --retries=N number of times to retry before switch to backup server (default: 5)\n";
|
||||
|
|
|
@ -41,8 +41,7 @@ constexpr size_t pageSize = 2 * 1024 * 1024;
|
|||
} // namespace xmrig
|
||||
|
||||
|
||||
xmrig::MemoryPool::MemoryPool(size_t size, bool hugePages, uint32_t node) :
|
||||
m_size(size)
|
||||
xmrig::MemoryPool::MemoryPool(size_t size, bool hugePages, uint32_t node)
|
||||
{
|
||||
if (!size) {
|
||||
return;
|
||||
|
|
|
@ -52,7 +52,6 @@ protected:
|
|||
void release(uint32_t node) override;
|
||||
|
||||
private:
|
||||
size_t m_size = 0;
|
||||
size_t m_refs = 0;
|
||||
size_t m_offset = 0;
|
||||
VirtualMemory *m_memory = nullptr;
|
||||
|
|
|
@ -34,15 +34,6 @@
|
|||
#include <algorithm>
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
||||
|
||||
constexpr size_t pageSize = 2 * 1024 * 1024;
|
||||
|
||||
|
||||
} // namespace xmrig
|
||||
|
||||
|
||||
xmrig::NUMAMemoryPool::NUMAMemoryPool(size_t size, bool hugePages) :
|
||||
m_hugePages(hugePages),
|
||||
m_nodeSize(std::max<size_t>(size / Cpu::info()->nodes(), 1)),
|
||||
|
|
|
@ -112,7 +112,7 @@ void xmrig::VirtualMemory::destroy()
|
|||
void xmrig::VirtualMemory::init(size_t poolSize, bool hugePages)
|
||||
{
|
||||
if (!pool) {
|
||||
osInit();
|
||||
osInit(hugePages);
|
||||
}
|
||||
|
||||
# ifdef XMRIG_FEATURE_HWLOC
|
||||
|
|
|
@ -78,7 +78,7 @@ private:
|
|||
FLAG_MAX
|
||||
};
|
||||
|
||||
static void osInit();
|
||||
static void osInit(bool hugePages);
|
||||
|
||||
bool allocateLargePagesMemory();
|
||||
void freeLargePagesMemory();
|
||||
|
|
|
@ -96,7 +96,7 @@ void xmrig::VirtualMemory::unprotectExecutableMemory(void *p, size_t size)
|
|||
}
|
||||
|
||||
|
||||
void xmrig::VirtualMemory::osInit()
|
||||
void xmrig::VirtualMemory::osInit(bool)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -201,9 +201,11 @@ void xmrig::VirtualMemory::unprotectExecutableMemory(void *p, size_t size)
|
|||
}
|
||||
|
||||
|
||||
void xmrig::VirtualMemory::osInit()
|
||||
void xmrig::VirtualMemory::osInit(bool hugePages)
|
||||
{
|
||||
hugepagesAvailable = TrySetLockPagesPrivilege();
|
||||
if (hugePages) {
|
||||
hugepagesAvailable = TrySetLockPagesPrivilege();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ static size_t CalcDatasetItemSize()
|
|||
{
|
||||
return
|
||||
// Prologue
|
||||
((uint8_t*)randomx_calc_dataset_item_aarch64_prefetch - (uint8_t*)randomx_calc_dataset_item_aarch64) +
|
||||
((uint8_t*)randomx_calc_dataset_item_aarch64_prefetch - (uint8_t*)randomx_calc_dataset_item_aarch64) +
|
||||
// Main loop
|
||||
RandomX_CurrentConfig.CacheAccesses * (
|
||||
// Main loop prologue
|
||||
|
@ -82,7 +82,7 @@ static size_t CalcDatasetItemSize()
|
|||
((RandomX_CurrentConfig.SuperscalarLatency * 3) + 2) * 16 +
|
||||
// Main loop epilogue
|
||||
((uint8_t*)randomx_calc_dataset_item_aarch64_store_result - (uint8_t*)randomx_calc_dataset_item_aarch64_mix) + 4
|
||||
) +
|
||||
) +
|
||||
// Epilogue
|
||||
((uint8_t*)randomx_calc_dataset_item_aarch64_end - (uint8_t*)randomx_calc_dataset_item_aarch64_store_result);
|
||||
}
|
||||
|
@ -103,6 +103,21 @@ JitCompilerA64::~JitCompilerA64()
|
|||
freePagedMemory(code, CodeSize + CalcDatasetItemSize());
|
||||
}
|
||||
|
||||
#if defined(ios_HOST_OS) || defined (darwin_HOST_OS)
|
||||
void sys_icache_invalidate(void *start, size_t len);
|
||||
#endif
|
||||
|
||||
static void clear_code_cache(char* p1, char* p2)
|
||||
{
|
||||
# if defined(ios_HOST_OS) || defined (darwin_HOST_OS)
|
||||
sys_icache_invalidate(p1, static_cast<size_t>(p2 - p1));
|
||||
# elif defined (HAVE_BUILTIN_CLEAR_CACHE) || defined (__GNUC__)
|
||||
__builtin___clear_cache(p1, p2);
|
||||
# else
|
||||
# error "No clear code cache function found"
|
||||
# endif
|
||||
}
|
||||
|
||||
void JitCompilerA64::generateProgram(Program& program, ProgramConfiguration& config)
|
||||
{
|
||||
uint32_t codePos = MainLoopBegin + 4;
|
||||
|
@ -149,9 +164,7 @@ void JitCompilerA64::generateProgram(Program& program, ProgramConfiguration& con
|
|||
codePos = ((uint8_t*)randomx_program_aarch64_update_spMix1) - ((uint8_t*)randomx_program_aarch64);
|
||||
emit32(ARMV8A::EOR | 10 | (IntRegMap[config.readReg0] << 5) | (IntRegMap[config.readReg1] << 16), code, codePos);
|
||||
|
||||
#ifdef __GNUC__
|
||||
__builtin___clear_cache(reinterpret_cast<char*>(code + MainLoopBegin), reinterpret_cast<char*>(code + codePos));
|
||||
#endif
|
||||
clear_code_cache(reinterpret_cast<char*>(code + MainLoopBegin), reinterpret_cast<char*>(code + codePos));
|
||||
}
|
||||
|
||||
void JitCompilerA64::generateProgramLight(Program& program, ProgramConfiguration& config, uint32_t datasetOffset)
|
||||
|
@ -206,9 +219,7 @@ void JitCompilerA64::generateProgramLight(Program& program, ProgramConfiguration
|
|||
emit32(ARMV8A::ADD_IMM_LO | 2 | (2 << 5) | (imm_lo << 10), code, codePos);
|
||||
emit32(ARMV8A::ADD_IMM_HI | 2 | (2 << 5) | (imm_hi << 10), code, codePos);
|
||||
|
||||
#ifdef __GNUC__
|
||||
__builtin___clear_cache(reinterpret_cast<char*>(code + MainLoopBegin), reinterpret_cast<char*>(code + codePos));
|
||||
#endif
|
||||
clear_code_cache(reinterpret_cast<char*>(code + MainLoopBegin), reinterpret_cast<char*>(code + codePos));
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
|
@ -324,9 +335,7 @@ void JitCompilerA64::generateSuperscalarHash(SuperscalarProgram(&programs)[N], s
|
|||
memcpy(code + codePos, p1, p2 - p1);
|
||||
codePos += p2 - p1;
|
||||
|
||||
#ifdef __GNUC__
|
||||
__builtin___clear_cache(reinterpret_cast<char*>(code + CodeSize), reinterpret_cast<char*>(code + codePos));
|
||||
#endif
|
||||
clear_code_cache(reinterpret_cast<char*>(code + CodeSize), reinterpret_cast<char*>(code + codePos));
|
||||
}
|
||||
|
||||
template void JitCompilerA64::generateSuperscalarHash(SuperscalarProgram(&programs)[RANDOMX_CACHE_MAX_ACCESSES], std::vector<uint64_t> &reciprocalCache);
|
||||
|
@ -858,7 +867,7 @@ void JitCompilerA64::h_FADD_M(Instruction& instr, uint32_t& codePos)
|
|||
const uint32_t dst = (instr.dst % 4) + 16;
|
||||
|
||||
constexpr uint32_t tmp_reg_fp = 28;
|
||||
emitMemLoadFP<tmp_reg_fp>(src, instr, code, k);
|
||||
emitMemLoadFP<tmp_reg_fp>(src, instr, code, k);
|
||||
|
||||
emit32(ARMV8A::FADD | dst | (dst << 5) | (tmp_reg_fp << 16), code, k);
|
||||
|
||||
|
@ -881,7 +890,7 @@ void JitCompilerA64::h_FSUB_M(Instruction& instr, uint32_t& codePos)
|
|||
const uint32_t dst = (instr.dst % 4) + 16;
|
||||
|
||||
constexpr uint32_t tmp_reg_fp = 28;
|
||||
emitMemLoadFP<tmp_reg_fp>(src, instr, code, k);
|
||||
emitMemLoadFP<tmp_reg_fp>(src, instr, code, k);
|
||||
|
||||
emit32(ARMV8A::FSUB | dst | (dst << 5) | (tmp_reg_fp << 16), code, k);
|
||||
|
||||
|
@ -911,7 +920,7 @@ void JitCompilerA64::h_FDIV_M(Instruction& instr, uint32_t& codePos)
|
|||
const uint32_t dst = (instr.dst % 4) + 20;
|
||||
|
||||
constexpr uint32_t tmp_reg_fp = 28;
|
||||
emitMemLoadFP<tmp_reg_fp>(src, instr, code, k);
|
||||
emitMemLoadFP<tmp_reg_fp>(src, instr, code, k);
|
||||
|
||||
// and tmp_reg_fp, tmp_reg_fp, and_mask_reg
|
||||
emit32(0x4E201C00 | tmp_reg_fp | (tmp_reg_fp << 5) | (29 << 16), code, k);
|
||||
|
|
|
@ -98,6 +98,7 @@
|
|||
# v30 -> E 'or' mask = 0x3*00000000******3*00000000******
|
||||
# v31 -> scale mask = 0x81f000000000000081f0000000000000
|
||||
|
||||
.balign 4
|
||||
randomx_program_aarch64:
|
||||
# Save callee-saved registers
|
||||
sub sp, sp, 192
|
||||
|
|
|
@ -631,7 +631,7 @@ namespace randomx {
|
|||
int cycle1 = scheduleUop<false>(mop.getUop1(), portBusy, cycle);
|
||||
int cycle2 = scheduleUop<false>(mop.getUop2(), portBusy, cycle);
|
||||
|
||||
if (cycle1 == cycle2) {
|
||||
if (cycle1 >= 0 && cycle1 == cycle2) {
|
||||
if (commit) {
|
||||
scheduleUop<true>(mop.getUop1(), portBusy, cycle1);
|
||||
scheduleUop<true>(mop.getUop2(), portBusy, cycle2);
|
||||
|
@ -755,6 +755,12 @@ namespace randomx {
|
|||
//recalculate when the instruction can be scheduled for execution based on operand availability
|
||||
scheduleCycle = scheduleMop<true>(mop, portBusy, scheduleCycle, scheduleCycle);
|
||||
|
||||
if (scheduleCycle < 0) {
|
||||
if (trace) std::cout << "Unable to map operation '" << mop.getName() << "' to execution port (cycle " << scheduleCycle << ")" << std::endl;
|
||||
portsSaturated = true;
|
||||
break;
|
||||
}
|
||||
|
||||
//calculate when the result will be ready
|
||||
depCycle = scheduleCycle + mop.getLatency();
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ xmrig::RxQueue::RxQueue(IRxListener *listener) :
|
|||
|
||||
uv_async_init(uv_default_loop(), m_async, [](uv_async_t *handle) { static_cast<RxQueue *>(handle->data)->onReady(); });
|
||||
|
||||
m_thread = std::move(std::thread(&RxQueue::backgroundInit, this));
|
||||
m_thread = std::thread(&RxQueue::backgroundInit, this);
|
||||
}
|
||||
|
||||
|
||||
|
@ -158,7 +158,7 @@ void xmrig::RxQueue::backgroundInit()
|
|||
|
||||
m_storage->init(item.seed, item.threads, item.hugePages);
|
||||
|
||||
lock = std::move(std::unique_lock<std::mutex>(m_mutex));
|
||||
lock = std::unique_lock<std::mutex>(m_mutex);
|
||||
|
||||
if (m_state == STATE_SHUTDOWN || !m_queue.empty()) {
|
||||
continue;
|
||||
|
|
|
@ -234,7 +234,7 @@ void xmrig::DonateStrategy::onTimer(const Timer *)
|
|||
}
|
||||
|
||||
|
||||
xmrig::Client *xmrig::DonateStrategy::createProxy()
|
||||
xmrig::IClient *xmrig::DonateStrategy::createProxy()
|
||||
{
|
||||
if (m_controller->config()->pools().proxyDonate() == Pools::PROXY_DONATE_NONE) {
|
||||
return nullptr;
|
||||
|
@ -251,7 +251,7 @@ xmrig::Client *xmrig::DonateStrategy::createProxy()
|
|||
Pool pool(client->ip(), client->pool().port(), m_userId, client->pool().password(), 0, true, client->isTLS());
|
||||
pool.setAlgo(client->pool().algorithm());
|
||||
|
||||
auto proxy = new Client(-1, Platform::userAgent(), this);
|
||||
IClient *proxy = new Client(-1, Platform::userAgent(), this);
|
||||
proxy->setPool(pool);
|
||||
proxy->setQuiet(true);
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ private:
|
|||
|
||||
inline State state() const { return m_state; }
|
||||
|
||||
Client *createProxy();
|
||||
IClient *createProxy();
|
||||
void idle(double min, double max);
|
||||
void setAlgorithms(rapidjson::Document &doc, rapidjson::Value ¶ms);
|
||||
void setJob(IClient *client, const Job &job);
|
||||
|
|
Loading…
Reference in a new issue