Bug de cesium : Implémentation dépense de sources CSV() et CLTV()

Bonjour,

Je me penche actuellement sur le remplissage automatique des Ğ1Pourboires. Ces pourboires ayant une date de péremption, je me suis dit que ce serait l’occasion parfaite pour implémenter une condition CSV()… Je me base sur du code de Silkaj, dans l’objectif de pouvoir ensuite coder les conditions de dépense directement dans Silkaj.

Les conditions sont :

(SIG({recipient}) || (SIG({sender}) && CSV({delay})))

Soit le récipiendaire utilise sa monnaie avant le délai d’expiration, soit l’émetteur peut la récupérer sans y penser après un délai de péremption, simplement en utilisant son client favori.

J’ai pu émettre des transactions valides (certains essais sont bloqués à tout jamais sur ĞTest :frowning: ) qu’on peut voir par exemple ici : https://ts.gt.librelois.fr/blockchain/block/440714

« 1:2:(SIG(2VgEZnrGQ5hEgwoNrcXZnD9c8o5jL63LPBmJdvMyFhGe) || (SIG(7nge6q7F4k7FQ2q4FRMMPvt2tK7AEx8gNNRLr6LwZN38) && CSV(864))) »

Si je regarde sur Cesium, les conditions de dépense ont l’air bonnes :

Malheureusement, lorsque je veux dépenser la monnaie, elle est bloquée quel que soit le compte que j’utilise (le délai de 14 minutes est largement dépassé). :

silkaj -p ts.gt.librelois.fr tx --output 7nge6q7F4k7FQ2q4FRMMPvt2tK7AEx8gNNRLr6LwZN38 --amount 1 
Please enter your Scrypt Salt (Secret identifier): 
Please enter your Scrypt password (masked): 
2VgEZnrGQ5hEgwoNrcXZnD9c8o5jL63LPBmJdvMyFhGe pubkey doesn’t have enough money for this transaction.

D’où ma question : est-ce une erreur de ma part, ou bien est-ce simplement que Cesium et Silkaj n’ont pas encore implémenté l’utilisation des sources en CSV() et CLTV(), comme je crois le lire ici ?

4 J'aimes

Aucun client (Césium, Silkaj, ni Sakia, ni autre), à ma connaissance, n’a implémenté les autres conditions de déblocage autre que SIG, à savoir CSV, CLTV, et XHX.
Tu es en train d’expérimenter ces nouvelles fonctionnalités du côté client :slight_smile:
Les méthodes pour gérer ces conditions sont implémentées dans DuniterPy. Il reste à en faire bon usage dans les clients Python.

1 J'aime

OK, merci :+1:

Donc je ne vais pas utiliser cette condition pour les Ğ1Pourboires pour le moment, le but étant que ce soit le plus facile pour une personne qui découvre Ğ1.

Mais je vais bosser dessus sur Silkaj, après les MR en cours. Et en commençant par utiliser ces sources.

3 J'aimes

Eh, j’ai deux nouvelles, une bonne et une mauvaise !

Cesium dépense des sources après un délai CSV() passé

La bonne : Si je n’arrivais à rien dépenser, c’est parce que les comptes étaient à 0 : j’avais envoyé moins de 100GT, soit 1GT *10^2 !

Mais depuis j’ai vérifié, avec des envois de 100 GT. La condition d’unlock est :

(SIG({recipient}) || (SIG({sender}) && CSV({delay})))

J’ai envoyé depuis Cesium, une tx avec la SIG(recipient), et une avec la SIG(sender), une fois le délai passé. Les deux ont été validées !

Et lorsque je veux utiliser toute la monnaie du compte (sender) avant le délai, je ne peux pas… Car le délai n’est pas passé, les sources sont bloquées ! J’ai une erreur « wrong unlocker in transaction »

Donc Cesium gère (un peu) la condition CSV(), et les opérandes || et &&. Je suppose que CLTV() fonctionne également. C’est cool !


MAIS Cesium bloque la plupart des tx depuis un compte avant que le délai CSV() soit passé

En revanche, Cesium me refuse certaines transactions depuis le compte « sender », de petits montants, avec la même erreur « Wrong Unlocker ». Donc il ne sait pas trier des sources qui seraient bloquées pour ne pas les utiliser. Autant dire que ce n’est pas encore utilisable pour Ğ1Pourboire.

Par ex. Si un compte a 1000GT dont 100 sont bloquées par CSV(), il ne pourra pas dépenser 500GT car Cesium choisit la mauvaise source, alors même qu’il a 900 GT en sources libres

