Encodage des documents

Effectivement, j’ai lu trop vite. C’est bien ça :slight_smile:

Pourquoi avoir appelé le fichier member.rs ? Il contient la description des documents Identity pourtant ?

Il contiendra aussi les documents de certification et de révocation :slight_smile: C’est pour faire une séparation avec les documents relatifs aux blocs et transactions.

Ca ne risque pas de faire de gros fichiers à la fin ?

Pas forcément. Après chaque fichier correspond à un module, et avec un module composé d’1 ou 2 petites structs est assez redondant. On peut sinon faire plein de petits modules pour séparer les comportements, et dans le module parent réexporter avec un pub use les types. Habituellement c’est utilisé pour exposer les types vraiment importants pour ne pas aller les chercher au fin fond de la hiérarchie.

Dans tous les cas pour 3 ou 4 petites structs ça ne me semble pas nécessaire de les faire dans des fichiers différents, surtout quand elle ont un rapport :slight_smile:

1 « J'aime »

J’ai commit une nouvelle version avec le parsing du BlockUID et son utilisation dans IdentityDocument. C’est du coup beaucoup plus propre. Je cherche vraiment à faire des wrappers qui propose directement des objets manipulables, et non les simples String contenus dans le format d’origine.

1 « J'aime »

Il va pas y avoir un problème dans le formattage de BlockUID en mode Debug ?

Je découvre Rust, donc mes questions sont des questions de newb :slight_smile:


    /// Convert a `BlockUId` to its text format.
    pub fn to_string(&self) -> String {
        format!("{}", self)
    }

Or, je vois 2 implémentations de format :


impl Display for BlockUId {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(f, "{}-{}", self.id, self.hash)
    }
}

impl Debug for BlockUId {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(f, "BlockUId ( {} )", self)
    }
}

Tu saurais m’expliquer dans le détail comment tout ça fonctionne / devrait fonctionner ?

Merci :slight_smile:

Dans le protocole actuel les scripts sont stockés sous une forme textuelle. Est-ce les entrées utilisateurs sont normalisées ? C’est à dire :

  • Plusieurs espaces consécutifs sont remplacés par un seul.
  • Les espaces en debut et fin de chaîne sont supprimés (trim)
  • Un espace est obligatoirement présent autour des && et ||

J’aimerais dans mon implémentation stocker en mémoire un AST de ces scripts et les retransformer en texte si besoin est, au lieu de les stocker en texte et de les parser à chaque fois que j’en ai besoin. Or si ces chaînes ne sont pas normalisées, je ne peux pas régénérer la chaîne originale à partir de l’AST si cette première contenait des espaces en plus (ou autres détails que j’aurais oubliés).

Ca ne me dérange pas trop de les stocker en texte, mais il serait plus pratique de les stocker en AST pour pouvoir faire des traitement dessus rapidement, et les convertir en texte uniquement à la fin.

(Cette question est aussi valable avec les inputs qui sont constitués d’une liste d’éléments débloquants)

Les entrées des utilisateurs sont signées par eux, donc il n’y a rien de modifiable, si ça peut répondre à ta question.

Des champs non normalisés pourraient être considérés invalides.

Je vais le stocker en texte du coup, mais c’est vraiment pas pratique :stuck_out_tongue:

J’avais dis au dessus que j’allais faire des type de document mémoire qui peuvent être transformés en texte, mais je ne pense pas le faire vu que le nouveau protocole (RFC2) change vraiment les contraintes et les formats des différentes données, du coup ce n’est pas directement compatible. Il y aura dans la partie gestion de la blockchain un code qui permettra de faire la transition de l’un à l’autre au moment du hardfork et la vérification de la blockchain (avec le protocole actuel puis le nouveau).

