api-anchorage: fix syntax errors, api-relay: refactor routes setup
**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
This commit is contained in:
parent
3c212e56e9
commit
4833fdbb53
@ -389,6 +389,7 @@ class BitcoinRPC {
|
|||||||
|
|
||||||
// Verrouiller l'UTXO sélectionné
|
// Verrouiller l'UTXO sélectionné
|
||||||
this.lockUtxo(selectedUtxo.txid, selectedUtxo.vout);
|
this.lockUtxo(selectedUtxo.txid, selectedUtxo.vout);
|
||||||
|
}
|
||||||
|
|
||||||
// Créer les outputs
|
// Créer les outputs
|
||||||
// Note: Bitcoin Core ne permet qu'un seul OP_RETURN par transaction via 'data'
|
// 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
|
// Calculer les frais réels de la transaction
|
||||||
// Frais = somme des inputs - somme des outputs
|
// Frais = somme des inputs - somme des outputs
|
||||||
let totalInputAmount = 0;
|
let totalInputAmountForFee = 0;
|
||||||
let totalOutputAmountInTx = 0;
|
let totalOutputAmountInTx = 0;
|
||||||
|
|
||||||
// Calculer la somme des inputs
|
// Calculer la somme des inputs
|
||||||
@ -637,16 +638,18 @@ class BitcoinRPC {
|
|||||||
try {
|
try {
|
||||||
const prevTx = await this.client.getRawTransaction(input.txid, true);
|
const prevTx = await this.client.getRawTransaction(input.txid, true);
|
||||||
if (prevTx.vout && prevTx.vout[input.vout]) {
|
if (prevTx.vout && prevTx.vout[input.vout]) {
|
||||||
totalInputAmount += prevTx.vout[input.vout].value || 0;
|
totalInputAmountForFee += prevTx.vout[input.vout].value || 0;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} 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', {
|
logger.debug('Could not get previous transaction for fee calculation', {
|
||||||
txid: input.txid,
|
txid: input.txid,
|
||||||
error: error.message,
|
error: error.message,
|
||||||
});
|
});
|
||||||
totalInputAmount += selectedUtxo.amount;
|
// Utiliser le montant total des UTXOs sélectionnés
|
||||||
break; // Utiliser le montant connu de l'UTXO sélectionné
|
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
|
// Construire la liste des outputs avec leur type explicite
|
||||||
// En analysant les outputs réels de la transaction brute
|
// En analysant les outputs réels de la transaction brute
|
||||||
|
|||||||
@ -26,31 +26,12 @@ const PEER_RELAYS = process.env.PEER_RELAYS
|
|||||||
: [];
|
: [];
|
||||||
const REQUIRE_API_KEY = process.env.REQUIRE_API_KEY !== 'false'; // Default: true
|
const REQUIRE_API_KEY = process.env.REQUIRE_API_KEY !== 'false'; // Default: true
|
||||||
|
|
||||||
async function main(): Promise<void> {
|
function setupRoutes(
|
||||||
const app = express();
|
app: express.Application,
|
||||||
|
storage: StorageAdapter,
|
||||||
registerMiddleware(app);
|
relay: RelayService,
|
||||||
app.use(express.json({ limit: getBodyLimit() }));
|
apiKeyService: ApiKeyService,
|
||||||
|
): void {
|
||||||
// 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);
|
|
||||||
|
|
||||||
app.use('/health', createHealthRouter());
|
app.use('/health', createHealthRouter());
|
||||||
app.use('/messages', createMessagesRouter(storage, relay));
|
app.use('/messages', createMessagesRouter(storage, relay));
|
||||||
app.use('/signatures', createSignaturesRouter(storage, relay));
|
app.use('/signatures', createSignaturesRouter(storage, relay));
|
||||||
@ -58,7 +39,6 @@ async function main(): Promise<void> {
|
|||||||
app.use('/metrics', createMetricsRouter(storage));
|
app.use('/metrics', createMetricsRouter(storage));
|
||||||
app.use('/bloom', createBloomRouter(storage));
|
app.use('/bloom', createBloomRouter(storage));
|
||||||
|
|
||||||
// API key management endpoint (admin only, should be protected in production)
|
|
||||||
app.post('/admin/api-keys', (req, res) => {
|
app.post('/admin/api-keys', (req, res) => {
|
||||||
const { description } = req.body as { description?: string };
|
const { description } = req.body as { description?: string };
|
||||||
const { key, prefix } = apiKeyService.generateApiKey(description);
|
const { key, prefix } = apiKeyService.generateApiKey(description);
|
||||||
@ -79,23 +59,9 @@ async function main(): Promise<void> {
|
|||||||
res.status(404).json({ error: 'API key not found' });
|
res.status(404).json({ error: 'API key not found' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const server = http.createServer(app);
|
function setupShutdown(dbStorage: DatabaseStorageService): void {
|
||||||
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',
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const shutdown = async (): Promise<void> => {
|
const shutdown = async (): Promise<void> => {
|
||||||
logger.info('Shutting down...');
|
logger.info('Shutting down...');
|
||||||
try {
|
try {
|
||||||
@ -116,6 +82,46 @@ async function main(): Promise<void> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function main(): Promise<void> {
|
||||||
|
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) => {
|
main().catch((error) => {
|
||||||
logger.fatal({ err: error }, 'Fatal error');
|
logger.fatal({ err: error }, 'Fatal error');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
|||||||
@ -1,6 +1,43 @@
|
|||||||
import type { Request, Response, NextFunction } from 'express';
|
import type { Request, Response, NextFunction } from 'express';
|
||||||
import { logger } from '../lib/logger.js';
|
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.
|
* Middleware to authenticate POST requests using API key.
|
||||||
* API key should be provided in the Authorization header as: "Bearer <key>"
|
* API key should be provided in the Authorization header as: "Bearer <key>"
|
||||||
@ -10,46 +47,19 @@ export function createAuthMiddleware(
|
|||||||
validateApiKey: (key: string) => boolean,
|
validateApiKey: (key: string) => boolean,
|
||||||
): (req: Request, res: Response, next: NextFunction) => void {
|
): (req: Request, res: Response, next: NextFunction) => void {
|
||||||
return (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') {
|
if (req.method !== 'POST') {
|
||||||
next();
|
next();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const authHeader = req.headers.authorization;
|
const apiKey = extractApiKey(req);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (apiKey === undefined || apiKey.length === 0) {
|
if (apiKey === undefined || apiKey.length === 0) {
|
||||||
logger.warn(
|
handleMissingApiKey(req, res);
|
||||||
{
|
|
||||||
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' });
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!validateApiKey(apiKey)) {
|
if (!validateApiKey(apiKey)) {
|
||||||
logger.warn(
|
handleInvalidApiKey(req, res);
|
||||||
{
|
|
||||||
method: req.method,
|
|
||||||
url: req.url,
|
|
||||||
ip: req.ip,
|
|
||||||
},
|
|
||||||
'POST request with invalid API key',
|
|
||||||
);
|
|
||||||
res.status(403).json({ error: 'Invalid API key' });
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,17 +5,11 @@ import type { MsgCle, StoredKey } from '../types/message.js';
|
|||||||
import { validateMsgCle } from '../lib/validate.js';
|
import { validateMsgCle } from '../lib/validate.js';
|
||||||
import { logger } from '../lib/logger.js';
|
import { logger } from '../lib/logger.js';
|
||||||
|
|
||||||
export function createKeysRouter(
|
function handleGetKeysInWindow(
|
||||||
storage: StorageServiceInterface,
|
storage: StorageServiceInterface,
|
||||||
relay: RelayService,
|
req: Request,
|
||||||
): Router {
|
res: Response,
|
||||||
const router = Router();
|
): void {
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 startRaw = req.query.start as string | undefined;
|
||||||
const endRaw = req.query.end as string | undefined;
|
const endRaw = req.query.end as string | undefined;
|
||||||
if (startRaw === undefined || endRaw === undefined) {
|
if (startRaw === undefined || endRaw === undefined) {
|
||||||
@ -31,12 +25,13 @@ export function createKeysRouter(
|
|||||||
const stored = storage.getKeysInWindow(start, end);
|
const stored = storage.getKeysInWindow(start, end);
|
||||||
const keys: MsgCle[] = stored.map((k) => k.msg);
|
const keys: MsgCle[] = stored.map((k) => k.msg);
|
||||||
res.json(keys);
|
res.json(keys);
|
||||||
});
|
}
|
||||||
|
|
||||||
/**
|
function handleGetKeysByHash(
|
||||||
* GET /keys/:hash - Get decryption keys for a message hash.
|
storage: StorageServiceInterface,
|
||||||
*/
|
req: Request,
|
||||||
router.get('/:hash', (req: Request, res: Response): void => {
|
res: Response,
|
||||||
|
): void {
|
||||||
try {
|
try {
|
||||||
const hash = req.params.hash as string;
|
const hash = req.params.hash as string;
|
||||||
if (hash.length === 0) {
|
if (hash.length === 0) {
|
||||||
@ -50,12 +45,14 @@ export function createKeysRouter(
|
|||||||
logger.error({ err: error }, 'Error getting keys');
|
logger.error({ err: error }, 'Error getting keys');
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
/**
|
function handlePostKey(
|
||||||
* POST /keys - Store and relay a decryption key.
|
storage: StorageServiceInterface,
|
||||||
*/
|
relay: RelayService,
|
||||||
router.post('/', (req: Request, res: Response): void => {
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
): void {
|
||||||
void (async (): Promise<void> => {
|
void (async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
if (!validateMsgCle(req.body)) {
|
if (!validateMsgCle(req.body)) {
|
||||||
@ -80,7 +77,17 @@ export function createKeysRouter(
|
|||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
});
|
}
|
||||||
|
|
||||||
|
export function createKeysRouter(
|
||||||
|
storage: StorageServiceInterface,
|
||||||
|
relay: RelayService,
|
||||||
|
): Router {
|
||||||
|
const router = Router();
|
||||||
|
|
||||||
|
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;
|
return router;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,17 +5,11 @@ import type { MsgChiffre, StoredMessage } from '../types/message.js';
|
|||||||
import { validateMsgChiffre } from '../lib/validate.js';
|
import { validateMsgChiffre } from '../lib/validate.js';
|
||||||
import { logger } from '../lib/logger.js';
|
import { logger } from '../lib/logger.js';
|
||||||
|
|
||||||
export function createMessagesRouter(
|
function handleGetMessages(
|
||||||
storage: StorageServiceInterface,
|
storage: StorageServiceInterface,
|
||||||
relay: RelayService,
|
req: Request,
|
||||||
): Router {
|
res: Response,
|
||||||
const router = Router();
|
): void {
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 {
|
try {
|
||||||
const start = parseInt(req.query.start as string, 10);
|
const start = parseInt(req.query.start as string, 10);
|
||||||
const end = parseInt(req.query.end as string, 10);
|
const end = parseInt(req.query.end as string, 10);
|
||||||
@ -33,12 +27,14 @@ export function createMessagesRouter(
|
|||||||
logger.error({ err: error }, 'Error getting messages');
|
logger.error({ err: error }, 'Error getting messages');
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
/**
|
function handlePostMessage(
|
||||||
* POST /messages - Store and relay an encrypted message.
|
storage: StorageServiceInterface,
|
||||||
*/
|
relay: RelayService,
|
||||||
router.post('/', (req: Request, res: Response): void => {
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
): void {
|
||||||
void (async (): Promise<void> => {
|
void (async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
if (!validateMsgChiffre(req.body)) {
|
if (!validateMsgChiffre(req.body)) {
|
||||||
@ -67,12 +63,13 @@ export function createMessagesRouter(
|
|||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
});
|
}
|
||||||
|
|
||||||
/**
|
function handleGetMessageByHash(
|
||||||
* GET /messages/:hash - Get a specific message by hash.
|
storage: StorageServiceInterface,
|
||||||
*/
|
req: Request,
|
||||||
router.get('/:hash', (req: Request, res: Response): void => {
|
res: Response,
|
||||||
|
): void {
|
||||||
try {
|
try {
|
||||||
const hash = req.params.hash as string;
|
const hash = req.params.hash as string;
|
||||||
if (hash.length === 0) {
|
if (hash.length === 0) {
|
||||||
@ -89,7 +86,17 @@ export function createMessagesRouter(
|
|||||||
logger.error({ err: error }, 'Error getting message by hash');
|
logger.error({ err: error }, 'Error getting message by hash');
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
export function createMessagesRouter(
|
||||||
|
storage: StorageServiceInterface,
|
||||||
|
relay: RelayService,
|
||||||
|
): Router {
|
||||||
|
const router = Router();
|
||||||
|
|
||||||
|
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;
|
return router;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,16 +5,11 @@ import type { MsgSignature, StoredSignature } from '../types/message.js';
|
|||||||
import { validateMsgSignature } from '../lib/validate.js';
|
import { validateMsgSignature } from '../lib/validate.js';
|
||||||
import { logger } from '../lib/logger.js';
|
import { logger } from '../lib/logger.js';
|
||||||
|
|
||||||
export function createSignaturesRouter(
|
function handleGetSignatures(
|
||||||
storage: StorageServiceInterface,
|
storage: StorageServiceInterface,
|
||||||
relay: RelayService,
|
req: Request,
|
||||||
): Router {
|
res: Response,
|
||||||
const router = Router();
|
): void {
|
||||||
|
|
||||||
/**
|
|
||||||
* GET /signatures/:hash - Get signatures for a message hash.
|
|
||||||
*/
|
|
||||||
router.get('/:hash', (req: Request, res: Response): void => {
|
|
||||||
try {
|
try {
|
||||||
const hash = req.params.hash as string;
|
const hash = req.params.hash as string;
|
||||||
if (hash.length === 0) {
|
if (hash.length === 0) {
|
||||||
@ -28,12 +23,14 @@ export function createSignaturesRouter(
|
|||||||
logger.error({ err: error }, 'Error getting signatures');
|
logger.error({ err: error }, 'Error getting signatures');
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
/**
|
function handlePostSignature(
|
||||||
* POST /signatures - Store and relay a signature.
|
storage: StorageServiceInterface,
|
||||||
*/
|
relay: RelayService,
|
||||||
router.post('/', (req: Request, res: Response): void => {
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
): void {
|
||||||
void (async (): Promise<void> => {
|
void (async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
if (!validateMsgSignature(req.body)) {
|
if (!validateMsgSignature(req.body)) {
|
||||||
@ -58,7 +55,16 @@ export function createSignaturesRouter(
|
|||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
});
|
}
|
||||||
|
|
||||||
|
export function createSignaturesRouter(
|
||||||
|
storage: StorageServiceInterface,
|
||||||
|
relay: RelayService,
|
||||||
|
): Router {
|
||||||
|
const router = Router();
|
||||||
|
|
||||||
|
router.get('/:hash', (req, res) => handleGetSignatures(storage, req, res));
|
||||||
|
router.post('/', (req, res) => handlePostSignature(storage, relay, req, res));
|
||||||
|
|
||||||
return router;
|
return router;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -81,7 +81,7 @@ export class StorageService {
|
|||||||
const results: StoredMessage[] = [];
|
const results: StoredMessage[] = [];
|
||||||
const iter =
|
const iter =
|
||||||
candidates !== null
|
candidates !== null
|
||||||
? (function* (self: StorageService) {
|
? (function* (self: StorageService): Generator<StoredMessage, void, unknown> {
|
||||||
for (const h of candidates) {
|
for (const h of candidates) {
|
||||||
const m = self.messages.get(h);
|
const m = self.messages.get(h);
|
||||||
if (m !== undefined) {
|
if (m !== undefined) {
|
||||||
|
|||||||
@ -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: 200000/225826 UTXOs insérés...
|
||||||
⏳ Traitement: 210000/225826 UTXOs insérés...
|
⏳ Traitement: 210000/225826 UTXOs insérés...
|
||||||
⏳ Traitement: 220000/225826 UTXOs insérés...
|
⏳ Traitement: 220000/225826 UTXOs insérés...
|
||||||
@ -98,3 +56,45 @@
|
|||||||
- Non dépensés: 61609
|
- Non dépensés: 61609
|
||||||
|
|
||||||
✅ Synchronisation terminée
|
✅ 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
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user