Évolutions du protocole vers v11, v12, etc

Nos derniers échanges concernant la RFC5 développée par @nanocryk montrent que l’évolution de Duniter vers ce protocole va être particulièrement longue. Je redoute un effet tunnel de 2 ans sans évolution même mineure du protocole, ce qui outre le fait de laisser traîner des vulnérabilités sur le protocole v10 met toute la responsabilité des évolutions sur les seules épaules des développeurs de cette RFC5.

Je pense qu’on pourrait pourtant acter le principe d’évolutions successives par forks déclenchés dynamiquement, qu’il s’agisse de hard-forks (HF) ou soft-forks (SF). Par exemple, on pourrait commencer par :

  1. HF : Évolution qui intègre les déclencheurs
  2. SF : Évolution de la règle de difficulté personnalisée (sujet porté par @elois)
  3. HF : Évolution de l’algorithme de preuve de travail (cc @aeris et @Inso)
  4. HF : Ajout des clés déléguées
  5. HF : Binarisation des documents
  6. HF : Scripting simple, 4 fonctions (XHX, SIG, CSV, CLTV)
  7. HF : Merklarisation des données de blocs
  8. HF : Scripting avancé

Ce sujet des forks peut être perçu, selon moi, sous 2 aspects liés : fork et déclencheur.

Fork

Il convient d’abord de se mettre d’accord sur les termes, et au sujet des forks ça n’a pas toujours été très clair me concernant. Voici les définitions que je propose, @nanocryk pourra confirmer.

D’abord, il faut bien comprendre que le concept de fork définit ci-après s’évalue toujours du point de vue d’un nœud ou d’un ensemble de nœuds qui intègrent un code nouveau vis-à-vis d’autres nœuds qui n’ont pas ce code nouveau.

Par exemple, si demain nous souhaitions modifier la règle de difficulté personnalisée (point 1. ci-dessus) afin de la rendre plus contraignante alors nous devrions introduire du code nouveau qui viendrait changer le comportement du nœud vis-à-vis des blocs qu’il accepte, et donc changerait son comportement vis-à-vis à des autres nœuds du réseau qui n’ont pas ce code nouveau.

En effet, s’il n’y a pas de nouveau code, ou si le code nouveau ne crée pas de blocs invalides vis-à-vis des autres nœuds du réseau qui n’auraient pas ce nouveau code, alors il n’y a pas de fork.

Ainsi certaines actions peuvent être entreprises sans aucune perturbation du réseau : par exemple, un nouveau code pourrait décider de ne plus inclure les transactions de X ou Y. Personne ne serait obligé d’installer un tel code sur son nœud, c’est néanmoins possible et permet de contrer certaines nuisances d’attaquants.

À noter que j’insiste sur le fait qu’il s’agit simplement de code nouveau, et pas de version de logiciel ou d’autre chose. Bitcoin amalgame un peu tout car il fonctionne en mode tout ou rien : soit il gère le code A soit il gère le code B, mais jamais les deux. Duniter sait gérer A et B en simultané par exemple, ce qui lui permet de rembobiner un fork utilisant B mais avorté, se rebrancher sur la branche utilisant A et recommencer plus tard, de façon automatique. Bitcoin n’a pas du tout cette nuance.

Pour simplifier, je parlerai ici de nouvelle version pour évoquer un logiciel contenant du code nouveau. Donc, une nouvelle version contient aussi l’ancien code. Importante nuance !

:warning: Attention ici nous raisonnerons façon Duniter, et donc la notion de hard-fork n’est pas strictement identique à celle que vous pourriez trouver sur le web.

Soft-fork

C’est un fork. Donc, ça crée un véritable instabilité au sein du réseau. Toutefois le soft-fork permet une transition en douceur.

Le soft-fork est le cas où des nœuds en nouvelle version créent des blocs tout à fait acceptés par les nœuds en ancienne version, mais refusent une partie des blocs créés par ces derniers.

En somme le soft-fork restreint les blocs acceptés par le réseau. Il se produit de façon souple et continue, à mesure que les nœuds passent en nouvelle version.

