Paiement simplifié avec GVA: génération du document transaction coté serveur

Non toutes les sources sont déjà exploitables. Mais s’il y en a plus de 40 il y a plusieurs aller-retour.

Pour rester KISS. Je sais pertinemment qu’il y a plus optimal, mais il est préférable d’avoir un algo quasi-optimal qui traite correctement tous les cas avec une complexité relativement faible qu’un algo totalement optimal qui explose la complexité de gestion de certains cas.

Mon but est de produire une codebase qui soit maintenable par mes successeurs, donc toute complexité non nécessaire est a évitée.

Toutefois pour le cas des paiements simples uniquement (1 seule pubkey qui envoie un montant à une seule autre pubkey) je peux modifier la constante à 46 :slight_smile:

4 Likes

Alors celle-là on me l’avait jamais faîte ! Si on modifie une constante c’est pas une variable ? :rofl:

Ok, je sors… :running_man:

2 Likes

Voila qui est implémenté, le commit : [feat] gva:gentxs: use pending outputs on mempool for inputs search (97659203) · Commits · nodes / typescript / duniter · GitLab

Il est donc désormais possible d’envoyer un gros montant via le paiement simplifié de GVA, voici comment faire :

  1. Demander la génération du/des documents transaction·s comme avant, si les 46 premières sources ne suffissent pas, des transactions de change seront générées:


  1. Signer puis soumettre la ou les transaction·s de change :

  1. Refaire la requête d’origine avec le paramètre useMempoolSources à true:

  1. Soit vous avez enfin la transaction finale (c’est le cas dans mon exemple), soit il faut recommencer les étapes 2 et 3 autant de fois que nécessaire :slight_smile:

Voilà il est désormais possible d’envoyer tout montant par paiement simplifié GVA (sous réserve d’avoir un solde suffisant).

2 Likes

Joli travail !

Est-ce que ce ne serais un bug ici, le document généré contient le commentaire “change” mais ne semble pas contenir de transaction de change ?
L’output est de 46736 au lieu de 47000, sans change. (dernier persion proto GVA, sur mon noeud comme sur le tiens) :

Généré avec:

{
  genTxs (
    amount: 47000
    issuer: "Do99s6wQR2JLfhirPdpAERSjNbmjjECzGxHNJMiNKT3P"
    recipient: "AhEDcWnSW4SdzidsDYhnDfs75DBpKQKDgHzJzrXdMmB9"
    comment: "Test de change !!"
  )
}

Je constate qu’en passant le amount de 47000 à 47800, le document reçus contient bien la transaction de change:

1 Like

Et pourtant sur ta screen on voit bien la transaction de change, tout fonctionne comme attendu, je ne comprends pas ce qui te chiffonne ?

Non ce que tu vois c’est juste un changement du nombre de transactions de change (2 au lieu de 1) :slight_smile:

Ok c’est que je n’ai pas dû bien comprendre comment sont gérés ces transactions de change.

J’ai compris la nécessité des 2 transactions dans le seconds cas car je passe de 46 à 48 sources, donc du premier palier au seconds.

Mais je n’ai pas compris comment identifier les transactions de changes alors, la seul différence que je vois c’est que le output n’est pas à la hauteur du amount lorsqu’il y a du change.

Entre un amount à 47000 et 47500 les documents générés sont strictement identiques (hormis le blockstamp bien sûr).

C’est qu’il va fusionner les 46 sources en une seul c’est ça, donc au deuxième essai on est sûr de n’avoir besoin que de cette nouvelle grosse source et quelques autres ?

(Je cherche dans la RFC je ne trouve pas …)

Dans le premier cas tu as besoin de 47 sources pour envoyer le montant désiré. Comme ce n’est pas possible directement (le max étant 46). Il est donc nécessaire de compacter une partie des sources pour réduire le nombre de sources afin que l’envoi devienne possible :slight_smile:

En effet c’est une manière de les différencier. Mais le plus simple c’est de regarder le destinataire du output, ce qui caractérise une transaction de change c’est le fait que le receveur soi le destinataire :wink:

Exactement :smiley:

Normal ce n’est pas protocolaire. Le protocole défini les règle à respecter, ce n’est pas son rôle de dire comment coder une implémentation en fonction de ce que l’on veut faire (ici envoyer un gros montant avec beaucoup de petites sources).

2 Likes

Ok merci c’est limpide :slight_smile:

En plus je le savais, j’ai dû traiter ce cas lorsque j’ai codé g1stats …

En plus j’avais un moyen simple de m’en rendre compte avec mon proto-client actuel lol

1 Like

Le document peut également être corrompu à cause d’un bug. Inviter directement à ne plus faire confiance me semble excessif et flou.
Tu pourrais par exemple écrire:

