Track whether bridge has actually been distributed to users
This commit is contained in:
parent
fcbffdc53e
commit
25d1fb96a6
|
@ -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,
|
||||||
|
|
89
src/main.rs
89
src/main.rs
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
129
src/user.rs
129
src/user.rs
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue