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

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:

5 « 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 »

Super, DuniterPy va donc poursuivre son cycle de vie, en ajoutant les outils et documents nécessaires à la nouvelle API substrate de Duniter (2.0/3.0 ?). :+1:

2 « J'aime »

Upstream (le projet substrate donc) est-il au courant de cette initiative de migration de Duniter vers leur plateforme ? Si oui comment est l’accueil ?

J’envisage de leur remonter mes soucis de dockerisation, mais je voudrais avoir une idée de l’ambiance avant :slight_smile:

1 « J'aime »

Non ils ne sont pas au courant, mais l’accueil est très bon, n’hésite pas à leur faire un ticket :slight_smile:

Précise bien qu’on est basé sur le node-template version monthly-2021-07 :wink:

EDIT: par contre ne t’attends pas à une courte réactivité, les équipes de parity sont débordées en ce moment avec la stabilisation des parachain !

2 « J'aime »

@elois, peux-tu trier l’index des RFCs pour grouper celles qui restent valables et celles qui sont obsolètes par rapport à la migration ?

Je pense surtout au DUBP mnemonic et au dewif.

Je peux le faire si j’ai la liste des RFCs compatibles substrate.

Je comprends @vit mais je ne peux pas encore le faire, car je ne sais pas encore qu’est-ce qu’il va être pertinent de reprendre ou non. Toutes les lib client substrate vienne avec la cryptographie nécessaire pour générer les clés, avec leur propre système de mnemonic plus standard et mieux supporté par des hardwares wallet, donc je pense ne pas garder la RFC DUBP_mnemonic.

Pour DEWIF je pense qu’on peut la garder, mais il faut la modifier pour pouvoir stocker une clé privée directement au lieu d’une seed dans le cas des trousseaux dérivés qui eux n’ont pas de seed.
Ça permettrait d’avoir un seul mnemonic qui génère sa clé maitre, et de définir des sous-clés pour différents usages (Du, certifications etc), et ne stocker sur ses appareils que ses sous-clés.

Une RFC qu’on devrait pouvoir garder (et la mettant à jour éventuellement), c’est le chiffrement des commentaires de transaction. Mais ça va dépendre de comment on stocke les commentaires, donc je dois d’abord me pencher sur la conception du système de stockage libre (car je ne veux pas mettre les commentaires onchain dans le nouveau cœur).

1 « J'aime »

C’est plutôt v3.0.0+monthly-2021-05.

Ça ne build pas, et j’ai l’impression que c’est une dépendance qui est en erreur :

node-template |   Downloaded libp2p-floodsub v0.29.0
node-template | error: failed to parse manifest at `/var/www/node-template/.cargo/registry/src/github.com-1ecc6299db9ec823/libp2p-floodsub-0.29.0/Cargo.toml`
node-template | 
node-template | Caused by:
node-template |   feature `resolver` is required
node-template | 
node-template |   this Cargo does not support nightly features, but if you
node-template |   switch to nightly channel you can add
node-template |   `cargo-features = ["resolver"]` to enable this feature
node-template exited with code 101

Comment faut-il procéder dans ce cas ?

Ça dit d’utiliser nightly, donc dans le répertoire du dépôt :

rustup override set nightly

et si cette commande fait une erreur, recommencer après cette commande :

rustup toolchain install nightly
3 « J'aime »

Merci @tuxmain, j’ai tenté ça. Mais ça coince ensuite avec une autre erreur, sur une autre dépendance :

  Downloaded parity-db v0.2.3
error: failed to parse manifest at `/root/.cargo/registry/src/github.com-1ecc6299db9ec823/parity-db-0.2.3/Cargo.toml`

Caused by:
  failed to parse the version requirement `0.11	` for dependency `parking_lot`

Caused by:
  expected comma after minor version number, found '\t'