KawPow WIP
This commit is contained in:
parent
07025dc41b
commit
22b937cc1c
88 changed files with 11004 additions and 8383 deletions
|
@ -83,7 +83,7 @@ protected:
|
|||
|
||||
inline bool isQuiet() const { return m_quiet || m_failures >= m_retries; }
|
||||
|
||||
bool handleResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error);
|
||||
virtual bool handleResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error);
|
||||
bool handleSubmitResponse(int64_t id, const char *error = nullptr);
|
||||
|
||||
bool m_quiet = false;
|
||||
|
|
|
@ -85,11 +85,19 @@ protected:
|
|||
inline const char *mode() const override { return "pool"; }
|
||||
inline void onLine(char *line, size_t size) override { parse(line, size); }
|
||||
|
||||
inline const char* agent() const { return m_agent; }
|
||||
inline const char* url() const { return m_pool.url(); }
|
||||
|
||||
virtual void login();
|
||||
virtual void parseNotification(const char* method, const rapidjson::Value& params, const rapidjson::Value& error);
|
||||
|
||||
bool close();
|
||||
virtual void onClose();
|
||||
|
||||
private:
|
||||
class Socks5;
|
||||
class Tls;
|
||||
|
||||
bool close();
|
||||
bool isCriticalError(const char *message);
|
||||
bool parseJob(const rapidjson::Value ¶ms, int *code);
|
||||
bool parseLogin(const rapidjson::Value &result, int *code);
|
||||
|
@ -100,11 +108,8 @@ private:
|
|||
int64_t send(size_t size);
|
||||
void connect(sockaddr *addr);
|
||||
void handshake();
|
||||
void login();
|
||||
void onClose();
|
||||
void parse(char *line, size_t len);
|
||||
void parseExtensions(const rapidjson::Value &result);
|
||||
void parseNotification(const char *method, const rapidjson::Value ¶ms, const rapidjson::Value &error);
|
||||
void parseResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error);
|
||||
void ping();
|
||||
void read(ssize_t nread, const uv_buf_t *buf);
|
||||
|
@ -112,7 +117,6 @@ private:
|
|||
void setState(SocketState state);
|
||||
void startTimeout();
|
||||
|
||||
inline const char *url() const { return m_pool.url(); }
|
||||
inline SocketState state() const { return m_state; }
|
||||
inline uv_stream_t *stream() const { return reinterpret_cast<uv_stream_t *>(m_socket); }
|
||||
inline void setExtension(Extension ext, bool enable) noexcept { m_extensions.set(ext, enable); }
|
||||
|
|
353
src/base/net/stratum/EthStratumClient.cpp
Normal file
353
src/base/net/stratum/EthStratumClient.cpp
Normal file
|
@ -0,0 +1,353 @@
|
|||
/* XMRig
|
||||
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
|
||||
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
|
||||
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
|
||||
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
||||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
|
||||
* Copyright 2019 jtgrassie <https://github.com/jtgrassie>
|
||||
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <cinttypes>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include "3rdparty/libethash/endian.h"
|
||||
#include "3rdparty/rapidjson/document.h"
|
||||
#include "3rdparty/rapidjson/error/en.h"
|
||||
#include "3rdparty/rapidjson/stringbuffer.h"
|
||||
#include "3rdparty/rapidjson/writer.h"
|
||||
|
||||
#include "base/io/json/Json.h"
|
||||
#include "base/io/json/JsonRequest.h"
|
||||
#include "base/io/log/Log.h"
|
||||
#include "base/kernel/interfaces/IClientListener.h"
|
||||
#include "base/net/stratum/EthStratumClient.h"
|
||||
|
||||
#include "net/JobResult.h"
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
||||
|
||||
EthStratumClient::EthStratumClient(int id, const char *agent, IClientListener *listener) :
|
||||
Client(id, agent, listener)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void EthStratumClient::login()
|
||||
{
|
||||
using namespace rapidjson;
|
||||
m_results.clear();
|
||||
|
||||
Document doc(kObjectType);
|
||||
auto& allocator = doc.GetAllocator();
|
||||
|
||||
Value params(kArrayType);
|
||||
params.PushBack(StringRef(agent()), allocator);
|
||||
|
||||
JsonRequest::create(doc, m_sequence, "mining.subscribe", params);
|
||||
|
||||
send(doc, [this](const rapidjson::Value& result, bool success, uint64_t elapsed) { OnSubscribeResponse(result, success, elapsed); });
|
||||
}
|
||||
|
||||
|
||||
void EthStratumClient::onClose()
|
||||
{
|
||||
m_authorized = false;
|
||||
Client::onClose();
|
||||
}
|
||||
|
||||
|
||||
int64_t EthStratumClient::submit(const JobResult& result)
|
||||
{
|
||||
# ifndef XMRIG_PROXY_PROJECT
|
||||
if ((m_state != ConnectedState) || !m_authorized) {
|
||||
return -1;
|
||||
}
|
||||
# endif
|
||||
|
||||
if (result.diff == 0) {
|
||||
disconnect();
|
||||
return -1;
|
||||
}
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
Document doc(kObjectType);
|
||||
auto& allocator = doc.GetAllocator();
|
||||
|
||||
Value params(kArrayType);
|
||||
params.PushBack(StringRef(m_pool.user().data()), allocator);
|
||||
params.PushBack(StringRef(result.jobId.data()), allocator);
|
||||
|
||||
std::stringstream s;
|
||||
s << "0x" << std::hex << std::setw(16) << std::setfill('0') << result.nonce;
|
||||
params.PushBack(rapidjson::Value(s.str().c_str(), allocator), allocator);
|
||||
|
||||
s.str(std::string());
|
||||
s << "0x";
|
||||
for (size_t i = 0; i < 32; ++i) {
|
||||
const uint32_t k = result.headerHash()[i];
|
||||
s << std::hex << std::setw(2) << std::setfill('0') << k;
|
||||
}
|
||||
params.PushBack(rapidjson::Value(s.str().c_str(), allocator), allocator);
|
||||
|
||||
s.str(std::string());
|
||||
s << "0x";
|
||||
for (size_t i = 0; i < 32; ++i) {
|
||||
const uint32_t k = result.mixHash()[i];
|
||||
s << std::hex << std::setw(2) << std::setfill('0') << k;
|
||||
}
|
||||
params.PushBack(rapidjson::Value(s.str().c_str(), allocator), allocator);
|
||||
|
||||
JsonRequest::create(doc, m_sequence, "mining.submit", params);
|
||||
|
||||
uint64_t actual_diff = ethash_swap_u64(*((uint64_t*)result.result()));
|
||||
actual_diff = actual_diff ? (uint64_t(-1) / actual_diff) : 0;
|
||||
|
||||
# ifdef XMRIG_PROXY_PROJECT
|
||||
m_results[m_sequence] = SubmitResult(m_sequence, result.diff, actual_diff, result.id, 0);
|
||||
# else
|
||||
m_results[m_sequence] = SubmitResult(m_sequence, result.diff, actual_diff, 0, result.backend);
|
||||
# endif
|
||||
|
||||
return send(doc);
|
||||
}
|
||||
|
||||
|
||||
bool EthStratumClient::handleResponse(int64_t id, const rapidjson::Value& result, const rapidjson::Value& error)
|
||||
{
|
||||
auto it = m_callbacks.find(id);
|
||||
if (it != m_callbacks.end()) {
|
||||
const uint64_t elapsed = Chrono::steadyMSecs() - it->second.ts;
|
||||
|
||||
if (error.IsObject()) {
|
||||
it->second.callback(error, false, elapsed);
|
||||
}
|
||||
else {
|
||||
it->second.callback(result, true, elapsed);
|
||||
}
|
||||
|
||||
m_callbacks.erase(it);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* err = nullptr;
|
||||
if (error.IsArray() && error.GetArray().Size() > 1) {
|
||||
auto& value = error.GetArray()[1];
|
||||
if (value.IsString()) {
|
||||
err = value.GetString();
|
||||
}
|
||||
}
|
||||
|
||||
handleSubmitResponse(id, err);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void EthStratumClient::parseNotification(const char* method, const rapidjson::Value& params, const rapidjson::Value& error)
|
||||
{
|
||||
if (error.IsObject()) {
|
||||
if (!isQuiet()) {
|
||||
LOG_ERR("[%s] error: \"%s\", code: %d", url(), error["message"].GetString(), error["code"].GetInt());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!method) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(method, "mining.set_target") == 0) {
|
||||
if (!params.IsArray()) {
|
||||
LOG_ERR("Invalid mining.set_target notification: params is not an array");
|
||||
return;
|
||||
}
|
||||
|
||||
if (params.GetArray().Size() != 1) {
|
||||
LOG_ERR("Invalid mining.set_target notification: params array has wrong size");
|
||||
return;
|
||||
}
|
||||
|
||||
auto& new_target = params.GetArray()[0];
|
||||
if (!new_target.IsString()) {
|
||||
LOG_ERR("Invalid mining.set_target notification: target is not a string");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string new_target_str = new_target.GetString();
|
||||
new_target_str.resize(16, '0');
|
||||
|
||||
m_target = std::stoull(new_target_str, nullptr, 16);
|
||||
LOG_DEBUG("Target set to %016" PRIX64, m_target);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(method, "mining.notify") == 0) {
|
||||
if (!params.IsArray()) {
|
||||
LOG_ERR("Invalid mining.notify notification: params is not an array");
|
||||
return;
|
||||
}
|
||||
|
||||
auto arr = params.GetArray();
|
||||
|
||||
if (arr.Size() < 6) {
|
||||
LOG_ERR("Invalid mining.notify notification: params array has wrong size");
|
||||
return;
|
||||
}
|
||||
|
||||
Job job;
|
||||
job.setId(arr[0].GetString());
|
||||
|
||||
Algorithm algo = m_pool.algorithm();
|
||||
if (algo == Algorithm::INVALID) {
|
||||
algo = m_pool.coin().algorithm(0);
|
||||
}
|
||||
job.setAlgorithm(algo);
|
||||
|
||||
std::stringstream s;
|
||||
|
||||
// header hash (32 bytes)
|
||||
s << arr[1].GetString();
|
||||
|
||||
// nonce template (8 bytes)
|
||||
for (uint64_t i = 0, k = m_extraNonce; i < sizeof(m_extraNonce); ++i, k >>= 8) {
|
||||
s << std::hex << std::setw(2) << std::setfill('0') << (k & 0xFF);
|
||||
}
|
||||
|
||||
std::string blob = s.str();
|
||||
|
||||
// zeros up to 76 bytes
|
||||
blob.resize(76 * 2, '0');
|
||||
job.setBlob(blob.c_str());
|
||||
|
||||
std::string target_str = arr[3].GetString();
|
||||
target_str.resize(16, '0');
|
||||
const uint64_t target = strtoull(target_str.c_str(), nullptr, 16);
|
||||
job.setDiff(job.toDiff(target));
|
||||
|
||||
job.setHeight(arr[5].GetUint64());
|
||||
|
||||
m_listener->onJobReceived(this, job, params);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool EthStratumClient::disconnect()
|
||||
{
|
||||
m_authorized = false;
|
||||
|
||||
return Client::disconnect();
|
||||
}
|
||||
|
||||
|
||||
void EthStratumClient::OnSubscribeResponse(const rapidjson::Value& result, bool success, uint64_t elapsed)
|
||||
{
|
||||
if (!success) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!result.IsArray()) {
|
||||
LOG_ERR("Invalid mining.subscribe response: result is not an array");
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.GetArray().Size() <= 1) {
|
||||
LOG_ERR("Invalid mining.subscribe response: result array is too short");
|
||||
return;
|
||||
}
|
||||
|
||||
auto& extra_nonce = result.GetArray()[1];
|
||||
if (!extra_nonce.IsString()) {
|
||||
LOG_ERR("Invalid mining.subscribe response: extra nonce is not a string");
|
||||
return;
|
||||
}
|
||||
|
||||
const char* s = extra_nonce.GetString();
|
||||
size_t len = extra_nonce.GetStringLength();
|
||||
|
||||
// Skip "0x"
|
||||
if ((len >= 2) && (s[0] == '0') && (s[1] == 'x')) {
|
||||
s += 2;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
if (len & 1) {
|
||||
LOG_ERR("Invalid mining.subscribe response: extra nonce has an odd number of hex chars");
|
||||
return;
|
||||
}
|
||||
|
||||
if (len > 8) {
|
||||
LOG_ERR("Invalid mining.subscribe response: extra nonce is too long");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string extra_nonce_str(s);
|
||||
extra_nonce_str.resize(16, '0');
|
||||
|
||||
m_extraNonce = std::stoull(extra_nonce_str, nullptr, 16);
|
||||
LOG_DEBUG("Extra nonce set to %s", s);
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
Document doc(kObjectType);
|
||||
auto& allocator = doc.GetAllocator();
|
||||
|
||||
Value params(kArrayType);
|
||||
|
||||
const char* user = m_pool.user().data();
|
||||
const char* pass = m_pool.password().data();
|
||||
|
||||
params.PushBack(StringRef(user), allocator);
|
||||
params.PushBack(StringRef(pass), allocator);
|
||||
|
||||
JsonRequest::create(doc, m_sequence, "mining.authorize", params);
|
||||
|
||||
send(doc, [this](const rapidjson::Value& result, bool success, uint64_t elapsed) { OnAuthorizeResponse(result, success, elapsed); });
|
||||
}
|
||||
|
||||
void EthStratumClient::OnAuthorizeResponse(const rapidjson::Value& result, bool success, uint64_t elapsed)
|
||||
{
|
||||
if (!success) {
|
||||
disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!result.IsBool()) {
|
||||
LOG_ERR("Invalid mining.authorize response: result is not a boolean");
|
||||
|
||||
disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!result.GetBool()) {
|
||||
LOG_ERR("Login failed");
|
||||
disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG("Login succeeded");
|
||||
|
||||
m_authorized = true;
|
||||
}
|
||||
|
||||
}
|
71
src/base/net/stratum/EthStratumClient.h
Normal file
71
src/base/net/stratum/EthStratumClient.h
Normal file
|
@ -0,0 +1,71 @@
|
|||
/* XMRig
|
||||
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
|
||||
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
|
||||
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
|
||||
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
||||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
|
||||
* Copyright 2019 jtgrassie <https://github.com/jtgrassie>
|
||||
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef XMRIG_ETHSTRATUMCLIENT_H
|
||||
#define XMRIG_ETHSTRATUMCLIENT_H
|
||||
|
||||
|
||||
#include "base/net/stratum/Client.h"
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
||||
|
||||
class IClientListener;
|
||||
|
||||
|
||||
class EthStratumClient : public Client
|
||||
{
|
||||
public:
|
||||
XMRIG_DISABLE_COPY_MOVE_DEFAULT(EthStratumClient)
|
||||
|
||||
EthStratumClient(int id, const char *agent, IClientListener *listener);
|
||||
|
||||
void login() override;
|
||||
void onClose() override;
|
||||
|
||||
protected:
|
||||
int64_t submit(const JobResult& result) override;
|
||||
|
||||
bool handleResponse(int64_t id, const rapidjson::Value& result, const rapidjson::Value& error) override;
|
||||
void parseNotification(const char* method, const rapidjson::Value& params, const rapidjson::Value& error) override;
|
||||
|
||||
bool disconnect() override;
|
||||
|
||||
private:
|
||||
void OnSubscribeResponse(const rapidjson::Value& result, bool success, uint64_t elapsed);
|
||||
void OnAuthorizeResponse(const rapidjson::Value& result, bool success, uint64_t elapsed);
|
||||
|
||||
bool m_authorized = false;
|
||||
|
||||
uint64_t m_target = 0;
|
||||
uint64_t m_extraNonce = 0;
|
||||
};
|
||||
|
||||
|
||||
} /* namespace xmrig */
|
||||
|
||||
|
||||
#endif /* XMRIG_ETHSTRATUMCLIENT_H */
|
|
@ -71,15 +71,17 @@ public:
|
|||
inline const String &extraNonce() const { return m_extraNonce; }
|
||||
inline const String &id() const { return m_id; }
|
||||
inline const String &poolWallet() const { return m_poolWallet; }
|
||||
inline const uint32_t *nonce() const { return reinterpret_cast<const uint32_t*>(m_blob + 39); }
|
||||
inline int32_t nonce_offset() const { return (algorithm().family() == Algorithm::KAWPOW) ? 32 : 39; }
|
||||
inline size_t nonce_size() const { return (algorithm().family() == Algorithm::KAWPOW) ? 8 : 4; }
|
||||
inline const uint32_t *nonce() const { return reinterpret_cast<const uint32_t*>(m_blob + nonce_offset()); }
|
||||
inline const uint8_t *blob() const { return m_blob; }
|
||||
inline uint8_t *blob() { return m_blob; }
|
||||
inline size_t size() const { return m_size; }
|
||||
inline uint32_t *nonce() { return reinterpret_cast<uint32_t*>(m_blob + 39); }
|
||||
inline uint32_t *nonce() { return reinterpret_cast<uint32_t*>(m_blob + nonce_offset()); }
|
||||
inline uint32_t backend() const { return m_backend; }
|
||||
inline uint64_t diff() const { return m_diff; }
|
||||
inline uint64_t height() const { return m_height; }
|
||||
inline uint64_t target() const { return m_target; }
|
||||
inline uint8_t fixedByte() const { return *(m_blob + 42); }
|
||||
inline uint8_t index() const { return m_index; }
|
||||
inline void reset() { m_size = 0; m_diff = 0; }
|
||||
inline void setAlgorithm(const Algorithm::Id id) { m_algorithm = id; }
|
||||
|
@ -98,7 +100,6 @@ public:
|
|||
inline const String &rawSeedHash() const { return m_rawSeedHash; }
|
||||
# endif
|
||||
|
||||
static inline uint32_t *nonce(uint8_t *blob) { return reinterpret_cast<uint32_t*>(blob + 39); }
|
||||
static inline uint64_t toDiff(uint64_t target) { return target ? (0xFFFFFFFFFFFFFFFFULL / target) : 0; }
|
||||
|
||||
inline bool operator!=(const Job &other) const { return !isEqual(other); }
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "base/io/log/Log.h"
|
||||
#include "base/kernel/Platform.h"
|
||||
#include "base/net/stratum/Client.h"
|
||||
#include "base/net/stratum/EthStratumClient.h"
|
||||
|
||||
|
||||
#ifdef XMRIG_FEATURE_HTTP
|
||||
|
@ -185,7 +186,12 @@ xmrig::IClient *xmrig::Pool::createClient(int id, IClientListener *listener) con
|
|||
IClient *client = nullptr;
|
||||
|
||||
if (m_mode == MODE_POOL) {
|
||||
client = new Client(id, Platform::userAgent(), listener);
|
||||
if ((m_algorithm.family() == Algorithm::KAWPOW) || (m_coin == Coin::RAVEN)) {
|
||||
client = new EthStratumClient(id, Platform::userAgent(), listener);
|
||||
}
|
||||
else {
|
||||
client = new Client(id, Platform::userAgent(), listener);
|
||||
}
|
||||
}
|
||||
# ifdef XMRIG_FEATURE_HTTP
|
||||
else if (m_mode == MODE_DAEMON) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue