Désyncro et résolution de fork durant les RML11, création DU lors de l’entrée d’un membre, v1.6.24

A part avoir une trace des documents, cela n’aurait de toute façon servi à rien : soit les certifications/identités/adhésions étaient valides et ont alors été répliquées sur tout le réseau, soit elles ne l’étaient pas et il fallait alors tout refaire.

Au final je suis assez “content” de cet incident, ça va peut-être faire bouger des contributeurs pour Cesium dont la notoriété mérite que son code soit davantage maintenu, et pas seulement par 1 seule personne. C’est pareil pour Duniter, sans les nombreux contributeurs le logiciel n’en serait pas là aujourd’hui.

Certes Duniter aurait pu éviter ce fork de longue durée, les nœuds ayant forké n’auraient pas dus être bloqués aussi longtemps. Mais qu’en sera-t-il demain quand il s’agira d’un nœud corrompu qui donnera sciemment de fausses informations pour tromper les utilisateurs ?

4 Likes

Je confirme que depuis que ça remarche, je suis obligé de re-syncroniser manuellement mon raspberry environ deux fois par jour. C’est chiant.

Il y a un fork de plus de 24h en cours :confused: j’ai lancé la synchro de mon noeud calculant sur la branche en tête (de plus ou moins 300 blocs).

Je pense avoir trouvé l’origine du bug : il s’agit d’une interférence entre le code d’élagage et l’algorithme de résolution de fork.

En fait ce n’est pas du tout ça ! Voir 2 réponses plus loin.

En effet à chaque bloc ajouté, le code d’élagage est déclenché : celui-ci s’occupe de nettoyer les index (identités, certifications, adhésions et sources de monnaie) en fusionnant les enregistrements qui sont considérés comme sortis de la fenêtre possible de fork afin de gagner de la place. Pour le cas du SINDEX et CINDEX (sources et certifications), l’élagage va même jusqu’à supprimer les enregistrements car une source consommée ou une certification expirée n’ont plus aucun impact.

La fenêtre de fork est de 100 blocs si vous avez la configuration par défaut de Duniter : donc au bout de 100 blocs, une information est considérée comme définitive.

Or ce qui se passe, c’est que la résolution de fork appelle le code d’élagage quand celle-ci vérifie la validité de chaque bloc du fork à rejoindre. Or tout fork à rejoindre est par définition, du point de vue de l’algorithme actuel, nécessairement devant nous. Par conséquent, le test de résolution élague des enregistrements à mesure que chaque bloc en avance sur nous est testé, et peut donc entériner des changements lors de ces tests.

Si donc une transaction T est émise au moment d’un fork et se retrouve sur les branches B1 et B2, puis que ce fork dure suffisamment longtemps (au moins 100 blocs), alors l’algorithme de résolution en testant la branche B2 depuis sa branche B1 pourra entériner T. Si cela se produit, alors le rembobinage du test sur B2 n’invalidera pas la consommation des sources par T. Si B2 est finalement sélectionnée parmi les forks (pour l’exemple il n’y a que B2, mais il pourrait y avoir B3, B4, …) alors lors de l’application finale des blocks de B2 Duniter se trouvera emmuré sur le block impliquant T (et même tout block potentiel impliquant T) car la source de T aura déjà été entérinée comme consommée.

Je ne vois pas d’autre explication car la cause est clairement la disparition d’une source dans le SINDEX, or il n’y a que deux méthodes qui y suppriment des entrées : l’élagage et l’annulation de bloc.