Conclusion : on peut bloquer TOUTE la monnaie d’un compte sur Cesium en utilisant la condition CSV(), ou en tout cas le rendre quasi inutilisable. C’est un vecteur d’attaque très facile, je peux faire chier qui je veux en lui envoyant une tx avec une condition, Cesium ne saura pas trier le bon grain de l’ivraie. J’ai 10 caractères à modifier dans Silkaj pour faire une telle attaque.

Testé sur Cesium v 1.4.2 et 1.4.6


Et Silkaj ?

Silkaj utilise uniquement les inputs avec SIG(pubkey) comme seule condition. Donc il ne saura pas dépenser les pourboires ou les CSV() passés, mais il ne sera pas non plus bloqué par des tx exotiques : il ne les lit pas.

Vous pouvez regarder les tx émises/reçues par le compte AhRMHUxMPXSeG7qXZrE6qCdjwK9p2bu5Eqei7xAWVEDK sur la GTest.


Solution 1 (court terme): n’utiliser que les conditions de dépenses simples en SIG(pubkey) et rien d’autre, aucune condition composée ni rien d’autre qu’un SIG unique.
Solution 2 (long terme): modifier l’algo de choix des sources pour écarter les sources sous condition de lock.

Et je vais faire un rapport de bug sur Cesium de ce pas. ping @kimamila


Si vous voulez étudier le problème, le compte 6etdjZMRV8p5e5V7AAu4ewChoS3vWrhbh7jn7ZL5g3X6 avec id et mdp : 123456789 a des inputs sous conditions SIG(6etdjZMRV8p5e5V7AAu4ewChoS3vWrhbh7jn7ZL5g3X6) && CSV(5 jours, me demandez pas).

3000 GT en tout, 1200 bloquées.


Si vous appréciez ce rapport de bug, vous pouvez me remercier : CvrMiUhAJpNyX5sdAyZqPE6yEFfSsf6j9EpMmeKvMCWW

3 J'aimes

Rah, tu as été plus rapide que moi à faire joujou avec ces conditions.
Je me disais bien qu’il y aurait de telles choses délectables à découvrir :wink:

Intéressant de savoir que Césium implémente déjà ces conditions.
Mais, vu ce que tu remontes, c’est bugé.

Avec quelques junes (N × 0.01 Ğ1 = 22,40 Ğ1), un Silkaj qui génère des transactions avec ces conditions, un algorithme pour envoyer de telles transactions en masse aux comptes membres récupérés préalablement via BMA, et cette personne a de quoi faire râler la communauté Ğ1/Césium et obliger son développeur à implémenter en urgence l’algorithme de sélection de sources ou faire comme Silkaj et lire que les sources avec condition unique SIG().

3 J'aimes

Vu ce que je rapporte, c’est plutôt que, là où Silkaj gère les outputs avec UNIQUEMENT UN SIG() ; Cesium gère les outputs avec SIG() et ne regarde pas plus loin (si cet output est dépensable ou non). D’où ce bug.

N * 0.01 ?

Je crois qu’il y a des façons plus polies de faire. Mais il est faux d’affirmer que je n’y ai pas pensé tout de suite :smiling_imp:

1 J'aime

Attention a ne pas confondre ce que fait Césium et ce que fait Duniter.
En l’occurrence, Cesium ne sais pas dépenser une source autrement qu’en signant avec SIG.
J’ai juste géré l’affichage des conditions dans l’explorateur de blocs, et commencé a y réfléchir, mais j’en étais resté la, faute d’utilisateur pour tester cela (et surtout de besoin réels).

Si tu as pu dépenser une source qui avait été bloqué, c’est simplement parce-que Duniter l’a renvoyer dans sa liste de sources utilisable, je suppose.

N’est-ce pas plus simple pour de rechercher sa s le code source ? C’est pas si compliqué le JS :slight_smile:

@kimamila Je pense que tu as lu le premier post, et non ce message qui détaille le bug.

Non, je dis que :

Si j’envoie une tx avec condition de lock sur un compte, je peux bloquer toutes les dépenses depuis ce compte faites depuis Cesium, ou en tout cas rendre ce compte inutilisable depuis Cesium.

J’ai également dit que :

Je peux envoyer une tx valide une fois que le délai CSV est passé. Duniter fait donc ce qu’on lui demande.

On est d’accord, par contre il essaie d’utiliser des sources qui ont des conditions de lock supplémentaires. Ceci fait que la tx n’est pas valide… Ce qui bloque la dépense, même s’il y a assez de monnaie sur le compte.

