Add support for GPU mining via GMiner from GitHub (Runs alongside XMRig CPU mining using same pool)
This commit is contained in:
1 parent
a695eeabee
commit
8561f6b0a7
1 file changed
+385
-4
+385
-4
@@ -17,8 +17,10 @@ import tarfile
|
|||||||
import zipfile
|
import zipfile
|
||||||
import re
|
import re
|
||||||
import threading
|
import threading
|
||||||
|
import tempfile
|
||||||
|
import shutil
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, Optional, Tuple
|
from typing import Dict, Optional, Tuple, List
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
class MoneroMiner:
|
class MoneroMiner:
|
||||||
@@ -27,8 +29,10 @@ class MoneroMiner:
|
|||||||
self.script_dir = os.path.dirname(os.path.abspath(__file__))
|
self.script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
self.config = None
|
self.config = None
|
||||||
self.process: Optional[subprocess.Popen] = None
|
self.process: Optional[subprocess.Popen] = None
|
||||||
|
self.gpu_process: Optional[subprocess.Popen] = None
|
||||||
self.stats_thread = None
|
self.stats_thread = None
|
||||||
self.stop_stats = False
|
self.stop_stats = False
|
||||||
|
self.has_nvidia_gpu = False
|
||||||
|
|
||||||
# Known mining pools (with minimum payout amounts)
|
# Known mining pools (with minimum payout amounts)
|
||||||
self.known_pools = [
|
self.known_pools = [
|
||||||
@@ -64,6 +68,45 @@ class MoneroMiner:
|
|||||||
else:
|
else:
|
||||||
return machine
|
return machine
|
||||||
|
|
||||||
|
def detect_nvidia_gpu(self) -> bool:
|
||||||
|
"""Detect if an NVIDIA GPU is present"""
|
||||||
|
os_type = self.detect_os()
|
||||||
|
|
||||||
|
try:
|
||||||
|
if os_type == 'windows':
|
||||||
|
# Try nvidia-smi on Windows
|
||||||
|
result = subprocess.run(
|
||||||
|
['nvidia-smi', '--query-gpu=name', '--format=csv,noheader'],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
timeout=10,
|
||||||
|
creationflags=subprocess.CREATE_NO_WINDOW if hasattr(subprocess, 'CREATE_NO_WINDOW') else 0
|
||||||
|
)
|
||||||
|
if result.returncode == 0 and result.stdout.strip():
|
||||||
|
gpu_name = result.stdout.strip().split('\n')[0]
|
||||||
|
print(f"NVIDIA GPU detected: {gpu_name}")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
# Linux/macOS - try nvidia-smi
|
||||||
|
result = subprocess.run(
|
||||||
|
['nvidia-smi', '--query-gpu=name', '--format=csv,noheader'],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
timeout=10
|
||||||
|
)
|
||||||
|
if result.returncode == 0 and result.stdout.strip():
|
||||||
|
gpu_name = result.stdout.strip().split('\n')[0]
|
||||||
|
print(f"NVIDIA GPU detected: {gpu_name}")
|
||||||
|
return True
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
pass
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error detecting NVIDIA GPU: {e}")
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
def get_latest_xmrig_release(self) -> Optional[Tuple[str, list]]:
|
def get_latest_xmrig_release(self) -> Optional[Tuple[str, list]]:
|
||||||
"""Fetch the latest XMRig version and available files from GitHub"""
|
"""Fetch the latest XMRig version and available files from GitHub"""
|
||||||
try:
|
try:
|
||||||
@@ -83,6 +126,30 @@ class MoneroMiner:
|
|||||||
print(f"Error fetching latest release info: {e}")
|
print(f"Error fetching latest release info: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def get_latest_gminer_release(self) -> Optional[Tuple[str, List[dict]]]:
|
||||||
|
"""Fetch the latest GMiner version and available files from GitHub"""
|
||||||
|
try:
|
||||||
|
url = "https://api.github.com/repos/develsoftware/GMinerRelease/releases/latest"
|
||||||
|
req = urllib.request.Request(url)
|
||||||
|
req.add_header('User-Agent', 'Mozilla/5.0')
|
||||||
|
|
||||||
|
with urllib.request.urlopen(req, timeout=10) as response:
|
||||||
|
data = json.loads(response.read().decode())
|
||||||
|
version = data['tag_name'].lstrip('v')
|
||||||
|
|
||||||
|
# Extract assets with download URLs
|
||||||
|
assets = []
|
||||||
|
for asset in data.get('assets', []):
|
||||||
|
assets.append({
|
||||||
|
'name': asset['name'],
|
||||||
|
'url': asset['browser_download_url']
|
||||||
|
})
|
||||||
|
|
||||||
|
return version, assets
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error fetching latest GMiner release info: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
def find_matching_file(self, assets: list, os_type: str, arch: str) -> Optional[str]:
|
def find_matching_file(self, assets: list, os_type: str, arch: str) -> Optional[str]:
|
||||||
"""Find the matching file for the given OS and architecture"""
|
"""Find the matching file for the given OS and architecture"""
|
||||||
# Build search patterns based on OS and architecture
|
# Build search patterns based on OS and architecture
|
||||||
@@ -118,6 +185,16 @@ class MoneroMiner:
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def find_matching_gminer_file(self, assets: List[dict], os_type: str) -> Optional[dict]:
|
||||||
|
"""Find the matching GMiner file for the given OS"""
|
||||||
|
for asset in assets:
|
||||||
|
name = asset['name'].lower()
|
||||||
|
if os_type == 'windows' and 'windows' in name and name.endswith('.zip'):
|
||||||
|
return asset
|
||||||
|
elif os_type == 'linux' and 'linux' in name and name.endswith('.tar.xz'):
|
||||||
|
return asset
|
||||||
|
return None
|
||||||
|
|
||||||
def check_xmrig_installed(self) -> bool:
|
def check_xmrig_installed(self) -> bool:
|
||||||
"""Check if xmrig is installed"""
|
"""Check if xmrig is installed"""
|
||||||
# Check in script directory first
|
# Check in script directory first
|
||||||
@@ -155,6 +232,17 @@ class MoneroMiner:
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def check_gminer_installed(self) -> bool:
|
||||||
|
"""Check if GMiner is installed in script directory"""
|
||||||
|
os_type = self.detect_os()
|
||||||
|
|
||||||
|
if os_type == 'windows':
|
||||||
|
gminer_path = os.path.join(self.script_dir, 'miner.exe')
|
||||||
|
else:
|
||||||
|
gminer_path = os.path.join(self.script_dir, 'miner')
|
||||||
|
|
||||||
|
return os.path.exists(gminer_path) and os.access(gminer_path, os.X_OK if os.name != 'nt' else os.F_OK)
|
||||||
|
|
||||||
def download_file_with_progress(self, url: str, local_filename: str, max_retries: int = 3) -> bool:
|
def download_file_with_progress(self, url: str, local_filename: str, max_retries: int = 3) -> bool:
|
||||||
"""Download a file with progress indication and retry logic"""
|
"""Download a file with progress indication and retry logic"""
|
||||||
for attempt in range(max_retries):
|
for attempt in range(max_retries):
|
||||||
@@ -385,6 +473,126 @@ class MoneroMiner:
|
|||||||
print(f"Error extracting archive: {e}")
|
print(f"Error extracting archive: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def download_and_install_gminer(self) -> bool:
|
||||||
|
"""Download and install GMiner for GPU mining"""
|
||||||
|
os_type = self.detect_os()
|
||||||
|
|
||||||
|
# GMiner only supports Windows and Linux
|
||||||
|
if os_type not in ['windows', 'linux']:
|
||||||
|
print(f"\nGMiner is not available for {os_type}.")
|
||||||
|
print("GPU mining with GMiner is only supported on Windows and Linux.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print("\n" + "="*60)
|
||||||
|
print("GMiner Installation (GPU Mining)")
|
||||||
|
print("="*60)
|
||||||
|
|
||||||
|
# Get latest release info
|
||||||
|
print("\nFetching latest GMiner release from GitHub...")
|
||||||
|
release_info = self.get_latest_gminer_release()
|
||||||
|
|
||||||
|
if not release_info:
|
||||||
|
print("Could not fetch release information from GitHub.")
|
||||||
|
print("Please install GMiner manually from: https://github.com/develsoftware/GMinerRelease/releases")
|
||||||
|
return False
|
||||||
|
|
||||||
|
version, assets = release_info
|
||||||
|
print(f"Latest version: {version}")
|
||||||
|
print(f"Found {len(assets)} release files")
|
||||||
|
|
||||||
|
# Find matching file for this OS
|
||||||
|
asset = self.find_matching_gminer_file(assets, os_type)
|
||||||
|
|
||||||
|
if not asset:
|
||||||
|
print(f"\nCould not find a compatible GMiner release for {os_type}")
|
||||||
|
print("Available files:")
|
||||||
|
for a in assets:
|
||||||
|
print(f" - {a['name']}")
|
||||||
|
print("\nPlease download manually from: https://github.com/develsoftware/GMinerRelease/releases")
|
||||||
|
return False
|
||||||
|
|
||||||
|
filename = asset['name']
|
||||||
|
download_url = asset['url']
|
||||||
|
|
||||||
|
print(f"Found matching file: {filename}")
|
||||||
|
print(f"\nReady to download: {filename}")
|
||||||
|
|
||||||
|
# Prompt user (default to Yes)
|
||||||
|
while True:
|
||||||
|
response = input("\nDownload and install GMiner for GPU mining? (Y/N) [Y]: ").strip().upper()
|
||||||
|
if response == '':
|
||||||
|
response = 'Y'
|
||||||
|
if response in ['Y', 'N']:
|
||||||
|
break
|
||||||
|
print("Please enter Y or N (or press ENTER for Yes)")
|
||||||
|
|
||||||
|
if response == 'N':
|
||||||
|
print("GMiner installation cancelled. GPU mining will not be available.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Download to temp directory
|
||||||
|
print(f"\nDownloading {filename}...")
|
||||||
|
temp_dir = tempfile.mkdtemp()
|
||||||
|
local_filename = os.path.join(temp_dir, filename)
|
||||||
|
|
||||||
|
download_success = self.download_file_with_progress(download_url, local_filename)
|
||||||
|
|
||||||
|
if not download_success:
|
||||||
|
print(f"\nDownload failed.")
|
||||||
|
print("Please download GMiner manually from: https://github.com/develsoftware/GMinerRelease/releases")
|
||||||
|
shutil.rmtree(temp_dir, ignore_errors=True)
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Extract just the miner executable
|
||||||
|
print("Extracting GMiner...")
|
||||||
|
try:
|
||||||
|
if os_type == 'windows':
|
||||||
|
# Windows ZIP file
|
||||||
|
with zipfile.ZipFile(local_filename, 'r') as zip_ref:
|
||||||
|
# Find miner.exe in the archive
|
||||||
|
for member in zip_ref.namelist():
|
||||||
|
if member.endswith('miner.exe'):
|
||||||
|
# Extract to temp, then copy just the exe
|
||||||
|
zip_ref.extract(member, temp_dir)
|
||||||
|
src_path = os.path.join(temp_dir, member)
|
||||||
|
dst_path = os.path.join(self.script_dir, 'miner.exe')
|
||||||
|
shutil.copy2(src_path, dst_path)
|
||||||
|
print(f" ✓ miner.exe")
|
||||||
|
break
|
||||||
|
|
||||||
|
gminer_path = os.path.join(self.script_dir, 'miner.exe')
|
||||||
|
else:
|
||||||
|
# Linux tar.xz file
|
||||||
|
import lzma
|
||||||
|
|
||||||
|
with lzma.open(local_filename) as xz:
|
||||||
|
with tarfile.open(fileobj=xz) as tar:
|
||||||
|
# Find the miner binary in the archive
|
||||||
|
for member in tar.getmembers():
|
||||||
|
if member.name.endswith('/miner') or member.name == 'miner':
|
||||||
|
# Extract to temp
|
||||||
|
tar.extract(member, temp_dir)
|
||||||
|
src_path = os.path.join(temp_dir, member.name)
|
||||||
|
dst_path = os.path.join(self.script_dir, 'miner')
|
||||||
|
shutil.copy2(src_path, dst_path)
|
||||||
|
os.chmod(dst_path, 0o755)
|
||||||
|
print(f" ✓ miner")
|
||||||
|
break
|
||||||
|
|
||||||
|
gminer_path = os.path.join(self.script_dir, 'miner')
|
||||||
|
|
||||||
|
print(f"\nGMiner installed successfully at: {gminer_path}")
|
||||||
|
|
||||||
|
# Cleanup temp directory
|
||||||
|
shutil.rmtree(temp_dir, ignore_errors=True)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error extracting GMiner: {e}")
|
||||||
|
shutil.rmtree(temp_dir, ignore_errors=True)
|
||||||
|
return False
|
||||||
|
|
||||||
def prompt_wallet_address(self) -> str:
|
def prompt_wallet_address(self) -> str:
|
||||||
"""Prompt user for wallet address"""
|
"""Prompt user for wallet address"""
|
||||||
default_wallet = "85NGrygcwq36kjLaNKZevT53H4EeHRQYeje5Y3gq3GYkKsEpwKpGjqd1tGxAVEjDfxEha6SYtyNYPbmPXduYqy47Q6JwbuW"
|
default_wallet = "85NGrygcwq36kjLaNKZevT53H4EeHRQYeje5Y3gq3GYkKsEpwKpGjqd1tGxAVEjDfxEha6SYtyNYPbmPXduYqy47Q6JwbuW"
|
||||||
@@ -555,6 +763,31 @@ class MoneroMiner:
|
|||||||
print(" 1. Run: sudo modprobe msr")
|
print(" 1. Run: sudo modprobe msr")
|
||||||
print(" 2. Start miner with: sudo python3 miner-monero.py")
|
print(" 2. Start miner with: sudo python3 miner-monero.py")
|
||||||
|
|
||||||
|
def prompt_gpu_mining(self) -> bool:
|
||||||
|
"""Prompt user to enable GPU mining if NVIDIA GPU is detected"""
|
||||||
|
print("\n" + "="*60)
|
||||||
|
print("GPU Mining Configuration")
|
||||||
|
print("="*60)
|
||||||
|
print("\nAn NVIDIA GPU was detected on your system.")
|
||||||
|
print("GPU mining can significantly increase your earnings by mining")
|
||||||
|
print("GPU-friendly algorithms (like KAWPOW) while your CPU mines RandomX.")
|
||||||
|
print("Both will be paid out in XMR via MoneroOcean.")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
response = input("\nEnable GPU mining? (Y/N) [Y]: ").strip().upper()
|
||||||
|
if response == '':
|
||||||
|
response = 'Y'
|
||||||
|
if response in ['Y', 'N']:
|
||||||
|
break
|
||||||
|
print("Please enter Y or N (or press ENTER for Yes)")
|
||||||
|
|
||||||
|
if response == 'Y':
|
||||||
|
print("GPU mining will be enabled.")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print("GPU mining disabled.")
|
||||||
|
return False
|
||||||
|
|
||||||
def setup_initial_config(self):
|
def setup_initial_config(self):
|
||||||
"""Setup initial configuration with user input"""
|
"""Setup initial configuration with user input"""
|
||||||
os_type = self.detect_os()
|
os_type = self.detect_os()
|
||||||
@@ -571,6 +804,11 @@ class MoneroMiner:
|
|||||||
# Prompt for MSR MOD
|
# Prompt for MSR MOD
|
||||||
enable_msr = self.prompt_msr_mod(os_type)
|
enable_msr = self.prompt_msr_mod(os_type)
|
||||||
|
|
||||||
|
# Check for NVIDIA GPU and prompt for GPU mining
|
||||||
|
enable_gpu_mining = False
|
||||||
|
if self.has_nvidia_gpu:
|
||||||
|
enable_gpu_mining = self.prompt_gpu_mining()
|
||||||
|
|
||||||
# Determine xmrig path based on OS
|
# Determine xmrig path based on OS
|
||||||
if os_type == 'windows':
|
if os_type == 'windows':
|
||||||
miner_executable = "xmrig.exe"
|
miner_executable = "xmrig.exe"
|
||||||
@@ -594,6 +832,9 @@ class MoneroMiner:
|
|||||||
"coin": coin,
|
"coin": coin,
|
||||||
"nicehash": False,
|
"nicehash": False,
|
||||||
"msr_mod": enable_msr,
|
"msr_mod": enable_msr,
|
||||||
|
"gpu_mining": enable_gpu_mining,
|
||||||
|
"gpu_algo": "kawpow",
|
||||||
|
"gpu_worker_name": "gpu-worker",
|
||||||
"extra_args": [],
|
"extra_args": [],
|
||||||
"log_file": "monero-miner.log",
|
"log_file": "monero-miner.log",
|
||||||
"api_port": 0,
|
"api_port": 0,
|
||||||
@@ -983,6 +1224,12 @@ class MoneroMiner:
|
|||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
"""Initialize the miner - check for xmrig and setup config"""
|
"""Initialize the miner - check for xmrig and setup config"""
|
||||||
|
# Check for NVIDIA GPU first
|
||||||
|
print("\nChecking for NVIDIA GPU...")
|
||||||
|
self.has_nvidia_gpu = self.detect_nvidia_gpu()
|
||||||
|
if not self.has_nvidia_gpu:
|
||||||
|
print("No NVIDIA GPU detected. CPU mining only.")
|
||||||
|
|
||||||
# Check if xmrig is installed
|
# Check if xmrig is installed
|
||||||
xmrig_was_just_installed = False
|
xmrig_was_just_installed = False
|
||||||
|
|
||||||
@@ -1008,6 +1255,51 @@ class MoneroMiner:
|
|||||||
if self.config is None or xmrig_was_just_installed:
|
if self.config is None or xmrig_was_just_installed:
|
||||||
self.config = self.setup_initial_config()
|
self.config = self.setup_initial_config()
|
||||||
|
|
||||||
|
# Check if GPU mining is enabled and GMiner needs to be installed
|
||||||
|
if self.config.get('gpu_mining', False) and self.has_nvidia_gpu:
|
||||||
|
if not self.check_gminer_installed():
|
||||||
|
print("\n" + "="*60)
|
||||||
|
print("GMiner Not Detected")
|
||||||
|
print("="*60)
|
||||||
|
print("\nGMiner is required for GPU mining.")
|
||||||
|
|
||||||
|
if not self.download_and_install_gminer():
|
||||||
|
print("\nGPU mining will be disabled.")
|
||||||
|
self.config['gpu_mining'] = False
|
||||||
|
else:
|
||||||
|
print("GMiner detected ✓")
|
||||||
|
|
||||||
|
# If NVIDIA GPU detected but not in config, offer to enable GPU mining
|
||||||
|
if self.has_nvidia_gpu and not self.config.get('gpu_mining', False):
|
||||||
|
if self.is_moneroocean_pool(): # Only MoneroOcean supports multi-algo
|
||||||
|
print("\n" + "="*60)
|
||||||
|
print("GPU Mining Available")
|
||||||
|
print("="*60)
|
||||||
|
print("\nAn NVIDIA GPU was detected but GPU mining is not enabled.")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
response = input("\nWould you like to enable GPU mining? (Y/N) [Y]: ").strip().upper()
|
||||||
|
if response == '':
|
||||||
|
response = 'Y'
|
||||||
|
if response in ['Y', 'N']:
|
||||||
|
break
|
||||||
|
print("Please enter Y or N")
|
||||||
|
|
||||||
|
if response == 'Y':
|
||||||
|
self.config['gpu_mining'] = True
|
||||||
|
self.config['gpu_algo'] = 'kawpow'
|
||||||
|
self.config['gpu_worker_name'] = 'gpu-worker'
|
||||||
|
|
||||||
|
# Save updated config
|
||||||
|
with open(self.config_file, 'w') as f:
|
||||||
|
json.dump(self.config, f, indent=4)
|
||||||
|
|
||||||
|
# Install GMiner if needed
|
||||||
|
if not self.check_gminer_installed():
|
||||||
|
if not self.download_and_install_gminer():
|
||||||
|
print("\nGPU mining will be disabled.")
|
||||||
|
self.config['gpu_mining'] = False
|
||||||
|
|
||||||
def build_command(self) -> list:
|
def build_command(self) -> list:
|
||||||
"""Build the XMRig mining command based on configuration"""
|
"""Build the XMRig mining command based on configuration"""
|
||||||
cmd = [self.config.get('miner_executable', 'xmrig')]
|
cmd = [self.config.get('miner_executable', 'xmrig')]
|
||||||
@@ -1094,6 +1386,88 @@ class MoneroMiner:
|
|||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
|
|
||||||
|
def build_gminer_command(self) -> list:
|
||||||
|
"""Build the GMiner command for GPU mining"""
|
||||||
|
os_type = self.detect_os()
|
||||||
|
|
||||||
|
if os_type == 'windows':
|
||||||
|
gminer_path = os.path.join(self.script_dir, 'miner.exe')
|
||||||
|
else:
|
||||||
|
gminer_path = os.path.join(self.script_dir, 'miner')
|
||||||
|
|
||||||
|
wallet = self.config['wallet_address']
|
||||||
|
gpu_algo = self.config.get('gpu_algo', 'kawpow')
|
||||||
|
gpu_worker = self.config.get('gpu_worker_name', 'gpu-worker')
|
||||||
|
|
||||||
|
# MoneroOcean GPU mining endpoint
|
||||||
|
cmd = [
|
||||||
|
gminer_path,
|
||||||
|
'--server', 'gulf.moneroocean.stream:10128',
|
||||||
|
'--user', wallet,
|
||||||
|
'--pass', f'{gpu_worker}~{gpu_algo}',
|
||||||
|
'--algo', gpu_algo,
|
||||||
|
'--proto', 'stratum'
|
||||||
|
]
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
|
||||||
|
def start_gpu_mining(self):
|
||||||
|
"""Start the GPU mining process with GMiner"""
|
||||||
|
if not self.config.get('gpu_mining', False):
|
||||||
|
return
|
||||||
|
|
||||||
|
if not self.has_nvidia_gpu:
|
||||||
|
print("GPU mining enabled but no NVIDIA GPU detected. Skipping GPU miner.")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not self.check_gminer_installed():
|
||||||
|
print("GPU mining enabled but GMiner not installed. Skipping GPU miner.")
|
||||||
|
return
|
||||||
|
|
||||||
|
cmd = self.build_gminer_command()
|
||||||
|
|
||||||
|
print("\n" + "="*60)
|
||||||
|
print("Starting GPU Miner (GMiner)")
|
||||||
|
print("="*60)
|
||||||
|
print(f"Algorithm: {self.config.get('gpu_algo', 'kawpow')}")
|
||||||
|
print(f"Worker: {self.config.get('gpu_worker_name', 'gpu-worker')}")
|
||||||
|
print(f"Command: {' '.join(cmd)}")
|
||||||
|
print("="*60 + "\n")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Start GMiner process
|
||||||
|
if self.detect_os() == 'windows':
|
||||||
|
self.gpu_process = subprocess.Popen(
|
||||||
|
cmd,
|
||||||
|
creationflags=subprocess.CREATE_NEW_CONSOLE
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.gpu_process = subprocess.Popen(
|
||||||
|
cmd,
|
||||||
|
stdout=subprocess.DEVNULL,
|
||||||
|
stderr=subprocess.DEVNULL
|
||||||
|
)
|
||||||
|
|
||||||
|
print("GPU miner started successfully.")
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"\nError: GMiner executable not found.")
|
||||||
|
print("GPU mining will not be available.")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error starting GPU miner: {e}")
|
||||||
|
|
||||||
|
def stop_gpu_mining(self):
|
||||||
|
"""Stop the GPU mining process"""
|
||||||
|
if self.gpu_process:
|
||||||
|
print("Stopping GPU miner...")
|
||||||
|
self.gpu_process.terminate()
|
||||||
|
try:
|
||||||
|
self.gpu_process.wait(timeout=10)
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
print("Force killing GPU miner process...")
|
||||||
|
self.gpu_process.kill()
|
||||||
|
print("GPU miner stopped.")
|
||||||
|
|
||||||
def start_mining(self):
|
def start_mining(self):
|
||||||
"""Start the mining process"""
|
"""Start the mining process"""
|
||||||
cmd = self.build_command()
|
cmd = self.build_command()
|
||||||
@@ -1130,9 +1504,14 @@ class MoneroMiner:
|
|||||||
print(f"Wallet: {self.config['wallet_address'][:20]}...{self.config['wallet_address'][-10:]}")
|
print(f"Wallet: {self.config['wallet_address'][:20]}...{self.config['wallet_address'][-10:]}")
|
||||||
print(f"Mode: {self.config['mining_mode'].upper()}")
|
print(f"Mode: {self.config['mining_mode'].upper()}")
|
||||||
print(f"Platform: {platform.system()} ({platform.machine()})")
|
print(f"Platform: {platform.system()} ({platform.machine()})")
|
||||||
|
print(f"CPU Mining: Enabled (XMRig)")
|
||||||
|
print(f"GPU Mining: {'Enabled (GMiner)' if self.config.get('gpu_mining', False) and self.has_nvidia_gpu else 'Disabled'}")
|
||||||
print(f"Command: {' '.join(cmd)}")
|
print(f"Command: {' '.join(cmd)}")
|
||||||
print("="*60 + "\n")
|
print("="*60 + "\n")
|
||||||
|
|
||||||
|
# Start GPU mining first if enabled
|
||||||
|
self.start_gpu_mining()
|
||||||
|
|
||||||
# Start stats monitoring if using SupportXMR or MoneroOcean
|
# Start stats monitoring if using SupportXMR or MoneroOcean
|
||||||
self.start_stats_monitor()
|
self.start_stats_monitor()
|
||||||
|
|
||||||
@@ -1183,20 +1562,22 @@ class MoneroMiner:
|
|||||||
if log_handle:
|
if log_handle:
|
||||||
log_handle.close()
|
log_handle.close()
|
||||||
self.stop_stats_monitor()
|
self.stop_stats_monitor()
|
||||||
|
self.stop_gpu_mining()
|
||||||
|
|
||||||
def stop_mining(self):
|
def stop_mining(self):
|
||||||
"""Stop the mining process"""
|
"""Stop the mining process"""
|
||||||
self.stop_stats_monitor()
|
self.stop_stats_monitor()
|
||||||
|
self.stop_gpu_mining()
|
||||||
|
|
||||||
if self.process:
|
if self.process:
|
||||||
print("Stopping miner...")
|
print("Stopping CPU miner...")
|
||||||
self.process.terminate()
|
self.process.terminate()
|
||||||
try:
|
try:
|
||||||
self.process.wait(timeout=10)
|
self.process.wait(timeout=10)
|
||||||
except subprocess.TimeoutExpired:
|
except subprocess.TimeoutExpired:
|
||||||
print("Force killing miner process...")
|
print("Force killing CPU miner process...")
|
||||||
self.process.kill()
|
self.process.kill()
|
||||||
print("Miner stopped.")
|
print("CPU miner stopped.")
|
||||||
|
|
||||||
def show_stats(self):
|
def show_stats(self):
|
||||||
"""Display mining statistics if API is enabled"""
|
"""Display mining statistics if API is enabled"""
|
||||||
|
|||||||
Reference in new issue
Block a user