From af5838494990c938817dbd82f0f60255f6a4be8c Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 23 Sep 2025 11:46:07 +0300 Subject: [PATCH] stratum - dynamic difficulty --- MINE/rin/stratum_proxy.py | 125 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 119 insertions(+), 6 deletions(-) diff --git a/MINE/rin/stratum_proxy.py b/MINE/rin/stratum_proxy.py index 95aeef9..5d05743 100644 --- a/MINE/rin/stratum_proxy.py +++ b/MINE/rin/stratum_proxy.py @@ -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: