Comme indiqué dans mon 1er post sur les développements nouveaux de Duniter, qui dit nouveau développement dit « explication préalable ». Voici.
Je compte développer pour Duniter 1.6 une nouvelle API de communication pour les nœuds. Je compte nommer celle-ci « WS2P » pour WebSocket 2 Peer.
Il s’agit d’une communication de type P2P directe et bidirectionnelle, qui ne nécessite pas de s’exposer soi-même publiquement sur le réseau. Typiquement, cette API permet de se connecter au réseau Duniter depuis à peu près n’importe quel réseau privé (derrière une box sans ouvrir de port, ou derrière un routeur 3G/4G comme son smartphone) et sans configuration particulière. Cela devrait aussi fonctionner dans un réseau d’université, d’entreprise, etc.
Cette API repose sur une technique permettant de traverser la barrière NAT des box et même les pare-feu. Tout cela est déjà très standard et nous utiliserons ici la variante HTTP de cette technique : les WebSocket.
Motivations
Les motivations principales pour le développement de cette API tiennent en quelques points :
- Zéro configuration
- Communication P2P bidirectionnelle
- Sans exposition systématique à l’extérieur (l’ouverture de port n’est pas nécessaire)
- Avoir une API spécialisée pour la communication inter-nœuds, plus rapide et allant à l’essentiel
- Avec authentification : tous les messages sont signés, ce qui autorise de nombreux contrôles supplémentaires ! (niveaux de trafic, tentatives d’attaques, etc.)
Aucun de ces points n’est satisfait avec l’API actuelle « BMA ».
Description fonctionnelle
Nous partons ici du principe que l’on a un nœud qui s’est déjà synchronisé sur une blockchain et possède un ensemble de fiches de pair, comme c’est le cas aujourd’hui quand on fait la synchronisation initiale.
Connexion réseau
Niveau 1 : Active
Tout nœud qui démarre scrute les fiches de pair à la recherche de nœuds acceptant la connexion WS2P. Le nœud tente alors de s’y connecter (dans la limite d’une dizaine de pairs par exemple), afin d’établir un lien de connexion.
Niveau 2 : Passive (facultatif)
Peu importe ce qui s’est passé au Niveau 1, le nœud peut aussi exposer sa propre interface réseau afin d’être sollicité par d’autres nœuds en vue qu’ils établissent une connexion de Niveau 1.
Ce niveau requiert une part de configuration identique à BMA aujourd’hui. Cela ouvre un port et expose une API WebSocket vouée uniquement à la connexion WS2P.
Ce niveau est facultatif, d’où la prétention du « Zéro configuration ». Mais bien sûr si tous les nœuds sont en Niveau 1, aucune communication WS2P n’est possible. Il doit nécessairement exister des Niveau 2 sur le réseau.
Plus il existe de Niveau 2 sur le réseau, plus celui-ci est décentralisé d’un point de vue communication et peut se mailler fortement.
Niveau 3 : Invitative
Si le Niveau 2 est activé, le nœud peut inviter d’autres nœuds à se connecter à lui. La liste des nœuds invités est configurable, et est vide par défaut.
Connexion logicielle
Une fois la connexion WS2P établie au niveau réseau, celle-ci doit passer l’étape d’acceptation de la connexion au niveau logiciel.
Négociation : connexion entrante
Celle-ci requiert une authentification : le nœud sollicitant doit être membre pour que la connexion soit autorisée¹. De plus, si le nœud sollicité a déjà trop de connexions, il peut refuser.
¹ : il existe toutefois des exceptions, configurables : on peut autoriser spécifiquement des clés, membres ou non-membres, de notre choix : ce sont les nœuds invités (voir : « Niveau 3 »).
Négociation : invitation de connexion
Toutefois, dans le cas d’une invitation on ne souhaite pas établir la connexion entrante : on souhaite inviter le nœud sollicité à devenir le nœud sollicitant dans le cadre d’une nouvelle connexion.
Dialogue
Quand une connexion WS2P est établie, toute communication se fait sur la base d’un dialogue Requête/Réponse. Plusieurs requêtes peuvent se faire en parallèle pour une même connexion, et toutes les connexions sont parallèles également.
Toute Requête et toute Réponse est signée. En cas de signature incorrecte, ou d’auteur différent de la connexion, la communication est considérée invalide. Toute communication invalide entraîne la fermeture de la connexion.
Les requêtes et réponses ne sont pas signées, on considère que l’authentification initiale suffit à établir la légitimité des communications.
Description technique
Niveaux de connexion
Le Niveau 1 est une simple requête de connexion à un WebSocket.
Le Niveau 2 implique la déclaration d’un point d’entrée dans la fiche de pair, par exemple :
WS2P duniter.org 443
Note : si le port de connexion est 443, le protocole de communication réseau est wss://
. Sinon, le protocole est ws://
.
Le Niveau 3 est équivalent au Niveau 1, qui va basculer sur une nouvelle connexion de Niveau 2.
Négociation
L’étape de connexion logicielle a deux cas possibles :
- Connexion entrante : dans ce cas le nœud connecté physiquement envoie un message
NEGO: IN
(grammaire encore à l’étude). Cela aboutit sur une connexion établie ou une connexion fermée immédiatement. - Invitation : dans ce cas le nœud connecté physiquement envoie un message
NEGO: OUT
. Cela aboutit systématiquement à une connexion qui se ferme immédiatement. Le nœud sollicité peut alors décider de devenir sollicitant, ou pas.
Dialogue
Reste à établir une API interne de dialogue, en JSON. Par exemple :
Requête :
{
"uuid": "c045a28e-aa5a-46cd-80b7-19729740c4d3",
"message": "block",
"body": {
...
}
}
Réponse :
{
"answer": "c045a28e-aa5a-46cd-80b7-19729740c4d3",
"code": 200,
"body": {
...
}
}
Dans tous les cas cette API sera strictement limitée aux besoins du réseau de nœuds, et ne sera pas à destination des clients (Sakia, Cesium, Silkaj, …).
Transition
Étant donné un réseau qui communique exclusivement à travers BMA, les nouveaux nœuds utilisant WS2P sont initialement isolés : les nœuds BMA causent entre eux, les nœuds WS2P de même.
Pour qu’un pont s’établisse entre les deux réseaux, il faut avoir des nœuds qui utilisent à la fois BMA et WS2P simultanément.
Ce peut tout à fait être le rôle de nœuds miroir, qu’ont aurait invité à se connecter à notre nœud membre afin qu’ils soient bien au courant de ce qui se passe sur le réseau WS2P. Typiquement, je vais personnellement inviter le nœud g1.duniter.org
à se connecter avec le mien.
Impact sur les clients
Les clients Sakia, Cesium ou Silkaj ne peuvent plus interroger directement les nœuds membres.
C’est un impact très fort, mais voulu afin que les nœuds Duniter soient libérés des sollicitations externes et puissent se concentrer sur leur travail de calculateur.
Comment communiquer, alors ?
Ces clients pourront toujours utiliser l’API BMA sur les nœuds où celle-ci est activée. Il s’agira principalement de nœuds miroirs a priori.
Donc les algorithmes qui prenaient en compte le caractère membre d’un nœud devront être revus à terme (par exemple Sakia, en tient compte pour connaître le consensus réseau le plus pertinent).
De même la vision réseau devra changer, puisqu’un nœud connecté via WS2P ne sera pas joignable par un client (sauf à ce que le client sache parler WS2P, ce qui est un autre sujet).
Comment connaître le consensus actuel ?
Des nouveautés seront introduites, à la fois dans WS2P et BMA, afin de connaître l’état du réseau et son consensus actuel. Ce point est en lien étroit avec l’algorithme de résolution de fork. L’arrivée de WS2P et de ces nouveautés sera d’ailleurs une étape clé permettant de nouveaux algorithme de résolution.
Je pense avoir à peu près tout dit. J’écouterai bien entendu vos retours, et j’espère bien entendu ne pas me planter
J’accueillerai bien entendu toute âme de testeur quand le temps sera venu !