stratum - dynamic difficulty

This commit is contained in:
Dobromir Popov
2025-09-23 11:46:07 +03:00
parent d8b019401f
commit af58384949

View File

@@ -33,6 +33,11 @@ class RinCoinStratumProxy:
self.running = True
self.extranonce1_counter = 0
# Dynamic difficulty adjustment
self.share_stats = {} # Track shares per client
self.last_difficulty_adjustment = time.time()
self.target_share_interval = 30 # Target: 1 share every 30 seconds per miner
# Logging setup
self.log_file = "mining_log.txt"
self.init_log_file()
@@ -370,6 +375,102 @@ class RinCoinStratumProxy:
print(f"Network difficulty calculation error: {e}")
return 1.0
def calculate_optimal_difficulty(self, addr, is_new_client=False):
"""Calculate optimal stratum difficulty for a client based on hashrate and network conditions"""
try:
# Get current network difficulty
network_diff = self.calculate_network_difficulty(self.current_job['target']) if self.current_job else 1.0
if is_new_client:
# For new clients, start with a conservative estimate
# Assuming typical CPU miner does 500kH/s, aim for 1 share per 30 seconds
# Difficulty calculation: target_shares_per_second = hashrate / (difficulty * 2^32 / 65535)
# Rearranged: difficulty = hashrate / (target_shares_per_second * 2^32 / 65535)
estimated_hashrate = 500000 # 500 kH/s conservative estimate
target_shares_per_second = 1.0 / self.target_share_interval
# Bitcoin-style difficulty calculation
diff1_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000
optimal_difficulty = (estimated_hashrate * diff1_target) / (target_shares_per_second * (2**256))
# More practical approach: start with network difficulty scaled down
optimal_difficulty = max(network_diff * 0.001, 0.0001) # 0.1% of network, min 0.0001
print(f" 📊 New client {addr}: Network diff {network_diff:.6f}, starting with {optimal_difficulty:.6f}")
return optimal_difficulty
# For existing clients, adjust based on actual performance
client_data = self.clients.get(addr, {})
if not client_data:
return self.calculate_optimal_difficulty(addr, is_new_client=True)
current_time = time.time()
connect_time = client_data.get('connect_time', current_time)
share_count = client_data.get('share_count', 0)
current_difficulty = client_data.get('stratum_difficulty', 0.001)
# Calculate actual share rate
mining_duration = current_time - connect_time
if mining_duration < 60: # Need at least 1 minute of data
return current_difficulty
actual_share_rate = share_count / mining_duration # shares per second
target_share_rate = 1.0 / self.target_share_interval
# Adjust difficulty to hit target share rate
if actual_share_rate > 0:
difficulty_multiplier = actual_share_rate / target_share_rate
new_difficulty = current_difficulty * difficulty_multiplier
# Apply conservative adjustment (don't change too dramatically)
max_change = 2.0 # Don't change by more than 2x in one adjustment
if difficulty_multiplier > max_change:
new_difficulty = current_difficulty * max_change
elif difficulty_multiplier < (1.0 / max_change):
new_difficulty = current_difficulty / max_change
# Bounds checking
min_difficulty = network_diff * 0.00001 # 0.001% of network minimum
max_difficulty = network_diff * 0.1 # 10% of network maximum
new_difficulty = max(min_difficulty, min(max_difficulty, new_difficulty))
print(f" 📊 {addr}: {share_count} shares in {mining_duration:.0f}s ({actual_share_rate:.4f}/s), adjusting {current_difficulty:.6f}{new_difficulty:.6f}")
return new_difficulty
return current_difficulty
except Exception as e:
print(f"Difficulty calculation error: {e}")
# Fallback to conservative difficulty
network_diff = self.calculate_network_difficulty(self.current_job['target']) if self.current_job else 1.0
return max(network_diff * 0.001, 0.0001)
def adjust_client_difficulty(self, addr):
"""Adjust difficulty for a specific client if needed"""
try:
current_time = time.time()
# Only adjust every 2 minutes minimum
last_adjustment = self.clients[addr].get('last_difficulty_adjustment', 0)
if current_time - last_adjustment < 120:
return
new_difficulty = self.calculate_optimal_difficulty(addr, is_new_client=False)
current_difficulty = self.clients[addr].get('stratum_difficulty', 0.001)
# Only send update if difficulty changed significantly (>20%)
if abs(new_difficulty - current_difficulty) / current_difficulty > 0.2:
self.clients[addr]['stratum_difficulty'] = new_difficulty
self.clients[addr]['last_difficulty_adjustment'] = current_time
# Send new difficulty to client
if 'socket' in self.clients[addr]:
self.send_stratum_notification(self.clients[addr]['socket'], "mining.set_difficulty", [new_difficulty])
print(f" 🎯 Updated difficulty for {addr}: {current_difficulty:.6f}{new_difficulty:.6f}")
except Exception as e:
print(f"Difficulty adjustment error for {addr}: {e}")
def submit_share(self, job, extranonce1, extranonce2, ntime, nonce, addr=None, target_address=None):
"""Validate share and submit block if valid - FIXED VERSION"""
try:
@@ -449,7 +550,15 @@ class RinCoinStratumProxy:
print(f" ❌ Share rejected (hash > stratum target)")
return False, "Share too high"
# Valid stratum share! Check if it's also a valid network block
# Valid stratum share! Update client stats
if addr and addr in self.clients:
self.clients[addr]['share_count'] = self.clients[addr].get('share_count', 0) + 1
self.clients[addr]['last_share_time'] = time.time()
# Check if we should adjust difficulty
self.adjust_client_difficulty(addr)
# Check if it's also a valid network block
if meets_network_target:
print(f" 🎉 BLOCK FOUND! Hash: {block_hash_hex}")
print(f" 💰 Reward: {job['coinbasevalue']/100000000:.2f} RIN -> {address}")
@@ -549,14 +658,18 @@ class RinCoinStratumProxy:
4 # extranonce2 size
])
# Send difficulty - set to reasonable level for stratum mining
network_diff = self.calculate_network_difficulty(self.current_job['target']) if self.current_job else 1.0
stratum_difficulty = min(network_diff * 0.001, 0.01) # Adaptive difficulty, max 0.01
# Calculate optimal stratum difficulty for this client
initial_difficulty = self.calculate_optimal_difficulty(addr, is_new_client=True)
# Store stratum difficulty for this client
if addr not in self.clients:
self.clients[addr] = {}
self.clients[addr]['stratum_difficulty'] = stratum_difficulty
self.send_stratum_notification(client, "mining.set_difficulty", [stratum_difficulty])
self.clients[addr]['stratum_difficulty'] = initial_difficulty
self.clients[addr]['last_share_time'] = time.time()
self.clients[addr]['share_count'] = 0
self.clients[addr]['connect_time'] = time.time()
self.send_stratum_notification(client, "mining.set_difficulty", [initial_difficulty])
print(f" 🎯 Set initial difficulty {initial_difficulty:.6f} for {addr}")
# Send initial job
if self.current_job: