initial commit
This commit is contained in:
commit
92d13e2973
5 changed files with 158 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
.env
|
||||||
|
venv/
|
||||||
|
/venv/
|
||||||
17
Dockerfile
Normal file
17
Dockerfile
Normal file
|
|
@ -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"]
|
||||||
15
docker-compose.yml
Normal file
15
docker-compose.yml
Normal file
|
|
@ -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
|
||||||
119
main.py
Normal file
119
main.py
Normal file
|
|
@ -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/<int:hoehe>', 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/<txid>', 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/<adresse>', 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)
|
||||||
4
requirements.txt
Normal file
4
requirements.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
Flask==3.0.2
|
||||||
|
python-dotenv==1.0.1
|
||||||
|
bitcoinlib==0.6.15
|
||||||
|
requests==2.31.0
|
||||||
Loading…
Reference in a new issue