Fonction d'aide pour avoir un vrai client python p2p!

get_available_nodes()

Plus d’excuse pour ne pas avoir un client python vraiment p2p.

https://git.duniter.org/clients/python/duniterpy/-/blob/helper_available_nodes/duniterpy/helpers/network.py

Diagramme pour les autres langages

duniter_available_nodes_diagram

Coming soon in DuniterPy !

Comme promis, je vous propose pour la prochaine version de DuniterPy, une fonction qui va vous permettre de sélectionner un serveur à jour. Finit les pannes “faut que tu changes de noeud”, “ah oui pardon mon nœud est désynchro”… Non, non non non non, y a pas d’limite ! (C’est mieux en anglais :wink: )

L’exemple qui permet de comprendre comment utiliser la fonction renvoie un résultat de ce genre :

block 379292-00000001A7B09DE19640733737D1B94CEDD2B52358E4637294334195107A45DF shared by 23 nodes
block 379291-0000000288D96A2692D29C6B4AF4F2C13A59B432E6C317B2D506E8E2C6F672D8 shared by 1 nodes
block 379284-000000220C6077796F6E71385A33F494CF9BC5AE51644718CD99102978C7E3AB shared by 1 nodes
block 379282-00000010260A1EAFA78710BEC13362D5049D875116B6DA3523F929B5EDF37AC4 shared by 1 nodes
block 379278-0000000ECFCEDF891D517765AD0E4A6E680E3ACD3BA843CCADEFCFB6FA1AF9DC shared by 1 nodes
block 379277-000000055B68D976E18734E4E2435A551C614192188BE05F737C8E27F8E6C456 shared by 1 nodes
block 379092-00000005B197E046819BC8F3FC410450E472B67CEA685522704EF4C5B651B99A shared by 1 nodes
block 378970-00000005AFCAA7F500FA7E03DDF6F88E8424D6E02A5BF059018307639170CFF4 shared by 1 nodes
block 378623-000000078BD582FB54C866BEBBEA00A7095ED7E6772C6FA20330DC78B268FFFB shared by 1 nodes
block 378605-0000000F7AF3399FFA1DF9A0FC331A303425FE513FB69C87B1F84B33DB5AAD95 shared by 1 nodes
block 377917-0000001904475390C0A4A1B5170EB6B916C1F496CD42E6CA376C679C30FCC965 shared by 1 nodes
block 376393-000000282C482280D4D04CE86A1D7A9BF09EC45F2E4F6E59AF273872E2A05575 shared by 1 nodes

Available endpoints:
BMAS g1.presles.fr 443
BMAS g1.presles.fr 82.64.214.110 443
BASIC_MERKLED_API nuc.moul.re 85.127.21.74 10901
BMAS duniter.moul.re 443
BASIC_MERKLED_API duniter.moul.re 80
BMAS g1.cgeek.fr 443
BASIC_MERKLED_API g1.cgeek.fr 35556
BASIC_MERKLED_API g1.halpanet.org 10900
BASIC_MERKLED_API g1.halpanet.org 10900
BMAS g1.e-is.pro 443
BASIC_MERKLED_API g1.is.pro 80
BASIC_MERKLED_API 81.57.152.178 57586
BMAS duniter-g1.p2p.legal 163.172.99.239 443
BASIC_MERKLED_API g1a.jytou.fr 9002
BMAS g1.leprette.fr 443
BASIC_MERKLED_API g1.leprette.fr 89.234.177.94 80
BASIC_MERKLED_API 82.64.191.57 2a01:e0a:353:280:2a:6182:4a42:f67c 20901
BASIC_MERKLED_API 95.130.13.155 12901
BASIC_MERKLED_API 192.168.1.253 127.0.0.1 20900
BMAS g1.duniter.org 443
BASIC_MERKLED_API 91.121.157.13 10901
BMAS g1.mithril.re 165.169.21.12 443
BASIC_MERKLED_API 91.163.124.198 20900
BMAS duniter.vincentux.fr 443
BASIC_MERKLED_API 5.51.176.238 19001
BASIC_MERKLED_API duniter.dethegeek.eu.org 192.168.3.12 10901
BASIC_MERKLED_API 82.64.191.57 2a01:e0a:353:280:2a:6182:4a42:f67c 20901
BASIC_MERKLED_API 95.130.13.155 12901
GVA S g1.librelois.fr 443 gva
GVASUB S g1.librelois.fr 443 gva-sub
BASIC_MERKLED_API g1.bizou.re 192.168.1.36 2a01:cb22:8ee:9d00:99ad:bf15:a8b:7631 10901
BASIC_MERKLED_API duniter.normandie-libre.fr 82.64.35.65 10902
BASIC_MERKLED_API nuc.moul.re 85.127.21.74 10901
BMAS duniter.moul.re 443
BASIC_MERKLED_API duniter.moul.re 80

La fonction renvoie des nœuds groupés par numéro de bloc.
Les groupes sont ordonnés par bloc en ordre descendant.

Pour allez vite, vous pouvez sélectionner le premier endpoint du premier nœud du premier groupe pour être quasi sûr d’avoir un nœud fiable (si le nœud que vous contactez est fiable évidemment).

La notice de la fonction pour une meilleure compréhension :

async def get_available_nodes(client: Client) -> List[List[Dict[str, Any]]]:
    """
    Get available nodes grouped and sorted by descending blockstamp

    Each entry is a list of nodes (HeadV2 instance, inline endpoint list) sharing the same blockstamp:

        [
            [{"head": HeadV2, "endpoints": [str, ...]}, ...],
            [{"head": HeadV2, "endpoints": [str, ...]}, ...],
            ...
        ]

    You can just select the first endpoint of the first node of the first group to quickly get an available node.

        groups = get_available_nodes(client)
        first_node_first_endpoint = groups[0][0]["endpoints"][0]

    If node is down, you can select another node.

    Warning : only nodes with BMAS, BASIC_MERKLED_API, GVA and GVASUB endpoint are selected
              and only those endpoints are available in the endpoint list

    :param client: Client instance
    :return:
    """

