Dev / transaction process / usage

Petite compilation des discussions pour “entrevoir” comment mettre en oeuvre une requête pour faire une transaction :fearful::

A envois 10 unités a B <=> accrochez vos ceintures : operation ninjaaa :fist_left: :facepunch: :fist_right:

KA = pubkey de A
KB = pubkey de B
M = 10 = montant de la transaction
TX = document de transaction


Le temps de traitement d’une transaction en blockchain est approximativement de 5 à 30 minutes.


Soit établir le processus suivant pour realiser une transaction :scream:

requête sur /tx/sources/KA => retourne les sources
traitement des sources pour composer TX
requête sur /tx/process avec parametre TX => retourne l’enregistrement de TX
requête sur /tx/history/KB => retourne l’historique des transactions de KB


  1. requête sur /tx/sources/KA => retourne les sources

.duniter/doc/HTTP_API.md at master · duniter/duniter · GitHub

Le montant total des sources c’est le solde du compte.

définition d’une source dans la doc - des key/values associées ?
déduction personnelle des keys/valeurs :

identifier = KA
type = D ou T .duniter/doc/Protocol.md at master · duniter/duniter · GitHub
conditions = fonction de (dé)vérrouillage, ex: SIG(KA)

noffset = " un numéro de block pour un Dividende, un id dans la liste des outputs"
“num_block” <=> type = D, accessible via blockchain/block/num_block,
“id dans la liste des outputs” <=> type = T , indexage dans la liste des inputs d’un TX précèdent que Duniter a traité ?

amount = montant
base = valeur de l’exposant (base = 0 , 1 , 2 …)

Pour écrire 10 unités :
10 (amount) et base (0) => 10 * 10^0 = 10
1 (amount) et base (1) => 1 * 10^1 = 10

La base peut augmenté pour 2 raisons :
1 : le dividende a augmenté et est passé dans une base supérieure
2 : un TX de base courante a aboutie en un TX de base supérieure
.Thought about big numbers - #2 by cgeek

Les montants sont en centimes donc 10000 cents = 100 g1 sur cet exemple:
AMOUNT:BASE:CONDITIONS
10000:0:SIG(TEN…vp1mS)

une pubkey qui possède moins de 1.00 Ğ1 en base courante voit son montant = à 0 (pour limiter l’inflation de la BDD aussi)

choisir les sources par rapport au montant de sortie
par exemple : si envois de 5 en base 0, ne pas prendre une source [ 1 * 10^1 ]
si tu dois envoyer quelque chose en base 0, ne pas prendre des inputs en base 1…
par contre pour envoyer quelque chose en base 1, tu peux prendre des choses en base 0 et 1

:tired_face:


  1. traitement des sources pour composer TX

définition du format de TX
.duniter/doc/Protocol.md at master · duniter/duniter · GitHub
.duniter/doc/Protocol.md at master · duniter/duniter · GitHub

Locktime : Integer, “waiting delay to be included in the blockchain”
dans les exemples, locktime = 0, valeur de base pour usage “simple” de TX ,
son utilisation est a mettre en relation avec la fonction XHX au regard de ce post
.[DAB, printing rules] How about fuduciary money? - #9 by Inso

Blockstamp : BLOCK_UID, définition : .duniter/doc/Protocol.md at master · duniter/duniter · GitHub
“prendre un block valide de la chaine, en général le block courant
(ça permet de dater la transaction vis à vis de la chaine de block et d’éviter les attaques type anti datage)”

déduction personnelle :
effectuer une requete /blockchain/current => retourne infos du dernier block
.duniter/doc/HTTP_API.md at master · duniter/duniter · GitHub
inner_hash = ?
hash = ?

définition du block:
.duniter/doc/Protocol.md at master · duniter/duniter · GitHub
InnerHash = The hash value of the block’s inner content
BlockHash = Hash from InnerHash: to SIGNATURE

déduction personnelle : d’apres la déf du block, BLOCK_UID, remplir le champ Blockstamp avec la valeur contenue par la clé “hash”.

définition inputs:
.duniter/doc/Protocol.md at master · duniter/duniter · GitHub

définition outputs:
.duniter/doc/Protocol.md at master · duniter/duniter · GitHub

