**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
4.5 KiB
4.5 KiB
Stockage des données - UserWallet
Author: Équipe 4NK Date: 2026-01-26
Synthèse
- Relais (api-relay) : Stockage hybride (mémoire +
./data/messages.json). Messages,seenHashes, signatures et clés persistés. Sauvegarde à l’arrêt (SIGINT/SIGTERM) et périodique (configurable viaSAVE_INTERVAL_SECONDS). - Front (userwallet) : LocalStorage (
userwallet_identity,userwallet_relays,userwallet_pairs,userwallet_hash_cache; legacy :userwallet_keypair,userwallet_services). Graphe contractuel en mémoire uniquement (GraphResolver).
Stockage sur le relais (api-relay)
Architecture
Le relais utilise un stockage hybride : mémoire + persistance sur disque.
Structure de stockage
En mémoire :
messages: Map<string, StoredMessage>- Messages chiffrés indexés par hashsignatures: Map<string, StoredSignature[]>- Signatures indexées par hash de messagekeys: Map<string, StoredKey[]>- Clés de déchiffrement indexées par hash de messageseenHashes: Set<string>- Hash vus pour déduplication
Sur disque :
- Fichier
{STORAGE_PATH}/messages.jsoncontenant :messages: Array de[hash, StoredMessage]seenHashes: Array de hash (string[])signatures: Array de[hash, StoredSignature[]]keys: Array de[hash, StoredKey[]]
Persistance
- Chargement : Au démarrage, charge
messages.jsonsi présent (ENOENT = premier run, démarrage à vide). - Sauvegarde : À l’arrêt (SIGINT/SIGTERM) et périodiquement si
SAVE_INTERVAL_SECONDS> 0 (défaut 300 s).
Format de données
StoredMessage :
{
msg: {
hash: string,
message_chiffre: string,
datajson_public: {
services_uuid: string[],
types_uuid: string[],
timestamp?: number,
...
}
},
received_at: number,
relayed: boolean
}
StoredSignature :
{
msg: {
signature: {
hash: string,
cle_publique: string,
signature: string,
nonce: string,
materiel?: object
},
hash_cible?: string
},
received_at: number,
relayed: boolean
}
StoredKey :
{
msg: {
hash_message: string,
cle_de_chiffrement_message: {
algo: string,
params: object,
cle_chiffree?: string
},
df_ecdh_scannable: string
},
received_at: number,
relayed: boolean
}
Configuration
STORAGE_PATH: Chemin du répertoire de stockage (défaut:./data)SAVE_INTERVAL_SECONDS: Intervalle de sauvegarde périodique en secondes (défaut: 300). Mettre à 0 pour désactiver.
Limitations actuelles
- Pas de base de données (SQLite/PostgreSQL recommandé en production)
- Pas de compression des données
Stockage sur le front (userwallet)
Architecture
Le front utilise LocalStorage du navigateur pour toutes les données locales.
Structure de stockage
Clés utilisées :
-
userwallet_identity: Identité locale{ uuid: string, privateKey: string, publicKey: string, name?: string, t0_anniversaire: number, version: string } -
userwallet_relays: Configuration des relaisArray<{ endpoint: string, priority: number, enabled: boolean, last_sync?: number }> -
userwallet_pairs: Configuration des pairsArray<{ uuid: string, membres_parents_uuid: string[], is_local: boolean, can_sign: boolean }> -
userwallet_hash_cache: Cache des hash vusstring[] // Array de hash -
userwallet_keypair: (Legacy) Paire de clés -
userwallet_services: (Legacy) Services configurés
Données en mémoire (non persistées)
- Graphe contractuel : Résolu dynamiquement depuis les messages synchronisés
- Services, Contrats, Champs, Actions, Membres, Pairs
- Stocké dans
GraphResolver.cache(Map) - Perdu au rechargement de page
Limitations
- Taille limitée : LocalStorage a une limite (~5-10MB selon navigateur)
- Pas de synchronisation : Données locales uniquement
- Sécurité : Clés privées stockées en clair (à chiffrer avec mot de passe)
- Pas de backup : Pas de mécanisme d'export/import automatique
Recommandations
- Chiffrer les clés privées avec un mot de passe utilisateur
- Implémenter un mécanisme d'export/import
- Utiliser IndexedDB pour des données plus volumineuses
- Implémenter une synchronisation cloud optionnelle (chiffrée)