Prototype de GVA

En fait la doc existe déjà elle est généré automatiquement et accessible via chaque noeud GVA:

:slight_smile:

Je la trouve très pratique, c’est grâce à ça que j’implémente GVA sans soucis.

Et au moins on est sûr qu’elle est à jours, à chaque nouvelle version de GVA, tu refresh la page et la doc est strictement à jour!


Edit:
Il y a même une zone de description custom qui je suppose est écrite par Elois, ici « Generate simple transaction document ». Je suppose que ces descriptions pourraient être plus explicites à l’avenir pour expliqué plus en détail à quoi peut servir la requête si ce n’est pas assez clair.

Perso je trouve les noms de queries et mutations choisis par Elois déjà assez clair intuitivement, mais si on veut chipoter, le top du top serait qu’en cliquant sur une queries dans la doc, cela pré-remplisse un exemple exhaustif dans graphql playground pour l’exécuter en un clique. Mais là c’est plus de l’ordre du luxe, je sais pas si graphql playground permet ça.

Je sais que d’autres outils permettent de le faire, comme ici.

6 Likes

C’est génial avec ces 3 souscriptions ya tout pour faire des widgets à changement d’état pour y afficher en temps réel l’arriver des nouvelles transactions en attentes, puis validés, le nombre de membre, le montant du DU ect ect … Et à moindre frais !

:+1:

3 Likes

Pour simplifier l’utilisation de GVA j’ai fusionné les souscriptions newBlock et newBlockMeta. Le serveur choisi automatiquement la variante la plus optimisée en interne, donc utilisez newBlock dans tous les cas :slight_smile:

5 Likes

Je ne vais pas développer de nouvelles fonctionnalités sur GVA pour le moment.

Je vais lancer une formation «comment contribuer à GVA» début Janvier 2021, je sais déjà que @tuxmain @vit @1000i100 et @HugoTrentesaux sont intéressés.

Je suis en train de découpler le plus possible le code de GVA du reste du cœur pour que les futurs contributeurs de GVA n’aient pas à se soucier du cœur :slight_smile:

Mon but est de pouvoir me consacrer aux autres gros chantiers de Duniter et de laisser le développement de GVA à d’autres contributeurs. Je pense avoir implémenté suffisamment de fonctionnalités pour que les futurs contributeurs de GVA aient suffisamment d’exemples pour s’y retrouver.

6 Likes

D’accords,

Du coup je lance un appel à tout future contributeur de GVA, une requête qui me semble très utile et probablement pas très compliqué à implémenter (j’en sais rien en fait), serait de pouvoir récupérer le userID correspondant a une clé publique et inversement :slight_smile:

6 Likes

En effet c’est simple et c’est précisément pour cela que je ne l’ai pas fait.
J’essaye volontairement de m’abstenir de faire les taches trop simples, car ce sont des 1eres taches idéales pour de nouveaux contributeurs :slight_smile:

6 Likes

2 messages ont été fusionnés à un sujet existant : Formation «Comment contribuer à GVA»

Dans les endpoints GVA publiés sur ton noeud, @elois, je vois un S (après le préfix GVA) dont je ne trouve pas de trace.

GVA S g1.librelois.fr 443 gva
GVASUB S g1.librelois.fr 443 gva-sub

Quel en est le sens ? Est-ce pour SSL ? Si oui, est-ce optionnel, ou bien y a t’il une autre lettre possible ?

1 Like

Réponse message #14:

Tu peux proposer une autre convention, mais il faut que la couche TLS soit explicitée, afin que le client sache quel protocole il doit utiliser, sans avoir à faire d’hypothèse en fonction du port. L’API GVA n’étant pas réservée au monde du web :wink:

avec un espace devant en plus, donc ? C’est volontaire ?
Ca ne devrait pas etre GVAS plutot ?

Oui je trouve que c’est mieux décollé. Ça permet de séparer l’information relative à la nature de l’API de l’information relative à la couche de sécurité.

Je trouvais justement chiant et pas élégant avec BMA de devoir chercher les endpoint BMA et BMAS.
Si on travaille sur l’API T, ça me semble plus propre de pouvoir chercher tout les endpoint de type T, indépendamment du fait qu’il y est une couche TLS ou non.

1 Like

ok ca me va. merci

Je viens de tester. Bravo c’est très rapide ! :slight_smile: Cela promet de belles choses.

En revanche, je trouve étrange de devoir encapsuler le retour dans both, sent, etc. Ce n’est pas intuitif.

