# Prototype de GVA

**URL:** https://forum.duniter.org/t/prototype-de-gva/7688
**Category:** Duniter-v1
**Tags:** gva
**Created:** [18 October 2020 14:40 UTC](https://forum.duniter.org/t/prototype-de-gva/7688 "2020-10-18T14:40:53Z")
**Posts on this page:** 20
**Page:** 4

<div class="post-metadata">

### Author: ![poka](https://forum.duniter.org/user_avatar/forum.duniter.org/poka/32/6827_2.png) [@poka](https://forum.duniter.org/u/poka)
#### Post date: [17 December 2020 12:45 UTC](https://forum.duniter.org/t/prototype-de-gva/7688/62 "2020-12-17T12:45:45Z")

</div>

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 !

👍

---

<div class="post-metadata">

### Author: ![elois](https://forum.duniter.org/user_avatar/forum.duniter.org/elois/32/1541_2.png) [@elois](https://forum.duniter.org/u/elois)
#### Post date: [18 December 2020 20:08 UTC](https://forum.duniter.org/t/prototype-de-gva/7688/63 "2020-12-18T20:08:26Z")

</div>

> [@elois](#):
>
> `newBlockMeta` donne accès uniquement aux méta-données du bloc mais est mieux optimisée

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 🙂

---

<div class="post-metadata">

### Author: ![elois](https://forum.duniter.org/user_avatar/forum.duniter.org/elois/32/1541_2.png) [@elois](https://forum.duniter.org/u/elois)
#### Post date: [19 December 2020 19:38 UTC](https://forum.duniter.org/t/prototype-de-gva/7688/64 "2020-12-19T19:38:15Z")

</div>

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 🙂

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.

---

<div class="post-metadata">

### Author: ![poka](https://forum.duniter.org/user_avatar/forum.duniter.org/poka/32/6827_2.png) [@poka](https://forum.duniter.org/u/poka)
#### Post date: [19 December 2020 21:09 UTC](https://forum.duniter.org/t/prototype-de-gva/7688/65 "2020-12-19T21:09:45Z")

</div>

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 🙂

---

<div class="post-metadata">

### Author: ![elois](https://forum.duniter.org/user_avatar/forum.duniter.org/elois/32/1541_2.png) [@elois](https://forum.duniter.org/u/elois)
#### Post date: [19 December 2020 21:13 UTC](https://forum.duniter.org/t/prototype-de-gva/7688/66 "2020-12-19T21:13:58Z")

</div>

> [@poka](#):
>
> pouvoir récupérer le userID correspondant a une clé publique et inversement

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 🙂

---

<div class="post-metadata">

### Author: ![elois](https://forum.duniter.org/user_avatar/forum.duniter.org/elois/32/1541_2.png) [@elois](https://forum.duniter.org/u/elois)
#### Post date: [20 December 2020 12:26 UTC](https://forum.duniter.org/t/prototype-de-gva/7688/67 "2020-12-20T12:26:35Z")

</div>

2 messages ont été fusionnés à un sujet existant : [Formation «Comment contribuer à GVA»](https://forum.duniter.org/t/formation-comment-contribuer-a-gva/7879/3)

---

<div class="post-metadata">

### Author: ![kimamila](https://forum.duniter.org/user_avatar/forum.duniter.org/kimamila/32/185_2.png) [@kimamila](https://forum.duniter.org/u/kimamila)
#### Post date: [30 December 2020 14:56 UTC](https://forum.duniter.org/t/prototype-de-gva/7688/68 "2020-12-30T14:56:50Z")

</div>

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.

```auto
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 ?

---

<div class="post-metadata">

### Author: ![elois](https://forum.duniter.org/user_avatar/forum.duniter.org/elois/32/1541_2.png) [@elois](https://forum.duniter.org/u/elois)
#### Post date: [30 December 2020 15:04 UTC](https://forum.duniter.org/t/prototype-de-gva/7688/69 "2020-12-30T15:04:51Z")

</div>

> [@kimamila](#):
>
> Quel en est le sens ? Est-ce pour SSL ? Si oui, est-ce optionnel, ou bien y a t’il une autre lettre possible ?

Réponse message #14:

> [@elois](#):
>
> J’ai gardé les mêmes conventions que pour les autres types d’endpoint à une différence près : la couche TLS est explicitée par un `S`. Cela permettra à ceux qui le souhaitent de pouvoir fournir un endpoint sécurisé sur un autre port que 443 (via l’option `remoteTls`, voir doc).

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 😉

---

<div class="post-metadata">

### Author: ![kimamila](https://forum.duniter.org/user_avatar/forum.duniter.org/kimamila/32/185_2.png) [@kimamila](https://forum.duniter.org/u/kimamila)
#### Post date: [30 December 2020 15:10 UTC](https://forum.duniter.org/t/prototype-de-gva/7688/70 "2020-12-30T15:10:47Z")

</div>

> [@elois](#):
>
> J’ai gardé les mêmes conventions que pour les autres types d’endpoint à une différence près : la couche TLS est explicitée par un `S`.

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

---

<div class="post-metadata">

### Author: ![elois](https://forum.duniter.org/user_avatar/forum.duniter.org/elois/32/1541_2.png) [@elois](https://forum.duniter.org/u/elois)
#### Post date: [30 December 2020 15:16 UTC](https://forum.duniter.org/t/prototype-de-gva/7688/71 "2020-12-30T15:16:50Z")

</div>

> [@kimamila](#):
>
> avec un espace devant en plus, donc ? C’est volontaire ?

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.

---

<div class="post-metadata">

### Author: ![kimamila](https://forum.duniter.org/user_avatar/forum.duniter.org/kimamila/32/185_2.png) [@kimamila](https://forum.duniter.org/u/kimamila)
#### Post date: [30 December 2020 15:20 UTC](https://forum.duniter.org/t/prototype-de-gva/7688/72 "2020-12-30T15:20:47Z")

</div>

> [@elois](#):
>
> 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.

ok ca me va. merci

---

<div class="post-metadata">

### Author: ![kimamila](https://forum.duniter.org/user_avatar/forum.duniter.org/kimamila/32/185_2.png) [@kimamila](https://forum.duniter.org/u/kimamila)
#### Post date: [30 December 2020 16:14 UTC](https://forum.duniter.org/t/prototype-de-gva/7688/73 "2020-12-30T16:14:00Z")

</div>

> [@elois](#):
>
> Vous l’attendiez tous, voici la pagination de l’historique des transactions :

> [@elois](#):
>
> En outre, j’ai également rajouté le champ `both` permettant de paginer à la fois les tx émises et reçues dans une même liste :

Je viens de tester. Bravo c’est très rapide ! 🙂 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 ?

---

<div class="post-metadata">

### Author: ![elois](https://forum.duniter.org/user_avatar/forum.duniter.org/elois/32/1541_2.png) [@elois](https://forum.duniter.org/u/elois)
#### Post date: [30 December 2020 16:34 UTC](https://forum.duniter.org/t/prototype-de-gva/7688/74 "2020-12-30T16:34:20Z")

</div>

> [@kimamila](#):
>
> 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.

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

> [@kimamila](#):
>
> 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) ?

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.

> [@kimamila](#):
>
> 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 ?

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é 🙂

> [@kimamila](#):
>
> 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 ?

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 😉

---

<div class="post-metadata">

### Author: ![poka](https://forum.duniter.org/user_avatar/forum.duniter.org/poka/32/6827_2.png) [@poka](https://forum.duniter.org/u/poka)
#### Post date: [30 December 2020 17:03 UTC](https://forum.duniter.org/t/prototype-de-gva/7688/75 "2020-12-30T17:03:10Z")

</div>

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

```auto
{
  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 😉

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.

---

<div class="post-metadata">

### Author: ![elois](https://forum.duniter.org/user_avatar/forum.duniter.org/elois/32/1541_2.png) [@elois](https://forum.duniter.org/u/elois)
#### Post date: [30 December 2020 17:21 UTC](https://forum.duniter.org/t/prototype-de-gva/7688/76 "2020-12-30T17:21:12Z")

</div>

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

> **[Pagination | GraphQL](https://graphql.org/learn/pagination/#complete-connection-model)**

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.

---

<div class="post-metadata">

### Author: ![poka](https://forum.duniter.org/user_avatar/forum.duniter.org/poka/32/6827_2.png) [@poka](https://forum.duniter.org/u/poka)
#### Post date: [30 December 2020 17:27 UTC](https://forum.duniter.org/t/prototype-de-gva/7688/77 "2020-12-30T17:27:30Z")

</div>

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 «&nbsp;out of the box&nbsp;» !

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](https://github.com/zino-app/graphql-flutter/issues/144#issuecomment-751199197) à 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.

---

<div class="post-metadata">

### Author: ![kimamila](https://forum.duniter.org/user_avatar/forum.duniter.org/kimamila/32/185_2.png) [@kimamila](https://forum.duniter.org/u/kimamila)
#### Post date: [30 December 2020 18:45 UTC](https://forum.duniter.org/t/prototype-de-gva/7688/78 "2020-12-30T18:45:59Z")

</div>

> [@elois](#):
>
> 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é

`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.

---

<div class="post-metadata">

### Author: ![elois](https://forum.duniter.org/user_avatar/forum.duniter.org/elois/32/1541_2.png) [@elois](https://forum.duniter.org/u/elois)
#### Post date: [30 December 2020 19:11 UTC](https://forum.duniter.org/t/prototype-de-gva/7688/79 "2020-12-30T19:11:54Z")

</div>

> [@poka](#):
>
> 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.

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

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

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 😆

> [@kimamila](#):
>
> `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 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` ?

> [@kimamila](#):
>
> D’ailleurs, ca me fait penser à un autre filtre, qui me semble utile : `type: simple|complex|all`.

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

> [@kimamila](#):
>
> Dans ce cas, une requete sans le txAmount sera sans doute exécutée.

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 :

```gql
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 🙂

---

<div class="post-metadata">

### Author: ![kimamila](https://forum.duniter.org/user_avatar/forum.duniter.org/kimamila/32/185_2.png) [@kimamila](https://forum.duniter.org/u/kimamila)
#### Post date: [31 December 2020 12:48 UTC](https://forum.duniter.org/t/prototype-de-gva/7688/80 "2020-12-31T12:48:49Z")

</div>

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…

> [@elois](#):
>
> ```auto
> TxHistoryBc(direction: TxDirection! = BOTH, pagination: Pagination) {
> simple(pubkey: String!): [SimpleTx]!
> all(pubkeyOrScript: String!): [Tx]!
> }
> 
> ```

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.

---

<div class="post-metadata">

### Author: ![elois](https://forum.duniter.org/user_avatar/forum.duniter.org/elois/32/1541_2.png) [@elois](https://forum.duniter.org/u/elois)
#### Post date: [31 December 2020 14:33 UTC](https://forum.duniter.org/t/prototype-de-gva/7688/81 "2020-12-31T14:33:47Z")

</div>

> [@kimamila](#):
>
> 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) )

Ok donc la valeur du champ `amout` dépend du compte pour lequel on demande l’historique c’est ça ?

Par exemple pour une transaction où A envoie 2 à B et 3 à C : dans l’historique de A le montant est 5 et dans l’historique de C le montant est 3, c’est bien cela ?

> [@kimamila](#):
>
> 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.

Oui c’est vrai, mais selon le filtrage certains champs ont un sens où n’en ont pas. Or tous les champs doivent être fournis par le résolveur. Pour éviter cet écueils, il est possible de retourner une erreur lorsque un champ qui n’a pas de sens est demandé

[Previous page](https://forum.duniter.org/t/prototype-de-gva/7688.md?page=3)

[Next page](https://forum.duniter.org/t/prototype-de-gva/7688.md?page=5)
