From 6b7c97aeabb6f2074d79c5bb8ff0790d0dd0c98b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Moreau?= <cem.moreau@gmail.com> Date: Fri, 5 Jan 2024 21:26:00 +0100 Subject: [PATCH] feat(#157) "Ease the installation of distance Oracle" (nodes/rust/duniter-v2s!214) * feat(#157): documentation with docker-compose.yml * fix(#157): review: apt-get clean * fix(#157): review: either `--` launch or loop * feat(#157): output example * feat(#157): Dockerfile update * feat(#157): add logs for oracle --- client/distance/src/lib.rs | 15 +++++++++++++-- distance-oracle/README.md | 11 ++++++++++- distance-oracle/src/api.rs | 16 +++++++++++++--- distance-oracle/src/lib.rs | 23 +++++++++++++++++------ docker-compose.yml | 13 +++++++++++++ docker/Dockerfile | 7 +++++++ docker/docker-distance-entrypoint | 21 +++++++++++++++++++++ 7 files changed, 94 insertions(+), 12 deletions(-) create mode 100755 docker/docker-distance-entrypoint diff --git a/client/distance/src/lib.rs b/client/distance/src/lib.rs index 821be0c6d..f2b29cbe9 100644 --- a/client/distance/src/lib.rs +++ b/client/distance/src/lib.rs @@ -43,6 +43,7 @@ where IdtyIndex: Decode + Encode + PartialEq + TypeInfo, { let &[owner_key] = owner_keys else { + log::error!("🧙 [distance oracle] More than one Babe owner key: oracle cannot work"); return Ok(sp_distance::InherentDataProvider::<IdtyIndex>::new(None)); }; let owner_key = sp_runtime::AccountId32::new(owner_key.0); @@ -82,23 +83,33 @@ where // Have we already published a result for this session? if published_results.evaluators.contains(&owner_key) { + log::debug!("🧙 [distance oracle] Already published a result for this session"); return Ok(sp_distance::InherentDataProvider::<IdtyIndex>::new(None)); } // Read evaluation result from file, if it exists + log::debug!( + "🧙 [distance oracle] Reading evaluation result from file {:?}", + distance_dir.clone().join(session_index.to_string()) + ); let evaluation_result = match std::fs::read(distance_dir.join(session_index.to_string())) { Ok(data) => data, Err(e) => { match e.kind() { - std::io::ErrorKind::NotFound => {} + std::io::ErrorKind::NotFound => { + log::debug!("🧙 [distance oracle] Evaluation result file not found"); + } _ => { - log::error!("Cannot read distance evaluation result file: {e:?}"); + log::error!( + "🧙 [distance oracle] Cannot read distance evaluation result file: {e:?}" + ); } } return Ok(sp_distance::InherentDataProvider::<IdtyIndex>::new(None)); } }; + log::info!("🧙 [distance oracle] Providing evaluation result"); Ok(sp_distance::InherentDataProvider::<IdtyIndex>::new(Some( sp_distance::ComputationResult::decode(&mut evaluation_result.as_slice()).unwrap(), ))) diff --git a/distance-oracle/README.md b/distance-oracle/README.md index 5a4233827..cff2d0546 100644 --- a/distance-oracle/README.md +++ b/distance-oracle/README.md @@ -17,4 +17,13 @@ This feature is organized in multiple parts: - **/distance-oracle/** (here): binary executing the distance algorithm - **/primitives/distance/**: primitive types used both by client and runtime - **/client/distance/**: exposes the `create_distance_inherent_data_provider` which provides data to the runtime -- **/pallets/distance/**: distance pallet exposing type, traits, storage/calls/hooks executing in the runtime \ No newline at end of file +- **/pallets/distance/**: distance pallet exposing type, traits, storage/calls/hooks executing in the runtime + +## Usage (with Docker) + +See [docker-compose.yml](../docker-compose.yml) for an example of how to run the distance oracle with Docker. + +Output: + + 2023-12-09T14:45:05.942Z INFO [distance_oracle] Nothing to do: Pool does not exist + Waiting 1800 seconds before next execution... \ No newline at end of file diff --git a/distance-oracle/src/api.rs b/distance-oracle/src/api.rs index 8a7699811..0ddcaba1d 100644 --- a/distance-oracle/src/api.rs +++ b/distance-oracle/src/api.rs @@ -15,6 +15,7 @@ // along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>. use crate::runtime; +use log::debug; use sp_core::H256; use subxt::storage::StorageKey; @@ -52,9 +53,18 @@ pub async fn current_pool( .storage() .at(parent_hash) .fetch(&match current_session % 3 { - 0 => runtime::storage().distance().evaluation_pool1(), - 1 => runtime::storage().distance().evaluation_pool2(), - 2 => runtime::storage().distance().evaluation_pool0(), + 0 => { + debug!("Looking at Pool1 for session {}", current_session); + runtime::storage().distance().evaluation_pool1() + } + 1 => { + debug!("Looking at Pool2 for session {}", current_session); + runtime::storage().distance().evaluation_pool2() + } + 2 => { + debug!("Looking at Pool0 for session {}", current_session); + runtime::storage().distance().evaluation_pool0() + } _ => unreachable!("n%3<3"), }) .await diff --git a/distance-oracle/src/lib.rs b/distance-oracle/src/lib.rs index 738e43bbc..bc8c432ba 100644 --- a/distance-oracle/src/lib.rs +++ b/distance-oracle/src/lib.rs @@ -28,7 +28,7 @@ use api::{AccountId, IdtyIndex}; use codec::Encode; use fnv::{FnvHashMap, FnvHashSet}; -use log::{debug, error, warn}; +use log::{debug, error, info, warn}; use rayon::iter::IntoParallelRefIterator; use rayon::iter::ParallelIterator; use std::io::Write; @@ -93,6 +93,7 @@ pub async fn run_and_save(client: &api::Client, settings: Settings) { return; }; + debug!("Saving distance evaluation result to file `{evaluation_result_path:?}`"); let mut evaluation_result_file = std::fs::OpenOptions::new() .write(true) .create_new(true) @@ -155,13 +156,13 @@ pub async fn run( // Fetch the pending identities let Some(evaluation_pool) = api::current_pool(client, parent_hash, current_session).await else { - debug!("Nothing to do: Pool does not exist"); + info!("Nothing to do: Pool does not exist"); return None; }; // Stop if nothing to evaluate if evaluation_pool.evaluations.0.is_empty() { - debug!("Nothing to do: Pool is empty"); + info!("Nothing to do: Pool is empty"); return None; } @@ -172,7 +173,7 @@ pub async fn run( if handle_fs { // Stop if already evaluated if evaluation_result_path.try_exists().unwrap() { - debug!("Nothing to do: File already exists"); + info!("Nothing to do: File already exists"); return None; } @@ -184,6 +185,7 @@ pub async fn run( }); } + info!("Evaluating distance for session {}", current_session); let evaluation_block = api::evaluation_block(client, parent_hash).await; // member idty -> issued certs @@ -292,6 +294,7 @@ fn distance_rule( depth: u32, idty: IdtyIndex, ) -> sp_runtime::Perbill { + debug!("Evaluating distance for idty {}", idty); let mut accessible_referees = FnvHashSet::<IdtyIndex>::with_capacity_and_hasher(referees.len(), Default::default()); let mut known_idties = @@ -304,12 +307,20 @@ fn distance_rule( &mut known_idties, depth, ); - if referees.contains_key(&idty) { + let result = if referees.contains_key(&idty) { sp_runtime::Perbill::from_rational( accessible_referees.len() as u32 - 1, referees.len() as u32 - 1, ) } else { sp_runtime::Perbill::from_rational(accessible_referees.len() as u32, referees.len() as u32) - } + }; + info!( + "Distance for idty {}: {}/{} = {}%", + idty, + accessible_referees.len(), + referees.len(), + result.deconstruct() as f32 / 1_000_000_000f32 * 100f32 + ); + result } diff --git a/docker-compose.yml b/docker-compose.yml index 5a575fc10..6fbb11bc9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -22,6 +22,19 @@ services: DUNITER_CHAIN_NAME: "gdev" volumes: - duniter-local-data:/var/lib/duniter + distance-oracle: + container_name: distance-oracle + # choose the version of the image here + image: duniter/duniter-v2s:latest + entrypoint: docker-distance-entrypoint + environment: + ORACLE_RPC_URL: "ws://duniter-v2s:9944" + ORACLE_RESULT_DIR: "/var/lib/duniter/chains/gdev/distance/" + ORACLE_EXECUTION_INTERVAL: "10" + ORACLE_MAX_DEPTH: "5" + ORACLE_LOG_LEVEL: "info" + volumes: + - duniter-local-data:/var/lib/duniter volumes: duniter-local-data: diff --git a/docker/Dockerfile b/docker/Dockerfile index b35823409..aa49422db 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -84,6 +84,12 @@ LABEL maintainer="Gilles Filippini <gilles.filippini@pini.fr>" LABEL version="0.0.0" LABEL description="Crypto-currency software (based on Substrate framework) to operate Ğ1 libre currency" +# Required certificates for RPC connections +RUN apt-get update \ + && apt-get install -y --no-install-recommends ca-certificates +RUN update-ca-certificates +RUN apt-get clean && rm -rf /var/lib/apt/lists/* + RUN adduser --home /var/lib/duniter duniter # Configuration @@ -96,3 +102,4 @@ USER duniter # Intall COPY --from=build /root/build /usr/local/bin/ COPY docker/docker-entrypoint /usr/local/bin/ +COPY docker/docker-distance-entrypoint /usr/local/bin/ diff --git a/docker/docker-distance-entrypoint b/docker/docker-distance-entrypoint new file mode 100755 index 000000000..3298bcdab --- /dev/null +++ b/docker/docker-distance-entrypoint @@ -0,0 +1,21 @@ +#!/bin/bash + +# Custom startup if a first argument is present and is equal to '--' +# then we just run duniter with the provided arguments (but the '--') +# without applying all the automated configuration below +if [ "$1" = -- ]; then + shift + distance-oracle "$@" +else + ORACLE_RESULT_DIR="${ORACLE_RESULT_DIR:-/distance}" + ORACLE_EXECUTION_INTERVAL="${ORACLE_EXECUTION_INTERVAL:-1800}" + ORACLE_MAX_DEPTH="${ORACLE_MAX_DEPTH:-5}" + ORACLE_RPC_URL="${ORACLE_RPC_URL:-ws://127.0.0.1:9944}" + ORACLE_LOG_LEVEL="${ORACLE_LOG_LEVEL:-info}" + + while [ true ]; do + distance-oracle -d "$ORACLE_RESULT_DIR" -D "$ORACLE_MAX_DEPTH" -u "$ORACLE_RPC_URL" -l "$ORACLE_LOG_LEVEL" + echo "Waiting $ORACLE_EXECUTION_INTERVAL seconds before next execution..." + sleep $ORACLE_EXECUTION_INTERVAL + done +fi -- GitLab