Bon je viens de relire entièrement le thread Block issuance distribution, et je crois avoir trouver une méthode déterministe de résolution des fork qui corrige les problèmes connus et qui ne demande pas d’avoir une vision du réseau
De plus cette méthode peut s’appliquer avec ou sans pow, attention c’est complexe :
On se situe dans le contexte local d’un nœud duniter qui reçoit un HEAD ou un Block et qui se rend compte que ce head ou block n’est pas empilable sur sa chaîne locale, il vas donc le stocker avec fork = F != 0 et demander au nœud dont il a reçu l’info tout les blocks précédents jusqu’à trouver le dernier bloc commun, de sorte a pouvoir calculer la longueur du rolling back que produirait le switch sur cette branche. La longueur du rolling back c’est le nombre de blocks entre le HEAD du nœud et le dernier block commun entre les branches fork = 0 et fork = F.
Deux cas sont alors possible :
1. Switcher sur F nécessite un rolling back de moins de 6 blocks
2. Switcher sur F nécessite un rolling back de 6 blocks ou plus
Dans le cas 1 :
avec pow : on switch si la branche F a plus de 3/6* blocks d’avance ET plus de 15/30* min d’avance sur la branche O et si l’on est exclu du calcul des blocks (si la diff perso du noeud est actuellement trop élevée.). (ce que je nomme branche O c’est la branche locale principale du noeud, celle pour laquelle fork=0)
sans pow (avec pop) : Notons R le numéro du dernier bloc commun.
Si le bloc F(R+1) n’est pas prioritaire sur le block O(R+1) : on supprime F.
Sinon si le nœud a écrit l’un des 6 derniers blocs de la branche O on switche sur F. Sinon, on tag la branche F(Hf) comme “fork trop jeune a réévaluer plus tard”. (Prioritaire selon les critères de la PoP)
*3/6 ou 15/30 selon qu’on applique la règle “3-3” ou la règle “6-6”, je n’ai pas d’avis tranché sur ce point.
Dans le cas 2 :
avec pow : si la branche F a moins de 3/6* blocks d’avance OU moins de 15/30* min d’avance, on ne switche pas, on ne fait rien. Sinon, on applique l’algo du nombre d’écrivains pour s’avoir s’il faut ou non switcher sur la branche F (voir paragraphe suivant).
sans pow (avec pop) : Si le block F(R+1) est prioritaire sur le block O(R+1), on applique l’algo du nombre d’écrivains pour s’avoir s’il faut ou non switcher sur la branche F (voir paragraphe suivant). Sinon, on supprime la branche F de la bdd locale.
Algo du nombre d’écrivains :
On a une branche locale principale O et n branches alternatives notés F1, F2, … Fn
On note que pour le cas avec PoP sans pow : pour tout entier i dans [1;n] on a Fi(Ri+1) est prioritaire sur le block O(Ri+1), sinon la branche Fi aurait été supprimée avant d’appliquer le présent algo.
On traite d’abord la branche Fi dont le point de jonction Ri à le numéro de block le plus faible, puis quand on aura fini, soit l’on en déduira qu’il faut switcher sur Fi et on sort de l’algo, soit l’on supprimera Fi de la bdd locale et l’on passera a la branche Fi+1.
Notons F la branche Fi actuellement traitée et F(H) le dernier bloc de la branche F que le nœud a en mémoire dans sa bdd locale. Notons R le dernier bloc commun entre mes branches F et O.
On liste les auteurs des blocs F(R+1:Hf). (Pas besoin de requêter le réseau, il suffit de lire les champ issuer
des blocks) et pour chaque auteur on mémorise temporairement le numéro du dernier bloc qu’il a écrit dans la branche F. On fait de même pour les blocs O(R+1:H).
On cherche ensuite les auteurs commun entre les deux branches et pour chaque auteur commun on prend le minimum entre les numéros des derniers blocs qu’il ont écrit dans chaque branche. On dépile ensuite virtuellement chaque branche pour annuler le dernier switch de chaque auteur.
On a deux nouveaux heads F(H’) et O(H’).
On calcule le nombre d’auteurs (d’issuers) différents sur la plage F(R+1:H’) et sur la plage O(R+1:H’).
On calcule le nombre d’auteurs (d’issuers) différents sur la plage F(R+1:Hf) et sur la plage O(R+1:Ho).
S’il y a plus d’auteurs sur la plage F(R+1:Hf) que sur la plage O(R+1:Ho) on switche sur F,
S’il y a exactement le même nombre d’auteur on choisi arbitrairement la branche donc le bloc R+1 a le plus petit hash // afin d’éviter un ping-pong du réseau
S’il y a moins d’auteurs sur la plage F(R+1:Hf) que sur la plage O(R+1:Ho), on note F(Hf) comme “branche minoritaire” et on la garde en mémoire jusqu’a ce que H-R soit supérieur au rolling back maximal (cgeek suggère 100 blocks je pense au contraire qu’il faut que ce soit beaucoup plus).
Fin de l’algo.
Ça mériterai que je formalise tout cas dans un langage plus proche d’un code, je prévois de le faire, mais dans un premier temps il fallait que je couche le concept par écrit. L’idée c’est de reprendre la proposition de choisir la branche sur laquelle il y a une majorité de nœuds membres, mais sans avoir besoin d’une vue du réseau, on choisi la branche ou le plus de membres ont écrits (uniquement depuis la bifurcation, ce qui est écrit avant la bifurcation ne compte pas).
Et pour éviter de nous faire influencer par les autres nœuds qui viendrais de switcher, on dépile virtuellement les deux branches jusqu’à annuler le dernier switch de chaque membre qui serait sur les deux branches.
Cet algo nous protège notamment de l’attaque qui consiste a soumettre au réseau une blockchain précalculée qui changerai le cours de l’histoire, car il faudrait que cette blockchain précalculée contienne plus d’auteurs que la branche principale, ce qui est possible pour une branche très courte mais plus la branche est longue moins c’est possible
Il permet aussi de ne pas être piéger dans un cycle ou l’on reswitcherai par ping-pong entre deux fork car chaque branche est testée dans l’ordre de l’ancienneté de son point de bifurcation.
Je peut me tromper mais Il me semble que si l’on souhaite un réseau stable alors les critères de type 3-3 ou 6-6 ainsi que tout ce qui se base sur la vision du réseau n’est pas suffisants, a mon avis le nœud doit trancher en fonction du contenu du fork.
EDIT : quelques améliorations substantielles :
- j’ai supprimer le dépilement virtuel qui avait pour but d’éviter d’être influencé par le switch récent d’autres membres afin que le consensus soit plus rapide, en effet si des membres switches de O sur F alors cela va diminuer le nombre d’auteurs spécifiques a O (cad présents sur O et absents sur F) et vas donc entrainer un appel d’air sur F, tout les noeuds vont donc converger d’autant plus rapidement sur la nouvelle branche.
- pour résoudre le problème des attaques qui consiste a soumettre une branche a rolling back faible , j’ai créer un point d’ancrage : Un nœud qui peut faire avancer la branche O restera sur la branche O tant qu’il n’aura pas écrit un bloc même si F est prioritaire selon l’algo, dés qu’il a écrit un bloc et qu’il est donc exclu du calcul alors là il réévaluera F. L’idée c’est que si des attaquants soumettent une branche précalculée sur un point de bifurcation proche du head de la branche principale, on force la branche principale a avancée jusque l’a ou elle peut avancée afin de recomparer F et O “a la loyale”. et ça ne bloque personne car ne reste sur O que les nœuds qui peuvent effectivement faire avancer la branche O, ce qui augmente le nombre d’auteurs sur la plage O(R+1:H)
- Ne pas supprimer F mais noté le bloc F(H) comme “fork minoritaire” afin de ne pas réévaluer la même situation plusieurs fois.