Je peux bloquer le compte portefeuille de ton choix (je n’ai pas essayé les comptes membres) si tu veux un cas à étudier.

Sans doute, mais j’apprends déjà Python.

2 J'aimes

Pour info, j’ai un peu regardé le code, si des devs JS passent par là :

Je ne sais pas coder en JS, cependant je peux vous indiquer les lignes qui me semblent poser souci (v1.4.2) :

5679 :
TX_OUTPUT_SIG: exact(SIG)

7506 :
 var sigMatches =  BMA.regexp.TX_OUTPUT_SIG.exec(outputCondition);

10859 : 
Block.prototype.regexp = {
  TX_OUTPUT_SIG: exact("SIG\\(([0-9a-zA-Z]{43,44})\\)")
};

10881 :
 var matches =  Block.prototype.regexp.TX_OUTPUT_SIG.exec(parts[2]);

En gros, le regexp cherche exactement SIG(pubkey) parmi les outputs reçus, et utilise tout ce qu’il trouve. Dont Cesium va utiliser AUSSI des sources avec conditions de lock non satisfaites, parce qu’il y a effectivement exactement SIG(pubkey) dedans (mais pas que).

J’ai un peu expérimenté, je crois que ceci ne bloque pas les sources D.U., par contre cela bloque les sources recues.

Pour comparaison, la ligne correspondante dans Silkaj est :

    for source in sources["sources"]:
        if source["conditions"] == "SIG(" + pubkey + ")":
2 J'aimes

Ici on a la fonction exact(condition) qui ajoute ^ et $ autour de la condition, donc on est bon :

TX_OUTPUT_SIG: exact(SIG)

Dans https://git.duniter.org/clients/cesium-grp/cesium/blob/master/www/js/services/tx-services.js

On execute TX_OUTPUT_SIG qui est défini comme exact(SIG), donc tout va bien…

 var sigMatches =  BMA.regexp.TX_OUTPUT_SIG.exec(outputCondition);

Le code qui suit me paraît bon, car il fait un match exact avec début et fin de ligne, donc si une autre condition est ajoutée la source ne matche pas.

Dans https://git.duniter.org/clients/cesium-grp/cesium/blob/master/www/js/entities/block.js

   function exact(regexpContent) {
     return new RegExp("^" + regexpContent + "$");
   }

   Block.prototype.regexp = {
     TX_OUTPUT_SIG: exact("SIG\\(([0-9a-zA-Z]{43,44})\\)")
   };

Ici on a une petite boulette sans conséquence, où il faudrait utiliser Block.prototype.regexp.TX_OUTPUT_SIG.exec(unlockCondition);

mais sinon la regexp est la même, donc test strictement un seul SIG()…

      var amount = parts[0];
      var unitbase = parts[1];
      var unlockCondition = parts[2];

      var matches =  Block.prototype.regexp.TX_OUTPUT_SIG.exec(parts[2]);

Etrange, le bug doit être ailleurs. Il faudrait poser des breakpoints…

[edit]
En fait il me semble que ce code refusent les sources ayant des conditions additionnelles. Ce qui a pour effet de les bloquer. Ce qui est normal. En fait je ne voit là rien de grave pour les comptes dans Duniter, juste qu’il n’existe aucun client qui accepte les sources ayant des conditions de dépense multiples.
Mais la solution ne doit pas être d’accepter des sources dont seule une partie est valide. Il faut implémenter la totalité des conditions existantes dans les clients pour débloquer les sources et donc les comptes.
Je ne sais pas si je suis clair ni logique, corrigez moi si je me trompe.

1 J'aime

C’est violent :worried:

3 J'aimes

Le comportement que j’observe est : Cesium essaie d’utiliser des sources bloquées, mais reçoit un « wrong unlocker in transaction ». Cesium ne fait pas le tri des sources. Ceci n’a rien de grave pour les comptes dans Duniter, mais est bien plus grave pour l’économie Ğ1 vu la position dominante de Cesium et l’exposition de tous les comptes à cette attaque.

Le souci, c’est que ça bloque également les sources qui n’ont pas de conditions de dépenses.

Pour confirmer, vous pouvez essayer d’envoyer des tx sur Cesium depuis le compte 6etdjZMRV8p5e5V7AAu4ewChoS3vWrhbh7jn7ZL5g3X6 : id/mdp 123456789 (blocage d’ici samedi 26). Sur la GTest uniquement. Seuls 2*100 GT sont bloquées pour Duniter, mais Cesium bloque tout.