N’est pas plus simple, d’ajouter un paramètre optionnel à la requete (par exemple direction: all|sent|received) - all par défaut. Aussi, pour avoir un seul type d’objet de retour, pouvoir récupérer direction dans le retour.

Autre question, concernant la pagination : de ce que je comprends, il n’y a pas possibilité de trier comme on veut ? Ce sera toujours par block (=date) (et pas par montant, etc) ?

Dans le type de retour, n’est pas utile ajouter des fonctions d’aggrégation (sur chaque TX) ? Par exemple pour avoir le montant d’un TX ? En l’état actuel, je ne vois pas le gain par rapport à BMA (outre les performances) : le client devra parser les inputs/outputs pour afficher un montant.
Ou alors j’ai loupé un truc ?

1 Like

Pourquoi pas, j’ai codé ça comme cela me venait. Ça peut être refactoré par de futurs contributeurs :slight_smile:

Oui la pagination ne peut être ordonnée que selon l’ordre des clés utilisées pour le stockage. Si on veut ordonner selon un autre critère il faut créer une collection d’index dont la clé est le critère voulu et la valeur la clé de la donnée.
Ce serait un développement complexe à faire, rien d’impossible mais une complexité inutile s’il n’y a pas un besoin qui ne peut être comblé autrement.

Pour cela il faut définir ce que tu nommes «montant d’une TX», cette notion n’existe pas.
Il est tout à fait possible d’ajouter des «champs calculés», c’est même assez simple à faire, à condition d’avoir une définition non-ambiguë de ce qui est demandé :slight_smile:

BMA ne proposait pas de pagination sur l’historique des TX. Et donnait tous les champs même ceux dont tu n’a pas besoin. Il y a donc déjà 2 gains importants sur la user story «historique du compte».
Bien sur on peut encore faire mieux, GVA n’est qu’un prototype, des champs pourront être ajoutés par les futurs contributeurs de GVA :wink:

1 Like

Un format de requète d’historique qui me semble pertinent serait quelque chose comme ça:

{
  txsHistoryBc(
    pubkeyOrScript: "Do99s6wQR2JLfhirPdpAERSjNbmjjECzGxHNJMiNKT3P"
    direction: both
    pagination: { pageSize: 2, ord: DESC }
  )
  pageInfo {
    hasPreviousPage
    hasNextPage
    startCursor
    endCursor
  }
  result {
    pubkey
    amount
    comment
    writtenTime
    direction
  }
}

Avec un champ direction optionnel en déclaration, moins d’encapsulation pour le pageInfo et le resultat, la champ direction reçus pour chaque tx, le amount en centime de g1 directement sans avoir à parser les outputs, le champ pubkey étant soit l’issuer pour les tx entrantes soit le receiver pour les tx sortantes.

(avec éventuellement même les champs de pageInfo directement dans result avec tout le reste si c’est plus simple. Aussi le champ direction n’est même pas nécessaire dans result si GVA renvoi une valeur négative pour amount pour les tx sortantes)

Bien sûr je ne sais pas la complexité que ça engendre, ni la possibilité d’avoir des tx unitaires dans le cas de transactions complexes.


Ce n’est qu’une proposition, au cas où un éventuel contributeur de GVA passe par là et trouve ça pertinent/faisable :wink:

Après en soit ce n’est pas bloquant, c’est plus du raffinage.

@kimamila tu peux peut être proposer toi aussi un format de requète qui te semble pertinent.

Attention @poka ta proposition n’est pas conforme aux spécifications de graphql pour la pagination :

Les données sont nécessairement dans edges.node, la lib async-graphql est faite comme ça. Et ça permet également d’utiliser les lib coté client intégrant ces spec, c’est le cas de React par exemple.

1 Like

Ok oui c’est vrai, c’est le cas pour la lib GQL Dart que j’utilise en plus, même pour la pagination en infinite scroll ça fonctionne quasiment « out of the box » !

Bon j’ai encore des soucis sur l’affichage de cet historique, au bout de plusieurs pages ça revient plusieurs pages en arrière qui sont déjà passé, avant de continuer plus loins, mais c’est certainement dû à un pbm de parsing de mon côté je suppose …

Ma lib se comporte bizarrement là dessus, j’ai l’impression qu’a chaque pages chargé, plusieurs requètes sont faites et j’ai en retour toutes les transactions depuis le début, plus celles de la nouvelle page, c’est assez étrange. J’ai d’ailleurs commenté une issue à ce sujet sur la lib que j’utilise.

