Prototype de GVA

Ah, par contre il faut pouvoir retrouver la certification, donc plutôt certified: HashMap<PublicKey, u64>

Bien vu encore, donc là ça commence à sentir le roussi, c’est le signe qu’il faut changer de stratégie.

En fait je pense qu’on doit plutôt associer un nombre entier unique à chaque identité, c’est déjà ce que fait le module wotb avec le wotb_id (un u32).

Ça implique de stocker quelque part le nombre d’identités qui ont été créées mais ce serait bien plus propre.

Ainsi la collection certifications pourrait avoir pour clé un (u32, u32).

On aurait donc:

  1. Ajout collection certifications clé (u32, u32) valeur GvaCert { created_on: BlockNumber, written_on: BlockNumber }
  2. Ajout 2 champs id: u32 et certifiers: Vec<u32> à la struct GvaIdtyDbV1.
  3. Ajout collection certs_by_expire clé U64BE valeur Vec<(u32, u32)>

Ça nous ferait une empreinte de 20 octets par certif (je compte que id et pubkey) au lieu de 121 ou 165. En contrepartie on se prendrait 8 octets de plus par identité mais comme il y a par construction beaucoup plus de certifications que d’identité on est vraiment ultra gagnant niveau place avec cette nouvelle approche :smiley:

J’expérimente la réflexion en public sur le schéma de la DB, d’habitude j’y réfléchis seul, et la seule fois ou @tuxmain a modifié la DB on a eu cette réflexion en discussion privée. Je pense qu’on doit perdre à peu près tout le monde mais bon :slight_smile:

2 Likes

Ah, un nouvel obstacle apparaît : quand une certification expire, il faut pouvoir mettre à jour le certifiers de l’identité certifiée… donc il faut une collection idties_by_id ou mettre la pubkey du certifié dans GvaCertDbV1. :sweat_smile:

Aussi, comment l’indexeur récupère la durée de validité d’une certification ? Et l’expiration arrive quand HEAD.median_time > created_time + sig_validity, ou alors c’est written_time + sig_window ? ou les deux ?

Edit: nouveau problème, pour le revert :

  • du renouvellement d’une certification, comment on retrouve l’ancienne ?
  • de l’expiration d’une certification, comment on la retrouve ?

cindex stocke encore les certifications expirées, avec un champ expired_on, ce doit être pour ça. On peut donc ajouter un champ expired_on à GvaCertDbV1.

Reste à retrouver la certification avant renouvellement. Avec un champ last_written_on, pour pouvoir la retrouver dans l’index des blocs, et written_on resterait la valeur pour la première certification ?

Et pour éviter de s’encombrer avec trop de certifications expirées, on peut dans un second temps supprimer celles datant d’avant la fenêtre de fork.

C’est vachement compliqué en fait ! :face_with_head_bandage:

OUI je suis perdu, mais j’aime bien me perdre dans ces discussion, parfois je comprend un truc. Mais surtout je constate en permanance, que vous faites un boulot formidable pour améliorer le système, et ça j’adore.

3 Likes

Ça me parait le mieux, cet index inversé nous servira fortement plus tard pour remplacer les clés publiques par des id dans plein de données relatives à la wot. Il nous faut effectivement le lien pubkey <-> id dans les 2 sens, c’est le plus propre et le plus souple pour la suite :slight_smile:

Il faut qu’on lui fournisse les paramètres de la monnaie, ça je vais m’en charger :slight_smile:

C’est bien la date de création qui compte pour l’expiration, et pas la date d’écriture.
Tu feras plutôt le calcul expire_time = created_time + sig_validity :wink:

Il suffit de créer une collection expired_certs qui contient comme clé le numéro de bloc d’expiration (U32BE) et comme valeur (u32, u32, GvaCertDbV1).

À chaque apply d’un bloc, la clé U32BE(block.number() - MAX_ROLLBACK) doit être supprimée :slight_smile:

Oui c’est pour ça que je voulais qu’on discute d’abord du schéma de la DB ensemble, car c’est la partie la plus difficile, une fois qu’on à un schéma qui conviens, le reste c’est des formalités :wink:

1 Like

Suite à une demande de @HugoTrentesaux , j’ai ajouté la possibilité de requêter GVA en GET :slight_smile:

Il est donc désormais possible d’écrire sa requête graphql directement dans l’url, exemple :

https://g1.librelois.fr/gva?query={currentUd{amount}}

Pour permettre cela, j’ai été obligé de modifier le path du playground, car les requêtes GET redirigeais sur le playground.

Le playground est désormais servi sur le path /gva/playground : GraphQL Playground

Tant qu’à refondre les path, j’en ai profité pour servir les souscriptions sur le path gva/subscription, et rendre paramétrable uniquement le premier segment du path (/gva).

Étant donné un endpoint GVA, on sait désormais que les souscriptions sont accessibles sur le sous-path /subscription, cela permet de supprimer les endpoint de type GVASUB :slight_smile:

