ソースを参照

Add probability of user treating throttling as interference

Vecna 9 ヶ月 前
コミット
c3b1908120
4 ファイル変更78 行追加34 行削除
  1. 2 0
      src/bin/simulation.rs
  2. 27 14
      src/simulation/censor.rs
  3. 1 0
      src/simulation/config.rs
  4. 48 20
      src/simulation/user.rs

+ 2 - 0
src/bin/simulation.rs

@@ -61,6 +61,7 @@ pub struct Config {
     pub prob_user_invites_friend: f64,
     pub prob_user_is_censor: f64,
     pub prob_user_submits_reports: f64,
+    pub prob_user_treats_throttling_as_blocking: f64,
 }
 
 #[tokio::main]
@@ -105,6 +106,7 @@ pub async fn main() {
         prob_user_invites_friend: config.prob_user_invites_friend,
         prob_user_is_censor: config.prob_user_is_censor,
         prob_user_submits_reports: config.prob_user_submits_reports,
+        prob_user_treats_throttling_as_blocking: config.prob_user_treats_throttling_as_blocking,
     };
 
     let mut rng = rand::thread_rng();

+ 27 - 14
src/simulation/censor.rs

@@ -94,6 +94,31 @@ impl Censor {
         }
     }
 
+    // Censor sends a positive report for the given bridge. Returns true
+    // if successful, false otherwise.
+    pub async fn send_positive_report(&self, config: &Config, fingerprint: &[u8; 20]) -> bool {
+        // If we don't have an appropriate Lox credential, we can't send
+        // a report. Return false.
+        if !self.has_lox_cred(fingerprint) {
+            return false;
+        }
+
+        let (cred, _) = &self.lox_credentials.get(fingerprint).unwrap();
+        let pr = PositiveReport::from_lox_credential(
+            *fingerprint,
+            None,
+            cred,
+            get_lox_pub(&config.la_pubkeys),
+            config.country.clone(),
+        )
+        .unwrap();
+        config
+            .tp_net
+            .request("/positivereport".to_string(), pr.to_json().into_bytes())
+            .await;
+        true
+    }
+
     // Make a bunch of connections and submit positive reports if possible
     async fn flood(&self, config: &Config, bridges: &mut HashMap<[u8; 20], Bridge>) {
         // Only do this if Flooding censor
@@ -115,8 +140,7 @@ impl Censor {
                     // If we have a lv3+ credential, submit a bunch of
                     // positive reports
                     if self.has_lox_cred(fingerprint) {
-                        let lox_pub = get_lox_pub(&config.la_pubkeys);
-                        let (cred, cred_count) =
+                        let (_cred, cred_count) =
                             &self.lox_credentials.get(&bridge.fingerprint).unwrap();
                         let num_prs = if config.one_positive_report_per_cred {
                             *cred_count
@@ -124,18 +148,7 @@ impl Censor {
                             rng.gen_range(1000..30000)
                         };
                         for _ in 0..num_prs {
-                            let pr = PositiveReport::from_lox_credential(
-                                bridge.fingerprint,
-                                None,
-                                cred,
-                                lox_pub,
-                                config.country.clone(),
-                            )
-                            .unwrap();
-                            config
-                                .tp_net
-                                .request("/positivereport".to_string(), pr.to_json().into_bytes())
-                                .await;
+                            self.send_positive_report(config, &bridge.fingerprint).await;
                         }
                     }
                 }

+ 1 - 0
src/simulation/config.rs

@@ -23,4 +23,5 @@ pub struct Config {
     pub prob_user_invites_friend: f64,
     pub prob_user_is_censor: f64,
     pub prob_user_submits_reports: f64,
+    pub prob_user_treats_throttling_as_blocking: f64,
 }

+ 48 - 20
src/simulation/user.rs

@@ -156,23 +156,45 @@ impl User {
         })
     }
 
-    // Attempt to "connect" to the bridge, returns true if successful
-    pub fn connect(&self, config: &Config, bridge: &mut Bridge, censor: &Censor) -> bool {
+    // Attempt to "connect" to the bridge, returns true if successful.
+    // Note that this does not involve making a real connection to a
+    // real bridge. The function is async because the *censor* might
+    // submit a positive report during this function.
+    pub async fn connect(&self, config: &Config, bridge: &mut Bridge, censor: &Censor) -> bool {
         if censor.blocks_bridge(config, &bridge.fingerprint) {
             if config.censor_totality == Full
                 || config.censor_totality == Partial
                     && event_happens(censor.partial_blocking_percent)
-                || config.censor_totality == Throttling
             {
-                // If censor tries to hide its censorship or
-                // throttles rather than actually blocking, record a
+                // If censor tries to hide its censorship, record a
                 // false connection
-                if config.censor_hides == Hiding || config.censor_totality == Throttling {
+                if config.censor_hides == Hiding {
                     bridge.connect_total();
                 }
 
                 // Return false because the connection failed
                 return false;
+            } else if config.censor_totality == Throttling {
+                // With some probability, the user connects but gives up
+                // because there is too much interference. In this case,
+                // a real connection occurs, but we treat it like a
+                // false connection from the censor.
+                if event_happens(config.prob_user_treats_throttling_as_blocking) {
+                    bridge.connect_total();
+
+                    // A Hiding censor does not make an additional
+                    // connection here, but it will make a false
+                    // positive report if possible.
+                    if config.censor_hides == Hiding && censor.has_lox_cred(&bridge.fingerprint) {
+                        censor
+                            .send_positive_report(config, &bridge.fingerprint)
+                            .await;
+                    }
+
+                    // Return false because there was interference
+                    // detected in the connection
+                    return false;
+                }
             }
         }
 
@@ -291,13 +313,16 @@ impl User {
             for i in 0..bucket.len() {
                 // At level 0, we only have 1 bridge
                 if bucket[i] != BridgeLine::default() {
-                    if self.connect(
-                        &config,
-                        bridges
-                            .get_mut(&bucket[i].get_hashed_fingerprint())
-                            .unwrap(),
-                        &censor,
-                    ) {
+                    if self
+                        .connect(
+                            &config,
+                            bridges
+                                .get_mut(&bucket[i].get_hashed_fingerprint())
+                                .unwrap(),
+                            &censor,
+                        )
+                        .await
+                    {
                         succeeded.push(bucket[i]);
                     } else {
                         failed.push(bucket[i]);
@@ -338,13 +363,16 @@ impl User {
                             );
                         }
                         // Attempt to connect to second cred's bridge
-                        if self.connect(
-                            &config,
-                            bridges
-                                .get_mut(&bridgeline.get_hashed_fingerprint())
-                                .unwrap(),
-                            censor,
-                        ) {
+                        if self
+                            .connect(
+                                &config,
+                                bridges
+                                    .get_mut(&bridgeline.get_hashed_fingerprint())
+                                    .unwrap(),
+                                censor,
+                            )
+                            .await
+                        {
                             succeeded.push(bridgeline);
                             if second_reachcred.is_some()
                                 && eligible_for_trust_promotion(&config.la_net, &second_cred).await