API des événements

Comme abordé dans la dernière visio dev, il va falloir discuter des événements qu’on veut avoir en blockchain car cela sera assez structurant dans la conception des indexeurs et des clients.

La doc substrate n’est pas très fournie au sujet des événements, mais voici en gros ce qu’il faut retenir :

Substrate provides a default implementation of how to deposit an event.

The default behavior of this function is to call deposit_event from the FRAME system, which writes the event to storage.

This function places the event in the System pallet’s runtime storage for that block. At the beginning of a new block, the System pallet automatically removes all events that were stored from the previous block.

Events deposited using the default implementation are directly supported by downstream libraries like the Polkadot-JS API. However, you can implement your own deposit_event function if you want to handle events differently.

Donc les événements sont des éléments du storage écrits dans un bloc et supprimés au début du suivant.


On peut distinguer deux catégories d’événements :

  • ceux émis suite à l’appel d’extrinsic (généralement à l’initiative d’un utilisateur)
  • ceux émis suite à une action automatique en blockchain

Dans l’app polkadotjs, les premiers apparaissent en face de l’extrinsic et les derniers dans la catégorie “system events”.

on voit en haut

  • event count 11
  • extrinsic count 2

puis les deux extrinsics et les événements associés
puis les system events
et aussi des logs

En gros, sans événements, difficile de voir ce qui se passe en blockchain.


Je vois deux cas d’usage des événements :

  1. savoir quel est le résultat d’un extrinsic soumis (succès / échec) et plus précisément, quel a été son effet
  2. observer la blockchain dans son intégralité et être informé des modifications du storage (en dehors des événements)

Plus concrètement :

1. résultat d’un extrinsic

Je soumets une certification :

  • elle peut échouer (avec un message d’erreur)
  • elle peut réussir et dans ce cas :
    • ça peut être une nouvelle certification
    • ça peut être un renouvellement de certification

ou

Je soumets un extrinsic pour lier mon compte à mon identité :

  • cela peut échouer (→ message d’erreur)
  • cela peut réussir
    • le compte est déjà lié (no-op)
    • le compte est désormais lié

2. observation de la blockchain

Je veux savoir quand un nouveau DU a été créé :arrow_right: je regarde l’événement UniversalDividend.NewUdCreated

Je veux savoir quand un virement de A → B est réalisé :arrow_right: je regarde l’événement Balances.Transfer.

Mais pour savoir l’évolution du solde de mon compte, je peux aussi faire directement une souscription pour les changements de la valeur dans le storage, pas besoin d’un événement pour ça.


Les événements peuvent contenir les informations qu’on veut, et on peut les organiser comme on veut. C’est le but de cette discussion. Je vais ajouter à la documentation automatisée une liste exhaustive des événements. En attendant, on peut utiliser celle que j’avais fait manuellement ici : Why we need a full featured indexer?.

2 Likes

Première question concrète : dans ce sujet Indexeurs : que faire au retrait d'une certification ? au renouvellement? j’exprime le besoin d’avoir accès au bloc programmé pour l’expiration d’une certification. Mais je peux déduire cette information de la durée de validité d’une certification. On a donc deux choix :

  • inclure le résultat du calcul dans l’événement
  • laisser à l’utilisateur le soin de calculer le résultat

D’ailleurs, les autres champs ne me paraissent pas utiles.

/// Removed certification
/// [issuer, issuer_issued_count, receiver, receiver_received_count, expiration]
RemovedCert {
    issuer: T::IdtyIndex,
    issuer_issued_count: u32, // est-ce utile ?
    receiver: T::IdtyIndex,
    receiver_received_count: u32, // est-ce utile ?
    expiration: bool,
    // on pourrait ajouter un champ `expire_on`
}

C’est en cours : Documentation des événements

[edit] c’est fait

C’est ce qui me paraît le plus judicieux car la date est dépendante d’un paramètre (durée de validité d’une certification) qui peut varier suite à un changement de Runtime. Les clients doivent avoir le moins possibles de règles de la blockchain en tête pour avoir le moins de sources possibles de bug (principe du SSoT).

Mais les clients doivent quand même savoir que cette projection (de la date d’expiration) est sujette à caution, notamment l’événement est exprimé dans une version du Runtime et peut être invalidé sur upgrade.

1 Like

Actuellement (cf doc Duniter | Runtime events)

Membership - 42
    MembershipAdded(member, expire_on) - 0
    MembershipRemoved(member, reason) - 1

Cert - 43
    CertAdded(issuer, receiver) - 0
    CertRemoved(issuer, receiver, expiration) - 1
    CertRenewed(issuer, receiver) - 2

Je trouve ça déjà plus facile à comprendre que les noms folkloriques qu’on avait avant du genre MembershipAcquired / MembershipExpired / NewCert / RenewedCert, et ça montre qu’il manque la distinction MembershipAdded / MembershipRenewed.

Est-ce que ça vous convient Added / Renewed / Removed ou est-ce que vous préférez d’autres mots ? New / Deleted / Started / Finished… ? Extended / Prolonged:smiley:

1 Like

Je trouve ça bien comme ça.

Je compte quand même ajouter cette distinction parce que ça n’a pas les mêmes conséquences, ce sera pratique pour l’indexeur et les clients qui voudront uniquement écouter les MembershipAdded mais pas les MembershipRenewed

Je retrace ici une discussion sur la nomenclature des événements qui a lieu sur gitlab : Resolve "Améliorations pour smith-members" (!228) · Merge requests · nodes / rust / Duniter v2S · GitLab

Juste pour montrer le genre de questions simples qu’on peut se poser et auxquelles tout le monde peut participer :slight_smile:

