From e2c58126e98a49415f7ff56177fb7da30e601519 Mon Sep 17 00:00:00 2001 From: SChernykh Date: Sat, 28 Jan 2023 19:42:02 +0100 Subject: [PATCH] Solo mining: added job timeout (default is 15 seconds) It's important to update jobs frequently to get new transactions into the block template. See https://rucknium.me/posts/monero-pool-transaction-delay/ for more details. --- src/base/kernel/config/BaseTransform.cpp | 4 ++++ src/base/kernel/interfaces/IConfig.h | 1 + src/base/net/stratum/DaemonClient.cpp | 24 +++++++++++++++++++++++- src/base/net/stratum/DaemonClient.h | 1 + src/base/net/stratum/Pool.cpp | 7 +++++++ src/base/net/stratum/Pool.h | 4 ++++ src/core/config/Config_platform.h | 1 + src/core/config/usage.h | 2 ++ 8 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/base/kernel/config/BaseTransform.cpp b/src/base/kernel/config/BaseTransform.cpp index c924dd59a..a1b430da3 100644 --- a/src/base/kernel/config/BaseTransform.cpp +++ b/src/base/kernel/config/BaseTransform.cpp @@ -247,6 +247,7 @@ void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const ch case IConfig::HttpPort: /* --http-port */ case IConfig::DonateLevelKey: /* --donate-level */ case IConfig::DaemonPollKey: /* --daemon-poll-interval */ + case IConfig::DaemonJobTimeoutKey: /* --daemon-job-timeout */ case IConfig::DnsTtlKey: /* --dns-ttl */ case IConfig::DaemonZMQPortKey: /* --daemon-zmq-port */ return transformUint64(doc, key, static_cast(strtol(arg, nullptr, 10))); @@ -360,6 +361,9 @@ void xmrig::BaseTransform::transformUint64(rapidjson::Document &doc, int key, ui case IConfig::DaemonPollKey: /* --daemon-poll-interval */ return add(doc, Pools::kPools, Pool::kDaemonPollInterval, arg); + case IConfig::DaemonJobTimeoutKey: /* --daemon-job-timeout */ + return add(doc, Pools::kPools, Pool::kDaemonJobTimeout, arg); + case IConfig::DaemonZMQPortKey: /* --daemon-zmq-port */ return add(doc, Pools::kPools, Pool::kDaemonZMQPort, arg); # endif diff --git a/src/base/kernel/interfaces/IConfig.h b/src/base/kernel/interfaces/IConfig.h index ed76f4cd2..98957fc4b 100644 --- a/src/base/kernel/interfaces/IConfig.h +++ b/src/base/kernel/interfaces/IConfig.h @@ -88,6 +88,7 @@ public: DaemonZMQPortKey = 1056, HugePagesJitKey = 1057, RotationKey = 1058, + DaemonJobTimeoutKey = 1059, // xmrig common CPUPriorityKey = 1021, diff --git a/src/base/net/stratum/DaemonClient.cpp b/src/base/net/stratum/DaemonClient.cpp index f383308c5..10c041163 100644 --- a/src/base/net/stratum/DaemonClient.cpp +++ b/src/base/net/stratum/DaemonClient.cpp @@ -303,6 +303,18 @@ void xmrig::DaemonClient::onHttpData(const HttpData &data) void xmrig::DaemonClient::onTimer(const Timer *) { + if (m_pool.zmq_port() >= 0) { + m_prevHash = nullptr; + m_blocktemplateRequestHash = nullptr; + send(kGetHeight); + return; + } + + if (Chrono::steadyMSecs() >= m_jobSteadyMs + m_pool.jobTimeout()) { + m_prevHash = nullptr; + m_blocktemplateRequestHash = nullptr; + } + if (m_state == ConnectingState) { connect(); } @@ -352,7 +364,7 @@ void xmrig::DaemonClient::onResolved(const DnsRecords &records, int status, cons bool xmrig::DaemonClient::isOutdated(uint64_t height, const char *hash) const { - return m_job.height() != height || m_prevHash != hash; + return m_job.height() != height || m_prevHash != hash || Chrono::steadyMSecs() >= m_jobSteadyMs + m_pool.jobTimeout(); } @@ -468,6 +480,7 @@ bool xmrig::DaemonClient::parseJob(const rapidjson::Value ¶ms, int *code) m_job = std::move(job); m_blocktemplateStr = std::move(blocktemplate); m_prevHash = Json::getString(params, "prev_hash"); + m_jobSteadyMs = Chrono::steadyMSecs(); if (m_state == ConnectingState) { setState(ConnectedState); @@ -596,6 +609,10 @@ void xmrig::DaemonClient::setState(SocketState state) const uint64_t interval = std::max(20, m_pool.pollInterval()); m_timer->start(interval, interval); } + else { + const uint64_t t = m_pool.jobTimeout(); + m_timer->start(t, t); + } } break; @@ -865,7 +882,12 @@ void xmrig::DaemonClient::ZMQParse() // Clear previous hash and check daemon height to guarantee that xmrig will call get_block_template RPC later // We can't call get_block_template directly because daemon is not ready yet m_prevHash = nullptr; + m_blocktemplateRequestHash = nullptr; send(kGetHeight); + + const uint64_t t = m_pool.jobTimeout(); + m_timer->stop(); + m_timer->start(t, t); } diff --git a/src/base/net/stratum/DaemonClient.h b/src/base/net/stratum/DaemonClient.h index 7880de404..94d2b973a 100644 --- a/src/base/net/stratum/DaemonClient.h +++ b/src/base/net/stratum/DaemonClient.h @@ -104,6 +104,7 @@ private: String m_blocktemplateStr; String m_currentJobId; String m_prevHash; + uint64_t m_jobSteadyMs = 0; String m_tlsFingerprint; String m_tlsVersion; Timer *m_timer; diff --git a/src/base/net/stratum/Pool.cpp b/src/base/net/stratum/Pool.cpp index 7a58f4cb5..b1773c46d 100644 --- a/src/base/net/stratum/Pool.cpp +++ b/src/base/net/stratum/Pool.cpp @@ -65,6 +65,7 @@ const char *Pool::kAlgo = "algo"; const char *Pool::kCoin = "coin"; const char *Pool::kDaemon = "daemon"; const char *Pool::kDaemonPollInterval = "daemon-poll-interval"; +const char *Pool::kDaemonJobTimeout = "daemon-job-timeout"; const char *Pool::kDaemonZMQPort = "daemon-zmq-port"; const char *Pool::kEnabled = "enabled"; const char *Pool::kFingerprint = "tls-fingerprint"; @@ -88,6 +89,7 @@ const char *Pool::kNicehashHost = "nicehash.com"; xmrig::Pool::Pool(const char *url) : m_flags(1 << FLAG_ENABLED), m_pollInterval(kDefaultPollInterval), + m_jobTimeout(kDefaultJobTimeout), m_url(url) { } @@ -101,6 +103,7 @@ xmrig::Pool::Pool(const char *host, uint16_t port, const char *user, const char m_user(user), m_spendSecretKey(spendSecretKey), m_pollInterval(kDefaultPollInterval), + m_jobTimeout(kDefaultJobTimeout), m_url(host, port, tls) { m_flags.set(FLAG_NICEHASH, nicehash || strstr(host, kNicehashHost)); @@ -111,6 +114,7 @@ xmrig::Pool::Pool(const char *host, uint16_t port, const char *user, const char xmrig::Pool::Pool(const rapidjson::Value &object) : m_flags(1 << FLAG_ENABLED), m_pollInterval(kDefaultPollInterval), + m_jobTimeout(kDefaultJobTimeout), m_url(Json::getString(object, kUrl)) { if (!m_url.isValid()) { @@ -123,6 +127,7 @@ xmrig::Pool::Pool(const rapidjson::Value &object) : m_rigId = Json::getString(object, kRigId); m_fingerprint = Json::getString(object, kFingerprint); m_pollInterval = Json::getUint64(object, kDaemonPollInterval, kDefaultPollInterval); + m_jobTimeout = Json::getUint64(object, kDaemonJobTimeout, kDefaultJobTimeout); m_algorithm = Json::getString(object, kAlgo); m_coin = Json::getString(object, kCoin); m_daemon = Json::getString(object, kSelfSelect); @@ -207,6 +212,7 @@ bool xmrig::Pool::isEqual(const Pool &other) const && m_url == other.m_url && m_user == other.m_user && m_pollInterval == other.m_pollInterval + && m_jobTimeout == other.m_jobTimeout && m_daemon == other.m_daemon && m_proxy == other.m_proxy ); @@ -299,6 +305,7 @@ rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const if (m_mode == MODE_DAEMON) { obj.AddMember(StringRef(kDaemonPollInterval), m_pollInterval, allocator); + obj.AddMember(StringRef(kDaemonJobTimeout), m_jobTimeout, allocator); obj.AddMember(StringRef(kDaemonZMQPort), m_zmqPort, allocator); } else { diff --git a/src/base/net/stratum/Pool.h b/src/base/net/stratum/Pool.h index 78684510f..8374f20ff 100644 --- a/src/base/net/stratum/Pool.h +++ b/src/base/net/stratum/Pool.h @@ -59,6 +59,7 @@ public: static const char *kCoin; static const char *kDaemon; static const char *kDaemonPollInterval; + static const char* kDaemonJobTimeout; static const char *kEnabled; static const char *kFingerprint; static const char *kKeepalive; @@ -78,6 +79,7 @@ public: constexpr static int kKeepAliveTimeout = 60; constexpr static uint16_t kDefaultPort = 3333; constexpr static uint64_t kDefaultPollInterval = 1000; + constexpr static uint64_t kDefaultJobTimeout = 15000; Pool() = default; Pool(const char *host, uint16_t port, const char *user, const char *password, const char* spendSecretKey, int keepAlive, bool nicehash, bool tls, Mode mode); @@ -110,6 +112,7 @@ public: inline uint16_t port() const { return m_url.port(); } inline int zmq_port() const { return m_zmqPort; } inline uint64_t pollInterval() const { return m_pollInterval; } + inline uint64_t jobTimeout() const { return m_jobTimeout; } inline void setAlgo(const Algorithm &algorithm) { m_algorithm = algorithm; } inline void setUrl(const char *url) { m_url = Url(url); } inline void setPassword(const String &password) { m_password = password; } @@ -156,6 +159,7 @@ private: String m_user; String m_spendSecretKey; uint64_t m_pollInterval = kDefaultPollInterval; + uint64_t m_jobTimeout = kDefaultJobTimeout; Url m_daemon; Url m_url; int m_zmqPort = -1; diff --git a/src/core/config/Config_platform.h b/src/core/config/Config_platform.h index d3d3157c3..52f66f301 100644 --- a/src/core/config/Config_platform.h +++ b/src/core/config/Config_platform.h @@ -50,6 +50,7 @@ static const option options[] = { { "http-no-restricted", 0, nullptr, IConfig::HttpRestrictedKey }, { "daemon", 0, nullptr, IConfig::DaemonKey }, { "daemon-poll-interval", 1, nullptr, IConfig::DaemonPollKey }, + { "daemon-job-timeout", 1, nullptr, IConfig::DaemonJobTimeoutKey }, { "self-select", 1, nullptr, IConfig::SelfSelectKey }, { "submit-to-origin", 0, nullptr, IConfig::SubmitToOriginKey }, { "daemon-zmq-port", 1, nullptr, IConfig::DaemonZMQPortKey }, diff --git a/src/core/config/usage.h b/src/core/config/usage.h index 6f74b21e5..eb7a9ec72 100644 --- a/src/core/config/usage.h +++ b/src/core/config/usage.h @@ -64,7 +64,9 @@ static inline const std::string &usage() # ifdef XMRIG_FEATURE_HTTP u += " --daemon use daemon RPC instead of pool for solo mining\n"; + u += " --daemon-zmq-port daemon's zmq-pub port number (only use it if daemon has it enabled)\n"; u += " --daemon-poll-interval=N daemon poll interval in milliseconds (default: 1000)\n"; + u += " --daemon-job-timeout=N daemon job timeout in milliseconds (default: 15000)\n"; u += " --self-select=URL self-select block templates from URL\n"; u += " --submit-to-origin also submit solution back to self-select URL\n"; # endif