#!/usr/bin/env python3 """ RinCoin Mining Pool Web Interface Provides web dashboard for pool statistics and miner management """ import json import sqlite3 from datetime import datetime, timedelta from http.server import HTTPServer, BaseHTTPRequestHandler import threading import time class PoolWebInterface: def __init__(self, pool_db, host='0.0.0.0', port=8080): self.pool_db = pool_db self.host = host self.port = port def format_hashrate(self, hashrate): """Format hashrate in human readable format""" if hashrate >= 1e12: return f"{hashrate/1e12:.2f} TH/s" elif hashrate >= 1e9: return f"{hashrate/1e9:.2f} GH/s" elif hashrate >= 1e6: return f"{hashrate/1e6:.2f} MH/s" elif hashrate >= 1e3: return f"{hashrate/1e3:.2f} KH/s" elif hashrate >= 0.01: return f"{hashrate:.2f} H/s" elif hashrate > 0: return f"{hashrate*1000:.2f} mH/s" else: return "0.00 H/s" def get_pool_stats(self): """Get current pool statistics""" try: cursor = self.pool_db.cursor() # Total miners (ever registered) cursor.execute('SELECT COUNT(DISTINCT id) FROM miners') total_miners = cursor.fetchone()[0] # Active miners (last 5 minutes) cursor.execute(''' SELECT COUNT(DISTINCT m.id) FROM miners m JOIN shares s ON m.id = s.miner_id WHERE s.submitted > datetime('now', '-5 minutes') ''') active_miners = cursor.fetchone()[0] # Total shares (last 24 hours) cursor.execute(''' SELECT COUNT(*) FROM shares WHERE submitted > datetime('now', '-24 hours') ''') total_shares_24h = cursor.fetchone()[0] # Better hashrate calculation (shares per second * difficulty) cursor.execute(''' SELECT SUM(difficulty), COUNT(*) FROM shares WHERE submitted > datetime('now', '-5 minutes') ''') result = cursor.fetchone() recent_difficulty = result[0] if result[0] else 0 recent_share_count = result[1] if result[1] else 0 # Convert to hashrate (difficulty per second) hashrate = recent_difficulty / 300.0 # 5 minutes = 300 seconds # Alternative calculation if difficulty is 0 but we have shares if hashrate == 0 and recent_share_count > 0: # Estimate based on share count (assume difficulty 0.001) hashrate = (recent_share_count * 0.001) / 300.0 # Total blocks found cursor.execute('SELECT COUNT(*) FROM blocks') total_blocks = cursor.fetchone()[0] # Recent blocks cursor.execute(''' SELECT block_hash, height, reward, found_at FROM blocks ORDER BY found_at DESC LIMIT 10 ''') recent_blocks = cursor.fetchall() # Top miners (last 24 hours) - show all miners, even without shares cursor.execute(''' SELECT m.user, m.worker, COALESCE(COUNT(s.id), 0) as shares, m.last_share, m.created FROM miners m LEFT JOIN shares s ON m.id = s.miner_id AND s.submitted > datetime('now', '-24 hours') GROUP BY m.id, m.user, m.worker ORDER BY shares DESC, m.created DESC LIMIT 20 ''') top_miners = cursor.fetchall() # All active miners (for better visibility) cursor.execute(''' SELECT user, worker, created, last_share FROM miners ORDER BY created DESC LIMIT 10 ''') all_miners = cursor.fetchall() return { 'total_miners': total_miners, 'active_miners': active_miners, 'total_shares_24h': total_shares_24h, 'hashrate': hashrate, 'total_blocks': total_blocks, 'recent_blocks': recent_blocks, 'top_miners': top_miners, 'all_miners': all_miners, 'debug': { 'recent_difficulty': recent_difficulty, 'recent_share_count': recent_share_count, 'total_shares_24h': total_shares_24h } } except Exception as e: print(f"Error getting pool stats: {e}") return {} def generate_html(self, stats): """Generate HTML dashboard""" html = f"""
Distribute block rewards among multiple miners
24h Shares: {stats.get('total_shares_24h', 0):,}
Pool Fee: 1%
Connection String: stratum+tcp://YOUR_IP:3333
Recent Difficulty (5min): {stats.get('debug', {}).get('recent_difficulty', 0):.6f}
Recent Share Count (5min): {stats.get('debug', {}).get('recent_share_count', 0)}
Total Shares (24h): {stats.get('debug', {}).get('total_shares_24h', 0):,}
Active Miners: {stats.get('active_miners', 0)} (last 5 minutes)
Total Miners: {stats.get('total_miners', 0)} (ever registered)
User | Worker | Connected | Last Share |
---|---|---|---|
{user} | {worker} | {created} | {last_share or 'Never'} |
No miners connected |
User | Worker | Shares | Last Share |
---|---|---|---|
{user} | {worker} | {shares:,} | {last_share or 'Never'} |
No shares submitted yet |
Height | Hash | Reward | Found At |
---|---|---|---|
{height} | {block_hash[:16]}... | {reward:.8f} RIN | {found_at} |
Use any RinHash-compatible miner:
./cpuminer -a rinhash -o stratum+tcp://YOUR_IP:3333 -u username.workername -p x
Replace YOUR_IP with your server's public IP address