IMPORTANT : Proposition de migrer la Ğ1 sur une blockchain substrate

Hello !
Donc, j’ai un peu regardé pour la CI, je pense que pour m’épargner du travail, ce serait bien d’attendre l’image docker de @Pini, ça permettrai de pas faire du travail en double :wink:

Ben la CI et la dockerisation c’est deux trucs biens différents même s’il y a des liens, et je vais avoir besoin d’une CI rapidement alors propose déjà ce que tu as :slight_smile:

Tu peux t’inspirer du template fourni par substrate : substrate/.gitlab-ci.yml at master · paritytech/substrate · GitHub

Sinon te met pas la pression non plus, je peux le faire :wink:

En fait, je trouve que tout est lié :smiley:
Plus sérieusement, gitlab CI utilise une image docker, donc c’est à peu prés la même chose.
Je vais pour l’instant partir de l’image Rust fournie par docker hub, j’ai fait des tests sur alpine, mais je pense que je vais passer sur debian.

La question incluait peut-être le plus bas niveau : quel est le protocole technique dont on fait abstraction et qui fait toutes ces promesses, quel serait le whitepaper de tout ce qui n’est pas dans le runtime. Comme leur site est tourné vers le « getting started », ces infos doivent être plus longues à trouver… Ou alors si les palettes importantes (grandpa, babe, etc.) ont des whitepaper.

Il y a au moins le whitepaper de Polkadot.

1 « J'aime »

@llaq J’ai poussé un début de dockerisation sur la branche docker. N’hésites pas s’il faut adapter des choses.

1 « J'aime »

Oui elle en ont, et ça me fait penser que j’avais pas encore parlé du consensus, je viens de faire un post dédié: Ğ1v2: proposition de passer au consensus hybride BABE/GRANDPA

1 « J'aime »

Non ce n’est pas la même chose. L’image docker pour la release ne contient que le binaire finale. L’image docker pour la CI ne contient pas le binaire final mais tout l’environnement nécessaire à l’exécution des job de la CI (rust, fmt, clippy, cargo-deny, scache, etc), donc il faut deux images docker différentes :slight_smile:

Mais pour l’image docker de la CI substrate fourni déjà une image : scripts/README.md at master · paritytech/scripts · GitHub

Oui, c’est cela. Et comment est fait le lien avec le protocole métier que l’on vient ajouter par-dessus.

J’essaye de me représenter le protocole complet, de voir quelles sont ses hypothèses, ses définitions et les traitements afin d’en comprendre pleinement le potentiel et les limites.

1 « J'aime »

Le protocole métier en fait c’est le programme runtime lui-même.

Le runtime (composé de palettes) interagit avec substrate en définissant des hooks et des appels dans l’API client, il peut changer des choses dans le stockage, et les palettes peuvent appeler des fonctions d’autres palettes (par exemple pour modifier le solde d’un compte).

Je suis encore en phase de découverte, en commençant à faire une palette de paiement récurrent.

D’ailleurs @elois on devra faire une palette de stockage libre dans les nœuds pour les clients, ou on utilisera plutôt le truc avec IPFS ?

1 « J'aime »

OK, avec vos réponses et diverses ressources je commence à y voir plus clair. Dites-moi si je fais fausse route, et j’ai aussi quelques questions repérées (par un :question:) si vous vous sentez d’y répondre :slight_smile:

Le protocole métier/Runtime

C’est le cœur d’une blockchain Substrate : à partir de la norme WebAssembly, la blockchain transporte carrément le protocole métier, aussi appelé Runtime, en plus des appels à celui-ci. Techniquement cela signifie que les blocs définissent les fonctions métier en plus de consigner leurs appels. Contrairement à Duniter par exemple où le protocole métier est codé dans le noeud et où seuls les appels aux fonctions sont dans les blocs, pour Substrate les deux sont inscrits dans la blockchain elle-même.

Je ne vois pas encore bien la différence avec Ethereum :question:, même si j’ai l’impression qu’en fait c’est surtout qu’il existe un smart contract de niveau blockchain, que celui-ci peut être mis à jour à chaud (et donc sans hard fork).

Le protocole technique/Substrate

Je perçois aussi ce protocole, qui engloberait le protocole Runtime, même si le nom n’est pas formellement posé je crois (bien que ce protocole technique semble implémenté par le Client Substrate, le noeud si j’ai bien suivi).

Le protocole technique définirait un socle de base, incluant les notions de blocs (leur format général, à savoir HEAD et body), définit au moins quelques méta-données (provenant du HEAD) qui sont transmises au Runtime à son exécution, et définit aussi la portée du Runtime (syntaxe, ressources, fonctions de base (sorte de librairie standard)).

Le client Substrate (ou noeud) implémente ce protocole. En cas d’évolution ou de bug bloquant sur ce protocole ou son implémentation, on passe par un hard-fork.

Quel est le cadre du Runtime :question: (ressources, syntaxe, fonctions de base, …)

Gouvernance

Je n’arrive pas encore bien à situer la gouvernance : plutôt métier ou technique, un peu des deux :question:

L’algo de consensus BABE/GRANDPA

Celui-là on l’avait vu venir (Algorand) :slight_smile: VRF et compagnie, consensus sans PoW.

Mais à l’époque la VRF était considérée trop récente, entre autres problèmes.

Et j’ai l’impression que BABE/GRANDPA va plus loin.

Charge / scalabilité

Je me demande à quel point une crypto-monnaie basée sur Substrate peut encaisser de charge ? Quelle serait la limite :question:

1 « J'aime »

Je ne sais pas comment le runtime communique avec le reste, mais si on utilise FRAME il y a toute la doc et des tutos sur substrate.dev qui répondent aux besoins d’un développeur qui voudrait faire un runtime. Théoriquement le runtime est un WASM fait dans le langage qu’on veut, mais si j’ai bien compris, FRAME donne un cadre et les abstractions pour communiquer avec Substrate.

Si l’objectif est de ne pas forker, alors tout peut se faire dans le runtime : on peut y mettre une palette qui gère un système de vote et qui permet par exemple de changer tel paramètre de la monnaie voire le runtime entier.

Mais je pense que c’est bien de garder la possibilité de hard-forker aussi, pour des cas de désaccord profond. (et je ne sais pas si c’est facilité par Substrate)

Il semblerait que Polkadot traite jusqu’à 10 000 transactions/jour actuellement : Polkascan | Multi-chain block explorer

J’avoue que je n’ai toujours pas saisi comment le consensus peut fonctionner avec des blocs si fréquents, il faut encore que je lise la doc…

C’est parce-que le consensus est divisé en 2 phases. Quand le réseau est bon, c’est à dire que les blocs se propagent suffisamment vite, 4, 5 ou 6 blocs peuvent être validés d’un coup (toutes les 30s ~), cette étape de validation n’est pas réalisé lors de l’émission du bloc.

De ce que je comprends, ceci n’est possible qu’a la seul condition que les générations de blocs se fassent de manière 100% déterministes.

Je ne sais pas du tout ce que ça donne en réel, avec les aléas réseau, comment tout ceci est géré reste encore un mystère pour moi pour le moment …

Je suppose qu’au lieu de valider 5 blocs d’un coup en 30s, le réseau va attendre d’être suffisamment synchro pour effectuer la validation, même si ça prend 10 minutes ou 3h, avec donc potentiellement des milliers de blocs à valider d’un coup …

Ça j’avais compris, mais si les nœuds génèrent chacun le prochain bloc de manière déterministe, les transactions ne leur arrivent pas de manière déterministe. Donc comment ils s’assurent de mettre les mêmes transactions dans leur bloc ?

Dans Polkascan je vois que le bloc le plus récent n’a pas forcément de champ « auteur ». Ça veut dire que l’« auteur » est celui qui valide ?

On en discutait hier avec @kimamila , je ne sais pas encore quelle est la meilleure manière de designer ça, je suis en pleine réflexion sur le sujet. La piste que j’aimerais creuser c’est publier les hash des données libres dans la blockchain et les données correspondantes dans un DHT kademlia qui serait gérée par les mêmes nœuds et exposée via la même API RPC (en définissant des customs rpc).

Je ne vois pas bien ce qui est commun à ethereum ? je travaille justement pour un projet qui réimplémente ethereum dans substrate, donc je vois au quotidien que c’est très différent !

@poka avait la même impression, dans l’idée on peut le voir comme ça, mais ça n’a rien à voir avec ce que l’on appelle smart contract dans l’usage.

Le runtime doit à minima implémenter une API de base permettant de créer un bloc et de l’exécuter. On peut étendre son API autant qu’on veut, on peut y définir des offchain worker pour faire des calculs plus couteux. Le point le plus crucial est de différencier le code qui fait partie de l’exécution d’un bloc, du reste. On parle de code onchain vs offchain.
La principale contrainte du runtime est que le temps d’exécution d’un bloc ne doit pas dépasser un temps cible permis par le consensus: 2 secondes pour un bloc toutes les 6 secondes avec BABE.
Pour s’en assurer, un « poids » est associé à chaque extrinsic, et seul les extrinsics dont le poids est inférieur au poids encore disponible sont exécutés, les autres restent en mempool pour un futur bloc.

Non l’impératif d’exécution déterministe des blocs n’a pas de rapport avce le consensus. C’est pour avoir un seul code qui génère et vérifie le bloc. Pour vérifier un bloc, il suffit de le générer avec une mempool virtuelle qui contient exactement les extrinsic dans le bloc, et vérifier qu’on obtient exactement le même bloc au bit près. Comme chaque bloc contient le nouveau merkel root du storage, on est alors certain que le nouvel état de storage on-chain est strictement identique.

