**Motivations:**
- Réduire la consommation mémoire en paginant côté serveur au lieu de charger toutes les données
- Corriger les erreurs "Input not found or already spent" dans l'API d'ancrage
- Maintenir la synchronisation entre la base de données et l'état réel de Bitcoin
- Améliorer l'expérience utilisateur avec un suivi de progression pour la collecte de signatures
**Root causes:**
- Pagination effectuée côté client : le serveur retournait tous les UTXOs/hashes (68k+ UTXOs, 32k+ hashes) puis le frontend paginait en JavaScript
- Désynchronisation entre la DB et Bitcoin : UTXOs dépensés non mis à jour dans la base de données
- Détection d'erreur incomplète : ne couvrait pas tous les cas ("already spent", "input not found")
- Pas de vérification de disponibilité de l'UTXO juste avant utilisation dans une transaction
**Correctifs:**
- Implémentation de la pagination côté serveur pour `/api/utxo/list` et `/api/hash/list` avec paramètres `page` et `limit`
- Amélioration de la détection d'erreur pour inclure "already spent" et "input not found"
- Ajout d'une vérification de disponibilité de l'UTXO avant utilisation avec mécanisme de retry (max 3 tentatives)
- Mise à jour automatique de tous les UTXOs dépensés dans la base de données lors de chaque synchronisation
- Script de synchronisation périodique avec cron job toutes les heures
- Optimisation mémoire : utilisation de tables temporaires SQL au lieu de charger tous les UTXOs en mémoire
**Evolutions:**
- Pagination serveur avec métadonnées (total, totalPages, page, limit) pour les endpoints `/api/utxo/list` et `/api/hash/list`
- Adaptation du frontend pour utiliser la pagination serveur (compatibilité maintenue avec chargement jusqu'à 1000 éléments)
- Ajout de `onProgress` callback dans `runCollectLoop` pour notifier la progression de la collecte de signatures
- Nouvelle fonction `collectProgress` pour calculer la progression (satisfied vs required) pour les notifications/UI
- Refactoring de `hasEnoughSignatures` avec extraction de `pairsPerMemberFromSigs` pour réutilisabilité
**Pages affectées:**
- `api-anchorage/src/bitcoin-rpc.js` : Vérification disponibilité UTXO, amélioration détection erreur, paramètre retryCount
- `api-anchorage/src/routes/anchor.js` : Passage des nouveaux paramètres à createAnchorTransaction
- `signet-dashboard/src/server.js` : Pagination pour `/api/hash/list` et `/api/utxo/list`
- `signet-dashboard/src/bitcoin-rpc.js` : Mise à jour automatique de tous les UTXOs dépensés avec optimisation mémoire
- `signet-dashboard/public/hash-list.html` : Adaptation pour charger avec pagination serveur
- `signet-dashboard/public/utxo-list.html` : Adaptation pour utiliser la pagination serveur par catégorie
- `userwallet/src/utils/collectSignatures.ts` : Ajout interface CollectLoopOpts avec onProgress callback
- `userwallet/src/utils/loginValidation.ts` : Ajout fonction collectProgress, refactoring avec pairsPerMemberFromSigs
- `data/sync-utxos-spent-status.mjs` : Script de synchronisation périodique des UTXOs dépensés
- `data/sync-utxos-cron.sh` : Script wrapper pour cron job
- `features/pagination-serveur-base-donnees.md` : Documentation de la pagination serveur
- `features/synchronisation-automatique-utxos-depenses.md` : Documentation de la synchronisation automatique
- `fixKnowledge/api-anchorage-utxo-already-spent-error.md` : Documentation de la correction de l'erreur UTXO déjà dépensé
159 lines
5.8 KiB
Markdown
159 lines
5.8 KiB
Markdown
# Correction : Erreur "Input not found or already spent" dans l'API d'ancrage
|
|
|
|
**Auteur** : Équipe 4NK
|
|
**Date** : 2026-01-27
|
|
**Version** : 1.0
|
|
|
|
## Problème Identifié
|
|
|
|
L'API d'ancrage retournait une erreur HTTP 500 avec le message "Input not found or already spent" lors de la création de transactions d'ancrage.
|
|
|
|
### Symptômes
|
|
|
|
- Erreur HTTP 500 lors des tests d'ancrage
|
|
- Message d'erreur : "Transaction signing failed: Input not found or already spent"
|
|
- L'UTXO sélectionné depuis la base de données n'est plus disponible dans Bitcoin
|
|
- La base de données n'est pas synchronisée avec l'état réel de Bitcoin
|
|
|
|
### Impact
|
|
|
|
- Les ancrages échouent avec une erreur 500
|
|
- Les UTXOs sélectionnés peuvent être déjà dépensés mais toujours marqués comme disponibles dans la DB
|
|
- Dégradation de la fiabilité de l'API d'ancrage
|
|
|
|
## Cause Racine
|
|
|
|
1. **Désynchronisation entre la DB et Bitcoin** : Un UTXO peut être dépensé entre le moment où il est sélectionné depuis la DB et le moment où il est utilisé dans une transaction.
|
|
|
|
2. **Détection d'erreur incomplète** : La détection d'erreur ne couvrait pas tous les cas ("already spent", "input not found").
|
|
|
|
3. **Pas de vérification de disponibilité** : Aucune vérification de disponibilité de l'UTXO juste avant de l'utiliser.
|
|
|
|
## Correctifs Appliqués
|
|
|
|
### 1. Amélioration de la détection d'erreur
|
|
|
|
**Fichier** : `api-anchorage/src/bitcoin-rpc.js`
|
|
|
|
**Modification** : Extension de la détection d'erreur pour inclure "already spent" et "input not found" :
|
|
|
|
```javascript
|
|
// Si l'erreur indique que l'UTXO n'existe plus ou est déjà dépensé, le marquer comme dépensé
|
|
const hasUtxoNotFoundError = errorDetails.some(e => {
|
|
const errorMsg = (e.error || '').toLowerCase();
|
|
return errorMsg.includes('not found') ||
|
|
errorMsg.includes('does not exist') ||
|
|
errorMsg.includes('missing') ||
|
|
errorMsg.includes('already spent') ||
|
|
errorMsg.includes('input not found');
|
|
});
|
|
```
|
|
|
|
### 2. Vérification de disponibilité avant utilisation
|
|
|
|
**Fichier** : `api-anchorage/src/bitcoin-rpc.js`
|
|
|
|
**Modification** : Ajout d'une vérification de disponibilité de l'UTXO juste avant de l'utiliser, avec mécanisme de retry :
|
|
|
|
```javascript
|
|
// Vérifier que l'UTXO est toujours disponible avant de l'utiliser
|
|
// (peut avoir été dépensé entre la sélection et l'utilisation)
|
|
// Limiter les tentatives pour éviter les boucles infinies
|
|
if (retryCount < 3) {
|
|
try {
|
|
const utxoCheck = await this.client.listunspent(0, 9999999, [selectedUtxo.address]);
|
|
const utxoStillAvailable = utxoCheck.some(u =>
|
|
u.txid === selectedUtxo.txid && u.vout === selectedUtxo.vout
|
|
);
|
|
|
|
if (!utxoStillAvailable) {
|
|
// L'UTXO n'est plus disponible, le marquer comme dépensé et réessayer
|
|
this.unlockUtxo(selectedUtxo.txid, selectedUtxo.vout);
|
|
// Marquer comme dépensé dans la DB
|
|
// Réessayer avec un autre UTXO
|
|
return this.createAnchorTransaction(hash, recipientAddress, provisioningAddresses, numberOfProvisioningUtxos, retryCount + 1);
|
|
}
|
|
} catch (checkError) {
|
|
// Continuer même si la vérification échoue
|
|
}
|
|
}
|
|
```
|
|
|
|
### 3. Ajout du paramètre retryCount
|
|
|
|
**Fichier** : `api-anchorage/src/bitcoin-rpc.js`
|
|
|
|
**Modification** : Ajout du paramètre `retryCount` à la fonction `createAnchorTransaction` pour limiter les tentatives :
|
|
|
|
```javascript
|
|
async createAnchorTransaction(hash, recipientAddress = null, provisioningAddresses = null, numberOfProvisioningUtxos = null, retryCount = 0) {
|
|
// ...
|
|
}
|
|
```
|
|
|
|
## Modifications
|
|
|
|
- `api-anchorage/src/bitcoin-rpc.js` :
|
|
- Ligne 207 : Ajout des paramètres `provisioningAddresses`, `numberOfProvisioningUtxos`, `retryCount` à `createAnchorTransaction`
|
|
- Ligne 404-431 : Ajout de la vérification de disponibilité de l'UTXO avant utilisation
|
|
- Ligne 455-477 : Amélioration de la détection d'erreur pour inclure "already spent" et "input not found"
|
|
|
|
## Modalités de Déploiement
|
|
|
|
### Redémarrage de l'API
|
|
|
|
1. **Redémarrer l'API** :
|
|
```bash
|
|
sudo systemctl restart anchorage-api.service
|
|
```
|
|
|
|
2. **Vérifier le statut** :
|
|
```bash
|
|
systemctl is-active anchorage-api.service
|
|
```
|
|
|
|
### Vérification
|
|
|
|
1. **Tester l'ancrage** :
|
|
```bash
|
|
curl -X POST https://anchorage.certificator.4nkweb.com/api/anchor/document \
|
|
-H 'Content-Type: application/json' \
|
|
-H 'x-api-key: <api-key>' \
|
|
--data-raw '{"hash":"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}'
|
|
```
|
|
|
|
2. **Vérifier les logs** :
|
|
```bash
|
|
journalctl -u anchorage-api.service --since "5 minutes ago" | grep -E "(UTXO|already spent|retrying)"
|
|
```
|
|
|
|
## Modalités d'Analyse
|
|
|
|
### Vérification que la correction fonctionne
|
|
|
|
1. **Vérifier la détection d'erreur** :
|
|
- Les logs doivent afficher "UTXO marked as spent due to signing error" si un UTXO est déjà dépensé
|
|
- Les erreurs "already spent" et "input not found" doivent être détectées
|
|
|
|
2. **Vérifier la vérification de disponibilité** :
|
|
- Les logs doivent afficher "Selected UTXO no longer available, marking as spent and retrying" si un UTXO n'est plus disponible
|
|
- Le mécanisme de retry doit fonctionner (maximum 3 tentatives)
|
|
|
|
3. **Vérifier les transactions d'ancrage** :
|
|
- Les ancrages doivent réussir même si le premier UTXO sélectionné est déjà dépensé
|
|
- Les UTXOs dépensés doivent être correctement marqués dans la DB
|
|
|
|
### Cas limites
|
|
|
|
1. **Tous les UTXOs sont déjà dépensés** :
|
|
- L'erreur doit indiquer "No available UTXOs in database (all are locked, spent, or unconfirmed)"
|
|
- Pas de boucle infinie
|
|
|
|
2. **Problème réseau lors de la vérification** :
|
|
- La vérification échoue silencieusement et l'opération continue
|
|
- L'erreur sera détectée lors de la signature de la transaction
|
|
|
|
3. **Maximum de tentatives atteint** :
|
|
- L'erreur doit indiquer "Failed to find available UTXO after multiple attempts"
|
|
- Pas de boucle infinie
|