Make censors less likely to get invites from trusted users

This commit is contained in:
Vecna 2024-06-04 14:48:26 -04:00
parent d32c352ccc
commit 12882938e3
3 changed files with 91 additions and 21 deletions

View File

@ -57,6 +57,7 @@ pub struct Config {
// We start with this many level 4 users // We start with this many level 4 users
pub num_initial_trusted_users: u32, pub num_initial_trusted_users: u32,
pub one_positive_report_per_cred: bool, pub one_positive_report_per_cred: bool,
pub prob_censor_gets_invite: f64,
pub prob_connection_fails: f64, pub prob_connection_fails: f64,
pub prob_user_invites_friend: f64, pub prob_user_invites_friend: f64,
pub prob_user_is_censor: f64, pub prob_user_is_censor: f64,
@ -102,6 +103,7 @@ pub async fn main() {
censor_partial_blocking_percent: config.censor_partial_blocking_percent, censor_partial_blocking_percent: config.censor_partial_blocking_percent,
country: config.country, country: config.country,
one_positive_report_per_cred: config.one_positive_report_per_cred, one_positive_report_per_cred: config.one_positive_report_per_cred,
prob_censor_gets_invite: config.prob_censor_gets_invite,
prob_connection_fails: config.prob_connection_fails, prob_connection_fails: config.prob_connection_fails,
prob_user_invites_friend: config.prob_user_invites_friend, prob_user_invites_friend: config.prob_user_invites_friend,
prob_user_is_censor: config.prob_user_is_censor, prob_user_is_censor: config.prob_user_is_censor,
@ -256,6 +258,30 @@ pub async fn main() {
let mut num_users_requesting_invites: u32 = let mut num_users_requesting_invites: u32 =
rng.gen_range(config.min_new_users_per_day..=config.max_new_users_per_day); rng.gen_range(config.min_new_users_per_day..=config.max_new_users_per_day);
// How many of the new users are censors?
let mut num_new_censor_users = 0;
for _ in 0..num_users_requesting_invites {
let num: f64 = rng.gen_range(0.0..1.0);
if num < config.prob_user_is_censor {
num_new_censor_users += 1;
num_users_requesting_invites -= 1;
}
}
// Determine whether each new censor user can get an invite from
// an existing trusted user or needs to join via open-entry
// invite. Note: We still favor honest users by giving them
// invites *first*. This means if only a small number of invites
// are available, the censor may still not get invited.
let mut num_censor_invitations = 0;
for _ in 0..num_new_censor_users {
let num: f64 = rng.gen_range(0.0..1.0);
if num < config.prob_censor_gets_invite {
num_censor_invitations += 1;
num_new_censor_users -= 1;
}
}
let mut new_users = Vec::<User>::new(); let mut new_users = Vec::<User>::new();
// Shuffle users so they act in a random order // Shuffle users so they act in a random order
@ -267,6 +293,7 @@ pub async fn main() {
.daily_tasks( .daily_tasks(
&sconfig, &sconfig,
num_users_requesting_invites, num_users_requesting_invites,
num_censor_invitations,
&mut bridges, &mut bridges,
&mut censor, &mut censor,
) )
@ -276,10 +303,17 @@ pub async fn main() {
let mut invited_friends = invited_friends.unwrap(); let mut invited_friends = invited_friends.unwrap();
if invited_friends.len() > 0 { if invited_friends.len() > 0 {
if !user.is_censor { if !user.is_censor {
// Users should never invite more friends than // Censors always invite as many censor friends
// need invitations, so this should never become // as possible. Honest users may invite honest
// negative // friends, or they may accidentally invite
num_users_requesting_invites -= invited_friends.len() as u32; // censor friends.
for inv_friend in &invited_friends {
if inv_friend.is_censor {
num_censor_invitations -= 1;
} else {
num_users_requesting_invites -= 1;
}
}
} }
// If this user invited any friends, add them to the // If this user invited any friends, add them to the
// list of users // list of users
@ -294,7 +328,7 @@ pub async fn main() {
// If any users couldn't get invites, they join with open-entry // If any users couldn't get invites, they join with open-entry
// invitations // invitations
for _ in 0..num_users_requesting_invites { for _ in 0..num_users_requesting_invites {
let user = User::new(&sconfig).await; let user = User::new(&sconfig, false).await;
if user.is_ok() { if user.is_ok() {
users.push(user.unwrap()); users.push(user.unwrap());
} else { } else {
@ -302,6 +336,17 @@ pub async fn main() {
} }
} }
// If any censor users couldn't get invites, they also join with
// open-entry invitations
for _ in 0..(num_new_censor_users + num_censor_invitations) {
let user = User::new(&sconfig, true).await;
if user.is_ok() {
users.push(user.unwrap());
} else {
eprintln!("Failed to create new censor user.");
}
}
// CENSOR TASKS // CENSOR TASKS
censor.end_of_day_tasks(&sconfig, &mut bridges).await; censor.end_of_day_tasks(&sconfig, &mut bridges).await;

View File

@ -17,6 +17,9 @@ pub struct Config {
// share information with each other. // share information with each other.
pub country: String, pub country: String,
pub one_positive_report_per_cred: bool, pub one_positive_report_per_cred: bool,
// Probability that a censor-cooperating user can convince an honest
// user to give them an invite.
pub prob_censor_gets_invite: f64,
// Probability that a connection randomly fails, even though censor // Probability that a connection randomly fails, even though censor
// does not block the bridge // does not block the bridge
pub prob_connection_fails: f64, pub prob_connection_fails: f64,

View File

@ -45,7 +45,7 @@ pub struct User {
} }
impl User { impl User {
pub async fn new(config: &Config) -> Result<Self, Error> { pub async fn new(config: &Config, is_censor: bool) -> Result<Self, Error> {
let cred = get_lox_credential( let cred = get_lox_credential(
&config.la_net, &config.la_net,
&get_open_invitation(&config.la_net).await?, &get_open_invitation(&config.la_net).await?,
@ -54,9 +54,6 @@ impl User {
.await? .await?
.0; .0;
// Probabilistically decide whether this user cooperates with a censor
let is_censor = event_happens(config.prob_user_is_censor);
// Probabilistically decide whether this user submits reports // Probabilistically decide whether this user submits reports
let submits_reports = if is_censor { let submits_reports = if is_censor {
false false
@ -96,7 +93,12 @@ impl User {
} }
// TODO: This should probably return an actual error type // TODO: This should probably return an actual error type
pub async fn invite(&mut self, config: &Config, censor: &mut Censor) -> Result<Self, Error> { pub async fn invite(
&mut self,
config: &Config,
censor: &mut Censor,
invited_user_is_censor: bool,
) -> Result<Self, Error> {
let etable = get_reachability_credential(&config.la_net).await?; let etable = get_reachability_credential(&config.la_net).await?;
let (new_cred, invite) = issue_invite( let (new_cred, invite) = issue_invite(
&config.la_net, &config.la_net,
@ -127,13 +129,8 @@ impl User {
.await? .await?
.0; .0;
// If the inviting user is a censor, the invitee will also be a // Calling function decides if the invited user is a censor
// censor. If not, probabilistically decide. let is_censor = invited_user_is_censor;
let is_censor = if self.is_censor {
true
} else {
event_happens(config.prob_user_is_censor)
};
// Probabilistically decide whether this user submits reports // Probabilistically decide whether this user submits reports
let submits_reports = if is_censor { let submits_reports = if is_censor {
@ -254,14 +251,21 @@ impl User {
&mut self, &mut self,
config: &Config, config: &Config,
num_users_requesting_invites: u32, num_users_requesting_invites: u32,
num_censor_invites: u32,
bridges: &mut HashMap<[u8; 20], Bridge>, bridges: &mut HashMap<[u8; 20], Bridge>,
censor: &mut Censor, censor: &mut Censor,
) -> Result<Vec<User>, Error> { ) -> Result<Vec<User>, Error> {
if self.is_censor { if self.is_censor {
self.daily_tasks_censor(config, bridges, censor).await self.daily_tasks_censor(config, bridges, censor).await
} else { } else {
self.daily_tasks_non_censor(config, num_users_requesting_invites, bridges, censor) self.daily_tasks_non_censor(
.await config,
num_users_requesting_invites,
num_censor_invites,
bridges,
censor,
)
.await
} }
} }
@ -273,6 +277,7 @@ impl User {
&mut self, &mut self,
config: &Config, config: &Config,
num_users_requesting_invites: u32, num_users_requesting_invites: u32,
num_censor_invites: u32,
bridges: &mut HashMap<[u8; 20], Bridge>, bridges: &mut HashMap<[u8; 20], Bridge>,
censor: &mut Censor, censor: &mut Censor,
) -> Result<Vec<User>, Error> { ) -> Result<Vec<User>, Error> {
@ -512,7 +517,8 @@ impl User {
let mut new_friends = Vec::<User>::new(); let mut new_friends = Vec::<User>::new();
for _i in 0..min(invitations, num_users_requesting_invites) { for _i in 0..min(invitations, num_users_requesting_invites) {
if event_happens(config.prob_user_invites_friend) { if event_happens(config.prob_user_invites_friend) {
match self.invite(&config, censor).await { // Invite non-censor friend
match self.invite(&config, censor, false).await {
Ok(friend) => { Ok(friend) => {
// You really shouldn't push your friends, // You really shouldn't push your friends,
// especially new ones whose boundaries you // especially new ones whose boundaries you
@ -526,6 +532,22 @@ impl User {
} }
} }
// Invite censor users if applicable
let invitations = invitations - new_friends.len() as u32;
for _i in 0..min(invitations, num_censor_invites) {
if event_happens(config.prob_user_invites_friend) {
// Invite non-censor friend
match self.invite(&config, censor, true).await {
Ok(friend) => {
new_friends.push(friend);
}
Err(e) => {
println!("{}", e);
}
}
}
}
Ok(new_friends) Ok(new_friends)
} else { } else {
Ok(Vec::<User>::new()) Ok(Vec::<User>::new())
@ -643,7 +665,7 @@ impl User {
let invitations = scalar_u32(&self.primary_cred.invites_remaining).unwrap(); let invitations = scalar_u32(&self.primary_cred.invites_remaining).unwrap();
let mut new_friends = Vec::<User>::new(); let mut new_friends = Vec::<User>::new();
for _ in 0..invitations { for _ in 0..invitations {
match self.invite(&config, censor).await { match self.invite(&config, censor, true).await {
Ok(friend) => { Ok(friend) => {
new_friends.push(friend); new_friends.push(friend);
} }