définition unlocks:
.duniter/doc/Protocol.md at master · duniter/duniter · GitHub

4 fonctions de lock/unlock :
SIG(PUBLIC_KEY), XHX(SHA256_HASH), CLTV(INTEGER), CSV(INTEGER)

SIG This function is a control over the signature
XHX This function is a password control
CLTV This function locks an output in the future, which will be unlocked at a given date
CSV This function locks an output in the future, which will be unlocked after the given amount of time has elapsed.

La liste “inputs” représente les TX précèdents de KA
La liste “outputs” représente les informations à générer, traiter par les TX suivants
La liste “unlocks” represente les fonctions de déverrouillage des inputs


  1. requête sur /tx/process avec parametre TX => retourne infos de l’enregistrement d’une transaction

.duniter/doc/HTTP_API.md at master · duniter/duniter · GitHub ← exemple du retour de l’envois de TX [ bien formaté, (pas pour autant validée par la blockchain ) ?:thinking: ].

quid du retour de la requete si TX erroné ?
ce pour ces raisons:

mal formaté : revenir à étape 1 / 2

bien formaté : je suppose devoir se réferer à l’etape 4
=> dont le montant est invalide >>> KA ne peut pas transférer 100 unités si il ne possède que 50 unités
=> dont KB est erroné >>> KA perd ses unités
=> dont KA est erroné >>> il ne va rien se passer


  1. requête sur /tx/history/KB => retourne l’historique des transactions de KB

.duniter/doc/HTTP_API.md at master · duniter/duniter · GitHub

permet a KB de voir l’historique de son portefeuille enregistré en blockchain
et de vérifier si TX est validé par la blockchain.

sent = transaction que KB a envoyé (validé !?)
received = transaction que KB a reçu (validé !?)
sending = transaction que KB a envoyé ( non traité [et / ou non validé ] par la blockchain !?)
receiving = transaction que KB recoit ( non traité [et / ou non validé ] par la blockchain !?)


:see_no_evil:

Tu aime le serpent :snake: => :ok_hand:
.https://github.com/duniter/silkaj/blob/master/src/tx.py#L176-L190
.sakia/src/sakia/services/documents.py at master · duniter/sakia · GitHub
.https://github.com/duniter/silkaj/blob/master/src/tx.py

Tu es arrivé jusque la => :clap:


j’ai hâte du jour où :
/sendTX/tx?src=KA&dest=KB&amount=M
@kimamila ?
:joy:

1 Like

Alors pour préciser :
Si type=D : la source est un dividende universel
identifier : clé publique du créateur (bah oui un DU c’est une création de monnaie)
noffset : numéro du bloc de création du DU
Si type=T : la source est un output d’une transaction précédente
identifier : hash du document transaction dont est issue cette source
noffset : position de cette source dans les output de la transaction qui l’a générée.

Oui c’est exact il faut bien prendre hash et pas inner_hash :slight_smile:

Ben non, si tu a le retour positif c’est juste que le nœud duniter a bien enregistrer ta TX, mais pour qu’elle soit en blockchain il faut qu’il l’écrive dans un block ou qu’il la propage (la tx) a un autre noeud qui lui l’écrira dans un block, d’ou le délai de 5 à 30 min, c’est le temps qu’il faut pour qu’un nœud qui à bien enregistrer ta TX dans sa piscine trouve un block.

Alors tx/history te donne les données en blockchain donc si la transaction s’y trouve c’est qu’elle a déjà été validée. Quand aux champs sending et receiving il sont toujours vide j’avoue ne pas savoir a quoi ils servent.

En revanche pour les transactions en attente donc bien reçus mais pas encore en blockchain ça se passe dans pending tu peut d’ailleurs utiliser l’url tx/history/:pubkey/pending pour ne récupérer que les transactions en attente :wink:

Apres relecture, j’ai trouvé mon interrogation stupide,
Apres reflexion, je l’ai trouvé pas aussi bête, ce a cause des websockets et la capacité de maintenir la connexion ouverte, soit , malgré les 5min de délais, pourquoi pas ? si j’ai une tite chance que ma TX soit validé par la blockchain et d’être prevenu aussitôt…

Returns : The recorded transaction
J’eusse apprécié : The recorded transaction into the pool for processing

… et qui découle de la fonction cachée qui me manque pour terminer le boulot :

