Pārlūkot izejas kodu

Simulation: Give user chance to use bridges each day

Vecna 9 mēneši atpakaļ
vecāks
revīzija
6b6836dbae
1 mainītis faili ar 176 papildinājumiem un 154 dzēšanām
  1. 176 154
      src/simulation/user.rs

+ 176 - 154
src/simulation/user.rs

@@ -26,6 +26,9 @@ pub struct User {
 
     // Does the user submit reports to Troll Patrol?
     submits_reports: bool,
+
+    // How likely is this user to use bridges on a given day?
+    prob_use_bridges: f64,
 }
 
 impl User {
@@ -63,12 +66,17 @@ impl User {
             cc
         };
 
+        // Randomly determine how likely this user is to use bridges on
+        // a given day
+        let prob_use_bridges = rng.gen_range(0.0..=1.0);
+
         Self {
             censor: censor,
             country: cc,
             primary_cred: cred,
             secondary_cred: None,
             submits_reports: submits_reports,
+            prob_use_bridges: prob_use_bridges,
         }
     }
 
@@ -127,12 +135,17 @@ impl User {
             cc
         };
 
+        // Randomly determine how likely this user is to use bridges on
+        // a given day
+        let prob_use_bridges = rng.gen_range(0.0..=1.0);
+
         Ok(Self {
             censor: censor,
             country: cc,
             primary_cred: friend_cred,
             secondary_cred: None,
             submits_reports: submits_reports,
+            prob_use_bridges: prob_use_bridges,
         })
     }
 
