Skip to content

Commit 164ee0e

Browse files
committed
Build-time versioning, public IP auto-detect, JSON-RPC explorer adapter
Version: - Inject version from git describe --tags at build time via CMake - Binary shows exact tag + commit: "c2pool/0.1.0-alpha-5-g4941a3ba" - No runtime GitHub fetch needed (requires HTTPS) Public IP auto-detection: - When external_ip not configured, fetch from ifconfig.me on startup - Runs on detached thread (non-blocking) - Dashboard stratum URL and miner config show real public IP Explorer JSON-RPC adapter: - Add getblockchaininfo, getblockhash, getblock, getmempoolinfo, getrawmempool to the JSON-RPC handler - Python explorer.py can now talk to c2pool as if it were a daemon - Accept both JSON-RPC 1.0 and 2.0 (auto-upgrade 1.0 to 2.0)
1 parent 4941a3b commit 164ee0e

4 files changed

Lines changed: 128 additions & 6 deletions

File tree

src/c2pool/CMakeLists.txt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,24 @@ target_link_libraries(c2pool_node_enhanced
5858
nlohmann_json::nlohmann_json
5959
)
6060

61+
# Inject version from git at build time
62+
execute_process(
63+
COMMAND git describe --tags --always
64+
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
65+
OUTPUT_VARIABLE C2POOL_GIT_VERSION
66+
OUTPUT_STRIP_TRAILING_WHITESPACE
67+
ERROR_QUIET
68+
)
69+
if(NOT C2POOL_GIT_VERSION)
70+
set(C2POOL_GIT_VERSION "0.1.0-alpha")
71+
endif()
72+
# Strip leading 'v'
73+
string(REGEX REPLACE "^v" "" C2POOL_GIT_VERSION "${C2POOL_GIT_VERSION}")
74+
6175
# Main C2Pool Enhanced Application (refactored with mining_shares/p2p_shares separation)
6276
add_executable(c2pool c2pool_refactored.cpp)
63-
target_link_libraries(c2pool
77+
target_compile_definitions(c2pool PRIVATE C2POOL_VERSION="${C2POOL_GIT_VERSION}")
78+
target_link_libraries(c2pool
6479
c2pool_node_enhanced
6580
c2pool_payout
6681
c2pool_merged_mining

src/c2pool/c2pool_refactored.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,6 +1363,13 @@ int main(int argc, char* argv[]) {
13631363
web_server.get_mining_interface()->set_p2p_port(static_cast<uint16_t>(p2p_port));
13641364
if (!external_ip.empty())
13651365
web_server.get_mining_interface()->set_external_ip(external_ip);
1366+
#ifdef C2POOL_VERSION
1367+
web_server.get_mining_interface()->set_pool_version(
1368+
"c2pool/" C2POOL_VERSION);
1369+
#endif
1370+
// Auto-detect public IP from external services
1371+
// (non-blocking, detached threads). Only fetches if not configured.
1372+
web_server.get_mining_interface()->auto_detect_external_info();
13661373
web_server.set_dashboard_dir(dashboard_dir);
13671374
if (!analytics_id.empty())
13681375
web_server.set_analytics_id(analytics_id);

src/core/web_server.cpp

Lines changed: 100 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -676,13 +676,19 @@ void HttpSession::process_request()
676676
response_body = rest_result.dump();
677677
}
678678
else if (request_.method() == http::verb::post) {
679-
// Handle JSON-RPC POST request
679+
// Handle JSON-RPC POST request.
680+
// Accept both 1.0 and 2.0 — upgrade 1.0 to 2.0 for the library.
680681
std::string request_body = request_.body();
681-
LOG_INFO << "Received JSON-RPC request: " << request_body;
682-
682+
{
683+
auto pos = request_body.find("\"1.0\"");
684+
if (pos != std::string::npos) {
685+
auto ctx = request_body.rfind("jsonrpc", pos);
686+
if (ctx != std::string::npos && pos - ctx < 15)
687+
request_body.replace(pos, 5, "\"2.0\"");
688+
}
689+
}
690+
683691
response_body = mining_interface_->HandleRequest(request_body);
684-
685-
LOG_INFO << "Sending JSON-RPC response: " << response_body;
686692
}
687693
else {
688694
response.result(http::status::method_not_allowed);
@@ -847,6 +853,42 @@ void MiningInterface::setup_methods()
847853
Add("getmessageblob", jsonrpccxx::MethodHandle([this](const nlohmann::json& params) -> nlohmann::json {
848854
return getmessageblob();
849855
}));
856+
857+
// Explorer JSON-RPC adapter — allows Python explorer to talk to c2pool
858+
// as if it were a standard Bitcoin/Litecoin daemon.
859+
Add("getblockchaininfo", jsonrpccxx::MethodHandle([this](const nlohmann::json& params) -> nlohmann::json {
860+
if (has_explorer_chaininfo_fn())
861+
return call_explorer_chaininfo("ltc");
862+
return nlohmann::json{{"error", "explorer not enabled"}};
863+
}));
864+
865+
Add("getblockhash", jsonrpccxx::MethodHandle([this](const nlohmann::json& params) -> nlohmann::json {
866+
if (!has_explorer_blockhash_fn() || params.empty())
867+
return nullptr;
868+
uint32_t h = params[0].get<uint32_t>();
869+
return call_explorer_blockhash(h, "ltc");
870+
}));
871+
872+
Add("getblock", jsonrpccxx::MethodHandle([this](const nlohmann::json& params) -> nlohmann::json {
873+
if (!has_explorer_getblock_fn() || params.empty())
874+
return nullptr;
875+
std::string hash = params[0].get<std::string>();
876+
return call_explorer_getblock(hash, "ltc");
877+
}));
878+
879+
Add("getmempoolinfo", jsonrpccxx::MethodHandle([this](const nlohmann::json& params) -> nlohmann::json {
880+
if (has_explorer_mempoolinfo_fn())
881+
return call_explorer_mempoolinfo("ltc");
882+
return nlohmann::json::object();
883+
}));
884+
885+
Add("getrawmempool", jsonrpccxx::MethodHandle([this](const nlohmann::json& params) -> nlohmann::json {
886+
if (has_explorer_rawmempool_fn()) {
887+
bool verbose = (!params.empty() && params[0].get<bool>());
888+
return call_explorer_rawmempool("ltc", verbose, 500);
889+
}
890+
return nlohmann::json::array();
891+
}));
850892
}
851893

852894
void MiningInterface::load_transition_blobs(const std::string& dir_path)
@@ -4674,6 +4716,59 @@ nlohmann::json MiningInterface::rest_stale_rates()
46744716
return result;
46754717
}
46764718

4719+
void MiningInterface::auto_detect_external_info()
4720+
{
4721+
// Auto-detect public IP if not configured
4722+
if (m_external_ip.empty() || m_external_ip == "0.0.0.0") {
4723+
std::thread([this]() {
4724+
try {
4725+
boost::asio::io_context tmp_ioc;
4726+
boost::asio::ip::tcp::resolver resolver(tmp_ioc);
4727+
4728+
// Try ifconfig.me (returns plain text IP)
4729+
auto endpoints = resolver.resolve("ifconfig.me", "80");
4730+
boost::asio::ip::tcp::socket sock(tmp_ioc);
4731+
boost::asio::connect(sock, endpoints);
4732+
4733+
std::string req =
4734+
"GET / HTTP/1.0\r\n"
4735+
"Host: ifconfig.me\r\n"
4736+
"User-Agent: c2pool/0.1\r\n"
4737+
"Connection: close\r\n\r\n";
4738+
boost::asio::write(sock, boost::asio::buffer(req));
4739+
4740+
std::string response;
4741+
boost::system::error_code ec;
4742+
char buf[1024];
4743+
while (true) {
4744+
size_t n = sock.read_some(boost::asio::buffer(buf), ec);
4745+
if (n > 0) response.append(buf, n);
4746+
if (ec) break;
4747+
}
4748+
4749+
auto body_pos = response.find("\r\n\r\n");
4750+
if (body_pos != std::string::npos) {
4751+
std::string ip = response.substr(body_pos + 4);
4752+
// Trim whitespace
4753+
while (!ip.empty() && (ip.back() == '\n' || ip.back() == '\r'
4754+
|| ip.back() == ' '))
4755+
ip.pop_back();
4756+
if (!ip.empty() && ip.find('.') != std::string::npos) {
4757+
m_external_ip = ip;
4758+
LOG_INFO << "[AUTO] Public IP detected: " << ip;
4759+
}
4760+
}
4761+
} catch (const std::exception& e) {
4762+
LOG_WARNING << "[AUTO] Public IP detection failed: " << e.what();
4763+
}
4764+
}).detach();
4765+
}
4766+
4767+
// Version is set at build time via C2POOL_VERSION from git describe.
4768+
// No runtime GitHub fetch needed (requires HTTPS which we can't do
4769+
// with raw TCP sockets).
4770+
}
4771+
46774772
nlohmann::json MiningInterface::rest_node_info()
46784773
{
46794774
nlohmann::json result = nlohmann::json::object();

src/core/web_server.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1142,6 +1142,11 @@ class MiningInterface : public jsonrpccxx::JsonRpc2Server
11421142
void set_external_ip(const std::string& ip) { m_external_ip = ip; }
11431143
void set_pool_version(const std::string& ver) { m_pool_version = ver; }
11441144

1145+
/// Auto-detect public IP and version from external services.
1146+
/// Runs on detached threads — non-blocking. Only fetches if not
1147+
/// already configured. Safe to call from any thread.
1148+
void auto_detect_external_info();
1149+
11451150
// Best share difficulty tracking (for /best_share, /miner_stats)
11461151
void record_share_difficulty(double difficulty, const std::string& miner);
11471152
void record_merged_share_difficulty(double difficulty, const std::string& miner);

0 commit comments

Comments
 (0)