Implémentation de Duniter en Rust?

J’ai tout installé sous une VM, et j’ai le même résultat que toi : segfault pour les tests, et rien pour l’index. Du coup je ne vois pas trop, je pensais que ça venait d’un problème de destruction de mon objet Rust, mais on dirait que non vu que index.js n’en provoque pas. J’ai essayé avec .memCopy() qui me semblait suspect, mais rien non plus. Je ne vois pas trop comment faire pour avancer.

Problèmes toujours non résolus :

  • segfault à la fin des tests unitaires
  • un test de distance qui ne passe pas

Petite question : pourquoi wotb-rs n’a pas son dépot git dédié ? :slight_smile:

Car les différentes crates ne sont pas assez matures et sont amenées à beaucoup évoluer. Je me vois mal ouvrir des issues et des merges request synchro sur plusieurs dépots pour faire un changement non rétro-compatible par exemple. Tout ce qui touche le coeur de duniter-rs est donc pour l’instant dans un seul dépot, et des utilisations en dehors du coeur seront dans un autre.

Tu remarquera dans le Cargo.toml de protocol que l’on va chercher keys directement dans le dépot sans passer par crates.io, ce qui veut dire que l’on peut adapter les changements dans le reste du code sans publier de version.

2 Likes

Un binaire du module wotb c++.
Après on peut aussi l’extraire de la bdd sqlite mais c’est long a coder, ce n’est pas un simple parser !

Si tu veut intégrer des tests propres sur des données réelles il faut d’abord définir un format pour le stockage de la blockchain en Rust et parser depuis ce format.

En fait je voudrais que tu n’utilise pas le format serialisé que j’ai fais :confused: Il est spécifique à l’inplémentation actuelle et va m’empecher de comparer facilement la vitesse d’execution. J’ai fait une issue pour ça.

Je fais comment alors ? De toute façon je suis encore en phase de dev et donc pour le moment il me faut une façon facile et rapide de stocker l’état de la wot, je peut toujours en changer plus tard :wink:

En fait il faudrait une méthode chargement de la wot qui n’appelle que les fonctions du trait (ce qui devrait suffire logiquement). Comme ça on peut changer d’implémentation, ce qui m’interesse vu que je refais le calcul de la WoT en hautement parallélisable :wink:

1 Like

Ça veut quand même dire qu’en cas de changement d’implémentation il faut réindexer les events wot la blockchain depuis le bloc genesis donc ça casse bien la compatibilité, en soi ce n’est pas gênant ça force juste une resync complète après la maj, ce que je ferai car je n’ai pas envie de coder un code de transfert.

Pas si c’est un format indépendant de l’implémentation et qui peux être chargé/écrit sur une WebOfTrust générique. En gros on te passe une variable d’un type qui implemente le trait WebOfTrust, et tu la rempli avec le contenu lu dans le fichier.

Edit : ce format doit juste contenir le nombre de noeuds, qui est actif ou non, et la liste des liens. Après si ton code construit une LegacyWebOfTrust, il suffira de faire to_file(“chemin”, mawot) pour récupérer ce format indépendant.

1 Like

Les méthodes de stockage du trait peuvent instancier et sérialiser un object persistentWot qui ne contiendra que les données a stocker de façon persistante, ça me semble le plus simple et rapide, ça te conviens ?

Ce ne sont pas des methodes du trait, ce sont 2 fonctions qui permettent de convertir dans les 2 sens un fichier en une wot, en appellant les methodes définies dans le trait. On pourra utiliser ce format pour stocker la derniere version de la wot sur le disque pour plus tard, et la charger en mémoire dans n’importe quelle impl du trait WebOfTrust.

Si elles sont spécifiques a chaque implémentation il n’y a pas compatibilité, du coup quel intérêt de faire du générique ?
Je propose plutot d’ajouter 4 fonctions, 2 spécifiques a l’implémentation from_persistent_wot() to_persistent_wot() + deux méthodes communes a toute implémentation, from_file et to_file directement implémenter a persistentWot

Non justement, elles ne sont pas spécifiques à l’implémentation ! Pas besoin de l’intégrer au trait non plus.

La fonction from_file sera du genre :

fn from_file<T: WebOfTrust>(path: &str, wot: WebOfTrust) {
    // lecture d'un noeud
    let id = wot->add_node()
    wot->set_enabled(id, value_in_file);
   // ...
}

Ce format est indépendant de toute implémentation, et utilise les méthodes du trait WebOfTrust pour la remplir.

De même dans ta crate, tu pourrais accepter en entrer une wot d’un type qui implémente WebOfTrust et appeller les methodes de trait pour la manipuler et ceux peu importe l’implémentation. C’est le but d’un trait.

Oui je connais le but d’un trait merci, ce que je ne comprend pas c’est ou est ton format unique compatible entre toutes les implémentations?
Soit tu défini des spec pour le format, et chaque implémentation doit coder son propre code d’écriture/lecture a partir de ces spec ce qui est lourd et fais redonder du code, soit tu défini un format intermédiaire de stockage en mémoire pour que le code qui fait le lien avec le système de fichier soit commun, c’est quand même beaucoup mieux !

A nouveau, il n’y a pas besoin ! Le format unique est un format de fichier, en texte, en binaire, en json, peu importe. Il y a un seul parseur qui lit ce fichier et l’insère dans la wot passée en paramètre, cette wot étant d’un type qui implémente WebOfTrust (le trait). Il peut la remplir uniquement en passant par les methodes du trait et ignore completement l’implémentation.

Je ne vois donc pas où tu vois que chaque impl doit avoir son parseur.

1 Like

Merci c’est ce point qui m’avais échappé. En effet là ça marche, je suis un peu lent a comprendre des fois :sweat_smile:
Pour le format du fichier on peut partir sur du binaire pour optimiser l’espace :
data size
nb_nodes 4bytes
enableds 1bit*nb_nodes
nb_links 4bytes
links 8bytes*nb_links

Qu’en dit tu ?

Ah bah voila ! :smiley:

Oui pour le format ça me va.

Edit : Cette joie quand tu arrive à faire compiler un code compliqué avec des itérateurs =D
Si je n’ai pas fait d’erreur, voila à quoi ressemble le nouveau get_path :

fn get_paths(&self, from: NodeId, to: NodeId, k_max: u32) -> Vec<Vec<NodeId>> {
        if from == to {
            vec![vec![to]]
        } else if k_max > 0 {
            self.nodes[from.0]
                .links_source
                .par_iter()
                .map(|&source| self.get_paths(source, to, k_max - 1))
                .reduce(
                    || vec![],
                    |mut acc, paths| {
                        acc.append(&mut paths
                            .par_iter()
                            .map(|path| {
                                let mut new_path = vec![from];
                                new_path.append(&mut path.clone());
                                new_path
                            })
                            .collect::<Vec<Vec<NodeId>>>());
                        acc
                    },
                )
        } else {
            vec![]
        }
    }
2 Likes

Putain ça c’est du récursif, chapeau :wink:

Aussi je repense au problème d’atomicité, enfin au besoin de synchronicité parfaite entre le fichier wotb et la bdd, un moyen simple de rendre le noeud plus robuste et capable de gérer un déphasage c’est de stocker le blockstamp en en-ête du fichier wotb. Ainsi en cas de déphase, le noeud sait qu’il doit réindexer quelques blocs pour mettre a jours les données de wotb (ou de la bdd si c’est wotb qui est en avance).

1 Like

Je te rassure, ce code ne donne pas le bon résultat xD