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.
This commit is contained in:
SChernykh 2023-01-28 19:42:02 +01:00
parent 0ed4b35cd3
commit e2c58126e9
8 changed files with 43 additions and 1 deletions

View file

@ -247,6 +247,7 @@ void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const ch
case IConfig::HttpPort: /* --http-port */ case IConfig::HttpPort: /* --http-port */
case IConfig::DonateLevelKey: /* --donate-level */ case IConfig::DonateLevelKey: /* --donate-level */
case IConfig::DaemonPollKey: /* --daemon-poll-interval */ case IConfig::DaemonPollKey: /* --daemon-poll-interval */
case IConfig::DaemonJobTimeoutKey: /* --daemon-job-timeout */
case IConfig::DnsTtlKey: /* --dns-ttl */ case IConfig::DnsTtlKey: /* --dns-ttl */
case IConfig::DaemonZMQPortKey: /* --daemon-zmq-port */ case IConfig::DaemonZMQPortKey: /* --daemon-zmq-port */
return transformUint64(doc, key, static_cast<uint64_t>(strtol(arg, nullptr, 10))); return transformUint64(doc, key, static_cast<uint64_t>(strtol(arg, nullptr, 10)));
@ -360,6 +361,9 @@ void xmrig::BaseTransform::transformUint64(rapidjson::Document &doc, int key, ui
case IConfig::DaemonPollKey: /* --daemon-poll-interval */ case IConfig::DaemonPollKey: /* --daemon-poll-interval */
return add(doc, Pools::kPools, Pool::kDaemonPollInterval, arg); 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 */ case IConfig::DaemonZMQPortKey: /* --daemon-zmq-port */
return add(doc, Pools::kPools, Pool::kDaemonZMQPort, arg); return add(doc, Pools::kPools, Pool::kDaemonZMQPort, arg);
# endif # endif

View file

@ -88,6 +88,7 @@ public:
DaemonZMQPortKey = 1056, DaemonZMQPortKey = 1056,
HugePagesJitKey = 1057, HugePagesJitKey = 1057,
RotationKey = 1058, RotationKey = 1058,
DaemonJobTimeoutKey = 1059,
// xmrig common // xmrig common
CPUPriorityKey = 1021, CPUPriorityKey = 1021,

View file

@ -303,6 +303,18 @@ void xmrig::DaemonClient::onHttpData(const HttpData &data)
void xmrig::DaemonClient::onTimer(const Timer *) 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) { if (m_state == ConnectingState) {
connect(); 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 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 &params, int *code)
m_job = std::move(job); m_job = std::move(job);
m_blocktemplateStr = std::move(blocktemplate); m_blocktemplateStr = std::move(blocktemplate);
m_prevHash = Json::getString(params, "prev_hash"); m_prevHash = Json::getString(params, "prev_hash");
m_jobSteadyMs = Chrono::steadyMSecs();
if (m_state == ConnectingState) { if (m_state == ConnectingState) {
setState(ConnectedState); setState(ConnectedState);
@ -596,6 +609,10 @@ void xmrig::DaemonClient::setState(SocketState state)
const uint64_t interval = std::max<uint64_t>(20, m_pool.pollInterval()); const uint64_t interval = std::max<uint64_t>(20, m_pool.pollInterval());
m_timer->start(interval, interval); m_timer->start(interval, interval);
} }
else {
const uint64_t t = m_pool.jobTimeout();
m_timer->start(t, t);
}
} }
break; 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 // 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 // We can't call get_block_template directly because daemon is not ready yet
m_prevHash = nullptr; m_prevHash = nullptr;
m_blocktemplateRequestHash = nullptr;
send(kGetHeight); send(kGetHeight);
const uint64_t t = m_pool.jobTimeout();
m_timer->stop();
m_timer->start(t, t);
} }

View file

@ -104,6 +104,7 @@ private:
String m_blocktemplateStr; String m_blocktemplateStr;
String m_currentJobId; String m_currentJobId;
String m_prevHash; String m_prevHash;
uint64_t m_jobSteadyMs = 0;
String m_tlsFingerprint; String m_tlsFingerprint;
String m_tlsVersion; String m_tlsVersion;
Timer *m_timer; Timer *m_timer;

