Machine à état et réponses prouvées des noeuds aux clients ?

Alors oui, bien vu pour la signature des blocs.

Vu comme ça, il n’y a pas de couche validation réseau à mettre en oeuvre. Si la validation doit se faire dans la chaine, il faut pouvoir y trouver des infos. Notamment :

  • Si une identité est “outdistanced” ou non
  • Si une identité est “membre” ou non
  • Les sources de monnaie détruite
  • etc.

Si on s’appuie sur les headers de la chaine de blocs, il faut pouvoir utiliser les merkleRoot pour avoir ces informations là.

Si on arrive à mettre toutes les validations dans les headers de la chaine, alors les API clients n’auraient plus qu’à prouver les données en faisant référence à la preuve via un chemin dans un arbre de merkle… Ce qui réglerait tout nos problèmes d’un coup.

@nanocryk : Est-ce que ça t’inspire ce problème ?

Alors c’est compliqué.

Dans la première version en cours de rédaction, ce n’est pas possible. L’arbre de Merkle des documents ne permet de prouver qu’un document existe dans la blockchain à condition qu’on connaisse son hash. Or quand le membre renouvelle son adhésion (document Membership) il faudrait que le client connaisse l’existence de son hash pour pouvoir le demander. Quand à la distance, rien dans la blockchain ne stocke explicitement les distances.

Une idée que j’ai eu hier et qui pourrait permettre de faire ça serait de stocker l’état complet de la WoT et des UTXO (sources non consommées) sous la forme d’un arbre de Merkle.

Je veux savoir si telle source (transaction + index) n’est pas consommée : son hash doit être dans l’arbre.
Je veux savoir si une identité (UID) est active : son hash doit être dans l’arbre.
Je veux savoir savoir si une identité est “outdistanced” (UID + outdistance) : son hash doit être dans l’arbre.

La blockchain étant une machine à état, on se retrouve dans chaque bloc avec :

  • Une liste de documents (qui globalement forment une fonction de changement d’état f tel que etat(t) = f(etat(t-1)) ).
  • L’arbre de Merkle “stockant” ces documents.
  • L’arbre de Merkle représentant l’état complet du système etat(t).
  • La preuve de travail permettant de rendre “légitime” cette fonction f.

Le nœud possédant déjà cet état complet pour fonctionner, il lui est possible de :

  • Le transformer en arbre de Merkle.
  • Vérifier que le nouvel état stocké dans un nouveau bloc est correct après l’ensemble des modifications.
  • Repérer une donnée demandée par un client, et régénérer à la volée la branche qui permet de prouver son existence dans l’arbre d’état.

Il y encore pas mal de réflexion à faire, mais l’idée générale me semble répondre aux problèmes, tout en prenant très peu de place en bloc et demandant peu de ressources supplémentaires.

va chercher un medoc pour le mal de tête :laughing:

2 « J'aime »

Oui c’est bien ce qui me pose problème avec l’approche “on s’appuie sur les headers pour valider” ^^ Maintenant, si on trouve une méthode de mettre toutes ces validations dans la chaine de bloc, on résout tout nos problèmes.

Ceci dit c’est pas trivial. Il suffit de voir tout ce qu’on a ajouté à BMA suite aux demandes utilisateurs (principalement via @kimamila et ses retours) :
https://g1.duniter.inso.ovh/wot/requirements/inso

