Oracle de distance dans un docker

Ce serait bien de fournir une image docker qui soit capable de faire tourner l’oracle de distance. Sinon on va avoir peu de forgerons qui publient des résultats d’évaluation de la règle de distance, et ce sera plus fragile (peu de forgerons nécessaires pour changer la médiane des résultats).

J’ai créé le ticket #138 à ce sujet. Est-ce que @Pini ça te tenterait ? La documentation de l’oracle de distance est ici : docs/user/distance.md · master · nodes / rust / Duniter v2S · GitLab.

OK je m’y colle. Il faut ça pour quand ?

On peut lancer le réseau de test sans, et il suffit d’un forgeron pour avoir un nombre non nul de résultats, donc pas d’urgence, fais selon ton rythme ! Si tu veux une échéance, ça fera un super cadeau de noël aux forgerons de la ǦTest :smiling_face:

Sur ma chaîne locale gdev_dev, si j’essaie de donner la dernière certification avant de pouvoir devenir membre à une identité, alors je tombe sur l’erreur DistanceNotOk. Est-ce que cela signifie que même sur les nœuds de dev locaux il est nécessaire de faire tourner l’oracle ?

Ça me semble assez logique vue qu’il s’agit du runtime de la gdev mais je préfère demander, si jamais il y a possiblité de faire autrement (option pour désactiver le check de distance en mode dev, ou implémentation sans oracle possible en mode dev même si ça me semble surfait).

L’oracle pourrait être intégré dans l’exécutable de Duniter comme sous-commande. Si une option --distance-oracle est passée au nœud, alors le client lancerait automatiquement l’oracle dans un processus à part. Ça évite de distribuer deux exécutables séparés et de devoir configurer cron.

On pourrait pousser l’intégration jusqu’à mettre l’oracle dans le client, ce qui simplifierait la communication oracle<->Duniter (runtime API plutôt que fichiers temporaires et RPC) mais on perd l’isolation qui permet que l’un plante ou redémarre sans conséquence sur l’autre.

4 Likes

Je pensais à un truc du même genre. En tout cas il me semble inutile de générer une image Docker spécifique pour l’oracle. En mode pragmatique voici ce que je propose dans un premier temps :

  • Générer l’exécutable de l’oracle dans l’image docker de duniter-v2s
  • Configurer l’entrée de crontab pour appeler cet exécutable dans le contexte du conteneur v2s. Par ex.:
    4,24,44 * * * * nice -n 2 docker exec <duniter-v2s-container> /usr/local/bin/distance-oracle
    

C’est très simple et ça permet de lever le blocage sur la disponibilité de l’outil.

Ensuite il sera possible de raffiner le mécanisme comme le propose @tuxmain si le besoin se confirme.

2 Likes

Voici la solution que j’ai retenue pour mon infra :

duniter-gdev-smith/
├── distance-oracle
│   └── docker-compose.yml
└── docker-compose.yml

et mon fichier distance-oracle/docker-compose.yml :

# Duniter distance oracle plugging to smith node

version: "3.5"

# distance oracle uses same image but another entrypoint
services:
  distance-oracle:
    image: duniter/duniter-v2s-gdev:latest
    entrypoint: docker-distance-entrypoint
    environment:
      ORACLE_RPC_URL: "ws://duniter-smith:9944"
      ORACLE_RESULT_DIR: "/var/lib/duniter/chains/gdev/distance/"
      ORACLE_EXECUTION_INTERVAL: "1800"
      ORACLE_MAX_DEPTH: "5"
      ORACLE_LOG_LEVEL: "debug"
    volumes:
      - data-smith:/var/lib/duniter

# external volume of duniter node to share data for the inherent to read
volumes:
  data-smith:
    name: duniter-gdev-smith_data-smith
    external: true

# external network of duniter node to read data from rpc API
networks:
  duniter:
    name: duniter-gdev-smith_default

Donc :

  • j’utilise la même image mais le nouvel entrypoint
  • je peux arrêter l’oracle de distance indépendamment de mon nœud forgeron (par exemple pour changer le niveau de log)
  • j’utilise un réseau docker pour lire les données depuis le nœud et un volume docker partagé pour poser les données dont l’inherent aura besoin

Tout ce qui me manque, c’est la bonne image docker, qui n’a pas été publiée puisque c’est maintenant une action manuelle.

J’ai fait tourner mon oracle de distance comme ça mais apparemment ça n’a pas marché. Exemple au bloc 73775 où l’on voit :

image

Un unreserve sans événement EvaluatedValid ou EvaluatedInvalid vient forcément de l’absence de résultat. Ceci se confirme en regardant le contenu de la pool d’évaluation pour le bloc précédent :

La solution dans les logs :