View file

@ -65,6 +65,7 @@ const char *Pool::kAlgo = "algo";
const char *Pool::kCoin = "coin"; const char *Pool::kCoin = "coin";
const char *Pool::kDaemon = "daemon"; const char *Pool::kDaemon = "daemon";
const char *Pool::kDaemonPollInterval = "daemon-poll-interval"; const char *Pool::kDaemonPollInterval = "daemon-poll-interval";
const char *Pool::kDaemonJobTimeout = "daemon-job-timeout";
const char *Pool::kDaemonZMQPort = "daemon-zmq-port"; const char *Pool::kDaemonZMQPort = "daemon-zmq-port";
const char *Pool::kEnabled = "enabled"; const char *Pool::kEnabled = "enabled";
const char *Pool::kFingerprint = "tls-fingerprint"; const char *Pool::kFingerprint = "tls-fingerprint";
@ -88,6 +89,7 @@ const char *Pool::kNicehashHost = "nicehash.com";
xmrig::Pool::Pool(const char *url) : xmrig::Pool::Pool(const char *url) :
m_flags(1 << FLAG_ENABLED), m_flags(1 << FLAG_ENABLED),
m_pollInterval(kDefaultPollInterval), m_pollInterval(kDefaultPollInterval),
m_jobTimeout(kDefaultJobTimeout),
m_url(url) 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_user(user),
m_spendSecretKey(spendSecretKey), m_spendSecretKey(spendSecretKey),
m_pollInterval(kDefaultPollInterval), m_pollInterval(kDefaultPollInterval),
m_jobTimeout(kDefaultJobTimeout),
m_url(host, port, tls) m_url(host, port, tls)
{ {
m_flags.set(FLAG_NICEHASH, nicehash || strstr(host, kNicehashHost)); 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) : xmrig::Pool::Pool(const rapidjson::Value &object) :
m_flags(1 << FLAG_ENABLED), m_flags(1 << FLAG_ENABLED),
m_pollInterval(kDefaultPollInterval), m_pollInterval(kDefaultPollInterval),
m_jobTimeout(kDefaultJobTimeout),
m_url(Json::getString(object, kUrl)) m_url(Json::getString(object, kUrl))
{ {
if (!m_url.isValid()) { if (!m_url.isValid()) {
@ -123,6 +127,7 @@ xmrig::Pool::Pool(const rapidjson::Value &object) :
m_rigId = Json::getString(object, kRigId); m_rigId = Json::getString(object, kRigId);
m_fingerprint = Json::getString(object, kFingerprint); m_fingerprint = Json::getString(object, kFingerprint);
m_pollInterval = Json::getUint64(object, kDaemonPollInterval, kDefaultPollInterval); m_pollInterval = Json::getUint64(object, kDaemonPollInterval, kDefaultPollInterval);
m_jobTimeout = Json::getUint64(object, kDaemonJobTimeout, kDefaultJobTimeout);
m_algorithm = Json::getString(object, kAlgo); m_algorithm = Json::getString(object, kAlgo);
m_coin = Json::getString(object, kCoin); m_coin = Json::getString(object, kCoin);
m_daemon = Json::getString(object, kSelfSelect); m_daemon = Json::getString(object, kSelfSelect);
@ -207,6 +212,7 @@ bool xmrig::Pool::isEqual(const Pool &other) const
&& m_url == other.m_url && m_url == other.m_url
&& m_user == other.m_user && m_user == other.m_user
&& m_pollInterval == other.m_pollInterval && m_pollInterval == other.m_pollInterval
&& m_jobTimeout == other.m_jobTimeout
&& m_daemon == other.m_daemon && m_daemon == other.m_daemon
&& m_proxy == other.m_proxy && m_proxy == other.m_proxy
); );
@ -299,6 +305,7 @@ rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const
if (m_mode == MODE_DAEMON) { if (m_mode == MODE_DAEMON) {
obj.AddMember(StringRef(kDaemonPollInterval), m_pollInterval, allocator); obj.AddMember(StringRef(kDaemonPollInterval), m_pollInterval, allocator);
obj.AddMember(StringRef(kDaemonJobTimeout), m_jobTimeout, allocator);
obj.AddMember(StringRef(kDaemonZMQPort), m_zmqPort, allocator); obj.AddMember(StringRef(kDaemonZMQPort), m_zmqPort, allocator);
} }
else { else {

View file

@ -59,6 +59,7 @@ public:
static const char *kCoin; static const char *kCoin;
static const char *kDaemon; static const char *kDaemon;
static const char *kDaemonPollInterval; static const char *kDaemonPollInterval;
static const char* kDaemonJobTimeout;
static const char *kEnabled; static const char *kEnabled;
static const char *kFingerprint; static const char *kFingerprint;
static const char *kKeepalive; static const char *kKeepalive;
@ -78,6 +79,7 @@ public:
constexpr static int kKeepAliveTimeout = 60; constexpr static int kKeepAliveTimeout = 60;
constexpr static uint16_t kDefaultPort = 3333; constexpr static uint16_t kDefaultPort = 3333;
constexpr static uint64_t kDefaultPollInterval = 1000; constexpr static uint64_t kDefaultPollInterval = 1000;
constexpr static uint64_t kDefaultJobTimeout = 15000;
Pool() = default; 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); 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 uint16_t port() const { return m_url.port(); }
inline int zmq_port() const { return m_zmqPort; } inline int zmq_port() const { return m_zmqPort; }
inline uint64_t pollInterval() const { return m_pollInterval; } 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 setAlgo(const Algorithm &algorithm) { m_algorithm = algorithm; }
inline void setUrl(const char *url) { m_url = Url(url); } inline void setUrl(const char *url) { m_url = Url(url); }
inline void setPassword(const String &password) { m_password = password; } inline void setPassword(const String &password) { m_password = password; }
@ -156,6 +159,7 @@ private:
String m_user; String m_user;
String m_spendSecretKey; String m_spendSecretKey;
uint64_t m_pollInterval = kDefaultPollInterval; uint64_t m_pollInterval = kDefaultPollInterval;
uint64_t m_jobTimeout = kDefaultJobTimeout;
Url m_daemon; Url m_daemon;
Url m_url; Url m_url;
int m_zmqPort = -1; int m_zmqPort = -1;

View file

@ -50,6 +50,7 @@ static const option options[] = {
{ "http-no-restricted", 0, nullptr, IConfig::HttpRestrictedKey }, { "http-no-restricted", 0, nullptr, IConfig::HttpRestrictedKey },
{ "daemon", 0, nullptr, IConfig::DaemonKey }, { "daemon", 0, nullptr, IConfig::DaemonKey },
{ "daemon-poll-interval", 1, nullptr, IConfig::DaemonPollKey }, { "daemon-poll-interval", 1, nullptr, IConfig::DaemonPollKey },
{ "daemon-job-timeout", 1, nullptr, IConfig::DaemonJobTimeoutKey },
{ "self-select", 1, nullptr, IConfig::SelfSelectKey }, { "self-select", 1, nullptr, IConfig::SelfSelectKey },
{ "submit-to-origin", 0, nullptr, IConfig::SubmitToOriginKey }, { "submit-to-origin", 0, nullptr, IConfig::SubmitToOriginKey },
{ "daemon-zmq-port", 1, nullptr, IConfig::DaemonZMQPortKey }, { "daemon-zmq-port", 1, nullptr, IConfig::DaemonZMQPortKey },

View file

@ -64,7 +64,9 @@ static inline const std::string &usage()
# ifdef XMRIG_FEATURE_HTTP # ifdef XMRIG_FEATURE_HTTP
u += " --daemon use daemon RPC instead of pool for solo mining\n"; 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-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 += " --self-select=URL self-select block templates from URL\n";
u += " --submit-to-origin also submit solution back to self-select URL\n"; u += " --submit-to-origin also submit solution back to self-select URL\n";
# endif # endif