Algorithme de sélection des sources pour transactions

transaction
silkaj
sakia
cesium

#1

Depuis la migration de Silkaj vers DuniterPy, un changement de comportement a été introduit, dont je n’ai pas encore trouvé la source.

Le changement est le suivant. Lorsqu’une ou des transactions intermédiaires (plus de quarante sources impliquées) ont lieu, Silkaj < 0.7 sélectionne des sources différentes par transactions intermédiaires.
Pour ce faire, après avoir envoyé une transaction intermédiaire, il récupère de nouveau les transactions du nœud et enlève les sources en attente. Ça fonctionne bien.

Avec Silkaj 0.7.0 (DuniterPy), il sélectionne les mêmes sources pour les transactions intermédiaires ainsi que pour deux transactions envoyés à la suite. Du coup, le nœud refuse la seconde transaction, car les sources sont en voie d’être consommées.

Une régression a surement été introduite. Je vais fouiller de nouveau. Les sources ne doivent pas être bien retirées pour la nouvelle transaction.

Avant ça, j’ai essayé un autre algorithme, qu’il sélectionne les sources suivantes par incrémentation, mais je ne crois pas que ça soit la bonne solution, car si deux transactions sont envoyées à la suite, ça peut ne pas passer.

Quel algorithme avez-vous utilisé ou utiliseriez-vous pour la sélection des sources des transactions ?

Le ticket un peu brouillon pour suivre.


#2

Dans sakia, avec du pseudocode rapide (et résumé du vrai code qui est un peu plus poussé, c’est pour donner l’idée générale) :

  1. Calcul des sources https://git.duniter.org/clients/python/sakia/blob/master/src/sakia/services/documents.py#L221
liste_sources = liste_vide()
depassement = 0
base_courante = base_courante_reseau() # par exemple, base 1
sources_disponibles = get_sources_disponibles(pubkey)
pour chaque source dans sources_disponibles:
  si source.base == base_courante:
      test_sources = liste_sources.copy()
      test_sources.ajout(source)
      list_sources.ajout(source)
      sources_disponible.retire(source)
      si valeur(test_sources) >= valeur_cible:
            depassement = valeur(test_sources) - valeur_cible

    base_courante -= 1
retourne liste_sources, depassement
  1. Génération des transactions et chainage https://git.duniter.org/clients/python/sakia/blob/master/src/sakia/services/documents.py#L351
fonction prepare_transaction(montant_cible, pubkey_cible):
   transactions = liste_vide()
   sources, depassement = calcul_sources(montant_cible, envoyeur, receveur)
   tant_que sources.length > 40:
      transaction_chainee = prepare_transaction(valeur(sources), notre_pubkey)
      transactions.ajout(transaction_chainee)
  consommation(sources)

  pour toutes les tx dans transactions:
      creation_sources_depuis_output_vers_envoyeur(tx) # permet de connaitre en avance les outputs générés par la transaction lorsqu'elle sera ajoutée à la  chaine
      generation_doc_et_envoi(tx)

#3

Je confirme :slight_smile: Surtout au début de la vie d’un compte.
De mon côté j’ai quasi le même algo de Sakia :

  • je sélectionne toutes les sources nécessaire, puis je les découpe par parquet, en chainant la 1ere à la 2ème, etc. Ca fonctionne bien.

#4

Si vous êtes d’accord, je suggère de placer tout pseudo code utile pour les développeurs dans le wiki de Duniter. Sinon ils vont disparaître dans les posts du forum…

Si @cgeek ou @elois ou @inso, vous avez un pseudo code pour détecter la chaîne majoritaire en WS2P , je suis preneur !


#5

Le code pour sakia est là : https://git.duniter.org/clients/python/sakia/blob/master/src/sakia/services/network.py#L250

Pour le pseudo code, je fais ça quand j’ai le temps :slight_smile:


#6

J’ai un début de code que j’ai mis dans Duniter UI v2 (visible dans ma démonstration aux RML12 où les nœuds changeaient de couleur), mais je compte la revoir/l’affiner. Donc pas de publication à court terme.