hugo@trentesaux:~/docker/duniter-gdev-smith/distance-oracle$ docker compose logs -f
distance-oracle-distance-oracle-1  | error: unexpected argument '-D' found
distance-oracle-distance-oracle-1  | 
distance-oracle-distance-oracle-1  | Usage: distance-oracle [OPTIONS]
distance-oracle-distance-oracle-1  | 
distance-oracle-distance-oracle-1  | For more information, try '--help'.
distance-oracle-distance-oracle-1  | Waiting 1800 seconds before next execution...
distance-oracle-distance-oracle-1  | error: unexpected argument '-D' found
distance-oracle-distance-oracle-1  | 
distance-oracle-distance-oracle-1  | Usage: distance-oracle [OPTIONS]
distance-oracle-distance-oracle-1  | 
distance-oracle-distance-oracle-1  | For more information, try '--help'.
distance-oracle-distance-oracle-1  | Waiting 1800 seconds before next execution...
distance-oracle-distance-oracle-1  | error: unexpected argument '-D' found
distance-oracle-distance-oracle-1  | 
distance-oracle-distance-oracle-1  | Usage: distance-oracle [OPTIONS]
distance-oracle-distance-oracle-1  | 
distance-oracle-distance-oracle-1  | For more information, try '--help'.
distance-oracle-distance-oracle-1  | Waiting 1800 seconds before next execution...
distance-oracle-distance-oracle-1  | error: unexpected argument '-D' found
distance-oracle-distance-oracle-1  | 
distance-oracle-distance-oracle-1  | Usage: distance-oracle [OPTIONS]
distance-oracle-distance-oracle-1  | 
distance-oracle-distance-oracle-1  | For more information, try '--help'.
distance-oracle-distance-oracle-1  | Waiting 1800 seconds before next execution...
distance-oracle-distance-oracle-1  | error: unexpected argument '-D' found
distance-oracle-distance-oracle-1  | 
distance-oracle-distance-oracle-1  | Usage: distance-oracle [OPTIONS]

C’est donc un problème de entrypoint docker qui n’a pas été mis à jour après !226

    ~/dev/duniter-v2s    master  ./target/debug/duniter distance-oracle --help                                                                                                             101 ✘ 
Run distance oracle

Usage: duniter distance-oracle [OPTIONS]