L’évolution 1. ci-dessus constitue typiquement un soft-fork, car son implémentation ne fait que restreindre les possibilités existantes en terme de niveau de preuve de travail requis.

En résumé, dans un soft-fork :

  • la compatibilité ascendante est perturbée :warning:
  • la compatibilité descendante est assurée :white_check_mark:

N.B. : un soft-fork qui restreint à aucune possibilité est un hard-fork.

Hard-fork Duniter

C’est un fork qui cette fois crée une instabilité sérieuse, beaucoup plus tranchée au sein du réseau.

Le hard-fork est le cas où des nœuds avec une nouvelle version créent des blocs refusés par les nœuds en ancienne version, et réciproquement.

Le hard-fork Duniter est toutefois plus nuancé, puisque le logiciel accepte tout de même les blocs créés par les nœuds en ancienne version jusqu’au point de bascule où le fork prend réellement son envol. Le hard-fork Duniter ne brise la compatibilité descendante qu’à partir de ce moment.

De même, Duniter est capable de générer des blocs en ancienne version tant que la phase active de fork n’a pas été déclenchée, ou si la phase active est avortée temporairement.

En résumé, dans un hard-fork Duniter :

  • la compatibilité ascendante est assurée mais vise à être brisée :white_check_mark: => :no_entry:
  • la compatibilité descendante est assurée mais vise à être brisée :white_check_mark: => :no_entry:

Pour comparaison, dans un hard-fork Bitcoin :

  • la compatibilité ascendante est brisée :no_entry:
  • la compatibilité descendante est brisée :no_entry:

Déclencheur

Historique

Pour le moment, nous n’avons pas expérimenté de soft-fork ni de hard-fork sur la Ğ1. Donc nous n’avons jamais eu besoin d’en déclencher.

Toutefois nous en prévoyons un dans pour la version 1.6 de Duniter, afin d’autoriser les transactions chaînées au sein d’un même bloc. Il s’agit d’un déclencheur temporel (en gros : le code déclenche la règle à partir d’une date) et la compatibilité descendante n’est pas assurée. Nous nous permettons cette exception car il y a peu de risques si la date est suffisamment lointaine pour que la majorité des auteurs de blocs se mettent à jour, et vu le nombre encore peu conséquent, ça devrait le faire.

Pour la suite : flag comme le Bitcoin

Il s’agirait d’implémenter un mécanisme similaire au Bitcoin. Je ne connais pas précisément la mécanique pour ce dernier, toutefois je comprends qu’il existe des champs dans les blocs qui permettent de savoir à quel point le réseau est prêt à activer une fonctionnalité, bien évidemment ceux activant ce flag ayant déjà le code prêt à être exécuté.

Pour ce déclencheur, si l’on veut rester simple dans Duniter alors on pourrait simplement ajouter un champ UpgradeProtocol: true dans les blocs.

Ajouter un tel champ est bien sûr un hard-fork, mais il s’agirait de la dernière opération de hard-fork sans déclencheur « explicite ». C’est l’évolution 0. que je vous proposais dans la liste au début de ce potst.

Éventuellement dans des versions plus lointaines, nous pourrions aller plus loin et activer des fonctionnalités, encore une fois comme le fait Bitcoin. C’est-à-dire que ce n’est pas du tout ou rien, on peut activer chaque nouvelle fonctionnalité indépendamment sans forcément incrémenter la version de bloc. @nanocryk en sait certainement plus que moi à ce sujet.

Voilà, qu’en pensez-vous ? J’aimerais particulièrement les avis de @nanocryk et @elois qui vont sûrement bosser sur l’implémentation d’un nouveau nœud Duniter, écrit en Rust. L’idée étant qu’en avançant petit à petit, on ne fiche pas tout le travail de RFC5 et de coding Duniter-RS en l’air :slight_smile:

3 Likes

Tous d’abord je suis d’accord sur la définition de soft fork et presque pour le hard fork. Tu donne une définition du hard fork dunitierenne, soit. Le “hard-fork Bitcoin” correspond au moment où ces nouvelles règles s’appliquent. Je note par contre que pendant le fork de Bitcoin Cash, le logiciel Bitcoin ABC supportait bien l’ancien protocole et à déclanché le hard-fork à une certaine hauteur de bloc. Je qualifierais donc le hard-fork le code nouveau au moment où il rentre en activation, ce qui correspond au “fork Bitcoin” et qui sera bien appliqué dans Duniter.

