mirror of
https://github.com/SChernykh/p2pool.git
synced 2024-12-23 03:49:23 +00:00
Merge mining RPC: added merge_mining_submit_solution
This commit is contained in:
parent
40b2c2a858
commit
9eab833f66
5 changed files with 118 additions and 8 deletions
|
@ -100,3 +100,12 @@ Note that `merkle_proof` only contains a vector of 32-byte hashes for `aux_hash`
|
||||||
|
|
||||||
`aux_nonce` and `n_aux_chains` can be extracted from the Merkle tree parameters (see above).
|
`aux_nonce` and `n_aux_chains` can be extracted from the Merkle tree parameters (see above).
|
||||||
`merkle_root_hash` can be extracted from the merge mining tag (see above).
|
`merkle_root_hash` can be extracted from the merge mining tag (see above).
|
||||||
|
|
||||||
|
Response: a JSON containing these fields:
|
||||||
|
Field|Description
|
||||||
|
-|-
|
||||||
|
`status`|Block submit status
|
||||||
|
|
||||||
|
Example response 1: `{"jsonrpc":"2.0","id":"0","result":{"status":"accepted"}}`
|
||||||
|
|
||||||
|
Example response 2: `{"jsonrpc":"2.0","id":"0","error":"something went wrong"}`
|
||||||
|
|
|
@ -499,7 +499,9 @@ void Call(const std::string& address, int port, const std::string& req, const st
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
LOGERR(1, "JSON RPC \"" << req << "\" failed");
|
static constexpr char err[] = "CallOnLoop failed";
|
||||||
|
LOGERR(1, err);
|
||||||
|
(*close_cb)(err, sizeof(err) - 1, 0.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ MergeMiningClient::MergeMiningClient(p2pool* pool, const std::string& host, cons
|
||||||
: m_host(host)
|
: m_host(host)
|
||||||
, m_port(80)
|
, m_port(80)
|
||||||
, m_auxAddress(address)
|
, m_auxAddress(address)
|
||||||
|
, m_ping(0.0)
|
||||||
, m_pool(pool)
|
, m_pool(pool)
|
||||||
, m_loop{}
|
, m_loop{}
|
||||||
, m_loopThread{}
|
, m_loopThread{}
|
||||||
|
@ -99,11 +100,16 @@ void MergeMiningClient::on_timer()
|
||||||
|
|
||||||
void MergeMiningClient::merge_mining_get_chain_id()
|
void MergeMiningClient::merge_mining_get_chain_id()
|
||||||
{
|
{
|
||||||
constexpr char req[] = "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"merge_mining_get_chain_id\"}";
|
const std::string req = "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"merge_mining_get_chain_id\"}";
|
||||||
|
|
||||||
JSONRPCRequest::call(m_host, m_port, req, std::string(), m_pool->params().m_socks5Proxy,
|
JSONRPCRequest::call(m_host, m_port, req, std::string(), m_pool->params().m_socks5Proxy,
|
||||||
[this](const char* data, size_t size, double) {
|
[this](const char* data, size_t size, double ping) {
|
||||||
if (parse_merge_mining_get_chain_id(data, size)) {
|
if (parse_merge_mining_get_chain_id(data, size)) {
|
||||||
|
if (ping > 0.0) {
|
||||||
|
m_ping = ping;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chain ID received successfully, we can start polling for new mining jobs now
|
||||||
const int err = uv_timer_start(&m_timer, on_timer, 0, 500);
|
const int err = uv_timer_start(&m_timer, on_timer, 0, 500);
|
||||||
if (err) {
|
if (err) {
|
||||||
LOGERR(1, "failed to start timer, error " << uv_err_name(err));
|
LOGERR(1, "failed to start timer, error " << uv_err_name(err));
|
||||||
|
@ -167,9 +173,9 @@ void MergeMiningClient::merge_mining_get_job(uint64_t height, const hash& prev_i
|
||||||
<< ",\"aux_hash\":\"" << aux_hash << '"'
|
<< ",\"aux_hash\":\"" << aux_hash << '"'
|
||||||
<< ",\"height\":" << height
|
<< ",\"height\":" << height
|
||||||
<< ",\"prev_id\":\"" << prev_id << '"'
|
<< ",\"prev_id\":\"" << prev_id << '"'
|
||||||
<< "}}\0";
|
<< "}}";
|
||||||
|
|
||||||
JSONRPCRequest::call(m_host, m_port, buf, std::string(), m_pool->params().m_socks5Proxy,
|
JSONRPCRequest::call(m_host, m_port, std::string(buf, s.m_pos), std::string(), m_pool->params().m_socks5Proxy,
|
||||||
[this](const char* data, size_t size, double) {
|
[this](const char* data, size_t size, double) {
|
||||||
parse_merge_mining_get_job(data, size);
|
parse_merge_mining_get_job(data, size);
|
||||||
},
|
},
|
||||||
|
@ -219,7 +225,9 @@ bool MergeMiningClient::parse_merge_mining_get_job(const char* data, size_t size
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result.HasMember("aux_blob") || !result["aux_blob"].IsString()) {
|
std::vector<uint8_t> aux_blob;
|
||||||
|
|
||||||
|
if (!result.HasMember("aux_blob") || !result["aux_blob"].IsString() || !from_hex(result["aux_blob"].GetString(), result["aux_blob"].GetStringLength(), aux_blob)) {
|
||||||
return err("invalid aux_blob");
|
return err("invalid aux_blob");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,7 +235,7 @@ bool MergeMiningClient::parse_merge_mining_get_job(const char* data, size_t size
|
||||||
return err("invalid aux_diff");
|
return err("invalid aux_diff");
|
||||||
}
|
}
|
||||||
|
|
||||||
m_auxBlob = result["aux_blob"].GetString();
|
m_auxBlob = std::move(aux_blob);
|
||||||
m_auxHash = h;
|
m_auxHash = h;
|
||||||
m_auxDiff.lo = result["aux_diff"].GetUint64();
|
m_auxDiff.lo = result["aux_diff"].GetUint64();
|
||||||
m_auxDiff.hi = 0;
|
m_auxDiff.hi = 0;
|
||||||
|
@ -235,6 +243,73 @@ bool MergeMiningClient::parse_merge_mining_get_job(const char* data, size_t size
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MergeMiningClient::merge_mining_submit_solution(const std::vector<uint8_t>& blob, const std::vector<hash>& merkle_proof)
|
||||||
|
{
|
||||||
|
std::vector<char> buf((m_auxBlob.size() + HASH_SIZE + blob.size()) * 2 + merkle_proof.size() * (HASH_SIZE * 2 + 3) + 256);
|
||||||
|
log::Stream s(buf.data(), buf.size());
|
||||||
|
|
||||||
|
s << "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"merge_mining_submit_solution\",\"params\":{"
|
||||||
|
<< "\"aux_blob\":\"" << log::hex_buf(m_auxBlob.data(), m_auxBlob.size()) << '"'
|
||||||
|
<< ",\"aux_hash\":\"" << m_auxHash << '"'
|
||||||
|
<< ",\"blob\":" << log::hex_buf(blob.data(), blob.size())
|
||||||
|
<< ",\"merkle_proof\":[";
|
||||||
|
|
||||||
|
for (size_t i = 0, n = merkle_proof.size(); i < n; ++i) {
|
||||||
|
if (i > 0) {
|
||||||
|
s << ',';
|
||||||
|
}
|
||||||
|
s << '"' << merkle_proof[i] << '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
s << "]}}";
|
||||||
|
|
||||||
|
JSONRPCRequest::call(m_host, m_port, std::string(buf.data(), s.m_pos), std::string(), m_pool->params().m_socks5Proxy,
|
||||||
|
[this](const char* data, size_t size, double) {
|
||||||
|
parse_merge_mining_submit_solution(data, size);
|
||||||
|
},
|
||||||
|
[](const char* data, size_t size, double) {
|
||||||
|
if (size > 0) {
|
||||||
|
LOGERR(1, "couldn't submit merge mining solution, error " << log::const_buf(data, size));
|
||||||
|
}
|
||||||
|
}, &m_loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MergeMiningClient::parse_merge_mining_submit_solution(const char* data, size_t size)
|
||||||
|
{
|
||||||
|
auto err = [](const char* msg) {
|
||||||
|
LOGWARN(1, "merge_mining_submit_solution RPC call failed: " << msg);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
rapidjson::Document doc;
|
||||||
|
|
||||||
|
if (doc.Parse(data, size).HasParseError() || !doc.IsObject()) {
|
||||||
|
return err("parsing failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doc.HasMember("error")) {
|
||||||
|
return err(doc["error"].IsString() ? doc["error"].GetString() : "an unknown error occurred");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& result = doc["result"];
|
||||||
|
|
||||||
|
if (!result.IsObject()) {
|
||||||
|
return err("couldn't parse result");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result.HasMember("status") || !result["status"].IsString()) {
|
||||||
|
return err("invalid status");
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* status = result["status"].GetString();
|
||||||
|
LOGINFO(0, log::LightGreen() << "merge_mining_submit_solution: " << status);
|
||||||
|
|
||||||
|
// Get new mining job
|
||||||
|
on_timer();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void MergeMiningClient::loop(void* data)
|
void MergeMiningClient::loop(void* data)
|
||||||
{
|
{
|
||||||
LOGINFO(1, "event loop started");
|
LOGINFO(1, "event loop started");
|
||||||
|
|
|
@ -29,6 +29,8 @@ public:
|
||||||
MergeMiningClient(p2pool* pool, const std::string& host, const std::string& address);
|
MergeMiningClient(p2pool* pool, const std::string& host, const std::string& address);
|
||||||
~MergeMiningClient();
|
~MergeMiningClient();
|
||||||
|
|
||||||
|
void merge_mining_submit_solution(const std::vector<uint8_t>& blob, const std::vector<hash>& merkle_proof);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void loop(void* data);
|
static void loop(void* data);
|
||||||
|
|
||||||
|
@ -41,15 +43,18 @@ private:
|
||||||
void merge_mining_get_job(uint64_t height, const hash& prev_id, const std::string& address, const hash& aux_hash);
|
void merge_mining_get_job(uint64_t height, const hash& prev_id, const std::string& address, const hash& aux_hash);
|
||||||
bool parse_merge_mining_get_job(const char* data, size_t size);
|
bool parse_merge_mining_get_job(const char* data, size_t size);
|
||||||
|
|
||||||
|
bool parse_merge_mining_submit_solution(const char* data, size_t size);
|
||||||
|
|
||||||
std::string m_host;
|
std::string m_host;
|
||||||
uint32_t m_port;
|
uint32_t m_port;
|
||||||
|
|
||||||
std::string m_auxAddress;
|
std::string m_auxAddress;
|
||||||
std::string m_auxBlob;
|
std::vector<uint8_t> m_auxBlob;
|
||||||
hash m_auxHash;
|
hash m_auxHash;
|
||||||
difficulty_type m_auxDiff;
|
difficulty_type m_auxDiff;
|
||||||
|
|
||||||
hash m_chainID;
|
hash m_chainID;
|
||||||
|
double m_ping;
|
||||||
|
|
||||||
p2pool* m_pool;
|
p2pool* m_pool;
|
||||||
|
|
||||||
|
|
19
src/util.h
19
src/util.h
|
@ -118,6 +118,25 @@ static FORCEINLINE bool from_hex(const char* s, size_t len, hash& h) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FORCEINLINE bool from_hex(const char* s, size_t len, std::vector<uint8_t>& data) {
|
||||||
|
if (len % 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> result(len / 2);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < HASH_SIZE; ++i) {
|
||||||
|
uint8_t d[2];
|
||||||
|
if (!from_hex(s[i * 2], d[0]) || !from_hex(s[i * 2 + 1], d[1])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
result[i] = (d[0] << 4) | d[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
data = std::move(result);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T, bool is_signed> struct is_negative_helper {};
|
template<typename T, bool is_signed> struct is_negative_helper {};
|
||||||
template<typename T> struct is_negative_helper<T, false> { static FORCEINLINE bool value(T) { return false; } };
|
template<typename T> struct is_negative_helper<T, false> { static FORCEINLINE bool value(T) { return false; } };
|
||||||
template<typename T> struct is_negative_helper<T, true> { static FORCEINLINE bool value(T x) { return (x < 0); } };
|
template<typename T> struct is_negative_helper<T, true> { static FORCEINLINE bool value(T x) { return (x < 0); } };
|
||||||
|
|
Loading…
Reference in a new issue