diff --git a/src/p2pool.cpp b/src/p2pool.cpp index eb76f73..ff61887 100644 --- a/src/p2pool.cpp +++ b/src/p2pool.cpp @@ -219,9 +219,9 @@ p2pool::~p2pool() delete m_params; } -bool p2pool::calculate_hash(const void* data, size_t size, uint64_t height, const hash& seed, hash& result) +bool p2pool::calculate_hash(const void* data, size_t size, uint64_t height, const hash& seed, hash& result, bool force_light_mode) { - return m_hasher->calculate(data, size, height, seed, result); + return m_hasher->calculate(data, size, height, seed, result, force_light_mode); } uint64_t p2pool::get_seed_height(uint64_t height) diff --git a/src/p2pool.h b/src/p2pool.h index 38d2590..bfc1337 100644 --- a/src/p2pool.h +++ b/src/p2pool.h @@ -60,7 +60,7 @@ public: p2pool_api* api() const { return m_api; } RandomX_Hasher_Base* hasher() const { return m_hasher; } - bool calculate_hash(const void* data, size_t size, uint64_t height, const hash& seed, hash& result); + bool calculate_hash(const void* data, size_t size, uint64_t height, const hash& seed, hash& result, bool force_light_mode); static uint64_t get_seed_height(uint64_t height); bool get_seed(uint64_t height, hash& seed) const; diff --git a/src/pool_block.cpp b/src/pool_block.cpp index f76fa4a..6e9b051 100644 --- a/src/pool_block.cpp +++ b/src/pool_block.cpp @@ -271,7 +271,7 @@ void PoolBlock::reset_offchain_data() m_receivedTimestamp = 0; } -bool PoolBlock::get_pow_hash(RandomX_Hasher_Base* hasher, uint64_t height, const hash& seed_hash, hash& pow_hash) +bool PoolBlock::get_pow_hash(RandomX_Hasher_Base* hasher, uint64_t height, const hash& seed_hash, hash& pow_hash, bool force_light_mode) { alignas(8) uint8_t hashes[HASH_SIZE * 3]; @@ -349,7 +349,7 @@ bool PoolBlock::get_pow_hash(RandomX_Hasher_Base* hasher, uint64_t height, const writeVarint(count, [&blob, &blob_size](uint8_t b) { blob[blob_size++] = b; }); - return hasher->calculate(blob, blob_size, height, seed_hash, pow_hash); + return hasher->calculate(blob, blob_size, height, seed_hash, pow_hash, force_light_mode); } uint64_t PoolBlock::get_payout(const Wallet& w) const diff --git a/src/pool_block.h b/src/pool_block.h index 793798f..49f2b25 100644 --- a/src/pool_block.h +++ b/src/pool_block.h @@ -141,7 +141,7 @@ struct PoolBlock int deserialize(const uint8_t* data, size_t size, const SideChain& sidechain, uv_loop_t* loop, bool compact); void reset_offchain_data(); - bool get_pow_hash(RandomX_Hasher_Base* hasher, uint64_t height, const hash& seed_hash, hash& pow_hash); + bool get_pow_hash(RandomX_Hasher_Base* hasher, uint64_t height, const hash& seed_hash, hash& pow_hash, bool force_light_mode = false); uint64_t get_payout(const Wallet& w) const; diff --git a/src/pow_hash.cpp b/src/pow_hash.cpp index 4713577..4afe46f 100644 --- a/src/pow_hash.cpp +++ b/src/pow_hash.cpp @@ -322,10 +322,10 @@ void RandomX_Hasher::sync_wait() ReadLock lock2(m_cacheLock); } -bool RandomX_Hasher::calculate(const void* data, size_t size, uint64_t /*height*/, const hash& seed, hash& result) +bool RandomX_Hasher::calculate(const void* data, size_t size, uint64_t /*height*/, const hash& seed, hash& result, bool force_light_mode) { // First try to use the dataset if it's ready - if (uv_rwlock_tryrdlock(&m_datasetLock) == 0) { + if (!force_light_mode && (uv_rwlock_tryrdlock(&m_datasetLock) == 0)) { ON_SCOPE_LEAVE([this]() { uv_rwlock_rdunlock(&m_datasetLock); }); if (m_stopped.load()) { @@ -340,7 +340,7 @@ bool RandomX_Hasher::calculate(const void* data, size_t size, uint64_t /*height* } } - // If dataset is not ready, use the cache and wait if necessary + // If dataset is not ready, or force_light_mode = true, use the cache and wait if necessary ReadLock lock(m_cacheLock); if (m_stopped.load()) { @@ -429,7 +429,7 @@ void RandomX_Hasher_RPC::loop(void* data) LOGINFO(1, "event loop stopped"); } -bool RandomX_Hasher_RPC::calculate(const void* data_ptr, size_t size, uint64_t height, const hash& /*seed*/, hash& h) +bool RandomX_Hasher_RPC::calculate(const void* data_ptr, size_t size, uint64_t height, const hash& /*seed*/, hash& h, bool /*force_light_mode*/) { MutexLock lock(m_requestMutex); diff --git a/src/pow_hash.h b/src/pow_hash.h index ff040b2..104adad 100644 --- a/src/pow_hash.h +++ b/src/pow_hash.h @@ -40,7 +40,7 @@ public: virtual uint32_t seed_counter() const { return 0; } virtual void sync_wait() {} - virtual bool calculate(const void* data, size_t size, uint64_t height, const hash& seed, hash& result) = 0; + virtual bool calculate(const void* data, size_t size, uint64_t height, const hash& seed, hash& result, bool force_light_mode) = 0; }; #ifdef WITH_RANDOMX @@ -60,7 +60,7 @@ public: uint32_t seed_counter() const override { return m_seedCounter.load(); } void sync_wait() override; - bool calculate(const void* data, size_t size, uint64_t height, const hash& seed, hash& result) override; + bool calculate(const void* data, size_t size, uint64_t height, const hash& seed, hash& result, bool force_light_mode) override; private: @@ -100,7 +100,7 @@ public: explicit RandomX_Hasher_RPC(p2pool* pool); ~RandomX_Hasher_RPC(); - bool calculate(const void* data_ptr, size_t size, uint64_t height, const hash& seed, hash& h) override; + bool calculate(const void* data_ptr, size_t size, uint64_t height, const hash& seed, hash& h, bool force_light_mode) override; private: static void loop(void* data); diff --git a/src/side_chain.cpp b/src/side_chain.cpp index 2a2a2dc..1b25bea 100644 --- a/src/side_chain.cpp +++ b/src/side_chain.cpp @@ -570,7 +570,20 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector& missing_ } if (!block.m_difficulty.check_pow(pow_hash)) { - LOGWARN(3, "add_external_block mined by " << block.m_minerWallet << ": not enough PoW for height = " << block.m_sidechainHeight << ", mainchain height " << block.m_txinGenHeight); + LOGWARN(3, + "add_external_block mined by " << block.m_minerWallet << + ": not enough PoW for height = " << block.m_sidechainHeight << + ", id = " << block.m_sidechainId << + ", nonce = " << block.m_nonce << + ", mainchain height = " << block.m_txinGenHeight + ); + + // Calculate the same hash second time to check if it's an unstable hardware that caused this + hash pow_hash2; + if (block.get_pow_hash(m_pool->hasher(), block.m_txinGenHeight, seed, pow_hash2, true) && (pow_hash2 != pow_hash)) { + LOGERR(0, "UNSTABLE HARDWARE DETECTED: Calculated the same hash twice, got different results: " << pow_hash << " != " << pow_hash2 << " (sidechain id = " << block.m_sidechainId << ')'); + } + return false; } diff --git a/src/stratum_server.cpp b/src/stratum_server.cpp index 293f349..a3d6c82 100644 --- a/src/stratum_server.cpp +++ b/src/stratum_server.cpp @@ -881,7 +881,7 @@ void StratumServer::on_share_found(uv_work_t* req) } hash pow_hash; - if (!pool->calculate_hash(blob, blob_size, height, seed_hash, pow_hash)) { + if (!pool->calculate_hash(blob, blob_size, height, seed_hash, pow_hash, false)) { LOGWARN(3, "client " << static_cast(client->m_addrString) << " couldn't check share PoW"); share->m_result = SubmittedShare::Result::COULDNT_CHECK_POW; return; @@ -891,6 +891,13 @@ void StratumServer::on_share_found(uv_work_t* req) LOGWARN(4, "client " << static_cast(client->m_addrString) << " submitted a share with invalid PoW"); share->m_result = SubmittedShare::Result::INVALID_POW; share->m_score = BAD_SHARE_POINTS; + + // Calculate the same hash second time to check if it's an unstable hardware that caused this + hash pow_hash2; + if (pool->calculate_hash(blob, blob_size, height, seed_hash, pow_hash2, true) && (pow_hash2 != pow_hash)) { + LOGERR(0, "UNSTABLE HARDWARE DETECTED: Calculated the same hash twice, got different results: " << pow_hash << " != " << pow_hash2); + } + return; } diff --git a/tests/src/pool_block_tests.cpp b/tests/src/pool_block_tests.cpp index 66b2db3..2b76386 100644 --- a/tests/src/pool_block_tests.cpp +++ b/tests/src/pool_block_tests.cpp @@ -87,7 +87,7 @@ TEST(pool_block, deserialize) class RandomX_Hasher_Test : public RandomX_Hasher_Base { public: - bool calculate(const void* data, size_t size, uint64_t, const hash&, hash& result) override + bool calculate(const void* data, size_t size, uint64_t, const hash&, hash& result, bool force_light_mode) override { if (size == 76) { char buf[76 * 2 + 1];