diff --git a/src/base/base.cmake b/src/base/base.cmake index 3246d6f..0f4f872 100644 --- a/src/base/base.cmake +++ b/src/base/base.cmake @@ -68,6 +68,7 @@ set(HEADERS_BASE src/base/net/tools/MemPool.h src/base/net/tools/NetBuffer.h src/base/net/tools/Storage.h + src/base/tools/Alignment.h src/base/tools/Arguments.h src/base/tools/Baton.h src/base/tools/bswap_64.h @@ -132,6 +133,7 @@ set(SOURCES_BASE src/base/net/tools/LineReader.cpp src/base/net/tools/NetBuffer.cpp src/base/tools/Arguments.cpp + src/base/tools/Chrono.cpp src/base/tools/cryptonote/BlockTemplate.cpp src/base/tools/cryptonote/crypto-ops-data.c src/base/tools/cryptonote/crypto-ops.c @@ -244,7 +246,7 @@ else() endif() -if (WITH_KAWPOW) +if (WITH_KAWPOW OR WITH_GHOSTRIDER) list(APPEND HEADERS_BASE src/base/net/stratum/AutoClient.h src/base/net/stratum/EthStratumClient.h diff --git a/src/base/crypto/Algorithm.cpp b/src/base/crypto/Algorithm.cpp index 8c3a1ad..6e76fd2 100644 --- a/src/base/crypto/Algorithm.cpp +++ b/src/base/crypto/Algorithm.cpp @@ -91,16 +91,16 @@ const char *Algorithm::kAR2_CHUKWA_V2 = "argon2/chukwav2"; const char *Algorithm::kAR2_WRKZ = "argon2/ninja"; #endif -#ifdef XMRIG_ALGO_ASTROBWT -const char *Algorithm::kASTROBWT = "astrobwt"; -const char *Algorithm::kASTROBWT_DERO = "astrobwt"; -#endif - #ifdef XMRIG_ALGO_KAWPOW const char *Algorithm::kKAWPOW = "kawpow"; const char *Algorithm::kKAWPOW_RVN = "kawpow"; #endif +#ifdef XMRIG_ALGO_GHOSTRIDER +const char* Algorithm::kGHOSTRIDER = "ghostrider"; +const char* Algorithm::kGHOSTRIDER_RTM = "ghostrider"; +#endif + #define ALGO_NAME(ALGO) { Algorithm::ALGO, Algorithm::k##ALGO } #define ALGO_ALIAS(ALGO, NAME) { NAME, Algorithm::ALGO } @@ -156,13 +156,13 @@ static const std::map kAlgorithmNames = { ALGO_NAME(AR2_WRKZ), # endif -# ifdef XMRIG_ALGO_ASTROBWT - ALGO_NAME(ASTROBWT_DERO), -# endif - # ifdef XMRIG_ALGO_KAWPOW ALGO_NAME(KAWPOW_RVN), # endif + +# ifdef XMRIG_ALGO_GHOSTRIDER + ALGO_NAME(GHOSTRIDER_RTM), +# endif }; @@ -271,13 +271,14 @@ static const std::map kAlgorithmAlias ALGO_ALIAS_AUTO(AR2_WRKZ), ALGO_ALIAS(AR2_WRKZ, "argon2/wrkz"), # endif -# ifdef XMRIG_ALGO_ASTROBWT - ALGO_ALIAS_AUTO(ASTROBWT_DERO), ALGO_ALIAS(ASTROBWT_DERO, "astrobwt/dero"), -# endif - # ifdef XMRIG_ALGO_KAWPOW ALGO_ALIAS_AUTO(KAWPOW_RVN), ALGO_ALIAS(KAWPOW_RVN, "kawpow/rvn"), # endif + +# ifdef XMRIG_ALGO_GHOSTRIDER + ALGO_ALIAS_AUTO(GHOSTRIDER_RTM), ALGO_ALIAS(GHOSTRIDER_RTM, "ghostrider/rtm"), + ALGO_ALIAS(GHOSTRIDER_RTM, "gr"), +# endif }; @@ -351,8 +352,8 @@ std::vector xmrig::Algorithm::all(const std::function> (64 - (y)))) #endif -const uint64_t keccakf_rndc[24] = +const uint64_t keccakf_rndc[24] = { 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, - 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 }; @@ -53,10 +53,8 @@ const uint64_t keccakf_rndc[24] = void xmrig::keccakf(uint64_t st[25], int rounds) { - int i, j, round; - uint64_t t, bc[5]; - - for (round = 0; round < rounds; ++round) { + for (int round = 0; round < rounds; ++round) { + uint64_t bc[5]; // Theta bc[0] = st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20]; @@ -65,17 +63,21 @@ void xmrig::keccakf(uint64_t st[25], int rounds) bc[3] = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23]; bc[4] = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24]; - for (i = 0; i < 5; ++i) { - t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); - st[i ] ^= t; - st[i + 5] ^= t; - st[i + 10] ^= t; - st[i + 15] ^= t; - st[i + 20] ^= t; +#define X(i) { \ + const uint64_t t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); \ + st[i ] ^= t; \ + st[i + 5] ^= t; \ + st[i + 10] ^= t; \ + st[i + 15] ^= t; \ + st[i + 20] ^= t; \ } + X(0); X(1); X(2); X(3); X(4); + +#undef X + // Rho Pi - t = st[1]; + const uint64_t t = st[1]; st[ 1] = ROTL64(st[ 6], 44); st[ 6] = ROTL64(st[ 9], 20); st[ 9] = ROTL64(st[22], 61); @@ -103,7 +105,7 @@ void xmrig::keccakf(uint64_t st[25], int rounds) // Chi // unrolled loop, where only last iteration is different - j = 0; + int j = 0; bc[0] = st[j ]; bc[1] = st[j + 1]; @@ -155,7 +157,7 @@ void xmrig::keccakf(uint64_t st[25], int rounds) st[j + 2] ^= (~bc[3]) & bc[4]; st[j + 3] ^= (~bc[4]) & bc[0]; st[j + 4] ^= (~bc[0]) & bc[1]; - + // Iota st[0] ^= keccakf_rndc[round]; } @@ -173,7 +175,7 @@ void xmrig::keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen) rsiz = sizeof(state_t) == mdlen ? HASH_DATA_AREA : 200 - 2 * mdlen; rsizw = rsiz / 8; - + memset(st, 0, sizeof(st)); for ( ; inlen >= rsiz; inlen -= rsiz, in += rsiz) { diff --git a/src/base/crypto/sha3.cpp b/src/base/crypto/sha3.cpp index ad41bd3..d05f9b6 100644 --- a/src/base/crypto/sha3.cpp +++ b/src/base/crypto/sha3.cpp @@ -1,16 +1,16 @@ /* ------------------------------------------------------------------------- - * Works when compiled for either 32-bit or 64-bit targets, optimized for + * Works when compiled for either 32-bit or 64-bit targets, optimized for * 64 bit. * - * Canonical implementation of Init/Update/Finalize for SHA-3 byte input. + * Canonical implementation of Init/Update/Finalize for SHA-3 byte input. * * SHA3-256, SHA3-384, SHA-512 are implemented. SHA-224 can easily be added. * * Based on code from http://keccak.noekeon.org/ . * - * I place the code that I wrote into public domain, free to use. + * I place the code that I wrote into public domain, free to use. * - * I would appreciate if you give credits to this work if you used it to + * I would appreciate if you give credits to this work if you used it to * write or test * your code. * * Aug 2015. Andrey Jivsov. crypto@brainhub.org @@ -32,7 +32,7 @@ #define SHA3_TRACE_BUF(format, buf, l, args...) #endif -/* +/* * This flag is used to configure "pure" Keccak, as opposed to NIST SHA3. */ #define SHA3_USE_KECCAK_FLAG 0x80000000 @@ -108,7 +108,7 @@ sha3_Update(void *priv, void const *bufIn, size_t len) SHA3_ASSERT(ctx->byteIndex < 8); SHA3_ASSERT(ctx->wordIndex < sizeof(ctx->s) / sizeof(ctx->s[0])); - if(len < old_tail) { /* have no complete word or haven't started + if(len < old_tail) { /* have no complete word or haven't started * the word yet */ SHA3_TRACE("because %d<%d, store it and return", (unsigned)len, (unsigned)old_tail); @@ -180,7 +180,7 @@ sha3_Update(void *priv, void const *bufIn, size_t len) } /* This is simply the 'update' with the padding block. - * The padding block is 0x01 || 0x00* || 0x80. First 0x01 and last 0x80 + * The padding block is 0x01 || 0x00* || 0x80. First 0x01 and last 0x80 * bytes are always present, but they can be the same byte. */ void const * @@ -214,7 +214,7 @@ sha3_Finalize(void *priv) /* Return first bytes of the ctx->s. This conversion is not needed for * little-endian platforms e.g. wrap with #if !defined(__BYTE_ORDER__) - * || !defined(__ORDER_LITTLE_ENDIAN__) || __BYTE_ORDER__!=__ORDER_LITTLE_ENDIAN__ + * || !defined(__ORDER_LITTLE_ENDIAN__) || __BYTE_ORDER__!=__ORDER_LITTLE_ENDIAN__ * ... the conversion below ... * #endif */ { diff --git a/src/base/crypto/sha3.h b/src/base/crypto/sha3.h index 463ac14..9979d82 100644 --- a/src/base/crypto/sha3.h +++ b/src/base/crypto/sha3.h @@ -2,18 +2,18 @@ #define SHA3_H /* ------------------------------------------------------------------------- - * Works when compiled for either 32-bit or 64-bit targets, optimized for + * Works when compiled for either 32-bit or 64-bit targets, optimized for * 64 bit. * - * Canonical implementation of Init/Update/Finalize for SHA-3 byte input. + * Canonical implementation of Init/Update/Finalize for SHA-3 byte input. * * SHA3-256, SHA3-384, SHA-512 are implemented. SHA-224 can easily be added. * * Based on code from http://keccak.noekeon.org/ . * - * I place the code that I wrote into public domain, free to use. + * I place the code that I wrote into public domain, free to use. * - * I would appreciate if you give credits to this work if you used it to + * I would appreciate if you give credits to this work if you used it to * write or test * your code. * * Aug 2015. Andrey Jivsov. crypto@brainhub.org @@ -65,9 +65,9 @@ void const *sha3_Finalize(void *priv); #ifdef __cplusplus extern "C" #endif -sha3_return_t sha3_HashBuffer( +sha3_return_t sha3_HashBuffer( unsigned bitSize, /* 256, 384, 512 */ enum SHA3_FLAGS flags, /* SHA3_FLAGS_NONE or SHA3_FLAGS_KECCAK */ - const void *in, unsigned inBytes, + const void *in, unsigned inBytes, void *out, unsigned outBytes ); /* up to bitSize/8; truncation OK */ #endif diff --git a/src/base/kernel/Base.cpp b/src/base/kernel/Base.cpp index 0e01218..4aa2e46 100644 --- a/src/base/kernel/Base.cpp +++ b/src/base/kernel/Base.cpp @@ -134,12 +134,12 @@ private: if (read(chain, config)) { return config.release(); } - + chain.addFile(Process::location(Process::HomeLocation, "." APP_ID ".json")); if (read(chain, config)) { return config.release(); } - + chain.addFile(Process::location(Process::HomeLocation, ".config" XMRIG_DIR_SEPARATOR APP_ID ".json")); if (read(chain, config)) { return config.release(); diff --git a/src/base/kernel/Process.cpp b/src/base/kernel/Process.cpp index 173fc2a..5e95e3c 100644 --- a/src/base/kernel/Process.cpp +++ b/src/base/kernel/Process.cpp @@ -152,7 +152,7 @@ xmrig::String xmrig::Process::exepath() { size_t size = sizeof(pathBuf); - return uv_exepath(pathBuf, &size) < 0 ? "" : String(pathBuf, size); + return uv_exepath(pathBuf, &size) < 0 ? String("") : String(pathBuf, size); } diff --git a/src/base/kernel/interfaces/IConfig.h b/src/base/kernel/interfaces/IConfig.h index bc46078..ed76f4c 100644 --- a/src/base/kernel/interfaces/IConfig.h +++ b/src/base/kernel/interfaces/IConfig.h @@ -87,6 +87,7 @@ public: SpendSecretKey = 1055, DaemonZMQPortKey = 1056, HugePagesJitKey = 1057, + RotationKey = 1058, // xmrig common CPUPriorityKey = 1021, @@ -110,8 +111,6 @@ public: CPUMaxThreadsKey = 1026, MemoryPoolKey = 1027, YieldKey = 1030, - AstroBWTMaxSizeKey = 1034, - AstroBWTAVX2Key = 1036, Argon2ImplKey = 1039, RandomXCacheQoSKey = 1040, diff --git a/src/base/net/dns/DnsUvBackend.cpp b/src/base/net/dns/DnsUvBackend.cpp index cb1c0c3..8de95df 100644 --- a/src/base/net/dns/DnsUvBackend.cpp +++ b/src/base/net/dns/DnsUvBackend.cpp @@ -28,13 +28,19 @@ namespace xmrig { +static Storage* storage = nullptr; Storage& DnsUvBackend::getStorage() { - static Storage* storage = new Storage(); + if (storage == nullptr) storage = new Storage(); return *storage; } +void DnsUvBackend::releaseStorage() +{ + delete storage; +} + static addrinfo hints{}; @@ -56,6 +62,7 @@ xmrig::DnsUvBackend::DnsUvBackend() xmrig::DnsUvBackend::~DnsUvBackend() { getStorage().release(m_key); + releaseStorage(); } diff --git a/src/base/net/dns/DnsUvBackend.h b/src/base/net/dns/DnsUvBackend.h index f3733f5..3c2436c 100644 --- a/src/base/net/dns/DnsUvBackend.h +++ b/src/base/net/dns/DnsUvBackend.h @@ -62,6 +62,7 @@ private: uintptr_t m_key; static Storage& getStorage(); + void releaseStorage(); }; diff --git a/src/base/net/stratum/AutoClient.cpp b/src/base/net/stratum/AutoClient.cpp index e3896b5..675be86 100644 --- a/src/base/net/stratum/AutoClient.cpp +++ b/src/base/net/stratum/AutoClient.cpp @@ -50,7 +50,7 @@ bool xmrig::AutoClient::parseLogin(const rapidjson::Value &result, int *code) } const Algorithm algo(Json::getString(result, "algo")); - if (algo.family() != Algorithm::KAWPOW) { + if (algo.family() != Algorithm::KAWPOW && algo.family() != Algorithm::GHOSTRIDER) { *code = 6; return false; } @@ -65,6 +65,12 @@ bool xmrig::AutoClient::parseLogin(const rapidjson::Value &result, int *code) m_mode = ETH_MODE; setAlgo(algo); +# ifdef XMRIG_ALGO_GHOSTRIDER + if (algo.family() == Algorithm::GHOSTRIDER) { + setExtraNonce2Size(Json::getUint64(result, "extra_nonce2_size")); + } +# endif + return true; } diff --git a/src/base/net/stratum/Client.cpp b/src/base/net/stratum/Client.cpp index db6ceca..7abb725 100644 --- a/src/base/net/stratum/Client.cpp +++ b/src/base/net/stratum/Client.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef XMRIG_FEATURE_TLS @@ -660,7 +661,7 @@ void xmrig::Client::parse(char *line, size_t len) LOG_DEBUG("[%s] received (%d bytes): \"%.*s\"", url(), len, static_cast(len), line); - if (len < 32 || line[0] != '{') { + if (len < 22 || line[0] != '{') { if (!isQuiet()) { LOG_ERR("%s " RED("JSON decode failed"), tag()); } @@ -683,12 +684,48 @@ void xmrig::Client::parse(char *line, size_t len) const auto &id = Json::getValue(doc, "id"); const auto &error = Json::getValue(doc, "error"); + const char *method = Json::getString(doc, "method"); + + if (method && strcmp(method, "client.reconnect") == 0) { + const auto ¶ms = Json::getValue(doc, "params"); + if (!params.IsArray()) { + LOG_ERR("%s " RED("invalid client.reconnect notification: params is not an array"), tag()); + return; + } + + auto arr = params.GetArray(); + + if (arr.Empty()) { + LOG_ERR("%s " RED("invalid client.reconnect notification: params array is empty"), tag()); + return; + } + + if (arr.Size() != 2) { + LOG_ERR("%s " RED("invalid client.reconnect notification: params array has wrong size"), tag()); + return; + } + + if (!arr[0].IsString()) { + LOG_ERR("%s " RED("invalid client.reconnect notification: host is not a string"), tag()); + return; + } + + if (!arr[1].IsString()) { + LOG_ERR("%s " RED("invalid client.reconnect notification: port is not a string"), tag()); + return; + } + + std::stringstream s; + s << arr[0].GetString() << ":" << arr[1].GetString(); + LOG_WARN("%s " YELLOW("client.reconnect to %s"), tag(), s.str().c_str()); + setPoolUrl(s.str().c_str()); + return reconnect(); + } if (id.IsInt64()) { return parseResponse(id.GetInt64(), Json::getValue(doc, "result"), error); } - const char *method = Json::getString(doc, "method"); if (!method) { return; } diff --git a/src/base/net/stratum/Client.h b/src/base/net/stratum/Client.h index e1f5d75..300db13 100644 --- a/src/base/net/stratum/Client.h +++ b/src/base/net/stratum/Client.h @@ -84,6 +84,7 @@ protected: inline const char *url() const { return m_pool.url(); } inline const String &rpcId() const { return m_rpcId; } inline void setRpcId(const char *id) { m_rpcId = id; } + inline void setPoolUrl(const char *url) { m_pool.setUrl(url); } virtual bool parseLogin(const rapidjson::Value &result, int *code); virtual void login(); diff --git a/src/base/net/stratum/DaemonClient.cpp b/src/base/net/stratum/DaemonClient.cpp index 57a8d6f..821045e 100644 --- a/src/base/net/stratum/DaemonClient.cpp +++ b/src/base/net/stratum/DaemonClient.cpp @@ -48,8 +48,14 @@ #include "net/JobResult.h" +#ifdef XMRIG_FEATURE_TLS +#include +#endif + + #include #include +#include namespace xmrig { @@ -58,7 +64,9 @@ namespace xmrig { Storage DaemonClient::m_storage; -static const char* kBlocktemplateBlob = "blocktemplate_blob"; +static const char* kBlocktemplateBlob = "blocktemplate_blob"; +static const char* kBlockhashingBlob = "blockhashing_blob"; +static const char* kLastError = "lasterror"; static const char *kGetHeight = "/getheight"; static const char *kGetInfo = "/getinfo"; static const char *kHash = "hash"; @@ -129,7 +137,7 @@ int64_t xmrig::DaemonClient::submit(const JobResult &result) return -1; } - char *data = (m_apiVersion == API_DERO) ? m_blockhashingblob.data() : m_blocktemplateStr.data(); + char *data = m_blocktemplateStr.data(); const size_t sig_offset = m_job.nonceOffset() + m_job.nonceSize(); @@ -161,13 +169,7 @@ int64_t xmrig::DaemonClient::submit(const JobResult &result) Document doc(kObjectType); Value params(kArrayType); - if (m_apiVersion == API_DERO) { - params.PushBack(m_blocktemplateStr.toJSON(), doc.GetAllocator()); - params.PushBack(m_blockhashingblob.toJSON(), doc.GetAllocator()); - } - else { - params.PushBack(m_blocktemplateStr.toJSON(), doc.GetAllocator()); - } + params.PushBack(m_blocktemplateStr.toJSON(), doc.GetAllocator()); JsonRequest::create(doc, m_sequence, "submitblock", params); @@ -193,16 +195,16 @@ void xmrig::DaemonClient::connect() setState(ConnectingState); - if (!m_walletAddress.isValid()) { - return connectError("Invalid wallet address."); - } - if (!m_coin.isValid() && !m_pool.algorithm().isValid()) { return connectError("Invalid algorithm."); } - if ((m_pool.algorithm() == Algorithm::ASTROBWT_DERO) || (m_coin == Coin::DERO)) { - m_apiVersion = API_DERO; + if (!m_pool.algorithm().isValid()) { + m_pool.setAlgo(m_coin.algorithm()); + } + + if ((m_apiVersion == API_MONERO) && !m_walletAddress.isValid()) { + return connectError("Invalid wallet address."); } if (m_pool.zmq_port() >= 0) { @@ -306,12 +308,7 @@ void xmrig::DaemonClient::onTimer(const Timer *) connect(); } else if (m_state == ConnectedState) { - if (m_apiVersion == API_DERO) { - rpcSend(JsonRequest::create(m_sequence, "get_info")); - } - else { - send((m_apiVersion == API_MONERO) ? kGetHeight : kGetInfo); - } + send((m_apiVersion == API_MONERO) ? kGetHeight : kGetInfo); } } @@ -330,26 +327,27 @@ void xmrig::DaemonClient::onResolved(const DnsRecords &records, int status, cons } - delete m_ZMQSocket; - - const auto &record = records.get(); m_ip = record.ip(); auto req = new uv_connect_t; req->data = m_storage.ptr(m_key); - m_ZMQSocket = new uv_tcp_t; - m_ZMQSocket->data = m_storage.ptr(m_key); + uv_tcp_t* s = new uv_tcp_t; + s->data = m_storage.ptr(m_key); - uv_tcp_init(uv_default_loop(), m_ZMQSocket); - uv_tcp_nodelay(m_ZMQSocket, 1); + uv_tcp_init(uv_default_loop(), s); + uv_tcp_nodelay(s, 1); # ifndef WIN32 - uv_tcp_keepalive(m_ZMQSocket, 1, 60); + uv_tcp_keepalive(s, 1, 60); # endif - uv_tcp_connect(req, m_ZMQSocket, record.addr(m_pool.zmq_port()), onZMQConnect); + if (m_pool.zmq_port() > 0) { + delete m_ZMQSocket; + m_ZMQSocket = s; + uv_tcp_connect(req, s, record.addr(m_pool.zmq_port()), onZMQConnect); + } } @@ -396,7 +394,7 @@ bool xmrig::DaemonClient::parseJob(const rapidjson::Value ¶ms, int *code) ); # endif - m_blockhashingblob = Json::getString(params, "blockhashing_blob"); + m_blockhashingblob = Json::getString(params, kBlockhashingBlob); if (m_blocktemplate.hasMinerSignature()) { if (m_pool.spendSecretKey().isEmpty()) { @@ -452,11 +450,6 @@ bool xmrig::DaemonClient::parseJob(const rapidjson::Value ¶ms, int *code) # endif } - if (m_apiVersion == API_DERO) { - const uint64_t offset = Json::getUint64(params, "reserved_offset"); - Cvt::toHex(m_blockhashingblob.data() + offset * 2, kBlobReserveSize * 2, Cvt::randomBytes(kBlobReserveSize).data(), kBlobReserveSize); - } - if (m_coin.isValid()) { job.setAlgorithm(m_coin.algorithm(m_blocktemplate.majorVersion())); } @@ -477,13 +470,6 @@ bool xmrig::DaemonClient::parseJob(const rapidjson::Value ¶ms, int *code) m_blocktemplateStr = std::move(blocktemplate); m_prevHash = Json::getString(params, "prev_hash"); - if (m_apiVersion == API_DERO) { - // Truncate to 32 bytes to have the same data as in get_info RPC - if (m_prevHash.size() > 64) { - m_prevHash.data()[64] = '\0'; - } - } - if (m_state == ConnectingState) { setState(ConnectedState); } @@ -527,13 +513,6 @@ bool xmrig::DaemonClient::parseResponse(int64_t id, const rapidjson::Value &resu const char* error_msg = nullptr; - if ((m_apiVersion == API_DERO) && result.HasMember("status")) { - error_msg = result["status"].GetString(); - if (!error_msg || (strlen(error_msg) == 0) || (strcmp(error_msg, "OK") == 0)) { - error_msg = nullptr; - } - } - if (handleSubmitResponse(id, error_msg)) { if (error_msg || (m_pool.zmq_port() < 0)) { getBlockTemplate(); @@ -554,12 +533,7 @@ int64_t xmrig::DaemonClient::getBlockTemplate() Value params(kObjectType); params.AddMember("wallet_address", m_user.toJSON(), allocator); - if (m_apiVersion == API_DERO) { - params.AddMember("reserve_size", static_cast(kBlobReserveSize), allocator); - } - else { - params.AddMember("extra_nonce", Cvt::toHex(Cvt::randomBytes(kBlobReserveSize)).toJSON(doc), allocator); - } + params.AddMember("extra_nonce", Cvt::toHex(Cvt::randomBytes(kBlobReserveSize)).toJSON(doc), allocator); JsonRequest::create(doc, m_sequence, "getblocktemplate", params); @@ -885,10 +859,14 @@ void xmrig::DaemonClient::ZMQParse() m_ZMQRecvBuf.erase(m_ZMQRecvBuf.begin(), m_ZMQRecvBuf.begin() + (data - m_ZMQRecvBuf.data())); # ifdef APP_DEBUG - LOG_DEBUG(CYAN("tcp-zmq://%s:%u") BLACK_BOLD(" read ") CYAN_BOLD("%zu") BLACK_BOLD(" bytes") " %s", m_pool.host().data(), m_pool.zmq_port(), msg.size(), msg.data()); + msg.push_back('\0'); + LOG_DEBUG(CYAN("tcp-zmq://%s:%u") BLACK_BOLD(" read ") CYAN_BOLD("%zu") BLACK_BOLD(" bytes") " %s", m_pool.host().data(), m_pool.zmq_port(), msg.size() - 1, msg.data()); # endif - getBlockTemplate(); + // 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; + send(kGetHeight); } diff --git a/src/base/net/stratum/DaemonClient.h b/src/base/net/stratum/DaemonClient.h index 5a6ca8c..7880de4 100644 --- a/src/base/net/stratum/DaemonClient.h +++ b/src/base/net/stratum/DaemonClient.h @@ -39,6 +39,12 @@ using uv_handle_t = struct uv_handle_s; using uv_stream_t = struct uv_stream_s; using uv_tcp_t = struct uv_tcp_s; +#ifdef XMRIG_FEATURE_TLS +using BIO = struct bio_st; +using SSL = struct ssl_st; +using SSL_CTX = struct ssl_ctx_st; +#endif + namespace xmrig { @@ -88,7 +94,6 @@ private: enum { API_CRYPTONOTE_DEFAULT, API_MONERO, - API_DERO, } m_apiVersion = API_MONERO; BlockTemplate m_blocktemplate; diff --git a/src/base/net/stratum/EthStratumClient.cpp b/src/base/net/stratum/EthStratumClient.cpp index 94d8563..fd877d7 100644 --- a/src/base/net/stratum/EthStratumClient.cpp +++ b/src/base/net/stratum/EthStratumClient.cpp @@ -34,6 +34,16 @@ #include "base/kernel/interfaces/IClientListener.h" #include "net/JobResult.h" +#ifdef XMRIG_ALGO_GHOSTRIDER +#include + +extern "C" { +#include "crypto/ghostrider/sph_sha2.h" +} + +#include "base/tools/Cvt.h" +#endif + xmrig::EthStratumClient::EthStratumClient(int id, const char *agent, IClientListener *listener) : @@ -63,32 +73,56 @@ int64_t xmrig::EthStratumClient::submit(const JobResult& result) auto& allocator = doc.GetAllocator(); Value params(kArrayType); - params.PushBack(m_pool.user().toJSON(), allocator); + params.PushBack(m_user.toJSON(), allocator); params.PushBack(result.jobId.toJSON(), allocator); - std::stringstream s; - s << "0x" << std::hex << std::setw(16) << std::setfill('0') << result.nonce; - params.PushBack(Value(s.str().c_str(), allocator), allocator); +# ifdef XMRIG_ALGO_GHOSTRIDER + if (m_pool.algorithm().id() == Algorithm::GHOSTRIDER_RTM) { + params.PushBack(Value("00000000000000000000000000000000", static_cast(m_extraNonce2Size * 2)), allocator); + params.PushBack(Value(m_ntime.data(), 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; + std::stringstream s; + s << std::hex << std::setw(8) << std::setfill('0') << result.nonce; + params.PushBack(Value(s.str().c_str(), allocator), allocator); } - params.PushBack(Value(s.str().c_str(), allocator), allocator); + else +# endif + { + std::stringstream s; + s << "0x" << std::hex << std::setw(16) << std::setfill('0') << result.nonce; + params.PushBack(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; + 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(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(Value(s.str().c_str(), allocator), allocator); } - params.PushBack(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())); + uint64_t actual_diff; + +# ifdef XMRIG_ALGO_GHOSTRIDER + if (result.algorithm == Algorithm::GHOSTRIDER_RTM) { + actual_diff = reinterpret_cast(result.result())[3]; + } + else +# endif + { + actual_diff = ethash_swap_u64(*((uint64_t*)result.result())); + } + actual_diff = actual_diff ? (uint64_t(-1) / actual_diff) : 0; # ifdef XMRIG_PROXY_PROJECT @@ -161,6 +195,34 @@ void xmrig::EthStratumClient::parseNotification(const char *method, const rapidj setExtraNonce(arr[0]); } +# ifdef XMRIG_ALGO_GHOSTRIDER + if (strcmp(method, "mining.set_difficulty") == 0) { + if (!params.IsArray()) { + LOG_ERR("%s " RED("invalid mining.set_difficulty notification: params is not an array"), tag()); + return; + } + + if (m_pool.algorithm().id() != Algorithm::GHOSTRIDER_RTM) { + return; + } + + auto arr = params.GetArray(); + + if (arr.Empty()) { + LOG_ERR("%s " RED("invalid mining.set_difficulty notification: params array is empty"), tag()); + return; + } + + if (!arr[0].IsDouble() && !arr[0].IsUint64()) { + LOG_ERR("%s " RED("invalid mining.set_difficulty notification: difficulty is not a number"), tag()); + return; + } + + const double diff = arr[0].IsDouble() ? arr[0].GetDouble() : arr[0].GetUint64(); + m_nextDifficulty = static_cast(ceil(diff * 65536.0)); + } +# endif + if (strcmp(method, "mining.notify") == 0) { if (!params.IsArray()) { LOG_ERR("%s " RED("invalid mining.notify notification: params is not an array"), tag()); @@ -169,44 +231,152 @@ void xmrig::EthStratumClient::parseNotification(const char *method, const rapidj auto arr = params.GetArray(); - if (arr.Size() < 6) { + auto algo = m_pool.algorithm(); + if (!algo.isValid()) { + algo = m_pool.coin().algorithm(); + } + + const size_t min_arr_size = (algo.id() == Algorithm::GHOSTRIDER_RTM) ? 8 : 6; + + if (arr.Size() < min_arr_size) { LOG_ERR("%s " RED("invalid mining.notify notification: params array has wrong size"), tag()); return; } + if (!arr[0].IsString()) { + LOG_ERR("%s " RED("invalid mining.notify notification: invalid job id"), tag()); + return; + } + Job job; job.setId(arr[0].GetString()); - auto algo = m_pool.algorithm(); - if (!algo.isValid()) { - algo = m_pool.coin().algorithm(); - } - job.setAlgorithm(algo); job.setExtraNonce(m_extraNonce.second); std::stringstream s; - // header hash (32 bytes) - s << arr[1].GetString(); +# ifdef XMRIG_ALGO_GHOSTRIDER + if (algo.id() == Algorithm::GHOSTRIDER_RTM) { + // Raptoreum uses Bitcoin's Stratum protocol + // https://en.bitcoinwiki.org/wiki/Stratum_mining_protocol#mining.notify - // nonce template (8 bytes) - for (uint64_t i = 0, k = m_extraNonce.first; i < sizeof(m_extraNonce.first); ++i, k >>= 8) { - s << std::hex << std::setw(2) << std::setfill('0') << (k & 0xFF); + if (!arr[1].IsString() || !arr[2].IsString() || !arr[3].IsString() || !arr[4].IsArray() || !arr[5].IsString() || !arr[6].IsString() || !arr[7].IsString()) { + LOG_ERR("%s " RED("invalid mining.notify notification: invalid param array"), tag()); + return; + } + + // Version + s << arr[5].GetString(); + + // Previous block hash + s << arr[1].GetString(); + + // Merkle tree root + std::string blob = arr[2].GetString(); + blob += m_extraNonce.second; + blob.append(m_extraNonce2Size * 2, '0'); + blob += arr[3].GetString(); + + uint8_t merkle_root[64]; + + Buffer buf = Cvt::fromHex(blob.c_str(), blob.length()); + + // Get height from coinbase + { + uint8_t* p = buf.data() + 32; + uint8_t* m = p + 128; + + while ((p < m) && (*p != 0xff)) ++p; + while ((p < m) && (*p == 0xff)) ++p; + + if ((p < m) && (*(p - 1) == 0xff) && (*(p - 2) == 0xff)) { + uint32_t height = *reinterpret_cast(p + 2); + switch (*(p + 1)) { + case 4: + height += *reinterpret_cast(p + 4) * 0x10000UL; + break; + case 3: + height += *(p + 4) * 0x10000UL; + break; + } + job.setHeight(height); + } + else { + job.setHeight(0); + } + } + + sha256d(merkle_root, buf.data(), static_cast(buf.size())); + + auto merkle_branches = arr[4].GetArray(); + for (int i = 0, n = merkle_branches.Size(); i < n; ++i) { + auto& b = merkle_branches[i]; + buf = b.IsString() ? Cvt::fromHex(b.GetString(), b.GetStringLength()) : Buffer(); + if (buf.size() != 32) { + LOG_ERR("%s " RED("invalid mining.notify notification: param 4 is invalid"), tag()); + return; + } + memcpy(merkle_root + 32, buf.data(), 32); + sha256d(merkle_root, merkle_root, 64); + } + + s << Cvt::toHex(merkle_root, 32); + + // ntime + m_ntime = arr[7].GetString(); + s << m_ntime; + + // nbits + s << arr[6].GetString(); + + blob = s.str(); + + if (blob.size() != 76 * 2) { + LOG_ERR("%s " RED("invalid mining.notify notification: invalid blob size"), tag()); + return; + } + + // zeros up to 80 bytes + blob.resize(80 * 2, '0'); + + // Invert byte order (no idea why, but it's done in Bitcoin's Stratum) + buf = Cvt::fromHex(blob.c_str(), blob.length()); + for (size_t i = 0; i < 80; i += sizeof(uint32_t)) { + uint32_t& k = *reinterpret_cast(buf.data() + i); + if ((i < 36) || (i >= 68)) { + k = ethash_swap_u32(k); + } + } + blob = Cvt::toHex(buf.data(), buf.size()); + + job.setBlob(blob.c_str()); + job.setDiff(m_nextDifficulty); } + else +# endif + { + // header hash (32 bytes) + s << arr[1].GetString(); - std::string blob = s.str(); + // nonce template (8 bytes) + for (uint64_t i = 0, k = m_extraNonce.first; i < sizeof(m_extraNonce.first); ++i, k >>= 8) { + s << std::hex << std::setw(2) << std::setfill('0') << (k & 0xFF); + } - // zeros up to 76 bytes - blob.resize(76 * 2, '0'); - job.setBlob(blob.c_str()); + std::string blob = s.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)); + // zeros up to 76 bytes + blob.resize(76 * 2, '0'); + job.setBlob(blob.c_str()); - job.setHeight(arr[5].GetUint64()); + 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()); + } bool ok = true; m_listener->onVerifyAlgorithm(this, algo, &ok); @@ -301,8 +471,8 @@ void xmrig::EthStratumClient::authorize() auto &allocator = doc.GetAllocator(); Value params(kArrayType); - params.PushBack(m_pool.user().toJSON(), allocator); - params.PushBack(m_pool.password().toJSON(), allocator); + params.PushBack(m_user.toJSON(), allocator); + params.PushBack(m_password.toJSON(), allocator); JsonRequest::create(doc, m_sequence, "mining.authorize", params); @@ -356,11 +526,19 @@ void xmrig::EthStratumClient::onSubscribeResponse(const rapidjson::Value &result throw std::runtime_error("invalid mining.subscribe response: result is not an array"); } - if (result.GetArray().Size() <= 1) { + auto arr = result.GetArray(); + + if (arr.Size() <= 1) { throw std::runtime_error("invalid mining.subscribe response: result array is too short"); } - setExtraNonce(result.GetArray()[1]); + setExtraNonce(arr[1]); + +# ifdef XMRIG_ALGO_GHOSTRIDER + if ((arr.Size() > 2) && (arr[2].IsUint())) { + m_extraNonce2Size = arr[2].GetUint(); + } +# endif if (m_pool.isNicehash()) { using namespace rapidjson; diff --git a/src/base/net/stratum/EthStratumClient.h b/src/base/net/stratum/EthStratumClient.h index 7f3c59e..ebfda6a 100644 --- a/src/base/net/stratum/EthStratumClient.h +++ b/src/base/net/stratum/EthStratumClient.h @@ -47,6 +47,10 @@ protected: void setExtraNonce(const rapidjson::Value &nonce); +# ifdef XMRIG_ALGO_GHOSTRIDER + inline void setExtraNonce2Size(uint64_t size) { m_extraNonce2Size = size; } +# endif + private: static const char *errorMessage(const rapidjson::Value &error); @@ -57,6 +61,12 @@ private: bool m_authorized = false; std::pair m_extraNonce{}; + +# ifdef XMRIG_ALGO_GHOSTRIDER + uint64_t m_extraNonce2Size = 0; + uint64_t m_nextDifficulty = 0; + String m_ntime; +# endif }; diff --git a/src/base/net/stratum/Job.cpp b/src/base/net/stratum/Job.cpp index 8181601..7f5d8d3 100644 --- a/src/base/net/stratum/Job.cpp +++ b/src/base/net/stratum/Job.cpp @@ -30,6 +30,7 @@ #include "base/net/stratum/Job.h" +#include "base/tools/Alignment.h" #include "base/tools/Buffer.h" #include "base/tools/Cvt.h" #include "base/tools/cryptonote/BlockTemplate.h" @@ -47,7 +48,7 @@ xmrig::Job::Job(bool nicehash, const Algorithm &algorithm, const String &clientI bool xmrig::Job::isEqual(const Job &other) const { - return m_id == other.m_id && m_clientId == other.m_clientId && memcmp(m_blob, other.m_blob, sizeof(m_blob)) == 0; + return m_id == other.m_id && m_clientId == other.m_clientId && memcmp(m_blob, other.m_blob, sizeof(m_blob)) == 0 && m_target == other.m_target; } @@ -73,7 +74,7 @@ bool xmrig::Job::setBlob(const char *blob) return false; } - if (*nonce() != 0 && !m_nicehash) { + if (readUnaligned(nonce()) != 0 && !m_nicehash) { m_nicehash = true; } @@ -163,6 +164,14 @@ void xmrig::Job::setSigKey(const char *sig_key) } +int32_t xmrig::Job::nonceOffset() const +{ + auto f = algorithm().family(); + if (f == Algorithm::KAWPOW) return 32; + if (f == Algorithm::GHOSTRIDER) return 76; + return 39; +} + uint32_t xmrig::Job::getNumTransactions() const { if (!(m_algorithm.isCN() || m_algorithm.family() == Algorithm::RANDOM_X)) { diff --git a/src/base/net/stratum/Job.h b/src/base/net/stratum/Job.h index 414da8f..3fb31ba 100644 --- a/src/base/net/stratum/Job.h +++ b/src/base/net/stratum/Job.h @@ -76,7 +76,7 @@ public: inline const String &poolWallet() const { return m_poolWallet; } inline const uint32_t *nonce() const { return reinterpret_cast(m_blob + nonceOffset()); } inline const uint8_t *blob() const { return m_blob; } - inline int32_t nonceOffset() const { return (algorithm().family() == Algorithm::KAWPOW) ? 32 : 39; } + int32_t nonceOffset() const; inline size_t nonceSize() const { return (algorithm().family() == Algorithm::KAWPOW) ? 8 : 4; } inline size_t size() const { return m_size; } inline uint32_t *nonce() { return reinterpret_cast(m_blob + nonceOffset()); } diff --git a/src/base/net/stratum/Pool.cpp b/src/base/net/stratum/Pool.cpp index 9a27d7c..7a58f4c 100644 --- a/src/base/net/stratum/Pool.cpp +++ b/src/base/net/stratum/Pool.cpp @@ -31,7 +31,7 @@ #include "base/kernel/Platform.h" #include "base/net/stratum/Client.h" -#ifdef XMRIG_ALGO_KAWPOW +#if defined XMRIG_ALGO_KAWPOW || defined XMRIG_ALGO_GHOSTRIDER # include "base/net/stratum/AutoClient.h" # include "base/net/stratum/EthStratumClient.h" #endif @@ -218,8 +218,9 @@ xmrig::IClient *xmrig::Pool::createClient(int id, IClientListener *listener) con IClient *client = nullptr; if (m_mode == MODE_POOL) { -# ifdef XMRIG_ALGO_KAWPOW - if ((m_algorithm.family() == Algorithm::KAWPOW) || (m_coin == Coin::RAVEN)) { +# if defined XMRIG_ALGO_KAWPOW || defined XMRIG_ALGO_GHOSTRIDER + const uint32_t f = m_algorithm.family(); + if ((f == Algorithm::KAWPOW) || (f == Algorithm::GHOSTRIDER) || (m_coin == Coin::RAVEN)) { client = new EthStratumClient(id, Platform::userAgent(), listener); } else @@ -236,7 +237,7 @@ xmrig::IClient *xmrig::Pool::createClient(int id, IClientListener *listener) con client = new SelfSelectClient(id, Platform::userAgent(), listener, m_submitToOrigin); } # endif -# ifdef XMRIG_ALGO_KAWPOW +# if defined XMRIG_ALGO_KAWPOW || defined XMRIG_ALGO_GHOSTRIDER else if (m_mode == MODE_AUTO_ETH) { client = new AutoClient(id, Platform::userAgent(), listener); } diff --git a/src/base/net/stratum/Pool.h b/src/base/net/stratum/Pool.h index 865d3db..7868451 100644 --- a/src/base/net/stratum/Pool.h +++ b/src/base/net/stratum/Pool.h @@ -111,6 +111,7 @@ public: inline int zmq_port() const { return m_zmqPort; } inline uint64_t pollInterval() const { return m_pollInterval; } 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; } inline void setProxy(const ProxyUrl &proxy) { m_proxy = proxy; } inline void setRigId(const String &rigId) { m_rigId = rigId; } diff --git a/src/base/net/stratum/Pools.cpp b/src/base/net/stratum/Pools.cpp index d70075a..a2374b9 100644 --- a/src/base/net/stratum/Pools.cpp +++ b/src/base/net/stratum/Pools.cpp @@ -171,7 +171,7 @@ uint32_t xmrig::Pools::benchSize() const return m_benchmark ? m_benchmark->size() : 0; # else return 0; -# endif +# endif } diff --git a/src/base/net/stratum/SelfSelectClient.cpp b/src/base/net/stratum/SelfSelectClient.cpp index a902e25..f411f3e 100644 --- a/src/base/net/stratum/SelfSelectClient.cpp +++ b/src/base/net/stratum/SelfSelectClient.cpp @@ -72,7 +72,14 @@ int64_t xmrig::SelfSelectClient::submit(const JobResult &result) submitOriginDaemon(result); } - return m_client->submit(result); + uint64_t submit_result = m_client->submit(result); + + if (m_submitToOrigin) { + // Ensure that the latest block template is available after block submission + getBlockTemplate(); + } + + return submit_result; } @@ -257,7 +264,7 @@ void xmrig::SelfSelectClient::submitOriginDaemon(const JobResult& result) if (result.diff == 0 || m_blockDiff == 0) { return; } - + if (result.actualDiff() < m_blockDiff) { m_originNotSubmitted++; LOG_DEBUG("%s " RED_BOLD("not submitted to origin daemon, difficulty too low") " (%" PRId64 "/%" PRId64 ") " @@ -280,14 +287,11 @@ void xmrig::SelfSelectClient::submitOriginDaemon(const JobResult& result) 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_originSubmitted++; - LOG_INFO("%s " GREEN_BOLD("submitted to origin daemon") " (%" PRId64 "/%" PRId64 ") " + LOG_INFO("%s " GREEN_BOLD("submitted to origin daemon") " (%" PRId64 "/%" PRId64 ") " " diff " WHITE("%" PRIu64) " vs. " WHITE("%" PRIu64), Tags::origin(), m_originSubmitted, m_originNotSubmitted, 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/tools/Alignment.h b/src/base/tools/Alignment.h new file mode 100644 index 0000000..7afe872 --- /dev/null +++ b/src/base/tools/Alignment.h @@ -0,0 +1,53 @@ +/* XMRig + * Copyright (c) 2018-2022 SChernykh + * Copyright (c) 2016-2022 XMRig , + * + * 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 . + */ + +#ifndef XMRIG_ALIGNMENT_H +#define XMRIG_ALIGNMENT_H + + +#include +#include + + +namespace xmrig { + + +template +inline T readUnaligned(const T* ptr) +{ + static_assert(std::is_trivially_copyable::value, "T must be trivially copyable"); + + T result; + memcpy(&result, ptr, sizeof(T)); + return result; +} + + +template +inline void writeUnaligned(T* ptr, T data) +{ + static_assert(std::is_trivially_copyable::value, "T must be trivially copyable"); + + memcpy(ptr, &data, sizeof(T)); +} + + +} /* namespace xmrig */ + + +#endif /* XMRIG_ALIGNMENT_H */ diff --git a/src/base/tools/Chrono.cpp b/src/base/tools/Chrono.cpp new file mode 100644 index 0000000..5697472 --- /dev/null +++ b/src/base/tools/Chrono.cpp @@ -0,0 +1,44 @@ +/* XMRig + * Copyright (c) 2018-2021 SChernykh + * Copyright (c) 2016-2021 XMRig , + * + * 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 . + */ + +#include "Chrono.h" + + +#ifdef XMRIG_OS_WIN +# include +#endif + + +namespace xmrig { + + +double Chrono::highResolutionMSecs() +{ +# ifdef XMRIG_OS_WIN + LARGE_INTEGER f, t; + QueryPerformanceFrequency(&f); + QueryPerformanceCounter(&t); + return static_cast(t.QuadPart) * 1e3 / f.QuadPart; +# else + using namespace std::chrono; + return static_cast(duration_cast(high_resolution_clock::now().time_since_epoch()).count()) / 1e6; +# endif +} + + +} /* namespace xmrig */ diff --git a/src/base/tools/Chrono.h b/src/base/tools/Chrono.h index 78da18c..65c3d5a 100644 --- a/src/base/tools/Chrono.h +++ b/src/base/tools/Chrono.h @@ -29,12 +29,7 @@ namespace xmrig { class Chrono { public: - static inline uint64_t highResolutionMSecs() - { - using namespace std::chrono; - - return static_cast(time_point_cast(high_resolution_clock::now()).time_since_epoch().count()); - } + static double highResolutionMSecs(); static inline uint64_t steadyMSecs() diff --git a/src/base/tools/bswap_64.h b/src/base/tools/bswap_64.h index 96335c6..462a335 100644 --- a/src/base/tools/bswap_64.h +++ b/src/base/tools/bswap_64.h @@ -23,10 +23,12 @@ #include #define bswap_64(x) _byteswap_uint64(x) +#define bswap_32(x) _byteswap_ulong(x) #elif defined __GNUC__ #define bswap_64(x) __builtin_bswap64(x) +#define bswap_32(x) __builtin_bswap32(x) #else diff --git a/src/base/tools/cryptonote/BlockTemplate.cpp b/src/base/tools/cryptonote/BlockTemplate.cpp index 4f6d273..b4fe4bc 100644 --- a/src/base/tools/cryptonote/BlockTemplate.cpp +++ b/src/base/tools/cryptonote/BlockTemplate.cpp @@ -228,14 +228,19 @@ bool xmrig::BlockTemplate::parse(bool hashes) ar(m_amount); ar(m_outputType); - // output type must be txout_to_key (2) - if (m_outputType != 2) { + // output type must be txout_to_key (2) or txout_to_tagged_key (3) + if ((m_outputType != 2) && (m_outputType != 3)) { return false; } setOffset(EPH_PUBLIC_KEY_OFFSET, ar.index()); ar(m_ephPublicKey, kKeySize); + + if (m_outputType == 3) { + ar(m_viewTag); + } + ar(m_extraSize); setOffset(TX_EXTRA_OFFSET, ar.index()); @@ -244,7 +249,9 @@ bool xmrig::BlockTemplate::parse(bool hashes) ar.skip(m_extraSize); while (ar_extra.index() < m_extraSize) { - uint64_t extra_tag = 0; + uint64_t extra_tag = 0; + uint64_t size = 0; + ar_extra(extra_tag); switch (extra_tag) { @@ -254,12 +261,15 @@ bool xmrig::BlockTemplate::parse(bool hashes) break; case 0x02: // TX_EXTRA_NONCE - { - uint64_t size = 0; - ar_extra(size); - setOffset(TX_EXTRA_NONCE_OFFSET, offset(TX_EXTRA_OFFSET) + ar_extra.index()); - ar_extra(m_txExtraNonce, size); - } + ar_extra(size); + setOffset(TX_EXTRA_NONCE_OFFSET, offset(TX_EXTRA_OFFSET) + ar_extra.index()); + ar_extra(m_txExtraNonce, size); + break; + + case 0x03: // TX_EXTRA_MERGE_MINING_TAG + ar_extra(size); + setOffset(TX_EXTRA_MERGE_MINING_TAG_OFFSET, offset(TX_EXTRA_OFFSET) + ar_extra.index()); + ar_extra(m_txMergeMiningTag, size + kKeySize); break; default: diff --git a/src/base/tools/cryptonote/BlockTemplate.h b/src/base/tools/cryptonote/BlockTemplate.h index 11d9e33..c731aad 100644 --- a/src/base/tools/cryptonote/BlockTemplate.h +++ b/src/base/tools/cryptonote/BlockTemplate.h @@ -54,6 +54,7 @@ public: TX_EXTRA_OFFSET, TX_PUBKEY_OFFSET, TX_EXTRA_NONCE_OFFSET, + TX_EXTRA_MERGE_MINING_TAG_OFFSET, OFFSET_COUNT }; @@ -86,6 +87,7 @@ public: inline uint64_t outputType() const { return m_outputType; } inline const Span &ephPublicKey() const { return m_ephPublicKey; } inline const Span &txExtraNonce() const { return m_txExtraNonce; } + inline const Span &txMergeMiningTag() const { return m_txMergeMiningTag; } // Transaction hashes inline uint64_t numHashes() const { return m_numHashes; } @@ -138,9 +140,10 @@ private: uint64_t m_amount = 0; uint8_t m_outputType = 0; Span m_ephPublicKey; + uint8_t m_viewTag = 0; uint64_t m_extraSize = 0; Span m_txExtraNonce; - + Span m_txMergeMiningTag = 0; uint64_t m_numHashes = 0; Buffer m_hashes; Buffer m_minerTxMerkleTreeBranch; diff --git a/src/base/tools/cryptonote/WalletAddress.cpp b/src/base/tools/cryptonote/WalletAddress.cpp index f05dec9..f9b8a9f 100644 --- a/src/base/tools/cryptonote/WalletAddress.cpp +++ b/src/base/tools/cryptonote/WalletAddress.cpp @@ -217,12 +217,6 @@ const xmrig::WalletAddress::TagInfo &xmrig::WalletAddress::tagInfo(uint64_t tag) { 0x1742ca, { Coin::ARQMA, STAGENET, INTEGRATED, 39994, 39995 } }, { 0x1d84ca, { Coin::ARQMA, STAGENET, SUBADDRESS, 39994, 39995 } }, - { 0xc8ed8, { Coin::DERO, MAINNET, PUBLIC, 20206, 0 } }, - { 0xa0ed8, { Coin::DERO, MAINNET, INTEGRATED, 20206, 0 } }, - - { 0x6cf58, { Coin::DERO, TESTNET, PUBLIC, 30306, 0 } }, - { 0x44f58, { Coin::DERO, TESTNET, INTEGRATED, 30306, 0 } }, - { 0x1032, { Coin::WOWNERO, MAINNET, PUBLIC, 34568, 34569 } }, { 0x1a9a, { Coin::WOWNERO, MAINNET, INTEGRATED, 34568, 34569 } }, { 0x2fb0, { Coin::WOWNERO, MAINNET, SUBADDRESS, 34568, 34569 } }, diff --git a/src/base/tools/cryptonote/crypto-ops-data.c b/src/base/tools/cryptonote/crypto-ops-data.c index d16fd94..a4d8de1 100644 --- a/src/base/tools/cryptonote/crypto-ops-data.c +++ b/src/base/tools/cryptonote/crypto-ops-data.c @@ -1,21 +1,21 @@ // Copyright (c) 2014-2020, The Monero Project -// +// // All rights reserved. -// +// // Redistribution and use in source and binary forms, with or without modification, are // permitted provided that the following conditions are met: -// +// // 1. Redistributions of source code must retain the above copyright notice, this list of // conditions and the following disclaimer. -// +// // 2. Redistributions in binary form must reproduce the above copyright notice, this list // of conditions and the following disclaimer in the documentation and/or other // materials provided with the distribution. -// +// // 3. Neither the name of the copyright holder nor the names of its contributors may be // used to endorse or promote products derived from this software without specific // prior written permission. -// +// // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL @@ -25,7 +25,7 @@ // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// +// // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers #include diff --git a/src/base/tools/cryptonote/crypto-ops.c b/src/base/tools/cryptonote/crypto-ops.c index 40bac73..ccd195a 100644 --- a/src/base/tools/cryptonote/crypto-ops.c +++ b/src/base/tools/cryptonote/crypto-ops.c @@ -1,21 +1,21 @@ // Copyright (c) 2014-2020, The Monero Project -// +// // All rights reserved. -// +// // Redistribution and use in source and binary forms, with or without modification, are // permitted provided that the following conditions are met: -// +// // 1. Redistributions of source code must retain the above copyright notice, this list of // conditions and the following disclaimer. -// +// // 2. Redistributions in binary form must reproduce the above copyright notice, this list // of conditions and the following disclaimer in the documentation and/or other // materials provided with the distribution. -// +// // 3. Neither the name of the copyright holder nor the names of its contributors may be // used to endorse or promote products derived from this software without specific // prior written permission. -// +// // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL @@ -25,7 +25,7 @@ // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// +// // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers #include diff --git a/src/base/tools/cryptonote/crypto-ops.h b/src/base/tools/cryptonote/crypto-ops.h index 22f7697..58b31ad 100644 --- a/src/base/tools/cryptonote/crypto-ops.h +++ b/src/base/tools/cryptonote/crypto-ops.h @@ -1,21 +1,21 @@ // Copyright (c) 2014-2020, The Monero Project -// +// // All rights reserved. -// +// // Redistribution and use in source and binary forms, with or without modification, are // permitted provided that the following conditions are met: -// +// // 1. Redistributions of source code must retain the above copyright notice, this list of // conditions and the following disclaimer. -// +// // 2. Redistributions in binary form must reproduce the above copyright notice, this list // of conditions and the following disclaimer in the documentation and/or other // materials provided with the distribution. -// +// // 3. Neither the name of the copyright holder nor the names of its contributors may be // used to endorse or promote products derived from this software without specific // prior written permission. -// +// // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL @@ -25,7 +25,7 @@ // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// +// // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers #pragma once diff --git a/src/proxy/splitters/extra_nonce/ExtraNonceSplitter.cpp b/src/proxy/splitters/extra_nonce/ExtraNonceSplitter.cpp index 288bea0..8928c1c 100644 --- a/src/proxy/splitters/extra_nonce/ExtraNonceSplitter.cpp +++ b/src/proxy/splitters/extra_nonce/ExtraNonceSplitter.cpp @@ -41,10 +41,6 @@ xmrig::ExtraNonceSplitter* xmrig::ExtraNonceSplitter::Create(Controller* controller) { for (const Pool& pool : controller->config()->pools().data()) { - if ((pool.algorithm() == Algorithm::ASTROBWT_DERO) || (pool.coin() == Coin::DERO)) { - LOG_ERR("extra_nonce mode is incompatible with Dero mining"); - return nullptr; - } if (pool.mode() != Pool::MODE_DAEMON) { LOG_ERR("extra_nonce mode can only be used when mining to daemon"); return nullptr;