Track whether bridge has actually been distributed to users

This commit is contained in:
Vecna 2024-06-18 14:31:37 -04:00
parent fcbffdc53e
commit 25d1fb96a6
3 changed files with 170 additions and 52 deletions

View File

@ -15,6 +15,9 @@ pub struct Bridge {
// we created this Bridge object // we created this Bridge object
pub first_distributed: u32, pub first_distributed: u32,
// Date the bridge was first distributed to a non-censor user
pub first_real_user: u32,
// First date a censor blocked this bridge // First date a censor blocked this bridge
pub first_blocked: u32, pub first_blocked: u32,
@ -35,6 +38,7 @@ impl Bridge {
Self { Self {
fingerprint: *fingerprint, fingerprint: *fingerprint,
first_distributed: get_date(), first_distributed: get_date(),
first_real_user: 0, // set this afterwards if user is non-censor
first_blocked: 0, first_blocked: 0,
first_detected_blocked: 0, first_detected_blocked: 0,
first_positive_report: 0, first_positive_report: 0,

View File

@ -126,11 +126,21 @@ pub async fn main() {
}); });
sleep(Duration::from_millis(1)).await; sleep(Duration::from_millis(1)).await;
// Only consider bridges that have been distributed to users
let mut false_neg = 0; let mut false_neg = 0;
let mut false_pos = 0; let mut false_pos = 0;
let mut true_neg = 0; let mut true_neg = 0;
let mut true_pos = 0; let mut true_pos = 0;
// All bridges, including those only known to the censor
let mut total_fn = 0;
let mut total_fp = 0;
let mut total_tn = 0;
let mut total_tp = 0;
// Track daily percentage of users who have at least one working bridge
let mut percent_users_can_connect = Vec::<f64>::new();
// Track memory use during simulation // Track memory use during simulation
let mut max_physical_mem = 0; let mut max_physical_mem = 0;
let mut max_virtual_mem = 0; let mut max_virtual_mem = 0;
@ -140,6 +150,10 @@ pub async fn main() {
// Save some function calls by storing this // Save some function calls by storing this
let date = get_date(); let date = get_date();
// Count of users who could use at least one bridge today
let mut count_users_can_connect = 0;
let mut count_users_cannot_connect = 0;
println!("Starting day {} of the simulation", day); println!("Starting day {} of the simulation", day);
println!( println!(
" We have {} users and {} bridges", " We have {} users and {} bridges",
@ -195,8 +209,37 @@ pub async fn main() {
new_users.append(&mut invited_friends); new_users.append(&mut invited_friends);
} }
} }
// Count the number of non-censor users who are able to
// connect to at least one bridge
if !user.is_censor {
if user.able_to_connect {
count_users_can_connect += 1;
} else {
count_users_cannot_connect += 1;
}
}
} }
// Also count number of new users with/without connections
for user in &new_users {
// Count the number of non-censor users who are able to
// connect to at least one bridge
if !user.is_censor {
if user.able_to_connect {
count_users_can_connect += 1;
} else {
count_users_cannot_connect += 1;
}
}
}
// Add percent of users who can connect to vector
percent_users_can_connect.push(
count_users_can_connect as f64
/ (count_users_can_connect + count_users_cannot_connect) as f64,
);
// Add new users // Add new users
users.append(&mut new_users); users.append(&mut new_users);
@ -285,14 +328,30 @@ pub async fn main() {
if really_blocked && bridge.first_blocked == 0 { if really_blocked && bridge.first_blocked == 0 {
bridge.first_blocked = date; bridge.first_blocked = date;
} }
// Increase appropriate count. Only increase main count if
// this is a bridge that has actually been distributed to a
// non-censor user. Increase the total count regardless.
if detected_blocked && really_blocked { if detected_blocked && really_blocked {
true_pos += 1; if bridge.first_real_user > 0 {
true_pos += 1;
}
total_tp += 1;
} else if detected_blocked { } else if detected_blocked {
false_pos += 1; if bridge.first_real_user > 0 {
false_pos += 1;
}
total_fp += 1;
} else if really_blocked { } else if really_blocked {
false_neg += 1; if bridge.first_real_user > 0 {
false_neg += 1;
}
total_fn += 1;
} else { } else {
true_neg += 1; if bridge.first_real_user > 0 {
true_neg += 1;
}
total_tn += 1;
} }
} }
@ -334,6 +393,13 @@ pub async fn main() {
max_virtual_mem max_virtual_mem
); );
println!("\nThese total values include bridges never distributed to real users...");
println!("Total true positives: {}", total_tp);
println!("Total true negatives: {}", total_tn);
println!("Total false positives: {}", total_fp);
println!("Total false negatives: {}", total_fn);
println!("\nThese values only include bridges actually distributed to users...");
println!("True Positives: {}", true_pos); println!("True Positives: {}", true_pos);
println!("True Negatives: {}", true_neg); println!("True Negatives: {}", true_neg);
println!("False Positives: {}", false_pos); println!("False Positives: {}", false_pos);
@ -342,16 +408,27 @@ pub async fn main() {
println!("\nFull stats per bridge:"); println!("\nFull stats per bridge:");
println!( println!(
"Fingerprint,first_distributed,first_blocked,first_detected_blocked,first_positive_report" "Fingerprint,first_distributed,first_real_user,first_blocked,first_detected_blocked,first_positive_report"
); );
for (fingerprint, bridge) in bridges { for (fingerprint, bridge) in bridges {
println!( println!(
"{},{},{},{},{}", "{},{},{},{},{},{}",
array_bytes::bytes2hex("", fingerprint), array_bytes::bytes2hex("", fingerprint),
bridge.first_distributed, bridge.first_distributed,
bridge.first_real_user,
bridge.first_blocked, bridge.first_blocked,
bridge.first_detected_blocked, bridge.first_detected_blocked,
bridge.first_positive_report bridge.first_positive_report
); );
} }
println!("End full stats per bridge\n");
println!("\nWhich users can connect:");
println!("join_date,able_to_connect");
for user in users {
if !user.is_censor {
println!("{},{}", user.join_date, user.able_to_connect);
}
}
println!("End which users can connect");
} }

