diff --git a/Cargo.lock b/Cargo.lock index bec05c6ea47a8ece731eaee0e898523d8379466d..3332a6a21e57245130de04a0a4f1616d15182949 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2402,6 +2402,8 @@ dependencies = [ "num-traits 0.2.19", "parity-scale-codec", "rayon", + "serde", + "serde_json", "simple_logger", "sp-core", "sp-distance", diff --git a/distance-oracle/Cargo.toml b/distance-oracle/Cargo.toml index 3f7614e3e36e6ddd85b76bf55a5df00e11bd59c1..34a63f798fda9c271d8c1c0140b69aac6598c063 100644 --- a/distance-oracle/Cargo.toml +++ b/distance-oracle/Cargo.toml @@ -22,6 +22,7 @@ std = [ "sp-core/std", "sp-distance/std", "sp-runtime/std", + "serde_json/std", ] try-runtime = ["sp-distance/try-runtime", "sp-runtime/try-runtime"] runtime-benchmarks = [] @@ -47,6 +48,8 @@ tokio = { workspace = true, features = [ "rt-multi-thread", "macros", ], optional = true } +serde = { workspace = true } +serde_json = { workspace = true } [dev-dependencies] bincode = { workspace = true } diff --git a/distance-oracle/src/bin/distance_precompute.rs b/distance-oracle/src/bin/distance_precompute.rs index cd07d7b23346628d588804e02a9f34fe37583309..1ffb8727cd8eb183020ce786060e226e76b738e9 100644 --- a/distance-oracle/src/bin/distance_precompute.rs +++ b/distance-oracle/src/bin/distance_precompute.rs @@ -1,4 +1,8 @@ +use api::IdtyIndex; use distance_oracle::api; +use fnv::FnvHashMap; +use log::debug; +use std::{io::Write, path::PathBuf}; // computes distance result for all identities with status other than Revoked // this allows to have a recent estimate of the distance computation @@ -16,28 +20,114 @@ struct Cli { log: log::LevelFilter, } +// +#[derive(serde::Serialize)] +struct PrecomputationResult { + block: sp_core::H256, + results: FnvHashMap<IdtyIndex, sp_runtime::Perbill>, +} + #[tokio::main] async fn main() { + let cli = Cli::parse(); + simple_logger::SimpleLogger::new() .with_level(cli.log) .init() .unwrap(); - let cli = Cli::parse(); - let client = &distance_oracle::api::client(cli.rpc_url.clone()).await; + let parent_hash = api::parent_hash(client).await; // get hash of recent block + let max_depth = api::max_referee_distance(client).await; // get param + let evaluation_block = parent_hash; + + // get certs and member iterators + let mut certs_iter = api::cert_iter(client, evaluation_block).await; + let mut members_iter = api::member_iter(client, evaluation_block).await; - let parent_hash = api::parent_hash(client).await; + // initialize hashmaps + // member idty -> issued certs count (will only retain referees) + let mut members = FnvHashMap::<IdtyIndex, u32>::default(); - let max_depth = api::max_referee_distance(client).await; + // idty -> received certs (collects once from iterator and is passed to distance function) + let mut received_certs = FnvHashMap::<IdtyIndex, Vec<IdtyIndex>>::default(); - let current_pool_index = api::current_pool_index(client, parent_hash).await; + // collect all members + while let Some(member_idty) = members_iter + .next() + .await + .expect("Cannot fetch next members") + { + members.insert(member_idty, 0); + } - let evaluation_block = parent_hash; + // compute certification threshold as a function of the total member count + let min_certs_for_referee = (members.len() as f32).powf(1. / (max_depth as f32)).ceil() as u32; - let mut certs_iter = api::cert_iter(client, evaluation_block).await; - let mut members_iter = api::member_iter(client, evaluation_block).await; + // collect certifications and updates members map at the same time + while let Some((receiver, issuers)) = certs_iter + .next() + .await + .expect("Cannot fetch next certification") + { + if (issuers.len() as u32) < min_certs_for_referee { + // This member is not referee (not enough received certs) + members.remove(&receiver); + } + for (issuer, _removable_on) in issuers.iter() { + if let Some(issued_certs) = members.get_mut(issuer) { + // update number of issued certs + *issued_certs += 1; + } + } + // collect certifications + received_certs.insert( + receiver, + issuers + .into_iter() + .map(|(issuer, _removable_on)| issuer) + .collect(), + ); + } + + // Only retain referees + members.retain(|_idty, issued_certs| *issued_certs >= min_certs_for_referee); + let referees = members; + + // initialize map of distance results + let mut results = FnvHashMap::<IdtyIndex, sp_runtime::Perbill>::default(); + + // compute all distances + received_certs.keys().into_iter().for_each(|idty| { + results.insert( + *idty, + distance_oracle::distance_rule(&received_certs, &referees, max_depth, *idty), + ); + }); - // TODO - unimplemented!() + // ---- SAVE + let evaluation_result_path = + Into::<PathBuf>::into(cli.evaluation_result_dir).join("todo-block-number".to_string()); + debug!("Saving distance evaluation result to file `{evaluation_result_path:?}`"); + let mut evaluation_result_file = std::fs::OpenOptions::new() + .write(true) + .create_new(true) + .open(&evaluation_result_path) + .unwrap_or_else(|e| { + panic!( + "Cannot open distance evaluation result file `{evaluation_result_path:?}`: {e:?}" + ) + }); + evaluation_result_file + .write_all( + &serde_json::to_vec( &PrecomputationResult { + block: evaluation_block, + results: results, + }).expect("Cannot serialize result"), + ) + .unwrap_or_else(|e| { + panic!( + "Cannot write distance evaluation result to file `{evaluation_result_path:?}`: {e:?}" + ) + }); } diff --git a/distance-oracle/src/lib.rs b/distance-oracle/src/lib.rs index 965ed8b20ee0d8f79eb261600ae948536b466559..855e1fea9e3a81b98719b6024b62063cf9b0021e 100644 --- a/distance-oracle/src/lib.rs +++ b/distance-oracle/src/lib.rs @@ -294,7 +294,7 @@ fn distance_rule_recursive( } /// Returns the fraction `nb_accessible_referees / nb_referees` -fn distance_rule( +pub fn distance_rule( received_certs: &FnvHashMap<IdtyIndex, Vec<IdtyIndex>>, referees: &FnvHashMap<IdtyIndex, u32>, depth: u32,