feat: Add ETChash/Ethash algorithm support
- Add core crypto implementation (ETChash.cpp, ETCCache.cpp) - Implement ECIP-1099 epoch calculation for Ethereum Classic - Add Ethash support with standard 30000 block epochs - Integrate with OpenCL and CUDA backends for memory calculation - Register ETCHASH_ETC and ETHASH_ETH algorithm IDs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
327a4968e1
commit
353afe46ae
10 changed files with 565 additions and 2 deletions
|
|
@ -9,6 +9,7 @@ option(WITH_CN_FEMTO "Enable CryptoNight-UPX2 algorithm" ON)
|
|||
option(WITH_RANDOMX "Enable RandomX algorithms family" ON)
|
||||
option(WITH_ARGON2 "Enable Argon2 algorithms family" ON)
|
||||
option(WITH_KAWPOW "Enable KawPow algorithms family" ON)
|
||||
option(WITH_ETCHASH "Enable ETChash/Ethash algorithms family" ON)
|
||||
option(WITH_GHOSTRIDER "Enable GhostRider algorithm" ON)
|
||||
option(WITH_HTTP "Enable HTTP protocol support (client/server)" ON)
|
||||
option(WITH_DEBUG_LOG "Enable debug log output" OFF)
|
||||
|
|
@ -201,6 +202,7 @@ include(cmake/flags.cmake)
|
|||
include(cmake/randomx.cmake)
|
||||
include(cmake/argon2.cmake)
|
||||
include(cmake/kawpow.cmake)
|
||||
include(cmake/etchash.cmake)
|
||||
include(cmake/ghostrider.cmake)
|
||||
include(cmake/OpenSSL.cmake)
|
||||
include(cmake/asm.cmake)
|
||||
|
|
|
|||
21
miner/core/cmake/etchash.cmake
Normal file
21
miner/core/cmake/etchash.cmake
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
if (WITH_ETCHASH)
|
||||
add_definitions(/DXMRIG_ALGO_ETCHASH)
|
||||
|
||||
list(APPEND HEADERS_CRYPTO
|
||||
src/crypto/etchash/ETChash.h
|
||||
src/crypto/etchash/ETCCache.h
|
||||
)
|
||||
|
||||
list(APPEND SOURCES_CRYPTO
|
||||
src/crypto/etchash/ETChash.cpp
|
||||
src/crypto/etchash/ETCCache.cpp
|
||||
)
|
||||
|
||||
# ETChash uses the same libethash library as KawPow
|
||||
if (NOT WITH_KAWPOW)
|
||||
add_subdirectory(src/3rdparty/libethash)
|
||||
set(ETHASH_LIBRARY ethash)
|
||||
endif()
|
||||
else()
|
||||
remove_definitions(/DXMRIG_ALGO_ETCHASH)
|
||||
endif()
|
||||
|
|
@ -46,6 +46,12 @@
|
|||
#endif
|
||||
|
||||
|
||||
#ifdef XMRIG_ALGO_ETCHASH
|
||||
# include "crypto/etchash/ETCCache.h"
|
||||
# include "crypto/etchash/ETChash.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef XMRIG_FEATURE_API
|
||||
# include "base/api/interfaces/IApiRequest.h"
|
||||
#endif
|
||||
|
|
@ -226,6 +232,15 @@ public:
|
|||
}
|
||||
# endif
|
||||
|
||||
# ifdef XMRIG_ALGO_ETCHASH
|
||||
if (algo.family() == Algorithm::ETCHASH) {
|
||||
const uint32_t epoch = (algo == Algorithm::ETCHASH_ETC)
|
||||
? ETChash::epoch(job.height())
|
||||
: Ethash::epoch(job.height());
|
||||
mem_used = (ETCCache::dagSize(epoch) + oneMiB - 1) / oneMiB;
|
||||
}
|
||||
# endif
|
||||
|
||||
Log::print("|" CYAN_BOLD("%3zu") " |" CYAN_BOLD("%4u") " |" YELLOW(" %7s") " |" CYAN_BOLD("%10d") " |" CYAN_BOLD("%8d") " |"
|
||||
CYAN_BOLD("%7d") " |" CYAN_BOLD("%3d") " |" CYAN_BOLD("%4d") " |" CYAN("%7zu") " | " GREEN_BOLD("%s"),
|
||||
i,
|
||||
|
|
|
|||
|
|
@ -47,6 +47,12 @@
|
|||
#endif
|
||||
|
||||
|
||||
#ifdef XMRIG_ALGO_ETCHASH
|
||||
# include "crypto/etchash/ETCCache.h"
|
||||
# include "crypto/etchash/ETChash.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef XMRIG_FEATURE_API
|
||||
# include "base/api/interfaces/IApiRequest.h"
|
||||
#endif
|
||||
|
|
@ -214,6 +220,15 @@ public:
|
|||
}
|
||||
# endif
|
||||
|
||||
# ifdef XMRIG_ALGO_ETCHASH
|
||||
if (algo.family() == Algorithm::ETCHASH) {
|
||||
const uint32_t epoch = (algo == Algorithm::ETCHASH_ETC)
|
||||
? ETChash::epoch(job.height())
|
||||
: Ethash::epoch(job.height());
|
||||
mem_used = (ETCCache::cacheSize(epoch) + ETCCache::dagSize(epoch)) / oneMiB;
|
||||
}
|
||||
# endif
|
||||
|
||||
Log::print("|" CYAN_BOLD("%3zu") " |" CYAN_BOLD("%4u") " |" YELLOW(" %7s") " |" CYAN_BOLD("%10u") " |" CYAN_BOLD("%6u") " |"
|
||||
CYAN("%7zu") " | %s",
|
||||
i,
|
||||
|
|
|
|||
|
|
@ -101,6 +101,13 @@ const char* Algorithm::kGHOSTRIDER = "ghostrider";
|
|||
const char* Algorithm::kGHOSTRIDER_RTM = "ghostrider";
|
||||
#endif
|
||||
|
||||
#ifdef XMRIG_ALGO_ETCHASH
|
||||
const char *Algorithm::kETCHASH = "etchash";
|
||||
const char *Algorithm::kETCHASH_ETC = "etchash";
|
||||
const char *Algorithm::kETHASH = "ethash";
|
||||
const char *Algorithm::kETHASH_ETH = "ethash";
|
||||
#endif
|
||||
|
||||
|
||||
#define ALGO_NAME(ALGO) { Algorithm::ALGO, Algorithm::k##ALGO }
|
||||
#define ALGO_ALIAS(ALGO, NAME) { NAME, Algorithm::ALGO }
|
||||
|
|
@ -163,6 +170,11 @@ static const std::map<uint32_t, const char *> kAlgorithmNames = {
|
|||
# ifdef XMRIG_ALGO_GHOSTRIDER
|
||||
ALGO_NAME(GHOSTRIDER_RTM),
|
||||
# endif
|
||||
|
||||
# ifdef XMRIG_ALGO_ETCHASH
|
||||
ALGO_NAME(ETCHASH_ETC),
|
||||
ALGO_NAME(ETHASH_ETH),
|
||||
# endif
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -279,6 +291,14 @@ static const std::map<const char *, Algorithm::Id, aliasCompare> kAlgorithmAlias
|
|||
ALGO_ALIAS_AUTO(GHOSTRIDER_RTM), ALGO_ALIAS(GHOSTRIDER_RTM, "ghostrider/rtm"),
|
||||
ALGO_ALIAS(GHOSTRIDER_RTM, "gr"),
|
||||
# endif
|
||||
|
||||
# ifdef XMRIG_ALGO_ETCHASH
|
||||
ALGO_ALIAS_AUTO(ETCHASH_ETC), ALGO_ALIAS(ETCHASH_ETC, "etchash/etc"),
|
||||
ALGO_ALIAS(ETCHASH_ETC, "etc"),
|
||||
ALGO_ALIAS_AUTO(ETHASH_ETH), ALGO_ALIAS(ETHASH_ETH, "ethash/eth"),
|
||||
ALGO_ALIAS(ETHASH_ETH, "eth"),
|
||||
ALGO_ALIAS(ETHASH_ETH, "daggerhashimoto"),
|
||||
# endif
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -353,7 +373,8 @@ std::vector<xmrig::Algorithm> xmrig::Algorithm::all(const std::function<bool(con
|
|||
RX_0, RX_WOW, RX_ARQ, RX_GRAFT, RX_SFX, RX_YADA,
|
||||
AR2_CHUKWA, AR2_CHUKWA_V2, AR2_WRKZ,
|
||||
KAWPOW_RVN,
|
||||
GHOSTRIDER_RTM
|
||||
GHOSTRIDER_RTM,
|
||||
ETCHASH_ETC, ETHASH_ETH
|
||||
};
|
||||
|
||||
Algorithms out;
|
||||
|
|
|
|||
|
|
@ -82,6 +82,8 @@ public:
|
|||
AR2_CHUKWA_V2 = 0x61140000, // "argon2/chukwav2" Argon2id (Chukwa v2).
|
||||
AR2_WRKZ = 0x61120000, // "argon2/wrkz" Argon2id (WRKZ)
|
||||
KAWPOW_RVN = 0x6b0f0000, // "kawpow/rvn" KawPow (RVN)
|
||||
ETCHASH_ETC = 0x65100000, // "etchash" ETChash (ETC)
|
||||
ETHASH_ETH = 0x65100001, // "ethash" Ethash (ETH)
|
||||
};
|
||||
|
||||
enum Family : uint32_t {
|
||||
|
|
@ -95,7 +97,8 @@ public:
|
|||
RANDOM_X = 0x72000000,
|
||||
ARGON2 = 0x61000000,
|
||||
KAWPOW = 0x6b000000,
|
||||
GHOSTRIDER = 0x6c000000
|
||||
GHOSTRIDER = 0x6c000000,
|
||||
ETCHASH = 0x65000000
|
||||
};
|
||||
|
||||
static const char *kINVALID;
|
||||
|
|
@ -163,6 +166,13 @@ public:
|
|||
static const char* kGHOSTRIDER_RTM;
|
||||
# endif
|
||||
|
||||
# ifdef XMRIG_ALGO_ETCHASH
|
||||
static const char *kETCHASH;
|
||||
static const char *kETCHASH_ETC;
|
||||
static const char *kETHASH;
|
||||
static const char *kETHASH_ETH;
|
||||
# endif
|
||||
|
||||
inline Algorithm() = default;
|
||||
inline Algorithm(const char *algo) : m_id(parse(algo)) {}
|
||||
inline Algorithm(Id id) : m_id(id) {}
|
||||
|
|
|
|||
134
miner/core/src/crypto/etchash/ETCCache.cpp
Normal file
134
miner/core/src/crypto/etchash/ETCCache.cpp
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
/* Miner
|
||||
* Copyright (c) 2025 Lethean
|
||||
*
|
||||
* 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 "crypto/etchash/ETCCache.h"
|
||||
#include "3rdparty/libethash/data_sizes.h"
|
||||
#include "3rdparty/libethash/ethash_internal.h"
|
||||
#include "3rdparty/libethash/ethash.h"
|
||||
#include "base/io/log/Log.h"
|
||||
#include "base/io/log/Tags.h"
|
||||
#include "base/tools/Chrono.h"
|
||||
#include "crypto/common/VirtualMemory.h"
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
||||
|
||||
std::mutex ETCCache::s_cacheMutex;
|
||||
ETCCache ETCCache::s_etcCache;
|
||||
ETCCache ETCCache::s_ethCache;
|
||||
|
||||
|
||||
ETCCache::ETCCache()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ETCCache::~ETCCache()
|
||||
{
|
||||
delete m_memory;
|
||||
}
|
||||
|
||||
|
||||
bool ETCCache::init(uint32_t epoch, bool isETC)
|
||||
{
|
||||
if (epoch >= sizeof(cache_sizes) / sizeof(cache_sizes[0])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_epoch == epoch && m_isETC == isETC) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const uint64_t start_ms = Chrono::steadyMSecs();
|
||||
|
||||
const size_t size = cache_sizes[epoch];
|
||||
if (!m_memory || m_memory->size() < size) {
|
||||
delete m_memory;
|
||||
m_memory = new VirtualMemory(size, false, false, false);
|
||||
}
|
||||
|
||||
// Calculate seed hash for this epoch
|
||||
uint8_t seed[32];
|
||||
seedHash(epoch, seed);
|
||||
|
||||
ethash_h256_t seedhash;
|
||||
memcpy(seedhash.b, seed, 32);
|
||||
|
||||
ethash_compute_cache_nodes(m_memory->raw(), size, &seedhash);
|
||||
|
||||
m_size = size;
|
||||
m_epoch = epoch;
|
||||
m_isETC = isETC;
|
||||
|
||||
const char* algoName = isETC ? "ETChash" : "Ethash";
|
||||
LOG_INFO("%s " YELLOW("%s") " light cache for epoch " WHITE_BOLD("%u") " calculated " BLACK_BOLD("(%" PRIu64 "ms)"),
|
||||
Tags::miner(), algoName, epoch, Chrono::steadyMSecs() - start_ms);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void* ETCCache::data() const
|
||||
{
|
||||
return m_memory ? m_memory->raw() : nullptr;
|
||||
}
|
||||
|
||||
|
||||
uint64_t ETCCache::cacheSize(uint32_t epoch)
|
||||
{
|
||||
if (epoch >= sizeof(cache_sizes) / sizeof(cache_sizes[0])) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return cache_sizes[epoch];
|
||||
}
|
||||
|
||||
|
||||
uint64_t ETCCache::dagSize(uint32_t epoch)
|
||||
{
|
||||
if (epoch >= sizeof(dag_sizes) / sizeof(dag_sizes[0])) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return dag_sizes[epoch];
|
||||
}
|
||||
|
||||
|
||||
void ETCCache::seedHash(uint32_t epoch, uint8_t (&seed)[32])
|
||||
{
|
||||
// Seed hash starts as zeros
|
||||
memset(seed, 0, 32);
|
||||
|
||||
// Each epoch, seed = keccak256(previous_seed)
|
||||
for (uint32_t i = 0; i < epoch; ++i) {
|
||||
ethash_h256_t hash;
|
||||
memcpy(hash.b, seed, 32);
|
||||
hash = ethash_get_seedhash(i + 1);
|
||||
memcpy(seed, hash.b, 32);
|
||||
}
|
||||
|
||||
// Actually just use libethash's function directly
|
||||
ethash_h256_t hash = ethash_get_seedhash(epoch);
|
||||
memcpy(seed, hash.b, 32);
|
||||
}
|
||||
|
||||
|
||||
} // namespace xmrig
|
||||
78
miner/core/src/crypto/etchash/ETCCache.h
Normal file
78
miner/core/src/crypto/etchash/ETCCache.h
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/* Miner
|
||||
* Copyright (c) 2025 Lethean
|
||||
*
|
||||
* 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_ETC_CACHE_H
|
||||
#define XMRIG_ETC_CACHE_H
|
||||
|
||||
|
||||
#include "base/tools/Object.h"
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
namespace xmrig
|
||||
{
|
||||
|
||||
|
||||
class VirtualMemory;
|
||||
|
||||
|
||||
class ETCCache
|
||||
{
|
||||
public:
|
||||
// Ethash cache item size = 64 bytes (HASH_BYTES)
|
||||
static constexpr size_t HASH_BYTES = 64;
|
||||
|
||||
XMRIG_DISABLE_COPY_MOVE(ETCCache)
|
||||
|
||||
ETCCache();
|
||||
~ETCCache();
|
||||
|
||||
// Initialize cache for given epoch
|
||||
bool init(uint32_t epoch, bool isETC = true);
|
||||
|
||||
// Access cache data
|
||||
void* data() const;
|
||||
size_t size() const { return m_size; }
|
||||
uint32_t epoch() const { return m_epoch; }
|
||||
bool isETC() const { return m_isETC; }
|
||||
|
||||
// Calculate cache and DAG sizes for epoch
|
||||
static uint64_t cacheSize(uint32_t epoch);
|
||||
static uint64_t dagSize(uint32_t epoch);
|
||||
|
||||
// Get seed hash for epoch
|
||||
static void seedHash(uint32_t epoch, uint8_t (&seed)[32]);
|
||||
|
||||
// Singleton instances
|
||||
static std::mutex s_cacheMutex;
|
||||
static ETCCache s_etcCache; // For ETC (ETChash)
|
||||
static ETCCache s_ethCache; // For ETH (Ethash)
|
||||
|
||||
private:
|
||||
VirtualMemory* m_memory = nullptr;
|
||||
size_t m_size = 0;
|
||||
uint32_t m_epoch = 0xFFFFFFFFUL;
|
||||
bool m_isETC = true;
|
||||
};
|
||||
|
||||
|
||||
} /* namespace xmrig */
|
||||
|
||||
|
||||
#endif /* XMRIG_ETC_CACHE_H */
|
||||
187
miner/core/src/crypto/etchash/ETChash.cpp
Normal file
187
miner/core/src/crypto/etchash/ETChash.cpp
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
/* Miner
|
||||
* Copyright (c) 2025 Lethean
|
||||
*
|
||||
* 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 "crypto/etchash/ETChash.h"
|
||||
#include "crypto/etchash/ETCCache.h"
|
||||
#include "3rdparty/libethash/ethash.h"
|
||||
#include "3rdparty/libethash/ethash_internal.h"
|
||||
#include "3rdparty/libethash/data_sizes.h"
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
||||
|
||||
// ECIP-1099: Calculate epoch from block number for Ethereum Classic
|
||||
// Before activation: epoch = block / 30000
|
||||
// After activation: epoch = 390 + (block - 11700000) / 60000
|
||||
uint32_t ETChash::epoch(uint64_t blockNumber)
|
||||
{
|
||||
if (blockNumber < ECIP1099_ACTIVATION_BLOCK) {
|
||||
return static_cast<uint32_t>(blockNumber / EPOCH_LENGTH_OLD);
|
||||
}
|
||||
|
||||
// After ECIP-1099 activation, epoch increases every 60000 blocks
|
||||
return ECIP1099_ACTIVATION_EPOCH +
|
||||
static_cast<uint32_t>((blockNumber - ECIP1099_ACTIVATION_BLOCK) / EPOCH_LENGTH_NEW);
|
||||
}
|
||||
|
||||
|
||||
uint64_t ETChash::epochStartBlock(uint32_t epoch)
|
||||
{
|
||||
if (epoch < ECIP1099_ACTIVATION_EPOCH) {
|
||||
return static_cast<uint64_t>(epoch) * EPOCH_LENGTH_OLD;
|
||||
}
|
||||
|
||||
// After ECIP-1099
|
||||
return ECIP1099_ACTIVATION_BLOCK +
|
||||
static_cast<uint64_t>(epoch - ECIP1099_ACTIVATION_EPOCH) * EPOCH_LENGTH_NEW;
|
||||
}
|
||||
|
||||
|
||||
void ETChash::calculate(const ETCCache& cache, uint64_t blockNumber,
|
||||
const uint8_t (&headerHash)[32], uint64_t nonce,
|
||||
uint8_t (&output)[32], uint8_t (&mixHash)[32])
|
||||
{
|
||||
const uint32_t epochNum = cache.epoch();
|
||||
|
||||
// Get DAG size for this epoch
|
||||
const uint64_t fullSize = dag_sizes[epochNum];
|
||||
|
||||
// Setup light cache structure for libethash
|
||||
ethash_light lightCache;
|
||||
lightCache.cache = cache.data();
|
||||
lightCache.cache_size = cache.size();
|
||||
lightCache.block_number = blockNumber;
|
||||
|
||||
// Calculate fast mod data for optimized DAG item calculation
|
||||
lightCache.num_parent_nodes = static_cast<uint32_t>(cache.size() / sizeof(node));
|
||||
|
||||
// Calculate reciprocal, increment, shift for fast modulo
|
||||
uint32_t divisor = lightCache.num_parent_nodes;
|
||||
if ((divisor & (divisor - 1)) == 0) {
|
||||
// Power of 2
|
||||
lightCache.reciprocal = 1;
|
||||
lightCache.increment = 0;
|
||||
uint32_t shift = 0;
|
||||
uint32_t temp = divisor;
|
||||
while (temp > 1) {
|
||||
temp >>= 1;
|
||||
shift++;
|
||||
}
|
||||
lightCache.shift = shift;
|
||||
} else {
|
||||
// Use fast division algorithm
|
||||
uint32_t shift = 31;
|
||||
uint32_t temp = divisor;
|
||||
while (temp > 0) {
|
||||
temp >>= 1;
|
||||
if (temp > 0) shift++;
|
||||
}
|
||||
shift = 63 - (31 - shift);
|
||||
|
||||
const uint64_t N = 1ULL << shift;
|
||||
const uint64_t q = N / divisor;
|
||||
const uint64_t r = N - q * divisor;
|
||||
|
||||
if (r * 2 < divisor) {
|
||||
lightCache.reciprocal = static_cast<uint32_t>(q);
|
||||
lightCache.increment = 1;
|
||||
} else {
|
||||
lightCache.reciprocal = static_cast<uint32_t>(q + 1);
|
||||
lightCache.increment = 0;
|
||||
}
|
||||
lightCache.shift = shift;
|
||||
}
|
||||
|
||||
// Convert header hash to libethash format
|
||||
ethash_h256_t header;
|
||||
memcpy(header.b, headerHash, 32);
|
||||
|
||||
// Compute the Ethash using light client verification
|
||||
ethash_return_value_t result = ethash_light_compute_internal(&lightCache, fullSize, header, nonce);
|
||||
|
||||
// Copy results
|
||||
memcpy(output, result.result.b, 32);
|
||||
memcpy(mixHash, result.mix_hash.b, 32);
|
||||
}
|
||||
|
||||
|
||||
// Ethash (standard Ethereum) - uses fixed 30000 block epochs
|
||||
void Ethash::calculate(const ETCCache& cache, uint64_t blockNumber,
|
||||
const uint8_t (&headerHash)[32], uint64_t nonce,
|
||||
uint8_t (&output)[32], uint8_t (&mixHash)[32])
|
||||
{
|
||||
const uint32_t epochNum = cache.epoch();
|
||||
|
||||
// Get DAG size for this epoch
|
||||
const uint64_t fullSize = dag_sizes[epochNum];
|
||||
|
||||
// Setup light cache structure for libethash
|
||||
ethash_light lightCache;
|
||||
lightCache.cache = cache.data();
|
||||
lightCache.cache_size = cache.size();
|
||||
lightCache.block_number = blockNumber;
|
||||
|
||||
// Calculate fast mod data
|
||||
lightCache.num_parent_nodes = static_cast<uint32_t>(cache.size() / sizeof(node));
|
||||
|
||||
uint32_t divisor = lightCache.num_parent_nodes;
|
||||
if ((divisor & (divisor - 1)) == 0) {
|
||||
lightCache.reciprocal = 1;
|
||||
lightCache.increment = 0;
|
||||
uint32_t shift = 0;
|
||||
uint32_t temp = divisor;
|
||||
while (temp > 1) {
|
||||
temp >>= 1;
|
||||
shift++;
|
||||
}
|
||||
lightCache.shift = shift;
|
||||
} else {
|
||||
uint32_t shift = 31;
|
||||
uint32_t temp = divisor;
|
||||
while (temp > 0) {
|
||||
temp >>= 1;
|
||||
if (temp > 0) shift++;
|
||||
}
|
||||
shift = 63 - (31 - shift);
|
||||
|
||||
const uint64_t N = 1ULL << shift;
|
||||
const uint64_t q = N / divisor;
|
||||
const uint64_t r = N - q * divisor;
|
||||
|
||||
if (r * 2 < divisor) {
|
||||
lightCache.reciprocal = static_cast<uint32_t>(q);
|
||||
lightCache.increment = 1;
|
||||
} else {
|
||||
lightCache.reciprocal = static_cast<uint32_t>(q + 1);
|
||||
lightCache.increment = 0;
|
||||
}
|
||||
lightCache.shift = shift;
|
||||
}
|
||||
|
||||
ethash_h256_t header;
|
||||
memcpy(header.b, headerHash, 32);
|
||||
|
||||
ethash_return_value_t result = ethash_light_compute_internal(&lightCache, fullSize, header, nonce);
|
||||
|
||||
memcpy(output, result.result.b, 32);
|
||||
memcpy(mixHash, result.mix_hash.b, 32);
|
||||
}
|
||||
|
||||
|
||||
} // namespace xmrig
|
||||
80
miner/core/src/crypto/etchash/ETChash.h
Normal file
80
miner/core/src/crypto/etchash/ETChash.h
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/* Miner
|
||||
* Copyright (c) 2025 Lethean
|
||||
*
|
||||
* 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_ETCHASH_H
|
||||
#define XMRIG_ETCHASH_H
|
||||
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
namespace xmrig
|
||||
{
|
||||
|
||||
|
||||
class ETCCache;
|
||||
|
||||
|
||||
class ETChash
|
||||
{
|
||||
public:
|
||||
// ETChash constants
|
||||
// ECIP-1099: After epoch 390, epoch length changes to 60000 blocks
|
||||
static constexpr uint32_t EPOCH_LENGTH_OLD = 30000; // Before ECIP-1099
|
||||
static constexpr uint32_t EPOCH_LENGTH_NEW = 60000; // After ECIP-1099
|
||||
static constexpr uint32_t ECIP1099_ACTIVATION_EPOCH = 390;
|
||||
static constexpr uint32_t ECIP1099_ACTIVATION_BLOCK = 11700000; // 390 * 30000
|
||||
|
||||
// Ethash core constants (shared with libethash)
|
||||
static constexpr uint32_t MIX_BYTES = 128;
|
||||
static constexpr uint32_t HASH_BYTES = 64;
|
||||
static constexpr uint32_t DATASET_PARENTS = 256;
|
||||
static constexpr uint32_t CACHE_ROUNDS = 3;
|
||||
static constexpr uint32_t ACCESSES = 64;
|
||||
|
||||
// Calculate epoch from block number (accounts for ECIP-1099)
|
||||
static uint32_t epoch(uint64_t blockNumber);
|
||||
|
||||
// Calculate block number at start of epoch
|
||||
static uint64_t epochStartBlock(uint32_t epoch);
|
||||
|
||||
// Calculate hash
|
||||
static void calculate(const ETCCache& cache, uint64_t blockNumber,
|
||||
const uint8_t (&headerHash)[32], uint64_t nonce,
|
||||
uint8_t (&output)[32], uint8_t (&mixHash)[32]);
|
||||
};
|
||||
|
||||
|
||||
// Ethash class - identical to ETChash but with standard epoch length
|
||||
class Ethash
|
||||
{
|
||||
public:
|
||||
static constexpr uint32_t EPOCH_LENGTH = 30000;
|
||||
|
||||
static uint32_t epoch(uint64_t blockNumber) { return static_cast<uint32_t>(blockNumber / EPOCH_LENGTH); }
|
||||
static uint64_t epochStartBlock(uint32_t epoch) { return static_cast<uint64_t>(epoch) * EPOCH_LENGTH; }
|
||||
|
||||
static void calculate(const ETCCache& cache, uint64_t blockNumber,
|
||||
const uint8_t (&headerHash)[32], uint64_t nonce,
|
||||
uint8_t (&output)[32], uint8_t (&mixHash)[32]);
|
||||
};
|
||||
|
||||
|
||||
} // namespace xmrig
|
||||
|
||||
|
||||
#endif // XMRIG_ETCHASH_H
|
||||
Loading…
Add table
Reference in a new issue