@@ -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
852894void 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+
46774772nlohmann::json MiningInterface::rest_node_info ()
46784773{
46794774 nlohmann::json result = nlohmann::json::object ();
0 commit comments