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

+
    +
    +
    + + + + +