{
  "identities": [
    {
      "pubkey": "5cnvo5bmR8QbtyNVnkDXWq6n5My6oNLd1o6auJApGCsv",
      "uid": "inso",
      "sig": "gTUSERA3IqEzMDvdpiFkTgBBFKwUl7M62e+VCzwyHJTrxvBSB+C+8ImoKsd7pYFAnZ+HL6cJ1p7jyVUIOZGqCw==",
      "meta": {
        "timestamp": "0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855"
      },
      "revocation_sig": null,
      "revoked": false,
      "revoked_on": null,
      "expired": false,
      "outdistanced": false,
      "isSentry": true,
      "wasMember": true,
      "certifications": [
        {
          "from": "BbdyLPyABYzx8Lef3oXzkoiAQ5kn3uU96ZED7Nt17gZx",
          "to": "5cnvo5bmR8QbtyNVnkDXWq6n5My6oNLd1o6auJApGCsv",
          "timestamp": 1488987127,
          "expiresIn": 34613048
        },
        {
          "from": "2ny7YAdmzReQxAayyJZsyVYwYhVyax2thKcGknmQy5nQ",
          "to": "5cnvo5bmR8QbtyNVnkDXWq6n5My6oNLd1o6auJApGCsv",
          "timestamp": 1488987127,
          "expiresIn": 34613048
        },
        {
          "from": "56aXsYLSQmGz75ZohRQMLcKiYaUmJK5cbyz4ZGiKsbAe",
          "to": "5cnvo5bmR8QbtyNVnkDXWq6n5My6oNLd1o6auJApGCsv",
          "timestamp": 1488987127,
          "expiresIn": 34613048
        },
        {
          "from": "3QLkBNoCNJENY8HyCDh1kDG2UKdg3q66z1Q91hpSJinD",
          "to": "5cnvo5bmR8QbtyNVnkDXWq6n5My6oNLd1o6auJApGCsv",
          "timestamp": 1488987127,
          "expiresIn": 34613048
        },
        {
          "from": "7vU9BMDhN6fBuRa2iK3JRbC6pqQKb4qDMGsFcQuT5cz",
          "to": "5cnvo5bmR8QbtyNVnkDXWq6n5My6oNLd1o6auJApGCsv",
          "timestamp": 1488987127,
          "expiresIn": 34613048
        },
        {
          "from": "FVUFRrk1K5TQGsY7PRLwqHgdHRoHrwb1hcucp4C2N5tD",
          "to": "5cnvo5bmR8QbtyNVnkDXWq6n5My6oNLd1o6auJApGCsv",
          "timestamp": 1488987127,
          "expiresIn": 34613048
        },
        {
          "from": "HovtdmYvNzwi9e2YTXaE4gr53czvEodDFXxgupvbzfNC",
          "to": "5cnvo5bmR8QbtyNVnkDXWq6n5My6oNLd1o6auJApGCsv",
          "timestamp": 1488987127,
          "expiresIn": 34613048
        },
        {
          "from": "ArcfiCb3FWBonodGtiznCdBdCH5EJTLUdAFHR4nRM4zf",
          "to": "5cnvo5bmR8QbtyNVnkDXWq6n5My6oNLd1o6auJApGCsv",
          "timestamp": 1488987127,
          "expiresIn": 34613048
        },
        {
          "from": "BPEap6B98qBxTmUMoxvCtuP2JXFMjX7kDJT1RaYn3UbS",
          "to": "5cnvo5bmR8QbtyNVnkDXWq6n5My6oNLd1o6auJApGCsv",
          "timestamp": 1488987127,
          "expiresIn": 34613048
        },
        {
          "from": "38MEAZN68Pz1DTvT3tqgxx4yQP6snJCQhPqEFxbDk4aE",
          "to": "5cnvo5bmR8QbtyNVnkDXWq6n5My6oNLd1o6auJApGCsv",
          "timestamp": 1488987127,
          "expiresIn": 34613048
        },
        {
          "from": "3wdDzBz18mWupx1UChMnhky2Nut3XVnyn9U7Y662J7yE",
          "to": "5cnvo5bmR8QbtyNVnkDXWq6n5My6oNLd1o6auJApGCsv",
          "timestamp": 1488987127,
          "expiresIn": 34613048
        },
        {
          "from": "GfKERHnJTYzKhKUma5h1uWhetbA8yHKymhVH2raf2aCP",
          "to": "5cnvo5bmR8QbtyNVnkDXWq6n5My6oNLd1o6auJApGCsv",
          "timestamp": 1488987127,
          "expiresIn": 34613048
        },
        {
          "from": "7F6oyFQywURCACWZZGtG97Girh9EL1kg2WBwftEZxDoJ",
          "to": "5cnvo5bmR8QbtyNVnkDXWq6n5My6oNLd1o6auJApGCsv",
          "timestamp": 1488987127,
          "expiresIn": 34613048
        },
        {
          "from": "Ds1z6Wd8hNTexBoo3LVG2oXLZN4dC9ZWxoWwnDbF1NEW",
          "to": "5cnvo5bmR8QbtyNVnkDXWq6n5My6oNLd1o6auJApGCsv",
          "timestamp": 1488987127,
          "expiresIn": 34613048
        },
        {
          "from": "4bD7J3uA5pH2N9Xqimspf2XxWN4ESM2Az2XBqtSeHvUZ",
          "to": "5cnvo5bmR8QbtyNVnkDXWq6n5My6oNLd1o6auJApGCsv",
          "timestamp": 1488987127,
          "expiresIn": 34613048
        },
        {
          "from": "DymYJziyjC9pyupKNxT9iukEKrnFSGNCLnxFQtSWJSg5",
          "to": "5cnvo5bmR8QbtyNVnkDXWq6n5My6oNLd1o6auJApGCsv",
          "timestamp": 1488987127,
          "expiresIn": 34613048
        },
        {
          "from": "4GdKJq2LqV1rrCkixUoSpg4w5Abz41knU4h9eov2R3QU",
          "to": "5cnvo5bmR8QbtyNVnkDXWq6n5My6oNLd1o6auJApGCsv",
          "timestamp": 1488987127,
          "expiresIn": 34613048
        },
        {
          "from": "Be1eVp7etVfA7cT6er6dcJ9d5KxGJVY2tzCGGCAz3yG",
          "to": "5cnvo5bmR8QbtyNVnkDXWq6n5My6oNLd1o6auJApGCsv",
          "timestamp": 1496384892,
          "expiresIn": 42010813
        },
        {
          "from": "Do99s6wQR2JLfhirPdpAERSjNbmjjECzGxHNJMiNKT3P",
          "to": "5cnvo5bmR8QbtyNVnkDXWq6n5My6oNLd1o6auJApGCsv",
          "timestamp": 1496404204,
          "expiresIn": 42030125
        },
        {
          "from": "4rWREtAxNS2L427f4vG2LafZNZ9ZLj3cvFFxGyrtFzGL",
          "to": "5cnvo5bmR8QbtyNVnkDXWq6n5My6oNLd1o6auJApGCsv",
          "timestamp": 1504624079,
          "expiresIn": 50250000
        },
        {
          "from": "8TqtovcRTgdbJXHKoKU5bU41a9B6SdR5rGGWRz6oY9hv",
          "to": "5cnvo5bmR8QbtyNVnkDXWq6n5My6oNLd1o6auJApGCsv",
          "timestamp": 1509667372,
          "expiresIn": 55293293
        }
      ],
      "pendingCerts": [],
      "pendingMemberships": [],
      "membershipPendingExpiresIn": 0,
      "membershipExpiresIn": 30081626
    },
    {
      "pubkey": "7hygreNPE4LJpQhB6zHqGsofKA2G3dDXQM2n6LkDBakB",
      "uid": "Mymypinson",
      "sig": "trkirggMe9HsnO4T2FV9h1NKzxiZncXB5D5znhuq3zDZaY3MTja2edWaJhO0KcFU4yZdQPudt8ltldYL0rk1Cg==",
      "meta": {
        "timestamp": "17524-00000C1533A49A4EC583B91148E2A38E91E39396BAD0C8D3A5B93338E905EF83"
      },
      "revocation_sig": null,
      "revoked": false,
      "revoked_on": null,
      "expired": false,
      "outdistanced": false,
      "isSentry": true,
      "wasMember": true,
      "certifications": [
        {
          "from": "FZwTmdizfMXHwHKAGpJm8kEg7DWKeoPw9M1qAFmTcraV",
          "to": "7hygreNPE4LJpQhB6zHqGsofKA2G3dDXQM2n6LkDBakB",
          "timestamp": 1499204026,
          "expiresIn": 44829947
        },
        {
          "from": "6rhGeDLkED3d13vrGGcXUqymFtgQgdBDyk5pUbe6icbh",
          "to": "7hygreNPE4LJpQhB6zHqGsofKA2G3dDXQM2n6LkDBakB",
          "timestamp": 1497741482,
          "expiresIn": 43367403
        },
        {
          "from": "8SJZia3RJ36hp3wXy8AJXJj8z7yeLHCVaTtv2xSi2MBj",
          "to": "7hygreNPE4LJpQhB6zHqGsofKA2G3dDXQM2n6LkDBakB",
          "timestamp": 1495043998,
          "expiresIn": 40669919
        },
        {
          "from": "zio4Jp8hnqkYmoz5FMYm1siCjGmjWzVUg27KMfDoefA",
          "to": "7hygreNPE4LJpQhB6zHqGsofKA2G3dDXQM2n6LkDBakB",
          "timestamp": 1495043540,
          "expiresIn": 40669461
        },
        {
          "from": "5SwfQubSat5SunNafCsunEGTY93nVM4kLSsuprNqQb6S",
          "to": "7hygreNPE4LJpQhB6zHqGsofKA2G3dDXQM2n6LkDBakB",
          "timestamp": 1495043540,
          "expiresIn": 40669461
        },
        {
          "from": "5hvx7VXG5yiD3NgZKpaVcjL1AtD8LMw6MfT7iERmW5AL",
          "to": "7hygreNPE4LJpQhB6zHqGsofKA2G3dDXQM2n6LkDBakB",
          "timestamp": 1498497857,
          "expiresIn": 44123778
        }
      ],
      "pendingCerts": [],
      "pendingMemberships": [],
      "membershipPendingExpiresIn": 0,
      "membershipExpiresIn": 8510998
    }
  ]
}