AHAHH !!! :stuck_out_tongue_closed_eyes:
Pris la main dans le sac !!!:hugs:
doc?
sinon rien d’autres dans les poches vis a vis de :

???:face_with_monocle: :yum:

Alors ça c’est pas documenté mais c’est dans le code (ça mériterait effectivement sa page de doc) :

Tu as ici toutes les erreurs que tu peux obtenir sur une requête Duniter. Celles qui concernent une tx sont :

WRONG_UNLOCKER:                       { httpCode: 400, uerr: { ucode: 2013, message: "Wrong unlocker in transaction" }},
LOCKTIME_PREVENT:                     { httpCode: 400, uerr: { ucode: 2014, message: "Locktime not elapsed yet" }},
SOURCE_ALREADY_CONSUMED:              { httpCode: 400, uerr: { ucode: 2015, message: "Source already consumed" }},
WRONG_AMOUNTS: { httpCode: 400, uerr: { ucode: 2016, message: "Sum of inputs must equal sum of outputs" }},
 WRONG_OUTPUT_BASE: { httpCode: 400, uerr: { ucode: 2017, message: "Wrong unit base for outputs" }},
TX_INPUTS_OUTPUTS_NOT_EQUAL:          { httpCode: 400, uerr: { ucode: 2024, message: "Transaction inputs sum must equal outputs sum" }},
TX_OUTPUT_SUM_NOT_EQUALS_PREV_DELTAS: { httpCode: 400, uerr: { ucode: 2025, message: "Transaction output base amount does not equal previous base deltas" }},
TX_INPUTS_OUTPUTS_NOT_EQUAL:          { httpCode: 400, uerr: { ucode: 2024, message: "Transaction inputs sum must equal outputs sum" }},
TX_OUTPUT_SUM_NOT_EQUALS_PREV_DELTAS: { httpCode: 400, uerr: { ucode: 2025, message: "Transaction output base amount does not equal previous base deltas" }},
MAXIMUM_LEN_OF_OUTPUT:                { httpCode: 400, uerr: { ucode: 2032, message: 'A transaction output has a maximum size of ' + MAXIMUM_LEN_OF_OUTPUT + ' characters' }},
MAXIMUM_LEN_OF_UNLOCK:                { httpCode: 400, uerr: { ucode: 2033, message: 'A transaction unlock has a maximum size of ' + MAXIMUM_LEN_OF_UNLOCK + ' characters' }},
WRONG_CURRENCY: { httpCode: 400, uerr: { ucode: 2500, message: 'Wrong currency' }},
``

En fait même si ta tx se retrouve direct dans le prochain block et que tu la voit de suite ça ne te donne pas plus de certitude sur la validation définitive de la transaction a cause des possibilités de roll back, donc si j’intégrer le paiement en g1 sur un site je ne fournirai définitivement la prestation que si la tx est dans un block a plus de 6 du bloc courant, il suffit d’une tache cron qui check la blockchain toute les heures et c’est bon :wink:

merci de l’eclairage, ca fait sens avec le document que je souhaite vous partager =)

Je ne comprends pas bien le sens, ici. Tu veux déléguer la signature de la TX ??

En revanche, il me parait plus sage d’avoir une fonction de création du document de TX (sans signature).
Ainsi l’appellant peut vérifier (par exemple, les destintaires, le montant, etc.) puis signer et renvoyer le tout.

Cela économise au moins la création du document, qui effectivement nécessite normalement d’avoir les sources.
Par exemple, pour une terminal de paiement “idiot”, qui n’effectue qu’une signature.

Je vais revenir sur le processus concernant la signature et son implémentation qui me pose problème.:dizzy_face:

Donc,

“La génération du document de transaction n’est pas une étape sensible” => OK
“C’est seulement et uniquement la signature du hash sha256 du document de transaction … la “carte” soit capable de calculer la signature d’un hash sha256…”

Soit,
je lis la documentation concernant le “format valide” d’un document de transaction :
.duniter/doc/Protocol.md at master · duniter/duniter · GitHub

concernant les transactions :
.duniter/doc/Protocol.md at master · duniter/duniter · GitHub
“A transaction must have signatures matching its content for each issuer”
“matching” des clés publiques => OK, par contre… “Signatures are made over the transaction’s content, signatures excepted”