Il reste à la charge du client de conserver une liste de endpoints fiables entre deux sessions pour ne jamais les perdre de vue sachant qu’ils serviront de bootstrap à la prochaine session.

Dites moi si c’est ce que vous attendiez, ou pas, et si vous avez des remarques.

5 Likes

Yes bravo !

Pour être complet je dirais qu’il faudrait lui inscrire en dur une liste de quelques nœuds connut comme étant fiable pour récupérer cette liste à coup sûr. (oui ça recentralise le côté entièrement p2p mais je ne vois pas trop comment faire autrement si on veut un truc fiable à 100%)

Aussi ce serait pas mal d’ajouter un test automatique de latence sur chaque nœud et de donner les 7 ou 10 nœuds les plus rapides dans un ordre aléatoire.

J’avais fait ça en bash mais impossible de remettre la main dessus …

1 Like

Oui, on fait comme ça dans Bitcoin et IPFS, il ne semble pas y avoir d’autre solution. Tant qu’il y a assez de nœuds bootstrap ça reste décentralisé.

Le problème en faisant ça c’est que si les 10 nœuds les plus rapides appartiennent à une même personne, c’est foutu. On pourrait augmenter la probabilité de contacter un nœud plus rapide, mais il ne faut pas exclure les autres.

2 Likes

Ah oui j’avais pas pensé à ce cas de figure … Enfin en même temps le but pour un client c’est d’avoir recours à un nœud fiable et performant, si dans la liste fournit ya une chance sur deux pour que le noeud choisit soit 2 ou 3 fois plus lent à répondre que le plus performant d’entre eux, c’est embêtant …

Le test de latence pourrait être optionnel, ou bien se faire côté client mais je pense que ce serait le bon endroit ici pour le faire.

1 Like

En fait, choisir un serveur au hasard dans le groupe majoritaire ne suffit pas pour garantir une vision la plus complète des données disponibles.

Car il faut tenir compte de la piscine (mempool).

Vous devez donc demander les informations à un maximum de serveur, rapidement. Vous devez ensuite faire le tri entre les infos de blockchain et les infos en attente en piscine.

Actuellement, bma ne permet pas de distinguer ce qui est en attente (mempool) de ce qui est en blockchain. C’est un manque qu’il faudrait combler en GVA. Ping @Elois.

1 Like

De quel type de données parle tu exactement ? Je ne comprends pas quel est le lien avec le consensus du réseau ?

Peu importe. Il faut évidemment réfléchir au cas par cas suivant le type de données.

Côté client, je sais qu’il y a des informations qui sont en blockchain et des informations qui sont en piscine.

Comment faire pour avertir l’utilisateur qu’une information est fiable (en blockchain, sur un serveur faisant partie du groupe majoritaire (et optionnellement, pour les rollbacks, dans la blockchain depuis N block), ou en attente (en piscine et donc susceptible de disparaître).

Pour aider le client à faire le tri entre les données en piscine (pas de consensus sur le réseau) et les données en blockchain (identique pour le même groupe de consensus), il faudrait que le serveur précise d’où vient le document/l’info qu’il renvoie.

Par exemple, sur des transactions, la réponse à la demande de l’historique serait :

{
"blockchain": ["tx1", "tx2"],
"mempool": ["tx3", "tx4"]
}

Ainsi le client sait que tx1 et tx2 seront renvoyées par tous les serveurs du même groupe majoritaire car en blockchain.
Il va donc demander uniquement, pour les autres serveurs, les tx en piscine, susceptible de s’ajouter aux tx3 et tx4 qu’il a déjà, pour faire lui même son consensus.

Le client devrait donc pouvoir aussi préciser la source des données qu’il désire, soit de la blockchain, soit de la piscine, ou des deux, comme le permet GraphQL.

Mais ça @vit ça n’a rien à voir avec la question du consensus !

Et pour l’historique des transactions c’est déjà le cas sur BMA comme sur GVA. Les transactions en mempool apparaissent déjà dans des champs séparés: pending et sending.

Du coup je ne comprends toujours dsl :confused:

Ne t’étonne pas que j’enfonce des portes ouvertes. C’est normal, car je suis en train d’essayer de monter en compétence sur les besoins des clients. Je défriche donc des sujets que tu connais par coeur, mais pas moi. Be patient. :wink:

Parfait, tu as répondu à ma question. Merci !

Le rapport avec le consensus c’est justement qu’il n’y en a pas pour les piscines et que ça m’a réveillé cette nuit. J’ai donc aussitôt exprimé le fait qu’un client ne peut pas se contenter des infos blockchain qui font consensus, mais doit aussi gérer des infos qui sont hors du consensus.

Merci pour tes réponses et désolé de remuer du déjà connu et assimilé pour toi. :blush:

2 Likes

Toujours dans l’idée d’avoir un moyen pour les clients de savoir quels nœuds sont dans le consensus,
après avoir obtenu la fameuse liste des nœuds fiables, je propose l’idée suivante :

  • Le client, peut partager en NFC/QRCODE/fichier cette fameuse liste à d’autre clients.

Ainsi, dans un Ğmarché, si une personne a son client dans les choux, elle peut récupérer la liste des serveurs fiables dans son client depuis un client qui possède cette liste.

Peu importe le moyen choisi, l’idée est de partager l’info entre les logiciels clients, sans que l’utilisateur ne rentre dans les détails des noms de serveurs. (genre un menu « importer état réseau », « exporter état réseau »). A creuser…

3 Likes