Quand à l’évolution graduelle, je suis d’accord pour les champs 0 à 3, car ils consernent des améliorations qui ne viennent pas de la RFC5 et qui n’en dépendent pas. Cependant la binarisation des documents (5) prend deja en compte les “scripts avancés” (8), et dépendra même peut-être de la merkle-isation (7) (petit spoil à ce niveau là, je pense que vais faire un fil à part pour l’expliquer, mais il pourrait diminuer drastiquement le coup d’un noeud calculateur). Je pense donc qu’il serait difficile de séparer 5,7 et 8, surtout que s’ils l’étaient il faudra prévoir a l’avance comment les suivant vont fonctionner pour espérer pouvoir les intégrer sans tout casser.

En résumé, quelques modifications du protocole 11, 12, etc en pré-RFC5, puis ensuite RFC5 (qui integrera aussi ses changements). Le but de la RFC5 est de stabiliser le protcole, et de permettre à un grand nombre d’ajout d’être fait par soft-fork. Par exemple au niveau des scripts, il y a peu de chances d’avoir un nouveau HF pour ça. On peut rajouter de nouveaux opcodes, et si on veut modifier le fonctionnement d’un ancien on peut changer de version de script.

1 Like

Question bête, ne peut-on pas binariser sans scripting (mais éventuellement déjà prévoir les champs dans le format, sans qu’ils soient réellement utilisés), laisser la binarisation se stabiliser et attaquer le scripting ensuite (quitte à rajouter des choses ensuite, mais si la binarisation est stabilisée, c’est déjà ça de moins…). Je redoute comme cgeek de trop nombreuses nouvelles fonctionnalités d’un coup, d’expérience on court le risque de casser pas mal de choses en même temps… et les réparations en catastrophe dans ces cas-là n’arrangent rien… du coup, à mon avis, on peut quand même séparer les choses dans le temps pour chaque point, ce qui n’empêche pas de prévoir quelques coups à l’avance quand on en joue un. :wink:

Le HF de la RFC5 sera testé de manière intensive sur des nouvelles chaines de tests, puis il y aura plusieurs test de transition sur G1test (via des splits en G1test1, G1test2, etc) et quand tout sera vérifié alors il sera appliqué sur la G1. La RFC5 décrit un tout qui fonctionne ensemble, et le faire en plusieurs étapes qui doivent supporter des changements important me semble plus à risque que de l’intégrer dans une seule.

1 Like

Je pense qu’il y a une incompréhension sur ce qu’est un hard/soft fork sur Bitcoin.
Soft fork = des transactions ou blocs valides sur l’ancienne version deviennent invalides sur la nouvelle
Hard fork = des transactions ou blocs invalides sur l’ancienne version deviennent valides sur la nouvelle

Dans les deux cas on a l’apparition de deux monnaies concurrentes sur la même blockchain, et on est en particulier vulnérable à de la double dépense ou autre (tu es en capacité de générer 2 blocs différents contenant une même transaction, chaque bloc n’étant valide que sur une seule version du fork, et donc chaque version acceptera sa transaction sans que la double dépense ne soit détectable).
Tant qu’il n’y a pas de consensus sur la version à conserver (par exemple si environ le même nombre de mineurs/utilisateurs utilisant chaque version), on conserve 2 monnaies.
Dès qu’il y a un consensus sur suffisamment de temps, le mécanisme de blockchain va de facto trancher pour l’une ou l’autre des versions (la chaîne principale sera suffisamment longue par rapport à la chaîne alternative pour espérer être rattrapée un jour).

