**Motivations:** - Ajouter dates manquantes dans hash_list.txt et compléter historique - Compléter blockTime manquants dans utxo_list.txt et compléter historique - Récupérer frais depuis transactions d'ancrage (OP_RETURN) et les stocker - Bouton UI pour déclencher récupération frais - Diagnostic Bloc Rewards (pourquoi ~4700 BTC au lieu de 50 BTC) **Root causes:** - hash_list.txt sans date (format ancien) - utxo_list.txt blockTime souvent vide - Frais absents du fichier (métadonnées OP_RETURN non stockées) - Pas de moyen de récupérer/compléter frais depuis UI **Correctifs:** - hash_list.txt : format étendu avec date (rétrocompatible) - utxo_list.txt : blockTime complété automatiquement lors écritures - fees_list.txt : nouveau fichier pour stocker frais - updateFeesFromAnchors() : récupère frais depuis OP_RETURN ancrages - Endpoint /api/utxo/fees/update pour déclencher récupération - Bouton "Récupérer les frais depuis les ancrages" dans section Frais (spinner) - Scripts batch : complete-hash-list-dates.js, complete-utxo-list-blocktime.js - Script diagnostic : diagnose-bloc-rewards.js (subsidy, coinbase, listunspent) **Evolutions:** - Frais chargés depuis fees_list.txt dans getUtxoList - Complétion automatique dates/blockTime lors écritures futures **Pages affectées:** - signet-dashboard/src/bitcoin-rpc.js - signet-dashboard/src/server.js - signet-dashboard/public/utxo-list.html - scripts/complete-hash-list-dates.js - scripts/complete-utxo-list-blocktime.js - scripts/diagnose-bloc-rewards.js - features/utxo-list-fees-update-and-historical-completion.md
122 lines
3.5 KiB
TypeScript
122 lines
3.5 KiB
TypeScript
import { useState, useEffect } from 'react';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { getStoredRelays, storeRelays, testRelay } from '../utils/relay';
|
|
import type { RelayConfig } from '../types/identity';
|
|
|
|
export function RelaySettingsScreen(): JSX.Element {
|
|
const navigate = useNavigate();
|
|
const [relays, setRelays] = useState<RelayConfig[]>([]);
|
|
const [newEndpoint, setNewEndpoint] = useState('');
|
|
const [testing, setTesting] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
setRelays(getStoredRelays());
|
|
}, []);
|
|
|
|
const handleAdd = (): void => {
|
|
if (newEndpoint.trim() === '') {
|
|
return;
|
|
}
|
|
const newRelay: RelayConfig = {
|
|
endpoint: newEndpoint.trim(),
|
|
priority: relays.length,
|
|
enabled: true,
|
|
};
|
|
const updated = [...relays, newRelay];
|
|
setRelays(updated);
|
|
storeRelays(updated);
|
|
setNewEndpoint('');
|
|
};
|
|
|
|
const handleRemove = (index: number): void => {
|
|
const updated = relays.filter((_, i) => i !== index);
|
|
setRelays(updated);
|
|
storeRelays(updated);
|
|
};
|
|
|
|
const handleToggle = (index: number): void => {
|
|
const updated = [...relays];
|
|
updated[index] = { ...updated[index]!, enabled: !updated[index]!.enabled };
|
|
setRelays(updated);
|
|
storeRelays(updated);
|
|
};
|
|
|
|
const handleTest = async (endpoint: string): Promise<void> => {
|
|
setTesting(endpoint);
|
|
const isOk = await testRelay(endpoint);
|
|
setTesting(null);
|
|
if (isOk) {
|
|
alert('Relais accessible');
|
|
} else {
|
|
alert('Relais inaccessible');
|
|
}
|
|
};
|
|
|
|
return (
|
|
<main>
|
|
<h1>Réglages relais</h1>
|
|
<section aria-labelledby="relays-list">
|
|
<h2 id="relays-list">Liste des relais</h2>
|
|
{relays.length === 0 ? (
|
|
<p>Aucun relais configuré</p>
|
|
) : (
|
|
<ul role="list">
|
|
{relays.map((relay, index) => (
|
|
<li key={index}>
|
|
<div>
|
|
<input
|
|
type="checkbox"
|
|
checked={relay.enabled}
|
|
onChange={() => {
|
|
handleToggle(index);
|
|
}}
|
|
aria-label={`Activer ${relay.endpoint}`}
|
|
/>
|
|
<span>{relay.endpoint}</span>
|
|
<button
|
|
onClick={() => {
|
|
handleTest(relay.endpoint);
|
|
}}
|
|
disabled={testing === relay.endpoint}
|
|
>
|
|
{testing === relay.endpoint ? 'Test...' : 'Tester'}
|
|
</button>
|
|
<button
|
|
onClick={() => {
|
|
handleRemove(index);
|
|
}}
|
|
>
|
|
Supprimer
|
|
</button>
|
|
</div>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
)}
|
|
</section>
|
|
<section aria-labelledby="add-relay">
|
|
<h2 id="add-relay">Ajouter un relais</h2>
|
|
<div>
|
|
<input
|
|
type="text"
|
|
value={newEndpoint}
|
|
onChange={(e) => {
|
|
setNewEndpoint(e.target.value);
|
|
}}
|
|
placeholder="http://relay.example.com:3019"
|
|
onKeyDown={(e) => {
|
|
if (e.key === 'Enter') {
|
|
handleAdd();
|
|
}
|
|
}}
|
|
/>
|
|
<button onClick={handleAdd}>Ajouter</button>
|
|
</div>
|
|
</section>
|
|
<div>
|
|
<button onClick={() => navigate('/')}>Retour</button>
|
|
</div>
|
|
</main>
|
|
);
|
|
}
|