Concrètement, comment est-ce qu’on peut valider chacune des informations présente dans cette URL via les simples headers des blocs ?

On ne peux demander la preuve de ce que le client peux générer en entier. En gros que des questions Oui/Non, et le noeud ne peux répondre que “Oui voila la preuve”, ou “Je te dis que non, mais tu dois demander à d’autres leur avis”. Mais on peut faire des requêtes plus compliquées qui sont prouvable avec ça.

Est-ce que machin est membre (machin,membre) ? On peut.
Est-ce qu’il est outdistanced (machin, outdistanced) ? On peut.
Est-ce que tu peux me donner la certification de machin à truc ? Oui, ça correspond à tel document (avec toutes les informations), et voila où se trouve ce document (hash) dans l’arbre.

Après cet arbre va être très dense, mais en organisant bien les données (une sorte de BMA plus complexe) ça devrait pouvoir être plutôt optimisé.

Edit : en poussant la réflexion au maximum je suis sûr que l’on peut exprimer toutes les des blocs la dedans, et même intégrer la PoW. On a juste un Merkle Tree qui stocke l’ancien état, les transformations, le nouveau (qui sera l’ancien état du bloc d’après). On rajoute un nonce la dedans, et le Merkle Root peut même la condition de validité de la PoW.

1 « J'aime »