@@ -179,180 +192,189 @@ impl User {
     // newly invited friends and a vector of fingerprints of successfully
     // contacted bridges.
     pub async fn daily_tasks(&mut self, state: &State) -> (Vec<User>, Vec<[u8; 20]>) {
-        // Download bucket to see if bridge is still reachable
-        // (We assume that this step can be done even if the user can't actually
-        // talk to the LA.)
-        let (bucket, reachcred) = get_bucket(&state.net, &self.primary_cred).await;
-        let level = scalar_u32(&self.primary_cred.trust_level).unwrap();
-
-        // Can we level up the main credential?
-        let can_level_up = reachcred.is_some()
-            && (level == 0 && eligible_for_trust_promotion(&state.net, &self.primary_cred).await
-                || level > 0 && eligible_for_level_up(&state.net, &self.primary_cred).await);
-
-        // Can we migrate the main credential?
-        let can_migrate = reachcred.is_none() && level >= MIN_TRUST_LEVEL;
-
-        // Can we level up the secondary credential?
-        let mut second_level_up = false;
-
-        let mut failed = Vec::<BridgeLine>::new();
-        let mut succeeded = Vec::<BridgeLine>::new();
-        for i in 0..bucket.len() {
-            // At level 0, we only have 1 bridge
-            if level > 0 || i == 0 {
-                if self.connect(&bucket[i]) {
-                    succeeded.push(bucket[i]);
-                } else {
-                    failed.push(bucket[i]);
+        // Probabilistically decide if the user should use bridges today
+        let mut rng = rand::thread_rng();
+        let num: f64 = rng.gen_range(0.0..1.0);
+        if num < self.prob_use_bridges {
+            // Download bucket to see if bridge is still reachable
+            // (We assume that this step can be done even if the user can't actually
+            // talk to the LA.)
+            let (bucket, reachcred) = get_bucket(&state.net, &self.primary_cred).await;
+            let level = scalar_u32(&self.primary_cred.trust_level).unwrap();
+
+            // Can we level up the main credential?
+            let can_level_up = reachcred.is_some()
+                && (level == 0
+                    && eligible_for_trust_promotion(&state.net, &self.primary_cred).await
+                    || level > 0 && eligible_for_level_up(&state.net, &self.primary_cred).await);
+
+            // Can we migrate the main credential?
+            let can_migrate = reachcred.is_none() && level >= MIN_TRUST_LEVEL;
+
+            // Can we level up the secondary credential?
+            let mut second_level_up = false;
+
+            let mut failed = Vec::<BridgeLine>::new();
+            let mut succeeded = Vec::<BridgeLine>::new();
+            for i in 0..bucket.len() {
+                // At level 0, we only have 1 bridge
+                if level > 0 || i == 0 {
+                    if self.connect(&bucket[i]) {
+                        succeeded.push(bucket[i]);
+                    } else {
+                        failed.push(bucket[i]);
+                    }
                 }
             }
-        }
-        let second_cred = if succeeded.len() < 1 {
-            if self.secondary_cred.is_some() {
-                std::mem::replace(&mut self.secondary_cred, None)
-            } else {
-                // Get new credential
-                let cred = get_lox_credential(
-                    &state.net,
-                    &get_open_invitation(&state.net).await,
-                    get_lox_pub(&state.la_pubkeys),
-                )
-                .await
-                .0;
-                Some(cred)
-            }
-        } else {
-            // If we're able to connect with the primary credential, don't
-            // keep a secondary one.
-            None
-        };
-        if second_cred.is_some() {
-            let second_cred = second_cred.as_ref().unwrap();
-            let (second_bucket, second_reachcred) = get_bucket(&state.net, &second_cred).await;
-            if self.connect(&second_bucket[0]) {
-                succeeded.push(second_bucket[0]);
-                if second_reachcred.is_some()
-                    && eligible_for_trust_promotion(&state.net, &second_cred).await
-                {
-                    second_level_up = true;
+            let second_cred = if succeeded.len() < 1 {
+                if self.secondary_cred.is_some() {
+                    std::mem::replace(&mut self.secondary_cred, None)
+                } else {
+                    // Get new credential
+                    let cred = get_lox_credential(
+                        &state.net,
+                        &get_open_invitation(&state.net).await,
+                        get_lox_pub(&state.la_pubkeys),
+                    )
+                    .await
+                    .0;
+                    Some(cred)
                 }
             } else {
-                failed.push(second_bucket[0]);
+                // If we're able to connect with the primary credential, don't
+                // keep a secondary one.
+                None
+            };
+            if second_cred.is_some() {
+                let second_cred = second_cred.as_ref().unwrap();
+                let (second_bucket, second_reachcred) = get_bucket(&state.net, &second_cred).await;
+                if self.connect(&second_bucket[0]) {
+                    succeeded.push(second_bucket[0]);
+                    if second_reachcred.is_some()
+                        && eligible_for_trust_promotion(&state.net, &second_cred).await
+                    {
+                        second_level_up = true;
+                    }
+                } else {
+                    failed.push(second_bucket[0]);
+                }
             }
-        }
 
-        let mut negative_reports = Vec::<NegativeReport>::new();
-        let mut positive_reports = Vec::<PositiveReport>::new();
-        if self.submits_reports {
-            for bridge in &failed {
-                negative_reports.push(NegativeReport::from_bridgeline(
-                    *bridge,
-                    self.country.to_string(),
-                    BridgeDistributor::Lox,
-                ));
-            }
-            if level >= 3 {
-                for bridge in &succeeded {
-                    positive_reports.push(
-                        PositiveReport::from_lox_credential(
-                            bridge.fingerprint,
-                            None,
-                            &self.primary_cred,
-                            get_lox_pub(&state.la_pubkeys),
-                            self.country.to_string(),
-                        )
-                        .unwrap(),
-                    );
+            let mut negative_reports = Vec::<NegativeReport>::new();
+            let mut positive_reports = Vec::<PositiveReport>::new();
+            if self.submits_reports {
+                for bridge in &failed {
+                    negative_reports.push(NegativeReport::from_bridgeline(
+                        *bridge,
+                        self.country.to_string(),
+                        BridgeDistributor::Lox,
+                    ));
+                }
+                if level >= 3 {
+                    for bridge in &succeeded {
+                        positive_reports.push(
+                            PositiveReport::from_lox_credential(
+                                bridge.fingerprint,
+                                None,
+                                &self.primary_cred,
+                                get_lox_pub(&state.la_pubkeys),
+                                self.country.to_string(),
+                            )
+                            .unwrap(),
+                        );
+                    }
                 }
             }
-        }
 
-        // We might restrict these steps to succeeded.len() > 0, but we do
-        // assume the user can contact the LA somehow, so let's just allow it.
-        if can_level_up {
-            let cred = level_up(
-                &state.net,
-                &self.primary_cred,
-                &reachcred.unwrap(),
-                get_lox_pub(&state.la_pubkeys),
-                get_reachability_pub(&state.la_pubkeys),
-            )
-            .await;
-            self.primary_cred = cred;
-            self.secondary_cred = None;
-        }
-        // We favor starting over at level 1 to migrating
-        else if second_level_up {
-            let second_cred = second_cred.as_ref().unwrap();
-            let cred = trust_migration(
-                &state.net,
-                &second_cred,
-                &trust_promotion(&state.net, &second_cred, get_lox_pub(&state.la_pubkeys)).await,
-                get_lox_pub(&state.la_pubkeys),
-                get_migration_pub(&state.la_pubkeys),
-            )
-            .await;
-            self.primary_cred = cred;
-            self.secondary_cred = None;
-        } else if can_migrate {
-            let cred = blockage_migration(
-                &state.net,
-                &self.primary_cred,
-                &check_blockage(
+            // We might restrict these steps to succeeded.len() > 0, but we do
+            // assume the user can contact the LA somehow, so let's just allow it.
+            if can_level_up {
+                let cred = level_up(
                     &state.net,
                     &self.primary_cred,
+                    &reachcred.unwrap(),
                     get_lox_pub(&state.la_pubkeys),
+                    get_reachability_pub(&state.la_pubkeys),
                 )
-                .await,
-                get_lox_pub(&state.la_pubkeys),
-                get_migration_pub(&state.la_pubkeys),
-            )
-            .await;
-            self.primary_cred = cred;
-            self.secondary_cred = None;
-        } else if second_cred.is_some() {
-            // Couldn't connect with primary credential
-            if succeeded.len() > 0 {
-                // Keep the second credential only if it's useful
-                self.secondary_cred = second_cred;
+                .await;
+                self.primary_cred = cred;
+                self.secondary_cred = None;
+            }
+            // We favor starting over at level 1 to migrating
+            else if second_level_up {
+                let second_cred = second_cred.as_ref().unwrap();
+                let cred = trust_migration(
+                    &state.net,
+                    &second_cred,
+                    &trust_promotion(&state.net, &second_cred, get_lox_pub(&state.la_pubkeys))
+                        .await,
+                    get_lox_pub(&state.la_pubkeys),
+                    get_migration_pub(&state.la_pubkeys),
+                )
+                .await;
+                self.primary_cred = cred;
+                self.secondary_cred = None;
+            } else if can_migrate {
+                let cred = blockage_migration(
+                    &state.net,
+                    &self.primary_cred,
+                    &check_blockage(
+                        &state.net,
+                        &self.primary_cred,
+                        get_lox_pub(&state.la_pubkeys),
+                    )
+                    .await,
+                    get_lox_pub(&state.la_pubkeys),
+                    get_migration_pub(&state.la_pubkeys),
+                )
+                .await;
+                self.primary_cred = cred;
+                self.secondary_cred = None;
+            } else if second_cred.is_some() {
+                // Couldn't connect with primary credential
+                if succeeded.len() > 0 {
+                    // Keep the second credential only if it's useful
+                    self.secondary_cred = second_cred;
+                }
             }
-        }
 
-        if negative_reports.len() > 0 {
-            Self::send_negative_reports(&state, negative_reports).await;
-        }
-        if positive_reports.len() > 0 {
-            Self::send_positive_reports(&state, positive_reports).await;
-        }
+            if negative_reports.len() > 0 {
+                Self::send_negative_reports(&state, negative_reports).await;
+            }
+            if positive_reports.len() > 0 {
+                Self::send_positive_reports(&state, positive_reports).await;
+            }
 
-        // Invite friends if applicable
-        let invitations = scalar_u32(&self.primary_cred.invites_remaining).unwrap();
-        let mut new_friends = Vec::<User>::new();
-        for _i in 0..invitations {
-            let mut rng = rand::thread_rng();
-            let num: f64 = rng.gen_range(0.0..1.0);
-            if num < state.prob_user_invites_friend {
-                match self.invite(&state).await {
-                    Ok(friend) => {
-                        // You really shouldn't push your friends, especially
-                        // new ones whose boundaries you might not know well.
-                        new_friends.push(friend);
-                    }
-                    Err(e) => {
-                        println!("{}", e);
+            // Invite friends if applicable
+            let invitations = scalar_u32(&self.primary_cred.invites_remaining).unwrap();
+            let mut new_friends = Vec::<User>::new();
+            for _i in 0..invitations {
+                let mut rng = rand::thread_rng();
+                let num: f64 = rng.gen_range(0.0..1.0);
+                if num < state.prob_user_invites_friend {
+                    match self.invite(&state).await {
+                        Ok(friend) => {
+                            // You really shouldn't push your friends, especially
+                            // new ones whose boundaries you might not know well.
+                            new_friends.push(friend);
+                        }
+                        Err(e) => {
+                            println!("{}", e);
+                        }
                     }
                 }
             }
-        }
 
-        // List of fingerprints we contacted. This should not actually be more
-        // than one.
-        let mut connections = Vec::<[u8; 20]>::new();
-        for bridge in succeeded {
-            connections.push(bridge.get_hashed_fingerprint());
-        }
+            // List of fingerprints we contacted. This should not actually be more
+            // than one.
+            let mut connections = Vec::<[u8; 20]>::new();
+            for bridge in succeeded {
+                connections.push(bridge.get_hashed_fingerprint());
+            }
 
-        (new_friends, connections)
+            (new_friends, connections)
+        } else {
+            (Vec::<User>::new(), Vec::<[u8; 20]>::new())
+        }
     }
 }