En fait il n’y a pas réellement de flag sur Bitcoin. Tout se règle par le consensus (ou non) des mineurs.
Les mineurs souhaitant le hard fork téléchargent la version hard-forkée, ceux ne le souhaitant pas restent sur l’ancienne version.
Tant qu’aucun mineur (hard-forké ou non d’ailleurs) ne génère un bloc invalide pour l’autre partie de la communauté, tout reste à l’identique. Au premier bloc non compatible, on assiste alors à deux monnaies concurrentes sur la même chaîne, non réconciliable (au niveau du fork dans la chaîne, le block est invalide d’un côté et valide de l’autre). C’est la majorité qui va alors l’emporter (ou non) pour déterminer qui de l’ancienne branche ou de la nouvelle va être valide, et ce que ça soit un hard ou un soft fork.

Les soft-fork nécessitent juste un consensus moins fort (50%+) que les hard-fork (80%+) pour éjecter définitivement l’ancienne chaîne, les soft-forks ayant les 2 communautés pouvant éventuellement travailler sur les 2 branches quand les hard-forks ne permettent que le travail d’une communauté sur chaque branche.

1 Like

Faux. Ce n’est plus la même blockchain mais 2 blockchains ayant une partie en commun. Et encore, il faut que les 2 protocoles soient encore calculés/minés.

Il n’y a pas non plus de double dépense (un double dépense c’est on peut dépenser une unité de compte 2 fois sur la même chaine), par contre il y a un risque de rejeu d’une transaction sur une autre après le fork si elle est compatible avec les 2 protocoles.

Ce qui est important avec le soft-fork, c’est que des clients ou des noeuds non à jour voient les blocs valides. Par contre oui si un noeud ancien calcul un bloc, il pourra ne pas être valide selon le nouveau code et ses blocs seront rejetés. Un soft-fork demande donc uniquement la mise à jour des noeuds calculant, alors qu’un hard-fork nécéssite la mise à jour de tous les clients et noeuds du réseau.

Et ben si. Activation de SegWit : BIP

While this BIP is active, all blocks must set the nVersion header top 3 bits to 001 together with bit field (1<<1) (according to the existing segwit deployment). Blocks that do not signal as required will be rejected.

Ce bit d’activation est utiliser pour se mettre d’accord sur la date du premier bloc divergent.

Non, pour les hardfork c’est 100%, sinon la chaine originele peut avancer autant qu’elle veut.

La je ne comprends même plus de quoi tu parles :stuck_out_tongue:

1 Like

Ça dépend comment on regarde. Techniquement parlant, on a bien une seule chaîne de bloc avec le même genesis block, avec 2 branches et chacun sa communauté dessus. On est dans un cas quand même différent de 2 chaînes de bloc différentes avec 2 genesis différents. Et surtout le hard/soft-fork peut être « annulé » n’importe quand (si les gens qui ont forkés considèrent que c’était une fausse piste) et se remettre à bosser sur la chaîne de départ (et même tenter de merger toutes leurs transactions forkées dessus !).

Je suis d’accord que si tu regardes sur chaque chaîne séparément, il n’y a pas de double dépense.
Mais il y en a une sur la chaîne globale. Par exemple dans le cas de BTC/BCC, tu peux réellement « double-dépenser » ton BTC acquis avant le hard-fork BCC : une fois en tant que BTC, et une autre fois en tant que BCC.

Ça a été conçu spécialement pour SegWit que tout le monde sentait comme foireux au possible et que le consensus allait être une vaste blague :joy:
Antérieurement à SegWit, les soft-fork étaient juste un flag dans le code pour dire d’activer la nouvelle fonctionnalité à partir du bloc n° tant.

C’est moins que ça en fait, puisque ne concerne que le cas où des utilisateurs de la version forkée continuerait à miner sur la version non forkée mais après le fork « genesis » block.
Au 1er bloc non compatible, les autres vont miner de leur côté et n’ont donc plus réellement d’impact sur la chaîne de départ (toutes leurs branches sont de facto invalides pour ceux qui restent sur l’ancienne version).
Du côté forké tu as de facto du consensus à 100% puisque l’ancienne version rejette cette branche complètement. Côté branche d’origine, tu peux te permettre du 80% : tu verras de temps en temps un fork mais qui sera très rapidement dépassé en longueur par la chaîne normale. 50-60% ne serait ici pas suffisant puisque tu aurais le risque d’avoir suffisamment de petits amis pour miner sur ton bloc forké et conserver du coup une longueur de chaîne identique à la version « normale » et donc faire un nouveau fork après le 1er fork.