C’est l’inconvenant d’utiliser une lib pour gérer la pagination, on n’est pas tout à fait maitre de comment coder finement celle ci.

txAmount(PUBKEY) = SUM(INPUTS_FROM_SIG_PUBKEY) - SUM(OUPUTS_TO_SIG_PUBKEY)
ce qui correspond à la variation de la quantité monétaire sur le compte PUBKEY.

Cela fonctionne avec les conditions de unlock simples, évidemment (SIG(PUBKEY)).

D’ailleurs, ca me fait penser à un autre filtre, qui me semble utile : type: simple|complex|all.
Comme vu avec @tuxmain et @vit, les TX complexes (plusieurs conditions de unlock) seront affichables plutôt à part (quelque soit le client), dans un historique dédié. Dans ce cas, une requete sans le txAmount sera sans doute executée.

1 Like

Tu peux toujours gérer la pagination à la main si tu préfères :slight_smile:

Respecter des spec communes permet de laisser le choix, alors qu’utiliser un truc custom pas standard oblige les clients à gérer «à la main» :wink:

Perso je préfère investir du temps à apprendre à utiliser finement une lib qui gère beaucoup de choses à ma place, car elle gérera très probablement mieux qu’une implémentation perso à la main, et ça rendra mon code plus propre et mieux maintenable, car il gère moins de choses.

En contrepartie il faut que la lib en question soit bien documentée et finement configurable, sinon effectivement, autant le faire soi-même :laughing:

Cela ne fonctionne que pour les transactions mono-ussuer, mono-receiver, et dont tous les inputs viennent du compte SIG(issuer). Que devrait afficher ce champ dans tous les autres cas ? null ?

Ok reste à définir simple, je propose la définition suivante :

  • 1 issuer
  • Tous les inputs viennent du compte SIG(issuer)
  • 1 ou 2 outputs
  • Si 2 outputs :
    • 1 output vers un compte différent de SIG(issuer)
    • 1 output vers SIG(issuer)

Notez que cette définition inclut les transactions de change

Je trouve ça moche d’avoir un champ qui n’aura pas de sens dans certains cas. Le mieux serait que les tx simple fassent l’objet d’une requête à part, requête qui fournirait le champ amount.

Exemple :

TxHistoryBc(direction: TxDirection! = BOTH, pagination: Pagination) {
  simple(pubkey: String!): [SimpleTx]!
  all(pubkeyOrScript: String!): [Tx]!
}

Seul le type SimpleTx aurait le champ amount.
L’idée étant de faire en sorte que le système de typage assure que tous les champs exposés ont un sens, et qu’il est impossible de recevoir une réponse valide au niveau du typage mais n’ayant pas de sens, afin de limiter les effets de bord.

Si le champ amount est toujours exposé mais vaut null pour une transaction complexe. Le client va devoir gérer le cas où amount vaut null pour une transaction simple, cas impossible mais permis par le système de typage.

Un typage bien fait est un typage dont les contraintes correspondent aux contraintes métier :slight_smile:

2 Likes

Le champ amount est un simple différentiel, entre ce qui ce qui sort et ce qui entre. Les seuls cas où il peut valoir null, c’est dans le cas de condition avec des “OR” (ex: SIG(0) || SIG(1) )
Pour moi, le nombre de issuers en entrée et de outputs n’est pas important.
Par exemple, quand j’affiche dans Cesium les TX provenant de Remuniter, je fais le delta qui concerne le compte, et arrive donc à calculer le amount.

Si on mets null comme tu le proposes, alors ces TX ne pourront pas etre affichée simplement dans un historique des TX. Le client devra le calculer lui-même…

Je comprends ton exemple, mais le all(pubkeyOrScript) ne sera sans doute pas utile tel quel, car les clients voudront soit les tx simples, soient les complexes, mais rarement les deux à la fois (all).
Dans ton exemple, il manque donc un complex(...).

Dans tous les cas, même si GraphQL le permet, encapsuler les fonctions n’ai généralement pas utile.
Je trouve cela peut intuitif d’avoir 2 fonctions, l’une sous-l’autre.
I me parait plus lisible d’avoir une approche “classique”, avec un fonction paramétrée (la query) puis la structure retour. La structure retour n’utilisant des fonctions que pour préciser des formats ou des points précis.

De la même manière qu’on filtre sur la direction de la TX, on filtre sur son caractère complexe ou non.
Dans les deux cas, ca reste du filtrage.