De la même façon, le playground est toujours accessible sur le sous-path /playground (relativement au endpoint GVA déclaré).

4 Likes

Super, ça va faciliter l’intégration de données directement dans les sites web sans passer par BMA.

3 Likes

Cool ! Du coup j’y penses, mais il serait possible de porter les requêtes BMA en GVA, dans Cesium. Comme Cesium v2 n’avance pas vraiment…

Ou alors ce qu’il serait chouette c’est que Gecko prenne en charge les certifications, etc. J’avoue que j’espérais avoir du relais côté client. Difficile de trouver du temps ces temps ci, pour moi.

2 Likes

@kimamila la gestion de la wot est prévu pour gecko v2 donc l’année prochaine oui :grin:

1 Like

L’année prochaine si on a le financement ADEME Ğecko — Résilience des Territoires ! Sinon probablement dans plus longtemps. Pour info @kimamila, je suis motivé pour aider poka sur Ǧecko autant que je peux :slight_smile:

2 Likes

Ah extra ! La relève ça fait du bien :slight_smile:
La c’est sûr que je suis en perm’ ! Mais le combat continue grâce à vous !

2 Likes

Un site web peut très bien faire des requêtes en POST, même depuis un formulaire. Je ne vois pas trop l’intérêt des requêtes en GET. De plus une requête en GET semble limitée à 8kb.

Du coup, ma question : est-ce qu’il est possible de faire des requêtes sur GVA avec des hashs (Automatic Persisted Queries (APQ)) ?

C’est en utilisant des clients Graphql comme Apollo couplé à des frameworks réactifs comme Vue ou React que l’on comprend tout l’intérêt de Graphql.
Par exemple, en faisant cette requête :

query User {
  user(name: "Thomas Piketty") {
    photo
    age
  }
}

Je vais pouvoir afficher la photo et l’âge de l’utilisateur. Si la requête doit être exécutée de nouveau, je vais pouvoir choisir différente option : utiliser le cache et ne pas refaire la requête, forcer un refetch, ou faire du SWR (Stale While Revalidate). Soit afficher les données du cache, mais refaire la requête en arrière-plan et actualiser si besoin.

De plus, avec un framework réactif, la réponse d’une mutation peut directement changer les données à l’écran car elles sont réactives :

mutation changeUserPhoto {
  user(name: "Thomas Piketty", _set: {photo: "https://..."}) {
    photo
  }
}

Comme la donnée photo est réactive, ça va automatiquement changer dans <img :src="photo" />. Si la mutation ne retourne pas la donnée photo, le cache Apollo ne sera pas mis à jour, et je serais obligé d’actualiser l’UI à la main.
C’est pas un super exemple. Sur un tableau de données c’est vraiment pratique. Si on modifie les données d’une ligne, pas besoin d’aller chercher la ligne dans tout le tableau pour mettre à jour l’UI, ça se fait tout seul ! C’est encore plus flagrant quand la mutation change beaucoup de données à l’écran.

De plus, Apollo sait optimiser les requêtes. Ici la 2ème ne sera pas exécutée car la réponse sera dans la 1ère requête :

# 1ère requête
query authorAndBook {
  book(isbn: "9780674430006") {
    title
  } 
  author(name: "Thomas Piketty") {
    name
    age
  }
}
query particularAuthor {
  author(name: "Thomas Piketty") {
    name
    age
  }
}

C’est expliqué en détail ici et c’est possible en utilisant le path (ici author(name: "Thomas Piketty")) d’une requête. Seulement, il n’y a pas toujours le même path pour la même donnée. Par exemple avec une query authors retournant Piketty. Du coup, il semble qu’Apollo cherche à optimiser en utilisant un ID.

Tout ça pour dire que je me pose la question de cette mise en cache sur certaines requêtes GVA :

  • idty() qui utilise pubkey: PubKeyGva! comme argument, mais qui ne renvoi pas le champ pubkey
  • balance() avec l’argument script: PkOrScriptGva!, pas de champ pubkey
  • wallets() idem
  • udsOfPubkey() qui a comme argument pubkey: PubKeyGva! mais qui renvoi en node UdGva issuer: PubKeyGva!
  • les types PendingTx et WrittenTx avec un champ issuers: [String!]!, ça devrait pas être PubKeyGva plutôt ?
  • Idem pour newBlocks()

@elois T’as déjà fait un boulot énorme. Te casses pas la tête là-dessus, c’est surtout pour faire la remarque sur ce système de cache. J’ai seulement joué dans le playground, pas encore utilisé avec Apollo. Il faut voir si ces inconsistances ont une influence sur le cache et les requêtes. Pour ça il faut tester et je n’ai pas encore eu le temps. Je te ferais remonter les problèmes quand je m’y mettrais…

Autre remarque, le cache utilise apparemment aussi le champ __typename. Certains serveur Graphql l’inclut automatiquement dans les réponses même s’il n’est pas demandé. Ça pourrait être bien de l’inclure par défaut ou d’avoir une option dans le header de la requête pour l’ajouter automatiquement du type X-Include-Typename: true

