#!/usr/bin/env node /** * Script pour synchroniser les UTXOs depuis Bitcoin RPC vers la base de données * * Ce script appelle le dashboard pour forcer une synchronisation complète des UTXOs * depuis Bitcoin RPC vers la base de données. * * Usage: node api-anchorage/sync-utxos-from-bitcoin.mjs */ import { bitcoinRPC } from './src/bitcoin-rpc.js'; async function syncUtxosFromBitcoin() { console.log('🔍 Démarrage de la synchronisation des UTXOs depuis Bitcoin...\n'); try { // Appeler le dashboard pour forcer une synchronisation const dashboardUrl = process.env.DASHBOARD_API_URL || 'http://localhost:3020'; console.log('📡 Appel du dashboard pour synchroniser les UTXOs...'); const response = await fetch(`${dashboardUrl}/api/utxo/fees`, { method: 'GET', headers: { 'Content-Type': 'application/json', }, }); if (!response.ok) { throw new Error(`Dashboard API error: ${response.status} ${response.statusText}`); } // Le dashboard synchronise automatiquement les UTXOs lors de l'appel à getUtxoList() // Appeler directement Bitcoin RPC pour synchroniser console.log('📡 Récupération des UTXOs depuis Bitcoin RPC...'); const unspent = await bitcoinRPC.callRPCCommandWithRetry('listunspent', 1, 9999999); console.log(`📊 UTXOs disponibles dans Bitcoin: ${unspent.length}`); if (unspent.length === 0) { console.log('⚠️ Aucun UTXO disponible dans Bitcoin'); return; } // Synchroniser avec la base de données const { getDatabase } = await import('./src/database.js'); const db = getDatabase(); // Créer une table temporaire pour les UTXOs disponibles db.exec(` CREATE TEMP TABLE IF NOT EXISTS temp_available_utxos ( txid TEXT, vout INTEGER, PRIMARY KEY (txid, vout) ) `); // Insérer les UTXOs disponibles par batch const insertStmt = db.prepare(` INSERT OR IGNORE INTO temp_available_utxos (txid, vout) VALUES (?, ?) `); const insertBatch = db.transaction((utxos) => { for (const utxo of utxos) { insertStmt.run(utxo.txid, utxo.vout); } }); const BATCH_SIZE = 1000; console.log('💾 Insertion des UTXOs disponibles dans la table temporaire...'); for (let i = 0; i < unspent.length; i += BATCH_SIZE) { const batch = unspent.slice(i, i + BATCH_SIZE); insertBatch(batch); if ((i + BATCH_SIZE) % 10000 === 0) { console.log(` ⏳ Traitement: ${Math.min(i + BATCH_SIZE, unspent.length)}/${unspent.length} UTXOs...`); } } // Mettre à jour les UTXOs existants comme non dépensés s'ils sont disponibles console.log('💾 Mise à jour des UTXOs dans la base de données...'); const updateStmt = db.prepare(` UPDATE utxos SET is_spent_onchain = 0, updated_at = CURRENT_TIMESTAMP WHERE (txid || ':' || vout) IN ( SELECT txid || ':' || vout FROM temp_available_utxos ) `); const updateResult = updateStmt.run(); // Nettoyer la table temporaire db.exec('DROP TABLE IF EXISTS temp_available_utxos'); console.log(`\n📊 Résumé:`); console.log(` - UTXOs disponibles dans Bitcoin: ${unspent.length}`); console.log(` - UTXOs mis à jour dans la base de données: ${updateResult.changes}`); // Afficher les statistiques finales const finalStats = { total: db.prepare('SELECT COUNT(*) as count FROM utxos').get().count, spent: db.prepare('SELECT COUNT(*) as count FROM utxos WHERE is_spent_onchain = 1').get().count, notSpent: db.prepare('SELECT COUNT(*) as count FROM utxos WHERE is_spent_onchain = 0').get().count, }; console.log(`\n📈 Statistiques finales:`); console.log(` - Total UTXOs: ${finalStats.total}`); console.log(` - Dépensés: ${finalStats.spent}`); console.log(` - Non dépensés: ${finalStats.notSpent}`); db.close(); } catch (error) { console.error('❌ Erreur lors de la synchronisation:', error.message); console.error(error.stack); process.exit(1); } } // Exécuter la synchronisation syncUtxosFromBitcoin() .then(() => { console.log('\n✅ Synchronisation terminée'); process.exit(0); }) .catch((error) => { console.error('❌ Erreur fatale:', error); process.exit(1); });