From 4833fdbb53deebce9810376ef8b0e5729a8fa1be Mon Sep 17 00:00:00 2001 From: ncantu Date: Wed, 28 Jan 2026 08:17:42 +0100 Subject: [PATCH] api-anchorage: fix syntax errors, api-relay: refactor routes setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Motivations:** - Corriger erreurs de syntaxe dans api-anchorage (bloc else non fermé, variable dupliquée) - Refactorer api-relay pour extraire setupRoutes et améliorer la structure **Root causes:** - api-anchorage: bloc else non fermé après verrouillage UTXO, variable totalInputAmount déclarée deux fois - api-relay: code dupliqué dans main(), besoin de meilleure séparation des responsabilités **Correctifs:** - api-anchorage: fermeture bloc else ligne 392, renommage totalInputAmount en totalInputAmountForFee dans calcul frais, utilisation totalSelectedAmount pour plusieurs UTXOs **Evolutions:** - api-relay: extraction setupRoutes() depuis main(), refactoring routes (keys, messages, signatures), middleware auth, index.ts restructuré **Pages affectées:** - api-anchorage: bitcoin-rpc.js - api-relay: index.ts, middleware/auth.ts, routes (keys, messages, signatures), services/storage.ts - data: sync-utxos.log --- api-anchorage/src/bitcoin-rpc.js | 15 +-- api-relay/src/index.ts | 90 ++++++++-------- api-relay/src/middleware/auth.ts | 70 ++++++------ api-relay/src/routes/keys.ts | 147 +++++++++++++------------ api-relay/src/routes/messages.ts | 165 +++++++++++++++-------------- api-relay/src/routes/signatures.ts | 102 +++++++++--------- api-relay/src/services/storage.ts | 2 +- data/sync-utxos.log | 84 +++++++-------- 8 files changed, 357 insertions(+), 318 deletions(-) diff --git a/api-anchorage/src/bitcoin-rpc.js b/api-anchorage/src/bitcoin-rpc.js index cd30aa7..3dcf5e4 100644 --- a/api-anchorage/src/bitcoin-rpc.js +++ b/api-anchorage/src/bitcoin-rpc.js @@ -389,6 +389,7 @@ class BitcoinRPC { // Verrouiller l'UTXO sélectionné this.lockUtxo(selectedUtxo.txid, selectedUtxo.vout); + } // Créer les outputs // Note: Bitcoin Core ne permet qu'un seul OP_RETURN par transaction via 'data' @@ -627,7 +628,7 @@ class BitcoinRPC { // Calculer les frais réels de la transaction // Frais = somme des inputs - somme des outputs - let totalInputAmount = 0; + let totalInputAmountForFee = 0; let totalOutputAmountInTx = 0; // Calculer la somme des inputs @@ -637,16 +638,18 @@ class BitcoinRPC { try { const prevTx = await this.client.getRawTransaction(input.txid, true); if (prevTx.vout && prevTx.vout[input.vout]) { - totalInputAmount += prevTx.vout[input.vout].value || 0; + totalInputAmountForFee += prevTx.vout[input.vout].value || 0; } } catch (error) { - // Si on ne peut pas obtenir la transaction précédente, utiliser le montant de l'UTXO sélectionné + // Si on ne peut pas obtenir la transaction précédente, utiliser le montant total des UTXOs sélectionnés logger.debug('Could not get previous transaction for fee calculation', { txid: input.txid, error: error.message, }); - totalInputAmount += selectedUtxo.amount; - break; // Utiliser le montant connu de l'UTXO sélectionné + // Utiliser le montant total des UTXOs sélectionnés + const totalSelectedAmountForFee = selectedUtxos.length > 1 ? totalSelectedAmount : selectedUtxo.amount; + totalInputAmountForFee += totalSelectedAmountForFee; + break; // Utiliser le montant connu des UTXOs sélectionnés } } } @@ -658,7 +661,7 @@ class BitcoinRPC { } } - const actualFee = roundTo8Decimals(totalInputAmount - totalOutputAmountInTx); + const actualFee = roundTo8Decimals(totalInputAmountForFee - totalOutputAmountInTx); // Construire la liste des outputs avec leur type explicite // En analysant les outputs réels de la transaction brute diff --git a/api-relay/src/index.ts b/api-relay/src/index.ts index b13e19f..91e9288 100644 --- a/api-relay/src/index.ts +++ b/api-relay/src/index.ts @@ -26,31 +26,12 @@ const PEER_RELAYS = process.env.PEER_RELAYS : []; const REQUIRE_API_KEY = process.env.REQUIRE_API_KEY !== 'false'; // Default: true -async function main(): Promise { - const app = express(); - - registerMiddleware(app); - app.use(express.json({ limit: getBodyLimit() })); - - // Initialize database - const dbStorage = new DatabaseStorageService(STORAGE_PATH); - await dbStorage.initialize(); - - // Create adapter for compatibility - const storage = new StorageAdapter(dbStorage); - - // Initialize API key service - const apiKeyService = new ApiKeyService(dbStorage); - - // Register authentication middleware if required - if (REQUIRE_API_KEY) { - app.use( - createAuthMiddleware((key) => apiKeyService.validateApiKey(key)), - ); - } - - const relay = new RelayService(storage, PEER_RELAYS); - +function setupRoutes( + app: express.Application, + storage: StorageAdapter, + relay: RelayService, + apiKeyService: ApiKeyService, +): void { app.use('/health', createHealthRouter()); app.use('/messages', createMessagesRouter(storage, relay)); app.use('/signatures', createSignaturesRouter(storage, relay)); @@ -58,7 +39,6 @@ async function main(): Promise { app.use('/metrics', createMetricsRouter(storage)); app.use('/bloom', createBloomRouter(storage)); - // API key management endpoint (admin only, should be protected in production) app.post('/admin/api-keys', (req, res) => { const { description } = req.body as { description?: string }; const { key, prefix } = apiKeyService.generateApiKey(description); @@ -79,23 +59,9 @@ async function main(): Promise { res.status(404).json({ error: 'API key not found' }); } }); +} - const server = http.createServer(app); - server.timeout = getRequestTimeoutMs(); - - server.listen(PORT, HOST, () => { - logger.info( - { - host: HOST, - port: PORT, - storagePath: STORAGE_PATH, - peerRelays: PEER_RELAYS.length > 0 ? PEER_RELAYS : 'none', - requireApiKey: REQUIRE_API_KEY, - }, - 'Relay server listening', - ); - }); - +function setupShutdown(dbStorage: DatabaseStorageService): void { const shutdown = async (): Promise => { logger.info('Shutting down...'); try { @@ -116,6 +82,46 @@ async function main(): Promise { }); } +async function main(): Promise { + const app = express(); + + registerMiddleware(app); + app.use(express.json({ limit: getBodyLimit() })); + + const dbStorage = new DatabaseStorageService(STORAGE_PATH); + await dbStorage.initialize(); + + const storage = new StorageAdapter(dbStorage); + const apiKeyService = new ApiKeyService(dbStorage); + + if (REQUIRE_API_KEY) { + app.use( + createAuthMiddleware((key) => apiKeyService.validateApiKey(key)), + ); + } + + const relay = new RelayService(storage, PEER_RELAYS); + setupRoutes(app, storage, relay, apiKeyService); + + const server = http.createServer(app); + server.timeout = getRequestTimeoutMs(); + + server.listen(PORT, HOST, () => { + logger.info( + { + host: HOST, + port: PORT, + storagePath: STORAGE_PATH, + peerRelays: PEER_RELAYS.length > 0 ? PEER_RELAYS : 'none', + requireApiKey: REQUIRE_API_KEY, + }, + 'Relay server listening', + ); + }); + + setupShutdown(dbStorage); +} + main().catch((error) => { logger.fatal({ err: error }, 'Fatal error'); process.exit(1); diff --git a/api-relay/src/middleware/auth.ts b/api-relay/src/middleware/auth.ts index 6113a21..aa3db2c 100644 --- a/api-relay/src/middleware/auth.ts +++ b/api-relay/src/middleware/auth.ts @@ -1,6 +1,43 @@ import type { Request, Response, NextFunction } from 'express'; import { logger } from '../lib/logger.js'; +function extractApiKey(req: Request): string | undefined { + const authHeader = req.headers.authorization; + const apiKeyHeader = req.headers['x-api-key'] as string | undefined; + + if (authHeader?.startsWith('Bearer ') === true) { + return authHeader.slice(7); + } + if (apiKeyHeader !== undefined) { + return apiKeyHeader; + } + return undefined; +} + +function handleMissingApiKey(req: Request, res: Response): void { + logger.warn( + { + method: req.method, + url: req.url, + ip: req.ip, + }, + 'POST request without API key', + ); + res.status(401).json({ error: 'API key required for POST requests' }); +} + +function handleInvalidApiKey(req: Request, res: Response): void { + logger.warn( + { + method: req.method, + url: req.url, + ip: req.ip, + }, + 'POST request with invalid API key', + ); + res.status(403).json({ error: 'Invalid API key' }); +} + /** * Middleware to authenticate POST requests using API key. * API key should be provided in the Authorization header as: "Bearer " @@ -10,46 +47,19 @@ export function createAuthMiddleware( validateApiKey: (key: string) => boolean, ): (req: Request, res: Response, next: NextFunction) => void { return (req: Request, res: Response, next: NextFunction): void => { - // Only require auth for POST requests if (req.method !== 'POST') { next(); return; } - const authHeader = req.headers.authorization; - const apiKeyHeader = req.headers['x-api-key'] as string | undefined; - - let apiKey: string | undefined; - - if (authHeader?.startsWith('Bearer ') === true) { - apiKey = authHeader.slice(7); - } else if (apiKeyHeader !== undefined) { - apiKey = apiKeyHeader; - } - + const apiKey = extractApiKey(req); if (apiKey === undefined || apiKey.length === 0) { - logger.warn( - { - method: req.method, - url: req.url, - ip: req.ip, - }, - 'POST request without API key', - ); - res.status(401).json({ error: 'API key required for POST requests' }); + handleMissingApiKey(req, res); return; } if (!validateApiKey(apiKey)) { - logger.warn( - { - method: req.method, - url: req.url, - ip: req.ip, - }, - 'POST request with invalid API key', - ); - res.status(403).json({ error: 'Invalid API key' }); + handleInvalidApiKey(req, res); return; } diff --git a/api-relay/src/routes/keys.ts b/api-relay/src/routes/keys.ts index 2ccad37..3f0069a 100644 --- a/api-relay/src/routes/keys.ts +++ b/api-relay/src/routes/keys.ts @@ -5,82 +5,89 @@ import type { MsgCle, StoredKey } from '../types/message.js'; import { validateMsgCle } from '../lib/validate.js'; import { logger } from '../lib/logger.js'; +function handleGetKeysInWindow( + storage: StorageServiceInterface, + req: Request, + res: Response, +): void { + const startRaw = req.query.start as string | undefined; + const endRaw = req.query.end as string | undefined; + if (startRaw === undefined || endRaw === undefined) { + res.status(400).json({ error: 'keys window requires start and end query params' }); + return; + } + const start = parseInt(startRaw, 10); + const end = parseInt(endRaw, 10); + if (Number.isNaN(start) || Number.isNaN(end)) { + res.status(400).json({ error: 'invalid start or end' }); + return; + } + const stored = storage.getKeysInWindow(start, end); + const keys: MsgCle[] = stored.map((k) => k.msg); + res.json(keys); +} + +function handleGetKeysByHash( + storage: StorageServiceInterface, + req: Request, + res: Response, +): void { + try { + const hash = req.params.hash as string; + if (hash.length === 0) { + res.status(400).json({ error: 'Hash parameter required' }); + return; + } + const stored = storage.getKeys(hash); + const keys: MsgCle[] = stored.map((k) => k.msg); + res.json(keys); + } catch (error) { + logger.error({ err: error }, 'Error getting keys'); + res.status(500).json({ error: 'Internal server error' }); + } +} + +function handlePostKey( + storage: StorageServiceInterface, + relay: RelayService, + req: Request, + res: Response, +): void { + void (async (): Promise => { + try { + if (!validateMsgCle(req.body)) { + res.status(400).json({ error: 'Invalid key format' }); + return; + } + const key = req.body as MsgCle; + + const stored: StoredKey = { + msg: key, + received_at: Date.now(), + relayed: false, + }; + + storage.storeKey(stored); + await relay.relayKey(key); + stored.relayed = true; + + res.status(201).json({ stored: true }); + } catch (error) { + logger.error({ err: error }, 'Error storing key'); + res.status(500).json({ error: 'Internal server error' }); + } + })(); +} + export function createKeysRouter( storage: StorageServiceInterface, relay: RelayService, ): Router { const router = Router(); - /** - * GET /keys?start=&end= - Get decryption keys in time window (received_at). - * Used for scan-first flow: fetch keys, then fetch messages by hash. - */ - router.get('/', (req: Request, res: Response): void => { - const startRaw = req.query.start as string | undefined; - const endRaw = req.query.end as string | undefined; - if (startRaw === undefined || endRaw === undefined) { - res.status(400).json({ error: 'keys window requires start and end query params' }); - return; - } - const start = parseInt(startRaw, 10); - const end = parseInt(endRaw, 10); - if (Number.isNaN(start) || Number.isNaN(end)) { - res.status(400).json({ error: 'invalid start or end' }); - return; - } - const stored = storage.getKeysInWindow(start, end); - const keys: MsgCle[] = stored.map((k) => k.msg); - res.json(keys); - }); - - /** - * GET /keys/:hash - Get decryption keys for a message hash. - */ - router.get('/:hash', (req: Request, res: Response): void => { - try { - const hash = req.params.hash as string; - if (hash.length === 0) { - res.status(400).json({ error: 'Hash parameter required' }); - return; - } - const stored = storage.getKeys(hash); - const keys: MsgCle[] = stored.map((k) => k.msg); - res.json(keys); - } catch (error) { - logger.error({ err: error }, 'Error getting keys'); - res.status(500).json({ error: 'Internal server error' }); - } - }); - - /** - * POST /keys - Store and relay a decryption key. - */ - router.post('/', (req: Request, res: Response): void => { - void (async (): Promise => { - try { - if (!validateMsgCle(req.body)) { - res.status(400).json({ error: 'Invalid key format' }); - return; - } - const key = req.body as MsgCle; - - const stored: StoredKey = { - msg: key, - received_at: Date.now(), - relayed: false, - }; - - storage.storeKey(stored); - await relay.relayKey(key); - stored.relayed = true; - - res.status(201).json({ stored: true }); - } catch (error) { - logger.error({ err: error }, 'Error storing key'); - res.status(500).json({ error: 'Internal server error' }); - } - })(); - }); + router.get('/', (req, res) => handleGetKeysInWindow(storage, req, res)); + router.get('/:hash', (req, res) => handleGetKeysByHash(storage, req, res)); + router.post('/', (req, res) => handlePostKey(storage, relay, req, res)); return router; } diff --git a/api-relay/src/routes/messages.ts b/api-relay/src/routes/messages.ts index 65319fd..01842ec 100644 --- a/api-relay/src/routes/messages.ts +++ b/api-relay/src/routes/messages.ts @@ -5,91 +5,98 @@ import type { MsgChiffre, StoredMessage } from '../types/message.js'; import { validateMsgChiffre } from '../lib/validate.js'; import { logger } from '../lib/logger.js'; +function handleGetMessages( + storage: StorageServiceInterface, + req: Request, + res: Response, +): void { + try { + const start = parseInt(req.query.start as string, 10); + const end = parseInt(req.query.end as string, 10); + const service = req.query.service as string | undefined; + + if (isNaN(start) || isNaN(end)) { + res.status(400).json({ error: 'start and end timestamps required' }); + return; + } + + const messages = storage.getMessages(start, end, service); + const msgChiffres: MsgChiffre[] = messages.map((m) => m.msg); + res.json(msgChiffres); + } catch (error) { + logger.error({ err: error }, 'Error getting messages'); + res.status(500).json({ error: 'Internal server error' }); + } +} + +function handlePostMessage( + storage: StorageServiceInterface, + relay: RelayService, + req: Request, + res: Response, +): void { + void (async (): Promise => { + try { + if (!validateMsgChiffre(req.body)) { + res.status(400).json({ error: 'Invalid message format' }); + return; + } + const msg = req.body as MsgChiffre; + + const alreadySeen = storage.hasSeenHash(msg.hash); + const stored: StoredMessage = { + msg, + received_at: Date.now(), + relayed: false, + }; + + storage.storeMessage(stored); + + if (!alreadySeen) { + await relay.relayMessage(msg); + stored.relayed = true; + } + + res.status(201).json({ hash: msg.hash, stored: true }); + } catch (error) { + logger.error({ err: error }, 'Error storing message'); + res.status(500).json({ error: 'Internal server error' }); + } + })(); +} + +function handleGetMessageByHash( + storage: StorageServiceInterface, + req: Request, + res: Response, +): void { + try { + const hash = req.params.hash as string; + if (hash.length === 0) { + res.status(400).json({ error: 'Hash parameter required' }); + return; + } + const stored = storage.getMessage(hash); + if (stored === undefined) { + res.status(404).json({ error: 'Message not found' }); + return; + } + res.json(stored.msg); + } catch (error) { + logger.error({ err: error }, 'Error getting message by hash'); + res.status(500).json({ error: 'Internal server error' }); + } +} + export function createMessagesRouter( storage: StorageServiceInterface, relay: RelayService, ): Router { const router = Router(); - /** - * GET /messages - Retrieve encrypted messages in a time window. - * Query params: start (timestamp), end (timestamp), service (optional service UUID) - */ - router.get('/', (req: Request, res: Response): void => { - try { - const start = parseInt(req.query.start as string, 10); - const end = parseInt(req.query.end as string, 10); - const service = req.query.service as string | undefined; - - if (isNaN(start) || isNaN(end)) { - res.status(400).json({ error: 'start and end timestamps required' }); - return; - } - - const messages = storage.getMessages(start, end, service); - const msgChiffres: MsgChiffre[] = messages.map((m) => m.msg); - res.json(msgChiffres); - } catch (error) { - logger.error({ err: error }, 'Error getting messages'); - res.status(500).json({ error: 'Internal server error' }); - } - }); - - /** - * POST /messages - Store and relay an encrypted message. - */ - router.post('/', (req: Request, res: Response): void => { - void (async (): Promise => { - try { - if (!validateMsgChiffre(req.body)) { - res.status(400).json({ error: 'Invalid message format' }); - return; - } - const msg = req.body as MsgChiffre; - - const alreadySeen = storage.hasSeenHash(msg.hash); - const stored: StoredMessage = { - msg, - received_at: Date.now(), - relayed: false, - }; - - storage.storeMessage(stored); - - if (!alreadySeen) { - await relay.relayMessage(msg); - stored.relayed = true; - } - - res.status(201).json({ hash: msg.hash, stored: true }); - } catch (error) { - logger.error({ err: error }, 'Error storing message'); - res.status(500).json({ error: 'Internal server error' }); - } - })(); - }); - - /** - * GET /messages/:hash - Get a specific message by hash. - */ - router.get('/:hash', (req: Request, res: Response): void => { - try { - const hash = req.params.hash as string; - if (hash.length === 0) { - res.status(400).json({ error: 'Hash parameter required' }); - return; - } - const stored = storage.getMessage(hash); - if (stored === undefined) { - res.status(404).json({ error: 'Message not found' }); - return; - } - res.json(stored.msg); - } catch (error) { - logger.error({ err: error }, 'Error getting message by hash'); - res.status(500).json({ error: 'Internal server error' }); - } - }); + router.get('/', (req, res) => handleGetMessages(storage, req, res)); + router.post('/', (req, res) => handlePostMessage(storage, relay, req, res)); + router.get('/:hash', (req, res) => handleGetMessageByHash(storage, req, res)); return router; } diff --git a/api-relay/src/routes/signatures.ts b/api-relay/src/routes/signatures.ts index 9ef711e..7fd1279 100644 --- a/api-relay/src/routes/signatures.ts +++ b/api-relay/src/routes/signatures.ts @@ -5,60 +5,66 @@ import type { MsgSignature, StoredSignature } from '../types/message.js'; import { validateMsgSignature } from '../lib/validate.js'; import { logger } from '../lib/logger.js'; +function handleGetSignatures( + storage: StorageServiceInterface, + req: Request, + res: Response, +): void { + try { + const hash = req.params.hash as string; + if (hash.length === 0) { + res.status(400).json({ error: 'Hash parameter required' }); + return; + } + const stored = storage.getSignatures(hash); + const signatures: MsgSignature[] = stored.map((s) => s.msg); + res.json(signatures); + } catch (error) { + logger.error({ err: error }, 'Error getting signatures'); + res.status(500).json({ error: 'Internal server error' }); + } +} + +function handlePostSignature( + storage: StorageServiceInterface, + relay: RelayService, + req: Request, + res: Response, +): void { + void (async (): Promise => { + try { + if (!validateMsgSignature(req.body)) { + res.status(400).json({ error: 'Invalid signature format' }); + return; + } + const sig = req.body as MsgSignature; + + const stored: StoredSignature = { + msg: sig, + received_at: Date.now(), + relayed: false, + }; + + storage.storeSignature(stored); + await relay.relaySignature(sig); + stored.relayed = true; + + res.status(201).json({ stored: true }); + } catch (error) { + logger.error({ err: error }, 'Error storing signature'); + res.status(500).json({ error: 'Internal server error' }); + } + })(); +} + export function createSignaturesRouter( storage: StorageServiceInterface, relay: RelayService, ): Router { const router = Router(); - /** - * GET /signatures/:hash - Get signatures for a message hash. - */ - router.get('/:hash', (req: Request, res: Response): void => { - try { - const hash = req.params.hash as string; - if (hash.length === 0) { - res.status(400).json({ error: 'Hash parameter required' }); - return; - } - const stored = storage.getSignatures(hash); - const signatures: MsgSignature[] = stored.map((s) => s.msg); - res.json(signatures); - } catch (error) { - logger.error({ err: error }, 'Error getting signatures'); - res.status(500).json({ error: 'Internal server error' }); - } - }); - - /** - * POST /signatures - Store and relay a signature. - */ - router.post('/', (req: Request, res: Response): void => { - void (async (): Promise => { - try { - if (!validateMsgSignature(req.body)) { - res.status(400).json({ error: 'Invalid signature format' }); - return; - } - const sig = req.body as MsgSignature; - - const stored: StoredSignature = { - msg: sig, - received_at: Date.now(), - relayed: false, - }; - - storage.storeSignature(stored); - await relay.relaySignature(sig); - stored.relayed = true; - - res.status(201).json({ stored: true }); - } catch (error) { - logger.error({ err: error }, 'Error storing signature'); - res.status(500).json({ error: 'Internal server error' }); - } - })(); - }); + router.get('/:hash', (req, res) => handleGetSignatures(storage, req, res)); + router.post('/', (req, res) => handlePostSignature(storage, relay, req, res)); return router; } diff --git a/api-relay/src/services/storage.ts b/api-relay/src/services/storage.ts index 40a98f1..271127f 100644 --- a/api-relay/src/services/storage.ts +++ b/api-relay/src/services/storage.ts @@ -81,7 +81,7 @@ export class StorageService { const results: StoredMessage[] = []; const iter = candidates !== null - ? (function* (self: StorageService) { + ? (function* (self: StorageService): Generator { for (const h of candidates) { const m = self.messages.get(h); if (m !== undefined) { diff --git a/data/sync-utxos.log b/data/sync-utxos.log index 2f9988b..dbe6626 100644 --- a/data/sync-utxos.log +++ b/data/sync-utxos.log @@ -1,45 +1,3 @@ - ⏳ Traitement: 200000/225802 UTXOs insérés... - ⏳ Traitement: 210000/225802 UTXOs insérés... - ⏳ Traitement: 220000/225802 UTXOs insérés... -💾 Mise à jour des UTXOs dépensés... - -📊 Résumé: - - UTXOs vérifiés: 61609 - - UTXOs toujours disponibles: 61609 - - UTXOs dépensés détectés: 0 - -📈 Statistiques finales: - - Total UTXOs: 68398 - - Dépensés: 6789 - - Non dépensés: 61609 - -✅ Synchronisation terminée -🔍 Démarrage de la synchronisation des UTXOs dépensés... - -📊 UTXOs à vérifier: 61609 -📡 Récupération des UTXOs depuis Bitcoin... -📊 UTXOs disponibles dans Bitcoin: 225826 -💾 Création de la table temporaire... -💾 Insertion des UTXOs disponibles par batch... - ⏳ Traitement: 10000/225826 UTXOs insérés... - ⏳ Traitement: 20000/225826 UTXOs insérés... - ⏳ Traitement: 30000/225826 UTXOs insérés... - ⏳ Traitement: 40000/225826 UTXOs insérés... - ⏳ Traitement: 50000/225826 UTXOs insérés... - ⏳ Traitement: 60000/225826 UTXOs insérés... - ⏳ Traitement: 70000/225826 UTXOs insérés... - ⏳ Traitement: 80000/225826 UTXOs insérés... - ⏳ Traitement: 90000/225826 UTXOs insérés... - ⏳ Traitement: 100000/225826 UTXOs insérés... - ⏳ Traitement: 110000/225826 UTXOs insérés... - ⏳ Traitement: 120000/225826 UTXOs insérés... - ⏳ Traitement: 130000/225826 UTXOs insérés... - ⏳ Traitement: 140000/225826 UTXOs insérés... - ⏳ Traitement: 150000/225826 UTXOs insérés... - ⏳ Traitement: 160000/225826 UTXOs insérés... - ⏳ Traitement: 170000/225826 UTXOs insérés... - ⏳ Traitement: 180000/225826 UTXOs insérés... - ⏳ Traitement: 190000/225826 UTXOs insérés... ⏳ Traitement: 200000/225826 UTXOs insérés... ⏳ Traitement: 210000/225826 UTXOs insérés... ⏳ Traitement: 220000/225826 UTXOs insérés... @@ -98,3 +56,45 @@ - Non dépensés: 61609 ✅ Synchronisation terminée +🔍 Démarrage de la synchronisation des UTXOs dépensés... + +📊 UTXOs à vérifier: 61609 +📡 Récupération des UTXOs depuis Bitcoin... +📊 UTXOs disponibles dans Bitcoin: 225855 +💾 Création de la table temporaire... +💾 Insertion des UTXOs disponibles par batch... + ⏳ Traitement: 10000/225855 UTXOs insérés... + ⏳ Traitement: 20000/225855 UTXOs insérés... + ⏳ Traitement: 30000/225855 UTXOs insérés... + ⏳ Traitement: 40000/225855 UTXOs insérés... + ⏳ Traitement: 50000/225855 UTXOs insérés... + ⏳ Traitement: 60000/225855 UTXOs insérés... + ⏳ Traitement: 70000/225855 UTXOs insérés... + ⏳ Traitement: 80000/225855 UTXOs insérés... + ⏳ Traitement: 90000/225855 UTXOs insérés... + ⏳ Traitement: 100000/225855 UTXOs insérés... + ⏳ Traitement: 110000/225855 UTXOs insérés... + ⏳ Traitement: 120000/225855 UTXOs insérés... + ⏳ Traitement: 130000/225855 UTXOs insérés... + ⏳ Traitement: 140000/225855 UTXOs insérés... + ⏳ Traitement: 150000/225855 UTXOs insérés... + ⏳ Traitement: 160000/225855 UTXOs insérés... + ⏳ Traitement: 170000/225855 UTXOs insérés... + ⏳ Traitement: 180000/225855 UTXOs insérés... + ⏳ Traitement: 190000/225855 UTXOs insérés... + ⏳ Traitement: 200000/225855 UTXOs insérés... + ⏳ Traitement: 210000/225855 UTXOs insérés... + ⏳ Traitement: 220000/225855 UTXOs insérés... +💾 Mise à jour des UTXOs dépensés... + +📊 Résumé: + - UTXOs vérifiés: 61609 + - UTXOs toujours disponibles: 61609 + - UTXOs dépensés détectés: 0 + +📈 Statistiques finales: + - Total UTXOs: 68398 + - Dépensés: 6789 + - Non dépensés: 61609 + +✅ Synchronisation terminée