mirror of
https://github.com/SChernykh/p2pool.git
synced 2024-12-22 19:39:22 +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).
|
||||
`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) {
|
||||
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_port(80)
|
||||
, m_auxAddress(address)
|
||||
, m_ping(0.0)
|
||||
, m_pool(pool)
|
||||
, m_loop{}
|
||||
, m_loopThread{}
|
||||
|
@ -99,11 +100,16 @@ void MergeMiningClient::on_timer()
|
|||
|
||||
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,
|
||||
[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 (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);
|
||||
if (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 << '"'
|
||||
<< ",\"height\":" << height
|
||||
<< ",\"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) {
|
||||
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;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
|
@ -227,7 +235,7 @@ bool MergeMiningClient::parse_merge_mining_get_job(const char* data, size_t size
|
|||
return err("invalid aux_diff");
|
||||
}
|
||||
|
||||
m_auxBlob = result["aux_blob"].GetString();
|
||||
m_auxBlob = std::move(aux_blob);
|
||||
m_auxHash = h;
|
||||
m_auxDiff.lo = result["aux_diff"].GetUint64();
|
||||
m_auxDiff.hi = 0;
|
||||
|
@ -235,6 +243,73 @@ bool MergeMiningClient::parse_merge_mining_get_job(const char* data, size_t size
|
|||
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)
|
||||
{
|
||||
LOGINFO(1, "event loop started");
|
||||
|
|
|
@ -29,6 +29,8 @@ public:
|
|||
MergeMiningClient(p2pool* pool, const std::string& host, const std::string& address);
|
||||
~MergeMiningClient();
|
||||
|
||||
void merge_mining_submit_solution(const std::vector<uint8_t>& blob, const std::vector<hash>& merkle_proof);
|
||||
|
||||
private:
|
||||
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);
|
||||
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;
|
||||
uint32_t m_port;
|
||||
|
||||
std::string m_auxAddress;
|
||||
std::string m_auxBlob;
|
||||
std::vector<uint8_t> m_auxBlob;
|
||||
hash m_auxHash;
|
||||
difficulty_type m_auxDiff;
|
||||
|
||||
hash m_chainID;
|
||||
double m_ping;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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> 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); } };
|
||||
|
|
Loading…
Reference in a new issue