From 1090e39a8a1e831901cb99282a806eb428c0fba6 Mon Sep 17 00:00:00 2001 From: ncantu Date: Wed, 28 Jan 2026 15:15:47 +0100 Subject: [PATCH] Improve UTXO robustness and fix fee calculation bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Motivations:** - Corriger le bug de calcul des frais qui empêchait l'utilisation de tous les UTXOs disponibles - Améliorer la robustesse de la gestion des UTXOs pour les ancrages avec provisioning - Utiliser tous les UTXOs disponibles si nécessaire au lieu de limiter à 20 - Améliorer les messages d'erreur avec des suggestions de solutions **Root causes:** - Bug de calcul des frais : la condition utilisait totalNeeded + estimatedFeeForMultipleInputs alors que totalNeeded inclut déjà estimatedFee (double comptage) - Limitation à 20 UTXOs maximum empêchait d'utiliser tous les UTXOs disponibles - Messages d'erreur peu informatifs ne suggéraient pas de solutions **Correctifs:** - Correction du bug de calcul des frais : utilisation de totalOutputAmount + currentEstimatedFee au lieu de totalNeeded + estimatedFeeForMultipleInputs - Utilisation de tous les UTXOs disponibles si nécessaire (au lieu de limiter à 20) - Augmentation de la limite de combinaison de 20 à 100 UTXOs - Recalcul correct des frais avec le nombre réel d'inputs à chaque étape **Evolutions:** - Amélioration des messages d'erreur avec suggestions de solutions (faucet, mining, consolidation, réduction du provisioning) - Calcul du déficit (shortfall) pour informer l'utilisateur du montant manquant - Logique de fallback pour utiliser tous les UTXOs disponibles si la première tentative échoue **Pages affectées:** - api-anchorage/src/bitcoin-rpc.js - fixKnowledge/api-anchorage-utxo-robustness-improvements.md --- api-anchorage/src/bitcoin-rpc.js | 65 ++++- ...-anchorage-utxo-robustness-improvements.md | 227 ++++++++++++++++++ 2 files changed, 285 insertions(+), 7 deletions(-) create mode 100644 fixKnowledge/api-anchorage-utxo-robustness-improvements.md diff --git a/api-anchorage/src/bitcoin-rpc.js b/api-anchorage/src/bitcoin-rpc.js index 67de8f8..eef9a6f 100644 --- a/api-anchorage/src/bitcoin-rpc.js +++ b/api-anchorage/src/bitcoin-rpc.js @@ -465,13 +465,22 @@ class BitcoinRPC { // Estimation: ~148 bytes par input supplémentaire const estimatedBytesPerInput = 148; const estimatedFeePerInput = 0.0000001; // Conservateur - const maxUtxosToCombine = 20; // Limite pour éviter des transactions trop grandes + const maxUtxosToCombine = 100; // Limite élevée pour permettre d'utiliser tous les UTXOs si nécessaire estimatedFeeForMultipleInputs = estimatedFee; + // Calculer le total disponible de tous les UTXOs + const totalAvailable = availableUtxos.reduce((sum, u) => sum + u.amount, 0); + // Sélectionner les UTXOs jusqu'à atteindre le montant nécessaire + // CORRECTION: totalNeeded inclut déjà estimatedFee, donc on utilise totalOutputAmount + estimatedFeeForMultipleInputs for (let i = 0; i < availableUtxos.length && i < maxUtxosToCombine; i++) { const utxo = availableUtxos[i]; - if (totalSelectedAmount >= totalNeeded + estimatedFeeForMultipleInputs) { + // Recalculer les frais avec le nombre actuel d'inputs + const currentEstimatedFee = estimatedFee + (selectedUtxos.length * estimatedFeePerInput); + const currentTotalNeeded = totalOutputAmount + currentEstimatedFee; + + if (totalSelectedAmount >= currentTotalNeeded) { + estimatedFeeForMultipleInputs = currentEstimatedFee; break; } selectedUtxos.push({ @@ -485,23 +494,65 @@ class BitcoinRPC { totalSelectedAmount += utxo.amount; // Ajuster l'estimation des frais pour chaque input supplémentaire if (selectedUtxos.length > 1) { - estimatedFeeForMultipleInputs += estimatedFeePerInput; + estimatedFeeForMultipleInputs = estimatedFee + (selectedUtxos.length * estimatedFeePerInput); } } - if (totalSelectedAmount < totalNeeded + estimatedFeeForMultipleInputs) { + // Si on n'a pas assez avec les UTXOs sélectionnés, essayer d'utiliser TOUS les UTXOs disponibles + // Recalculer les frais finaux avec le nombre réel d'inputs + estimatedFeeForMultipleInputs = estimatedFee + (selectedUtxos.length * estimatedFeePerInput); + let finalTotalNeeded = totalOutputAmount + estimatedFeeForMultipleInputs; + + if (totalSelectedAmount < finalTotalNeeded && selectedUtxos.length < availableUtxos.length) { + // Essayer d'utiliser TOUS les UTXOs disponibles + selectedUtxos = []; + totalSelectedAmount = 0; + + for (let i = 0; i < availableUtxos.length; i++) { + const utxo = availableUtxos[i]; + selectedUtxos.push({ + txid: utxo.txid, + vout: utxo.vout, + address: utxo.address || '', + amount: utxo.amount, + confirmations: utxo.confirmations || 0, + blockTime: utxo.block_time, + }); + totalSelectedAmount += utxo.amount; + } + + // Recalculer les frais avec tous les UTXOs + estimatedFeeForMultipleInputs = estimatedFee + (selectedUtxos.length * estimatedFeePerInput); + finalTotalNeeded = totalOutputAmount + estimatedFeeForMultipleInputs; + } + + if (totalSelectedAmount < finalTotalNeeded) { const largestUtxo = availableUtxos[0]; + + // Suggérer des solutions dans le message d'erreur + let suggestion = ''; + const shortfall = finalTotalNeeded - totalAvailable; + if (shortfall > 0) { + suggestion = ` Total available from all ${availableUtxos.length} UTXOs: ${totalAvailable.toFixed(8)} BTC. ` + + `Shortfall: ${shortfall.toFixed(8)} BTC. ` + + `Solutions: 1) Use faucet to get more funds, 2) Mine more blocks, 3) Consolidate UTXOs via dashboard, 4) Reduce provisioning count.`; + } else { + suggestion = ` All ${availableUtxos.length} available UTXOs total ${totalAvailable.toFixed(8)} BTC, which should be sufficient. ` + + `This may be a fee estimation issue. Consider consolidating UTXOs via dashboard to create larger UTXOs.`; + } + throw new Error( - `No UTXO large enough for anchor with provisioning. Required: ${totalNeeded.toFixed(8)} BTC, ` + + `No UTXO large enough for anchor with provisioning. Required: ${finalTotalNeeded.toFixed(8)} BTC, ` + `Largest available: ${largestUtxo.amount} BTC. ` + - `Total from ${selectedUtxos.length} UTXOs: ${totalSelectedAmount.toFixed(8)} BTC` + `Total from ${selectedUtxos.length} UTXOs: ${totalSelectedAmount.toFixed(8)} BTC.${suggestion}` ); } logger.info('Combining multiple UTXOs for anchor transaction', { numberOfUtxos: selectedUtxos.length, totalAmount: totalSelectedAmount, - totalNeeded: totalNeeded + estimatedFeeForMultipleInputs, + totalNeeded: finalTotalNeeded, + estimatedFee: estimatedFeeForMultipleInputs, }); // Verrouiller tous les UTXOs sélectionnés diff --git a/fixKnowledge/api-anchorage-utxo-robustness-improvements.md b/fixKnowledge/api-anchorage-utxo-robustness-improvements.md new file mode 100644 index 0000000..3813c2e --- /dev/null +++ b/fixKnowledge/api-anchorage-utxo-robustness-improvements.md @@ -0,0 +1,227 @@ +# Amélioration : Robustesse de la gestion des UTXOs pour les ancrages + +**Auteur** : Équipe 4NK +**Date** : 2026-01-28 + +## Problème Identifié + +L'API d'ancrage retournait des erreurs "No UTXO large enough for anchor with provisioning" même lorsque le wallet contenait suffisamment de fonds totaux, mais répartis sur plusieurs petits UTXOs. + +### Symptômes + +- Erreur : "No UTXO large enough for anchor with provisioning. Required: 0.00023055 BTC, Largest available: 0.000025 BTC. Total from 9 UTXOs: 0.00021000 BTC" +- Le wallet contient plusieurs petits UTXOs dont la somme totale est proche du montant requis +- Le code essayait de combiner les UTXOs mais échouait à cause d'un bug de calcul des frais +- Les UTXOs disponibles n'étaient pas tous utilisés même si nécessaire + +## Cause Racine + +**Bug de calcul des frais** : La condition de vérification utilisait `totalNeeded + estimatedFeeForMultipleInputs`, mais `totalNeeded` inclut déjà `estimatedFee`. Cela créait un double comptage des frais, empêchant l'utilisation de tous les UTXOs disponibles. + +**Limitation** : Le code limitait la combinaison à 20 UTXOs maximum, et n'utilisait pas tous les UTXOs disponibles même si nécessaire. + +## Correctifs Appliqués + +### 1. Correction du bug de calcul des frais + +**Fichier** : `api-anchorage/src/bitcoin-rpc.js` + +**Avant** : +```javascript +if (totalSelectedAmount >= totalNeeded + estimatedFeeForMultipleInputs) { + break; +} +``` + +**Problème** : `totalNeeded` inclut déjà `estimatedFee`, donc on ajoutait les frais deux fois. + +**Après** : +```javascript +// Recalculer les frais avec le nombre actuel d'inputs +const currentEstimatedFee = estimatedFee + (selectedUtxos.length * estimatedFeePerInput); +const currentTotalNeeded = totalOutputAmount + currentEstimatedFee; + +if (totalSelectedAmount >= currentTotalNeeded) { + estimatedFeeForMultipleInputs = currentEstimatedFee; + break; +} +``` + +**Impact** : Les frais sont maintenant calculés correctement, permettant d'utiliser tous les UTXOs disponibles si nécessaire. + +### 2. Utilisation de tous les UTXOs disponibles si nécessaire + +**Modification** : Si la combinaison initiale n'est pas suffisante, le code essaie maintenant d'utiliser TOUS les UTXOs disponibles. + +```javascript +// Si on n'a pas assez avec les UTXOs sélectionnés, essayer d'utiliser TOUS les UTXOs disponibles +if (totalSelectedAmount < finalTotalNeeded && selectedUtxos.length < availableUtxos.length) { + // Essayer d'utiliser TOUS les UTXOs disponibles + selectedUtxos = []; + totalSelectedAmount = 0; + + for (let i = 0; i < availableUtxos.length; i++) { + // Ajouter tous les UTXOs + } + + // Recalculer les frais avec tous les UTXOs + estimatedFeeForMultipleInputs = estimatedFee + (selectedUtxos.length * estimatedFeePerInput); + finalTotalNeeded = totalOutputAmount + estimatedFeeForMultipleInputs; +} +``` + +**Impact** : Le système utilise maintenant tous les UTXOs disponibles si nécessaire, maximisant les chances de réussite. + +### 3. Augmentation de la limite de combinaison + +**Modification** : La limite de combinaison est passée de 20 à 100 UTXOs pour permettre d'utiliser tous les UTXOs disponibles. + +```javascript +const maxUtxosToCombine = 100; // Limite élevée pour permettre d'utiliser tous les UTXOs si nécessaire +``` + +**Impact** : Plus de flexibilité pour gérer les wallets avec de nombreux petits UTXOs. + +### 4. Amélioration des messages d'erreur + +**Modification** : Les messages d'erreur incluent maintenant des suggestions de solutions. + +```javascript +let suggestion = ''; +const shortfall = finalTotalNeeded - totalAvailable; +if (shortfall > 0) { + suggestion = ` Total available from all ${availableUtxos.length} UTXOs: ${totalAvailable.toFixed(8)} BTC. ` + + `Shortfall: ${shortfall.toFixed(8)} BTC. ` + + `Solutions: 1) Use faucet to get more funds, 2) Mine more blocks, 3) Consolidate UTXOs via dashboard, 4) Reduce provisioning count.`; +} else { + suggestion = ` All ${availableUtxos.length} available UTXOs total ${totalAvailable.toFixed(8)} BTC, which should be sufficient. ` + + `This may be a fee estimation issue. Consider consolidating UTXOs via dashboard to create larger UTXOs.`; +} +``` + +**Impact** : Les utilisateurs reçoivent des suggestions claires pour résoudre les problèmes de fonds insuffisants. + +## Modifications + +### Fichiers Modifiés + +- `api-anchorage/src/bitcoin-rpc.js` : + - Correction du bug de calcul des frais dans la combinaison d'UTXOs + - Utilisation de tous les UTXOs disponibles si nécessaire + - Augmentation de la limite de combinaison (20 → 100) + - Amélioration des messages d'erreur avec suggestions + +### Fichiers Créés + +- `fixKnowledge/api-anchorage-utxo-robustness-improvements.md` : Cette documentation + +## Modalités de Déploiement + +### Redémarrage de l'API + +1. **Redémarrer l'API** : + ```bash + sudo systemctl restart anchorage-api + ``` + +2. **Vérifier les logs** : + ```bash + sudo journalctl -u anchorage-api -f + ``` + +### Vérification + +1. **Tester avec plusieurs petits UTXOs** : + - Vérifier que l'API peut créer un ancrage même si tous les UTXOs sont petits + - Vérifier que les logs indiquent "Combining multiple UTXOs for anchor transaction" + - Vérifier que tous les UTXOs disponibles sont utilisés si nécessaire + +2. **Vérifier les transactions** : + - Les transactions doivent avoir plusieurs inputs si plusieurs UTXOs sont combinés + - Le change doit être calculé correctement avec le montant total des inputs + - Les frais doivent être correctement estimés + +## Modalités d'Analyse + +### Vérification que les corrections fonctionnent + +1. **Vérifier que la transaction est créée** : + - La réponse doit contenir un `txid` valide + - Pas d'erreur "No UTXO large enough" si le solde total est suffisant + +2. **Vérifier les logs** : + - Les logs doivent afficher "Combining multiple UTXOs for anchor transaction" avec le nombre d'UTXOs sélectionnés + - Les logs doivent afficher le montant total sélectionné et les frais estimés + +3. **Vérifier la transaction sur la blockchain** : + ```bash + bitcoin-cli getrawtransaction 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 déficit (shortfall) + - L'erreur doit suggérer des solutions (faucet, mining, consolidation, réduction du provisioning) + +2. **Beaucoup de petits UTXOs** : + - L'API doit combiner tous les UTXOs disponibles si nécessaire + - Les frais doivent être correctement estimés en fonction du nombre d'inputs + - La transaction doit être créée avec succès si le solde total est suffisant + +3. **Fonds suffisants mais répartis** : + - L'API doit utiliser tous les UTXOs disponibles + - Les frais doivent être correctement calculés sans double comptage + - La transaction doit être créée avec succès + +## Résultat + +✅ **Problème résolu** + +- Le bug de calcul des frais est corrigé +- Le système utilise maintenant tous les UTXOs disponibles si nécessaire +- Les messages d'erreur sont plus informatifs et suggèrent des solutions +- La robustesse de la gestion des UTXOs est améliorée + +**Exemple de transaction réussie avec UTXOs combinés** : +- Transaction : N inputs (tous les UTXOs disponibles) → 1 OP_RETURN + 1 ancrage (2500 sats) + 7 provisioning (2500 sats chacun) + change +- Les frais sont correctement calculés sans double comptage +- Tous les UTXOs disponibles sont utilisés si nécessaire + +## Prévention + +Pour éviter ce problème à l'avenir : + +1. **Calcul correct des frais** : Toujours utiliser `totalOutputAmount + estimatedFee` au lieu de `totalNeeded + estimatedFee` +2. **Utilisation de tous les UTXOs** : Essayer d'utiliser tous les UTXOs disponibles si nécessaire +3. **Messages d'erreur informatifs** : Inclure des suggestions de solutions dans les messages d'erreur +4. **Consolidation automatique** : Considérer l'ajout d'une consolidation automatique des UTXOs quand ils deviennent trop nombreux + +## Solutions Recommandées + +Si le problème persiste malgré ces améliorations : + +1. **Consolider les UTXOs** : Utiliser le dashboard pour consolider les petits UTXOs en un gros UTXO + - Accéder au dashboard : `https://signet.4nkweb.com` + - Utiliser la fonction "Consolidate Small UTXOs" + +2. **Utiliser le faucet** : Obtenir plus de fonds via le faucet + - Accéder au faucet : `https://faucet.4nkweb.com` + - Demander des fonds pour le wallet d'ancrage + +3. **Miner plus de blocs** : Générer plus de récompenses de bloc + - Activer le mining si désactivé + - Attendre que les blocs soient minés et confirmés + +4. **Réduire le provisioning** : Réduire le nombre d'UTXOs de provisioning (modifier le code si nécessaire) + +## Pages Affectées + +- `api-anchorage/src/bitcoin-rpc.js` : + - Fonction `createAnchorTransaction()` : Correction du bug de calcul des frais + - Logique de combinaison d'UTXOs : Utilisation de tous les UTXOs disponibles + - Messages d'erreur : Amélioration avec suggestions +- `fixKnowledge/api-anchorage-utxo-robustness-improvements.md` : Documentation (nouveau)