«La transaction générée par le serveur “g1.domaine.tld” semble incorrecte. Le serveur “g1.domaine.tld” est peut-être bugué ou malveillant, merci de signaler ce problème sur le forum Duniter en copiant le rapport d’erreur ci-après. En attendant une réponse, utilisez un autre nœud Duniter. »

Puis tu génères un rapport d’erreur qui peut être la diff entre l’attendu et le constaté.

Ce qui aurait l’avantage de nous permettre d’être alerté rapidement en cas de présence d’un nœud malveillant sur le réseau et d’impliquer les utilisateurs dans la détection des bugs :slight_smile:

3 Likes

Je crois savoir la raison du comportement qui va suivre mais dans le doute je l’explique quand même.
J’ai commencé par envoyer 100Ḡ1 sur une nouvelle clé: Dz64d7msKK2LvSJE9DM4c8oAgRvrKjh1wPY88fnmbQav

Ensuite une fois la transaction validé en blockchain, j’ai voulu envoyer des suites de transactions de 1Ḡ1 depuis cette clé vers une autre clé.

J’ai pu en envoyé une, puis à la seconde GVA me répondait insufficient balance.
5 minutes plus tard j’ai réessayé toujours 1Ḡ1, ça marche, puis de nouveau une 1Ḡ1 de nouveau en échec pour la même raison.

La seconde bonne transaction était visible en attente immédiatement sur Cesium, puis à finit en échec quelques minutes plus tard.

Je suppose que c’est parceque la seule source étant de 100Ḡ1, lors de l’envoi de 1ḡ1 le noeud a effectué une transaction de change de 99ḡ1 ? Du coup tant que la transaction de 1Ḡ1 n’est pas validé je ne peux pas consommer le reste de la source ?

Une transaction valide détruit des sources (UD ou UTXO) et génère des UTXO.

UTXO : Unspent TXransaction Output.

La somme des sources entrantes doit être égale à la somme des UTXO sortantes. Dans la situation que tu décris, il y a 1 source de 10000 qui va être sépaéré : 1UTXO de 100 vers le destinataire et 1 de 9900 vers l’émetteur. Le 2e UTXO est le backchange : la tx “rend la monnaie”.

C’est ce backchange qui va être utilisé comme source pour la tx suivante. Mais tant qu’il n’est pas en BC, il est dans la pool. (edit- c’est la tx qui est en pool, pas le backchange seul). Donc je suppose que tu dois passer le paramètre useMempoolSources à true pour pouvoir envoyer une 2e tx de suite.

(Je ne sais pas si useMempoolSources autorise l’utilisation de sources en piscine, ou s’il oblige à utiliser uniquement des sources en piscine)

4 Likes

Oui @matograine à bien répondu, le comportement que tu observes est tout à fait normal @poka :slight_smile:

useMempoolSources autorise l’utilisation de sources en piscine, comportement désactivé par défaut pour 2 raisons :

  1. Pour des raisons de performances.
  2. Pour éviter de faire grimper la profondeur de chaînage des transactions au-delà du nécessaire, ce qui aurait pour conséquence de retarder certains paiements pour rien.
2 Likes

Parfois sur certaines transactions passant par une étape de change, le document final renvoyé par GVA ne semble pas générer un backchange correct:

$ ./pay.py -d AhEDcWnSW4SdzidsDYhnDfs75DBpKQKDgHzJzrXdMmB9 -c "GVA: $(date '+%d-%m-%y - %H:%M:%S')" -m 70000 -v
Le document contient une transaction de change
Le document généré est conforme.
Echec de la transaction:
Not same sum of inputs amount and outputs amount: (SourceAmount([0, 0, 0, 0, 0, 1, 136, 238, 0, 0, 0, 0, 0, 0, 0, 0]), SourceAmount([0, 0, 0, 0, 0, 2, 191, 211, 0, 0, 0, 0, 0, 0, 0, 0])).
Version: 10
Type: Transaction
Currency: g1
Blockstamp: 374815-0000002B54A002AEC8229C672CB8F7DFF4FA727C0725251010CC10DC8B8AE0B6
Locktime: 0
Issuers:
Do99s6wQR2JLfhirPdpAERSjNbmjjECzGxHNJMiNKT3P
Inputs:
43950:0:T:8B37338D7807E58AA55FA1D5121E95C7E1CC52555486C2E8C1C008E15D552F4C:1
56640:0:T:BBA1724A2191B53FDB0474662DB69B3328C1937510968F7A0B2105C19D8821A9:0
Unlocks:
0:SIG(0)
1:SIG(0)
Outputs:
70000:0:SIG(AhEDcWnSW4SdzidsDYhnDfs75DBpKQKDgHzJzrXdMmB9)
110179:0:SIG(Do99s6wQR2JLfhirPdpAERSjNbmjjECzGxHNJMiNKT3P)
Comment: GVA: 19-11-20 - 18:24:30
Pc26+B9/PJosgSlSYL2S58aMLkoUg9ntbOGq6l6cS+VO0bPkex8emunhH/s23GZ5IGYDMPzn1cFmrZ4gmqIsBg==

