docs(sdk_relay): alignement avec 4NK_node (installation, usage, configuration, testing, quick ref, dev, performance, troubleshooting, open source, gitea, release, roadmap, security audit)
Some checks failed
CI - sdk_relay / build-test (push) Failing after 37s
CI - sdk_relay / security (push) Successful in 2m3s

This commit is contained in:
Nicolas Cantu 2025-08-25 15:31:34 +02:00
parent f2b20aee77
commit ccdb2d69fb
15 changed files with 383 additions and 21 deletions

View File

@ -1006,18 +1006,18 @@ class SdkRelayClient {
async connect() { async connect() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.ws = new WebSocket(this.wsUrl); this.ws = new WebSocket(this.wsUrl);
this.ws.onopen = () => { this.ws.onopen = () => {
console.log('Connecté à sdk_relay'); console.log('Connecté à sdk_relay');
this.sendHandshake(); this.sendHandshake();
resolve(); resolve();
}; };
this.ws.onmessage = (event) => { this.ws.onmessage = (event) => {
const message = JSON.parse(event.data); const message = JSON.parse(event.data);
this.handleMessage(message); this.handleMessage(message);
}; };
this.ws.onerror = (error) => { this.ws.onerror = (error) => {
console.error('Erreur WebSocket:', error); console.error('Erreur WebSocket:', error);
reject(error); reject(error);
@ -1097,11 +1097,11 @@ const client = new SdkRelayClient('ws://localhost:8090', 'http://localhost:8091'
async function main() { async function main() {
await client.connect(); await client.connect();
// Obtenir les métriques // Obtenir les métriques
const metrics = await client.getMetrics(); const metrics = await client.getMetrics();
console.log('Métriques:', metrics); console.log('Métriques:', metrics);
// Forcer une synchronisation // Forcer une synchronisation
await client.forceSync(['HealthSync']); await client.forceSync(['HealthSync']);
} }
@ -1124,11 +1124,11 @@ class SdkRelayClient:
self.http_url = http_url self.http_url = http_url
self.websocket = None self.websocket = None
self.client_id = f"python-client-{int(datetime.now().timestamp())}" self.client_id = f"python-client-{int(datetime.now().timestamp())}"
async def connect(self): async def connect(self):
self.websocket = await websockets.connect(self.ws_url) self.websocket = await websockets.connect(self.ws_url)
await self.send_handshake() await self.send_handshake()
async def send_handshake(self): async def send_handshake(self):
handshake = { handshake = {
"type": "handshake", "type": "handshake",
@ -1137,12 +1137,12 @@ class SdkRelayClient:
"capabilities": ["sync", "notifications", "health"] "capabilities": ["sync", "notifications", "health"]
} }
await self.websocket.send(json.dumps(handshake)) await self.websocket.send(json.dumps(handshake))
async def listen(self): async def listen(self):
async for message in self.websocket: async for message in self.websocket:
data = json.loads(message) data = json.loads(message)
await self.handle_message(data) await self.handle_message(data)
async def handle_message(self, message): async def handle_message(self, message):
if message['type'] == 'handshake_response': if message['type'] == 'handshake_response':
print(f"Handshake accepté par {message['relay_id']}") print(f"Handshake accepté par {message['relay_id']}")
@ -1150,57 +1150,57 @@ class SdkRelayClient:
await self.handle_notification(message) await self.handle_notification(message)
elif message['type'] == 'sync': elif message['type'] == 'sync':
await self.handle_sync(message) await self.handle_sync(message)
async def handle_notification(self, message): async def handle_notification(self, message):
print(f"Notification {message['notification_type']}: {message['data']}") print(f"Notification {message['notification_type']}: {message['data']}")
async def handle_sync(self, message): async def handle_sync(self, message):
print(f"Sync {message['sync_type']}: {message['payload']}") print(f"Sync {message['sync_type']}: {message['payload']}")
# Méthodes HTTP # Méthodes HTTP
async def get_health(self): async def get_health(self):
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.get(f"{self.http_url}/health") as response: async with session.get(f"{self.http_url}/health") as response:
return await response.json() return await response.json()
async def get_metrics(self): async def get_metrics(self):
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.get(f"{self.http_url}/metrics") as response: async with session.get(f"{self.http_url}/metrics") as response:
return await response.json() return await response.json()
async def get_relays(self): async def get_relays(self):
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.get(f"{self.http_url}/relays") as response: async with session.get(f"{self.http_url}/relays") as response:
return await response.json() return await response.json()
async def force_sync(self, sync_types=None): async def force_sync(self, sync_types=None):
if sync_types is None: if sync_types is None:
sync_types = ['StateSync'] sync_types = ['StateSync']
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.post( async with session.post(
f"{self.http_url}/sync/force", f"{self.http_url}/sync/force",
json={"sync_types": sync_types} json={"sync_types": sync_types}
) as response: ) as response:
return await response.json() return await response.json()
async def close(self): async def close(self):
if self.websocket: if self.websocket:
await self.websocket.close() await self.websocket.close()
async def main(): async def main():
client = SdkRelayClient('ws://localhost:8090', 'http://localhost:8091') client = SdkRelayClient('ws://localhost:8090', 'http://localhost:8091')
try: try:
await client.connect() await client.connect()
# Obtenir les métriques # Obtenir les métriques
metrics = await client.get_metrics() metrics = await client.get_metrics()
print("Métriques:", metrics) print("Métriques:", metrics)
# Écouter les messages # Écouter les messages
await client.listen() await client.listen()
except Exception as e: except Exception as e:
print(f"Erreur: {e}") print(f"Erreur: {e}")
finally: finally:

27
docs/CONFIGURATION.md Normal file
View File

@ -0,0 +1,27 @@
# Configuration - sdk_relay
## Fichier `.conf`
Champs principaux:
- core_url=http://bitcoin:18443
- core_wallet=relay_wallet
- ws_url=0.0.0.0:8090
- blindbit_url=http://blindbit:8000
- zmq_url=tcp://bitcoin:29000
- network=signet
- relay_id=relay-1
- sync_interval=30
- health_interval=60
## Variables d'environnement
- RUST_LOG=debug,bitcoincore_rpc=trace
- BITCOIN_COOKIE_PATH=/home/bitcoin/.4nk/bitcoin.cookie
- ENABLE_SYNC_TEST=1
## Hiérarchie de configuration
1. Variables d'environnement
2. Fichier `.conf`
3. Valeurs par défaut

32
docs/DEVELOPMENT.md Normal file
View File

@ -0,0 +1,32 @@
# Développement - sdk_relay
## Environnement
- Rust 1.70+
- cargo, rustfmt, clippy
## Commandes
```bash
# Lancer en dev
RUST_LOG=debug cargo run -- --config .conf
# Lint et format
cargo clippy -- -D warnings
cargo fmt
# Tests
cargo test --all
```
## Conventions
- Messages de commit conventionnels (feat/fix/docs/test/chore)
- Code lisible, erreurs gérées, early returns
- Pas de secrets en dur
## Structure
- `src/` modules (websocket, http, sync, daemon)
- `docs/` documentation utilisateur/technique
- `tests/` scripts et artefacts

21
docs/GITEA_SETUP.md Normal file
View File

@ -0,0 +1,21 @@
# Gitea Setup - sdk_relay
## Dépôt
- Hébergeur: `git.4nkweb.com`
- Protocole: SSH recommandé
- Protection des branches (main)
## Templates
- `.gitea/ISSUE_TEMPLATE/*`
- `.gitea/PULL_REQUEST_TEMPLATE.md`
- `.gitea/workflows/ci.yml`
## Droits et revues
- Reviews requises pour PR → main
- Checks CI obligatoires
- Stratégie de merge: squash + rebase
## Releases
- Tags SemVer
- CHANGELOG mis à jour
- Artefacts (binaires/images) optionnels

View File

@ -3,6 +3,18 @@
## Guides ## Guides
- [Architecture](ARCHITECTURE.md) - Architecture technique détaillée - [Architecture](ARCHITECTURE.md) - Architecture technique détaillée
- [API](API.md) - Référence complète des APIs WebSocket et HTTP - [API](API.md) - Référence complète des APIs WebSocket et HTTP
- [Installation](INSTALLATION.md) - Installation et vérifications
- [Utilisation](USAGE.md) - Guide d'utilisation
- [Configuration](CONFIGURATION.md) - Paramètres et env vars
- [Développement](DEVELOPMENT.md) - Environnement développeur
- [Tests](TESTING.md) - Stratégie et commandes
- [Performance](PERFORMANCE.md) - Objectifs et mesures
- [Dépannage](TROUBLESHOOTING.md) - Problèmes courants
- [Open Source Checklist](OPEN_SOURCE_CHECKLIST.md) - Préparation open source
- [Gitea Setup](GITEA_SETUP.md) - CI/TEMPLATES Gitea
- [Plan de Release](RELEASE_PLAN.md) - Processus de release
- [Roadmap](ROADMAP.md) - Évolution
- [Audit de Sécurité](SECURITY_AUDIT.md) - Contrôles et recommandations
- [Contribution](../CONTRIBUTING.md) - Guide de contribution - [Contribution](../CONTRIBUTING.md) - Guide de contribution
- [Sécurité](../SECURITY.md) - Politique de sécurité - [Sécurité](../SECURITY.md) - Politique de sécurité
- [Changelog](../CHANGELOG.md) - Historique des versions - [Changelog](../CHANGELOG.md) - Historique des versions

25
docs/INSTALLATION.md Normal file
View File

@ -0,0 +1,25 @@
# Installation - sdk_relay
## Prérequis
- Docker 24+ ou Rust 1.70+
- Bitcoin Core (signet) accessible via RPC
- Blindbit (oracle) accessible via HTTP
## Méthodes d'installation
### Docker (recommandé)
- Construire l'image locale puis exécuter le conteneur
- Exposer les ports 8090 (WebSocket) et 8091 (HTTP)
- Fournir la configuration via fichier `.conf` ou variables d'environnement
### Binaire Rust
- Compiler en profil release
- Lancer avec un fichier `.conf`
## Vérifications post-installation
- Endpoint `HTTP /health` répond avec `status=healthy`
- Port WebSocket en écoute sur 8090
- Connexion RPC à Bitcoin Core opérationnelle
- Accès au service Blindbit opérationnel

View File

@ -0,0 +1,28 @@
# Open Source Checklist - sdk_relay
## Fichiers requis
- LICENSE (MIT)
- CONTRIBUTING.md
- CODE_OF_CONDUCT.md
- SECURITY.md
- CHANGELOG.md
- docs/ (complet)
- .gitea/ (templates + workflows)
## CI/CD (Gitea Actions)
- Lint (clippy, fmt)
- Tests unitaires/integration
- Audit de sécurité (cargo audit)
- Build Docker
- Vérif docs
## Qualité et sécurité
- Pas de secrets en dur
- Dépendances à jour
- Politique de versions (SemVer)
- Changelog maintenu
## Communication
- Templates Issues/PR
- Guide Communauté
- Plan de release

26
docs/PERFORMANCE.md Normal file
View File

@ -0,0 +1,26 @@
# Performance - sdk_relay
## Objectifs
- Latence sync < 100 ms (local)
- Messages/s > 1000 (agrégé)
- CPU < 70% en nominal
- Mémoire < 512MB/relais
## Tests de performance
- Tests WebSocket de charge
- Mesure latence/percentiles
- Monitoring CPU/Mem/FDs
## Optimisations
- Async `tokio`
- Cache de déduplication
- Batching raisonnable
- Backpressure côté clients
## Monitoring
- Scripts dobservation (stats système)
- Export métriques endpoints `/metrics`

31
docs/QUICK_REFERENCE.md Normal file
View File

@ -0,0 +1,31 @@
# Référence Rapide - sdk_relay
## Endpoints clés
- WS: `ws://host:8090`
- HTTP: `http://host:8091`
- Health: `GET /health`
- Métriques: `GET /metrics`
## Messages WS
- handshake → handshake_response
- ping → pong
- subscribe/unsubscribe
- notifications: payment_detected, block_mined
## Sync
- Types: StateSync, HealthSync, MetricsSync
- Forcer: `POST /sync/force`
## Logs
- Niveau: `RUST_LOG=debug`
- Fichiers: selon loutil de lancement
## Dépannage rapide
- Ports 8090/8091 ouverts
- Bitcoin Core RPC OK
- Blindbit HTTP OK

19
docs/RELEASE_PLAN.md Normal file
View File

@ -0,0 +1,19 @@
# Plan de Release - sdk_relay
## Versioning
- SemVer: MAJOR.MINOR.PATCH
- Branches: `main`, `develop`, `feature/*`
## Phases
1. Gel des fonctionnalités
2. Stabilisation et correctifs
3. Mise à jour CHANGELOG
4. Tag et build
5. Publication et communication
## Checklist release
- CI verte (lint, tests, audit)
- Docs à jour (API, INSTALLATION, USAGE)
- CHANGELOG complété
- Tag créé (`vX.Y.Z`)
- Annonce préparée (Gitea release notes)

25
docs/ROADMAP.md Normal file
View File

@ -0,0 +1,25 @@
# Roadmap - sdk_relay
## Court terme (1-2 mois)
- Finaliser API HTTP (statut détaillé, relays)
- Stabiliser sync (State/Health/Metrics)
- Tests de performance et robustesse
- Documentation complète
## Moyen terme (3-6 mois)
- Signatures des messages de sync
- Compression et fragmentation des messages
- Persistences des états (CRDT/Log)
- Export Prometheus
## Long terme (6-12 mois)
- Mode cluster (HA)
- Découverte via DNS/bootstrap
- Webhooks/REST complets
- Intégrations wallets externes
## Indicateurs
- Latence moyenne sync
- Taux derreurs
- Couverture de tests
- SLO disponibilité

28
docs/SECURITY_AUDIT.md Normal file
View File

@ -0,0 +1,28 @@
# Audit de Sécurité - sdk_relay
## Portée
- Serveur WebSocket (8090)
- Serveur HTTP (8091)
- Sync Manager
- Intégration Bitcoin Core/Blindbit
## Contrôles
- Dépendances (`cargo audit`)
- Secrets en dur (grep tokens/password/key)
- Permissions de fichiers (cookies, clés)
- Validation des entrées (WS/HTTP)
## Tests
- Tests automatiques (scripts + cargo)
- Fuzzing (cibles parsing JSON)
- Charge et DoS (rate limiting)
## Recommandations
- Activer WSS/HTTPS en prod
- Signer/valider les messages de sync
- Journalisation sécurisée (sans secrets)
- Mise à jour régulière des deps
## Résultats et suivi
- Issues Gitea créées pour findings
- Plan de remédiation par priorité

34
docs/TESTING.md Normal file
View File

@ -0,0 +1,34 @@
# Tests - sdk_relay
## Catégories
- Unitaires: tests de fonctions/méthodes
- Intégration: interaction HTTP/WS
- Connectivité: accès réseau et ports
- Externes: tests contre nœuds externes (ex: dev3)
- Performance: charge et latence
## Commandes
```bash
# Tous les tests Rust
cargo test --all
# Lint et format
cargo clippy -- -D warnings
cargo fmt -- --check
# Scripts (si présents)
./tests/run_all_tests.sh
```
## Rapports
- logs: `tests/logs/`
- reports: `tests/reports/`
## Bonnes pratiques
- Tests déterministes
- Données de test isolées
- Nettoyage après exécution

28
docs/TROUBLESHOOTING.md Normal file
View File

@ -0,0 +1,28 @@
# Dépannage - sdk_relay
## Problèmes courants
### 1) `/health` renvoie erreur
- Vérifier Bitcoin Core RPC (`bitcoin-cli -signet getblockchaininfo`)
- Vérifier Blindbit (`curl http://blindbit:8000/health`)
- Vérifier variables `BITCOIN_COOKIE_PATH`
### 2) Port 8090 non accessible
- Vérifier pare-feu
- Vérifier que le processus écoute (netstat/ss)
- Conflit de ports ?
### 3) Messages WS non reçus
- Handshake bien envoyé ?
- Capabilities compatibles ?
- Heartbeat actif (ping/pong) ?
### 4) Sync inopérante
- Relais voisins connus ? (`GET /relays`)
- `StateSync` visible dans logs ?
- Latence réseau élevée ?
## Outils utiles
- `docker logs`, `journalctl` (si service)
- `RUST_LOG=debug`
- Scripts de tests/monitoring

26
docs/USAGE.md Normal file
View File

@ -0,0 +1,26 @@
# Utilisation - sdk_relay
## Démarrage rapide
- Démarrer le service (Docker ou binaire)
- Vérifier `GET /health`
- Connecter un client WebSocket à `ws://host:8090`
## WebSocket
- Envoyer un handshake JSON avec `type=handshake`
- Recevoir `handshake_response`
- S'abonner aux notifications si nécessaire (`subscribe`)
## HTTP
- `GET /health` : santé
- `GET /metrics` : métriques
- `GET /relays` : relais connus
- `POST /sync/force` : forcer une synchronisation
## Bonnes pratiques
- Reconnexion automatique côté client
- Heartbeat régulier (ping/pong)
- Limiter la taille des messages (< 1MB)