From 02c23db39f969432a40b096229667f71c9f3e9a3 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 2 Sep 2025 19:29:37 +0300 Subject: [PATCH 01/30] notes --- MINE/notes.md | 6 ++++-- MINE/rin/README.md | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/MINE/notes.md b/MINE/notes.md index cef5a04..5513971 100644 --- a/MINE/notes.md +++ b/MINE/notes.md @@ -61,10 +61,12 @@ sudo docker exec -it amd-strix-halo-llama-rocm bash -c "/mnt/dl/rinhash/cpumine [sudo docker exec -it amd-strix-halo-llama-rocm bash -c "/mnt/dl/rinhash/cpuminer-opt-rin/cpuminer --algo rinhash --benchmark -t 4" rinhash.mine.zergpool.com:7148 c=RIN] -!!!!!!!!!!!!!!!!!!!!!! BEST CURRENT CPU !!!!!!!!!!!!!!!!!! Active exchange: Listed on Exbitron (RIN/USDT) + sudo docker exec -it amd-strix-halo-llama-rocm bash -c "/mnt/dl/rinhash/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://rinhash.mine.zergpool.com:7148 -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC,mc=RIN,ID=StrixHalo -t 32" ------------------------------------------------------------------ +----------------------------------------------------------------- +SOLO: +/home/db/Downloads/rinhash/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://192.168.0.188:3333 -u username.workername -p x -t 28 ./cpuminer --algo rinhash --url [pool_url] --user [your_rin_wallet] --pass x --threads 32 diff --git a/MINE/rin/README.md b/MINE/rin/README.md index 26a84e3..3d898fd 100644 --- a/MINE/rin/README.md +++ b/MINE/rin/README.md @@ -5,6 +5,8 @@ ### **Option 1: Solo Mining (Single Miner, All Rewards to You)** ```bash # Start solo mining proxy +cd /mnt/shared/DEV/repos/d-popov.com/scripts + ./MINE/rin/start_stratum_proxy.sh # Run your miner From 1bcf7109cff9098f57e3b0f46bd0b70894252e11 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Thu, 4 Sep 2025 21:06:37 +0300 Subject: [PATCH 02/30] real mining --- MINE/rin/QUICK_REFERENCE.md | 21 ++ MINE/rin/README.md | 2 +- MINE/rin/miner/readme.md | 23 -- MINE/rin/stratum_pool.py | 2 +- MINE/rin/stratum_proxy.py | 468 ++++++++++++++++++++++++++---------- 5 files changed, 361 insertions(+), 155 deletions(-) delete mode 100644 MINE/rin/miner/readme.md diff --git a/MINE/rin/QUICK_REFERENCE.md b/MINE/rin/QUICK_REFERENCE.md index 4fb079f..6debf73 100644 --- a/MINE/rin/QUICK_REFERENCE.md +++ b/MINE/rin/QUICK_REFERENCE.md @@ -43,4 +43,25 @@ ./MINE/rin/start_stratum_proxy.sh & sleep 5 ./cpuminer -a rinhash -o stratum+tcp://127.0.0.1:3333 -u user -p pass -t 4 + + + +## Check wallets + +# First, check available wallets and load one if needed +curl -u rinrpc:745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90 -d '{"jsonrpc":"1.0","id":"1","method":"listwalletdir","params":[]}' -H 'content-type: text/plain;' http://127.0.0.1:9556/ + +# Load wallet (replace "main" with your wallet name) +curl -u rinrpc:745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90 -d '{"jsonrpc":"1.0","id":"1","method":"loadwallet","params":["main"]}' -H 'content-type: text/plain;' http://127.0.0.1:9556/ + +# Total received by your address +curl -u rinrpc:745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90 -d '{"jsonrpc":"1.0","id":"1","method":"getreceivedbyaddress","params":["rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q",0]}' -H 'content-type: text/plain;' http://127.0.0.1:9556/ + +# Wallet balance +curl -u rinrpc:745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90 -d '{"jsonrpc":"1.0","id":"1","method":"getbalance","params":[]}' -H 'content-type: text/plain;' http://127.0.0.1:9556/ + +# Recent transactions +curl -u rinrpc:745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90 -d '{"jsonrpc":"1.0","id":"1","method":"listtransactions","params":[]}' -H 'content-type: text/plain;' http://127.0.0.1:9556/ ``` + + diff --git a/MINE/rin/README.md b/MINE/rin/README.md index 3d898fd..97fcf50 100644 --- a/MINE/rin/README.md +++ b/MINE/rin/README.md @@ -27,7 +27,7 @@ cd /mnt/shared/DEV/repos/d-popov.com/scripts ./cpuminer -a rinhash -o stratum+tcp://YOUR_IP:3333 -u rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q.worker1 -p x # Option 3: Traditional username (rewards to pool address) -./cpuminer -a rinhash -o stratum+tcp://192.168.0.188:3333 -u username.workername -p x -t 4 +./cpuminer -a rinhash -o stratum+tcp://192.168.0.188:3333 -u username.workername -p x -t 24 ``` **Result**: Block rewards distributed among all miners based on shares diff --git a/MINE/rin/miner/readme.md b/MINE/rin/miner/readme.md deleted file mode 100644 index 53fb967..0000000 --- a/MINE/rin/miner/readme.md +++ /dev/null @@ -1,23 +0,0 @@ -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 \ No newline at end of file diff --git a/MINE/rin/stratum_pool.py b/MINE/rin/stratum_pool.py index be7dea6..f32b699 100644 --- a/MINE/rin/stratum_pool.py +++ b/MINE/rin/stratum_pool.py @@ -344,7 +344,7 @@ class RinCoinMiningPool: ]) # Send difficulty (lower for CPU mining) - self.send_stratum_notification(client, "mining.set_difficulty", [0.001]) + self.send_stratum_notification(client, "mining.set_difficulty", [0.0001]) # Send initial job if self.get_block_template(): diff --git a/MINE/rin/stratum_proxy.py b/MINE/rin/stratum_proxy.py index d780f32..e9f2e2e 100644 --- a/MINE/rin/stratum_proxy.py +++ b/MINE/rin/stratum_proxy.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """ -RinCoin Stratum Proxy Server -Bridges cpuminer-opt-rin (Stratum protocol) to RinCoin node (RPC protocol) +RinCoin Stratum Proxy Server - REAL MINING VERSION +Properly constructs Stratum jobs and validates/submits real blocks """ import socket @@ -31,8 +31,9 @@ class RinCoinStratumProxy: self.job_counter = 0 self.current_job = None self.running = True + self.extranonce1_counter = 0 - print(f"RinCoin Stratum Proxy Server") + print(f"RinCoin Stratum Proxy Server - REAL MINING") print(f"Stratum: {stratum_host}:{stratum_port}") print(f"RPC: {rpc_host}:{rpc_port}") print(f"Target: {target_address}") @@ -51,7 +52,7 @@ class RinCoinStratumProxy: "params": params } - response = requests.post(url, json=payload, headers=headers, auth=auth, timeout=10) + response = requests.post(url, json=payload, headers=headers, auth=auth, timeout=30) if response.status_code == 200: result = response.json() @@ -66,37 +67,230 @@ class RinCoinStratumProxy: except Exception as e: print(f"RPC Call Error: {e}") return None - + + def encode_varint(self, n): + """Encode integer as Bitcoin-style varint""" + if n < 0xfd: + return bytes([n]) + elif n <= 0xffff: + return b"\xfd" + struct.pack(' 1: + if len(hashes) % 2 == 1: + hashes.append(hashes[-1]) # Duplicate last hash if odd + + next_level = [] + for i in range(0, len(hashes), 2): + combined = hashes[i] + hashes[i + 1] + next_level.append(hashlib.sha256(hashlib.sha256(combined).digest()).digest()) + + hashes = next_level + + return hashes[0] if hashes else b'\x00' * 32 + + except Exception as e: + print(f"Merkle root calculation error: {e}") + return b'\x00' * 32 + + def bits_to_target(self, bits_hex): + """Convert bits to target""" + try: + bits = int(bits_hex, 16) + exponent = bits >> 24 + mantissa = bits & 0xffffff + target = mantissa * (256 ** (exponent - 3)) + return f"{target:064x}" + except: + return "0000ffff00000000000000000000000000000000000000000000000000000000" + def get_block_template(self): - """Get new block template from RinCoin node""" + """Get new block template and create Stratum job""" try: template = self.rpc_call("getblocktemplate", [{"rules": ["segwit", "mweb"]}]) - if template: - self.job_counter += 1 + if not template: + return None - # Store the full template for later block construction - job = { - "job_id": f"job_{self.job_counter}", - "template": template, # Store full template - "prevhash": template.get("previousblockhash", "0" * 64), - "coinb1": "01000000" + "0" * 60, # Simplified coinbase (will be properly constructed on submission) - "coinb2": "ffffffff", - "merkle_branch": [], - "version": f"{template.get('version', 1):08x}", - "nbits": template.get("bits", "1d00ffff"), - "ntime": f"{int(time.time()):08x}", - "clean_jobs": True, - "target": template.get("target", "0000ffff00000000000000000000000000000000000000000000000000000000") - } - - self.current_job = job - print(f"New job created: {job['job_id']} (coinbase value: {template.get('coinbasevalue', 0)} satoshis)") - return job - return None + self.job_counter += 1 + + job = { + "job_id": f"job_{self.job_counter:08x}", + "template": template, + "prevhash": template.get("previousblockhash", "0" * 64), + "version": template.get('version', 1), + "bits": template.get('bits', '1d00ffff'), + "ntime": f"{int(time.time()):08x}", + "target": self.bits_to_target(template.get('bits', '1d00ffff')), + "height": template.get('height', 0), + "coinbasevalue": template.get('coinbasevalue', 0), + "transactions": template.get('transactions', []) + } + + self.current_job = job + print(f"New job: {job['job_id']} | Height: {job['height']} | Reward: {job['coinbasevalue']/100000000:.2f} RIN") + return job + except Exception as e: print(f"Get block template error: {e}") return None - + + def submit_share(self, job, extranonce1, extranonce2, ntime, nonce): + """Validate share and submit block if valid""" + try: + print(f"Share: job={job['job_id']} nonce={nonce}") + + # Build coinbase transaction + coinbase = self.build_coinbase_transaction(job['template'], extranonce1, extranonce2) + if not coinbase: + return False, "Coinbase construction failed" + + # Calculate coinbase transaction hash + coinbase_hash = hashlib.sha256(hashlib.sha256(coinbase).digest()).digest()[::-1] + + # Calculate merkle root + merkle_root = self.calculate_merkle_root(coinbase_hash, job['transactions']) + + # Build block header + header = b'' + header += struct.pack(' target_int: + # Valid share but not a block + return True, "Share accepted" + + # Valid block! Build full block and submit + print(f"BLOCK FOUND! Hash: {block_hash_hex}") + + # Build complete block + block = header + + # Transaction count + tx_count = 1 + len(job['transactions']) + block += self.encode_varint(tx_count) + + # Add coinbase transaction + block += coinbase + + # Add other transactions + for tx in job['transactions']: + block += bytes.fromhex(tx['data']) + + # Submit block + block_hex = block.hex() + result = self.rpc_call("submitblock", [block_hex]) + + if result is None: + print(f"Block accepted: {block_hash_hex}") + print(f"Reward: {job['coinbasevalue']/100000000:.2f} RIN -> {self.target_address}") + return True, "Block found and submitted" + else: + print(f"Block rejected: {result}") + return False, f"Block rejected: {result}" + + except Exception as e: + print(f"Share submission error: {e}") + return False, f"Submission error: {e}" + def send_stratum_response(self, client, msg_id, result, error=None): """Send Stratum response to client""" try: @@ -105,12 +299,11 @@ class RinCoinStratumProxy: "result": result, "error": error } - message = json.dumps(response) + "\n" client.send(message.encode('utf-8')) except Exception as e: print(f"Send response error: {e}") - + def send_stratum_notification(self, client, method, params): """Send Stratum notification to client""" try: @@ -119,12 +312,11 @@ class RinCoinStratumProxy: "method": method, "params": params } - message = json.dumps(notification) + "\n" client.send(message.encode('utf-8')) except Exception as e: print(f"Send notification error: {e}") - + def handle_stratum_message(self, client, addr, message): """Handle incoming Stratum message from miner""" try: @@ -133,75 +325,71 @@ class RinCoinStratumProxy: msg_id = data.get("id") params = data.get("params", []) - print(f"[{addr}] {method}: {params}") - if method == "mining.subscribe": + # Generate unique extranonce1 for this connection + self.extranonce1_counter += 1 + extranonce1 = f"{self.extranonce1_counter:08x}" + + # Store extranonce1 for this client + if addr not in self.clients: + self.clients[addr] = {} + self.clients[addr]['extranonce1'] = extranonce1 + # Subscribe response self.send_stratum_response(client, msg_id, [ [["mining.set_difficulty", "subscription_id"], ["mining.notify", "subscription_id"]], - "extranonce1", - 4 + extranonce1, + 4 # extranonce2 size ]) # Send difficulty - self.send_stratum_notification(client, "mining.set_difficulty", [1]) + self.send_stratum_notification(client, "mining.set_difficulty", [0.0001]) # Send initial job - if self.get_block_template(): - job = self.current_job - self.send_stratum_notification(client, "mining.notify", [ - job["job_id"], - job["prevhash"], - job["coinb1"], - job["coinb2"], - job["merkle_branch"], - job["version"], - job["nbits"], - job["ntime"], - job["clean_jobs"] - ]) + if self.current_job: + self.send_job_to_client(client, self.current_job) + else: + if self.get_block_template(): + self.send_job_to_client(client, self.current_job) elif method == "mining.authorize": - # Authorization + username = params[0] if params else "anonymous" + self.clients[addr]['username'] = username + self.send_stratum_response(client, msg_id, True) + print(f"[{addr}] Authorized as {username}") + + elif method == "mining.extranonce.subscribe": + # Handle extranonce subscription self.send_stratum_response(client, msg_id, True) - print(f"[{addr}] Authorized") elif method == "mining.submit": - # Submit share - print(f"[{addr}] Share submitted: {params}") - - # Try to submit block if it's a valid solution - try: - if self.current_job and len(params) >= 5: - job_id = params[0] - extranonce2 = params[1] - ntime = params[2] - nonce = params[3] + if len(params) >= 5: + username = params[0] + job_id = params[1] + extranonce2 = params[2] + ntime = params[3] + nonce = params[4] + + print(f"[{addr}] Submit: {username} | job={job_id} | nonce={nonce}") + + # Validate submission + if self.current_job and job_id == self.current_job['job_id']: + extranonce1 = self.clients[addr].get('extranonce1', '00000000') - print(f"[{addr}] Attempting to submit block solution...") - print(f" Job: {job_id}, Nonce: {nonce}, Time: {ntime}") + # Submit share + success, message = self.submit_share(self.current_job, extranonce1, extranonce2, ntime, nonce) - # Use generatetoaddress to submit the mining result - # This is a simplified approach - the real block construction would be more complex - result = self.rpc_call("generatetoaddress", [1, self.target_address, 1]) - - if result and len(result) > 0: - block_hash = result[0] - print(f"๐ŸŽ‰ [{addr}] BLOCK FOUND! Hash: {block_hash}") - print(f"๐Ÿ’ฐ Block reward sent to: {self.target_address}") + if success: self.send_stratum_response(client, msg_id, True) + if "Block found" in message: + # Get new job after block found + threading.Thread(target=self.update_job_after_block, daemon=True).start() else: - # Accept as share even if not a block - print(f"[{addr}] Share accepted (not a block)") - self.send_stratum_response(client, msg_id, True) + self.send_stratum_response(client, msg_id, False, message) else: - print(f"[{addr}] Invalid share parameters") - self.send_stratum_response(client, msg_id, False, "Invalid parameters") - - except Exception as e: - print(f"[{addr}] Block submission error: {e}") - # Still accept the share for mining statistics - self.send_stratum_response(client, msg_id, True) + self.send_stratum_response(client, msg_id, False, "Stale job") + else: + self.send_stratum_response(client, msg_id, False, "Invalid parameters") else: print(f"[{addr}] Unknown method: {method}") @@ -211,11 +399,51 @@ class RinCoinStratumProxy: print(f"[{addr}] Invalid JSON: {message}") except Exception as e: print(f"[{addr}] Message handling error: {e}") - + + def send_job_to_client(self, client, job): + """Send mining job to specific client""" + try: + # Send proper Stratum job + self.send_stratum_notification(client, "mining.notify", [ + job["job_id"], + job["prevhash"], + "", # coinb1 (empty for now - miner handles coinbase) + "", # coinb2 (empty for now - miner handles coinbase) + [], # merkle_branch (empty for now - we calculate merkle root) + f"{job['version']:08x}", + job["bits"], + job["ntime"], + True # clean_jobs + ]) + except Exception as e: + print(f"Failed to send job: {e}") + + def update_job_after_block(self): + """Update job after a block is found""" + time.sleep(2) # Brief delay to let network propagate + if self.get_block_template(): + self.broadcast_new_job() + + def broadcast_new_job(self): + """Broadcast new job to all connected clients""" + if not self.current_job: + return + + print(f"Broadcasting new job to {len(self.clients)} clients") + + for addr, client_data in list(self.clients.items()): + try: + if 'socket' in client_data: + self.send_job_to_client(client_data['socket'], self.current_job) + except Exception as e: + print(f"Failed to send job to {addr}: {e}") + def handle_client(self, client, addr): """Handle individual client connection""" print(f"[{addr}] Connected") - self.clients[addr] = client + if addr not in self.clients: + self.clients[addr] = {} + self.clients[addr]['socket'] = client try: while self.running: @@ -236,48 +464,41 @@ class RinCoinStratumProxy: if addr in self.clients: del self.clients[addr] print(f"[{addr}] Disconnected") - + def job_updater(self): """Periodically update mining jobs""" while self.running: try: - # Update job every 30 seconds - time.sleep(30) + time.sleep(30) # Update every 30 seconds + + old_height = self.current_job['height'] if self.current_job else 0 if self.get_block_template(): - job = self.current_job - print(f"Broadcasting new job: {job['job_id']}") - - # Send to all connected clients - for addr, client in list(self.clients.items()): - try: - self.send_stratum_notification(client, "mining.notify", [ - job["job_id"], - job["prevhash"], - job["coinb1"], - job["coinb2"], - job["merkle_branch"], - job["version"], - job["nbits"], - job["ntime"], - job["clean_jobs"] - ]) - except Exception as e: - print(f"Failed to send job to {addr}: {e}") - + new_height = self.current_job['height'] + if new_height > old_height: + print(f"New block detected! Broadcasting new job...") + self.broadcast_new_job() + except Exception as e: print(f"Job updater error: {e}") - + def start(self): """Start the Stratum proxy server""" try: # Test RPC connection blockchain_info = self.rpc_call("getblockchaininfo") if not blockchain_info: - print("โŒ Failed to connect to RinCoin node!") + print("Failed to connect to RinCoin node!") return - print(f"โœ… Connected to RinCoin node (block {blockchain_info.get('blocks', 'unknown')})") + print(f"Connected to RinCoin node") + print(f"Current height: {blockchain_info.get('blocks', 'unknown')}") + print(f"Chain: {blockchain_info.get('chain', 'unknown')}") + + # Get initial block template + if not self.get_block_template(): + print("Failed to get initial block template!") + return # Start job updater thread job_thread = threading.Thread(target=self.job_updater, daemon=True) @@ -289,13 +510,13 @@ class RinCoinStratumProxy: server_socket.bind((self.stratum_host, self.stratum_port)) server_socket.listen(10) - print(f"๐Ÿš€ Stratum proxy listening on {self.stratum_host}:{self.stratum_port}") - print("Ready for cpuminer-opt-rin connections...") + print(f"REAL Mining Stratum proxy ready!") + print(f"Listening on {self.stratum_host}:{self.stratum_port}") + print(f"Mining to: {self.target_address}") + print(f"Current job: {self.current_job['job_id'] if self.current_job else 'None'}") print("") - print(f"๐Ÿ’ฐ Block rewards will be sent to: {self.target_address}") - print("") - print("Connect your miner with:") - print(f"./cpuminer -a rinhash -o stratum+tcp://{self.stratum_host}:{self.stratum_port} -u user -p pass -t 28") + print("Miner command:") + print(f"./cpuminer -a rinhash -o stratum+tcp://{self.stratum_host}:{self.stratum_port} -u worker1 -p x -t 4") print("") while self.running: @@ -314,19 +535,6 @@ class RinCoinStratumProxy: except Exception as e: print(f"Server error: {e}") - except OSError as e: - if "Address already in use" in str(e): - print(f"โŒ Port {self.stratum_port} is already in use!") - print("") - print("๐Ÿ” Check what's using the port:") - print(f"sudo netstat -tlnp | grep :{self.stratum_port}") - print("") - print("๐Ÿ›‘ Kill existing process:") - print(f"sudo lsof -ti:{self.stratum_port} | xargs sudo kill -9") - print("") - print("๐Ÿ”„ Or use a different port by editing the script") - else: - print(f"Failed to start server: {e}") except Exception as e: print(f"Failed to start server: {e}") finally: @@ -334,4 +542,4 @@ class RinCoinStratumProxy: if __name__ == "__main__": proxy = RinCoinStratumProxy() - proxy.start() + proxy.start() \ No newline at end of file From fec5f35cce9bba2ad7744701a5a05ca4bccc86e4 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Fri, 5 Sep 2025 00:10:46 +0300 Subject: [PATCH 03/30] latest fixes --- MINE/rin/stratum_proxy.py | 74 +++++++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 18 deletions(-) diff --git a/MINE/rin/stratum_proxy.py b/MINE/rin/stratum_proxy.py index e9f2e2e..294b316 100644 --- a/MINE/rin/stratum_proxy.py +++ b/MINE/rin/stratum_proxy.py @@ -14,7 +14,7 @@ import struct from requests.auth import HTTPBasicAuth class RinCoinStratumProxy: - def __init__(self, stratum_host='0.0.0.0', stratum_port=3333, + def __init__(self, stratum_host='0.0.0.0', stratum_port=3334, rpc_host='127.0.0.1', rpc_port=9556, rpc_user='rinrpc', rpc_password='745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90', target_address='rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q'): @@ -80,18 +80,28 @@ class RinCoinStratumProxy: return b"\xff" + struct.pack(' {self.target_address}") + print(f"โœ… Block accepted: {block_hash_hex}") + print(f"๐Ÿ’ฐ Reward: {job['coinbasevalue']/100000000:.2f} RIN -> {self.target_address}") + print(f"๐Ÿ“Š Block height: {job['height']}") return True, "Block found and submitted" else: - print(f"Block rejected: {result}") + print(f"โŒ Block rejected: {result}") + print(f"๐Ÿ“ฆ Block hash: {block_hash_hex}") + print(f"๐Ÿ“Š Block height: {job['height']}") + print(f"๐Ÿ” Debug: Block size {len(block_hex)//2} bytes, {len(job['transactions'])} transactions") return False, f"Block rejected: {result}" except Exception as e: @@ -387,7 +409,23 @@ class RinCoinStratumProxy: else: self.send_stratum_response(client, msg_id, False, message) else: - self.send_stratum_response(client, msg_id, False, "Stale job") + # For stale jobs, still validate for blocks but don't require exact job match + # This prevents missing blocks due to job timing issues + if self.current_job: + extranonce1 = self.clients[addr].get('extranonce1', '00000000') + # Use current job template but allow stale job_id + success, message = self.submit_share(self.current_job, extranonce1, extranonce2, ntime, nonce) + + if success: + self.send_stratum_response(client, msg_id, True) + if "Block found" in message: + # Get new job after block found + threading.Thread(target=self.update_job_after_block, daemon=True).start() + else: + # Accept as share even if block validation fails for stale jobs + self.send_stratum_response(client, msg_id, True) + else: + self.send_stratum_response(client, msg_id, True) else: self.send_stratum_response(client, msg_id, False, "Invalid parameters") From 48060c360f75e0dc13004b0bfa0da53be7106100 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Fri, 5 Sep 2025 00:57:22 +0300 Subject: [PATCH 04/30] pool uses proxy --- MINE/rin/start_stratum_proxy.sh | 18 +-- MINE/rin/stratum_pool.py | 271 ++++++++++---------------------- MINE/rin/stratum_proxy.py | 176 +++++++++++---------- 3 files changed, 183 insertions(+), 282 deletions(-) diff --git a/MINE/rin/start_stratum_proxy.sh b/MINE/rin/start_stratum_proxy.sh index 36c03d7..f6ad91f 100644 --- a/MINE/rin/start_stratum_proxy.sh +++ b/MINE/rin/start_stratum_proxy.sh @@ -31,22 +31,22 @@ python3 -c "import requests" 2>/dev/null || { echo "โœ… Python dependencies ready" -# Check if port 3333 is already in use -if netstat -tln | grep -q ":3333 "; then +# Check if port 3334 is already in use +if netstat -tln | grep -q ":3334 "; then echo "" - echo "โš ๏ธ Port 3333 is already in use!" + echo "โš ๏ธ Port 3334 is already in use!" echo "" - echo "๐Ÿ” Process using port 3333:" - sudo netstat -tlnp | grep ":3333 " || echo "Could not determine process" + echo "๐Ÿ” Process using port 3334:" + sudo netstat -tlnp | grep ":3334 " || echo "Could not determine process" echo "" echo "๐Ÿ›‘ To kill existing process:" - echo "sudo lsof -ti:3333 | xargs sudo kill -9" + echo "sudo lsof -ti:3334 | xargs sudo kill -9" echo "" read -p "Kill existing process and continue? (y/N): " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then - echo "Killing processes using port 3333..." - sudo lsof -ti:3333 | xargs sudo kill -9 2>/dev/null || echo "No processes to kill" + echo "Killing processes using port 3334..." + sudo lsof -ti:3334 | xargs sudo kill -9 2>/dev/null || echo "No processes to kill" sleep 2 else echo "Exiting..." @@ -59,7 +59,7 @@ echo "๐Ÿš€ Starting Stratum Proxy Server..." echo "This will bridge cpuminer-opt-rin to your RinCoin node" echo "" echo "After it starts, connect your miner with:" -echo "sudo docker exec -it amd-strix-halo-llama-rocm bash -c \"/mnt/dl/rinhash/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://127.0.0.1:3333 -u user -p pass -t 28\"" +echo "sudo docker exec -it amd-strix-halo-llama-rocm bash -c \"/mnt/dl/rinhash/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://127.0.0.1:3334 -u user -p pass -t 28\"" echo "" echo "Press Ctrl+C to stop the proxy" echo "" diff --git a/MINE/rin/stratum_pool.py b/MINE/rin/stratum_pool.py index f32b699..692b94f 100644 --- a/MINE/rin/stratum_pool.py +++ b/MINE/rin/stratum_pool.py @@ -18,28 +18,22 @@ from requests.auth import HTTPBasicAuth # Import web interface from pool_web_interface import start_web_interface -class RinCoinMiningPool: +# Import stratum base class +from stratum_proxy import RinCoinStratumBase + +class RinCoinMiningPool(RinCoinStratumBase): def __init__(self, stratum_host='0.0.0.0', stratum_port=3333, rpc_host='127.0.0.1', rpc_port=9556, rpc_user='rinrpc', rpc_password='745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90', pool_address='rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q', pool_fee_percent=1.0): - self.stratum_host = stratum_host - self.stratum_port = stratum_port - self.rpc_host = rpc_host - self.rpc_port = rpc_port - self.rpc_user = rpc_user - self.rpc_password = rpc_password + # Initialize base class + super().__init__(stratum_host, stratum_port, rpc_host, rpc_port, rpc_user, rpc_password, pool_address) + self.pool_address = pool_address self.pool_fee_percent = pool_fee_percent - # Miner tracking - self.clients = {} # {addr: {'client': socket, 'worker': str, 'user': str, 'shares': 0, 'last_share': time}} - self.job_counter = 0 - self.current_job = None - self.running = True - # Pool statistics self.total_shares = 0 self.total_blocks = 0 @@ -107,75 +101,26 @@ class RinCoinMiningPool: self.db.commit() - def rpc_call(self, method, params=[]): - """Make RPC call to RinCoin node""" - try: - url = f"http://{self.rpc_host}:{self.rpc_port}/" - headers = {'content-type': 'text/plain'} - auth = HTTPBasicAuth(self.rpc_user, self.rpc_password) - - payload = { - "jsonrpc": "1.0", - "id": "mining_pool", - "method": method, - "params": params - } - - response = requests.post(url, json=payload, headers=headers, auth=auth, timeout=10) - - if response.status_code == 200: - result = response.json() - if 'error' in result and result['error'] is not None: - print(f"RPC Error: {result['error']}") - return None - return result.get('result') - else: - print(f"HTTP Error: {response.status_code}") - return None - - except Exception as e: - print(f"RPC Call Error: {e}") - return None - - def get_block_template(self): - """Get new block template from RinCoin node""" - try: - template = self.rpc_call("getblocktemplate", [{"rules": ["segwit", "mweb"]}]) - if template: - self.job_counter += 1 - - job = { - "job_id": f"job_{self.job_counter}", - "template": template, - "prevhash": template.get("previousblockhash", "0" * 64), - "coinb1": "01000000" + "0" * 60, - "coinb2": "ffffffff", - "merkle_branch": [], - "version": f"{template.get('version', 1):08x}", - "nbits": template.get("bits", "1d00ffff"), - "ntime": f"{int(time.time()):08x}", - "clean_jobs": True, - "target": template.get("target", "0000ffff00000000000000000000000000000000000000000000000000000000") - } - - self.current_job = job - print(f"New job created: {job['job_id']} (coinbase value: {template.get('coinbasevalue', 0)} satoshis)") - return job - return None - except Exception as e: - print(f"Get block template error: {e}") - return None + def get_pool_block_template(self): + """Get new block template and create pool-style job""" + template = super().get_block_template() + if template: + # Convert to pool-style job format if needed + job = self.current_job + if job: + # Add pool-specific fields + job["coinb1"] = "01000000" + "0" * 60 + job["coinb2"] = "ffffffff" + job["merkle_branch"] = [] + job["clean_jobs"] = True + return job + return None def validate_rincoin_address(self, address): """Validate if an address is a valid RinCoin address""" - if not address or not address.startswith('rin'): - return False - try: - result = self.rpc_call("validateaddress", [address]) - return result and result.get('isvalid', False) - except Exception as e: - print(f"Address validation error: {e}") + return self.decode_bech32_address(address) is not None + except: return False def register_miner(self, user, worker, address=None): @@ -297,33 +242,7 @@ class RinCoinMiningPool: if miners_without_addresses: print(f"๐Ÿ“Š Summary: {len(miners_with_addresses)} miners with addresses, {len(miners_without_addresses)} without (rewards to pool)") - def send_stratum_response(self, client, msg_id, result, error=None): - """Send Stratum response to client""" - try: - response = { - "id": msg_id, - "result": result, - "error": error - } - - message = json.dumps(response) + "\n" - client.send(message.encode('utf-8')) - except Exception as e: - print(f"Send response error: {e}") - - def send_stratum_notification(self, client, method, params): - """Send Stratum notification to client""" - try: - notification = { - "id": None, - "method": method, - "params": params - } - - message = json.dumps(notification) + "\n" - client.send(message.encode('utf-8')) - except Exception as e: - print(f"Send notification error: {e}") + # Use inherited send_stratum_response and send_stratum_notification from base class def handle_stratum_message(self, client, addr, message): """Handle incoming Stratum message from miner""" @@ -347,7 +266,7 @@ class RinCoinMiningPool: self.send_stratum_notification(client, "mining.set_difficulty", [0.0001]) # Send initial job - if self.get_block_template(): + if self.get_pool_block_template(): job = self.current_job self.send_stratum_notification(client, "mining.notify", [ job["job_id"], @@ -355,8 +274,8 @@ class RinCoinMiningPool: job["coinb1"], job["coinb2"], job["merkle_branch"], - job["version"], - job["nbits"], + f"{job['version']:08x}", + job["bits"], job["ntime"], job["clean_jobs"] ]) @@ -416,7 +335,8 @@ class RinCoinMiningPool: 'miner_id': miner_id, 'address': miner_address, 'shares': 0, - 'last_share': time.time() + 'last_share': time.time(), + 'extranonce1': '00000000' # Default extranonce1 } if miner_address: @@ -432,101 +352,70 @@ class RinCoinMiningPool: if addr not in self.clients: self.send_stratum_response(client, msg_id, False, "Not authorized") return - + miner_info = self.clients[addr] - + try: if self.current_job and len(params) >= 5: - job_id = params[0] - extranonce2 = params[1] - ntime = params[2] - nonce = params[3] + username = params[0] + job_id = params[1] + extranonce2 = params[2] + ntime = params[3] + nonce = params[4] - # Calculate actual difficulty from the share submission - # 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 + # Use base class to validate and submit share + extranonce1 = miner_info.get('extranonce1', '00000000') + miner_address = miner_info.get('address') - # Record share with calculated difficulty - self.record_share(miner_info['miner_id'], job_id, actual_difficulty) + # For pool mining, always mine to pool address + success, message = self.submit_share( + self.current_job, extranonce1, extranonce2, ntime, nonce, + target_address=self.pool_address + ) - # 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['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']})") - - # Send acceptance response - self.send_stratum_response(client, msg_id, True, None) - - # Try to submit block if it's a valid solution - print(f"[{addr}] ๐Ÿ” Attempting to submit block solution...") - - # Use generatetoaddress to submit the mining result - # Always use pool address for block submission (rewards will be distributed later) - result = self.rpc_call("generatetoaddress", [1, self.pool_address, 1]) - - if result and len(result) > 0: - block_hash = result[0] + if success: + # Record share with estimated difficulty + actual_difficulty = 0.00133 # Estimated for ~381 kH/s + self.record_share(miner_info['miner_id'], job_id, actual_difficulty) - # Get block info - block_info = self.rpc_call("getblock", [block_hash]) - if block_info: - block_height = block_info.get('height', 0) - coinbase_tx = block_info.get('tx', [])[0] if block_info.get('tx') else None - - # Get coinbase value (simplified) - total_reward = 50.0 # Default block reward - - print(f"๐ŸŽ‰ [{addr}] BLOCK FOUND! Hash: {block_hash}") - print(f"๐Ÿ’ฐ Block reward: {total_reward} RIN") - - # Distribute rewards to miners with valid addresses - self.distribute_block_reward(block_hash, block_height, total_reward) + # Update miner stats + now_ts = time.time() + prev_ts = miner_info.get('last_share') or now_ts + dt = max(now_ts - prev_ts, 1e-3) + miner_hashrate = actual_difficulty * (2**32) / dt + if miner_info['shares'] == 0: + miner_hashrate = 381000 # Default estimate + miner_info['shares'] += 1 + miner_info['last_share'] = now_ts + + # Update database + 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 error: {e}") + + print(f"[{addr}] โœ… Share accepted from {miner_info['user']}.{miner_info['worker']} (Total: {miner_info['shares']})") self.send_stratum_response(client, msg_id, True) + + # If block was found, distribute rewards + if "Block found" in message: + print(f"๐ŸŽ‰ [{addr}] BLOCK FOUND!") + # Get block info and distribute rewards + total_reward = self.current_job['coinbasevalue'] / 100000000 if self.current_job else 25.0 + self.distribute_block_reward("pending", self.current_job['height'] if self.current_job else 0, total_reward) else: - # Accept as share even if not a block + # Accept as share for pool statistics even if block validation fails self.send_stratum_response(client, msg_id, True) else: print(f"[{addr}] Invalid share parameters") self.send_stratum_response(client, msg_id, False, "Invalid parameters") except Exception as e: - print(f"[{addr}] Block submission error: {e}") + print(f"[{addr}] Share processing error: {e}") # Still accept the share for mining statistics self.send_stratum_response(client, msg_id, True) @@ -590,7 +479,7 @@ class RinCoinMiningPool: ) if should_create_job: - if self.get_block_template(): + if self.get_pool_block_template(): job = self.current_job last_job_time = time.time() last_block_height = current_height @@ -606,8 +495,8 @@ class RinCoinMiningPool: job["coinb1"], job["coinb2"], job["merkle_branch"], - job["version"], - job["nbits"], + f"{job['version']:08x}", + job["bits"], job["ntime"], job["clean_jobs"] ]) diff --git a/MINE/rin/stratum_proxy.py b/MINE/rin/stratum_proxy.py index 294b316..1dd5906 100644 --- a/MINE/rin/stratum_proxy.py +++ b/MINE/rin/stratum_proxy.py @@ -13,7 +13,7 @@ import hashlib import struct from requests.auth import HTTPBasicAuth -class RinCoinStratumProxy: +class RinCoinStratumBase: def __init__(self, stratum_host='0.0.0.0', stratum_port=3334, rpc_host='127.0.0.1', rpc_port=9556, rpc_user='rinrpc', rpc_password='745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90', @@ -82,93 +82,92 @@ class RinCoinStratumProxy: def decode_bech32_address(self, address): """Decode RinCoin bech32 address to script""" try: - if not address.startswith('rin1'): + if not address or not address.startswith('rin1'): raise ValueError("Not a RinCoin bech32 address") - # Use generatetoaddress to get a proper script for this address - # This ensures we create valid outputs that can actually be spent result = self.rpc_call("validateaddress", [address]) - if result and result.get('isvalid') and 'scriptPubKey' in result: - script_hex = result['scriptPubKey'] - return bytes.fromhex(script_hex) - else: - # Fallback: create a basic P2WPKH script if RPC validation fails - # Extract the witness program (assuming it's standard 20-byte) - # This is a simplified approach - in production use a proper bech32 library - print(f"Warning: Using fallback script for {address}") - return bytes([0x00, 0x14]) + bytes(20) # OP_0 + 20 zero bytes - + if not result or not result.get('isvalid'): + raise ValueError("Address not valid per node") + script_hex = result.get('scriptPubKey') + if not script_hex: + raise ValueError("Node did not return scriptPubKey") + return bytes.fromhex(script_hex) except Exception as e: print(f"Address decode error: {e}") - # Emergency fallback - this should never happen in production - return bytes([0x00, 0x14]) + bytes(20) + return None def build_coinbase_transaction(self, template, extranonce1, extranonce2): - """Build complete coinbase transaction""" + """Build coinbase transaction variants (with and without witness) for default address""" + return self.build_coinbase_transaction_for_address(template, extranonce1, extranonce2, self.target_address) + + def build_coinbase_transaction_for_address(self, template, extranonce1, extranonce2, target_address): + """Build coinbase transaction variants (with and without witness)""" try: - coinbase = b'' - - # Version - coinbase += struct.pack(' bytes: + outputs_blob = b'' + outputs_list = [] + # Main output + outputs_list.append(struct.pack(' {self.target_address}") + print(f"๐Ÿ’ฐ Reward: {job['coinbasevalue']/100000000:.2f} RIN -> {address}") print(f"๐Ÿ“Š Block height: {job['height']}") return True, "Block found and submitted" else: @@ -578,6 +581,15 @@ class RinCoinStratumProxy: finally: print("Server stopped") +class RinCoinStratumProxy(RinCoinStratumBase): + """Solo mining stratum proxy implementation""" + + def __init__(self, stratum_host='0.0.0.0', stratum_port=3334, + rpc_host='127.0.0.1', rpc_port=9556, + rpc_user='rinrpc', rpc_password='745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90', + target_address='rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q'): + super().__init__(stratum_host, stratum_port, rpc_host, rpc_port, rpc_user, rpc_password, target_address) + if __name__ == "__main__": proxy = RinCoinStratumProxy() proxy.start() \ No newline at end of file From 34b095d6ff840ff511020cc4649f79dc42e5c517 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Fri, 5 Sep 2025 01:15:58 +0300 Subject: [PATCH 05/30] refactoring --- .../pool_web_interface.cpython-312.pyc | Bin 20611 -> 22762 bytes MINE/rin/pool_web_interface.py | 54 +++++++++++++++++- MINE/rin/stratum_pool.py | 6 +- 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/MINE/rin/__pycache__/pool_web_interface.cpython-312.pyc b/MINE/rin/__pycache__/pool_web_interface.cpython-312.pyc index 066190d5f898c51420a8a3c358f511f40f104320..56c1c8f0264e2beb32293d7fcd6037ccf9c13e7c 100644 GIT binary patch delta 4637 zcmaJ^eQX>@6`%dOy|wSl_I=;kKF413m)muG=Ip!d zuH*Q)i&JQ+g<8}yNNH)Jrbq~v6lySnf{@xK5=wwSE+nYOCjCMcs34H@0hF{7yxF@; z?5ePq-@Nzc&2Q%3ym|BHt1nT1`4MINjn!I);M-~a#aP|GXKmiuAA)oeNhpjYN}>}~ zm@-;AOdBl|W}syf>;xNTC%7<25j!?vn&89yggI)1;f59Tm~(dD4(!|Efk{B z4kVc#M-qRQCi5Z`wi-G!=mgn(wwo!cZ2}UIWR=Pur^0sGA(elr86icWkz65J&Qb*{ z3eC_nv}k+w-28narCSFN92n`1s`1#iDQzrPuqn{uZ0P2CkWV5R!S6z0+L*+QpP_0x z$+E)c8D120$4D}n_`G~*Xi}4v(P&JLnU`S^D6-0%8oo-k&1TpPiWFCkP=*7EEm>zw zAaQpj9wbvqk|>b)k~D)vdQaS8Lr661d<7Pv@3G^q>d!Cv(_9;u=>4iopHQo?N*8IvQ*gVHxG5hexba+)I z3>Imn3L2ePr2YfZ#rEJr%-f?gz7O7#u4G39tweM;n{=Ptcwup#|8Q^?? z@>r!t{9=5Py`+5sou-$a7DvW3?!u3ms(LD<%F+?c@|veKGQ*dwrK&WnZ$Daw>MSf~ z_S2yCNb{Be8j#}6nwJf7Wy~w>A4ZZbYd&tCaTMBVY8oA59!ArY=uX$}khKsA|IlA0kuCS+|a32iE>L?_e_N%(;cOKfz0 zOpZ#jqUvlE63eX4lY^C<(muQZRyrpuN>bUA4#4_C{e%y}JX(D6aB1}$Lw_#$M>i?5 zI+f5A5)^Ut{y(^Mkfg2uH834qi3q=EHgOkMv@ScrB*^a`W5^itkttc#VA&~>N6J+# zs!gepSQ37VXskS?#3wbKf#vGlXd)TabfN!POipR>f4G5mR zGw|H@7k59u`?;<2b@SU_-Tm_J`K_*DMt|XZu3M0+Xxkx?<_RR^|S9 ziGz;YY6H0DE4_g}4?0&EPli@Sw3@bTKF;c}T%YFn0oTP8#g9Gl*dNo%`mMSyel?ObI zVl*7`s;u|8cYm>6{8!mIidNbdU$>m+8!fs;OKQ?SvG7fYWJ3Qtl_J zZG;RHRk<;Fgd7T08N$DC?O4@MItK{ZLC7E>WC04f`Bai+@%tM*EV;4pdUuy?gs5Mo z3qiYm@tFHQ+8PYK6==T{Xulj-H@6EfctbV$(3M`R04C^Q^z}y05}%TS669 z+efz=@L#Byjx}L?uzE2zyQ%d8K z{RP-EJmT}Q1&O@=e5$)Nl(N~NJLtOY5A7XtNx;9*o+waR5^sV)t* zNR|d}75;mmnySZ^V54g#mf4uU1`h=5?KPQ|n8$+kfrd|EHr~NpZD2OxE5Z8B)fo${ zqB&D8iBgLn0e?@%DiL3;$=JyHP78%`Pt~yq*0Z*RvLA`9i(S=E@>C!GWy32b5?|@> zV5+eS*S2tYq|t%5uIBOSM$J@Bx=w$p>nPQa-)!i@e_P#(Q>*)JMp%)}oFZ4lr;Pc^ z5po6g7Vp012Zr{DV6qAanx3%qg8gl3O{#sR_?V&w z@Y>FUi{I?b3O1#i=xcz8cBKkeZ}!$4Aesk(=zL6(p%jyphluKPgjD1GoBJszetz>h zQyvuRBlyzh>1uWdB`%p!OWUiymwgLc-sre2_P-I!H4iT#ekUH@;;*ImQEl(Fb-gB7b-5d?Yz*JYaLlarhU}bB?}(k@=DoWc#SwLbL`Tt#n9HbsVJ%U_K2q2e0!_$ z7k{P}oFsIt>oMex4-YiLDot?Pk^8>Ar>i?A_uShhbxYlyJ)^Pq^&Rcq(T+nKI=c_` ztncpG(B2svjrDXyyGIXo9@@|@3fQ@=ahBvfg=7K44TTi+1tP`?AyunF7GjjM3b_Ie zLh5Q&1oAk_hab&%#BMSIxB7;g=ENIjJ6CgKRW;|iv1Nef+&4$q;|%94pb&r<{NMTT z{I;L?G!S)8ok~H`LDnO3h0Lensoth~Qb-%>w1-3lykQ2TlTt!fS|gG8WL%3x{(xWa zT}`@ZnZhIoiA@xUN>UJ9@Q?>D z4XmQxUc5C>Pf>2{9bDCLlo%0blt%3(ieo^Qje2x&P2>iIrAi82DD%x0<423Uk|fqC zLXHq(`22CgeGQ0ijYMJzc;&?8L?RLqDJ2bB6@bwF1-Gljl#o3BaIj{tu^&W?k>aTI z5!V_?^v5vr$+DA3BM8QqK^clv;ZTcn8PnO~sIQliSL$3D-ZK=a=V4BrlDC80K~z{3?alNx&Vb;;qhv?820MKiGqh*_>Vi+QJ-MfuKEGu z9*CgN^7)gbi#EWNr+_z}S@#z(biNo?%GaUiV|;v<*JOD5X?$weT22XpcJa5nD9T}+ z0%K3eMk`(T?cG~;!&Od%|N974o(2=$1jXf1h;(xQ7FIzU<<3C1a6D;f(O=kwjdRI~7vH z;-BqZH>+DqrFScNFeoI73JJk*1zByu=Us$bnK*8nH%%m^sf4^mIR(8WFjX1I5<^kc zb(W#nn`MZyTt&94$o?*Beiv=LiX2x_`P-=JU+e%+Ij?U;q`5U>3sTmc>z-Q(+NDkC o5$Yh7?}^`JJd}TF9bzqW>EAKF_gNuV*7SR}d5J@;-#CT;1vocg+W-In delta 2768 zcmZuzeQZi}G-P}&kdmY&1QKAlnvCoBLK2+Vz0YAy z`T~)fs%UGswHGa$3RU@I6)j!6$`b#q(*&KgAf^t4CZWeB+N$fcO`8&e)Gpezo%0-* zf_5$a?z!jObKbe%`jPM zh4li_2)IkYRfYeGR<}*t!gkX;m`Wv&XixV|W;8YuPiP70YZlM|`mwT&yM;)lN(~ZQ z^NWya5*7x=ylz6m691u4#%~J6!;&fKT5^P8+?W%=1)!tRS{SRnk%`GnL?4YaO^xj7 zIUHeHI;BU{wsb0;I@z8`O+@qr8%t;O$iBXTo(LP8jPNS4tJZ^NY5?ZQZGZI{=_S|g zl5&_FYZE^!Mym=z9u^q5L`+535~)d5*YOawwamkvQg>-7EOc~kj(l9#az^@ty_)&> z>tY3ePP$8H_*3$@-%_`a#`RGa&u93e*R1(gosp z^$CCWuxqolTQEdJGGwFJC^1TnGQ(*&48^b;lIlGts=jm1AyQ8=UdsqT17Vf3{!DRx ztri)6{!g#p=|ANkB5Lt0%vrDRDs>*uZ<+Z%_m-Atmy6z1sFVMsvf5S!BIf5GR7QCq z&?pwL0=_%YJdVLJ?IT(yF&a-MO zu(O<1v>`B+1&|d)XhfECVr)`lF+CH{=&XU?4D1cmqOcAjgisG)QcW+1nfuE9B4*@J z@Eh)Rz|hY@lIF;gv@5$1{HDM^t*#1u9PYZkZrkma&SgcaEL!$^OWaGuTj>7seu!7q ztn29Q=l1Cy2edQE$XK=Zn^Ay>8yY&3Yn^_Z!0$>(5omz)zHRY&<<pVhbujsZ0`a?Z{a(8z8g~Z z(zYcxY2WmvWpzVA3uf6X(l4Rp7d(zuRIL!FvP>tQixY$tBo z1)$@NgN_fk{G)*oeK)&2P*16kmkx#+4&Wv{SzZf!02>1Mn$}Z;t+5ZGK6DxQ(5>w* z>o8%3_2cd*5S~P^V)rysDu7uSizSkAT~BDqWGoh@>=1BuFhq9cVmN?X5#HjT4_2SH zf{V)pdYm6NAgrG8HfX+RTOb*OA=!v!a7! z@DMp|&>ewSA%EkAS&6@VV5=yNJNPG02Kk>46nkXVmceeFQ;@lG@K6}q$$8gJCN1oBK-moZHT?A2ho$bMP!4gz2HoW5n4o0>;R6K=aT239w=g z$(x(Yh0M$UGPH^Qj#m!Xs~9gRo&T2v4Ml=wjEw_rJ)OI9HcX{AKB*?5_C`T+9TSTs z_pf>Kg+Lv>beSOL>h%P_Fx)1t(yr{SVM@JL(OX%=D6)3`*`XaB$|HX<*a?uCHeF*U z;TxT}(Q-in3Qht8($7JIwcv%WZw1Mf zpksHDc%^Y`cZ+znr5WfCeROvbKYJwHAh14A9piX?J*E`p()ITV%q!c{stats.get('total_blocks', 0)}
Blocks Found
+
+
{stats.get('pool_balance', 0):.2f}
+
Pool Balance (RIN)
+

๐Ÿ“Š Pool Statistics

24h Shares: {stats.get('total_shares_24h', 0):,}

Pool Fee: 1%

+

Pool Balance: {stats.get('pool_balance', 0):.8f} RIN

Connection String: stratum+tcp://YOUR_IP:3333

@@ -452,9 +499,10 @@ class PoolWebHandler(BaseHTTPRequestHandler): # Suppress access logs pass -def start_web_interface(pool_db, host='0.0.0.0', port=8083): +def start_web_interface(pool_db, host='0.0.0.0', port=8083, rpc_host='127.0.0.1', rpc_port=9556, + rpc_user='rinrpc', rpc_password='745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90'): """Start the web interface server""" - interface = PoolWebInterface(pool_db, host, port) + interface = PoolWebInterface(pool_db, host, port, rpc_host, rpc_port, rpc_user, rpc_password) class Handler(PoolWebHandler): def __init__(self, *args, **kwargs): diff --git a/MINE/rin/stratum_pool.py b/MINE/rin/stratum_pool.py index 692b94f..cba81a2 100644 --- a/MINE/rin/stratum_pool.py +++ b/MINE/rin/stratum_pool.py @@ -542,7 +542,11 @@ class RinCoinMiningPool(RinCoinStratumBase): stats_thread.start() # Start web interface in background - web_thread = threading.Thread(target=start_web_interface, args=(self.db, '0.0.0.0', 8083), daemon=True) + web_thread = threading.Thread(target=start_web_interface, + args=(self.db, '0.0.0.0', 8083, + self.rpc_host, self.rpc_port, + self.rpc_user, self.rpc_password), + daemon=True) web_thread.start() print(f"๐ŸŒ Web dashboard started on http://0.0.0.0:8083") From d6a5389a074423cf4776fc7a2a34dcc87406d9ba Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Fri, 5 Sep 2025 14:41:43 +0300 Subject: [PATCH 06/30] wip --- MINE/rin/stratum_proxy copy.py | 550 +++++++++++++++++++++++++++++++++ MINE/rin/stratum_proxy.py | 138 +++++++-- 2 files changed, 668 insertions(+), 20 deletions(-) create mode 100644 MINE/rin/stratum_proxy copy.py diff --git a/MINE/rin/stratum_proxy copy.py b/MINE/rin/stratum_proxy copy.py new file mode 100644 index 0000000..5b43c29 --- /dev/null +++ b/MINE/rin/stratum_proxy copy.py @@ -0,0 +1,550 @@ +#!/usr/bin/env python3 +""" +RinCoin Stratum Proxy Server - PRODUCTION VERSION +Bridges cpuminer-opt-rin (Stratum protocol) to RinCoin node (RPC protocol) +For real solo mining with actual block construction and submission +""" + +import socket +import threading +import json +import time +import requests +import hashlib +import struct +import binascii +from requests.auth import HTTPBasicAuth + +class RinCoinStratumProxy: + def __init__(self, stratum_host='0.0.0.0', stratum_port=3333, + rpc_host='127.0.0.1', rpc_port=9556, + rpc_user='rinrpc', rpc_password='745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90', + target_address='rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q'): + + self.stratum_host = stratum_host + self.stratum_port = stratum_port + self.rpc_host = rpc_host + self.rpc_port = rpc_port + self.rpc_user = rpc_user + self.rpc_password = rpc_password + self.target_address = target_address + + self.clients = {} + self.job_counter = 0 + self.current_job = None + self.running = True + self.extranonce1_counter = 0 + + print(f"๐Ÿ”ฅ RinCoin PRODUCTION Stratum Proxy Server") + print(f"Stratum: {stratum_host}:{stratum_port}") + print(f"RPC: {rpc_host}:{rpc_port}") + print(f"Target: {target_address}") + + def rpc_call(self, method, params=[]): + """Make RPC call to RinCoin node""" + try: + url = f"http://{self.rpc_host}:{self.rpc_port}/" + headers = {'content-type': 'text/plain'} + auth = HTTPBasicAuth(self.rpc_user, self.rpc_password) + + payload = { + "jsonrpc": "1.0", + "id": "stratum_proxy", + "method": method, + "params": params + } + + response = requests.post(url, json=payload, headers=headers, auth=auth, timeout=10) + + if response.status_code == 200: + result = response.json() + if 'error' in result and result['error'] is not None: + print(f"RPC Error: {result['error']}") + return None + return result.get('result') + else: + print(f"HTTP Error: {response.status_code}") + return None + + except Exception as e: + print(f"RPC Call Error: {e}") + return None + + def create_coinbase_tx(self, template, extranonce1, extranonce2): + """Create coinbase transaction""" + try: + # Get coinbase value (block reward + fees) + coinbase_value = template.get('coinbasevalue', 2500000000) # 25 RIN in satoshis + + # Create coinbase transaction + # Version (4 bytes) + coinbase_tx = struct.pack(' 1: + if len(tx_hashes) % 2 == 1: + tx_hashes.append(tx_hashes[-1]) # Duplicate last hash if odd number + + new_level = [] + for i in range(0, len(tx_hashes), 2): + combined = tx_hashes[i] + tx_hashes[i + 1] + hash_result = hashlib.sha256(hashlib.sha256(combined).digest()).digest() + new_level.append(hash_result) + tx_hashes = new_level + + return tx_hashes[0] if tx_hashes else b'\x00' * 32 + + def get_block_template(self): + """Get new block template from RinCoin node""" + try: + template = self.rpc_call("getblocktemplate", [{"rules": ["segwit"]}]) + if not template: + return None + + self.job_counter += 1 + + # Calculate target from bits + bits = template.get('bits', '1d00ffff') + target = self.bits_to_target(bits) + + # Prepare transaction list (without coinbase) + transactions = template.get('transactions', []) + tx_hashes = [bytes.fromhex(tx['hash'])[::-1] for tx in transactions] # Reverse for little-endian + + job = { + "job_id": f"job_{self.job_counter:08x}", + "template": template, + "prevhash": template.get("previousblockhash", "0" * 64), + "version": template.get('version', 1), + "bits": bits, + "ntime": int(time.time()), + "target": target, + "transactions": transactions, + "tx_hashes": tx_hashes, + "height": template.get('height', 0), + "coinbasevalue": template.get('coinbasevalue', 2500000000) + } + + self.current_job = job + print(f"๐Ÿ“ฆ New job: {job['job_id']} | Height: {job['height']} | Reward: {job['coinbasevalue']/100000000:.2f} RIN") + return job + + except Exception as e: + print(f"Get block template error: {e}") + return None + + def bits_to_target(self, bits_hex): + """Convert bits to target (difficulty)""" + try: + bits = int(bits_hex, 16) + exponent = bits >> 24 + mantissa = bits & 0xffffff + target = mantissa * (256 ** (exponent - 3)) + return f"{target:064x}" + except: + return "0000ffff00000000000000000000000000000000000000000000000000000000" + + def construct_block_header(self, job, extranonce1, extranonce2, ntime, nonce): + """Construct block header for submission""" + try: + # Create coinbase transaction + coinbase_tx = self.create_coinbase_tx(job['template'], extranonce1, extranonce2) + if not coinbase_tx: + return None, None + + # Calculate coinbase hash + coinbase_hash = hashlib.sha256(hashlib.sha256(coinbase_tx).digest()).digest()[::-1] # Reverse for little-endian + + # Create full transaction list (coinbase + other transactions) + all_tx_hashes = [coinbase_hash] + job['tx_hashes'] + + # Calculate merkle root + merkle_root = self.calculate_merkle_root(all_tx_hashes) + + # Construct block header (80 bytes) + header = b'' + header += struct.pack(' {self.target_address}") + return True, "Block accepted" + else: + print(f"โŒ Block rejected: {result}") + return False, f"Block rejected: {result}" + else: + # Valid share but not a block + return True, "Share accepted" + + except Exception as e: + print(f"Block submission error: {e}") + return False, f"Submission error: {e}" + + def send_stratum_response(self, client, msg_id, result, error=None): + """Send Stratum response to client""" + try: + response = { + "id": msg_id, + "result": result, + "error": error + } + + message = json.dumps(response) + "\n" + client.send(message.encode('utf-8')) + except Exception as e: + print(f"Send response error: {e}") + + def send_stratum_notification(self, client, method, params): + """Send Stratum notification to client""" + try: + notification = { + "id": None, + "method": method, + "params": params + } + + message = json.dumps(notification) + "\n" + client.send(message.encode('utf-8')) + except Exception as e: + print(f"Send notification error: {e}") + + def handle_stratum_message(self, client, addr, message): + """Handle incoming Stratum message from miner""" + try: + data = json.loads(message.strip()) + method = data.get("method") + msg_id = data.get("id") + params = data.get("params", []) + + if method == "mining.subscribe": + # Generate unique extranonce1 for this connection + self.extranonce1_counter += 1 + extranonce1 = f"ex{self.extranonce1_counter:06x}" + + # Store extranonce1 for this client + if addr not in self.clients: + self.clients[addr] = {} + self.clients[addr]['extranonce1'] = extranonce1 + + # Subscribe response + self.send_stratum_response(client, msg_id, [ + [["mining.set_difficulty", "subscription_id"], ["mining.notify", "subscription_id"]], + extranonce1, + 4 # extranonce2 size + ]) + + # Send difficulty (simplified - always 1 for now) + self.send_stratum_notification(client, "mining.set_difficulty", [1]) + + # Send initial job + if self.current_job: + self.send_job_to_client(client, self.current_job) + else: + # Get new job if none exists + if self.get_block_template(): + self.send_job_to_client(client, self.current_job) + + elif method == "mining.authorize": + # Authorization (accept any user/pass for now) + username = params[0] if params else "anonymous" + self.clients[addr]['username'] = username + self.send_stratum_response(client, msg_id, True) + print(f"[{addr}] Authorized as {username}") + + elif method == "mining.submit": + # Submit share/block + if len(params) >= 5: + username = params[0] + job_id = params[1] + extranonce2 = params[2] + ntime = params[3] + nonce = params[4] + + print(f"[{addr}] Submit: job={job_id}, nonce={nonce}") + + # Validate submission + if self.current_job and job_id == self.current_job['job_id']: + extranonce1 = self.clients[addr].get('extranonce1', 'ex000000') + + # Validate and potentially submit block + success, message = self.validate_and_submit_block( + self.current_job, extranonce1, extranonce2, ntime, nonce + ) + + if success: + self.send_stratum_response(client, msg_id, True) + if "Block accepted" in message: + # Broadcast new job after block found + threading.Thread(target=self.update_job_after_block, daemon=True).start() + else: + self.send_stratum_response(client, msg_id, False, message) + else: + self.send_stratum_response(client, msg_id, False, "Stale job") + else: + self.send_stratum_response(client, msg_id, False, "Invalid parameters") + + else: + print(f"[{addr}] Unknown method: {method}") + self.send_stratum_response(client, msg_id, None, "Unknown method") + + except json.JSONDecodeError: + print(f"[{addr}] Invalid JSON: {message}") + except Exception as e: + print(f"[{addr}] Message handling error: {e}") + + def send_job_to_client(self, client, job): + """Send mining job to specific client""" + try: + self.send_stratum_notification(client, "mining.notify", [ + job["job_id"], + job["prevhash"], + "", # coinb1 (empty - we handle coinbase internally) + "", # coinb2 (empty - we handle coinbase internally) + [], # merkle_branch (empty - we calculate merkle root) + f"{job['version']:08x}", + job["bits"], + f"{job['ntime']:08x}", + True # clean_jobs + ]) + except Exception as e: + print(f"Failed to send job: {e}") + + def update_job_after_block(self): + """Update job after a block is found""" + time.sleep(2) # Brief delay to let network propagate + if self.get_block_template(): + self.broadcast_new_job() + + def broadcast_new_job(self): + """Broadcast new job to all connected clients""" + if not self.current_job: + return + + print(f"๐Ÿ“ก Broadcasting job {self.current_job['job_id']} to {len(self.clients)} clients") + + for addr, client_data in list(self.clients.items()): + try: + if 'socket' in client_data: + self.send_job_to_client(client_data['socket'], self.current_job) + except Exception as e: + print(f"Failed to send job to {addr}: {e}") + + def handle_client(self, client, addr): + """Handle individual client connection""" + print(f"[{addr}] Connected") + if addr not in self.clients: + self.clients[addr] = {} + self.clients[addr]['socket'] = client + + try: + while self.running: + data = client.recv(4096) + if not data: + break + + # Handle multiple messages in one packet + messages = data.decode('utf-8').strip().split('\n') + for message in messages: + if message: + self.handle_stratum_message(client, addr, message) + + except Exception as e: + print(f"[{addr}] Client error: {e}") + finally: + client.close() + if addr in self.clients: + del self.clients[addr] + print(f"[{addr}] Disconnected") + + def job_updater(self): + """Periodically update mining jobs""" + while self.running: + try: + time.sleep(30) # Update every 30 seconds + + old_height = self.current_job['height'] if self.current_job else 0 + + if self.get_block_template(): + new_height = self.current_job['height'] + if new_height > old_height: + print(f"๐Ÿ†• New block detected! Broadcasting new job...") + self.broadcast_new_job() + + except Exception as e: + print(f"Job updater error: {e}") + + def start(self): + """Start the Stratum proxy server""" + try: + # Test RPC connection + blockchain_info = self.rpc_call("getblockchaininfo") + if not blockchain_info: + print("โŒ Failed to connect to RinCoin node!") + return + + print(f"โœ… Connected to RinCoin node") + print(f"๐Ÿ“Š Current height: {blockchain_info.get('blocks', 'unknown')}") + print(f"โ›“๏ธ Chain: {blockchain_info.get('chain', 'unknown')}") + + # Get initial block template + if not self.get_block_template(): + print("โŒ Failed to get initial block template!") + return + + # Start job updater thread + job_thread = threading.Thread(target=self.job_updater, daemon=True) + job_thread.start() + + # Start Stratum server + server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + server_socket.bind((self.stratum_host, self.stratum_port)) + server_socket.listen(10) + + print(f"๐Ÿš€ PRODUCTION Stratum proxy ready!") + print(f"๐Ÿ“ก Listening on {self.stratum_host}:{self.stratum_port}") + print(f"๐Ÿ’ฐ Mining to: {self.target_address}") + print(f"โšก Current job: {self.current_job['job_id']}") + print("") + print("๐Ÿ”ง Miner command:") + print(f"./cpuminer -a rinhash -o stratum+tcp://{self.stratum_host}:{self.stratum_port} -u worker1 -p x -t 4") + print("") + + while self.running: + try: + client, addr = server_socket.accept() + client_thread = threading.Thread( + target=self.handle_client, + args=(client, addr), + daemon=True + ) + client_thread.start() + except KeyboardInterrupt: + print("\n๐Ÿ›‘ Shutting down...") + self.running = False + break + except Exception as e: + print(f"Server error: {e}") + + except Exception as e: + print(f"Failed to start server: {e}") + finally: + print("๐Ÿ’ค Server stopped") + +if __name__ == "__main__": + proxy = RinCoinStratumProxy() + proxy.start() \ No newline at end of file diff --git a/MINE/rin/stratum_proxy.py b/MINE/rin/stratum_proxy.py index 1dd5906..d677f8a 100644 --- a/MINE/rin/stratum_proxy.py +++ b/MINE/rin/stratum_proxy.py @@ -229,18 +229,58 @@ class RinCoinStratumBase: } self.current_job = job - print(f"New job: {job['job_id']} | Height: {job['height']} | Reward: {job['coinbasevalue']/100000000:.2f} RIN") + timestamp = time.strftime("%Y-%m-%d %H:%M:%S") + network_difficulty = self.calculate_network_difficulty(job['target']) + print(f"[{timestamp}] ๐Ÿ†• NEW JOB: {job['job_id']} | Height: {job['height']} | Reward: {job['coinbasevalue']/100000000:.2f} RIN") + print(f" ๐ŸŽฏ Network Difficulty: {network_difficulty:.6f} | Bits: {job['bits']}") + print(f" ๐Ÿ“ Target: {job['target'][:16]}... | Transactions: {len(job['transactions'])}") return job except Exception as e: print(f"Get block template error: {e}") return None + def calculate_share_difficulty(self, hash_hex, target_hex): + """Calculate actual share difficulty from hash""" + try: + hash_int = int(hash_hex, 16) + target_int = int(target_hex, 16) + + if hash_int == 0: + return float('inf') # Perfect hash + + # Bitcoin-style difficulty calculation + # Lower hash = higher difficulty + # Difficulty 1.0 = finding hash that meets network target exactly + max_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 + + # Share difficulty = how hard this specific hash was to find + difficulty = max_target / hash_int + + return difficulty + except Exception as e: + print(f"Difficulty calculation error: {e}") + return 0.0 + + def calculate_network_difficulty(self, target_hex): + """Calculate network difficulty from target""" + try: + target_int = int(target_hex, 16) + + # Bitcoin difficulty 1.0 target + max_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 + + # Network difficulty = how much harder than difficulty 1.0 + network_difficulty = max_target / target_int + + return network_difficulty + except Exception as e: + print(f"Network difficulty calculation error: {e}") + return 1.0 + def submit_share(self, job, extranonce1, extranonce2, ntime, nonce, target_address=None): """Validate share and submit block if valid""" try: - print(f"Share: job={job['job_id']} nonce={nonce}") - # Use provided address or default address = target_address or self.target_address @@ -269,16 +309,72 @@ class RinCoinStratumBase: block_hash = hashlib.sha256(hashlib.sha256(header).digest()).digest() block_hash_hex = block_hash[::-1].hex() + # Calculate real difficulties + share_difficulty = self.calculate_share_difficulty(block_hash_hex, job['target']) + network_difficulty = self.calculate_network_difficulty(job['target']) + # Check if hash meets target hash_int = int(block_hash_hex, 16) target_int = int(job['target'], 16) + # Enhanced logging + timestamp = time.strftime("%Y-%m-%d %H:%M:%S") + difficulty_percentage = (share_difficulty / network_difficulty) * 100 if network_difficulty > 0 else 0 + + # Progress indicator based on percentage + if difficulty_percentage >= 100: + progress_icon = "๐ŸŽ‰" # Block found! + elif difficulty_percentage >= 50: + progress_icon = "๐Ÿ”ฅ" # Very close + elif difficulty_percentage >= 10: + progress_icon = "โšก" # Getting warm + elif difficulty_percentage >= 1: + progress_icon = "๐Ÿ’ซ" # Some progress + else: + progress_icon = "๐Ÿ“Š" # Low progress + + print(f"[{timestamp}] {progress_icon} SHARE: job={job['job_id']} | nonce={nonce} | hash={block_hash_hex[:16]}...") + print(f" ๐ŸŽฏ Share Diff: {share_difficulty:.2e} | Network Diff: {network_difficulty:.6f}") + print(f" ๐Ÿ“ˆ Progress: {difficulty_percentage:.4f}% of network difficulty") + print(f" ๐Ÿ“ Target: {job['target'][:16]}... | Height: {job['height']}") + print(f" โฐ Time: {ntime} | Extranonce: {extranonce1}:{extranonce2}") + if hash_int > target_int: - # Valid share but not a block + # Valid share but not a block - still send to node for validation + print(f" โœ… Share accepted (below network difficulty)") + + # Send to node anyway to validate our work + try: + # Build complete block for validation + block = header + tx_count = 1 + len(job['transactions']) + block += self.encode_varint(tx_count) + block += coinbase_wit + for tx in job['transactions']: + block += bytes.fromhex(tx['data']) + + block_hex = block.hex() + print(f" ๐Ÿ” Sending share to node for validation...") + result = self.rpc_call("submitblock", [block_hex]) + + if result is None: + print(f" ๐ŸŽ‰ SURPRISE BLOCK! Node accepted our 'low difficulty' share as valid block!") + return True, "Block found and submitted" + else: + print(f" ๐Ÿ“Š Node rejected as expected: {result}") + return True, "Share validated by node" + + except Exception as e: + print(f" โš ๏ธ Node validation error: {e}") + return True, "Share accepted (node validation failed)" + return True, "Share accepted" # Valid block! Build full block and submit - print(f"BLOCK FOUND! Hash: {block_hash_hex}") + print(f" ๐ŸŽ‰ BLOCK FOUND! Hash: {block_hash_hex}") + print(f" ๐Ÿ’ฐ Reward: {job['coinbasevalue']/100000000:.2f} RIN -> {address}") + print(f" ๐Ÿ“Š Block height: {job['height']}") + print(f" ๐Ÿ” Difficulty: {share_difficulty:.6f} (target: {network_difficulty:.6f})") # Build complete block block = header @@ -296,25 +392,25 @@ class RinCoinStratumBase: # Submit block block_hex = block.hex() - print(f"Submitting block of size {len(block_hex)//2} bytes...") + print(f" ๐Ÿ“ฆ Submitting block of size {len(block_hex)//2} bytes...") result = self.rpc_call("submitblock", [block_hex]) if result is None: - print(f"โœ… Block accepted: {block_hash_hex}") - print(f"๐Ÿ’ฐ Reward: {job['coinbasevalue']/100000000:.2f} RIN -> {address}") - print(f"๐Ÿ“Š Block height: {job['height']}") + print(f" โœ… Block accepted by network!") return True, "Block found and submitted" else: - print(f"โŒ Block rejected: {result}") - print(f"๐Ÿ“ฆ Block hash: {block_hash_hex}") - print(f"๐Ÿ“Š Block height: {job['height']}") - print(f"๐Ÿ” Debug: Block size {len(block_hex)//2} bytes, {len(job['transactions'])} transactions") + print(f" โŒ Block rejected: {result}") + print(f" ๐Ÿ” Debug: Block size {len(block_hex)//2} bytes, {len(job['transactions'])} transactions") return False, f"Block rejected: {result}" except Exception as e: print(f"Share submission error: {e}") return False, f"Submission error: {e}" + + except Exception as e: + print(f"Share submission error: {e}") + return False, f"Submission error: {e}" def send_stratum_response(self, client, msg_id, result, error=None): """Send Stratum response to client""" @@ -381,7 +477,8 @@ class RinCoinStratumBase: username = params[0] if params else "anonymous" self.clients[addr]['username'] = username self.send_stratum_response(client, msg_id, True) - print(f"[{addr}] Authorized as {username}") + timestamp = time.strftime("%Y-%m-%d %H:%M:%S") + print(f"[{timestamp}] ๐Ÿ” [{addr}] Authorized as {username}") elif method == "mining.extranonce.subscribe": # Handle extranonce subscription @@ -551,13 +648,14 @@ class RinCoinStratumBase: server_socket.bind((self.stratum_host, self.stratum_port)) server_socket.listen(10) - print(f"REAL Mining Stratum proxy ready!") - print(f"Listening on {self.stratum_host}:{self.stratum_port}") - print(f"Mining to: {self.target_address}") - print(f"Current job: {self.current_job['job_id'] if self.current_job else 'None'}") + timestamp = time.strftime("%Y-%m-%d %H:%M:%S") + print(f"[{timestamp}] ๐Ÿš€ REAL Mining Stratum proxy ready!") + print(f" ๐Ÿ“ก Listening on {self.stratum_host}:{self.stratum_port}") + print(f" ๐Ÿ’ฐ Mining to: {self.target_address}") + print(f" ๐Ÿ“Š Current job: {self.current_job['job_id'] if self.current_job else 'None'}") print("") - print("Miner command:") - print(f"./cpuminer -a rinhash -o stratum+tcp://{self.stratum_host}:{self.stratum_port} -u worker1 -p x -t 4") + print(" ๐Ÿ”ง Miner command:") + print(f" ./cpuminer -a rinhash -o stratum+tcp://{self.stratum_host}:{self.stratum_port} -u worker1 -p x -t 4") print("") while self.running: From 15f41c32683f2faa563c2068367212dce111b1b5 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Mon, 15 Sep 2025 22:26:12 +0300 Subject: [PATCH 07/30] rename --- MINE/rin/solo_mining_zergpool.sh | 76 ++++++++++++++++++++++++++++++++ MINE/stratum | 1 + 2 files changed, 77 insertions(+) create mode 100644 MINE/rin/solo_mining_zergpool.sh create mode 160000 MINE/stratum diff --git a/MINE/rin/solo_mining_zergpool.sh b/MINE/rin/solo_mining_zergpool.sh new file mode 100644 index 0000000..7f44f5d --- /dev/null +++ b/MINE/rin/solo_mining_zergpool.sh @@ -0,0 +1,76 @@ +#!/bin/bash + +# RinCoin Solo Mining via RPC +# This script uses RinCoin's RPC interface for solo mining + +echo "=== RinCoin Solo Mining via RPC ===" +echo "" + +# Configuration +RPC_HOST="127.0.0.1" +RPC_PORT="9556" +RPC_USER="rinrpc" +RPC_PASS="745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90" + +# Function to call RPC +call_rpc() { + local method="$1" + local params="$2" + + curl -s --user "$RPC_USER:$RPC_PASS" \ + -H 'content-type: text/plain' \ + --data "{\"jsonrpc\":\"1.0\",\"id\":\"curl\",\"method\":\"$method\",\"params\":$params}" \ + "http://$RPC_HOST:$RPC_PORT/" +} + +# Wait for node to be ready +echo "Waiting for RinCoin node to be ready..." +while true; do + response=$(call_rpc "getblockchaininfo" "[]") + if [[ $response != *"Loading block index"* ]]; then + break + fi + echo "Node still loading... waiting 10 seconds" + sleep 10 +done + +echo "โœ… Node is ready!" +echo "" + +# Get wallet address +echo "Getting wallet address..." +wallet_response=$(call_rpc "getnewaddress" "[]") +rin_address=$(echo "$wallet_response" | grep -o '"result":"[^"]*"' | cut -d'"' -f4) + +if [ -z "$rin_address" ]; then + echo "โŒ Error: Could not get RinCoin address!" + echo "Response: $wallet_response" + exit 1 +fi + +echo "โœ… RinCoin Address: $rin_address" +echo "" + +# Get blockchain info +echo "Blockchain Status:" +blockchain_info=$(call_rpc "getblockchaininfo" "[]") +blocks=$(echo "$blockchain_info" | grep -o '"blocks":[^,]*' | cut -d':' -f2) +headers=$(echo "$blockchain_info" | grep -o '"headers":[^,]*' | cut -d':' -f2) +difficulty=$(echo "$blockchain_info" | grep -o '"difficulty":[^,]*' | cut -d':' -f2) + +echo "Blocks: $blocks" +echo "Headers: $headers" +echo "Difficulty: $difficulty" +echo "" + +echo "โš ๏ธ IMPORTANT: RinCoin solo mining requires:" +echo "1. A fully synced node (currently at block $blocks of $headers)" +echo "2. Mining software that supports RinCoin's RPC mining protocol" +echo "3. Very high hashpower to find blocks solo" +echo "" +echo "For now, we recommend pool mining for consistent rewards:" +echo "" +echo "Pool Mining Command:" +echo "sudo docker exec -it amd-strix-halo-llama-rocm bash -c \"/mnt/dl/rinhash/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://rinhash.mine.zergpool.com:7148 -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC,mc=RIN,ID=StrixHalo -t 32\"" +echo "" +echo "Your RinCoin address for solo mining: $rin_address" diff --git a/MINE/stratum b/MINE/stratum new file mode 160000 index 0000000..8290751 --- /dev/null +++ b/MINE/stratum @@ -0,0 +1 @@ +Subproject commit 829075155a56e7294063954d0c44ae2722199de3 From 2bcd28be2872e10dc7b45581ef93dcc4fc9ce214 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Wed, 17 Sep 2025 17:53:40 +0300 Subject: [PATCH 08/30] proxy fix --- MINE/rin/start_stratum_proxy.sh | 1 - MINE/rin/stratum_proxy.py | 222 +++++----- MINE/rin/stratum_proxy_debug.py | 705 ++++++++++++++++++++++++++++++++ MINE/rin/view_mining_log.sh | 45 ++ 4 files changed, 867 insertions(+), 106 deletions(-) create mode 100644 MINE/rin/stratum_proxy_debug.py create mode 100644 MINE/rin/view_mining_log.sh diff --git a/MINE/rin/start_stratum_proxy.sh b/MINE/rin/start_stratum_proxy.sh index f6ad91f..4bf852c 100644 --- a/MINE/rin/start_stratum_proxy.sh +++ b/MINE/rin/start_stratum_proxy.sh @@ -56,7 +56,6 @@ fi echo "" echo "๐Ÿš€ Starting Stratum Proxy Server..." -echo "This will bridge cpuminer-opt-rin to your RinCoin node" echo "" echo "After it starts, connect your miner with:" echo "sudo docker exec -it amd-strix-halo-llama-rocm bash -c \"/mnt/dl/rinhash/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://127.0.0.1:3334 -u user -p pass -t 28\"" diff --git a/MINE/rin/stratum_proxy.py b/MINE/rin/stratum_proxy.py index d677f8a..e9e4bd6 100644 --- a/MINE/rin/stratum_proxy.py +++ b/MINE/rin/stratum_proxy.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """ -RinCoin Stratum Proxy Server - REAL MINING VERSION -Properly constructs Stratum jobs and validates/submits real blocks +RinCoin Stratum Proxy Server - FIXED VERSION +Fixed block hash calculation and validation issues """ import socket @@ -13,7 +13,7 @@ import hashlib import struct from requests.auth import HTTPBasicAuth -class RinCoinStratumBase: +class RinCoinStratumProxy: def __init__(self, stratum_host='0.0.0.0', stratum_port=3334, rpc_host='127.0.0.1', rpc_port=9556, rpc_user='rinrpc', rpc_password='745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90', @@ -33,11 +33,57 @@ class RinCoinStratumBase: self.running = True self.extranonce1_counter = 0 - print(f"RinCoin Stratum Proxy Server - REAL MINING") + # Logging setup + self.log_file = "mining_log.txt" + self.init_log_file() + + print(f"RinCoin Stratum Proxy Server") print(f"Stratum: {stratum_host}:{stratum_port}") print(f"RPC: {rpc_host}:{rpc_port}") print(f"Target: {target_address}") + def init_log_file(self): + """Initialize mining log file with header""" + try: + with open(self.log_file, 'w') as f: + f.write("=" * 80 + "\n") + f.write("RinCoin Mining Log\n") + f.write("=" * 80 + "\n") + f.write(f"Started: {time.strftime('%Y-%m-%d %H:%M:%S')}\n") + f.write(f"Target Address: {self.target_address}\n") + f.write(f"Stratum: {self.stratum_host}:{self.stratum_port}\n") + f.write(f"RPC: {self.rpc_host}:{self.rpc_port}\n") + f.write("=" * 80 + "\n\n") + except Exception as e: + print(f"Failed to initialize log file: {e}") + + def log_hash_found(self, hash_hex, difficulty, height, reward, nonce, ntime): + """Log found hash to file""" + try: + timestamp = time.strftime('%Y-%m-%d %H:%M:%S') + with open(self.log_file, 'a') as f: + f.write(f"[{timestamp}] ๐ŸŽ‰ HASH FOUND!\n") + f.write(f" Hash: {hash_hex}\n") + f.write(f" Difficulty: {difficulty:.6f}\n") + f.write(f" Height: {height}\n") + f.write(f" Reward: {reward:.8f} RIN\n") + f.write(f" Nonce: {nonce}\n") + f.write(f" Time: {ntime}\n") + f.write("-" * 40 + "\n") + except Exception as e: + print(f"Failed to log hash: {e}") + + def log_wallet_balance(self): + """Log current wallet balance to file""" + try: + balance = self.rpc_call("getbalance") + if balance is not None: + timestamp = time.strftime('%Y-%m-%d %H:%M:%S') + with open(self.log_file, 'a') as f: + f.write(f"[{timestamp}] ๐Ÿ’ฐ Wallet Balance: {balance:.8f} RIN\n") + except Exception as e: + print(f"Failed to log wallet balance: {e}") + def rpc_call(self, method, params=[]): """Make RPC call to RinCoin node""" try: @@ -196,14 +242,21 @@ class RinCoinStratumBase: return b'\x00' * 32 def bits_to_target(self, bits_hex): - """Convert bits to target""" + """Convert bits to target - FIXED VERSION""" try: bits = int(bits_hex, 16) exponent = bits >> 24 mantissa = bits & 0xffffff - target = mantissa * (256 ** (exponent - 3)) + + # Bitcoin target calculation + if exponent <= 3: + target = mantissa >> (8 * (3 - exponent)) + else: + target = mantissa << (8 * (exponent - 3)) + return f"{target:064x}" - except: + except Exception as e: + print(f"Bits to target error: {e}") return "0000ffff00000000000000000000000000000000000000000000000000000000" def get_block_template(self): @@ -241,21 +294,19 @@ class RinCoinStratumBase: return None def calculate_share_difficulty(self, hash_hex, target_hex): - """Calculate actual share difficulty from hash""" + """Calculate actual share difficulty from hash - FIXED""" try: hash_int = int(hash_hex, 16) - target_int = int(target_hex, 16) if hash_int == 0: return float('inf') # Perfect hash - # Bitcoin-style difficulty calculation - # Lower hash = higher difficulty - # Difficulty 1.0 = finding hash that meets network target exactly - max_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 + # Bitcoin-style difficulty calculation using difficulty 1 target + # Difficulty 1 target for mainnet + diff1_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 - # Share difficulty = how hard this specific hash was to find - difficulty = max_target / hash_int + # Share difficulty = how much harder this hash was compared to diff 1 + difficulty = diff1_target / hash_int return difficulty except Exception as e: @@ -263,15 +314,15 @@ class RinCoinStratumBase: return 0.0 def calculate_network_difficulty(self, target_hex): - """Calculate network difficulty from target""" + """Calculate network difficulty from target - FIXED""" try: target_int = int(target_hex, 16) # Bitcoin difficulty 1.0 target - max_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 + diff1_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 # Network difficulty = how much harder than difficulty 1.0 - network_difficulty = max_target / target_int + network_difficulty = diff1_target / target_int return network_difficulty except Exception as e: @@ -279,7 +330,7 @@ class RinCoinStratumBase: return 1.0 def submit_share(self, job, extranonce1, extranonce2, ntime, nonce, target_address=None): - """Validate share and submit block if valid""" + """Validate share and submit block if valid - FIXED VERSION""" try: # Use provided address or default address = target_address or self.target_address @@ -296,33 +347,34 @@ class RinCoinStratumBase: # Calculate merkle root merkle_root = self.calculate_merkle_root(coinbase_txid, job['transactions']) - # Build block header + # Build block header - FIXED ENDIANNESS header = b'' - header += struct.pack(' 0 else 0 # Progress indicator based on percentage - if difficulty_percentage >= 100: + if meets_target: progress_icon = "๐ŸŽ‰" # Block found! elif difficulty_percentage >= 50: progress_icon = "๐Ÿ”ฅ" # Very close @@ -338,37 +390,12 @@ class RinCoinStratumBase: print(f" ๐Ÿ“ˆ Progress: {difficulty_percentage:.4f}% of network difficulty") print(f" ๐Ÿ“ Target: {job['target'][:16]}... | Height: {job['height']}") print(f" โฐ Time: {ntime} | Extranonce: {extranonce1}:{extranonce2}") + print(f" ๐Ÿ” Hash vs Target: {hash_int} {'<=' if meets_target else '>'} {target_int}") - if hash_int > target_int: - # Valid share but not a block - still send to node for validation - print(f" โœ… Share accepted (below network difficulty)") - - # Send to node anyway to validate our work - try: - # Build complete block for validation - block = header - tx_count = 1 + len(job['transactions']) - block += self.encode_varint(tx_count) - block += coinbase_wit - for tx in job['transactions']: - block += bytes.fromhex(tx['data']) - - block_hex = block.hex() - print(f" ๐Ÿ” Sending share to node for validation...") - result = self.rpc_call("submitblock", [block_hex]) - - if result is None: - print(f" ๐ŸŽ‰ SURPRISE BLOCK! Node accepted our 'low difficulty' share as valid block!") - return True, "Block found and submitted" - else: - print(f" ๐Ÿ“Š Node rejected as expected: {result}") - return True, "Share validated by node" - - except Exception as e: - print(f" โš ๏ธ Node validation error: {e}") - return True, "Share accepted (node validation failed)" - - return True, "Share accepted" + if not meets_target: + # Share doesn't meet target - reject but still useful for debugging + print(f" โŒ Share rejected (hash > target)") + return False, "Share too high" # Valid block! Build full block and submit print(f" ๐ŸŽ‰ BLOCK FOUND! Hash: {block_hash_hex}") @@ -376,6 +403,10 @@ class RinCoinStratumBase: print(f" ๐Ÿ“Š Block height: {job['height']}") print(f" ๐Ÿ” Difficulty: {share_difficulty:.6f} (target: {network_difficulty:.6f})") + # Log the found hash + reward_rin = job['coinbasevalue'] / 100000000 + self.log_hash_found(block_hash_hex, share_difficulty, job['height'], reward_rin, nonce, ntime) + # Build complete block block = header @@ -398,6 +429,8 @@ class RinCoinStratumBase: if result is None: print(f" โœ… Block accepted by network!") + # Log wallet balance after successful block submission + self.log_wallet_balance() return True, "Block found and submitted" else: print(f" โŒ Block rejected: {result}") @@ -407,10 +440,6 @@ class RinCoinStratumBase: except Exception as e: print(f"Share submission error: {e}") return False, f"Submission error: {e}" - - except Exception as e: - print(f"Share submission error: {e}") - return False, f"Submission error: {e}" def send_stratum_response(self, client, msg_id, result, error=None): """Send Stratum response to client""" @@ -463,8 +492,8 @@ class RinCoinStratumBase: 4 # extranonce2 size ]) - # Send difficulty - self.send_stratum_notification(client, "mining.set_difficulty", [0.0001]) + # Send difficulty - MUCH LOWER for testing + self.send_stratum_notification(client, "mining.set_difficulty", [0.00001]) # Send initial job if self.current_job: @@ -481,7 +510,6 @@ class RinCoinStratumBase: print(f"[{timestamp}] ๐Ÿ” [{addr}] Authorized as {username}") elif method == "mining.extranonce.subscribe": - # Handle extranonce subscription self.send_stratum_response(client, msg_id, True) elif method == "mining.submit": @@ -494,38 +522,21 @@ class RinCoinStratumBase: print(f"[{addr}] Submit: {username} | job={job_id} | nonce={nonce}") - # Validate submission - if self.current_job and job_id == self.current_job['job_id']: + # Always validate against current job + if self.current_job: extranonce1 = self.clients[addr].get('extranonce1', '00000000') # Submit share success, message = self.submit_share(self.current_job, extranonce1, extranonce2, ntime, nonce) - if success: - self.send_stratum_response(client, msg_id, True) - if "Block found" in message: - # Get new job after block found - threading.Thread(target=self.update_job_after_block, daemon=True).start() - else: - self.send_stratum_response(client, msg_id, False, message) + # Always accept shares for debugging, even if they don't meet target + self.send_stratum_response(client, msg_id, True) + + if success and "Block found" in message: + # Get new job after block found + threading.Thread(target=self.update_job_after_block, daemon=True).start() else: - # For stale jobs, still validate for blocks but don't require exact job match - # This prevents missing blocks due to job timing issues - if self.current_job: - extranonce1 = self.clients[addr].get('extranonce1', '00000000') - # Use current job template but allow stale job_id - success, message = self.submit_share(self.current_job, extranonce1, extranonce2, ntime, nonce) - - if success: - self.send_stratum_response(client, msg_id, True) - if "Block found" in message: - # Get new job after block found - threading.Thread(target=self.update_job_after_block, daemon=True).start() - else: - # Accept as share even if block validation fails for stale jobs - self.send_stratum_response(client, msg_id, True) - else: - self.send_stratum_response(client, msg_id, True) + self.send_stratum_response(client, msg_id, True) else: self.send_stratum_response(client, msg_id, False, "Invalid parameters") @@ -541,7 +552,6 @@ class RinCoinStratumBase: def send_job_to_client(self, client, job): """Send mining job to specific client""" try: - # Send proper Stratum job self.send_stratum_notification(client, "mining.notify", [ job["job_id"], job["prevhash"], @@ -605,6 +615,7 @@ class RinCoinStratumBase: def job_updater(self): """Periodically update mining jobs""" + balance_log_counter = 0 while self.running: try: time.sleep(30) # Update every 30 seconds @@ -616,6 +627,12 @@ class RinCoinStratumBase: if new_height > old_height: print(f"New block detected! Broadcasting new job...") self.broadcast_new_job() + + # Log wallet balance every 10 minutes (20 cycles of 30 seconds) + balance_log_counter += 1 + if balance_log_counter >= 20: + self.log_wallet_balance() + balance_log_counter = 0 except Exception as e: print(f"Job updater error: {e}") @@ -633,6 +650,9 @@ class RinCoinStratumBase: print(f"Current height: {blockchain_info.get('blocks', 'unknown')}") print(f"Chain: {blockchain_info.get('chain', 'unknown')}") + # Log initial wallet balance + self.log_wallet_balance() + # Get initial block template if not self.get_block_template(): print("Failed to get initial block template!") @@ -649,10 +669,11 @@ class RinCoinStratumBase: server_socket.listen(10) timestamp = time.strftime("%Y-%m-%d %H:%M:%S") - print(f"[{timestamp}] ๐Ÿš€ REAL Mining Stratum proxy ready!") + print(f"[{timestamp}] ๐Ÿš€ Mining Stratum proxy ready!") print(f" ๐Ÿ“ก Listening on {self.stratum_host}:{self.stratum_port}") print(f" ๐Ÿ’ฐ Mining to: {self.target_address}") print(f" ๐Ÿ“Š Current job: {self.current_job['job_id'] if self.current_job else 'None'}") + print(f" ๐Ÿ“ Mining log: {self.log_file}") print("") print(" ๐Ÿ”ง Miner command:") print(f" ./cpuminer -a rinhash -o stratum+tcp://{self.stratum_host}:{self.stratum_port} -u worker1 -p x -t 4") @@ -679,15 +700,6 @@ class RinCoinStratumBase: finally: print("Server stopped") -class RinCoinStratumProxy(RinCoinStratumBase): - """Solo mining stratum proxy implementation""" - - def __init__(self, stratum_host='0.0.0.0', stratum_port=3334, - rpc_host='127.0.0.1', rpc_port=9556, - rpc_user='rinrpc', rpc_password='745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90', - target_address='rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q'): - super().__init__(stratum_host, stratum_port, rpc_host, rpc_port, rpc_user, rpc_password, target_address) - if __name__ == "__main__": proxy = RinCoinStratumProxy() - proxy.start() \ No newline at end of file + proxy.start() diff --git a/MINE/rin/stratum_proxy_debug.py b/MINE/rin/stratum_proxy_debug.py new file mode 100644 index 0000000..e9e4bd6 --- /dev/null +++ b/MINE/rin/stratum_proxy_debug.py @@ -0,0 +1,705 @@ +#!/usr/bin/env python3 +""" +RinCoin Stratum Proxy Server - FIXED VERSION +Fixed block hash calculation and validation issues +""" + +import socket +import threading +import json +import time +import requests +import hashlib +import struct +from requests.auth import HTTPBasicAuth + +class RinCoinStratumProxy: + def __init__(self, stratum_host='0.0.0.0', stratum_port=3334, + rpc_host='127.0.0.1', rpc_port=9556, + rpc_user='rinrpc', rpc_password='745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90', + target_address='rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q'): + + self.stratum_host = stratum_host + self.stratum_port = stratum_port + self.rpc_host = rpc_host + self.rpc_port = rpc_port + self.rpc_user = rpc_user + self.rpc_password = rpc_password + self.target_address = target_address + + self.clients = {} + self.job_counter = 0 + self.current_job = None + self.running = True + self.extranonce1_counter = 0 + + # Logging setup + self.log_file = "mining_log.txt" + self.init_log_file() + + print(f"RinCoin Stratum Proxy Server") + print(f"Stratum: {stratum_host}:{stratum_port}") + print(f"RPC: {rpc_host}:{rpc_port}") + print(f"Target: {target_address}") + + def init_log_file(self): + """Initialize mining log file with header""" + try: + with open(self.log_file, 'w') as f: + f.write("=" * 80 + "\n") + f.write("RinCoin Mining Log\n") + f.write("=" * 80 + "\n") + f.write(f"Started: {time.strftime('%Y-%m-%d %H:%M:%S')}\n") + f.write(f"Target Address: {self.target_address}\n") + f.write(f"Stratum: {self.stratum_host}:{self.stratum_port}\n") + f.write(f"RPC: {self.rpc_host}:{self.rpc_port}\n") + f.write("=" * 80 + "\n\n") + except Exception as e: + print(f"Failed to initialize log file: {e}") + + def log_hash_found(self, hash_hex, difficulty, height, reward, nonce, ntime): + """Log found hash to file""" + try: + timestamp = time.strftime('%Y-%m-%d %H:%M:%S') + with open(self.log_file, 'a') as f: + f.write(f"[{timestamp}] ๐ŸŽ‰ HASH FOUND!\n") + f.write(f" Hash: {hash_hex}\n") + f.write(f" Difficulty: {difficulty:.6f}\n") + f.write(f" Height: {height}\n") + f.write(f" Reward: {reward:.8f} RIN\n") + f.write(f" Nonce: {nonce}\n") + f.write(f" Time: {ntime}\n") + f.write("-" * 40 + "\n") + except Exception as e: + print(f"Failed to log hash: {e}") + + def log_wallet_balance(self): + """Log current wallet balance to file""" + try: + balance = self.rpc_call("getbalance") + if balance is not None: + timestamp = time.strftime('%Y-%m-%d %H:%M:%S') + with open(self.log_file, 'a') as f: + f.write(f"[{timestamp}] ๐Ÿ’ฐ Wallet Balance: {balance:.8f} RIN\n") + except Exception as e: + print(f"Failed to log wallet balance: {e}") + + def rpc_call(self, method, params=[]): + """Make RPC call to RinCoin node""" + try: + url = f"http://{self.rpc_host}:{self.rpc_port}/" + headers = {'content-type': 'text/plain'} + auth = HTTPBasicAuth(self.rpc_user, self.rpc_password) + + payload = { + "jsonrpc": "1.0", + "id": "stratum_proxy", + "method": method, + "params": params + } + + response = requests.post(url, json=payload, headers=headers, auth=auth, timeout=30) + + if response.status_code == 200: + result = response.json() + if 'error' in result and result['error'] is not None: + print(f"RPC Error: {result['error']}") + return None + return result.get('result') + else: + print(f"HTTP Error: {response.status_code}") + return None + + except Exception as e: + print(f"RPC Call Error: {e}") + return None + + def encode_varint(self, n): + """Encode integer as Bitcoin-style varint""" + if n < 0xfd: + return bytes([n]) + elif n <= 0xffff: + return b"\xfd" + struct.pack(' bytes: + outputs_blob = b'' + outputs_list = [] + # Main output + outputs_list.append(struct.pack(' 1: + if len(hashes) % 2 == 1: + hashes.append(hashes[-1]) # Duplicate last hash if odd + + next_level = [] + for i in range(0, len(hashes), 2): + combined = hashes[i] + hashes[i + 1] + next_level.append(hashlib.sha256(hashlib.sha256(combined).digest()).digest()) + + hashes = next_level + + return hashes[0] if hashes else b'\x00' * 32 + + except Exception as e: + print(f"Merkle root calculation error: {e}") + return b'\x00' * 32 + + def bits_to_target(self, bits_hex): + """Convert bits to target - FIXED VERSION""" + try: + bits = int(bits_hex, 16) + exponent = bits >> 24 + mantissa = bits & 0xffffff + + # Bitcoin target calculation + if exponent <= 3: + target = mantissa >> (8 * (3 - exponent)) + else: + target = mantissa << (8 * (exponent - 3)) + + return f"{target:064x}" + except Exception as e: + print(f"Bits to target error: {e}") + return "0000ffff00000000000000000000000000000000000000000000000000000000" + + def get_block_template(self): + """Get new block template and create Stratum job""" + try: + template = self.rpc_call("getblocktemplate", [{"rules": ["segwit", "mweb"]}]) + if not template: + return None + + self.job_counter += 1 + + job = { + "job_id": f"job_{self.job_counter:08x}", + "template": template, + "prevhash": template.get("previousblockhash", "0" * 64), + "version": template.get('version', 1), + "bits": template.get('bits', '1d00ffff'), + "ntime": f"{int(time.time()):08x}", + "target": self.bits_to_target(template.get('bits', '1d00ffff')), + "height": template.get('height', 0), + "coinbasevalue": template.get('coinbasevalue', 0), + "transactions": template.get('transactions', []) + } + + self.current_job = job + timestamp = time.strftime("%Y-%m-%d %H:%M:%S") + network_difficulty = self.calculate_network_difficulty(job['target']) + print(f"[{timestamp}] ๐Ÿ†• NEW JOB: {job['job_id']} | Height: {job['height']} | Reward: {job['coinbasevalue']/100000000:.2f} RIN") + print(f" ๐ŸŽฏ Network Difficulty: {network_difficulty:.6f} | Bits: {job['bits']}") + print(f" ๐Ÿ“ Target: {job['target'][:16]}... | Transactions: {len(job['transactions'])}") + return job + + except Exception as e: + print(f"Get block template error: {e}") + return None + + def calculate_share_difficulty(self, hash_hex, target_hex): + """Calculate actual share difficulty from hash - FIXED""" + try: + hash_int = int(hash_hex, 16) + + if hash_int == 0: + return float('inf') # Perfect hash + + # Bitcoin-style difficulty calculation using difficulty 1 target + # Difficulty 1 target for mainnet + diff1_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 + + # Share difficulty = how much harder this hash was compared to diff 1 + difficulty = diff1_target / hash_int + + return difficulty + except Exception as e: + print(f"Difficulty calculation error: {e}") + return 0.0 + + def calculate_network_difficulty(self, target_hex): + """Calculate network difficulty from target - FIXED""" + try: + target_int = int(target_hex, 16) + + # Bitcoin difficulty 1.0 target + diff1_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 + + # Network difficulty = how much harder than difficulty 1.0 + network_difficulty = diff1_target / target_int + + return network_difficulty + except Exception as e: + print(f"Network difficulty calculation error: {e}") + return 1.0 + + def submit_share(self, job, extranonce1, extranonce2, ntime, nonce, target_address=None): + """Validate share and submit block if valid - FIXED VERSION""" + try: + # Use provided address or default + address = target_address or self.target_address + + # Build coinbase (with and without witness) + coinbase_wit, coinbase_nowit = self.build_coinbase_transaction_for_address( + job['template'], extranonce1, extranonce2, address) + if not coinbase_wit or not coinbase_nowit: + return False, "Coinbase construction failed" + + # Calculate coinbase txid (non-witness serialization) + coinbase_txid = hashlib.sha256(hashlib.sha256(coinbase_nowit).digest()).digest()[::-1] + + # Calculate merkle root + merkle_root = self.calculate_merkle_root(coinbase_txid, job['transactions']) + + # Build block header - FIXED ENDIANNESS + header = b'' + header += struct.pack(' 0 else 0 + + # Progress indicator based on percentage + if meets_target: + progress_icon = "๐ŸŽ‰" # Block found! + elif difficulty_percentage >= 50: + progress_icon = "๐Ÿ”ฅ" # Very close + elif difficulty_percentage >= 10: + progress_icon = "โšก" # Getting warm + elif difficulty_percentage >= 1: + progress_icon = "๐Ÿ’ซ" # Some progress + else: + progress_icon = "๐Ÿ“Š" # Low progress + + print(f"[{timestamp}] {progress_icon} SHARE: job={job['job_id']} | nonce={nonce} | hash={block_hash_hex[:16]}...") + print(f" ๐ŸŽฏ Share Diff: {share_difficulty:.2e} | Network Diff: {network_difficulty:.6f}") + print(f" ๐Ÿ“ˆ Progress: {difficulty_percentage:.4f}% of network difficulty") + print(f" ๐Ÿ“ Target: {job['target'][:16]}... | Height: {job['height']}") + print(f" โฐ Time: {ntime} | Extranonce: {extranonce1}:{extranonce2}") + print(f" ๐Ÿ” Hash vs Target: {hash_int} {'<=' if meets_target else '>'} {target_int}") + + if not meets_target: + # Share doesn't meet target - reject but still useful for debugging + print(f" โŒ Share rejected (hash > target)") + return False, "Share too high" + + # Valid block! Build full block and submit + print(f" ๐ŸŽ‰ BLOCK FOUND! Hash: {block_hash_hex}") + print(f" ๐Ÿ’ฐ Reward: {job['coinbasevalue']/100000000:.2f} RIN -> {address}") + print(f" ๐Ÿ“Š Block height: {job['height']}") + print(f" ๐Ÿ” Difficulty: {share_difficulty:.6f} (target: {network_difficulty:.6f})") + + # Log the found hash + reward_rin = job['coinbasevalue'] / 100000000 + self.log_hash_found(block_hash_hex, share_difficulty, job['height'], reward_rin, nonce, ntime) + + # Build complete block + block = header + + # Transaction count + tx_count = 1 + len(job['transactions']) + block += self.encode_varint(tx_count) + + # Add coinbase transaction (witness variant for block body) + block += coinbase_wit + + # Add other transactions + for tx in job['transactions']: + block += bytes.fromhex(tx['data']) + + # Submit block + block_hex = block.hex() + print(f" ๐Ÿ“ฆ Submitting block of size {len(block_hex)//2} bytes...") + + result = self.rpc_call("submitblock", [block_hex]) + + if result is None: + print(f" โœ… Block accepted by network!") + # Log wallet balance after successful block submission + self.log_wallet_balance() + return True, "Block found and submitted" + else: + print(f" โŒ Block rejected: {result}") + print(f" ๐Ÿ” Debug: Block size {len(block_hex)//2} bytes, {len(job['transactions'])} transactions") + return False, f"Block rejected: {result}" + + except Exception as e: + print(f"Share submission error: {e}") + return False, f"Submission error: {e}" + + def send_stratum_response(self, client, msg_id, result, error=None): + """Send Stratum response to client""" + try: + response = { + "id": msg_id, + "result": result, + "error": error + } + message = json.dumps(response) + "\n" + client.send(message.encode('utf-8')) + except Exception as e: + print(f"Send response error: {e}") + + def send_stratum_notification(self, client, method, params): + """Send Stratum notification to client""" + try: + notification = { + "id": None, + "method": method, + "params": params + } + message = json.dumps(notification) + "\n" + client.send(message.encode('utf-8')) + except Exception as e: + print(f"Send notification error: {e}") + + def handle_stratum_message(self, client, addr, message): + """Handle incoming Stratum message from miner""" + try: + data = json.loads(message.strip()) + method = data.get("method") + msg_id = data.get("id") + params = data.get("params", []) + + if method == "mining.subscribe": + # Generate unique extranonce1 for this connection + self.extranonce1_counter += 1 + extranonce1 = f"{self.extranonce1_counter:08x}" + + # Store extranonce1 for this client + if addr not in self.clients: + self.clients[addr] = {} + self.clients[addr]['extranonce1'] = extranonce1 + + # Subscribe response + self.send_stratum_response(client, msg_id, [ + [["mining.set_difficulty", "subscription_id"], ["mining.notify", "subscription_id"]], + extranonce1, + 4 # extranonce2 size + ]) + + # Send difficulty - MUCH LOWER for testing + self.send_stratum_notification(client, "mining.set_difficulty", [0.00001]) + + # Send initial job + if self.current_job: + self.send_job_to_client(client, self.current_job) + else: + if self.get_block_template(): + self.send_job_to_client(client, self.current_job) + + elif method == "mining.authorize": + username = params[0] if params else "anonymous" + self.clients[addr]['username'] = username + self.send_stratum_response(client, msg_id, True) + timestamp = time.strftime("%Y-%m-%d %H:%M:%S") + print(f"[{timestamp}] ๐Ÿ” [{addr}] Authorized as {username}") + + elif method == "mining.extranonce.subscribe": + self.send_stratum_response(client, msg_id, True) + + elif method == "mining.submit": + if len(params) >= 5: + username = params[0] + job_id = params[1] + extranonce2 = params[2] + ntime = params[3] + nonce = params[4] + + print(f"[{addr}] Submit: {username} | job={job_id} | nonce={nonce}") + + # Always validate against current job + if self.current_job: + extranonce1 = self.clients[addr].get('extranonce1', '00000000') + + # Submit share + success, message = self.submit_share(self.current_job, extranonce1, extranonce2, ntime, nonce) + + # Always accept shares for debugging, even if they don't meet target + self.send_stratum_response(client, msg_id, True) + + if success and "Block found" in message: + # Get new job after block found + threading.Thread(target=self.update_job_after_block, daemon=True).start() + else: + self.send_stratum_response(client, msg_id, True) + else: + self.send_stratum_response(client, msg_id, False, "Invalid parameters") + + else: + print(f"[{addr}] Unknown method: {method}") + self.send_stratum_response(client, msg_id, None, "Unknown method") + + except json.JSONDecodeError: + print(f"[{addr}] Invalid JSON: {message}") + except Exception as e: + print(f"[{addr}] Message handling error: {e}") + + def send_job_to_client(self, client, job): + """Send mining job to specific client""" + try: + self.send_stratum_notification(client, "mining.notify", [ + job["job_id"], + job["prevhash"], + "", # coinb1 (empty for now - miner handles coinbase) + "", # coinb2 (empty for now - miner handles coinbase) + [], # merkle_branch (empty for now - we calculate merkle root) + f"{job['version']:08x}", + job["bits"], + job["ntime"], + True # clean_jobs + ]) + except Exception as e: + print(f"Failed to send job: {e}") + + def update_job_after_block(self): + """Update job after a block is found""" + time.sleep(2) # Brief delay to let network propagate + if self.get_block_template(): + self.broadcast_new_job() + + def broadcast_new_job(self): + """Broadcast new job to all connected clients""" + if not self.current_job: + return + + print(f"Broadcasting new job to {len(self.clients)} clients") + + for addr, client_data in list(self.clients.items()): + try: + if 'socket' in client_data: + self.send_job_to_client(client_data['socket'], self.current_job) + except Exception as e: + print(f"Failed to send job to {addr}: {e}") + + def handle_client(self, client, addr): + """Handle individual client connection""" + print(f"[{addr}] Connected") + if addr not in self.clients: + self.clients[addr] = {} + self.clients[addr]['socket'] = client + + try: + while self.running: + data = client.recv(4096) + if not data: + break + + # Handle multiple messages in one packet + messages = data.decode('utf-8').strip().split('\n') + for message in messages: + if message: + self.handle_stratum_message(client, addr, message) + + except Exception as e: + print(f"[{addr}] Client error: {e}") + finally: + client.close() + if addr in self.clients: + del self.clients[addr] + print(f"[{addr}] Disconnected") + + def job_updater(self): + """Periodically update mining jobs""" + balance_log_counter = 0 + while self.running: + try: + time.sleep(30) # Update every 30 seconds + + old_height = self.current_job['height'] if self.current_job else 0 + + if self.get_block_template(): + new_height = self.current_job['height'] + if new_height > old_height: + print(f"New block detected! Broadcasting new job...") + self.broadcast_new_job() + + # Log wallet balance every 10 minutes (20 cycles of 30 seconds) + balance_log_counter += 1 + if balance_log_counter >= 20: + self.log_wallet_balance() + balance_log_counter = 0 + + except Exception as e: + print(f"Job updater error: {e}") + + def start(self): + """Start the Stratum proxy server""" + try: + # Test RPC connection + blockchain_info = self.rpc_call("getblockchaininfo") + if not blockchain_info: + print("Failed to connect to RinCoin node!") + return + + print(f"Connected to RinCoin node") + print(f"Current height: {blockchain_info.get('blocks', 'unknown')}") + print(f"Chain: {blockchain_info.get('chain', 'unknown')}") + + # Log initial wallet balance + self.log_wallet_balance() + + # Get initial block template + if not self.get_block_template(): + print("Failed to get initial block template!") + return + + # Start job updater thread + job_thread = threading.Thread(target=self.job_updater, daemon=True) + job_thread.start() + + # Start Stratum server + server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + server_socket.bind((self.stratum_host, self.stratum_port)) + server_socket.listen(10) + + timestamp = time.strftime("%Y-%m-%d %H:%M:%S") + print(f"[{timestamp}] ๐Ÿš€ Mining Stratum proxy ready!") + print(f" ๐Ÿ“ก Listening on {self.stratum_host}:{self.stratum_port}") + print(f" ๐Ÿ’ฐ Mining to: {self.target_address}") + print(f" ๐Ÿ“Š Current job: {self.current_job['job_id'] if self.current_job else 'None'}") + print(f" ๐Ÿ“ Mining log: {self.log_file}") + print("") + print(" ๐Ÿ”ง Miner command:") + print(f" ./cpuminer -a rinhash -o stratum+tcp://{self.stratum_host}:{self.stratum_port} -u worker1 -p x -t 4") + print("") + + while self.running: + try: + client, addr = server_socket.accept() + client_thread = threading.Thread( + target=self.handle_client, + args=(client, addr), + daemon=True + ) + client_thread.start() + except KeyboardInterrupt: + print("\nShutting down...") + self.running = False + break + except Exception as e: + print(f"Server error: {e}") + + except Exception as e: + print(f"Failed to start server: {e}") + finally: + print("Server stopped") + +if __name__ == "__main__": + proxy = RinCoinStratumProxy() + proxy.start() diff --git a/MINE/rin/view_mining_log.sh b/MINE/rin/view_mining_log.sh new file mode 100644 index 0000000..de4ec60 --- /dev/null +++ b/MINE/rin/view_mining_log.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +# View RinCoin Mining Log +# Shows the latest mining activity and wallet balance + +LOG_FILE="mining_log.txt" + +if [ ! -f "$LOG_FILE" ]; then + echo "โŒ Mining log file '$LOG_FILE' not found!" + echo "Make sure the stratum proxy has been started at least once." + exit 1 +fi + +echo "=== RinCoin Mining Log Viewer ===" +echo "" + +# Show last 20 lines of the log +echo "๐Ÿ“Š Recent Activity (last 20 entries):" +echo "----------------------------------------" +tail -20 "$LOG_FILE" + +echo "" +echo "๐Ÿ’ฐ Current Wallet Balance:" +echo "----------------------------------------" +grep "Wallet Balance:" "$LOG_FILE" | tail -1 || echo "No balance logged yet" + +echo "" +echo "๐ŸŽ‰ Total Blocks Found:" +echo "----------------------------------------" +grep -c "HASH FOUND!" "$LOG_FILE" || echo "0" + +echo "" +echo "๐Ÿ“ˆ Total Mining Time:" +echo "----------------------------------------" +if grep -q "Started:" "$LOG_FILE"; then + START_TIME=$(grep "Started:" "$LOG_FILE" | head -1 | cut -d' ' -f2-3) + echo "Started: $START_TIME" + echo "Current: $(date '+%Y-%m-%d %H:%M:%S')" +else + echo "Start time not available" +fi + +echo "" +echo "๐Ÿ“ Full log available at: $LOG_FILE" +echo "๐Ÿ”„ To watch live updates: tail -f $LOG_FILE" From 747b8efb1055ab051a89d1e21449aed46540068a Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Sat, 20 Sep 2025 22:09:14 +0300 Subject: [PATCH 09/30] move readmes --- MINE/rin/QUICK_REFERENCE.md | 67 ------------------------- MINE/rin/REWARD_DISTRIBUTION_EXAMPLE.md | 40 --------------- 2 files changed, 107 deletions(-) delete mode 100644 MINE/rin/QUICK_REFERENCE.md delete mode 100644 MINE/rin/REWARD_DISTRIBUTION_EXAMPLE.md diff --git a/MINE/rin/QUICK_REFERENCE.md b/MINE/rin/QUICK_REFERENCE.md deleted file mode 100644 index 6debf73..0000000 --- a/MINE/rin/QUICK_REFERENCE.md +++ /dev/null @@ -1,67 +0,0 @@ -# RinCoin Mining Quick Reference - -## ๐Ÿš€ **Quick Commands:** - -### **Solo Mining (All Rewards to You)** -```bash -# Start solo mining proxy -./MINE/rin/start_stratum_proxy.sh - -# Connect miner -./cpuminer -a rinhash -o stratum+tcp://127.0.0.1:3333 -u user -p pass -t 28 -``` - -### **Mining Pool (Distribute Rewards)** -```bash -# Start mining pool -./MINE/rin/start_mining_pool.sh - -# Miners connect -./cpuminer -a rinhash -o stratum+tcp://YOUR_IP:3333 -u username.workername -p x -``` - -### **Cleanup** -```bash -# Kill proxy/pool processes -./MINE/rin/kill_stratum_proxy.sh -``` - -## ๐Ÿ“Š **What Each Does:** - -| Command | Purpose | Rewards | Miners | -|---------|---------|---------|--------| -| `start_stratum_proxy.sh` | Solo mining | 100% to you | Single | -| `start_mining_pool.sh` | Pool mining | Distributed | Multiple | - -## ๐ŸŒ **Web Dashboard (Pool Only)** -- **URL**: `http://YOUR_IP:8080` -- **Features**: Stats, miners, blocks, hashrate - -## โšก **Quick Test** -```bash -# Test solo mining -./MINE/rin/start_stratum_proxy.sh & -sleep 5 -./cpuminer -a rinhash -o stratum+tcp://127.0.0.1:3333 -u user -p pass -t 4 - - - -## Check wallets - -# First, check available wallets and load one if needed -curl -u rinrpc:745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90 -d '{"jsonrpc":"1.0","id":"1","method":"listwalletdir","params":[]}' -H 'content-type: text/plain;' http://127.0.0.1:9556/ - -# Load wallet (replace "main" with your wallet name) -curl -u rinrpc:745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90 -d '{"jsonrpc":"1.0","id":"1","method":"loadwallet","params":["main"]}' -H 'content-type: text/plain;' http://127.0.0.1:9556/ - -# Total received by your address -curl -u rinrpc:745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90 -d '{"jsonrpc":"1.0","id":"1","method":"getreceivedbyaddress","params":["rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q",0]}' -H 'content-type: text/plain;' http://127.0.0.1:9556/ - -# Wallet balance -curl -u rinrpc:745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90 -d '{"jsonrpc":"1.0","id":"1","method":"getbalance","params":[]}' -H 'content-type: text/plain;' http://127.0.0.1:9556/ - -# Recent transactions -curl -u rinrpc:745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90 -d '{"jsonrpc":"1.0","id":"1","method":"listtransactions","params":[]}' -H 'content-type: text/plain;' http://127.0.0.1:9556/ -``` - - diff --git a/MINE/rin/REWARD_DISTRIBUTION_EXAMPLE.md b/MINE/rin/REWARD_DISTRIBUTION_EXAMPLE.md deleted file mode 100644 index 1f042c9..0000000 --- a/MINE/rin/REWARD_DISTRIBUTION_EXAMPLE.md +++ /dev/null @@ -1,40 +0,0 @@ -# Reward Distribution Example - -## Scenario: Block Reward = 50 RIN (49 RIN after 1% pool fee) - -### Miners Connected: -1. **Miner A**: `rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q.worker1` (30 difficulty) -2. **Miner B**: `user.worker2` (20 difficulty) - No address specified -3. **Miner C**: `rin1qxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.worker3` (50 difficulty) - **INVALID ADDRESS** - -### Total Difficulty: 100 - -### Reward Distribution: - -#### **Step 1: Calculate Individual Shares** -- **Miner A**: (30/100) ร— 49 = **14.7 RIN** โ†’ `rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q` -- **Miner B**: (20/100) ร— 49 = **9.8 RIN** โ†’ **Pool address** (no valid address) -- **Miner C**: (50/100) ร— 49 = **24.5 RIN** โ†’ **Pool address** (invalid address) - -#### **Step 2: Final Distribution** -- **Pool Address**: 1 RIN (fee) + 9.8 RIN (from Miner B) + 24.5 RIN (from Miner C) = **35.3 RIN** -- **Miner A**: **14.7 RIN** - -### Pool Logs: -``` -[127.0.0.1] โœ… Authorized: miner_rin1qah.worker1 -> rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q -[127.0.0.1] โš ๏ธ Authorized: user.worker2 (rewards will go to pool address) -[127.0.0.1] โŒ Invalid RinCoin address: rin1qxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -๐Ÿ’ฐ Miner rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q: 14.70000000 RIN (30 difficulty) -โš ๏ธ Miner without address: 20 difficulty -> 9.80000000 RIN to pool -โš ๏ธ Miner without address: 50 difficulty -> 24.50000000 RIN to pool -๐Ÿ’ฐ Pool keeps 34.30000000 RIN from miners without addresses -๐Ÿ“Š Summary: 1 miners with addresses, 2 without (rewards to pool) -``` - -### Key Points: -- โœ… **Miners with valid addresses**: Get their full share -- โš ๏ธ **Miners without addresses**: Contribute to difficulty but rewards go to pool -- โŒ **Miners with invalid addresses**: Rejected at connection time -- ๐Ÿ’ฐ **Pool benefits**: Gets additional rewards from careless miners -- ๐Ÿ“Š **Transparent**: All distributions clearly logged From 992a7704b6b55d9fc40b96d7da47c2a15d12a944 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 23 Sep 2025 11:29:56 +0300 Subject: [PATCH 10/30] stratum proxy wip --- MINE/rin/mining_log.txt | 10 +++ MINE/rin/stratum_proxy.py | 150 ++++++++++++++++++++++---------------- mining_log.txt | 10 +++ 3 files changed, 106 insertions(+), 64 deletions(-) create mode 100644 MINE/rin/mining_log.txt create mode 100644 mining_log.txt diff --git a/MINE/rin/mining_log.txt b/MINE/rin/mining_log.txt new file mode 100644 index 0000000..5a399b5 --- /dev/null +++ b/MINE/rin/mining_log.txt @@ -0,0 +1,10 @@ +================================================================================ +RinCoin Mining Log +================================================================================ +Started: 2025-09-23 11:28:19 +Target Address: rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q +Stratum: 0.0.0.0:3334 +RPC: 127.0.0.1:9556 +================================================================================ + +[2025-09-23 11:28:19] ๐Ÿ’ฐ Wallet Balance: 25.00000000 RIN diff --git a/MINE/rin/stratum_proxy.py b/MINE/rin/stratum_proxy.py index e9e4bd6..4378ad9 100644 --- a/MINE/rin/stratum_proxy.py +++ b/MINE/rin/stratum_proxy.py @@ -329,7 +329,7 @@ class RinCoinStratumProxy: print(f"Network difficulty calculation error: {e}") return 1.0 - def submit_share(self, job, extranonce1, extranonce2, ntime, nonce, target_address=None): + def submit_share(self, job, extranonce1, extranonce2, ntime, nonce, addr=None, target_address=None): """Validate share and submit block if valid - FIXED VERSION""" try: # Use provided address or default @@ -353,7 +353,7 @@ class RinCoinStratumProxy: header += bytes.fromhex(job['prevhash'])[::-1] # Previous block hash (big-endian in block) header += merkle_root # Merkle root (already in correct endian) header += struct.pack(' 0 else 0 - - # Progress indicator based on percentage - if meets_target: + network_percentage = (share_difficulty / network_difficulty) * 100 if network_difficulty > 0 else 0 + stratum_percentage = (share_difficulty / client_stratum_diff) * 100 if client_stratum_diff > 0 else 0 + + # Progress indicator based on network percentage + if meets_network_target: progress_icon = "๐ŸŽ‰" # Block found! - elif difficulty_percentage >= 50: - progress_icon = "๐Ÿ”ฅ" # Very close - elif difficulty_percentage >= 10: + elif meets_stratum_target: + progress_icon = "โœ…" # Valid share for stratum + elif network_percentage >= 50: + progress_icon = "๐Ÿ”ฅ" # Very close to network + elif network_percentage >= 10: progress_icon = "โšก" # Getting warm - elif difficulty_percentage >= 1: + elif network_percentage >= 1: progress_icon = "๐Ÿ’ซ" # Some progress else: progress_icon = "๐Ÿ“Š" # Low progress - + print(f"[{timestamp}] {progress_icon} SHARE: job={job['job_id']} | nonce={nonce} | hash={block_hash_hex[:16]}...") - print(f" ๐ŸŽฏ Share Diff: {share_difficulty:.2e} | Network Diff: {network_difficulty:.6f}") - print(f" ๐Ÿ“ˆ Progress: {difficulty_percentage:.4f}% of network difficulty") + print(f" ๐ŸŽฏ Share Diff: {share_difficulty:.2e} | Stratum Diff: {client_stratum_diff:.6f} | Network Diff: {network_difficulty:.6f}") + print(f" ๐Ÿ“ˆ Progress: {network_percentage:.4f}% of network, {stratum_percentage:.1f}% of stratum") print(f" ๐Ÿ“ Target: {job['target'][:16]}... | Height: {job['height']}") print(f" โฐ Time: {ntime} | Extranonce: {extranonce1}:{extranonce2}") - print(f" ๐Ÿ” Hash vs Target: {hash_int} {'<=' if meets_target else '>'} {target_int}") - - if not meets_target: - # Share doesn't meet target - reject but still useful for debugging - print(f" โŒ Share rejected (hash > target)") + print(f" ๐Ÿ” Hash vs Network: {hash_int} {'<=' if meets_network_target else '>'} {network_target_int}") + print(f" ๐Ÿ” Hash vs Stratum: {hash_int} {'<=' if meets_stratum_target else '>'} {stratum_target_int}") + + if not meets_stratum_target: + # Share doesn't meet stratum target - reject + print(f" โŒ Share rejected (hash > stratum target)") return False, "Share too high" - - # Valid block! Build full block and submit - print(f" ๐ŸŽ‰ BLOCK FOUND! Hash: {block_hash_hex}") - print(f" ๐Ÿ’ฐ Reward: {job['coinbasevalue']/100000000:.2f} RIN -> {address}") - print(f" ๐Ÿ“Š Block height: {job['height']}") - print(f" ๐Ÿ” Difficulty: {share_difficulty:.6f} (target: {network_difficulty:.6f})") - - # Log the found hash - reward_rin = job['coinbasevalue'] / 100000000 - self.log_hash_found(block_hash_hex, share_difficulty, job['height'], reward_rin, nonce, ntime) - - # Build complete block - block = header - - # Transaction count - tx_count = 1 + len(job['transactions']) - block += self.encode_varint(tx_count) - - # Add coinbase transaction (witness variant for block body) - block += coinbase_wit - - # Add other transactions - for tx in job['transactions']: - block += bytes.fromhex(tx['data']) - - # Submit block - block_hex = block.hex() - print(f" ๐Ÿ“ฆ Submitting block of size {len(block_hex)//2} bytes...") - - result = self.rpc_call("submitblock", [block_hex]) - - if result is None: - print(f" โœ… Block accepted by network!") - # Log wallet balance after successful block submission - self.log_wallet_balance() - return True, "Block found and submitted" + + # Valid stratum share! 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}") + print(f" ๐Ÿ“Š Block height: {job['height']}") + print(f" ๐Ÿ” Difficulty: {share_difficulty:.6f} (target: {network_difficulty:.6f})") + + # Log the found hash + reward_rin = job['coinbasevalue'] / 100000000 + self.log_hash_found(block_hash_hex, share_difficulty, job['height'], reward_rin, nonce, ntime) + + # Build complete block + block = header + + # Transaction count + tx_count = 1 + len(job['transactions']) + block += self.encode_varint(tx_count) + + # Add coinbase transaction (witness variant for block body) + block += coinbase_wit + + # Add other transactions + for tx in job['transactions']: + block += bytes.fromhex(tx['data']) + + # Submit block + block_hex = block.hex() + print(f" ๐Ÿ“ฆ Submitting block of size {len(block_hex)//2} bytes...") + + result = self.rpc_call("submitblock", [block_hex]) + + if result is None: + print(f" โœ… Block accepted by network!") + # Log wallet balance after successful block submission + self.log_wallet_balance() + return True, "Block found and submitted" + else: + print(f" โŒ Block rejected: {result}") + print(f" ๐Ÿ” Debug: Block size {len(block_hex)//2} bytes, {len(job['transactions'])} transactions") + return False, f"Block rejected: {result}" else: - print(f" โŒ Block rejected: {result}") - print(f" ๐Ÿ” Debug: Block size {len(block_hex)//2} bytes, {len(job['transactions'])} transactions") - return False, f"Block rejected: {result}" + # Valid stratum share but not network-valid block + print(f" โœ… Valid stratum share accepted") + return True, "Valid stratum share" except Exception as e: print(f"Share submission error: {e}") @@ -492,8 +508,14 @@ class RinCoinStratumProxy: 4 # extranonce2 size ]) - # Send difficulty - MUCH LOWER for testing - self.send_stratum_notification(client, "mining.set_difficulty", [0.00001]) + # 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 + # 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]) # Send initial job if self.current_job: @@ -527,7 +549,7 @@ class RinCoinStratumProxy: extranonce1 = self.clients[addr].get('extranonce1', '00000000') # Submit share - success, message = self.submit_share(self.current_job, extranonce1, extranonce2, ntime, nonce) + success, message = self.submit_share(self.current_job, extranonce1, extranonce2, ntime, nonce, addr) # Always accept shares for debugging, even if they don't meet target self.send_stratum_response(client, msg_id, True) diff --git a/mining_log.txt b/mining_log.txt new file mode 100644 index 0000000..e731e0b --- /dev/null +++ b/mining_log.txt @@ -0,0 +1,10 @@ +================================================================================ +RinCoin Mining Log +================================================================================ +Started: 2025-09-23 11:27:51 +Target Address: rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q +Stratum: 0.0.0.0:3334 +RPC: 127.0.0.1:9556 +================================================================================ + +[2025-09-23 11:27:51] ๐Ÿ’ฐ Wallet Balance: 25.00000000 RIN From bc50e52cdb0dbe4bd64a85a1e773699efc3a4515 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 23 Sep 2025 11:34:13 +0300 Subject: [PATCH 11/30] stratum - fix miner info --- MINE/rin/mining_log.txt | 4 +- MINE/rin/stratum_proxy.py | 78 +++++++++++++++++++++++++++++++++++---- 2 files changed, 72 insertions(+), 10 deletions(-) diff --git a/MINE/rin/mining_log.txt b/MINE/rin/mining_log.txt index 5a399b5..22b4fca 100644 --- a/MINE/rin/mining_log.txt +++ b/MINE/rin/mining_log.txt @@ -1,10 +1,10 @@ ================================================================================ RinCoin Mining Log ================================================================================ -Started: 2025-09-23 11:28:19 +Started: 2025-09-23 11:31:27 Target Address: rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q Stratum: 0.0.0.0:3334 RPC: 127.0.0.1:9556 ================================================================================ -[2025-09-23 11:28:19] ๐Ÿ’ฐ Wallet Balance: 25.00000000 RIN +[2025-09-23 11:31:27] ๐Ÿ’ฐ Wallet Balance: 25.00000000 RIN diff --git a/MINE/rin/stratum_proxy.py b/MINE/rin/stratum_proxy.py index 4378ad9..e775691 100644 --- a/MINE/rin/stratum_proxy.py +++ b/MINE/rin/stratum_proxy.py @@ -222,25 +222,66 @@ class RinCoinStratumProxy: hashes = [coinbase_txid] for tx in transactions: hashes.append(bytes.fromhex(tx['hash'])[::-1]) # Reverse for little-endian - + # Build merkle tree while len(hashes) > 1: if len(hashes) % 2 == 1: hashes.append(hashes[-1]) # Duplicate last hash if odd - + next_level = [] for i in range(0, len(hashes), 2): combined = hashes[i] + hashes[i + 1] next_level.append(hashlib.sha256(hashlib.sha256(combined).digest()).digest()) - + hashes = next_level - + return hashes[0] if hashes else b'\x00' * 32 - + except Exception as e: print(f"Merkle root calculation error: {e}") return b'\x00' * 32 + def calculate_merkle_branches(self, tx_hashes, tx_index): + """Calculate merkle branches for a specific transaction index""" + try: + if not tx_hashes or tx_index >= len(tx_hashes): + return [] + + branches = [] + current_index = tx_index + + # Start with the full list of transaction hashes + hashes = tx_hashes[:] + + while len(hashes) > 1: + if len(hashes) % 2 == 1: + hashes.append(hashes[-1]) # Duplicate last hash if odd + + # Find the partner for current_index + partner_index = current_index ^ 1 # Flip the least significant bit + + if partner_index < len(hashes): + # Add the partner hash to branches (in big-endian for stratum) + branches.append(hashes[partner_index][::-1].hex()) + else: + # This shouldn't happen, but add the duplicate if it does + branches.append(hashes[current_index][::-1].hex()) + + # Move to next level + next_level = [] + for i in range(0, len(hashes), 2): + combined = hashes[i] + hashes[i + 1] + next_level.append(hashlib.sha256(hashlib.sha256(combined).digest()).digest()) + + hashes = next_level + current_index //= 2 + + return branches + + except Exception as e: + print(f"Merkle branches calculation error: {e}") + return [] + def bits_to_target(self, bits_hex): """Convert bits to target - FIXED VERSION""" try: @@ -574,12 +615,33 @@ class RinCoinStratumProxy: def send_job_to_client(self, client, job): """Send mining job to specific client""" try: + # Build coinbase components for stratum + height = job.get('height', 0) + height_bytes = struct.pack(' Date: Tue, 23 Sep 2025 11:39:03 +0300 Subject: [PATCH 12/30] stratum wip - valid block info --- MINE/rin/stratum_proxy.py | 199 +++++++++++++++++++++++++++++++++----- 1 file changed, 177 insertions(+), 22 deletions(-) diff --git a/MINE/rin/stratum_proxy.py b/MINE/rin/stratum_proxy.py index e775691..95aeef9 100644 --- a/MINE/rin/stratum_proxy.py +++ b/MINE/rin/stratum_proxy.py @@ -613,28 +613,97 @@ class RinCoinStratumProxy: print(f"[{addr}] Message handling error: {e}") def send_job_to_client(self, client, job): - """Send mining job to specific client""" + """Send mining job to specific client with proper stratum parameters""" try: - # Build coinbase components for stratum + # Get network difficulty for display + network_difficulty = self.calculate_network_difficulty(job['target']) + + # Build proper coinbase transaction parts for stratum protocol + template = job.get('template', {}) height = job.get('height', 0) - height_bytes = struct.pack(' 1 and height_bytes[-1] == 0: + height_bytes = height_bytes[:-1] + height_push = bytes([len(height_bytes)]) + height_bytes + + # Build coinbase input script: height + arbitrary data + extranonces + coinb1_script = height_push + b'/RinCoin/' + + # Build coinbase transaction structure + # Version (4 bytes) + coinb1 = struct.pack(' Date: Tue, 23 Sep 2025 11:46:07 +0300 Subject: [PATCH 13/30] 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: From 210bfc5176dfa9a859c785215093e080302fe618 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 23 Sep 2025 11:48:27 +0300 Subject: [PATCH 14/30] stratum - dynamic difficulty to 1m --- MINE/rin/mining_log.txt | 3 +-- MINE/rin/stratum_proxy.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/MINE/rin/mining_log.txt b/MINE/rin/mining_log.txt index 22b4fca..1c21907 100644 --- a/MINE/rin/mining_log.txt +++ b/MINE/rin/mining_log.txt @@ -1,10 +1,9 @@ ================================================================================ RinCoin Mining Log ================================================================================ -Started: 2025-09-23 11:31:27 +Started: 2025-09-23 11:44:13 Target Address: rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q Stratum: 0.0.0.0:3334 RPC: 127.0.0.1:9556 ================================================================================ -[2025-09-23 11:31:27] ๐Ÿ’ฐ Wallet Balance: 25.00000000 RIN diff --git a/MINE/rin/stratum_proxy.py b/MINE/rin/stratum_proxy.py index 5d05743..eb2bef8 100644 --- a/MINE/rin/stratum_proxy.py +++ b/MINE/rin/stratum_proxy.py @@ -36,7 +36,7 @@ class RinCoinStratumProxy: # 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 + self.target_share_interval = 120 # Target: 1 share every 2 minutes per miner (aligned with ~1min blocks) # Logging setup self.log_file = "mining_log.txt" From 44d6d911036a10af07dddc4011be412fff0c3381 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 23 Sep 2025 11:52:01 +0300 Subject: [PATCH 15/30] stratum: "shares should now be accepted" --- MINE/rin/mining_log.txt | 3 +- MINE/rin/stratum_proxy.py | 85 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 84 insertions(+), 4 deletions(-) diff --git a/MINE/rin/mining_log.txt b/MINE/rin/mining_log.txt index 1c21907..070a8c4 100644 --- a/MINE/rin/mining_log.txt +++ b/MINE/rin/mining_log.txt @@ -1,9 +1,10 @@ ================================================================================ RinCoin Mining Log ================================================================================ -Started: 2025-09-23 11:44:13 +Started: 2025-09-23 11:51:14 Target Address: rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q Stratum: 0.0.0.0:3334 RPC: 127.0.0.1:9556 ================================================================================ +[2025-09-23 11:51:14] ๐Ÿ’ฐ Wallet Balance: 25.00000000 RIN diff --git a/MINE/rin/stratum_proxy.py b/MINE/rin/stratum_proxy.py index eb2bef8..64ebb95 100644 --- a/MINE/rin/stratum_proxy.py +++ b/MINE/rin/stratum_proxy.py @@ -2,6 +2,7 @@ """ RinCoin Stratum Proxy Server - FIXED VERSION Fixed block hash calculation and validation issues +DEBUG: we get node logs with 'docker logs --tail=200 rincoin-node' """ import socket @@ -38,6 +39,18 @@ class RinCoinStratumProxy: self.last_difficulty_adjustment = time.time() self.target_share_interval = 120 # Target: 1 share every 2 minutes per miner (aligned with ~1min blocks) + # Production monitoring + self.stats = { + 'start_time': time.time(), + 'total_shares': 0, + 'accepted_shares': 0, + 'rejected_shares': 0, + 'blocks_found': 0, + 'total_hashrate': 0, + 'connections': 0 + } + self.max_connections = 50 # Production limit + # Logging setup self.log_file = "mining_log.txt" self.init_log_file() @@ -513,7 +526,8 @@ class RinCoinStratumProxy: # Get the stratum difficulty that was sent to this miner client_stratum_diff = self.clients.get(addr, {}).get('stratum_difficulty', 0.001) diff1_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 - stratum_target_int = diff1_target // max(1, int(client_stratum_diff * 1000000)) * 1000000 + # Correct stratum target calculation: target = diff1_target / difficulty + stratum_target_int = int(diff1_target / client_stratum_diff) meets_stratum_target = hash_int <= stratum_target_int meets_network_target = hash_int <= network_target_int @@ -548,6 +562,8 @@ class RinCoinStratumProxy: if not meets_stratum_target: # Share doesn't meet stratum target - reject print(f" โŒ Share rejected (hash > stratum target)") + self.stats['total_shares'] += 1 + self.stats['rejected_shares'] += 1 return False, "Share too high" # Valid stratum share! Update client stats @@ -555,8 +571,16 @@ class RinCoinStratumProxy: self.clients[addr]['share_count'] = self.clients[addr].get('share_count', 0) + 1 self.clients[addr]['last_share_time'] = time.time() + # Update global stats + self.stats['total_shares'] += 1 + self.stats['accepted_shares'] += 1 + # Check if we should adjust difficulty self.adjust_client_difficulty(addr) + else: + # Track rejected shares + self.stats['total_shares'] += 1 + self.stats['rejected_shares'] += 1 # Check if it's also a valid network block if meets_network_target: @@ -591,6 +615,8 @@ class RinCoinStratumProxy: if result is None: print(f" โœ… Block accepted by network!") + # Update block stats + self.stats['blocks_found'] += 1 # Log wallet balance after successful block submission self.log_wallet_balance() return True, "Block found and submitted" @@ -859,10 +885,17 @@ class RinCoinStratumProxy: def handle_client(self, client, addr): """Handle individual client connection""" - print(f"[{addr}] Connected") + # Check connection limits + if len(self.clients) >= self.max_connections: + print(f"[{addr}] Connection rejected - max connections ({self.max_connections}) reached") + client.close() + return + + print(f"[{addr}] Connected (clients: {len(self.clients) + 1}/{self.max_connections})") if addr not in self.clients: self.clients[addr] = {} self.clients[addr]['socket'] = client + self.stats['connections'] = len(self.clients) try: while self.running: @@ -882,11 +915,51 @@ class RinCoinStratumProxy: client.close() if addr in self.clients: del self.clients[addr] - print(f"[{addr}] Disconnected") + self.stats['connections'] = len(self.clients) + print(f"[{addr}] Disconnected (clients: {len(self.clients)}/{self.max_connections})") + + def print_stats(self): + """Print pool statistics""" + try: + uptime = time.time() - self.stats['start_time'] + uptime_str = f"{int(uptime//3600)}h {int((uptime%3600)//60)}m" + + accept_rate = 0 + if self.stats['total_shares'] > 0: + accept_rate = (self.stats['accepted_shares'] / self.stats['total_shares']) * 100 + + print(f"\n๐Ÿ“Š POOL STATISTICS:") + print(f" โฐ Uptime: {uptime_str}") + print(f" ๐Ÿ‘ฅ Connected miners: {self.stats['connections']}") + print(f" ๐Ÿ“ˆ Shares: {self.stats['accepted_shares']}/{self.stats['total_shares']} ({accept_rate:.1f}% accepted)") + print(f" ๐ŸŽ‰ Blocks found: {self.stats['blocks_found']}") + print(f" ๐ŸŽฏ Network difficulty: {self.calculate_network_difficulty(self.current_job['target']) if self.current_job else 'unknown':.6f}") + + # Calculate hashrate estimate from connected clients + total_hashrate = 0 + for addr, client_data in self.clients.items(): + share_count = client_data.get('share_count', 0) + connect_time = client_data.get('connect_time', time.time()) + mining_duration = time.time() - connect_time + if mining_duration > 60 and share_count > 0: + stratum_diff = client_data.get('stratum_difficulty', 0.001) + # Rough hashrate estimate: shares * difficulty * 2^32 / time + hashrate = (share_count * stratum_diff * 4294967296) / mining_duration + total_hashrate += hashrate + print(f" ๐Ÿ”ฅ {addr}: ~{hashrate/1000:.0f} kH/s") + + if total_hashrate > 0: + print(f" ๐Ÿš€ Total pool hashrate: ~{total_hashrate/1000:.0f} kH/s") + print() + + except Exception as e: + print(f"Stats error: {e}") def job_updater(self): """Periodically update mining jobs""" balance_log_counter = 0 + stats_counter = 0 + while self.running: try: time.sleep(30) # Update every 30 seconds @@ -904,6 +977,12 @@ class RinCoinStratumProxy: if balance_log_counter >= 20: self.log_wallet_balance() balance_log_counter = 0 + + # Print stats every 5 minutes (10 cycles of 30 seconds) + stats_counter += 1 + if stats_counter >= 10: + self.print_stats() + stats_counter = 0 except Exception as e: print(f"Job updater error: {e}") From 4743ee4369c05163b7b20a611ae837c1598adc09 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 23 Sep 2025 13:27:27 +0300 Subject: [PATCH 16/30] stratum - submit all blocks option. cleanup --- MINE/rin/README.md | 2 + MINE/rin/mining_log.txt | 4 +- MINE/rin/start_mining_with_address.sh | 81 --- MINE/rin/stratum_proxy copy.py | 550 -------------------- MINE/rin/stratum_proxy.py | 33 +- MINE/rin/stratum_proxy_debug.py | 705 -------------------------- MINE/rin/stratum_proxy_explanation.sh | 52 -- MINE/rin/test_address_validation.sh | 78 --- MINE/rin/test_pool_connections.sh | 69 --- MINE/rin/view_mining_log.sh | 45 -- 10 files changed, 27 insertions(+), 1592 deletions(-) delete mode 100644 MINE/rin/start_mining_with_address.sh delete mode 100644 MINE/rin/stratum_proxy copy.py delete mode 100644 MINE/rin/stratum_proxy_debug.py delete mode 100644 MINE/rin/stratum_proxy_explanation.sh delete mode 100644 MINE/rin/test_address_validation.sh delete mode 100644 MINE/rin/test_pool_connections.sh delete mode 100644 MINE/rin/view_mining_log.sh diff --git a/MINE/rin/README.md b/MINE/rin/README.md index 97fcf50..d8f6f1d 100644 --- a/MINE/rin/README.md +++ b/MINE/rin/README.md @@ -151,6 +151,8 @@ Your Stratum proxy can be enhanced to work as a **full mining pool** that distri # 2. Miners connect with: ./cpuminer -a rinhash -o stratum+tcp://YOUR_IP:3333 -u username.workername -p x + +cd /mnt/shared/DEV/repos/d-popov.com/scripts/MINE/rin && python3 stratum_proxy.py --submit-all-blocks ``` ### **Pool vs Solo Mining:** diff --git a/MINE/rin/mining_log.txt b/MINE/rin/mining_log.txt index 070a8c4..68e4b6d 100644 --- a/MINE/rin/mining_log.txt +++ b/MINE/rin/mining_log.txt @@ -1,10 +1,10 @@ ================================================================================ RinCoin Mining Log ================================================================================ -Started: 2025-09-23 11:51:14 +Started: 2025-09-23 13:26:20 Target Address: rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q Stratum: 0.0.0.0:3334 RPC: 127.0.0.1:9556 ================================================================================ -[2025-09-23 11:51:14] ๐Ÿ’ฐ Wallet Balance: 25.00000000 RIN +[2025-09-23 13:26:20] ๐Ÿ’ฐ Wallet Balance: 25.00000000 RIN diff --git a/MINE/rin/start_mining_with_address.sh b/MINE/rin/start_mining_with_address.sh deleted file mode 100644 index 5b135ad..0000000 --- a/MINE/rin/start_mining_with_address.sh +++ /dev/null @@ -1,81 +0,0 @@ -#!/bin/bash - -# Start RinCoin Solo Mining with Custom Address -# Usage: ./start_mining_with_address.sh [rincoin_address] [threads] - -# Default values -DEFAULT_ADDRESS="rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q" -DEFAULT_THREADS="28" - -# Parse arguments -RINCOIN_ADDRESS="${1:-$DEFAULT_ADDRESS}" -THREADS="${2:-$DEFAULT_THREADS}" - -echo "=== RinCoin Solo Mining Setup ===" -echo "RinCoin Address: $RINCOIN_ADDRESS" -echo "Threads: $THREADS" -echo "" - -# Validate RinCoin address format -if [[ ! "$RINCOIN_ADDRESS" =~ ^rin1[a-zA-Z0-9]{25,}$ ]]; then - echo "โŒ Error: Invalid RinCoin address format: $RINCOIN_ADDRESS" - echo "RinCoin addresses should start with 'rin1' and be ~30 characters long" - exit 1 -fi - -# Check if RinCoin node is running -if ! sudo docker ps | grep -q "rincoin-node"; then - echo "โŒ Error: rincoin-node container is not running!" - echo "Please start it first: sudo docker start rincoin-node" - exit 1 -fi - -echo "โœ… RinCoin node is running" - -# Check dependencies -if ! command -v python3 &> /dev/null; then - echo "โŒ Error: python3 is not installed!" - exit 1 -fi - -python3 -c "import requests" 2>/dev/null || { - echo "Installing python3-requests..." - sudo apt-get update && sudo apt-get install -y python3-requests -} - -echo "โœ… Dependencies ready" -echo "" - -# Create temporary proxy script with custom address -TEMP_PROXY="/tmp/rincoin_proxy_${RANDOM}.py" -sed "s/target_address='[^']*'/target_address='$RINCOIN_ADDRESS'/" MINE/rin/stratum_proxy.py > "$TEMP_PROXY" - -echo "๐Ÿš€ Starting Stratum Proxy with address: $RINCOIN_ADDRESS" -echo "" - -# Start proxy in background -python3 "$TEMP_PROXY" & -PROXY_PID=$! - -# Wait for proxy to start -sleep 3 - -echo "๐Ÿ“‹ Mining Commands:" -echo "" -echo "1. For Docker container mining:" -echo "sudo docker exec -it amd-strix-halo-llama-rocm bash -c \"/mnt/dl/rinhash/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://172.17.0.1:3333 -u user -p pass -t $THREADS\"" -echo "" -echo "2. For native mining (if cpuminer is installed locally):" -echo "/home/db/Downloads/rinhash/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://127.0.0.1:3333 -u user -p pass -t $THREADS" -echo "" -echo "๐Ÿ’ก Tips:" -echo "- Use 172.17.0.1:3333 from Docker containers" -echo "- Use 127.0.0.1:3333 from host system" -echo "- All block rewards will go to: $RINCOIN_ADDRESS" -echo "" -echo "Press Ctrl+C to stop the proxy and mining" - -# Wait for user to stop -trap "echo ''; echo 'Stopping proxy...'; kill $PROXY_PID 2>/dev/null; rm -f '$TEMP_PROXY'; exit 0" INT - -wait $PROXY_PID diff --git a/MINE/rin/stratum_proxy copy.py b/MINE/rin/stratum_proxy copy.py deleted file mode 100644 index 5b43c29..0000000 --- a/MINE/rin/stratum_proxy copy.py +++ /dev/null @@ -1,550 +0,0 @@ -#!/usr/bin/env python3 -""" -RinCoin Stratum Proxy Server - PRODUCTION VERSION -Bridges cpuminer-opt-rin (Stratum protocol) to RinCoin node (RPC protocol) -For real solo mining with actual block construction and submission -""" - -import socket -import threading -import json -import time -import requests -import hashlib -import struct -import binascii -from requests.auth import HTTPBasicAuth - -class RinCoinStratumProxy: - def __init__(self, stratum_host='0.0.0.0', stratum_port=3333, - rpc_host='127.0.0.1', rpc_port=9556, - rpc_user='rinrpc', rpc_password='745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90', - target_address='rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q'): - - self.stratum_host = stratum_host - self.stratum_port = stratum_port - self.rpc_host = rpc_host - self.rpc_port = rpc_port - self.rpc_user = rpc_user - self.rpc_password = rpc_password - self.target_address = target_address - - self.clients = {} - self.job_counter = 0 - self.current_job = None - self.running = True - self.extranonce1_counter = 0 - - print(f"๐Ÿ”ฅ RinCoin PRODUCTION Stratum Proxy Server") - print(f"Stratum: {stratum_host}:{stratum_port}") - print(f"RPC: {rpc_host}:{rpc_port}") - print(f"Target: {target_address}") - - def rpc_call(self, method, params=[]): - """Make RPC call to RinCoin node""" - try: - url = f"http://{self.rpc_host}:{self.rpc_port}/" - headers = {'content-type': 'text/plain'} - auth = HTTPBasicAuth(self.rpc_user, self.rpc_password) - - payload = { - "jsonrpc": "1.0", - "id": "stratum_proxy", - "method": method, - "params": params - } - - response = requests.post(url, json=payload, headers=headers, auth=auth, timeout=10) - - if response.status_code == 200: - result = response.json() - if 'error' in result and result['error'] is not None: - print(f"RPC Error: {result['error']}") - return None - return result.get('result') - else: - print(f"HTTP Error: {response.status_code}") - return None - - except Exception as e: - print(f"RPC Call Error: {e}") - return None - - def create_coinbase_tx(self, template, extranonce1, extranonce2): - """Create coinbase transaction""" - try: - # Get coinbase value (block reward + fees) - coinbase_value = template.get('coinbasevalue', 2500000000) # 25 RIN in satoshis - - # Create coinbase transaction - # Version (4 bytes) - coinbase_tx = struct.pack(' 1: - if len(tx_hashes) % 2 == 1: - tx_hashes.append(tx_hashes[-1]) # Duplicate last hash if odd number - - new_level = [] - for i in range(0, len(tx_hashes), 2): - combined = tx_hashes[i] + tx_hashes[i + 1] - hash_result = hashlib.sha256(hashlib.sha256(combined).digest()).digest() - new_level.append(hash_result) - tx_hashes = new_level - - return tx_hashes[0] if tx_hashes else b'\x00' * 32 - - def get_block_template(self): - """Get new block template from RinCoin node""" - try: - template = self.rpc_call("getblocktemplate", [{"rules": ["segwit"]}]) - if not template: - return None - - self.job_counter += 1 - - # Calculate target from bits - bits = template.get('bits', '1d00ffff') - target = self.bits_to_target(bits) - - # Prepare transaction list (without coinbase) - transactions = template.get('transactions', []) - tx_hashes = [bytes.fromhex(tx['hash'])[::-1] for tx in transactions] # Reverse for little-endian - - job = { - "job_id": f"job_{self.job_counter:08x}", - "template": template, - "prevhash": template.get("previousblockhash", "0" * 64), - "version": template.get('version', 1), - "bits": bits, - "ntime": int(time.time()), - "target": target, - "transactions": transactions, - "tx_hashes": tx_hashes, - "height": template.get('height', 0), - "coinbasevalue": template.get('coinbasevalue', 2500000000) - } - - self.current_job = job - print(f"๐Ÿ“ฆ New job: {job['job_id']} | Height: {job['height']} | Reward: {job['coinbasevalue']/100000000:.2f} RIN") - return job - - except Exception as e: - print(f"Get block template error: {e}") - return None - - def bits_to_target(self, bits_hex): - """Convert bits to target (difficulty)""" - try: - bits = int(bits_hex, 16) - exponent = bits >> 24 - mantissa = bits & 0xffffff - target = mantissa * (256 ** (exponent - 3)) - return f"{target:064x}" - except: - return "0000ffff00000000000000000000000000000000000000000000000000000000" - - def construct_block_header(self, job, extranonce1, extranonce2, ntime, nonce): - """Construct block header for submission""" - try: - # Create coinbase transaction - coinbase_tx = self.create_coinbase_tx(job['template'], extranonce1, extranonce2) - if not coinbase_tx: - return None, None - - # Calculate coinbase hash - coinbase_hash = hashlib.sha256(hashlib.sha256(coinbase_tx).digest()).digest()[::-1] # Reverse for little-endian - - # Create full transaction list (coinbase + other transactions) - all_tx_hashes = [coinbase_hash] + job['tx_hashes'] - - # Calculate merkle root - merkle_root = self.calculate_merkle_root(all_tx_hashes) - - # Construct block header (80 bytes) - header = b'' - header += struct.pack(' {self.target_address}") - return True, "Block accepted" - else: - print(f"โŒ Block rejected: {result}") - return False, f"Block rejected: {result}" - else: - # Valid share but not a block - return True, "Share accepted" - - except Exception as e: - print(f"Block submission error: {e}") - return False, f"Submission error: {e}" - - def send_stratum_response(self, client, msg_id, result, error=None): - """Send Stratum response to client""" - try: - response = { - "id": msg_id, - "result": result, - "error": error - } - - message = json.dumps(response) + "\n" - client.send(message.encode('utf-8')) - except Exception as e: - print(f"Send response error: {e}") - - def send_stratum_notification(self, client, method, params): - """Send Stratum notification to client""" - try: - notification = { - "id": None, - "method": method, - "params": params - } - - message = json.dumps(notification) + "\n" - client.send(message.encode('utf-8')) - except Exception as e: - print(f"Send notification error: {e}") - - def handle_stratum_message(self, client, addr, message): - """Handle incoming Stratum message from miner""" - try: - data = json.loads(message.strip()) - method = data.get("method") - msg_id = data.get("id") - params = data.get("params", []) - - if method == "mining.subscribe": - # Generate unique extranonce1 for this connection - self.extranonce1_counter += 1 - extranonce1 = f"ex{self.extranonce1_counter:06x}" - - # Store extranonce1 for this client - if addr not in self.clients: - self.clients[addr] = {} - self.clients[addr]['extranonce1'] = extranonce1 - - # Subscribe response - self.send_stratum_response(client, msg_id, [ - [["mining.set_difficulty", "subscription_id"], ["mining.notify", "subscription_id"]], - extranonce1, - 4 # extranonce2 size - ]) - - # Send difficulty (simplified - always 1 for now) - self.send_stratum_notification(client, "mining.set_difficulty", [1]) - - # Send initial job - if self.current_job: - self.send_job_to_client(client, self.current_job) - else: - # Get new job if none exists - if self.get_block_template(): - self.send_job_to_client(client, self.current_job) - - elif method == "mining.authorize": - # Authorization (accept any user/pass for now) - username = params[0] if params else "anonymous" - self.clients[addr]['username'] = username - self.send_stratum_response(client, msg_id, True) - print(f"[{addr}] Authorized as {username}") - - elif method == "mining.submit": - # Submit share/block - if len(params) >= 5: - username = params[0] - job_id = params[1] - extranonce2 = params[2] - ntime = params[3] - nonce = params[4] - - print(f"[{addr}] Submit: job={job_id}, nonce={nonce}") - - # Validate submission - if self.current_job and job_id == self.current_job['job_id']: - extranonce1 = self.clients[addr].get('extranonce1', 'ex000000') - - # Validate and potentially submit block - success, message = self.validate_and_submit_block( - self.current_job, extranonce1, extranonce2, ntime, nonce - ) - - if success: - self.send_stratum_response(client, msg_id, True) - if "Block accepted" in message: - # Broadcast new job after block found - threading.Thread(target=self.update_job_after_block, daemon=True).start() - else: - self.send_stratum_response(client, msg_id, False, message) - else: - self.send_stratum_response(client, msg_id, False, "Stale job") - else: - self.send_stratum_response(client, msg_id, False, "Invalid parameters") - - else: - print(f"[{addr}] Unknown method: {method}") - self.send_stratum_response(client, msg_id, None, "Unknown method") - - except json.JSONDecodeError: - print(f"[{addr}] Invalid JSON: {message}") - except Exception as e: - print(f"[{addr}] Message handling error: {e}") - - def send_job_to_client(self, client, job): - """Send mining job to specific client""" - try: - self.send_stratum_notification(client, "mining.notify", [ - job["job_id"], - job["prevhash"], - "", # coinb1 (empty - we handle coinbase internally) - "", # coinb2 (empty - we handle coinbase internally) - [], # merkle_branch (empty - we calculate merkle root) - f"{job['version']:08x}", - job["bits"], - f"{job['ntime']:08x}", - True # clean_jobs - ]) - except Exception as e: - print(f"Failed to send job: {e}") - - def update_job_after_block(self): - """Update job after a block is found""" - time.sleep(2) # Brief delay to let network propagate - if self.get_block_template(): - self.broadcast_new_job() - - def broadcast_new_job(self): - """Broadcast new job to all connected clients""" - if not self.current_job: - return - - print(f"๐Ÿ“ก Broadcasting job {self.current_job['job_id']} to {len(self.clients)} clients") - - for addr, client_data in list(self.clients.items()): - try: - if 'socket' in client_data: - self.send_job_to_client(client_data['socket'], self.current_job) - except Exception as e: - print(f"Failed to send job to {addr}: {e}") - - def handle_client(self, client, addr): - """Handle individual client connection""" - print(f"[{addr}] Connected") - if addr not in self.clients: - self.clients[addr] = {} - self.clients[addr]['socket'] = client - - try: - while self.running: - data = client.recv(4096) - if not data: - break - - # Handle multiple messages in one packet - messages = data.decode('utf-8').strip().split('\n') - for message in messages: - if message: - self.handle_stratum_message(client, addr, message) - - except Exception as e: - print(f"[{addr}] Client error: {e}") - finally: - client.close() - if addr in self.clients: - del self.clients[addr] - print(f"[{addr}] Disconnected") - - def job_updater(self): - """Periodically update mining jobs""" - while self.running: - try: - time.sleep(30) # Update every 30 seconds - - old_height = self.current_job['height'] if self.current_job else 0 - - if self.get_block_template(): - new_height = self.current_job['height'] - if new_height > old_height: - print(f"๐Ÿ†• New block detected! Broadcasting new job...") - self.broadcast_new_job() - - except Exception as e: - print(f"Job updater error: {e}") - - def start(self): - """Start the Stratum proxy server""" - try: - # Test RPC connection - blockchain_info = self.rpc_call("getblockchaininfo") - if not blockchain_info: - print("โŒ Failed to connect to RinCoin node!") - return - - print(f"โœ… Connected to RinCoin node") - print(f"๐Ÿ“Š Current height: {blockchain_info.get('blocks', 'unknown')}") - print(f"โ›“๏ธ Chain: {blockchain_info.get('chain', 'unknown')}") - - # Get initial block template - if not self.get_block_template(): - print("โŒ Failed to get initial block template!") - return - - # Start job updater thread - job_thread = threading.Thread(target=self.job_updater, daemon=True) - job_thread.start() - - # Start Stratum server - server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - server_socket.bind((self.stratum_host, self.stratum_port)) - server_socket.listen(10) - - print(f"๐Ÿš€ PRODUCTION Stratum proxy ready!") - print(f"๐Ÿ“ก Listening on {self.stratum_host}:{self.stratum_port}") - print(f"๐Ÿ’ฐ Mining to: {self.target_address}") - print(f"โšก Current job: {self.current_job['job_id']}") - print("") - print("๐Ÿ”ง Miner command:") - print(f"./cpuminer -a rinhash -o stratum+tcp://{self.stratum_host}:{self.stratum_port} -u worker1 -p x -t 4") - print("") - - while self.running: - try: - client, addr = server_socket.accept() - client_thread = threading.Thread( - target=self.handle_client, - args=(client, addr), - daemon=True - ) - client_thread.start() - except KeyboardInterrupt: - print("\n๐Ÿ›‘ Shutting down...") - self.running = False - break - except Exception as e: - print(f"Server error: {e}") - - except Exception as e: - print(f"Failed to start server: {e}") - finally: - print("๐Ÿ’ค Server stopped") - -if __name__ == "__main__": - proxy = RinCoinStratumProxy() - proxy.start() \ No newline at end of file diff --git a/MINE/rin/stratum_proxy.py b/MINE/rin/stratum_proxy.py index 64ebb95..aff5ee6 100644 --- a/MINE/rin/stratum_proxy.py +++ b/MINE/rin/stratum_proxy.py @@ -18,7 +18,8 @@ class RinCoinStratumProxy: def __init__(self, stratum_host='0.0.0.0', stratum_port=3334, rpc_host='127.0.0.1', rpc_port=9556, rpc_user='rinrpc', rpc_password='745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90', - target_address='rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q'): + target_address='rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q', + submit_all_blocks=False): self.stratum_host = stratum_host self.stratum_port = stratum_port @@ -27,6 +28,7 @@ class RinCoinStratumProxy: self.rpc_user = rpc_user self.rpc_password = rpc_password self.target_address = target_address + self.submit_all_blocks = submit_all_blocks # If True, submit even invalid blocks for testing self.clients = {} self.job_counter = 0 @@ -406,8 +408,8 @@ class RinCoinStratumProxy: 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 + # More practical approach: start with network difficulty scaled way down for solo mining + optimal_difficulty = max(network_diff * 0.00001, 0.000001) # 0.001% of network, min 0.000001 print(f" ๐Ÿ“Š New client {addr}: Network diff {network_diff:.6f}, starting with {optimal_difficulty:.6f}") return optimal_difficulty @@ -442,9 +444,9 @@ class RinCoinStratumProxy: 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 + # Bounds checking for solo mining + min_difficulty = max(network_diff * 0.000001, 0.000001) # 0.0001% of network minimum + max_difficulty = network_diff * 0.01 # 1% 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}") @@ -582,9 +584,12 @@ class RinCoinStratumProxy: self.stats['total_shares'] += 1 self.stats['rejected_shares'] += 1 - # Check if it's also a valid network block - if meets_network_target: - print(f" ๐ŸŽ‰ BLOCK FOUND! Hash: {block_hash_hex}") + # Check if it's also a valid network block OR if we should submit all blocks for testing + if meets_network_target or self.submit_all_blocks: + if meets_network_target: + print(f" ๐ŸŽ‰ VALID BLOCK FOUND! Hash: {block_hash_hex}") + else: + print(f" ๐Ÿงช TEST BLOCK SUBMISSION! Hash: {block_hash_hex} (submit_all_blocks=True)") print(f" ๐Ÿ’ฐ Reward: {job['coinbasevalue']/100000000:.2f} RIN -> {address}") print(f" ๐Ÿ“Š Block height: {job['height']}") print(f" ๐Ÿ” Difficulty: {share_difficulty:.6f} (target: {network_difficulty:.6f})") @@ -1132,5 +1137,13 @@ class RinCoinStratumProxy: print("Server stopped") if __name__ == "__main__": - proxy = RinCoinStratumProxy() + import sys + + # Check for submit_all_blocks parameter + submit_all = False + if len(sys.argv) > 1 and sys.argv[1] == "--submit-all-blocks": + submit_all = True + print("๐Ÿงช TEST MODE: Will submit ALL blocks for validation (submit_all_blocks=True)") + + proxy = RinCoinStratumProxy(submit_all_blocks=submit_all) proxy.start() diff --git a/MINE/rin/stratum_proxy_debug.py b/MINE/rin/stratum_proxy_debug.py deleted file mode 100644 index e9e4bd6..0000000 --- a/MINE/rin/stratum_proxy_debug.py +++ /dev/null @@ -1,705 +0,0 @@ -#!/usr/bin/env python3 -""" -RinCoin Stratum Proxy Server - FIXED VERSION -Fixed block hash calculation and validation issues -""" - -import socket -import threading -import json -import time -import requests -import hashlib -import struct -from requests.auth import HTTPBasicAuth - -class RinCoinStratumProxy: - def __init__(self, stratum_host='0.0.0.0', stratum_port=3334, - rpc_host='127.0.0.1', rpc_port=9556, - rpc_user='rinrpc', rpc_password='745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90', - target_address='rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q'): - - self.stratum_host = stratum_host - self.stratum_port = stratum_port - self.rpc_host = rpc_host - self.rpc_port = rpc_port - self.rpc_user = rpc_user - self.rpc_password = rpc_password - self.target_address = target_address - - self.clients = {} - self.job_counter = 0 - self.current_job = None - self.running = True - self.extranonce1_counter = 0 - - # Logging setup - self.log_file = "mining_log.txt" - self.init_log_file() - - print(f"RinCoin Stratum Proxy Server") - print(f"Stratum: {stratum_host}:{stratum_port}") - print(f"RPC: {rpc_host}:{rpc_port}") - print(f"Target: {target_address}") - - def init_log_file(self): - """Initialize mining log file with header""" - try: - with open(self.log_file, 'w') as f: - f.write("=" * 80 + "\n") - f.write("RinCoin Mining Log\n") - f.write("=" * 80 + "\n") - f.write(f"Started: {time.strftime('%Y-%m-%d %H:%M:%S')}\n") - f.write(f"Target Address: {self.target_address}\n") - f.write(f"Stratum: {self.stratum_host}:{self.stratum_port}\n") - f.write(f"RPC: {self.rpc_host}:{self.rpc_port}\n") - f.write("=" * 80 + "\n\n") - except Exception as e: - print(f"Failed to initialize log file: {e}") - - def log_hash_found(self, hash_hex, difficulty, height, reward, nonce, ntime): - """Log found hash to file""" - try: - timestamp = time.strftime('%Y-%m-%d %H:%M:%S') - with open(self.log_file, 'a') as f: - f.write(f"[{timestamp}] ๐ŸŽ‰ HASH FOUND!\n") - f.write(f" Hash: {hash_hex}\n") - f.write(f" Difficulty: {difficulty:.6f}\n") - f.write(f" Height: {height}\n") - f.write(f" Reward: {reward:.8f} RIN\n") - f.write(f" Nonce: {nonce}\n") - f.write(f" Time: {ntime}\n") - f.write("-" * 40 + "\n") - except Exception as e: - print(f"Failed to log hash: {e}") - - def log_wallet_balance(self): - """Log current wallet balance to file""" - try: - balance = self.rpc_call("getbalance") - if balance is not None: - timestamp = time.strftime('%Y-%m-%d %H:%M:%S') - with open(self.log_file, 'a') as f: - f.write(f"[{timestamp}] ๐Ÿ’ฐ Wallet Balance: {balance:.8f} RIN\n") - except Exception as e: - print(f"Failed to log wallet balance: {e}") - - def rpc_call(self, method, params=[]): - """Make RPC call to RinCoin node""" - try: - url = f"http://{self.rpc_host}:{self.rpc_port}/" - headers = {'content-type': 'text/plain'} - auth = HTTPBasicAuth(self.rpc_user, self.rpc_password) - - payload = { - "jsonrpc": "1.0", - "id": "stratum_proxy", - "method": method, - "params": params - } - - response = requests.post(url, json=payload, headers=headers, auth=auth, timeout=30) - - if response.status_code == 200: - result = response.json() - if 'error' in result and result['error'] is not None: - print(f"RPC Error: {result['error']}") - return None - return result.get('result') - else: - print(f"HTTP Error: {response.status_code}") - return None - - except Exception as e: - print(f"RPC Call Error: {e}") - return None - - def encode_varint(self, n): - """Encode integer as Bitcoin-style varint""" - if n < 0xfd: - return bytes([n]) - elif n <= 0xffff: - return b"\xfd" + struct.pack(' bytes: - outputs_blob = b'' - outputs_list = [] - # Main output - outputs_list.append(struct.pack(' 1: - if len(hashes) % 2 == 1: - hashes.append(hashes[-1]) # Duplicate last hash if odd - - next_level = [] - for i in range(0, len(hashes), 2): - combined = hashes[i] + hashes[i + 1] - next_level.append(hashlib.sha256(hashlib.sha256(combined).digest()).digest()) - - hashes = next_level - - return hashes[0] if hashes else b'\x00' * 32 - - except Exception as e: - print(f"Merkle root calculation error: {e}") - return b'\x00' * 32 - - def bits_to_target(self, bits_hex): - """Convert bits to target - FIXED VERSION""" - try: - bits = int(bits_hex, 16) - exponent = bits >> 24 - mantissa = bits & 0xffffff - - # Bitcoin target calculation - if exponent <= 3: - target = mantissa >> (8 * (3 - exponent)) - else: - target = mantissa << (8 * (exponent - 3)) - - return f"{target:064x}" - except Exception as e: - print(f"Bits to target error: {e}") - return "0000ffff00000000000000000000000000000000000000000000000000000000" - - def get_block_template(self): - """Get new block template and create Stratum job""" - try: - template = self.rpc_call("getblocktemplate", [{"rules": ["segwit", "mweb"]}]) - if not template: - return None - - self.job_counter += 1 - - job = { - "job_id": f"job_{self.job_counter:08x}", - "template": template, - "prevhash": template.get("previousblockhash", "0" * 64), - "version": template.get('version', 1), - "bits": template.get('bits', '1d00ffff'), - "ntime": f"{int(time.time()):08x}", - "target": self.bits_to_target(template.get('bits', '1d00ffff')), - "height": template.get('height', 0), - "coinbasevalue": template.get('coinbasevalue', 0), - "transactions": template.get('transactions', []) - } - - self.current_job = job - timestamp = time.strftime("%Y-%m-%d %H:%M:%S") - network_difficulty = self.calculate_network_difficulty(job['target']) - print(f"[{timestamp}] ๐Ÿ†• NEW JOB: {job['job_id']} | Height: {job['height']} | Reward: {job['coinbasevalue']/100000000:.2f} RIN") - print(f" ๐ŸŽฏ Network Difficulty: {network_difficulty:.6f} | Bits: {job['bits']}") - print(f" ๐Ÿ“ Target: {job['target'][:16]}... | Transactions: {len(job['transactions'])}") - return job - - except Exception as e: - print(f"Get block template error: {e}") - return None - - def calculate_share_difficulty(self, hash_hex, target_hex): - """Calculate actual share difficulty from hash - FIXED""" - try: - hash_int = int(hash_hex, 16) - - if hash_int == 0: - return float('inf') # Perfect hash - - # Bitcoin-style difficulty calculation using difficulty 1 target - # Difficulty 1 target for mainnet - diff1_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 - - # Share difficulty = how much harder this hash was compared to diff 1 - difficulty = diff1_target / hash_int - - return difficulty - except Exception as e: - print(f"Difficulty calculation error: {e}") - return 0.0 - - def calculate_network_difficulty(self, target_hex): - """Calculate network difficulty from target - FIXED""" - try: - target_int = int(target_hex, 16) - - # Bitcoin difficulty 1.0 target - diff1_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 - - # Network difficulty = how much harder than difficulty 1.0 - network_difficulty = diff1_target / target_int - - return network_difficulty - except Exception as e: - print(f"Network difficulty calculation error: {e}") - return 1.0 - - def submit_share(self, job, extranonce1, extranonce2, ntime, nonce, target_address=None): - """Validate share and submit block if valid - FIXED VERSION""" - try: - # Use provided address or default - address = target_address or self.target_address - - # Build coinbase (with and without witness) - coinbase_wit, coinbase_nowit = self.build_coinbase_transaction_for_address( - job['template'], extranonce1, extranonce2, address) - if not coinbase_wit or not coinbase_nowit: - return False, "Coinbase construction failed" - - # Calculate coinbase txid (non-witness serialization) - coinbase_txid = hashlib.sha256(hashlib.sha256(coinbase_nowit).digest()).digest()[::-1] - - # Calculate merkle root - merkle_root = self.calculate_merkle_root(coinbase_txid, job['transactions']) - - # Build block header - FIXED ENDIANNESS - header = b'' - header += struct.pack(' 0 else 0 - - # Progress indicator based on percentage - if meets_target: - progress_icon = "๐ŸŽ‰" # Block found! - elif difficulty_percentage >= 50: - progress_icon = "๐Ÿ”ฅ" # Very close - elif difficulty_percentage >= 10: - progress_icon = "โšก" # Getting warm - elif difficulty_percentage >= 1: - progress_icon = "๐Ÿ’ซ" # Some progress - else: - progress_icon = "๐Ÿ“Š" # Low progress - - print(f"[{timestamp}] {progress_icon} SHARE: job={job['job_id']} | nonce={nonce} | hash={block_hash_hex[:16]}...") - print(f" ๐ŸŽฏ Share Diff: {share_difficulty:.2e} | Network Diff: {network_difficulty:.6f}") - print(f" ๐Ÿ“ˆ Progress: {difficulty_percentage:.4f}% of network difficulty") - print(f" ๐Ÿ“ Target: {job['target'][:16]}... | Height: {job['height']}") - print(f" โฐ Time: {ntime} | Extranonce: {extranonce1}:{extranonce2}") - print(f" ๐Ÿ” Hash vs Target: {hash_int} {'<=' if meets_target else '>'} {target_int}") - - if not meets_target: - # Share doesn't meet target - reject but still useful for debugging - print(f" โŒ Share rejected (hash > target)") - return False, "Share too high" - - # Valid block! Build full block and submit - print(f" ๐ŸŽ‰ BLOCK FOUND! Hash: {block_hash_hex}") - print(f" ๐Ÿ’ฐ Reward: {job['coinbasevalue']/100000000:.2f} RIN -> {address}") - print(f" ๐Ÿ“Š Block height: {job['height']}") - print(f" ๐Ÿ” Difficulty: {share_difficulty:.6f} (target: {network_difficulty:.6f})") - - # Log the found hash - reward_rin = job['coinbasevalue'] / 100000000 - self.log_hash_found(block_hash_hex, share_difficulty, job['height'], reward_rin, nonce, ntime) - - # Build complete block - block = header - - # Transaction count - tx_count = 1 + len(job['transactions']) - block += self.encode_varint(tx_count) - - # Add coinbase transaction (witness variant for block body) - block += coinbase_wit - - # Add other transactions - for tx in job['transactions']: - block += bytes.fromhex(tx['data']) - - # Submit block - block_hex = block.hex() - print(f" ๐Ÿ“ฆ Submitting block of size {len(block_hex)//2} bytes...") - - result = self.rpc_call("submitblock", [block_hex]) - - if result is None: - print(f" โœ… Block accepted by network!") - # Log wallet balance after successful block submission - self.log_wallet_balance() - return True, "Block found and submitted" - else: - print(f" โŒ Block rejected: {result}") - print(f" ๐Ÿ” Debug: Block size {len(block_hex)//2} bytes, {len(job['transactions'])} transactions") - return False, f"Block rejected: {result}" - - except Exception as e: - print(f"Share submission error: {e}") - return False, f"Submission error: {e}" - - def send_stratum_response(self, client, msg_id, result, error=None): - """Send Stratum response to client""" - try: - response = { - "id": msg_id, - "result": result, - "error": error - } - message = json.dumps(response) + "\n" - client.send(message.encode('utf-8')) - except Exception as e: - print(f"Send response error: {e}") - - def send_stratum_notification(self, client, method, params): - """Send Stratum notification to client""" - try: - notification = { - "id": None, - "method": method, - "params": params - } - message = json.dumps(notification) + "\n" - client.send(message.encode('utf-8')) - except Exception as e: - print(f"Send notification error: {e}") - - def handle_stratum_message(self, client, addr, message): - """Handle incoming Stratum message from miner""" - try: - data = json.loads(message.strip()) - method = data.get("method") - msg_id = data.get("id") - params = data.get("params", []) - - if method == "mining.subscribe": - # Generate unique extranonce1 for this connection - self.extranonce1_counter += 1 - extranonce1 = f"{self.extranonce1_counter:08x}" - - # Store extranonce1 for this client - if addr not in self.clients: - self.clients[addr] = {} - self.clients[addr]['extranonce1'] = extranonce1 - - # Subscribe response - self.send_stratum_response(client, msg_id, [ - [["mining.set_difficulty", "subscription_id"], ["mining.notify", "subscription_id"]], - extranonce1, - 4 # extranonce2 size - ]) - - # Send difficulty - MUCH LOWER for testing - self.send_stratum_notification(client, "mining.set_difficulty", [0.00001]) - - # Send initial job - if self.current_job: - self.send_job_to_client(client, self.current_job) - else: - if self.get_block_template(): - self.send_job_to_client(client, self.current_job) - - elif method == "mining.authorize": - username = params[0] if params else "anonymous" - self.clients[addr]['username'] = username - self.send_stratum_response(client, msg_id, True) - timestamp = time.strftime("%Y-%m-%d %H:%M:%S") - print(f"[{timestamp}] ๐Ÿ” [{addr}] Authorized as {username}") - - elif method == "mining.extranonce.subscribe": - self.send_stratum_response(client, msg_id, True) - - elif method == "mining.submit": - if len(params) >= 5: - username = params[0] - job_id = params[1] - extranonce2 = params[2] - ntime = params[3] - nonce = params[4] - - print(f"[{addr}] Submit: {username} | job={job_id} | nonce={nonce}") - - # Always validate against current job - if self.current_job: - extranonce1 = self.clients[addr].get('extranonce1', '00000000') - - # Submit share - success, message = self.submit_share(self.current_job, extranonce1, extranonce2, ntime, nonce) - - # Always accept shares for debugging, even if they don't meet target - self.send_stratum_response(client, msg_id, True) - - if success and "Block found" in message: - # Get new job after block found - threading.Thread(target=self.update_job_after_block, daemon=True).start() - else: - self.send_stratum_response(client, msg_id, True) - else: - self.send_stratum_response(client, msg_id, False, "Invalid parameters") - - else: - print(f"[{addr}] Unknown method: {method}") - self.send_stratum_response(client, msg_id, None, "Unknown method") - - except json.JSONDecodeError: - print(f"[{addr}] Invalid JSON: {message}") - except Exception as e: - print(f"[{addr}] Message handling error: {e}") - - def send_job_to_client(self, client, job): - """Send mining job to specific client""" - try: - self.send_stratum_notification(client, "mining.notify", [ - job["job_id"], - job["prevhash"], - "", # coinb1 (empty for now - miner handles coinbase) - "", # coinb2 (empty for now - miner handles coinbase) - [], # merkle_branch (empty for now - we calculate merkle root) - f"{job['version']:08x}", - job["bits"], - job["ntime"], - True # clean_jobs - ]) - except Exception as e: - print(f"Failed to send job: {e}") - - def update_job_after_block(self): - """Update job after a block is found""" - time.sleep(2) # Brief delay to let network propagate - if self.get_block_template(): - self.broadcast_new_job() - - def broadcast_new_job(self): - """Broadcast new job to all connected clients""" - if not self.current_job: - return - - print(f"Broadcasting new job to {len(self.clients)} clients") - - for addr, client_data in list(self.clients.items()): - try: - if 'socket' in client_data: - self.send_job_to_client(client_data['socket'], self.current_job) - except Exception as e: - print(f"Failed to send job to {addr}: {e}") - - def handle_client(self, client, addr): - """Handle individual client connection""" - print(f"[{addr}] Connected") - if addr not in self.clients: - self.clients[addr] = {} - self.clients[addr]['socket'] = client - - try: - while self.running: - data = client.recv(4096) - if not data: - break - - # Handle multiple messages in one packet - messages = data.decode('utf-8').strip().split('\n') - for message in messages: - if message: - self.handle_stratum_message(client, addr, message) - - except Exception as e: - print(f"[{addr}] Client error: {e}") - finally: - client.close() - if addr in self.clients: - del self.clients[addr] - print(f"[{addr}] Disconnected") - - def job_updater(self): - """Periodically update mining jobs""" - balance_log_counter = 0 - while self.running: - try: - time.sleep(30) # Update every 30 seconds - - old_height = self.current_job['height'] if self.current_job else 0 - - if self.get_block_template(): - new_height = self.current_job['height'] - if new_height > old_height: - print(f"New block detected! Broadcasting new job...") - self.broadcast_new_job() - - # Log wallet balance every 10 minutes (20 cycles of 30 seconds) - balance_log_counter += 1 - if balance_log_counter >= 20: - self.log_wallet_balance() - balance_log_counter = 0 - - except Exception as e: - print(f"Job updater error: {e}") - - def start(self): - """Start the Stratum proxy server""" - try: - # Test RPC connection - blockchain_info = self.rpc_call("getblockchaininfo") - if not blockchain_info: - print("Failed to connect to RinCoin node!") - return - - print(f"Connected to RinCoin node") - print(f"Current height: {blockchain_info.get('blocks', 'unknown')}") - print(f"Chain: {blockchain_info.get('chain', 'unknown')}") - - # Log initial wallet balance - self.log_wallet_balance() - - # Get initial block template - if not self.get_block_template(): - print("Failed to get initial block template!") - return - - # Start job updater thread - job_thread = threading.Thread(target=self.job_updater, daemon=True) - job_thread.start() - - # Start Stratum server - server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - server_socket.bind((self.stratum_host, self.stratum_port)) - server_socket.listen(10) - - timestamp = time.strftime("%Y-%m-%d %H:%M:%S") - print(f"[{timestamp}] ๐Ÿš€ Mining Stratum proxy ready!") - print(f" ๐Ÿ“ก Listening on {self.stratum_host}:{self.stratum_port}") - print(f" ๐Ÿ’ฐ Mining to: {self.target_address}") - print(f" ๐Ÿ“Š Current job: {self.current_job['job_id'] if self.current_job else 'None'}") - print(f" ๐Ÿ“ Mining log: {self.log_file}") - print("") - print(" ๐Ÿ”ง Miner command:") - print(f" ./cpuminer -a rinhash -o stratum+tcp://{self.stratum_host}:{self.stratum_port} -u worker1 -p x -t 4") - print("") - - while self.running: - try: - client, addr = server_socket.accept() - client_thread = threading.Thread( - target=self.handle_client, - args=(client, addr), - daemon=True - ) - client_thread.start() - except KeyboardInterrupt: - print("\nShutting down...") - self.running = False - break - except Exception as e: - print(f"Server error: {e}") - - except Exception as e: - print(f"Failed to start server: {e}") - finally: - print("Server stopped") - -if __name__ == "__main__": - proxy = RinCoinStratumProxy() - proxy.start() diff --git a/MINE/rin/stratum_proxy_explanation.sh b/MINE/rin/stratum_proxy_explanation.sh deleted file mode 100644 index 3f9ec4c..0000000 --- a/MINE/rin/stratum_proxy_explanation.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash - -# RinCoin Stratum Proxy for cpuminer-opt-rin -# Bridges cpuminer's Stratum protocol to RinCoin's RPC mining - -echo "=== RinCoin Stratum Proxy ===" -echo "This script creates a bridge between cpuminer and RinCoin node" -echo "" - -# Configuration -RPC_HOST="127.0.0.1" -RPC_PORT="9556" -RPC_USER="rinrpc" -RPC_PASS="745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90" -STRATUM_PORT="3333" -TARGET_ADDRESS="rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q" - -# Function to call RPC -call_rpc() { - local method="$1" - local params="$2" - - curl -s --user "$RPC_USER:$RPC_PASS" \ - -H 'content-type: text/plain' \ - --data "{\"jsonrpc\":\"1.0\",\"id\":\"curl\",\"method\":\"$method\",\"params\":$params}" \ - "http://$RPC_HOST:$RPC_PORT/" -} - -echo "โš ๏ธ IMPORTANT: This is a simplified proxy demonstration." -echo "For production use, you would need a full Stratum server implementation." -echo "" - -echo "Current RinCoin mining options:" -echo "1. Built-in Core Mining (Recommended for solo):" -echo " bash MINE/rin/solo_mining_core.sh -t 28" -echo "" -echo "2. Pool Mining (Recommended for consistent rewards):" -echo " sudo docker exec -it amd-strix-halo-llama-rocm bash -c \"/mnt/dl/rinhash/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://rinhash.mine.zergpool.com:7148 -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC,mc=RIN,ID=StrixHalo -t 28\"" -echo "" -echo "3. Direct RPC Mining (Advanced - requires custom miner):" -echo " Use getblocktemplate RPC calls directly" -echo "" - -echo "โŒ cpuminer-opt-rin cannot directly mine to RinCoin node because:" -echo " - cpuminer uses Stratum protocol" -echo " - RinCoin node uses RPC protocol" -echo " - No built-in protocol conversion" -echo "" - -echo "โœ… Recommended approach:" -echo " Use the built-in core mining script for solo mining" -echo " Use pool mining for consistent rewards" diff --git a/MINE/rin/test_address_validation.sh b/MINE/rin/test_address_validation.sh deleted file mode 100644 index 34ebd9c..0000000 --- a/MINE/rin/test_address_validation.sh +++ /dev/null @@ -1,78 +0,0 @@ -#!/bin/bash - -# Test RinCoin Address Validation and Behavior - -echo "=== RinCoin Address Validation Test ===" -echo "" - -# Kill any existing processes -./MINE/rin/kill_stratum_proxy.sh - -echo "๐Ÿงช Testing different address types with RinCoin node:" -echo "" - -echo "1๏ธโƒฃ Valid RinCoin address:" -curl -s -u rinrpc:745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90 \ - -H 'content-type: text/plain' \ - --data '{"jsonrpc":"1.0","id":"curl","method":"validateaddress","params":["rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q"]}' \ - http://127.0.0.1:9556/ | jq '.result' - -echo "" -echo "2๏ธโƒฃ Invalid BTC address:" -curl -s -u rinrpc:745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90 \ - -H 'content-type: text/plain' \ - --data '{"jsonrpc":"1.0","id":"curl","method":"validateaddress","params":["bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j"]}' \ - http://127.0.0.1:9556/ | jq '.result' - -echo "" -echo "3๏ธโƒฃ Invalid Litecoin address:" -curl -s -u rinrpc:745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90 \ - -H 'content-type: text/plain' \ - --data '{"jsonrpc":"1.0","id":"curl","method":"validateaddress","params":["LQnYyekHhQ7nMUTGJ1ZnYz8s9QJ2mKLM9P"]}' \ - http://127.0.0.1:9556/ | jq '.result' - -echo "" -echo "4๏ธโƒฃ Test generatetoaddress with invalid address:" -curl -s -u rinrpc:745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90 \ - -H 'content-type: text/plain' \ - --data '{"jsonrpc":"1.0","id":"curl","method":"generatetoaddress","params":[1, "bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j", 1]}' \ - http://127.0.0.1:9556/ | jq '.error' - -echo "" -echo "๐Ÿš€ Starting mining pool to test address validation..." -./MINE/rin/start_mining_pool.sh & -POOL_PID=$! - -echo "" -echo "โณ Waiting for pool to start..." -sleep 5 - -echo "" -echo "๐Ÿงช Testing pool with different address types:" -echo "" - -echo "Test 1: Valid RinCoin address" -echo "Expected: โœ… Accept connection" -timeout 5s ./cpuminer -a rinhash -o stratum+tcp://127.0.0.1:3333 -u rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q -p x -t 1 - -echo "" -echo "Test 2: Invalid BTC address" -echo "Expected: โŒ Reject connection" -timeout 5s ./cpuminer -a rinhash -o stratum+tcp://127.0.0.1:3333 -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p x -t 1 - -echo "" -echo "Test 3: Traditional username (no address)" -echo "Expected: โš ๏ธ Accept but warn no address" -timeout 5s ./cpuminer -a rinhash -o stratum+tcp://127.0.0.1:3333 -u user.worker -p x -t 1 - -echo "" -echo "๐Ÿงน Cleaning up..." -kill $POOL_PID 2>/dev/null -./MINE/rin/kill_stratum_proxy.sh - -echo "" -echo "๐Ÿ“‹ Summary:" -echo "โœ… Valid RinCoin addresses (rin1q...) - Accepted" -echo "โŒ Invalid addresses (bc1q..., LQnY...) - Rejected" -echo "โš ๏ธ Traditional usernames - Accepted but no rewards" -echo "๐Ÿ’ฐ Block rewards always go to pool address, then distributed" diff --git a/MINE/rin/test_pool_connections.sh b/MINE/rin/test_pool_connections.sh deleted file mode 100644 index 8d22208..0000000 --- a/MINE/rin/test_pool_connections.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash - -# Test different mining pool connection methods - -echo "=== Testing Mining Pool Connection Methods ===" -echo "" - -# Kill any existing processes -./MINE/rin/kill_stratum_proxy.sh - -echo "๐Ÿš€ Starting mining pool..." -./MINE/rin/start_mining_pool.sh & -POOL_PID=$! - -echo "" -echo "โณ Waiting for pool to start..." -sleep 5 - -echo "" -echo "๐Ÿงช Testing different connection methods:" -echo "" - -echo "1๏ธโƒฃ Test 1: Address as username" -echo "Command: ./cpuminer -a rinhash -o stratum+tcp://127.0.0.1:3333 -u rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q -p x -t 2" -echo "Expected: Pool should recognize this as a RinCoin address" -echo "" - -echo "2๏ธโƒฃ Test 2: Address.workername format" -echo "Command: ./cpuminer -a rinhash -o stratum+tcp://127.0.0.1:3333 -u rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q.worker1 -p x -t 2" -echo "Expected: Pool should recognize address and worker separately" -echo "" - -echo "3๏ธโƒฃ Test 3: Traditional username" -echo "Command: ./cpuminer -a rinhash -o stratum+tcp://127.0.0.1:3333 -u user.worker -p x -t 2" -echo "Expected: Pool should use default pool address for rewards" -echo "" - -echo "๐Ÿ“Š Pool Status:" -echo "Web Dashboard: http://127.0.0.1:8080" -echo "Pool Address: rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q" -echo "" - -echo "Press Enter to run test 1..." -read - -echo "Running Test 1..." -timeout 10s ./cpuminer -a rinhash -o stratum+tcp://127.0.0.1:3333 -u rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q -p x -t 2 - -echo "" -echo "Press Enter to run test 2..." -read - -echo "Running Test 2..." -timeout 10s ./cpuminer -a rinhash -o stratum+tcp://127.0.0.1:3333 -u rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q.worker1 -p x -t 2 - -echo "" -echo "Press Enter to run test 3..." -read - -echo "Running Test 3..." -timeout 10s ./cpuminer -a rinhash -o stratum+tcp://127.0.0.1:3333 -u user.worker -p x -t 2 - -echo "" -echo "๐Ÿงน Cleaning up..." -kill $POOL_PID 2>/dev/null -./MINE/rin/kill_stratum_proxy.sh - -echo "" -echo "โœ… Test complete! Check the pool logs above to see how each connection was handled." diff --git a/MINE/rin/view_mining_log.sh b/MINE/rin/view_mining_log.sh deleted file mode 100644 index de4ec60..0000000 --- a/MINE/rin/view_mining_log.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash - -# View RinCoin Mining Log -# Shows the latest mining activity and wallet balance - -LOG_FILE="mining_log.txt" - -if [ ! -f "$LOG_FILE" ]; then - echo "โŒ Mining log file '$LOG_FILE' not found!" - echo "Make sure the stratum proxy has been started at least once." - exit 1 -fi - -echo "=== RinCoin Mining Log Viewer ===" -echo "" - -# Show last 20 lines of the log -echo "๐Ÿ“Š Recent Activity (last 20 entries):" -echo "----------------------------------------" -tail -20 "$LOG_FILE" - -echo "" -echo "๐Ÿ’ฐ Current Wallet Balance:" -echo "----------------------------------------" -grep "Wallet Balance:" "$LOG_FILE" | tail -1 || echo "No balance logged yet" - -echo "" -echo "๐ŸŽ‰ Total Blocks Found:" -echo "----------------------------------------" -grep -c "HASH FOUND!" "$LOG_FILE" || echo "0" - -echo "" -echo "๐Ÿ“ˆ Total Mining Time:" -echo "----------------------------------------" -if grep -q "Started:" "$LOG_FILE"; then - START_TIME=$(grep "Started:" "$LOG_FILE" | head -1 | cut -d' ' -f2-3) - echo "Started: $START_TIME" - echo "Current: $(date '+%Y-%m-%d %H:%M:%S')" -else - echo "Start time not available" -fi - -echo "" -echo "๐Ÿ“ Full log available at: $LOG_FILE" -echo "๐Ÿ”„ To watch live updates: tail -f $LOG_FILE" From b5c03755696d7c2e6ff6d0e6c19ce8b7e2cb040e Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 23 Sep 2025 13:33:10 +0300 Subject: [PATCH 17/30] stratuu - try fix block subm - proper difficulty --- MINE/rin/stratum_proxy.py | 79 ++++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 27 deletions(-) diff --git a/MINE/rin/stratum_proxy.py b/MINE/rin/stratum_proxy.py index aff5ee6..8635169 100644 --- a/MINE/rin/stratum_proxy.py +++ b/MINE/rin/stratum_proxy.py @@ -408,8 +408,19 @@ class RinCoinStratumProxy: diff1_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 optimal_difficulty = (estimated_hashrate * diff1_target) / (target_shares_per_second * (2**256)) - # More practical approach: start with network difficulty scaled way down for solo mining - optimal_difficulty = max(network_diff * 0.00001, 0.000001) # 0.001% of network, min 0.000001 + # Calculate proper difficulty based on expected hashrate for solo mining + # Target: 1 share every 2 minutes (120 seconds) + # Conservative estimate: 500 kH/s for CPU mining + estimated_hashrate = 500000 # 500 kH/s + target_shares_per_second = 1.0 / self.target_share_interval + + # Calculate difficulty to achieve target share rate + # Formula: difficulty = hashrate / (target_shares_per_second * 2^32 / max_target) + max_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 + optimal_difficulty = (estimated_hashrate * target_shares_per_second) / (max_target / (2**32)) + + # Ensure it's not too low or too high + optimal_difficulty = max(0.000001, min(optimal_difficulty, network_diff * 0.01)) print(f" ๐Ÿ“Š New client {addr}: Network diff {network_diff:.6f}, starting with {optimal_difficulty:.6f}") return optimal_difficulty @@ -445,8 +456,8 @@ class RinCoinStratumProxy: new_difficulty = current_difficulty / max_change # Bounds checking for solo mining - min_difficulty = max(network_diff * 0.000001, 0.000001) # 0.0001% of network minimum - max_difficulty = network_diff * 0.01 # 1% of network maximum + min_difficulty = 0.0000001 # Very low minimum + max_difficulty = 0.001 # Maximum 0.1% of typical network diff 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}") @@ -561,31 +572,41 @@ class RinCoinStratumProxy: print(f" ๐Ÿ” Hash vs Network: {hash_int} {'<=' if meets_network_target else '>'} {network_target_int}") print(f" ๐Ÿ” Hash vs Stratum: {hash_int} {'<=' if meets_stratum_target else '>'} {stratum_target_int}") - if not meets_stratum_target: - # Share doesn't meet stratum target - reject - print(f" โŒ Share rejected (hash > stratum target)") - self.stats['total_shares'] += 1 - self.stats['rejected_shares'] += 1 - return False, "Share too high" - - # 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() - - # Update global stats + # Handle submit_all_blocks mode - bypass all difficulty checks + if self.submit_all_blocks: + print(f" ๐Ÿงช TEST MODE: Submitting ALL shares to node for validation") + # Update stats for test mode self.stats['total_shares'] += 1 self.stats['accepted_shares'] += 1 - # Check if we should adjust difficulty - self.adjust_client_difficulty(addr) + # Always submit in test mode + should_submit = True else: - # Track rejected shares - self.stats['total_shares'] += 1 - self.stats['rejected_shares'] += 1 + # Normal mode - check stratum difficulty + if not meets_stratum_target: + # Share doesn't meet stratum target - reject + print(f" โŒ Share rejected (hash > stratum target)") + self.stats['total_shares'] += 1 + self.stats['rejected_shares'] += 1 + return False, "Share too high" - # Check if it's also a valid network block OR if we should submit all blocks for testing - if meets_network_target or self.submit_all_blocks: + # 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() + + # Update global stats + self.stats['total_shares'] += 1 + self.stats['accepted_shares'] += 1 + + # Check if we should adjust difficulty + self.adjust_client_difficulty(addr) + + # Only submit if it meets network target in normal mode + should_submit = meets_network_target + + # Submit block if conditions are met + if should_submit: if meets_network_target: print(f" ๐ŸŽ‰ VALID BLOCK FOUND! Hash: {block_hash_hex}") else: @@ -630,9 +651,13 @@ class RinCoinStratumProxy: print(f" ๐Ÿ” Debug: Block size {len(block_hex)//2} bytes, {len(job['transactions'])} transactions") return False, f"Block rejected: {result}" else: - # Valid stratum share but not network-valid block - print(f" โœ… Valid stratum share accepted") - return True, "Valid stratum share" + # Valid stratum share but not network-valid block (normal mode only) + if not self.submit_all_blocks: + print(f" โœ… Valid stratum share accepted") + return True, "Valid stratum share" + else: + # This shouldn't happen in test mode since should_submit would be True + return True, "Test mode share processed" except Exception as e: print(f"Share submission error: {e}") From ba93f8807b2bd7509e9cfd0a521b518af115bc09 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 23 Sep 2025 13:46:15 +0300 Subject: [PATCH 18/30] ajdust diff --- MINE/rin/mining_log.txt | 4 ++-- MINE/rin/stratum_proxy.py | 38 +++++++++++++++++++++----------------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/MINE/rin/mining_log.txt b/MINE/rin/mining_log.txt index 68e4b6d..bf927ec 100644 --- a/MINE/rin/mining_log.txt +++ b/MINE/rin/mining_log.txt @@ -1,10 +1,10 @@ ================================================================================ RinCoin Mining Log ================================================================================ -Started: 2025-09-23 13:26:20 +Started: 2025-09-23 13:41:11 Target Address: rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q Stratum: 0.0.0.0:3334 RPC: 127.0.0.1:9556 ================================================================================ -[2025-09-23 13:26:20] ๐Ÿ’ฐ Wallet Balance: 25.00000000 RIN +[2025-09-23 13:41:11] ๐Ÿ’ฐ Wallet Balance: 25.00000000 RIN diff --git a/MINE/rin/stratum_proxy.py b/MINE/rin/stratum_proxy.py index 8635169..28d2fad 100644 --- a/MINE/rin/stratum_proxy.py +++ b/MINE/rin/stratum_proxy.py @@ -420,7 +420,7 @@ class RinCoinStratumProxy: optimal_difficulty = (estimated_hashrate * target_shares_per_second) / (max_target / (2**32)) # Ensure it's not too low or too high - optimal_difficulty = max(0.000001, min(optimal_difficulty, network_diff * 0.01)) + optimal_difficulty = max(0.0000001, min(optimal_difficulty, network_diff * 0.01)) print(f" ๐Ÿ“Š New client {addr}: Network diff {network_diff:.6f}, starting with {optimal_difficulty:.6f}") return optimal_difficulty @@ -455,9 +455,9 @@ class RinCoinStratumProxy: elif difficulty_multiplier < (1.0 / max_change): new_difficulty = current_difficulty / max_change - # Bounds checking for solo mining - min_difficulty = 0.0000001 # Very low minimum - max_difficulty = 0.001 # Maximum 0.1% of typical network diff + # Bounds checking for solo mining + min_difficulty = 0.00000001 # Extremely low minimum for CPU mining + max_difficulty = 0.0001 # Maximum 0.01% of typical network diff 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}") @@ -544,16 +544,20 @@ class RinCoinStratumProxy: meets_stratum_target = hash_int <= stratum_target_int meets_network_target = hash_int <= network_target_int + + # CRITICAL FIX: Check if share difficulty meets minimum requirements + meets_stratum_difficulty = share_difficulty >= client_stratum_diff + meets_network_difficulty = share_difficulty >= network_difficulty # Enhanced logging timestamp = time.strftime("%Y-%m-%d %H:%M:%S") network_percentage = (share_difficulty / network_difficulty) * 100 if network_difficulty > 0 else 0 stratum_percentage = (share_difficulty / client_stratum_diff) * 100 if client_stratum_diff > 0 else 0 - # Progress indicator based on network percentage - if meets_network_target: + # Progress indicator based on difficulty comparison + if meets_network_difficulty: progress_icon = "๐ŸŽ‰" # Block found! - elif meets_stratum_target: + elif meets_stratum_difficulty: progress_icon = "โœ…" # Valid share for stratum elif network_percentage >= 50: progress_icon = "๐Ÿ”ฅ" # Very close to network @@ -569,8 +573,8 @@ class RinCoinStratumProxy: print(f" ๐Ÿ“ˆ Progress: {network_percentage:.4f}% of network, {stratum_percentage:.1f}% of stratum") print(f" ๐Ÿ“ Target: {job['target'][:16]}... | Height: {job['height']}") print(f" โฐ Time: {ntime} | Extranonce: {extranonce1}:{extranonce2}") - print(f" ๐Ÿ” Hash vs Network: {hash_int} {'<=' if meets_network_target else '>'} {network_target_int}") - print(f" ๐Ÿ” Hash vs Stratum: {hash_int} {'<=' if meets_stratum_target else '>'} {stratum_target_int}") + print(f" ๐Ÿ” Difficulty Check: Share {share_difficulty:.2e} vs Stratum {client_stratum_diff:.6f} = {'โœ…' if meets_stratum_difficulty else 'โŒ'}") + print(f" ๐Ÿ” Difficulty Check: Share {share_difficulty:.2e} vs Network {network_difficulty:.6f} = {'โœ…' if meets_network_difficulty else 'โŒ'}") # Handle submit_all_blocks mode - bypass all difficulty checks if self.submit_all_blocks: @@ -582,13 +586,13 @@ class RinCoinStratumProxy: # Always submit in test mode should_submit = True else: - # Normal mode - check stratum difficulty - if not meets_stratum_target: - # Share doesn't meet stratum target - reject - print(f" โŒ Share rejected (hash > stratum target)") + # Normal mode - check stratum difficulty properly + if not meets_stratum_difficulty: + # Share doesn't meet minimum stratum difficulty - reject + print(f" โŒ Share rejected (difficulty too low: {share_difficulty:.2e} < {client_stratum_diff:.6f})") self.stats['total_shares'] += 1 self.stats['rejected_shares'] += 1 - return False, "Share too high" + return False, "Share does not meet stratum difficulty" # Valid stratum share! Update client stats if addr and addr in self.clients: @@ -602,12 +606,12 @@ class RinCoinStratumProxy: # Check if we should adjust difficulty self.adjust_client_difficulty(addr) - # Only submit if it meets network target in normal mode - should_submit = meets_network_target + # Only submit if it meets network difficulty in normal mode + should_submit = meets_network_difficulty # Submit block if conditions are met if should_submit: - if meets_network_target: + if meets_network_difficulty: print(f" ๐ŸŽ‰ VALID BLOCK FOUND! Hash: {block_hash_hex}") else: print(f" ๐Ÿงช TEST BLOCK SUBMISSION! Hash: {block_hash_hex} (submit_all_blocks=True)") From 5f9db3836fbc145da9c32277b4279b8fe768a59c Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 23 Sep 2025 18:09:55 +0300 Subject: [PATCH 19/30] finaly working difficulty! --- .gitignore | 1 + MINE/rin/README.md | 1 + MINE/rin/mining_log.txt | 4 +- MINE/rin/stratum_proxy.py | 153 +++++++++++++++++++++++++------------- 4 files changed, 107 insertions(+), 52 deletions(-) diff --git a/.gitignore b/.gitignore index d52b6ab..8300d53 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ AI/MCP/* .fuse_hidde* *.pyc +MINE/rin/mining_log.txt diff --git a/MINE/rin/README.md b/MINE/rin/README.md index d8f6f1d..6869eef 100644 --- a/MINE/rin/README.md +++ b/MINE/rin/README.md @@ -152,6 +152,7 @@ Your Stratum proxy can be enhanced to work as a **full mining pool** that distri # 2. Miners connect with: ./cpuminer -a rinhash -o stratum+tcp://YOUR_IP:3333 -u username.workername -p x +# submit every share cd /mnt/shared/DEV/repos/d-popov.com/scripts/MINE/rin && python3 stratum_proxy.py --submit-all-blocks ``` diff --git a/MINE/rin/mining_log.txt b/MINE/rin/mining_log.txt index bf927ec..4729580 100644 --- a/MINE/rin/mining_log.txt +++ b/MINE/rin/mining_log.txt @@ -1,10 +1,10 @@ ================================================================================ RinCoin Mining Log ================================================================================ -Started: 2025-09-23 13:41:11 +Started: 2025-09-23 18:00:59 Target Address: rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q Stratum: 0.0.0.0:3334 RPC: 127.0.0.1:9556 ================================================================================ -[2025-09-23 13:41:11] ๐Ÿ’ฐ Wallet Balance: 25.00000000 RIN +[2025-09-23 18:00:59] ๐Ÿ’ฐ Wallet Balance: 25.00000000 RIN diff --git a/MINE/rin/stratum_proxy.py b/MINE/rin/stratum_proxy.py index 28d2fad..fe37e3d 100644 --- a/MINE/rin/stratum_proxy.py +++ b/MINE/rin/stratum_proxy.py @@ -49,7 +49,10 @@ class RinCoinStratumProxy: 'rejected_shares': 0, 'blocks_found': 0, 'total_hashrate': 0, - 'connections': 0 + 'connections': 0, + 'last_share_time': time.time(), + 'shares_last_minute': [], + 'current_share_rate': 0.0 } self.max_connections = 50 # Production limit @@ -397,35 +400,18 @@ class RinCoinStratumProxy: 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 + # Start new clients at 0.5% of network difficulty + initial_difficulty = network_diff * 0.005 # 0.5% of network difficulty - # Bitcoin-style difficulty calculation - diff1_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 - optimal_difficulty = (estimated_hashrate * diff1_target) / (target_shares_per_second * (2**256)) + # Ensure reasonable bounds + min_difficulty = 0.000001 # Absolute minimum + max_difficulty = network_diff * 0.05 # Maximum 5% of network + initial_difficulty = max(min_difficulty, min(max_difficulty, initial_difficulty)) - # Calculate proper difficulty based on expected hashrate for solo mining - # Target: 1 share every 2 minutes (120 seconds) - # Conservative estimate: 500 kH/s for CPU mining - estimated_hashrate = 500000 # 500 kH/s - target_shares_per_second = 1.0 / self.target_share_interval - - # Calculate difficulty to achieve target share rate - # Formula: difficulty = hashrate / (target_shares_per_second * 2^32 / max_target) - max_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 - optimal_difficulty = (estimated_hashrate * target_shares_per_second) / (max_target / (2**32)) - - # Ensure it's not too low or too high - optimal_difficulty = max(0.0000001, min(optimal_difficulty, network_diff * 0.01)) - - print(f" ๐Ÿ“Š New client {addr}: Network diff {network_diff:.6f}, starting with {optimal_difficulty:.6f}") - return optimal_difficulty + print(f" ๐Ÿ“Š NEW CLIENT {addr}: Network diff {network_diff:.6f}, starting with {initial_difficulty:.6f} (0.5% of network)") + return initial_difficulty - # For existing clients, adjust based on actual performance + # For existing clients, adjust based on actual hashrate performance client_data = self.clients.get(addr, {}) if not client_data: return self.calculate_optimal_difficulty(addr, is_new_client=True) @@ -433,34 +419,30 @@ class RinCoinStratumProxy: 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) + current_difficulty = client_data.get('stratum_difficulty', network_diff * 0.005) + estimated_hashrate = client_data.get('estimated_hashrate', 0) - # Calculate actual share rate - mining_duration = current_time - connect_time - if mining_duration < 60: # Need at least 1 minute of data + # Need at least 3 shares to make adjustments + if share_count < 3: 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 + # Calculate target difficulty based on hashrate and desired share interval + # Target: 1 share every 60 seconds (self.target_share_interval) + if estimated_hashrate > 0: + # Formula: difficulty = (hashrate * target_time) / (2^32) + diff1_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 + target_difficulty = (estimated_hashrate * self.target_share_interval) / (2**32) - # 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.0001 # 0.01% of network + max_difficulty = network_diff * 0.02 # 2% of network + target_difficulty = max(min_difficulty, min(max_difficulty, target_difficulty)) - # Bounds checking for solo mining - min_difficulty = 0.00000001 # Extremely low minimum for CPU mining - max_difficulty = 0.0001 # Maximum 0.01% of typical network diff - new_difficulty = max(min_difficulty, min(max_difficulty, new_difficulty)) + # Conservative adjustment - move only 50% towards target each time + adjustment_factor = 0.5 + new_difficulty = current_difficulty + (target_difficulty - current_difficulty) * adjustment_factor - print(f" ๐Ÿ“Š {addr}: {share_count} shares in {mining_duration:.0f}s ({actual_share_rate:.4f}/s), adjusting {current_difficulty:.6f} โ†’ {new_difficulty:.6f}") + print(f" ๐Ÿ“Š {addr}: {estimated_hashrate:.0f} H/s, {share_count} shares, adjusting {current_difficulty:.6f} โ†’ {new_difficulty:.6f}") return new_difficulty return current_difficulty @@ -470,6 +452,38 @@ class RinCoinStratumProxy: # 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_global_difficulty_if_needed(self): + """Adjust difficulty globally if share rate is too high/low""" + try: + current_rate = self.stats['current_share_rate'] + + # Target: 0.5-2 shares per second (30-120 second intervals) + target_min_rate = 0.008 # ~1 share per 2 minutes + target_max_rate = 0.033 # ~1 share per 30 seconds + + if current_rate > target_max_rate: + # Too many shares - increase difficulty for all clients + multiplier = min(2.0, current_rate / target_max_rate) + print(f" ๐Ÿšจ HIGH SHARE RATE: {current_rate:.3f}/s > {target_max_rate:.3f}/s - increasing difficulty by {multiplier:.2f}x") + for addr in self.clients: + current_diff = self.clients[addr].get('stratum_difficulty', 0.001) + new_diff = min(0.001, current_diff * multiplier) + self.clients[addr]['stratum_difficulty'] = new_diff + print(f" ๐Ÿ“ˆ {addr}: {current_diff:.6f} โ†’ {new_diff:.6f}") + + elif current_rate < target_min_rate and current_rate > 0: + # Too few shares - decrease difficulty for all clients + multiplier = max(0.5, target_min_rate / current_rate) + print(f" ๐ŸŒ LOW SHARE RATE: {current_rate:.3f}/s < {target_min_rate:.3f}/s - decreasing difficulty by {multiplier:.2f}x") + for addr in self.clients: + current_diff = self.clients[addr].get('stratum_difficulty', 0.001) + new_diff = max(0.000001, current_diff / multiplier) + self.clients[addr]['stratum_difficulty'] = new_diff + print(f" ๐Ÿ“‰ {addr}: {current_diff:.6f} โ†’ {new_diff:.6f}") + + except Exception as e: + print(f"Global difficulty adjustment error: {e}") def adjust_client_difficulty(self, addr): """Adjust difficulty for a specific client if needed""" @@ -549,6 +563,13 @@ class RinCoinStratumProxy: meets_stratum_difficulty = share_difficulty >= client_stratum_diff meets_network_difficulty = share_difficulty >= network_difficulty + # Track share rate + current_time = time.time() + self.stats['shares_last_minute'].append(current_time) + # Remove shares older than 60 seconds + self.stats['shares_last_minute'] = [t for t in self.stats['shares_last_minute'] if current_time - t <= 60] + self.stats['current_share_rate'] = len(self.stats['shares_last_minute']) / 60.0 + # Enhanced logging timestamp = time.strftime("%Y-%m-%d %H:%M:%S") network_percentage = (share_difficulty / network_difficulty) * 100 if network_difficulty > 0 else 0 @@ -571,6 +592,7 @@ class RinCoinStratumProxy: print(f"[{timestamp}] {progress_icon} SHARE: job={job['job_id']} | nonce={nonce} | hash={block_hash_hex[:16]}...") print(f" ๐ŸŽฏ Share Diff: {share_difficulty:.2e} | Stratum Diff: {client_stratum_diff:.6f} | Network Diff: {network_difficulty:.6f}") print(f" ๐Ÿ“ˆ Progress: {network_percentage:.4f}% of network, {stratum_percentage:.1f}% of stratum") + print(f" ๐Ÿ“Š Share Rate: {self.stats['current_share_rate']:.2f}/s | Total: {len(self.stats['shares_last_minute'])}/min") print(f" ๐Ÿ“ Target: {job['target'][:16]}... | Height: {job['height']}") print(f" โฐ Time: {ntime} | Extranonce: {extranonce1}:{extranonce2}") print(f" ๐Ÿ” Difficulty Check: Share {share_difficulty:.2e} vs Stratum {client_stratum_diff:.6f} = {'โœ…' if meets_stratum_difficulty else 'โŒ'}") @@ -596,8 +618,34 @@ class RinCoinStratumProxy: # Valid stratum share! Update client stats if addr and addr in self.clients: + current_time = time.time() self.clients[addr]['share_count'] = self.clients[addr].get('share_count', 0) + 1 - self.clients[addr]['last_share_time'] = time.time() + self.clients[addr]['last_share_time'] = current_time + + # Calculate hashrate from this share + # Hashrate = difficulty * 2^32 / time_to_find_share + client_difficulty = self.clients[addr].get('stratum_difficulty', 0.001) + last_share_time = self.clients[addr].get('last_share_time', current_time - 60) + time_since_last = max(1, current_time - last_share_time) # Avoid division by zero + + # Calculate instantaneous hashrate for this share + diff1_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 + instant_hashrate = (client_difficulty * (2**32)) / time_since_last + + # Store hashrate sample (keep last 10 samples) + if 'hashrate_samples' not in self.clients[addr]: + self.clients[addr]['hashrate_samples'] = [] + self.clients[addr]['hashrate_samples'].append((current_time, instant_hashrate)) + # Keep only last 10 samples + if len(self.clients[addr]['hashrate_samples']) > 10: + self.clients[addr]['hashrate_samples'] = self.clients[addr]['hashrate_samples'][-10:] + + # Calculate average hashrate from recent samples + if self.clients[addr]['hashrate_samples']: + total_hashrate = sum(hr for _, hr in self.clients[addr]['hashrate_samples']) + self.clients[addr]['estimated_hashrate'] = total_hashrate / len(self.clients[addr]['hashrate_samples']) + + print(f" โ›๏ธ Miner {addr}: {self.clients[addr]['estimated_hashrate']:.0f} H/s (avg of {len(self.clients[addr]['hashrate_samples'])} samples)") # Update global stats self.stats['total_shares'] += 1 @@ -605,6 +653,9 @@ class RinCoinStratumProxy: # Check if we should adjust difficulty self.adjust_client_difficulty(addr) + + # Global difficulty adjustment based on share rate + self.adjust_global_difficulty_if_needed() # Only submit if it meets network difficulty in normal mode should_submit = meets_network_difficulty @@ -727,6 +778,8 @@ class RinCoinStratumProxy: self.clients[addr]['last_share_time'] = time.time() self.clients[addr]['share_count'] = 0 self.clients[addr]['connect_time'] = time.time() + self.clients[addr]['hashrate_samples'] = [] # Store recent hashrate measurements + self.clients[addr]['estimated_hashrate'] = 0 # Current estimated hashrate self.send_stratum_notification(client, "mining.set_difficulty", [initial_difficulty]) print(f" ๐ŸŽฏ Set initial difficulty {initial_difficulty:.6f} for {addr}") From a6c271d3f32f53afeafcbd13b3fe53a23e53fd57 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 23 Sep 2025 18:20:17 +0300 Subject: [PATCH 20/30] more proxy work --- .gitignore | 1 + MINE/rin/mining_log.txt | 4 +-- MINE/rin/stratum_proxy.py | 54 +++++++++++++++++++++++++++------------ 3 files changed, 41 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index 8300d53..5937352 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ AI/MCP/* .fuse_hidde* *.pyc MINE/rin/mining_log.txt +*mining_log.txt diff --git a/MINE/rin/mining_log.txt b/MINE/rin/mining_log.txt index 4729580..67a3143 100644 --- a/MINE/rin/mining_log.txt +++ b/MINE/rin/mining_log.txt @@ -1,10 +1,10 @@ ================================================================================ RinCoin Mining Log ================================================================================ -Started: 2025-09-23 18:00:59 +Started: 2025-09-23 18:18:32 Target Address: rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q Stratum: 0.0.0.0:3334 RPC: 127.0.0.1:9556 ================================================================================ -[2025-09-23 18:00:59] ๐Ÿ’ฐ Wallet Balance: 25.00000000 RIN +[2025-09-23 18:18:32] ๐Ÿ’ฐ Wallet Balance: 25.00000000 RIN diff --git a/MINE/rin/stratum_proxy.py b/MINE/rin/stratum_proxy.py index fe37e3d..aecc5aa 100644 --- a/MINE/rin/stratum_proxy.py +++ b/MINE/rin/stratum_proxy.py @@ -39,7 +39,7 @@ class RinCoinStratumProxy: # Dynamic difficulty adjustment self.share_stats = {} # Track shares per client self.last_difficulty_adjustment = time.time() - self.target_share_interval = 120 # Target: 1 share every 2 minutes per miner (aligned with ~1min blocks) + self.target_share_interval = 20 # Target: 1 share every 20 seconds (optimized from public pool data) # Production monitoring self.stats = { @@ -245,21 +245,21 @@ class RinCoinStratumProxy: hashes = [coinbase_txid] for tx in transactions: hashes.append(bytes.fromhex(tx['hash'])[::-1]) # Reverse for little-endian - + # Build merkle tree while len(hashes) > 1: if len(hashes) % 2 == 1: hashes.append(hashes[-1]) # Duplicate last hash if odd - + next_level = [] for i in range(0, len(hashes), 2): combined = hashes[i] + hashes[i + 1] next_level.append(hashlib.sha256(hashlib.sha256(combined).digest()).digest()) - + hashes = next_level - + return hashes[0] if hashes else b'\x00' * 32 - + except Exception as e: print(f"Merkle root calculation error: {e}") return b'\x00' * 32 @@ -400,15 +400,32 @@ class RinCoinStratumProxy: network_diff = self.calculate_network_difficulty(self.current_job['target']) if self.current_job else 1.0 if is_new_client: - # Start new clients at 0.5% of network difficulty - initial_difficulty = network_diff * 0.005 # 0.5% of network difficulty + # Use optimized difficulty based on updated hashrate analysis (680kH/s, 20s intervals) + # Updated: Doubled hashrate requires doubled difficulty for same share rate + optimal_difficulty = 0.003182 # Optimized for 680kH/s (2x original 340kH/s) + + # Scale based on network difficulty to maintain relative percentage + target_percentage = 0.003924 # 0.3924% of network (updated for 680kH/s) + scaled_difficulty = network_diff * target_percentage + + # Use the better of the two approaches + initial_difficulty = min(optimal_difficulty, scaled_difficulty) # Ensure reasonable bounds - min_difficulty = 0.000001 # Absolute minimum - max_difficulty = network_diff * 0.05 # Maximum 5% of network + min_difficulty = 0.0001 # Absolute minimum + # IMPORTANT: DO NOT CHANGE THIS VALUE. our pool may grow big in the future, so we need to be able to handle it. + max_difficulty = network_diff * 0.1 # Maximum 10% of network initial_difficulty = max(min_difficulty, min(max_difficulty, initial_difficulty)) - print(f" ๐Ÿ“Š NEW CLIENT {addr}: Network diff {network_diff:.6f}, starting with {initial_difficulty:.6f} (0.5% of network)") + percentage = (initial_difficulty / network_diff) * 100 + print(f" ๐Ÿ“Š NEW CLIENT {addr}: Network diff {network_diff:.6f}") + print(f" ๐ŸŽฏ Starting difficulty: {initial_difficulty:.6f} ({percentage:.4f}% of network)") + miner_hashrate = self.clients.get(addr, {}).get('estimated_hashrate', 0) + if miner_hashrate > 0: + print(f" Target: 1 share every {self.target_share_interval}s @ {miner_hashrate:.0f} H/s") + else: + print(f" Target: 1 share every {self.target_share_interval}s (miner hashrate unknown)") + print(f" ๐Ÿ”ง Per-miner adjustment: Difficulty will adapt to each device's actual hashrate") return initial_difficulty # For existing clients, adjust based on actual hashrate performance @@ -569,12 +586,12 @@ class RinCoinStratumProxy: # Remove shares older than 60 seconds self.stats['shares_last_minute'] = [t for t in self.stats['shares_last_minute'] if current_time - t <= 60] self.stats['current_share_rate'] = len(self.stats['shares_last_minute']) / 60.0 - + # Enhanced logging timestamp = time.strftime("%Y-%m-%d %H:%M:%S") network_percentage = (share_difficulty / network_difficulty) * 100 if network_difficulty > 0 else 0 stratum_percentage = (share_difficulty / client_stratum_diff) * 100 if client_stratum_diff > 0 else 0 - + # Progress indicator based on difficulty comparison if meets_network_difficulty: progress_icon = "๐ŸŽ‰" # Block found! @@ -588,7 +605,7 @@ class RinCoinStratumProxy: progress_icon = "๐Ÿ’ซ" # Some progress else: progress_icon = "๐Ÿ“Š" # Low progress - + print(f"[{timestamp}] {progress_icon} SHARE: job={job['job_id']} | nonce={nonce} | hash={block_hash_hex[:16]}...") print(f" ๐ŸŽฏ Share Diff: {share_difficulty:.2e} | Stratum Diff: {client_stratum_diff:.6f} | Network Diff: {network_difficulty:.6f}") print(f" ๐Ÿ“ˆ Progress: {network_percentage:.4f}% of network, {stratum_percentage:.1f}% of stratum") @@ -691,11 +708,15 @@ class RinCoinStratumProxy: # Submit block block_hex = block.hex() print(f" ๐Ÿ“ฆ Submitting block of size {len(block_hex)//2} bytes...") - + print(f" ๐Ÿš€ Calling RPC: submitblock([block_hex={len(block_hex)//2}_bytes])") + result = self.rpc_call("submitblock", [block_hex]) - + print(f" ๐Ÿ“ก RPC RESPONSE: {result}") # Log the actual RPC response + if result is None: print(f" โœ… Block accepted by network!") + print(f" ๐ŸŽŠ SUCCESS: Block {job['height']} submitted successfully!") + print(f" ๐Ÿ’ฐ Reward earned: {job['coinbasevalue']/100000000:.8f} RIN") # Update block stats self.stats['blocks_found'] += 1 # Log wallet balance after successful block submission @@ -704,6 +725,7 @@ class RinCoinStratumProxy: else: print(f" โŒ Block rejected: {result}") print(f" ๐Ÿ” Debug: Block size {len(block_hex)//2} bytes, {len(job['transactions'])} transactions") + print(f" ๐Ÿ“‹ Full RPC error details: {result}") return False, f"Block rejected: {result}" else: # Valid stratum share but not network-valid block (normal mode only) From 7a806e53cbc31c045fa983e34f6eaf04afef23d4 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 23 Sep 2025 18:38:28 +0300 Subject: [PATCH 21/30] more difficulty fns --- MINE/rin/README.md | 12 ++++++ MINE/rin/mining_log.txt | 4 +- MINE/rin/stratum_proxy.py | 91 ++++++++++++++++++++++++++------------- 3 files changed, 74 insertions(+), 33 deletions(-) diff --git a/MINE/rin/README.md b/MINE/rin/README.md index 6869eef..d2304fe 100644 --- a/MINE/rin/README.md +++ b/MINE/rin/README.md @@ -154,6 +154,18 @@ Your Stratum proxy can be enhanced to work as a **full mining pool** that distri # submit every share cd /mnt/shared/DEV/repos/d-popov.com/scripts/MINE/rin && python3 stratum_proxy.py --submit-all-blocks + +python3 stratum_proxy.py --submit-threshold 0.05 + +# For production (10% threshold - good balance) +python3 stratum_proxy.py --submit-threshold 0.1 + +# For aggressive testing (1% threshold) +python3 stratum_proxy.py --submit-threshold 0.01 + +# For normal operation (only valid blocks) +python3 stratum_proxy.py + ``` ### **Pool vs Solo Mining:** diff --git a/MINE/rin/mining_log.txt b/MINE/rin/mining_log.txt index 67a3143..8310afb 100644 --- a/MINE/rin/mining_log.txt +++ b/MINE/rin/mining_log.txt @@ -1,10 +1,10 @@ ================================================================================ RinCoin Mining Log ================================================================================ -Started: 2025-09-23 18:18:32 +Started: 2025-09-23 18:38:03 Target Address: rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q Stratum: 0.0.0.0:3334 RPC: 127.0.0.1:9556 ================================================================================ -[2025-09-23 18:18:32] ๐Ÿ’ฐ Wallet Balance: 25.00000000 RIN +[2025-09-23 18:38:03] ๐Ÿ’ฐ Wallet Balance: 25.00000000 RIN diff --git a/MINE/rin/stratum_proxy.py b/MINE/rin/stratum_proxy.py index aecc5aa..c47fb9e 100644 --- a/MINE/rin/stratum_proxy.py +++ b/MINE/rin/stratum_proxy.py @@ -15,11 +15,11 @@ import struct from requests.auth import HTTPBasicAuth class RinCoinStratumProxy: - def __init__(self, stratum_host='0.0.0.0', stratum_port=3334, - rpc_host='127.0.0.1', rpc_port=9556, + def __init__(self, stratum_host='0.0.0.0', stratum_port=3334, + rpc_host='127.0.0.1', rpc_port=9556, rpc_user='rinrpc', rpc_password='745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90', target_address='rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q', - submit_all_blocks=False): + submit_all_blocks=False, submit_threshold=0.1): self.stratum_host = stratum_host self.stratum_port = stratum_port @@ -28,7 +28,9 @@ class RinCoinStratumProxy: self.rpc_user = rpc_user self.rpc_password = rpc_password self.target_address = target_address - self.submit_all_blocks = submit_all_blocks # If True, submit even invalid blocks for testing + self.submit_all_blocks = submit_all_blocks + # For debugging: submit blocks that meet this fraction of network difficulty + self.submit_threshold = submit_threshold # Configurable percentage of network difficulty self.clients = {} self.job_counter = 0 @@ -39,7 +41,7 @@ class RinCoinStratumProxy: # Dynamic difficulty adjustment self.share_stats = {} # Track shares per client self.last_difficulty_adjustment = time.time() - self.target_share_interval = 20 # Target: 1 share every 20 seconds (optimized from public pool data) + self.target_share_interval = 15 # Target: 1 share every 15 seconds (optimal for 1-min blocks) # Production monitoring self.stats = { @@ -398,16 +400,16 @@ class RinCoinStratumProxy: 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: - # Use optimized difficulty based on updated hashrate analysis (680kH/s, 20s intervals) - # Updated: Doubled hashrate requires doubled difficulty for same share rate - optimal_difficulty = 0.003182 # Optimized for 680kH/s (2x original 340kH/s) - + # Use optimized difficulty based on updated hashrate analysis (680kH/s, 15s intervals) + # Updated: 15s intervals for better responsiveness with 1-min blocks + optimal_difficulty = 0.002375 # Optimized for 680kH/s at 15s intervals + # Scale based on network difficulty to maintain relative percentage - target_percentage = 0.003924 # 0.3924% of network (updated for 680kH/s) + target_percentage = 0.003382 # 0.3382% of network (updated for 680kH/s, 15s) scaled_difficulty = network_diff * target_percentage - + # Use the better of the two approaches initial_difficulty = min(optimal_difficulty, scaled_difficulty) @@ -444,7 +446,7 @@ class RinCoinStratumProxy: return current_difficulty # Calculate target difficulty based on hashrate and desired share interval - # Target: 1 share every 60 seconds (self.target_share_interval) + # Target: 1 share every 15 seconds (self.target_share_interval) if estimated_hashrate > 0: # Formula: difficulty = (hashrate * target_time) / (2^32) diff1_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 @@ -615,13 +617,24 @@ class RinCoinStratumProxy: print(f" ๐Ÿ” Difficulty Check: Share {share_difficulty:.2e} vs Stratum {client_stratum_diff:.6f} = {'โœ…' if meets_stratum_difficulty else 'โŒ'}") print(f" ๐Ÿ” Difficulty Check: Share {share_difficulty:.2e} vs Network {network_difficulty:.6f} = {'โœ…' if meets_network_difficulty else 'โŒ'}") + # Initialize submission variables + submit_network_difficulty = meets_network_difficulty + submit_debug_threshold = share_difficulty >= (network_difficulty * self.submit_threshold) + + if submit_network_difficulty: + submit_reason = "meets network difficulty" + elif submit_debug_threshold: + submit_reason = f"meets debug threshold ({self.submit_threshold*100:.0f}% of network)" + else: + submit_reason = "does not meet minimum requirements" + # Handle submit_all_blocks mode - bypass all difficulty checks if self.submit_all_blocks: print(f" ๐Ÿงช TEST MODE: Submitting ALL shares to node for validation") # Update stats for test mode self.stats['total_shares'] += 1 self.stats['accepted_shares'] += 1 - + # Always submit in test mode should_submit = True else: @@ -638,17 +651,17 @@ class RinCoinStratumProxy: current_time = time.time() self.clients[addr]['share_count'] = self.clients[addr].get('share_count', 0) + 1 self.clients[addr]['last_share_time'] = current_time - + # Calculate hashrate from this share # Hashrate = difficulty * 2^32 / time_to_find_share client_difficulty = self.clients[addr].get('stratum_difficulty', 0.001) last_share_time = self.clients[addr].get('last_share_time', current_time - 60) time_since_last = max(1, current_time - last_share_time) # Avoid division by zero - + # Calculate instantaneous hashrate for this share diff1_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 instant_hashrate = (client_difficulty * (2**32)) / time_since_last - + # Store hashrate sample (keep last 10 samples) if 'hashrate_samples' not in self.clients[addr]: self.clients[addr]['hashrate_samples'] = [] @@ -656,36 +669,38 @@ class RinCoinStratumProxy: # Keep only last 10 samples if len(self.clients[addr]['hashrate_samples']) > 10: self.clients[addr]['hashrate_samples'] = self.clients[addr]['hashrate_samples'][-10:] - + # Calculate average hashrate from recent samples if self.clients[addr]['hashrate_samples']: total_hashrate = sum(hr for _, hr in self.clients[addr]['hashrate_samples']) self.clients[addr]['estimated_hashrate'] = total_hashrate / len(self.clients[addr]['hashrate_samples']) - + print(f" โ›๏ธ Miner {addr}: {self.clients[addr]['estimated_hashrate']:.0f} H/s (avg of {len(self.clients[addr]['hashrate_samples'])} samples)") - + # Update global stats self.stats['total_shares'] += 1 self.stats['accepted_shares'] += 1 - + # Check if we should adjust difficulty self.adjust_client_difficulty(addr) - + # Global difficulty adjustment based on share rate self.adjust_global_difficulty_if_needed() - - # Only submit if it meets network difficulty in normal mode - should_submit = meets_network_difficulty + + should_submit = submit_network_difficulty or submit_debug_threshold # Submit block if conditions are met if should_submit: - if meets_network_difficulty: + if submit_network_difficulty: print(f" ๐ŸŽ‰ VALID BLOCK FOUND! Hash: {block_hash_hex}") + elif submit_debug_threshold: + print(f" ๐Ÿงช DEBUG SUBMISSION! Hash: {block_hash_hex} ({submit_reason})") else: print(f" ๐Ÿงช TEST BLOCK SUBMISSION! Hash: {block_hash_hex} (submit_all_blocks=True)") print(f" ๐Ÿ’ฐ Reward: {job['coinbasevalue']/100000000:.2f} RIN -> {address}") print(f" ๐Ÿ“Š Block height: {job['height']}") print(f" ๐Ÿ” Difficulty: {share_difficulty:.6f} (target: {network_difficulty:.6f})") + print(f" ๐Ÿ“‹ Submit reason: {submit_reason}") # Log the found hash reward_rin = job['coinbasevalue'] / 100000000 @@ -1214,6 +1229,7 @@ class RinCoinStratumProxy: print(f" ๐Ÿ’ฐ Mining to: {self.target_address}") print(f" ๐Ÿ“Š Current job: {self.current_job['job_id'] if self.current_job else 'None'}") print(f" ๐Ÿ“ Mining log: {self.log_file}") + print(f" ๐Ÿงช Debug mode: Submit blocks at {self.submit_threshold*100:.0f}% of network difficulty") print("") print(" ๐Ÿ”ง Miner command:") print(f" ./cpuminer -a rinhash -o stratum+tcp://{self.stratum_host}:{self.stratum_port} -u worker1 -p x -t 4") @@ -1243,11 +1259,24 @@ class RinCoinStratumProxy: if __name__ == "__main__": import sys - # Check for submit_all_blocks parameter + # Parse command line arguments submit_all = False - if len(sys.argv) > 1 and sys.argv[1] == "--submit-all-blocks": - submit_all = True - print("๐Ÿงช TEST MODE: Will submit ALL blocks for validation (submit_all_blocks=True)") + submit_threshold = 0.1 # Default 10% - proxy = RinCoinStratumProxy(submit_all_blocks=submit_all) + for i, arg in enumerate(sys.argv[1:], 1): + if arg == "--submit-all-blocks": + submit_all = True + print("๐Ÿงช TEST MODE: Will submit ALL blocks for validation (submit_all_blocks=True)") + elif arg == "--submit-threshold" and i + 1 < len(sys.argv): + try: + submit_threshold = float(sys.argv[i + 1]) + if submit_threshold <= 0 or submit_threshold > 1: + print(f"โŒ Invalid threshold {submit_threshold}. Must be between 0 and 1 (0-100%)") + sys.exit(1) + print(f"๐Ÿงช DEBUG MODE: Will submit blocks at {submit_threshold*100:.1f}% of network difficulty") + except ValueError: + print(f"โŒ Invalid threshold value: {sys.argv[i + 1]}") + sys.exit(1) + + proxy = RinCoinStratumProxy(submit_all_blocks=submit_all, submit_threshold=submit_threshold) proxy.start() From 353b8120c871d6ffe09b61f8bf134f737d96f6df Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 23 Sep 2025 20:37:12 +0300 Subject: [PATCH 22/30] net hashrate log --- MINE/rin/start_stratum_proxy.sh | 2 +- MINE/rin/stratum_proxy.py | 37 ++++++++++++++++++++++++++------- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/MINE/rin/start_stratum_proxy.sh b/MINE/rin/start_stratum_proxy.sh index 4bf852c..0d9c82f 100644 --- a/MINE/rin/start_stratum_proxy.sh +++ b/MINE/rin/start_stratum_proxy.sh @@ -65,4 +65,4 @@ echo "" # Start the proxy cd "$(dirname "$0")" -python3 stratum_proxy.py +python3 stratum_proxy.py --submit-all-blocks diff --git a/MINE/rin/stratum_proxy.py b/MINE/rin/stratum_proxy.py index c47fb9e..ca9cc3e 100644 --- a/MINE/rin/stratum_proxy.py +++ b/MINE/rin/stratum_proxy.py @@ -608,10 +608,27 @@ class RinCoinStratumProxy: else: progress_icon = "๐Ÿ“Š" # Low progress + # Calculate network and pool hashrates + block_time = 60 # RinCoin 1-minute blocks + network_hashrate = (network_difficulty * (2**32)) / block_time + network_mhs = network_hashrate / 1e6 + + # Calculate pool hashrate (sum of all connected miners) + pool_hashrate = 0 + for client_addr, client_data in self.clients.items(): + pool_hashrate += client_data.get('estimated_hashrate', 0) + pool_mhs = pool_hashrate / 1e6 + + # Calculate percentages + pool_network_percentage = (pool_mhs / network_mhs) * 100 if network_mhs > 0 else 0 + miner_pool_percentage = (0.87 / pool_mhs) * 100 if pool_mhs > 0 else 0 # Assuming 870kH/s miner + print(f"[{timestamp}] {progress_icon} SHARE: job={job['job_id']} | nonce={nonce} | hash={block_hash_hex[:16]}...") print(f" ๐ŸŽฏ Share Diff: {share_difficulty:.2e} | Stratum Diff: {client_stratum_diff:.6f} | Network Diff: {network_difficulty:.6f}") print(f" ๐Ÿ“ˆ Progress: {network_percentage:.4f}% of network, {stratum_percentage:.1f}% of stratum") print(f" ๐Ÿ“Š Share Rate: {self.stats['current_share_rate']:.2f}/s | Total: {len(self.stats['shares_last_minute'])}/min") + print(f" ๐ŸŒ Network: {network_mhs:.1f} MH/s | Pool: {pool_mhs:.1f} MH/s ({pool_network_percentage:.2f}% of network)") + print(f" โ›๏ธ Miner: 0.87 MH/s ({miner_pool_percentage:.1f}% of pool) | Expected solo: {network_mhs/0.87:.0f}h") print(f" ๐Ÿ“ Target: {job['target'][:16]}... | Height: {job['height']}") print(f" โฐ Time: {ntime} | Extranonce: {extranonce1}:{extranonce2}") print(f" ๐Ÿ” Difficulty Check: Share {share_difficulty:.2e} vs Stratum {client_stratum_diff:.6f} = {'โœ…' if meets_stratum_difficulty else 'โŒ'}") @@ -693,18 +710,22 @@ class RinCoinStratumProxy: if should_submit: if submit_network_difficulty: print(f" ๐ŸŽ‰ VALID BLOCK FOUND! Hash: {block_hash_hex}") + print(f" ๐Ÿ’ฐ Reward: {job['coinbasevalue']/100000000:.2f} RIN -> {address}") + print(f" ๐Ÿ“Š Block height: {job['height']}") + print(f" ๐Ÿ” Difficulty: {share_difficulty:.6f} (target: {network_difficulty:.6f})") + print(f" ๐Ÿ“‹ Submit reason: {submit_reason}") + + # Log the found hash - ONLY for actual network-valid blocks + reward_rin = job['coinbasevalue'] / 100000000 + self.log_hash_found(block_hash_hex, share_difficulty, job['height'], reward_rin, nonce, ntime) elif submit_debug_threshold: print(f" ๐Ÿงช DEBUG SUBMISSION! Hash: {block_hash_hex} ({submit_reason})") + print(f" ๐Ÿ“Š Block height: {job['height']} | Difficulty: {share_difficulty:.6f}") + print(f" ๐Ÿ’ก This is a test submission - not a real block") else: print(f" ๐Ÿงช TEST BLOCK SUBMISSION! Hash: {block_hash_hex} (submit_all_blocks=True)") - print(f" ๐Ÿ’ฐ Reward: {job['coinbasevalue']/100000000:.2f} RIN -> {address}") - print(f" ๐Ÿ“Š Block height: {job['height']}") - print(f" ๐Ÿ” Difficulty: {share_difficulty:.6f} (target: {network_difficulty:.6f})") - print(f" ๐Ÿ“‹ Submit reason: {submit_reason}") - - # Log the found hash - reward_rin = job['coinbasevalue'] / 100000000 - self.log_hash_found(block_hash_hex, share_difficulty, job['height'], reward_rin, nonce, ntime) + print(f" ๐Ÿ“Š Block height: {job['height']} | Difficulty: {share_difficulty:.6f}") + print(f" ๐Ÿ’ก This is a test submission - not a real block") # Build complete block block = header From 2fd3146bdbd5c78e26e07dac406025db6b24b5a6 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 23 Sep 2025 22:44:03 +0300 Subject: [PATCH 23/30] notes & stats --- MINE/rin/stratum_proxy.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/MINE/rin/stratum_proxy.py b/MINE/rin/stratum_proxy.py index ca9cc3e..21b7952 100644 --- a/MINE/rin/stratum_proxy.py +++ b/MINE/rin/stratum_proxy.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 """ -RinCoin Stratum Proxy Server - FIXED VERSION -Fixed block hash calculation and validation issues -DEBUG: we get node logs with 'docker logs --tail=200 rincoin-node' +RinCoin Stratum Proxy Server +DEBUG RPC: we get node logs with 'docker logs --tail=200 rincoin-node' +MINE: /mnt/shared/DEV/repos/d-popov.com/mines/rin/miner/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://localhost:3334 -u x -p x -t 32 """ import socket @@ -402,16 +402,18 @@ class RinCoinStratumProxy: network_diff = self.calculate_network_difficulty(self.current_job['target']) if self.current_job else 1.0 if is_new_client: - # Use optimized difficulty based on updated hashrate analysis (680kH/s, 15s intervals) - # Updated: 15s intervals for better responsiveness with 1-min blocks - optimal_difficulty = 0.002375 # Optimized for 680kH/s at 15s intervals + # Calculate difficulty for 4 shares per minute (15 second intervals) + # Formula: difficulty = (shares_per_second * 2^32) / hashrate + target_shares_per_second = 4 / 60 # 4 shares per minute + assumed_hashrate = 680000 # H/s (conservative estimate) + calculated_difficulty = (target_shares_per_second * (2**32)) / assumed_hashrate # Scale based on network difficulty to maintain relative percentage - target_percentage = 0.003382 # 0.3382% of network (updated for 680kH/s, 15s) + target_percentage = calculated_difficulty / network_diff if network_diff > 0 else 0.32 scaled_difficulty = network_diff * target_percentage - # Use the better of the two approaches - initial_difficulty = min(optimal_difficulty, scaled_difficulty) + # Use the calculated difficulty (should be around 421 for 680kH/s) + initial_difficulty = calculated_difficulty # Ensure reasonable bounds min_difficulty = 0.0001 # Absolute minimum From a1a35a6bd60436a031ee6e6a725333d0483ad718 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Wed, 24 Sep 2025 11:20:28 +0300 Subject: [PATCH 24/30] rin wallet --- MINE/cmds | 21 ++ MINE/rin/README.md | 25 ++ MINE/rin/dump_wallet.sh | 65 +++++ MINE/rin/restore_wallet.sh | 63 +++++ MINE/rin/send_rin.sh | 55 ++++ MINE/rin/start_web_wallet.sh | 14 ++ MINE/rin/web_wallet.send.sh | 11 + MINE/rin/web_wallet/server.py | 150 +++++++++++ MINE/rin/web_wallet/start_web_wallet.sh | 24 ++ MINE/rin/web_wallet/static/index.html | 318 ++++++++++++++++++++++++ 10 files changed, 746 insertions(+) create mode 100644 MINE/rin/dump_wallet.sh create mode 100644 MINE/rin/restore_wallet.sh create mode 100644 MINE/rin/send_rin.sh create mode 100644 MINE/rin/start_web_wallet.sh create mode 100644 MINE/rin/web_wallet.send.sh create mode 100644 MINE/rin/web_wallet/server.py create mode 100644 MINE/rin/web_wallet/start_web_wallet.sh create mode 100644 MINE/rin/web_wallet/static/index.html diff --git a/MINE/cmds b/MINE/cmds index 3e905e4..9f9ccb5 100644 --- a/MINE/cmds +++ b/MINE/cmds @@ -1,4 +1,25 @@ +# RANDOMX: root@db-NucBox-EVO-X2:/home/db/Downloads/SRBMiner-Multi-2-9-6# ./SRBMiner-MULTI --algorithm randomx --pool xmr-us-east1.nanopool.org:14444 --wallet bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j --disable-gpu --cpu-threads 28 +cd /home/db/Downloads/SRBMiner-Multi-2-9-6 +./SRBMiner-MULTI --algorithm randomx --pool randomx.mine.zergpool.com:4453 --wallet bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC,mc=ZEPH --cpu-threads 28 +./SRBMiner-MULTI --algorithm randomx --pool randomx.mine.zergpool.com:4453 --wallet bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC,mc=ZEPH --cpu-threads 28 --gpu-id 1 + +# pool/solo/party -p [m=solo][m=party] +# experim + +export LD_LIBRARY_PATH=/opt/rocm-6.4.3/lib:$LD_LIBRARY_PATH +./SRBMiner-MULTI --algorithm ethash --pool ethash.mine.zergpool.com:9999 --wallet bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j --disable-cpu +-o stratum+tcp://ethash.mine.zergpool.com:9999 -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC +./SRBMiner-MULTI --algorithm blake2s --pool auto.nicehash.com:3333 --wallet bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j --disable-cpu + + +# RIN +/mnt/shared/DEV/repos/d-popov.com/mines/rin/miner/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://192.168.0.188:3334 -u x -p x -t 32 + +cd /mnt/shared/DEV/repos/d-popov.com/mines/rin/miner/cpuminer-opt-rin +cpuminer -a rinhash -o stratum+tcp://rinhash.mine.zergpool.com:7148 -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC,mc=RIN,ID=StrixHalo -t 32 + +/mnt/shared/DEV/repos/d-popov.com/mines/rin/miner/cpuminer-opt-rin/cpuminer -o stratum+tcp://randomx.eu.zergpool.com:4453 -a randomx -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC,mc=ZEPH -t 32 diff --git a/MINE/rin/README.md b/MINE/rin/README.md index d2304fe..5e8cd73 100644 --- a/MINE/rin/README.md +++ b/MINE/rin/README.md @@ -329,9 +329,34 @@ tail -f stratum_proxy.log ps aux | grep stratum_proxy ``` +## ๐Ÿ” **Wallet Backup & Restoration** + +### **Backup Your Wallet** +```bash +# Run the backup script +./MINE/rin/dump_wallet.sh +``` +- This creates a text file with all private keys in `~/rin_wallet_backups/`. +- **Security**: Encrypt immediately with `gpg -c `, store offline, delete unencrypted copy. +- Contains sensitive dataโ€”anyone with this can spend your coins. + +### **Restore on New Node** +```bash +# Automated restoration (requires new node setup) +./MINE/rin/restore_wallet.sh /path/to/backup.txt + +# Manual steps: +# 1. Stop new node: sudo docker stop rincoin-node +# 2. Copy wallet.dat or import dump file +# 3. Start node: sudo docker start rincoin-node +# 4. Load wallet: sudo docker exec rincoin-node rincoin-cli ... loadwallet main +# 5. Import if using dump: importwallet /path/to/dump.txt +``` + ## ๐ŸŽฏ **Next Steps:** 1. โœ… **Node is synced** - Ready for all operations 2. **Choose mining strategy**: Pool mining for consistent income vs Solo mining for block rewards 3. **Monitor performance** and adjust thread count as needed 4. **Set up monitoring** for node health and mining performance +5. **Backup wallet regularly** - Use the dump script above diff --git a/MINE/rin/dump_wallet.sh b/MINE/rin/dump_wallet.sh new file mode 100644 index 0000000..b8c1da5 --- /dev/null +++ b/MINE/rin/dump_wallet.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +# RinCoin Wallet Backup Script +# Dumps all private keys to a secure text file for backup. +# WARNING: This file contains sensitive private keys. Store it securely (encrypted, offline). +# Do not share or email it. Anyone with this file can spend your coins. + +set -euo pipefail + +# Configuration +CONTAINER="rincoin-node" +WALLET="main" +BACKUP_DIR="${HOME}/rin_wallet_backups" +TIMESTAMP=$(date +%Y%m%d_%H%M%S) +BACKUP_FILE="${BACKUP_DIR}/rin_wallet_backup_${TIMESTAMP}.txt" + +# Ensure backup directory exists +mkdir -p "$BACKUP_DIR" + +# Check if container is running +if ! sudo docker ps --format '{{.Names}}' | grep -q "^${CONTAINER}$"; then + echo "Error: ${CONTAINER} container is not running. Start it with 'sudo docker start ${CONTAINER}'." + exit 1 +fi + +# Ensure wallet is loaded +CLI_CMD=(sudo docker exec "$CONTAINER" rincoin-cli -datadir=/data -conf=/data/rincoin.conf -rpcwallet="$WALLET") +if ! "${CLI_CMD[@]//-rpcwallet=$WALLET/}" listwallets | grep -q '"main"'; then + echo "Wallet '${WALLET}' not loaded. Attempting to load..." + "${CLI_CMD[@]//-rpcwallet=$WALLET/}" loadwallet "$WALLET" >/dev/null 2>&1 || { + echo "Failed to load wallet. Ensure it exists." + exit 1 + } +fi + +echo "Dumping wallet to: $BACKUP_FILE" +echo "This may take a moment..." + +# Dump wallet +"${CLI_CMD[@]}" dumpwallet "$BACKUP_FILE" + +# Verify the file was created and has content +if [[ ! -f "$BACKUP_FILE" ]]; then + echo "Error: Backup file was not created." + exit 1 +fi + +LINE_COUNT=$(wc -l < "$BACKUP_FILE") +if [[ $LINE_COUNT -lt 10 ]]; then + echo "Warning: Backup file seems too small (${LINE_COUNT} lines). Check for errors." + exit 1 +fi + +echo "โœ… Wallet successfully backed up to: $BACKUP_FILE" +echo "" +echo "๐Ÿ” SECURITY REMINDERS:" +echo " - This file contains private keys for ALL addresses in the wallet." +echo " - Encrypt it immediately: gpg -c $BACKUP_FILE" +echo " - Store on encrypted media (e.g., USB drive in safe)." +echo " - Delete the unencrypted file after encryption." +echo " - Test restoration on a testnet node before relying on it." +echo "" +echo "File size: $(du -h "$BACKUP_FILE" | cut -f1)" +echo "Lines: $LINE_COUNT" + diff --git a/MINE/rin/restore_wallet.sh b/MINE/rin/restore_wallet.sh new file mode 100644 index 0000000..26cc982 --- /dev/null +++ b/MINE/rin/restore_wallet.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +# RinCoin Wallet Restoration Script +# Restores a wallet from a dump file on a new RinCoin node. +# Prerequisites: New RinCoin node running in Docker, backup file available. + +set -euo pipefail + +if [[ $# -ne 1 ]]; then + echo "Usage: $0 " + echo "Example: $0 ~/rin_wallet_backups/rin_wallet_backup_20230923.txt" + exit 1 +fi + +BACKUP_FILE="$1" +CONTAINER="rincoin-node" +WALLET_NAME="main" # Will be renamed to avoid conflicts +NEW_WALLET_NAME="restored_main" + +# Verify backup file exists +if [[ ! -f "$BACKUP_FILE" ]]; then + echo "Error: Backup file '$BACKUP_FILE' not found." + exit 1 +fi + +# Check if container is running +if ! sudo docker ps --format '{{.Names}}' | grep -q "^${CONTAINER}$"; then + echo "Error: ${CONTAINER} container is not running. Start it with 'sudo docker start ${CONTAINER}'." + exit 1 +fi + +echo "Stopping RinCoin node for safe restoration..." +sudo docker stop "$CONTAINER" + +echo "Copying backup file into container..." +sudo docker cp "$BACKUP_FILE" "$CONTAINER:/tmp/wallet_backup.txt" + +echo "Starting RinCoin node..." +sudo docker start "$CONTAINER" + +# Wait for RPC to be ready +echo "Waiting for node to fully start..." +sleep 10 + +echo "Creating new wallet and importing keys..." +# Create a new wallet to avoid conflicts +sudo docker exec "$CONTAINER" rincoin-cli -datadir=/data -conf=/data/rincoin.conf createwallet "$NEW_WALLET_NAME" + +# Import the dump file +sudo docker exec "$CONTAINER" rincoin-cli -datadir=/data -conf=/data/rincoin.conf -rpcwallet="$NEW_WALLET_NAME" importwallet /tmp/wallet_backup.txt + +# Clean up +sudo docker exec "$CONTAINER" rm /tmp/wallet_backup.txt + +echo "โœ… Wallet restored successfully!" +echo "New wallet name: $NEW_WALLET_NAME" +echo "" +echo "Verify with:" +echo "sudo docker exec $CONTAINER rincoin-cli -datadir=/data -conf=/data/rincoin.conf -rpcwallet=$NEW_WALLET_NAME getbalance" +echo "" +echo "To use this wallet, update scripts to use -rpcwallet=$NEW_WALLET_NAME" +echo "Or rename it back: unloadwallet $NEW_WALLET_NAME && loadwallet $WALLET_NAME" + diff --git a/MINE/rin/send_rin.sh b/MINE/rin/send_rin.sh new file mode 100644 index 0000000..c175945 --- /dev/null +++ b/MINE/rin/send_rin.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +set -euo pipefail + +if [[ ${1-} == "" ]]; then + echo "Usage: $0 [amount]" + echo "Amount defaults to 1 RIN if not specified." + exit 1 +fi + +ADDRESS="$1" +AMOUNT="${2-1}" +WALLET="main" +CONTAINER="rincoin-node" +CLI_CMD=(sudo docker exec "$CONTAINER" rincoin-cli -datadir=/data -conf=/data/rincoin.conf -rpcwallet="$WALLET") + +echo "Checking RinCoin node container..." +if ! sudo docker ps --format '{{.Names}}' | grep -q "^${CONTAINER}$"; then + echo "Error: container ${CONTAINER} is not running. Start it with 'sudo docker start ${CONTAINER}'." + exit 1 +fi + +echo "Ensuring wallet '${WALLET}' is loaded..." +if ! "${CLI_CMD[@]//-rpcwallet=$WALLET/}" listwallets | grep -q '"main"'; then + echo "Wallet ${WALLET} not loaded, attempting to load..." + "${CLI_CMD[@]//-rpcwallet=$WALLET/}" loadwallet "$WALLET" >/dev/null +fi + +echo "Checking available balance..." +BALANCE_RAW=$("${CLI_CMD[@]}" getbalance) +BALANCE=$(printf '%.8f' "$BALANCE_RAW") + +if [[ $(bc <<< "$BALANCE_RAW < $AMOUNT") -eq 1 ]]; then + echo "Error: insufficient balance. Available ${BALANCE} RIN, but ${AMOUNT} RIN requested." + exit 1 +fi + +echo "Broadcasting transaction..." +set +e +TX_OUTPUT=$("${CLI_CMD[@]}" sendtoaddress "$ADDRESS" "$AMOUNT" '' '' false true) +STATUS=$? +set -e + +if [[ $STATUS -ne 0 ]]; then + echo "Failed to send transaction." + if [[ $STATUS -eq 4 ]]; then + echo "Wallet appears to be locked. Unlock it with 'sudo docker exec ${CONTAINER} rincoin-cli -datadir=/data -conf=/data/rincoin.conf -rpcwallet=${WALLET} walletpassphrase 600 true' and rerun." + fi + exit $STATUS +fi + +echo "Transaction broadcast. TXID: ${TX_OUTPUT}" +echo "Verify with: sudo docker exec ${CONTAINER} rincoin-cli -datadir=/data -conf=/data/rincoin.conf gettransaction ${TX_OUTPUT}" + + diff --git a/MINE/rin/start_web_wallet.sh b/MINE/rin/start_web_wallet.sh new file mode 100644 index 0000000..930ee98 --- /dev/null +++ b/MINE/rin/start_web_wallet.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +set -euo pipefail + +SCRIPT_DIR="/mnt/shared/DEV/repos/d-popov.com/scripts/MINE/rin/web_wallet" + +if ! command -v python3 >/dev/null 2>&1; then + echo "python3 is required" + exit 1 +fi + +python3 "${SCRIPT_DIR}/server.py" + + diff --git a/MINE/rin/web_wallet.send.sh b/MINE/rin/web_wallet.send.sh new file mode 100644 index 0000000..e62cc36 --- /dev/null +++ b/MINE/rin/web_wallet.send.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -euo pipefail + +SCRIPT_DIR=$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd) + +WEB_WALLET_DIR="${SCRIPT_DIR}/web_wallet" + +bash /mnt/shared/DEV/repos/d-popov.com/scripts/MINE/rin/send_rin.sh "$@" + + diff --git a/MINE/rin/web_wallet/server.py b/MINE/rin/web_wallet/server.py new file mode 100644 index 0000000..b3f176c --- /dev/null +++ b/MINE/rin/web_wallet/server.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import json +import os +import secrets +from functools import wraps + +from flask import Flask, jsonify, request, send_from_directory + +try: + from bitcoinrpc.authproxy import AuthServiceProxy +except ImportError: # pragma: no cover + raise SystemExit("Missing python-bitcoinrpc. Install with: pip install python-bitcoinrpc") + + +RIN_RPC_HOST = os.environ.get("RIN_RPC_HOST", "127.0.0.1") +RIN_RPC_PORT = int(os.environ.get("RIN_RPC_PORT", "9556")) +RIN_RPC_USER = os.environ.get("RIN_RPC_USER", "rinrpc") +RIN_RPC_PASSWORD = os.environ.get("RIN_RPC_PASSWORD", "745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90") +RIN_WALLET_NAME = os.environ.get("RIN_WALLET_NAME", "main") + +API_TOKEN = os.environ.get("RIN_WEB_WALLET_TOKEN") +if not API_TOKEN: + API_TOKEN = secrets.token_urlsafe(32) + print("[web-wallet] No RIN_WEB_WALLET_TOKEN provided. Generated one for this session.") + print(f"[web-wallet] API token: {API_TOKEN}") + + +def create_rpc_client() -> AuthServiceProxy: + url = f"http://{RIN_RPC_USER}:{RIN_RPC_PASSWORD}@{RIN_RPC_HOST}:{RIN_RPC_PORT}/wallet/{RIN_WALLET_NAME}" + return AuthServiceProxy(url, timeout=15) + + +def require_token(view_func): + @wraps(view_func) + def wrapper(*args, **kwargs): + header = request.headers.get("Authorization", "") + if not header.startswith("Bearer "): + return jsonify({"error": "missing_token"}), 401 + token = header.split(" ", 1)[1] + if token != API_TOKEN: + return jsonify({"error": "invalid_token"}), 403 + return view_func(*args, **kwargs) + + return wrapper + + +app = Flask(__name__, static_folder="static", static_url_path="") + + +def rpc_call(method: str, *params): + try: + rpc = create_rpc_client() + return rpc.__getattr__(method)(*params) + except Exception as exc: # noqa: BLE001 + raise RuntimeError(str(exc)) from exc + + +@app.route("/api/session", methods=["GET"]) +def session_info(): + return jsonify({ + "wallet": RIN_WALLET_NAME, + "host": RIN_RPC_HOST, + }) + + +@app.route("/api/address", methods=["POST"]) +@require_token +def create_address(): + data = request.get_json(silent=True) or {} + label = data.get("label", "") + try: + address = rpc_call("getnewaddress", label) + return jsonify({"address": address}) + except RuntimeError as exc: + return jsonify({"error": str(exc)}), 500 + + +@app.route("/api/balance", methods=["GET"]) +@require_token +def get_balance(): + try: + info = rpc_call("getwalletinfo") + confirmed = info.get("balance", 0) + unconfirmed = info.get("unconfirmed_balance", 0) + immature = info.get("immature_balance", 0) + total = confirmed + unconfirmed + immature + return jsonify({ + "confirmed": confirmed, + "unconfirmed": unconfirmed, + "immature": immature, + "total": total, + }) + except RuntimeError as exc: + return jsonify({"error": str(exc)}), 500 + + +@app.route("/api/send", methods=["POST"]) +@require_token +def send(): + payload = request.get_json(force=True) + address = payload.get("address") + amount = payload.get("amount") + subtract_fee = bool(payload.get("subtractFee", True)) + + if not address or not isinstance(amount, (int, float)): + return jsonify({"error": "invalid_request"}), 400 + + if amount <= 0: + return jsonify({"error": "amount_must_be_positive"}), 400 + + try: + txid = rpc_call("sendtoaddress", address, float(amount), "", "", subtract_fee) + return jsonify({"txid": txid}) + except RuntimeError as exc: + status = 400 if "Invalid RinCoin address" in str(exc) else 500 + return jsonify({"error": str(exc)}), status + + +@app.route("/api/transactions", methods=["GET"]) +@require_token +def list_transactions(): + count = int(request.args.get("count", 10)) + try: + txs = rpc_call("listtransactions", "*", count, 0, True) + return jsonify({"transactions": txs}) + except RuntimeError as exc: + return jsonify({"error": str(exc)}), 500 + + +@app.route("/") +def root(): + return send_from_directory(app.static_folder, "index.html") + + +@app.route("/") +def static_proxy(path): + return send_from_directory(app.static_folder, path) + + +def main(): + port = int(os.environ.get("RIN_WEB_WALLET_PORT", "8787")) + app.run(host="127.0.0.1", port=port, debug=False) + + +if __name__ == "__main__": + main() + diff --git a/MINE/rin/web_wallet/start_web_wallet.sh b/MINE/rin/web_wallet/start_web_wallet.sh new file mode 100644 index 0000000..059658a --- /dev/null +++ b/MINE/rin/web_wallet/start_web_wallet.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +set -euo pipefail + +SCRIPT_DIR=$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd) +CONTAINER="rincoin-node" + +if ! sudo docker ps --format '{{.Names}}' | grep -q "^${CONTAINER}$"; then + echo "Error: ${CONTAINER} container is not running. Start it with 'sudo docker start ${CONTAINER}'." + exit 1 +fi + +if ! command -v flask >/dev/null 2>&1; then + echo "Missing Flask. Install with 'pip install flask python-bitcoinrpc'." + exit 1 +fi + +echo "Starting RinCoin web wallet on http://127.0.0.1:8787" +export FLASK_APP="${SCRIPT_DIR}/server.py" +export FLASK_ENV=production +export PYTHONPATH="${SCRIPT_DIR}" +flask run --host 127.0.0.1 --port 8787 + + diff --git a/MINE/rin/web_wallet/static/index.html b/MINE/rin/web_wallet/static/index.html new file mode 100644 index 0000000..3c63934 --- /dev/null +++ b/MINE/rin/web_wallet/static/index.html @@ -0,0 +1,318 @@ + + + + + + RinCoin Web Wallet + + + + +
+

RinCoin Wallet

+ +
+
Confirmed Balance
+
โ€”
+
Total: โ€”
+
+ +
+

Send RinCoin

+ + + + + + +
+ + + +
+

Recent Activity

+
    +
    +
    + + + + + From 77c7c249b3832d3984c875d755a0d3fafb2475b4 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Wed, 24 Sep 2025 14:31:10 +0300 Subject: [PATCH 25/30] try to support xmrig --- MINE/cmds | 31 ++++++++++++++++++++++- MINE/rin/mining_log.txt | 3 +-- MINE/rin/stratum_proxy.py | 53 ++++++++++++++++++++++++++++++++++++--- mining_log.txt | 3 +-- 4 files changed, 81 insertions(+), 9 deletions(-) diff --git a/MINE/cmds b/MINE/cmds index 9f9ccb5..3e84b4a 100644 --- a/MINE/cmds +++ b/MINE/cmds @@ -1,3 +1,6 @@ +pool: + + # RANDOMX: root@db-NucBox-EVO-X2:/home/db/Downloads/SRBMiner-Multi-2-9-6# ./SRBMiner-MULTI --algorithm randomx --pool xmr-us-east1.nanopool.org:14444 --wallet bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j --disable-gpu --cpu-threads 28 cd /home/db/Downloads/SRBMiner-Multi-2-9-6 @@ -11,6 +14,22 @@ export LD_LIBRARY_PATH=/opt/rocm-6.4.3/lib:$LD_LIBRARY_PATH ./SRBMiner-MULTI --algorithm ethash --pool ethash.mine.zergpool.com:9999 --wallet bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j --disable-cpu -o stratum+tcp://ethash.mine.zergpool.com:9999 -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC ./SRBMiner-MULTI --algorithm blake2s --pool auto.nicehash.com:3333 --wallet bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j --disable-cpu +# exp-eth +./SRBMiner-MULTI --algorithm ethash --pool ethash.mine.zergpool.com:9999 --wallet bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j --gpu-boost 3 +./SRBMiner-MULTI --algorithm ethash --pool ethash.mine.zergpool.com:9999 --wallet bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j --gpu-id 0 --gpu-intensity 24 --gpu-worksize 256 --gpu-threads 1 --gpu-boost 3 --disable-cpu + +#xmrig +cd /home/db/Downloads/xmrig-6.21.0 && ./xmrig -o stratum+tcp://randomx.mine.zergpool.com:4453 -a randomx -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC,mc=ZEPH -t 32 + +./xmrig --opencl --opencl-platform=1 --opencl-devices=0 -o stratum+tcp://randomx.mine.zergpool.com:4453 -a randomx -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC,mc=ZEPH -t 16 + # ok working kawpow + ./xmrig --opencl --opencl-platform=1 --opencl-devices=0 -o stratum+tcp://kawpow.mine.zergpool.com:3638 -a kawpow -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC --no-cpu + ./xmrig --opencl --opencl-platform=1 --opencl-devices=0 -o stratum+tcp://ethash.mine.zergpool.com:9999 -a ethash -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC --no-cpu + + ./xmrig --opencl --opencl-platform=1 --opencl-devices=0 -o stratum+tcp://rinhash.mine.zergpool.com:7148 -a rinhash -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC,mc=RIN --no-cpu + # RIN GPU local??? + ./xmrig --opencl --opencl-platform=1 --opencl-devices=0 -o stratum+tcp://localhost:3334 -a rinhash -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC,mc=RIN --no-cpu + # RIN @@ -19,7 +38,17 @@ export LD_LIBRARY_PATH=/opt/rocm-6.4.3/lib:$LD_LIBRARY_PATH cd /mnt/shared/DEV/repos/d-popov.com/mines/rin/miner/cpuminer-opt-rin cpuminer -a rinhash -o stratum+tcp://rinhash.mine.zergpool.com:7148 -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC,mc=RIN,ID=StrixHalo -t 32 -/mnt/shared/DEV/repos/d-popov.com/mines/rin/miner/cpuminer-opt-rin/cpuminer -o stratum+tcp://randomx.eu.zergpool.com:4453 -a randomx -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC,mc=ZEPH -t 32 +/mnt/shared/DEV/repos/d-popov.com/mines/rin/miner/cpuminer-opt-rin/cpuminer -o stratum+tcp://randomx.mine.zergpool.com:4453 -a randomx -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC,mc=ZEPH -t 32 +# EXPERM MINERS +# Install OpenCL development libraries +sudo apt install opencl-headers ocl-icd-opencl-dev + +# Download XMRig source and compile with OpenCL +git clone https://github.com/xmrig/xmrig.git +cd xmrig +mkdir build && cd build +cmake .. -DWITH_OPENCL=ON +make -j$(nproc) diff --git a/MINE/rin/mining_log.txt b/MINE/rin/mining_log.txt index 8310afb..4d4b51b 100644 --- a/MINE/rin/mining_log.txt +++ b/MINE/rin/mining_log.txt @@ -1,10 +1,9 @@ ================================================================================ RinCoin Mining Log ================================================================================ -Started: 2025-09-23 18:38:03 +Started: 2025-09-24 14:20:13 Target Address: rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q Stratum: 0.0.0.0:3334 RPC: 127.0.0.1:9556 ================================================================================ -[2025-09-23 18:38:03] ๐Ÿ’ฐ Wallet Balance: 25.00000000 RIN diff --git a/MINE/rin/stratum_proxy.py b/MINE/rin/stratum_proxy.py index 21b7952..5ce89b3 100644 --- a/MINE/rin/stratum_proxy.py +++ b/MINE/rin/stratum_proxy.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 """ +stratum_proxy.py RinCoin Stratum Proxy Server DEBUG RPC: we get node logs with 'docker logs --tail=200 rincoin-node' MINE: /mnt/shared/DEV/repos/d-popov.com/mines/rin/miner/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://localhost:3334 -u x -p x -t 32 @@ -807,11 +808,16 @@ class RinCoinStratumProxy: def handle_stratum_message(self, client, addr, message): """Handle incoming Stratum message from miner""" try: + # Debug: log raw message + print(f"[{addr}] Raw message: {repr(message)}") + data = json.loads(message.strip()) method = data.get("method") msg_id = data.get("id") params = data.get("params", []) + print(f"[{addr}] Parsed: method={method}, id={msg_id}, params={params}") + if method == "mining.subscribe": # Generate unique extranonce1 for this connection self.extranonce1_counter += 1 @@ -858,6 +864,43 @@ class RinCoinStratumProxy: timestamp = time.strftime("%Y-%m-%d %H:%M:%S") print(f"[{timestamp}] ๐Ÿ” [{addr}] Authorized as {username}") + elif method == "login": + # Handle xmrig's login method (JSON-RPC format with object params) + if isinstance(params, dict): + # xmrig format: {"login": "username", "pass": "password", "agent": "...", "algo": [...]} + username = params.get('login', 'anonymous') + password = params.get('pass', 'x') + agent = params.get('agent', 'unknown') + algorithms = params.get('algo', []) + else: + # Standard stratum format: ["username", "password"] + username = params[0] if params else "anonymous" + password = params[1] if len(params) > 1 else "x" + agent = "unknown" + algorithms = [] + + self.clients[addr]['username'] = username + self.clients[addr]['password'] = password + self.clients[addr]['agent'] = agent + self.clients[addr]['algorithms'] = algorithms + + # Check if rinhash is supported + rinhash_supported = any('rinhash' in algo.lower() or 'rin' in algo.lower() for algo in algorithms) + if not rinhash_supported: + print(f"[{addr}] Warning: rinhash not in supported algorithms: {algorithms}") + + self.send_stratum_response(client, msg_id, True) + timestamp = time.strftime("%Y-%m-%d %H:%M:%S") + print(f"[{timestamp}] ๐Ÿ” [{addr}] xmrig Login as {username} (agent: {agent})") + print(f"[{addr}] Supported algorithms: {algorithms}") + + # Send initial job after login + if self.current_job: + self.send_job_to_client(client, self.current_job) + else: + if self.get_block_template(): + self.send_job_to_client(client, self.current_job) + elif method == "mining.extranonce.subscribe": self.send_stratum_response(client, msg_id, True) @@ -893,10 +936,12 @@ class RinCoinStratumProxy: print(f"[{addr}] Unknown method: {method}") self.send_stratum_response(client, msg_id, None, "Unknown method") - except json.JSONDecodeError: + except json.JSONDecodeError as e: print(f"[{addr}] Invalid JSON: {message}") + print(f"[{addr}] JSON Error: {e}") except Exception as e: print(f"[{addr}] Message handling error: {e}") + print(f"[{addr}] Error type: {type(e).__name__}") def send_job_to_client(self, client, job): """Send mining job to specific client with proper stratum parameters""" @@ -1293,10 +1338,10 @@ if __name__ == "__main__": elif arg == "--submit-threshold" and i + 1 < len(sys.argv): try: submit_threshold = float(sys.argv[i + 1]) - if submit_threshold <= 0 or submit_threshold > 1: - print(f"โŒ Invalid threshold {submit_threshold}. Must be between 0 and 1 (0-100%)") + if submit_threshold <= 0: + print(f"โŒ Invalid threshold {submit_threshold}. Must be greater than 0") sys.exit(1) - print(f"๐Ÿงช DEBUG MODE: Will submit blocks at {submit_threshold*100:.1f}% of network difficulty") + print(f"๐Ÿงช DEBUG MODE: Will submit blocks at {submit_threshold:.1f}x network difficulty") except ValueError: print(f"โŒ Invalid threshold value: {sys.argv[i + 1]}") sys.exit(1) diff --git a/mining_log.txt b/mining_log.txt index e731e0b..28bfc32 100644 --- a/mining_log.txt +++ b/mining_log.txt @@ -1,10 +1,9 @@ ================================================================================ RinCoin Mining Log ================================================================================ -Started: 2025-09-23 11:27:51 +Started: 2025-09-24 14:14:54 Target Address: rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q Stratum: 0.0.0.0:3334 RPC: 127.0.0.1:9556 ================================================================================ -[2025-09-23 11:27:51] ๐Ÿ’ฐ Wallet Balance: 25.00000000 RIN From 6d08bbb3ae848d360b4c02a55fac6d3ea3030b7d Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Fri, 26 Sep 2025 10:50:18 +0300 Subject: [PATCH 26/30] notes --- MINE/rin/README.md | 5 +++++ MINE/rin/mining_log.txt | 2 +- MINE/rin/web_wallet.send.sh | 1 + dev/AI.md | 6 ++++++ 4 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 dev/AI.md diff --git a/MINE/rin/README.md b/MINE/rin/README.md index 5e8cd73..611d617 100644 --- a/MINE/rin/README.md +++ b/MINE/rin/README.md @@ -11,6 +11,11 @@ cd /mnt/shared/DEV/repos/d-popov.com/scripts # Run your miner ./cpuminer -a rinhash -o stratum+tcp://127.0.0.1:3333 -u user -p pass -t 28 + +#zergpool: +/mnt/shared/DEV/repos/d-popov.com/mines/rin/miner/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://rinhash.eu.mine.zergpool.com:7148 -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC,mc=RIN,m=solo + + ``` **Result**: 100% of block rewards go to your wallet diff --git a/MINE/rin/mining_log.txt b/MINE/rin/mining_log.txt index 4d4b51b..3150f55 100644 --- a/MINE/rin/mining_log.txt +++ b/MINE/rin/mining_log.txt @@ -1,7 +1,7 @@ ================================================================================ RinCoin Mining Log ================================================================================ -Started: 2025-09-24 14:20:13 +Started: 2025-09-24 14:21:00 Target Address: rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q Stratum: 0.0.0.0:3334 RPC: 127.0.0.1:9556 diff --git a/MINE/rin/web_wallet.send.sh b/MINE/rin/web_wallet.send.sh index e62cc36..75b8d9b 100644 --- a/MINE/rin/web_wallet.send.sh +++ b/MINE/rin/web_wallet.send.sh @@ -9,3 +9,4 @@ WEB_WALLET_DIR="${SCRIPT_DIR}/web_wallet" bash /mnt/shared/DEV/repos/d-popov.com/scripts/MINE/rin/send_rin.sh "$@" + \ No newline at end of file diff --git a/dev/AI.md b/dev/AI.md new file mode 100644 index 0000000..84ea2ae --- /dev/null +++ b/dev/AI.md @@ -0,0 +1,6 @@ +curl -fsSL https://cli.coderabbit.ai/install.sh | bash + 1. Restart your shell or run: source ~/.bashrc + 2. Run 'coderabbit auth login' to authenticate + + + From 6de346d0ebb3f867c11dc9de161669b4089c24f2 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Sat, 27 Sep 2025 15:23:04 +0300 Subject: [PATCH 27/30] more mining cmds - new pool --- MINE/rin/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MINE/rin/README.md b/MINE/rin/README.md index 611d617..b8d9cc6 100644 --- a/MINE/rin/README.md +++ b/MINE/rin/README.md @@ -15,6 +15,10 @@ cd /mnt/shared/DEV/repos/d-popov.com/scripts #zergpool: /mnt/shared/DEV/repos/d-popov.com/mines/rin/miner/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://rinhash.eu.mine.zergpool.com:7148 -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC,mc=RIN,m=solo +# rplant +/mnt/shared/DEV/repos/d-popov.com/mines/rin/miner/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://eu.rplant.xyz:17148 -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC,mc=RIN,m=solo +/mnt/shared/DEV/repos/d-popov.com/mines/rin/miner/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://eu.rplant.xyz:17148 -u rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q -p m=solo +cpuminer-sse2 -a rinhash -o stratum+tcps://eu.rplant.xyz:17148 -u wallet -p m=solo ``` **Result**: 100% of block rewards go to your wallet From 720c74db128caf0b62ec0b96cf3c7a0f119ac395 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Mon, 29 Sep 2025 21:50:56 +0300 Subject: [PATCH 28/30] rincoin cmds moved to mines repo --- MINE/rin/README.md | 6 + MINE/rin/dump_wallet.sh | 65 ----- MINE/rin/mining_log.txt | 10 +- MINE/rin/restore_wallet.sh | 63 ----- MINE/rin/send_rin.sh | 55 ---- MINE/rin/web_wallet.send.sh | 12 - MINE/rin/web_wallet/server.py | 150 ----------- MINE/rin/web_wallet/start_web_wallet.sh | 24 -- MINE/rin/web_wallet/static/index.html | 318 ------------------------ 9 files changed, 7 insertions(+), 696 deletions(-) delete mode 100644 MINE/rin/dump_wallet.sh delete mode 100644 MINE/rin/restore_wallet.sh delete mode 100644 MINE/rin/send_rin.sh delete mode 100644 MINE/rin/web_wallet.send.sh delete mode 100644 MINE/rin/web_wallet/server.py delete mode 100644 MINE/rin/web_wallet/start_web_wallet.sh delete mode 100644 MINE/rin/web_wallet/static/index.html diff --git a/MINE/rin/README.md b/MINE/rin/README.md index b8d9cc6..6233b9f 100644 --- a/MINE/rin/README.md +++ b/MINE/rin/README.md @@ -279,6 +279,12 @@ sudo docker exec rincoin-node rincoin-cli -datadir=/data -conf=/data/rincoin.con ### **Wallet Management** ```bash +# List all wallets +sudo docker exec rincoin-node rincoin-cli -datadir=/data -conf=/data/rincoin.conf listwallets + +# Load wallet +sudo docker exec rincoin-node rincoin-cli -datadir=/data -conf=/data/rincoin.conf loadwallet "main" + # Get new address sudo docker exec rincoin-node rincoin-cli -datadir=/data -conf=/data/rincoin.conf -rpcwallet=main getnewaddress diff --git a/MINE/rin/dump_wallet.sh b/MINE/rin/dump_wallet.sh deleted file mode 100644 index b8c1da5..0000000 --- a/MINE/rin/dump_wallet.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/bash - -# RinCoin Wallet Backup Script -# Dumps all private keys to a secure text file for backup. -# WARNING: This file contains sensitive private keys. Store it securely (encrypted, offline). -# Do not share or email it. Anyone with this file can spend your coins. - -set -euo pipefail - -# Configuration -CONTAINER="rincoin-node" -WALLET="main" -BACKUP_DIR="${HOME}/rin_wallet_backups" -TIMESTAMP=$(date +%Y%m%d_%H%M%S) -BACKUP_FILE="${BACKUP_DIR}/rin_wallet_backup_${TIMESTAMP}.txt" - -# Ensure backup directory exists -mkdir -p "$BACKUP_DIR" - -# Check if container is running -if ! sudo docker ps --format '{{.Names}}' | grep -q "^${CONTAINER}$"; then - echo "Error: ${CONTAINER} container is not running. Start it with 'sudo docker start ${CONTAINER}'." - exit 1 -fi - -# Ensure wallet is loaded -CLI_CMD=(sudo docker exec "$CONTAINER" rincoin-cli -datadir=/data -conf=/data/rincoin.conf -rpcwallet="$WALLET") -if ! "${CLI_CMD[@]//-rpcwallet=$WALLET/}" listwallets | grep -q '"main"'; then - echo "Wallet '${WALLET}' not loaded. Attempting to load..." - "${CLI_CMD[@]//-rpcwallet=$WALLET/}" loadwallet "$WALLET" >/dev/null 2>&1 || { - echo "Failed to load wallet. Ensure it exists." - exit 1 - } -fi - -echo "Dumping wallet to: $BACKUP_FILE" -echo "This may take a moment..." - -# Dump wallet -"${CLI_CMD[@]}" dumpwallet "$BACKUP_FILE" - -# Verify the file was created and has content -if [[ ! -f "$BACKUP_FILE" ]]; then - echo "Error: Backup file was not created." - exit 1 -fi - -LINE_COUNT=$(wc -l < "$BACKUP_FILE") -if [[ $LINE_COUNT -lt 10 ]]; then - echo "Warning: Backup file seems too small (${LINE_COUNT} lines). Check for errors." - exit 1 -fi - -echo "โœ… Wallet successfully backed up to: $BACKUP_FILE" -echo "" -echo "๐Ÿ” SECURITY REMINDERS:" -echo " - This file contains private keys for ALL addresses in the wallet." -echo " - Encrypt it immediately: gpg -c $BACKUP_FILE" -echo " - Store on encrypted media (e.g., USB drive in safe)." -echo " - Delete the unencrypted file after encryption." -echo " - Test restoration on a testnet node before relying on it." -echo "" -echo "File size: $(du -h "$BACKUP_FILE" | cut -f1)" -echo "Lines: $LINE_COUNT" - diff --git a/MINE/rin/mining_log.txt b/MINE/rin/mining_log.txt index 3150f55..f0c0d3c 100644 --- a/MINE/rin/mining_log.txt +++ b/MINE/rin/mining_log.txt @@ -1,9 +1 @@ -================================================================================ -RinCoin Mining Log -================================================================================ -Started: 2025-09-24 14:21:00 -Target Address: rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q -Stratum: 0.0.0.0:3334 -RPC: 127.0.0.1:9556 -================================================================================ - +[2025-09-29 20:11:03] ๐Ÿ’ฐ Wallet Balance: 0.00000000 RIN diff --git a/MINE/rin/restore_wallet.sh b/MINE/rin/restore_wallet.sh deleted file mode 100644 index 26cc982..0000000 --- a/MINE/rin/restore_wallet.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/bash - -# RinCoin Wallet Restoration Script -# Restores a wallet from a dump file on a new RinCoin node. -# Prerequisites: New RinCoin node running in Docker, backup file available. - -set -euo pipefail - -if [[ $# -ne 1 ]]; then - echo "Usage: $0 " - echo "Example: $0 ~/rin_wallet_backups/rin_wallet_backup_20230923.txt" - exit 1 -fi - -BACKUP_FILE="$1" -CONTAINER="rincoin-node" -WALLET_NAME="main" # Will be renamed to avoid conflicts -NEW_WALLET_NAME="restored_main" - -# Verify backup file exists -if [[ ! -f "$BACKUP_FILE" ]]; then - echo "Error: Backup file '$BACKUP_FILE' not found." - exit 1 -fi - -# Check if container is running -if ! sudo docker ps --format '{{.Names}}' | grep -q "^${CONTAINER}$"; then - echo "Error: ${CONTAINER} container is not running. Start it with 'sudo docker start ${CONTAINER}'." - exit 1 -fi - -echo "Stopping RinCoin node for safe restoration..." -sudo docker stop "$CONTAINER" - -echo "Copying backup file into container..." -sudo docker cp "$BACKUP_FILE" "$CONTAINER:/tmp/wallet_backup.txt" - -echo "Starting RinCoin node..." -sudo docker start "$CONTAINER" - -# Wait for RPC to be ready -echo "Waiting for node to fully start..." -sleep 10 - -echo "Creating new wallet and importing keys..." -# Create a new wallet to avoid conflicts -sudo docker exec "$CONTAINER" rincoin-cli -datadir=/data -conf=/data/rincoin.conf createwallet "$NEW_WALLET_NAME" - -# Import the dump file -sudo docker exec "$CONTAINER" rincoin-cli -datadir=/data -conf=/data/rincoin.conf -rpcwallet="$NEW_WALLET_NAME" importwallet /tmp/wallet_backup.txt - -# Clean up -sudo docker exec "$CONTAINER" rm /tmp/wallet_backup.txt - -echo "โœ… Wallet restored successfully!" -echo "New wallet name: $NEW_WALLET_NAME" -echo "" -echo "Verify with:" -echo "sudo docker exec $CONTAINER rincoin-cli -datadir=/data -conf=/data/rincoin.conf -rpcwallet=$NEW_WALLET_NAME getbalance" -echo "" -echo "To use this wallet, update scripts to use -rpcwallet=$NEW_WALLET_NAME" -echo "Or rename it back: unloadwallet $NEW_WALLET_NAME && loadwallet $WALLET_NAME" - diff --git a/MINE/rin/send_rin.sh b/MINE/rin/send_rin.sh deleted file mode 100644 index c175945..0000000 --- a/MINE/rin/send_rin.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -if [[ ${1-} == "" ]]; then - echo "Usage: $0 [amount]" - echo "Amount defaults to 1 RIN if not specified." - exit 1 -fi - -ADDRESS="$1" -AMOUNT="${2-1}" -WALLET="main" -CONTAINER="rincoin-node" -CLI_CMD=(sudo docker exec "$CONTAINER" rincoin-cli -datadir=/data -conf=/data/rincoin.conf -rpcwallet="$WALLET") - -echo "Checking RinCoin node container..." -if ! sudo docker ps --format '{{.Names}}' | grep -q "^${CONTAINER}$"; then - echo "Error: container ${CONTAINER} is not running. Start it with 'sudo docker start ${CONTAINER}'." - exit 1 -fi - -echo "Ensuring wallet '${WALLET}' is loaded..." -if ! "${CLI_CMD[@]//-rpcwallet=$WALLET/}" listwallets | grep -q '"main"'; then - echo "Wallet ${WALLET} not loaded, attempting to load..." - "${CLI_CMD[@]//-rpcwallet=$WALLET/}" loadwallet "$WALLET" >/dev/null -fi - -echo "Checking available balance..." -BALANCE_RAW=$("${CLI_CMD[@]}" getbalance) -BALANCE=$(printf '%.8f' "$BALANCE_RAW") - -if [[ $(bc <<< "$BALANCE_RAW < $AMOUNT") -eq 1 ]]; then - echo "Error: insufficient balance. Available ${BALANCE} RIN, but ${AMOUNT} RIN requested." - exit 1 -fi - -echo "Broadcasting transaction..." -set +e -TX_OUTPUT=$("${CLI_CMD[@]}" sendtoaddress "$ADDRESS" "$AMOUNT" '' '' false true) -STATUS=$? -set -e - -if [[ $STATUS -ne 0 ]]; then - echo "Failed to send transaction." - if [[ $STATUS -eq 4 ]]; then - echo "Wallet appears to be locked. Unlock it with 'sudo docker exec ${CONTAINER} rincoin-cli -datadir=/data -conf=/data/rincoin.conf -rpcwallet=${WALLET} walletpassphrase 600 true' and rerun." - fi - exit $STATUS -fi - -echo "Transaction broadcast. TXID: ${TX_OUTPUT}" -echo "Verify with: sudo docker exec ${CONTAINER} rincoin-cli -datadir=/data -conf=/data/rincoin.conf gettransaction ${TX_OUTPUT}" - - diff --git a/MINE/rin/web_wallet.send.sh b/MINE/rin/web_wallet.send.sh deleted file mode 100644 index 75b8d9b..0000000 --- a/MINE/rin/web_wallet.send.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -SCRIPT_DIR=$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd) - -WEB_WALLET_DIR="${SCRIPT_DIR}/web_wallet" - -bash /mnt/shared/DEV/repos/d-popov.com/scripts/MINE/rin/send_rin.sh "$@" - - - \ No newline at end of file diff --git a/MINE/rin/web_wallet/server.py b/MINE/rin/web_wallet/server.py deleted file mode 100644 index b3f176c..0000000 --- a/MINE/rin/web_wallet/server.py +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env python3 - -from __future__ import annotations - -import json -import os -import secrets -from functools import wraps - -from flask import Flask, jsonify, request, send_from_directory - -try: - from bitcoinrpc.authproxy import AuthServiceProxy -except ImportError: # pragma: no cover - raise SystemExit("Missing python-bitcoinrpc. Install with: pip install python-bitcoinrpc") - - -RIN_RPC_HOST = os.environ.get("RIN_RPC_HOST", "127.0.0.1") -RIN_RPC_PORT = int(os.environ.get("RIN_RPC_PORT", "9556")) -RIN_RPC_USER = os.environ.get("RIN_RPC_USER", "rinrpc") -RIN_RPC_PASSWORD = os.environ.get("RIN_RPC_PASSWORD", "745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90") -RIN_WALLET_NAME = os.environ.get("RIN_WALLET_NAME", "main") - -API_TOKEN = os.environ.get("RIN_WEB_WALLET_TOKEN") -if not API_TOKEN: - API_TOKEN = secrets.token_urlsafe(32) - print("[web-wallet] No RIN_WEB_WALLET_TOKEN provided. Generated one for this session.") - print(f"[web-wallet] API token: {API_TOKEN}") - - -def create_rpc_client() -> AuthServiceProxy: - url = f"http://{RIN_RPC_USER}:{RIN_RPC_PASSWORD}@{RIN_RPC_HOST}:{RIN_RPC_PORT}/wallet/{RIN_WALLET_NAME}" - return AuthServiceProxy(url, timeout=15) - - -def require_token(view_func): - @wraps(view_func) - def wrapper(*args, **kwargs): - header = request.headers.get("Authorization", "") - if not header.startswith("Bearer "): - return jsonify({"error": "missing_token"}), 401 - token = header.split(" ", 1)[1] - if token != API_TOKEN: - return jsonify({"error": "invalid_token"}), 403 - return view_func(*args, **kwargs) - - return wrapper - - -app = Flask(__name__, static_folder="static", static_url_path="") - - -def rpc_call(method: str, *params): - try: - rpc = create_rpc_client() - return rpc.__getattr__(method)(*params) - except Exception as exc: # noqa: BLE001 - raise RuntimeError(str(exc)) from exc - - -@app.route("/api/session", methods=["GET"]) -def session_info(): - return jsonify({ - "wallet": RIN_WALLET_NAME, - "host": RIN_RPC_HOST, - }) - - -@app.route("/api/address", methods=["POST"]) -@require_token -def create_address(): - data = request.get_json(silent=True) or {} - label = data.get("label", "") - try: - address = rpc_call("getnewaddress", label) - return jsonify({"address": address}) - except RuntimeError as exc: - return jsonify({"error": str(exc)}), 500 - - -@app.route("/api/balance", methods=["GET"]) -@require_token -def get_balance(): - try: - info = rpc_call("getwalletinfo") - confirmed = info.get("balance", 0) - unconfirmed = info.get("unconfirmed_balance", 0) - immature = info.get("immature_balance", 0) - total = confirmed + unconfirmed + immature - return jsonify({ - "confirmed": confirmed, - "unconfirmed": unconfirmed, - "immature": immature, - "total": total, - }) - except RuntimeError as exc: - return jsonify({"error": str(exc)}), 500 - - -@app.route("/api/send", methods=["POST"]) -@require_token -def send(): - payload = request.get_json(force=True) - address = payload.get("address") - amount = payload.get("amount") - subtract_fee = bool(payload.get("subtractFee", True)) - - if not address or not isinstance(amount, (int, float)): - return jsonify({"error": "invalid_request"}), 400 - - if amount <= 0: - return jsonify({"error": "amount_must_be_positive"}), 400 - - try: - txid = rpc_call("sendtoaddress", address, float(amount), "", "", subtract_fee) - return jsonify({"txid": txid}) - except RuntimeError as exc: - status = 400 if "Invalid RinCoin address" in str(exc) else 500 - return jsonify({"error": str(exc)}), status - - -@app.route("/api/transactions", methods=["GET"]) -@require_token -def list_transactions(): - count = int(request.args.get("count", 10)) - try: - txs = rpc_call("listtransactions", "*", count, 0, True) - return jsonify({"transactions": txs}) - except RuntimeError as exc: - return jsonify({"error": str(exc)}), 500 - - -@app.route("/") -def root(): - return send_from_directory(app.static_folder, "index.html") - - -@app.route("/") -def static_proxy(path): - return send_from_directory(app.static_folder, path) - - -def main(): - port = int(os.environ.get("RIN_WEB_WALLET_PORT", "8787")) - app.run(host="127.0.0.1", port=port, debug=False) - - -if __name__ == "__main__": - main() - diff --git a/MINE/rin/web_wallet/start_web_wallet.sh b/MINE/rin/web_wallet/start_web_wallet.sh deleted file mode 100644 index 059658a..0000000 --- a/MINE/rin/web_wallet/start_web_wallet.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -SCRIPT_DIR=$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd) -CONTAINER="rincoin-node" - -if ! sudo docker ps --format '{{.Names}}' | grep -q "^${CONTAINER}$"; then - echo "Error: ${CONTAINER} container is not running. Start it with 'sudo docker start ${CONTAINER}'." - exit 1 -fi - -if ! command -v flask >/dev/null 2>&1; then - echo "Missing Flask. Install with 'pip install flask python-bitcoinrpc'." - exit 1 -fi - -echo "Starting RinCoin web wallet on http://127.0.0.1:8787" -export FLASK_APP="${SCRIPT_DIR}/server.py" -export FLASK_ENV=production -export PYTHONPATH="${SCRIPT_DIR}" -flask run --host 127.0.0.1 --port 8787 - - diff --git a/MINE/rin/web_wallet/static/index.html b/MINE/rin/web_wallet/static/index.html deleted file mode 100644 index 3c63934..0000000 --- a/MINE/rin/web_wallet/static/index.html +++ /dev/null @@ -1,318 +0,0 @@ - - - - - - RinCoin Web Wallet - - - - -
    -

    RinCoin Wallet

    - -
    -
    Confirmed Balance
    -
    โ€”
    -
    Total: โ€”
    -
    - -
    -

    Send RinCoin

    - - - - - - -
    - - - -
    -

    Recent Activity

    -
      -
      -
      - - - - - From 6f13d87f6cecaaf16edd16c917d334acecf165ea Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 30 Sep 2025 00:07:07 +0300 Subject: [PATCH 29/30] code moved to mines --- MINE/rin/README.md | 2 +- MINE/rin/kill_stratum_proxy.sh | 66 +- MINE/rin/mining_log.txt | 1 + MINE/rin/pool_web_interface.py | 946 +++++----- MINE/rin/solo_mining.sh | 74 +- MINE/rin/solo_mining_core.sh | 292 +-- MINE/rin/solo_mining_remote.sh | 132 +- MINE/rin/solo_mining_rpc.sh | 126 +- MINE/rin/solo_mining_zergpool.sh | 126 +- MINE/rin/start_mining_pool.sh | 146 +- MINE/rin/start_stratum_proxy.sh | 116 +- MINE/rin/start_web_wallet.sh | 16 +- MINE/rin/stratum_pool.py | 1016 +++++------ MINE/rin/stratum_proxy.py | 2248 ++++++++++++------------ MINE/rin/test_reward_redistribution.sh | 120 +- 15 files changed, 2714 insertions(+), 2713 deletions(-) diff --git a/MINE/rin/README.md b/MINE/rin/README.md index 6233b9f..e32da9a 100644 --- a/MINE/rin/README.md +++ b/MINE/rin/README.md @@ -19,7 +19,7 @@ cd /mnt/shared/DEV/repos/d-popov.com/scripts /mnt/shared/DEV/repos/d-popov.com/mines/rin/miner/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://eu.rplant.xyz:17148 -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC,mc=RIN,m=solo /mnt/shared/DEV/repos/d-popov.com/mines/rin/miner/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://eu.rplant.xyz:17148 -u rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q -p m=solo cpuminer-sse2 -a rinhash -o stratum+tcps://eu.rplant.xyz:17148 -u wallet -p m=solo - +??? rin1qvj0yyt9phvled9kxflju3p687a4s7kareglpk5 ??? ``` **Result**: 100% of block rewards go to your wallet diff --git a/MINE/rin/kill_stratum_proxy.sh b/MINE/rin/kill_stratum_proxy.sh index 136f5c6..cfba4f3 100644 --- a/MINE/rin/kill_stratum_proxy.sh +++ b/MINE/rin/kill_stratum_proxy.sh @@ -1,40 +1,40 @@ -#!/bin/bash +# #!/bin/bash -# Kill RinCoin Stratum Proxy processes +# # Kill RinCoin Stratum Proxy processes -echo "=== Killing RinCoin Stratum Proxy ===" -echo "" +# echo "=== Killing RinCoin Stratum Proxy ===" +# echo "" -# Find and kill Python processes running stratum_proxy.py -PIDS=$(ps aux | grep "stratum_proxy.py" | grep -v grep | awk '{print $2}') +# # Find and kill Python processes running stratum_proxy.py +# PIDS=$(ps aux | grep "stratum_proxy.py" | grep -v grep | awk '{print $2}') -if [ -n "$PIDS" ]; then - echo "Found Stratum Proxy processes: $PIDS" - echo "Killing processes..." - for pid in $PIDS; do - kill -9 "$pid" 2>/dev/null && echo "Killed PID: $pid" || echo "Failed to kill PID: $pid" - done -else - echo "No Stratum Proxy processes found" -fi +# if [ -n "$PIDS" ]; then +# echo "Found Stratum Proxy processes: $PIDS" +# echo "Killing processes..." +# for pid in $PIDS; do +# kill -9 "$pid" 2>/dev/null && echo "Killed PID: $pid" || echo "Failed to kill PID: $pid" +# done +# else +# echo "No Stratum Proxy processes found" +# fi -# Also kill any process using port 3333 -echo "" -echo "Checking port 3333..." -PORT_PIDS=$(sudo lsof -ti:3333 2>/dev/null) +# # Also kill any process using port 3333 +# echo "" +# echo "Checking port 3333..." +# PORT_PIDS=$(sudo lsof -ti:3333 2>/dev/null) -if [ -n "$PORT_PIDS" ]; then - echo "Found processes using port 3333: $PORT_PIDS" - echo "Killing processes..." - for pid in $PORT_PIDS; do - sudo kill -9 "$pid" 2>/dev/null && echo "Killed PID: $pid" || echo "Failed to kill PID: $pid" - done -else - echo "No processes using port 3333" -fi +# if [ -n "$PORT_PIDS" ]; then +# echo "Found processes using port 3333: $PORT_PIDS" +# echo "Killing processes..." +# for pid in $PORT_PIDS; do +# sudo kill -9 "$pid" 2>/dev/null && echo "Killed PID: $pid" || echo "Failed to kill PID: $pid" +# done +# else +# echo "No processes using port 3333" +# fi -echo "" -echo "โœ… Cleanup complete!" -echo "" -echo "Port 3333 status:" -netstat -tln | grep ":3333 " || echo "Port 3333 is free" +# echo "" +# echo "โœ… Cleanup complete!" +# echo "" +# echo "Port 3333 status:" +# netstat -tln | grep ":3333 " || echo "Port 3333 is free" diff --git a/MINE/rin/mining_log.txt b/MINE/rin/mining_log.txt index f0c0d3c..0d4d460 100644 --- a/MINE/rin/mining_log.txt +++ b/MINE/rin/mining_log.txt @@ -1 +1,2 @@ [2025-09-29 20:11:03] ๐Ÿ’ฐ Wallet Balance: 0.00000000 RIN +[2025-09-29 22:31:04] ๐Ÿ’ฐ Wallet Balance: 0.00000000 RIN diff --git a/MINE/rin/pool_web_interface.py b/MINE/rin/pool_web_interface.py index 80ca03b..1577778 100644 --- a/MINE/rin/pool_web_interface.py +++ b/MINE/rin/pool_web_interface.py @@ -1,529 +1,529 @@ -#!/usr/bin/env python3 -""" -RinCoin Mining Pool Web Interface -Provides web dashboard for pool statistics and miner management -""" +# #!/usr/bin/env python3 +# """ +# RinCoin Mining Pool Web Interface +# Provides web dashboard for pool statistics and miner management +# """ -import json -import sqlite3 -import requests -from datetime import datetime, timedelta -from http.server import HTTPServer, BaseHTTPRequestHandler -import threading -import time -from requests.auth import HTTPBasicAuth +# import json +# import sqlite3 +# import requests +# from datetime import datetime, timedelta +# from http.server import HTTPServer, BaseHTTPRequestHandler +# import threading +# import time +# from requests.auth import HTTPBasicAuth -class PoolWebInterface: - def __init__(self, pool_db, host='0.0.0.0', port=8080, rpc_host='127.0.0.1', rpc_port=9556, - rpc_user='rinrpc', rpc_password='745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90'): - self.pool_db = pool_db - self.host = host - self.port = port - self.rpc_host = rpc_host - self.rpc_port = rpc_port - self.rpc_user = rpc_user - self.rpc_password = rpc_password - self.chart_time_window = 3600 # 1 hour default, adjustable +# class PoolWebInterface: +# def __init__(self, pool_db, host='0.0.0.0', port=8080, rpc_host='127.0.0.1', rpc_port=9556, +# rpc_user='rinrpc', rpc_password='745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90'): +# self.pool_db = pool_db +# self.host = host +# self.port = port +# self.rpc_host = rpc_host +# self.rpc_port = rpc_port +# self.rpc_user = rpc_user +# self.rpc_password = rpc_password +# 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 set_chart_time_window(self, seconds): +# """Set the chart time window""" +# self.chart_time_window = seconds - def format_hashrate(self, hashrate): - """Format hashrate in human readable format""" - if hashrate >= 1e12: - return f"{hashrate/1e12:.2f} TH/s" - elif hashrate >= 1e9: - return f"{hashrate/1e9:.2f} GH/s" - elif hashrate >= 1e6: - return f"{hashrate/1e6:.2f} MH/s" - elif hashrate >= 1e3: - return f"{hashrate/1e3:.2f} KH/s" - elif hashrate >= 0.01: - return f"{hashrate:.2f} H/s" - elif hashrate > 0: - return f"{hashrate*1000:.2f} mH/s" - else: - return "0.00 H/s" +# def format_hashrate(self, hashrate): +# """Format hashrate in human readable format""" +# if hashrate >= 1e12: +# return f"{hashrate/1e12:.2f} TH/s" +# elif hashrate >= 1e9: +# return f"{hashrate/1e9:.2f} GH/s" +# elif hashrate >= 1e6: +# return f"{hashrate/1e6:.2f} MH/s" +# elif hashrate >= 1e3: +# return f"{hashrate/1e3:.2f} KH/s" +# elif hashrate >= 0.01: +# return f"{hashrate:.2f} H/s" +# elif hashrate > 0: +# return f"{hashrate*1000:.2f} mH/s" +# else: +# return "0.00 H/s" - def get_pool_balance(self): - """Get pool wallet balance via RPC""" - try: - url = f"http://{self.rpc_host}:{self.rpc_port}/" - headers = {'content-type': 'text/plain'} - auth = HTTPBasicAuth(self.rpc_user, self.rpc_password) +# def get_pool_balance(self): +# """Get pool wallet balance via RPC""" +# try: +# url = f"http://{self.rpc_host}:{self.rpc_port}/" +# headers = {'content-type': 'text/plain'} +# auth = HTTPBasicAuth(self.rpc_user, self.rpc_password) - payload = { - "jsonrpc": "1.0", - "id": "pool_balance", - "method": "getbalance", - "params": [] - } +# payload = { +# "jsonrpc": "1.0", +# "id": "pool_balance", +# "method": "getbalance", +# "params": [] +# } - response = requests.post(url, json=payload, headers=headers, auth=auth, timeout=10) +# response = requests.post(url, json=payload, headers=headers, auth=auth, timeout=10) - if response.status_code == 200: - result = response.json() - if 'error' in result and result['error'] is not None: - print(f"RPC Error getting balance: {result['error']}") - return 0.0 - balance = result.get('result', 0) - return float(balance) / 100000000 # Convert from satoshis to RIN - else: - print(f"HTTP Error getting balance: {response.status_code}") - return 0.0 +# if response.status_code == 200: +# result = response.json() +# if 'error' in result and result['error'] is not None: +# print(f"RPC Error getting balance: {result['error']}") +# return 0.0 +# balance = result.get('result', 0) +# return float(balance) / 100000000 # Convert from satoshis to RIN +# else: +# print(f"HTTP Error getting balance: {response.status_code}") +# return 0.0 - except Exception as e: - print(f"Error getting pool balance: {e}") - return 0.0 +# except Exception as e: +# print(f"Error getting pool balance: {e}") +# return 0.0 - def get_pool_stats(self): - """Get current pool statistics""" - try: - cursor = self.pool_db.cursor() +# def get_pool_stats(self): +# """Get current pool statistics""" +# try: +# cursor = self.pool_db.cursor() - # Total miners (ever registered) - cursor.execute('SELECT COUNT(DISTINCT id) FROM miners') - total_miners = cursor.fetchone()[0] +# # Total miners (ever registered) +# cursor.execute('SELECT COUNT(DISTINCT id) FROM miners') +# total_miners = cursor.fetchone()[0] - # Active miners (last 5 minutes) - cursor.execute(''' - SELECT COUNT(DISTINCT m.id) FROM miners m - JOIN shares s ON m.id = s.miner_id - WHERE s.submitted > datetime('now', '-5 minutes') - ''') - active_miners = cursor.fetchone()[0] +# # Active miners (last 5 minutes) +# cursor.execute(''' +# SELECT COUNT(DISTINCT m.id) FROM miners m +# JOIN shares s ON m.id = s.miner_id +# WHERE s.submitted > datetime('now', '-5 minutes') +# ''') +# active_miners = cursor.fetchone()[0] - # Total shares (last 24 hours) - cursor.execute(''' - SELECT COUNT(*) FROM shares - WHERE submitted > datetime('now', '-24 hours') - ''') - total_shares_24h = cursor.fetchone()[0] +# # Total shares (last 24 hours) +# cursor.execute(''' +# SELECT COUNT(*) FROM shares +# WHERE submitted > datetime('now', '-24 hours') +# ''') +# total_shares_24h = cursor.fetchone()[0] - # 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 +# # 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(''' - SELECT SUM(difficulty), COUNT(*) FROM shares - WHERE submitted > datetime('now', '-5 minutes') - ''') - rd = cursor.fetchone() - recent_difficulty = rd[0] if rd and rd[0] else 0 - recent_share_count = rd[1] if rd and rd[1] else 0 +# # Debug stats +# cursor.execute(''' +# SELECT SUM(difficulty), COUNT(*) FROM shares +# WHERE submitted > datetime('now', '-5 minutes') +# ''') +# rd = cursor.fetchone() +# recent_difficulty = rd[0] if rd and rd[0] else 0 +# recent_share_count = rd[1] if rd and rd[1] else 0 - # Get historical hashrate data for chart - 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() +# # Get historical hashrate data for chart +# 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() - # Calculate individual miner hashrates - cursor.execute(''' - SELECT - 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 miner hashrates +# cursor.execute(''' +# SELECT +# 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)) +# # 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 - cursor.execute('SELECT COUNT(*) FROM blocks') - total_blocks = cursor.fetchone()[0] +# # Total blocks found +# cursor.execute('SELECT COUNT(*) FROM blocks') +# total_blocks = cursor.fetchone()[0] - # Recent blocks - cursor.execute(''' - SELECT block_hash, height, reward, found_at - FROM blocks - ORDER BY found_at DESC - LIMIT 10 - ''') - recent_blocks = cursor.fetchall() +# # Recent blocks +# cursor.execute(''' +# SELECT block_hash, height, reward, found_at +# FROM blocks +# ORDER BY found_at DESC +# LIMIT 10 +# ''') +# recent_blocks = cursor.fetchall() - # Top miners (last 24 hours) - show all miners, even without shares - cursor.execute(''' - SELECT m.user, m.worker, - COALESCE(COUNT(s.id), 0) as shares, - m.last_share, - m.created - FROM miners m - LEFT JOIN shares s ON m.id = s.miner_id - AND s.submitted > datetime('now', '-24 hours') - GROUP BY m.id, m.user, m.worker - ORDER BY shares DESC, m.created DESC - LIMIT 20 - ''') - top_miners = cursor.fetchall() +# # Top miners (last 24 hours) - show all miners, even without shares +# cursor.execute(''' +# SELECT m.user, m.worker, +# COALESCE(COUNT(s.id), 0) as shares, +# m.last_share, +# m.created +# FROM miners m +# LEFT JOIN shares s ON m.id = s.miner_id +# AND s.submitted > datetime('now', '-24 hours') +# GROUP BY m.id, m.user, m.worker +# ORDER BY shares DESC, m.created DESC +# LIMIT 20 +# ''') +# top_miners = cursor.fetchall() - # All active miners (for better visibility) - cursor.execute(''' - SELECT user, worker, created, last_share - FROM miners - ORDER BY created DESC - LIMIT 10 - ''') - all_miners = cursor.fetchall() +# # All active miners (for better visibility) +# cursor.execute(''' +# SELECT user, worker, created, last_share +# FROM miners +# ORDER BY created DESC +# LIMIT 10 +# ''') +# all_miners = cursor.fetchall() - # Get pool balance - pool_balance = self.get_pool_balance() +# # Get pool balance +# pool_balance = self.get_pool_balance() - return { - 'total_miners': total_miners, - 'active_miners': active_miners, - 'total_shares_24h': total_shares_24h, - 'hashrate': hashrate, - 'total_blocks': total_blocks, - 'recent_blocks': recent_blocks, - 'top_miners': top_miners, - 'all_miners': all_miners, - 'miner_hashrates': miner_hashrates, - 'historical_data': historical_data, - 'pool_balance': pool_balance, - 'debug': { - 'recent_difficulty': recent_difficulty, - 'recent_share_count': recent_share_count, - 'total_shares_24h': total_shares_24h - } - } - except Exception as e: - print(f"Error getting pool stats: {e}") - return {} +# return { +# 'total_miners': total_miners, +# 'active_miners': active_miners, +# 'total_shares_24h': total_shares_24h, +# 'hashrate': hashrate, +# 'total_blocks': total_blocks, +# 'recent_blocks': recent_blocks, +# 'top_miners': top_miners, +# 'all_miners': all_miners, +# 'miner_hashrates': miner_hashrates, +# 'historical_data': historical_data, +# 'pool_balance': pool_balance, +# 'debug': { +# 'recent_difficulty': recent_difficulty, +# 'recent_share_count': recent_share_count, +# 'total_shares_24h': total_shares_24h +# } +# } +# except Exception as e: +# print(f"Error getting pool stats: {e}") +# return {} - def generate_html(self, stats): - """Generate HTML dashboard""" - html = f""" - - - - RinCoin Mining Pool - - - - - -
      -
      -

      ๐ŸŠโ€โ™‚๏ธ RinCoin Mining Pool

      -

      Distribute block rewards among multiple miners

      -
      +# def generate_html(self, stats): +# """Generate HTML dashboard""" +# html = f""" +# +# +# +# RinCoin Mining Pool +# +# +# +# +# +#
      +#
      +#

      ๐ŸŠโ€โ™‚๏ธ RinCoin Mining Pool

      +#

      Distribute block rewards among multiple miners

      +#
      - +# -
      -
      -
      {stats.get('total_miners', 0)}
      -
      Total Miners
      -
      -
      -
      {stats.get('active_miners', 0)}
      -
      Active Miners
      -
      -
      -
      {self.format_hashrate(stats.get('hashrate', 0))}
      -
      Hashrate
      -
      -
      -
      {stats.get('total_blocks', 0)}
      -
      Blocks Found
      -
      -
      -
      {stats.get('pool_balance', 0):.2f}
      -
      Pool Balance (RIN)
      -
      -
      +#
      +#
      +#
      {stats.get('total_miners', 0)}
      +#
      Total Miners
      +#
      +#
      +#
      {stats.get('active_miners', 0)}
      +#
      Active Miners
      +#
      +#
      +#
      {self.format_hashrate(stats.get('hashrate', 0))}
      +#
      Hashrate
      +#
      +#
      +#
      {stats.get('total_blocks', 0)}
      +#
      Blocks Found
      +#
      +#
      +#
      {stats.get('pool_balance', 0):.2f}
      +#
      Pool Balance (RIN)
      +#
      +#
      -
      -

      ๐Ÿ“Š Pool Statistics

      -

      24h Shares: {stats.get('total_shares_24h', 0):,}

      -

      Pool Fee: 1%

      -

      Pool Balance: {stats.get('pool_balance', 0):.8f} RIN

      -

      Connection String: stratum+tcp://YOUR_IP:3333

      +#
      +#

      ๐Ÿ“Š Pool Statistics

      +#

      24h Shares: {stats.get('total_shares_24h', 0):,}

      +#

      Pool Fee: 1%

      +#

      Pool Balance: {stats.get('pool_balance', 0):.8f} RIN

      +#

      Connection String: stratum+tcp://YOUR_IP:3333

      - -
      - ๐Ÿ” Debug Info -

      Recent Difficulty (5min): {stats.get('debug', {}).get('recent_difficulty', 0):.6f}

      -

      Recent Share Count (5min): {stats.get('debug', {}).get('recent_share_count', 0)}

      -

      Total Shares (24h): {stats.get('debug', {}).get('total_shares_24h', 0):,}

      -

      Active Miners: {stats.get('active_miners', 0)} (last 5 minutes)

      -

      Total Miners: {stats.get('total_miners', 0)} (ever registered)

      -
      -
      +# +#
      +# ๐Ÿ” Debug Info +#

      Recent Difficulty (5min): {stats.get('debug', {}).get('recent_difficulty', 0):.6f}

      +#

      Recent Share Count (5min): {stats.get('debug', {}).get('recent_share_count', 0)}

      +#

      Total Shares (24h): {stats.get('debug', {}).get('total_shares_24h', 0):,}

      +#

      Active Miners: {stats.get('active_miners', 0)} (last 5 minutes)

      +#

      Total Miners: {stats.get('total_miners', 0)} (ever registered)

      +#
      +#
      -
      -

      ๐Ÿ“ˆ Hashrate Chart

      -
      - - -
      -
      - -
      -
      +#
      +#

      ๐Ÿ“ˆ Hashrate Chart

      +#
      +# +# +#
      +#
      +# +#
      +#
      -
      -

      ๐Ÿ‘ฅ Connected Miners

      - - - - - - - - """ +#
      +#

      ๐Ÿ‘ฅ Connected Miners

      +#
      UserWorkerConnectedLast Share
      +# +# +# +# +# +# +# """ - for miner in stats.get('all_miners', []): - user, worker, created, last_share = miner - html += f""" - - - - - - - """ +# for miner in stats.get('all_miners', []): +# user, worker, created, last_share = miner +# html += f""" +# +# +# +# +# +# +# """ - if not stats.get('all_miners', []): - html += """ - - - - """ +# if not stats.get('all_miners', []): +# html += """ +# +# +# +# """ - html += """ -
      UserWorkerConnectedLast Share
      {user}{worker}{created}{last_share or 'Never'}
      {user}{worker}{created}{last_share or 'Never'}
      No miners connected
      No miners connected
      -
      +# html += """ +# +#
      -
      -

      ๐Ÿ† Top Miners (24h Shares)

      - - - - - - - - - """ +#
      +#

      ๐Ÿ† Top Miners (24h Shares)

      +#
      UserWorkerSharesHashrateLast Share
      +# +# +# +# +# +# +# +# """ - for miner in stats.get('miner_hashrates', []): - user, worker, shares, hashrate, last_share = miner - html += f""" - - - - - - - - """ +# for miner in stats.get('miner_hashrates', []): +# user, worker, shares, hashrate, last_share = miner +# html += f""" +# +# +# +# +# +# +# +# """ - if not stats.get('top_miners', []): - html += """ - - - - """ +# if not stats.get('top_miners', []): +# html += """ +# +# +# +# """ - html += """ -
      UserWorkerSharesHashrateLast Share
      {user}{worker}{shares:,}{self.format_hashrate(hashrate)}{last_share or 'Never'}
      {user}{worker}{shares:,}{self.format_hashrate(hashrate)}{last_share or 'Never'}
      No shares submitted yet
      No shares submitted yet
      -
      +# html += """ +# +#
      -
      -

      ๐Ÿ† Recent Blocks

      - - - - - - - - """ +#
      +#

      ๐Ÿ† Recent Blocks

      +#
      HeightHashRewardFound At
      +# +# +# +# +# +# +# """ - for block in stats.get('recent_blocks', []): - block_hash, height, reward, found_at = block - html += f""" - - - - - - - """ +# for block in stats.get('recent_blocks', []): +# block_hash, height, reward, found_at = block +# html += f""" +# +# +# +# +# +# +# """ - html += """ -
      HeightHashRewardFound At
      {height}{block_hash[:16]}...{reward:.8f} RIN{found_at}
      {height}{block_hash[:16]}...{reward:.8f} RIN{found_at}
      -
      +# html += """ +# +#
      -
      -

      ๐Ÿ”— Connect to Pool

      -

      Use any RinHash-compatible miner:

      -
      ./cpuminer -a rinhash -o stratum+tcp://YOUR_IP:3333 -u username.workername -p x
      -

      Replace YOUR_IP with your server's public IP address

      -
      - +#
      +#

      ๐Ÿ”— Connect to Pool

      +#

      Use any RinHash-compatible miner:

      +#
      ./cpuminer -a rinhash -o stratum+tcp://YOUR_IP:3333 -u username.workername -p x
      +#

      Replace YOUR_IP with your server's public IP address

      +#
      +# - - +# +# 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(); +# }} +# - - - - """ - return html +# +# +# +# """ +# return html -class PoolWebHandler(BaseHTTPRequestHandler): - def __init__(self, *args, pool_interface=None, **kwargs): - self.pool_interface = pool_interface - super().__init__(*args, **kwargs) +# class PoolWebHandler(BaseHTTPRequestHandler): +# def __init__(self, *args, pool_interface=None, **kwargs): +# self.pool_interface = pool_interface +# super().__init__(*args, **kwargs) - def do_GET(self): - if self.path == '/': - stats = self.pool_interface.get_pool_stats() - html = self.pool_interface.generate_html(stats) +# def do_GET(self): +# if self.path == '/': +# stats = self.pool_interface.get_pool_stats() +# html = self.pool_interface.generate_html(stats) - self.send_response(200) - self.send_header('Content-type', 'text/html') - self.end_headers() - self.wfile.write(html.encode('utf-8')) - elif self.path == '/api/stats': - stats = self.pool_interface.get_pool_stats() +# self.send_response(200) +# self.send_header('Content-type', 'text/html') +# self.end_headers() +# self.wfile.write(html.encode('utf-8')) +# elif self.path == '/api/stats': +# stats = self.pool_interface.get_pool_stats() - self.send_response(200) - self.send_header('Content-type', 'application/json') - self.end_headers() - self.wfile.write(json.dumps(stats).encode('utf-8')) - else: - self.send_response(404) - self.end_headers() - self.wfile.write(b'Not Found') +# self.send_response(200) +# self.send_header('Content-type', 'application/json') +# self.end_headers() +# self.wfile.write(json.dumps(stats).encode('utf-8')) +# else: +# self.send_response(404) +# self.end_headers() +# self.wfile.write(b'Not Found') - def log_message(self, format, *args): - # Suppress access logs - pass +# def log_message(self, format, *args): +# # Suppress access logs +# pass -def start_web_interface(pool_db, host='0.0.0.0', port=8083, rpc_host='127.0.0.1', rpc_port=9556, - rpc_user='rinrpc', rpc_password='745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90'): - """Start the web interface server""" - interface = PoolWebInterface(pool_db, host, port, rpc_host, rpc_port, rpc_user, rpc_password) +# def start_web_interface(pool_db, host='0.0.0.0', port=8083, rpc_host='127.0.0.1', rpc_port=9556, +# rpc_user='rinrpc', rpc_password='745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90'): +# """Start the web interface server""" +# interface = PoolWebInterface(pool_db, host, port, rpc_host, rpc_port, rpc_user, rpc_password) - class Handler(PoolWebHandler): - def __init__(self, *args, **kwargs): - super().__init__(*args, pool_interface=interface, **kwargs) +# class Handler(PoolWebHandler): +# def __init__(self, *args, **kwargs): +# super().__init__(*args, pool_interface=interface, **kwargs) - try: - server = HTTPServer((host, port), Handler) - print(f"๐ŸŒ Web interface running on http://{host}:{port}") - print("Press Ctrl+C to stop") +# try: +# server = HTTPServer((host, port), Handler) +# print(f"๐ŸŒ Web interface running on http://{host}:{port}") +# print("Press Ctrl+C to stop") - server.serve_forever() - except OSError as e: - if "Address already in use" in str(e): - print(f"โš ๏ธ Port {port} is already in use, web interface not started") - print(f"๐Ÿ’ก Try a different port or kill the process using port {port}") - else: - print(f"โŒ Failed to start web interface: {e}") - except KeyboardInterrupt: - print("\n๐Ÿ›‘ Shutting down web interface...") - server.shutdown() +# server.serve_forever() +# except OSError as e: +# if "Address already in use" in str(e): +# print(f"โš ๏ธ Port {port} is already in use, web interface not started") +# print(f"๐Ÿ’ก Try a different port or kill the process using port {port}") +# else: +# print(f"โŒ Failed to start web interface: {e}") +# except KeyboardInterrupt: +# print("\n๐Ÿ›‘ Shutting down web interface...") +# server.shutdown() -if __name__ == "__main__": - # This would be called from the main pool server - print("Web interface module loaded") +# if __name__ == "__main__": +# # This would be called from the main pool server +# print("Web interface module loaded") diff --git a/MINE/rin/solo_mining.sh b/MINE/rin/solo_mining.sh index b0ec0ad..54001dc 100644 --- a/MINE/rin/solo_mining.sh +++ b/MINE/rin/solo_mining.sh @@ -1,47 +1,47 @@ -#!/bin/bash +# #!/bin/bash -# Solo Mining Script for RinCoin -# Uses local RinCoin node for solo mining +# # Solo Mining Script for RinCoin +# # Uses local RinCoin node for solo mining -echo "=== RinCoin Solo Mining Setup ===" -echo "" +# echo "=== RinCoin Solo Mining Setup ===" +# echo "" -# Check if rincoin-node container is running -if ! sudo docker ps | grep -q "rincoin-node"; then - echo "Error: rincoin-node container is not running!" - echo "Please start it first:" - echo "sudo docker start rincoin-node" - exit 1 -fi +# # Check if rincoin-node container is running +# if ! sudo docker ps | grep -q "rincoin-node"; then +# echo "Error: rincoin-node container is not running!" +# echo "Please start it first:" +# echo "sudo docker start rincoin-node" +# exit 1 +# fi -# Get wallet address -RIN_ADDRESS=$(sudo docker exec rincoin-node rincoin-cli -datadir=/data -conf=/data/rincoin.conf -rpcwallet=main getnewaddress 2>/dev/null) +# # Get wallet address +# RIN_ADDRESS=$(sudo docker exec rincoin-node rincoin-cli -datadir=/data -conf=/data/rincoin.conf -rpcwallet=main getnewaddress 2>/dev/null) -if [ -z "$RIN_ADDRESS" ]; then - echo "Error: Could not get RinCoin address!" - echo "Make sure the wallet is created and the node is synced." - exit 1 -fi +# if [ -z "$RIN_ADDRESS" ]; then +# echo "Error: Could not get RinCoin address!" +# echo "Make sure the wallet is created and the node is synced." +# exit 1 +# fi -echo "RinCoin Address: $RIN_ADDRESS" -echo "" +# echo "RinCoin Address: $RIN_ADDRESS" +# echo "" -# Check node sync status -SYNC_STATUS=$(sudo docker exec rincoin-node rincoin-cli -datadir=/data -conf=/data/rincoin.conf getblockchaininfo | grep -o '"initialblockdownload": [^,]*' | cut -d' ' -f2) +# # Check node sync status +# SYNC_STATUS=$(sudo docker exec rincoin-node rincoin-cli -datadir=/data -conf=/data/rincoin.conf getblockchaininfo | grep -o '"initialblockdownload": [^,]*' | cut -d' ' -f2) -if [ "$SYNC_STATUS" = "true" ]; then - echo "โš ๏ธ WARNING: Node is still syncing (initialblockdownload: true)" - echo "Solo mining may not work properly until sync is complete." - echo "" -fi +# if [ "$SYNC_STATUS" = "true" ]; then +# echo "โš ๏ธ WARNING: Node is still syncing (initialblockdownload: true)" +# echo "Solo mining may not work properly until sync is complete." +# echo "" +# fi -echo "Starting solo mining with cpuminer-opt-rin..." -echo "Algorithm: rinhash" -echo "Target: Local RinCoin node (127.0.0.1:9555)" -echo "Wallet: $RIN_ADDRESS" -echo "" -echo "Press Ctrl+C to stop mining" -echo "" +# echo "Starting solo mining with cpuminer-opt-rin..." +# echo "Algorithm: rinhash" +# echo "Target: Local RinCoin node (127.0.0.1:9555)" +# echo "Wallet: $RIN_ADDRESS" +# echo "" +# echo "Press Ctrl+C to stop mining" +# echo "" -# Start solo mining -sudo docker exec -it amd-strix-halo-llama-rocm bash -c "/mnt/dl/rinhash/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://127.0.0.1:9555 -u $RIN_ADDRESS -p x -t 32" +# # Start solo mining +# sudo docker exec -it amd-strix-halo-llama-rocm bash -c "/mnt/dl/rinhash/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://127.0.0.1:9555 -u $RIN_ADDRESS -p x -t 32" diff --git a/MINE/rin/solo_mining_core.sh b/MINE/rin/solo_mining_core.sh index 1ade71d..3a9efe5 100644 --- a/MINE/rin/solo_mining_core.sh +++ b/MINE/rin/solo_mining_core.sh @@ -1,171 +1,171 @@ -#!/bin/bash +# #!/bin/bash -# RinCoin Solo Mining using Built-in Core Mining -# Uses RinCoin Core's generatetoaddress command +# # RinCoin Solo Mining using Built-in Core Mining +# # Uses RinCoin Core's generatetoaddress command -# Default address (can be overridden with command line parameter) -DEFAULT_ADDRESS="rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q" +# # Default address (can be overridden with command line parameter) +# DEFAULT_ADDRESS="rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q" -# Get total CPU cores for default thread count -TOTAL_CORES=$(nproc) -DEFAULT_THREADS=$TOTAL_CORES +# # Get total CPU cores for default thread count +# TOTAL_CORES=$(nproc) +# DEFAULT_THREADS=$TOTAL_CORES -# Parse command line arguments -RIN_ADDRESS="" -THREAD_COUNT="" +# # Parse command line arguments +# RIN_ADDRESS="" +# THREAD_COUNT="" -# Parse arguments -while [[ $# -gt 0 ]]; do - case $1 in - -a|--address) - RIN_ADDRESS="$2" - shift 2 - ;; - -t|--threads) - THREAD_COUNT="$2" - shift 2 - ;; - -h|--help) - echo "Usage: $0 [OPTIONS]" - echo "" - echo "Options:" - echo " -a, --address ADDRESS RinCoin address to mine to (default: $DEFAULT_ADDRESS)" - echo " -t, --threads COUNT Number of threads to use (default: $DEFAULT_THREADS)" - echo " -h, --help Show this help message" - echo "" - echo "Examples:" - echo " $0 # Use defaults (all cores, default address)" - echo " $0 -a rin1q... -t 16 # Custom address and 16 threads" - echo " $0 --address rin1q... --threads 8 # Custom address and 8 threads" - exit 0 - ;; - *) - echo "Unknown option: $1" - echo "Use -h or --help for usage information" - exit 1 - ;; - esac -done +# # Parse arguments +# while [[ $# -gt 0 ]]; do +# case $1 in +# -a|--address) +# RIN_ADDRESS="$2" +# shift 2 +# ;; +# -t|--threads) +# THREAD_COUNT="$2" +# shift 2 +# ;; +# -h|--help) +# echo "Usage: $0 [OPTIONS]" +# echo "" +# echo "Options:" +# echo " -a, --address ADDRESS RinCoin address to mine to (default: $DEFAULT_ADDRESS)" +# echo " -t, --threads COUNT Number of threads to use (default: $DEFAULT_THREADS)" +# echo " -h, --help Show this help message" +# echo "" +# echo "Examples:" +# echo " $0 # Use defaults (all cores, default address)" +# echo " $0 -a rin1q... -t 16 # Custom address and 16 threads" +# echo " $0 --address rin1q... --threads 8 # Custom address and 8 threads" +# exit 0 +# ;; +# *) +# echo "Unknown option: $1" +# echo "Use -h or --help for usage information" +# exit 1 +# ;; +# esac +# done -# Set defaults if not provided -if [ -z "$RIN_ADDRESS" ]; then - RIN_ADDRESS="$DEFAULT_ADDRESS" - echo "No address provided, using default: $RIN_ADDRESS" -fi +# # Set defaults if not provided +# if [ -z "$RIN_ADDRESS" ]; then +# RIN_ADDRESS="$DEFAULT_ADDRESS" +# echo "No address provided, using default: $RIN_ADDRESS" +# fi -if [ -z "$THREAD_COUNT" ]; then - THREAD_COUNT="$DEFAULT_THREADS" - echo "No thread count provided, using all cores: $THREAD_COUNT" -fi +# if [ -z "$THREAD_COUNT" ]; then +# THREAD_COUNT="$DEFAULT_THREADS" +# echo "No thread count provided, using all cores: $THREAD_COUNT" +# fi -# Validate thread count -if ! [[ "$THREAD_COUNT" =~ ^[0-9]+$ ]] || [ "$THREAD_COUNT" -lt 1 ] || [ "$THREAD_COUNT" -gt "$TOTAL_CORES" ]; then - echo "โŒ Error: Invalid thread count: $THREAD_COUNT" - echo "Thread count must be between 1 and $TOTAL_CORES" - exit 1 -fi +# # Validate thread count +# if ! [[ "$THREAD_COUNT" =~ ^[0-9]+$ ]] || [ "$THREAD_COUNT" -lt 1 ] || [ "$THREAD_COUNT" -gt "$TOTAL_CORES" ]; then +# echo "โŒ Error: Invalid thread count: $THREAD_COUNT" +# echo "Thread count must be between 1 and $TOTAL_CORES" +# exit 1 +# fi -echo "=== RinCoin Solo Mining (Built-in Core Mining) ===" -echo "CPU Cores Available: $TOTAL_CORES" -echo "Threads to Use: $THREAD_COUNT" -echo "Target Address: $RIN_ADDRESS" -echo "" -echo "" +# echo "=== RinCoin Solo Mining (Built-in Core Mining) ===" +# echo "CPU Cores Available: $TOTAL_CORES" +# echo "Threads to Use: $THREAD_COUNT" +# echo "Target Address: $RIN_ADDRESS" +# echo "" +# echo "" -# Configuration -RPC_HOST="127.0.0.1" -RPC_PORT="9556" -RPC_USER="rinrpc" -RPC_PASS="745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90" +# # Configuration +# RPC_HOST="127.0.0.1" +# RPC_PORT="9556" +# RPC_USER="rinrpc" +# RPC_PASS="745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90" -# Function to call RPC -call_rpc() { - local method="$1" - local params="$2" +# # Function to call RPC +# call_rpc() { +# local method="$1" +# local params="$2" - curl -s --user "$RPC_USER:$RPC_PASS" \ - -H 'content-type: text/plain' \ - --data "{\"jsonrpc\":\"1.0\",\"id\":\"curl\",\"method\":\"$method\",\"params\":$params}" \ - "http://$RPC_HOST:$RPC_PORT/" -} +# curl -s --user "$RPC_USER:$RPC_PASS" \ +# -H 'content-type: text/plain' \ +# --data "{\"jsonrpc\":\"1.0\",\"id\":\"curl\",\"method\":\"$method\",\"params\":$params}" \ +# "http://$RPC_HOST:$RPC_PORT/" +# } -# Wait for node to be ready -echo "Waiting for RinCoin node to be ready..." -while true; do - response=$(call_rpc "getblockchaininfo" "[]") - if [[ $response != *"Loading block index"* ]]; then - break - fi - echo "Node still loading... waiting 10 seconds" - sleep 10 -done +# # Wait for node to be ready +# echo "Waiting for RinCoin node to be ready..." +# while true; do +# response=$(call_rpc "getblockchaininfo" "[]") +# if [[ $response != *"Loading block index"* ]]; then +# break +# fi +# echo "Node still loading... waiting 10 seconds" +# sleep 10 +# done -echo "โœ… Node is ready!" -echo "" +# echo "โœ… Node is ready!" +# echo "" -# Load wallet if not already loaded -echo "Loading wallet..." -wallet_response=$(call_rpc "loadwallet" "[\"main\"]") -if [[ $wallet_response == *"error"* ]] && [[ $wallet_response == *"already loaded"* ]]; then - echo "โœ… Wallet already loaded" -else - echo "โœ… Wallet loaded successfully" -fi -echo "" +# # Load wallet if not already loaded +# echo "Loading wallet..." +# wallet_response=$(call_rpc "loadwallet" "[\"main\"]") +# if [[ $wallet_response == *"error"* ]] && [[ $wallet_response == *"already loaded"* ]]; then +# echo "โœ… Wallet already loaded" +# else +# echo "โœ… Wallet loaded successfully" +# fi +# echo "" -# Validate the provided address (basic check) -if [[ ! "$RIN_ADDRESS" =~ ^rin1[a-zA-Z0-9]{25,}$ ]]; then - echo "โŒ Error: Invalid RinCoin address format: $RIN_ADDRESS" - echo "RinCoin addresses should start with 'rin1' and be ~30 characters long" - exit 1 -fi +# # Validate the provided address (basic check) +# if [[ ! "$RIN_ADDRESS" =~ ^rin1[a-zA-Z0-9]{25,}$ ]]; then +# echo "โŒ Error: Invalid RinCoin address format: $RIN_ADDRESS" +# echo "RinCoin addresses should start with 'rin1' and be ~30 characters long" +# exit 1 +# fi -echo "โœ… Using RinCoin Address: $RIN_ADDRESS" -echo "" +# echo "โœ… Using RinCoin Address: $RIN_ADDRESS" +# echo "" -# Get blockchain info -echo "Blockchain Status:" -blockchain_info=$(call_rpc "getblockchaininfo" "[]") -blocks=$(echo "$blockchain_info" | grep -o '"blocks":[^,]*' | cut -d':' -f2) -headers=$(echo "$blockchain_info" | grep -o '"headers":[^,]*' | cut -d':' -f2) -difficulty=$(echo "$blockchain_info" | grep -o '"difficulty":[^,]*' | cut -d':' -f2) +# # Get blockchain info +# echo "Blockchain Status:" +# blockchain_info=$(call_rpc "getblockchaininfo" "[]") +# blocks=$(echo "$blockchain_info" | grep -o '"blocks":[^,]*' | cut -d':' -f2) +# headers=$(echo "$blockchain_info" | grep -o '"headers":[^,]*' | cut -d':' -f2) +# difficulty=$(echo "$blockchain_info" | grep -o '"difficulty":[^,]*' | cut -d':' -f2) -echo "Blocks: $blocks" -echo "Headers: $headers" -echo "Difficulty: $difficulty" -echo "" +# echo "Blocks: $blocks" +# echo "Headers: $headers" +# echo "Difficulty: $difficulty" +# echo "" -echo "โš ๏ธ IMPORTANT: Built-in Core Mining Limitations:" -echo "1. Uses CPU only (not GPU)" -echo "2. Very low hashpower compared to specialized miners" -echo "3. Extremely low chance of finding blocks solo" -echo "4. Best for testing, not profitable mining" -echo "5. Thread count affects mining attempts per cycle" -echo "" +# echo "โš ๏ธ IMPORTANT: Built-in Core Mining Limitations:" +# echo "1. Uses CPU only (not GPU)" +# echo "2. Very low hashpower compared to specialized miners" +# echo "3. Extremely low chance of finding blocks solo" +# echo "4. Best for testing, not profitable mining" +# echo "5. Thread count affects mining attempts per cycle" +# echo "" -echo "๐Ÿš€ Starting Built-in Solo Mining..." -echo "Target Address: $RIN_ADDRESS" -echo "Threads: $THREAD_COUNT" -echo "Press Ctrl+C to stop mining" -echo "" +# echo "๐Ÿš€ Starting Built-in Solo Mining..." +# echo "Target Address: $RIN_ADDRESS" +# echo "Threads: $THREAD_COUNT" +# echo "Press Ctrl+C to stop mining" +# echo "" -# Start built-in mining with specified thread count -# Note: RinCoin Core's generatetoaddress doesn't directly support thread count -# but we can run multiple instances or adjust the maxtries parameter -while true; do - echo "Attempting to mine 1 block with $THREAD_COUNT threads..." +# # Start built-in mining with specified thread count +# # Note: RinCoin Core's generatetoaddress doesn't directly support thread count +# # but we can run multiple instances or adjust the maxtries parameter +# while true; do +# echo "Attempting to mine 1 block with $THREAD_COUNT threads..." - # Adjust maxtries based on thread count for better distribution - adjusted_tries=$((1000000 * THREAD_COUNT / TOTAL_CORES)) +# # Adjust maxtries based on thread count for better distribution +# adjusted_tries=$((1000000 * THREAD_COUNT / TOTAL_CORES)) - mining_result=$(call_rpc "generatetoaddress" "[1, \"$RIN_ADDRESS\", $adjusted_tries]") +# mining_result=$(call_rpc "generatetoaddress" "[1, \"$RIN_ADDRESS\", $adjusted_tries]") - if [[ $mining_result == *"result"* ]] && [[ $mining_result != *"[]"* ]]; then - echo "๐ŸŽ‰ BLOCK FOUND!" - echo "Result: $mining_result" - break - else - echo "No block found in this attempt (tries: $adjusted_tries). Retrying..." - sleep 5 - fi -done +# if [[ $mining_result == *"result"* ]] && [[ $mining_result != *"[]"* ]]; then +# echo "๐ŸŽ‰ BLOCK FOUND!" +# echo "Result: $mining_result" +# break +# else +# echo "No block found in this attempt (tries: $adjusted_tries). Retrying..." +# sleep 5 +# fi +# done diff --git a/MINE/rin/solo_mining_remote.sh b/MINE/rin/solo_mining_remote.sh index 6b1ef9a..843df89 100644 --- a/MINE/rin/solo_mining_remote.sh +++ b/MINE/rin/solo_mining_remote.sh @@ -1,81 +1,81 @@ -#!/bin/bash +# #!/bin/bash -# Remote Solo Mining Script for RinCoin -# Connects to RinCoin node over network/RPC +# # Remote Solo Mining Script for RinCoin +# # Connects to RinCoin node over network/RPC -# Configuration -RPC_HOST="127.0.0.1" # Change to your server IP for remote access -RPC_PORT="9556" -RPC_USER="rinrpc" -RPC_PASS="745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90" +# # Configuration +# RPC_HOST="127.0.0.1" # Change to your server IP for remote access +# RPC_PORT="9556" +# RPC_USER="rinrpc" +# RPC_PASS="745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90" -echo "=== Remote RinCoin Solo Mining Setup ===" -echo "RPC Host: $RPC_HOST:$RPC_PORT" -echo "" +# echo "=== Remote RinCoin Solo Mining Setup ===" +# echo "RPC Host: $RPC_HOST:$RPC_PORT" +# echo "" -# Test RPC connection -echo "Testing RPC connection..." -RPC_RESPONSE=$(curl -s --user "$RPC_USER:$RPC_PASS" \ - -H 'content-type: text/plain' \ - --data '{"jsonrpc":"1.0","id":"curl","method":"getblockchaininfo","params":[]}' \ - "http://$RPC_HOST:$RPC_PORT/") +# # Test RPC connection +# echo "Testing RPC connection..." +# RPC_RESPONSE=$(curl -s --user "$RPC_USER:$RPC_PASS" \ +# -H 'content-type: text/plain' \ +# --data '{"jsonrpc":"1.0","id":"curl","method":"getblockchaininfo","params":[]}' \ +# "http://$RPC_HOST:$RPC_PORT/") -if [[ $RPC_RESPONSE == *"error"* ]]; then - echo "โŒ Error: Could not connect to RinCoin RPC!" - echo "Response: $RPC_RESPONSE" - echo "" - echo "Check:" - echo "1. RinCoin node is running" - echo "2. RPC port $RPC_PORT is accessible" - echo "3. Firewall allows connections to port $RPC_PORT" - exit 1 -fi +# if [[ $RPC_RESPONSE == *"error"* ]]; then +# echo "โŒ Error: Could not connect to RinCoin RPC!" +# echo "Response: $RPC_RESPONSE" +# echo "" +# echo "Check:" +# echo "1. RinCoin node is running" +# echo "2. RPC port $RPC_PORT is accessible" +# echo "3. Firewall allows connections to port $RPC_PORT" +# exit 1 +# fi -echo "โœ… RPC connection successful!" -echo "" +# echo "โœ… RPC connection successful!" +# echo "" -# Get wallet address via RPC -echo "Getting wallet address..." -WALLET_RESPONSE=$(curl -s --user "$RPC_USER:$RPC_PASS" \ - -H 'content-type: text/plain' \ - --data '{"jsonrpc":"1.0","id":"curl","method":"getnewaddress","params":[]}' \ - "http://$RPC_HOST:$RPC_PORT/") +# # Get wallet address via RPC +# echo "Getting wallet address..." +# WALLET_RESPONSE=$(curl -s --user "$RPC_USER:$RPC_PASS" \ +# -H 'content-type: text/plain' \ +# --data '{"jsonrpc":"1.0","id":"curl","method":"getnewaddress","params":[]}' \ +# "http://$RPC_HOST:$RPC_PORT/") -RIN_ADDRESS=$(echo "$WALLET_RESPONSE" | grep -o '"result":"[^"]*"' | cut -d'"' -f4) +# RIN_ADDRESS=$(echo "$WALLET_RESPONSE" | grep -o '"result":"[^"]*"' | cut -d'"' -f4) -if [ -z "$RIN_ADDRESS" ]; then - echo "โŒ Error: Could not get RinCoin address!" - echo "Response: $WALLET_RESPONSE" - echo "" - echo "Make sure wallet 'main' exists:" - echo "curl --user $RPC_USER:$RPC_PASS -H 'content-type: text/plain' --data '{\"jsonrpc\":\"1.0\",\"id\":\"curl\",\"method\":\"createwallet\",\"params\":[\"main\"]}' http://$RPC_HOST:$RPC_PORT/" - exit 1 -fi +# if [ -z "$RIN_ADDRESS" ]; then +# echo "โŒ Error: Could not get RinCoin address!" +# echo "Response: $WALLET_RESPONSE" +# echo "" +# echo "Make sure wallet 'main' exists:" +# echo "curl --user $RPC_USER:$RPC_PASS -H 'content-type: text/plain' --data '{\"jsonrpc\":\"1.0\",\"id\":\"curl\",\"method\":\"createwallet\",\"params\":[\"main\"]}' http://$RPC_HOST:$RPC_PORT/" +# exit 1 +# fi -echo "โœ… RinCoin Address: $RIN_ADDRESS" -echo "" +# echo "โœ… RinCoin Address: $RIN_ADDRESS" +# echo "" -# Check node sync status -SYNC_RESPONSE=$(curl -s --user "$RPC_USER:$RPC_PASS" \ - -H 'content-type: text/plain' \ - --data '{"jsonrpc":"1.0","id":"curl","method":"getblockchaininfo","params":[]}' \ - "http://$RPC_HOST:$RPC_PORT/") +# # Check node sync status +# SYNC_RESPONSE=$(curl -s --user "$RPC_USER:$RPC_PASS" \ +# -H 'content-type: text/plain' \ +# --data '{"jsonrpc":"1.0","id":"curl","method":"getblockchaininfo","params":[]}' \ +# "http://$RPC_HOST:$RPC_PORT/") -SYNC_STATUS=$(echo "$SYNC_RESPONSE" | grep -o '"initialblockdownload":[^,]*' | cut -d':' -f2 | tr -d ' ') +# SYNC_STATUS=$(echo "$SYNC_RESPONSE" | grep -o '"initialblockdownload":[^,]*' | cut -d':' -f2 | tr -d ' ') -if [ "$SYNC_STATUS" = "true" ]; then - echo "โš ๏ธ WARNING: Node is still syncing (initialblockdownload: true)" - echo "Solo mining may not work properly until sync is complete." - echo "" -fi +# if [ "$SYNC_STATUS" = "true" ]; then +# echo "โš ๏ธ WARNING: Node is still syncing (initialblockdownload: true)" +# echo "Solo mining may not work properly until sync is complete." +# echo "" +# fi -echo "Starting remote solo mining with cpuminer-opt-rin..." -echo "Algorithm: rinhash" -echo "Target: RinCoin node at $RPC_HOST:9555" -echo "Wallet: $RIN_ADDRESS" -echo "" -echo "Press Ctrl+C to stop mining" -echo "" +# echo "Starting remote solo mining with cpuminer-opt-rin..." +# echo "Algorithm: rinhash" +# echo "Target: RinCoin node at $RPC_HOST:9555" +# echo "Wallet: $RIN_ADDRESS" +# echo "" +# echo "Press Ctrl+C to stop mining" +# echo "" -# Start solo mining (connect to P2P port, not RPC) -sudo docker exec -it amd-strix-halo-llama-rocm bash -c "/mnt/dl/rinhash/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://$RPC_HOST:9555 -u $RIN_ADDRESS -p x -t 32" +# # Start solo mining (connect to P2P port, not RPC) +# sudo docker exec -it amd-strix-halo-llama-rocm bash -c "/mnt/dl/rinhash/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://$RPC_HOST:9555 -u $RIN_ADDRESS -p x -t 32" diff --git a/MINE/rin/solo_mining_rpc.sh b/MINE/rin/solo_mining_rpc.sh index 7f44f5d..220e641 100644 --- a/MINE/rin/solo_mining_rpc.sh +++ b/MINE/rin/solo_mining_rpc.sh @@ -1,76 +1,76 @@ -#!/bin/bash +# #!/bin/bash -# RinCoin Solo Mining via RPC -# This script uses RinCoin's RPC interface for solo mining +# # RinCoin Solo Mining via RPC +# # This script uses RinCoin's RPC interface for solo mining -echo "=== RinCoin Solo Mining via RPC ===" -echo "" +# echo "=== RinCoin Solo Mining via RPC ===" +# echo "" -# Configuration -RPC_HOST="127.0.0.1" -RPC_PORT="9556" -RPC_USER="rinrpc" -RPC_PASS="745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90" +# # Configuration +# RPC_HOST="127.0.0.1" +# RPC_PORT="9556" +# RPC_USER="rinrpc" +# RPC_PASS="745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90" -# Function to call RPC -call_rpc() { - local method="$1" - local params="$2" +# # Function to call RPC +# call_rpc() { +# local method="$1" +# local params="$2" - curl -s --user "$RPC_USER:$RPC_PASS" \ - -H 'content-type: text/plain' \ - --data "{\"jsonrpc\":\"1.0\",\"id\":\"curl\",\"method\":\"$method\",\"params\":$params}" \ - "http://$RPC_HOST:$RPC_PORT/" -} +# curl -s --user "$RPC_USER:$RPC_PASS" \ +# -H 'content-type: text/plain' \ +# --data "{\"jsonrpc\":\"1.0\",\"id\":\"curl\",\"method\":\"$method\",\"params\":$params}" \ +# "http://$RPC_HOST:$RPC_PORT/" +# } -# Wait for node to be ready -echo "Waiting for RinCoin node to be ready..." -while true; do - response=$(call_rpc "getblockchaininfo" "[]") - if [[ $response != *"Loading block index"* ]]; then - break - fi - echo "Node still loading... waiting 10 seconds" - sleep 10 -done +# # Wait for node to be ready +# echo "Waiting for RinCoin node to be ready..." +# while true; do +# response=$(call_rpc "getblockchaininfo" "[]") +# if [[ $response != *"Loading block index"* ]]; then +# break +# fi +# echo "Node still loading... waiting 10 seconds" +# sleep 10 +# done -echo "โœ… Node is ready!" -echo "" +# echo "โœ… Node is ready!" +# echo "" -# Get wallet address -echo "Getting wallet address..." -wallet_response=$(call_rpc "getnewaddress" "[]") -rin_address=$(echo "$wallet_response" | grep -o '"result":"[^"]*"' | cut -d'"' -f4) +# # Get wallet address +# echo "Getting wallet address..." +# wallet_response=$(call_rpc "getnewaddress" "[]") +# rin_address=$(echo "$wallet_response" | grep -o '"result":"[^"]*"' | cut -d'"' -f4) -if [ -z "$rin_address" ]; then - echo "โŒ Error: Could not get RinCoin address!" - echo "Response: $wallet_response" - exit 1 -fi +# if [ -z "$rin_address" ]; then +# echo "โŒ Error: Could not get RinCoin address!" +# echo "Response: $wallet_response" +# exit 1 +# fi -echo "โœ… RinCoin Address: $rin_address" -echo "" +# echo "โœ… RinCoin Address: $rin_address" +# echo "" -# Get blockchain info -echo "Blockchain Status:" -blockchain_info=$(call_rpc "getblockchaininfo" "[]") -blocks=$(echo "$blockchain_info" | grep -o '"blocks":[^,]*' | cut -d':' -f2) -headers=$(echo "$blockchain_info" | grep -o '"headers":[^,]*' | cut -d':' -f2) -difficulty=$(echo "$blockchain_info" | grep -o '"difficulty":[^,]*' | cut -d':' -f2) +# # Get blockchain info +# echo "Blockchain Status:" +# blockchain_info=$(call_rpc "getblockchaininfo" "[]") +# blocks=$(echo "$blockchain_info" | grep -o '"blocks":[^,]*' | cut -d':' -f2) +# headers=$(echo "$blockchain_info" | grep -o '"headers":[^,]*' | cut -d':' -f2) +# difficulty=$(echo "$blockchain_info" | grep -o '"difficulty":[^,]*' | cut -d':' -f2) -echo "Blocks: $blocks" -echo "Headers: $headers" -echo "Difficulty: $difficulty" -echo "" +# echo "Blocks: $blocks" +# echo "Headers: $headers" +# echo "Difficulty: $difficulty" +# echo "" -echo "โš ๏ธ IMPORTANT: RinCoin solo mining requires:" -echo "1. A fully synced node (currently at block $blocks of $headers)" -echo "2. Mining software that supports RinCoin's RPC mining protocol" -echo "3. Very high hashpower to find blocks solo" -echo "" -echo "For now, we recommend pool mining for consistent rewards:" -echo "" -echo "Pool Mining Command:" -echo "sudo docker exec -it amd-strix-halo-llama-rocm bash -c \"/mnt/dl/rinhash/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://rinhash.mine.zergpool.com:7148 -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC,mc=RIN,ID=StrixHalo -t 32\"" -echo "" -echo "Your RinCoin address for solo mining: $rin_address" +# echo "โš ๏ธ IMPORTANT: RinCoin solo mining requires:" +# echo "1. A fully synced node (currently at block $blocks of $headers)" +# echo "2. Mining software that supports RinCoin's RPC mining protocol" +# echo "3. Very high hashpower to find blocks solo" +# echo "" +# echo "For now, we recommend pool mining for consistent rewards:" +# echo "" +# echo "Pool Mining Command:" +# echo "sudo docker exec -it amd-strix-halo-llama-rocm bash -c \"/mnt/dl/rinhash/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://rinhash.mine.zergpool.com:7148 -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC,mc=RIN,ID=StrixHalo -t 32\"" +# echo "" +# echo "Your RinCoin address for solo mining: $rin_address" diff --git a/MINE/rin/solo_mining_zergpool.sh b/MINE/rin/solo_mining_zergpool.sh index 7f44f5d..220e641 100644 --- a/MINE/rin/solo_mining_zergpool.sh +++ b/MINE/rin/solo_mining_zergpool.sh @@ -1,76 +1,76 @@ -#!/bin/bash +# #!/bin/bash -# RinCoin Solo Mining via RPC -# This script uses RinCoin's RPC interface for solo mining +# # RinCoin Solo Mining via RPC +# # This script uses RinCoin's RPC interface for solo mining -echo "=== RinCoin Solo Mining via RPC ===" -echo "" +# echo "=== RinCoin Solo Mining via RPC ===" +# echo "" -# Configuration -RPC_HOST="127.0.0.1" -RPC_PORT="9556" -RPC_USER="rinrpc" -RPC_PASS="745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90" +# # Configuration +# RPC_HOST="127.0.0.1" +# RPC_PORT="9556" +# RPC_USER="rinrpc" +# RPC_PASS="745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90" -# Function to call RPC -call_rpc() { - local method="$1" - local params="$2" +# # Function to call RPC +# call_rpc() { +# local method="$1" +# local params="$2" - curl -s --user "$RPC_USER:$RPC_PASS" \ - -H 'content-type: text/plain' \ - --data "{\"jsonrpc\":\"1.0\",\"id\":\"curl\",\"method\":\"$method\",\"params\":$params}" \ - "http://$RPC_HOST:$RPC_PORT/" -} +# curl -s --user "$RPC_USER:$RPC_PASS" \ +# -H 'content-type: text/plain' \ +# --data "{\"jsonrpc\":\"1.0\",\"id\":\"curl\",\"method\":\"$method\",\"params\":$params}" \ +# "http://$RPC_HOST:$RPC_PORT/" +# } -# Wait for node to be ready -echo "Waiting for RinCoin node to be ready..." -while true; do - response=$(call_rpc "getblockchaininfo" "[]") - if [[ $response != *"Loading block index"* ]]; then - break - fi - echo "Node still loading... waiting 10 seconds" - sleep 10 -done +# # Wait for node to be ready +# echo "Waiting for RinCoin node to be ready..." +# while true; do +# response=$(call_rpc "getblockchaininfo" "[]") +# if [[ $response != *"Loading block index"* ]]; then +# break +# fi +# echo "Node still loading... waiting 10 seconds" +# sleep 10 +# done -echo "โœ… Node is ready!" -echo "" +# echo "โœ… Node is ready!" +# echo "" -# Get wallet address -echo "Getting wallet address..." -wallet_response=$(call_rpc "getnewaddress" "[]") -rin_address=$(echo "$wallet_response" | grep -o '"result":"[^"]*"' | cut -d'"' -f4) +# # Get wallet address +# echo "Getting wallet address..." +# wallet_response=$(call_rpc "getnewaddress" "[]") +# rin_address=$(echo "$wallet_response" | grep -o '"result":"[^"]*"' | cut -d'"' -f4) -if [ -z "$rin_address" ]; then - echo "โŒ Error: Could not get RinCoin address!" - echo "Response: $wallet_response" - exit 1 -fi +# if [ -z "$rin_address" ]; then +# echo "โŒ Error: Could not get RinCoin address!" +# echo "Response: $wallet_response" +# exit 1 +# fi -echo "โœ… RinCoin Address: $rin_address" -echo "" +# echo "โœ… RinCoin Address: $rin_address" +# echo "" -# Get blockchain info -echo "Blockchain Status:" -blockchain_info=$(call_rpc "getblockchaininfo" "[]") -blocks=$(echo "$blockchain_info" | grep -o '"blocks":[^,]*' | cut -d':' -f2) -headers=$(echo "$blockchain_info" | grep -o '"headers":[^,]*' | cut -d':' -f2) -difficulty=$(echo "$blockchain_info" | grep -o '"difficulty":[^,]*' | cut -d':' -f2) +# # Get blockchain info +# echo "Blockchain Status:" +# blockchain_info=$(call_rpc "getblockchaininfo" "[]") +# blocks=$(echo "$blockchain_info" | grep -o '"blocks":[^,]*' | cut -d':' -f2) +# headers=$(echo "$blockchain_info" | grep -o '"headers":[^,]*' | cut -d':' -f2) +# difficulty=$(echo "$blockchain_info" | grep -o '"difficulty":[^,]*' | cut -d':' -f2) -echo "Blocks: $blocks" -echo "Headers: $headers" -echo "Difficulty: $difficulty" -echo "" +# echo "Blocks: $blocks" +# echo "Headers: $headers" +# echo "Difficulty: $difficulty" +# echo "" -echo "โš ๏ธ IMPORTANT: RinCoin solo mining requires:" -echo "1. A fully synced node (currently at block $blocks of $headers)" -echo "2. Mining software that supports RinCoin's RPC mining protocol" -echo "3. Very high hashpower to find blocks solo" -echo "" -echo "For now, we recommend pool mining for consistent rewards:" -echo "" -echo "Pool Mining Command:" -echo "sudo docker exec -it amd-strix-halo-llama-rocm bash -c \"/mnt/dl/rinhash/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://rinhash.mine.zergpool.com:7148 -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC,mc=RIN,ID=StrixHalo -t 32\"" -echo "" -echo "Your RinCoin address for solo mining: $rin_address" +# echo "โš ๏ธ IMPORTANT: RinCoin solo mining requires:" +# echo "1. A fully synced node (currently at block $blocks of $headers)" +# echo "2. Mining software that supports RinCoin's RPC mining protocol" +# echo "3. Very high hashpower to find blocks solo" +# echo "" +# echo "For now, we recommend pool mining for consistent rewards:" +# echo "" +# echo "Pool Mining Command:" +# echo "sudo docker exec -it amd-strix-halo-llama-rocm bash -c \"/mnt/dl/rinhash/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://rinhash.mine.zergpool.com:7148 -u bc1qjn4m6rmrveuxhk02a5qhe4r6kdcsvvt3vhdn9j -p c=BTC,mc=RIN,ID=StrixHalo -t 32\"" +# echo "" +# echo "Your RinCoin address for solo mining: $rin_address" diff --git a/MINE/rin/start_mining_pool.sh b/MINE/rin/start_mining_pool.sh index 9f95eb8..ec4c828 100644 --- a/MINE/rin/start_mining_pool.sh +++ b/MINE/rin/start_mining_pool.sh @@ -1,83 +1,83 @@ -#!/bin/bash +# #!/bin/bash -# RinCoin Mining Pool Server Startup Script -# Distributes block rewards among multiple miners +# # RinCoin Mining Pool Server Startup Script +# # Distributes block rewards among multiple miners -echo "=== RinCoin Mining Pool Server ===" -echo "" +# echo "=== RinCoin Mining Pool Server ===" +# echo "" -# Check if RinCoin node is running -echo "Checking RinCoin node status..." -if ! curl -s -u rinrpc:745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90 \ - -H 'content-type: text/plain' \ - --data '{"jsonrpc":"1.0","id":"curl","method":"getblockchaininfo","params":[]}' \ - http://127.0.0.1:9556/ > /dev/null; then - echo "โŒ RinCoin node is not running!" - echo "Start it first with: docker start rincoin-node" - exit 1 -fi +# # Check if RinCoin node is running +# echo "Checking RinCoin node status..." +# if ! curl -s -u rinrpc:745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90 \ +# -H 'content-type: text/plain' \ +# --data '{"jsonrpc":"1.0","id":"curl","method":"getblockchaininfo","params":[]}' \ +# http://127.0.0.1:9556/ > /dev/null; then +# echo "โŒ RinCoin node is not running!" +# echo "Start it first with: docker start rincoin-node" +# exit 1 +# fi -echo "โœ… RinCoin node is running" +# echo "โœ… RinCoin node is running" -# Check Python dependencies -echo "Checking Python dependencies..." -python3 -c "import requests, sqlite3" 2>/dev/null || { - echo "Installing python3-requests..." - sudo apt-get update && sudo apt-get install -y python3-requests -} +# # Check Python dependencies +# echo "Checking Python dependencies..." +# python3 -c "import requests, sqlite3" 2>/dev/null || { +# echo "Installing python3-requests..." +# sudo apt-get update && sudo apt-get install -y python3-requests +# } -echo "โœ… Python dependencies ready" +# echo "โœ… Python dependencies ready" -# Check if port 3333 is already in use -if netstat -tln | grep -q ":3333 "; then - echo "" - echo "โš ๏ธ Port 3333 is already in use!" - echo "" - echo "๐Ÿ” Process using port 3333:" - sudo netstat -tlnp | grep ":3333 " || echo "Could not determine process" - echo "" - echo "๐Ÿ›‘ To kill existing process:" - echo "sudo lsof -ti:3333 | xargs sudo kill -9" - echo "" - read -p "Kill existing process and continue? (y/N): " -n 1 -r - echo - if [[ $REPLY =~ ^[Yy]$ ]]; then - echo "Killing processes using port 3333..." - sudo lsof -ti:3333 | xargs sudo kill -9 2>/dev/null || echo "No processes to kill" - sleep 2 - else - echo "Exiting..." - exit 1 - fi -fi +# # Check if port 3333 is already in use +# if netstat -tln | grep -q ":3333 "; then +# echo "" +# echo "โš ๏ธ Port 3333 is already in use!" +# echo "" +# echo "๐Ÿ” Process using port 3333:" +# sudo netstat -tlnp | grep ":3333 " || echo "Could not determine process" +# echo "" +# echo "๐Ÿ›‘ To kill existing process:" +# echo "sudo lsof -ti:3333 | xargs sudo kill -9" +# echo "" +# read -p "Kill existing process and continue? (y/N): " -n 1 -r +# echo +# if [[ $REPLY =~ ^[Yy]$ ]]; then +# echo "Killing processes using port 3333..." +# sudo lsof -ti:3333 | xargs sudo kill -9 2>/dev/null || echo "No processes to kill" +# sleep 2 +# else +# echo "Exiting..." +# exit 1 +# fi +# fi -echo "" -echo "๐Ÿš€ Starting Mining Pool Server..." -echo "This will distribute block rewards among multiple miners" -echo "" -echo "Pool Features:" -echo "- Multiple miner support" -echo "- Share-based reward distribution" -echo "- Pool fee: 1%" -echo "- Real-time statistics" -echo "- Web dashboard on port 8083" -echo "" +# echo "" +# echo "๐Ÿš€ Starting Mining Pool Server..." +# echo "This will distribute block rewards among multiple miners" +# echo "" +# echo "Pool Features:" +# echo "- Multiple miner support" +# echo "- Share-based reward distribution" +# echo "- Pool fee: 1%" +# echo "- Real-time statistics" +# echo "- Web dashboard on port 8083" +# echo "" -echo "After it starts, miners can connect with:" -echo "" -echo "Option 1: Address as username" -echo "./cpuminer -a rinhash -o stratum+tcp://YOUR_IP:3333 -u rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q -p x" -echo "" -echo "Option 2: Address.workername format" -echo "./cpuminer -a rinhash -o stratum+tcp://YOUR_IP:3333 -u rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q.worker1 -p x" -echo "" -echo "Option 3: Traditional username (rewards to pool address)" -echo "./cpuminer -a rinhash -o stratum+tcp://YOUR_IP:3333 -u username.workername -p x" -echo "" -echo "๐ŸŒ Web Dashboard: http://YOUR_IP:8083" -echo "๐Ÿ“Š View real-time pool statistics, miners, and blocks" -echo "" -echo "Press Ctrl+C to stop the pool" +# echo "After it starts, miners can connect with:" +# echo "" +# echo "Option 1: Address as username" +# echo "./cpuminer -a rinhash -o stratum+tcp://YOUR_IP:3333 -u rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q -p x" +# echo "" +# echo "Option 2: Address.workername format" +# echo "./cpuminer -a rinhash -o stratum+tcp://YOUR_IP:3333 -u rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q.worker1 -p x" +# echo "" +# echo "Option 3: Traditional username (rewards to pool address)" +# echo "./cpuminer -a rinhash -o stratum+tcp://YOUR_IP:3333 -u username.workername -p x" +# echo "" +# echo "๐ŸŒ Web Dashboard: http://YOUR_IP:8083" +# echo "๐Ÿ“Š View real-time pool statistics, miners, and blocks" +# echo "" +# echo "Press Ctrl+C to stop the pool" -# Start the mining pool -python3 MINE/rin/stratum_pool.py +# # Start the mining pool +# python3 MINE/rin/stratum_pool.py diff --git a/MINE/rin/start_stratum_proxy.sh b/MINE/rin/start_stratum_proxy.sh index 0d9c82f..1e317f1 100644 --- a/MINE/rin/start_stratum_proxy.sh +++ b/MINE/rin/start_stratum_proxy.sh @@ -1,68 +1,68 @@ -#!/bin/bash +# #!/bin/bash -# Start RinCoin Stratum Proxy Server -# Bridges cpuminer-opt-rin to RinCoin node +# # Start RinCoin Stratum Proxy Server +# # Bridges cpuminer-opt-rin to RinCoin node -echo "=== RinCoin Stratum Proxy Server ===" -echo "" +# echo "=== RinCoin Stratum Proxy Server ===" +# echo "" -# Check if RinCoin node is running -if ! sudo docker ps | grep -q "rincoin-node"; then - echo "โŒ Error: rincoin-node container is not running!" - echo "Please start it first:" - echo "sudo docker start rincoin-node" - exit 1 -fi +# # Check if RinCoin node is running +# if ! sudo docker ps | grep -q "rincoin-node"; then +# echo "โŒ Error: rincoin-node container is not running!" +# echo "Please start it first:" +# echo "sudo docker start rincoin-node" +# exit 1 +# fi -echo "โœ… RinCoin node is running" +# echo "โœ… RinCoin node is running" -# Check if Python3 and requests are available -if ! command -v python3 &> /dev/null; then - echo "โŒ Error: python3 is not installed!" - echo "Please install it: sudo apt-get install python3" - exit 1 -fi +# # Check if Python3 and requests are available +# if ! command -v python3 &> /dev/null; then +# echo "โŒ Error: python3 is not installed!" +# echo "Please install it: sudo apt-get install python3" +# exit 1 +# fi -# Install requests if not available -python3 -c "import requests" 2>/dev/null || { - echo "Installing python3-requests..." - sudo apt-get update && sudo apt-get install -y python3-requests -} +# # Install requests if not available +# python3 -c "import requests" 2>/dev/null || { +# echo "Installing python3-requests..." +# sudo apt-get update && sudo apt-get install -y python3-requests +# } -echo "โœ… Python dependencies ready" +# echo "โœ… Python dependencies ready" -# Check if port 3334 is already in use -if netstat -tln | grep -q ":3334 "; then - echo "" - echo "โš ๏ธ Port 3334 is already in use!" - echo "" - echo "๐Ÿ” Process using port 3334:" - sudo netstat -tlnp | grep ":3334 " || echo "Could not determine process" - echo "" - echo "๐Ÿ›‘ To kill existing process:" - echo "sudo lsof -ti:3334 | xargs sudo kill -9" - echo "" - read -p "Kill existing process and continue? (y/N): " -n 1 -r - echo - if [[ $REPLY =~ ^[Yy]$ ]]; then - echo "Killing processes using port 3334..." - sudo lsof -ti:3334 | xargs sudo kill -9 2>/dev/null || echo "No processes to kill" - sleep 2 - else - echo "Exiting..." - exit 1 - fi -fi +# # Check if port 3334 is already in use +# if netstat -tln | grep -q ":3334 "; then +# echo "" +# echo "โš ๏ธ Port 3334 is already in use!" +# echo "" +# echo "๐Ÿ” Process using port 3334:" +# sudo netstat -tlnp | grep ":3334 " || echo "Could not determine process" +# echo "" +# echo "๐Ÿ›‘ To kill existing process:" +# echo "sudo lsof -ti:3334 | xargs sudo kill -9" +# echo "" +# read -p "Kill existing process and continue? (y/N): " -n 1 -r +# echo +# if [[ $REPLY =~ ^[Yy]$ ]]; then +# echo "Killing processes using port 3334..." +# sudo lsof -ti:3334 | xargs sudo kill -9 2>/dev/null || echo "No processes to kill" +# sleep 2 +# else +# echo "Exiting..." +# exit 1 +# fi +# fi -echo "" -echo "๐Ÿš€ Starting Stratum Proxy Server..." -echo "" -echo "After it starts, connect your miner with:" -echo "sudo docker exec -it amd-strix-halo-llama-rocm bash -c \"/mnt/dl/rinhash/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://127.0.0.1:3334 -u user -p pass -t 28\"" -echo "" -echo "Press Ctrl+C to stop the proxy" -echo "" +# echo "" +# echo "๐Ÿš€ Starting Stratum Proxy Server..." +# echo "" +# echo "After it starts, connect your miner with:" +# echo "sudo docker exec -it amd-strix-halo-llama-rocm bash -c \"/mnt/dl/rinhash/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://127.0.0.1:3334 -u user -p pass -t 28\"" +# echo "" +# echo "Press Ctrl+C to stop the proxy" +# echo "" -# Start the proxy -cd "$(dirname "$0")" -python3 stratum_proxy.py --submit-all-blocks +# # Start the proxy +# cd "$(dirname "$0")" +# python3 stratum_proxy.py --submit-all-blocks diff --git a/MINE/rin/start_web_wallet.sh b/MINE/rin/start_web_wallet.sh index 930ee98..9de5c6f 100644 --- a/MINE/rin/start_web_wallet.sh +++ b/MINE/rin/start_web_wallet.sh @@ -1,14 +1,14 @@ -#!/bin/bash +# #!/bin/bash -set -euo pipefail +# set -euo pipefail -SCRIPT_DIR="/mnt/shared/DEV/repos/d-popov.com/scripts/MINE/rin/web_wallet" +# SCRIPT_DIR="/mnt/shared/DEV/repos/d-popov.com/scripts/MINE/rin/web_wallet" -if ! command -v python3 >/dev/null 2>&1; then - echo "python3 is required" - exit 1 -fi +# if ! command -v python3 >/dev/null 2>&1; then +# echo "python3 is required" +# exit 1 +# fi -python3 "${SCRIPT_DIR}/server.py" +# python3 "${SCRIPT_DIR}/server.py" diff --git a/MINE/rin/stratum_pool.py b/MINE/rin/stratum_pool.py index cba81a2..5ef3e8a 100644 --- a/MINE/rin/stratum_pool.py +++ b/MINE/rin/stratum_pool.py @@ -1,602 +1,602 @@ -#!/usr/bin/env python3 -""" -RinCoin Mining Pool Server -Distributes block rewards among multiple miners based on share contributions -""" +# #!/usr/bin/env python3 +# """ +# RinCoin Mining Pool Server +# Distributes block rewards among multiple miners based on share contributions +# """ -import socket -import threading -import json -import time -import requests -import hashlib -import struct -import sqlite3 -from datetime import datetime -from requests.auth import HTTPBasicAuth +# import socket +# import threading +# import json +# import time +# import requests +# import hashlib +# import struct +# import sqlite3 +# from datetime import datetime +# from requests.auth import HTTPBasicAuth -# Import web interface -from pool_web_interface import start_web_interface +# # Import web interface +# from pool_web_interface import start_web_interface -# Import stratum base class -from stratum_proxy import RinCoinStratumBase +# # Import stratum base class +# from stratum_proxy import RinCoinStratumBase -class RinCoinMiningPool(RinCoinStratumBase): - def __init__(self, stratum_host='0.0.0.0', stratum_port=3333, - rpc_host='127.0.0.1', rpc_port=9556, - rpc_user='rinrpc', rpc_password='745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90', - pool_address='rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q', - pool_fee_percent=1.0): +# class RinCoinMiningPool(RinCoinStratumBase): +# def __init__(self, stratum_host='0.0.0.0', stratum_port=3333, +# rpc_host='127.0.0.1', rpc_port=9556, +# rpc_user='rinrpc', rpc_password='745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90', +# pool_address='rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q', +# pool_fee_percent=1.0): - # Initialize base class - super().__init__(stratum_host, stratum_port, rpc_host, rpc_port, rpc_user, rpc_password, pool_address) +# # Initialize base class +# super().__init__(stratum_host, stratum_port, rpc_host, rpc_port, rpc_user, rpc_password, pool_address) - self.pool_address = pool_address - self.pool_fee_percent = pool_fee_percent +# self.pool_address = pool_address +# self.pool_fee_percent = pool_fee_percent - # Pool statistics - self.total_shares = 0 - self.total_blocks = 0 - self.pool_hashrate = 0 +# # Pool statistics +# self.total_shares = 0 +# self.total_blocks = 0 +# self.pool_hashrate = 0 - # Database for persistent storage - self.init_database() +# # Database for persistent storage +# self.init_database() - print(f"=== RinCoin Mining Pool Server ===") - print(f"Stratum: {stratum_host}:{stratum_port}") - print(f"RPC: {rpc_host}:{rpc_port}") - print(f"Pool Address: {pool_address}") - print(f"Pool Fee: {pool_fee_percent}%") +# print(f"=== RinCoin Mining Pool Server ===") +# print(f"Stratum: {stratum_host}:{stratum_port}") +# print(f"RPC: {rpc_host}:{rpc_port}") +# print(f"Pool Address: {pool_address}") +# print(f"Pool Fee: {pool_fee_percent}%") - def init_database(self): - """Initialize SQLite database for miner tracking""" - self.db = sqlite3.connect(':memory:', check_same_thread=False) - cursor = self.db.cursor() +# def init_database(self): +# """Initialize SQLite database for miner tracking""" +# self.db = sqlite3.connect(':memory:', check_same_thread=False) +# cursor = self.db.cursor() - # Create tables - cursor.execute(''' - CREATE TABLE IF NOT EXISTS miners ( - id INTEGER PRIMARY KEY, - user TEXT NOT NULL, - worker TEXT NOT NULL, - address TEXT, - shares INTEGER DEFAULT 0, - last_share TIMESTAMP, - last_hashrate REAL DEFAULT 0, - created TIMESTAMP DEFAULT CURRENT_TIMESTAMP - ) - ''') +# # Create tables +# cursor.execute(''' +# CREATE TABLE IF NOT EXISTS miners ( +# id INTEGER PRIMARY KEY, +# user TEXT NOT NULL, +# worker TEXT NOT NULL, +# address TEXT, +# shares INTEGER DEFAULT 0, +# last_share TIMESTAMP, +# last_hashrate REAL DEFAULT 0, +# created TIMESTAMP DEFAULT CURRENT_TIMESTAMP +# ) +# ''') - cursor.execute(''' - CREATE TABLE IF NOT EXISTS shares ( - id INTEGER PRIMARY KEY, - miner_id INTEGER, - job_id TEXT, - difficulty REAL, - submitted TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (miner_id) REFERENCES miners (id) - ) - ''') +# cursor.execute(''' +# CREATE TABLE IF NOT EXISTS shares ( +# id INTEGER PRIMARY KEY, +# miner_id INTEGER, +# job_id TEXT, +# difficulty REAL, +# submitted TIMESTAMP DEFAULT CURRENT_TIMESTAMP, +# FOREIGN KEY (miner_id) REFERENCES miners (id) +# ) +# ''') - cursor.execute(''' - CREATE TABLE IF NOT EXISTS blocks ( - id INTEGER PRIMARY KEY, - block_hash TEXT, - height INTEGER, - reward REAL, - pool_fee REAL, - miner_rewards TEXT, -- JSON of {address: amount} - found_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP - ) - ''') +# cursor.execute(''' +# CREATE TABLE IF NOT EXISTS blocks ( +# id INTEGER PRIMARY KEY, +# block_hash TEXT, +# height INTEGER, +# reward REAL, +# pool_fee REAL, +# miner_rewards TEXT, -- JSON of {address: amount} +# found_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +# ) +# ''') - # 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 - ) - ''') +# # 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 get_pool_block_template(self): - """Get new block template and create pool-style job""" - template = super().get_block_template() - if template: - # Convert to pool-style job format if needed - job = self.current_job - if job: - # Add pool-specific fields - job["coinb1"] = "01000000" + "0" * 60 - job["coinb2"] = "ffffffff" - job["merkle_branch"] = [] - job["clean_jobs"] = True - return job - return None +# def get_pool_block_template(self): +# """Get new block template and create pool-style job""" +# template = super().get_block_template() +# if template: +# # Convert to pool-style job format if needed +# job = self.current_job +# if job: +# # Add pool-specific fields +# job["coinb1"] = "01000000" + "0" * 60 +# job["coinb2"] = "ffffffff" +# job["merkle_branch"] = [] +# job["clean_jobs"] = True +# return job +# return None - def validate_rincoin_address(self, address): - """Validate if an address is a valid RinCoin address""" - try: - return self.decode_bech32_address(address) is not None - except: - return False +# def validate_rincoin_address(self, address): +# """Validate if an address is a valid RinCoin address""" +# try: +# return self.decode_bech32_address(address) is not None +# except: +# return False - def register_miner(self, user, worker, address=None): - """Register or update miner in database""" - cursor = self.db.cursor() +# def register_miner(self, user, worker, address=None): +# """Register or update miner in database""" +# cursor = self.db.cursor() - # Check if miner exists - cursor.execute('SELECT id, address FROM miners WHERE user = ? AND worker = ?', (user, worker)) - result = cursor.fetchone() +# # Check if miner exists +# cursor.execute('SELECT id, address FROM miners WHERE user = ? AND worker = ?', (user, worker)) +# result = cursor.fetchone() - if result: - miner_id, existing_address = result - if address and not existing_address: - cursor.execute('UPDATE miners SET address = ? WHERE id = ?', (address, miner_id)) - self.db.commit() - return miner_id - else: - # Create new miner - cursor.execute('INSERT INTO miners (user, worker, address) VALUES (?, ?, ?)', (user, worker, address)) - self.db.commit() - return cursor.lastrowid +# if result: +# miner_id, existing_address = result +# if address and not existing_address: +# cursor.execute('UPDATE miners SET address = ? WHERE id = ?', (address, miner_id)) +# self.db.commit() +# return miner_id +# else: +# # Create new miner +# cursor.execute('INSERT INTO miners (user, worker, address) VALUES (?, ?, ?)', (user, worker, address)) +# self.db.commit() +# return cursor.lastrowid - def record_share(self, miner_id, job_id, difficulty): - """Record a share submission""" - cursor = self.db.cursor() +# def record_share(self, miner_id, job_id, difficulty): +# """Record a share submission""" +# cursor = self.db.cursor() - # Record share - cursor.execute('INSERT INTO shares (miner_id, job_id, difficulty) VALUES (?, ?, ?)', - (miner_id, job_id, difficulty)) +# # Record share +# cursor.execute('INSERT INTO shares (miner_id, job_id, difficulty) VALUES (?, ?, ?)', +# (miner_id, job_id, difficulty)) - # Update miner stats - cursor.execute('UPDATE miners SET shares = shares + 1, last_share = CURRENT_TIMESTAMP WHERE id = ?', (miner_id,)) +# # Update miner stats +# cursor.execute('UPDATE miners SET shares = shares + 1, last_share = CURRENT_TIMESTAMP WHERE id = ?', (miner_id,)) - self.db.commit() - self.total_shares += 1 +# self.db.commit() +# self.total_shares += 1 - def distribute_block_reward(self, block_hash, block_height, total_reward): - """Distribute block reward among miners based on their shares""" - cursor = self.db.cursor() +# def distribute_block_reward(self, block_hash, block_height, total_reward): +# """Distribute block reward among miners based on their shares""" +# cursor = self.db.cursor() - # Calculate pool fee - pool_fee = total_reward * (self.pool_fee_percent / 100.0) - miner_reward = total_reward - pool_fee +# # Calculate pool fee +# pool_fee = total_reward * (self.pool_fee_percent / 100.0) +# miner_reward = total_reward - pool_fee - # Get shares from last 24 hours - cursor.execute(''' - SELECT m.address, COUNT(s.id) as share_count, SUM(s.difficulty) as total_difficulty - FROM miners m - JOIN shares s ON m.id = s.miner_id - WHERE s.submitted > datetime('now', '-1 day') - GROUP BY m.id, m.address - HAVING share_count > 0 - ''') +# # Get shares from last 24 hours +# cursor.execute(''' +# SELECT m.address, COUNT(s.id) as share_count, SUM(s.difficulty) as total_difficulty +# FROM miners m +# JOIN shares s ON m.id = s.miner_id +# WHERE s.submitted > datetime('now', '-1 day') +# GROUP BY m.id, m.address +# HAVING share_count > 0 +# ''') - miners = cursor.fetchall() +# miners = cursor.fetchall() - if not miners: - print("No miners with shares in last 24 hours") - return +# if not miners: +# print("No miners with shares in last 24 hours") +# return - # Calculate total difficulty - total_difficulty = sum(row[2] for row in miners) +# # Calculate total difficulty +# total_difficulty = sum(row[2] for row in miners) - # Separate miners with and without addresses - miners_with_addresses = [] - miners_without_addresses = [] - total_difficulty_with_addresses = 0 - total_difficulty_without_addresses = 0 +# # Separate miners with and without addresses +# miners_with_addresses = [] +# miners_without_addresses = [] +# total_difficulty_with_addresses = 0 +# total_difficulty_without_addresses = 0 - for address, share_count, difficulty in miners: - if address: - miners_with_addresses.append((address, share_count, difficulty)) - total_difficulty_with_addresses += difficulty - else: - miners_without_addresses.append((address, share_count, difficulty)) - total_difficulty_without_addresses += difficulty +# for address, share_count, difficulty in miners: +# if address: +# miners_with_addresses.append((address, share_count, difficulty)) +# total_difficulty_with_addresses += difficulty +# else: +# miners_without_addresses.append((address, share_count, difficulty)) +# total_difficulty_without_addresses += difficulty - # Calculate total difficulty - total_difficulty = total_difficulty_with_addresses + total_difficulty_without_addresses +# # Calculate total difficulty +# total_difficulty = total_difficulty_with_addresses + total_difficulty_without_addresses - if total_difficulty == 0: - print("No valid difficulty found") - return +# if total_difficulty == 0: +# print("No valid difficulty found") +# return - # Distribute rewards - miner_rewards = {} +# # Distribute rewards +# miner_rewards = {} - # First, distribute to miners with valid addresses - if miners_with_addresses: - for address, share_count, difficulty in miners_with_addresses: - reward_share = (difficulty / total_difficulty) * miner_reward - miner_rewards[address] = reward_share - print(f"๐Ÿ’ฐ Miner {address}: {reward_share:.8f} RIN ({difficulty} difficulty)") +# # First, distribute to miners with valid addresses +# if miners_with_addresses: +# for address, share_count, difficulty in miners_with_addresses: +# reward_share = (difficulty / total_difficulty) * miner_reward +# miner_rewards[address] = reward_share +# print(f"๐Ÿ’ฐ Miner {address}: {reward_share:.8f} RIN ({difficulty} difficulty)") - # Calculate undistributed rewards (from miners without addresses) - if miners_without_addresses: - undistributed_reward = 0 - for address, share_count, difficulty in miners_without_addresses: - undistributed_reward += (difficulty / total_difficulty) * miner_reward - print(f"โš ๏ธ Miner without address: {difficulty} difficulty -> {undistributed_reward:.8f} RIN to pool") +# # Calculate undistributed rewards (from miners without addresses) +# if miners_without_addresses: +# undistributed_reward = 0 +# for address, share_count, difficulty in miners_without_addresses: +# undistributed_reward += (difficulty / total_difficulty) * miner_reward +# print(f"โš ๏ธ Miner without address: {difficulty} difficulty -> {undistributed_reward:.8f} RIN to pool") - # Keep undistributed rewards for pool (no redistribution) - print(f"๐Ÿ’ฐ Pool keeps {undistributed_reward:.8f} RIN from miners without addresses") +# # Keep undistributed rewards for pool (no redistribution) +# print(f"๐Ÿ’ฐ Pool keeps {undistributed_reward:.8f} RIN from miners without addresses") - # Record block - cursor.execute(''' - INSERT INTO blocks (block_hash, height, reward, pool_fee, miner_rewards) - VALUES (?, ?, ?, ?, ?) - ''', (block_hash, block_height, total_reward, pool_fee, json.dumps(miner_rewards))) +# # Record block +# cursor.execute(''' +# INSERT INTO blocks (block_hash, height, reward, pool_fee, miner_rewards) +# VALUES (?, ?, ?, ?, ?) +# ''', (block_hash, block_height, total_reward, pool_fee, json.dumps(miner_rewards))) - self.db.commit() - self.total_blocks += 1 +# self.db.commit() +# self.total_blocks += 1 - print(f"๐ŸŽ‰ Block {block_height} reward distributed!") - print(f"๐Ÿ’ฐ Pool fee: {pool_fee:.8f} RIN") - print(f"๐Ÿ’ฐ Total distributed: {sum(miner_rewards.values()):.8f} RIN") +# print(f"๐ŸŽ‰ Block {block_height} reward distributed!") +# print(f"๐Ÿ’ฐ Pool fee: {pool_fee:.8f} RIN") +# print(f"๐Ÿ’ฐ Total distributed: {sum(miner_rewards.values()):.8f} RIN") - # Summary - if miners_without_addresses: - print(f"๐Ÿ“Š Summary: {len(miners_with_addresses)} miners with addresses, {len(miners_without_addresses)} without (rewards to pool)") +# # Summary +# if miners_without_addresses: +# print(f"๐Ÿ“Š Summary: {len(miners_with_addresses)} miners with addresses, {len(miners_without_addresses)} without (rewards to pool)") - # Use inherited send_stratum_response and send_stratum_notification from base class +# # Use inherited send_stratum_response and send_stratum_notification from base class - def handle_stratum_message(self, client, addr, message): - """Handle incoming Stratum message from miner""" - try: - data = json.loads(message.strip()) - method = data.get("method") - msg_id = data.get("id") - params = data.get("params", []) +# def handle_stratum_message(self, client, addr, message): +# """Handle incoming Stratum message from miner""" +# try: +# data = json.loads(message.strip()) +# method = data.get("method") +# msg_id = data.get("id") +# params = data.get("params", []) - print(f"[{addr}] {method}: {params}") +# print(f"[{addr}] {method}: {params}") - if method == "mining.subscribe": - # Subscribe response - self.send_stratum_response(client, msg_id, [ - [["mining.set_difficulty", "subscription_id"], ["mining.notify", "subscription_id"]], - "extranonce1", - 4 - ]) +# if method == "mining.subscribe": +# # Subscribe response +# self.send_stratum_response(client, msg_id, [ +# [["mining.set_difficulty", "subscription_id"], ["mining.notify", "subscription_id"]], +# "extranonce1", +# 4 +# ]) - # Send difficulty (lower for CPU mining) - self.send_stratum_notification(client, "mining.set_difficulty", [0.0001]) +# # Send difficulty (lower for CPU mining) +# self.send_stratum_notification(client, "mining.set_difficulty", [0.0001]) - # Send initial job - if self.get_pool_block_template(): - job = self.current_job - self.send_stratum_notification(client, "mining.notify", [ - job["job_id"], - job["prevhash"], - job["coinb1"], - job["coinb2"], - job["merkle_branch"], - f"{job['version']:08x}", - job["bits"], - job["ntime"], - job["clean_jobs"] - ]) +# # Send initial job +# if self.get_pool_block_template(): +# job = self.current_job +# self.send_stratum_notification(client, "mining.notify", [ +# job["job_id"], +# job["prevhash"], +# job["coinb1"], +# job["coinb2"], +# job["merkle_branch"], +# f"{job['version']:08x}", +# job["bits"], +# job["ntime"], +# job["clean_jobs"] +# ]) - elif method == "mining.extranonce.subscribe": - # Handle extranonce subscription - print(f"[{addr}] Extranonce subscription requested") - self.send_stratum_response(client, msg_id, True) +# elif method == "mining.extranonce.subscribe": +# # Handle extranonce subscription +# print(f"[{addr}] Extranonce subscription requested") +# self.send_stratum_response(client, msg_id, True) - elif method == "mining.authorize": - # Parse user.worker format - if len(params) >= 2: - user_worker = params[0] - password = params[1] if len(params) > 1 else "" +# elif method == "mining.authorize": +# # Parse user.worker format +# if len(params) >= 2: +# user_worker = params[0] +# password = params[1] if len(params) > 1 else "" - # Extract user and worker - if '.' in user_worker: - user, worker = user_worker.split('.', 1) - else: - user = user_worker - worker = "default" +# # Extract user and worker +# if '.' in user_worker: +# user, worker = user_worker.split('.', 1) +# else: +# user = user_worker +# worker = "default" - # Check if user contains a RinCoin address (starts with 'rin') - miner_address = None - if user.startswith('rin'): - # User is a RinCoin address - if self.validate_rincoin_address(user): - miner_address = user - user = f"miner_{miner_address[:8]}" # Create a user ID from address - print(f"[{addr}] โœ… Miner using valid RinCoin address: {miner_address}") - else: - print(f"[{addr}] โŒ Invalid RinCoin address: {user}") - self.send_stratum_response(client, msg_id, False, "Invalid RinCoin address") - return - elif '.' in user and user.split('.')[0].startswith('rin'): - # Format: rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q.workername - address_part, worker_part = user.split('.', 1) - if address_part.startswith('rin'): - if self.validate_rincoin_address(address_part): - miner_address = address_part - user = f"miner_{miner_address[:8]}" - worker = worker_part - print(f"[{addr}] โœ… Miner using valid RinCoin address format: {miner_address}.{worker}") - else: - print(f"[{addr}] โŒ Invalid RinCoin address: {address_part}") - self.send_stratum_response(client, msg_id, False, "Invalid RinCoin address") - return +# # Check if user contains a RinCoin address (starts with 'rin') +# miner_address = None +# if user.startswith('rin'): +# # User is a RinCoin address +# if self.validate_rincoin_address(user): +# miner_address = user +# user = f"miner_{miner_address[:8]}" # Create a user ID from address +# print(f"[{addr}] โœ… Miner using valid RinCoin address: {miner_address}") +# else: +# print(f"[{addr}] โŒ Invalid RinCoin address: {user}") +# self.send_stratum_response(client, msg_id, False, "Invalid RinCoin address") +# return +# elif '.' in user and user.split('.')[0].startswith('rin'): +# # Format: rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q.workername +# address_part, worker_part = user.split('.', 1) +# if address_part.startswith('rin'): +# if self.validate_rincoin_address(address_part): +# miner_address = address_part +# user = f"miner_{miner_address[:8]}" +# worker = worker_part +# print(f"[{addr}] โœ… Miner using valid RinCoin address format: {miner_address}.{worker}") +# else: +# print(f"[{addr}] โŒ Invalid RinCoin address: {address_part}") +# self.send_stratum_response(client, msg_id, False, "Invalid RinCoin address") +# return - # Register miner with address - miner_id = self.register_miner(user, worker, miner_address) +# # Register miner with address +# miner_id = self.register_miner(user, worker, miner_address) - # Store client info - self.clients[addr] = { - 'client': client, - 'user': user, - 'worker': worker, - 'miner_id': miner_id, - 'address': miner_address, - 'shares': 0, - 'last_share': time.time(), - 'extranonce1': '00000000' # Default extranonce1 - } +# # Store client info +# self.clients[addr] = { +# 'client': client, +# 'user': user, +# 'worker': worker, +# 'miner_id': miner_id, +# 'address': miner_address, +# 'shares': 0, +# 'last_share': time.time(), +# 'extranonce1': '00000000' # Default extranonce1 +# } - if miner_address: - print(f"[{addr}] โœ… Authorized: {user}.{worker} -> {miner_address}") - else: - print(f"[{addr}] โš ๏ธ Authorized: {user}.{worker} (rewards will go to pool address)") - self.send_stratum_response(client, msg_id, True) - else: - self.send_stratum_response(client, msg_id, False, "Invalid authorization") +# if miner_address: +# print(f"[{addr}] โœ… Authorized: {user}.{worker} -> {miner_address}") +# else: +# print(f"[{addr}] โš ๏ธ Authorized: {user}.{worker} (rewards will go to pool address)") +# self.send_stratum_response(client, msg_id, True) +# else: +# self.send_stratum_response(client, msg_id, False, "Invalid authorization") - elif method == "mining.submit": - # Submit share - if addr not in self.clients: - self.send_stratum_response(client, msg_id, False, "Not authorized") - return +# elif method == "mining.submit": +# # Submit share +# if addr not in self.clients: +# self.send_stratum_response(client, msg_id, False, "Not authorized") +# return - miner_info = self.clients[addr] +# miner_info = self.clients[addr] - try: - if self.current_job and len(params) >= 5: - username = params[0] - job_id = params[1] - extranonce2 = params[2] - ntime = params[3] - nonce = params[4] +# try: +# if self.current_job and len(params) >= 5: +# username = params[0] +# job_id = params[1] +# extranonce2 = params[2] +# ntime = params[3] +# nonce = params[4] - # Use base class to validate and submit share - extranonce1 = miner_info.get('extranonce1', '00000000') - miner_address = miner_info.get('address') +# # Use base class to validate and submit share +# extranonce1 = miner_info.get('extranonce1', '00000000') +# miner_address = miner_info.get('address') - # For pool mining, always mine to pool address - success, message = self.submit_share( - self.current_job, extranonce1, extranonce2, ntime, nonce, - target_address=self.pool_address - ) +# # For pool mining, always mine to pool address +# success, message = self.submit_share( +# self.current_job, extranonce1, extranonce2, ntime, nonce, +# target_address=self.pool_address +# ) - if success: - # Record share with estimated difficulty - actual_difficulty = 0.00133 # Estimated for ~381 kH/s - self.record_share(miner_info['miner_id'], job_id, actual_difficulty) +# if success: +# # Record share with estimated difficulty +# actual_difficulty = 0.00133 # Estimated for ~381 kH/s +# self.record_share(miner_info['miner_id'], job_id, actual_difficulty) - # Update miner stats - now_ts = time.time() - prev_ts = miner_info.get('last_share') or now_ts - dt = max(now_ts - prev_ts, 1e-3) - miner_hashrate = actual_difficulty * (2**32) / dt +# # Update miner stats +# now_ts = time.time() +# prev_ts = miner_info.get('last_share') or now_ts +# dt = max(now_ts - prev_ts, 1e-3) +# miner_hashrate = actual_difficulty * (2**32) / dt - if miner_info['shares'] == 0: - miner_hashrate = 381000 # Default estimate - miner_info['shares'] += 1 - miner_info['last_share'] = now_ts +# if miner_info['shares'] == 0: +# miner_hashrate = 381000 # Default estimate +# miner_info['shares'] += 1 +# miner_info['last_share'] = now_ts - # Update database - 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 error: {e}") +# # Update database +# 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 error: {e}") - print(f"[{addr}] โœ… Share accepted from {miner_info['user']}.{miner_info['worker']} (Total: {miner_info['shares']})") - self.send_stratum_response(client, msg_id, True) +# print(f"[{addr}] โœ… Share accepted from {miner_info['user']}.{miner_info['worker']} (Total: {miner_info['shares']})") +# self.send_stratum_response(client, msg_id, True) - # If block was found, distribute rewards - if "Block found" in message: - print(f"๐ŸŽ‰ [{addr}] BLOCK FOUND!") - # Get block info and distribute rewards - total_reward = self.current_job['coinbasevalue'] / 100000000 if self.current_job else 25.0 - self.distribute_block_reward("pending", self.current_job['height'] if self.current_job else 0, total_reward) - else: - # Accept as share for pool statistics even if block validation fails - self.send_stratum_response(client, msg_id, True) - else: - print(f"[{addr}] Invalid share parameters") - self.send_stratum_response(client, msg_id, False, "Invalid parameters") +# # If block was found, distribute rewards +# if "Block found" in message: +# print(f"๐ŸŽ‰ [{addr}] BLOCK FOUND!") +# # Get block info and distribute rewards +# total_reward = self.current_job['coinbasevalue'] / 100000000 if self.current_job else 25.0 +# self.distribute_block_reward("pending", self.current_job['height'] if self.current_job else 0, total_reward) +# else: +# # Accept as share for pool statistics even if block validation fails +# self.send_stratum_response(client, msg_id, True) +# else: +# print(f"[{addr}] Invalid share parameters") +# self.send_stratum_response(client, msg_id, False, "Invalid parameters") - except Exception as e: - print(f"[{addr}] Share processing error: {e}") - # Still accept the share for mining statistics - self.send_stratum_response(client, msg_id, True) +# except Exception as e: +# print(f"[{addr}] Share processing error: {e}") +# # Still accept the share for mining statistics +# self.send_stratum_response(client, msg_id, True) - else: - print(f"[{addr}] โš ๏ธ Unknown method: {method}") - # Send null result for unknown methods (standard Stratum behavior) - self.send_stratum_response(client, msg_id, None, None) +# else: +# print(f"[{addr}] โš ๏ธ Unknown method: {method}") +# # Send null result for unknown methods (standard Stratum behavior) +# self.send_stratum_response(client, msg_id, None, None) - except json.JSONDecodeError: - print(f"[{addr}] Invalid JSON: {message}") - except Exception as e: - print(f"[{addr}] Message handling error: {e}") +# except json.JSONDecodeError: +# print(f"[{addr}] Invalid JSON: {message}") +# except Exception as e: +# print(f"[{addr}] Message handling error: {e}") - def handle_client(self, client, addr): - """Handle individual client connection""" - print(f"[{addr}] Connected") +# def handle_client(self, client, addr): +# """Handle individual client connection""" +# print(f"[{addr}] Connected") - try: - while self.running: - data = client.recv(4096) - if not data: - break +# try: +# while self.running: +# data = client.recv(4096) +# if not data: +# break - # Handle multiple messages in one packet - messages = data.decode('utf-8').strip().split('\n') - for message in messages: - if message: - self.handle_stratum_message(client, addr, message) +# # Handle multiple messages in one packet +# messages = data.decode('utf-8').strip().split('\n') +# for message in messages: +# if message: +# self.handle_stratum_message(client, addr, message) - except Exception as e: - print(f"[{addr}] Client error: {e}") - finally: - client.close() - if addr in self.clients: - del self.clients[addr] - print(f"[{addr}] Disconnected") +# except Exception as e: +# print(f"[{addr}] Client error: {e}") +# finally: +# client.close() +# if addr in self.clients: +# del self.clients[addr] +# print(f"[{addr}] Disconnected") - def job_updater(self): - """Periodically update mining jobs""" - last_job_time = 0 - last_block_height = 0 +# def job_updater(self): +# """Periodically update mining jobs""" +# last_job_time = 0 +# last_block_height = 0 - while self.running: - try: - # Check for new blocks every 10 seconds - time.sleep(10) +# while self.running: +# try: +# # Check for new blocks every 10 seconds +# time.sleep(10) - # Get current blockchain info - blockchain_info = self.rpc_call("getblockchaininfo") - if blockchain_info: - current_height = blockchain_info.get('blocks', 0) +# # Get current blockchain info +# blockchain_info = self.rpc_call("getblockchaininfo") +# if blockchain_info: +# current_height = blockchain_info.get('blocks', 0) - # Create new job if: - # 1. New block detected - # 2. 30+ seconds since last job - # 3. No current job exists - should_create_job = ( - current_height != last_block_height or - time.time() - last_job_time > 30 or - not self.current_job - ) +# # Create new job if: +# # 1. New block detected +# # 2. 30+ seconds since last job +# # 3. No current job exists +# should_create_job = ( +# current_height != last_block_height or +# time.time() - last_job_time > 30 or +# not self.current_job +# ) - if should_create_job: - if self.get_pool_block_template(): - job = self.current_job - last_job_time = time.time() - last_block_height = current_height +# if should_create_job: +# if self.get_pool_block_template(): +# job = self.current_job +# last_job_time = time.time() +# last_block_height = current_height - print(f"๐Ÿ“ฆ New job created: {job['job_id']} (block {current_height})") +# print(f"๐Ÿ“ฆ New job created: {job['job_id']} (block {current_height})") - # Send to all connected clients - for addr, miner_info in list(self.clients.items()): - try: - self.send_stratum_notification(miner_info['client'], "mining.notify", [ - job["job_id"], - job["prevhash"], - job["coinb1"], - job["coinb2"], - job["merkle_branch"], - f"{job['version']:08x}", - job["bits"], - job["ntime"], - job["clean_jobs"] - ]) - except Exception as e: - print(f"Failed to send job to {addr}: {e}") +# # Send to all connected clients +# for addr, miner_info in list(self.clients.items()): +# try: +# self.send_stratum_notification(miner_info['client'], "mining.notify", [ +# job["job_id"], +# job["prevhash"], +# job["coinb1"], +# job["coinb2"], +# job["merkle_branch"], +# f"{job['version']:08x}", +# job["bits"], +# job["ntime"], +# job["clean_jobs"] +# ]) +# except Exception as e: +# print(f"Failed to send job to {addr}: {e}") - except Exception as e: - print(f"Job updater error: {e}") +# except Exception as e: +# print(f"Job updater error: {e}") - def stats_updater(self): - """Periodically update pool statistics""" - while self.running: - try: - time.sleep(60) # Update every minute - cursor = self.db.cursor() - # Pool hashrate is the sum of miners' last hashrates - cursor.execute('SELECT COALESCE(SUM(last_hashrate), 0) FROM miners') - self.pool_hashrate = cursor.fetchone()[0] or 0.0 - # Sample for chart - cursor.execute('INSERT INTO hashrate_samples (hashrate) VALUES (?)', (self.pool_hashrate,)) - self.db.commit() - print(f"๐Ÿ“Š Pool Stats: {len(self.clients)} miners, {self.total_shares} shares, {self.pool_hashrate/1000:.2f} kH/s") +# def stats_updater(self): +# """Periodically update pool statistics""" +# while self.running: +# try: +# time.sleep(60) # Update every minute +# cursor = self.db.cursor() +# # Pool hashrate is the sum of miners' last hashrates +# cursor.execute('SELECT COALESCE(SUM(last_hashrate), 0) FROM miners') +# self.pool_hashrate = cursor.fetchone()[0] or 0.0 +# # Sample for chart +# cursor.execute('INSERT INTO hashrate_samples (hashrate) VALUES (?)', (self.pool_hashrate,)) +# self.db.commit() +# print(f"๐Ÿ“Š Pool Stats: {len(self.clients)} miners, {self.total_shares} shares, {self.pool_hashrate/1000:.2f} kH/s") - except Exception as e: - print(f"Stats updater error: {e}") +# except Exception as e: +# print(f"Stats updater error: {e}") - def start(self): - """Start the mining pool server""" - try: - # Test RPC connection - blockchain_info = self.rpc_call("getblockchaininfo") - if not blockchain_info: - print("โŒ Failed to connect to RinCoin node!") - return +# def start(self): +# """Start the mining pool server""" +# try: +# # Test RPC connection +# blockchain_info = self.rpc_call("getblockchaininfo") +# if not blockchain_info: +# print("โŒ Failed to connect to RinCoin node!") +# return - print(f"โœ… Connected to RinCoin node (block {blockchain_info.get('blocks', 'unknown')})") +# print(f"โœ… Connected to RinCoin node (block {blockchain_info.get('blocks', 'unknown')})") - # Start background threads - job_thread = threading.Thread(target=self.job_updater, daemon=True) - job_thread.start() +# # Start background threads +# job_thread = threading.Thread(target=self.job_updater, daemon=True) +# job_thread.start() - stats_thread = threading.Thread(target=self.stats_updater, daemon=True) - stats_thread.start() +# stats_thread = threading.Thread(target=self.stats_updater, daemon=True) +# stats_thread.start() - # Start web interface in background - web_thread = threading.Thread(target=start_web_interface, - args=(self.db, '0.0.0.0', 8083, - self.rpc_host, self.rpc_port, - self.rpc_user, self.rpc_password), - daemon=True) - web_thread.start() +# # Start web interface in background +# web_thread = threading.Thread(target=start_web_interface, +# args=(self.db, '0.0.0.0', 8083, +# self.rpc_host, self.rpc_port, +# self.rpc_user, self.rpc_password), +# daemon=True) +# web_thread.start() - print(f"๐ŸŒ Web dashboard started on http://0.0.0.0:8083") +# print(f"๐ŸŒ Web dashboard started on http://0.0.0.0:8083") - # Start Stratum server - server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - server_socket.bind((self.stratum_host, self.stratum_port)) - server_socket.listen(10) +# # Start Stratum server +# server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) +# server_socket.bind((self.stratum_host, self.stratum_port)) +# server_socket.listen(10) - print(f"๐Ÿš€ Mining pool listening on {self.stratum_host}:{self.stratum_port}") - print("Ready for multiple miners...") - print("") - print(f"๐Ÿ’ฐ Pool address: {self.pool_address}") - print(f"๐Ÿ’ฐ Pool fee: {self.pool_fee_percent}%") - print("") - print("Connect miners with:") - print(f"./cpuminer -a rinhash -o stratum+tcp://{self.stratum_host}:{self.stratum_port} -u username.workername -p x") - print("") +# print(f"๐Ÿš€ Mining pool listening on {self.stratum_host}:{self.stratum_port}") +# print("Ready for multiple miners...") +# print("") +# print(f"๐Ÿ’ฐ Pool address: {self.pool_address}") +# print(f"๐Ÿ’ฐ Pool fee: {self.pool_fee_percent}%") +# print("") +# print("Connect miners with:") +# print(f"./cpuminer -a rinhash -o stratum+tcp://{self.stratum_host}:{self.stratum_port} -u username.workername -p x") +# print("") - while self.running: - try: - client, addr = server_socket.accept() - client_thread = threading.Thread(target=self.handle_client, args=(client, addr), daemon=True) - client_thread.start() - except KeyboardInterrupt: - print("\n๐Ÿ›‘ Shutting down pool...") - self.running = False - break - except Exception as e: - print(f"Server error: {e}") +# while self.running: +# try: +# client, addr = server_socket.accept() +# client_thread = threading.Thread(target=self.handle_client, args=(client, addr), daemon=True) +# client_thread.start() +# except KeyboardInterrupt: +# print("\n๐Ÿ›‘ Shutting down pool...") +# self.running = False +# break +# except Exception as e: +# print(f"Server error: {e}") - except OSError as e: - if "Address already in use" in str(e): - print(f"โŒ Port {self.stratum_port} is already in use!") - print("") - print("๐Ÿ” Check what's using the port:") - print(f"sudo netstat -tlnp | grep :{self.stratum_port}") - print("") - print("๐Ÿ›‘ Kill existing process:") - print(f"sudo lsof -ti:{self.stratum_port} | xargs sudo kill -9") - print("") - print("๐Ÿ”„ Or use a different port by editing the script") - else: - print(f"Failed to start server: {e}") - except Exception as e: - print(f"Failed to start server: {e}") - finally: - print("Pool server stopped") +# except OSError as e: +# if "Address already in use" in str(e): +# print(f"โŒ Port {self.stratum_port} is already in use!") +# print("") +# print("๐Ÿ” Check what's using the port:") +# print(f"sudo netstat -tlnp | grep :{self.stratum_port}") +# print("") +# print("๐Ÿ›‘ Kill existing process:") +# print(f"sudo lsof -ti:{self.stratum_port} | xargs sudo kill -9") +# print("") +# print("๐Ÿ”„ Or use a different port by editing the script") +# else: +# print(f"Failed to start server: {e}") +# except Exception as e: +# print(f"Failed to start server: {e}") +# finally: +# print("Pool server stopped") -if __name__ == "__main__": - pool = RinCoinMiningPool() - pool.start() +# if __name__ == "__main__": +# pool = RinCoinMiningPool() +# pool.start() diff --git a/MINE/rin/stratum_proxy.py b/MINE/rin/stratum_proxy.py index 5ce89b3..3833e9d 100644 --- a/MINE/rin/stratum_proxy.py +++ b/MINE/rin/stratum_proxy.py @@ -1,1350 +1,1350 @@ -#!/usr/bin/env python3 -""" -stratum_proxy.py -RinCoin Stratum Proxy Server -DEBUG RPC: we get node logs with 'docker logs --tail=200 rincoin-node' -MINE: /mnt/shared/DEV/repos/d-popov.com/mines/rin/miner/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://localhost:3334 -u x -p x -t 32 -""" +# #!/usr/bin/env python3 +# """ +# stratum_proxy.py +# RinCoin Stratum Proxy Server +# DEBUG RPC: we get node logs with 'docker logs --tail=200 rincoin-node' +# MINE: /mnt/shared/DEV/repos/d-popov.com/mines/rin/miner/cpuminer-opt-rin/cpuminer -a rinhash -o stratum+tcp://localhost:3334 -u x -p x -t 32 +# """ -import socket -import threading -import json -import time -import requests -import hashlib -import struct -from requests.auth import HTTPBasicAuth +# import socket +# import threading +# import json +# import time +# import requests +# import hashlib +# import struct +# from requests.auth import HTTPBasicAuth -class RinCoinStratumProxy: - def __init__(self, stratum_host='0.0.0.0', stratum_port=3334, - rpc_host='127.0.0.1', rpc_port=9556, - rpc_user='rinrpc', rpc_password='745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90', - target_address='rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q', - submit_all_blocks=False, submit_threshold=0.1): +# class RinCoinStratumProxy: +# def __init__(self, stratum_host='0.0.0.0', stratum_port=3334, +# rpc_host='127.0.0.1', rpc_port=9556, +# rpc_user='rinrpc', rpc_password='745ce784d5d537fc06105a1b935b7657903cfc71a5fb3b90', +# target_address='rin1qahvvv9d5f3443wtckeqavwp9950wacxfmwv20q', +# submit_all_blocks=False, submit_threshold=0.1): - self.stratum_host = stratum_host - self.stratum_port = stratum_port - self.rpc_host = rpc_host - self.rpc_port = rpc_port - self.rpc_user = rpc_user - self.rpc_password = rpc_password - self.target_address = target_address - self.submit_all_blocks = submit_all_blocks - # For debugging: submit blocks that meet this fraction of network difficulty - self.submit_threshold = submit_threshold # Configurable percentage of network difficulty +# self.stratum_host = stratum_host +# self.stratum_port = stratum_port +# self.rpc_host = rpc_host +# self.rpc_port = rpc_port +# self.rpc_user = rpc_user +# self.rpc_password = rpc_password +# self.target_address = target_address +# self.submit_all_blocks = submit_all_blocks +# # For debugging: submit blocks that meet this fraction of network difficulty +# self.submit_threshold = submit_threshold # Configurable percentage of network difficulty - self.clients = {} - self.job_counter = 0 - self.current_job = None - self.running = True - self.extranonce1_counter = 0 +# self.clients = {} +# self.job_counter = 0 +# self.current_job = None +# 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 = 15 # Target: 1 share every 15 seconds (optimal for 1-min blocks) +# # Dynamic difficulty adjustment +# self.share_stats = {} # Track shares per client +# self.last_difficulty_adjustment = time.time() +# self.target_share_interval = 15 # Target: 1 share every 15 seconds (optimal for 1-min blocks) - # Production monitoring - self.stats = { - 'start_time': time.time(), - 'total_shares': 0, - 'accepted_shares': 0, - 'rejected_shares': 0, - 'blocks_found': 0, - 'total_hashrate': 0, - 'connections': 0, - 'last_share_time': time.time(), - 'shares_last_minute': [], - 'current_share_rate': 0.0 - } - self.max_connections = 50 # Production limit +# # Production monitoring +# self.stats = { +# 'start_time': time.time(), +# 'total_shares': 0, +# 'accepted_shares': 0, +# 'rejected_shares': 0, +# 'blocks_found': 0, +# 'total_hashrate': 0, +# 'connections': 0, +# 'last_share_time': time.time(), +# 'shares_last_minute': [], +# 'current_share_rate': 0.0 +# } +# self.max_connections = 50 # Production limit - # Logging setup - self.log_file = "mining_log.txt" - self.init_log_file() +# # Logging setup +# self.log_file = "mining_log.txt" +# self.init_log_file() - print(f"RinCoin Stratum Proxy Server") - print(f"Stratum: {stratum_host}:{stratum_port}") - print(f"RPC: {rpc_host}:{rpc_port}") - print(f"Target: {target_address}") +# print(f"RinCoin Stratum Proxy Server") +# print(f"Stratum: {stratum_host}:{stratum_port}") +# print(f"RPC: {rpc_host}:{rpc_port}") +# print(f"Target: {target_address}") - def init_log_file(self): - """Initialize mining log file with header""" - try: - with open(self.log_file, 'w') as f: - f.write("=" * 80 + "\n") - f.write("RinCoin Mining Log\n") - f.write("=" * 80 + "\n") - f.write(f"Started: {time.strftime('%Y-%m-%d %H:%M:%S')}\n") - f.write(f"Target Address: {self.target_address}\n") - f.write(f"Stratum: {self.stratum_host}:{self.stratum_port}\n") - f.write(f"RPC: {self.rpc_host}:{self.rpc_port}\n") - f.write("=" * 80 + "\n\n") - except Exception as e: - print(f"Failed to initialize log file: {e}") +# def init_log_file(self): +# """Initialize mining log file with header""" +# try: +# with open(self.log_file, 'w') as f: +# f.write("=" * 80 + "\n") +# f.write("RinCoin Mining Log\n") +# f.write("=" * 80 + "\n") +# f.write(f"Started: {time.strftime('%Y-%m-%d %H:%M:%S')}\n") +# f.write(f"Target Address: {self.target_address}\n") +# f.write(f"Stratum: {self.stratum_host}:{self.stratum_port}\n") +# f.write(f"RPC: {self.rpc_host}:{self.rpc_port}\n") +# f.write("=" * 80 + "\n\n") +# except Exception as e: +# print(f"Failed to initialize log file: {e}") - def log_hash_found(self, hash_hex, difficulty, height, reward, nonce, ntime): - """Log found hash to file""" - try: - timestamp = time.strftime('%Y-%m-%d %H:%M:%S') - with open(self.log_file, 'a') as f: - f.write(f"[{timestamp}] ๐ŸŽ‰ HASH FOUND!\n") - f.write(f" Hash: {hash_hex}\n") - f.write(f" Difficulty: {difficulty:.6f}\n") - f.write(f" Height: {height}\n") - f.write(f" Reward: {reward:.8f} RIN\n") - f.write(f" Nonce: {nonce}\n") - f.write(f" Time: {ntime}\n") - f.write("-" * 40 + "\n") - except Exception as e: - print(f"Failed to log hash: {e}") +# def log_hash_found(self, hash_hex, difficulty, height, reward, nonce, ntime): +# """Log found hash to file""" +# try: +# timestamp = time.strftime('%Y-%m-%d %H:%M:%S') +# with open(self.log_file, 'a') as f: +# f.write(f"[{timestamp}] ๐ŸŽ‰ HASH FOUND!\n") +# f.write(f" Hash: {hash_hex}\n") +# f.write(f" Difficulty: {difficulty:.6f}\n") +# f.write(f" Height: {height}\n") +# f.write(f" Reward: {reward:.8f} RIN\n") +# f.write(f" Nonce: {nonce}\n") +# f.write(f" Time: {ntime}\n") +# f.write("-" * 40 + "\n") +# except Exception as e: +# print(f"Failed to log hash: {e}") - def log_wallet_balance(self): - """Log current wallet balance to file""" - try: - balance = self.rpc_call("getbalance") - if balance is not None: - timestamp = time.strftime('%Y-%m-%d %H:%M:%S') - with open(self.log_file, 'a') as f: - f.write(f"[{timestamp}] ๐Ÿ’ฐ Wallet Balance: {balance:.8f} RIN\n") - except Exception as e: - print(f"Failed to log wallet balance: {e}") +# def log_wallet_balance(self): +# """Log current wallet balance to file""" +# try: +# balance = self.rpc_call("getbalance") +# if balance is not None: +# timestamp = time.strftime('%Y-%m-%d %H:%M:%S') +# with open(self.log_file, 'a') as f: +# f.write(f"[{timestamp}] ๐Ÿ’ฐ Wallet Balance: {balance:.8f} RIN\n") +# except Exception as e: +# print(f"Failed to log wallet balance: {e}") - def rpc_call(self, method, params=[]): - """Make RPC call to RinCoin node""" - try: - url = f"http://{self.rpc_host}:{self.rpc_port}/" - headers = {'content-type': 'text/plain'} - auth = HTTPBasicAuth(self.rpc_user, self.rpc_password) +# def rpc_call(self, method, params=[]): +# """Make RPC call to RinCoin node""" +# try: +# url = f"http://{self.rpc_host}:{self.rpc_port}/" +# headers = {'content-type': 'text/plain'} +# auth = HTTPBasicAuth(self.rpc_user, self.rpc_password) - payload = { - "jsonrpc": "1.0", - "id": "stratum_proxy", - "method": method, - "params": params - } +# payload = { +# "jsonrpc": "1.0", +# "id": "stratum_proxy", +# "method": method, +# "params": params +# } - response = requests.post(url, json=payload, headers=headers, auth=auth, timeout=30) +# response = requests.post(url, json=payload, headers=headers, auth=auth, timeout=30) - if response.status_code == 200: - result = response.json() - if 'error' in result and result['error'] is not None: - print(f"RPC Error: {result['error']}") - return None - return result.get('result') - else: - print(f"HTTP Error: {response.status_code}") - return None +# if response.status_code == 200: +# result = response.json() +# if 'error' in result and result['error'] is not None: +# print(f"RPC Error: {result['error']}") +# return None +# return result.get('result') +# else: +# print(f"HTTP Error: {response.status_code}") +# return None - except Exception as e: - print(f"RPC Call Error: {e}") - return None +# except Exception as e: +# print(f"RPC Call Error: {e}") +# return None - def encode_varint(self, n): - """Encode integer as Bitcoin-style varint""" - if n < 0xfd: - return bytes([n]) - elif n <= 0xffff: - return b"\xfd" + struct.pack(' bytes: - outputs_blob = b'' - outputs_list = [] - # Main output - outputs_list.append(struct.pack(' bytes: +# outputs_blob = b'' +# outputs_list = [] +# # Main output +# outputs_list.append(struct.pack(' 1: - if len(hashes) % 2 == 1: - hashes.append(hashes[-1]) # Duplicate last hash if odd +# # Build merkle tree +# while len(hashes) > 1: +# if len(hashes) % 2 == 1: +# hashes.append(hashes[-1]) # Duplicate last hash if odd - next_level = [] - for i in range(0, len(hashes), 2): - combined = hashes[i] + hashes[i + 1] - next_level.append(hashlib.sha256(hashlib.sha256(combined).digest()).digest()) +# next_level = [] +# for i in range(0, len(hashes), 2): +# combined = hashes[i] + hashes[i + 1] +# next_level.append(hashlib.sha256(hashlib.sha256(combined).digest()).digest()) - hashes = next_level +# hashes = next_level - return hashes[0] if hashes else b'\x00' * 32 +# return hashes[0] if hashes else b'\x00' * 32 - except Exception as e: - print(f"Merkle root calculation error: {e}") - return b'\x00' * 32 +# except Exception as e: +# print(f"Merkle root calculation error: {e}") +# return b'\x00' * 32 - def calculate_merkle_branches(self, tx_hashes, tx_index): - """Calculate merkle branches for a specific transaction index""" - try: - if not tx_hashes or tx_index >= len(tx_hashes): - return [] +# def calculate_merkle_branches(self, tx_hashes, tx_index): +# """Calculate merkle branches for a specific transaction index""" +# try: +# if not tx_hashes or tx_index >= len(tx_hashes): +# return [] - branches = [] - current_index = tx_index +# branches = [] +# current_index = tx_index - # Start with the full list of transaction hashes - hashes = tx_hashes[:] +# # Start with the full list of transaction hashes +# hashes = tx_hashes[:] - while len(hashes) > 1: - if len(hashes) % 2 == 1: - hashes.append(hashes[-1]) # Duplicate last hash if odd +# while len(hashes) > 1: +# if len(hashes) % 2 == 1: +# hashes.append(hashes[-1]) # Duplicate last hash if odd - # Find the partner for current_index - partner_index = current_index ^ 1 # Flip the least significant bit +# # Find the partner for current_index +# partner_index = current_index ^ 1 # Flip the least significant bit - if partner_index < len(hashes): - # Add the partner hash to branches (in big-endian for stratum) - branches.append(hashes[partner_index][::-1].hex()) - else: - # This shouldn't happen, but add the duplicate if it does - branches.append(hashes[current_index][::-1].hex()) +# if partner_index < len(hashes): +# # Add the partner hash to branches (in big-endian for stratum) +# branches.append(hashes[partner_index][::-1].hex()) +# else: +# # This shouldn't happen, but add the duplicate if it does +# branches.append(hashes[current_index][::-1].hex()) - # Move to next level - next_level = [] - for i in range(0, len(hashes), 2): - combined = hashes[i] + hashes[i + 1] - next_level.append(hashlib.sha256(hashlib.sha256(combined).digest()).digest()) +# # Move to next level +# next_level = [] +# for i in range(0, len(hashes), 2): +# combined = hashes[i] + hashes[i + 1] +# next_level.append(hashlib.sha256(hashlib.sha256(combined).digest()).digest()) - hashes = next_level - current_index //= 2 +# hashes = next_level +# current_index //= 2 - return branches +# return branches - except Exception as e: - print(f"Merkle branches calculation error: {e}") - return [] +# except Exception as e: +# print(f"Merkle branches calculation error: {e}") +# return [] - def bits_to_target(self, bits_hex): - """Convert bits to target - FIXED VERSION""" - try: - bits = int(bits_hex, 16) - exponent = bits >> 24 - mantissa = bits & 0xffffff +# def bits_to_target(self, bits_hex): +# """Convert bits to target - FIXED VERSION""" +# try: +# bits = int(bits_hex, 16) +# exponent = bits >> 24 +# mantissa = bits & 0xffffff - # Bitcoin target calculation - if exponent <= 3: - target = mantissa >> (8 * (3 - exponent)) - else: - target = mantissa << (8 * (exponent - 3)) +# # Bitcoin target calculation +# if exponent <= 3: +# target = mantissa >> (8 * (3 - exponent)) +# else: +# target = mantissa << (8 * (exponent - 3)) - return f"{target:064x}" - except Exception as e: - print(f"Bits to target error: {e}") - return "0000ffff00000000000000000000000000000000000000000000000000000000" +# return f"{target:064x}" +# except Exception as e: +# print(f"Bits to target error: {e}") +# return "0000ffff00000000000000000000000000000000000000000000000000000000" - def get_block_template(self): - """Get new block template and create Stratum job""" - try: - template = self.rpc_call("getblocktemplate", [{"rules": ["segwit", "mweb"]}]) - if not template: - return None +# def get_block_template(self): +# """Get new block template and create Stratum job""" +# try: +# template = self.rpc_call("getblocktemplate", [{"rules": ["segwit", "mweb"]}]) +# if not template: +# return None - self.job_counter += 1 +# self.job_counter += 1 - job = { - "job_id": f"job_{self.job_counter:08x}", - "template": template, - "prevhash": template.get("previousblockhash", "0" * 64), - "version": template.get('version', 1), - "bits": template.get('bits', '1d00ffff'), - "ntime": f"{int(time.time()):08x}", - "target": self.bits_to_target(template.get('bits', '1d00ffff')), - "height": template.get('height', 0), - "coinbasevalue": template.get('coinbasevalue', 0), - "transactions": template.get('transactions', []) - } +# job = { +# "job_id": f"job_{self.job_counter:08x}", +# "template": template, +# "prevhash": template.get("previousblockhash", "0" * 64), +# "version": template.get('version', 1), +# "bits": template.get('bits', '1d00ffff'), +# "ntime": f"{int(time.time()):08x}", +# "target": self.bits_to_target(template.get('bits', '1d00ffff')), +# "height": template.get('height', 0), +# "coinbasevalue": template.get('coinbasevalue', 0), +# "transactions": template.get('transactions', []) +# } - self.current_job = job - timestamp = time.strftime("%Y-%m-%d %H:%M:%S") - network_difficulty = self.calculate_network_difficulty(job['target']) - print(f"[{timestamp}] ๐Ÿ†• NEW JOB: {job['job_id']} | Height: {job['height']} | Reward: {job['coinbasevalue']/100000000:.2f} RIN") - print(f" ๐ŸŽฏ Network Difficulty: {network_difficulty:.6f} | Bits: {job['bits']}") - print(f" ๐Ÿ“ Target: {job['target'][:16]}... | Transactions: {len(job['transactions'])}") - return job +# self.current_job = job +# timestamp = time.strftime("%Y-%m-%d %H:%M:%S") +# network_difficulty = self.calculate_network_difficulty(job['target']) +# print(f"[{timestamp}] ๐Ÿ†• NEW JOB: {job['job_id']} | Height: {job['height']} | Reward: {job['coinbasevalue']/100000000:.2f} RIN") +# print(f" ๐ŸŽฏ Network Difficulty: {network_difficulty:.6f} | Bits: {job['bits']}") +# print(f" ๐Ÿ“ Target: {job['target'][:16]}... | Transactions: {len(job['transactions'])}") +# return job - except Exception as e: - print(f"Get block template error: {e}") - return None +# except Exception as e: +# print(f"Get block template error: {e}") +# return None - def calculate_share_difficulty(self, hash_hex, target_hex): - """Calculate actual share difficulty from hash - FIXED""" - try: - hash_int = int(hash_hex, 16) +# def calculate_share_difficulty(self, hash_hex, target_hex): +# """Calculate actual share difficulty from hash - FIXED""" +# try: +# hash_int = int(hash_hex, 16) - if hash_int == 0: - return float('inf') # Perfect hash +# if hash_int == 0: +# return float('inf') # Perfect hash - # Bitcoin-style difficulty calculation using difficulty 1 target - # Difficulty 1 target for mainnet - diff1_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 +# # Bitcoin-style difficulty calculation using difficulty 1 target +# # Difficulty 1 target for mainnet +# diff1_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 - # Share difficulty = how much harder this hash was compared to diff 1 - difficulty = diff1_target / hash_int +# # Share difficulty = how much harder this hash was compared to diff 1 +# difficulty = diff1_target / hash_int - return difficulty - except Exception as e: - print(f"Difficulty calculation error: {e}") - return 0.0 +# return difficulty +# except Exception as e: +# print(f"Difficulty calculation error: {e}") +# return 0.0 - def calculate_network_difficulty(self, target_hex): - """Calculate network difficulty from target - FIXED""" - try: - target_int = int(target_hex, 16) +# def calculate_network_difficulty(self, target_hex): +# """Calculate network difficulty from target - FIXED""" +# try: +# target_int = int(target_hex, 16) - # Bitcoin difficulty 1.0 target - diff1_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 +# # Bitcoin difficulty 1.0 target +# diff1_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 - # Network difficulty = how much harder than difficulty 1.0 - network_difficulty = diff1_target / target_int +# # Network difficulty = how much harder than difficulty 1.0 +# network_difficulty = diff1_target / target_int - return network_difficulty - except Exception as e: - print(f"Network difficulty calculation error: {e}") - return 1.0 +# return network_difficulty +# except Exception as e: +# 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 +# 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: - # Calculate difficulty for 4 shares per minute (15 second intervals) - # Formula: difficulty = (shares_per_second * 2^32) / hashrate - target_shares_per_second = 4 / 60 # 4 shares per minute - assumed_hashrate = 680000 # H/s (conservative estimate) - calculated_difficulty = (target_shares_per_second * (2**32)) / assumed_hashrate +# if is_new_client: +# # Calculate difficulty for 4 shares per minute (15 second intervals) +# # Formula: difficulty = (shares_per_second * 2^32) / hashrate +# target_shares_per_second = 4 / 60 # 4 shares per minute +# assumed_hashrate = 680000 # H/s (conservative estimate) +# calculated_difficulty = (target_shares_per_second * (2**32)) / assumed_hashrate - # Scale based on network difficulty to maintain relative percentage - target_percentage = calculated_difficulty / network_diff if network_diff > 0 else 0.32 - scaled_difficulty = network_diff * target_percentage +# # Scale based on network difficulty to maintain relative percentage +# target_percentage = calculated_difficulty / network_diff if network_diff > 0 else 0.32 +# scaled_difficulty = network_diff * target_percentage - # Use the calculated difficulty (should be around 421 for 680kH/s) - initial_difficulty = calculated_difficulty +# # Use the calculated difficulty (should be around 421 for 680kH/s) +# initial_difficulty = calculated_difficulty - # Ensure reasonable bounds - min_difficulty = 0.0001 # Absolute minimum - # IMPORTANT: DO NOT CHANGE THIS VALUE. our pool may grow big in the future, so we need to be able to handle it. - max_difficulty = network_diff * 0.1 # Maximum 10% of network - initial_difficulty = max(min_difficulty, min(max_difficulty, initial_difficulty)) +# # Ensure reasonable bounds +# min_difficulty = 0.0001 # Absolute minimum +# # IMPORTANT: DO NOT CHANGE THIS VALUE. our pool may grow big in the future, so we need to be able to handle it. +# max_difficulty = network_diff * 0.1 # Maximum 10% of network +# initial_difficulty = max(min_difficulty, min(max_difficulty, initial_difficulty)) - percentage = (initial_difficulty / network_diff) * 100 - print(f" ๐Ÿ“Š NEW CLIENT {addr}: Network diff {network_diff:.6f}") - print(f" ๐ŸŽฏ Starting difficulty: {initial_difficulty:.6f} ({percentage:.4f}% of network)") - miner_hashrate = self.clients.get(addr, {}).get('estimated_hashrate', 0) - if miner_hashrate > 0: - print(f" Target: 1 share every {self.target_share_interval}s @ {miner_hashrate:.0f} H/s") - else: - print(f" Target: 1 share every {self.target_share_interval}s (miner hashrate unknown)") - print(f" ๐Ÿ”ง Per-miner adjustment: Difficulty will adapt to each device's actual hashrate") - return initial_difficulty +# percentage = (initial_difficulty / network_diff) * 100 +# print(f" ๐Ÿ“Š NEW CLIENT {addr}: Network diff {network_diff:.6f}") +# print(f" ๐ŸŽฏ Starting difficulty: {initial_difficulty:.6f} ({percentage:.4f}% of network)") +# miner_hashrate = self.clients.get(addr, {}).get('estimated_hashrate', 0) +# if miner_hashrate > 0: +# print(f" Target: 1 share every {self.target_share_interval}s @ {miner_hashrate:.0f} H/s") +# else: +# print(f" Target: 1 share every {self.target_share_interval}s (miner hashrate unknown)") +# print(f" ๐Ÿ”ง Per-miner adjustment: Difficulty will adapt to each device's actual hashrate") +# return initial_difficulty - # For existing clients, adjust based on actual hashrate performance - client_data = self.clients.get(addr, {}) - if not client_data: - return self.calculate_optimal_difficulty(addr, is_new_client=True) +# # For existing clients, adjust based on actual hashrate 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', network_diff * 0.005) - estimated_hashrate = client_data.get('estimated_hashrate', 0) +# 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', network_diff * 0.005) +# estimated_hashrate = client_data.get('estimated_hashrate', 0) - # Need at least 3 shares to make adjustments - if share_count < 3: - return current_difficulty +# # Need at least 3 shares to make adjustments +# if share_count < 3: +# return current_difficulty - # Calculate target difficulty based on hashrate and desired share interval - # Target: 1 share every 15 seconds (self.target_share_interval) - if estimated_hashrate > 0: - # Formula: difficulty = (hashrate * target_time) / (2^32) - diff1_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 - target_difficulty = (estimated_hashrate * self.target_share_interval) / (2**32) +# # Calculate target difficulty based on hashrate and desired share interval +# # Target: 1 share every 15 seconds (self.target_share_interval) +# if estimated_hashrate > 0: +# # Formula: difficulty = (hashrate * target_time) / (2^32) +# diff1_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 +# target_difficulty = (estimated_hashrate * self.target_share_interval) / (2**32) - # Bounds checking - min_difficulty = network_diff * 0.0001 # 0.01% of network - max_difficulty = network_diff * 0.02 # 2% of network - target_difficulty = max(min_difficulty, min(max_difficulty, target_difficulty)) +# # Bounds checking +# min_difficulty = network_diff * 0.0001 # 0.01% of network +# max_difficulty = network_diff * 0.02 # 2% of network +# target_difficulty = max(min_difficulty, min(max_difficulty, target_difficulty)) - # Conservative adjustment - move only 50% towards target each time - adjustment_factor = 0.5 - new_difficulty = current_difficulty + (target_difficulty - current_difficulty) * adjustment_factor +# # Conservative adjustment - move only 50% towards target each time +# adjustment_factor = 0.5 +# new_difficulty = current_difficulty + (target_difficulty - current_difficulty) * adjustment_factor - print(f" ๐Ÿ“Š {addr}: {estimated_hashrate:.0f} H/s, {share_count} shares, adjusting {current_difficulty:.6f} โ†’ {new_difficulty:.6f}") - return new_difficulty +# print(f" ๐Ÿ“Š {addr}: {estimated_hashrate:.0f} H/s, {share_count} shares, adjusting {current_difficulty:.6f} โ†’ {new_difficulty:.6f}") +# return new_difficulty - return current_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) +# 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_global_difficulty_if_needed(self): - """Adjust difficulty globally if share rate is too high/low""" - try: - current_rate = self.stats['current_share_rate'] +# def adjust_global_difficulty_if_needed(self): +# """Adjust difficulty globally if share rate is too high/low""" +# try: +# current_rate = self.stats['current_share_rate'] - # Target: 0.5-2 shares per second (30-120 second intervals) - target_min_rate = 0.008 # ~1 share per 2 minutes - target_max_rate = 0.033 # ~1 share per 30 seconds +# # Target: 0.5-2 shares per second (30-120 second intervals) +# target_min_rate = 0.008 # ~1 share per 2 minutes +# target_max_rate = 0.033 # ~1 share per 30 seconds - if current_rate > target_max_rate: - # Too many shares - increase difficulty for all clients - multiplier = min(2.0, current_rate / target_max_rate) - print(f" ๐Ÿšจ HIGH SHARE RATE: {current_rate:.3f}/s > {target_max_rate:.3f}/s - increasing difficulty by {multiplier:.2f}x") - for addr in self.clients: - current_diff = self.clients[addr].get('stratum_difficulty', 0.001) - new_diff = min(0.001, current_diff * multiplier) - self.clients[addr]['stratum_difficulty'] = new_diff - print(f" ๐Ÿ“ˆ {addr}: {current_diff:.6f} โ†’ {new_diff:.6f}") +# if current_rate > target_max_rate: +# # Too many shares - increase difficulty for all clients +# multiplier = min(2.0, current_rate / target_max_rate) +# print(f" ๐Ÿšจ HIGH SHARE RATE: {current_rate:.3f}/s > {target_max_rate:.3f}/s - increasing difficulty by {multiplier:.2f}x") +# for addr in self.clients: +# current_diff = self.clients[addr].get('stratum_difficulty', 0.001) +# new_diff = min(0.001, current_diff * multiplier) +# self.clients[addr]['stratum_difficulty'] = new_diff +# print(f" ๐Ÿ“ˆ {addr}: {current_diff:.6f} โ†’ {new_diff:.6f}") - elif current_rate < target_min_rate and current_rate > 0: - # Too few shares - decrease difficulty for all clients - multiplier = max(0.5, target_min_rate / current_rate) - print(f" ๐ŸŒ LOW SHARE RATE: {current_rate:.3f}/s < {target_min_rate:.3f}/s - decreasing difficulty by {multiplier:.2f}x") - for addr in self.clients: - current_diff = self.clients[addr].get('stratum_difficulty', 0.001) - new_diff = max(0.000001, current_diff / multiplier) - self.clients[addr]['stratum_difficulty'] = new_diff - print(f" ๐Ÿ“‰ {addr}: {current_diff:.6f} โ†’ {new_diff:.6f}") +# elif current_rate < target_min_rate and current_rate > 0: +# # Too few shares - decrease difficulty for all clients +# multiplier = max(0.5, target_min_rate / current_rate) +# print(f" ๐ŸŒ LOW SHARE RATE: {current_rate:.3f}/s < {target_min_rate:.3f}/s - decreasing difficulty by {multiplier:.2f}x") +# for addr in self.clients: +# current_diff = self.clients[addr].get('stratum_difficulty', 0.001) +# new_diff = max(0.000001, current_diff / multiplier) +# self.clients[addr]['stratum_difficulty'] = new_diff +# print(f" ๐Ÿ“‰ {addr}: {current_diff:.6f} โ†’ {new_diff:.6f}") - except Exception as e: - print(f"Global difficulty adjustment error: {e}") +# except Exception as e: +# print(f"Global difficulty adjustment error: {e}") - def adjust_client_difficulty(self, addr): - """Adjust difficulty for a specific client if needed""" - try: - current_time = time.time() +# 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 +# # 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) +# 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 +# # 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}") +# # 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}") +# 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: - # Use provided address or default - address = target_address or self.target_address +# def submit_share(self, job, extranonce1, extranonce2, ntime, nonce, addr=None, target_address=None): +# """Validate share and submit block if valid - FIXED VERSION""" +# try: +# # Use provided address or default +# address = target_address or self.target_address - # Build coinbase (with and without witness) - coinbase_wit, coinbase_nowit = self.build_coinbase_transaction_for_address( - job['template'], extranonce1, extranonce2, address) - if not coinbase_wit or not coinbase_nowit: - return False, "Coinbase construction failed" +# # Build coinbase (with and without witness) +# coinbase_wit, coinbase_nowit = self.build_coinbase_transaction_for_address( +# job['template'], extranonce1, extranonce2, address) +# if not coinbase_wit or not coinbase_nowit: +# return False, "Coinbase construction failed" - # Calculate coinbase txid (non-witness serialization) - coinbase_txid = hashlib.sha256(hashlib.sha256(coinbase_nowit).digest()).digest()[::-1] +# # Calculate coinbase txid (non-witness serialization) +# coinbase_txid = hashlib.sha256(hashlib.sha256(coinbase_nowit).digest()).digest()[::-1] - # Calculate merkle root - merkle_root = self.calculate_merkle_root(coinbase_txid, job['transactions']) +# # Calculate merkle root +# merkle_root = self.calculate_merkle_root(coinbase_txid, job['transactions']) - # Build block header - FIXED ENDIANNESS - header = b'' - header += struct.pack('= client_stratum_diff - meets_network_difficulty = share_difficulty >= network_difficulty +# # CRITICAL FIX: Check if share difficulty meets minimum requirements +# meets_stratum_difficulty = share_difficulty >= client_stratum_diff +# meets_network_difficulty = share_difficulty >= network_difficulty - # Track share rate - current_time = time.time() - self.stats['shares_last_minute'].append(current_time) - # Remove shares older than 60 seconds - self.stats['shares_last_minute'] = [t for t in self.stats['shares_last_minute'] if current_time - t <= 60] - self.stats['current_share_rate'] = len(self.stats['shares_last_minute']) / 60.0 +# # Track share rate +# current_time = time.time() +# self.stats['shares_last_minute'].append(current_time) +# # Remove shares older than 60 seconds +# self.stats['shares_last_minute'] = [t for t in self.stats['shares_last_minute'] if current_time - t <= 60] +# self.stats['current_share_rate'] = len(self.stats['shares_last_minute']) / 60.0 - # Enhanced logging - timestamp = time.strftime("%Y-%m-%d %H:%M:%S") - network_percentage = (share_difficulty / network_difficulty) * 100 if network_difficulty > 0 else 0 - stratum_percentage = (share_difficulty / client_stratum_diff) * 100 if client_stratum_diff > 0 else 0 +# # Enhanced logging +# timestamp = time.strftime("%Y-%m-%d %H:%M:%S") +# network_percentage = (share_difficulty / network_difficulty) * 100 if network_difficulty > 0 else 0 +# stratum_percentage = (share_difficulty / client_stratum_diff) * 100 if client_stratum_diff > 0 else 0 - # Progress indicator based on difficulty comparison - if meets_network_difficulty: - progress_icon = "๐ŸŽ‰" # Block found! - elif meets_stratum_difficulty: - progress_icon = "โœ…" # Valid share for stratum - elif network_percentage >= 50: - progress_icon = "๐Ÿ”ฅ" # Very close to network - elif network_percentage >= 10: - progress_icon = "โšก" # Getting warm - elif network_percentage >= 1: - progress_icon = "๐Ÿ’ซ" # Some progress - else: - progress_icon = "๐Ÿ“Š" # Low progress +# # Progress indicator based on difficulty comparison +# if meets_network_difficulty: +# progress_icon = "๐ŸŽ‰" # Block found! +# elif meets_stratum_difficulty: +# progress_icon = "โœ…" # Valid share for stratum +# elif network_percentage >= 50: +# progress_icon = "๐Ÿ”ฅ" # Very close to network +# elif network_percentage >= 10: +# progress_icon = "โšก" # Getting warm +# elif network_percentage >= 1: +# progress_icon = "๐Ÿ’ซ" # Some progress +# else: +# progress_icon = "๐Ÿ“Š" # Low progress - # Calculate network and pool hashrates - block_time = 60 # RinCoin 1-minute blocks - network_hashrate = (network_difficulty * (2**32)) / block_time - network_mhs = network_hashrate / 1e6 +# # Calculate network and pool hashrates +# block_time = 60 # RinCoin 1-minute blocks +# network_hashrate = (network_difficulty * (2**32)) / block_time +# network_mhs = network_hashrate / 1e6 - # Calculate pool hashrate (sum of all connected miners) - pool_hashrate = 0 - for client_addr, client_data in self.clients.items(): - pool_hashrate += client_data.get('estimated_hashrate', 0) - pool_mhs = pool_hashrate / 1e6 +# # Calculate pool hashrate (sum of all connected miners) +# pool_hashrate = 0 +# for client_addr, client_data in self.clients.items(): +# pool_hashrate += client_data.get('estimated_hashrate', 0) +# pool_mhs = pool_hashrate / 1e6 - # Calculate percentages - pool_network_percentage = (pool_mhs / network_mhs) * 100 if network_mhs > 0 else 0 - miner_pool_percentage = (0.87 / pool_mhs) * 100 if pool_mhs > 0 else 0 # Assuming 870kH/s miner +# # Calculate percentages +# pool_network_percentage = (pool_mhs / network_mhs) * 100 if network_mhs > 0 else 0 +# miner_pool_percentage = (0.87 / pool_mhs) * 100 if pool_mhs > 0 else 0 # Assuming 870kH/s miner - print(f"[{timestamp}] {progress_icon} SHARE: job={job['job_id']} | nonce={nonce} | hash={block_hash_hex[:16]}...") - print(f" ๐ŸŽฏ Share Diff: {share_difficulty:.2e} | Stratum Diff: {client_stratum_diff:.6f} | Network Diff: {network_difficulty:.6f}") - print(f" ๐Ÿ“ˆ Progress: {network_percentage:.4f}% of network, {stratum_percentage:.1f}% of stratum") - print(f" ๐Ÿ“Š Share Rate: {self.stats['current_share_rate']:.2f}/s | Total: {len(self.stats['shares_last_minute'])}/min") - print(f" ๐ŸŒ Network: {network_mhs:.1f} MH/s | Pool: {pool_mhs:.1f} MH/s ({pool_network_percentage:.2f}% of network)") - print(f" โ›๏ธ Miner: 0.87 MH/s ({miner_pool_percentage:.1f}% of pool) | Expected solo: {network_mhs/0.87:.0f}h") - print(f" ๐Ÿ“ Target: {job['target'][:16]}... | Height: {job['height']}") - print(f" โฐ Time: {ntime} | Extranonce: {extranonce1}:{extranonce2}") - print(f" ๐Ÿ” Difficulty Check: Share {share_difficulty:.2e} vs Stratum {client_stratum_diff:.6f} = {'โœ…' if meets_stratum_difficulty else 'โŒ'}") - print(f" ๐Ÿ” Difficulty Check: Share {share_difficulty:.2e} vs Network {network_difficulty:.6f} = {'โœ…' if meets_network_difficulty else 'โŒ'}") +# print(f"[{timestamp}] {progress_icon} SHARE: job={job['job_id']} | nonce={nonce} | hash={block_hash_hex[:16]}...") +# print(f" ๐ŸŽฏ Share Diff: {share_difficulty:.2e} | Stratum Diff: {client_stratum_diff:.6f} | Network Diff: {network_difficulty:.6f}") +# print(f" ๐Ÿ“ˆ Progress: {network_percentage:.4f}% of network, {stratum_percentage:.1f}% of stratum") +# print(f" ๐Ÿ“Š Share Rate: {self.stats['current_share_rate']:.2f}/s | Total: {len(self.stats['shares_last_minute'])}/min") +# print(f" ๐ŸŒ Network: {network_mhs:.1f} MH/s | Pool: {pool_mhs:.1f} MH/s ({pool_network_percentage:.2f}% of network)") +# print(f" โ›๏ธ Miner: 0.87 MH/s ({miner_pool_percentage:.1f}% of pool) | Expected solo: {network_mhs/0.87:.0f}h") +# print(f" ๐Ÿ“ Target: {job['target'][:16]}... | Height: {job['height']}") +# print(f" โฐ Time: {ntime} | Extranonce: {extranonce1}:{extranonce2}") +# print(f" ๐Ÿ” Difficulty Check: Share {share_difficulty:.2e} vs Stratum {client_stratum_diff:.6f} = {'โœ…' if meets_stratum_difficulty else 'โŒ'}") +# print(f" ๐Ÿ” Difficulty Check: Share {share_difficulty:.2e} vs Network {network_difficulty:.6f} = {'โœ…' if meets_network_difficulty else 'โŒ'}") - # Initialize submission variables - submit_network_difficulty = meets_network_difficulty - submit_debug_threshold = share_difficulty >= (network_difficulty * self.submit_threshold) +# # Initialize submission variables +# submit_network_difficulty = meets_network_difficulty +# submit_debug_threshold = share_difficulty >= (network_difficulty * self.submit_threshold) - if submit_network_difficulty: - submit_reason = "meets network difficulty" - elif submit_debug_threshold: - submit_reason = f"meets debug threshold ({self.submit_threshold*100:.0f}% of network)" - else: - submit_reason = "does not meet minimum requirements" +# if submit_network_difficulty: +# submit_reason = "meets network difficulty" +# elif submit_debug_threshold: +# submit_reason = f"meets debug threshold ({self.submit_threshold*100:.0f}% of network)" +# else: +# submit_reason = "does not meet minimum requirements" - # Handle submit_all_blocks mode - bypass all difficulty checks - if self.submit_all_blocks: - print(f" ๐Ÿงช TEST MODE: Submitting ALL shares to node for validation") - # Update stats for test mode - self.stats['total_shares'] += 1 - self.stats['accepted_shares'] += 1 +# # Handle submit_all_blocks mode - bypass all difficulty checks +# if self.submit_all_blocks: +# print(f" ๐Ÿงช TEST MODE: Submitting ALL shares to node for validation") +# # Update stats for test mode +# self.stats['total_shares'] += 1 +# self.stats['accepted_shares'] += 1 - # Always submit in test mode - should_submit = True - else: - # Normal mode - check stratum difficulty properly - if not meets_stratum_difficulty: - # Share doesn't meet minimum stratum difficulty - reject - print(f" โŒ Share rejected (difficulty too low: {share_difficulty:.2e} < {client_stratum_diff:.6f})") - self.stats['total_shares'] += 1 - self.stats['rejected_shares'] += 1 - return False, "Share does not meet stratum difficulty" +# # Always submit in test mode +# should_submit = True +# else: +# # Normal mode - check stratum difficulty properly +# if not meets_stratum_difficulty: +# # Share doesn't meet minimum stratum difficulty - reject +# print(f" โŒ Share rejected (difficulty too low: {share_difficulty:.2e} < {client_stratum_diff:.6f})") +# self.stats['total_shares'] += 1 +# self.stats['rejected_shares'] += 1 +# return False, "Share does not meet stratum difficulty" - # Valid stratum share! Update client stats - if addr and addr in self.clients: - current_time = time.time() - self.clients[addr]['share_count'] = self.clients[addr].get('share_count', 0) + 1 - self.clients[addr]['last_share_time'] = current_time +# # Valid stratum share! Update client stats +# if addr and addr in self.clients: +# current_time = time.time() +# self.clients[addr]['share_count'] = self.clients[addr].get('share_count', 0) + 1 +# self.clients[addr]['last_share_time'] = current_time - # Calculate hashrate from this share - # Hashrate = difficulty * 2^32 / time_to_find_share - client_difficulty = self.clients[addr].get('stratum_difficulty', 0.001) - last_share_time = self.clients[addr].get('last_share_time', current_time - 60) - time_since_last = max(1, current_time - last_share_time) # Avoid division by zero +# # Calculate hashrate from this share +# # Hashrate = difficulty * 2^32 / time_to_find_share +# client_difficulty = self.clients[addr].get('stratum_difficulty', 0.001) +# last_share_time = self.clients[addr].get('last_share_time', current_time - 60) +# time_since_last = max(1, current_time - last_share_time) # Avoid division by zero - # Calculate instantaneous hashrate for this share - diff1_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 - instant_hashrate = (client_difficulty * (2**32)) / time_since_last +# # Calculate instantaneous hashrate for this share +# diff1_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 +# instant_hashrate = (client_difficulty * (2**32)) / time_since_last - # Store hashrate sample (keep last 10 samples) - if 'hashrate_samples' not in self.clients[addr]: - self.clients[addr]['hashrate_samples'] = [] - self.clients[addr]['hashrate_samples'].append((current_time, instant_hashrate)) - # Keep only last 10 samples - if len(self.clients[addr]['hashrate_samples']) > 10: - self.clients[addr]['hashrate_samples'] = self.clients[addr]['hashrate_samples'][-10:] +# # Store hashrate sample (keep last 10 samples) +# if 'hashrate_samples' not in self.clients[addr]: +# self.clients[addr]['hashrate_samples'] = [] +# self.clients[addr]['hashrate_samples'].append((current_time, instant_hashrate)) +# # Keep only last 10 samples +# if len(self.clients[addr]['hashrate_samples']) > 10: +# self.clients[addr]['hashrate_samples'] = self.clients[addr]['hashrate_samples'][-10:] - # Calculate average hashrate from recent samples - if self.clients[addr]['hashrate_samples']: - total_hashrate = sum(hr for _, hr in self.clients[addr]['hashrate_samples']) - self.clients[addr]['estimated_hashrate'] = total_hashrate / len(self.clients[addr]['hashrate_samples']) +# # Calculate average hashrate from recent samples +# if self.clients[addr]['hashrate_samples']: +# total_hashrate = sum(hr for _, hr in self.clients[addr]['hashrate_samples']) +# self.clients[addr]['estimated_hashrate'] = total_hashrate / len(self.clients[addr]['hashrate_samples']) - print(f" โ›๏ธ Miner {addr}: {self.clients[addr]['estimated_hashrate']:.0f} H/s (avg of {len(self.clients[addr]['hashrate_samples'])} samples)") +# print(f" โ›๏ธ Miner {addr}: {self.clients[addr]['estimated_hashrate']:.0f} H/s (avg of {len(self.clients[addr]['hashrate_samples'])} samples)") - # Update global stats - self.stats['total_shares'] += 1 - self.stats['accepted_shares'] += 1 +# # Update global stats +# self.stats['total_shares'] += 1 +# self.stats['accepted_shares'] += 1 - # Check if we should adjust difficulty - self.adjust_client_difficulty(addr) +# # Check if we should adjust difficulty +# self.adjust_client_difficulty(addr) - # Global difficulty adjustment based on share rate - self.adjust_global_difficulty_if_needed() +# # Global difficulty adjustment based on share rate +# self.adjust_global_difficulty_if_needed() - should_submit = submit_network_difficulty or submit_debug_threshold +# should_submit = submit_network_difficulty or submit_debug_threshold - # Submit block if conditions are met - if should_submit: - if submit_network_difficulty: - print(f" ๐ŸŽ‰ VALID BLOCK FOUND! Hash: {block_hash_hex}") - print(f" ๐Ÿ’ฐ Reward: {job['coinbasevalue']/100000000:.2f} RIN -> {address}") - print(f" ๐Ÿ“Š Block height: {job['height']}") - print(f" ๐Ÿ” Difficulty: {share_difficulty:.6f} (target: {network_difficulty:.6f})") - print(f" ๐Ÿ“‹ Submit reason: {submit_reason}") +# # Submit block if conditions are met +# if should_submit: +# if submit_network_difficulty: +# print(f" ๐ŸŽ‰ VALID BLOCK FOUND! Hash: {block_hash_hex}") +# print(f" ๐Ÿ’ฐ Reward: {job['coinbasevalue']/100000000:.2f} RIN -> {address}") +# print(f" ๐Ÿ“Š Block height: {job['height']}") +# print(f" ๐Ÿ” Difficulty: {share_difficulty:.6f} (target: {network_difficulty:.6f})") +# print(f" ๐Ÿ“‹ Submit reason: {submit_reason}") - # Log the found hash - ONLY for actual network-valid blocks - reward_rin = job['coinbasevalue'] / 100000000 - self.log_hash_found(block_hash_hex, share_difficulty, job['height'], reward_rin, nonce, ntime) - elif submit_debug_threshold: - print(f" ๐Ÿงช DEBUG SUBMISSION! Hash: {block_hash_hex} ({submit_reason})") - print(f" ๐Ÿ“Š Block height: {job['height']} | Difficulty: {share_difficulty:.6f}") - print(f" ๐Ÿ’ก This is a test submission - not a real block") - else: - print(f" ๐Ÿงช TEST BLOCK SUBMISSION! Hash: {block_hash_hex} (submit_all_blocks=True)") - print(f" ๐Ÿ“Š Block height: {job['height']} | Difficulty: {share_difficulty:.6f}") - print(f" ๐Ÿ’ก This is a test submission - not a real block") +# # Log the found hash - ONLY for actual network-valid blocks +# reward_rin = job['coinbasevalue'] / 100000000 +# self.log_hash_found(block_hash_hex, share_difficulty, job['height'], reward_rin, nonce, ntime) +# elif submit_debug_threshold: +# print(f" ๐Ÿงช DEBUG SUBMISSION! Hash: {block_hash_hex} ({submit_reason})") +# print(f" ๐Ÿ“Š Block height: {job['height']} | Difficulty: {share_difficulty:.6f}") +# print(f" ๐Ÿ’ก This is a test submission - not a real block") +# else: +# print(f" ๐Ÿงช TEST BLOCK SUBMISSION! Hash: {block_hash_hex} (submit_all_blocks=True)") +# print(f" ๐Ÿ“Š Block height: {job['height']} | Difficulty: {share_difficulty:.6f}") +# print(f" ๐Ÿ’ก This is a test submission - not a real block") - # Build complete block - block = header +# # Build complete block +# block = header - # Transaction count - tx_count = 1 + len(job['transactions']) - block += self.encode_varint(tx_count) +# # Transaction count +# tx_count = 1 + len(job['transactions']) +# block += self.encode_varint(tx_count) - # Add coinbase transaction (witness variant for block body) - block += coinbase_wit +# # Add coinbase transaction (witness variant for block body) +# block += coinbase_wit - # Add other transactions - for tx in job['transactions']: - block += bytes.fromhex(tx['data']) +# # Add other transactions +# for tx in job['transactions']: +# block += bytes.fromhex(tx['data']) - # Submit block - block_hex = block.hex() - print(f" ๐Ÿ“ฆ Submitting block of size {len(block_hex)//2} bytes...") - print(f" ๐Ÿš€ Calling RPC: submitblock([block_hex={len(block_hex)//2}_bytes])") +# # Submit block +# block_hex = block.hex() +# print(f" ๐Ÿ“ฆ Submitting block of size {len(block_hex)//2} bytes...") +# print(f" ๐Ÿš€ Calling RPC: submitblock([block_hex={len(block_hex)//2}_bytes])") - result = self.rpc_call("submitblock", [block_hex]) - print(f" ๐Ÿ“ก RPC RESPONSE: {result}") # Log the actual RPC response +# result = self.rpc_call("submitblock", [block_hex]) +# print(f" ๐Ÿ“ก RPC RESPONSE: {result}") # Log the actual RPC response - if result is None: - print(f" โœ… Block accepted by network!") - print(f" ๐ŸŽŠ SUCCESS: Block {job['height']} submitted successfully!") - print(f" ๐Ÿ’ฐ Reward earned: {job['coinbasevalue']/100000000:.8f} RIN") - # Update block stats - self.stats['blocks_found'] += 1 - # Log wallet balance after successful block submission - self.log_wallet_balance() - return True, "Block found and submitted" - else: - print(f" โŒ Block rejected: {result}") - print(f" ๐Ÿ” Debug: Block size {len(block_hex)//2} bytes, {len(job['transactions'])} transactions") - print(f" ๐Ÿ“‹ Full RPC error details: {result}") - return False, f"Block rejected: {result}" - else: - # Valid stratum share but not network-valid block (normal mode only) - if not self.submit_all_blocks: - print(f" โœ… Valid stratum share accepted") - return True, "Valid stratum share" - else: - # This shouldn't happen in test mode since should_submit would be True - return True, "Test mode share processed" +# if result is None: +# print(f" โœ… Block accepted by network!") +# print(f" ๐ŸŽŠ SUCCESS: Block {job['height']} submitted successfully!") +# print(f" ๐Ÿ’ฐ Reward earned: {job['coinbasevalue']/100000000:.8f} RIN") +# # Update block stats +# self.stats['blocks_found'] += 1 +# # Log wallet balance after successful block submission +# self.log_wallet_balance() +# return True, "Block found and submitted" +# else: +# print(f" โŒ Block rejected: {result}") +# print(f" ๐Ÿ” Debug: Block size {len(block_hex)//2} bytes, {len(job['transactions'])} transactions") +# print(f" ๐Ÿ“‹ Full RPC error details: {result}") +# return False, f"Block rejected: {result}" +# else: +# # Valid stratum share but not network-valid block (normal mode only) +# if not self.submit_all_blocks: +# print(f" โœ… Valid stratum share accepted") +# return True, "Valid stratum share" +# else: +# # This shouldn't happen in test mode since should_submit would be True +# return True, "Test mode share processed" - except Exception as e: - print(f"Share submission error: {e}") - return False, f"Submission error: {e}" +# except Exception as e: +# print(f"Share submission error: {e}") +# return False, f"Submission error: {e}" - def send_stratum_response(self, client, msg_id, result, error=None): - """Send Stratum response to client""" - try: - response = { - "id": msg_id, - "result": result, - "error": error - } - message = json.dumps(response) + "\n" - client.send(message.encode('utf-8')) - except Exception as e: - print(f"Send response error: {e}") +# def send_stratum_response(self, client, msg_id, result, error=None): +# """Send Stratum response to client""" +# try: +# response = { +# "id": msg_id, +# "result": result, +# "error": error +# } +# message = json.dumps(response) + "\n" +# client.send(message.encode('utf-8')) +# except Exception as e: +# print(f"Send response error: {e}") - def send_stratum_notification(self, client, method, params): - """Send Stratum notification to client""" - try: - notification = { - "id": None, - "method": method, - "params": params - } - message = json.dumps(notification) + "\n" - client.send(message.encode('utf-8')) - except Exception as e: - print(f"Send notification error: {e}") +# def send_stratum_notification(self, client, method, params): +# """Send Stratum notification to client""" +# try: +# notification = { +# "id": None, +# "method": method, +# "params": params +# } +# message = json.dumps(notification) + "\n" +# client.send(message.encode('utf-8')) +# except Exception as e: +# print(f"Send notification error: {e}") - def handle_stratum_message(self, client, addr, message): - """Handle incoming Stratum message from miner""" - try: - # Debug: log raw message - print(f"[{addr}] Raw message: {repr(message)}") +# def handle_stratum_message(self, client, addr, message): +# """Handle incoming Stratum message from miner""" +# try: +# # Debug: log raw message +# print(f"[{addr}] Raw message: {repr(message)}") - data = json.loads(message.strip()) - method = data.get("method") - msg_id = data.get("id") - params = data.get("params", []) +# data = json.loads(message.strip()) +# method = data.get("method") +# msg_id = data.get("id") +# params = data.get("params", []) - print(f"[{addr}] Parsed: method={method}, id={msg_id}, params={params}") +# print(f"[{addr}] Parsed: method={method}, id={msg_id}, params={params}") - if method == "mining.subscribe": - # Generate unique extranonce1 for this connection - self.extranonce1_counter += 1 - extranonce1 = f"{self.extranonce1_counter:08x}" +# if method == "mining.subscribe": +# # Generate unique extranonce1 for this connection +# self.extranonce1_counter += 1 +# extranonce1 = f"{self.extranonce1_counter:08x}" - # Store extranonce1 for this client - if addr not in self.clients: - self.clients[addr] = {} - self.clients[addr]['extranonce1'] = extranonce1 +# # Store extranonce1 for this client +# if addr not in self.clients: +# self.clients[addr] = {} +# self.clients[addr]['extranonce1'] = extranonce1 - # Subscribe response - self.send_stratum_response(client, msg_id, [ - [["mining.set_difficulty", "subscription_id"], ["mining.notify", "subscription_id"]], - extranonce1, - 4 # extranonce2 size - ]) +# # Subscribe response +# self.send_stratum_response(client, msg_id, [ +# [["mining.set_difficulty", "subscription_id"], ["mining.notify", "subscription_id"]], +# extranonce1, +# 4 # extranonce2 size +# ]) - # 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'] = initial_difficulty - self.clients[addr]['last_share_time'] = time.time() - self.clients[addr]['share_count'] = 0 - self.clients[addr]['connect_time'] = time.time() - self.clients[addr]['hashrate_samples'] = [] # Store recent hashrate measurements - self.clients[addr]['estimated_hashrate'] = 0 # Current estimated hashrate +# # 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'] = initial_difficulty +# self.clients[addr]['last_share_time'] = time.time() +# self.clients[addr]['share_count'] = 0 +# self.clients[addr]['connect_time'] = time.time() +# self.clients[addr]['hashrate_samples'] = [] # Store recent hashrate measurements +# self.clients[addr]['estimated_hashrate'] = 0 # Current estimated hashrate - self.send_stratum_notification(client, "mining.set_difficulty", [initial_difficulty]) - print(f" ๐ŸŽฏ Set initial difficulty {initial_difficulty:.6f} for {addr}") +# 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: - self.send_job_to_client(client, self.current_job) - else: - if self.get_block_template(): - self.send_job_to_client(client, self.current_job) +# # Send initial job +# if self.current_job: +# self.send_job_to_client(client, self.current_job) +# else: +# if self.get_block_template(): +# self.send_job_to_client(client, self.current_job) - elif method == "mining.authorize": - username = params[0] if params else "anonymous" - self.clients[addr]['username'] = username - self.send_stratum_response(client, msg_id, True) - timestamp = time.strftime("%Y-%m-%d %H:%M:%S") - print(f"[{timestamp}] ๐Ÿ” [{addr}] Authorized as {username}") +# elif method == "mining.authorize": +# username = params[0] if params else "anonymous" +# self.clients[addr]['username'] = username +# self.send_stratum_response(client, msg_id, True) +# timestamp = time.strftime("%Y-%m-%d %H:%M:%S") +# print(f"[{timestamp}] ๐Ÿ” [{addr}] Authorized as {username}") - elif method == "login": - # Handle xmrig's login method (JSON-RPC format with object params) - if isinstance(params, dict): - # xmrig format: {"login": "username", "pass": "password", "agent": "...", "algo": [...]} - username = params.get('login', 'anonymous') - password = params.get('pass', 'x') - agent = params.get('agent', 'unknown') - algorithms = params.get('algo', []) - else: - # Standard stratum format: ["username", "password"] - username = params[0] if params else "anonymous" - password = params[1] if len(params) > 1 else "x" - agent = "unknown" - algorithms = [] +# elif method == "login": +# # Handle xmrig's login method (JSON-RPC format with object params) +# if isinstance(params, dict): +# # xmrig format: {"login": "username", "pass": "password", "agent": "...", "algo": [...]} +# username = params.get('login', 'anonymous') +# password = params.get('pass', 'x') +# agent = params.get('agent', 'unknown') +# algorithms = params.get('algo', []) +# else: +# # Standard stratum format: ["username", "password"] +# username = params[0] if params else "anonymous" +# password = params[1] if len(params) > 1 else "x" +# agent = "unknown" +# algorithms = [] - self.clients[addr]['username'] = username - self.clients[addr]['password'] = password - self.clients[addr]['agent'] = agent - self.clients[addr]['algorithms'] = algorithms +# self.clients[addr]['username'] = username +# self.clients[addr]['password'] = password +# self.clients[addr]['agent'] = agent +# self.clients[addr]['algorithms'] = algorithms - # Check if rinhash is supported - rinhash_supported = any('rinhash' in algo.lower() or 'rin' in algo.lower() for algo in algorithms) - if not rinhash_supported: - print(f"[{addr}] Warning: rinhash not in supported algorithms: {algorithms}") +# # Check if rinhash is supported +# rinhash_supported = any('rinhash' in algo.lower() or 'rin' in algo.lower() for algo in algorithms) +# if not rinhash_supported: +# print(f"[{addr}] Warning: rinhash not in supported algorithms: {algorithms}") - self.send_stratum_response(client, msg_id, True) - timestamp = time.strftime("%Y-%m-%d %H:%M:%S") - print(f"[{timestamp}] ๐Ÿ” [{addr}] xmrig Login as {username} (agent: {agent})") - print(f"[{addr}] Supported algorithms: {algorithms}") +# self.send_stratum_response(client, msg_id, True) +# timestamp = time.strftime("%Y-%m-%d %H:%M:%S") +# print(f"[{timestamp}] ๐Ÿ” [{addr}] xmrig Login as {username} (agent: {agent})") +# print(f"[{addr}] Supported algorithms: {algorithms}") - # Send initial job after login - if self.current_job: - self.send_job_to_client(client, self.current_job) - else: - if self.get_block_template(): - self.send_job_to_client(client, self.current_job) +# # Send initial job after login +# if self.current_job: +# self.send_job_to_client(client, self.current_job) +# else: +# if self.get_block_template(): +# self.send_job_to_client(client, self.current_job) - elif method == "mining.extranonce.subscribe": - self.send_stratum_response(client, msg_id, True) +# elif method == "mining.extranonce.subscribe": +# self.send_stratum_response(client, msg_id, True) - elif method == "mining.submit": - if len(params) >= 5: - username = params[0] - job_id = params[1] - extranonce2 = params[2] - ntime = params[3] - nonce = params[4] +# elif method == "mining.submit": +# if len(params) >= 5: +# username = params[0] +# job_id = params[1] +# extranonce2 = params[2] +# ntime = params[3] +# nonce = params[4] - print(f"[{addr}] Submit: {username} | job={job_id} | nonce={nonce}") +# print(f"[{addr}] Submit: {username} | job={job_id} | nonce={nonce}") - # Always validate against current job - if self.current_job: - extranonce1 = self.clients[addr].get('extranonce1', '00000000') +# # Always validate against current job +# if self.current_job: +# extranonce1 = self.clients[addr].get('extranonce1', '00000000') - # Submit share - success, message = self.submit_share(self.current_job, extranonce1, extranonce2, ntime, nonce, addr) +# # Submit share +# success, message = self.submit_share(self.current_job, extranonce1, extranonce2, ntime, nonce, addr) - # Always accept shares for debugging, even if they don't meet target - self.send_stratum_response(client, msg_id, True) +# # Always accept shares for debugging, even if they don't meet target +# self.send_stratum_response(client, msg_id, True) - if success and "Block found" in message: - # Get new job after block found - threading.Thread(target=self.update_job_after_block, daemon=True).start() - else: - self.send_stratum_response(client, msg_id, True) - else: - self.send_stratum_response(client, msg_id, False, "Invalid parameters") +# if success and "Block found" in message: +# # Get new job after block found +# threading.Thread(target=self.update_job_after_block, daemon=True).start() +# else: +# self.send_stratum_response(client, msg_id, True) +# else: +# self.send_stratum_response(client, msg_id, False, "Invalid parameters") - else: - print(f"[{addr}] Unknown method: {method}") - self.send_stratum_response(client, msg_id, None, "Unknown method") +# else: +# print(f"[{addr}] Unknown method: {method}") +# self.send_stratum_response(client, msg_id, None, "Unknown method") - except json.JSONDecodeError as e: - print(f"[{addr}] Invalid JSON: {message}") - print(f"[{addr}] JSON Error: {e}") - except Exception as e: - print(f"[{addr}] Message handling error: {e}") - print(f"[{addr}] Error type: {type(e).__name__}") +# except json.JSONDecodeError as e: +# print(f"[{addr}] Invalid JSON: {message}") +# print(f"[{addr}] JSON Error: {e}") +# except Exception as e: +# print(f"[{addr}] Message handling error: {e}") +# print(f"[{addr}] Error type: {type(e).__name__}") - def send_job_to_client(self, client, job): - """Send mining job to specific client with proper stratum parameters""" - try: - # Get network difficulty for display - network_difficulty = self.calculate_network_difficulty(job['target']) +# def send_job_to_client(self, client, job): +# """Send mining job to specific client with proper stratum parameters""" +# try: +# # Get network difficulty for display +# network_difficulty = self.calculate_network_difficulty(job['target']) - # Build proper coinbase transaction parts for stratum protocol - template = job.get('template', {}) - height = job.get('height', 0) +# # Build proper coinbase transaction parts for stratum protocol +# template = job.get('template', {}) +# height = job.get('height', 0) - # Encode height as minimal push (BIP34 compliance) - if height == 0: - height_push = b'' - else: - height_bytes = struct.pack(' 1 and height_bytes[-1] == 0: - height_bytes = height_bytes[:-1] - height_push = bytes([len(height_bytes)]) + height_bytes +# # Encode height as minimal push (BIP34 compliance) +# if height == 0: +# height_push = b'' +# else: +# height_bytes = struct.pack(' 1 and height_bytes[-1] == 0: +# height_bytes = height_bytes[:-1] +# height_push = bytes([len(height_bytes)]) + height_bytes - # Build coinbase input script: height + arbitrary data + extranonces - coinb1_script = height_push + b'/RinCoin/' +# # Build coinbase input script: height + arbitrary data + extranonces +# coinb1_script = height_push + b'/RinCoin/' - # Build coinbase transaction structure - # Version (4 bytes) - coinb1 = struct.pack('= self.max_connections: - print(f"[{addr}] Connection rejected - max connections ({self.max_connections}) reached") - client.close() - return +# def handle_client(self, client, addr): +# """Handle individual client connection""" +# # Check connection limits +# if len(self.clients) >= self.max_connections: +# print(f"[{addr}] Connection rejected - max connections ({self.max_connections}) reached") +# client.close() +# return - print(f"[{addr}] Connected (clients: {len(self.clients) + 1}/{self.max_connections})") - if addr not in self.clients: - self.clients[addr] = {} - self.clients[addr]['socket'] = client - self.stats['connections'] = len(self.clients) +# print(f"[{addr}] Connected (clients: {len(self.clients) + 1}/{self.max_connections})") +# if addr not in self.clients: +# self.clients[addr] = {} +# self.clients[addr]['socket'] = client +# self.stats['connections'] = len(self.clients) - try: - while self.running: - data = client.recv(4096) - if not data: - break +# try: +# while self.running: +# data = client.recv(4096) +# if not data: +# break - # Handle multiple messages in one packet - messages = data.decode('utf-8').strip().split('\n') - for message in messages: - if message: - self.handle_stratum_message(client, addr, message) +# # Handle multiple messages in one packet +# messages = data.decode('utf-8').strip().split('\n') +# for message in messages: +# if message: +# self.handle_stratum_message(client, addr, message) - except Exception as e: - print(f"[{addr}] Client error: {e}") - finally: - client.close() - if addr in self.clients: - del self.clients[addr] - self.stats['connections'] = len(self.clients) - print(f"[{addr}] Disconnected (clients: {len(self.clients)}/{self.max_connections})") +# except Exception as e: +# print(f"[{addr}] Client error: {e}") +# finally: +# client.close() +# if addr in self.clients: +# del self.clients[addr] +# self.stats['connections'] = len(self.clients) +# print(f"[{addr}] Disconnected (clients: {len(self.clients)}/{self.max_connections})") - def print_stats(self): - """Print pool statistics""" - try: - uptime = time.time() - self.stats['start_time'] - uptime_str = f"{int(uptime//3600)}h {int((uptime%3600)//60)}m" +# def print_stats(self): +# """Print pool statistics""" +# try: +# uptime = time.time() - self.stats['start_time'] +# uptime_str = f"{int(uptime//3600)}h {int((uptime%3600)//60)}m" - accept_rate = 0 - if self.stats['total_shares'] > 0: - accept_rate = (self.stats['accepted_shares'] / self.stats['total_shares']) * 100 +# accept_rate = 0 +# if self.stats['total_shares'] > 0: +# accept_rate = (self.stats['accepted_shares'] / self.stats['total_shares']) * 100 - print(f"\n๐Ÿ“Š POOL STATISTICS:") - print(f" โฐ Uptime: {uptime_str}") - print(f" ๐Ÿ‘ฅ Connected miners: {self.stats['connections']}") - print(f" ๐Ÿ“ˆ Shares: {self.stats['accepted_shares']}/{self.stats['total_shares']} ({accept_rate:.1f}% accepted)") - print(f" ๐ŸŽ‰ Blocks found: {self.stats['blocks_found']}") - print(f" ๐ŸŽฏ Network difficulty: {self.calculate_network_difficulty(self.current_job['target']) if self.current_job else 'unknown':.6f}") +# print(f"\n๐Ÿ“Š POOL STATISTICS:") +# print(f" โฐ Uptime: {uptime_str}") +# print(f" ๐Ÿ‘ฅ Connected miners: {self.stats['connections']}") +# print(f" ๐Ÿ“ˆ Shares: {self.stats['accepted_shares']}/{self.stats['total_shares']} ({accept_rate:.1f}% accepted)") +# print(f" ๐ŸŽ‰ Blocks found: {self.stats['blocks_found']}") +# print(f" ๐ŸŽฏ Network difficulty: {self.calculate_network_difficulty(self.current_job['target']) if self.current_job else 'unknown':.6f}") - # Calculate hashrate estimate from connected clients - total_hashrate = 0 - for addr, client_data in self.clients.items(): - share_count = client_data.get('share_count', 0) - connect_time = client_data.get('connect_time', time.time()) - mining_duration = time.time() - connect_time - if mining_duration > 60 and share_count > 0: - stratum_diff = client_data.get('stratum_difficulty', 0.001) - # Rough hashrate estimate: shares * difficulty * 2^32 / time - hashrate = (share_count * stratum_diff * 4294967296) / mining_duration - total_hashrate += hashrate - print(f" ๐Ÿ”ฅ {addr}: ~{hashrate/1000:.0f} kH/s") +# # Calculate hashrate estimate from connected clients +# total_hashrate = 0 +# for addr, client_data in self.clients.items(): +# share_count = client_data.get('share_count', 0) +# connect_time = client_data.get('connect_time', time.time()) +# mining_duration = time.time() - connect_time +# if mining_duration > 60 and share_count > 0: +# stratum_diff = client_data.get('stratum_difficulty', 0.001) +# # Rough hashrate estimate: shares * difficulty * 2^32 / time +# hashrate = (share_count * stratum_diff * 4294967296) / mining_duration +# total_hashrate += hashrate +# print(f" ๐Ÿ”ฅ {addr}: ~{hashrate/1000:.0f} kH/s") - if total_hashrate > 0: - print(f" ๐Ÿš€ Total pool hashrate: ~{total_hashrate/1000:.0f} kH/s") - print() +# if total_hashrate > 0: +# print(f" ๐Ÿš€ Total pool hashrate: ~{total_hashrate/1000:.0f} kH/s") +# print() - except Exception as e: - print(f"Stats error: {e}") +# except Exception as e: +# print(f"Stats error: {e}") - def job_updater(self): - """Periodically update mining jobs""" - balance_log_counter = 0 - stats_counter = 0 +# def job_updater(self): +# """Periodically update mining jobs""" +# balance_log_counter = 0 +# stats_counter = 0 - while self.running: - try: - time.sleep(30) # Update every 30 seconds +# while self.running: +# try: +# time.sleep(30) # Update every 30 seconds - old_height = self.current_job['height'] if self.current_job else 0 +# old_height = self.current_job['height'] if self.current_job else 0 - if self.get_block_template(): - new_height = self.current_job['height'] - if new_height > old_height: - print(f"New block detected! Broadcasting new job...") - self.broadcast_new_job() +# if self.get_block_template(): +# new_height = self.current_job['height'] +# if new_height > old_height: +# print(f"New block detected! Broadcasting new job...") +# self.broadcast_new_job() - # Log wallet balance every 10 minutes (20 cycles of 30 seconds) - balance_log_counter += 1 - if balance_log_counter >= 20: - self.log_wallet_balance() - balance_log_counter = 0 +# # Log wallet balance every 10 minutes (20 cycles of 30 seconds) +# balance_log_counter += 1 +# if balance_log_counter >= 20: +# self.log_wallet_balance() +# balance_log_counter = 0 - # Print stats every 5 minutes (10 cycles of 30 seconds) - stats_counter += 1 - if stats_counter >= 10: - self.print_stats() - stats_counter = 0 +# # Print stats every 5 minutes (10 cycles of 30 seconds) +# stats_counter += 1 +# if stats_counter >= 10: +# self.print_stats() +# stats_counter = 0 - except Exception as e: - print(f"Job updater error: {e}") +# except Exception as e: +# print(f"Job updater error: {e}") - def validate_mining_capability(self): - """Validate that we can mine valid blocks against the RinCoin node""" - try: - print("๐Ÿ” Validating mining capability...") +# def validate_mining_capability(self): +# """Validate that we can mine valid blocks against the RinCoin node""" +# try: +# print("๐Ÿ” Validating mining capability...") - # Get block template - template = self.rpc_call("getblocktemplate", [{"rules": ["segwit", "mweb"]}]) - if not template: - print("โŒ Cannot get block template") - return False +# # Get block template +# template = self.rpc_call("getblocktemplate", [{"rules": ["segwit", "mweb"]}]) +# if not template: +# print("โŒ Cannot get block template") +# return False - # Test address validation - result = self.rpc_call("validateaddress", [self.target_address]) - if not result or not result.get('isvalid'): - print(f"โŒ Target address {self.target_address} is invalid") - return False +# # Test address validation +# result = self.rpc_call("validateaddress", [self.target_address]) +# if not result or not result.get('isvalid'): +# print(f"โŒ Target address {self.target_address} is invalid") +# return False - print(f"โœ… Target address {self.target_address} is valid") +# print(f"โœ… Target address {self.target_address} is valid") - # Test coinbase construction - coinbase_wit, coinbase_nowit = self.build_coinbase_transaction_for_address( - template, "00000001", "01000000", self.target_address) +# # Test coinbase construction +# coinbase_wit, coinbase_nowit = self.build_coinbase_transaction_for_address( +# template, "00000001", "01000000", self.target_address) - if not coinbase_wit or not coinbase_nowit: - print("โŒ Cannot construct coinbase transaction") - return False +# if not coinbase_wit or not coinbase_nowit: +# print("โŒ Cannot construct coinbase transaction") +# return False - print(f"โœ… Coinbase construction works") +# print(f"โœ… Coinbase construction works") - # Test block header construction with dummy values - test_nonce = "12345678" - test_ntime = f"{int(time.time()):08x}" +# # Test block header construction with dummy values +# test_nonce = "12345678" +# test_ntime = f"{int(time.time()):08x}" - # Calculate merkle root - coinbase_txid = hashlib.sha256(hashlib.sha256(coinbase_nowit).digest()).digest()[::-1] - merkle_root = self.calculate_merkle_root(coinbase_txid, template.get('transactions', [])) +# # Calculate merkle root +# coinbase_txid = hashlib.sha256(hashlib.sha256(coinbase_nowit).digest()).digest()[::-1] +# merkle_root = self.calculate_merkle_root(coinbase_txid, template.get('transactions', [])) - # Build test header - header = b'' - header += struct.pack(' X.XX RIN to pool' - Undistributed" -echo "3. '๐Ÿ’ฐ Pool keeps X.XX RIN from miners without addresses' - Pool keeps rewards" -echo "4. '๐Ÿ“Š Summary: X miners with addresses, Y without (rewards to pool)' - Final summary" +# echo "" +# echo "๐Ÿ“Š Pool Log Analysis:" +# echo "Look for these patterns in the logs above:" +# echo "1. '๐Ÿ’ฐ Miner rin1q...: X.XX RIN (difficulty)' - Base rewards" +# echo "2. 'โš ๏ธ Miner without address: X difficulty -> X.XX RIN to pool' - Undistributed" +# echo "3. '๐Ÿ’ฐ Pool keeps X.XX RIN from miners without addresses' - Pool keeps rewards" +# echo "4. '๐Ÿ“Š Summary: X miners with addresses, Y without (rewards to pool)' - Final summary" -echo "" -echo "๐Ÿงน Cleaning up..." -kill $POOL_PID 2>/dev/null -./MINE/rin/kill_stratum_proxy.sh +# echo "" +# echo "๐Ÿงน Cleaning up..." +# kill $POOL_PID 2>/dev/null +# ./MINE/rin/kill_stratum_proxy.sh -echo "" -echo "๐Ÿ“‹ Reward Distribution Logic Summary:" -echo "" -echo "โœ… Miners with valid RinCoin addresses:" -echo " - Get reward based on their difficulty" -echo " - Rewards sent directly to their addresses" -echo "" -echo "โš ๏ธ Miners without addresses:" -echo " - Contribute to total difficulty" -echo " - Their reward share goes to pool address" -echo " - No direct rewards received" -echo "" -echo "๐Ÿ’ฐ Pool fee: Always 1% of total block reward" -echo "๐Ÿ’ฐ Pool bonus: Additional rewards from miners without addresses" +# echo "" +# echo "๐Ÿ“‹ Reward Distribution Logic Summary:" +# echo "" +# echo "โœ… Miners with valid RinCoin addresses:" +# echo " - Get reward based on their difficulty" +# echo " - Rewards sent directly to their addresses" +# echo "" +# echo "โš ๏ธ Miners without addresses:" +# echo " - Contribute to total difficulty" +# echo " - Their reward share goes to pool address" +# echo " - No direct rewards received" +# echo "" +# echo "๐Ÿ’ฐ Pool fee: Always 1% of total block reward" +# echo "๐Ÿ’ฐ Pool bonus: Additional rewards from miners without addresses" From d9bb3addf2146710c813d8908b71b79e63db17cb Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 30 Sep 2025 12:11:57 +0300 Subject: [PATCH 30/30] store git creds in file --- linux/setup git.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linux/setup git.sh b/linux/setup git.sh index c1899fe..ba0e4ef 100644 --- a/linux/setup git.sh +++ b/linux/setup git.sh @@ -2,10 +2,10 @@ git config --global user.name "Dobromir Popov" -#store credentals -git config --global credential.helper store - +#store credentals in file +git config --global credential.helper store --file +git config credential.helper store --file #add upstream (when forked) git remote add upstream https://github.com/petals-infra/health.petals.dev.git