@@ -3066,12 +3066,18 @@ nlohmann::json MiningInterface::rest_connected_miners()
30663066
30673067nlohmann::json MiningInterface::rest_stratum_stats ()
30683068{
3069+ // p2pool format: { pool: {...}, workers: {...} }
3070+ // stratum.html reads data.pool.* and data.workers.*
30693071 nlohmann::json result = nlohmann::json::object ();
30703072 auto workers = get_stratum_workers ();
3073+ auto now = std::time (nullptr );
3074+ auto now_steady = std::chrono::steady_clock::now ();
30713075
30723076 double total_hashrate = 0.0 ;
30733077 uint64_t total_accepted = 0 , total_rejected = 0 , total_stale = 0 ;
30743078 std::set<std::string> unique_addrs;
3079+ std::map<std::string, int > ip_connections; // IP → connection count
3080+ std::map<std::string, std::set<std::string>> ip_workers_set; // IP → unique workers
30753081
30763082 nlohmann::json workers_json = nlohmann::json::object ();
30773083 for (const auto & [sid, w] : workers) {
@@ -3081,10 +3087,19 @@ nlohmann::json MiningInterface::rest_stratum_stats()
30813087 total_stale += w.stale ;
30823088 unique_addrs.insert (w.username );
30833089
3090+ // Track connections per IP
3091+ auto colon = w.remote_endpoint .rfind (' :' );
3092+ std::string ip = (colon != std::string::npos) ? w.remote_endpoint .substr (0 , colon) : w.remote_endpoint ;
3093+ if (!ip.empty ()) {
3094+ ip_connections[ip]++;
3095+ ip_workers_set[ip].insert (w.username );
3096+ }
3097+
30843098 auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(
3085- std::chrono::steady_clock::now () - w.connected_at ).count ();
3099+ now_steady - w.connected_at ).count ();
3100+ auto first_seen_ts = static_cast <uint64_t >(now) - static_cast <uint64_t >(elapsed);
30863101
3087- // Key by worker name: "ADDRESS.worker" (like p2pool) or just "ADDRESS" if no worker suffix
3102+ // Key by worker name: "ADDRESS.worker" (like p2pool)
30883103 std::string worker_key = w.worker_name .empty ()
30893104 ? w.username
30903105 : w.username + " ." + w.worker_name ;
@@ -3098,46 +3113,53 @@ nlohmann::json MiningInterface::rest_stratum_stats()
30983113 workers_json[worker_key][" accepted" ] = workers_json[worker_key][" accepted" ].get <uint64_t >() + w.accepted ;
30993114 workers_json[worker_key][" rejected" ] = workers_json[worker_key][" rejected" ].get <uint64_t >() + w.rejected ;
31003115 workers_json[worker_key][" stale" ] = workers_json[worker_key][" stale" ].get <uint64_t >() + w.stale ;
3116+ workers_json[worker_key][" shares" ] = workers_json[worker_key][" shares" ].get <uint64_t >() + w.accepted + w.stale ;
3117+ // Keep earliest first_seen
3118+ if (first_seen_ts < workers_json[worker_key][" first_seen" ].get <uint64_t >())
3119+ workers_json[worker_key][" first_seen" ] = first_seen_ts;
31013120 } else {
31023121 workers_json[worker_key] = {
3103- {" hash_rate" , w.hashrate },
3104- {" dead_hash_rate" , w.dead_hashrate },
3105- {" connections" , 1 },
3106- {" connection_difficulties" , nlohmann::json::array ({w.difficulty })},
3107- {" last_seen" , static_cast <uint64_t >(std::time (nullptr ))},
3108- {" difficulty" , w.difficulty },
3109- {" accepted" , w.accepted },
3110- {" rejected" , w.rejected },
3111- {" stale" , w.stale },
3112- {" connected_seconds" , elapsed},
3113- {" remote_endpoint" , w.remote_endpoint }
3114- };
3122+ {" hash_rate" , w.hashrate },
3123+ {" dead_hash_rate" , w.dead_hashrate },
3124+ {" connections" , 1 },
3125+ {" connection_difficulties" , nlohmann::json::array ({w.difficulty })},
3126+ {" last_seen" , static_cast <uint64_t >(now)},
3127+ {" first_seen" , first_seen_ts},
3128+ {" difficulty" , w.difficulty },
3129+ {" accepted" , w.accepted },
3130+ {" rejected" , w.rejected },
3131+ {" stale" , w.stale },
3132+ {" shares" , w.accepted + w.stale },
3133+ {" connected_seconds" , elapsed},
3134+ {" remote_endpoint" , w.remote_endpoint }
3135+ };
31153136 }
31163137 }
31173138
3118- result[" difficulty" ] = 1.0 ;
3119- if (!workers.empty ())
3120- result[" difficulty" ] = workers.begin ()->second .difficulty ;
3121- result[" accepted_shares" ] = total_accepted;
3122- result[" rejected_shares" ] = total_rejected;
3123- result[" stale_shares" ] = total_stale;
3124- result[" hashrate" ] = total_hashrate;
3125- result[" active_workers" ] = static_cast <int >(workers.size ());
3126- result[" unique_addresses" ] = static_cast <int >(unique_addrs.size ());
3127- result[" workers" ] = workers_json;
3128-
3129- double total_shares = static_cast <double >(total_accepted + total_rejected + total_stale);
3139+ // Pool-level stats (stratum.html reads data.pool.*)
31303140 auto uptime = std::chrono::duration_cast<std::chrono::seconds>(
3131- std::chrono::steady_clock::now () - m_stratum_start_time).count ();
3132- result[" shares_per_minute" ] = (uptime > 0 ) ? (total_shares * 60.0 / uptime) : 0.0 ;
3133- result[" last_share_time" ] = static_cast <uint64_t >(std::time (nullptr ));
3134- result[" uptime_seconds" ] = static_cast <double >(uptime);
3135-
3136- {
3137- std::lock_guard<std::mutex> lock (m_control_mutex);
3138- result[" mining_enabled" ] = m_mining_enabled;
3139- result[" banned_count" ] = static_cast <uint64_t >(m_banned_targets.size ());
3140- }
3141+ now_steady - m_stratum_start_time).count ();
3142+ double total_shares = static_cast <double >(total_accepted + total_rejected + total_stale);
3143+ double submission_rate = (uptime > 0 ) ? (total_shares / static_cast <double >(uptime)) : 0.0 ;
3144+
3145+ nlohmann::json ip_workers_json = nlohmann::json::object ();
3146+ for (const auto & [ip, wset] : ip_workers_set)
3147+ ip_workers_json[ip] = static_cast <int >(wset.size ());
3148+
3149+ result[" pool" ] = {
3150+ {" connections" , static_cast <int >(workers.size ())},
3151+ {" workers" , static_cast <int >(unique_addrs.size ())},
3152+ {" unique_addresses" , static_cast <int >(unique_addrs.size ())},
3153+ {" total_accepted" , total_accepted},
3154+ {" total_rejected" , total_rejected},
3155+ {" total_stale" , total_stale},
3156+ {" submission_rate" , submission_rate},
3157+ {" uptime" , static_cast <double >(uptime)},
3158+ {" hashrate" , total_hashrate},
3159+ {" ip_connections" , ip_connections},
3160+ {" ip_workers" , ip_workers_json}
3161+ };
3162+ result[" workers" ] = workers_json;
31413163
31423164 return result;
31433165}
0 commit comments