Oui, j’en suis bien conscient. Je souhaiterais juste être certain que chacune des infos présentes dans cette requête peut être accompagnée d’une preuve par un chemin de merkle :slight_smile:

Ca se fait en plusieurs étapes, mais oui. Vu que toutes les requêtes que tu veux faire dépendent de l’état du système, et que l’état complet est prouvée dans la chaîne, alors on peut faire toutes les requêtes.

Les noeuds doivent stocker tout cet état (ce qui est déjà le cas logiquement) et peuvent donc vérifier leurs pairs, et les clients peuvent demander des informations avec preuve infalsifiable.

Edit : pour tester vite fait, donne moi quelques requêtes (simples ou compliqués) et j’essaye de te donner les preuves qui seront dans l’arbre :slight_smile: Ca pourrait aussi nous permettre d’établir la liste des données à stocker dans cet arbre.

(En vrai si on part sur ça, ça va me demander de refaire une bonne partie de ma RFC pour avoir un truc bien foutu. Mais c’est pas grave, ça devient encore plus intéressant)

2 « J'aime »

A priori :

  • Est-ce qu’elle est dans la toile ou trop loin des sentries (outdistanced) au block N ?
  • Est-ce qu’elle est membre au bloc N ?
    • Répond à la question “est-ce qu’elle a été écrite en blockchain ?” avec la réponse “au block N avec la preuve merkle P”
    • Répond à la question “quelle est la liste des DU qui ont été générés par cette identité ?” avec pour chaque block N de génération, la preuve merkle P
  • Est-ce qu’elle est révoquée ?
  • Quelle est la liste des documents d’adhésion émis ? avec la réponse “aux blocks N avec la preuve merkle P” (y compris celles expirées)
  • Quelles sont les certifications émises ? (y compris celles expirées) avec la réponse “aux blocks N avec la preuve merkle P”
  • Quelles sont les certifications reçues ? (y compris celles expirées) avec la réponse “aux blocks N avec la preuve merkle P”
  • Quelles sont les sources de monnaie détruites ? avec la réponse “aux blocks N avec la preuve merkle P”