Comme ces événements sont l’interface entre Duniter et le monde extérieur (indexeurs, clients…), ça vaut le coup de se mettre d’accord sur une nomenclature qui convient à tous plutôt que de laisser ceux qui ont le nez dans le code manquer de recul ^^

@1000i100 par exemple, je pense que tu as l’œil pour ce genre de choses. Il suffit de parcourir la documentation autogénérée (calls, events, errors).

2 Likes

Hier en relisant le travail de @poka sur Duniter-squid, j’ai repéré quelques petites changements à faire dans Duniter, notamment l’événement IdtyValidated. La MR associée est !230.

Avec ce fonctionnement quand l’identité devient membre la première fois, il y a deux événements : identity.IdtyValidated et membership.MembershipAdded. Alors que quand l’identité redevient membre après avoir perdu son statut (membership.MembershipRemoved), il n’y a plus que l’événement membership.MembershipAdded qui est émis.

De plus, comme le statut de l’identité est central, ce serait bien de discuter les noms. Dans cette discussion (Simplification de la machine à état des identités - #11 by poka), il y a plusieurs propositions pour renommer NotMember :

  • NoMoreMember
  • NotMemberAnymore
  • ExMember

J’avais également pensé à Disabled ou Suspended par le passé.

Lequel préférez-vous (2 choix max) ?

  • NotMember
  • NoMoreMember
  • NotMemberAnymore
  • ExMember
  • Disabled
  • Suspended
  • wasMember
0 voters
2 Likes

Très bonne initiative ce sondage !

1 Like

N’avait on pas un wasMember dans la V1?

WasMember j’adore (parce que c’est mon idée, donc en toute mauvaise foi). :joy:

4 Likes

C’est bizarre que Member et NotMember soient dans pallet_identity qui ne connaît pas le concept de membre. En remplaçant ces deux variantes par Validated(T::ValidatedIdtyStatus)T::ValidatedIdtyStatus serait défini dans pallet_membership : MembershipStatus { #[default] Member, NotMember }.

Ainsi pallet_identity n’a pas à gérer (et ne peut pas introduire de bug dans) les états de membership. Je ne sais pas si ça simplifie vraiment l’automate mais ça réduit le nombre de transitions possibles.

Oui, je suis d’accord, c’est bizarre, mais ça vient de Résistance au changement, la nuit porte conseil.
Je n’avais pas encore franchi le pas de faire disparaître totalement la pallet membership, alors que vous raisonniez déjà sous l’hypothèse que ce serait fait

Maintenant que la pallet membership est quasi vide, ça me semble aussi plus logique de déplacer son contenu dans la pallet identity. Mais là j’ai surtout envie d’arrêter de tout chambouler côté Duniter et d’avancer sur le reste de l’écosystème :sweat_smile:

On ne chamboule pas par plaisir de chambouler : c’est surtout une conséquence de la volonté de maîtriser le workflow et d’éviter les bugs.

On peut garder cette palette membership, mais bon vu qu’il ne reste qu’une seule donnée dedans (l’expiration du statut de membre il me semble), est-ce que ça vaut le coup ? La palette identity pourrait tout à fait porter le concept de membre. En fait elle existe même précisément dans l’objectif que l’on puisse établir ce concept ! Donc c’est vraiment tout proche.

2 Likes

Oui, je suis d’accord, on peut fusionner maintenant, c’est encore plus facile à faire qu’avant. Et ce sera pas trop compliqué non plus à ajuster côté client, il suffira d’écouter les événements identity.membershipAdded au lieu de membership.membershipAdded, et il n’y a plus de call en plus depuis que c’est automatique après l’évaluation de la règle de distance.

1 Like

AnyMore ? Non, la signification n’est pas bonne car l’identité peut redevenir membre.
D’ailleus j’ai voté pour NoMoreMember mais l’expression souffre du même symptôme.

Oui en fait c’est le bon concept.

2 Likes

Ok j’ai refait le sondage et je fais ma girouette du coup, vous m’avez convaincu…

2 Likes

C’est pas moi qui vais m’opposer à WasMember, ça fait déjà des années que j’utilise ce mot dans DataJune ! DataJune.jl/WotHistory.jl at master - DataJune.jl - Service Git

1 Like

Nouveaux événements - smith-members

Il s’agit de la nouvelle palette permettant de définir les Smith.

Je liste ses événements ici afin pour obtenir d’éventuelles réactions.

cc créateurs de clients : @kimamila @poka @HugoTrentesaux @vit

  • SmithMembers - 10
    • InvitationSent(receiver, issuer) - 0 An identity is being inivited to become a smith.
      receiver: T::IdtyIndex
      issuer: T::IdtyIndex
      
    • InvitationAccepted(idty_index) - 1 The invitation has been accepted.
      idty_index: T::IdtyIndex
      
    • SmithCertAdded(receiver, issuer) - 2 Certification received
      receiver: T::IdtyIndex
      issuer: T::IdtyIndex
      
    • SmithCertRemoved(receiver, issuer) - 3 Certification lost
      receiver: T::IdtyIndex
      issuer: T::IdtyIndex
      
    • SmithMembershipAdded(idty_index) - 4 A smith gathered enough certifications to become an authority (can call `go_online()`).
      idty_index: T::IdtyIndex
      
    • SmithMembershipRemoved(idty_index) - 5 A smith has been removed from the smiths set.
      idty_index: T::IdtyIndex
      
  • 3 Likes

    Peut-être qu’ici aussi on pourrait avoir issuer / receiver. Mais je chipote ><

    1 Like