Or l’entrée supprimée de SINDEX est en l’occurrence une vieille source (block #86788), et le fork s’est produit au bloc #123034, soit l’équivalent de 36246 blocs plus tard (= environ 125 jours). L’annulation n’est pas possible au-delà de 100 blocs, seul l’élagage peut intervenir aussi loin.

J’en déduis donc que c’est l’élagage le problème, en l’occurrence son interférence via la résolution de fork.

Cela se corrige, j’essaierai donc de faire une nouvelle version de Duniter demain.

3 Likes

Bon tout cette théorie semble s’écrouler car quand je regarde de façon chiffrée, il aurait fallu un fork d’un moins 284 blocs au-dessus du #123033 pour supprimer la source de monnaie manquante D:29VXS2FLZ6QPHioeAXpL5q4K6UtcgxBGnzLjhzuaHRV3:86788. Or, ma sauvegarde montre au plus un fork de 145 blocs d’avance. Donc ça ne marche pas.

Quoi qu’il en soit l’interférence est identifiée et je vais la corriger (il suffit de désactiver l’élagage pour les résolutions de fork). Mais je ne peux pas affirmer avoir trouvé le scénario qui a mené à ce bug pour le moment. :confused:

J’ai trouvé ! Cela n’avait rien à voir …

Qu’est-ce qui peut équivaloir à une suppression ? Une absence de création.

Il se trouve que la clé 29VX est arrivée dans un bloc à DU : https://g1.cgeek.fr/blockchain/block/86788

Or dans ce cas, le protocole stipule que cette identité ne produit pas de DU car pas encore membre (elle le sera au terme de l’inscription du bloc). Toutefois la synchro rapide ne respectait pas cette règle, et produisait un DU. Donc pour un nœud qui a resynchronisé, une source de DU était présente. Pour les autres, les nœuds qui resynchronisent très rarement (poke @elois et tes 5 nœuds qui tombent !), il n’y avait pas de source.

Donc au moment où 29VX fait une transaction qui consomme cette source, c’est le hard-fork !

Côté correctif, il y a ici 2 solutions :

  1. soit l’on considère que “Code is Law” et donc que c’est le protocole qu’il faut revoir (presque tout le réseau est d’accord sur le fait que le DU a été créé par 29VX)
  2. soit l’on considère que c’est le protocole qui avait raison et alors il faut invalider 1 semaine de données

Je penche clairement pour la solution 1°, d’autant que je ne recense que 3 autres cas dans toute la blockchain et qu’il n’est vraiment pas difficile d’inclure un correctif. Et nous parlons ici de 4 DU en plus dans la monnaie.

12 Likes

C’est… c’est… c’est totalement injuste ! Remboursez !

:smiley:

Chapeau pour l’analyse, et youpi pour les 4 DU. :wink:

Merci, et dis-moi, tu te souviens comment faire une release ARM ? Je suis en train de lancer celle pour Linux :slight_smile:

Oui, c’est tout mais je peux la faire. :slight_smile:

Merci pour le lien ! D’ailleurs je suis en train de mettre à jour la page https://duniter.org/fr/wiki/duniter/livraisons/ plutôt obsolète.

Ce serait vraiment sympa ! :smiley:

1 Like

C’est parti…

Edit : problème de carte SD mourante… je build sur un autre raspi en croisant les doigts…

1 Like

La pre-release est disponible ici : https://git.duniter.org/nodes/typescript/duniter/tags/v1.6.24


Page de livraison mise à jour : https://duniter.org/fr/wiki/duniter/livraisons/
Avec un lien vers l’ancienne version, au cas où : https://duniter.org/fr/wiki/duniter/livraisons-old/

Merci @Moul pour avoir migré le site vers GitLab, ça fonctionne comme avant mais en mieux (GitLab !)

1 Like

@nanocryk @Paidge @Moul @hacky @1000i100 @fdrubigny

Votre nœud est visiblement victime du bug, donc je vous invite à le mettre à jour en v1.6.24 et à resynchroniser celui-ci totalement.

==> Duniter v1.6.24

1 Like

Haha je me souviens que j’avais posé cette question n’ayant pas trouver la réponse dans la doc du protocole.
On considère donc désormais qu’un membre qui rentre lors d’un bloc DU créer se DU ? rah faut que je modifie mon code du coup :stuck_out_tongue:

1 Like

C’était pourtant bien marqué, certes pas forcément de façon explicite ou en langage humain :

BR_G91 - Dividend

REDUCE_BY(GLOBAL_IINDEX[member=true], 'pub') as IDTY

On va donc chercher les membres dans le GLOBAL_IINDEX, or cet index comme tous les index GLOBAL_ est alimenté en toute fin de traitement :

BR_G97 - Final INDEX operations

If all the rules [BR_G49 ; BR_G90] pass, then all the LOCAL INDEX values (IINDEX, MINDEX, CINDEX, SINDEX, BINDEX) have to be appended to the GLOBAL INDEX.

@cgeek Quelle version de node dois-je utiliser ? 9.4.0 ? J’en avais une ancienne et ça passe pas du tout, du coup je préfère demander la bonne… :slight_smile:

Edit : en attendant je fais un build avec la 9.4.0…

Oui tente plutôt avec la 9, bien que la 8 est censée passer.

Ok. Avec la 8.9.1, je me prends l’insulte suivante :

module.js:557
    throw err;
    ^

Error: Cannot find module '/opt/duniter/node_modules/sqlite3/lib/binding/node-v59-linux-arm/node_sqlite3.node'
    at Function.Module._resolveFilename (module.js:555:15)
    at Function.Module._load (module.js:482:25)
    at Module.require (module.js:604:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/opt/duniter/node_modules/sqlite3/lib/sqlite3.js:4:15)
    at Module._compile (module.js:660:30)
    at Object.Module._extensions..js (module.js:671:10)
    at Module.load (module.js:573:32)
    at tryModuleLoad (module.js:513:12)
    at Function.Module._load (module.js:505:3)

Version raspberry (enfin) livrée. La version Windows est dans le four (je l’avais oubliée celle-là). Ça devrait aller vite.

Version Windows livrée.

1 Like

Magnifique. :clap: :slight_smile:

De mon point de vue, ce qui permet interprétation, c’est qu’on voit sur la blockchain uniquement l’info DU émis mais pas à qui. C’est les noeuds qui interprètent la donné en fonction de si on est membre ou non.

Avant de lire un bloc avec le DU, je pensais qu’on aurai une TX pour chaque UTXO Coinbase → membre ; ce qui ne laisserai pas de place à l’interprétation, l’UTXO existe sur la blockchain ou non.

Je comprends le gain de place, mais ça implique une potentielle interprétation, comme nous avons pu le voir.

My 2Cts,