From 92d13e2973fb912b0816b972db47849ff109cce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Tr=C3=B6mml?= Date: Wed, 29 Apr 2026 19:04:18 +0000 Subject: [PATCH] initial commit --- .gitignore | 3 ++ Dockerfile | 17 +++++++ docker-compose.yml | 15 ++++++ main.py | 119 +++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 4 ++ 5 files changed, 158 insertions(+) create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 main.py create mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..df7bb3f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.env +venv/ +/venv/ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..cbde229 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +FROM python:3.11-slim + +WORKDIR /app + +# System-Abhängigkeiten installieren (bitcoinlib braucht oft gcc) +RUN apt-get update && apt-get install -y gcc && rm -rf /var/lib/apt/lists/* + +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +# Kopiert den Code UND die .env-Datei in den Container +COPY . . + +# Teilt Docker mit, dass dieser Container auf Port 5000 lauscht +EXPOSE 5001 + +CMD ["python", "main.py"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..e9e318c --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,15 @@ +version: '3.8' + +services: + bitcoin-api: + build: . + container_name: btc_api_service + ports: + - "5001:5001" # Mappt den Port 5000 deines PCs auf Port 5000 im Container + environment: + - PYTHONUNBUFFERED=1 + # Hier kannst du Variablen setzen, die deine main.py ausliest + # - BTC_NODE_URL=http://user:pass@192.168.1.x:8332 + volumes: + - .:/app + restart: always diff --git a/main.py b/main.py new file mode 100644 index 0000000..d6ca4ef --- /dev/null +++ b/main.py @@ -0,0 +1,119 @@ +import os +from flask import Flask, jsonify, request +from bitcoinlib.services.bitcoind import BitcoindClient +from dotenv import load_dotenv + +# Lade die Variablen aus der .env-Datei in die Umgebung +load_dotenv() + +app = Flask(__name__) + +# --- ZUGANGSDATEN AUS UMGEBUNGSVARIABLEN LADEN --- +# os.getenv sucht nach dem Namen und liest den Wert aus +RPC_USER = os.getenv('RPC_USER') +RPC_PASS = os.getenv('RPC_PASS') +# Da das Skript IN der Windows-VM läuft, ist der Node lokal erreichbar: +IP_ADRESSE = '192.168.178.225' + +# Sicherheits-Check: Falls die .env fehlt oder leer ist, bricht das Skript ab +if not RPC_USER or not RPC_PASS: + raise ValueError("Fehler: RPC_USER oder RPC_PASS wurden nicht in der Umgebung gefunden!") + +rpc_url = f'http://{RPC_USER}:{RPC_PASS}@{IP_ADRESSE}:8332' + +def get_node(): + return BitcoindClient(network='bitcoin', base_url=rpc_url).proxy + +# ========================================== +# ENDPUNKT 1: Aktuelle Blockhöhe abfragen +# ========================================== +@app.route('/api/blockhoehe', methods=['GET']) +def get_blockhoehe(): + try: + node = get_node() + info = node.getblockchaininfo() + return jsonify({ + 'status': 'success', + 'blockhoehe': info['blocks'], + 'sync_fortschritt_prozent': round(info.get('verificationprogress', 0) * 100, 2) + }) + except Exception as e: + return jsonify({'status': 'error', 'message': str(e)}), 500 + +# ========================================== +# ENDPUNKT 2: Bestimmten Block abfragen +# ========================================== +@app.route('/api/block/', methods=['GET']) +def get_block(hoehe): + try: + node = get_node() + block_hash = node.getblockhash(hoehe) + block_daten = node.getblock(block_hash, 2) + return jsonify({'status': 'success', 'block': block_daten}) + except Exception as e: + return jsonify({'status': 'error', 'message': str(e)}), 500 + +# ========================================== +# ENDPUNKT 3: Einzelne Transaktion abfragen +# ========================================== +@app.route('/api/tx/', methods=['GET']) +def get_tx(txid): + try: + node = get_node() + tx_daten = node.getrawtransaction(txid, True) + return jsonify({'status': 'success', 'transaction': tx_daten}) + except Exception as e: + return jsonify({'status': 'error', 'message': str(e)}), 500 + +# ========================================== +# ENDPUNKT 4: Guthaben einer beliebigen Adresse +# ========================================== +@app.route('/api/guthaben/', methods=['GET']) +def get_guthaben(adresse): + try: + node = get_node() + scan_result = node.scantxoutset("start", [f"addr({adresse})"]) + return jsonify({ + 'status': 'success', + 'adresse': adresse, + 'guthaben_btc': scan_result.get('total_amount', 0), + 'anzahl_utxos': len(scan_result.get('unspents', [])), + # NEU: Wir schicken die komplette Liste der Münzen mit! + 'utxos': scan_result.get('unspents', []) + }) + except Exception as e: + return jsonify({'status': 'error', 'message': str(e)}), 500 + +# ========================================== +# NEU: ENDPUNKT 5: Transaktion senden (POST) +# ========================================== +@app.route('/api/sendtx', methods=['POST']) +def send_tx(): + try: + # Wir erwarten ein JSON-Body mit dem Inhalt: {"hex": "01000000..."} + daten = request.get_json() + + if not daten or 'hex' not in daten: + return jsonify({'status': 'error', 'message': 'Kein gueltiger Hex-String uebergeben. Sende ein JSON mit dem Key "hex".'}), 400 + + raw_tx_hex = daten['hex'] + node = get_node() + + # Sende die Transaktion an den Node, der sie ins Netzwerk broadcastet + txid = node.sendrawtransaction(raw_tx_hex) + + return jsonify({ + 'status': 'success', + 'message': 'Transaktion erfolgreich an das Netzwerk uebermittelt!', + 'txid': txid + }) + except Exception as e: + return jsonify({'status': 'error', 'message': str(e)}), 500 + +# ========================================== +# Server starten +# ========================================== +if __name__ == '__main__': + print("🚀 API Server startet...") + # host='0.0.0.0' bedeutet, dass die API von anderen Geräten im Heimnetzwerk erreichbar ist! + app.run(host='0.0.0.0', port=5001) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..06bc7e1 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +Flask==3.0.2 +python-dotenv==1.0.1 +bitcoinlib==0.6.15 +requests==2.31.0