Aussi, tu as vu qu’il y avait pas mal de changement du côté de graphql-playground qui fusionne vers graphiql ?

Un script n’est pas forcément SIG(pubkey), ça peut être un hash, donc il faudrait retourner un script et non une clé publique.

Je n’ai pas compris l’intérêt d’inclure la requête dans la réponse… (à part dans un batch, si les réponses ne sont pas dans le même ordre que les requêtes)

2 Likes

Le problème était plutôt pour le cas spécifique de Zola qui gère les requêtes GET à la compilation mais pas les POST.

Il semble que async_graphql n’inclus pas les APQ, après je peux toujours le développer moi-même par-dessus, mais c’est pas dans mes priorités… EDIT: en fait si, ce n’est pas suffisamment mis en avant dans leur doc, mais il y a bien une extension APQ : ApolloPersistedQueries in async_graphql::extensions::apollo_persisted_queries - Rust

GVA est encore en plein développement, c’est normal qu’il y ai des inconsistances dans le schéma, quand le développement arrivera à maturité je corrigerai les inconsistances qui sont vraiment des inconsistances pour moi, ce qui n’est pas le cas de tout ce que tu soulèves, notamment le fait de ne pas renvoyer l’input c’est voulu car ça me semble du gaspillage inutile.

J’utilise async_graphql qui intègre son propre système de cache.

Je ne sais pas exactement quel est le fonctionnement interne du système de cache de async_graphql (il faudrait lire le code source pour ça). Mais je peux aussi développer mon propre système de cache pour centaines requêtes GVA gourmandes, je pense d’ailleurs que je le ferai, c’est très simple à développer :slight_smile:

Je ne sais pas si c’est le cas du cache d’async_graphql, mais si je développe ma propre ctouche de cache elle ne dépendra pas du champ __typename.

C’est async_graphql qui intègre un playground embarqué, j’ai pas la main la dessus, je vais pas forker async_graphql, j’ai déjà bien assez de codebase à maintenir :wink:

Pour les batchs GVA les réponses sont toujours dans le même ordre que les requêtes donc moi aussi je ne comprends pas l’intérêt d’inclure la requête dans la réponse.

1 Like

OK pour APQ. C’était pour savoir, c’est pas du tout prioritaire.

J’ai dû mal m’exprimer. Je ne parlais pas du tout du cache côté duniter, mais du cache côté client (navigateur ou app) ! Utiliser un cache des réponses graphql permet d’éviter de refaire une requête, ou de choisir la méthode comme faire du SWR. Ce cache permet d’accélérer l’UI en évitant de refaire une requête similaire, et de soulager le serveur en lui redemandant une requête qui a déjà était faite.
Avec des frameworks réactifs, l’interface dépend directement de ce cache. Les champs de la réponse d’une mutation permet de mettre à jour les données correspondantes dans le cache, et d’actualiser directement l’interface…

Il est donc important que les données renvoyées par le serveur graphql soient optimisées pour faciliter le cache côté client. L’article que je citais explique comment le cache d’Apollo s’y prend pour optimiser les données.
Aussi, Apollo federation permet de merger des apis graphql pour une architecture en micro-services. Le champ __typename est utilisé pour ça entre autre, pas seulement pour le cache client.

Bon, j’essayerais de faire une démo sur cette histoire de cache pour l’axiom-boat. Ce sera plus simple…

Chaque client peut être développé dans une stack différente et avoir des besoins bien différent.
Pour que les données renvoyées par le serveur soient optimisées pour faciliter le cache côté client, il faut faire des hypothèses forte sur ce que le client va devoir mettre en cache et de quelle manière.

Ma priorité étant que GVA permettent d’optimiser les clients Ğ1 (Cesium v2, Ğecko, Tikka, etc), c’est aux développeurs de ses clients Ğ1 de m’indiquer de quoi ils ont besoin pour que les traitements soient plus optimisés de leur côté.

@ManUtopiK si tu as un besoin spécifique concernant GVA dans le cadre d’un projet bien spécifique que tu développes et qui à besoin de GVA, dis-moi directement de quoi tu as besoin et pourquoi.
Là je ne comprends pas le but de tes messages, je n’arrive pas à identifier un besoin derrière, et ne vois donc aucune action concrète que je puisse faire pour y répondre :confused:

2 Likes

En fait si, ce n’est pas suffisamment mis en avant dans leur doc, mais il y a bien une extension APQ : ApolloPersistedQueries in async_graphql::extensions::apollo_persisted_queries - Rust

Je peux l’activer si ça vous semble pertinent, encore faut-il que les clients s’en servent :slight_smile:

2 Likes

Oui, désolé. J’ai eu des idées qu’il faut que je test avant de m’emballer…

Génial pour APQ ! Ben c’est tiptop async_graphql ! Voilà, il suffit d’en parler :slight_smile:
Pas besoin de l’activer pour l’instant, mais c’est bon à savoir !

1 Like