@kimamila : Ca t’intéresse cette problématique ? Tu vois d’autres preuves à demander à @nanocryk ?

  • On le stocke dans l’arbre d’état, et on le met à jour à chaque bloc.
  • On stocke dans l’arbre d’état la liste de tous les membres actuels, et pendant une certaines durée les membres qui ne le sont plus. On peut donc prouver qu’une identité est membre, si elle l’était durant cette durée, sinon elle n’est pas membre ou ne l’est plus depuis longtemps.
  • On stocke la somme en G1 des DU non consommés par chaque membre dans l’arbre d’état. Quand un bloc contient dans son changement d’état “création du DU”, le DU est ajouté à chaque membre. Quand un membre utilise comme source le DU, on peut l’enlever de cette somme.
  • On stocke la liste des documents d’adhésion en cours dans l’arbre d’état. Le client demande les documents et les preuves qu’ils sont dans l’arbre d’état.
  • On stocke la liste des certifications, ainsi que la liste des certifications émises et reçues par chaque membre dans l’arbre d’état. (on pourrait en enlever quand elles sont expirées depuis assez longtemps).
    Un client peut demander a un nœud de lui donner le document qui liste les certifications émises et reçues, ainsi que la preuve que ce document est dans l’arbre d’état. La mise à jour de ce document est faite quand des certifications sont données, reçues, expirent et sont vérifiées quand un nouveau bloc est reçu.
  • Au dessus.
  • On stocke dans l’arbre de changement d’état les sources de monnaie détruites, et on peut stocker dans l’arbre d’état les sources détruites pendant un certain temps.

En fait on peut stocker toutes les informations non déductibles d’autres informations dans l’arbre d’état, et chaque changement d’état est vérifié par tous les noeuds. Le nouvel état fait alors consensus et on peut recommencer. Il faut toujours stocker un certain nombre de blocs précédents en cas de fork, mais on peut oublier les blocs plus anciens.

Si c’est pas clair : je pense qu’on peut étendre l’idée proposée à toutes les informations de la monnaie, de sorte qu’elles soient toutes prouvable et reliées par la PoW. La racine de Merkle subit la condition de PoW (nombre de 0) et l’arbre suivant référence la racine du précédent. La structure de la blockchain est intégrée dans les arbres.

Edit : quand je dis “on stocke dans l’arbre d’état”, c’est bien “on stocke le hash”. Ce sont potentiellement des informations que les nœuds peuvent calculer, mais qui doivent être prouvable rapidement, on peut donc les inclure dans l’arbre.

1 « J'aime »

Finalement le hash du block courant d’un noeud est déjà une sorte de racine résumant l’ensemble de la blockchain correspondante, donc ça ne me choque pas, je pense qu’on peut merkeliser l’ensemble des évènements de la monnaie dans un seule grand arbre général :grinning:

2 « J'aime »

Presque, car là par construction on peut retrouver avec seulement quelques informations. On peut par exemple retrouver le hash avec la racine de l’arbre d’état (contenu dans l’ancien bloc), la racine de l’arbre de transformation, la racine du nouvel arbre (qui peut être retrouvée par n’importe quel noeud en appliquant les transformations sur l’état précédent), le nonce et la signature (de l’arbre de transformation par exemple).

Le documents complets (et qui prennent de la place) peuvent être communiqués a part, voir même pas pour un client. Ce dernier, pour être sur que le bloc est correct, pourra demander à plusieurs nœuds s’ils ont le même hash, et au cas où d’attendre la création des quelques blocs par dessus. Par contre pour qu’un nœud accepte le bloc, il doit recevoir le nouveau Merkle root et les documents, appliquer les transformations et vérifier qu’il obtient la même chose.

2 « J'aime »

Marrant, je voyais ça très différemment.

Les clients ont besoin d’afficher l’historique des transactions,des DU émis, de la monnaie détruite (y compris les très anciennes).
Je ne pense pas qu’il soit nécessaire de stocker dans l’arbre d’état les membres “qui ont été membre”. On peut y stocker tout les membres courant, ça suffit, non ?

Idem pour la destruction de monnaie. Il faut que l’évènement soit loggué dans un arbre de merkle pour un block donné, mais il ne faut pas que ça s’accumule. Sinon, l’arbre de merkle des destructions de monnaie va exploser (alors que l’objectif est justement d’alléger les noeuds en droppant complètement l’information de la BDD).