En effet ici le backchange devrait être de 30590 hors il est de 110179, soit plus que le total des inputs qui est de 100590.

Rejouer la même transaction une seconde fois manuellement fonctionne.

Est-ce un bug ou encore une fois une mauvaise compréhension/implémentation de ma part ?

:thinking:

1 Like

Merci beaucoup pour tes tests @poka, cela m’aide énormément :blush:

Bien joué, tu viens de déceler un bug dans le calcul du montant du backchange, je viens de commiter un correctif :slight_smile: (je n’ai pas encore maj mon serveur par contre, je ne peux pas le faire de suite)

4 Likes

Aaaah j’ai enfin relevé un bug j’y croyais plus :joy:

Ok j’ai mis à jour mon noeud, je vais continuer mes tests.

6 Likes

Je n’arrive plus à faire de transaction avec GVA depuis la dernière mise à jours (commit 7961e589e16423079c9c9a2e8536b3e8c16aaa42), les documents générés semblent ne plus comporter les backchanges:

./pay.py -d ERQJAWCvDoDus3tzUuz8vZ2jutEiZ1z4UZhYxBbbEr9T -c "GVA: $(date '+%d-%m-%y - %H:%M:%S')" -m 20
Version: 10
Type: Transaction
Currency: g1
Blockstamp: 665155-000010EC2B9956A299EB6855D0D942C006C398037F706B4842BC7C73E7B1E32E
Locktime: 0
Issuers:
CrznBiyq8G4RVUprH9jHmAw1n1iuzw8y9FdJbrESnaX7
Inputs:
1000:0:D:CrznBiyq8G4RVUprH9jHmAw1n1iuzw8y9FdJbrESnaX7:1
Unlocks:
0:SIG(0)
Outputs:
20:3:SIG(ERQJAWCvDoDus3tzUuz8vZ2jutEiZ1z4UZhYxBbbEr9T)
Comment: GVA: 26-11-20 - 02:44:37

Aussi je remarque que lorsque le montant de la transaction est exactement égal à la source sélectionné, GVA va piocher une seconde source en input, alors que cela semble inutile:

./pay.py -d ERQJAWCvDoDus3tzUuz8vZ2jutEiZ1z4UZhYxBbbEr9T -c "GVA: $(date '+%d-%m-%y - %H:%M:%S')" -m 1000
Version: 10
Type: Transaction
Currency: g1
Blockstamp: 665155-000010EC2B9956A299EB6855D0D942C006C398037F706B4842BC7C73E7B1E32E
Locktime: 0
Issuers:
CrznBiyq8G4RVUprH9jHmAw1n1iuzw8y9FdJbrESnaX7
Inputs:
1000:0:D:CrznBiyq8G4RVUprH9jHmAw1n1iuzw8y9FdJbrESnaX7:1
1000:0:D:CrznBiyq8G4RVUprH9jHmAw1n1iuzw8y9FdJbrESnaX7:2
Unlocks:
0:SIG(0)
1:SIG(0)
Outputs:
1000:3:SIG(ERQJAWCvDoDus3tzUuz8vZ2jutEiZ1z4UZhYxBbbEr9T)
Comment: GVA: 26-11-20 - 03:19:21
2 Likes

Ce qui m’étonne, c’est que tes output sont en unitbase 3 alors que les TX sont sur g1 (où on est en unitbase 0)

1 Like

A vrai dire je ne sais pas ce que cela signifie…

Mais je suis sur la gtest, je suppose que ca a son importance.

Non ce n’est pas depuis la dernière mise à jours, c’est depuis toujours. Les bases > 0 ne sont pas encore gérées. Tu verras que ça fonctionne toujours nickel sur la Ğ1.

Je travaille sur la gestion des bases ce soir :wink:

Concernant le nom de la monnaie c’est le nom dans le fichier conf.json qui est utilisé, ou “g1” si le nom n’est par renseigner. Faut que je récupère le nom de la monnaie depuis la blockchain. Donc la aussi pas de régression, juste des subtilités pas encore gérées :wink:

1 Like

Ok j’aurais dû me douter que le soucis ne se présentait que avec la gtest.

En fait je ne test plus avec la g1 parceque passer de l’un à l’autre sur mon PC est très fastidieux, la sync rends mon PC inutilisable pendant plus d’1h. Ou alors il faudrait que je sync les 2 dans deux home différents.

Pour les bases, si je comprends bien ce n’est pas vraiment une base (base2 base10 base16 base58) mais un coefficient diviseur ?