La syntaxe, si tu utilises FRAME c’est celle de FRAME, sinon je sais pas. Je connais pas de projet qui utilise substrate sans FRAME, même si c’est théoriquement possible.

Je ne comprends pas la question. La gouvernance c’est au métier de la définir, mais son implémentation est une problématique technique.

Si c’est forker en 2 réseaux différents appliquant des règles différentes en cas de désaccord, ce n’est ni facilité ni rendu plus compliqué, et je ne vois pas comment ça pourrait l’être.

Sachant que dans la conf de polkadot le poid maximal d’un bloc est 2000 milliard de poids et qu’une transaction monétaire à un poid de 68885000. La limiti théorique maximale est de 14516 transactions monétaires par bloc, soit 2419 transactions par seconde soit environ 209 millions de transactions par jour.
On parle bien de limite onchain et mono-blockchain, il est possible de scaler bien plus avec un layer 2 offchain pour les paiements (par exemple les lightning network) ou/et des parachains (sorte de sidechain mais customisables pour se spécialiser dans une tache, pas encore mature mais c’est pour bientôt, polkadot va lancer ses premières parachain dans quelques mois, l’une d’entre elle est d’ailleurs développée par ma boite).

Non c’est un artefact de polkascan, l’auteur est bien celui qui génère le bloc :slight_smile:

4 « J'aime »

@cgeek sur le salon xmpp @kimamila me demandait pour le nom. Il aimerait qu’on reprenne le nom Duniter. Perso ça m’est égal de reprendre le nom ou d’en changer, mais faut qu’on sache rapidement ce qu’on fait car on à un module npm à publier pour la génération des types et on sait pas sous quel nom le publier du coup :sweat_smile:

3 « J'aime »

Super question, je suppose que chaque transaction peut glisser d’un bloc à l’autre tant que les blocs ne sont pas signés par les validateurs ?

Les validateurs voient disons 5 blocs d’un coup, je suppose qu’ils en extraits chaque transaction (demande de changement d’état), peu importe le bloc dans lesquels elles sont, et les rerange en bloc en fonction du leur probabilité d’occurrence.
Une transaction qui n’apparaît alors pas dans le pool des 5 blocs de TOUT le swarm (ou une proportion de ce swarm, laquelle ?) est retiré des blocs où elle se trouve et sera rejoué au prochain round de validation.

J’ai bon ?

Je crois que tout simplement le nœud pioche dans le bloc reçu les transactions et n’utilise que celles-ci.

Oui aucun problème, je suis de cet avis aussi.

Du reste, je vais digérer un peu vos réponses et faire mes propres tests de code pour y voir plus clair. Merci à vous.

6 « J'aime »

Pour moi cette question a trouvé en partie sa réponse :

Mais du coup il me reste des questions :

  • j’imagine que parmi les nœuds autorisés à forger, il y en a plusieurs qui émettent leur bloc, et alors comment fait-on pour choisir le bon ?
  • ce bloc doit bien être propagé super rapidement dans le réseau pour que tout le monde puisse l’avoir avant le prochain qui est dans 6s…
  • pareil pour la propagation des transactions, il y a des mempools comme dans Duniter ?

Et pourtant les calls du client via l’API peuvent modifier directement le storage. Du coup je n’ai toujours pas compris. Mais c’est peut-être mieux d’en parler demain.

Ils n’ont pas à se l’assurer. 2 validateurs peuvent mettre des transactions différentes dans leur bloc respectif.

ce qui est déterministe, c’est la fonction de transition d’état (STF), qui donnera toujours le même résultat avec la même entrée, elle prend en entrée l’état onchain actuel et une liste d’extrinsics.

Je ne comprends pas cette question, tout bloc est signé par son auteur.

non pas du tout :confused:

Exactement :slight_smile:

Ok :slight_smile:

Merci à toi, si tu veux creuser tout ça on peut se faire une visio à occasion :slight_smile:

Tout dépend du mécanisme de consensus utilisé, c’est justement le role premier d’un mécanisme de consensus, déterminer qu’elle est la « bonne » branche, celle qui fait consensus :wink:

Non pas besoin, je ne connais aucun mécanisme de consensus qui impose une telle contrainte, et je ne vois pas l’intérêt :thinking:

Il y a une seule mempool, la mempool des extrinsics, et la aussi elle à pas besoin d’être parfaitement synchrone, c’est pourtant similaire à Duniter sur ce point, je ne comprends pas ce qui te chiffonne ?

2 « J'aime »

Firefox, bien qu’entièrement recodé en Rust a gardé le nom Firefox !

Après par contre ce serait bien que le numéro de version marque le coup.

2 « J'aime »