Gestion d'un échec d'extrinsic, via la lib @polkadot/api (ts/js)

Salut @HugoTrentesaux j’ai vu ta MR pour la gestion des types. Merci je vais regarder ca.

Sinon, j’ai encore un soucis suite à la discussion d’hier pour la gestion des erreurs.
J’'arrive bien à récupérer l’Event system.ExtrinsicFailed Mais pas encore à récupérer le code d’erreur associé :

Voici mon code :

try {
      const { status, events } = await ExtrinsicUtils.submit(this.api.tx.certification.addCert(to.meta?.index), issuerPair);
      console.info(`${this._logPrefix}Extrinsic status`, status.toHuman());
      console.info(`${this._logPrefix}Certifying completed at block hash #${status.hash.toHuman()}`);

      return status.hash.toHuman();
    } catch (err) {
      console.error(`${this._logPrefix}Cannot certify`, err.toJSON());
      throw new ExtrinsicError('ERROR.SEND_CERT_FAILED', err);
    }

Ma console javascript m’affiche ceci :

[account-service] Cannot certify 
{
  index: '0x0001', 
  data: [
   {module: {index:40, error: '0x05000000'},
   {weight: {…}, class: 'Normal', paysFee: 'Yes'}
  ]
} 

Dans le catch (err), je récupère l’Event. Il a un index et un code d’erreur en hexa. Mais comment retrouver l’erreur ?

Je ne connais pas encore bien polkadotjs contrairement à @poka qui pourra certainement être plus utile que moi. Mais :

   {module: {index:40, error: '0x05000000'},

Cela veut dire que l’erreur provient de la pallet 40 (Wot) et que l’erreur est la numéro 5 (IssuerNotMember). On retrouve les erreurs ici :

Duniter | Runtime errors documentation de l’API des erreurs

Normalement si tu as les types correctement générés, tu peux matcher cette erreur contre une enum : https://git.duniter.org/clients/cesium-grp/cesium2s/-/blob/hugo/fix-typegen/src/interfaces/types-lookup.ts?ref_type=heads#L2622-L2640

PS :

Est-ce que tu peux pousser ton code sur une branche temporaire si tu veux que je regarde comment faire une gestion d’erreur ?

PPS :

Une autre option, mais je ne sais pas si c’est recommandé, est de faire system.dryRun(extrinsic, at) pour avoir les erreurs sans soumettre l’extrinsic

1 Like

La doc polkadot.js explique bien cela: https://polkadot.js.org/docs/api/cookbook/tx/#how-do-i-get-the-decoded-enum-for-an-extrinsicfailed-event

If an extrinsic fails via system.ExtrinsicFailed event, you can retrieve the error, if defined as an enum on a module.

api.tx.balances
  .transfer(recipient, 123)
  .signAndSend(sender, ({ status, events }) => {
    if (status.isInBlock || status.isFinalized) {
      events
        // find/filter for failed events
        .filter(({ event }) =>
          api.events.system.ExtrinsicFailed.is(event)
        )
        // we know that data for system.ExtrinsicFailed is
        // (DispatchError, DispatchInfo)
        .forEach(({ event: { data: [error, info] } }) => {
          if (error.isModule) {
            // for module errors, we have the section indexed, lookup
            const decoded = api.registry.findMetaError(error.asModule);
            const { docs, method, section } = decoded;

            console.log(`${section}.${method}: ${docs.join(' ')}`);
          } else {
            // Other, CannotLookup, BadOrigin, no extra info
            console.log(error.toString());
          }
        });
    }
  });

Dans ton code, voilà comment tu peux retrouver l’erreur en théorie:

try {
  const { status, events } = await ExtrinsicUtils.submit(this.api.tx.certification.addCert(to.meta?.index), issuerPair);
  console.info(`${this._logPrefix}Extrinsic status`, status.toHuman());
  console.info(`${this._logPrefix}Certifying completed at block hash #${status.hash.toHuman()}`);

  return status.hash.toHuman();
} catch (err) {
  console.error(`${this._logPrefix}Cannot certify`, err.toJSON());
  
  events.forEach(({ event }) => {
    if (this.api.events.system.ExtrinsicFailed.is(event)) {
      const [dispatchError, dispatchInfo] = event.data;
      
      if (dispatchError.isModule) {
        const decoded = this.api.registry.findMetaError(dispatchError.asModule);
        const { docs, name, section } = decoded;
        console.error(`${section}.${name}: ${docs.join(' ')}`);
      } else {
        console.error(dispatchError.toString());
      }
    }
  });

  throw new ExtrinsicError('ERROR.SEND_CERT_FAILED', err);
}

Plutôt que de boucler sur les events, tu peux peut être obtenir le dispatchError à partir de l’objet err ainsi:

const dispatchError = err.dispatchError;

Mais comme le dit Hugo, il nous faudrait le code entier pour tester et ainsi répondre de manière fiable.

1 Like