Il n’y a pas de chaine globale. Avant il y a 1 chaine, après il y en a 2. Maintenant les blockchains de Bitcoin et Bitcoin Cash sont completements indépendantes et ce sont bien 2 chaines distinctes. Ton exBTC acquis avec le fork devient BTC et BCH après le fork. Aucune double dépense de BTC ni de BCH.

  1. Pour SegWit et pour des soft-forks ultérieurs, notament Schnorr et les MAST.
  2. SegWit est loin d’être foireux, et règle énormement de problèmes

C’est bien ce que je disais par 100%. Si tout le monde change logiciel, plus personne ne mine sur la verison non forké, et donc elle ne se développe pas.

En terme monétaire, et c’est surtout ça qui est embétant avec Duniter, tu as quand même d’un coup dupliqué l’ensemble des richesses déjà acquises…
Le fait d’avoir déjà des g1 avant le fork g2 est du coup un avantage monétaire non négligeable et rompt l’équité. Si tu es là avant le fork, tu es avantagé par rapport à ceux qui n’arriveront qu’après.

Je veux dire foireux au niveau du consensus. Oui ça réglerait certains problèmes, mais la communauté y reste très frileuse et le consensus a quand même été atteint à l’arrachée…

Le consensus minimal est un paramètre de sécurité et se calcule justement en supposant que tout le monde ne va pas changer de logiciel. Ça définit la proportion nécessaire minimale de personnes à faire la mise-à-jour pour obtenir une stabilité de la chaîne.
Oui, en théorie on aimerait bien avoir du 100% rapidement :joy:
Mais ce paramètre permet justement de savoir à partir de quel moment on peut considérer que le fork a réussi (ou échoué) et remonte la confiance en la chaîne de blocs. Si tu restes en dessous, c’est que ton fork ne prend pas et que la confiance ne peut pas vraiment être là.

Tu peux très bien devenir membre sur les 2 chaines et du coup n’être désavantagé par rapport à personne. De même, quelqu’un pourrait créer une nouvelle monnaie libre K1 completement indépendante. Des membres pourraient devenir membre sur la G1 comme K1 et seraient donc “avantagés”. Mais quelqu’un qui utilise G1 et qui ne donne pas de valeur à K1 se moque de ne pas avoir de DU K1, comme quelqu’un qui utiliserait G1 ou G2 se moquerais de ne pas avoir de DU sur l’autre chaine.

1 Like

Si A est arrivé sur G1 avant le fork, il peut dépenser sa monnaie ga1=ga2 obtenue avant le fork à la fois sur G1 et sur G2, sa monnaie ga1’ obtenue sur G1 après le fork et sa monnaie ga2’ obtenue sur G2 après le fork (puisqu’il est de facto aussi membre là-bas). Richesse totale une durée T de membre dont le point de départ est avant le fork = ga1 + ga2 + ga1’ + ga2’
S’il est arrivé sur G1 après le fork, il se prend une double peine. Il ne peut pas « double dépenser » ce qu’il touche sur G1 (ga2 = 0) mais en plus il n’est pas membre de G2 et donc ne touche pas son dividende là-bas non plus (ga2’ = 0). Richesse totale pour la même durée T de membre mais avec un point de départ après le fork = ga1 + ga1’.

Le cas est bien différent de 2 monnaies indépendantes, parce qu’il aurait fallu faire une action explicite pour s’enregistrer comme membre auprès des 2 monnaies. Tu ne serais pas subitement devenu membre « par hasard » d’une autre monnaie. Tu aurais soit g1 + g1’ si tu n’étais que sur G1 (g2 = g2’ = 0), soit g2 + g2’ si tu étais sur G2 (g1 = g1’ = 0).

De toute manière, c’est forcement quelque chose qui peut arriver quand on fait un changement. Si tu ne veux aucun fork, alors à chaque fois qu’on veut corriger un problème on doit relancer une nouvelle monnaie à partir de 0.

