sequenceDiagram title Native — ConnectToNatives + Consensus (Pair A bootstrap) participant NodeA as Node A participant Native1 as Native #1 (primary) participant Native2 as Native #2 participant NativeN as Native #N participant DHT as DHT Kademlia Note over NodeA: NativeIndexerAddresses configuré
Appelé pendant InitNode → ConnectToIndexers NodeA->>NodeA: Parse NativeIndexerAddresses → StaticNatives NodeA->>Native1: SendHeartbeat /opencloud/heartbeat/1.0 (20s tick) NodeA->>Native2: SendHeartbeat /opencloud/heartbeat/1.0 (20s tick) %% Étape 1 : récupérer un pool initial NodeA->>Native1: Connect + NewStream /opencloud/native/indexers/1.0 NodeA->>Native1: json.Encode(GetIndexersRequest{Count: maxIndexer}) Native1->>Native1: reachableLiveIndexers() Note over Native1: Filtre liveIndexers par TTL
ping chaque candidat (PeerIsAlive) alt Aucun indexer connu par Native1 Native1->>Native1: selfDelegate(NodeA.PeerID, resp) Note over Native1: IsSelfFallback=true
Indexers=[native1 addr] Native1->>NodeA: GetIndexersResponse{IsSelfFallback:true, Indexers:[native1]} NodeA->>NodeA: StaticIndexers[native1] = native1 Note over NodeA: Pas de consensus — native1 utilisé directement comme indexeur else Indexers disponibles Native1->>NodeA: GetIndexersResponse{Indexers:[Addr_IndexerA, Addr_IndexerB, ...]} %% Étape 2 : consensus Note over NodeA: clientSideConsensus(candidates) par Requêtes consensus parallèles NodeA->>Native1: NewStream /opencloud/native/consensus/1.0 NodeA->>Native1: ConsensusRequest{Candidates:[Addr_A, Addr_B]} Native1->>Native1: Croiser avec liveIndexers propres Native1->>NodeA: ConsensusResponse{Trusted:[Addr_A, Addr_B], Suggestions:[]} and NodeA->>Native2: NewStream /opencloud/native/consensus/1.0 NodeA->>Native2: ConsensusRequest{Candidates:[Addr_A, Addr_B]} Native2->>Native2: Croiser avec liveIndexers propres Native2->>NodeA: ConsensusResponse{Trusted:[Addr_A], Suggestions:[Addr_C]} and NodeA->>NativeN: NewStream /opencloud/native/consensus/1.0 NodeA->>NativeN: ConsensusRequest{Candidates:[Addr_A, Addr_B]} NativeN->>NativeN: Croiser avec liveIndexers propres NativeN->>NodeA: ConsensusResponse{Trusted:[Addr_A, Addr_B], Suggestions:[]} end Note over NodeA: Aggrège les votes (timeout 4s)
Addr_A → 3/3 votes → confirmé ✓
Addr_B → 2/3 votes → confirmé ✓ alt confirmed < maxIndexer && suggestions disponibles Note over NodeA: Round 2 — rechallenge avec suggestions NodeA->>NodeA: clientSideConsensus(confirmed + sample(suggestions)) end NodeA->>NodeA: StaticIndexers = adresses confirmées à majorité end