Browse Source

Use simple thresholds

Vecna 4 months ago
parent
commit
ac1f09a8c1
4 changed files with 188 additions and 1 deletions
  1. 13 0
      src/analysis.rs
  2. 2 0
      src/lib.rs
  3. 172 0
      src/lox_analysis.rs
  4. 1 1
      src/main.rs

+ 13 - 0
src/analysis.rs

@@ -13,6 +13,7 @@ pub trait Analyzer {
     /// Evaluate open-entry bridge. Returns true if blocked, false otherwise.
     /// Evaluate open-entry bridge. Returns true if blocked, false otherwise.
     fn stage_one(
     fn stage_one(
         &self,
         &self,
+        age: u32,
         confidence: f64,
         confidence: f64,
         bridge_ips: &[u32],
         bridge_ips: &[u32],
         bridge_ips_today: u32,
         bridge_ips_today: u32,
@@ -24,6 +25,7 @@ pub trait Analyzer {
     /// blocked, false otherwise.
     /// blocked, false otherwise.
     fn stage_two(
     fn stage_two(
         &self,
         &self,
+        age: u32,
         confidence: f64,
         confidence: f64,
         bridge_ips: &[u32],
         bridge_ips: &[u32],
         bridge_ips_today: u32,
         bridge_ips_today: u32,
@@ -35,6 +37,7 @@ pub trait Analyzer {
     /// blocked, false otherwise.
     /// blocked, false otherwise.
     fn stage_three(
     fn stage_three(
         &self,
         &self,
+        age: u32,
         confidence: f64,
         confidence: f64,
         bridge_ips: &[u32],
         bridge_ips: &[u32],
         bridge_ips_today: u32,
         bridge_ips_today: u32,
@@ -118,6 +121,7 @@ pub fn blocked_in(
                 // open-entry bridge and/or not enough days of
                 // open-entry bridge and/or not enough days of
                 // historical days for stages 2 and 3
                 // historical days for stages 2 and 3
                 if analyzer.stage_one(
                 if analyzer.stage_one(
+                    age,
                     confidence,
                     confidence,
                     &bridge_ips,
                     &bridge_ips,
                     bridge_ips_today,
                     bridge_ips_today,
@@ -132,6 +136,7 @@ pub fn blocked_in(
                 // invite-only bridge without min_historical_days of
                 // invite-only bridge without min_historical_days of
                 // historical data on positive reports
                 // historical data on positive reports
                 if analyzer.stage_two(
                 if analyzer.stage_two(
+                    age,
                     confidence,
                     confidence,
                     &bridge_ips,
                     &bridge_ips,
                     bridge_ips_today,
                     bridge_ips_today,
@@ -144,6 +149,7 @@ pub fn blocked_in(
                 // invite-only bridge that has min_historical_days or
                 // invite-only bridge that has min_historical_days or
                 // more of historical data since the first positive report
                 // more of historical data since the first positive report
                 if analyzer.stage_three(
                 if analyzer.stage_three(
+                    age,
                     confidence,
                     confidence,
                     &bridge_ips,
                     &bridge_ips,
                     bridge_ips_today,
                     bridge_ips_today,
@@ -168,6 +174,7 @@ pub struct ExampleAnalyzer {}
 impl Analyzer for ExampleAnalyzer {
 impl Analyzer for ExampleAnalyzer {
     fn stage_one(
     fn stage_one(
         &self,
         &self,
+        _age: u32,
         _confidence: f64,
         _confidence: f64,
         _bridge_ips: &[u32],
         _bridge_ips: &[u32],
         _bridge_ips_today: u32,
         _bridge_ips_today: u32,
@@ -179,6 +186,7 @@ impl Analyzer for ExampleAnalyzer {
 
 
     fn stage_two(
     fn stage_two(
         &self,
         &self,
+        _age: u32,
         _confidence: f64,
         _confidence: f64,
         _bridge_ips: &[u32],
         _bridge_ips: &[u32],
         _bridge_ips_today: u32,
         _bridge_ips_today: u32,
@@ -190,6 +198,7 @@ impl Analyzer for ExampleAnalyzer {
 
 
     fn stage_three(
     fn stage_three(
         &self,
         &self,
+        _age: u32,
         _confidence: f64,
         _confidence: f64,
         _bridge_ips: &[u32],
         _bridge_ips: &[u32],
         _bridge_ips_today: u32,
         _bridge_ips_today: u32,
@@ -221,6 +230,7 @@ impl Analyzer for NormalAnalyzer {
     /// Evaluate open-entry bridge based on only today's data
     /// Evaluate open-entry bridge based on only today's data
     fn stage_one(
     fn stage_one(
         &self,
         &self,
+        _age: u32,
         _confidence: f64,
         _confidence: f64,
         _bridge_ips: &[u32],
         _bridge_ips: &[u32],
         bridge_ips_today: u32,
         bridge_ips_today: u32,
@@ -234,6 +244,7 @@ impl Analyzer for NormalAnalyzer {
     /// Evaluate invite-only bridge based on historical data
     /// Evaluate invite-only bridge based on historical data
     fn stage_two(
     fn stage_two(
         &self,
         &self,
+        _age: u32,
         confidence: f64,
         confidence: f64,
         bridge_ips: &[u32],
         bridge_ips: &[u32],
         bridge_ips_today: u32,
         bridge_ips_today: u32,
@@ -305,6 +316,7 @@ impl Analyzer for NormalAnalyzer {
     /// Evaluate invite-only bridge with lv3+ users submitting positive reports
     /// Evaluate invite-only bridge with lv3+ users submitting positive reports
     fn stage_three(
     fn stage_three(
         &self,
         &self,
+        age: u32,
         confidence: f64,
         confidence: f64,
         bridge_ips: &[u32],
         bridge_ips: &[u32],
         bridge_ips_today: u32,
         bridge_ips_today: u32,
@@ -401,6 +413,7 @@ impl Analyzer for NormalAnalyzer {
                 // evaluate each variable. Ignore positive reports and
                 // evaluate each variable. Ignore positive reports and
                 // compute as in stage 2
                 // compute as in stage 2
                 if self.stage_two(
                 if self.stage_two(
+                    age,
                     confidence,
                     confidence,
                     bridge_ips,
                     bridge_ips,
                     bridge_ips_today,
                     bridge_ips_today,

+ 2 - 0
src/lib.rs

@@ -23,6 +23,7 @@ pub mod analysis;
 pub mod bridge_verification_info;
 pub mod bridge_verification_info;
 pub mod crypto;
 pub mod crypto;
 pub mod extra_info;
 pub mod extra_info;
+pub mod lox_analysis;
 pub mod negative_report;
 pub mod negative_report;
 pub mod positive_report;
 pub mod positive_report;
 pub mod request_handler;
 pub mod request_handler;
@@ -34,6 +35,7 @@ pub mod simulation {
 
 
 use analysis::Analyzer;
 use analysis::Analyzer;
 use extra_info::*;
 use extra_info::*;
+use lox_analysis::LoxAnalyzer;
 use negative_report::*;
 use negative_report::*;
 use positive_report::*;
 use positive_report::*;
 
 

+ 172 - 0
src/lox_analysis.rs

@@ -0,0 +1,172 @@
+use crate::{analysis::Analyzer, BridgeCountryInfo, BridgeInfoType};
+use lox_library::{
+    bridge_table::MAX_BRIDGES_PER_BUCKET,
+    proto::{
+        level_up::{LEVEL_INTERVAL, LEVEL_INVITATIONS, MAX_LEVEL},
+        trust_promotion::UNTRUSTED_INTERVAL,
+    },
+    OPENINV_K,
+};
+
+// Get max value from slice, or 0 if empty
+fn max(nums: &[u32]) -> u32 {
+    let mut max_num = 0;
+    for i in nums {
+        if *i > max_num {
+            max_num = *i;
+        }
+    }
+    max_num
+}
+
+// Max users expected on a Lox bridge based on how long it's been around
+fn max_users(days: u32) -> u32 {
+    if days <= UNTRUSTED_INTERVAL {
+        // k users for open-entry bucket
+        OPENINV_K
+    } else if days <= UNTRUSTED_INTERVAL + LEVEL_INTERVAL[1] {
+        // k users per bridge x 3 bridges in invite-only bucket
+        OPENINV_K * MAX_BRIDGES_PER_BUCKET as u32
+    } else if days <= UNTRUSTED_INTERVAL + LEVEL_INTERVAL[2] {
+        // suppose users have used all their invitations
+        OPENINV_K * MAX_BRIDGES_PER_BUCKET as u32 * (1 + LEVEL_INVITATIONS[1])
+    } else {
+        // stop counting here, just say it's a lot
+        100
+    }
+}
+
+// Maximum number of negative reports without considering the bridge blocked
+fn max_negative_reports(days: u32) -> u32 {
+    // How many users do we expect to use this bridge?
+    let max_users = max_users(days);
+
+    // Based on that, allow this many negative reports
+    if max_users <= 10 {
+        0
+    } else if max_users <= 30 {
+        5
+    } else {
+        10
+    }
+}
+
+fn too_few_bridge_ips(
+    days: u32,
+    max_bridge_ips: u32,
+    bridge_ips_today: u32,
+    positive_reports_today: u32,
+) -> bool {
+    // How many users do we expect to use this bridge?
+    let max_users = max_users(days);
+
+    // Based on that, expect this many bridge ips
+    let min_bip = if max_users <= 16 {
+        // expect 10
+        8
+    } else if max_users <= 40 {
+        // expect 30
+        24
+    } else if max_users <= 96 {
+        // expect 90
+        32
+    } else {
+        // also 32, but it could be something else
+        32
+    };
+
+    // If we normally see low usage, halve the minimum
+    let min_bip = if max_bridge_ips <= 8 {
+        // If we have 1-8 users, allow the number to be 0
+        0
+    } else if max_bridge_ips <= max_users / 2 {
+        min_bip / 2
+    } else {
+        min_bip
+    };
+
+    // If we see positive reports from trusted users, double the minimum
+    let min_bip = if positive_reports_today > 0 {
+        min_bip * 2
+    } else {
+        min_bip
+    };
+
+    bridge_ips_today < min_bip
+}
+
+/// Analyzer for Lox bridges based on how long they've been active
+pub struct LoxAnalyzer {}
+
+impl Analyzer for LoxAnalyzer {
+    // At this stage, we expect 0-10 users, so 0, 8, or 16 bridge-ips
+    fn stage_one(
+        &self,
+        age: u32,
+        _confidence: f64,
+        bridge_ips: &[u32],
+        bridge_ips_today: u32,
+        _negative_reports: &[u32],
+        negative_reports_today: u32,
+    ) -> bool {
+        // Get max bridge_ips we've seen
+        let max_bridge_ips = max(bridge_ips);
+
+        if too_few_bridge_ips(age, max_bridge_ips, bridge_ips_today, 0) {
+            return true;
+        }
+
+        // If we have more negative reports than expected, consider the
+        // bridge blocked
+        negative_reports_today > max_negative_reports(age)
+    }
+
+    fn stage_two(
+        &self,
+        age: u32,
+        _confidence: f64,
+        bridge_ips: &[u32],
+        bridge_ips_today: u32,
+        _negative_reports: &[u32],
+        negative_reports_today: u32,
+    ) -> bool {
+        // Get max bridge_ips we've seen
+        let max_bridge_ips = max(bridge_ips);
+
+        if too_few_bridge_ips(age, max_bridge_ips, bridge_ips_today, 0) {
+            return true;
+        }
+
+        // If we have more negative reports than expected, consider the
+        // bridge blocked
+        negative_reports_today > max_negative_reports(age)
+    }
+
+    fn stage_three(
+        &self,
+        age: u32,
+        _confidence: f64,
+        bridge_ips: &[u32],
+        bridge_ips_today: u32,
+        _negative_reports: &[u32],
+        negative_reports_today: u32,
+        _positive_reports: &[u32],
+        positive_reports_today: u32,
+    ) -> bool {
+        // Get max bridge_ips we've seen
+        let max_bridge_ips = max(bridge_ips);
+
+        if too_few_bridge_ips(
+            age,
+            max_bridge_ips,
+            bridge_ips_today,
+            positive_reports_today,
+        ) {
+            return true;
+        }
+
+        // If we have more negative reports than expected, consider the
+        // bridge blocked
+        negative_reports_today > max_negative_reports(age)
+    }
+}

+ 1 - 1
src/main.rs

@@ -103,7 +103,7 @@ async fn update_daily_info(
     update_positive_reports(db, distributors).await;
     update_positive_reports(db, distributors).await;
     let new_blockages = guess_blockages(
     let new_blockages = guess_blockages(
         db,
         db,
-        &analysis::NormalAnalyzer::new(max_threshold, scaling_factor),
+        &lox_analysis::LoxAnalyzer {},
         confidence,
         confidence,
         min_historical_days,
         min_historical_days,
         max_historical_days,
         max_historical_days,