ncantu cb13ab6fbf Add skipIfExists parameter to anchor API endpoint
**Motivations:**
- Avoid unnecessary re-anchoring of already anchored hashes
- Improve performance by using database as source of truth
- Return consistent information without additional RPC calls

**Evolutions:**
- Added optional skipIfExists parameter to /api/anchor/document endpoint
- Check database for existing anchors before creating new transaction
- Automatically store anchors in database after transaction creation
- Return old: true/false flag and ok: true in all responses
- Enrich anchors table with all necessary information for retrieval without RPC calls

**Pages affectées:**
- api-anchorage/src/routes/anchor.js: Added skipIfExists parameter and database check
- api-anchorage/src/bitcoin-rpc.js: Store anchor in database after transaction creation
- api-anchorage/README.md: Updated documentation with new parameter and response format
- features/api-anchorage-skip-if-exists.md: Evolution documentation
2026-01-28 08:24:23 +01:00

407 lines
9.8 KiB
Markdown

# API d'Ancrage Bitcoin Signet
**Auteur** : Équipe 4NK
**Date** : 2026-01-23
**Version** : 1.0
## Description
API REST pour ancrer des documents sur la blockchain Bitcoin Signet. Cette API permet de créer des transactions Bitcoin qui incluent les hash de documents dans des outputs OP_RETURN, permettant ainsi de prouver l'existence d'un document à un moment donné.
## Caractéristiques
- **Port** : `3010`
- **Domaine** : `certificator.4nkweb.com` (via nginx sur proxy 192.168.1.100)
- **Authentification** : API Key via header `x-api-key`
- **Format** : JSON REST API
- **Bitcoin** : Connexion RPC au nœud Bitcoin Signet (port 38332)
- **Mempool** : Les transactions sont envoyées au mempool et retournées immédiatement (pas de callbacks)
## Installation
### Prérequis
- Node.js >= 18.0.0
- Accès au nœud Bitcoin Signet (RPC sur port 38332)
- Wallet Bitcoin avec des fonds pour créer des transactions
### Installation des Dépendances
```bash
cd api-anchorage
npm install
```
### Configuration
1. Copier le fichier d'exemple :
```bash
cp .env.example .env
```
2. Éditer `.env` :
```bash
# Bitcoin RPC Configuration
BITCOIN_RPC_HOST=localhost
BITCOIN_RPC_PORT=38332
BITCOIN_RPC_USER=bitcoin
BITCOIN_RPC_PASSWORD=bitcoin
# API Configuration
API_PORT=3010
API_HOST=0.0.0.0
# API Keys (séparées par des virgules)
API_KEYS=your-api-key-here,another-api-key
# Logging
LOG_LEVEL=info
# Mining Configuration
MINING_ENABLED=true
MINING_FEE_RATE=0.00001
```
**Important** :
- `BITCOIN_RPC_HOST` : Si l'API est dans un conteneur Docker, utiliser l'IP du conteneur Bitcoin ou `host.docker.internal`
- `API_KEYS` : Définir au moins une clé API valide
## Démarrage
### Mode Développement
```bash
npm run dev
```
### Mode Production
```bash
npm start
```
### Avec PM2 (recommandé pour production)
```bash
pm2 start src/server.js --name anchor-api
pm2 save
pm2 startup
```
## Endpoints
### GET /health
Vérifie l'état de l'API et de la connexion Bitcoin.
**Authentification** : Non requise
**Réponse** :
```json
{
"ok": true,
"service": "anchor-api",
"bitcoin": {
"connected": true,
"blocks": 152321,
"chain": "signet",
"networkactive": true,
"connections": 1
},
"timestamp": "2026-01-23T16:35:27.821Z"
}
```
### POST /api/anchor/document
Ancre un document sur Bitcoin Signet. La transaction est créée et envoyée au mempool, puis retournée immédiatement.
**Authentification** : Requise (header `x-api-key`)
**Body** :
```json
{
"documentUid": "doc-123456",
"hash": "a1b2c3d4e5f6...",
"skipIfExists": false
}
```
**Paramètres** :
- `documentUid` : string (optionnel, identifiant du document)
- `hash` : string (requis, hash SHA256 du document en hex, 64 caractères)
- `skipIfExists` : boolean (optionnel, par défaut `false`, si `true`, ne réancrera pas un hash déjà ancré et retournera les informations existantes)
**Note** : La transaction est envoyée au mempool et retournée immédiatement. Aucun callback n'est supporté.
**Réponse** (nouvel ancrage) :
```json
{
"ok": true,
"txid": "56504e002d95301ebcfb4b30eaedc5d3fd9a448e121ffdce4f356b8d34169e85",
"status": "confirmed",
"confirmations": 0,
"block_height": 152321,
"outputs": [...],
"fee": 0.00001,
"fee_sats": 1000,
"old": false
}
```
**Réponse** (hash déjà ancré avec `skipIfExists: true`) :
```json
{
"ok": true,
"txid": "56504e002d95301ebcfb4b30eaedc5d3fd9a448e121ffdce4f356b8d34169e85",
"status": "confirmed",
"confirmations": 5,
"block_height": 152316,
"old": true
}
```
**Champs de réponse** :
- `ok` : boolean, toujours `true` en cas de succès
- `txid` : string, ID de la transaction Bitcoin
- `status` : string, statut de la transaction (`"confirmed"` ou `"pending"`)
- `confirmations` : number, nombre de confirmations
- `block_height` : number|null, hauteur du bloc (null si pas encore dans un bloc)
- `outputs` : array, liste des outputs de la transaction (uniquement pour nouveaux ancrages)
- `fee` : number|null, frais de transaction en BTC (uniquement pour nouveaux ancrages)
- `fee_sats` : number|null, frais de transaction en sats (uniquement pour nouveaux ancrages)
- `old` : boolean, `true` si le hash était déjà ancré, `false` si c'est un nouvel ancrage
**Erreurs** :
- `400 Bad Request` : Hash invalide
- `401 Unauthorized` : Clé API invalide ou manquante
- `402 Payment Required` : Solde insuffisant
- `500 Internal Server Error` : Erreur serveur
### POST /api/anchor/verify
Vérifie si un hash est ancré sur Bitcoin Signet.
**Authentification** : Requise (header `x-api-key`)
**Body** :
```json
{
"hash": "a1b2c3d4e5f6...",
"txid": "56504e002d95301ebcfb4b30eaedc5d3fd9a448e121ffdce4f356b8d34169e85" // optionnel
}
```
**Réponse** (hash trouvé) :
```json
{
"verified": true,
"anchor_info": {
"transaction_id": "56504e002d95301ebcfb4b30eaedc5d3fd9a448e121ffdce4f356b8d34169e85",
"block_height": 152321,
"confirmations": 0,
"current_block_height": 152321
}
}
```
**Réponse** (hash non trouvé) :
```json
{
"verified": false,
"message": "Hash not found in recent blocks"
}
```
## Utilisation
### Exemple avec curl
```bash
# Health check
curl http://localhost:3010/health
# Ancrer un document
curl -X POST http://localhost:3010/api/anchor/document \
-H "Content-Type: application/json" \
-H "x-api-key: your-api-key-here" \
-d '{
"documentUid": "doc-123",
"hash": "a1b2c3d4e5f6789012345678901234567890123456789012345678901234567890"
}'
# Ancrer un document sans réancrer si déjà ancré
curl -X POST http://localhost:3010/api/anchor/document \
-H "Content-Type: application/json" \
-H "x-api-key: your-api-key-here" \
-d '{
"documentUid": "doc-123",
"hash": "a1b2c3d4e5f6789012345678901234567890123456789012345678901234567890",
"skipIfExists": true
}'
# Vérifier un ancrage
curl -X POST http://localhost:3010/api/anchor/verify \
-H "Content-Type: application/json" \
-H "x-api-key: your-api-key-here" \
-d '{
"hash": "a1b2c3d4e5f6789012345678901234567890123456789012345678901234567890"
}'
```
### Exemple avec le client de test
```bash
# Configurer la clé API
export API_KEY=your-api-key-here
export API_URL=http://localhost:3010
# Exécuter le test
npm test
```
## Configuration Nginx (sur proxy 192.168.1.100)
Ajouter dans la configuration nginx du proxy :
```nginx
# API Anchor sur certificator.4nkweb.com
server {
listen 443 ssl http2;
server_name certificator.4nkweb.com;
ssl_certificate /etc/letsencrypt/live/certificator.4nkweb.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/certificator.4nkweb.com/privkey.pem;
location / {
proxy_pass http://192.168.1.103:3010;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}
```
**Note** : Remplacer `192.168.1.103` par l'IP du serveur où l'API est déployée.
## Architecture
```
Client
↓ HTTPS
Nginx (proxy 192.168.1.100:443)
↓ HTTP
API Anchor (port 3010)
↓ RPC
Bitcoin Signet Node (port 38332)
```
## Sécurité
### Clés API
- Les clés API sont définies dans `.env` (variable `API_KEYS`)
- Plusieurs clés peuvent être définies (séparées par des virgules)
- La clé doit être envoyée dans le header `x-api-key`
- Le endpoint `/health` ne nécessite pas d'authentification
### Recommandations
1. **Ne jamais commiter `.env`** : Le fichier `.env` contient des secrets
2. **Utiliser HTTPS** : Via nginx avec certificats Let's Encrypt
3. **Restreindre RPCALLOWIP** : Dans la configuration Bitcoin, limiter l'accès RPC
4. **Rotater les clés API** : Changer régulièrement les clés API
5. **Monitoring** : Surveiller les logs pour détecter les abus
## Dépannage
### L'API ne peut pas se connecter à Bitcoin
**Vérifier** :
```bash
# Vérifier que le nœud Bitcoin est accessible
curl -u bitcoin:bitcoin http://localhost:38332
# Vérifier les variables d'environnement
grep BITCOIN_RPC .env
```
### Erreur "Insufficient balance"
Le wallet Bitcoin n'a pas assez de fonds pour créer des transactions.
**Solution** :
- Miner des blocs pour obtenir des récompenses
- Recevoir des fonds depuis un autre wallet
- Vérifier le solde : `bitcoin-cli getbalance`
### Erreur "Unauthorized"
La clé API est invalide ou manquante.
**Solution** :
- Vérifier que le header `x-api-key` est présent
- Vérifier que la clé est dans `API_KEYS` du `.env`
## Logs
Les logs sont affichés sur la console avec le format :
```
[2026-01-23T16:35:27.821Z] [INFO] API d'ancrage Bitcoin Signet démarrée {"host":"0.0.0.0","port":3010}
```
Niveaux de log :
- `error` : Erreurs critiques
- `warn` : Avertissements
- `info` : Informations générales
- `debug` : Détails de débogage
Contrôlé par la variable `LOG_LEVEL` dans `.env`.
## Structure du Projet
```
api-anchorage/
├── src/
│ ├── server.js # Serveur Express principal
│ ├── bitcoin-rpc.js # Client Bitcoin RPC
│ ├── logger.js # Système de logging
│ └── routes/
│ ├── health.js # Route health check
│ └── anchor.js # Routes d'ancrage
├── package.json
├── .env.example
├── .env # Configuration (ne pas commiter)
├── README.md
└── src/test-client.js # Client de test
```
## Développement
### Tests Locaux
```bash
# Démarrer l'API
npm run dev
# Dans un autre terminal, tester
npm test
```
### Format de Transaction
Les transactions d'ancrage utilisent un output OP_RETURN avec le format :
- Préfixe : `"ANCHOR:"` (7 bytes)
- Hash : Hash SHA256 du document (32 bytes)
Total : 39 bytes dans l'output OP_RETURN.
---
**Dernière mise à jour** : 2026-01-23