diff --git a/src/simulation/user.rs b/src/simulation/user.rs index f7d996d..84374eb 100644 --- a/src/simulation/user.rs +++ b/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, 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(); + // 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 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 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; + // Can we level up the secondary credential? + let mut second_level_up = false; - let mut failed = Vec::::new(); - let mut succeeded = Vec::::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]); + let mut failed = Vec::::new(); + let mut succeeded = Vec::::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 { - 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; + // 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]); - } - } - - let mut negative_reports = Vec::::new(); - let mut positive_reports = Vec::::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(), - ); + // 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]); } } - } - // 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( + let mut negative_reports = Vec::::new(); + let mut positive_reports = Vec::::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, - 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::::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::::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::::new(), Vec::<[u8; 20]>::new()) + } } }