Migration du cœur de Duniter vers C++/TypeScript

Remarque de la FSF sur VSC

3 Likes

Ok, ça fonctionne bien :smile:

Ravi que ça vous plaise! :slight_smile:

Bon ! 49 commits plus tard, l’ensemble du code de Duniter Core (GitHub - duniter/duniter: Crypto-currency software to manage libre currency such as Ğ1. Mirror of:) est migré vers TypeScript. Je reste pour le moment sur la branche ts pour cette migration.

Je n’ai toutefois pas migré les tests automatisés, dont une large part reste écrite en JavaScript. Si vous voulez vous entraîner, migrez donc quelques fichiers :slight_smile: je n’y toucherait pas, la compatibilité TS/JS fait qu’ils fonctionnent parfaitement, du coup j’ai d’autres priorités.

En fait, j’ai encore 3 points à traiter :

  1. J’aimerais réintégrer les modules duniter-(common|prover|keypair|bma|crawler) dans le cœur, et les passer en TypeScript. Ils resteront toutefois dans les sous-dossier dédiés au modules, mais feront partie du code source principal. D’une part cela me permettra d’avoir une vue complète du code tout en profitant partout vérifications statiques du TypeScript (notamment pour retirer du code mort ou redondant, mais aussi pour opérer de substantielles optimisations), mais d’autre part il y a encore un lien très fort entre ces quelques modules (encore très légers) et le cœur.
    Il me paraît donc préférable d’avoir ce petit écosystème ensemble pour le moment, c’est plus pratique.

  2. Retirer les nombreux :any du code source. Car voilà, même si j’ai ajouté beaucoup de typage, il est parfois plus simple de tricher et de typer une variable avec any afin de contourner les erreurs TypeScript. Mais bien sûr on perd tout l’intérêt du TypeScript. Il y a donc un gros travail de remplacement de ces variables non typées.
    Cela peut se faire progressivement ! C’est d’ailleurs un excellent exercice que je vous invite à réaliser : repérez un fichier avec quelques any à l’intérieur, et tentez de les remplacer par le typage adéquat.

Je vais bien sûr m’en coltiner une bonne part ! Mais si vous vous prenez au jeu et que vous souhaitez que vos essais se transforment en contribution, alertez-moi afin qu’on ne touche pas aux mêmes fichiers !

  1. Transposer les outils d’intégration continue vers la nouvelle mouture : Coveralls pour la couverture du code TypeScript (car aujourd’hui on ne vérifie que la couverture du code écrit en JS … or il n’y en a plus), mais aussi adapter les builds de livraison des binaires Duniter Server et Duniter Desktop avec la phase de transpilation.

Ensuite, je pourrais fusionner cette branche ts avec la branche dev, et continuer la version 1.4.0 qui sera décidément une version avec de grandes nouveautés !

En tout cas, je pense que tout cela facilitera grandement le compréhension du code et son appropriation. Je vous invite vraiment à l’ouvrir avec VS Code et à naviguer dedans. Si vous avez la possibilité de lancer le débogueur en plus, alors là vous pouvez carrément tout maîtriser ! La voie royale !

Ce que j’ai pu noter avec cette migration :

  • Adieu le const that = this (mention spéciale pour @Inso).
  • Avec l’utilisation du async/await, nous avons de meilleures chaînes de traces en cas d’erreur : on a la stack complète, là où en JS simple celle-ci se voyait coupée à cause des librairies comme co. On pouvait donc totalement perdre de vue l’origine d’un appel … ce qui était une vraie plaie !
  • Grâce à async/await, j’ai pu supprimer un grand nombre d’appels à des librairies tierces comme co ou Q. On gagne en nombre de lignes de code (réduction), le code se trouve allégé et on a de légers gains en vitesse d’exécution.
  • J’ai pu repérer des absurdités dans le code, parfois des bugs en devenir du fais d’appels incorrects au fonctions (mauvais type, mauvais nombre de paramètres, …).

