| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- // Before running this, run:
- // 1. rdsys
- // 2. lox-distributor
- // 3. troll-patrol with the feature "simulation"
- use troll_patrol::{
- extra_info::ExtraInfo,
- get_date, increment_simulated_date, set_simulated_date,
- simulation::{
- bridge::Bridge,
- censor::{self, Censor},
- config::Config as SConfig,
- extra_infos_server,
- user::User,
- },
- };
- use clap::Parser;
- use lox_cli::{networking::*, *};
- use lox_library::proto::{level_up::LEVEL_INTERVAL, trust_promotion::UNTRUSTED_INTERVAL};
- use rand::Rng;
- use serde::Deserialize;
- use std::{
- collections::{HashMap, HashSet},
- fs::File,
- io::BufReader,
- path::PathBuf,
- time::Duration,
- };
- use tokio::{spawn, time::sleep};
- #[derive(Parser, Debug)]
- #[command(author, version, about, long_about = None)]
- struct Args {
- /// Name/path of the configuration file
- #[arg(short, long, default_value = "simulation_config.json")]
- config: PathBuf,
- }
- #[derive(Debug, Deserialize)]
- pub struct Config {
- pub la_port: u16,
- pub la_test_port: u16,
- pub tp_port: u16,
- pub tp_test_port: u16,
- pub censor_hides: censor::Hides,
- pub censor_speed: censor::Speed,
- pub censor_event_duration: u32,
- pub censor_totality: censor::Totality,
- pub censor_partial_blocking_percent: f64,
- pub country: String,
- pub min_new_users_per_day: u32,
- pub max_new_users_per_day: u32,
- // How many days to simulate
- pub num_days: u32,
- // We start with this many level 4 users
- pub num_initial_trusted_users: u32,
- pub one_positive_report_per_cred: bool,
- pub prob_connection_fails: f64,
- pub prob_user_invites_friend: f64,
- pub prob_user_is_censor: f64,
- pub prob_user_submits_reports: f64,
- }
- #[tokio::main]
- pub async fn main() {
- let args: Args = Args::parse();
- let config: Config = serde_json::from_reader(BufReader::new(
- File::open(&args.config).expect("Could not read config file"),
- ))
- .expect("Reading config file from JSON failed");
- let la_net = HyperNet {
- hostname: format!("http://localhost:{}", config.la_port),
- };
- let la_net_test = HyperNet {
- hostname: format!("http://localhost:{}", config.la_test_port),
- };
- let tp_net = HyperNet {
- hostname: format!("http://localhost:{}", config.tp_port),
- };
- let tp_net_test = HyperNet {
- hostname: format!("http://localhost:{}", config.tp_test_port),
- };
- let extra_infos_net = HyperNet {
- hostname: "http://localhost:8004".to_string(),
- };
- let la_pubkeys = get_lox_auth_keys(&la_net).await;
- let sconfig = SConfig {
- la_pubkeys,
- la_net,
- tp_net,
- censor_hides: config.censor_hides,
- censor_speed: config.censor_speed,
- censor_event_duration: config.censor_event_duration,
- censor_totality: config.censor_totality,
- censor_partial_blocking_percent: config.censor_partial_blocking_percent,
- country: config.country,
- one_positive_report_per_cred: config.one_positive_report_per_cred,
- prob_connection_fails: config.prob_connection_fails,
- 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,
- };
- let mut rng = rand::thread_rng();
- // Set up censor
- let mut censor = Censor::new(&sconfig);
- // Set up bridges (no bridges yet)
- let mut bridges = HashMap::<[u8; 20], Bridge>::new();
- // Set up users
- let mut users = Vec::<User>::new();
- if config.num_initial_trusted_users > 0 {
- // Add some number of trusted users initially
- for _ in 0..config.num_initial_trusted_users {
- users.push(User::trusted_user(&sconfig).await);
- }
- // Level trusted users up to level 4
- // Advance LA's time
- la_net_test
- .request(
- "/advancedays".to_string(),
- serde_json::to_string(&(UNTRUSTED_INTERVAL as u16))
- .unwrap()
- .into(),
- )
- .await;
- // Advance simulated time
- set_simulated_date(get_date() + UNTRUSTED_INTERVAL);
- for user in &mut users {
- user.primary_cred = trust_migration(
- &sconfig.la_net,
- &user.primary_cred,
- &trust_promotion(
- &sconfig.la_net,
- &user.primary_cred,
- get_lox_pub(&sconfig.la_pubkeys),
- )
- .await,
- get_lox_pub(&sconfig.la_pubkeys),
- get_migration_pub(&sconfig.la_pubkeys),
- )
- .await;
- }
- for i in 1..LEVEL_INTERVAL.len() - 2 {
- // Advance LA's time
- la_net_test
- .request(
- "/advancedays".to_string(),
- serde_json::to_string(&(LEVEL_INTERVAL[i] as u16))
- .unwrap()
- .into(),
- )
- .await;
- // Advance simulated time
- set_simulated_date(get_date() + LEVEL_INTERVAL[i]);
- for user in &mut users {
- let reachcred = get_bucket(&sconfig.la_net, &user.primary_cred).await.1;
- user.primary_cred = level_up(
- &sconfig.la_net,
- &user.primary_cred,
- &reachcred.unwrap(),
- get_lox_pub(&sconfig.la_pubkeys),
- get_reachability_pub(&sconfig.la_pubkeys),
- )
- .await;
- }
- }
- // Have Troll Patrol run its update process so we have a negative
- // report key for tomorrow
- tp_net_test.request("/update".to_string(), vec![]).await;
- // Advance LA's time to tomorrow
- la_net_test
- .request(
- "/advancedays".to_string(),
- serde_json::to_string(&(1 as u16)).unwrap().into(),
- )
- .await;
- // Advance simulated time to tomorrow
- increment_simulated_date();
- }
- // Set up extra-infos server
- spawn(async move {
- extra_infos_server::server().await;
- });
- sleep(Duration::from_millis(1)).await;
- let mut fp = 0;
- let mut tp = 0;
- // Main loop
- for day in 1..=config.num_days {
- println!("Starting day {} of the simulation", day);
- // USER TASKS
- // Add some new users
- let num_new_users: u32 =
- rng.gen_range(config.min_new_users_per_day..=config.max_new_users_per_day);
- for _ in 0..num_new_users {
- users.push(User::new(&sconfig).await);
- }
- let mut new_users = Vec::<User>::new();
- // Users do daily actions
- for user in &mut users {
- let mut invited_friends = user.daily_tasks(&sconfig, &mut bridges, &mut censor).await;
- // If this user invited any friends, add them to the list of users
- new_users.append(&mut invited_friends);
- }
- // Add new users
- users.append(&mut new_users);
- // CENSOR TASKS
- censor.end_of_day_tasks(&sconfig, &mut bridges).await;
- // BRIDGE TASKS
- let mut new_extra_infos = HashSet::<ExtraInfo>::new();
- for (_, bridge) in bridges.iter_mut() {
- // Bridge reports its connections for the day
- new_extra_infos.insert(bridge.gen_extra_info(&sconfig.country));
- // Bridge resets for tomorrow
- bridge.reset_for_tomorrow();
- }
- // Publish all the bridges' extra-infos for today
- extra_infos_net
- .request(
- "/add".to_string(),
- serde_json::to_string(&new_extra_infos).unwrap().into(),
- )
- .await;
- // TROLL PATROL TASKS
- let new_blockages_resp = tp_net_test.request("/update".to_string(), vec![]).await;
- let new_blockages: HashMap<String, HashSet<String>> =
- serde_json::from_slice(&new_blockages_resp).unwrap();
- // TODO: Track more stats about new blockages
- for (bridge, ccs) in new_blockages {
- let fingerprint = array_bytes::hex2array(bridge).unwrap();
- for cc in ccs {
- if cc == sconfig.country {
- if censor.knows_bridge(&fingerprint) {
- tp += 1;
- } else {
- fp += 1;
- }
- }
- }
- }
- // LOX AUTHORITY TASKS
- // Advance LA's time to tomorrow
- la_net_test
- .request(
- "/advancedays".to_string(),
- serde_json::to_string(&(1 as u16)).unwrap().into(),
- )
- .await;
- // SIMULATION TASKS
- // Advance simulated time to tomorrow
- increment_simulated_date();
- }
- println!("True Positives: {}", tp);
- println!("False Positives: {}", fp);
- }
|