Options:
  -d, --evaluation-result-dir <EVALUATION_RESULT_DIR>  [default: /tmp/duniter/chains/gdev/distance]
  -u, --rpc-url <RPC_URL>                              [default: ws://127.0.0.1:9944]
  -h, --help                                           Print help
  -V, --version                                        Print version
1 Like

J’ai avancé à deux à l’heure sur le sujet mais :

  • j’ai corrigé le entrypoint !242
  • j’ai autorisé la connexion à une URL non TLS et non localhost !250
  • j’ai publié une image docker correspondant à ces changements (en attendant qu’on règle #195) h30x/duniter-v2s-gdev:800.2
schéma de la #195

J’ai testé sur mon nœud forgeron et demandé l’évaluation de la règle de distance pour benjamin gcli identity request-distance-evaluation-for 14572 au bloc 262489 (après avoir utilisé mon pouvoir de sudo pour qu’il ait plus de certifications, parce que depuis ça on a redémarré le réseau).

J’ai créé #202 parce que ça me gave d’attendre deux heures à chaque test.

Je vais ajouter mon docker compose à la doc parce que ça me semble pas mal de séparer en deux parties.

D’ailleurs GPT-4 m’a dit qu’il manquait networks: -duniter dans

et il avait raison, merci à lui et à @poka

3 Likes

Je fais trop de choses en même temps en ce moment (mais on a bien avancé sur l’intégration de Hasura à duniter-squid avec @poka), donc je n’ai pas donné de suite à ce fil. Mais voici un résumé :

Au bloc 262489, je fais la demande d’évaluation de la règle de distance pour @bgallois :

# oui, c'est bien son pseudo "14572", qui correspond également à son idty index
gcli identity request-distance-evaluation-for 14572

Au bloc 263585, mon nœud forgeron publie un résultat de 98.9 % (supérieur à 80 %).

Au bloc 263587, mon nœud forgeron tente de publier à nouveau le résultat, mais la blockchain refuse. Donc c’est un bug (#207), @tuxmain, il me semble que le nœud forgeron ne devrait pas essayer de publier plusieurs fois.

Même chose au bloc 263604.

Même chose au bloc 263605.

Pour retrouver ces blocs, voici la requête GraphQL que j’ai exécutée :

# au format squid
query Distance {
  calls(limit: 10, where: {pallet_eq: "Distance"}) {
    pallet
    name
    block {
      height
    }
  }
}
# au format Hasura
query Distance {
  call(limit: 10, where: {pallet: {_eq: "Distance"}}) {
    pallet
    name
    block {
      height
    }
  }
}

Au bloc 264181, Duniter intègre le résultat et émet l’événement EvaluatedValid (cf doc des événements), ainsi que IdtyValidated et MembershipAdded. Donc tout a eu lieu automatiquement, c’est bon :tada: :tada: :tada:

Cf Adhésion automatique après évaluation de la distance pour les discussions qui ont abouti à ça.

À noter que si l’identité avait déjà été membre par le passé, on aurait juste eu l’événement MembershipAdded et pas IdtyValidated.

Et s’il s’était agit d’un renouvellement d’identité, on aurait eu MembershipRenewed seulement.


C’est donc le moment pour ceux qui utilisent docker d’installer un oracle de distance : Duniter | Run distance oracle. Mais il vous faut pour cela utiliser l’image h30x/duniter-v2s-gdev:800.2 pour l’instant parce qu’on n’en a pas encore publié d’officielle (cf #195)

:warning: image à utiliser : h30x/duniter-v2s-gdev:800.2

(Et il nous faudra régler le bug pour éviter que l’oracle soumette des inhérents en échec, ça fait tâche même si c’est sans conséquences :laughing:)

3 Likes

Docker d’un oracle mis en place.
ici les logs du démarrage de cet oracle

2024-02-27T15:10:14.466Z DEBUG [distance_oracle::api] Looking at Pool1 for session 549
2024-02-27T15:10:14.467Z INFO [distance_oracle] Nothing to do: Pool does not exist
Waiting 1800 seconds before next execution…
2024-02-27T15:21:28.838Z DEBUG [distance_oracle::api] Looking at Pool2 for session 550
2024-02-27T15:21:28.839Z INFO [distance_oracle] Nothing to do: Pool does not exist
Waiting 1800 seconds before next execution…

je l’ai redemarré des l’ouverture de la session 550 mais pas de changement, il ne trouve pas les Pool…

Normal ? Plus qu’à laisser attendre les 30 minutes ?

1 Like

2024-02-27T15:10:14.466Z DEBUG [distance_oracle::api] Looking at Pool1 for session 549
2024-02-27T15:10:14.467Z INFO [distance_oracle] Nothing to do: Pool does not exist
Waiting 1800 seconds before next execution…
2024-02-27T15:21:28.838Z DEBUG [distance_oracle::api] Looking at Pool2 for session 550
2024-02-27T15:21:28.839Z INFO [distance_oracle] Nothing to do: Pool does not exist
Waiting 1800 seconds before next execution…
2024-02-27T15:51:28.895Z DEBUG [distance_oracle::api] Looking at Pool2 for session 550
2024-02-27T15:51:28.895Z INFO [distance_oracle] Nothing to do: Pool does not exist
Waiting 1800 seconds before next execution…
2024-02-27T16:21:28.947Z DEBUG [distance_oracle::api] Looking at Pool0 for session 551
2024-02-27T16:21:28.948Z INFO [distance_oracle] Nothing to do: Pool does not exist
Waiting 1800 seconds before next execution…

l’oracle tourne en rond j’ai l’impression…

1 Like
distance-oracle-distance-oracle-1  | 2024-02-23T00:07:03.793Z DEBUG [distance_oracle::api] Looking at Pool1 for session 438
distance-oracle-distance-oracle-1  | 2024-02-23T00:07:03.794Z INFO  [distance_oracle] Nothing to do: Pool does not exist
distance-oracle-distance-oracle-1  | Waiting 1800 seconds before next execution...
distance-oracle-distance-oracle-1  | 2024-02-23T00:37:03.853Z DEBUG [distance_oracle::api] Looking at Pool2 for session 439
distance-oracle-distance-oracle-1  | 2024-02-23T00:37:03.861Z INFO  [distance_oracle] Evaluating distance for session 439
distance-oracle-distance-oracle-1  | 2024-02-23T00:37:07.762Z DEBUG [distance_oracle] Evaluating distance for idty 14572
distance-oracle-distance-oracle-1  | 2024-02-23T00:37:07.770Z INFO  [distance_oracle] Distance for idty 14572: 4020/4063 = 98.94167%
distance-oracle-distance-oracle-1  | 2024-02-23T00:37:07.772Z DEBUG [distance_oracle] Saving distance evaluation result to file `"/var/lib/duniter/chains/gdev/distance/440"`
distance-oracle-distance-oracle-1  | Waiting 1800 seconds before next execution...
distance-oracle-distance-oracle-1  | 2024-02-23T01:07:07.835Z DEBUG [distance_oracle::api] Looking at Pool2 for session 439
distance-oracle-distance-oracle-1  | 2024-02-23T01:07:07.837Z INFO  [distance_oracle] Nothing to do: File already exists
distance-oracle-distance-oracle-1  | Waiting 1800 seconds before next execution...

Oui j’ai eu peur un moment, mais c’est le bon message quand il n’y a rien à faire pour la session.


Quand il n’y a aucune demande, l’oracle n’est pas consulté. Il ne parle que quand on a besoin de lui comme l’exemple dans mes logs.

1 Like

ouf… car si l’oracle est aveugle, on n’est pas dans la merde !!! :joy:

1 Like

Voilà en plus lisible la partie intéressante :

DEBUG [distance_oracle::api] Looking at Pool2 for session 439
INFO  [distance_oracle] Evaluating distance for session 439
DEBUG [distance_oracle] Evaluating distance for idty 14572
INFO  [distance_oracle] Distance for idty 14572: 4020/4063 = 98.94167%
DEBUG [distance_oracle] Saving distance evaluation result to file `"/var/lib/duniter/chains/gdev/distance/440"`

Il faudra faire des renouvellements d’adhésion en masse pour voir comment l’oracle se comporte maintenant qu’il y en a deux.

1 Like

Toujours pareil, je reste à votre dispo !!


Je vois de la commande Sudo !!! Monsieur @HugoTrentesaux fait des tests !!! :saluting_face:

2 Likes

Affirmatif ! J’ai demandé l’évaluation de la distance pour plusieurs identités, certaines dont l’adhésion a expiré, d’autres qui étaient sur le point d’expirer. Dans les interfaces ça s’appellera “redemander l’adhésion” ou “renouveler l’adhésion” en fonction des cas. Mais c’est le même appel. Je l’ai fait en sudo car seul les utilisateurs peuvent gérer leurs identités. Et pour savoir quels utilisateurs utiliser, j’ai fait :

query MembershipsToExpire {
  identities(
    limit: 10
    orderBy: expireOn_ASC
    where: { expireOn_gt: 320000, AND: { expireOn_lt: 333333 } }
  ) {
    id
    index
    name
    expireOn
  }
}

Donc au prochain round, ton oracle (et le mien) auront un peu de travail.

2 Likes

_duniter-v2s-oracle-dist-distance-oracle-1_logs.txt (3,7 Ko)
pas bossé longtemps l’oracle…quel faignasse!!!

1 Like

C’est étonnant, je regarderai. Il est censé vérifier s’il a déjà publié.

Justement, ça veut dire qu’il travaille vite ! Et si tu regardes le graphique d’utilisation des cœurs du processeur, ils devraient tous être utilisés simultanément.
Sur une machine moins puissante, avec beaucoup plus de demandes et une toile plus large, il pourrait mettre plusieurs secondes voire minutes à tourner.

Edit: par contre les erreurs et les documentations ont été changées, je ne comprends pas ce que signifie TooManyEvaluationsByAuthor dont le doc-comment me semble avoir un sens contradictoire. Je n’ai pas suivi la vague de changements que vous avez faits depuis donc je suis complètement perdu, il faudra que je relise tout.

1 Like

Ça n’a pas tant changé que ça, c’est surtout des commentaires en plus. Et l’erreur TooManyEvaluationsByAuthor est toujours retournée lorsque l’auteur essaye de publier plusieurs fois une évaluation dans la même session avec l’inherent update_evaluation.

/// update distance evaluation in next pool
fn do_update_evaluation(
    evaluator: <T as frame_system::Config>::AccountId,
    computation_result: ComputationResult,
) -> DispatchResult {
    Pallet::<T>::mutate_next_pool(pallet_session::CurrentIndex::<T>::get(), |result_pool| {
        // evaluation must be provided for all identities (no more, no less)
        ensure!(
            computation_result.distances.len() == result_pool.evaluations.len(),
            Error::<T>::WrongResultLength
        );

        // insert the evaluator if not already there
        if result_pool
            .evaluators
            .try_insert(evaluator.clone())
            .map_err(|_| Error::<T>::TooManyEvaluators)?
        {
            // update the median accumulator with the new result
            for (distance_value, (_identity, median_acc)) in computation_result
                .distances
                .into_iter()
                .zip(result_pool.evaluations.iter_mut())
            {
                median_acc.push(distance_value);
            }
            Ok(())
        } else {
            // one author can only submit one evaluation
            Err(Error::<T>::TooManyEvaluationsByAuthor.into())
        }
    })
}

Pour l’instant je vois que le client de distance regarde s’il ne fait pas partie des evaluators des published_results, mais il récupère cette donnée en utilisant un storage prefix hardcodé :

let published_results = client
    .storage(
        parent,
        &StorageKey(
            frame_support::storage::storage_prefix(

Il est possible que ce préfixe ait évolué et comme il n’y a pas de test pour ce scénario on ne s’en est pas aperçu. C’est mon hypothèse pour l’instant.