On stocke la somme en G1 des DU non consommés par chaque membre dans l’arbre d’état. Quand un bloc contient dans son changement d’état “création du DU”, le DU est ajouté à chaque membre. Quand un membre utilise comme source le DU, on peut l’enlever de cette somme.

En fait je m’auto répondais en parlant du DU. D’après moi, si le client peut obtenir une preuve merkle que “Alice était membre au block 28000”, il a juste à regarder le header du block 28000, vérifier si la preuve de Merkle est valide. Si l’arbre est valide, Alice a bien généré un DU au block 28000 (puisque ce block a généré un DU. Il faut d’ailleurs que l’info “génération de DU” soit dans le header pour ça).

En fait dans le header, j’ai l’impression qu’on peut avoir 2 types d’informations différentes :

  • Les évènements (“Destruction de la source de monnaie”, “Génération du DU de montant X”…)
  • Les états (“Telle identité est couramment membre”, “L’arbre des UTXO”,…)

La différence entre les deux est simple : un évènement fait qu’un ce qui est impacté ne peut pas revenir en arrière (la monnaie détruite est détruite pour toujours). Un état vient du fait qu’une identité qui n’est plus membre peut redevenir membre plus tard.

On en a discuter en private hier avec @nanocryk, je pense surtout que dans le niveau protocole il faudrait cesser cette histoire de destruction de monnaie et plutôt imposer un montant minimal de 1 G1 pour chaque output, la protection sera la même et les clients n’auront plus cette partie super chiante a gérer !

1 « J'aime »

Si on étant l’arbre de Merkle à toute la blockchain, non. L’idée est que l’on aura besoin de stocker les transformation d’état précédentes uniquement pour régler des forks. On a pu vérifier qu’on passait bien de l’état(t) à l’état(t+1) en appliquant les transformations, celles-ci ne sont plus utiles.

Si on stocke uniquement la date d’entrée (et potentiellement de fin) d’un membre dans la toile, alors ce n’est pas utile de stocker “Alice a bien généré un DU au block 28000”. Le bloc 28000 ne peut être valide que si 1 DU a été ajouté à son solde de DU non consommés, et ce pour tous les membres.

Un état c’est une liste de variable qui sont fixées à un temps t. Un évènement (ou transformation) c’est un procédé valide qui permet de passer à un état du temps t au temps t+1. Pour tes exemples je suis d’accord, mais il n’est pas nécéssaire de les stocker après application (sauf pour résoudre des forks) car l’état suivant contient les effets de ces transformations.

Pour permettre à des commerçant d’accepter des paiements de moins 1 G1 tout en se protégeant des spams, on peut autoriser les outputs inférieurs à 1 G1 ssi ils sont consommés par une autre transaction dans ce meme bloc qui lui à un output suppérieur à 1. Ainsi un commerçant peut récolter plusieurs paiements inférieurs à 1, et quand il en a assez les regrouper dans une seule transaction. Elles seront toutes dans la transformation, mais à la fin seule la transaction avec plus de 1 G1 sera concervée.

1 « J'aime »

La destruction gère aussi la rotation de la monnaie sur le temps long (tout ce qui est inférieur à 0.1 DU est détruit en réalité … n’est-ce pas @cgeek ? Enfin ça n’empêche pas d’interdire ces transactions aussi.)

On pourraient être perdues quand elles sont inférieures au montant minimum (décalage de la base).

1 « J'aime »

Oui évidemment, je parles du point de vue du client. Il ne vérifie pas la validité du block lui, il vérifie de l’inclusion des données dans le block.
Le client doit pour ça pouvoir vérifier :

  • Que tel block a généré un DU
  • Que telle identité était membre à tel block

D’autres options comme ci-dessous me semblent incorrectes :

  • Vérifier que le block contient des UTXO de DU pour l’identité donnée ne garantie pas que le DU a été créé à ce block là (on peut pointer sur le block N+10 et si le DU n’est toujours pas dépensé, les UTXO contiendront toujours le DU)
  • Vérifier que l’identité était membre avant le DU ne permet pas au client de savoir si l’identité était encore membre à la génération du DU. Et il n’est pas possible de d’envoyer une preuve disant “l’identité n’a pas quitté la WoT”

