From fbac0a9d476168232fc59f08fbd93e11d50bd436 Mon Sep 17 00:00:00 2001 From: Capri Date: Wed, 16 Sep 2026 21:53:20 +0000 Subject: [PATCH] Reuse RandomX hashing context during mining --- src/crypto/randomx_hash.cpp | 95 +++++++++++++++++++++++++++++-------- src/crypto/randomx_hash.h | 22 +++++++++ src/primitives/block.cpp | 17 +++++-- src/primitives/block.h | 3 ++ src/rpc/mining.cpp | 15 +++++- 5 files changed, 128 insertions(+), 24 deletions(-) diff --git a/src/crypto/randomx_hash.cpp b/src/crypto/randomx_hash.cpp index 83a4e27..7efcc6e 100644 --- a/src/crypto/randomx_hash.cpp +++ b/src/crypto/randomx_hash.cpp @@ -2,6 +2,77 @@ #include +struct VextaRandomXHasher::Impl +{ + randomx_cache* cache{nullptr}; + randomx_vm* vm{nullptr}; + + Impl(const void* key, std::size_t key_size) + { + cache = randomx_alloc_cache(RANDOMX_FLAG_DEFAULT); + if (cache == nullptr) { + return; + } + + randomx_init_cache(cache, key, key_size); + + vm = randomx_create_vm( + RANDOMX_FLAG_DEFAULT, + cache, + nullptr); + + if (vm == nullptr) { + randomx_release_cache(cache); + cache = nullptr; + } + } + + ~Impl() + { + if (vm != nullptr) { + randomx_destroy_vm(vm); + } + + if (cache != nullptr) { + randomx_release_cache(cache); + } + } +}; + +VextaRandomXHasher::VextaRandomXHasher( + const void* key, + std::size_t key_size) + : m_impl(std::make_unique(key, key_size)) +{ +} + +VextaRandomXHasher::~VextaRandomXHasher() = default; + +bool VextaRandomXHasher::IsValid() const +{ + return m_impl != nullptr && + m_impl->cache != nullptr && + m_impl->vm != nullptr; +} + +bool VextaRandomXHasher::Hash( + const void* input, + std::size_t input_size, + uint8_t output[VEXTA_RANDOMX_HASH_SIZE]) +{ + if (!IsValid()) { + return false; + } + + randomx_calculate_hash( + m_impl->vm, + input, + input_size, + output); + + return true; +} + bool VextaRandomXHash( const void* input, std::size_t input_size, @@ -9,27 +80,11 @@ bool VextaRandomXHash( std::size_t key_size, uint8_t output[VEXTA_RANDOMX_HASH_SIZE]) { - randomx_cache* cache = randomx_alloc_cache(RANDOMX_FLAG_DEFAULT); - if (cache == nullptr) { + VextaRandomXHasher hasher(key, key_size); + + if (!hasher.IsValid()) { return false; } - randomx_init_cache(cache, key, key_size); - - randomx_vm* vm = randomx_create_vm( - RANDOMX_FLAG_DEFAULT, - cache, - nullptr); - - if (vm == nullptr) { - randomx_release_cache(cache); - return false; - } - - randomx_calculate_hash(vm, input, input_size, output); - - randomx_destroy_vm(vm); - randomx_release_cache(cache); - - return true; + return hasher.Hash(input, input_size, output); } diff --git a/src/crypto/randomx_hash.h b/src/crypto/randomx_hash.h index ca2150a..479251e 100644 --- a/src/crypto/randomx_hash.h +++ b/src/crypto/randomx_hash.h @@ -3,9 +3,31 @@ #include #include +#include static constexpr std::size_t VEXTA_RANDOMX_HASH_SIZE = 32; +class VextaRandomXHasher +{ +public: + VextaRandomXHasher(const void* key, std::size_t key_size); + ~VextaRandomXHasher(); + + VextaRandomXHasher(const VextaRandomXHasher&) = delete; + VextaRandomXHasher& operator=(const VextaRandomXHasher&) = delete; + + bool IsValid() const; + + bool Hash( + const void* input, + std::size_t input_size, + uint8_t output[VEXTA_RANDOMX_HASH_SIZE]); + +private: + struct Impl; + std::unique_ptr m_impl; +}; + /** * Calculate a RandomX hash using an explicit key. * diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index a2e22ea..3e75524 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -33,15 +33,26 @@ int CBlockHeader::GetAlgo() const } bool CBlockHeader::GetRandomXPoWHash(const uint256& seed, uint256& result) const +{ + VextaRandomXHasher hasher(seed.data(), seed.size()); + + if (!hasher.IsValid()) { + return false; + } + + return GetRandomXPoWHash(hasher, result); +} + +bool CBlockHeader::GetRandomXPoWHash( + VextaRandomXHasher& hasher, + uint256& result) const { CDataStream stream(SER_GETHASH, PROTOCOL_VERSION); stream << *this; - return VextaRandomXHash( + return hasher.Hash( stream.data(), stream.size(), - seed.data(), - seed.size(), result.begin()); } diff --git a/src/primitives/block.h b/src/primitives/block.h index 928ac6b..1f4b5b8 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -51,6 +51,8 @@ inline int GetVersionForAlgo(int algo) * in the block is a special one that creates a new coin owned by the creator * of the block. */ +class VextaRandomXHasher; + class CBlockHeader { public: @@ -101,6 +103,7 @@ public: * The seed is supplied in raw uint256 serialization byte order. */ bool GetRandomXPoWHash(const uint256& seed, uint256& result) const; + bool GetRandomXPoWHash(VextaRandomXHasher& hasher, uint256& result) const; int64_t GetBlockTime() const { diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index c422f01..3fa3642 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -200,6 +201,8 @@ static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t& const int algo = block.GetAlgo(); uint256 randomx_seed; + std::unique_ptr randomx_hasher; + if (algo == ALGO_RANDOMX) { if (pindexPrev == nullptr || !GetRandomXSeed( @@ -211,6 +214,16 @@ static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t& RPC_INTERNAL_ERROR, "Failed to resolve RandomX seed"); } + + randomx_hasher = std::make_unique( + randomx_seed.data(), + randomx_seed.size()); + + if (!randomx_hasher->IsValid()) { + throw JSONRPCError( + RPC_INTERNAL_ERROR, + "Failed to initialize RandomX hasher"); + } } else if (algo != ALGO_SHA256D) { throw JSONRPCError( RPC_INVALID_PARAMETER, @@ -225,7 +238,7 @@ static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t& if (algo == ALGO_SHA256D) { pow_hash = block.GetHash(); } else { - if (!block.GetRandomXPoWHash(randomx_seed, pow_hash)) { + if (!block.GetRandomXPoWHash(*randomx_hasher, pow_hash)) { throw JSONRPCError( RPC_INTERNAL_ERROR, "Failed to calculate RandomX proof of work hash");