**Motivations:** - Resolve insufficient UTXO amount errors when wallet has many small UTXOs - Prevent race conditions when multiple anchor requests arrive simultaneously - Improve signet dashboard functionality and documentation **Root causes:** - API tried to find a single UTXO large enough instead of combining multiple UTXOs - No mutex mechanism to prevent concurrent transactions from using the same UTXOs - UTXOs in mempool still appear as available in listunspent before block confirmation **Correctifs:** - Implement coin selection algorithm to combine multiple UTXOs when needed - Add mutex-based locking mechanism to serialize UTXO access - Filter locked UTXOs during selection to prevent double spending - Properly handle change output when combining multiple UTXOs - Lock UTXOs during transaction creation and unlock after mempool broadcast **Evolutions:** - Enhance signet dashboard with improved Bitcoin RPC integration - Update mempool documentation - Add comprehensive fix documentation in fixKnowledge/ **Pages affectées:** - api-anchorage/src/bitcoin-rpc.js - signet-dashboard/src/bitcoin-rpc.js - signet-dashboard/src/server.js - signet-dashboard/public/app.js - signet-dashboard/public/index.html - signet-dashboard/public/styles.css - signet-dashboard/start.sh - docs/MEMPOOL.md - fixKnowledge/api-anchorage-insufficient-utxo.md (new) - fixKnowledge/api-anchorage-utxo-race-condition.md (new) - anchor_count.txt (new) - mempool (submodule update)
213 lines
7.0 KiB
Markdown
213 lines
7.0 KiB
Markdown
# Correction : Erreur "Insufficient UTXO amount" sur l'API d'ancrage
|
|
|
|
**Auteur** : Équipe 4NK
|
|
**Date** : 2026-01-24
|
|
**Version** : 1.0
|
|
|
|
## Problème Identifié
|
|
|
|
L'API d'ancrage retournait une erreur "Insufficient UTXO amount. Required: 0.00006 BTC, Largest available: 0.00001 BTC" même lorsque le wallet avait suffisamment de fonds totaux.
|
|
|
|
### Symptômes
|
|
|
|
- Erreur : "Insufficient UTXO amount. Required: 0.00006 BTC, Largest available: 0.00001 BTC"
|
|
- Le wallet contient de nombreux UTXOs de 0.00001 BTC chacun
|
|
- Le solde total du wallet est suffisant, mais aucun UTXO individuel n'est assez grand
|
|
- L'API ne peut pas créer de transaction d'ancrage
|
|
|
|
## Cause Racine
|
|
|
|
L'API essayait de trouver un seul UTXO avec suffisamment de fonds pour couvrir le montant requis (0.00006 BTC = montant de sortie + frais estimés). Cependant, tous les UTXOs disponibles étaient de 0.00001 BTC chacun, ce qui est insuffisant individuellement.
|
|
|
|
**Problème technique** : L'algorithme de sélection d'UTXO ne combinait pas plusieurs UTXOs pour atteindre le montant requis. Il cherchait uniquement un UTXO unique assez grand.
|
|
|
|
## Correctifs Appliqués
|
|
|
|
### Modification de la sélection d'UTXOs dans `bitcoin-rpc.js`
|
|
|
|
**Fichier** : `api-anchorage/src/bitcoin-rpc.js`
|
|
|
|
**Avant** :
|
|
```javascript
|
|
// Sélectionner un UTXO avec suffisamment de fonds
|
|
const sortedUnspent = [...unspent].sort((a, b) => b.amount - a.amount);
|
|
const amount = 0.00001;
|
|
const estimatedFee = 0.00005;
|
|
const totalNeeded = amount + estimatedFee;
|
|
|
|
// Trouver un UTXO avec suffisamment de fonds
|
|
let utxo = sortedUnspent.find(u => u.amount >= totalNeeded);
|
|
if (!utxo) {
|
|
utxo = sortedUnspent[0];
|
|
if (utxo.amount < totalNeeded) {
|
|
throw new Error(`Insufficient UTXO amount...`);
|
|
}
|
|
}
|
|
|
|
const inputs = [{
|
|
txid: utxo.txid,
|
|
vout: utxo.vout,
|
|
}];
|
|
```
|
|
|
|
**Après** :
|
|
```javascript
|
|
// Sélectionner plusieurs UTXOs si nécessaire (coin selection)
|
|
const sortedUnspent = [...unspent].sort((a, b) => b.amount - a.amount);
|
|
const amount = 0.00001;
|
|
const estimatedFeePerInput = 0.000001;
|
|
const estimatedFeeBase = 0.00001;
|
|
|
|
// Sélectionner les UTXOs nécessaires pour couvrir le montant + frais
|
|
const selectedUtxos = [];
|
|
let totalSelected = 0;
|
|
let estimatedInputs = 1;
|
|
let totalNeeded = amount + estimatedFeeBase;
|
|
|
|
// Itérer jusqu'à trouver une combinaison qui fonctionne
|
|
for (let iteration = 0; iteration < 10; iteration++) {
|
|
totalNeeded = amount + estimatedFeeBase + (estimatedInputs * estimatedFeePerInput);
|
|
selectedUtxos.length = 0;
|
|
totalSelected = 0;
|
|
|
|
for (const utxo of sortedUnspent) {
|
|
if (totalSelected >= totalNeeded) break;
|
|
selectedUtxos.push(utxo);
|
|
totalSelected += utxo.amount;
|
|
}
|
|
|
|
if (totalSelected >= totalNeeded) break;
|
|
estimatedInputs = selectedUtxos.length + 1;
|
|
}
|
|
|
|
const inputs = selectedUtxos.map(utxo => ({
|
|
txid: utxo.txid,
|
|
vout: utxo.vout,
|
|
}));
|
|
```
|
|
|
|
**Impact** : L'API peut maintenant combiner plusieurs UTXOs pour créer une transaction, même si aucun UTXO individuel n'est assez grand.
|
|
|
|
### Gestion du change (monnaie restante)
|
|
|
|
**Ajout** : Calcul et gestion du change lorsque plusieurs UTXOs sont utilisés :
|
|
|
|
```javascript
|
|
// Calculer le change (monnaie restante après avoir payé le montant)
|
|
const estimatedFee = estimatedFeeBase + (selectedUtxos.length * estimatedFeePerInput);
|
|
const change = totalSelected - amount - estimatedFee;
|
|
|
|
const outputs = {
|
|
data: anchorData.toString('hex'), // OP_RETURN output
|
|
[address]: amount, // Montant minimal pour la transaction
|
|
};
|
|
|
|
// Si le change est significatif (> 0.000001 BTC), l'envoyer à une adresse de change
|
|
if (change > 0.000001) {
|
|
const changeAddress = await this.getNewAddress();
|
|
outputs[changeAddress] = change;
|
|
}
|
|
```
|
|
|
|
**Impact** : Le change est correctement géré et renvoyé au wallet au lieu d'être perdu.
|
|
|
|
## Modifications
|
|
|
|
### Fichiers Modifiés
|
|
|
|
- `api-anchorage/src/bitcoin-rpc.js` : Implémentation de la sélection multiple d'UTXOs (coin selection) et gestion du change
|
|
|
|
### Fichiers Créés
|
|
|
|
- `fixKnowledge/api-anchorage-insufficient-utxo.md` : Cette documentation
|
|
|
|
## Modalités de Déploiement
|
|
|
|
### Redémarrage de l'API
|
|
|
|
1. **Arrêter l'API** :
|
|
```bash
|
|
ps aux | grep "node.*api-anchorage" | grep -v grep | awk '{print $2}' | xargs kill
|
|
```
|
|
|
|
2. **Redémarrer l'API** :
|
|
```bash
|
|
cd /home/ncantu/Bureau/code/bitcoin/api-anchorage
|
|
npm start
|
|
```
|
|
|
|
### Vérification
|
|
|
|
1. **Tester l'ancrage** :
|
|
```bash
|
|
curl -X POST http://localhost:3010/api/anchor/document \
|
|
-H 'Content-Type: application/json' \
|
|
-H 'x-api-key: 770b9b33-8a15-4a6d-8f95-1cd2b36e7376' \
|
|
--data-raw '{"hash":"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}'
|
|
```
|
|
|
|
2. **Vérifier les logs** :
|
|
```bash
|
|
tail -f /tmp/anchorage-api.log | grep -E "(Selected UTXOs|change)"
|
|
```
|
|
|
|
## Modalités d'Analyse
|
|
|
|
### Vérification que la correction fonctionne
|
|
|
|
1. **Vérifier que la transaction est créée** :
|
|
- La réponse doit contenir un `txid` valide
|
|
- Pas d'erreur "Insufficient UTXO amount"
|
|
|
|
2. **Vérifier les logs** :
|
|
- Les logs doivent afficher "Selected UTXOs for transaction" avec le nombre d'UTXOs sélectionnés
|
|
- Les logs doivent afficher le montant total sélectionné et le change calculé
|
|
|
|
3. **Vérifier la transaction sur la blockchain** :
|
|
```bash
|
|
bitcoin-cli getrawtransaction <txid> true
|
|
```
|
|
- La transaction doit avoir plusieurs inputs (un par UTXO sélectionné)
|
|
- La transaction doit avoir un output de change si le change est significatif
|
|
|
|
### Cas limites
|
|
|
|
1. **Pas assez de fonds totaux** :
|
|
- L'erreur doit indiquer le montant total disponible
|
|
- L'erreur doit indiquer le nombre d'UTXOs disponibles
|
|
|
|
2. **Beaucoup de petits UTXOs** :
|
|
- L'API doit combiner plusieurs UTXOs jusqu'à avoir suffisamment de fonds
|
|
- Les frais doivent être correctement estimés en fonction du nombre d'inputs
|
|
|
|
3. **Change très petit** :
|
|
- Si le change est < 0.000001 BTC, il sera inclus dans les frais (dust)
|
|
- Si le change est >= 0.000001 BTC, il sera renvoyé au wallet
|
|
|
|
## Résultat
|
|
|
|
✅ **Problème résolu**
|
|
|
|
- L'API peut maintenant combiner plusieurs UTXOs pour créer une transaction
|
|
- Les transactions d'ancrage fonctionnent même avec de nombreux petits UTXOs
|
|
- Le change est correctement géré et renvoyé au wallet
|
|
- Les frais sont correctement estimés en fonction du nombre d'inputs
|
|
|
|
**Exemple de transaction réussie** :
|
|
- Transaction ID : `edacb5000f2f0520072f277e06406b1287f1d38531e7810d33939e5d9cbd598b`
|
|
- Plusieurs UTXOs de 0.00001 BTC combinés pour atteindre le montant requis
|
|
|
|
## Prévention
|
|
|
|
Pour éviter ce problème à l'avenir :
|
|
|
|
1. **Utiliser un algorithme de coin selection** : Toujours combiner plusieurs UTXOs si nécessaire
|
|
2. **Estimer correctement les frais** : Prendre en compte le nombre d'inputs dans l'estimation des frais
|
|
3. **Gérer le change** : Toujours renvoyer le change au wallet au lieu de le perdre
|
|
4. **Tester avec différents scénarios** : Tester avec des wallets contenant de nombreux petits UTXOs
|
|
|
|
## Pages Affectées
|
|
|
|
- `api-anchorage/src/bitcoin-rpc.js` : Implémentation de la sélection multiple d'UTXOs et gestion du change
|
|
- `fixKnowledge/api-anchorage-insufficient-utxo.md` : Documentation (nouveau)
|