EDIT : En fait ce n’est pas un problème de les stocker en texte, je réfléchissais du côté de mon builder mais celui-ci permet de créer de nouveaux documents, donc ce n’est pas un problème. Par contre pour vérifier d’anciens documents au format texte brut il faut que j’implémente un parseur capable de retourner une HashMap tout en gérant correctement les champs multilignes. Une idée de comment déterminer si une nouvelle ligne est une nouvelle ligne d’un champ ou un nouveau champ ? Je pensais le détecter avec le pattern KEY:VALUE mais certains champ multi-lignes ont des valeurs du style A:B:C:D … Je voudrais faire un parseur générique à tous documents. Une solution est d’enregistrer dans le parseur le nom des champs pour qu’il soit capable de les récupérer sans faire d’erreur avec les multilignes, mais ça me semble un peu sale et surtout demande trop de setup à l’utilisation, ce que je voudrais éviter :slight_smile:

T’es allé voir côté api python comment les documents étaient structurés ?

Je sais comment sont structurés les documents, là je parle du parsing. Dans ce code python il est fait à la main pour chaque document en utilisant des expressions rationnelles pour extraire directement les données.

Pour ma part je voudrais dans un premier temps transformer le document texte en une HashMap pour avoir mon Document (voir ici), puis ensuite dans le type de document spécifique parser quand j’ai besoin d’un champ (comme fait pour des champs simples ici et ). Par exemple je parse les issuers d’une transaction comme ceci. Je voudrais donc avoir le champ multi-ligne stocké dans ma HashMap.

Il me faut donc trouver une méthode générique pour parser n’importe quel document. Une première solution et de passer à ce parser la liste des clés dans un tableau (['Issuers', 'Outputs', 'Unlocks', ...]) pour détecter facilement les champs multilignes (qui ne commenceraient donc pas par ces mots clés). Cependant c’est un peu bancal et demande de passer une liste de champs à l’appel, ce qui pourrait poser problème si je veux ajouter une détection automatique du type de document en une seule passe. Je cherche donc une méthode pour différencier une nouvelle ligne d’une clée ou d’un champ multi-ligne.

Je suis peut-être hors sujet, mais autant passer l’info, au cas où. Les transactions sur le réseau stellar sont sérialisées au format xdr https://en.wikipedia.org/wiki/External_Data_Representation

Je trouve que c’est assez pratique, on peut stocker la transaction signée sous forme d’une chaîne texte en base 64, et la “poster” sur le réseau.

J’ai créé un paiement sur le réseau de test pour exemple :

lien vers une transaction signée, “prêt à poster” sur le réseau stellar

Hors sujet, en tout cas pour ce topic ^^ La j’implemente le protocole actuel en Rust, donc pas de changement de structure de données la dedans. Par contre dans le cadre des RFC pour la prochaine version du protocole ça peut être intéressant. Je vais voir ce que ça donne mais je ne suis pas sûr que ça soit adapté à notre structure, ni qu’il y ai déjà une implémentation en TypeScript et en Rust.

Je viens de remarquer que les champs multi-lignes sont directement à la ligne, et il n’y a rien après le : de la clé. Je peux donc utiliser ça pour reconnaître et parser les champs multi-lignes.

EDIT : J’ai un problème au niveau du document Transaction. En exemple j’ai le doc signé :

Version: 10
Type: Transaction
Currency: duniter_unit_test_currency
Blockstamp: 3-73434C90B0609B5B6A624D63EE1BD763B0E49CBF5D817321D8CA6875772F2260
Locktime: 0
Issuers:
DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo
Inputs:
1200:0:D:DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo:2
510:0:T:B6DCADFB841AC05A902741A8772A70B4086D5AEAB147AD48987DDC3887DD55C8:0
Unlocks:
0:SIG(0)
1:SIG(0)
Outputs:
1710:0:SIG(DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV)
Comment: 
coU3A3t0P7UkLQ6+O+utznx7ztLX2BuDtVRQ0ux9fwcRW1VgrOLzLXFTMzSGpUXW2Ad3kJzmfqA4hz2B8tBPCA==

Mon document généré (avec des @ à la place des espaces pour les voir) :

