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
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
pub first_blocked: u32,
@ -35,6 +38,7 @@ impl Bridge {
Self {
fingerprint: *fingerprint,
first_distributed: get_date(),
first_real_user: 0, // set this afterwards if user is non-censor
first_blocked: 0,
first_detected_blocked: 0,
first_positive_report: 0,

View File

@ -126,11 +126,21 @@ pub async fn main() {
});
sleep(Duration::from_millis(1)).await;
// Only consider bridges that have been distributed to users
let mut false_neg = 0;
let mut false_pos = 0;
let mut true_neg = 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
let mut max_physical_mem = 0;
let mut max_virtual_mem = 0;
@ -140,6 +150,10 @@ pub async fn main() {
// Save some function calls by storing this
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!(
" We have {} users and {} bridges",
@ -195,8 +209,37 @@ pub async fn main() {
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
users.append(&mut new_users);
@ -285,14 +328,30 @@ pub async fn main() {
if really_blocked && bridge.first_blocked == 0 {
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 {
true_pos += 1;
if bridge.first_real_user > 0 {
true_pos += 1;
}
total_tp += 1;
} else if detected_blocked {
false_pos += 1;
if bridge.first_real_user > 0 {
false_pos += 1;
}
total_fp += 1;
} else if really_blocked {
false_neg += 1;
if bridge.first_real_user > 0 {
false_neg += 1;
}
total_fn += 1;
} 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
);
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 Negatives: {}", true_neg);
println!("False Positives: {}", false_pos);
@ -342,16 +408,27 @@ pub async fn main() {
println!("\nFull stats per bridge:");
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 {
println!(
"{},{},{},{},{}",
"{},{},{},{},{},{}",
array_bytes::bytes2hex("", fingerprint),
bridge.first_distributed,
bridge.first_real_user,
bridge.first_blocked,
bridge.first_detected_blocked,
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();
if is_censor {
censor.learn_bridge(&bridgeline.get_hashed_fingerprint());
} else if Self::connect(in_censorship_range, config, bridge, censor) {
able_to_connect = true;
} else if submits_reports {
// New user only has one bridge, so no need
// to collect the negative reports before
// 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?;
} else {
// If this is the first time the bridge has been
// distributed to a real user, store that info
if bridge.first_real_user == 0 {
bridge.first_real_user = get_date();
}
if Self::connect(in_censorship_range, config, bridge, censor) {
able_to_connect = true;
} else if submits_reports {
// New user only has one bridge, so no need
// to collect the negative reports before
// 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?;
self.primary_cred = new_cred;
if self.is_censor {
// Make sure censor has access to each bridge and each
// credential
let (bucket, _reachcred) = get_bucket(&config.la_net, &self.primary_cred).await?;
for bl in bucket {
// Make sure bridge is in list of bridges and that censor has
// access if applicable
let (bucket, _reachcred) = get_bucket(&config.la_net, &self.primary_cred).await?;
for bl in bucket {
if bl != BridgeLine::default() {
let fingerprint = bl.get_hashed_fingerprint();
censor.learn_bridge(&fingerprint);
censor.give_lox_cred(&fingerprint, &self.primary_cred);
if !bridges.contains_key(&fingerprint) {
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(
&config.la_net,
&invite,
@ -184,24 +204,31 @@ impl User {
let mut negative_reports = Vec::<NegativeReport>::new();
let (bucket, _reachcred) = get_bucket(&config.la_net, &friend_cred).await?;
for bridgeline in bucket {
let fingerprint = bridgeline.get_hashed_fingerprint();
if bridgeline != BridgeLine::default() {
if !bridges.contains_key(&bridgeline.get_hashed_fingerprint()) {
if !bridges.contains_key(&fingerprint) {
let bridge = Bridge::from_bridge_line(&bridgeline);
bridges.insert(bridgeline.get_hashed_fingerprint(), bridge);
bridges.insert(fingerprint, bridge);
}
let bridge = bridges
.get_mut(&bridgeline.get_hashed_fingerprint())
.unwrap();
let bridge = bridges.get_mut(&fingerprint).unwrap();
if is_censor {
censor.learn_bridge(&bridgeline.get_hashed_fingerprint());
} else 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,
));
censor.learn_bridge(&fingerprint);
} else {
// If this is the first time the bridge has been
// distributed to a real user, store that info
if bridge.first_real_user == 0 {
bridge.first_real_user = get_date();
}
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
for bridgeline in bucket {
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);
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?;
for bridgeline in second_bucket {
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(
bridgeline.get_hashed_fingerprint(),
bridgeline.fingerprint,
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
if Self::connect(
self.in_censorship_range,
&config,
bridges
.get_mut(&bridgeline.get_hashed_fingerprint())
.unwrap(),
censor,
) {
if Self::connect(self.in_censorship_range, &config, bridge, censor) {
succeeded.push(bridgeline);
if second_reachcred.is_some()
&& eligible_for_trust_promotion(&config.la_net, &second_cred).await