From d1033abbe54e9819b0815fde5e15026e51b2b2e5 Mon Sep 17 00:00:00 2001 From: XMRig Date: Tue, 17 Aug 2021 08:17:21 +0700 Subject: [PATCH 1/2] Update Coin, BlobReader and WalletAddress. --- src/base/crypto/Coin.cpp | 130 +++++++------- src/base/crypto/Coin.h | 55 +++--- src/base/net/stratum/DaemonClient.cpp | 6 +- src/base/tools/cryptonote/BlobReader.h | 66 +++++--- src/base/tools/cryptonote/BlockTemplate.cpp | 12 +- src/base/tools/cryptonote/BlockTemplate.h | 8 +- src/base/tools/cryptonote/WalletAddress.cpp | 178 ++++++++++++++++---- src/base/tools/cryptonote/WalletAddress.h | 79 +++++++-- 8 files changed, 369 insertions(+), 165 deletions(-) diff --git a/src/base/crypto/Coin.cpp b/src/base/crypto/Coin.cpp index a70ca0751..2895636ea 100644 --- a/src/base/crypto/Coin.cpp +++ b/src/base/crypto/Coin.cpp @@ -1,13 +1,6 @@ /* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018 Lee Clagett - * Copyright 2018-2020 SChernykh - * Copyright 2016-2020 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 @@ -23,9 +16,10 @@ * along with this program. If not, see . */ - #include "base/crypto/Coin.h" #include "3rdparty/rapidjson/document.h" +#include "base/io/json/Json.h" +#include "base/io/log/Log.h" #include @@ -39,74 +33,66 @@ namespace xmrig { -struct CoinName +struct CoinInfo { + const Algorithm::Id algorithm; + const char *code; const char *name; - const Coin::Id id; + const uint64_t target; + const uint64_t units; + const char *tag; }; -static CoinName const coin_names[] = { - { "monero", Coin::MONERO }, - { "xmr", Coin::MONERO }, - { "arqma", Coin::ARQMA }, - { "arq", Coin::ARQMA }, - { "dero", Coin::DERO }, - { "keva", Coin::KEVA }, - { "ravencoin", Coin::RAVEN }, - { "raven", Coin::RAVEN }, - { "rvn", Coin::RAVEN }, - { "conceal", Coin::CONCEAL }, - { "wownero", Coin::WOWNERO } +static const CoinInfo coinInfo[] = { + { Algorithm::INVALID, nullptr, nullptr, 0, 0, nullptr }, + { Algorithm::RX_0, "XMR", "Monero", 120, 1000000000000, YELLOW_BG_BOLD( WHITE_BOLD_S " monero ") }, + { Algorithm::CN_R, "SUMO", "Sumokoin", 240, 1000000000, BLUE_BG_BOLD( WHITE_BOLD_S " sumo ") }, + { Algorithm::RX_ARQ, "ARQ", "ArQmA", 120, 1000000000, BLUE_BG_BOLD( WHITE_BOLD_S " arqma ") }, + { Algorithm::ASTROBWT_DERO, "DERO", "DERO", 0, 0, BLUE_BG_BOLD( WHITE_BOLD_S " dero ") }, + { Algorithm::RX_KEVA, "KVA", "Kevacoin", 0, 0, MAGENTA_BG_BOLD(WHITE_BOLD_S " keva ") }, + { Algorithm::KAWPOW_RVN, "RVN", "Ravencoin", 0, 0, BLUE_BG_BOLD( WHITE_BOLD_S " raven ") }, + { Algorithm::RX_WOW, "WOW", "Wownero", 300, 100000000000, MAGENTA_BG_BOLD(WHITE_BOLD_S " wownero ") }, }; +static_assert(Coin::MAX == sizeof(coinInfo) / sizeof(coinInfo[0]), "size mismatch"); + + +const char *Coin::kDisabled = "DISABLED_COIN"; +const char *Coin::kField = "coin"; +const char *Coin::kUnknown = "UNKNOWN_COIN"; + + } /* namespace xmrig */ - -xmrig::Algorithm::Id xmrig::Coin::algorithm(uint8_t blobVersion) const +xmrig::Coin::Coin(const rapidjson::Value &value) { - switch (id()) { - case MONERO: - return (blobVersion >= 12) ? Algorithm::RX_0 : Algorithm::CN_R; - - case ARQMA: - return (blobVersion >= 15) ? Algorithm::RX_ARQ : Algorithm::CN_PICO_0; - - case DERO: - return (blobVersion >= 4) ? Algorithm::ASTROBWT_DERO : Algorithm::CN_0; - - case KEVA: - return (blobVersion >= 11) ? Algorithm::RX_KEVA : Algorithm::CN_R; - - case RAVEN: - return Algorithm::KAWPOW_RVN; - - case CONCEAL: - return Algorithm::CN_CCX; - - case WOWNERO: - return Algorithm::RX_WOW; - - case INVALID: - break; + if (value.IsString()) { + m_id = parse(value.GetString()); + } + else if (value.IsObject() && !value.ObjectEmpty()) { + m_id = parse(Json::getString(value, kField)); } - - return Algorithm::INVALID; } +xmrig::Algorithm xmrig::Coin::algorithm(uint8_t) const +{ + return coinInfo[m_id].algorithm; +} + + +const char *xmrig::Coin::code() const +{ + return coinInfo[m_id].code; +} + const char *xmrig::Coin::name() const { - for (const auto &i : coin_names) { - if (i.id == m_id) { - return i.name; - } - } - - return nullptr; + return coinInfo[m_id].name; } @@ -114,7 +100,19 @@ rapidjson::Value xmrig::Coin::toJSON() const { using namespace rapidjson; - return isValid() ? Value(StringRef(name())) : Value(kNullType); + return isValid() ? Value(StringRef(code())) : Value(kNullType); +} + + +uint64_t xmrig::Coin::target(uint8_t) const +{ + return coinInfo[m_id].target; +} + + +uint64_t xmrig::Coin::units() const +{ + return coinInfo[m_id].units; } @@ -124,11 +122,17 @@ xmrig::Coin::Id xmrig::Coin::parse(const char *name) return INVALID; } - for (const auto &i : coin_names) { - if (strcasecmp(name, i.name) == 0) { - return i.id; + for (uint32_t i = 1; i < MAX; ++i) { + if (strcasecmp(name, coinInfo[i].code) == 0 || strcasecmp(name, coinInfo[i].name) == 0) { + return static_cast(i); } } return INVALID; } + + +const char *xmrig::Coin::tag(Id id) +{ + return coinInfo[id].tag; +} diff --git a/src/base/crypto/Coin.h b/src/base/crypto/Coin.h index 985335cb4..ac661b7d1 100644 --- a/src/base/crypto/Coin.h +++ b/src/base/crypto/Coin.h @@ -1,13 +1,6 @@ /* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018 Lee Clagett - * Copyright 2018-2020 SChernykh - * Copyright 2016-2020 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 @@ -37,38 +30,52 @@ namespace xmrig { class Coin { public: - enum Id : int { - INVALID = -1, + enum Id : uint32_t { + INVALID, MONERO, + SUMO, ARQMA, DERO, KEVA, RAVEN, - CONCEAL, - WOWNERO + WOWNERO, + MAX }; + static const char *kDisabled; + static const char *kField; + static const char *kUnknown; Coin() = default; - inline Coin(const char *name) : m_id(parse(name)) {} - inline Coin(Id id) : m_id(id) {} + Coin(const rapidjson::Value &value); + inline Coin(const char *name) : m_id(parse(name)) {} + inline Coin(Id id) : m_id(id) {} + inline Coin(uint32_t id) : m_id(id < MAX ? static_cast(id) : INVALID) {} - inline bool isEqual(const Coin &other) const { return m_id == other.m_id; } - inline bool isValid() const { return m_id != INVALID; } - inline Id id() const { return m_id; } + inline bool isEqual(const Coin &other) const { return m_id == other.m_id; } + inline bool isValid() const { return m_id != INVALID; } + inline Id id() const { return m_id; } + inline const char *tag() const { return tag(m_id); } + inline double decimal(uint64_t amount) const { return static_cast(amount) / units(); } - Algorithm::Id algorithm(uint8_t blobVersion = 255) const; + Algorithm algorithm(uint8_t blobVersion = 255) const; + const char *code() const; const char *name() const; rapidjson::Value toJSON() const; + uint64_t target(uint8_t blobVersion = 255) const; + uint64_t units() const; - inline bool operator!=(Coin::Id id) const { return m_id != id; } - inline bool operator!=(const Coin &other) const { return !isEqual(other); } - inline bool operator==(Coin::Id id) const { return m_id == id; } - inline bool operator==(const Coin &other) const { return isEqual(other); } - inline operator Coin::Id() const { return m_id; } + inline bool operator!=(Id id) const { return m_id != id; } + inline bool operator!=(const Coin &other) const { return !isEqual(other); } + inline bool operator<(Id id) const { return m_id < id; } + inline bool operator<(const Coin &other) const { return m_id < other.m_id; } + inline bool operator==(Id id) const { return m_id == id; } + inline bool operator==(const Coin &other) const { return isEqual(other); } + inline operator Id() const { return m_id; } static Id parse(const char *name); + static const char *tag(Id id); private: Id m_id = INVALID; diff --git a/src/base/net/stratum/DaemonClient.cpp b/src/base/net/stratum/DaemonClient.cpp index 3a1a3abf1..c9af2801e 100644 --- a/src/base/net/stratum/DaemonClient.cpp +++ b/src/base/net/stratum/DaemonClient.cpp @@ -414,19 +414,19 @@ bool xmrig::DaemonClient::parseJob(const rapidjson::Value ¶ms, int *code) } WalletAddress user_address; - if (!user_address.Decode(m_pool.user())) { + if (!user_address.decode(m_pool.user())) { LOG_ERR("Invalid wallet address."); *code = 10; return false; } - if (memcmp(user_address.public_spend_key, public_spendkey, sizeof(public_spendkey)) != 0) { + if (memcmp(user_address.spendKey(), public_spendkey, sizeof(public_spendkey)) != 0) { LOG_ERR("Wallet address and spend key don't match."); *code = 11; return false; } - if (memcmp(user_address.public_view_key, public_viewkey, sizeof(public_viewkey)) != 0) { + if (memcmp(user_address.viewKey(), public_viewkey, sizeof(public_viewkey)) != 0) { LOG_ERR("Wallet address and view key don't match."); *code = 12; return false; diff --git a/src/base/tools/cryptonote/BlobReader.h b/src/base/tools/cryptonote/BlobReader.h index f10bcd88b..e8be0d65f 100644 --- a/src/base/tools/cryptonote/BlobReader.h +++ b/src/base/tools/cryptonote/BlobReader.h @@ -1,8 +1,8 @@ /* XMRig - * Copyright 2012-2013 The Cryptonote developers - * Copyright 2014-2021 The Monero Project - * Copyright 2018-2021 SChernykh - * Copyright 2016-2021 XMRig , + * Copyright (c) 2012-2013 The Cryptonote developers + * Copyright (c) 2014-2021 The Monero Project + * 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 @@ -23,58 +23,71 @@ #include +#include namespace xmrig { -class CBlobReader +class BlobReader { public: - inline CBlobReader(const void* data, size_t size) - : m_data(reinterpret_cast(data)) - , m_size(size) - , m_index(0) + inline BlobReader(const uint8_t *data, size_t size) : + m_size(size), + m_data(data) {} - inline bool operator()(uint8_t& data) { return getByte(data); } - inline bool operator()(uint64_t& data) { return getVarint(data); } + inline bool operator()(uint64_t &data) { return getVarint(data); } + inline bool operator()(uint8_t &data) { return getByte(data); } + inline size_t index() const { return m_index; } + inline size_t remaining() const { return m_size - m_index; } + + inline bool skip(size_t n) + { + if (m_index + n > m_size) { + return false; + } + + m_index += n; + + return true; + } template inline bool operator()(uint8_t(&data)[N]) { - for (size_t i = 0; i < N; ++i) { - if (!getByte(data[i])) { - return false; - } + if (m_index + N > m_size) { + return false; } + + memcpy(data, m_data + m_index, N); + m_index += N; + return true; } template - inline void readItems(T& data, size_t count) + inline void readItems(T &data, size_t count) { data.resize(count); - for (size_t i = 0; i < count; ++i) + for (size_t i = 0; i < count; ++i) { operator()(data[i]); + } } - inline size_t index() const { return m_index; } - - inline void skip(size_t N) { m_index += N; } - private: - inline bool getByte(uint8_t& data) + inline bool getByte(uint8_t &data) { if (m_index >= m_size) { return false; } data = m_data[m_index++]; + return true; } - inline bool getVarint(uint64_t& data) + inline bool getVarint(uint64_t &data) { uint64_t result = 0; uint8_t t; @@ -89,12 +102,13 @@ private: } while (t & 0x80); data = result; + return true; } - const uint8_t* m_data; - size_t m_size; - size_t m_index; + const size_t m_size; + const uint8_t *m_data; + size_t m_index = 0; }; diff --git a/src/base/tools/cryptonote/BlockTemplate.cpp b/src/base/tools/cryptonote/BlockTemplate.cpp index 29653441d..ede0b19a8 100644 --- a/src/base/tools/cryptonote/BlockTemplate.cpp +++ b/src/base/tools/cryptonote/BlockTemplate.cpp @@ -1,8 +1,8 @@ /* XMRig - * Copyright 2012-2013 The Cryptonote developers - * Copyright 2014-2021 The Monero Project - * Copyright 2018-2021 SChernykh - * Copyright 2016-2021 XMRig , + * Copyright (c) 2012-2013 The Cryptonote developers + * Copyright (c) 2014-2021 The Monero Project + * 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 @@ -32,7 +32,7 @@ bool BlockTemplate::Init(const String& blockTemplate, Coin coin) { raw_blob = Cvt::fromHex(blockTemplate); - CBlobReader ar(raw_blob.data(), raw_blob.size()); + BlobReader ar(raw_blob.data(), raw_blob.size()); // Block header ar(major_version); @@ -90,7 +90,7 @@ bool BlockTemplate::Init(const String& blockTemplate, Coin coin) ar.readItems(extra, extra_size); - CBlobReader ar_extra(extra.data(), extra_size); + BlobReader ar_extra(extra.data(), extra_size); tx_extra_nonce_size = 0; tx_extra_nonce_index = 0; diff --git a/src/base/tools/cryptonote/BlockTemplate.h b/src/base/tools/cryptonote/BlockTemplate.h index 4a6ef8051..6effd3feb 100644 --- a/src/base/tools/cryptonote/BlockTemplate.h +++ b/src/base/tools/cryptonote/BlockTemplate.h @@ -1,8 +1,8 @@ /* XMRig - * Copyright 2012-2013 The Cryptonote developers - * Copyright 2014-2021 The Monero Project - * Copyright 2018-2021 SChernykh - * Copyright 2016-2021 XMRig , + * Copyright (c) 2012-2013 The Cryptonote developers + * Copyright (c) 2014-2021 The Monero Project + * 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 diff --git a/src/base/tools/cryptonote/WalletAddress.cpp b/src/base/tools/cryptonote/WalletAddress.cpp index 7be1ef9d6..6b7f5343d 100644 --- a/src/base/tools/cryptonote/WalletAddress.cpp +++ b/src/base/tools/cryptonote/WalletAddress.cpp @@ -1,8 +1,8 @@ /* XMRig - * Copyright 2012-2013 The Cryptonote developers - * Copyright 2014-2021 The Monero Project - * Copyright 2018-2021 SChernykh - * Copyright 2016-2021 XMRig , + * Copyright (c) 2012-2013 The Cryptonote developers + * Copyright (c) 2014-2021 The Monero Project + * 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 @@ -18,24 +18,29 @@ * along with this program. If not, see . */ - -#include "base/crypto/keccak.h" -#include "base/tools/cryptonote/BlobReader.h" #include "base/tools/cryptonote/WalletAddress.h" -#include "base/tools/cryptonote/umul128.h" +#include "3rdparty/rapidjson/document.h" +#include "base/crypto/keccak.h" #include "base/tools/Buffer.h" +#include "base/tools/cryptonote/BlobReader.h" +#include "base/tools/cryptonote/umul128.h" +#include "base/tools/Cvt.h" + + #include +#include -namespace xmrig { - - -bool WalletAddress::Decode(const String& address) +bool xmrig::WalletAddress::decode(const char *address, size_t size) { static constexpr std::array block_sizes{ 0, 2, 3, 5, 6, 7, 9, 10, 11 }; static constexpr char alphabet[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; constexpr size_t alphabet_size = sizeof(alphabet) - 1; + if (size < kMinSize || size > kMaxSize) { + return false; + } + int8_t reverse_alphabet[256]; memset(reverse_alphabet, -1, sizeof(reverse_alphabet)); @@ -43,7 +48,7 @@ bool WalletAddress::Decode(const String& address) reverse_alphabet[static_cast(alphabet[i])] = i; } - const int len = static_cast(address.size()); + const int len = static_cast(size); const int num_full_blocks = len / block_sizes.back(); const int last_block_size = len % block_sizes.back(); @@ -60,10 +65,15 @@ bool WalletAddress::Decode(const String& address) return false; } - Buffer data; - data.reserve(static_cast(num_full_blocks) * sizeof(uint64_t) + last_block_size_index); + const size_t data_size = static_cast(num_full_blocks) * sizeof(uint64_t) + last_block_size_index; + if (data_size < kMinDataSize) { + return false; + } - const char* address_data = address.data(); + Buffer data; + data.reserve(data_size); + + const char *address_data = address; for (int i = 0; i <= num_full_blocks; ++i) { uint64_t num = 0; @@ -87,28 +97,138 @@ bool WalletAddress::Decode(const String& address) address_data += block_sizes.back(); - uint8_t* p = reinterpret_cast(&num); - for (int j = ((i < num_full_blocks) ? sizeof(num) : last_block_size_index) - 1; j >= 0; --j) { + auto p = reinterpret_cast(&num); + for (int j = ((i < num_full_blocks) ? static_cast(sizeof(num)) : last_block_size_index) - 1; j >= 0; --j) { data.emplace_back(p[j]); } } - CBlobReader ar(data.data(), data.size()); + assert(data.size() == data_size); - ar(tag); - ar(public_spend_key); - ar(public_view_key); - ar(checksum); + BlobReader ar(data.data(), data_size); - uint8_t md[200]; - keccak(data.data(), data.size() - sizeof(checksum), md); + if (ar(m_tag) && ar(m_publicSpendKey) && ar(m_publicViewKey) && ar.skip(ar.remaining() - sizeof(m_checksum)) && ar(m_checksum)) { + uint8_t md[200]; + keccak(data.data(), data_size - sizeof(m_checksum), md); - if (memcmp(checksum, md, sizeof(checksum)) != 0) { - return false; + if (memcmp(m_checksum, md, sizeof(m_checksum)) == 0) { + m_data = { address, size }; + + return true; + } } - return true; + m_tag = 0; + + return false; } -} /* namespace xmrig */ +bool xmrig::WalletAddress::decode(const rapidjson::Value &address) +{ + return address.IsString() && decode(address.GetString(), address.GetStringLength()); +} + + +const char *xmrig::WalletAddress::netName() const +{ + static const std::array names = { "mainnet", "testnet", "stagenet" }; + + return names[net()]; +} + + +const char *xmrig::WalletAddress::typeName() const +{ + static const std::array names = { "public", "integrated", "subaddress" }; + + return names[type()]; +} + + +rapidjson::Value xmrig::WalletAddress::toJSON(rapidjson::Document &doc) const +{ + using namespace rapidjson; + + return isValid() ? m_data.toJSON(doc) : Value(kNullType); +} + + +#ifdef XMRIG_FEATURE_API +rapidjson::Value xmrig::WalletAddress::toAPI(rapidjson::Document &doc) const +{ + using namespace rapidjson; + + if (!isValid()) { + return Value(kNullType); + } + + auto &allocator = doc.GetAllocator(); + Value out(kObjectType); + out.AddMember(StringRef(Coin::kField), coin().toJSON(), allocator); + out.AddMember("address", m_data.toJSON(doc), allocator); + out.AddMember("type", StringRef(typeName()), allocator); + out.AddMember("net", StringRef(netName()), allocator); + out.AddMember("rpc_port", rpcPort(), allocator); + out.AddMember("zmq_port", zmqPort(), allocator); + out.AddMember("tag", m_tag, allocator); + out.AddMember("view_key", Cvt::toHex(m_publicViewKey, kKeySize, doc), allocator); + out.AddMember("spend_key", Cvt::toHex(m_publicSpendKey, kKeySize, doc), allocator); + out.AddMember("checksum", Cvt::toHex(m_checksum, sizeof(m_checksum), doc), allocator); + + return out; +} +#endif + + +const xmrig::WalletAddress::TagInfo &xmrig::WalletAddress::tagInfo(uint64_t tag) +{ + static TagInfo dummy = { Coin::INVALID, MAINNET, PUBLIC, 0 }; + static const std::map tags = { + { 18, { Coin::MONERO, MAINNET, PUBLIC, 18081, 18082 } }, + { 19, { Coin::MONERO, MAINNET, INTEGRATED, 18081, 18082 } }, + { 42, { Coin::MONERO, MAINNET, SUBADDRESS, 18081, 18082 } }, + + { 53, { Coin::MONERO, TESTNET, PUBLIC, 28081, 28082 } }, + { 54, { Coin::MONERO, TESTNET, INTEGRATED, 28081, 28082 } }, + { 63, { Coin::MONERO, TESTNET, SUBADDRESS, 28081, 28082 } }, + + { 24, { Coin::MONERO, STAGENET, PUBLIC, 38081, 38082 } }, + { 25, { Coin::MONERO, STAGENET, INTEGRATED, 38081, 38082 } }, + { 36, { Coin::MONERO, STAGENET, SUBADDRESS, 38081, 38082 } }, + + { 0x2bb39a, { Coin::SUMO, MAINNET, PUBLIC, 19734, 19735 } }, + { 0x29339a, { Coin::SUMO, MAINNET, INTEGRATED, 19734, 19735 } }, + { 0x8319a, { Coin::SUMO, MAINNET, SUBADDRESS, 19734, 19735 } }, + + { 0x37751a, { Coin::SUMO, TESTNET, PUBLIC, 29734, 29735 } }, + { 0x34f51a, { Coin::SUMO, TESTNET, INTEGRATED, 29734, 29735 } }, + { 0x1d351a, { Coin::SUMO, TESTNET, SUBADDRESS, 29734, 29735 } }, + + { 0x2cca, { Coin::ARQMA, MAINNET, PUBLIC, 19994, 19995 } }, + { 0x116bc7, { Coin::ARQMA, MAINNET, INTEGRATED, 19994, 19995 } }, + { 0x6847, { Coin::ARQMA, MAINNET, SUBADDRESS, 19994, 19995 } }, + + { 0x53ca, { Coin::ARQMA, TESTNET, PUBLIC, 29994, 29995 } }, + { 0x504a, { Coin::ARQMA, TESTNET, INTEGRATED, 29994, 29995 } }, + { 0x524a, { Coin::ARQMA, TESTNET, SUBADDRESS, 29994, 29995 } }, + + { 0x39ca, { Coin::ARQMA, STAGENET, PUBLIC, 39994, 39995 } }, + { 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 } }, + + { 4146, { Coin::WOWNERO, MAINNET, PUBLIC, 34568, 34569 } }, + { 6810, { Coin::WOWNERO, MAINNET, INTEGRATED, 34568, 34569 } }, + { 12208, { Coin::WOWNERO, MAINNET, SUBADDRESS, 34568, 34569 } }, + }; + + const auto it = tags.find(tag); + + return it == tags.end() ? dummy : it->second; +} diff --git a/src/base/tools/cryptonote/WalletAddress.h b/src/base/tools/cryptonote/WalletAddress.h index cc3c2ec42..1c82c92bc 100644 --- a/src/base/tools/cryptonote/WalletAddress.h +++ b/src/base/tools/cryptonote/WalletAddress.h @@ -1,8 +1,8 @@ /* XMRig - * Copyright 2012-2013 The Cryptonote developers - * Copyright 2014-2021 The Monero Project - * Copyright 2018-2021 SChernykh - * Copyright 2016-2021 XMRig , + * Copyright (c) 2012-2013 The Cryptonote developers + * Copyright (c) 2014-2021 The Monero Project + * 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 @@ -23,19 +23,78 @@ #include "base/tools/String.h" +#include "base/crypto/Coin.h" namespace xmrig { -struct WalletAddress +class WalletAddress { - uint64_t tag; - uint8_t public_spend_key[32]; - uint8_t public_view_key[32]; - uint8_t checksum[4]; +public: + enum Net : uint32_t { + MAINNET, + TESTNET, + STAGENET + }; - bool Decode(const String& address); + enum Type : uint32_t { + PUBLIC, + INTEGRATED, + SUBADDRESS + }; + + constexpr static size_t kKeySize = 32; + constexpr static size_t kMaxSize = 256; + constexpr static size_t kMinDataSize = 69; + constexpr static size_t kMinSize = 95; + + WalletAddress() = default; + inline WalletAddress(const char *address, size_t size) { decode(address, size); } + inline WalletAddress(const char *address) { decode(address); } + inline WalletAddress(const rapidjson::Value &address) { decode(address); } + inline WalletAddress(const String &address) { decode(address); } + + inline bool decode(const char *address) { return decode(address, strlen(address)); } + inline bool decode(const String &address) { return decode(address, address.size()); } + inline bool isValid() const { return m_tag > 0 && m_data.size() >= kMinSize; } + inline const char *data() const { return m_data; } + inline const Coin &coin() const { return tagInfo(m_tag).coin; } + inline const uint8_t *spendKey() const { return m_publicSpendKey; } + inline const uint8_t *viewKey() const { return m_publicViewKey; } + inline Net net() const { return tagInfo(m_tag).net; } + inline Type type() const { return tagInfo(m_tag).type; } + inline uint16_t rpcPort() const { return tagInfo(m_tag).rpcPort; } + inline uint16_t zmqPort() const { return tagInfo(m_tag).zmqPort; } + inline uint64_t tag() const { return m_tag; } + + bool decode(const char *address, size_t size); + bool decode(const rapidjson::Value &address); + const char *netName() const; + const char *typeName() const; + rapidjson::Value toJSON(rapidjson::Document &doc) const; + +# ifdef XMRIG_FEATURE_API + rapidjson::Value toAPI(rapidjson::Document &doc) const; +# endif + +private: + struct TagInfo + { + const Coin coin; + const Net net; + const Type type; + const uint16_t rpcPort; + const uint16_t zmqPort; + }; + + static const TagInfo &tagInfo(uint64_t tag); + + String m_data; + uint64_t m_tag = 0; + uint8_t m_checksum[4]{}; + uint8_t m_publicSpendKey[kKeySize]{}; + uint8_t m_publicViewKey[kKeySize]{}; }; From 460d9c75c5ecfb0c9db37285d3bebea1aca33168 Mon Sep 17 00:00:00 2001 From: XMRig Date: Wed, 18 Aug 2021 13:36:50 +0700 Subject: [PATCH 2/2] Add global wallet address parser for DaemonClient. --- src/base/kernel/interfaces/IClient.h | 16 ++- src/base/net/stratum/BaseClient.cpp | 14 +-- src/base/net/stratum/BaseClient.h | 10 +- src/base/net/stratum/DaemonClient.cpp | 143 ++++++++++++++------------ src/base/net/stratum/DaemonClient.h | 40 +++---- src/base/net/stratum/Pool.cpp | 4 - 6 files changed, 110 insertions(+), 117 deletions(-) diff --git a/src/base/kernel/interfaces/IClient.h b/src/base/kernel/interfaces/IClient.h index 456d603d2..6cf4ff03a 100644 --- a/src/base/kernel/interfaces/IClient.h +++ b/src/base/kernel/interfaces/IClient.h @@ -1,12 +1,6 @@ /* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018-2020 SChernykh - * Copyright 2016-2020 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 @@ -27,6 +21,7 @@ #include "3rdparty/rapidjson/fwd.h" +#include "base/tools/Object.h" #include @@ -46,6 +41,8 @@ class String; class IClient { public: + XMRIG_DISABLE_COPY_MOVE(IClient) + enum Extension { EXT_ALGO, EXT_NICEHASH, @@ -57,7 +54,8 @@ public: using Callback = std::function; - virtual ~IClient() = default; + IClient() = default; + virtual ~IClient() = default; virtual bool disconnect() = 0; virtual bool hasExtension(Extension extension) const noexcept = 0; diff --git a/src/base/net/stratum/BaseClient.cpp b/src/base/net/stratum/BaseClient.cpp index 12b7ca76e..7c9a728d1 100644 --- a/src/base/net/stratum/BaseClient.cpp +++ b/src/base/net/stratum/BaseClient.cpp @@ -1,12 +1,6 @@ /* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018-2020 SChernykh - * Copyright 2016-2020 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 @@ -22,8 +16,8 @@ * along with this program. If not, see . */ - #include "base/net/stratum/BaseClient.h" +#include "3rdparty/fmt/core.h" #include "3rdparty/rapidjson/document.h" #include "base/io/Env.h" #include "base/io/log/Log.h" @@ -58,7 +52,7 @@ void xmrig::BaseClient::setPool(const Pool &pool) m_user = Env::expand(pool.user()); m_password = Env::expand(pool.password()); m_rigId = Env::expand(pool.rigId()); - m_tag = std::string(Tags::network()) + " " CYAN_BOLD_S + m_pool.url().data() + CLEAR; + m_tag = fmt::format("{} " CYAN_BOLD("{}"), Tags::network(), m_pool.url().data()); } diff --git a/src/base/net/stratum/BaseClient.h b/src/base/net/stratum/BaseClient.h index 0a87fedb0..53fa59f72 100644 --- a/src/base/net/stratum/BaseClient.h +++ b/src/base/net/stratum/BaseClient.h @@ -1,12 +1,6 @@ /* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2018-2020 SChernykh - * Copyright 2016-2020 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 diff --git a/src/base/net/stratum/DaemonClient.cpp b/src/base/net/stratum/DaemonClient.cpp index c9af2801e..5cea361d8 100644 --- a/src/base/net/stratum/DaemonClient.cpp +++ b/src/base/net/stratum/DaemonClient.cpp @@ -24,6 +24,9 @@ */ +#include + + #include "base/net/stratum/DaemonClient.h" #include "3rdparty/rapidjson/document.h" #include "3rdparty/rapidjson/error/en.h" @@ -42,7 +45,6 @@ #include "base/tools/Cvt.h" #include "base/tools/Timer.h" #include "base/tools/cryptonote/Signatures.h" -#include "base/tools/cryptonote/WalletAddress.h" #include "net/JobResult.h" @@ -181,12 +183,28 @@ int64_t xmrig::DaemonClient::submit(const JobResult &result) void xmrig::DaemonClient::connect() { - if ((m_pool.algorithm() == Algorithm::ASTROBWT_DERO) || (m_pool.coin() == Coin::DERO)) { - m_apiVersion = API_DERO; - } + auto connectError = [this](const char *message) { + if (!isQuiet()) { + LOG_ERR("%s " RED("connect error: ") RED_BOLD("\"%s\""), tag(), message); + } + + retry(); + }; 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.zmq_port() >= 0) { m_dns = Dns::resolve(m_pool.host(), this); } @@ -203,6 +221,20 @@ void xmrig::DaemonClient::connect(const Pool &pool) } +void xmrig::DaemonClient::setPool(const Pool &pool) +{ + BaseClient::setPool(pool); + + m_walletAddress.decode(m_user); + + m_coin = pool.coin().isValid() ? pool.coin() : m_walletAddress.coin(); + + if (!m_coin.isValid() && pool.algorithm() == Algorithm::RX_WOW) { + m_coin = Coin::WOWNERO; + } +} + + void xmrig::DaemonClient::onHttpData(const HttpData &data) { if (data.status != 200) { @@ -219,7 +251,7 @@ void xmrig::DaemonClient::onHttpData(const HttpData &data) rapidjson::Document doc; if (doc.Parse(data.body.c_str()).HasParseError()) { if (!isQuiet()) { - LOG_ERR("[%s:%d] JSON decode failed: \"%s\"", m_pool.host().data(), m_pool.port(), rapidjson::GetParseError_En(doc.GetParseError())); + LOG_ERR("%s " RED("JSON decode failed: ") RED_BOLD("\"%s\""), tag(), rapidjson::GetParseError_En(doc.GetParseError())); } return retry(); @@ -284,7 +316,7 @@ void xmrig::DaemonClient::onTimer(const Timer *) } -void xmrig::DaemonClient::onResolved(const DnsRecords& records, int status, const char* error) +void xmrig::DaemonClient::onResolved(const DnsRecords &records, int status, const char* error) { m_dns.reset(); @@ -297,14 +329,14 @@ void xmrig::DaemonClient::onResolved(const DnsRecords& records, int status, cons return; } - if (m_ZMQSocket) { - delete m_ZMQSocket; - } - const auto& record = records.get(); + delete m_ZMQSocket; + + + const auto &record = records.get(); m_ip = record.ip(); - uv_connect_t* req = new uv_connect_t; + auto req = new uv_connect_t; req->data = m_storage.ptr(m_key); m_ZMQSocket = new uv_tcp_t; @@ -329,26 +361,26 @@ bool xmrig::DaemonClient::isOutdated(uint64_t height, const char *hash) const bool xmrig::DaemonClient::parseJob(const rapidjson::Value ¶ms, int *code) { + auto jobError = [this, code](const char *message) { + if (!isQuiet()) { + LOG_ERR("%s " RED("job error: ") RED_BOLD("\"%s\""), tag(), message); + } + + *code = 1; + + return false; + }; + Job job(false, m_pool.algorithm(), String()); String blocktemplate = Json::getString(params, kBlocktemplateBlob); if (blocktemplate.isNull()) { - LOG_ERR("Empty block template received from daemon"); - *code = 1; - return false; + return jobError("Empty block template received from daemon."); } - Coin pool_coin = m_pool.coin(); - - if (!pool_coin.isValid() && (m_pool.algorithm() == Algorithm::RX_WOW)) { - pool_coin = Coin::WOWNERO; - } - - if (!m_blocktemplate.Init(blocktemplate, pool_coin)) { - LOG_ERR("Invalid block template received from daemon"); - *code = 2; - return false; + if (!m_blocktemplate.Init(blocktemplate, m_coin)) { + return jobError("Invalid block template received from daemon."); } # ifdef XMRIG_PROXY_PROJECT @@ -368,29 +400,21 @@ bool xmrig::DaemonClient::parseJob(const rapidjson::Value ¶ms, int *code) if (m_blocktemplate.has_miner_signature) { if (m_pool.spendSecretKey().isEmpty()) { - LOG_ERR("Secret spend key is not set"); - *code = 4; - return false; + return jobError("Secret spend key is not set."); } if (m_pool.spendSecretKey().size() != 64) { - LOG_ERR("Secret spend key has invalid length. It must be 64 hex characters."); - *code = 5; - return false; + return jobError("Secret spend key has invalid length. It must be 64 hex characters."); } uint8_t secret_spendkey[32]; if (!Cvt::fromHex(secret_spendkey, 32, m_pool.spendSecretKey(), 64)) { - LOG_ERR("Secret spend key is not a valid hex data."); - *code = 6; - return false; + return jobError("Secret spend key is not a valid hex data."); } uint8_t public_spendkey[32]; if (!secret_key_to_public_key(secret_spendkey, public_spendkey)) { - LOG_ERR("Secret spend key is invalid."); - *code = 7; - return false; + return jobError("Secret spend key is invalid."); } # ifdef XMRIG_PROXY_PROJECT @@ -401,35 +425,24 @@ bool xmrig::DaemonClient::parseJob(const rapidjson::Value ¶ms, int *code) uint8_t public_viewkey[32]; if (!secret_key_to_public_key(secret_viewkey, public_viewkey)) { - LOG_ERR("Secret view key is invalid."); - *code = 8; - return false; + return jobError("Secret view key is invalid."); } uint8_t derivation[32]; if (!generate_key_derivation(m_blocktemplate.raw_blob.data() + m_blocktemplate.tx_pubkey_index, secret_viewkey, derivation)) { - LOG_ERR("Failed to generate key derivation for miner signature."); - *code = 9; - return false; + return jobError("Failed to generate key derivation for miner signature."); } - WalletAddress user_address; - if (!user_address.decode(m_pool.user())) { - LOG_ERR("Invalid wallet address."); - *code = 10; - return false; + if (!m_walletAddress.decode(m_pool.user())) { + return jobError("Invalid wallet address."); } - if (memcmp(user_address.spendKey(), public_spendkey, sizeof(public_spendkey)) != 0) { - LOG_ERR("Wallet address and spend key don't match."); - *code = 11; - return false; + if (memcmp(m_walletAddress.spendKey(), public_spendkey, sizeof(public_spendkey)) != 0) { + return jobError("Wallet address and spend key don't match."); } - if (memcmp(user_address.viewKey(), public_viewkey, sizeof(public_viewkey)) != 0) { - LOG_ERR("Wallet address and view key don't match."); - *code = 12; - return false; + if (memcmp(m_walletAddress.viewKey(), public_viewkey, sizeof(public_viewkey)) != 0) { + return jobError("Wallet address and view key don't match."); } uint8_t eph_secret_key[32]; @@ -444,8 +457,8 @@ bool xmrig::DaemonClient::parseJob(const rapidjson::Value ¶ms, int *code) Cvt::toHex(m_blockhashingblob.data() + offset * 2, kBlobReserveSize * 2, Cvt::randomBytes(kBlobReserveSize).data(), kBlobReserveSize); } - if (pool_coin.isValid()) { - job.setAlgorithm(pool_coin.algorithm(m_blocktemplate.major_version)); + if (m_coin.isValid()) { + job.setAlgorithm(m_coin.algorithm(m_blocktemplate.major_version)); } if (!job.setBlob(m_blockhashingblob)) { @@ -594,7 +607,6 @@ void xmrig::DaemonClient::send(const char *path) void xmrig::DaemonClient::setState(SocketState state) { - assert(m_state != state); if (m_state == state) { return; } @@ -735,10 +747,9 @@ void xmrig::DaemonClient::ZMQRead(ssize_t nread, const uv_buf_t* buf) m_ZMQConnectionState = ZMQ_GREETING_2; break; } - else { - LOG_ERR("%s " RED("ZMQ handshake failed: invalid greeting format"), tag()); - ZMQClose(); - } + + LOG_ERR("%s " RED("ZMQ handshake failed: invalid greeting format"), tag()); + ZMQClose(); } return; @@ -751,10 +762,10 @@ void xmrig::DaemonClient::ZMQRead(ssize_t nread, const uv_buf_t* buf) ZMQWrite(kZMQHandshake, sizeof(kZMQHandshake) - 1); break; } - else { - LOG_ERR("%s " RED("ZMQ handshake failed: invalid greeting format 2"), tag()); - ZMQClose(); - } + + LOG_ERR("%s " RED("ZMQ handshake failed: invalid greeting format 2"), tag()); + ZMQClose(); + } return; diff --git a/src/base/net/stratum/DaemonClient.h b/src/base/net/stratum/DaemonClient.h index 2844d15fe..5a6ca8ca8 100644 --- a/src/base/net/stratum/DaemonClient.h +++ b/src/base/net/stratum/DaemonClient.h @@ -1,13 +1,7 @@ /* XMRig - * Copyright 2010 Jeff Garzik - * Copyright 2012-2014 pooler - * Copyright 2014 Lucas Jones - * Copyright 2014-2016 Wolf9466 - * Copyright 2016 Jay D Dee - * Copyright 2017-2018 XMR-Stak , - * Copyright 2019 Howard Chu - * Copyright 2018-2020 SChernykh - * Copyright 2016-2020 XMRig , + * Copyright (c) 2019 Howard Chu + * 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 @@ -27,21 +21,25 @@ #define XMRIG_DAEMONCLIENT_H -#include - - #include "base/kernel/interfaces/IDnsListener.h" #include "base/kernel/interfaces/IHttpListener.h" #include "base/kernel/interfaces/ITimerListener.h" #include "base/net/stratum/BaseClient.h" -#include "base/tools/Object.h" -#include "base/tools/cryptonote/BlockTemplate.h" #include "base/net/tools/Storage.h" +#include "base/tools/cryptonote/BlockTemplate.h" +#include "base/tools/cryptonote/WalletAddress.h" #include +using uv_buf_t = struct uv_buf_t; +using uv_connect_t = struct uv_connect_s; +using uv_handle_t = struct uv_handle_s; +using uv_stream_t = struct uv_stream_s; +using uv_tcp_t = struct uv_tcp_s; + + namespace xmrig { @@ -62,10 +60,11 @@ protected: int64_t submit(const JobResult &result) override; void connect() override; void connect(const Pool &pool) override; + void setPool(const Pool &pool) override; void onHttpData(const HttpData &data) override; void onTimer(const Timer *timer) override; - void onResolved(const DnsRecords& records, int status, const char* error) override; + void onResolved(const DnsRecords &records, int status, const char* error) override; inline bool hasExtension(Extension) const noexcept override { return false; } inline const char *mode() const override { return "daemon"; } @@ -92,18 +91,19 @@ private: API_DERO, } m_apiVersion = API_MONERO; + BlockTemplate m_blocktemplate; + Coin m_coin; std::shared_ptr m_httpListener; - String m_currentJobId; - String m_blocktemplateStr; String m_blockhashingblob; + String m_blocktemplateRequestHash; + String m_blocktemplateStr; + String m_currentJobId; String m_prevHash; String m_tlsFingerprint; String m_tlsVersion; Timer *m_timer; uint64_t m_blocktemplateRequestHeight = 0; - String m_blocktemplateRequestHash; - - BlockTemplate m_blocktemplate; + WalletAddress m_walletAddress; private: static inline DaemonClient* getClient(void* data) { return m_storage.get(data); } diff --git a/src/base/net/stratum/Pool.cpp b/src/base/net/stratum/Pool.cpp index f11c5e2d3..367e66677 100644 --- a/src/base/net/stratum/Pool.cpp +++ b/src/base/net/stratum/Pool.cpp @@ -190,10 +190,6 @@ bool xmrig::Pool::isEnabled() const } # endif - if (m_mode == MODE_DAEMON && (!algorithm().isValid() && !coin().isValid())) { - return false; - } - return m_flags.test(FLAG_ENABLED) && isValid(); }