Version:@10
Type:@Transaction
Currency:@duniter_unit_test_currency
Blockstamp:@3-73434C90B0609B5B6A624D63EE1BD763B0E49CBF5D817321D8CA6875772F2260
Locktime:@0
Issuers:
DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo
Inputs:
1200:0:D:DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo:2
510:0:T:B6DCADFB841AC05A902741A8772A70B4086D5AEAB147AD48987DDC3887DD55C8:0
Unlocks:
0:SIG(0)
1:SIG(0)
Outputs:
1710:0:SIG(DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV)
Comment:@

Avec un diff je ne vois aucune différence, hors je n’ai pas la même signature :

  • Original : coU3A3t0P7UkLQ6+O+utznx7ztLX2BuDtVRQ0ux9fwcRW1VgrOLzLXFTMzSGpUXW2Ad3kJzmfqA4hz2B8tBPCA==
  • Rust : /pIiZaY9K7TIwMGJ+PUT0XPBd+NRXwQWaFUoEaAtAOApSHVpn/NtyTYWMIw/uATiSpacZwnodFIoIgQ9PukXCg==

Ce problème est reproductible dans les tests unitaires de la branche protocol-10-documents de duniter-rs.

Si quelqu’un à une idée du pourquoi ? :stuck_out_tongue: (@cgeek ?)

Passe les documents dans une fonction de hashage pour vérifier qu’ils sont bien identiques, car la signature peut varier d’une implémentation de Ed25519 à l’autre.

Euh avec un diff j’ai pas de différence, donc ça ne devrait pas changer le hash. Je veux bien essayer, mais il faut que tu me passe le hash de ton document, si je le fait moi même je vais forcement trouver le même.

Par contre le fait que la signature peut varier suivant l’implémentation de ed25519 est très inquiétante, tu en es sur ?

Mais de toute façon ça ne peux pas être ça car mes autres documents sont correctement signés. Je dois faire une erreur débile dans le test mais là je ne vois pas xD

EDIT : ou alors c’est peut-être dû au champ multi-lignes, je vais regarder de ce côté là.

Oui logiquement le diff a dû déjà te donner le résultat.

Absolument certain. C’est notamment pour ça que Algorand s’appuie sur les VRF, afin justement de n’avoir qu’une signature possible pour un document donné.

Tu veux dire qu’ils produisent la même signature ? Mais la même signature que quoi exactement ? Je ne sais pas trop sur quoi tu compares.

C’est très bizarre ça. Comment un même algorithme ne peux pas être déterministe ? Ce n’est pas plutot la distinction entre les clés ed25519 et curve25519 ?

Tous les autres documents (sauf le bloc qui n’est pas encore fait) passent les tests. Mon code génère donc les même signature que dans tes exemples. (voir tests en bas de duniter-rs/protocol-10/members.rs). Donc je sais qu’au niveau des signatures ça marche. Mais pour ce document là ça marche pas. Il faudrait que je l’exporte en tableau d’octets et vérifier qu’il n’y a pas de caractères Unicode à la con qui trainent.

Voici un commentaire sur crypto.stackexchange.com :

However, that’s not enough, because signature schemes do not usually guarantee uniqueness of the signature. […] and the signer can choose any per-signature secret nonce they want without the verifier noticing.

Oui vérifie, l’espace insécable est très vite inséré dans le code. Normalement les diffs le repèrent, mais sait-on jamais. D’où l’idée du test avec une fonction de hashage pour être tranquille :slight_smile:

De toute façon dans le prochain protocole on pourra permettre d’utiliser d’autre schemas de signature comme les VRF.

Pour le hash ça sera le même problème que la signature : je saurais que ce n’est pas égal, mais je ne saurais pas d’où ça vient. Et puis s’il y a un espace insécable il est dans ton document, or ils ne sont cencé être que du texte simple :stuck_out_tongue: (j’ai juste copié les hashs, clés, signatures, le reste est procédural).