diff --git a/docs/COMMAND_LINE.MD b/docs/COMMAND_LINE.MD index 5abf070..03a4248 100644 --- a/docs/COMMAND_LINE.MD +++ b/docs/COMMAND_LINE.MD @@ -29,6 +29,7 @@ --no-upnp Disable UPnP port forwarding --no-igd An alias for --no-upnp --upnp-stratum Port forward Stratum port (it's not forwarded by default) +--merge-mine IP:port and wallet address for another blockchain to merge mine with --version Print p2pool's version and build details ``` @@ -50,3 +51,9 @@ In this example, you have local Monero host running on ports 18081/18083 (RPC/zm ``` p2pool.exe --host 127.0.0.1 --host xmr1.rs.me --rpc-port 18089 --zmq-port 18084 --host xmr2.rs.me --host xmr3.rs.me --wallet YOUR_WALLET_ADDRESS ``` + +### Merge mining + +``` +p2pool.exe --wallet YOUR_WALLET_ADDRESS --merge-mine IP:port YOUR_WALLET_ADDRESS_ON_ANOTHER_BLOCKCHAIN +``` diff --git a/docs/MERGE_MINING.MD b/docs/MERGE_MINING.MD index 223c721..a58f0c1 100644 --- a/docs/MERGE_MINING.MD +++ b/docs/MERGE_MINING.MD @@ -86,6 +86,8 @@ Example response 2: `{"jsonrpc":"2.0","id":"0","result":{}}` ### merge_mining_submit_solution +Example request: `{"jsonrpc":"2.0","id":"0","method":"merge_mining_submit_solution","params":{"aux_blob":"4c6f72656d20697073756d","aux_hash":"f6952d6eef555ddd87aca66e56b91530222d6e318414816f3ba7cf5bf694bf0f","blob":"...","merkle_proof":["hash1","hash2","hash3"]}}` + Request: a JSON containing these fields: Field|Description -|- diff --git a/src/common.h b/src/common.h index 7ab2c6f..db1c894 100644 --- a/src/common.h +++ b/src/common.h @@ -385,6 +385,8 @@ struct TxMempoolData struct AuxChainData { + FORCEINLINE AuxChainData(const hash& _id, const hash& _data, const difficulty_type& _difficulty) : unique_id(_id), data(_data), difficulty(_difficulty) {} + hash unique_id; hash data; difficulty_type difficulty; diff --git a/src/keccak.h b/src/keccak.h index 145df55..7274d61 100644 --- a/src/keccak.h +++ b/src/keccak.h @@ -42,18 +42,6 @@ FORCEINLINE void keccak(const uint8_t* in, int inlen, uint8_t (&md)[N]) template FORCEINLINE void keccak_custom(T&& in, int inlen, uint8_t* md, int mdlen) { - // TODO: remove after testing -#if 0 - if (inlen > 100) { - printf("\nkeccak_custom %d", inlen); - for (int i = 0; i < inlen; ++i) { - if ((i & 31) == 0) printf("\n"); - printf("%02X ", static_cast(in(i))); - } - printf("\n"); - } -#endif - uint64_t st[25] = {}; const int rsiz = sizeof(st) == mdlen ? KeccakParams::HASH_DATA_AREA : 200 - 2 * mdlen; diff --git a/src/main.cpp b/src/main.cpp index c1f9d12..3d3d2c4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -62,6 +62,7 @@ void p2pool_usage() "--no-igd An alias for --no-upnp\n" "--upnp-stratum Port forward Stratum port (it's not forwarded by default)\n" #endif + "--merge-mine IP:port and wallet address for another blockchain to merge mine with" "--version Print p2pool's version and build details\n" "--help Show this help message\n\n" "Example command line:\n\n" diff --git a/src/merge_mining_client.cpp b/src/merge_mining_client.cpp index b078909..340d86a 100644 --- a/src/merge_mining_client.cpp +++ b/src/merge_mining_client.cpp @@ -27,10 +27,10 @@ LOG_CATEGORY(MergeMiningClient) namespace p2pool { -MergeMiningClient::MergeMiningClient(p2pool* pool, const std::string& host, const std::string& address) +MergeMiningClient::MergeMiningClient(p2pool* pool, const std::string& host, const std::string& wallet) : m_host(host) , m_port(80) - , m_auxAddress(address) + , m_auxWallet(wallet) , m_ping(0.0) , m_pool(pool) , m_loop{} @@ -42,7 +42,7 @@ MergeMiningClient::MergeMiningClient(p2pool* pool, const std::string& host, cons const size_t k = host.find_last_of(':'); if (k != std::string::npos) { m_host = host.substr(0, k); - m_port = strtoul(host.substr(k + 1).c_str(), nullptr, 10); + m_port = std::stoul(host.substr(k + 1), nullptr, 10); } if (m_host.empty() || (m_port == 0) || (m_port >= 65536)) { @@ -95,7 +95,7 @@ MergeMiningClient::~MergeMiningClient() void MergeMiningClient::on_timer() { MinerData data = m_pool->miner_data(); - merge_mining_get_job(data.height, data.prev_id, m_auxAddress, m_auxHash); + merge_mining_get_job(data.height, data.prev_id, m_auxWallet, m_auxHash); } void MergeMiningClient::merge_mining_get_chain_id() @@ -157,7 +157,7 @@ bool MergeMiningClient::parse_merge_mining_get_chain_id(const char* data, size_t return true; } -void MergeMiningClient::merge_mining_get_job(uint64_t height, const hash& prev_id, const std::string& address, const hash& aux_hash) +void MergeMiningClient::merge_mining_get_job(uint64_t height, const hash& prev_id, const std::string& wallet, const hash& aux_hash) { if (m_getJobRunning) { return; @@ -169,7 +169,7 @@ void MergeMiningClient::merge_mining_get_job(uint64_t height, const hash& prev_i log::Stream s(buf); s << "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"merge_mining_get_job\",\"params\":{" - << "\"address\":\"" << address << '"' + << "\"address\":\"" << wallet << '"' << ",\"aux_hash\":\"" << aux_hash << '"' << ",\"height\":" << height << ",\"prev_id\":\"" << prev_id << '"' diff --git a/src/merge_mining_client.h b/src/merge_mining_client.h index 54ca44f..14f2f17 100644 --- a/src/merge_mining_client.h +++ b/src/merge_mining_client.h @@ -26,11 +26,15 @@ class p2pool; class MergeMiningClient { public: - MergeMiningClient(p2pool* pool, const std::string& host, const std::string& address); + MergeMiningClient(p2pool* pool, const std::string& host, const std::string& wallet); ~MergeMiningClient(); void merge_mining_submit_solution(const std::vector& blob, const std::vector& merkle_proof); + FORCEINLINE const hash& aux_id() const { return m_chainID; } + FORCEINLINE const hash& aux_data() const { return m_auxHash; } + FORCEINLINE const difficulty_type& aux_diff() const { return m_auxDiff; } + private: static void loop(void* data); @@ -40,7 +44,7 @@ private: void merge_mining_get_chain_id(); bool parse_merge_mining_get_chain_id(const char* data, size_t size); - 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& wallet, 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); @@ -48,7 +52,7 @@ private: std::string m_host; uint32_t m_port; - std::string m_auxAddress; + std::string m_auxWallet; std::vector m_auxBlob; hash m_auxHash; difficulty_type m_auxDiff; diff --git a/src/p2pool.cpp b/src/p2pool.cpp index cb52eae..5b88d74 100644 --- a/src/p2pool.cpp +++ b/src/p2pool.cpp @@ -37,6 +37,7 @@ #include "pool_block.h" #include "keccak.h" #include "merkle.h" +#include "merge_mining_client.h" #include #include #include @@ -186,6 +187,11 @@ p2pool::~p2pool() } #endif + for (const MergeMiningClient* c : m_mergeMiningClients) { + delete c; + } + m_mergeMiningClients.clear(); + uv_rwlock_destroy(&m_mainchainLock); uv_rwlock_destroy(&m_minerDataLock); uv_rwlock_destroy(&m_ZMQReaderLock); @@ -334,6 +340,25 @@ void p2pool::handle_miner_data(MinerData& data) cleanup_mainchain_data(data.height); } + data.aux_chains.clear(); + + if (!m_mergeMiningClients.empty()) { + data.aux_chains.reserve(m_mergeMiningClients.size()); + + std::vector tmp; + tmp.reserve(m_mergeMiningClients.size()); + + for (const MergeMiningClient* c : m_mergeMiningClients) { + data.aux_chains.emplace_back(c->aux_id(), c->aux_data(), c->aux_diff()); + tmp.emplace_back(c->aux_data()); + } + + if (!find_aux_nonce(tmp, data.aux_nonce)) { + LOGERR(1, "Failed to find the aux nonce for merge mining. Merge mining will be off this round."); + data.aux_chains.clear(); + } + } + // TODO: remove after testing #if 0 { @@ -840,6 +865,10 @@ void p2pool::download_block_headers(uint64_t current_height) } } + for (const auto& h : m_params->m_mergeMiningHosts) { + m_mergeMiningClients.push_back(new MergeMiningClient(this, h.m_host, h.m_wallet)); + } + m_startupFinished = true; } } @@ -1136,11 +1165,10 @@ void p2pool::get_miner_data(bool retry) std::this_thread::sleep_for(std::chrono::milliseconds(1000)); m_getMinerDataPending = false; get_miner_data(); + return; } } - else { - m_getMinerDataPending = false; - } + m_getMinerDataPending = false; }); } diff --git a/src/p2pool.h b/src/p2pool.h index 9f16512..3cccabd 100644 --- a/src/p2pool.h +++ b/src/p2pool.h @@ -33,6 +33,7 @@ class Miner; class ConsoleCommands; class p2pool_api; class ZMQReader; +class MergeMiningClient; struct PoolBlock; class p2pool : public MinerCallbackHandler, public nocopy_nomove @@ -226,6 +227,8 @@ private: mutable uv_rwlock_t m_ZMQReaderLock; ZMQReader* m_ZMQReader = nullptr; + std::vector m_mergeMiningClients; + hash m_getMinerDataHash; bool m_getMinerDataPending = false; diff --git a/src/params.cpp b/src/params.cpp index de5ed45..e0d508e 100644 --- a/src/params.cpp +++ b/src/params.cpp @@ -189,6 +189,12 @@ Params::Params(int argc, char* const argv[]) } #endif + if ((strcmp(argv[i], "--merge-mine") == 0) && (i + 2 < argc)) { + m_mergeMiningHosts.emplace_back(argv[i + 1], argv[i + 2]); + i += 2; + ok = true; + } + if (!ok) { fprintf(stderr, "Unknown command line parameter %s\n\n", argv[i]); p2pool_usage(); diff --git a/src/params.h b/src/params.h index a23e7aa..0458434 100644 --- a/src/params.h +++ b/src/params.h @@ -53,6 +53,16 @@ struct Params std::vector m_hosts; + struct MergeMiningHost + { + MergeMiningHost(const char* host, const char* wallet) : m_host(host), m_wallet(wallet) {} + + std::string m_host; + std::string m_wallet; + }; + + std::vector m_mergeMiningHosts; + bool m_lightMode = false; Wallet m_wallet{ nullptr }; std::string m_stratumAddresses; diff --git a/src/tcp_server.cpp b/src/tcp_server.cpp index e276a74..f11b76f 100644 --- a/src/tcp_server.cpp +++ b/src/tcp_server.cpp @@ -113,7 +113,7 @@ void TCPServer::parse_address_list_internal(const std::string& address_list, Cal } } - const int port = strtol(address.substr(k2 + 1).c_str(), nullptr, 10); + const uint32_t port = std::stoul(address.substr(k2 + 1), nullptr, 10); if ((port > 0) && (port < 65536)) { callback(is_v6, address, ip, port); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 173369f..00f640d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -53,6 +53,7 @@ set(SOURCES ../src/log.cpp ../src/memory_leak_debug.cpp ../src/mempool.cpp + ../src/merge_mining_client.cpp ../src/merkle.cpp ../src/miner.cpp ../src/p2p_server.cpp