"Les signatures sont faites sur le contenu de la transaction,
excepté les signatures " <= ???:face_with_raised_eyebrow:

je dispose également d’examples pour générer un document valide dans cette page.

je dispose de la documentation concernant le RETOUR d’un appel à => tx/process :
.duniter/doc/HTTP_API.md at master · duniter/duniter · GitHub

(au passage, je vois qu’il y a des signatures dans cette réponse…)

requête où il est stipulé en parametre
transaction : the raw transaction
soit => “Version:10\r\n…\r\n”


Maintenant, je ne comprends pas l’utilisation, ici, dans le cadre de la signature, de ces fonctions cryptographique (en l’occurence sha256 mais peu importe…).

Pour moi, une telle fonction prend en paramétre 1 seule information
et me retourne le resultat haché.
exemple sur mon poste :
sha256sum(“abcdef”) = ae06…a57

$>echo “abcdef” | sha256sum
ae0666f161fed1a5dde998bbd0e140550d2da0db27db1d0e31e370f2bd366a57 -

Dixit :

“C’est seulement et uniquement la signature du hash sha256 du document de transaction”
“Signatures are made over the transaction’s content, signatures excepted”

alors, j’applique la fonction sha256 sur mon document de transaction et je nomme le résultat R :

R = sha256(“Version:10\r\n…\r\n”)

et là, je me trouve bien embêté parce que j’en fais quoi de R ?
A quelle moment j’intègre cette information avec ma clé privée ?
Comment et a quelle étape cette information R est transmise ?
:thinking:

Dixit :

“la clé privée d’un compte n’est jamais stockée nulle part sur aucun support physique.” => OK
“Elle est générée a chaque fois que tu saisi ton couple identifiant secret/mot de passe …” => OK
“pour signer une transaction ou une certification” => comment ?:face_with_raised_eyebrow:


je fais une tentative :

var ID = “max”
var PASS = “monpass”

je concatene mon identifiant et mon mot de pass, applique une fonction de hashage sha256 et j’enregistre ce resultat dans K qui est ma clé privée.

var K = sha256(ID + PASS) ?
var R = sha256(“Version:10\r\n…\r\n”) ?

a quelle étape K signe le document ?

var SIGNED_DOC = sha256(K + R) ?

et cette nouvelle information SIGNED_DOC, j’en fais quoi ?
cette information doit elle faire partie de la requete /tx/process ?


Dixit:

“C’est seulement et uniquement la signature du hash sha256 du document de transaction … la “carte” soit capable de calculer la signature d’un hash sha256…”

Pour revenir au module dont on discute dans l’autre topic et de son fonctionnement (j’ignore ici le code PIN pour simplifier ) :

Je prends 2 parametres :
-en entrée : TX (provenant de l’exterieur, le TPE)
-en interne : K (supposons pour simplifier qu’elle est stockée en dur)

ainsi je hash selon les étapes vu précèdemment et je renvois SIGNED_DOC ?


Tout cela reviens à savoir, s’il vous plait,
selon quelle procédure ma clé privée signe un document de transaction et de quelle manière je communique les informations qui en découlent.
Un tout petit petit petit exemple de code sera le bienvenu.
:sweat_smile:

Il faut signer le document avec libsodium /nacl. Voir l’exemple de la librairie python (méthode sign ) : https://github.com/duniter/duniter-python-api/blob/master/duniterpy/documents/document.py

@Max ok en fait ton problème semble être que tu ne connais pas le concept de signature cryptographique.

Ce concept est basé sur les clés asymétriques : ce qu’une clé chiffre l’autre le déchiffre.

Tu a donc deux cas d’utilisation possible :

  1. chiffrer avec la clé publique et déchiffrer avec la clé privée => utilisé pour communiquer un message confidentiel (par exemple un mail chiffré)

  2. chiffrer avec la clé privé puis déchiffrer avec la clé publique => utilisé pour la signature numérique.

Comme le chiffrement asymétrique est très lent, et que le but d’une signature n’est pas de cacher le contenu d’un document mais seulement de le “signer”, on signe seulement le hash du document, avec la fonction de hashage de notre choix (dans le protocole duniter c’est actuellement du sha256).

