diff --git a/Cargo.lock b/Cargo.lock index a56b5b7923bd05f566a13dcfd200c065feef7522..c22bb19bf1ea8829d83603e313f2a3b609c270a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -577,6 +577,7 @@ dependencies = [ "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "unwrap 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1327,6 +1328,38 @@ dependencies = [ "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "num" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "num-complex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-bigint" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-complex" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num-integer" version = "0.1.41" @@ -1336,6 +1369,27 @@ dependencies = [ "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "num-iter" +version = "0.1.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-rational" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num-traits" version = "0.2.8" @@ -2611,7 +2665,12 @@ dependencies = [ "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" +"checksum num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf4825417e1e1406b3782a8ce92f4d53f26ec055e3622e1881ca8e9f5f9e08db" +"checksum num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f9c3f34cdd24f334cb265d9bf8bfa8a241920d026916785747a92f0e55541a1a" +"checksum num-complex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fcb0cf31fb3ff77e6d2a6ebd6800df7fdcd106f2ad89113c9130bcd07f93dffc" "checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" +"checksum num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "76bd5272412d173d6bf9afdf98db8612bbabc9a7a830b7bfc9c188911716132e" +"checksum num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2885278d5fe2adc2f75ced642d52d879bffaceb5a2e0b1d4309ffdfb239b454" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" "checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" diff --git a/lib/modules-lib/bc-db-reader/Cargo.toml b/lib/modules-lib/bc-db-reader/Cargo.toml index e23d3c150523ed07643a7c6e95209790aedb2f7d..c5bff6033995025fc64f8bb5fbe58d667df271cb 100644 --- a/lib/modules-lib/bc-db-reader/Cargo.toml +++ b/lib/modules-lib/bc-db-reader/Cargo.toml @@ -26,6 +26,7 @@ maplit = "1.0.1" fnv = "1.0.6" serde = { version = "1.0.*", features = ["derive"] } unwrap = "1.2.1" +num = "0.2" [dev-dependencies] dup-crypto-tests-tools = { path = "../../tests-tools/crypto-tests-tools" } diff --git a/lib/modules-lib/bc-db-reader/src/current_frame.rs b/lib/modules-lib/bc-db-reader/src/current_frame.rs index a69091ea0d559dd161b65295bb2886273ffe62ad..07e3259916ab50c705cc03a90d90b1f113169fe0 100644 --- a/lib/modules-lib/bc-db-reader/src/current_frame.rs +++ b/lib/modules-lib/bc-db-reader/src/current_frame.rs @@ -17,8 +17,11 @@ //use crate::constants::*; use crate::*; +extern crate num; +use dubp_common_doc::BlockNumber; use durs_dbs_tools::DbError; use durs_wot::WotId; +use num::Float; #[derive(Clone, Copy, Debug, Eq, PartialEq)] /// Describe a member in current frame @@ -54,3 +57,95 @@ pub fn get_member_diffi<DB: DbReadable, R: DbReader>( ) -> Result<PersonalDifficulty, DbError> { unimplemented!(); } + +/// calcule la difficulté personnalisée à partir des données prêtes à l'emploi +/// reference dans le protocol : https://github.com/duniter/duniter/blob/master/doc/Protocol.md#br_g18---headpowzeros-and-headpowremainder +pub fn compute_personal_difficulty( + nb_member_in_frame: usize, + last_personal_block_number: BlockNumber, + current_block_number: BlockNumber, + nb_personal_blocks_in_frame: usize, + median_of_blocks_in_frame: usize, +) -> PersonalDifficulty { + PersonalDifficulty { + exclusion_factor: exclusion_factor( + nb_member_in_frame, + current_block_number.0 - last_personal_block_number.0, + ), + handicap: handicap(nb_personal_blocks_in_frame, median_of_blocks_in_frame), + } +} + +/// calcule le facteur d'exclusion à partir des membres de la fenêtres courante et du dernier block du membre concerné +/// ne gère pas le cas où le membre n'est pas dans la fenêtre courante +/// +/// nb_member_in_frame : la valeur du champ issuersCount du dernier bloc trouvé par le membre +/// nb_blocks_since : le nombre de blocs trouvés par le reste du réseau depuis que le membre considéré a trouvé son dernier bloc +/// exclusion_factor = MAX [ 1 ; FLOOR (0.67 * nb_member_in_frame / (1 + nb_blocks_since)) ] +/// +/// reference dans le protocol : https://github.com/duniter/duniter/blob/master/doc/Protocol.md#br_g18---headpowzeros-and-headpowremainder +pub fn exclusion_factor(nb_member_in_frame: usize, nb_blocks_since: u32) -> usize { + std::cmp::max( + 1, + (0.67 * (nb_member_in_frame as f64 / (1 + nb_blocks_since) as f64)).floor() as usize, + ) +} + +/// handicap calcule le handicap d'un membre à partir du nombre de blocs qu'il a caclulé dans la fenêtre courante et du +/// nombre median de blocs écrits par les membres dans la fenêtre courante. +/// ne gère pas le cas où le membre n'est pas dans la fenêtre courante +/// +/// nb_personal_blocks_in_frame : le nombre de blocs écrits par le membre considéré dans la fenêtre courante +/// median_of_blocks_in_frame : le nombre médian de blocs écrits par les membres au sein de la fenêtre courante. +/// handicap = FLOOR(LN(MAX(1;(nb_personal_blocks_in_frame + 1) / median_of_blocks_in_frame)) / LN(1.189)) +/// +/// reference dans le protocol : https://github.com/duniter/duniter/blob/master/doc/Protocol.md#br_g18---headpowzeros-and-headpowremainder +pub fn handicap(nb_personal_blocks_in_frame: usize, median_of_blocks_in_frame: usize) -> usize { + (((std::cmp::max( + 1, + (nb_personal_blocks_in_frame + 1) / median_of_blocks_in_frame, + )) as f64) + .ln() + / 1.189.ln()) + .floor() as usize +} + +#[cfg(test)] +mod tests { + use super::*; + //TODO: déplacer la fonction métier dans blockchain ou bc-db-writer + + #[test] + fn test_exclusion_factor() { + assert_eq!(1, exclusion_factor(1, 0)); + assert_eq!(2, exclusion_factor(15, 4)); + } + + #[test] + fn test_handicap() { + assert_eq!(13, handicap(500, 50)); + assert_eq!(0, handicap(1, 50)); + } + + #[test] + fn test_compute_personal_difficulty_no_penality() { + assert_eq!( + PersonalDifficulty { + exclusion_factor: 1, + handicap: 0 + }, + compute_personal_difficulty(100, BlockNumber(1000), BlockNumber(1100), 2, 5) + ); + } + + #[test] + fn test_compute_personal_difficulty_double_penality() { + assert_eq!( + PersonalDifficulty { + exclusion_factor: 3, + handicap: 10 + }, + compute_personal_difficulty(50, BlockNumber(1000), BlockNumber(1010), 5, 1) + ); + } +}