363 lines
16 KiB
Plaintext
363 lines
16 KiB
Plaintext
================================================================================
|
||
OC-DISCOVERY : ARCHITECTURE CIBLE — RÉSEAU DHT SANS NATIFS
|
||
Vision d'évolution long terme, issue d'une analyse comparative
|
||
================================================================================
|
||
|
||
Rédigé à partir de l'analyse de l'architecture actuelle et de la discussion
|
||
comparative avec Tapestry, Kademlia, EigenTrust et les systèmes de réputation
|
||
distribués.
|
||
|
||
Référence : DECENTRALIZED_SYSTEMS_COMPARISON.txt §9
|
||
|
||
|
||
================================================================================
|
||
1. MOTIVATION
|
||
================================================================================
|
||
|
||
L'architecture actuelle (node → indexer → native indexer) est robuste et bien
|
||
adaptée à une phase précoce du réseau. Ses limites à l'échelle sont :
|
||
|
||
- Pool de natives statique au démarrage → dépendance à la configuration
|
||
- Cache local des natives = point de défaillance unique (perte = pool vide)
|
||
- Consensus inter-natives bloquant (~7s) déclenché à chaque bootstrap node
|
||
- État O(N indexers) par native → croît linéairement avec le réseau
|
||
- Nœuds privilégiés structurellement → SPOFs relatifs
|
||
|
||
La cible décrite ici supprime la notion de native indexer en tant que tier
|
||
architectural. Le réseau devient plat : indexers et nodes sont des acteurs
|
||
de même nature, différenciés uniquement par leur rôle volontaire.
|
||
|
||
|
||
================================================================================
|
||
2. PRINCIPES FONDAMENTAUX
|
||
================================================================================
|
||
|
||
P1. Aucun nœud n'est structurellement privilégié.
|
||
P2. La confiance est un produit du temps et de la vérification, pas d'un arbitre.
|
||
P3. Les claims d'un acteur sont vérifiables indépendamment par tout pair.
|
||
P4. La réputation émerge du comportement collectif, pas d'un signalement central.
|
||
P5. La DHT est une infrastructure neutre — elle stocke des faits, pas des jugements.
|
||
P6. La configuration statique n'existe plus au runtime — seulement au bootstrap.
|
||
|
||
|
||
================================================================================
|
||
3. RÔLES
|
||
================================================================================
|
||
|
||
3.1 Node
|
||
--------
|
||
Consommateur du réseau. Démarre, sélectionne un pool d'indexers via DHT,
|
||
heartbeat ses indexers, accumule des scores localement. Ne publie rien en
|
||
routine. Participe aux challenges de consensus à la demande.
|
||
|
||
3.2 Indexer
|
||
-----------
|
||
Acteur volontaire. S'inscrit dans la DHT à la naissance, maintient son record,
|
||
sert le trafic des nodes (heartbeat, Publish, Get). Déclare ses métriques dans
|
||
chaque réponse heartbeat. Maintient un score agrégé depuis ses nodes connectés.
|
||
|
||
Différence avec l'actuel : l'indexer n'a plus de lien avec une native.
|
||
Il est autonome. Son existence dans le réseau est prouvée par son record DHT
|
||
et par les nodes qui le contactent directement.
|
||
|
||
3.3 Nœud DHT infrastructure (ex-native)
|
||
----------------------------------------
|
||
N'importe quel nœud suffisamment stable peut maintenir la DHT sans être un
|
||
indexer. C'est une configuration, pas un type architectural : `dht_mode: server`.
|
||
Ces nœuds maintiennent les k-buckets Kademlia et stockent les records des
|
||
indexers. Ils ne connaissent pas le trafic node↔indexer et ne l'orchestrent pas.
|
||
|
||
|
||
================================================================================
|
||
4. BOOTSTRAP D'UN NODE
|
||
================================================================================
|
||
|
||
4.1 Entrée dans le réseau
|
||
-------------------------
|
||
Le node démarre avec 1 à 3 adresses de nœuds DHT connus (bootstrap peers).
|
||
Ce sont les seules informations statiques nécessaires. Ces peers n'ont pas de
|
||
rôle sémantique — ils servent uniquement à entrer dans l'overlay DHT.
|
||
|
||
4.2 Découverte du pool d'indexers
|
||
----------------------------------
|
||
|
||
Node → DHT.FindProviders(hash("/opencloud/indexers"))
|
||
→ reçoit une liste de N candidats avec leurs records
|
||
|
||
Sélection du pool initial :
|
||
|
||
1. Filtre latence : ping < seuil → proximité réseau réelle
|
||
2. Filtre fill rate : préférer les indexers moins chargés
|
||
3. Tirage pondéré : probabilité ∝ (1 - fill_rate), courbe w(F) = F×(1-F)
|
||
indexer à 20% charge → très probable
|
||
indexer à 80% charge → peu probable
|
||
4. Filtre diversité : subnet /24 différent pour chaque entrée du pool
|
||
|
||
Aucun consensus nécessaire à cette étape. Le node démarre avec une tolérance
|
||
basse (voir §7) — il accepte des indexers imparfaits et les évalue au fil du temps.
|
||
|
||
|
||
================================================================================
|
||
5. REGISTRATION D'UN INDEXER DANS LA DHT
|
||
================================================================================
|
||
|
||
À la naissance, l'indexer publie son record DHT :
|
||
|
||
clé : hash("/opencloud/indexers") ← clé fixe, connue de tous
|
||
valeur: {
|
||
multiaddr : <adresse réseau>,
|
||
region : <subnet /24>,
|
||
capacity : <maxNodesConn>,
|
||
fill_rate : <float 0-1>, ← auto-déclaré, vérifiable
|
||
peer_count : <int>, ← auto-déclaré, vérifiable
|
||
peers : [hash(nodeID1), ...], ← liste hashée des nodes connectés
|
||
born_at : <timestamp>,
|
||
sig : <signature clé indexer>, ← non-forgeable (PSK context)
|
||
}
|
||
|
||
Le record est rafraîchi toutes les ~60s (avant expiration du TTL).
|
||
Si l'indexer tombe : TTL expire → disparaît de la DHT automatiquement.
|
||
|
||
La peer list est hashée pour la confidentialité mais reste vérifiable :
|
||
un challenger peut demander directement à un node s'il est connecté à cet indexer.
|
||
|
||
|
||
================================================================================
|
||
6. PROTOCOLE HEARTBEAT — QUESTION ET RÉPONSE
|
||
================================================================================
|
||
|
||
Le heartbeat devient bidirectionnel : le node pose des questions, l'indexer
|
||
répond avec ses déclarations courantes.
|
||
|
||
6.1 Structure
|
||
-------------
|
||
|
||
Node → Indexer :
|
||
{
|
||
ts : now,
|
||
challenge : <optionnel, voir §8>
|
||
}
|
||
|
||
Indexer → Node :
|
||
{
|
||
ts : now,
|
||
fill_rate : 0.42,
|
||
peer_count : 87,
|
||
cached_score : 0.74, ← score agrégé depuis tous ses nodes connectés
|
||
challenge_response : {...} ← si challenge présent dans la requête
|
||
}
|
||
|
||
Le heartbeat normal (sans challenge) est quasi-identique à l'actuel en poids.
|
||
Le cached_score indexer est mis à jour progressivement par les feedbacks reçus.
|
||
|
||
6.2 Le cached_score de l'indexer
|
||
---------------------------------
|
||
L'indexer agrège les scores que ses nodes connectés lui communiquent
|
||
(implicitement via le fait qu'ils restent connectés, ou explicitement lors
|
||
d'un consensus). Ce score lui donne une vision de sa propre qualité réseau.
|
||
|
||
Un node peut comparer son score local de l'indexer avec le cached_score déclaré.
|
||
Une forte divergence est un signal d'alerte.
|
||
|
||
Score local node : 0.40 ← cet indexer est médiocre pour moi
|
||
Cached score : 0.91 ← il se prétend excellent globalement
|
||
→ déclenche un challenge de vérification
|
||
|
||
|
||
================================================================================
|
||
7. MODÈLE DE CONFIANCE PROGRESSIVE
|
||
================================================================================
|
||
|
||
7.1 Cycle de vie d'un node
|
||
---------------------------
|
||
|
||
Naissance
|
||
→ tolérance basse : accepte presque n'importe quel indexer du DHT
|
||
→ switching cost faible : peu de contexte accumulé
|
||
→ minScore ≈ 20% (dynamicMinScore existant, conservé)
|
||
|
||
Quelques heures
|
||
→ uptime s'accumule sur chaque indexer connu
|
||
→ scores se stabilisent
|
||
→ seuil de remplacement qui monte progressivement
|
||
|
||
Long terme (jours)
|
||
→ pool stable, confiance élevée sur les indexers connus
|
||
→ switching coûteux mais déclenché sur déception franche
|
||
→ minScore ≈ 80% (maturité)
|
||
|
||
7.2 Modèle sous-jacent : beta distribution implicite
|
||
------------------------------------------------------
|
||
|
||
α = succès cumulés (heartbeats OK, probes OK, challenges réussis)
|
||
β = échecs cumulés (timeouts, probes échoués, challenges ratés)
|
||
|
||
confiance = α / (α + β)
|
||
|
||
Nouveau indexer : α=0, β=0 → prior neutre, tolérance basse
|
||
Après 10 jours : α élevé → confiance stable, seuil de switch élevé
|
||
Déception franche : β monte → confiance chute → switch déclenché
|
||
|
||
7.3 Ce que "décevoir" signifie
|
||
--------------------------------
|
||
|
||
Heartbeat rate → trop de timeouts → fiabilité en baisse
|
||
Bandwidth probe → chute sous déclaré → dégradation ou mensonge
|
||
Fill rate réel → supérieur au déclaré → indexer surchargé ou malhonnête
|
||
Challenge échoué → peer déclaré absent du réseau → claim invalide
|
||
Latence → dérive progressive → qualité réseau dégradée
|
||
Cached_score gonflé → divergence forte avec score local → suspicion
|
||
|
||
|
||
================================================================================
|
||
8. VÉRIFICATION DES CLAIMS — TROIS COUCHES
|
||
================================================================================
|
||
|
||
8.1 Couche 1 : passive (chaque heartbeat, 60s)
|
||
-----------------------------------------------
|
||
Mesures automatiques, zéro coût supplémentaire.
|
||
|
||
- RTT du heartbeat → latence directe
|
||
- fill_rate déclaré → tiny payload dans la réponse
|
||
- peer_count déclaré → tiny payload
|
||
- cached_score indexer → comparé au score local
|
||
|
||
8.2 Couche 2 : sampling actif (1 heartbeat sur N)
|
||
--------------------------------------------------
|
||
Vérifications périodiques, asynchrones, légères.
|
||
|
||
Tous les 5 HB (~5min) : spot-check 1 peer aléatoire (voir §8.4)
|
||
Tous les 10 HB (~10min): vérification diversité subnet (lookups DHT légers)
|
||
Tous les 15 HB (~15min): bandwidth probe (transfert réel, protocole dédié)
|
||
|
||
8.3 Couche 3 : consensus (événementiel)
|
||
-----------------------------------------
|
||
Déclenché sur : admission d'un nouvel indexer dans le pool, ou suspicion détectée.
|
||
|
||
Node sélectionne une claim vérifiable de l'indexer cible X
|
||
Node vérifie lui-même
|
||
Node demande à ses indexers de confiance : "vérifiez cette claim sur X"
|
||
Chaque indexer vérifie indépendamment
|
||
Convergence des résultats → X est honnête → admission
|
||
Divergence → X est suspect → rejet ou probation
|
||
|
||
Le consensus est léger : quelques contacts out-of-band, pas de round bloquant.
|
||
Il n'est pas continu — il est événementiel.
|
||
|
||
8.4 Vérification out-of-band (pas de DHT writes par les nodes)
|
||
----------------------------------------------------------------
|
||
Les nodes ne publient PAS de contact records continus dans la DHT.
|
||
Cela éviterait N×M records à rafraîchir (coût DHT élevé à l'échelle).
|
||
|
||
À la place, lors d'un challenge :
|
||
|
||
Challenger sélectionne 2-3 peers dans la peer list déclarée par X
|
||
→ contacte ces peers directement : "es-tu connecté à indexer X ?"
|
||
→ réponse directe (out-of-band, pas via DHT)
|
||
→ vérification sans écriture DHT
|
||
|
||
L'indexer ne peut pas faire répondre "oui" à des peers qui ne lui sont pas
|
||
connectés. La vérification est non-falsifiable et sans coût DHT.
|
||
|
||
8.5 Pourquoi X ne peut pas tricher
|
||
------------------------------------
|
||
X ne peut pas coordonner des réponses différentes vers des challengers
|
||
simultanés. Chaque challenger contacte indépendamment les mêmes peers.
|
||
Si X ment sur sa peer list :
|
||
|
||
- Challenger A contacte peer P → "non, pas connecté à X"
|
||
- Challenger B contacte peer P → "non, pas connecté à X"
|
||
- Consensus : X ment → score chute chez tous les challengers
|
||
- Effet réseau : progressivement, X perd ses connections
|
||
- Peer list DHT se vide → claims futures encore moins crédibles
|
||
|
||
|
||
================================================================================
|
||
9. EFFET RÉSEAU SANS SIGNALEMENT CENTRAL
|
||
================================================================================
|
||
|
||
Un node qui pénalise un indexer n'envoie aucun "rapport" à quiconque.
|
||
Ses actions locales produisent l'effet réseau par agrégation :
|
||
|
||
Node baisse le score de X → X reçoit moins de trafic de ce node
|
||
Node switche vers Y → X perd un client
|
||
Node refuse les challenges X → X ne peut plus participer aux consensus
|
||
|
||
Si 200 nodes font pareil :
|
||
|
||
X perd la majorité de ses connections
|
||
Sa peer list DHT se vide (peers contactés directement disent "non")
|
||
Son cached_score s'effondre (peu de nodes restent)
|
||
Les nouveaux nodes qui voient X dans la DHT obtiennent des challenges échoués
|
||
X est naturellement exclu sans aucune décision centrale
|
||
|
||
Inversement, un indexer honnête voit ses scores monter sur tous ses nodes
|
||
connectés, sa peer list se densifier, ses challenges réussis systématiquement.
|
||
Sa réputation est un produit observable et vérifiable.
|
||
|
||
|
||
================================================================================
|
||
10. RÉSUMÉ DE L'ARCHITECTURE
|
||
================================================================================
|
||
|
||
DHT → annuaire neutre, vérité des records indexers
|
||
maintenu par tout nœud stable (dht_mode: server)
|
||
|
||
Indexer → acteur volontaire, s'inscrit, maintient ses claims,
|
||
sert le trafic, accumule son propre score agrégé
|
||
|
||
Node → consommateur, score passif + sampling + consensus léger,
|
||
confiance progressive, switching adaptatif
|
||
|
||
Heartbeat → métronome 60s + vecteur de déclarations légères + challenge optionnel
|
||
|
||
Consensus → événementiel, multi-challengers indépendants,
|
||
vérification out-of-band sur claims DHT
|
||
|
||
Confiance → beta implicite, progressive, switching cost croissant avec l'âge
|
||
|
||
Réputation → émerge du comportement collectif, aucun arbitre central
|
||
|
||
Bootstrap → 1-3 peers DHT connus → seule configuration statique nécessaire
|
||
|
||
|
||
================================================================================
|
||
11. TRAJECTOIRE DE MIGRATION
|
||
================================================================================
|
||
|
||
Phase 1 (actuel)
|
||
Natives statiques, pool indexers dynamique, consensus inter-natives
|
||
→ robuste, adapté à la phase précoce
|
||
|
||
Phase 2 (intermédiaire)
|
||
Pool de natives dynamique via DHT (bootstrap + gossip)
|
||
Même protocole natif, juste la découverte devient dynamique
|
||
→ supprime la dépendance à la configuration statique des natives
|
||
→ voir DECENTRALIZED_SYSTEMS_COMPARISON.txt §9.2
|
||
|
||
Phase 3 (cible)
|
||
Architecture décrite dans ce document
|
||
Natives disparaissent en tant que tier architectural
|
||
DHT = infrastructure, indexers = acteurs autonomes
|
||
Scoring et consensus entièrement côté node
|
||
→ aucun nœud privilégié, scalabilité O(log N)
|
||
|
||
La migration Phase 2 → Phase 3 est une refonte du plan de contrôle.
|
||
Le plan de données (heartbeat node↔indexer, Publish, Get) est inchangé.
|
||
Les primitives libp2p (Kademlia DHT, GossipSub) sont déjà présentes.
|
||
|
||
|
||
================================================================================
|
||
12. PROPRIÉTÉS DU SYSTÈME CIBLE
|
||
================================================================================
|
||
|
||
Scalabilité O(log N) — routage DHT Kademlia
|
||
Résilience Pas de SPOF structurel, TTL = seule source de vérité
|
||
Confiance Progressive, vérifiable, émergente
|
||
Sybil resistance PSK — seuls les nœuds avec la clé peuvent publier
|
||
Cold start Tolérance basse initiale, montée progressive (existant)
|
||
Honnêteté Claims vérifiables out-of-band, non-falsifiables
|
||
Décentralisation Aucun nœud ne connaît l'état global complet
|
||
|
||
================================================================================
|