Donc l’individu qui souhaite signer un document chiffre le hash de ce document avec sa clé privée et ajoute ce hash chiffré a la fin du document. C’est ce hash chiffré que l’on nomme signature, hash chiffré = signature.

De là, toute personne ou tout programme qui reçoit ce document peut déchiffrer la signature avec la clé publique du prétendu signataire, et il doit trouver en sortie le hash en clair du document, hash en clair qu’il va vérifier en hashant lui même le document, si les deux hash sont identiques la signature est valide, s’il sont différents la signature est invalide. (c’est pour ça qu’il faut se mettre d’accord sur la fonction de hashage utilisée).

L’explication vidéo en 2min : https://youtu.be/Sx7ZNDppxQc

Dans le cas précis de duniter nous utilisons l’algo de chiffrement asymétrique ed25519, qui a l’avantage de permettre de générer une paire de clé très rapidement, ainsi il n’y a pas besoin des stocker ta clé privée contrairement a PGP par exemple, ta clé privée est régénérée a chaque fois que tu saisie ton couple (id secret+password), mais attention la clé privée n’est pas un hash de ton (id secret+password), c’est une opération mathématique complexe qui nécessite une librairie de crypto comme libsodium ou nacl.

Ceci étant la puce client n’a pas besoin se savoir générer la clé privée, elle pourrais la stockée directement mais chiffré par un code pin. Les 3 seules choses que la puce client doit savoir faire c’est :

  1. donner sa clé publique sur demande (stockée en clair sur la puce client)
  2. déchiffré la clé privée stockée vie le code pin que lui donne le terminal commerçant
  3. chiffré le hash que lui donne le terminal avec la clé privée et retourner ce hash chiffré au terminal commerçant, c’est tout.

Ainsi ce que doit faire le terminal commerçant c’est :

  1. mémoriser le montant M saisi par le commerçant
  2. lire la clé publique sur la puce client
  3. récupéré sur le réseau les sources correspondantes a la clé publique du client et créer le document transaction // Et en parallèle demander au client de saisir son code pin
  4. Envoyer a la puce client le hash sha256 du document transaction + le code pin
  5. récupérer le hash chiffré = signature qui lui renvoi le puce client
  6. vérifier la validité de cette signature
  7. Si la signature est valide, transmettre le document transaction signé au réseau duniter
3 Likes

Merci pour la procédure,

de la nature même de la fonction SHA256 qui prend 1 seul et unique paramétre,

on peut essayer la

on peut regarder ici

ou encore l’utilisation que je fais la

ALORS:

OK,

apparement c’est la question à 100 millions de Ğ1.:smiley: :sun_with_face:

J’insiste :

Comment un individu n’ayant pas connaissance du fonctionnement d’un moteur d’une voiture peut-il lui même écrire la documentation le concernant ? :face_with_raised_eyebrow:

La doc, la doc, la doc :sparkling_heart: :sparkling_heart: :sparkling_heart:

@Max cette fameuse fonction de signature c’est la fonction de chiffrement de l’algo ed25519, c’est une fonction mathématique complexe que je serait bien incapable de te décrire, il faut nécessairement passer par une librairie tierce de crypto qui intègre l’algo ed25519, comme c’est le cas pour NaCl et libsopdium

1 Like

merci @elois

comme cela n’etait pas explicitement dit dans ton dernier post,
alors que tu m’as bien décrit que l’on passé par la lib de crypto concernant le hash(id, pass)
maintenant
je sais a quoi m’en tenir :slight_smile:

Oui, cf cette spec : Signatures: crypto_sign

1 Like

je ne vois que du base64 pour l’encodage de la signature , l’usage de la lib de crypto, c’est où ?
“key.signature” ?
duniter-python-api/duniterpy/key/signing_key.py at master · duniter/duniter-python-api · GitHub ?

1 Like

A priori, tu as key.signature(..) ici :

on est bon ou pas ?

4 Likes

Oui a ceci près qu’il est également possible de stocker en clair la clé publique sur la puce client de manière a ce que le terminal commerçant puisse commencer a récupérer les sources et rédiger le document transaction sans avoir a attendre que le client saisisse son code pin, c’est donc beaucoup plus rapide :slight_smile:

Reste 1 doute:

comment tu check ca ?