Added "calc_pow" RPC support

This commit is contained in:
SChernykh 2021-11-20 11:51:22 +01:00
parent 2f659c8ecf
commit f9def6cb73
16 changed files with 201 additions and 28 deletions

View file

@ -1018,7 +1018,7 @@ void BlockTemplate::submit_sidechain_block(uint32_t template_id, uint32_t nonce,
}
hash pow_hash;
if (!check.get_pow_hash(m_pool->hasher(), m_seedHash, pow_hash)) {
if (!check.get_pow_hash(m_pool->hasher(), check.m_txinGenHeight, m_seedHash, pow_hash)) {
LOGERR(1, "PoW check failed for the sidechain block. Fix it! ");
}
else if (!check.m_difficulty.check_pow(pow_hash)) {

View file

@ -25,7 +25,7 @@ static constexpr char log_category_prefix[] = "JSONRPCRequest ";
namespace p2pool {
JSONRPCRequest::JSONRPCRequest(const char* address, int port, const char* req, CallbackBase* cb, CallbackBase* close_cb)
JSONRPCRequest::JSONRPCRequest(const char* address, int port, const char* req, CallbackBase* cb, CallbackBase* close_cb, uv_loop_t* loop)
: m_socket{}
, m_connect{}
, m_write{}
@ -38,7 +38,7 @@ JSONRPCRequest::JSONRPCRequest(const char* address, int port, const char* req, C
{
m_readBuf[0] = '\0';
uv_tcp_init(uv_default_loop_checked(), &m_socket);
uv_tcp_init(loop ? loop : uv_default_loop_checked(), &m_socket);
uv_tcp_nodelay(&m_socket, 1);
sockaddr_storage addr;

View file

@ -26,18 +26,18 @@ public:
static FORCEINLINE void call(const char* address, int port, const char* req, T&& cb)
{
// It will be deleted in one of the tcp callbacks eventually
JSONRPCRequest* r = new JSONRPCRequest(address, port, req, new Callback<T>(std::move(cb)), nullptr);
JSONRPCRequest* r = new JSONRPCRequest(address, port, req, new Callback<T>(std::move(cb)), nullptr, nullptr);
if (!r->m_valid) {
delete r;
}
}
template<typename T, typename U>
static FORCEINLINE void call(const char* address, int port, const char* req, T&& cb, U&& close_cb)
static FORCEINLINE void call(const char* address, int port, const char* req, T&& cb, U&& close_cb, uv_loop_t* loop = nullptr)
{
// It will be deleted in one of the tcp callbacks eventually
CallbackBase* close_callback = new Callback<U>(std::move(close_cb));
JSONRPCRequest* r = new JSONRPCRequest(address, port, req, new Callback<T>(std::move(cb)), close_callback);
JSONRPCRequest* r = new JSONRPCRequest(address, port, req, new Callback<T>(std::move(cb)), close_callback, loop);
if (!r->m_valid) {
constexpr char err[] = "internal error";
(*close_callback)(err, sizeof(err) - 1);
@ -63,7 +63,7 @@ private:
T m_cb;
};
JSONRPCRequest(const char* address, int port, const char* req, CallbackBase* cb, CallbackBase* close_cb);
JSONRPCRequest(const char* address, int port, const char* req, CallbackBase* cb, CallbackBase* close_cb, uv_loop_t* loop);
~JSONRPCRequest();
static void on_connect(uv_connect_t* req, int status);

View file

@ -39,6 +39,7 @@ static void usage()
"--stratum-api Enable /local/ path in api path for Stratum Server statistics\n"
"--no-cache Disable p2pool.cache\n"
"--no-color Disable colors in console output\n"
"--no-randomx Disable internal RandomX hasher: p2pool will use RPC calls to monerod to check PoW hashes\n"
"--help Show this help message\n\n"
"Example command line:\n\n"
"%s --host 127.0.0.1 --rpc-port 18081 --zmq-port 18083 --wallet YOUR_WALLET_ADDRESS --stratum 0.0.0.0:%d --p2p 0.0.0.0:%d\n\n",

View file

@ -110,7 +110,14 @@ p2pool::p2pool(int argc, char* argv[])
m_api = m_params->m_apiPath.empty() ? nullptr : new p2pool_api(m_params->m_apiPath, m_params->m_localStats);
m_sideChain = new SideChain(this, type);
m_hasher = new RandomX_Hasher(this);
if (m_params->m_disableRandomX) {
m_hasher = new RandomX_Hasher_RPC(this);
}
else {
m_hasher = new RandomX_Hasher(this);
}
m_blockTemplate = new BlockTemplate(this);
m_mempool = new Mempool();
m_consoleCommands = new ConsoleCommands(this);
@ -131,9 +138,9 @@ p2pool::~p2pool()
delete m_consoleCommands;
}
bool p2pool::calculate_hash(const void* data, size_t size, const hash& seed, hash& result)
bool p2pool::calculate_hash(const void* data, size_t size, uint64_t height, const hash& seed, hash& result)
{
return m_hasher->calculate(data, size, seed, result);
return m_hasher->calculate(data, size, height, seed, result);
}
uint64_t p2pool::get_seed_height(uint64_t height)
@ -811,10 +818,14 @@ void p2pool::parse_get_version_rpc(const char* data, size_t size)
return;
}
if (version < 0x30008) {
const uint64_t required = m_params->m_disableRandomX ? 0x30009 : 0x30008;
if (version < required) {
const uint64_t version_hi = version >> 16;
const uint64_t version_lo = version & 65535;
LOGERR(1, "monerod RPC v" << version_hi << '.' << version_lo << " is incompatible, update to RPC >= v3.8");
const uint64_t required_version_hi = required >> 16;
const uint64_t required_version_lo = required & 65535;
LOGERR(1, "monerod RPC v" << version_hi << '.' << version_lo << " is incompatible, update to RPC >= v" << required_version_hi << '.' << required_version_lo);
panic();
}

View file

@ -23,7 +23,7 @@
namespace p2pool {
struct Params;
class RandomX_Hasher;
class RandomX_Hasher_Base;
class BlockTemplate;
class Mempool;
class SideChain;
@ -51,8 +51,8 @@ public:
p2pool_api* api() const { return m_api; }
RandomX_Hasher* hasher() const { return m_hasher; }
bool calculate_hash(const void* data, size_t size, const hash& seed, hash& result);
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);
static uint64_t get_seed_height(uint64_t height);
bool get_seed(uint64_t height, hash& seed) const;
@ -97,7 +97,7 @@ private:
p2pool_api* m_api;
SideChain* m_sideChain;
RandomX_Hasher* m_hasher;
RandomX_Hasher_Base* m_hasher;
BlockTemplate* m_blockTemplate;
MinerData m_minerData;
bool m_updateSeed;

View file

@ -81,6 +81,10 @@ Params::Params(int argc, char* argv[])
if (strcmp(argv[i], "--no-color") == 0) {
log::CONSOLE_COLORS = false;
}
if (strcmp(argv[i], "--no-randomx") == 0) {
m_disableRandomX = true;
}
}
if (m_stratumAddresses.empty()) {

View file

@ -39,6 +39,7 @@ struct Params
std::string m_apiPath;
bool m_localStats = false;
bool m_blockCache = true;
bool m_disableRandomX = false;
};
} // namespace p2pool

View file

@ -225,7 +225,7 @@ void PoolBlock::serialize_sidechain_data()
writeVarint(m_cumulativeDifficulty.hi, m_sideChainData);
}
bool PoolBlock::get_pow_hash(RandomX_Hasher* hasher, 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)
{
alignas(8) uint8_t hashes[HASH_SIZE * 3];
@ -295,7 +295,7 @@ bool PoolBlock::get_pow_hash(RandomX_Hasher* hasher, const hash& seed_hash, hash
writeVarint(count, [&blob, &blob_size](uint8_t b) { blob[blob_size++] = b; });
return hasher->calculate(blob, blob_size, seed_hash, pow_hash);
return hasher->calculate(blob, blob_size, height, seed_hash, pow_hash);
}
} // namespace p2pool

View file

@ -28,7 +28,7 @@
namespace p2pool {
class RandomX_Hasher;
class RandomX_Hasher_Base;
class SideChain;
/*
@ -136,7 +136,7 @@ struct PoolBlock
void serialize_sidechain_data();
int deserialize(const uint8_t* data, size_t size, SideChain& sidechain);
bool get_pow_hash(RandomX_Hasher* hasher, 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);
};
} // namespace p2pool

View file

@ -22,6 +22,9 @@
#include "randomx.h"
#include "configuration.h"
#include "virtual_machine.hpp"
#include "json_rpc_request.h"
#include "json_parsers.h"
#include <rapidjson/document.h>
#include <thread>
static constexpr char log_category_prefix[] = "RandomX_Hasher ";
@ -302,7 +305,7 @@ void RandomX_Hasher::set_old_seed(const hash& seed)
LOGINFO(1, log::LightCyan() << "old cache updated");
}
bool RandomX_Hasher::calculate(const void* data, size_t size, const hash& seed, hash& result)
bool RandomX_Hasher::calculate(const void* data, size_t size, uint64_t /*height*/, const hash& seed, hash& result)
{
// First try to use the dataset if it's ready
if (uv_rwlock_tryrdlock(&m_datasetLock) == 0) {
@ -348,4 +351,113 @@ bool RandomX_Hasher::calculate(const void* data, size_t size, const hash& seed,
return false;
}
RandomX_Hasher_RPC::RandomX_Hasher_RPC(p2pool* pool)
: m_pool(pool)
, m_loopStopped(false)
, m_loopThread{}
{
int err = uv_loop_init(&m_loop);
if (err) {
LOGERR(1, "failed to create event loop, error " << uv_err_name(err));
panic();
}
uv_async_init(&m_loop, &m_shutdownAsync, on_shutdown);
uv_async_init(&m_loop, &m_kickTheLoopAsync, nullptr);
m_shutdownAsync.data = this;
uv_mutex_init_checked(&m_requestMutex);
uv_mutex_init_checked(&m_condMutex);
err = uv_cond_init(&m_cond);
if (err) {
LOGERR(1, "failed to create cond, error " << uv_err_name(err));
panic();
}
err = uv_thread_create(&m_loopThread, loop, this);
if (err) {
LOGERR(1, "failed to start event loop thread, error " << uv_err_name(err));
panic();
}
}
RandomX_Hasher_RPC::~RandomX_Hasher_RPC()
{
uv_async_send(&m_shutdownAsync);
using namespace std::chrono;
while (!m_loopStopped) {
std::this_thread::sleep_for(milliseconds(1));
}
uv_mutex_destroy(&m_requestMutex);
uv_mutex_destroy(&m_condMutex);
uv_cond_destroy(&m_cond);
LOGINFO(1, "stopped");
}
void RandomX_Hasher_RPC::loop(void* data)
{
LOGINFO(1, "event loop started");
RandomX_Hasher_RPC* hasher = static_cast<RandomX_Hasher_RPC*>(data);
uv_run(&hasher->m_loop, UV_RUN_DEFAULT);
uv_loop_close(&hasher->m_loop);
LOGINFO(1, "event loop stopped");
hasher->m_loopStopped = true;
}
bool RandomX_Hasher_RPC::calculate(const void* data_ptr, size_t size, uint64_t height, const hash& /*seed*/, hash& h)
{
MutexLock lock(m_requestMutex);
const uint8_t* data = reinterpret_cast<const uint8_t*>(data_ptr);
const uint8_t major_version = data[0];
char buf[log::Stream::BUF_SIZE + 1];
log::Stream s(buf);
s << "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"calc_pow\",\"params\":{\"major_version\":" << major_version <<
",\"height\":" << height <<
",\"block_blob\":\"" << log::hex_buf(data, size) << '"' <<
",\"seed_hash\":\"\"}}";
volatile int result = 0;
volatile bool done = false;
JSONRPCRequest::call(m_pool->params().m_host.c_str(), m_pool->params().m_rpcPort, buf,
[&result, &h](const char* data, size_t size)
{
rapidjson::Document doc;
if (doc.Parse(data, size).HasParseError() || !parseValue(doc, "result", h)) {
LOGWARN(3, "RPC calc_pow: invalid JSON response (parse error)");
result = -1;
return;
}
result = 1;
},
[this, &result, &done](const char* data, size_t size)
{
if (size > 0) {
LOGWARN(3, "RPC calc_pow: server returned error " << log::const_buf(data, size));
result = -1;
}
MutexLock lock2(m_condMutex);
done = true;
uv_cond_signal(&m_cond);
}, &m_loop);
uv_async_send(&m_kickTheLoopAsync);
{
MutexLock lock2(m_condMutex);
while (!done) {
uv_cond_wait(&m_cond, &m_condMutex);
}
}
return result > 0;
}
} // namespace p2pool

View file

@ -27,18 +27,29 @@ namespace p2pool {
class p2pool;
class RandomX_Hasher
class RandomX_Hasher_Base
{
public:
virtual ~RandomX_Hasher_Base() {}
virtual void set_seed_async(const hash&) {}
virtual void set_old_seed(const hash&) {}
virtual bool calculate(const void* data, size_t size, uint64_t height, const hash& seed, hash& result) = 0;
};
class RandomX_Hasher : public RandomX_Hasher_Base
{
public:
explicit RandomX_Hasher(p2pool* pool);
~RandomX_Hasher();
void set_seed_async(const hash& seed);
void set_seed_async(const hash& seed) override;
void set_seed(const hash& seed);
void set_old_seed(const hash& seed);
void set_old_seed(const hash& seed) override;
bool calculate(const void* data, size_t size, const hash& seed, hash& result);
bool calculate(const void* data, size_t size, uint64_t height, const hash& seed, hash& result) override;
private:
@ -70,4 +81,36 @@ private:
std::atomic<uint32_t> m_setSeedCounter;
};
class RandomX_Hasher_RPC : public RandomX_Hasher_Base
{
public:
explicit RandomX_Hasher_RPC(p2pool* pool);
~RandomX_Hasher_RPC();
bool calculate(const void* data, size_t size, uint64_t height, const hash& seed, hash& result) override;
private:
static void loop(void* data);
p2pool* m_pool;
uv_mutex_t m_requestMutex;
uv_loop_t m_loop;
volatile bool m_loopStopped;
uv_thread_t m_loopThread;
uv_mutex_t m_condMutex;
uv_cond_t m_cond;
uv_async_t m_shutdownAsync;
uv_async_t m_kickTheLoopAsync;
static void on_shutdown(uv_async_t* async)
{
RandomX_Hasher_RPC* server = reinterpret_cast<RandomX_Hasher_RPC*>(async->data);
uv_close(reinterpret_cast<uv_handle_t*>(&server->m_shutdownAsync), nullptr);
uv_close(reinterpret_cast<uv_handle_t*>(&server->m_kickTheLoopAsync), nullptr);
}
};
} // namespace p2pool

View file

@ -429,7 +429,7 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector<hash>& missing_
}
hash pow_hash;
if (!block.get_pow_hash(m_pool->hasher(), seed, pow_hash)) {
if (!block.get_pow_hash(m_pool->hasher(), block.m_txinGenHeight, seed, pow_hash)) {
LOGWARN(3, "add_external_block: couldn't get PoW hash for height = " << block.m_sidechainHeight << ", mainchain height " << block.m_txinGenHeight << ". Ignoring it.");
unsee_block(block);
return true;

View file

@ -661,7 +661,7 @@ void StratumServer::on_share_found(uv_work_t* req)
}
hash pow_hash;
if (!pool->calculate_hash(blob, blob_size, seed_hash, pow_hash)) {
if (!pool->calculate_hash(blob, blob_size, height, seed_hash, pow_hash)) {
LOGWARN(3, "client " << static_cast<char*>(client->m_addrString) << " couldn't check share PoW");
share->m_result = SubmittedShare::Result::COULDNT_CHECK_POW;
return;

View file

@ -564,6 +564,7 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::loop(void* data)
TCPServer* server = static_cast<TCPServer*>(data);
uv_run(&server->m_loop, UV_RUN_DEFAULT);
uv_loop_close(&server->m_loop);
LOGINFO(1, "event loop stopped");
server->m_loopStopped = true;
}

View file

@ -91,7 +91,7 @@ TEST(pool_block, deserialize)
hasher.set_seed(seed);
hash pow_hash;
ASSERT_EQ(b.get_pow_hash(&hasher, seed, pow_hash), true);
ASSERT_EQ(b.get_pow_hash(&hasher, 0, seed, pow_hash), true);
std::stringstream s;
s << pow_hash;