From ac1f09a8c10e72b9baa0f6a2e4895c07dabcd3c6 Mon Sep 17 00:00:00 2001 From: Vecna Date: Sat, 29 Jun 2024 10:15:48 -0400 Subject: [PATCH] Use simple thresholds --- src/analysis.rs | 13 ++++ src/lib.rs | 2 + src/lox_analysis.rs | 172 ++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 2 +- 4 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 src/lox_analysis.rs diff --git a/src/analysis.rs b/src/analysis.rs index 6496bd6..69a11b6 100644 --- a/src/analysis.rs +++ b/src/analysis.rs @@ -13,6 +13,7 @@ pub trait Analyzer { /// Evaluate open-entry bridge. Returns true if blocked, false otherwise. fn stage_one( &self, + age: u32, confidence: f64, bridge_ips: &[u32], bridge_ips_today: u32, @@ -24,6 +25,7 @@ pub trait Analyzer { /// blocked, false otherwise. fn stage_two( &self, + age: u32, confidence: f64, bridge_ips: &[u32], bridge_ips_today: u32, @@ -35,6 +37,7 @@ pub trait Analyzer { /// blocked, false otherwise. fn stage_three( &self, + age: u32, confidence: f64, bridge_ips: &[u32], bridge_ips_today: u32, @@ -118,6 +121,7 @@ pub fn blocked_in( // open-entry bridge and/or not enough days of // historical days for stages 2 and 3 if analyzer.stage_one( + age, confidence, &bridge_ips, bridge_ips_today, @@ -132,6 +136,7 @@ pub fn blocked_in( // invite-only bridge without min_historical_days of // historical data on positive reports if analyzer.stage_two( + age, confidence, &bridge_ips, bridge_ips_today, @@ -144,6 +149,7 @@ pub fn blocked_in( // invite-only bridge that has min_historical_days or // more of historical data since the first positive report if analyzer.stage_three( + age, confidence, &bridge_ips, bridge_ips_today, @@ -168,6 +174,7 @@ pub struct ExampleAnalyzer {} impl Analyzer for ExampleAnalyzer { fn stage_one( &self, + _age: u32, _confidence: f64, _bridge_ips: &[u32], _bridge_ips_today: u32, @@ -179,6 +186,7 @@ impl Analyzer for ExampleAnalyzer { fn stage_two( &self, + _age: u32, _confidence: f64, _bridge_ips: &[u32], _bridge_ips_today: u32, @@ -190,6 +198,7 @@ impl Analyzer for ExampleAnalyzer { fn stage_three( &self, + _age: u32, _confidence: f64, _bridge_ips: &[u32], _bridge_ips_today: u32, @@ -221,6 +230,7 @@ impl Analyzer for NormalAnalyzer { /// Evaluate open-entry bridge based on only today's data fn stage_one( &self, + _age: u32, _confidence: f64, _bridge_ips: &[u32], bridge_ips_today: u32, @@ -234,6 +244,7 @@ impl Analyzer for NormalAnalyzer { /// Evaluate invite-only bridge based on historical data fn stage_two( &self, + _age: u32, confidence: f64, bridge_ips: &[u32], bridge_ips_today: u32, @@ -305,6 +316,7 @@ impl Analyzer for NormalAnalyzer { /// Evaluate invite-only bridge with lv3+ users submitting positive reports fn stage_three( &self, + age: u32, confidence: f64, bridge_ips: &[u32], bridge_ips_today: u32, @@ -401,6 +413,7 @@ impl Analyzer for NormalAnalyzer { // evaluate each variable. Ignore positive reports and // compute as in stage 2 if self.stage_two( + age, confidence, bridge_ips, bridge_ips_today, diff --git a/src/lib.rs b/src/lib.rs index 7bdfa18..070ff92 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,6 +23,7 @@ pub mod analysis; pub mod bridge_verification_info; pub mod crypto; pub mod extra_info; +pub mod lox_analysis; pub mod negative_report; pub mod positive_report; pub mod request_handler; @@ -34,6 +35,7 @@ pub mod simulation { use analysis::Analyzer; use extra_info::*; +use lox_analysis::LoxAnalyzer; use negative_report::*; use positive_report::*; diff --git a/src/lox_analysis.rs b/src/lox_analysis.rs new file mode 100644 index 0000000..6b3ab16 --- /dev/null +++ b/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) + } +} diff --git a/src/main.rs b/src/main.rs index 21ab4c5..2188d4a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -103,7 +103,7 @@ async fn update_daily_info( update_positive_reports(db, distributors).await; let new_blockages = guess_blockages( db, - &analysis::NormalAnalyzer::new(max_threshold, scaling_factor), + &lox_analysis::LoxAnalyzer {}, confidence, min_historical_days, max_historical_days,