Il faut bien comprendre que le client ne travaille pas en mode flux, mais avec des historiques de données. Ce sera à la charge d’autres API comme GVA de founir les historiques. Mais pour les vérifier, le client doit avoir un moyen simple, en log(1), pour chaque information de vérifier sa validité historique dans la chaine. Et ça, le coeur du protocole doit l’offrir, sinon les performances sur les clients seront désastreuses.

EDIT : Pour le DU, en fait on a l’option suivante

Le header contient 2 informations, “Ce block génère un DU” et l’arbre des UTXO contient “Alice a généré un DU à ce block”.

Dans ce cas, le client sait que Alice a généré un DU à ce block donné.

Mais par exemple, ça ne permet pas de répondre à la question “Alice est outdistanced”. Un noeud pourrait répondre “Oui, elle est outdistanced”, en faisant référence à une transition passée, alors que depuis, son état a changé en “elle n’est pas outdistanced”.

Tiens, un autre problème de ce mode de validation : les noeuds peuvent mentir par omission.

Dans Bitcoin, ils ont le même problème. Lorsque les wallets SPV demandent au réseau l’historique des transactions, les noeuds aussi peuvent leur répondre par omission.


Bon, pour revenir au sujet de départ et se recentrer.

On peut avoir dans les headers l’état des outputs :

  • Contiennent les DU et les TX

On peut je crois faire de même pour l’état de la WoT :

  • L’état des membres (identité est membre + distancée ou non)
  • L’état des certifications

Le mode état ne peut être utilisé pour :

  • La destruction de monnaie

Les API clientes doivent enregistrer les historiques de manière distincte du coeur du noeud. Cette historique contiendrait :

  • Les DU générés par chaque identité avec la preuve de merkle associée (UTXO + Block générateur de DU)
  • Les transactions reçus et émises
  • Les certifications reçues et émises

Pour valider ces historiques et vérifier que personne ne ment, le client doit faire confiance à des noeuds anonymes. C’est une contrainte qu’on va définir afin de vous permettre de développer les fonctions de noeuds anonymes en toute sérénité.

Libre à l’utilisateur d’héberger son propre noeud ou de définir des noeuds de confiance.

1 « J'aime »

Oui je suis favorable a cette voie, car le mode historique est plus lourd que le mode flux et ça permettrais aux machines modestes type rpi de ne pas a voir a gérer ça. l’APi cliente serait une sorte de module duniter finalement :slight_smile: (qu’on installerait par défaut dans les releases comme le module web-ui mais qui serait désactivable pour les config modestes).

Non, cette information serait dans l’état et serait actualisé à chaque bloc, et vérifié par consensus.

Et du coup tu peux demander à d’autres noeuds, et ne plus compter sur ceux qui ne répondent pas. C’est d’ailleurs pour ça que je propose de stocker pendant un certain temps les membres qui ne sont plus membre, il est possible de le prouver et du coup on peux distinguer l’omission de la négation.

Tu réponds toi même au problème la aussi :wink:

Si, si l’arbre d’état contient la liste de tous les membres.

En mode flux ? C’est à dire ?

Bien sur que si. Quand il y a la transformation disant qu’on change de base (qui est obligatoire sous certains conditions) alors on supprime les sources trop petites. Tous les noeuds font ça, et obtiennent le même arbre.

1 « J'aime »

Oui ok, on est d’accord.

A vrai dire ça ne marche qu’à moitié, et durant un certain temps. Par exemple, pour la réception de transaction, un réseau malveillant pourrait répondre “non je ne la vois toujours dans aucun header”. Bref, l’attaque par omission, je crois qu’elle est inévitable dans ce modèle.

Oui je fais souvent ça quand on brainstorm :slight_smile:

Ok, parfait, on est aligné sur le concept.

Donc un merkleRoot dans les blocks qui contiennent un changement de base, afin de détruire les vieilles sources de monnaie. Et interdiction de transférer la monnaie sur les comptes dont les outputs sont trop petits. C’est plus cohérent comme approche.

Par contre ça implique un gros changement de protocole. Aujourd’hui, il y a déja des sources de monnaies détruites “sans raison”. Il faudra décider de ce qu’on en fait pour le protocole v11.

Bon globalement, on commence à s’aligner sur l’objectif, et ça me parait assez cohérent :slight_smile:

,

1 « J'aime »