J’ai ma version de Silkaj qui me permet de bloquer un compte sans sommation avec du CSV(), mais je préfère ne pas la publier. Demandez-moi de bloquer des comptes GT si vous le souhaitez.

Pour moi, il est sain de proposer une solution de court terme (utiliser uniquement les sources SIG(pubkey) qui évite cette attaque à court terme, et prévoir de développer l’algo pour traiter tous les cas de déblocage des sources à moyen terme.

Je prévois de me pencher sur ce problème pour Silkaj courant Novembre.

2 J'aimes

Je plussoie à 200% :slight_smile:

Ce serait peut-être l’occasion de lancer un système de bug bounty afin de rémunérer en Ğ1 ceux qui fixerai des bug dans cesium. L’idée est d’indiquer un montant en Ğ1 sur l’issue correspondante, iel contributeur.ice qui corrigera le bug percevra le montant indiqué sur la clé publique de son choix.

Qu’en dit tu @kimamila ? Tu peut même utiliser la barre de financement intégrable de @Paidge pour financer la caisse qui servira a payer les bug bounty :smiley:

Je crois mieux comprendre : si au moins une source contient une condition non gérée, alors Cesium refuse toutes les sources de ce compte ?

Si c’est ça le comportement, alors oui c’est extrêmement plus gênant…

@paidge, tu as du temps pour un nouveau projet, genre debug Cesium ? :wink:

Moi qui croyais être clair :sweat_smile:

Oui, c’est ça. :+1:

Toutes les sources ne sont pas nécessairement bloquées. D’après mes observations, je suppose que :

  • les sources DU ne sont pas bloquées
  • si la source bloquante est la plus petite du compte, alors toutes les autres sont bloquées sur Cesium.
1 J'aime

Je ne suis pas compétent malheureusement :confused: Et puis après 3 semaines de développement de la barre de financement sur mon temps de travail, je vais ptet passer à faire ce pour quoi je suis payé ^^

3 J'aimes

Je pense qu’il faut chercher ici :

et ici :

Bon, vu qu’il n’y a pas de correction de bug, je vais le lancer moi-même, ce financement participatif / bug bounty. Je prévois plusieurs paliers :

400 DU : correction minimale du bug.
700 DU : dépense des sources composées avec conditions CSV et CLTV valides. Vérification que les sources XHX ne reproduisent pas ce blocage.
1500 DU : envoi de tx avec conditions composées et déblocage de conditions XHX (nécessité une modification de l’interface Cesium).

Ce serait en même temps un appel à financement et une demande de contribution. La somme récoltée serait reversée à læ dev qui aura fait la contribution en premier.

Est-il envisageable, dans la mesure où il s’ agit d’un bug critique, que la caisse des devs abonde à un tel financement?

2 J'aimes

Je pense qu’il faut pas faire trop de choses à la fois. Et que la première contribution est suffisamment intéressante. Pas sûr que ça soit un souhait d’implémenter la gestion des autres conditions alors qu’un Césium 2 est en développement.

On en a discuté dans ce post.

2 J'aimes

Financement lancé sur https://g1pourboire.fr/correction-bug-cesium.html !

Pour participer :
GcjRNKNjcGmMdcGjki1DVo5YDrXcRHPHLGBMKYVoZrV8

Le financement participatif vise 700 DU Ğ1. Parmi ces 700 :

  • 400 sont destinés à la dev, ou au dev, qui corrigera le bug. Ils seront versés après que le correctif ait été mergé.
  • 100 me sont destinés, pour la découverte du bug, l’insistance auprès des devs Cesium et l’animation de ce financement.
  • 100 sont destinés au développeur de Cesium qui relira le code et publiera une version officielle testée de Cesium
  • 50 sont un bonus pour læ dev, si la correction de bug est faite avant le 21 décembre 2019 à minuit.
  • 50 sont un bonus pour le développeur Cesium, si la publication de la version officielle de Cesium a lieu dans les 2 semaines qui suivent la correction de bug.
  • Si les bonus ne sont pas utilisés, ils financeront les noeuds et le développement logiciel de Duniter.

Les devs qui souhaitent corriger ce bug sont invités à se faire connaître sur le forum technique. Si le financement participatif n’est pas atteint à publication du correctif, un premier paiement aura lieu. Le deuxième paiement aura lieu lorsque le financement aura été rempli. Si un.e dev souhaite corriger ce bug, mais trouve le prix inadapté, qu’iel le signale, je choisirai en fonction des différentes offres proposées.

edit - selon ce que j’ai lu, @kimamila peut demander à verser 3*100=300DU depuis la caisse des devs.

3 J'aimes