#!/usr/bin/env python3 """ DragonX RandomX Block Time Calculator Estimates how long it will take to find a block given your hashrate and the current network difficulty. Usage: python3 block_time_calculator.py [--difficulty ] Examples: python3 block_time_calculator.py 1000 # 1000 H/s, auto-fetch difficulty python3 block_time_calculator.py 5K # 5 KH/s python3 block_time_calculator.py 1.2M # 1.2 MH/s python3 block_time_calculator.py 500 --difficulty 1234.56 """ import argparse import json import subprocess import sys # DragonX chain constants BLOCK_TIME = 36 # seconds # powLimit = 0x0f0f0f0f... (32 bytes of 0x0f) = (2^256 - 1) / 17 # The multiplier 2^256 / powLimit ≈ 17 POW_LIMIT_HEX = "0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f" POW_LIMIT = int(POW_LIMIT_HEX, 16) TWO_256 = 2 ** 256 def parse_hashrate(value): """Parse hashrate string with optional K/M/G/T suffix.""" suffixes = {"K": 1e3, "M": 1e6, "G": 1e9, "T": 1e12} value = value.strip().upper() if value and value[-1] in suffixes: return float(value[:-1]) * suffixes[value[-1]] return float(value) def get_difficulty_from_node(): """Try to fetch current difficulty from a running DragonX node.""" try: result = subprocess.run( ["dragonx-cli", "getmininginfo"], capture_output=True, text=True, timeout=10 ) if result.returncode == 0: info = json.loads(result.stdout) return float(info["difficulty"]) except FileNotFoundError: pass except (subprocess.TimeoutExpired, json.JSONDecodeError, KeyError): pass # Try with src/ path relative to script location try: import os script_dir = os.path.dirname(os.path.abspath(__file__)) cli_path = os.path.join(script_dir, "src", "dragonx-cli") result = subprocess.run( [cli_path, "getmininginfo"], capture_output=True, text=True, timeout=10 ) if result.returncode == 0: info = json.loads(result.stdout) return float(info["difficulty"]) except (FileNotFoundError, subprocess.TimeoutExpired, json.JSONDecodeError, KeyError): pass return None def format_duration(seconds): """Format seconds into a human-readable duration string.""" days = seconds / 86400 if days >= 365: years = days / 365.25 return f"{years:.2f} years ({days:.1f} days)" if days >= 1: hours = (seconds % 86400) / 3600 return f"{days:.2f} days ({days * 24:.1f} hours)" hours = seconds / 3600 if hours >= 1: return f"{hours:.2f} hours" minutes = seconds / 60 return f"{minutes:.1f} minutes" def main(): parser = argparse.ArgumentParser( description="DragonX RandomX Block Time Calculator" ) parser.add_argument( "hashrate", help="Your hashrate in H/s (supports K/M/G/T suffixes, e.g. 5K, 1.2M)" ) parser.add_argument( "--difficulty", "-d", type=float, default=None, help="Network difficulty (auto-fetched from local node if omitted)" ) args = parser.parse_args() try: hashrate = parse_hashrate(args.hashrate) except ValueError: print(f"Error: Invalid hashrate '{args.hashrate}'", file=sys.stderr) sys.exit(1) if hashrate <= 0: print("Error: Hashrate must be positive", file=sys.stderr) sys.exit(1) difficulty = args.difficulty if difficulty is None: print("Querying local DragonX node for current difficulty...") difficulty = get_difficulty_from_node() if difficulty is None: print( "Error: Could not connect to DragonX node.\n" "Make sure dragonxd is running, or pass --difficulty manually.", file=sys.stderr ) sys.exit(1) if difficulty <= 0: print("Error: Difficulty must be positive", file=sys.stderr) sys.exit(1) # Expected hashes to find a block = 2^256 / current_target # Since difficulty = powLimit / current_target: # current_target = powLimit / difficulty # expected_hashes = 2^256 / (powLimit / difficulty) = difficulty * 2^256 / powLimit expected_hashes = difficulty * TWO_256 / POW_LIMIT time_seconds = expected_hashes / hashrate time_days = time_seconds / 86400 # Estimate network hashrate from difficulty and block time network_hashrate = expected_hashes / BLOCK_TIME print() print("=" * 50) print(" DragonX Block Time Estimator (RandomX)") print("=" * 50) print(f" Network difficulty : {difficulty:,.4f}") print(f" Your hashrate : {hashrate:,.0f} H/s") print(f" Est. network hash : {network_hashrate:,.0f} H/s") print(f" Block time target : {BLOCK_TIME}s") print(f" Block reward : 3 DRGX") print("-" * 50) print(f" Expected time to find a block:") print(f" {format_duration(time_seconds)}") print(f" ({time_days:.4f} days)") print("-" * 50) print(f" Est. blocks/day : {86400 / time_seconds:.6f}") print(f" Est. DRGX/day : {86400 / time_seconds * 3:.6f}") print("=" * 50) print() print("Note: This is a statistical estimate. Actual time varies due to randomness.") if __name__ == "__main__": main()