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.