Skip to content
Snippets Groups Projects
Select Git revision
  • master
  • develop default protected
  • feature/add_code_pin
  • 35-endpoint-discovery-and-filtering
  • bugfix/dorian_rx-state
  • enh/forget-account-dev-mode
  • hugo/i18n
  • feature/test_ci protected
  • feature/release-description
  • hugo-dev
  • demo-cgeek
  • 2.0.0-alpha53
  • 2.0.0-alpha52
  • 2.0.0-alpha51
  • 2.0.0-alpha49
  • 2.0.0-alpha48
  • 2.0.0-alpha47
  • 2.0.0-alpha46
  • 2.0.0-alpha45
  • 2.0.0-alpha43
  • 2.0.0-alpha42
  • 2.0.0-alpha41
  • 2.0.0-alpha40
  • 2.0.0-alpha38
  • 2.0.0-alpha37
  • 2.0.0-alpha36
  • 2.0.0-alpha22
  • 2.0.0-alpha21
  • 2.0.0-alpha20
  • 2.0.0-alpha13
  • 2.0.0-alpha10
31 results

build.md

Blame
  • lib.rs 19.97 KiB
    //  Copyright (C) 2017-2018  The Duniter Project Developers.
    //
    // This program is free software: you can redistribute it and/or modify
    // it under the terms of the GNU Affero General Public License as
    // published by the Free Software Foundation, either version 3 of the
    // License, or (at your option) any later version.
    //
    // This program is distributed in the hope that it will be useful,
    // but WITHOUT ANY WARRANTY; without even the implied warranty of
    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    // GNU Affero General Public License for more details.
    //
    // You should have received a copy of the GNU Affero General Public License
    // along with this program.  If not, see <https://www.gnu.org/licenses/>.
    
    //! `wot` is a crate making "Web of Trust" computations for
    //! the [Duniter] project.
    //!
    //! [Duniter]: https://duniter.org/
    //!
    //! It defines a trait representing a Web of Trust and allow to do calculations on it.
    //!
    //! It also contains an "legacy" implementation translated from the original C++ code.
    //!
    //! Web of Trust tests are translated from [duniter/wot Javascript test][js-tests].
    //!
    //! [js-tests]: https://github.com/duniter/wot/blob/master/wotcpp/webOfTrust.cpp
    
    #![cfg_attr(feature = "strict", deny(warnings))]
    #![deny(
        missing_docs,
        missing_debug_implementations,
        missing_copy_implementations,
        trivial_casts,
        trivial_numeric_casts,
        unsafe_code,
        unstable_features,
        unused_import_braces,
        unused_qualifications
    )]
    
    extern crate bincode;
    extern crate byteorder;
    extern crate rayon;
    extern crate serde;
    #[macro_use]
    extern crate serde_derive;
    
    pub mod data;
    pub mod operations;
    
    pub use data::{NodeId, WebOfTrust};
    
    #[cfg(test)]
    mod tests {
        use super::*;
        use data::*;
        use operations::centrality::*;
        use operations::distance::*;
        use operations::file::*;
        use operations::path::*;
    
        /// Test translated from https://github.com/duniter/wot/blob/master/tests/test.js
        ///
        /// Clone and file tests are not included in this generic test and should be done in
        /// the implementation test.
        pub fn generic_wot_test<W>()
        where
            W: WebOfTrust + Sync,
        {
            let centralities_calculator = UlrikBrandesCentralityCalculator {};
            let distance_calculator = RustyDistanceCalculator {};
            let path_finder = RustyPathFinder {};
            let mut wot = W::new(3);
    
            // should have an initial size of 0
            assert_eq!(wot.size(), 0);
    
            // should return `None()` if testing `is_enabled()` with out-of-bounds node
            assert_eq!(wot.is_enabled(NodeId(0)), None);
            assert_eq!(wot.is_enabled(NodeId(23)), None);
    
            // should give nomber 0 if we add a node
            // - add a node
            assert_eq!(wot.add_node(), NodeId(0));
            assert_eq!(wot.size(), 1);
            assert_eq!(wot.get_disabled().len(), 0);
    
            // - add another
            assert_eq!(wot.add_node(), NodeId(1));
            assert_eq!(wot.size(), 2);
            assert_eq!(wot.get_disabled().len(), 0);
    
            // - add 10 nodes
            for i in 0..10 {
                assert_eq!(wot.add_node(), NodeId(i + 2));
            }
    
            assert_eq!(wot.size(), 12);
    
            // shouldn't be able to self cert
            assert_eq!(
                wot.add_link(NodeId(0), NodeId(0)),
                NewLinkResult::SelfLinkingForbidden()
            );
    
            // should add certs only in the boundaries of max_cert
            assert_eq!(wot.add_link(NodeId(0), NodeId(1)), NewLinkResult::Ok(1));
            assert_eq!(wot.add_link(NodeId(0), NodeId(2)), NewLinkResult::Ok(1));
            assert_eq!(wot.add_link(NodeId(0), NodeId(3)), NewLinkResult::Ok(1));
            assert_eq!(
                wot.add_link(NodeId(0), NodeId(4)),
                NewLinkResult::AllCertificationsUsed(0)
            );
    
            assert_eq!(wot.get_max_link(), 3);
            assert_eq!(
                wot.has_link(NodeId(0), NodeId(1)),
                HasLinkResult::Link(true)
            );
            assert_eq!(
                wot.has_link(NodeId(0), NodeId(2)),
                HasLinkResult::Link(true)
            );
            assert_eq!(
                wot.has_link(NodeId(0), NodeId(3)),
                HasLinkResult::Link(true)
            );
            assert_eq!(
                wot.has_link(NodeId(0), NodeId(4)),
                HasLinkResult::Link(false)
            );
    
            wot.set_max_link(4);
            assert_eq!(wot.get_max_link(), 4);
            assert_eq!(
                wot.has_link(NodeId(0), NodeId(4)),
                HasLinkResult::Link(false)
            );
            wot.add_link(NodeId(0), NodeId(4));
            assert_eq!(
                wot.has_link(NodeId(0), NodeId(4)),
                HasLinkResult::Link(true)
            );
            wot.rem_link(NodeId(0), NodeId(1));
            wot.rem_link(NodeId(0), NodeId(2));
            wot.rem_link(NodeId(0), NodeId(3));
            wot.rem_link(NodeId(0), NodeId(4));
    
            // false when not linked + test out of bounds
            assert_eq!(
                wot.has_link(NodeId(0), NodeId(6)),
                HasLinkResult::Link(false)
            );
            assert_eq!(
                wot.has_link(NodeId(23), NodeId(0)),
                HasLinkResult::UnknownSource()
            );
            assert_eq!(
                wot.has_link(NodeId(2), NodeId(53)),
                HasLinkResult::UnknownTarget()
            );
    
            // created nodes should be enabled
            assert_eq!(wot.is_enabled(NodeId(0)), Some(true));
            assert_eq!(wot.is_enabled(NodeId(1)), Some(true));
            assert_eq!(wot.is_enabled(NodeId(2)), Some(true));
            assert_eq!(wot.is_enabled(NodeId(3)), Some(true));
            assert_eq!(wot.is_enabled(NodeId(11)), Some(true));
    
            // should be able to disable some nodes
            assert_eq!(wot.set_enabled(NodeId(0), false), Some(false));
            assert_eq!(wot.set_enabled(NodeId(1), false), Some(false));
            assert_eq!(wot.set_enabled(NodeId(2), false), Some(false));
            assert_eq!(wot.get_disabled().len(), 3);
            assert_eq!(wot.set_enabled(NodeId(1), true), Some(true));
    
            // node 0 and 2 should be disabled
            assert_eq!(wot.is_enabled(NodeId(0)), Some(false));
            assert_eq!(wot.is_enabled(NodeId(1)), Some(true));
            assert_eq!(wot.is_enabled(NodeId(2)), Some(false));
            assert_eq!(wot.is_enabled(NodeId(3)), Some(true));
            // - set enabled again
            assert_eq!(wot.set_enabled(NodeId(0), true), Some(true));
            assert_eq!(wot.set_enabled(NodeId(1), true), Some(true));
            assert_eq!(wot.set_enabled(NodeId(2), true), Some(true));
            assert_eq!(wot.set_enabled(NodeId(1), true), Some(true));
            assert_eq!(wot.get_disabled().len(), 0);
    
            // should not exist a link from 2 to 0
            assert_eq!(
                wot.has_link(NodeId(2), NodeId(0)),
                HasLinkResult::Link(false)
            );
    
            // should be able to add some links, cert count is returned
            assert_eq!(wot.add_link(NodeId(2), NodeId(0)), NewLinkResult::Ok(1));
            assert_eq!(wot.add_link(NodeId(4), NodeId(0)), NewLinkResult::Ok(2));
            assert_eq!(wot.add_link(NodeId(5), NodeId(0)), NewLinkResult::Ok(3));
    
            // should exist new links
            /* WoT is:
             *
             * 2 --> 0
             * 4 --> 0
             * 5 --> 0
             */
    
            assert_eq!(
                wot.has_link(NodeId(2), NodeId(0)),
                HasLinkResult::Link(true)
            );
            assert_eq!(
                wot.has_link(NodeId(4), NodeId(0)),
                HasLinkResult::Link(true)
            );
            assert_eq!(
                wot.has_link(NodeId(5), NodeId(0)),
                HasLinkResult::Link(true)
            );
            assert_eq!(
                wot.has_link(NodeId(2), NodeId(1)),
                HasLinkResult::Link(false)
            );
    
            // should be able to remove some links
            assert_eq!(
                wot.rem_link(NodeId(4), NodeId(0)),
                RemLinkResult::Removed(2)
            );
            /*
             * WoT is now:
             *
             * 2 --> 0
             * 5 --> 0
             */
    
            // should exist less links
            assert_eq!(
                wot.has_link(NodeId(2), NodeId(0)),
                HasLinkResult::Link(true)
            );
            assert_eq!(
                wot.has_link(NodeId(4), NodeId(0)),
                HasLinkResult::Link(false)
            );
            assert_eq!(
                wot.has_link(NodeId(5), NodeId(0)),
                HasLinkResult::Link(true)
            );
            assert_eq!(
                wot.has_link(NodeId(2), NodeId(1)),
                HasLinkResult::Link(false)
            );
    
            // should successfully use distance rule
            assert_eq!(
                distance_calculator.is_outdistanced(
                    &wot,
                    WotDistanceParameters {
                        node: NodeId(0),
                        sentry_requirement: 1,
                        step_max: 1,
                        x_percent: 1.0,
                    },
                ),
                Some(false)
            );
            // => no because 2,4,5 have certified him
            assert_eq!(
                distance_calculator.is_outdistanced(
                    &wot,
                    WotDistanceParameters {
                        node: NodeId(0),
                        sentry_requirement: 2,
                        step_max: 1,
                        x_percent: 1.0,
                    },
                ),
                Some(false)
            );
            // => no because only member 2 has 2 certs, and has certified him
            assert_eq!(
                distance_calculator.is_outdistanced(
                    &wot,
                    WotDistanceParameters {
                        node: NodeId(0),
                        sentry_requirement: 3,
                        step_max: 1,
                        x_percent: 1.0,
                    },
                ),
                Some(false)
            );
            // => no because no member has issued 3 certifications
    
            // - we add links from member 3
            assert_eq!(wot.add_link(NodeId(3), NodeId(1)), NewLinkResult::Ok(1));
            assert_eq!(wot.add_link(NodeId(3), NodeId(2)), NewLinkResult::Ok(1));
            /*
             * WoT is now:
             *
             * 2 --> 0
             * 5 --> 0
             * 3 --> 1
             * 3 --> 2
             */
            assert_eq!(wot.size(), 12);
            assert_eq!(wot.get_sentries(1).len(), 1);
            assert_eq!(wot.get_sentries(1)[0], NodeId(2));
            assert_eq!(wot.get_sentries(2).len(), 0);
            assert_eq!(wot.get_sentries(3).len(), 0);
            assert_eq!(wot.get_non_sentries(1).len(), 11); // 12 - 1
            assert_eq!(wot.get_non_sentries(2).len(), 12); // 12 - 0
            assert_eq!(wot.get_non_sentries(3).len(), 12); // 12 - 0
            assert_eq!(
                path_finder.find_paths(&wot, NodeId(3), NodeId(0), 1).len(),
                0
            ); // KO
            assert_eq!(
                path_finder.find_paths(&wot, NodeId(3), NodeId(0), 2).len(),
                1
            ); // It exists 3 -> 2 -> 0
            assert!(path_finder
                .find_paths(&wot, NodeId(3), NodeId(0), 2)
                .contains(&vec![NodeId(3), NodeId(2), NodeId(0)]));
    
            assert_eq!(
                distance_calculator.is_outdistanced(
                    &wot,
                    WotDistanceParameters {
                        node: NodeId(0),
                        sentry_requirement: 1,
                        step_max: 1,
                        x_percent: 1.0,
                    },
                ),
                Some(false)
            ); // OK : 2 -> 0
            assert_eq!(
                distance_calculator.is_outdistanced(
                    &wot,
                    WotDistanceParameters {
                        node: NodeId(0),
                        sentry_requirement: 2,
                        step_max: 1,
                        x_percent: 1.0,
                    },
                ),
                Some(false)
            ); // OK : 2 -> 0
            assert_eq!(
                distance_calculator.is_outdistanced(
                    &wot,
                    WotDistanceParameters {
                        node: NodeId(0),
                        sentry_requirement: 3,
                        step_max: 1,
                        x_percent: 1.0,
                    },
                ),
                Some(false)
            ); // OK : no stry \w 3 lnk
            assert_eq!(
                distance_calculator.is_outdistanced(
                    &wot,
                    WotDistanceParameters {
                        node: NodeId(0),
                        sentry_requirement: 2,
                        step_max: 2,
                        x_percent: 1.0,
                    },
                ),
                Some(false)
            ); // OK : 2 -> 0
    
            wot.add_link(NodeId(1), NodeId(3));
            wot.add_link(NodeId(2), NodeId(3));
    
            assert_eq!(wot.size(), 12);
            assert_eq!(wot.get_sentries(1).len(), 3);
            assert_eq!(wot.get_sentries(1)[0], NodeId(1));
            assert_eq!(wot.get_sentries(1)[1], NodeId(2));
            assert_eq!(wot.get_sentries(1)[2], NodeId(3));
    
            assert_eq!(wot.get_sentries(2).len(), 1);
            assert_eq!(wot.get_sentries(2)[0], NodeId(3));
            assert_eq!(wot.get_sentries(3).len(), 0);
            assert_eq!(wot.get_non_sentries(1).len(), 9); // 12 - 3
            assert_eq!(wot.get_non_sentries(2).len(), 11); // 12 - 1
            assert_eq!(wot.get_non_sentries(3).len(), 12); // 12 - 0
            assert_eq!(
                path_finder.find_paths(&wot, NodeId(3), NodeId(0), 1).len(),
                0
            ); // KO
            assert_eq!(
                path_finder.find_paths(&wot, NodeId(3), NodeId(0), 2).len(),
                1
            ); // It exists 3 -> 2 -> 0
            assert!(path_finder
                .find_paths(&wot, NodeId(3), NodeId(0), 2)
                .contains(&vec![NodeId(3), NodeId(2), NodeId(0)]));
    
            assert_eq!(
                distance_calculator.is_outdistanced(
                    &wot,
                    WotDistanceParameters {
                        node: NodeId(0),
                        sentry_requirement: 1,
                        step_max: 1,
                        x_percent: 1.0,
                    },
                ),
                Some(true)
            ); // KO : No path 3 -> 0
            assert_eq!(
                distance_calculator.is_outdistanced(
                    &wot,
                    WotDistanceParameters {
                        node: NodeId(0),
                        sentry_requirement: 2,
                        step_max: 1,
                        x_percent: 1.0,
                    },
                ),
                Some(true)
            ); // KO : No path 3 -> 0
            assert_eq!(
                distance_calculator.is_outdistanced(
                    &wot,
                    WotDistanceParameters {
                        node: NodeId(0),
                        sentry_requirement: 3,
                        step_max: 1,
                        x_percent: 1.0,
                    },
                ),
                Some(false)
            ); // OK : no stry \w 3 lnk
            assert_eq!(
                distance_calculator.is_outdistanced(
                    &wot,
                    WotDistanceParameters {
                        node: NodeId(0),
                        sentry_requirement: 2,
                        step_max: 2,
                        x_percent: 1.0,
                    },
                ),
                Some(false)
            ); // OK : 3 -> 2 -> 0
    
            // should have 12 nodes
            assert_eq!(wot.size(), 12);
    
            // delete top node (return new top node id)
            assert_eq!(wot.rem_node(), Some(NodeId(10)));
    
            // should have 11 nodes
            assert_eq!(wot.size(), 11);
    
            // should work with member 3 disabled
            // - with member 3 disabled (non-member)
            assert_eq!(wot.set_enabled(NodeId(3), false), Some(false));
            assert_eq!(wot.get_disabled().len(), 1);
            assert_eq!(
                distance_calculator.is_outdistanced(
                    &wot,
                    WotDistanceParameters {
                        node: NodeId(0),
                        sentry_requirement: 2,
                        step_max: 1,
                        x_percent: 1.0,
                    },
                ),
                Some(false)
            ); // OK : Disabled
    
            let file_formater = BinaryFileFormater {};
    
            // Write wot in file
            assert_eq!(
                file_formater
                    .to_file(
                        &wot,
                        &[0b0000_0000, 0b0000_0001, 0b0000_0001, 0b0000_0000],
                        "test.wot"
                    )
                    .unwrap(),
                ()
            );
    
            let (wot2, blockstamp2) = file_formater.from_file::<W>("test.wot", 3).unwrap();
    
            // Read wot from file
            {
                assert_eq!(
                    blockstamp2,
                    vec![0b0000_0000, 0b0000_0001, 0b0000_0001, 0b0000_0000]
                );
                assert_eq!(wot.size(), wot2.size());
                assert_eq!(
                    wot.get_non_sentries(1).len(),
                    wot2.get_non_sentries(1).len()
                );
                assert_eq!(wot.get_disabled().len(), wot2.get_disabled().len());
                assert_eq!(wot2.get_disabled().len(), 1);
                assert_eq!(wot2.is_enabled(NodeId(3)), Some(false));
                assert_eq!(
                    distance_calculator.is_outdistanced(
                        &wot2,
                        WotDistanceParameters {
                            node: NodeId(0),
                            sentry_requirement: 2,
                            step_max: 1,
                            x_percent: 1.0,
                        },
                    ),
                    Some(false)
                );
            }
    
            // Read g1_genesis wot
            let (wot3, blockstamp3) = file_formater
                .from_file::<W>("tests/g1_genesis.bin", 100)
                .unwrap();
            assert_eq!(
                blockstamp3,
                vec![
                    57, 57, 45, 48, 48, 48, 48, 49, 50, 65, 68, 52, 57, 54, 69, 67, 65, 53, 54, 68, 69,
                    48, 66, 56, 69, 53, 68, 54, 70, 55, 52, 57, 66, 55, 67, 66, 69, 55, 56, 53, 53, 51,
                    69, 54, 51, 56, 53, 51, 51, 51, 65, 52, 52, 69, 48, 52, 51, 55, 55, 69, 70, 70, 67,
                    67, 65, 53, 51,
                ]
            );
    
            // Check g1_genesis wot members_count
            let members_count = wot3.get_enabled().len() as u64;
            assert_eq!(members_count, 59);
    
            // Test compute_distance in g1_genesis wot
            assert_eq!(
                distance_calculator.compute_distance(
                    &wot3,
                    WotDistanceParameters {
                        node: NodeId(37),
                        sentry_requirement: 3,
                        step_max: 5,
                        x_percent: 0.8,
                    },
                ),
                Some(WotDistance {
                    sentries: 48,
                    success: 48,
                    success_at_border: 3,
                    reached: 51,
                    reached_at_border: 3,
                    outdistanced: false,
                },)
            );
    
            // Test betweenness centralities computation in g1_genesis wot
            let centralities = centralities_calculator.betweenness_centralities(&wot3);
            assert_eq!(centralities.len(), 59);
            assert_eq!(
                centralities,
                vec![
                    148, 30, 184, 11, 60, 51, 40, 115, 24, 140, 47, 69, 16, 34, 94, 126, 151, 0, 34,
                    133, 20, 103, 38, 144, 73, 523, 124, 23, 47, 17, 9, 64, 77, 281, 6, 105, 54, 0,
                    111, 21, 6, 2, 0, 1, 47, 59, 28, 236, 0, 0, 0, 0, 60, 6, 0, 1, 8, 33, 169,
                ]
            );
    
            // Test stress centralities computation in g1_genesis wot
            let stress_centralities = centralities_calculator.stress_centralities(&wot3);
            assert_eq!(stress_centralities.len(), 59);
            assert_eq!(
                stress_centralities,
                vec![
                    848, 240, 955, 80, 416, 203, 290, 645, 166, 908, 313, 231, 101, 202, 487, 769, 984,
                    0, 154, 534, 105, 697, 260, 700, 496, 1726, 711, 160, 217, 192, 89, 430, 636, 1276,
                    41, 420, 310, 0, 357, 125, 50, 15, 0, 12, 275, 170, 215, 1199, 0, 0, 0, 0, 201, 31,
                    0, 9, 55, 216, 865,
                ]
            );
    
            // Test distance stress centralities computation in g1_genesis wot
            let distance_stress_centralities =
                centralities_calculator.distance_stress_centralities(&wot3, 5);
            assert_eq!(distance_stress_centralities.len(), 59);
            assert_eq!(
                distance_stress_centralities,
                vec![
                    848, 240, 955, 80, 416, 203, 290, 645, 166, 908, 313, 231, 101, 202, 487, 769, 984,
                    0, 154, 534, 105, 697, 260, 700, 496, 1726, 711, 160, 217, 192, 89, 430, 636, 1276,
                    41, 420, 310, 0, 357, 125, 50, 15, 0, 12, 275, 170, 215, 1199, 0, 0, 0, 0, 201, 31,
                    0, 9, 55, 216, 865,
                ]
            );
        }
    }