Malgré tout, il n’y avait pas de bugs manifestes. De toute façon Duniter n’est pas un si gros programme, donc le moindre bug aurait vite fait d’être ressenti.

Voilà donc pour ces quelques retours, je continue :slight_smile: N’hésitez pas à faire un peu de trajet avec moi ! La compagnie et les coups de mains sont appréciés :grin:

10 Likes

Je mets ta réponse comme solution, car vraiment je pense qu’on est sur la bonne voie.

Fin du suspens, pour l’instant la migration du cœur en C++ n’est plus d’actualité, la migration en TypeScript étant déjà très satisfaisante.

Éventuellement, ceux voulant développer un nouveau cœur dans le langage de leur choix peuvent tout à faite le faire.

4 Likes

Du coup le titre du topic est devenu trompeur :slight_smile:

1 Like

Ça me fait penser : @kimamila, tu me demandais jadis ce que je pensais de TypeScript et/ou Angular 2.

À l’époque j’étais dubitatif voire méfiant du fait que l’auteur est Microsoft.

Désormais, j’ai un peu plus de recul : fonce. :+1:

2 Likes

Bon, pour être tout à fait transparent : je viens de tomber sur un bug majeur : il est possible de provoquer sciemment des forks sur la blockchain actuelle par le biais du renouvellement d’adhésion. C’est-à-dire qu’un membre par le seul fait de se renouveler, peut provoquer un fork des nœuds vulnérables.

Il faut toutefois minimiser le risque, car cette attaque ne peut être reproduite qu’une seule fois par membre et par période de 7 jours.

J’ai détecté cette anomalie lors des tests d’invariance de la BDD par changement de code (Duniter 1.3.14 / Duniter 1.4.0 TypeScript) : il y a une valeur en BDD qui est correcte en 1.4.0, mais pas en version 1.3.14 suite à une resynchronisation complète.

L’utilisation du TypeScript aurait certainement évité ce bug.

Mais donc, je ne corrigerai pas ce bug en version 1.3.x vu que la gêne est minime et qu’une 1.4.x sortira dans quelques semaines.

10 Likes

Je n’arrive pas à débugguer le code de Duniter sous VSC.

Il serait intéressant que tu partages ton launch.json :slight_smile: On pourra ainsi mettre à jour le tuto de dev.

Il semble que tu aies réussi depuis, puisque tu as réalisé 2 contributions cet après-midi (merci bien, tu es le 1er contributeur post-TypeScript !).

Quelle a été ta solution ?

Me rappeler que le mode de démarrage adapté était le direct_start au lieu du start :slight_smile:

Du coup j’en profite pour le partager :

{
    // Use IntelliSense to learn about possible Node.js debug attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "Mocha Tests Peers",
            "program": "${workspaceRoot}/node_modules/mocha/bin/_mocha",
            "args": [
                "-u",
                "tdd",
                "--timeout",
                "999999",
                "--colors",
                "${workspaceRoot}/test"
//               ,"-g", "NetworkUpdate"
            ],
            "runtimeExecutable": "${env:HOME}/.nvm/versions/node/v6.9.4/bin/node",
            "internalConsoleOptions": "openOnSessionStart"
        },
        {
            "type": "node",
            "request": "launch",
            "name": "Launch Program",
            "program": "${workspaceRoot}/bin/duniter",
            "args": ["direct_start"],
            "runtimeExecutable": "${env:HOME}/.nvm/versions/node/v6.9.4/bin/node",
            "outFiles": [
                "${workspaceRoot}/out/**/*.js"
            ]
        }
    ]
}
1 Like

Yop !
De mon côté , je suis + fan du C.
C’est un constat sans appel pour moi d’utiliser le C quant aux performances / optimisations et dans la structuration du code, en comparaison avec tout autre langage , que ce soit du C++ ou encore un langage interpreté… soyons fou, faut le développer en assembleur :wink:

Quant à NodeJS, “Node.js® is a JavaScript runtime built on Chrome’s V8 JavaScript engine” une machine virtuelle dont le coeur est écrit en C++, j’aime bien le JS, je suis pas fan des surcouches…

