From 3b87cd97cef6f3c47ab1637075def4398f9f62a3 Mon Sep 17 00:00:00 2001 From: Hansie Odendaal Date: Wed, 17 Feb 2021 18:05:13 +0200 Subject: [PATCH] Allow result submission to origin daemon with self-select With `self-select` mode enabled, the `submit-to-origin` config option will let the `SelfSelectClient` submit the solution to both the daemon where it got the template from as well as to the connected pool, for miners that want to do pool minining with Monero and solo mining with an altcoin (merged mining variant). Thank you and special credit to @StriderDM (https://github.com/StriderDM)! --- src/base/io/log/Tags.cpp | 6 +++ src/base/io/log/Tags.h | 1 + src/base/kernel/config/BaseTransform.cpp | 3 ++ src/base/kernel/interfaces/IConfig.h | 1 + src/base/net/stratum/Pool.cpp | 7 ++- src/base/net/stratum/Pool.h | 2 + src/base/net/stratum/SelfSelectClient.cpp | 54 ++++++++++++++++++++++- src/base/net/stratum/SelfSelectClient.h | 13 ++++-- src/config.json | 3 +- src/core/config/Config_default.h | 3 +- src/core/config/Config_platform.h | 1 + src/core/config/usage.h | 1 + 12 files changed, 86 insertions(+), 9 deletions(-) diff --git a/src/base/io/log/Tags.cpp b/src/base/io/log/Tags.cpp index 3960a14d..75b4ca8a 100644 --- a/src/base/io/log/Tags.cpp +++ b/src/base/io/log/Tags.cpp @@ -36,6 +36,12 @@ const char *xmrig::Tags::network() return tag; } +const char* xmrig::Tags::origin() +{ + static const char* tag = YELLOW_BG_BOLD(WHITE_BOLD_S " origin "); + + return tag; +} const char *xmrig::Tags::signal() { diff --git a/src/base/io/log/Tags.h b/src/base/io/log/Tags.h index 9f690ef2..fc2c7485 100644 --- a/src/base/io/log/Tags.h +++ b/src/base/io/log/Tags.h @@ -32,6 +32,7 @@ class Tags public: static const char *config(); static const char *network(); + static const char *origin(); static const char *signal(); # ifdef XMRIG_MINER_PROJECT diff --git a/src/base/kernel/config/BaseTransform.cpp b/src/base/kernel/config/BaseTransform.cpp index 7df0a795..e6dc4e2e 100644 --- a/src/base/kernel/config/BaseTransform.cpp +++ b/src/base/kernel/config/BaseTransform.cpp @@ -260,6 +260,7 @@ void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const ch case IConfig::DryRunKey: /* --dry-run */ case IConfig::HttpEnabledKey: /* --http-enabled */ case IConfig::DaemonKey: /* --daemon */ + case IConfig::SubmitToOriginKey: /* --submit-to-origin */ case IConfig::VerboseKey: /* --verbose */ case IConfig::PauseOnBatteryKey: /* --pause-on-battery */ case IConfig::PauseOnActiveKey: /* --pause-on-active */ @@ -291,6 +292,8 @@ void xmrig::BaseTransform::transformBoolean(rapidjson::Document &doc, int key, b case IConfig::TlsKey: /* --tls */ return add(doc, Pools::kPools, Pool::kTls, enable); + case IConfig::SubmitToOriginKey: /* --submit-to-origin */ + return add(doc, Pools::kPools, Pool::kSubmitToOrigin, enable); # ifdef XMRIG_FEATURE_HTTP case IConfig::DaemonKey: /* --daemon */ return add(doc, Pools::kPools, Pool::kDaemon, enable); diff --git a/src/base/kernel/interfaces/IConfig.h b/src/base/kernel/interfaces/IConfig.h index d5fdb5c9..0e03f786 100644 --- a/src/base/kernel/interfaces/IConfig.h +++ b/src/base/kernel/interfaces/IConfig.h @@ -73,6 +73,7 @@ public: DaemonKey = 1018, DaemonPollKey = 1019, SelfSelectKey = 1028, + SubmitToOriginKey = 1049, DataDirKey = 1035, TitleKey = 1037, NoTitleKey = 1038, diff --git a/src/base/net/stratum/Pool.cpp b/src/base/net/stratum/Pool.cpp index f80f1f62..8148deae 100644 --- a/src/base/net/stratum/Pool.cpp +++ b/src/base/net/stratum/Pool.cpp @@ -79,6 +79,7 @@ const char *Pool::kNicehash = "nicehash"; const char *Pool::kPass = "pass"; const char *Pool::kRigId = "rig-id"; const char *Pool::kSelfSelect = "self-select"; +const char* Pool::kSubmitToOrigin = "submit-to-origin"; const char *Pool::kSOCKS5 = "socks5"; const char *Pool::kTls = "tls"; const char *Pool::kUrl = "url"; @@ -138,6 +139,7 @@ xmrig::Pool::Pool(const rapidjson::Value &object) : if (m_daemon.isValid()) { m_mode = MODE_SELF_SELECT; + m_submit_to_origin = Json::getBool(object, kSubmitToOrigin, false); } else if (Json::getBool(object, kDaemon)) { m_mode = MODE_DAEMON; @@ -237,7 +239,7 @@ xmrig::IClient *xmrig::Pool::createClient(int id, IClientListener *listener) con client = new DaemonClient(id, listener); } else if (m_mode == MODE_SELF_SELECT) { - client = new SelfSelectClient(id, Platform::userAgent(), listener); + client = new SelfSelectClient(id, Platform::userAgent(), listener, m_submit_to_origin); } # endif # ifdef XMRIG_ALGO_KAWPOW @@ -301,6 +303,7 @@ rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const } else { obj.AddMember(StringRef(kSelfSelect), m_daemon.url().toJSON(), allocator); + obj.AddMember(StringRef(kSubmitToOrigin), m_submit_to_origin, allocator); } return obj; @@ -319,7 +322,7 @@ std::string xmrig::Pool::printableName() const } 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; + out += std::string(" self-select ") + CSI "1;" + std::to_string(m_daemon.isTLS() ? 32 : 36) + "m" + m_daemon.url().data() + WHITE_BOLD_S + (m_submit_to_origin ? " submit-to-origin" : "") + CLEAR; } return out; diff --git a/src/base/net/stratum/Pool.h b/src/base/net/stratum/Pool.h index dc0fec87..97ef3fac 100644 --- a/src/base/net/stratum/Pool.h +++ b/src/base/net/stratum/Pool.h @@ -72,6 +72,7 @@ public: static const char *kPass; static const char *kRigId; static const char *kSelfSelect; + static const char* kSubmitToOrigin; static const char *kSOCKS5; static const char *kTls; static const char *kUrl; @@ -156,6 +157,7 @@ private: uint64_t m_pollInterval = kDefaultPollInterval; Url m_daemon; Url m_url; + bool m_submit_to_origin = false; # ifdef XMRIG_FEATURE_BENCHMARK std::shared_ptr m_benchmark; diff --git a/src/base/net/stratum/SelfSelectClient.cpp b/src/base/net/stratum/SelfSelectClient.cpp index fc4cea6e..b2bb291e 100644 --- a/src/base/net/stratum/SelfSelectClient.cpp +++ b/src/base/net/stratum/SelfSelectClient.cpp @@ -31,9 +31,12 @@ #include "base/io/json/Json.h" #include "base/io/json/JsonRequest.h" #include "base/io/log/Log.h" +#include "base/io/log/Tags.h" #include "base/net/http/Fetch.h" #include "base/net/http/HttpData.h" #include "base/net/stratum/Client.h" +#include "net/JobResult.h" +#include "base/tools/Cvt.h" namespace xmrig { @@ -54,8 +57,8 @@ static const char * const required_fields[] = { kBlocktemplateBlob, kBlockhashin } /* namespace xmrig */ -xmrig::SelfSelectClient::SelfSelectClient(int id, const char *agent, IClientListener *listener) : - m_listener(listener) +xmrig::SelfSelectClient::SelfSelectClient(int id, const char *agent, IClientListener *listener, bool submit_to_origin) : + m_listener(listener), m_submit_to_origin(submit_to_origin) { m_httpListener = std::make_shared(this); m_client = new Client(id, agent, this); @@ -201,6 +204,9 @@ void xmrig::SelfSelectClient::submitBlockTemplate(rapidjson::Value &result) Document doc(kObjectType); auto &allocator = doc.GetAllocator(); + m_blocktemplate = Json::getString(result,kBlocktemplateBlob); + m_blockdiff = Json::getUint64(result, kDifficulty); + Value params(kObjectType); params.AddMember(StringRef(kId), m_job.clientId().toJSON(), allocator); params.AddMember(StringRef(kJobId), m_job.id().toJSON(), allocator); @@ -235,6 +241,50 @@ void xmrig::SelfSelectClient::submitBlockTemplate(rapidjson::Value &result) }); } +int64_t xmrig::SelfSelectClient::submit(const JobResult& result) +{ + if (m_submit_to_origin) { + submitOriginDaemon(result); + } + return m_client->submit(result); +} + +void xmrig::SelfSelectClient::submitOriginDaemon(const JobResult& result) +{ + if (result.diff == 0 || m_blockdiff == 0) { + return; + } + + if (result.actualDiff() < m_blockdiff) { + m_origin_not_submitted++; + LOG_DEBUG("%s " RED_BOLD("not submitted to origin daemon, difficulty too low") " (%" PRId64 "/%" PRId64 ") " + BLACK_BOLD(" diff ") BLACK_BOLD("%" PRIu64) BLACK_BOLD(" vs. ") BLACK_BOLD("%" PRIu64), + Tags::origin(), m_origin_submitted, m_origin_not_submitted, m_blockdiff, result.actualDiff()); + return; + } + char *data = m_blocktemplate.data(); + Cvt::toHex(data + 78, 8, reinterpret_cast(&result.nonce), 4); + + using namespace rapidjson; + Document doc(kObjectType); + + Value params(kArrayType); + params.PushBack(m_blocktemplate.toJSON(), doc.GetAllocator()); + + JsonRequest::create(doc, m_sequence, "submitblock", params); + m_results[m_sequence] = SubmitResult(m_sequence, result.diff, result.actualDiff(), 0, result.backend); + + FetchRequest req(HTTP_POST, pool().daemon().host(), pool().daemon().port(), "/json_rpc", doc, pool().daemon().isTLS(), isQuiet()); + fetch(tag(), std::move(req), m_httpListener); + + m_origin_submitted++; + LOG_INFO("%s " GREEN_BOLD("submitted to origin daemon") " (%" PRId64 "/%" PRId64 ") " + " diff " WHITE("%" PRIu64) " vs. " WHITE("%" PRIu64), + Tags::origin(), m_origin_submitted, m_origin_not_submitted, m_blockdiff, result.actualDiff(), result.diff); + + // Ensure that the latest block template is available after block submission + getBlockTemplate(); +} void xmrig::SelfSelectClient::onHttpData(const HttpData &data) { diff --git a/src/base/net/stratum/SelfSelectClient.h b/src/base/net/stratum/SelfSelectClient.h index b02e5212..2cf0e6d0 100644 --- a/src/base/net/stratum/SelfSelectClient.h +++ b/src/base/net/stratum/SelfSelectClient.h @@ -35,6 +35,7 @@ #include +#include namespace xmrig { @@ -45,7 +46,7 @@ class SelfSelectClient : public IClient, public IClientListener, public IHttpLis public: XMRIG_DISABLE_COPY_MOVE_DEFAULT(SelfSelectClient) - SelfSelectClient(int id, const char *agent, IClientListener *listener); + SelfSelectClient(int id, const char *agent, IClientListener *listener, bool submit_to_origin); ~SelfSelectClient() override; protected: @@ -65,7 +66,7 @@ protected: 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 int64_t submit(const JobResult &result) override; 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(); } @@ -105,7 +106,7 @@ private: void retry(); void setState(State state); void submitBlockTemplate(rapidjson::Value &result); - + inline void submitOriginDaemon(const JobResult &result); bool m_active = false; bool m_quiet = false; IClient *m_client; @@ -115,9 +116,15 @@ private: int64_t m_sequence = 1; Job m_job; State m_state = IdleState; + String m_blocktemplate; + bool m_submit_to_origin = false; + std::map m_results; std::shared_ptr m_httpListener; uint64_t m_retryPause = 5000; uint64_t m_timestamp = 0; + uint64_t m_blockdiff = 0; + uint64_t m_origin_submitted = 0; + uint64_t m_origin_not_submitted = 0; }; diff --git a/src/config.json b/src/config.json index 7722d19b..e25c5767 100644 --- a/src/config.json +++ b/src/config.json @@ -75,7 +75,8 @@ "tls-fingerprint": null, "daemon": false, "socks5": null, - "self-select": null + "self-select": null, + "submit-to-origin": false } ], "print-time": 60, diff --git a/src/core/config/Config_default.h b/src/core/config/Config_default.h index c16d421e..6c46fa95 100644 --- a/src/core/config/Config_default.h +++ b/src/core/config/Config_default.h @@ -105,7 +105,8 @@ R"===( "tls-fingerprint": null, "daemon": false, "socks5": null, - "self-select": null + "self-select": null, + "submit-to-origin": false } ], "print-time": 60, diff --git a/src/core/config/Config_platform.h b/src/core/config/Config_platform.h index d1b17345..f97d6fd8 100644 --- a/src/core/config/Config_platform.h +++ b/src/core/config/Config_platform.h @@ -57,6 +57,7 @@ static const option options[] = { { "daemon", 0, nullptr, IConfig::DaemonKey }, { "daemon-poll-interval", 1, nullptr, IConfig::DaemonPollKey }, { "self-select", 1, nullptr, IConfig::SelfSelectKey }, + { "submit-to-origin", 0, nullptr, IConfig::SubmitToOriginKey }, # endif { "av", 1, nullptr, IConfig::AVKey }, { "background", 0, nullptr, IConfig::BackgroundKey }, diff --git a/src/core/config/usage.h b/src/core/config/usage.h index bf908848..8078e1a4 100644 --- a/src/core/config/usage.h +++ b/src/core/config/usage.h @@ -64,6 +64,7 @@ static inline const std::string &usage() 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"; + u += " --submit-to-origin also submit solution back to self-select URL\n"; # endif u += " -r, --retries=N number of times to retry before switch to backup server (default: 5)\n";