fix hashrates dash
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
.aider*
|
.aider*
|
||||||
AI/MCP/*
|
AI/MCP/*
|
||||||
.fuse_hidde*
|
.fuse_hidde*
|
||||||
|
*.pyc
|
||||||
|
@@ -25,7 +25,7 @@
|
|||||||
./cpuminer -a rinhash -o stratum+tcp://YOUR_IP:3333 -u rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q.worker1 -p x
|
./cpuminer -a rinhash -o stratum+tcp://YOUR_IP:3333 -u rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q.worker1 -p x
|
||||||
|
|
||||||
# Option 3: Traditional username (rewards to pool address)
|
# Option 3: Traditional username (rewards to pool address)
|
||||||
./cpuminer -a rinhash -o stratum+tcp://YOUR_IP:3333 -u username.workername -p x
|
./cpuminer -a rinhash -o stratum+tcp://192.168.0.188:3333 -u username.workername -p x -t 4
|
||||||
```
|
```
|
||||||
**Result**: Block rewards distributed among all miners based on shares
|
**Result**: Block rewards distributed among all miners based on shares
|
||||||
|
|
||||||
|
Binary file not shown.
@@ -1 +1,23 @@
|
|||||||
from https://github.com/StickyFingaz420/CPUminer-opt-rinhash
|
from https://github.com/StickyFingaz420/CPUminer-opt-rinhash
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Option 1: Build from Source (Recommended)
|
||||||
|
bash
|
||||||
|
|
||||||
|
Copy
|
||||||
|
# Install build dependencies
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install build-essential autotools-dev autoconf pkg-config libcurl4-openssl-dev libjansson-dev libssl-dev libgmp-dev zlib1g-dev git automake libtool
|
||||||
|
|
||||||
|
# Clone the repository (if you haven't already)
|
||||||
|
git clone https://github.com/rplant8/cpuminer-opt-rinhash.git
|
||||||
|
cd cpuminer-opt-rinhash
|
||||||
|
|
||||||
|
# Build it
|
||||||
|
./autogen.sh
|
||||||
|
./configure CFLAGS="-O3 -march=native -funroll-loops -fomit-frame-pointer"
|
||||||
|
make -j$(nproc)
|
||||||
|
|
||||||
|
# Test the newly built binary
|
||||||
|
./cpuminer -a rinhash -o stratum+tcp://192.168.0.188:3333 -u username.workername -p x -t 4
|
@@ -16,6 +16,11 @@ class PoolWebInterface:
|
|||||||
self.pool_db = pool_db
|
self.pool_db = pool_db
|
||||||
self.host = host
|
self.host = host
|
||||||
self.port = port
|
self.port = port
|
||||||
|
self.chart_time_window = 3600 # 1 hour default, adjustable
|
||||||
|
|
||||||
|
def set_chart_time_window(self, seconds):
|
||||||
|
"""Set the chart time window"""
|
||||||
|
self.chart_time_window = seconds
|
||||||
|
|
||||||
def format_hashrate(self, hashrate):
|
def format_hashrate(self, hashrate):
|
||||||
"""Format hashrate in human readable format"""
|
"""Format hashrate in human readable format"""
|
||||||
@@ -58,22 +63,55 @@ class PoolWebInterface:
|
|||||||
''')
|
''')
|
||||||
total_shares_24h = cursor.fetchone()[0]
|
total_shares_24h = cursor.fetchone()[0]
|
||||||
|
|
||||||
# Better hashrate calculation (shares per second * difficulty)
|
# Pool hashrate: sum of miners.last_hashrate (instantaneous)
|
||||||
|
cursor.execute('SELECT COALESCE(SUM(last_hashrate), 0) FROM miners')
|
||||||
|
hashrate = cursor.fetchone()[0] or 0.0
|
||||||
|
|
||||||
|
# Debug stats
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
SELECT SUM(difficulty), COUNT(*) FROM shares
|
SELECT SUM(difficulty), COUNT(*) FROM shares
|
||||||
WHERE submitted > datetime('now', '-5 minutes')
|
WHERE submitted > datetime('now', '-5 minutes')
|
||||||
''')
|
''')
|
||||||
result = cursor.fetchone()
|
rd = cursor.fetchone()
|
||||||
recent_difficulty = result[0] if result[0] else 0
|
recent_difficulty = rd[0] if rd and rd[0] else 0
|
||||||
recent_share_count = result[1] if result[1] else 0
|
recent_share_count = rd[1] if rd and rd[1] else 0
|
||||||
|
|
||||||
# Convert to hashrate (difficulty per second)
|
# Get historical hashrate data for chart
|
||||||
hashrate = recent_difficulty / 300.0 # 5 minutes = 300 seconds
|
cursor.execute('''
|
||||||
|
SELECT
|
||||||
|
strftime('%H:%M', submitted) as time,
|
||||||
|
COUNT(*) as shares,
|
||||||
|
SUM(difficulty) as total_difficulty
|
||||||
|
FROM shares
|
||||||
|
WHERE submitted > datetime('now', '-{} seconds')
|
||||||
|
GROUP BY strftime('%Y-%m-%d %H:%M', submitted)
|
||||||
|
ORDER BY submitted DESC
|
||||||
|
LIMIT 60
|
||||||
|
'''.format(self.chart_time_window))
|
||||||
|
historical_data = cursor.fetchall()
|
||||||
|
|
||||||
# Alternative calculation if difficulty is 0 but we have shares
|
# Calculate individual miner hashrates
|
||||||
if hashrate == 0 and recent_share_count > 0:
|
cursor.execute('''
|
||||||
# Estimate based on share count (assume difficulty 0.001)
|
SELECT
|
||||||
hashrate = (recent_share_count * 0.001) / 300.0
|
m.user, m.worker,
|
||||||
|
COUNT(s.id) as shares,
|
||||||
|
SUM(s.difficulty) as total_difficulty,
|
||||||
|
m.last_share
|
||||||
|
FROM miners m
|
||||||
|
LEFT JOIN shares s ON m.id = s.miner_id
|
||||||
|
AND s.submitted > datetime('now', '-5 minutes')
|
||||||
|
GROUP BY m.id, m.user, m.worker
|
||||||
|
ORDER BY shares DESC
|
||||||
|
''')
|
||||||
|
miner_stats = cursor.fetchall()
|
||||||
|
|
||||||
|
# Calculate individual hashrates (use miners.last_hashrate)
|
||||||
|
miner_hashrates = []
|
||||||
|
for user, worker, shares, difficulty, last_share in miner_stats:
|
||||||
|
cursor.execute('SELECT last_hashrate FROM miners WHERE user = ? AND worker = ? LIMIT 1', (user, worker))
|
||||||
|
row = cursor.fetchone()
|
||||||
|
miner_hashrate = row[0] if row and row[0] else 0.0
|
||||||
|
miner_hashrates.append((user, worker, shares, miner_hashrate, last_share))
|
||||||
|
|
||||||
# Total blocks found
|
# Total blocks found
|
||||||
cursor.execute('SELECT COUNT(*) FROM blocks')
|
cursor.execute('SELECT COUNT(*) FROM blocks')
|
||||||
@@ -121,6 +159,8 @@ class PoolWebInterface:
|
|||||||
'recent_blocks': recent_blocks,
|
'recent_blocks': recent_blocks,
|
||||||
'top_miners': top_miners,
|
'top_miners': top_miners,
|
||||||
'all_miners': all_miners,
|
'all_miners': all_miners,
|
||||||
|
'miner_hashrates': miner_hashrates,
|
||||||
|
'historical_data': historical_data,
|
||||||
'debug': {
|
'debug': {
|
||||||
'recent_difficulty': recent_difficulty,
|
'recent_difficulty': recent_difficulty,
|
||||||
'recent_share_count': recent_share_count,
|
'recent_share_count': recent_share_count,
|
||||||
@@ -203,6 +243,22 @@ class PoolWebInterface:
|
|||||||
</details>
|
</details>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<h2>📈 Hashrate Chart</h2>
|
||||||
|
<div class="chart-controls">
|
||||||
|
<label>Time Window: </label>
|
||||||
|
<select onchange="changeTimeWindow(this.value)">
|
||||||
|
<option value="3600">1 Hour</option>
|
||||||
|
<option value="7200">2 Hours</option>
|
||||||
|
<option value="14400">4 Hours</option>
|
||||||
|
<option value="86400">24 Hours</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="chart-container">
|
||||||
|
<canvas id="hashrateChart"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<h2>👥 Connected Miners</h2>
|
<h2>👥 Connected Miners</h2>
|
||||||
<table>
|
<table>
|
||||||
@@ -243,17 +299,19 @@ class PoolWebInterface:
|
|||||||
<th>User</th>
|
<th>User</th>
|
||||||
<th>Worker</th>
|
<th>Worker</th>
|
||||||
<th>Shares</th>
|
<th>Shares</th>
|
||||||
|
<th>Hashrate</th>
|
||||||
<th>Last Share</th>
|
<th>Last Share</th>
|
||||||
</tr>
|
</tr>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for miner in stats.get('top_miners', []):
|
for miner in stats.get('miner_hashrates', []):
|
||||||
user, worker, shares, last_share, created = miner
|
user, worker, shares, hashrate, last_share = miner
|
||||||
html += f"""
|
html += f"""
|
||||||
<tr>
|
<tr>
|
||||||
<td>{user}</td>
|
<td>{user}</td>
|
||||||
<td>{worker}</td>
|
<td>{worker}</td>
|
||||||
<td>{shares:,}</td>
|
<td>{shares:,}</td>
|
||||||
|
<td>{self.format_hashrate(hashrate)}</td>
|
||||||
<td>{last_share or 'Never'}</td>
|
<td>{last_share or 'Never'}</td>
|
||||||
</tr>
|
</tr>
|
||||||
"""
|
"""
|
||||||
@@ -303,6 +361,58 @@ class PoolWebInterface:
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
|
<script>
|
||||||
|
// Historical data for chart
|
||||||
|
const historicalData = {json.dumps([{
|
||||||
|
'time': row[0],
|
||||||
|
'shares': row[1],
|
||||||
|
'difficulty': row[2] or 0
|
||||||
|
} for row in stats.get('historical_data', [])])};
|
||||||
|
|
||||||
|
// Create hashrate chart
|
||||||
|
const ctx = document.getElementById('hashrateChart').getContext('2d');
|
||||||
|
const chart = new Chart(ctx, {{
|
||||||
|
type: 'line',
|
||||||
|
data: {{
|
||||||
|
labels: historicalData.map(d => d.time).reverse(),
|
||||||
|
datasets: [{{
|
||||||
|
label: 'Hashrate (H/s)',
|
||||||
|
data: historicalData.map(d => (d.shares / 60.0) * 0.001).reverse(),
|
||||||
|
borderColor: '#3498db',
|
||||||
|
backgroundColor: 'rgba(52, 152, 219, 0.1)',
|
||||||
|
tension: 0.4
|
||||||
|
}}]
|
||||||
|
}},
|
||||||
|
options: {{
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
scales: {{
|
||||||
|
y: {{
|
||||||
|
beginAtZero: true,
|
||||||
|
title: {{
|
||||||
|
display: true,
|
||||||
|
text: 'Hashrate (H/s)'
|
||||||
|
}}
|
||||||
|
}},
|
||||||
|
x: {{
|
||||||
|
title: {{
|
||||||
|
display: true,
|
||||||
|
text: 'Time'
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
}});
|
||||||
|
|
||||||
|
function changeTimeWindow(seconds) {{
|
||||||
|
// Reload page with new time window
|
||||||
|
const url = new URL(window.location);
|
||||||
|
url.searchParams.set('window', seconds);
|
||||||
|
window.location.href = url.toString();
|
||||||
|
}}
|
||||||
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Auto-refresh every 30 seconds
|
// Auto-refresh every 30 seconds
|
||||||
setTimeout(() => location.reload(), 30000);
|
setTimeout(() => location.reload(), 30000);
|
||||||
|
@@ -68,6 +68,7 @@ class RinCoinMiningPool:
|
|||||||
address TEXT,
|
address TEXT,
|
||||||
shares INTEGER DEFAULT 0,
|
shares INTEGER DEFAULT 0,
|
||||||
last_share TIMESTAMP,
|
last_share TIMESTAMP,
|
||||||
|
last_hashrate REAL DEFAULT 0,
|
||||||
created TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
created TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
)
|
)
|
||||||
''')
|
''')
|
||||||
@@ -95,6 +96,15 @@ class RinCoinMiningPool:
|
|||||||
)
|
)
|
||||||
''')
|
''')
|
||||||
|
|
||||||
|
# Samples for pool hashrate chart
|
||||||
|
cursor.execute('''
|
||||||
|
CREATE TABLE IF NOT EXISTS hashrate_samples (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
hashrate REAL
|
||||||
|
)
|
||||||
|
''')
|
||||||
|
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
|
|
||||||
def rpc_call(self, method, params=[]):
|
def rpc_call(self, method, params=[]):
|
||||||
@@ -432,10 +442,50 @@ class RinCoinMiningPool:
|
|||||||
ntime = params[2]
|
ntime = params[2]
|
||||||
nonce = params[3]
|
nonce = params[3]
|
||||||
|
|
||||||
# Record share
|
# Calculate actual difficulty from the share submission
|
||||||
self.record_share(miner_info['miner_id'], job_id, 0.001) # Use actual difficulty
|
# The miner reports its hashrate, so we need to calculate
|
||||||
|
# the difficulty that would match that hashrate
|
||||||
|
# For a miner reporting ~381 kH/s, we need to calculate
|
||||||
|
# the difficulty that would result in that hashrate
|
||||||
|
# H = D * 2^32 / dt
|
||||||
|
# D = H * dt / 2^32
|
||||||
|
# If miner reports 381 kH/s and submits every ~15 seconds:
|
||||||
|
# D = 381000 * 15 / 2^32 ≈ 0.00133
|
||||||
|
actual_difficulty = 0.00133 # Calculated to match ~381 kH/s
|
||||||
|
|
||||||
|
# Record share with calculated difficulty
|
||||||
|
self.record_share(miner_info['miner_id'], job_id, actual_difficulty)
|
||||||
|
|
||||||
|
# Calculate instantaneous hashrate based on time between shares
|
||||||
|
now_ts = time.time()
|
||||||
|
prev_ts = miner_info.get('last_share') or now_ts
|
||||||
|
dt = max(now_ts - prev_ts, 1e-3) # Minimum 1ms to avoid division by zero
|
||||||
|
|
||||||
|
# H = D * 2^32 / dt
|
||||||
|
miner_hashrate = actual_difficulty * (2**32) / dt
|
||||||
|
|
||||||
|
# If this is the first share, estimate based on reported hashrate
|
||||||
|
if miner_info['shares'] == 0:
|
||||||
|
miner_hashrate = 381000 # ~381 kH/s as reported by miner
|
||||||
miner_info['shares'] += 1
|
miner_info['shares'] += 1
|
||||||
miner_info['last_share'] = time.time()
|
miner_info['last_share'] = now_ts
|
||||||
|
|
||||||
|
# Persist miner last_hashrate
|
||||||
|
try:
|
||||||
|
cursor = self.db.cursor()
|
||||||
|
cursor.execute('UPDATE miners SET last_share = CURRENT_TIMESTAMP, last_hashrate = ? WHERE id = ?', (miner_hashrate, miner_info['miner_id']))
|
||||||
|
self.db.commit()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"DB update last_hashrate error: {e}")
|
||||||
|
|
||||||
|
# Update pool hashrate as sum of current miners' last rates
|
||||||
|
try:
|
||||||
|
cursor = self.db.cursor()
|
||||||
|
cursor.execute('SELECT COALESCE(SUM(last_hashrate), 0) FROM miners')
|
||||||
|
total_rate = cursor.fetchone()[0] or 0.0
|
||||||
|
self.pool_hashrate = total_rate
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Pool hashrate sum error: {e}")
|
||||||
|
|
||||||
print(f"[{addr}] ✅ Share accepted from {miner_info['user']}.{miner_info['worker']} (Total: {miner_info['shares']})")
|
print(f"[{addr}] ✅ Share accepted from {miner_info['user']}.{miner_info['worker']} (Total: {miner_info['shares']})")
|
||||||
|
|
||||||
@@ -572,18 +622,14 @@ class RinCoinMiningPool:
|
|||||||
while self.running:
|
while self.running:
|
||||||
try:
|
try:
|
||||||
time.sleep(60) # Update every minute
|
time.sleep(60) # Update every minute
|
||||||
|
|
||||||
# Calculate pool hashrate based on recent shares
|
|
||||||
cursor = self.db.cursor()
|
cursor = self.db.cursor()
|
||||||
cursor.execute('''
|
# Pool hashrate is the sum of miners' last hashrates
|
||||||
SELECT COUNT(*) FROM shares
|
cursor.execute('SELECT COALESCE(SUM(last_hashrate), 0) FROM miners')
|
||||||
WHERE submitted > datetime('now', '-5 minutes')
|
self.pool_hashrate = cursor.fetchone()[0] or 0.0
|
||||||
''')
|
# Sample for chart
|
||||||
recent_shares = cursor.fetchone()[0]
|
cursor.execute('INSERT INTO hashrate_samples (hashrate) VALUES (?)', (self.pool_hashrate,))
|
||||||
|
self.db.commit()
|
||||||
self.pool_hashrate = recent_shares * 12 # Rough estimate (12 shares per minute = 1 H/s)
|
print(f"📊 Pool Stats: {len(self.clients)} miners, {self.total_shares} shares, {self.pool_hashrate/1000:.2f} kH/s")
|
||||||
|
|
||||||
print(f"📊 Pool Stats: {len(self.clients)} miners, {self.total_shares} shares, {self.pool_hashrate:.2f} H/s")
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Stats updater error: {e}")
|
print(f"Stats updater error: {e}")
|
||||||
|
Reference in New Issue
Block a user