Oui et non. C’est justement pour moi la vraie différence entre soft fork et hard fork. Et ça se situe plus dans la philosophie que dans la technique.
Hard-fork, c’est agressif et tu t’attends à avoir 2 monnaies à la fin parce que les 2 communautés seront irréconciliables et que chacun va partir sur sa solution (cas BTC/BCC).
Soft-fork, tu arriveras à un consensus (dans un sens ou dans l’autre) et il n’y a réellement duplication de la monnaie que sur une zone de temps limitée mais à moyen long terme tous les mineurs et les utilisateurs seront sur une seule et même version (Segwit & cie).

C’est bien pour ça que je défends l’utilisation des soft-forks.

A la limite, la définition des soft-fork et hard-fork dans la crypto, on s’en fiche. J’ai l’impression que ya autant de définitions de ces forks qu’il y a de personnes qui en parlent :slight_smile:

La question est : dans le cadre de Duniter, pour parler entre nous de l’évolution du protocole, est-ce que vous voyez quelque chose à préciser par rapport aux définitions de @cgeek ?

1 Like

Oui, mais philosophiquement parlant il n’y a pas de différence entre « garder la compatibilité » et « perdre la compatibilité ». La seule problématique est la durée de la phase de stabilisation (hard-fork selon la définition donnée dans le 1er post = transition devant être rapide pour ne pas foutre le bordel, coordination nécessaire, etc, soft-fork = la blockchain va encaisser les changements de branche et ça va se réguler tout seul à la longue)

Ce qui est important avec un soft-fork, c’est que les clients et les noeuds mirroirs n’ont pas besoin d’avoir une mise à jour coordonnée pour continuer a fonctionner sur la nouvelle version. C’est tout.

Dans tous les cas ça continuera à fonctionner. Sauf que ça sera sur une chaîne (éventuellement) séparée…

Bon, on tourne en rond pour pas grand chose sur un sujet qui a déjà été abordé plusieurs fois, et on ne répond pas à la proposition de cgeek. J’arrêtrais donc pour ce sujet.

On ne tourne pas en rond, au contraire.
Prend le cas du soft-fork sur la diff personalisée. Oui c’est un soft fork parce que ça reste compatible avec l’ancien code (un block valide par le nouveau soft = un block valide par l’ancien soft) et que no problem.

Sauf que sans upgrade massif des mineurs et des nœuds, on aura à terme un problème. Parce que le nouveau code va se mettre à virer les blocks des anciens nœuds qui ne respecteront pas le critère de difficulté. Et donc potentiellement, les anciens nœuds vont se mettre à fonder une chaine de block valide de leur point de vue, mais avec une difficulté non recevable pour les nouveaux nœuds.
Les anciens nœuds continueront sans problème à fonctionner et à pondre des blocks, mais si on n’a pas de consensus rapide (ici plus de 50% des mineurs) à passer sur le nouvel algo, on aura un problème (ou en tout cas un algo de diff personnalisé inutile car inutilisé).

Si on est sur un rejet de la fonction (adoption < 40%), c’est que la fonctionnalité n’est pas souhaité par la communauté. On va avoir une chaîne low diff plus longue (beaucoup de mineurs dessus) que la high diff (peu de mineur), les anciens nœuds la prendront donc comme référence, alors que les nouveaux nœuds seront sur la chaîne high diff (la low diff n’est pas valide de leur point de vue). Et on a donc 2 monnaies qui coexistent = hard fork philosophique, malgré un soft-fork au niveau technique.
Si on est sur un consensus mou (adoption 40-60%), les anciens nœuds risquent de passer leur vie à faire du flipping entre les 2 branches. Des fois la plus longue sera la high diff, des fois la low diff.
Si on est sur une adoption > 60%, la fonctionnalité est adoptée par la communauté et il n’y a pas de hard fork philosophique puisque la chaîne la plus longue sera la high diff qui est valide des 2 côtés. Juste qu’on se traîne des nœuds qui minent pour rien tant qu’on a pas atteint le 100% d’adoption.

En dehors du problème de la compatibilité, ça sera surtout celle de la cohésion des nœuds et de la bonne volonté à mettre à jour qui va primer pour savoir si on est dans un hard ou un soft fork !

2 Likes