View File

@ -90,19 +90,27 @@ impl User {
.unwrap(); .unwrap();
if is_censor { if is_censor {
censor.learn_bridge(&bridgeline.get_hashed_fingerprint()); censor.learn_bridge(&bridgeline.get_hashed_fingerprint());
} else if Self::connect(in_censorship_range, config, bridge, censor) { } else {
able_to_connect = true; // If this is the first time the bridge has been
} else if submits_reports { // distributed to a real user, store that info
// New user only has one bridge, so no need if bridge.first_real_user == 0 {
// to collect the negative reports before bridge.first_real_user = get_date();
// sending. Just send one now. }
let mut negative_reports = Vec::<NegativeReport>::new();
negative_reports.push(NegativeReport::from_bridgeline( if Self::connect(in_censorship_range, config, bridge, censor) {
bridgeline, able_to_connect = true;
config.country.to_string(), } else if submits_reports {
BridgeDistributor::Lox, // New user only has one bridge, so no need
)); // to collect the negative reports before
Self::send_negative_reports(&config, negative_reports).await?; // sending. Just send one now.
let mut negative_reports = Vec::<NegativeReport>::new();
negative_reports.push(NegativeReport::from_bridgeline(
bridgeline,
config.country.to_string(),
BridgeDistributor::Lox,
));
Self::send_negative_reports(&config, negative_reports).await?;
}
} }
} }
} }
@ -138,16 +146,28 @@ impl User {
) )
.await?; .await?;
self.primary_cred = new_cred; self.primary_cred = new_cred;
if self.is_censor { // Make sure bridge is in list of bridges and that censor has
// Make sure censor has access to each bridge and each // access if applicable
// credential let (bucket, _reachcred) = get_bucket(&config.la_net, &self.primary_cred).await?;
let (bucket, _reachcred) = get_bucket(&config.la_net, &self.primary_cred).await?; for bl in bucket {
for bl in bucket { if bl != BridgeLine::default() {
let fingerprint = bl.get_hashed_fingerprint(); let fingerprint = bl.get_hashed_fingerprint();
censor.learn_bridge(&fingerprint); if !bridges.contains_key(&fingerprint) {
censor.give_lox_cred(&fingerprint, &self.primary_cred); let bridge = Bridge::from_bridge_line(&bl);
bridges.insert(fingerprint, bridge);
}
let bridge = bridges.get_mut(&fingerprint).unwrap();
if self.is_censor {
censor.learn_bridge(&fingerprint);
censor.give_lox_cred(&fingerprint, &self.primary_cred);
// If this is the first time the bridge has been
// distributed to a real user, store that info
} else if bridge.first_real_user == 0 {
bridge.first_real_user = get_date();
}
} }
} }
let friend_cred = redeem_invite( let friend_cred = redeem_invite(
&config.la_net, &config.la_net,
&invite, &invite,
@ -184,24 +204,31 @@ impl User {
let mut negative_reports = Vec::<NegativeReport>::new(); let mut negative_reports = Vec::<NegativeReport>::new();
let (bucket, _reachcred) = get_bucket(&config.la_net, &friend_cred).await?; let (bucket, _reachcred) = get_bucket(&config.la_net, &friend_cred).await?;
for bridgeline in bucket { for bridgeline in bucket {
let fingerprint = bridgeline.get_hashed_fingerprint();
if bridgeline != BridgeLine::default() { if bridgeline != BridgeLine::default() {
if !bridges.contains_key(&bridgeline.get_hashed_fingerprint()) { if !bridges.contains_key(&fingerprint) {
let bridge = Bridge::from_bridge_line(&bridgeline); let bridge = Bridge::from_bridge_line(&bridgeline);
bridges.insert(bridgeline.get_hashed_fingerprint(), bridge); bridges.insert(fingerprint, bridge);
} }
let bridge = bridges let bridge = bridges.get_mut(&fingerprint).unwrap();
.get_mut(&bridgeline.get_hashed_fingerprint())
.unwrap();
if is_censor { if is_censor {
censor.learn_bridge(&bridgeline.get_hashed_fingerprint()); censor.learn_bridge(&fingerprint);
} else if Self::connect(in_censorship_range, config, bridge, censor) { } else {
able_to_connect = true; // If this is the first time the bridge has been
} else if submits_reports { // distributed to a real user, store that info
negative_reports.push(NegativeReport::from_bridgeline( if bridge.first_real_user == 0 {
bridgeline, bridge.first_real_user = get_date();
config.country.to_string(), }
BridgeDistributor::Lox,
)); if Self::connect(in_censorship_range, config, bridge, censor) {
able_to_connect = true;
} else if submits_reports {
negative_reports.push(NegativeReport::from_bridgeline(
bridgeline,
config.country.to_string(),
BridgeDistributor::Lox,
));
}
} }
} }
} }
@ -370,9 +397,17 @@ impl User {
// Make sure each bridge in bucket is in the global bridges set // Make sure each bridge in bucket is in the global bridges set
for bridgeline in bucket { for bridgeline in bucket {
if bridgeline != BridgeLine::default() { if bridgeline != BridgeLine::default() {
if !bridges.contains_key(&bridgeline.get_hashed_fingerprint()) { let fingerprint = bridgeline.get_hashed_fingerprint();
if !bridges.contains_key(&fingerprint) {
let bridge = Bridge::from_bridge_line(&bridgeline); let bridge = Bridge::from_bridge_line(&bridgeline);
bridges.insert(bridgeline.get_hashed_fingerprint(), bridge); bridges.insert(fingerprint, bridge);
}
// If this is the first time the bridge has been
// distributed to a real user, store that info
let bridge = bridges.get_mut(&fingerprint).unwrap();
if bridge.first_real_user == 0 {
bridge.first_real_user = get_date();
} }
} }
} }
@ -437,21 +472,23 @@ impl User {
get_bucket(&config.la_net, &second_cred).await?; get_bucket(&config.la_net, &second_cred).await?;
for bridgeline in second_bucket { for bridgeline in second_bucket {
if bridgeline != BridgeLine::default() { if bridgeline != BridgeLine::default() {
if !bridges.contains_key(&bridgeline.get_hashed_fingerprint()) { let fingerprint = bridgeline.get_hashed_fingerprint();
if !bridges.contains_key(&fingerprint) {
bridges.insert( bridges.insert(
bridgeline.get_hashed_fingerprint(), bridgeline.fingerprint,
Bridge::from_bridge_line(&bridgeline), Bridge::from_bridge_line(&bridgeline),
); );
} }
// If this is the first time the bridge has been
// distributed to a real user, store that info
let bridge = bridges.get_mut(&fingerprint).unwrap();
if bridge.first_real_user == 0 {
bridge.first_real_user = get_date();
}
// Attempt to connect to second cred's bridge // Attempt to connect to second cred's bridge
if Self::connect( if Self::connect(self.in_censorship_range, &config, bridge, censor) {
self.in_censorship_range,
&config,
bridges
.get_mut(&bridgeline.get_hashed_fingerprint())
.unwrap(),
censor,
) {
succeeded.push(bridgeline); succeeded.push(bridgeline);
if second_reachcred.is_some() if second_reachcred.is_some()
&& eligible_for_trust_promotion(&config.la_net, &second_cred).await && eligible_for_trust_promotion(&config.la_net, &second_cred).await