Autant dire que mes rétissences quant à l’utilisation du C++ sont assez bien résumé par @olimoi :

difficiles à comprendre et à gérer…

failles de sécu soulevées par @Inso dont le C n’est pas exempt… Cependant la rigueur prime !

j’ai pas compris, de faire quoi ? je suppose que c’est de faire le choix du langage a adopter…

la où je te rejoins, il semble a mes yeux necessaire d’avoir un document relatant le pseudo-code, indépendant du langage utiliser, c’est la trame de fond et comme le note @devingfx :

yeah ! en attente de + de docs :slight_smile:

la référence c’est le protocole, il a été grammaticalisé (càd formalisé) donc il est théoriquement implémentable dans n’importe-quel langage : duniter/doc/Protocol.md at master · duniter/duniter · GitHub

Bon ceci étant, pour dev un server duniter dans un autre langage Il manque encore un protocole standardisé pour la communication entre les nœuds mais c’est déjà partiellement en projets : https://github.com/duniter/duniter/issues/1056

1 Like

merci pour le lien concernant le protocole,

comme dit précédemment, je parle ‘pseudo-code’ (EDIT: c’est vrai en relisant le post precedent me concernant, c’était peut etre confus dit dans le contexte, mais je parle bien de pseudo-code)

dixit le lien ci dessus: “son aspect descriptif permet de décrire avec plus ou moins de détail l’algorithme, permettant de ce fait de commencer par une vision très large”

pour faire simple / être plus précis, c’est la recette de cuisine que le dev applique

et pour être plus clair, j’ai lu de nombreux posts concernant vos discussions sur les algos avec beaucoup de formules mathématique et moultes paramètres, à la lecture c’est hard, je te laisse imaginer dans le code.

On peut pendre un cas concret que tu peux peut etre me détailler en pseudo-code dans le contexte de son execution ?
formule inscrite dans le mabre de la License G1 où il est dit:

Ğ1 occurs via a Universal Dividend (DU) for any human member, which is of the form:
.1 DU per person per day
The amount of DU is identical each day until the next equinox, where the DU will then be reevaluated according to the formula:
.DU day (the following equinox) = DU (equinox) + c² (M / N) (equinox) / (15778800 seconds)
With as parameters:
c = 4.88% / equinox
UD (0) = 10.00 Ğ1
And as variables:
M the total monetary mass at the equinox
N the number of members at the equinox

1 Like

Et bien cette formule est appliquée par la règle BR_G13 du protocole, c’est vrai que c’est très technique mais c’est la référence qui indique exactement et précisément ce que doit faire duniter et comment il doit le faire.

Réécrire tout le protocole en pseudo-code, c’est un travail colossal et je ne crois pas que ce soit en projets, par contre nous essayons de centraliser sur le wiki duniter https://duniter.org/fr/wiki/duniter/ une documentation un peu plus accessible, un peu plus pseudo-code justement :slight_smile:

1 Like

juste pour savoir , y a personne qui a essayer de faire des choses en perl ?

En fait, la communication entre nœuds n’est pas dans le protocole car justement j’ai considéré que la communication réseau n’était pas le cœur du protocole.

La couche réseau se change. Par contre l’invariant entre toutes les implémentations réseau possible, c’est bien la blockchain Duniter. C’est elle qui ne doit pas (ou très peu) varier.

La recette complète est déjà écrite : elle est en TypeScript. Après, il y a la recette plus générale, se rapprochant d’un pseudo-code tel que tu le souhaites, et c’est effectivement le procole dont parle @elois .

Mais je ne vais pas tout réécrire en pseudo-code, ça n’aurait pas d’intérêt à court terme. Pourquoi pas sur le long terme afin d’avoir plusieurs implémentations de Duniter, mais je t’avoue qu’il faudra me payer très cher pour le faire :slight_smile: Je laisse cela à d’autres, le TypeScript se lit quand même assez facilement.

3 Likes