From 020c0c4d50947ef61c3a15864bdc6167b66891cd Mon Sep 17 00:00:00 2001 From: ibaryshnikov Date: Tue, 24 Aug 2021 23:03:35 +0300 Subject: [PATCH 1/2] updated the coordinator logic to let the verifiers join mid-round, updated tests --- phase1-coordinator/Cargo.toml | 1 + .../src/commands/aggregation.rs | 23 +- .../src/commands/verification.rs | 7 +- phase1-coordinator/src/coordinator.rs | 534 +++-------- phase1-coordinator/src/coordinator_state.rs | 903 +++--------------- phase1-coordinator/src/environment.rs | 46 - phase1-coordinator/src/objects/chunk.rs | 5 - phase1-coordinator/src/objects/round.rs | 146 +-- phase1-coordinator/src/testing/coordinator.rs | 1 - .../src/testing/resources/round.json | 4 +- .../src/testing/resources/round_partial.json | 4 +- .../src/testing/resources/test_round_0.json | 4 +- .../resources/test_round_1_initial.json | 4 +- .../resources/test_round_1_partial.json | 7 +- phase1-coordinator/src/tests.rs | 426 +++------ 15 files changed, 443 insertions(+), 1672 deletions(-) diff --git a/phase1-coordinator/Cargo.toml b/phase1-coordinator/Cargo.toml index 1f4494fb..e26a7bb2 100644 --- a/phase1-coordinator/Cargo.toml +++ b/phase1-coordinator/Cargo.toml @@ -11,6 +11,7 @@ edition = "2018" [[bin]] name = "phase1-coordinator" path = "src/main.rs" +required-features = ["parallel"] [dependencies] phase1 = { path = "../phase1" } diff --git a/phase1-coordinator/src/commands/aggregation.rs b/phase1-coordinator/src/commands/aggregation.rs index 58ff4256..912ecff2 100644 --- a/phase1-coordinator/src/commands/aggregation.rs +++ b/phase1-coordinator/src/commands/aggregation.rs @@ -148,6 +148,7 @@ mod tests { use crate::{ authentication::Dummy, commands::{Aggregation, Seed, SigningKey, SEED_LENGTH}, + objects::Task, storage::{Locator, Storage}, testing::prelude::*, Coordinator, @@ -181,10 +182,7 @@ mod tests { assert_eq!(0, round_height); let contributors = vec![contributor.clone()]; - let verifiers = vec![verifier.clone()]; - coordinator - .next_round(*TEST_STARTED_AT, contributors, verifiers) - .unwrap(); + coordinator.next_round(*TEST_STARTED_AT, contributors).unwrap(); } // Check current round height is now 1. @@ -240,21 +238,10 @@ mod tests { contribute.unwrap(); } } - { - // Acquire the lock as the verifier. - let try_lock = coordinator.try_lock_chunk(chunk_id, &verifier.clone()); - if try_lock.is_err() { - error!( - "Failed to acquire lock as verifier {:?}\n{}", - &verifier, - serde_json::to_string_pretty(&coordinator.current_round().unwrap()).unwrap() - ); - try_lock.unwrap(); - } - } { // Run verification as verifier. - let verify = coordinator.run_verification(round_height, chunk_id, 1, &verifier, &verifier_signing_key); + let task = Task::new(chunk_id, 1); + let verify = coordinator.run_verification(round_height, &task, &verifier, &verifier_signing_key); if verify.is_err() { error!( "Failed to run verification as verifier {:?}\n{}", @@ -265,7 +252,7 @@ mod tests { } // Run verification as the verifier. - let verify = coordinator.verify_contribution(chunk_id, &verifier.clone()); + let verify = coordinator.verify_contribution(&task, &verifier.clone()); if verify.is_err() { error!( "Failed to run verification as verifier {:?}\n{}", diff --git a/phase1-coordinator/src/commands/verification.rs b/phase1-coordinator/src/commands/verification.rs index 0116543d..bca69193 100644 --- a/phase1-coordinator/src/commands/verification.rs +++ b/phase1-coordinator/src/commands/verification.rs @@ -360,7 +360,7 @@ mod tests { let contributor = Lazy::force(&TEST_CONTRIBUTOR_ID).clone(); let contributor_signing_key = "secret_key".to_string(); - let verifier = Lazy::force(&TEST_VERIFIER_ID).clone(); + let _verifier = Lazy::force(&TEST_VERIFIER_ID).clone(); let verifier_signing_key = "secret_key".to_string(); { @@ -373,10 +373,7 @@ mod tests { assert_eq!(0, round_height); let contributors = vec![contributor.clone()]; - let verifiers = vec![verifier.clone()]; - coordinator - .next_round(*TEST_STARTED_AT, contributors, verifiers) - .unwrap(); + coordinator.next_round(*TEST_STARTED_AT, contributors).unwrap(); } // Check current round height is now 1. diff --git a/phase1-coordinator/src/coordinator.rs b/phase1-coordinator/src/coordinator.rs index 892c8524..88031055 100644 --- a/phase1-coordinator/src/coordinator.rs +++ b/phase1-coordinator/src/coordinator.rs @@ -35,6 +35,9 @@ use std::{ }; use tracing::*; +#[cfg(any(test, feature = "operator"))] +use std::collections::HashMap; + #[derive(Debug)] pub enum CoordinatorError { AggregateContributionFileSizeMismatch, @@ -462,10 +465,6 @@ where self.state.update_current_contributors(self.time.as_ref())?; self.save_state()?; - // Update the state of current round verifiers. - self.state.update_current_verifiers(self.time.as_ref())?; - self.save_state()?; - // Drop disconnected participants from the current round. for drop in self.state.update_dropped_participants(self.time.as_ref())? { // Update the round to reflect the coordinator state changes. @@ -568,14 +567,6 @@ where self.state.is_queue_contributor(&participant) } - /// - /// Returns `true` if the given participant is a verifier in the queue. - /// - #[inline] - pub fn is_queue_verifier(&self, participant: &Participant) -> bool { - self.state.is_queue_verifier(&participant) - } - /// /// Returns the total number of contributors currently in the queue. /// @@ -584,14 +575,6 @@ where self.state.number_of_queue_contributors() } - /// - /// Returns the total number of verifiers currently in the queue. - /// - #[inline] - pub fn number_of_queue_verifiers(&self) -> usize { - self.state.number_of_queue_verifiers() - } - /// /// Returns a list of the contributors currently in the queue. /// @@ -600,14 +583,6 @@ where self.state.queue_contributors() } - /// - /// Returns a list of the verifiers currently in the queue. - /// - #[inline] - pub fn queue_verifiers(&self) -> Vec<(Participant, (u8, Option))> { - self.state.queue_verifiers() - } - /// /// Returns a list of the contributors currently in the round. /// @@ -616,14 +591,6 @@ where self.state.current_contributors() } - /// - /// Returns a list of the verifiers currently in the round. - /// - #[inline] - pub fn current_verifiers(&self) -> Vec<(Participant, ParticipantInfo)> { - self.state.current_verifiers() - } - /// /// Returns a list of participants that were dropped from the current round. /// @@ -782,32 +749,6 @@ where self.state.is_current_contributor(participant) } - /// - /// Returns `true` if the given participant is authorized as a - /// verifier and listed in the verifier IDs for this round. - /// - /// If the participant is not a verifier, or if there are - /// no prior rounds, returns `false`. - /// - #[inline] - pub fn is_current_verifier(&self, participant: &Participant) -> bool { - // Fetch the current round from storage. - let round = match Self::load_current_round(&self.storage) { - // Case 1 - This is a typical round of the ceremony. - Ok(round) => round, - // Case 2 - The ceremony has not started or storage has failed. - _ => return false, - }; - - // Check that the participant is a verifier for the given round height. - if !round.is_verifier(participant) { - return false; - } - - // Check that the participant is a current verifier. - self.state.is_current_verifier(participant) - } - /// /// Returns `true` if the given participant has finished contributing /// in the current round. @@ -823,21 +764,6 @@ where self.state.is_finished_contributor(&participant) } - /// - /// Returns `true` if the given participant has finished verifying - /// in the current round. - /// - #[inline] - pub fn is_finished_verifier(&self, participant: &Participant) -> bool { - // Check that the participant is a current verifier. - if !self.is_current_verifier(participant) { - return false; - } - - // Fetch the state of the current verifier. - self.state.is_finished_verifier(&participant) - } - /// /// Returns `true` if the given participant is a contributor managed /// by the coordinator. @@ -941,8 +867,12 @@ where err )] pub fn try_lock(&mut self, participant: &Participant) -> Result<(u64, LockedLocators), CoordinatorError> { + if participant.is_verifier() { + return Err(CoordinatorError::ExpectedContributor); + } + // Check that the participant is in the current round, and has not been dropped or finished. - if !self.state.is_current_contributor(participant) && !self.state.is_current_verifier(participant) { + if !self.state.is_current_contributor(participant) { return Err(CoordinatorError::ParticipantUnauthorized); } @@ -1106,7 +1036,7 @@ where trace!("Release the lock on chunk"); let completed_task = Task::new(chunk_id, contribution_id); self.state - .completed_task(participant, completed_task, self.time.as_ref())?; + .completed_task(participant, &completed_task, self.time.as_ref())?; // Save the coordinator state in storage. self.save_state()?; @@ -1148,26 +1078,21 @@ where /// #[tracing::instrument( level = "error", - skip(self, chunk_id), - fields(participant = %participant, chunk = chunk_id), + skip(self, task), + fields(participant = %participant), err )] - pub fn try_verify(&mut self, participant: &Participant, chunk_id: u64) -> Result<(), CoordinatorError> { + pub fn try_verify(&mut self, participant: &Participant, task: &Task) -> Result<(), CoordinatorError> { // Check that the participant is a verifier. if !participant.is_verifier() { return Err(CoordinatorError::ExpectedVerifier); } // Check that the chunk ID is valid. - if chunk_id > self.environment.number_of_chunks() { + if task.chunk_id() > self.environment.number_of_chunks() { return Err(CoordinatorError::ChunkIdInvalid); } - // Check that the participant is in the current round, and has not been dropped or finished. - if !self.state.is_current_verifier(participant) { - return Err(CoordinatorError::ParticipantUnauthorized); - } - // Check that the current round is not yet finished. if self.state.is_current_round_finished() { return Err(CoordinatorError::CurrentRoundFinished); @@ -1183,113 +1108,58 @@ where return Err(CoordinatorError::CurrentRoundAggregated); } - // Check if the participant should dispose the response being contributed. - if let Some(task) = self.state.lookup_disposing_task(participant, chunk_id)?.cloned() { - let contribution_id = task.contribution_id(); - - // Move the task to the disposed tasks of the verifier. - self.state.disposed_task(participant, &task, self.time.as_ref())?; - - // Save the coordinator state in storage. - self.save_state()?; - - debug!( - "Removing lock for verifier {} disposed task {} {}", - participant, chunk_id, contribution_id - ); - - // Fetch the current round from storage. - let mut round = Self::load_current_round(&self.storage)?; - - // TODO (raychu86): Move this unsafe call out of `try_verify`. - // Release the lock on this chunk from the contributor. - round.chunk_mut(chunk_id)?.set_lock_holder_unsafe(None); + debug!( + "Adding verification from {} for chunk {} contribution {}", + participant, + task.chunk_id(), + task.contribution_id() + ); - // Fetch the next challenge locator. - let is_final_contribution = contribution_id == round.expected_number_of_contributions() - 1; - let next_challenge = match is_final_contribution { - true => { - Locator::ContributionFile(ContributionLocator::new(round.round_height() + 1, chunk_id, 0, true)) + match self.verify_contribution(task, participant) { + // Case 1 - Participant verified contribution, return the response file locator. + Ok(contribution_id) => { + if contribution_id != task.contribution_id() { + return Err(CoordinatorError::ContributionIdMismatch); } - false => Locator::ContributionFile(ContributionLocator::new( - round.round_height(), - chunk_id, - contribution_id, - true, - )), - }; + self.state.completed_task(participant, task, self.time.as_ref())?; - // Save the updated round to storage. - self.storage.update( - &Locator::RoundState { - round_height: round.round_height(), - }, - Object::RoundState(round), - )?; - - // Remove the next challenge file from storage. - self.storage.remove(&next_challenge)?; - - return Ok(()); - } - - // Check if the participant has this chunk ID in a pending task. - if let Some(task) = self.state.lookup_pending_task(participant, chunk_id)? { - let contribution_id = task.contribution_id(); - - debug!( - "Adding verification from {} for chunk {} contribution {}", - participant, chunk_id, contribution_id - ); - - match self.verify_contribution(chunk_id, participant) { - // Case 1 - Participant verified contribution, return the response file locator. - Ok(contribution_id) => { - trace!("Release the lock on chunk {} from {}", chunk_id, participant); - let completed_task = Task::new(chunk_id, contribution_id); - self.state - .completed_task(participant, completed_task, self.time.as_ref())?; - - // Save the coordinator state in storage. - self.save_state()?; - - info!("Added verification from {} for chunk {}", participant, chunk_id); - return Ok(()); - } - // Case 2 - Participant failed to add their contribution, remove the contribution file. - Err(error) => { - info!("Failed to add a verification and removing the contribution file"); + // Save the coordinator state in storage. + self.save_state()?; - // Fetch the current round from storage. - let round = Self::load_current_round(&self.storage)?; + info!("Added verification from {} for chunk {}", participant, task.chunk_id()); + Ok(()) + } + // Case 2 - Participant failed to add their contribution, remove the contribution file. + Err(error) => { + info!("Failed to add a verification and removing the contribution file"); - // Fetch the next challenge locator. - let is_final_contribution = contribution_id == round.expected_number_of_contributions() - 1; - let next_challenge = match is_final_contribution { - true => Locator::ContributionFile(ContributionLocator::new( - round.round_height() + 1, - chunk_id, - 0, - true, - )), - false => Locator::ContributionFile(ContributionLocator::new( - round.round_height(), - chunk_id, - contribution_id, - true, - )), - }; + // Fetch the current round from storage. + let round = Self::load_current_round(&self.storage)?; + + // Fetch the next challenge locator. + let is_final_contribution = task.contribution_id() == round.expected_number_of_contributions() - 1; + let next_challenge = match is_final_contribution { + true => Locator::ContributionFile(ContributionLocator::new( + round.round_height() + 1, + task.chunk_id(), + 0, + true, + )), + false => Locator::ContributionFile(ContributionLocator::new( + round.round_height(), + task.chunk_id(), + task.contribution_id(), + true, + )), + }; - // Remove the invalid next challenge file from storage. - self.storage.remove(&next_challenge)?; + // Remove the invalid next challenge file from storage. + self.storage.remove(&next_challenge)?; - error!("{}", error); - return Err(error); - } + error!("{}", error); + Err(error) } } - - Err(CoordinatorError::VerificationFailed) } /// @@ -1416,9 +1286,9 @@ where .precommit_next_round(current_round_height + 1, self.time.as_ref()) { // Case 1 - Precommit succeed, attempt to advance the round. - Ok((contributors, verifiers)) => { + Ok(contributors) => { trace!("Trying to add advance to the next round"); - match self.next_round(started_at, contributors, verifiers) { + match self.next_round(started_at, contributors) { // Case 1a - Coordinator advanced the round. Ok(next_round_height) => { // If success, update coordinator state to next round. @@ -1714,15 +1584,19 @@ where /// in the next round's directory as contribution 0. /// #[tracing::instrument( - skip(self, chunk_id, participant), - fields(chunk = chunk_id, participant = %participant) + skip(self, participant), + fields(participant = %participant) )] pub(crate) fn verify_contribution( &mut self, - chunk_id: u64, + task: &Task, participant: &Participant, ) -> Result { + let chunk_id = task.chunk_id(); debug!("Attempting to verify a contribution for chunk {}", chunk_id); + if !participant.is_verifier() { + return Err(CoordinatorError::ExpectedVerifier); + } // Fetch the current round height from storage. let current_round_height = Self::load_current_round_height(&self.storage)?; @@ -1730,24 +1604,14 @@ where // Fetch the current round from storage. let mut round = Self::load_current_round(&self.storage)?; - { - // Check that the participant is an authorized verifier to the current round. - if !round.is_verifier(participant) { - error!("{} is unauthorized to verify chunk {})", participant, chunk_id); - return Err(CoordinatorError::UnauthorizedChunkContributor); - } - - // Check that the chunk lock is currently held by this verifier. - if !round.is_chunk_locked_by(chunk_id, participant) { - error!("{} should have lock on chunk {} but does not", participant, chunk_id); - return Err(CoordinatorError::ChunkNotLockedOrByWrongParticipant); - } - } // Fetch the chunk corresponding to the given chunk ID. let chunk = round.chunk(chunk_id)?; // Fetch the current contribution ID. let contribution_id = chunk.current_contribution_id(); + if contribution_id != task.contribution_id() { + return Err(CoordinatorError::ContributionIdMismatch); + } // Fetch the challenge, response, next challenge, and contribution file signature locators. let challenge_file_locator = Locator::ContributionFile(ContributionLocator::new( @@ -2059,16 +1923,11 @@ where &mut self, started_at: DateTime, contributors: Vec, - verifiers: Vec, ) -> Result { // Check that the next round has at least one authorized contributor. if contributors.is_empty() { return Err(CoordinatorError::ContributorsMissing); } - // Check that the next round has at least one authorized verifier. - if verifiers.is_empty() { - return Err(CoordinatorError::VerifierMissing); - } // Fetch the current round height from storage. let current_round_height = Self::load_current_round_height(&self.storage)?; @@ -2124,7 +1983,6 @@ where new_height, started_at, contributors, - verifiers, )?; #[cfg(test)] @@ -2182,16 +2040,6 @@ where // Initialize the contributors as an empty list as this is for initialization. let contributors = vec![]; - // Initialize the verifiers as a list comprising only one coordinator verifier, - // as this is for initialization. - let verifiers = vec![ - self.environment - .coordinator_verifiers() - .first() - .ok_or(CoordinatorError::VerifierMissing)? - .clone(), - ]; - // Create a new round instance. Round::new( &self.environment, @@ -2199,7 +2047,6 @@ where round_height, started_at, contributors, - verifiers, )? }; @@ -2309,38 +2156,6 @@ where replace_action.replacement_contributor ); - // Save the updated round to storage. - self.storage.update( - &Locator::RoundState { - round_height: round.round_height(), - }, - Object::RoundState(round), - )?; - } - CeremonyStorageAction::RemoveVerifier(remove_action) => { - warn!("Removing verifier {}", remove_action.dropped_verifier); - - // Fetch the current round from storage. - let mut round = Self::load_current_round(&self.storage)?; - - warn!("Removing locked chunks and all impacted contributions"); - - // Remove the lock from the specified chunks. - round.remove_locks_unsafe( - &mut self.storage, - &remove_action.dropped_verifier, - &remove_action.locked_chunks, - )?; - warn!("Removed locked chunks"); - - // Remove the contributions from the specified chunks. - round.remove_chunk_contributions_unsafe( - &mut self.storage, - &remove_action.dropped_verifier, - &remove_action.tasks, - )?; - warn!("Removed impacted contributions"); - // Save the updated round to storage. self.storage.update( &Locator::RoundState { @@ -2559,22 +2374,33 @@ where Ok(()) } + pub fn get_pending_verifications(&self) -> &HashMap { + self.state.get_pending_verifications() + } + #[tracing::instrument( skip(self, verifier, verifier_signing_key), fields(verifier = %verifier), )] - pub fn verify(&mut self, verifier: &Participant, verifier_signing_key: &SigningKey) -> anyhow::Result<()> { - let (_chunk_id, locked_locators) = self.try_lock(&verifier)?; - let response_locator = &locked_locators.current_contribution(); - let round_height = response_locator.round_height(); - let chunk_id = response_locator.chunk_id(); - let contribution_id = response_locator.contribution_id(); - - debug!("Running verification for round {} chunk {}", round_height, chunk_id); - let _next_challenge = - self.run_verification(round_height, chunk_id, contribution_id, &verifier, verifier_signing_key)?; - self.try_verify(&verifier, chunk_id)?; - debug!("Successful verification for round {} chunk {}", round_height, chunk_id); + pub fn verify( + &mut self, + verifier: &Participant, + verifier_signing_key: &SigningKey, + task: &Task, + ) -> anyhow::Result<()> { + let round_height = self.current_round_height()?; + debug!( + "Running verification for round {} chunk {}", + round_height, + task.chunk_id() + ); + let _next_challenge = self.run_verification(round_height, task, verifier, verifier_signing_key)?; + self.try_verify(verifier, task)?; + debug!( + "Successful verification for round {} chunk {}", + round_height, + task.chunk_id() + ); Ok(()) } @@ -2678,11 +2504,12 @@ where pub fn run_verification( &mut self, round_height: u64, - chunk_id: u64, - contribution_id: u64, + task: &Task, participant: &Participant, participant_signing_key: &SigningKey, ) -> Result { + let chunk_id = task.chunk_id(); + let contribution_id = task.contribution_id(); info!( "Running verification for round {} chunk {} contribution {} as {}", round_height, chunk_id, contribution_id, participant @@ -2706,12 +2533,6 @@ where // Fetch the specified round from storage. let round = Self::load_round(&self.storage, round_height)?; - // Check that the chunk lock is currently held by this contributor. - if !round.is_chunk_locked_by(chunk_id, &participant) { - error!("{} should have lock on chunk {} but does not", &participant, chunk_id); - return Err(CoordinatorError::ChunkNotLockedOrByWrongParticipant); - } - // Check that the contribution locator corresponding to the response file exists. let response_locator = Locator::ContributionFile(ContributionLocator::new(round_height, chunk_id, contribution_id, false)); @@ -2795,7 +2616,7 @@ mod tests { authentication::Dummy, commands::{Seed, SigningKey, SEED_LENGTH}, environment::*, - objects::Participant, + objects::{Participant, Task}, storage::Disk, testing::prelude::*, Coordinator, @@ -2806,11 +2627,7 @@ mod tests { use rand::RngCore; use std::{collections::HashMap, sync::Arc}; - fn initialize_to_round_1( - coordinator: &mut Coordinator, - contributors: &[Participant], - verifiers: &[Participant], - ) -> anyhow::Result<()> { + fn initialize_to_round_1(coordinator: &mut Coordinator, contributors: &[Participant]) -> anyhow::Result<()> { // Initialize the ceremony and add the contributors and verifiers to the queue. { // Run initialization. @@ -2829,9 +2646,6 @@ mod tests { for contributor in contributors { coordinator.state.add_to_queue(contributor.clone(), 10)?; } - for verifier in verifiers { - coordinator.state.add_to_queue(verifier.clone(), 10)?; - } // Update the queue. coordinator.state.update_queue()?; @@ -2865,17 +2679,15 @@ mod tests { Lazy::force(&TEST_CONTRIBUTOR_ID).clone(), Lazy::force(&TEST_CONTRIBUTOR_ID_2).clone(), ]; - let verifiers = vec![Lazy::force(&TEST_VERIFIER_ID).clone()]; - initialize_to_round_1(coordinator, &contributors, &verifiers) + initialize_to_round_1(coordinator, &contributors) } fn initialize_coordinator_single_contributor(coordinator: &mut Coordinator) -> anyhow::Result<()> { // Load the contributors and verifiers. let contributors = vec![Lazy::force(&TEST_CONTRIBUTOR_ID).clone()]; - let verifiers = vec![Lazy::force(&TEST_VERIFIER_ID).clone()]; - initialize_to_round_1(coordinator, &contributors, &verifiers) + initialize_to_round_1(coordinator, &contributors) } #[test] @@ -2927,12 +2739,9 @@ mod tests { Lazy::force(&TEST_CONTRIBUTOR_ID).clone(), Lazy::force(&TEST_CONTRIBUTOR_ID_2).clone(), ]; - let verifiers = vec![Lazy::force(&TEST_VERIFIER_ID).clone()]; // Start round 1. - coordinator - .next_round(*TEST_STARTED_AT, contributors, verifiers) - .unwrap(); + coordinator.next_round(*TEST_STARTED_AT, contributors).unwrap(); } { @@ -2958,10 +2767,7 @@ mod tests { assert!(!current_round.is_contributor(&TEST_VERIFIER_ID)); // Check round 1 verifiers. - assert_eq!(1, current_round.number_of_verifiers()); - assert!(current_round.is_verifier(&TEST_VERIFIER_ID)); - assert!(!current_round.is_verifier(&TEST_VERIFIER_ID_2)); - assert!(!current_round.is_verifier(&TEST_CONTRIBUTOR_ID)); + assert_eq!(0, current_round.number_of_verifiers()); // Check round 1 is NOT complete. assert!(!current_round.is_complete()); @@ -3142,41 +2948,17 @@ mod tests { assert!(coordinator.add_contribution(chunk_id, &contributor).is_ok()); } - // Acquire lock for round 1 chunk 0 contribution 1. - { - // Acquire the lock on chunk 0 for the verifier. - let verifier = Lazy::force(&TEST_VERIFIER_ID).clone(); - { - assert!(coordinator.try_lock_chunk(chunk_id, &verifier).is_ok()); - } - - // Check that chunk 0 is locked. - let round = coordinator.current_round()?; - let chunk = round.chunk(chunk_id)?; - assert!(chunk.is_locked()); - assert!(!chunk.is_unlocked()); - - // Check that chunk 0 is locked by the verifier. - debug!("{:#?}", round); - assert!(chunk.is_locked_by(&verifier)); - } - // Verify round 1 chunk 0 contribution 1. { let verifier = Lazy::force(&TEST_VERIFIER_ID).clone(); let verifier_signing_key: SigningKey = "secret_key".to_string(); // Run verification. - let verify = coordinator.run_verification( - round_height, - chunk_id, - contribution_id, - &verifier, - &verifier_signing_key, - ); + let task = Task::new(chunk_id, contribution_id); + let verify = coordinator.run_verification(round_height, &task, &verifier, &verifier_signing_key); assert!(verify.is_ok()); // Verify contribution 1. - coordinator.verify_contribution(chunk_id, &verifier)?; + coordinator.verify_contribution(&task, &verifier)?; } Ok(()) @@ -3265,25 +3047,12 @@ mod tests { let verifier = verifier.clone(); let verifier_signing_key: SigningKey = "secret_key".to_string(); - { - // Acquire the lock as the verifier. - let try_lock = coordinator_clone.write().unwrap().try_lock_chunk(chunk_id, &verifier); - if try_lock.is_err() { - println!( - "Failed to acquire lock as verifier {:?}\n{}", - verifier.clone(), - serde_json::to_string_pretty(&coordinator_clone.read().unwrap().current_round().unwrap()) - .unwrap() - ); - panic!("{:?}", try_lock.unwrap()) - } - } { // Run verification as verifier. + let task = Task::new(chunk_id, contribution_id); let verify = coordinator_clone.write().unwrap().run_verification( round_height, - chunk_id, - contribution_id, + &task, &verifier, &verifier_signing_key, ); @@ -3298,10 +3067,7 @@ mod tests { } // Add the verification as the verifier. - let verify = coordinator_clone - .write() - .unwrap() - .verify_contribution(chunk_id, &verifier); + let verify = coordinator_clone.write().unwrap().verify_contribution(&task, &verifier); if verify.is_err() { println!( "Failed to run verification as verifier {:?}\n{}", @@ -3325,14 +3091,14 @@ mod tests { #[test] #[serial] - fn coordinator_aggregation() -> anyhow::Result<()> { + fn coordinator_aggregation() { initialize_test_environment(&TEST_ENVIRONMENT_3); - let mut coordinator = Coordinator::new(TEST_ENVIRONMENT_3.clone(), Arc::new(Dummy))?; - initialize_coordinator(&mut coordinator)?; + let mut coordinator = Coordinator::new(TEST_ENVIRONMENT_3.clone(), Arc::new(Dummy)).unwrap(); + initialize_coordinator(&mut coordinator).unwrap(); // Check current round height is now 1. - let round_height = coordinator.current_round_height()?; + let round_height = coordinator.current_round_height().unwrap(); assert_eq!(1, round_height); // Run computation and verification on each contribution in each chunk. @@ -3350,7 +3116,7 @@ mod tests { for chunk_id in 0..TEST_ENVIRONMENT_3.number_of_chunks() { // As contribution ID 0 is initialized by the coordinator, iterate from // contribution ID 1 up to the expected number of contributions. - for contribution_id in 1..coordinator.current_round()?.expected_number_of_contributions() { + for contribution_id in 1..coordinator.current_round().unwrap().expected_number_of_contributions() { let contributor = &contributors[contribution_id as usize - 1].clone(); let contributor_signing_key: SigningKey = "secret_key".to_string(); @@ -3363,9 +3129,9 @@ mod tests { "Failed to acquire lock for chunk {} as contributor {:?}\n{}", chunk_id, &contributor, - serde_json::to_string_pretty(&coordinator.current_round()?)? + serde_json::to_string_pretty(&coordinator.current_round().unwrap()).unwrap() ); - try_lock?; + try_lock.unwrap(); } } { @@ -3391,9 +3157,9 @@ mod tests { error!( "Failed to run computation as contributor {:?}\n{}", &contributor, - serde_json::to_string_pretty(&coordinator.current_round()?)? + serde_json::to_string_pretty(&coordinator.current_round().unwrap()).unwrap() ); - contribute?; + contribute.unwrap(); } // Add the contribution as the contributor. @@ -3402,50 +3168,33 @@ mod tests { error!( "Failed to add contribution as contributor {:?}\n{}", &contributor, - serde_json::to_string_pretty(&coordinator.current_round()?)? + serde_json::to_string_pretty(&coordinator.current_round().unwrap()).unwrap() ); - contribute?; - } - } - { - // Acquire the lock as the verifier. - let try_lock = coordinator.try_lock_chunk(chunk_id, &verifier); - if try_lock.is_err() { - error!( - "Failed to acquire lock as verifier {:?}\n{}", - &verifier, - serde_json::to_string_pretty(&coordinator.current_round()?)? - ); - try_lock?; + contribute.unwrap(); } } { // Run verification as verifier. - let verify = coordinator.run_verification( - round_height, - chunk_id, - contribution_id, - &verifier, - &verifier_signing_key, - ); + let task = Task::new(chunk_id, contribution_id); + let verify = coordinator.run_verification(round_height, &task, &verifier, &verifier_signing_key); if verify.is_err() { error!( "Failed to run verification as verifier {:?}\n{}", &verifier, - serde_json::to_string_pretty(&coordinator.current_round()?)? + serde_json::to_string_pretty(&coordinator.current_round().unwrap()).unwrap() ); - verify?; + verify.unwrap(); } // Add the verification as the verifier. - let verify = coordinator.verify_contribution(chunk_id, &verifier); + let verify = coordinator.verify_contribution(&task, &verifier); if verify.is_err() { error!( "Failed to run verification as verifier {:?}\n{}", &verifier, - serde_json::to_string_pretty(&coordinator.current_round()?)? + serde_json::to_string_pretty(&coordinator.current_round().unwrap()).unwrap() ); - verify?; + verify.unwrap(); } } } @@ -3453,23 +3202,21 @@ mod tests { println!( "Starting aggregation with this transcript {}", - serde_json::to_string_pretty(&coordinator.current_round()?)? + serde_json::to_string_pretty(&coordinator.current_round().unwrap()).unwrap() ); { // Run aggregation for round 1. - coordinator.aggregate_contributions()?; + coordinator.aggregate_contributions().unwrap(); } // Check that the round is still round 1, as try_advance has not been called. - assert_eq!(1, coordinator.current_round_height()?); + assert_eq!(1, coordinator.current_round_height().unwrap()); println!( "Finished aggregation with this transcript {}", - serde_json::to_string_pretty(&coordinator.current_round()?)? + serde_json::to_string_pretty(&coordinator.current_round().unwrap()).unwrap() ); - - Ok(()) } #[test] @@ -3555,27 +3302,10 @@ mod tests { contribute?; } } - { - // Acquire the lock as the verifier. - let try_lock = coordinator.try_lock_chunk(chunk_id, &verifier); - if try_lock.is_err() { - error!( - "Failed to acquire lock as verifier {:?}\n{}", - &verifier, - serde_json::to_string_pretty(&coordinator.current_round()?)? - ); - try_lock?; - } - } { // Run verification as verifier. - let verify = coordinator.run_verification( - round_height, - chunk_id, - contribution_id, - &verifier, - &verifier_signing_key, - ); + let task = Task::new(chunk_id, contribution_id); + let verify = coordinator.run_verification(round_height, &task, &verifier, &verifier_signing_key); if verify.is_err() { error!( "Failed to run verification as verifier {:?}\n{}", @@ -3586,7 +3316,7 @@ mod tests { } // Add the verification as the verifier. - let verify = coordinator.verify_contribution(chunk_id, &verifier); + let verify = coordinator.verify_contribution(&task, &verifier); if verify.is_err() { error!( "Failed to run verification as verifier {:?}\n{}", @@ -3609,7 +3339,7 @@ mod tests { coordinator.aggregate_contributions()?; // Run aggregation and transition from round 1 to round 2. - coordinator.next_round(Utc::now(), vec![contributor.clone()], vec![verifier.clone()])?; + coordinator.next_round(Utc::now(), vec![contributor.clone()])?; } // Check that the ceremony has advanced to round 2. diff --git a/phase1-coordinator/src/coordinator_state.rs b/phase1-coordinator/src/coordinator_state.rs index 421d3128..2d2e104a 100644 --- a/phase1-coordinator/src/coordinator_state.rs +++ b/phase1-coordinator/src/coordinator_state.rs @@ -330,63 +330,6 @@ impl ParticipantInfo { Ok(()) } - /// - /// Adds the given (chunk ID, contribution ID) task in FIFO order for the participant to process. - /// - #[inline] - fn push_back_task(&mut self, task: Task, time: &dyn TimeSource) -> Result<(), CoordinatorError> { - trace!("Pushing back task for {}", self.id); - - // Check that the participant has started in the round. - if self.started_at.is_none() { - return Err(CoordinatorError::ParticipantHasNotStarted); - } - - // Check that the participant was not dropped from the round. - if self.dropped_at.is_some() { - return Err(CoordinatorError::ParticipantWasDropped); - } - - // Check that the participant has not finished the round. - if self.finished_at.is_some() { - return Err(CoordinatorError::ParticipantAlreadyFinished); - } - - // Check that if the participant is a contributor, this chunk is not currently locked. - if self.id.is_contributor() && self.locked_chunks.contains_key(&task.chunk_id()) { - return Err(CoordinatorError::ParticipantAlreadyWorkingOnChunk { - chunk_id: task.chunk_id(), - }); - } - - // Check that the task was not already given the assigned task. - if self.assigned_tasks.contains(&task) { - return Err(CoordinatorError::ParticipantAlreadyAddedChunk); - } - - // Check that the task was not already in progress. - if self.pending_tasks.contains(&task) { - return Err(CoordinatorError::ParticipantAlreadyWorkingOnChunk { - chunk_id: task.chunk_id(), - }); - } - - // Check that the participant has not already completed the task. - if self.completed_tasks.contains(&task) { - return Err(CoordinatorError::ParticipantAlreadyFinishedChunk { - chunk_id: task.chunk_id(), - }); - } - - // Update the last seen time. - self.last_seen = time.utc_now(); - - // Add the task to the back of the pending tasks. - self.assigned_tasks.push_back(task); - - Ok(()) - } - /// /// Adds the given (chunk ID, contribution ID) task in LIFO order for the participant to process. /// @@ -629,7 +572,7 @@ impl ParticipantInfo { /// removes the given chunk ID from the locked chunks held by this /// participant. /// - fn completed_task(&mut self, task: Task, time: &dyn TimeSource) -> Result<(), CoordinatorError> { + fn completed_task(&mut self, task: &Task, time: &dyn TimeSource) -> Result<(), CoordinatorError> { trace!("Completing task for {}", self.id); // Check that the participant has started in the round. @@ -653,18 +596,20 @@ impl ParticipantInfo { } // Check that the participant does not have a assigned task remaining for this. - if self.assigned_tasks.contains(&task) { + if self.assigned_tasks.contains(task) { return Err(CoordinatorError::ParticipantStillHasTaskAsAssigned); } // Check that the participant has a pending task for this. - if !self.pending_tasks.contains(&task) { - return Err(CoordinatorError::ParticipantMissingPendingTask { pending_task: task }); + if !self.pending_tasks.contains(task) { + return Err(CoordinatorError::ParticipantMissingPendingTask { + pending_task: task.clone(), + }); } // Check that the participant has not already completed the task. - if self.completed_tasks.contains(&task) { - return Err(CoordinatorError::ParticipantAlreadyFinishedTask(task)); + if self.completed_tasks.contains(task) { + return Err(CoordinatorError::ParticipantAlreadyFinishedTask(task.clone())); } // Check that if the participant is a contributor, this chunk was not already completed. @@ -692,11 +637,11 @@ impl ParticipantInfo { .pending_tasks .clone() .into_par_iter() - .filter(|t| *t != task) + .filter(|t| t != task) .collect(); // Add the task to the completed tasks. - self.completed_tasks.push_back(task); + self.completed_tasks.push_back(task.clone()); Ok(()) } @@ -1009,14 +954,7 @@ impl CoordinatorState { .cloned() .unwrap_or_else(|| HashMap::new()); - let finished_verifiers = self - .finished_verifiers - .get(¤t_round_height) - .cloned() - .unwrap_or_else(|| HashMap::new()); - let number_of_contributors = self.current_contributors.len() + finished_contributors.len(); - let number_of_verifiers = self.current_verifiers.len() + finished_verifiers.len(); let number_of_chunks = self.environment.number_of_chunks() as u64; let current_contributors = self @@ -1033,18 +971,7 @@ impl CoordinatorState { }) .collect::, CoordinatorError>>()?; - let current_verifiers = self - .current_verifiers - .clone() - .into_iter() - .chain(finished_verifiers.clone().into_iter()) - .map(|(participant, mut participant_info)| { - participant_info.restart_tasks(LinkedList::new(), time)?; - Ok((participant, participant_info)) - }) - .collect::, CoordinatorError>>()?; - - let need_to_rollback = force_rollback || number_of_contributors == 0 || number_of_verifiers == 0; + let need_to_rollback = force_rollback || number_of_contributors == 0; if need_to_rollback { // Will roll back to the previous round and await new @@ -1059,14 +986,6 @@ impl CoordinatorState { ); } - if number_of_verifiers == 0 { - tracing::warn!( - "No verifiers remaining to reset and complete the current round. \ - Rolling back to round {} to wait and accept new participants.", - new_round_height - ); - } - let remove_participants: Vec = self .current_contributors .clone() @@ -1085,11 +1004,7 @@ impl CoordinatorState { let mut queue = self.queue.clone(); // Add each participant back into the queue. - for (participant, participant_info) in current_contributors - .iter() - .chain(self.current_verifiers.iter()) - .chain(self.next.iter()) - { + for (participant, participant_info) in current_contributors.iter().chain(self.next.iter()) { queue.insert( participant.clone(), (participant_info.reliability, Some(participant_info.round_height)), @@ -1138,7 +1053,7 @@ impl CoordinatorState { *self = Self { current_contributors, - current_verifiers, + current_verifiers: Default::default(), queue: self.queue.clone(), banned: self.banned.clone(), @@ -1194,14 +1109,6 @@ impl CoordinatorState { participant.is_contributor() && self.queue.contains_key(participant) } - /// - /// Returns `true` if the given participant is a verifier in the queue. - /// - #[inline] - pub fn is_queue_verifier(&self, participant: &Participant) -> bool { - participant.is_verifier() && self.queue.contains_key(participant) - } - /// /// Returns `true` if the given participant is an authorized contributor in the ceremony. /// @@ -1210,14 +1117,6 @@ impl CoordinatorState { participant.is_contributor() && !self.banned.contains(participant) } - /// - /// Returns `true` if the given participant is an authorized verifier in the ceremony. - /// - #[inline] - pub fn is_authorized_verifier(&self, participant: &Participant) -> bool { - participant.is_verifier() && !self.banned.contains(participant) - } - /// /// Returns `true` if the given participant is actively contributing /// in the current round. @@ -1227,15 +1126,6 @@ impl CoordinatorState { self.is_authorized_contributor(participant) && self.current_contributors.contains_key(participant) } - /// - /// Returns `true` if the given participant is actively verifying - /// in the current round. - /// - #[inline] - pub fn is_current_verifier(&self, participant: &Participant) -> bool { - self.is_authorized_verifier(participant) && self.current_verifiers.contains_key(participant) - } - /// /// Returns `true` if the given participant is banned. /// @@ -1270,21 +1160,6 @@ impl CoordinatorState { .contains_key(participant) } - /// - /// Returns `true` if the given participant has finished verifying - /// in the current round. - /// - #[inline] - pub fn is_finished_verifier(&self, participant: &Participant) -> bool { - let current_round_height = self.current_round_height.unwrap_or_default(); - participant.is_verifier() - && self - .finished_verifiers - .get(¤t_round_height) - .get_or_insert(&HashMap::new()) - .contains_key(participant) - } - pub fn current_round_finished_contributors(&self) -> anyhow::Result> { let current_round_height = self .current_round_height @@ -1325,14 +1200,6 @@ impl CoordinatorState { self.queue.par_iter().filter(|(p, _)| p.is_contributor()).count() } - /// - /// Returns the total number of verifiers currently in the queue. - /// - #[inline] - pub fn number_of_queue_verifiers(&self) -> usize { - self.queue.par_iter().filter(|(p, _)| p.is_verifier()).count() - } - /// /// Returns a list of the contributors currently in the queue. /// @@ -1345,18 +1212,6 @@ impl CoordinatorState { .collect() } - /// - /// Returns a list of the verifiers currently in the queue. - /// - #[inline] - pub fn queue_verifiers(&self) -> Vec<(Participant, (u8, Option))> { - self.queue - .clone() - .into_par_iter() - .filter(|(p, _)| p.is_verifier()) - .collect() - } - /// /// Returns a list of the contributors currently in the round. /// @@ -1383,14 +1238,6 @@ impl CoordinatorState { } } - /// - /// Returns a list of the verifiers currently in the round. - /// - #[inline] - pub fn current_verifiers(&self) -> Vec<(Participant, ParticipantInfo)> { - self.current_verifiers.clone().into_iter().collect() - } - /// /// Returns a list of participants that were dropped from the current round. /// @@ -1426,8 +1273,6 @@ impl CoordinatorState { self.pending_verification.is_empty() // Check that all current contributors are finished. && self.current_contributors.is_empty() - // Check that all current verifiers are finished. - && self.current_verifiers.is_empty() } /// @@ -1520,24 +1365,11 @@ impl CoordinatorState { .filter(|(p, (_, rh))| p.is_contributor() && rh.unwrap_or_default() == next_round_height) .count(); - // Fetch the state of assigned verifiers for the next round in the queue. - let minimum_verifiers = self.environment.minimum_verifiers_per_round(); - let maximum_verifiers = self.environment.maximum_verifiers_per_round(); - let number_of_assigned_verifiers = self - .queue - .clone() - .into_par_iter() - .filter(|(p, (_, rh))| p.is_verifier() && rh.unwrap_or_default() == next_round_height) - .count(); - trace!( - "Prepare precommit status - {} contributors assigned ({}-{} required), {} verifiers assigned ({}-{} required)", + "Prepare precommit status - {} contributors assigned ({}-{} required)", number_of_assigned_contributors, minimum_contributors, maximum_contributors, - number_of_assigned_verifiers, - minimum_verifiers, - maximum_verifiers ); // Check that the next round contains a permitted number of contributors. @@ -1548,12 +1380,6 @@ impl CoordinatorState { return false; } - // Check that the next round contains a permitted number of verifiers. - if number_of_assigned_verifiers < minimum_verifiers || number_of_assigned_verifiers > maximum_verifiers { - trace!("Insufficient or unauthorized number of verifiers"); - return false; - } - true } @@ -1596,17 +1422,7 @@ impl CoordinatorState { } } Participant::Verifier(_) => { - // Check if the verifier is authorized. - if !self.is_authorized_verifier(&participant) { - return Err(CoordinatorError::ParticipantUnauthorized); - } - - // Check that the verifier is not in the current round. - if !self.environment.allow_current_verifiers_in_queue() - && self.current_verifiers.contains_key(&participant) - { - return Err(CoordinatorError::ParticipantInCurrentRoundCannotJoinQueue); - } + return Err(CoordinatorError::ExpectedContributor); } } @@ -1638,16 +1454,15 @@ impl CoordinatorState { } /// - /// Pops the next (chunk ID, contribution ID) task that the participant should process. + /// Pops the next (chunk ID, contribution ID) task that the contributor should process. /// pub(super) fn fetch_task( &mut self, participant: &Participant, time: &dyn TimeSource, ) -> Result { - // Fetch the contributor and verifier chunk lock limit. + // Fetch the contributor chunk lock limit. let contributor_limit = self.environment.contributor_lock_chunk_limit(); - let verifier_limit = self.environment.verifier_lock_chunk_limit(); // Remove the next chunk ID from the pending chunks of the given participant. match participant { @@ -1663,18 +1478,9 @@ impl CoordinatorState { }, None => Err(CoordinatorError::ParticipantNotFound(participant.clone())), }, - Participant::Verifier(_) => match self.current_verifiers.get_mut(participant) { - // Check that the participant is holding less than the chunk lock limit. - Some(participant_info) => match participant_info.locked_chunks.len() < verifier_limit { - true => { - let task = participant_info.pop_task(time)?; - self.start_task_timer(participant, &task, time); - Ok(task) - } - false => Err(CoordinatorError::ParticipantHasLockedMaximumChunks), - }, - None => Err(CoordinatorError::ParticipantNotFound(participant.clone())), - }, + Participant::Verifier(_) => { + return Err(CoordinatorError::ExpectedContributor); + } } } @@ -1699,11 +1505,9 @@ impl CoordinatorState { Some(participant) => Ok(participant.acquired_lock(chunk_id, time)?), None => Err(CoordinatorError::ParticipantNotFound(participant.clone())), }, - Participant::Verifier(_) => match self.current_verifiers.get_mut(participant) { - // Acquire the chunk lock for the verifier. - Some(participant) => Ok(participant.acquired_lock(chunk_id, time)?), - None => Err(CoordinatorError::ParticipantNotFound(participant.clone())), - }, + Participant::Verifier(_) => { + return Err(CoordinatorError::ExpectedContributor); + } } } @@ -1860,64 +1664,52 @@ impl CoordinatorState { /// Adds the given (chunk ID, contribution ID) task to the pending verification set. /// The verification task is then assigned to the verifier with the least number of tasks in its queue. /// - /// On success, this function returns the verifier that was assigned to the verification task. - /// #[inline] - pub(super) fn add_pending_verification( - &mut self, - task: Task, - time: &dyn TimeSource, - ) -> Result { + pub(super) fn add_pending_verification(&mut self, task: &Task) -> Result<(), CoordinatorError> { // Check that the chunk ID is valid. if task.chunk_id() > self.environment.number_of_chunks() { return Err(CoordinatorError::ChunkIdInvalid); } // Check that the pending verification set does not already contain the chunk ID. - if self.pending_verification.contains_key(&task) { + if self.pending_verification.contains_key(task) { return Err(CoordinatorError::ChunkIdAlreadyAdded); } - let verifier = match self - .current_verifiers - .par_iter() - .min_by_key(|(_, v)| v.assigned_tasks.len() + v.pending_tasks.len() + v.locked_chunks.len()) - { - Some((verifier, _verifier_info)) => verifier.clone(), - None => return Err(CoordinatorError::VerifierMissing), - }; + let verifier = self + .environment + .coordinator_verifiers() + .first() + .ok_or_else(|| CoordinatorError::VerifierMissing)? + .clone(); info!( - "Assigning (chunk {}, contribution {}) to {} for verification", + "Adding (chunk {}, contribution {}) to pending verifications", task.chunk_id(), task.contribution_id(), - verifier ); - match self.current_verifiers.get_mut(&verifier) { - Some(verifier_info) => verifier_info.push_back_task(task, time)?, - None => return Err(CoordinatorError::VerifierMissing), - }; + self.pending_verification.insert(task.clone(), verifier.clone()); - self.pending_verification.insert(task, verifier.clone()); + Ok(()) + } - Ok(verifier) + pub fn get_pending_verifications(&self) -> &HashMap { + &self.pending_verification } /// /// Remove the given (chunk ID, contribution ID) task from the map of chunks that are pending verification. /// - /// On success, this function returns the verifier that completed the verification task. - /// #[inline] - pub(super) fn remove_pending_verification(&mut self, task: Task) -> Result { + pub(super) fn remove_pending_verification(&mut self, task: &Task) -> Result<(), CoordinatorError> { // Check that the chunk ID is valid. if task.chunk_id() > self.environment.number_of_chunks() { return Err(CoordinatorError::ChunkIdInvalid); } // Check that the set pending verification does not already contain the chunk ID. - if !self.pending_verification.contains_key(&task) { + if !self.pending_verification.contains_key(task) { return Err(CoordinatorError::ChunkIdMissing); } @@ -1928,12 +1720,12 @@ impl CoordinatorState { ); // Remove the task from the pending verification. - let verifier = self + let _verifier = self .pending_verification - .remove(&task) + .remove(task) .ok_or(CoordinatorError::VerifierMissing)?; - Ok(verifier) + Ok(()) } /// @@ -1951,9 +1743,9 @@ impl CoordinatorState { pub(super) fn completed_task( &mut self, participant: &Participant, - task: Task, + task: &Task, time: &dyn TimeSource, - ) -> Result { + ) -> Result<(), CoordinatorError> { // Check that the chunk ID is valid. if task.chunk_id() > self.environment.number_of_chunks() { return Err(CoordinatorError::ChunkIdInvalid); @@ -1966,20 +1758,14 @@ impl CoordinatorState { Some(participant_info) => { participant_info.completed_task(task, time)?; self.stop_task_timer(participant, &task, time); - Ok(self.add_pending_verification(task, time)?) - } - None => Err(CoordinatorError::ParticipantNotFound(participant.clone())), - }, - Participant::Verifier(_) => match self.current_verifiers.get_mut(participant) { - // Adds the task to the list of completed tasks for the verifier, - // and remove the task from the pending verification set. - Some(participant_info) => { - participant_info.completed_task(task, time)?; - self.stop_task_timer(participant, &task, time); - Ok(self.remove_pending_verification(task)?) + self.add_pending_verification(task) } None => Err(CoordinatorError::ParticipantNotFound(participant.clone())), }, + Participant::Verifier(_) => { + // Remove the task from the pending verification set. + self.remove_pending_verification(task) + } } } @@ -2382,50 +2168,7 @@ impl CoordinatorState { action } Participant::Verifier(_id) => { - // Add just the current pending tasks to a pending verifications list. - let mut pending_verifications = vec![]; - for task in &tasks { - pending_verifications.push(task); - } - - // Set the participant as dropped. - let mut dropped_info = participant_info.clone(); - dropped_info.drop(time)?; - - // Remove the current verifier from the coordinator state. - self.current_verifiers.remove(&participant); - - // TODO (howardwu): Make this operation atomic. - for task in pending_verifications { - // Remove the task from the pending verifications. - self.remove_pending_verification(*task)?; - - // Reassign the pending verification task to a new verifier. - self.add_pending_verification(*task, time)?; - } - - // Add the participant info to the dropped participants. - self.dropped.push(dropped_info); - - warn!("Dropped {} from the ceremony", participant); - - // Restart the round because there are no verifiers - // left for this round. - let reset_round = self.current_verifiers.is_empty() && self.finished_verifiers.is_empty(); - - if reset_round { - CeremonyStorageAction::ResetCurrentRound(ResetCurrentRoundStorageAction { - remove_participants: vec![participant.clone()], - rollback: false, - }) - } else { - CeremonyStorageAction::RemoveVerifier(RemoveVerifierStorageAction { - dropped_verifier: participant.clone(), - bucket_id, - locked_chunks, - tasks, - }) - } + return Err(CoordinatorError::ExpectedContributor); } }; @@ -2585,17 +2328,12 @@ impl CoordinatorState { .into_par_iter() .filter(|(p, _)| p.is_contributor() && !self.banned.contains(&p)) .collect(); - let verifiers: Vec<(_, _)> = queue - .into_par_iter() - .filter(|(p, _)| p.is_verifier() && !self.banned.contains(&p)) - .collect(); - // Fetch the permitted number of contributors and verifiers. + // Fetch the permitted number of contributors let maximum_contributors = self.environment.maximum_contributors_per_round(); - let maximum_verifiers = self.environment.maximum_verifiers_per_round(); // Initialize the updated queue. - let mut updated_queue = HashMap::with_capacity(contributors.len() + verifiers.len()); + let mut updated_queue = HashMap::with_capacity(contributors.len()); // Update assigned round height for each contributor. for (index, round) in contributors.chunks(maximum_contributors).enumerate() { @@ -2611,20 +2349,6 @@ impl CoordinatorState { } } - // Update assigned round height for each verifier. - for (index, round) in verifiers.chunks(maximum_verifiers).enumerate() { - for (verifier, reliability) in round.into_iter() { - let assigned_round = next_round + index as u64; - trace!( - "Assigning verifier {} with reliability {} in queue to round {}", - verifier, - reliability, - assigned_round - ); - updated_queue.insert(verifier.clone(), (*reliability, Some(assigned_round))); - } - } - // Set the queue to the updated queue. self.queue = updated_queue; @@ -2686,71 +2410,6 @@ impl CoordinatorState { Ok(()) } - /// - /// Updates the state of verifiers in the current round. - /// - /// This function should never be run prior to calling `update_current_contributors`. - /// - #[inline] - pub(super) fn update_current_verifiers(&mut self, time: &dyn TimeSource) -> Result<(), CoordinatorError> { - // Check if the contributors are finished. - let is_contributors_finished = self.current_contributors.is_empty(); - - // If all contributors are finished, this means there are no new verification jobs - // to be added to the pending verifications queue. So if a verifier is finished - // with their verifications, then they are finished for this round. - if is_contributors_finished { - // Fetch the current round height. - let current_round_height = self.current_round_height.ok_or(CoordinatorError::RoundHeightNotSet)?; - - // Fetch the current number of verifiers. - let number_of_current_verifiers = self.current_verifiers.len(); - - // Initialize a map for newly finished verifiers. - let mut newly_finished: HashMap = HashMap::new(); - - // Iterate through all of the current verifiers and check if they have finished. - self.current_verifiers = self - .current_verifiers - .clone() - .into_iter() - .filter(|(verifier, verifier_info)| { - // Check if the verifier has finished. - if verifier_info.is_finished() { - return false; - } - - // Attempt to set the verifier as finished. - let mut finished_info = verifier_info.clone(); - if let Err(_) = finished_info.finish(time) { - return true; - } - - // Add the verifier to the set of finished verifier. - newly_finished.insert(verifier.clone(), finished_info); - - debug!("{} has finished", verifier); - false - }) - .collect(); - - // Check that the update preserves the same number of verifiers. - if number_of_current_verifiers != self.current_verifiers.len() + newly_finished.len() { - return Err(CoordinatorError::RoundUpdateCorruptedStateOfVerifiers); - } - - trace!("Marking {} current verifiers as finished", newly_finished.len()); - - // Update the map of finished verifiers. - match self.finished_verifiers.get_mut(¤t_round_height) { - Some(contributors) => contributors.extend(newly_finished.into_iter()), - None => return Err(CoordinatorError::RoundCommitFailedOrCorrupted), - }; - } - - Ok(()) - } - /// /// Updates the current round for dropped participants. /// @@ -2992,14 +2651,14 @@ impl CoordinatorState { /// /// Prepares transition of the coordinator state from the current round to the next round. - /// On precommit success, returns the list of contributors and verifiers for the next round. + /// On precommit success, returns the list of contributors for the next round. /// #[tracing::instrument(skip(self, time))] pub(super) fn precommit_next_round( &mut self, next_round_height: u64, time: &dyn TimeSource, - ) -> Result<(Vec, Vec), CoordinatorError> { + ) -> Result, CoordinatorError> { tracing::debug!("Attempting to run precommit for round {}", next_round_height); // Check that the coordinator state is initialized. @@ -3066,13 +2725,6 @@ impl CoordinatorState { .map(|(p, (r, rh))| (p, (r, rh.unwrap_or_default()))) .filter(|(p, (_, rh))| p.is_contributor() && *rh == next_round_height) .collect(); - let verifiers: Vec<(_, (_, _))> = self - .queue - .clone() - .into_par_iter() - .map(|(p, (r, rh))| (p, (r, rh.unwrap_or_default()))) - .filter(|(p, (_, rh))| p.is_verifier() && *rh == next_round_height) - .collect(); // Check that each participant in the next round is authorized. if contributors @@ -3083,14 +2735,6 @@ impl CoordinatorState { { return Err(CoordinatorError::ParticipantUnauthorized); } - if verifiers - .par_iter() - .filter(|(participant, _)| self.banned.contains(participant)) - .count() - > 0 - { - return Err(CoordinatorError::ParticipantUnauthorized); - } // Check that the next round contains a permitted number of contributors. let minimum_contributors = self.environment.minimum_contributors_per_round(); @@ -3104,23 +2748,10 @@ impl CoordinatorState { return Err(CoordinatorError::RoundNumberOfContributorsUnauthorized); } - // Check that the next round contains a permitted number of verifiers. - let minimum_verifiers = self.environment.minimum_verifiers_per_round(); - let maximum_verifiers = self.environment.maximum_verifiers_per_round(); - let number_of_verifiers = verifiers.len(); - if number_of_verifiers < minimum_verifiers || number_of_verifiers > maximum_verifiers { - warn!( - "Precommit found {} verifiers, but expected between {} and {} verifiers", - number_of_verifiers, minimum_verifiers, maximum_verifiers - ); - return Err(CoordinatorError::RoundNumberOfVerifiersUnauthorized); - } - // Initialize the precommit stage for the next round. let mut queue = self.queue.clone(); let mut next = HashMap::default(); let mut next_contributors = Vec::with_capacity(number_of_contributors); - let mut next_verifiers = Vec::with_capacity(number_of_verifiers); // Create the initial chunk locking sequence for each contributor. { @@ -3198,29 +2829,6 @@ impl CoordinatorState { } } - // Initialize the participant info for each verifier. - for (participant, (reliability, next_round)) in verifiers { - // Check that each participant is storing the correct round height. - if next_round != next_round_height && next_round != current_round_height + 1 { - warn!("Verifier claims round is {}, not {}", next_round, next_round_height); - return Err(CoordinatorError::RoundHeightMismatch); - } - - // Initialize the participant info for the verifier. - let mut participant_info = - ParticipantInfo::new(participant.clone(), next_round_height, reliability, 0, time); - participant_info.start(LinkedList::new(), time)?; - - // Add the verifier to staging for the next round. - next.insert(participant.clone(), participant_info); - - // Remove the verifier from the queue. - queue.remove(&participant); - - // Add the next round contributors to the return output. - next_verifiers.push(participant); - } - // Update the coordinator state to the updated queue and next map. self.queue = queue; self.next = next; @@ -3228,7 +2836,7 @@ impl CoordinatorState { // Set the coordinator status to precommit. self.status = CoordinatorStatus::Precommit; - Ok((next_contributors, next_verifiers)) + Ok(next_contributors) } /// @@ -3360,17 +2968,11 @@ impl CoordinatorState { }; let number_of_current_contributors = self.current_contributors.len(); - let number_of_current_verifiers = self.current_verifiers.len(); let number_of_finished_contributors = self .finished_contributors .get(¤t_round_height) .get_or_insert(&HashMap::new()) .len(); - let number_of_finished_verifiers = self - .finished_verifiers - .get(¤t_round_height) - .get_or_insert(&HashMap::new()) - .len(); let number_of_pending_verifications = self.pending_verification.len(); // Parse the queue for assigned contributors and verifiers of the next round. @@ -3380,15 +2982,8 @@ impl CoordinatorState { .into_par_iter() .filter(|(p, (_, rh))| p.is_contributor() && rh.unwrap_or_default() == next_round_height) .count(); - let number_of_assigned_verifiers = self - .queue - .clone() - .into_par_iter() - .filter(|(p, (_, rh))| p.is_verifier() && rh.unwrap_or_default() == next_round_height) - .count(); let number_of_queue_contributors = self.number_of_queue_contributors(); - let number_of_queue_verifiers = self.number_of_queue_verifiers(); let number_of_dropped_participants = self.dropped.len(); let number_of_banned_participants = self.banned.len(); @@ -3403,12 +2998,12 @@ impl CoordinatorState { | {} | {} - | {} contributors and {} verifiers active in the current round - | {} contributors and {} verifiers completed the current round + | {} contributors active in the current round + | {} contributors completed the current round | {} chunks are pending verification - | {} contributors and {} verifiers assigned to the next round - | {} contributors and {} verifiers in queue for the ceremony + | {} contributors assigned to the next round + | {} contributors in queue for the ceremony | {} participants dropped | {} participants banned @@ -3418,14 +3013,10 @@ impl CoordinatorState { current_round_aggregated, precommit_next_round_ready, number_of_current_contributors, - number_of_current_verifiers, number_of_finished_contributors, - number_of_finished_verifiers, number_of_pending_verifications, number_of_assigned_contributors, - number_of_assigned_verifiers, number_of_queue_contributors, - number_of_queue_verifiers, number_of_dropped_participants, number_of_banned_participants ) @@ -3491,23 +3082,6 @@ pub struct ResetCurrentRoundStorageAction { pub rollback: bool, } -/// Action to update the storage to reflect a verifier being -/// removed in [CoordinatorState]. -#[derive(Debug)] -pub struct RemoveVerifierStorageAction { - /// The verifier being dropped. - pub dropped_verifier: Participant, - /// Determines the starting chunk, and subsequent tasks selected - /// for this verifier. See [initialize_tasks] for more - /// information about this parameter. - pub bucket_id: u64, - /// Chunks currently locked by the verifier being dropped. - pub locked_chunks: Vec, - /// Tasks currently being performed by the verifier being - /// dropped. - pub tasks: Vec, -} - /// Action to update the storage to reflect a contributor being /// replaced in [CoordinatorState]. #[derive(Debug)] @@ -3535,8 +3109,6 @@ pub enum CeremonyStorageAction { ResetCurrentRound(ResetCurrentRoundStorageAction), /// See [ReplaceContributorStorageAction]. ReplaceContributor(ReplaceContributorStorageAction), - /// See [RemoveVerifierStorageAction]. - RemoveVerifier(RemoveVerifierStorageAction), } /// Data required by the coordinator to drop a participant from the @@ -3579,6 +3151,10 @@ mod tests { SystemTimeSource, }; + fn fetch_task_for_verifier(state: &CoordinatorState) -> Option { + state.get_pending_verifications().keys().next().cloned() + } + #[test] fn test_new() { // Initialize a new coordinator state. @@ -3657,8 +3233,9 @@ mod tests { assert_eq!(0, state.queue.len()); // Add the verifier of the coordinator. - state.add_to_queue(verifier.clone(), 10).unwrap(); - assert_eq!(1, state.queue.len()); + let result = state.add_to_queue(verifier.clone(), 10); + assert!(result.is_err()); + assert_eq!(0, state.queue.len()); assert_eq!(0, state.next.len()); assert_eq!(None, state.current_round_height); assert_eq!(0, state.current_contributors.len()); @@ -3671,13 +3248,13 @@ mod tests { // Fetch the verifier from the queue. let participant = state.queue.get(&verifier); - assert_eq!(Some(&(10, None)), participant); + assert_eq!(None, participant); // Attempt to add the verifier again. for _ in 0..10 { let result = state.add_to_queue(verifier.clone(), 10); assert!(result.is_err()); - assert_eq!(1, state.queue.len()); + assert_eq!(0, state.queue.len()); } } @@ -3687,7 +3264,6 @@ mod tests { // Fetch the contributor and verifier of the coordinator. let contributor = test_coordinator_contributor(&environment).unwrap(); - let verifier = test_coordinator_verifier(&environment).unwrap(); // Initialize a new coordinator state. let mut state = CoordinatorState::new(environment.clone()); @@ -3702,8 +3278,7 @@ mod tests { // Add the contributor and verifier of the coordinator. state.add_to_queue(contributor.clone(), 10).unwrap(); - state.add_to_queue(verifier.clone(), 10).unwrap(); - assert_eq!(2, state.queue.len()); + assert_eq!(1, state.queue.len()); assert_eq!(0, state.next.len()); assert_eq!(Some(current_round_height), state.current_round_height); @@ -3711,13 +3286,9 @@ mod tests { let participant = state.queue.get(&contributor); assert_eq!(Some(&(10, None)), participant); - // Fetch the verifier from the queue. - let participant = state.queue.get(&verifier); - assert_eq!(Some(&(10, None)), participant); - // Update the state of the queue. state.update_queue().unwrap(); - assert_eq!(2, state.queue.len()); + assert_eq!(1, state.queue.len()); assert_eq!(0, state.next.len()); assert_eq!(Some(current_round_height), state.current_round_height); assert_eq!(0, state.current_contributors.len()); @@ -3732,17 +3303,11 @@ mod tests { let participant = state.queue.get(&contributor); assert_eq!(Some(&(10, Some(6))), participant); - // Fetch the verifier from the queue. - let participant = state.queue.get(&verifier); - assert_eq!(Some(&(10, Some(6))), participant); - // Attempt to add the contributor and verifier again. for _ in 0..10 { let contributor_result = state.add_to_queue(contributor.clone(), 10); - let verifier_result = state.add_to_queue(verifier.clone(), 10); assert!(contributor_result.is_err()); - assert!(verifier_result.is_err()); - assert_eq!(2, state.queue.len()); + assert_eq!(1, state.queue.len()); } } @@ -3799,44 +3364,9 @@ mod tests { assert_eq!(0, state.next.len()); assert_eq!(Some(current_round_height), state.current_round_height); - // Add (2 * maximum_verifiers_per_round) to the queue. - let maximum_verifiers_per_round = environment.maximum_verifiers_per_round(); - let number_of_verifiers_in_queue = 2 * maximum_verifiers_per_round; - for id in 1..=number_of_verifiers_in_queue { - trace!("Adding verifier with ID {}", id); - - // Add a unique verifier. - let verifier = Participant::Verifier(id.to_string()); - let reliability = 10 - id as u8; - state.add_to_queue(verifier.clone(), reliability).unwrap(); - assert_eq!(number_of_contributors_in_queue + id, state.queue.len()); - assert_eq!(0, state.next.len()); - assert_eq!(Some(current_round_height), state.current_round_height); - - // Fetch the verifier from the queue. - let participant = state.queue.get(&verifier); - assert_eq!(Some(&(reliability, None)), participant); - - // Update the state of the queue. - state.update_queue().unwrap(); - assert_eq!(number_of_contributors_in_queue + id, state.queue.len()); - assert_eq!(0, state.next.len()); - assert_eq!(Some(current_round_height), state.current_round_height); - - // Fetch the verifier from the queue. - let participant = state.queue.get(&verifier); - match id <= maximum_verifiers_per_round { - true => assert_eq!(Some(&(reliability, Some(6))), participant), - false => assert_eq!(Some(&(reliability, Some(7))), participant), - } - } - // Update the state of the queue. state.update_queue().unwrap(); - assert_eq!( - number_of_contributors_in_queue + number_of_verifiers_in_queue, - state.queue.len() - ); + assert_eq!(number_of_contributors_in_queue, state.queue.len()); assert_eq!(0, state.next.len()); assert_eq!(Some(current_round_height), state.current_round_height); } @@ -3876,41 +3406,6 @@ mod tests { } } - #[test] - fn test_remove_to_queue_verifier() { - let environment = TEST_ENVIRONMENT.clone(); - - // Fetch the verifier of the coordinator. - let verifier = test_coordinator_verifier(&environment).unwrap(); - - // Initialize a new coordinator state. - let mut state = CoordinatorState::new(environment.clone()); - assert_eq!(0, state.queue.len()); - - // Add the verifier of the coordinator. - state.add_to_queue(verifier.clone(), 10).unwrap(); - assert_eq!(1, state.queue.len()); - assert_eq!(0, state.next.len()); - assert_eq!(None, state.current_round_height); - - // Fetch the verifier from the queue. - let participant = state.queue.get(&verifier); - assert_eq!(Some(&(10, None)), participant); - - // Remove the verifier from the queue. - state.remove_from_queue(&verifier).unwrap(); - assert_eq!(0, state.queue.len()); - assert_eq!(0, state.next.len()); - assert_eq!(None, state.current_round_height); - - // Attempt to remove the verifier again. - for _ in 0..10 { - let result = state.remove_from_queue(&verifier); - assert!(result.is_err()); - assert_eq!(0, state.queue.len()); - } - } - #[test] fn test_commit_next_round() { test_logger(); @@ -3919,7 +3414,6 @@ mod tests { // Fetch the contributor and verifier of the coordinator. let contributor = test_coordinator_contributor(&environment).unwrap(); - let verifier = test_coordinator_verifier(&environment).unwrap(); // Initialize a new coordinator state. let mut state = CoordinatorState::new(environment.clone()); @@ -3934,16 +3428,14 @@ mod tests { // Add the contributor and verifier of the coordinator. state.add_to_queue(contributor.clone(), 10).unwrap(); - state.add_to_queue(verifier.clone(), 10).unwrap(); - assert_eq!(2, state.queue.len()); + assert_eq!(1, state.queue.len()); // Update the state of the queue. state.update_queue().unwrap(); - assert_eq!(2, state.queue.len()); + assert_eq!(1, state.queue.len()); assert_eq!(0, state.next.len()); assert_eq!(Some(current_round_height), state.current_round_height); assert_eq!(Some(&(10, Some(6))), state.queue.get(&contributor)); - assert_eq!(Some(&(10, Some(6))), state.queue.get(&verifier)); // TODO (howardwu): Add individual tests and assertions after each of these operations. { @@ -3957,18 +3449,16 @@ mod tests { // Update the state of current round contributors. state.update_current_contributors(&time).unwrap(); - // Update the state of current round verifiers. - state.update_current_verifiers(&time).unwrap(); - // Drop disconnected participants from the current round. - state.update_dropped_participants(&time).unwrap(); + let dropped = state.update_dropped_participants(&time).unwrap(); + assert_eq!(0, dropped.len()); // Ban any participants who meet the coordinator criteria. state.update_banned_participants().unwrap(); } // Determine if current round is finished and precommit to next round is ready. - assert_eq!(2, state.queue.len()); + assert_eq!(1, state.queue.len()); assert_eq!(0, state.next.len()); assert_eq!(Some(current_round_height), state.current_round_height); assert!(state.is_current_round_finished()); @@ -3980,7 +3470,7 @@ mod tests { let next_round_height = current_round_height + 1; let _precommit = state.precommit_next_round(next_round_height, &time).unwrap(); assert_eq!(0, state.queue.len()); - assert_eq!(2, state.next.len()); + assert_eq!(1, state.next.len()); assert_eq!(Some(current_round_height), state.current_round_height); assert!(state.is_current_round_finished()); assert!(state.is_current_round_aggregated()); @@ -3992,7 +3482,7 @@ mod tests { assert_eq!(0, state.next.len()); assert_eq!(Some(next_round_height), state.current_round_height); assert_eq!(1, state.current_contributors.len()); - assert_eq!(1, state.current_verifiers.len()); + assert_eq!(0, state.current_verifiers.len()); assert_eq!(0, state.pending_verification.len()); assert_eq!(0, state.finished_contributors.get(&next_round_height).unwrap().len()); assert_eq!(0, state.finished_verifiers.get(&next_round_height).unwrap().len()); @@ -4012,7 +3502,6 @@ mod tests { // Fetch the contributor and verifier of the coordinator. let contributor = test_coordinator_contributor(&environment).unwrap(); - let verifier = test_coordinator_verifier(&environment).unwrap(); // Initialize a new coordinator state. let mut state = CoordinatorState::new(environment.clone()); @@ -4027,16 +3516,14 @@ mod tests { // Add the contributor and verifier of the coordinator. state.add_to_queue(contributor.clone(), 10).unwrap(); - state.add_to_queue(verifier.clone(), 10).unwrap(); - assert_eq!(2, state.queue.len()); + assert_eq!(1, state.queue.len()); // Update the state of the queue. state.update_queue().unwrap(); - assert_eq!(2, state.queue.len()); + assert_eq!(1, state.queue.len()); assert_eq!(0, state.next.len()); assert_eq!(Some(current_round_height), state.current_round_height); assert_eq!(Some(&(10, Some(6))), state.queue.get(&contributor)); - assert_eq!(Some(&(10, Some(6))), state.queue.get(&verifier)); // TODO (howardwu): Add individual tests and assertions after each of these operations. { @@ -4050,9 +3537,6 @@ mod tests { // Update the state of current round contributors. state.update_current_contributors(&time).unwrap(); - // Update the state of current round verifiers. - state.update_current_verifiers(&time).unwrap(); - // Drop disconnected participants from the current round. state.update_dropped_participants(&time).unwrap(); @@ -4061,7 +3545,7 @@ mod tests { } // Determine if current round is finished and precommit to next round is ready. - assert_eq!(2, state.queue.len()); + assert_eq!(1, state.queue.len()); assert_eq!(0, state.next.len()); assert_eq!(Some(current_round_height), state.current_round_height); assert!(state.is_current_round_finished()); @@ -4072,7 +3556,7 @@ mod tests { trace!("Running precommit for the next round"); let _precommit = state.precommit_next_round(current_round_height + 1, &time).unwrap(); assert_eq!(0, state.queue.len()); - assert_eq!(2, state.next.len()); + assert_eq!(1, state.next.len()); assert_eq!(Some(current_round_height), state.current_round_height); assert!(state.is_current_round_finished()); assert!(state.is_current_round_aggregated()); @@ -4080,7 +3564,7 @@ mod tests { // Rollback the coordinator to the current round. state.rollback_next_round(); - assert_eq!(2, state.queue.len()); + assert_eq!(1, state.queue.len()); assert_eq!(0, state.next.len()); assert_eq!(Some(current_round_height), state.current_round_height); assert_eq!(0, state.current_contributors.len()); @@ -4102,14 +3586,12 @@ mod tests { // Fetch the contributor and verifier of the coordinator. let contributor = test_coordinator_contributor(&environment).unwrap(); - let verifier = test_coordinator_verifier(&environment).unwrap(); // Initialize a new coordinator state. let current_round_height = 5; let mut state = CoordinatorState::new(environment.clone()); state.initialize(current_round_height); state.add_to_queue(contributor.clone(), 10).unwrap(); - state.add_to_queue(verifier.clone(), 10).unwrap(); state.update_queue().unwrap(); state.aggregating_current_round(&time).unwrap(); state.aggregated_current_round(&time).unwrap(); @@ -4125,7 +3607,7 @@ mod tests { assert_eq!(0, state.next.len()); assert_eq!(Some(next_round_height), state.current_round_height); assert_eq!(1, state.current_contributors.len()); - assert_eq!(1, state.current_verifiers.len()); + assert_eq!(0, state.current_verifiers.len()); assert_eq!(0, state.pending_verification.len()); assert_eq!(0, state.finished_contributors.get(&next_round_height).unwrap().len()); assert_eq!(0, state.finished_verifiers.get(&next_round_height).unwrap().len()); @@ -4145,7 +3627,7 @@ mod tests { assert_eq!(Some(next_round_height), state.current_round_height); assert_eq!(1, state.current_contributors.len()); - assert_eq!(1, state.current_verifiers.len()); + assert_eq!(0, state.current_verifiers.len()); assert_eq!(0, state.pending_verification.len()); assert_eq!(0, state.finished_contributors.get(&next_round_height).unwrap().len()); assert_eq!(0, state.finished_verifiers.get(&next_round_height).unwrap().len()); @@ -4171,7 +3653,6 @@ mod tests { let mut state = CoordinatorState::new(environment.clone()); state.initialize(current_round_height); state.add_to_queue(contributor.clone(), 10).unwrap(); - state.add_to_queue(verifier.clone(), 10).unwrap(); state.update_queue().unwrap(); state.aggregating_current_round(&time).unwrap(); state.aggregated_current_round(&time).unwrap(); @@ -4185,7 +3666,7 @@ mod tests { state.commit_next_round(); assert_eq!(Some(next_round_height), state.current_round_height); assert_eq!(1, state.current_contributors.len()); - assert_eq!(1, state.current_verifiers.len()); + assert_eq!(0, state.current_verifiers.len()); assert_eq!(0, state.pending_verification.len()); assert_eq!(0, state.finished_contributors.get(&next_round_height).unwrap().len()); assert_eq!(0, state.finished_verifiers.get(&next_round_height).unwrap().len()); @@ -4204,37 +3685,32 @@ mod tests { state.acquired_lock(&contributor, chunk_id, &time).unwrap(); let completed_task = Task::new(chunk_id, task.contribution_id()); - state.completed_task(&contributor, completed_task, &time).unwrap(); + state.completed_task(&contributor, &completed_task, &time).unwrap(); assert_eq!(i + 1, state.pending_verification.len()); } assert_eq!(Some(next_round_height), state.current_round_height); assert_eq!(1, state.current_contributors.len()); - assert_eq!(1, state.current_verifiers.len()); + assert_eq!(0, state.current_verifiers.len()); assert_eq!(contributor_lock_chunk_limit, state.pending_verification.len()); assert_eq!(0, state.finished_contributors.get(&next_round_height).unwrap().len()); assert_eq!(0, state.finished_verifiers.get(&next_round_height).unwrap().len()); // Fetch the maximum number of tasks permitted for a verifier. - for i in 0..environment.verifier_lock_chunk_limit() { + for _ in 0..environment.verifier_lock_chunk_limit() { // Fetch a pending task for the verifier. - let task = state.fetch_task(&verifier, &time).unwrap(); - assert_eq!((i as u64, 1), (task.chunk_id(), task.contribution_id())); - - state.acquired_lock(&verifier, task.chunk_id(), &time).unwrap(); - state.completed_task(&verifier, task, &time).unwrap(); - assert_eq!(contributor_lock_chunk_limit - i - 1, state.pending_verification.len()); + let task = fetch_task_for_verifier(&state).unwrap(); + state.completed_task(&verifier, &task, &time).unwrap(); } assert_eq!(Some(next_round_height), state.current_round_height); assert_eq!(1, state.current_contributors.len()); - assert_eq!(1, state.current_verifiers.len()); + assert_eq!(0, state.current_verifiers.len()); assert_eq!(0, state.pending_verification.len()); assert_eq!(0, state.finished_contributors.get(&next_round_height).unwrap().len()); assert_eq!(0, state.finished_verifiers.get(&next_round_height).unwrap().len()); // Attempt to fetch past the permitted lock chunk limit. for _ in 0..10 { - let try_task = state.fetch_task(&verifier, &time); - assert!(try_task.is_err()); + assert_eq!(None, fetch_task_for_verifier(&state)); } } @@ -4256,7 +3732,6 @@ mod tests { state.initialize(current_round_height); state.add_to_queue(contributor_1.clone(), 10).unwrap(); state.add_to_queue(contributor_2.clone(), 9).unwrap(); - state.add_to_queue(verifier.clone(), 10).unwrap(); state.update_queue().unwrap(); state.aggregating_current_round(&time).unwrap(); state.aggregated_current_round(&time).unwrap(); @@ -4266,11 +3741,11 @@ mod tests { // Advance the coordinator to the next round. let next_round_height = current_round_height + 1; - assert_eq!(3, state.queue.len()); + assert_eq!(2, state.queue.len()); assert_eq!(0, state.next.len()); state.precommit_next_round(next_round_height, &time).unwrap(); assert_eq!(0, state.queue.len()); - assert_eq!(3, state.next.len()); + assert_eq!(2, state.next.len()); state.commit_next_round(); assert_eq!(0, state.queue.len()); assert_eq!(0, state.next.len()); @@ -4284,7 +3759,7 @@ mod tests { for _ in 0..number_of_chunks { assert_eq!(Some(next_round_height), state.current_round_height); assert_eq!(2, state.current_contributors.len()); - assert_eq!(1, state.current_verifiers.len()); + assert_eq!(0, state.current_verifiers.len()); assert_eq!(0, state.pending_verification.len()); assert_eq!(0, state.finished_contributors.get(&next_round_height).unwrap().len()); assert_eq!(0, state.finished_verifiers.get(&next_round_height).unwrap().len()); @@ -4297,10 +3772,9 @@ mod tests { assert_eq!(expected_task1, Some(&task)); state.acquired_lock(&contributor_1, task.chunk_id(), &time).unwrap(); - let assigned_verifier_1 = state.completed_task(&contributor_1, task, &time).unwrap(); + state.completed_task(&contributor_1, &task, &time).unwrap(); assert_eq!(1, state.pending_verification.len()); assert!(!state.is_current_round_finished()); - assert_eq!(verifier, assigned_verifier_1); // Fetch a pending task for contributor 2. let task = state.fetch_task(&contributor_2, &time).unwrap(); @@ -4308,26 +3782,19 @@ mod tests { assert_eq!(expected_task2, Some(&task)); state.acquired_lock(&contributor_2, task.chunk_id(), &time).unwrap(); - let assigned_verifier_2 = state.completed_task(&contributor_2, task, &time).unwrap(); + state.completed_task(&contributor_2, &task, &time).unwrap(); assert_eq!(2, state.pending_verification.len()); assert!(!state.is_current_round_finished()); - assert_eq!(assigned_verifier_1, assigned_verifier_2); // Fetch a pending task for the verifier. - let task = state.fetch_task(&verifier, &time).unwrap(); - assert_eq!(expected_task1, Some(&task)); - - state.acquired_lock(&verifier, task.chunk_id(), &time).unwrap(); - state.completed_task(&verifier, task, &time).unwrap(); + let task = fetch_task_for_verifier(&state).unwrap(); + state.completed_task(&verifier, &task, &time).unwrap(); assert_eq!(1, state.pending_verification.len()); assert!(!state.is_current_round_finished()); // Fetch a pending task for the verifier. - let task = state.fetch_task(&verifier, &time).unwrap(); - assert_eq!(expected_task2, Some(&task)); - - state.acquired_lock(&verifier, task.chunk_id(), &time).unwrap(); - state.completed_task(&verifier, task, &time).unwrap(); + let task = fetch_task_for_verifier(&state).unwrap(); + state.completed_task(&verifier, &task, &time).unwrap(); assert_eq!(0, state.pending_verification.len()); assert!(!state.is_current_round_finished()); @@ -4338,9 +3805,6 @@ mod tests { // Update the state of current round contributors. state.update_current_contributors(&time).unwrap(); - // Update the state of current round verifiers. - state.update_current_verifiers(&time).unwrap(); - // Drop disconnected participants from the current round. state.update_dropped_participants(&time).unwrap(); @@ -4354,7 +3818,7 @@ mod tests { assert_eq!(0, state.current_verifiers.len()); assert_eq!(0, state.pending_verification.len()); assert_eq!(2, state.finished_contributors.get(&next_round_height).unwrap().len()); - assert_eq!(1, state.finished_verifiers.get(&next_round_height).unwrap().len()); + assert_eq!(0, state.finished_verifiers.get(&next_round_height).unwrap().len()); assert_eq!(0, state.dropped.len()); assert_eq!(0, state.banned.len()); } @@ -4370,7 +3834,6 @@ mod tests { let contributor_1 = TEST_CONTRIBUTOR_ID.clone(); let contributor_2 = TEST_CONTRIBUTOR_ID_2.clone(); let verifier_1 = TEST_VERIFIER_ID.clone(); - let verifier_2 = TEST_VERIFIER_ID_2.clone(); // Initialize a new coordinator state. let current_round_height = 5; @@ -4378,8 +3841,6 @@ mod tests { state.initialize(current_round_height); state.add_to_queue(contributor_1.clone(), 10).unwrap(); state.add_to_queue(contributor_2.clone(), 9).unwrap(); - state.add_to_queue(verifier_1.clone(), 10).unwrap(); - state.add_to_queue(verifier_2.clone(), 9).unwrap(); state.update_queue().unwrap(); state.aggregating_current_round(&time).unwrap(); state.aggregated_current_round(&time).unwrap(); @@ -4389,11 +3850,11 @@ mod tests { // Advance the coordinator to the next round. let next_round_height = current_round_height + 1; - assert_eq!(4, state.queue.len()); + assert_eq!(2, state.queue.len()); assert_eq!(0, state.next.len()); state.precommit_next_round(next_round_height, &time).unwrap(); assert_eq!(0, state.queue.len()); - assert_eq!(4, state.next.len()); + assert_eq!(2, state.next.len()); state.commit_next_round(); assert_eq!(0, state.queue.len()); assert_eq!(0, state.next.len()); @@ -4405,7 +3866,7 @@ mod tests { for _ in 0..number_of_chunks { assert_eq!(Some(next_round_height), state.current_round_height); assert_eq!(2, state.current_contributors.len()); - assert_eq!(2, state.current_verifiers.len()); + assert_eq!(0, state.current_verifiers.len()); assert_eq!(0, state.pending_verification.len()); assert_eq!(0, state.finished_contributors.get(&next_round_height).unwrap().len()); assert_eq!(0, state.finished_verifiers.get(&next_round_height).unwrap().len()); @@ -4418,16 +3879,13 @@ mod tests { assert_eq!(expected_task1, Some(&task)); state.acquired_lock(&contributor_1, task.chunk_id(), &time).unwrap(); - let assigned_verifier = state.completed_task(&contributor_1, task, &time).unwrap(); + state.completed_task(&contributor_1, &task, &time).unwrap(); assert_eq!(1, state.pending_verification.len()); assert!(!state.is_current_round_finished()); // Fetch a pending task for the verifier. - let task = state.fetch_task(&assigned_verifier, &time).unwrap(); - assert_eq!(expected_task1, Some(&task)); - - state.acquired_lock(&assigned_verifier, task.chunk_id(), &time).unwrap(); - state.completed_task(&assigned_verifier, task, &time).unwrap(); + let task = fetch_task_for_verifier(&state).unwrap(); + state.completed_task(&verifier_1, &task, &time).unwrap(); assert_eq!(0, state.pending_verification.len()); assert!(!state.is_current_round_finished()); @@ -4438,11 +3896,9 @@ mod tests { // Update the state of current round contributors. state.update_current_contributors(&time).unwrap(); - // Update the state of current round verifiers. - state.update_current_verifiers(&time).unwrap(); - // Drop disconnected participants from the current round. - state.update_dropped_participants(&time).unwrap(); + let dropped = state.update_dropped_participants(&time).unwrap(); + assert_eq!(0, dropped.len()); // Ban any participants who meet the coordinator criteria. state.update_banned_participants().unwrap(); @@ -4455,7 +3911,7 @@ mod tests { for _ in 0..number_of_chunks { assert_eq!(Some(next_round_height), state.current_round_height); assert_eq!(1, state.current_contributors.len()); - assert_eq!(2, state.current_verifiers.len()); + assert_eq!(0, state.current_verifiers.len()); assert_eq!(0, state.pending_verification.len()); assert_eq!(1, state.finished_contributors.get(&next_round_height).unwrap().len()); assert_eq!(0, state.finished_verifiers.get(&next_round_height).unwrap().len()); @@ -4468,16 +3924,13 @@ mod tests { assert_eq!(expected_task2, Some(&task)); state.acquired_lock(&contributor_2, task.chunk_id(), &time).unwrap(); - let assigned_verifier = state.completed_task(&contributor_2, task, &time).unwrap(); + state.completed_task(&contributor_2, &task, &time).unwrap(); assert_eq!(1, state.pending_verification.len()); assert!(!state.is_current_round_finished()); // Fetch a pending task for the verifier. - let task = state.fetch_task(&assigned_verifier, &time).unwrap(); - assert_eq!(expected_task2, Some(&task)); - - state.acquired_lock(&assigned_verifier, task.chunk_id(), &time).unwrap(); - state.completed_task(&assigned_verifier, task, &time).unwrap(); + let task = fetch_task_for_verifier(&state).unwrap(); + state.completed_task(&verifier_1, &task, &time).unwrap(); assert_eq!(0, state.pending_verification.len()); assert!(!state.is_current_round_finished()); @@ -4488,11 +3941,9 @@ mod tests { // Update the state of current round contributors. state.update_current_contributors(&time).unwrap(); - // Update the state of current round verifiers. - state.update_current_verifiers(&time).unwrap(); - // Drop disconnected participants from the current round. - state.update_dropped_participants(&time).unwrap(); + let dropped = state.update_dropped_participants(&time).unwrap(); + assert_eq!(0, dropped.len()); // Ban any participants who meet the coordinator criteria. state.update_banned_participants().unwrap(); @@ -4504,7 +3955,7 @@ mod tests { assert_eq!(0, state.current_verifiers.len()); assert_eq!(0, state.pending_verification.len()); assert_eq!(2, state.finished_contributors.get(&next_round_height).unwrap().len()); - assert_eq!(2, state.finished_verifiers.get(&next_round_height).unwrap().len()); + assert_eq!(0, state.finished_verifiers.get(&next_round_height).unwrap().len()); assert_eq!(0, state.dropped.len()); assert_eq!(0, state.banned.len()); } @@ -4524,7 +3975,6 @@ mod tests { let contributor_1 = TEST_CONTRIBUTOR_ID.clone(); let contributor_2 = TEST_CONTRIBUTOR_ID_2.clone(); let verifier_1 = TEST_VERIFIER_ID.clone(); - let verifier_2 = TEST_VERIFIER_ID_2.clone(); // Initialize a new coordinator state. let current_round_height = 5; @@ -4532,8 +3982,6 @@ mod tests { state.initialize(current_round_height); state.add_to_queue(contributor_1.clone(), 10).unwrap(); state.add_to_queue(contributor_2.clone(), 9).unwrap(); - state.add_to_queue(verifier_1.clone(), 10).unwrap(); - state.add_to_queue(verifier_2.clone(), 9).unwrap(); state.update_queue().unwrap(); state.aggregating_current_round(&time).unwrap(); state.aggregated_current_round(&time).unwrap(); @@ -4552,12 +4000,10 @@ mod tests { // Fetch a pending task for the contributor. let task = state.fetch_task(&contributor_1, &time).unwrap(); state.acquired_lock(&contributor_1, task.chunk_id(), &time).unwrap(); - let assigned_verifier = state.completed_task(&contributor_1, task, &time).unwrap(); + state.completed_task(&contributor_1, &task, &time).unwrap(); // Fetch a pending task for the verifier. - let task = state.fetch_task(&assigned_verifier, &time).unwrap(); - - state.acquired_lock(&assigned_verifier, task.chunk_id(), &time).unwrap(); - state.completed_task(&assigned_verifier, task, &time).unwrap(); + let task = fetch_task_for_verifier(&state).unwrap(); + state.completed_task(&verifier_1, &task, &time).unwrap(); { // Update the current round metrics. @@ -4566,11 +4012,9 @@ mod tests { // Update the state of current round contributors. state.update_current_contributors(&time).unwrap(); - // Update the state of current round verifiers. - state.update_current_verifiers(&time).unwrap(); - // Drop disconnected participants from the current round. - state.update_dropped_participants(&time).unwrap(); + let dropped = state.update_dropped_participants(&time).unwrap(); + assert_eq!(0, dropped.len()); // Ban any participants who meet the coordinator criteria. state.update_banned_participants().unwrap(); @@ -4582,11 +4026,10 @@ mod tests { // Fetch a pending task for the contributor. let task = state.fetch_task(&contributor_2, &time).unwrap(); state.acquired_lock(&contributor_2, task.chunk_id(), &time).unwrap(); - let assigned_verifier = state.completed_task(&contributor_2, task, &time).unwrap(); + state.completed_task(&contributor_2, &task, &time).unwrap(); // Fetch a pending task for the verifier. - let task = state.fetch_task(&assigned_verifier, &time).unwrap(); - state.acquired_lock(&assigned_verifier, task.chunk_id(), &time).unwrap(); - state.completed_task(&assigned_verifier, task, &time).unwrap(); + let task = fetch_task_for_verifier(&state).unwrap(); + state.completed_task(&verifier_1, &task, &time).unwrap(); { // Update the current round metrics. @@ -4595,11 +4038,9 @@ mod tests { // Update the state of current round contributors. state.update_current_contributors(&time).unwrap(); - // Update the state of current round verifiers. - state.update_current_verifiers(&time).unwrap(); - // Drop disconnected participants from the current round. - state.update_dropped_participants(&time).unwrap(); + let dropped = state.update_dropped_participants(&time).unwrap(); + assert_eq!(0, dropped.len()); // Ban any participants who meet the coordinator criteria. state.update_banned_participants().unwrap(); @@ -4620,12 +4061,10 @@ mod tests { // Fetch a pending task for the contributor. let task = state.fetch_task(&contributor_1, &time).unwrap(); state.acquired_lock(&contributor_1, task.chunk_id(), &time).unwrap(); - let assigned_verifier = state.completed_task(&contributor_1, task, &time).unwrap(); + state.completed_task(&contributor_1, &task, &time).unwrap(); // Fetch a pending task for the verifier. - let task = state.fetch_task(&assigned_verifier, &time).unwrap(); - - state.acquired_lock(&assigned_verifier, task.chunk_id(), &time).unwrap(); - state.completed_task(&assigned_verifier, task, &time).unwrap(); + let task = fetch_task_for_verifier(&state).unwrap(); + state.completed_task(&verifier_1, &task, &time).unwrap(); { // Update the current round metrics. @@ -4634,11 +4073,9 @@ mod tests { // Update the state of current round contributors. state.update_current_contributors(&time).unwrap(); - // Update the state of current round verifiers. - state.update_current_verifiers(&time).unwrap(); - // Drop disconnected participants from the current round. - state.update_dropped_participants(&time).unwrap(); + let dropped = state.update_dropped_participants(&time).unwrap(); + assert_eq!(0, dropped.len()); // Ban any participants who meet the coordinator criteria. state.update_banned_participants().unwrap(); @@ -4650,11 +4087,10 @@ mod tests { // Fetch a pending task for the contributor. let task = state.fetch_task(&contributor_2, &time).unwrap(); state.acquired_lock(&contributor_2, task.chunk_id(), &time).unwrap(); - let assigned_verifier = state.completed_task(&contributor_2, task, &time).unwrap(); + state.completed_task(&contributor_2, &task, &time).unwrap(); // Fetch a pending task for the verifier. - let task = state.fetch_task(&assigned_verifier, &time).unwrap(); - state.acquired_lock(&assigned_verifier, task.chunk_id(), &time).unwrap(); - state.completed_task(&assigned_verifier, task, &time).unwrap(); + let task = fetch_task_for_verifier(&state).unwrap(); + state.completed_task(&verifier_1, &task, &time).unwrap(); { // Update the current round metrics. @@ -4663,11 +4099,9 @@ mod tests { // Update the state of current round contributors. state.update_current_contributors(&time).unwrap(); - // Update the state of current round verifiers. - state.update_current_verifiers(&time).unwrap(); - // Drop disconnected participants from the current round. - state.update_dropped_participants(&time).unwrap(); + let dropped = state.update_dropped_participants(&time).unwrap(); + assert_eq!(0, dropped.len()); // Ban any participants who meet the coordinator criteria. state.update_banned_participants().unwrap(); @@ -4695,7 +4129,6 @@ mod tests { let contributor_1 = TEST_CONTRIBUTOR_ID.clone(); let contributor_2 = TEST_CONTRIBUTOR_ID_2.clone(); let verifier_1 = TEST_VERIFIER_ID.clone(); - let verifier_2 = TEST_VERIFIER_ID_2.clone(); // Initialize a new coordinator state. let current_round_height = 5; @@ -4703,8 +4136,6 @@ mod tests { state.initialize(current_round_height); state.add_to_queue(contributor_1.clone(), 10).unwrap(); state.add_to_queue(contributor_2.clone(), 9).unwrap(); - state.add_to_queue(verifier_1.clone(), 10).unwrap(); - state.add_to_queue(verifier_2.clone(), 9).unwrap(); state.update_queue().unwrap(); state.aggregating_current_round(&time).unwrap(); state.aggregated_current_round(&time).unwrap(); @@ -4723,12 +4154,10 @@ mod tests { // Fetch a pending task for the contributor. let task = state.fetch_task(&contributor_1, &time).unwrap(); state.acquired_lock(&contributor_1, task.chunk_id(), &time).unwrap(); - let assigned_verifier = state.completed_task(&contributor_1, task, &time).unwrap(); + state.completed_task(&contributor_1, &task, &time).unwrap(); // Fetch a pending task for the verifier. - let task = state.fetch_task(&assigned_verifier, &time).unwrap(); - - state.acquired_lock(&assigned_verifier, task.chunk_id(), &time).unwrap(); - state.completed_task(&assigned_verifier, task, &time).unwrap(); + let task = fetch_task_for_verifier(&state).unwrap(); + state.completed_task(&verifier_1, &task, &time).unwrap(); { // Update the current round metrics. @@ -4737,11 +4166,9 @@ mod tests { // Update the state of current round contributors. state.update_current_contributors(&time).unwrap(); - // Update the state of current round verifiers. - state.update_current_verifiers(&time).unwrap(); - // Drop disconnected participants from the current round. - state.update_dropped_participants(&time).unwrap(); + let dropped = state.update_dropped_participants(&time).unwrap(); + assert_eq!(0, dropped.len()); // Ban any participants who meet the coordinator criteria. state.update_banned_participants().unwrap(); @@ -4753,11 +4180,10 @@ mod tests { // Fetch a pending task for the contributor. let task = state.fetch_task(&contributor_2, &time).unwrap(); state.acquired_lock(&contributor_2, task.chunk_id(), &time).unwrap(); - let assigned_verifier = state.completed_task(&contributor_2, task, &time).unwrap(); + state.completed_task(&contributor_2, &task, &time).unwrap(); // Fetch a pending task for the verifier. - let task = state.fetch_task(&assigned_verifier, &time).unwrap(); - state.acquired_lock(&assigned_verifier, task.chunk_id(), &time).unwrap(); - state.completed_task(&assigned_verifier, task, &time).unwrap(); + let task = fetch_task_for_verifier(&state).unwrap(); + state.completed_task(&verifier_1, &task, &time).unwrap(); { // Update the current round metrics. @@ -4766,11 +4192,9 @@ mod tests { // Update the state of current round contributors. state.update_current_contributors(&time).unwrap(); - // Update the state of current round verifiers. - state.update_current_verifiers(&time).unwrap(); - // Drop disconnected participants from the current round. - state.update_dropped_participants(&time).unwrap(); + let dropped = state.update_dropped_participants(&time).unwrap(); + assert_eq!(0, dropped.len()); // Ban any participants who meet the coordinator criteria. state.update_banned_participants().unwrap(); @@ -4807,11 +4231,10 @@ mod tests { // Fetch a pending task for the contributor. let task = state.fetch_task(&contributor_2, &time).unwrap(); state.acquired_lock(&contributor_2, task.chunk_id(), &time).unwrap(); - let assigned_verifier = state.completed_task(&contributor_2, task, &time).unwrap(); + state.completed_task(&contributor_2, &task, &time).unwrap(); // Fetch a pending task for the verifier. - let task = state.fetch_task(&assigned_verifier, &time).unwrap(); - state.acquired_lock(&assigned_verifier, task.chunk_id(), &time).unwrap(); - state.completed_task(&assigned_verifier, task, &time).unwrap(); + let task = fetch_task_for_verifier(&state).unwrap(); + state.completed_task(&verifier_1, &task, &time).unwrap(); { // Update the current round metrics. @@ -4820,11 +4243,9 @@ mod tests { // Update the state of current round contributors. state.update_current_contributors(&time).unwrap(); - // Update the state of current round verifiers. - state.update_current_verifiers(&time).unwrap(); - // Drop disconnected participants from the current round. - state.update_dropped_participants(&time).unwrap(); + let dropped = state.update_dropped_participants(&time).unwrap(); + assert_eq!(0, dropped.len()); // Ban any participants who meet the coordinator criteria. state.update_banned_participants().unwrap(); @@ -4854,7 +4275,6 @@ mod tests { // Fetch two contributors and two verifiers. let contributor_1 = TEST_CONTRIBUTOR_ID.clone(); - let _contributor_2 = TEST_CONTRIBUTOR_ID_2.clone(); let verifier_1 = TEST_VERIFIER_ID.clone(); // Initialize a new coordinator state. @@ -4862,7 +4282,6 @@ mod tests { let mut state = CoordinatorState::new(environment.clone()); state.initialize(current_round_height); state.add_to_queue(contributor_1.clone(), 10).unwrap(); - state.add_to_queue(verifier_1.clone(), 10).unwrap(); state.update_queue().unwrap(); state.aggregating_current_round(&time).unwrap(); state.aggregated_current_round(&time).unwrap(); @@ -4881,12 +4300,10 @@ mod tests { // Fetch a pending task for the contributor. let task = state.fetch_task(&contributor_1, &time).unwrap(); state.acquired_lock(&contributor_1, task.chunk_id(), &time).unwrap(); - let assigned_verifier = state.completed_task(&contributor_1, task, &time).unwrap(); + state.completed_task(&contributor_1, &task, &time).unwrap(); // Fetch a pending task for the verifier. - let task = state.fetch_task(&assigned_verifier, &time).unwrap(); - - state.acquired_lock(&assigned_verifier, task.chunk_id(), &time).unwrap(); - state.completed_task(&assigned_verifier, task, &time).unwrap(); + let task = fetch_task_for_verifier(&state).unwrap(); + state.completed_task(&verifier_1, &task, &time).unwrap(); { // Update the current round metrics. @@ -4895,11 +4312,9 @@ mod tests { // Update the state of current round contributors. state.update_current_contributors(&time).unwrap(); - // Update the state of current round verifiers. - state.update_current_verifiers(&time).unwrap(); - // Drop disconnected participants from the current round. - state.update_dropped_participants(&time).unwrap(); + let dropped = state.update_dropped_participants(&time).unwrap(); + assert_eq!(0, dropped.len()); // Ban any participants who meet the coordinator criteria. state.update_banned_participants().unwrap(); diff --git a/phase1-coordinator/src/environment.rs b/phase1-coordinator/src/environment.rs index 4e2da3e4..a6a75002 100644 --- a/phase1-coordinator/src/environment.rs +++ b/phase1-coordinator/src/environment.rs @@ -316,22 +316,6 @@ impl Environment { self.maximum_contributors_per_round } - /// - /// Returns the minimum number of verifiers permitted to - /// participate in a round. - /// - pub const fn minimum_verifiers_per_round(&self) -> usize { - self.minimum_verifiers_per_round - } - - /// - /// Returns the maximum number of verifiers permitted to - /// participate in a round. - /// - pub const fn maximum_verifiers_per_round(&self) -> usize { - self.maximum_verifiers_per_round - } - /// /// Returns the number of chunks a contributor is /// authorized to lock in tandem at any point during a round. @@ -498,16 +482,6 @@ impl Testing { self } - pub fn minimum_verifiers_per_round(mut self, minimum: usize) -> Self { - self.environment.minimum_verifiers_per_round = minimum; - self - } - - pub fn maximum_verifiers_per_round(mut self, maximum: usize) -> Self { - self.environment.maximum_verifiers_per_round = maximum; - self - } - #[inline] pub fn coordinator_contributors(&self, contributors: &[Participant]) -> Self { // Check that all participants are contributors. @@ -612,16 +586,6 @@ impl Development { self } - pub fn minimum_verifiers_per_round(mut self, minimum: usize) -> Self { - self.environment.minimum_verifiers_per_round = minimum; - self - } - - pub fn maximum_verifiers_per_round(mut self, maximum: usize) -> Self { - self.environment.maximum_verifiers_per_round = maximum; - self - } - #[inline] pub fn coordinator_contributors(&self, contributors: &[Participant]) -> Self { // Check that all participants are contributors. @@ -720,16 +684,6 @@ impl Production { self } - pub fn minimum_verifiers_per_round(mut self, minimum: usize) -> Self { - self.environment.minimum_verifiers_per_round = minimum; - self - } - - pub fn maximum_verifiers_per_round(mut self, maximum: usize) -> Self { - self.environment.maximum_verifiers_per_round = maximum; - self - } - #[inline] pub fn coordinator_contributors(&self, contributors: &[Participant]) -> Self { // Check that all participants are contributors. diff --git a/phase1-coordinator/src/objects/chunk.rs b/phase1-coordinator/src/objects/chunk.rs index 446eb2cd..d6638aa5 100644 --- a/phase1-coordinator/src/objects/chunk.rs +++ b/phase1-coordinator/src/objects/chunk.rs @@ -419,11 +419,6 @@ impl Chunk { return Err(CoordinatorError::ExpectedVerifier); } - // Check that this chunk is locked by the verifier before attempting to verify contribution. - if !self.is_locked_by(&verifier) { - return Err(CoordinatorError::ChunkNotLockedOrByWrongParticipant); - } - // Fetch the contribution to be verified from the chunk. let contribution = match self.contributions.get_mut(&contribution_id) { Some(contribution) => contribution, diff --git a/phase1-coordinator/src/objects/round.rs b/phase1-coordinator/src/objects/round.rs index 9223b641..129f3c87 100644 --- a/phase1-coordinator/src/objects/round.rs +++ b/phase1-coordinator/src/objects/round.rs @@ -91,7 +91,6 @@ impl Round { round_height: u64, started_at: DateTime, contributor_ids: Vec, - verifier_ids: Vec, ) -> Result { debug!("Starting to create round {}", round_height); @@ -101,7 +100,11 @@ impl Round { } // Fetch the initial verifier. - let verifier = verifier_ids.first().ok_or(CoordinatorError::VerifierMissing)?; + let verifier = environment + .coordinator_verifiers() + .first() + .ok_or_else(|| CoordinatorError::VerifierMissing)? + .clone(); // Check that all contributor IDs are valid. { @@ -125,27 +128,6 @@ impl Round { } } - // Check that all verifier IDs are valid. - { - // Check that each verifier ID is unique. - if !has_unique_elements(&verifier_ids) { - return Err(CoordinatorError::RoundVerifiersNotUnique); - } - // Check that each verifier ID is a verifier participant type. - let num_verifiers = verifier_ids - .par_iter() - .filter(|id| Participant::is_verifier(id)) - .count(); - if num_verifiers != verifier_ids.len() { - error!("{} IDs are not verifiers", verifier_ids.len() - num_verifiers); - return Err(CoordinatorError::ExpectedVerifier); - } - // Check that the list of verifier IDs is not empty. - if num_verifiers == 0 { - return Err(CoordinatorError::RoundVerifiersMissing); - } - } - // Construct the chunks for this round. // // Initialize the chunk verifiers as a list comprising only @@ -180,7 +162,7 @@ impl Round { started_at: Some(started_at), finished_at: None, contributor_ids, - verifier_ids, + verifier_ids: vec![], chunks, }) } @@ -238,23 +220,6 @@ impl Round { } } - /// - /// Returns `true` if the given participant is authorized as a - /// verifier and listed in the verifier IDs for this round. - /// - /// If the participant is not a verifier, or if there are - /// no prior rounds, returns `false`. - /// - #[inline] - pub fn is_verifier(&self, participant: &Participant) -> bool { - // Check that the participant is a verifier. - match participant { - Participant::Contributor(_) => false, - // Check that the participant is a verifier for the given round height. - Participant::Verifier(_) => self.verifier_ids.contains(participant), - } - } - /// /// Returns a reference to the chunk, if it exists. /// Otherwise returns `None`. @@ -324,12 +289,8 @@ impl Round { } } Participant::Verifier(_) => { - // Check that the participant is an authorized verifier - // for the current round. - if !self.is_verifier(participant) { - error!("{} is not an authorized verifier", participant); - return Err(CoordinatorError::UnauthorizedChunkVerifier); - } + // Verifiers don't lock chunks + return Err(CoordinatorError::ExpectedContributor); } }; @@ -566,10 +527,7 @@ impl Round { } } Participant::Verifier(_) => { - if number_of_locks_held >= environment.verifier_lock_chunk_limit() { - trace!("{} chunks are locked by {}", &number_of_locks_held, participant); - return Err(CoordinatorError::ChunkLockLimitReached); - } + return Err(CoordinatorError::ExpectedContributor); } }; @@ -631,62 +589,7 @@ impl Round { } } Participant::Verifier(_) => { - // Check that the participant is an authorized verifier - // for the current round. - if !self.is_verifier(participant) { - error!("{} is not an authorized verifier", participant); - return Err(CoordinatorError::UnauthorizedChunkVerifier); - } - - // Fetch the current round height. - let current_round_height = self.round_height(); - // Fetch the chunk corresponding to the given chunk ID. - let chunk = self.chunk(chunk_id)?; - // Fetch the current contribution ID. - let current_contribution_id = chunk.current_contribution_id(); - - if current_contribution_id == 0 { - return Err(CoordinatorError::ChunkCannotLockZeroContributions { chunk_id }); - } - - // Fetch the previous contribution locator. - let previous_contribution = - ContributionLocator::new(current_round_height, chunk_id, current_contribution_id - 1, true); - - // This call enforces a strict check that the - // current contribution locator exist and - // has not been verified yet. - let current_contribution = self.current_contribution_locator(storage, chunk_id, false)?; - - tracing::debug!("Obtained response locator {:?}", current_contribution); - - // Fetch whether this is the final contribution of the specified chunk. - let is_final_contribution = chunk.only_contributions_complete(self.expected_number_of_contributions()); - // Fetch the next contribution locator and its contribution file signature locator. - let (next_contribution, next_contribution_file_signature) = match is_final_contribution { - // This is the final contribution in the chunk. - true => ( - ContributionLocator::new(current_round_height + 1, chunk_id, 0, true), - ContributionSignatureLocator::new(current_round_height + 1, chunk_id, 0, true), - ), - // This is a typical contribution in the chunk. - false => ( - ContributionLocator::new(current_round_height, chunk_id, current_contribution_id, true), - ContributionSignatureLocator::new( - current_round_height, - chunk_id, - current_contribution_id, - true, - ), - ), - }; - - LockedLocators { - previous_contribution, - current_contribution, - next_contribution, - next_contribution_file_signature, - } + return Err(CoordinatorError::ExpectedContributor); } }; @@ -864,12 +767,7 @@ impl Round { } } Participant::Verifier(_) => { - // Check that the participant is an *authorized* verifier - // for the current round. - if !self.is_verifier(participant) { - error!("{} is not an authorized verifier", participant); - return Err(CoordinatorError::UnauthorizedChunkVerifier); - } + return Err(CoordinatorError::ExpectedContributor); } }; @@ -1261,7 +1159,6 @@ mod tests { 0, /* height */ *TEST_STARTED_AT, vec![], - TEST_VERIFIER_IDS.to_vec(), ) .unwrap(); @@ -1294,8 +1191,6 @@ mod tests { let mut round_1: Round = test_round_1_partial_json().unwrap(); assert!(round_1.is_contributor(&TEST_CONTRIBUTOR_ID_2)); assert!(round_1.is_contributor(&TEST_CONTRIBUTOR_ID_3)); - assert!(round_1.is_verifier(&TEST_VERIFIER_ID_2)); - assert!(round_1.is_verifier(&TEST_VERIFIER_ID_3)); assert!(round_1.chunks[14].is_locked()); let n_contributions = 89; @@ -1318,8 +1213,6 @@ mod tests { assert!(!round_1.is_contributor(&*TEST_CONTRIBUTOR_ID_2)); assert!(round_1.is_contributor(&*TEST_CONTRIBUTOR_ID_3)); - assert!(round_1.is_verifier(&*TEST_VERIFIER_ID_2)); - assert!(round_1.is_verifier(&*TEST_VERIFIER_ID_3)); } #[test] @@ -1331,18 +1224,6 @@ mod tests { assert!(round_1.is_contributor(&TEST_CONTRIBUTOR_ID)); } - #[test] - #[serial] - fn test_is_authorized_verifier() { - initialize_test_environment(&TEST_ENVIRONMENT); - - let round_0 = test_round_0().unwrap(); - assert!(round_0.is_verifier(&TEST_VERIFIER_ID)); - - let round_1 = test_round_1_initial_json().unwrap(); - assert!(round_1.is_contributor(&TEST_CONTRIBUTOR_ID)); - } - #[test] #[serial] fn test_get_chunk() { @@ -1371,10 +1252,7 @@ mod tests { initialize_test_environment(&TEST_ENVIRONMENT); let candidates = test_round_0().unwrap().verifiers().clone(); - assert_eq!(TEST_VERIFIER_IDS.len(), candidates.len()); - for id in TEST_VERIFIER_IDS.iter() { - assert!(candidates.contains(id)); - } + assert_eq!(0, candidates.len()); } #[test] diff --git a/phase1-coordinator/src/testing/coordinator.rs b/phase1-coordinator/src/testing/coordinator.rs index 88ff5024..7e72a475 100644 --- a/phase1-coordinator/src/testing/coordinator.rs +++ b/phase1-coordinator/src/testing/coordinator.rs @@ -144,7 +144,6 @@ pub fn test_round_0() -> anyhow::Result { 0, /* height */ *TEST_STARTED_AT, vec![], - TEST_VERIFIER_IDS.to_vec(), )?) } diff --git a/phase1-coordinator/src/testing/resources/round.json b/phase1-coordinator/src/testing/resources/round.json index 6a1d0b38..852b474b 100644 --- a/phase1-coordinator/src/testing/resources/round.json +++ b/phase1-coordinator/src/testing/resources/round.json @@ -7,9 +7,7 @@ "0xd0FaDc3C5899c28c581c0e06819f4113cb08b0e4", "0xEC60b9a43529c12CA83Af466D8A6F8444392D47C" ], - "verifierIds": [ - "0xEC60b9a43529c12CA83Af466D8A6F8444392D47C" - ], + "verifierIds": [], "chunks": [ { "chunkId": "0", diff --git a/phase1-coordinator/src/testing/resources/round_partial.json b/phase1-coordinator/src/testing/resources/round_partial.json index eb4efe31..728e94b0 100644 --- a/phase1-coordinator/src/testing/resources/round_partial.json +++ b/phase1-coordinator/src/testing/resources/round_partial.json @@ -4,9 +4,7 @@ "0xd0FaDc3C5899c28c581c0e06819f4113cb08b0e4", "0xEC60b9a43529c12CA83Af466D8A6F8444392D47C" ], - "verifierIds": [ - "0xEC60b9a43529c12CA83Af466D8A6F8444392D47C" - ], + "verifierIds": [], "chunks": [ { "chunkId": "0", diff --git a/phase1-coordinator/src/testing/resources/test_round_0.json b/phase1-coordinator/src/testing/resources/test_round_0.json index b0f986a4..cbcd219c 100644 --- a/phase1-coordinator/src/testing/resources/test_round_0.json +++ b/phase1-coordinator/src/testing/resources/test_round_0.json @@ -5,9 +5,7 @@ "startedAt": "1970-01-01T00:01:01Z", "finishedAt": null, "contributorIds": [], - "verifierIds": [ - "testing-coordinator-verifier.verifier" - ], + "verifierIds": [], "chunks": [ { "chunkId": "0", diff --git a/phase1-coordinator/src/testing/resources/test_round_1_initial.json b/phase1-coordinator/src/testing/resources/test_round_1_initial.json index 64cadefa..5ef82b0a 100644 --- a/phase1-coordinator/src/testing/resources/test_round_1_initial.json +++ b/phase1-coordinator/src/testing/resources/test_round_1_initial.json @@ -7,9 +7,7 @@ "contributorIds": [ "testing-coordinator-contributor.contributor" ], - "verifierIds": [ - "testing-coordinator-verifier.verifier" - ], + "verifierIds": [], "chunks": [ { "chunkId": "0", diff --git a/phase1-coordinator/src/testing/resources/test_round_1_partial.json b/phase1-coordinator/src/testing/resources/test_round_1_partial.json index 13aaf351..a9952012 100644 --- a/phase1-coordinator/src/testing/resources/test_round_1_partial.json +++ b/phase1-coordinator/src/testing/resources/test_round_1_partial.json @@ -7,10 +7,7 @@ "testing-coordinator-contributor-3.contributor", "testing-coordinator-contributor-2.contributor" ], - "verifierIds": [ - "testing-coordinator-verifier-3.verifier", - "testing-coordinator-verifier-2.verifier" - ], + "verifierIds": [], "chunks": [ { "chunkId": 0, @@ -1774,4 +1771,4 @@ } } ] -} \ No newline at end of file +} diff --git a/phase1-coordinator/src/tests.rs b/phase1-coordinator/src/tests.rs index 7ab7c29f..69c7f01e 100644 --- a/phase1-coordinator/src/tests.rs +++ b/phase1-coordinator/src/tests.rs @@ -73,8 +73,10 @@ struct VerifierTestDetails { } impl VerifierTestDetails { - fn verify(&self, coordinator: &mut Coordinator) -> anyhow::Result<()> { - coordinator.verify(&self.participant, &self.signing_key) + /// If there are pending verifications, grab one and verify it. + /// Otherwise do nothing + fn verify_if_available(&self, coordinator: &mut Coordinator) -> anyhow::Result<()> { + verify_task_if_available(coordinator, &self.participant, &self.signing_key) } } @@ -109,20 +111,17 @@ fn execute_round(proving_system: ProvingSystem, curve: CurveKind) -> anyhow::Res let (contributor, contributor_signing_key, seed) = create_contributor("1"); let (verifier, verifier_signing_key) = create_verifier("1"); coordinator.add_to_queue(contributor.clone(), 10)?; - coordinator.add_to_queue(verifier.clone(), 10)?; assert_eq!(1, coordinator.number_of_queue_contributors()); - assert_eq!(1, coordinator.number_of_queue_verifiers()); // Advance the ceremony from round 0 to round 1. coordinator.update()?; assert_eq!(1, coordinator.current_round_height()?); assert_eq!(0, coordinator.number_of_queue_contributors()); - assert_eq!(0, coordinator.number_of_queue_verifiers()); // Run contribution and verification for round 1. for _ in 0..number_of_chunks { coordinator.contribute(&contributor, &contributor_signing_key, &seed)?; - coordinator.verify(&verifier, &verifier_signing_key)?; + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key)?; } // @@ -135,17 +134,13 @@ fn execute_round(proving_system: ProvingSystem, curve: CurveKind) -> anyhow::Res // changing the outcome of this test, if necessary. // let (contributor, _, _) = create_contributor("1"); - let (verifier, _) = create_verifier("1"); coordinator.add_to_queue(contributor.clone(), 10)?; - coordinator.add_to_queue(verifier.clone(), 10)?; assert_eq!(1, coordinator.number_of_queue_contributors()); - assert_eq!(1, coordinator.number_of_queue_verifiers()); // Update the ceremony from round 1 to round 2. coordinator.update()?; assert_eq!(2, coordinator.current_round_height()?); assert_eq!(0, coordinator.number_of_queue_contributors()); - assert_eq!(0, coordinator.number_of_queue_verifiers()); Ok(()) } @@ -191,10 +186,28 @@ fn execute_round(proving_system: ProvingSystem, curve: CurveKind) -> anyhow::Res */ +/// If there are pending verifications, grab one and verify it. +/// Otherwise do nothing +fn verify_task_if_available( + coordinator: &mut Coordinator, + verifier: &Participant, + signing_key: &SigningKey, +) -> anyhow::Result<()> { + let pending_tasks = coordinator.get_pending_verifications(); + if let Some(task) = pending_tasks.keys().next().cloned() { + coordinator.verify(&verifier, signing_key, &task)?; + } + Ok(()) +} + +fn fetch_task_for_verifier(coordinator: &Coordinator) -> Option { + coordinator.get_pending_verifications().keys().next().cloned() +} + #[test] #[serial] /// Drops a contributor who does not affect other contributors or verifiers. -fn coordinator_drop_contributor_basic() -> anyhow::Result<()> { +fn coordinator_drop_contributor_basic() { let parameters = Parameters::Custom(Settings::new( ContributionMode::Chunked, ProvingSystem::Groth16, @@ -207,75 +220,64 @@ fn coordinator_drop_contributor_basic() -> anyhow::Result<()> { let number_of_chunks = environment.number_of_chunks() as usize; // Instantiate a coordinator. - let mut coordinator = Coordinator::new(environment, Arc::new(Dummy))?; + let mut coordinator = Coordinator::new(environment, Arc::new(Dummy)).unwrap(); // Initialize the ceremony to round 0. - coordinator.initialize()?; - assert_eq!(0, coordinator.current_round_height()?); + coordinator.initialize().unwrap(); + assert_eq!(0, coordinator.current_round_height().unwrap()); // Add a contributor and verifier to the queue. let (contributor1, contributor_signing_key1, seed1) = create_contributor("1"); let (contributor2, contributor_signing_key2, seed2) = create_contributor("2"); let (verifier, verifier_signing_key) = create_verifier("1"); - coordinator.add_to_queue(contributor1.clone(), 10)?; - coordinator.add_to_queue(contributor2.clone(), 9)?; - coordinator.add_to_queue(verifier.clone(), 10)?; + coordinator.add_to_queue(contributor1.clone(), 10).unwrap(); + coordinator.add_to_queue(contributor2.clone(), 9).unwrap(); assert_eq!(2, coordinator.number_of_queue_contributors()); - assert_eq!(1, coordinator.number_of_queue_verifiers()); assert!(coordinator.is_queue_contributor(&contributor1)); assert!(coordinator.is_queue_contributor(&contributor2)); - assert!(coordinator.is_queue_verifier(&verifier)); assert!(!coordinator.is_current_contributor(&contributor1)); assert!(!coordinator.is_current_contributor(&contributor2)); - assert!(!coordinator.is_current_verifier(&verifier)); assert!(!coordinator.is_finished_contributor(&contributor1)); assert!(!coordinator.is_finished_contributor(&contributor2)); - assert!(!coordinator.is_finished_verifier(&verifier)); // Update the ceremony to round 1. - coordinator.update()?; - assert_eq!(1, coordinator.current_round_height()?); + coordinator.update().unwrap(); + assert_eq!(1, coordinator.current_round_height().unwrap()); assert_eq!(0, coordinator.number_of_queue_contributors()); - assert_eq!(0, coordinator.number_of_queue_verifiers()); assert!(!coordinator.is_queue_contributor(&contributor1)); assert!(!coordinator.is_queue_contributor(&contributor2)); - assert!(!coordinator.is_queue_verifier(&verifier)); assert!(coordinator.is_current_contributor(&contributor1)); assert!(coordinator.is_current_contributor(&contributor2)); - assert!(coordinator.is_current_verifier(&verifier)); assert!(!coordinator.is_finished_contributor(&contributor1)); assert!(!coordinator.is_finished_contributor(&contributor2)); - assert!(!coordinator.is_finished_verifier(&verifier)); // Contribute and verify up to the penultimate chunk. - for _ in 0..(number_of_chunks - 1) { - coordinator.contribute(&contributor1, &contributor_signing_key1, &seed1)?; - coordinator.contribute(&contributor2, &contributor_signing_key2, &seed2)?; - coordinator.verify(&verifier, &verifier_signing_key)?; - coordinator.verify(&verifier, &verifier_signing_key)?; + for _ in 0..(number_of_chunks - 1) as u64 { + coordinator + .contribute(&contributor1, &contributor_signing_key1, &seed1) + .unwrap(); + coordinator + .contribute(&contributor2, &contributor_signing_key2, &seed2) + .unwrap(); + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key).unwrap(); + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key).unwrap(); } assert!(!coordinator.is_queue_contributor(&contributor1)); assert!(!coordinator.is_queue_contributor(&contributor2)); - assert!(!coordinator.is_queue_verifier(&verifier)); assert!(coordinator.is_current_contributor(&contributor1)); assert!(coordinator.is_current_contributor(&contributor2)); - assert!(coordinator.is_current_verifier(&verifier)); assert!(!coordinator.is_finished_contributor(&contributor1)); assert!(!coordinator.is_finished_contributor(&contributor2)); - assert!(!coordinator.is_finished_verifier(&verifier)); // Drop the contributor from the current round. - coordinator.drop_participant(&contributor1)?; + coordinator.drop_participant(&contributor1).unwrap(); assert!(!coordinator.is_queue_contributor(&contributor1)); assert!(!coordinator.is_queue_contributor(&contributor2)); - assert!(!coordinator.is_queue_verifier(&verifier)); assert!(!coordinator.is_current_contributor(&contributor1)); assert!(coordinator.is_current_contributor(&contributor2)); - assert!(coordinator.is_current_verifier(&verifier)); assert!(!coordinator.is_finished_contributor(&contributor1)); assert!(!coordinator.is_finished_contributor(&contributor2)); - assert!(!coordinator.is_finished_verifier(&verifier)); // Check that contributor 1 was dropped and coordinator state was updated. let contributors = coordinator.current_contributors(); @@ -301,12 +303,13 @@ fn coordinator_drop_contributor_basic() -> anyhow::Result<()> { // Print the coordinator state. let state = coordinator.state(); - debug!("{}", serde_json::to_string_pretty(&state)?); + debug!("{}", serde_json::to_string_pretty(&state).unwrap()); assert_eq!(1, state.current_round_height()); - debug!("{}", serde_json::to_string_pretty(&coordinator.current_round()?)?); - - Ok(()) + debug!( + "{}", + serde_json::to_string_pretty(&coordinator.current_round().unwrap()).unwrap() + ); } #[test] @@ -339,52 +342,43 @@ fn coordinator_drop_contributor_in_between_two_contributors() -> anyhow::Result< coordinator.add_to_queue(contributor1.clone(), 10)?; coordinator.add_to_queue(contributor2.clone(), 9)?; coordinator.add_to_queue(contributor3.clone(), 8)?; - coordinator.add_to_queue(verifier.clone(), 10)?; assert_eq!(3, coordinator.number_of_queue_contributors()); - assert_eq!(1, coordinator.number_of_queue_verifiers()); // Update the ceremony to round 1. coordinator.update()?; assert_eq!(1, coordinator.current_round_height()?); assert_eq!(0, coordinator.number_of_queue_contributors()); - assert_eq!(0, coordinator.number_of_queue_verifiers()); // Contribute and verify up to the penultimate chunk. for _ in 0..(number_of_chunks - 1) { coordinator.contribute(&contributor1, &contributor_signing_key1, &seed1)?; coordinator.contribute(&contributor2, &contributor_signing_key2, &seed2)?; coordinator.contribute(&contributor3, &contributor_signing_key3, &seed3)?; - coordinator.verify(&verifier, &verifier_signing_key)?; - coordinator.verify(&verifier, &verifier_signing_key)?; - coordinator.verify(&verifier, &verifier_signing_key)?; + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key)?; + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key)?; + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key)?; } assert!(!coordinator.is_queue_contributor(&contributor1)); assert!(!coordinator.is_queue_contributor(&contributor2)); assert!(!coordinator.is_queue_contributor(&contributor3)); - assert!(!coordinator.is_queue_verifier(&verifier)); assert!(coordinator.is_current_contributor(&contributor1)); assert!(coordinator.is_current_contributor(&contributor2)); assert!(coordinator.is_current_contributor(&contributor3)); - assert!(coordinator.is_current_verifier(&verifier)); assert!(!coordinator.is_finished_contributor(&contributor1)); assert!(!coordinator.is_finished_contributor(&contributor2)); assert!(!coordinator.is_finished_contributor(&contributor3)); - assert!(!coordinator.is_finished_verifier(&verifier)); // Drop the contributor from the current round. coordinator.drop_participant(&contributor2)?; assert!(!coordinator.is_queue_contributor(&contributor1)); assert!(!coordinator.is_queue_contributor(&contributor2)); assert!(!coordinator.is_queue_contributor(&contributor3)); - assert!(!coordinator.is_queue_verifier(&verifier)); assert!(coordinator.is_current_contributor(&contributor1)); assert!(!coordinator.is_current_contributor(&contributor2)); assert!(coordinator.is_current_contributor(&contributor3)); - assert!(coordinator.is_current_verifier(&verifier)); assert!(!coordinator.is_finished_contributor(&contributor1)); assert!(!coordinator.is_finished_contributor(&contributor2)); assert!(!coordinator.is_finished_contributor(&contributor3)); - assert!(!coordinator.is_finished_verifier(&verifier)); // Print the coordinator state. let state = coordinator.state(); @@ -468,24 +462,21 @@ fn coordinator_drop_contributor_with_contributors_in_pending_tasks() -> anyhow:: coordinator.add_to_queue(contributor1.clone(), 10)?; coordinator.add_to_queue(contributor2.clone(), 9)?; coordinator.add_to_queue(contributor3.clone(), 8)?; - coordinator.add_to_queue(verifier.clone(), 10)?; assert_eq!(3, coordinator.number_of_queue_contributors()); - assert_eq!(1, coordinator.number_of_queue_verifiers()); // Update the ceremony to round 1. coordinator.update()?; assert_eq!(1, coordinator.current_round_height()?); assert_eq!(0, coordinator.number_of_queue_contributors()); - assert_eq!(0, coordinator.number_of_queue_verifiers()); // Contribute and verify up to 2 before the final chunk. for _ in 0..(number_of_chunks - 2) { coordinator.contribute(&contributor1, &contributor_signing_key1, &seed1)?; coordinator.contribute(&contributor2, &contributor_signing_key2, &seed2)?; coordinator.contribute(&contributor3, &contributor_signing_key3, &seed3)?; - coordinator.verify(&verifier, &verifier_signing_key)?; - coordinator.verify(&verifier, &verifier_signing_key)?; - coordinator.verify(&verifier, &verifier_signing_key)?; + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key)?; + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key)?; + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key)?; } // Lock the next task for contributor 1 and 3. @@ -534,15 +525,12 @@ fn coordinator_drop_contributor_with_contributors_in_pending_tasks() -> anyhow:: assert!(!coordinator.is_queue_contributor(&contributor1)); assert!(!coordinator.is_queue_contributor(&contributor2)); assert!(!coordinator.is_queue_contributor(&contributor3)); - assert!(!coordinator.is_queue_verifier(&verifier)); assert!(coordinator.is_current_contributor(&contributor1)); assert!(!coordinator.is_current_contributor(&contributor2)); assert!(coordinator.is_current_contributor(&contributor3)); - assert!(coordinator.is_current_verifier(&verifier)); assert!(!coordinator.is_finished_contributor(&contributor1)); assert!(!coordinator.is_finished_contributor(&contributor2)); assert!(!coordinator.is_finished_contributor(&contributor3)); - assert!(!coordinator.is_finished_verifier(&verifier)); // Print the coordinator state. let state = coordinator.state(); @@ -627,24 +615,21 @@ fn coordinator_drop_contributor_locked_chunks() -> anyhow::Result<()> { coordinator.add_to_queue(contributor1.clone(), 10)?; coordinator.add_to_queue(contributor2.clone(), 9)?; coordinator.add_to_queue(contributor3.clone(), 8)?; - coordinator.add_to_queue(verifier.clone(), 10)?; assert_eq!(3, coordinator.number_of_queue_contributors()); - assert_eq!(1, coordinator.number_of_queue_verifiers()); // Update the ceremony to round 1. coordinator.update()?; assert_eq!(1, coordinator.current_round_height()?); assert_eq!(0, coordinator.number_of_queue_contributors()); - assert_eq!(0, coordinator.number_of_queue_verifiers()); // Contribute and verify up to 2 before the final chunk. for _ in 0..(number_of_chunks - 2) { coordinator.contribute(&contributor1, &contributor_signing_key1, &seed1)?; coordinator.contribute(&contributor2, &contributor_signing_key2, &seed2)?; coordinator.contribute(&contributor3, &contributor_signing_key3, &seed3)?; - coordinator.verify(&verifier, &verifier_signing_key)?; - coordinator.verify(&verifier, &verifier_signing_key)?; - coordinator.verify(&verifier, &verifier_signing_key)?; + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key)?; + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key)?; + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key)?; } // Lock the next task for contributor 1 and 3. @@ -696,15 +681,12 @@ fn coordinator_drop_contributor_locked_chunks() -> anyhow::Result<()> { assert!(!coordinator.is_queue_contributor(&contributor1)); assert!(!coordinator.is_queue_contributor(&contributor2)); assert!(!coordinator.is_queue_contributor(&contributor3)); - assert!(!coordinator.is_queue_verifier(&verifier)); assert!(coordinator.is_current_contributor(&contributor1)); assert!(!coordinator.is_current_contributor(&contributor2)); assert!(coordinator.is_current_contributor(&contributor3)); - assert!(coordinator.is_current_verifier(&verifier)); assert!(!coordinator.is_finished_contributor(&contributor1)); assert!(!coordinator.is_finished_contributor(&contributor2)); assert!(!coordinator.is_finished_contributor(&contributor3)); - assert!(!coordinator.is_finished_verifier(&verifier)); // Print the coordinator state. let state = coordinator.state(); @@ -790,62 +772,47 @@ fn coordinator_drop_contributor_removes_contributions() -> anyhow::Result<()> { let (verifier, verifier_signing_key) = create_verifier("1"); coordinator.add_to_queue(contributor1.clone(), 10)?; coordinator.add_to_queue(contributor2.clone(), 9)?; - coordinator.add_to_queue(verifier.clone(), 10)?; assert_eq!(2, coordinator.number_of_queue_contributors()); - assert_eq!(1, coordinator.number_of_queue_verifiers()); assert!(coordinator.is_queue_contributor(&contributor1)); assert!(coordinator.is_queue_contributor(&contributor2)); - assert!(coordinator.is_queue_verifier(&verifier)); assert!(!coordinator.is_current_contributor(&contributor1)); assert!(!coordinator.is_current_contributor(&contributor2)); - assert!(!coordinator.is_current_verifier(&verifier)); assert!(!coordinator.is_finished_contributor(&contributor1)); assert!(!coordinator.is_finished_contributor(&contributor2)); - assert!(!coordinator.is_finished_verifier(&verifier)); // Update the ceremony to round 1. coordinator.update()?; assert_eq!(1, coordinator.current_round_height()?); assert_eq!(0, coordinator.number_of_queue_contributors()); - assert_eq!(0, coordinator.number_of_queue_verifiers()); assert!(!coordinator.is_queue_contributor(&contributor1)); assert!(!coordinator.is_queue_contributor(&contributor2)); - assert!(!coordinator.is_queue_verifier(&verifier)); assert!(coordinator.is_current_contributor(&contributor1)); assert!(coordinator.is_current_contributor(&contributor2)); - assert!(coordinator.is_current_verifier(&verifier)); assert!(!coordinator.is_finished_contributor(&contributor1)); assert!(!coordinator.is_finished_contributor(&contributor2)); - assert!(!coordinator.is_finished_verifier(&verifier)); // Contribute and verify up to the penultimate chunk. for _ in 0..(number_of_chunks - 1) { coordinator.contribute(&contributor1, &contributor_signing_key1, &seed1)?; coordinator.contribute(&contributor2, &contributor_signing_key2, &seed2)?; - coordinator.verify(&verifier, &verifier_signing_key)?; - coordinator.verify(&verifier, &verifier_signing_key)?; + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key)?; + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key)?; } assert!(!coordinator.is_queue_contributor(&contributor1)); assert!(!coordinator.is_queue_contributor(&contributor2)); - assert!(!coordinator.is_queue_verifier(&verifier)); assert!(coordinator.is_current_contributor(&contributor1)); assert!(coordinator.is_current_contributor(&contributor2)); - assert!(coordinator.is_current_verifier(&verifier)); assert!(!coordinator.is_finished_contributor(&contributor1)); assert!(!coordinator.is_finished_contributor(&contributor2)); - assert!(!coordinator.is_finished_verifier(&verifier)); // Drop the contributor from the current round. coordinator.drop_participant(&contributor1)?; assert!(!coordinator.is_queue_contributor(&contributor1)); assert!(!coordinator.is_queue_contributor(&contributor2)); - assert!(!coordinator.is_queue_verifier(&verifier)); assert!(!coordinator.is_current_contributor(&contributor1)); assert!(coordinator.is_current_contributor(&contributor2)); - assert!(coordinator.is_current_verifier(&verifier)); assert!(!coordinator.is_finished_contributor(&contributor1)); assert!(!coordinator.is_finished_contributor(&contributor2)); - assert!(!coordinator.is_finished_verifier(&verifier)); // Check that contributor 1 was dropped and coordinator state was updated. let contributors = coordinator.current_contributors(); @@ -906,52 +873,60 @@ fn coordinator_drop_contributor_clear_locks() -> anyhow::Result<()> { let number_of_chunks = environment.number_of_chunks() as usize; // Instantiate a coordinator. - let mut coordinator = Coordinator::new(environment.clone(), Arc::new(Dummy))?; + let mut coordinator = Coordinator::new(environment.clone(), Arc::new(Dummy)).unwrap(); // Initialize the ceremony to round 0. - coordinator.initialize()?; - assert_eq!(0, coordinator.current_round_height()?); + coordinator.initialize().unwrap(); + assert_eq!(0, coordinator.current_round_height().unwrap()); // Add a contributor and verifier to the queue. let (contributor1, contributor_signing_key1, seed1) = create_contributor("1"); let (contributor2, contributor_signing_key2, seed2) = create_contributor("2"); let (contributor3, contributor_signing_key3, seed3) = create_contributor("3"); let (verifier, verifier_signing_key) = create_verifier("1"); - coordinator.add_to_queue(contributor1.clone(), 10)?; - coordinator.add_to_queue(contributor2.clone(), 9)?; - coordinator.add_to_queue(contributor3.clone(), 8)?; - coordinator.add_to_queue(verifier.clone(), 10)?; + coordinator.add_to_queue(contributor1.clone(), 10).unwrap(); + coordinator.add_to_queue(contributor2.clone(), 9).unwrap(); + coordinator.add_to_queue(contributor3.clone(), 8).unwrap(); assert_eq!(3, coordinator.number_of_queue_contributors()); - assert_eq!(1, coordinator.number_of_queue_verifiers()); // Update the ceremony to round 1. - coordinator.update()?; - assert_eq!(1, coordinator.current_round_height()?); + coordinator.update().unwrap(); + assert_eq!(1, coordinator.current_round_height().unwrap()); assert_eq!(0, coordinator.number_of_queue_contributors()); - assert_eq!(0, coordinator.number_of_queue_verifiers()); // Contribute and verify up to 2 before the final chunk. for _ in 0..(number_of_chunks - 2) { - coordinator.contribute(&contributor1, &contributor_signing_key1, &seed1)?; - coordinator.contribute(&contributor2, &contributor_signing_key2, &seed2)?; - coordinator.contribute(&contributor3, &contributor_signing_key3, &seed3)?; - coordinator.verify(&verifier, &verifier_signing_key)?; - coordinator.verify(&verifier, &verifier_signing_key)?; - coordinator.verify(&verifier, &verifier_signing_key)?; + coordinator + .contribute(&contributor1, &contributor_signing_key1, &seed1) + .unwrap(); + coordinator + .contribute(&contributor2, &contributor_signing_key2, &seed2) + .unwrap(); + coordinator + .contribute(&contributor3, &contributor_signing_key3, &seed3) + .unwrap(); + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key).unwrap(); + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key).unwrap(); + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key).unwrap(); } // Contribute up to the final chunk. - coordinator.contribute(&contributor1, &contributor_signing_key1, &seed1)?; - coordinator.contribute(&contributor2, &contributor_signing_key2, &seed2)?; - coordinator.contribute(&contributor3, &contributor_signing_key3, &seed3)?; + coordinator + .contribute(&contributor1, &contributor_signing_key1, &seed1) + .unwrap(); + coordinator + .contribute(&contributor2, &contributor_signing_key2, &seed2) + .unwrap(); + coordinator + .contribute(&contributor3, &contributor_signing_key3, &seed3) + .unwrap(); // Lock the next task for the verifier and contributor 1 and 3. - let (contributor1_locked_chunk_id, _) = coordinator.try_lock(&contributor1)?; - let (verifier_locked_chunk_id, _) = coordinator.try_lock(&verifier)?; + let (contributor1_locked_chunk_id, _) = coordinator.try_lock(&contributor1).unwrap(); // Print the coordinator state. let state = coordinator.state(); - debug!("{}", serde_json::to_string_pretty(&state)?); + debug!("{}", serde_json::to_string_pretty(&state).unwrap()); assert_eq!(1, state.current_round_height()); // Check that coordinator state includes a pending task for contributor 1 and 3. @@ -1002,30 +977,32 @@ fn coordinator_drop_contributor_clear_locks() -> anyhow::Result<()> { } // Lock the next task for contributor 2. - coordinator.try_lock(&contributor2)?; + coordinator.try_lock(&contributor2).unwrap(); // Drop the contributor from the current round. - coordinator.drop_participant(&contributor2)?; + coordinator.drop_participant(&contributor2).unwrap(); assert!(!coordinator.is_queue_contributor(&contributor1)); assert!(!coordinator.is_queue_contributor(&contributor2)); assert!(!coordinator.is_queue_contributor(&contributor3)); - assert!(!coordinator.is_queue_verifier(&verifier)); assert!(coordinator.is_current_contributor(&contributor1)); assert!(!coordinator.is_current_contributor(&contributor2)); assert!(coordinator.is_current_contributor(&contributor3)); - assert!(coordinator.is_current_verifier(&verifier)); assert!(!coordinator.is_finished_contributor(&contributor1)); assert!(!coordinator.is_finished_contributor(&contributor2)); assert!(!coordinator.is_finished_contributor(&contributor3)); - assert!(!coordinator.is_finished_verifier(&verifier)); - // Run `try_contribute` and `try_verify` to remove disposed tasks. - coordinator.try_contribute(&contributor1, contributor1_locked_chunk_id)?; - coordinator.try_verify(&verifier, verifier_locked_chunk_id)?; + // Run `try_contribute` to remove disposed tasks. + coordinator + .try_contribute(&contributor1, contributor1_locked_chunk_id) + .unwrap(); + // No more disposed tasks for verifiers, so this call should return Err + let task = fetch_task_for_verifier(&coordinator).unwrap(); + let result = coordinator.try_verify(&verifier, &task); + assert!(result.is_err()); // Print the coordinator state. let state = coordinator.state(); - debug!("{}", serde_json::to_string_pretty(&state)?); + debug!("{}", serde_json::to_string_pretty(&state).unwrap()); assert_eq!(1, state.current_round_height()); // Check that contributor 2 was dropped and coordinator state was updated. @@ -1072,17 +1049,6 @@ fn coordinator_drop_contributor_clear_locks() -> anyhow::Result<()> { } } - let verifiers = coordinator.current_verifiers(); - assert_eq!(1, verifiers.len()); - for (_, verifier_info) in verifiers { - assert_eq!(0, verifier_info.locked_chunks().len()); - assert_eq!(2, verifier_info.assigned_tasks().len()); - assert_eq!(0, verifier_info.pending_tasks().len()); - assert_eq!(8, verifier_info.completed_tasks().len()); - assert_eq!(0, verifier_info.disposing_tasks().len()); - assert_eq!(11, verifier_info.disposed_tasks().len()); - } - Ok(()) } @@ -1116,7 +1082,6 @@ fn coordinator_drop_contributor_removes_subsequent_contributions() -> anyhow::Re let (verifier, verifier_signing_key) = create_verifier("1"); coordinator.add_to_queue(contributor1.clone(), 10)?; coordinator.add_to_queue(contributor2.clone(), 9)?; - coordinator.add_to_queue(verifier.clone(), 10)?; // Update the ceremony to round 1. coordinator.update()?; @@ -1125,8 +1090,8 @@ fn coordinator_drop_contributor_removes_subsequent_contributions() -> anyhow::Re for _ in 0..number_of_chunks { coordinator.contribute(&contributor1, &contributor_signing_key1, &seed1)?; coordinator.contribute(&contributor2, &contributor_signing_key2, &seed2)?; - coordinator.verify(&verifier, &verifier_signing_key)?; - coordinator.verify(&verifier, &verifier_signing_key)?; + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key)?; + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key)?; } // Check that all contributors completed expected tasks @@ -1200,7 +1165,6 @@ fn coordinator_drop_contributor_and_release_locks() { let verifier_1 = create_verifier_test_details("1"); coordinator.add_to_queue(contributor_1.participant.clone(), 10).unwrap(); coordinator.add_to_queue(contributor_2.participant.clone(), 9).unwrap(); - coordinator.add_to_queue(verifier_1.participant.clone(), 10).unwrap(); // Update the ceremony to round 1. coordinator.update().unwrap(); @@ -1215,27 +1179,24 @@ fn coordinator_drop_contributor_and_release_locks() { for _ in 0..number_of_chunks { replacement_contributor.contribute_to(&mut coordinator).unwrap(); contributor_2.contribute_to(&mut coordinator).unwrap(); - verifier_1.verify(&mut coordinator).unwrap(); - verifier_1.verify(&mut coordinator).unwrap(); + verifier_1.verify_if_available(&mut coordinator).unwrap(); + verifier_1.verify_if_available(&mut coordinator).unwrap(); } // Add some more participants to proceed to the next round let test_contributor_3 = create_contributor_test_details("3"); let test_contributor_4 = create_contributor_test_details("4"); - let verifier_2 = create_verifier_test_details("2"); coordinator .add_to_queue(test_contributor_3.participant.clone(), 10) .unwrap(); coordinator .add_to_queue(test_contributor_4.participant.clone(), 10) .unwrap(); - coordinator.add_to_queue(verifier_2.participant.clone(), 10).unwrap(); // Update the ceremony to round 2. coordinator.update().unwrap(); assert_eq!(2, coordinator.current_round_height().unwrap()); assert_eq!(0, coordinator.number_of_queue_contributors()); - assert_eq!(0, coordinator.number_of_queue_verifiers()); } /// Drops a few contributors and see what happens @@ -1277,7 +1238,6 @@ fn coordinator_drop_several_contributors() { coordinator.add_to_queue(contributor_1.participant.clone(), 10).unwrap(); coordinator.add_to_queue(contributor_2.participant.clone(), 10).unwrap(); coordinator.add_to_queue(contributor_3.participant.clone(), 10).unwrap(); - coordinator.add_to_queue(verifier_1.participant.clone(), 10).unwrap(); // Update the ceremony to round 1. coordinator.update().unwrap(); @@ -1290,9 +1250,9 @@ fn coordinator_drop_several_contributors() { contributor_2.contribute_to(&mut coordinator).unwrap(); contributor_3.contribute_to(&mut coordinator).unwrap(); - verifier_1.verify(&mut coordinator).unwrap(); - verifier_1.verify(&mut coordinator).unwrap(); - verifier_1.verify(&mut coordinator).unwrap(); + verifier_1.verify_if_available(&mut coordinator).unwrap(); + verifier_1.verify_if_available(&mut coordinator).unwrap(); + verifier_1.verify_if_available(&mut coordinator).unwrap(); } { @@ -1321,7 +1281,7 @@ fn coordinator_drop_several_contributors() { Err(CoordinatorError::ParticipantHasNoRemainingTasks) => Ok(true), Err(CoordinatorError::PreviousContributionMissing { current_task: _ }) => Ok(false), Ok(_) => { - verifier.verify(coordinator)?; + verifier.verify_if_available(coordinator)?; Ok(false) } Err(error) => return Err(error.into()), @@ -1349,21 +1309,18 @@ fn coordinator_drop_several_contributors() { // Add some more participants to proceed to the next round let test_contributor_3 = create_contributor_test_details("3"); let test_contributor_4 = create_contributor_test_details("4"); - let verifier_2 = create_verifier_test_details("2"); coordinator .add_to_queue(test_contributor_3.participant.clone(), 10) .unwrap(); coordinator .add_to_queue(test_contributor_4.participant.clone(), 10) .unwrap(); - coordinator.add_to_queue(verifier_2.participant.clone(), 10).unwrap(); // Update the ceremony to round 2. coordinator.update().unwrap(); assert_eq!(2, coordinator.current_round_height().unwrap()); assert_eq!(0, coordinator.number_of_queue_contributors()); - assert_eq!(0, coordinator.number_of_queue_verifiers()); } fn check_round_matches_storage_files(storage: &impl Storage, round: &Round) { @@ -1484,14 +1441,13 @@ fn coordinator_drop_contributor_and_update_verifier_tasks() { let verifier_1 = create_verifier_test_details("1"); coordinator.add_to_queue(contributor_1.participant.clone(), 10).unwrap(); coordinator.add_to_queue(contributor_2.participant.clone(), 9).unwrap(); - coordinator.add_to_queue(verifier_1.participant.clone(), 10).unwrap(); // Update the ceremony to round 1. coordinator.update().unwrap(); contributor_1.contribute_to(&mut coordinator).unwrap(); - verifier_1.verify(&mut coordinator).unwrap(); + verifier_1.verify_if_available(&mut coordinator).unwrap(); coordinator.drop_participant(&contributor_1.participant).unwrap(); @@ -1499,27 +1455,24 @@ fn coordinator_drop_contributor_and_update_verifier_tasks() { for _ in 0..number_of_chunks { replacement_contributor.contribute_to(&mut coordinator).unwrap(); contributor_2.contribute_to(&mut coordinator).unwrap(); - verifier_1.verify(&mut coordinator).unwrap(); - verifier_1.verify(&mut coordinator).unwrap(); + verifier_1.verify_if_available(&mut coordinator).unwrap(); + verifier_1.verify_if_available(&mut coordinator).unwrap(); } // Add some more participants to proceed to the next round let test_contributor_3 = create_contributor_test_details("3"); let test_contributor_4 = create_contributor_test_details("4"); - let verifier_2 = create_verifier_test_details("2"); coordinator .add_to_queue(test_contributor_3.participant.clone(), 10) .unwrap(); coordinator .add_to_queue(test_contributor_4.participant.clone(), 10) .unwrap(); - coordinator.add_to_queue(verifier_2.participant.clone(), 10).unwrap(); // Update the ceremony to round 2. coordinator.update().unwrap(); assert_eq!(2, coordinator.current_round_height().unwrap()); assert_eq!(0, coordinator.number_of_queue_contributors()); - assert_eq!(0, coordinator.number_of_queue_verifiers()); } #[test] @@ -1558,24 +1511,21 @@ fn coordinator_drop_multiple_contributors() -> anyhow::Result<()> { coordinator.add_to_queue(contributor1.clone(), 10)?; coordinator.add_to_queue(contributor2.clone(), 9)?; coordinator.add_to_queue(contributor3.clone(), 8)?; - coordinator.add_to_queue(verifier.clone(), 10)?; assert_eq!(3, coordinator.number_of_queue_contributors()); - assert_eq!(1, coordinator.number_of_queue_verifiers()); // Update the ceremony to round 1. coordinator.update()?; assert_eq!(1, coordinator.current_round_height()?); assert_eq!(0, coordinator.number_of_queue_contributors()); - assert_eq!(0, coordinator.number_of_queue_verifiers()); // Contribute and verify up to 2 before the final chunk. for _ in 0..(number_of_chunks - 2) { coordinator.contribute(&contributor1, &contributor_signing_key1, &seed1)?; coordinator.contribute(&contributor2, &contributor_signing_key2, &seed2)?; coordinator.contribute(&contributor3, &contributor_signing_key3, &seed3)?; - coordinator.verify(&verifier, &verifier_signing_key)?; - coordinator.verify(&verifier, &verifier_signing_key)?; - coordinator.verify(&verifier, &verifier_signing_key)?; + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key)?; + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key)?; + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key)?; } // Aggregate all of the tasks for each of the contributors into a HashSet. @@ -1613,45 +1563,36 @@ fn coordinator_drop_multiple_contributors() -> anyhow::Result<()> { assert!(!coordinator.is_queue_contributor(&contributor1)); assert!(!coordinator.is_queue_contributor(&contributor2)); assert!(!coordinator.is_queue_contributor(&contributor3)); - assert!(!coordinator.is_queue_verifier(&verifier)); assert!(!coordinator.is_current_contributor(&contributor1)); assert!(coordinator.is_current_contributor(&contributor2)); assert!(coordinator.is_current_contributor(&contributor3)); - assert!(coordinator.is_current_verifier(&verifier)); assert!(!coordinator.is_finished_contributor(&contributor1)); assert!(!coordinator.is_finished_contributor(&contributor2)); assert!(!coordinator.is_finished_contributor(&contributor3)); - assert!(!coordinator.is_finished_verifier(&verifier)); // Drop the contributor 2 from the current round. coordinator.drop_participant(&contributor2)?; assert!(!coordinator.is_queue_contributor(&contributor1)); assert!(!coordinator.is_queue_contributor(&contributor2)); assert!(!coordinator.is_queue_contributor(&contributor3)); - assert!(!coordinator.is_queue_verifier(&verifier)); assert!(!coordinator.is_current_contributor(&contributor1)); assert!(!coordinator.is_current_contributor(&contributor2)); assert!(coordinator.is_current_contributor(&contributor3)); - assert!(coordinator.is_current_verifier(&verifier)); assert!(!coordinator.is_finished_contributor(&contributor1)); assert!(!coordinator.is_finished_contributor(&contributor2)); assert!(!coordinator.is_finished_contributor(&contributor3)); - assert!(!coordinator.is_finished_verifier(&verifier)); // Drop the contributor 3 from the current round. coordinator.drop_participant(&contributor3)?; assert!(!coordinator.is_queue_contributor(&contributor1)); assert!(!coordinator.is_queue_contributor(&contributor2)); assert!(!coordinator.is_queue_contributor(&contributor3)); - assert!(!coordinator.is_queue_verifier(&verifier)); assert!(!coordinator.is_current_contributor(&contributor1)); assert!(!coordinator.is_current_contributor(&contributor2)); assert!(!coordinator.is_current_contributor(&contributor3)); - assert!(coordinator.is_current_verifier(&verifier)); assert!(!coordinator.is_finished_contributor(&contributor1)); assert!(!coordinator.is_finished_contributor(&contributor2)); assert!(!coordinator.is_finished_contributor(&contributor3)); - assert!(!coordinator.is_finished_verifier(&verifier)); // Print the coordinator state. let state = coordinator.state(); @@ -1715,15 +1656,12 @@ fn try_lock_blocked() -> anyhow::Result<()> { let (verifier, verifier_signing_key) = create_verifier("1"); coordinator.add_to_queue(contributor1.clone(), 10)?; coordinator.add_to_queue(contributor2.clone(), 10)?; - coordinator.add_to_queue(verifier.clone(), 10)?; assert_eq!(2, coordinator.number_of_queue_contributors()); - assert_eq!(1, coordinator.number_of_queue_verifiers()); // Advance the ceremony from round 0 to round 1. coordinator.update()?; assert_eq!(1, coordinator.current_round_height()?); assert_eq!(0, coordinator.number_of_queue_contributors()); - assert_eq!(0, coordinator.number_of_queue_verifiers()); // Fetch the bucket size. fn bucket_size(number_of_chunks: u64, number_of_contributors: u64) -> u64 { @@ -1786,7 +1724,14 @@ fn try_lock_blocked() -> anyhow::Result<()> { } // Clear all pending verifications, so the locked chunk is released as well. - while coordinator.verify(&verifier, &verifier_signing_key).is_ok() {} + loop { + let pending_tasks = coordinator.get_pending_verifications(); + if let Some(task) = pending_tasks.keys().next().cloned() { + coordinator.verify(&verifier, &verifier_signing_key, &task)?; + } else { + break; + } + } // Now try to lock the next chunk as contributor 1 again. // @@ -1835,7 +1780,6 @@ fn drop_all_contributors_and_complete_round() -> anyhow::Result<()> { let (verifier, verifier_signing_key) = create_verifier("1"); coordinator.add_to_queue(test_contributor_1.participant.clone(), 10)?; coordinator.add_to_queue(test_contributor_2.participant.clone(), 9)?; - coordinator.add_to_queue(verifier.clone(), 10)?; // Update the ceremony to round 1. coordinator.update()?; @@ -1867,23 +1811,20 @@ fn drop_all_contributors_and_complete_round() -> anyhow::Result<()> { for _ in 0..number_of_chunks { replacement_contributor_1.contribute_to(&mut coordinator)?; replacement_contributor_2.contribute_to(&mut coordinator)?; - coordinator.verify(&verifier, &verifier_signing_key)?; - coordinator.verify(&verifier, &verifier_signing_key)?; + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key)?; + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key)?; } // Add some more participants to proceed to the next round let test_contributor_3 = create_contributor_test_details("3"); let test_contributor_4 = create_contributor_test_details("4"); - let (verifier, _verifier_signing_key) = create_verifier("2"); coordinator.add_to_queue(test_contributor_3.participant.clone(), 10)?; coordinator.add_to_queue(test_contributor_4.participant.clone(), 10)?; - coordinator.add_to_queue(verifier, 10)?; // Update the ceremony to round 2. coordinator.update()?; assert_eq!(2, coordinator.current_round_height()?, "Should proceed to the round 2"); assert_eq!(0, coordinator.number_of_queue_contributors()); - assert_eq!(0, coordinator.number_of_queue_verifiers()); Ok(()) } @@ -1915,7 +1856,6 @@ fn drop_contributor_and_reassign_tasks() -> anyhow::Result<()> { let (verifier, verifier_signing_key) = create_verifier("1"); coordinator.add_to_queue(contributor1.clone(), 10)?; coordinator.add_to_queue(contributor2.clone(), 9)?; - coordinator.add_to_queue(verifier.clone(), 10)?; // Update the ceremony to round 1. coordinator.update()?; @@ -1923,8 +1863,8 @@ fn drop_contributor_and_reassign_tasks() -> anyhow::Result<()> { for _ in 0..number_of_chunks { coordinator.contribute(&contributor1, &contributor_signing_key1, &seed1)?; coordinator.contribute(&contributor2, &contributor_signing_key2, &seed2)?; - coordinator.verify(&verifier, &verifier_signing_key)?; - coordinator.verify(&verifier, &verifier_signing_key)?; + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key)?; + verify_task_if_available(&mut coordinator, &verifier, &verifier_signing_key)?; } for (_participant, contributor_info) in coordinator.current_contributors() { @@ -1938,13 +1878,10 @@ fn drop_contributor_and_reassign_tasks() -> anyhow::Result<()> { coordinator.drop_participant(&contributor1)?; assert_eq!(false, coordinator.is_queue_contributor(&contributor1)); assert_eq!(false, coordinator.is_queue_contributor(&contributor2)); - assert_eq!(false, coordinator.is_queue_verifier(&verifier)); assert_eq!(false, coordinator.is_current_contributor(&contributor1)); assert_eq!(true, coordinator.is_current_contributor(&contributor2)); - assert_eq!(true, coordinator.is_current_verifier(&verifier)); assert_eq!(false, coordinator.is_finished_contributor(&contributor1)); assert_eq!(false, coordinator.is_finished_contributor(&contributor2)); - assert_eq!(false, coordinator.is_finished_verifier(&verifier)); for (participant, contributor_info) in coordinator.current_contributors() { if participant == contributor2 { @@ -1964,109 +1901,6 @@ fn drop_contributor_and_reassign_tasks() -> anyhow::Result<()> { Ok(()) } -/// This test assures that, when a verifier is dropped while holding a lock, -/// the verification can still be safely passed over to another verifier. -#[test] -#[serial] -fn drop_verifier() -> anyhow::Result<()> { - let parameters = Parameters::Custom(Settings::new( - ContributionMode::Chunked, - ProvingSystem::Groth16, - CurveKind::Bls12_377, - 6, /* power */ - 16, /* batch_size */ - 16, /* chunk_size */ - )); - let environment = initialize_test_environment(&Testing::from(parameters).into()); - let number_of_chunks = environment.number_of_chunks() as usize; - - // Instantiate a coordinator. - let mut coordinator = Coordinator::new(environment, Arc::new(Dummy))?; - - // Initialize the ceremony to round 0. - coordinator.initialize()?; - assert_eq!(0, coordinator.current_round_height()?); - - // Add a contributor and verifier to the queue. - let (contributor, contributor_signing_key, seed1) = create_contributor("1"); - let (verifier1, verifier_signing_key1) = create_verifier("1"); - let (verifier2, verifier_signing_key2) = create_verifier("2"); - coordinator.add_to_queue(contributor.clone(), 10)?; - coordinator.add_to_queue(verifier1.clone(), 10)?; - coordinator.add_to_queue(verifier2.clone(), 9)?; - - // Update the ceremony to round 1. - coordinator.update()?; - - for _ in 0..number_of_chunks { - coordinator.contribute(&contributor, &contributor_signing_key, &seed1)?; - } - - // Assigning verification tasks is random, so we need to see who got them. - let (verifier1_assigned_num, verifier2_assigned_num) = { - let mut verifier1_assigned_num = 0; - let mut verifier2_assigned_num = 0; - for (participant, contributor_info) in coordinator.current_verifiers() { - match participant == verifier1 { - true => verifier1_assigned_num += contributor_info.assigned_tasks().len(), - false => verifier2_assigned_num += contributor_info.assigned_tasks().len(), - }; - } - - (verifier1_assigned_num, verifier2_assigned_num) - }; - - // Drop the contributor from the current round. - let (drop_verifier, stay_verifier, stay_verifier_signing_key) = - match verifier1_assigned_num >= verifier2_assigned_num { - true => (verifier1, verifier2, verifier_signing_key2), - false => (verifier2, verifier1, verifier_signing_key1), - }; - - coordinator.try_lock(&drop_verifier)?; - - coordinator.drop_participant(&drop_verifier)?; - assert_eq!(false, coordinator.is_queue_contributor(&contributor)); - assert_eq!(false, coordinator.is_queue_verifier(&drop_verifier)); - assert_eq!(false, coordinator.is_queue_verifier(&stay_verifier)); - assert_eq!(true, coordinator.is_current_contributor(&contributor)); - assert_eq!(false, coordinator.is_current_verifier(&drop_verifier)); - assert_eq!(true, coordinator.is_current_verifier(&stay_verifier)); - assert_eq!(false, coordinator.is_finished_contributor(&contributor)); - assert_eq!(false, coordinator.is_finished_verifier(&drop_verifier)); - assert_eq!(false, coordinator.is_finished_verifier(&stay_verifier)); - - for (participant, contributor_info) in coordinator.current_verifiers() { - if participant == stay_verifier { - assert_eq!(contributor_info.completed_tasks().len(), 0); - assert_eq!(contributor_info.assigned_tasks().len(), 8); - assert_eq!(contributor_info.disposing_tasks().len(), 0); - assert_eq!(contributor_info.disposed_tasks().len(), 0); - } - } - - for _ in 0..number_of_chunks { - coordinator.verify(&stay_verifier, &stay_verifier_signing_key)?; - } - - // Add some more participants to proceed to the next round - let test_contributor_3 = create_contributor_test_details("3"); - let test_contributor_4 = create_contributor_test_details("4"); - let verifier_2 = create_verifier_test_details("2"); - coordinator - .add_to_queue(test_contributor_3.participant.clone(), 10) - .unwrap(); - coordinator - .add_to_queue(test_contributor_4.participant.clone(), 10) - .unwrap(); - coordinator.add_to_queue(verifier_2.participant.clone(), 10).unwrap(); - - // Update the ceremony to round 2. - coordinator.update().unwrap(); - - Ok(()) -} - /// Test that participants who have not been seen for longer than the /// [Environment::contributor_timeout_in_minutes] will be dropped. #[test] @@ -2096,10 +1930,8 @@ fn contributor_timeout_drop_test() -> anyhow::Result<()> { coordinator.initialize()?; let (contributor1, _contributor_signing_key1, _seed1) = create_contributor("1"); - let (verifier, _verifier_signing_key) = create_verifier("1"); coordinator.add_to_queue(contributor1.clone(), 10)?; - coordinator.add_to_queue(verifier.clone(), 10)?; // Update the ceremony to round 1. coordinator.update()?; @@ -2159,11 +1991,9 @@ fn contributor_wait_verifier_test() -> anyhow::Result<()> { let (contributor1, contributor_signing_key1, seed1) = create_contributor("1"); let (contributor2, contributor_signing_key2, seed2) = create_contributor("2"); - let (verifier, _verifier_signing_key) = create_verifier("1"); coordinator.add_to_queue(contributor1.clone(), 10)?; coordinator.add_to_queue(contributor2.clone(), 10)?; - coordinator.add_to_queue(verifier.clone(), 10)?; // Update the ceremony to round 1. coordinator.update()?; @@ -2233,10 +2063,8 @@ fn participant_lock_timeout_drop_test() -> anyhow::Result<()> { coordinator.initialize()?; let (contributor1, contributor_signing_key1, seed1) = create_contributor("1"); - let (verifier, _verifier_signing_key) = create_verifier("1"); coordinator.add_to_queue(contributor1.clone(), 10)?; - coordinator.add_to_queue(verifier.clone(), 10)?; // Update the ceremony to round 1. coordinator.update()?; @@ -2246,7 +2074,6 @@ fn participant_lock_timeout_drop_test() -> anyhow::Result<()> { coordinator.contribute(&contributor1, &contributor_signing_key1, &seed1)?; - coordinator.try_lock(&verifier)?; coordinator.try_lock(&contributor1)?; // increment the time a little bit (but not enough for the @@ -2264,10 +2091,9 @@ fn participant_lock_timeout_drop_test() -> anyhow::Result<()> { // Check that replacement contributor has been added, and that the // contributor1 has been dropped. assert_eq!(1, coordinator.current_contributors().len()); - assert_eq!(2, coordinator.dropped_participants().len()); + assert_eq!(1, coordinator.dropped_participants().len()); assert!(coordinator.current_contributors().get(0).unwrap().0 != contributor1); assert_eq!(&contributor1, coordinator.dropped_participants().get(0).unwrap().id()); - assert_eq!(&verifier, coordinator.dropped_participants().get(1).unwrap().id()); Ok(()) } From c6d44f8e06d88ceb0ae769976a63463ae402ca33 Mon Sep 17 00:00:00 2001 From: ibaryshnikov Date: Mon, 30 Aug 2021 23:09:30 +0300 Subject: [PATCH 2/2] updated phase1-coordinator to match new verifier logic, updated setup1-verifier implementation --- Cargo.lock | 28 -- phase1-coordinator/src/coordinator.rs | 32 +- phase1-coordinator/src/objects/round.rs | 107 ++++++- setup1-contributor/Cargo.toml | 2 +- setup1-shared/Cargo.toml | 3 +- setup1-shared/src/structures.rs | 1 + setup1-verifier/Cargo.toml | 7 +- setup1-verifier/src/coordinator_requests.rs | 147 +-------- setup1-verifier/src/errors.rs | 9 - setup1-verifier/src/main.rs | 15 +- setup1-verifier/src/objects.rs | 44 --- setup1-verifier/src/tasks.rs | 256 ---------------- setup1-verifier/src/utils/logger.rs | 12 +- setup1-verifier/src/utils/mod.rs | 22 +- setup1-verifier/src/verifier.rs | 323 ++++++++------------ 15 files changed, 284 insertions(+), 724 deletions(-) delete mode 100644 setup1-verifier/src/objects.rs delete mode 100644 setup1-verifier/src/tasks.rs diff --git a/Cargo.lock b/Cargo.lock index 10a560b9..de0ecf3e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -585,16 +585,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "ctrlc" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "377c9b002a72a0b2c1a18c62e2f3864bdfea4a015e3683a96e24aa45dd6c02d1" -dependencies = [ - "nix", - "winapi", -] - [[package]] name = "curl" version = "0.4.38" @@ -1596,19 +1586,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab250442c86f1850815b5d268639dff018c0627022bc1940eb2d642ca1ce12f0" -[[package]] -name = "nix" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7555d6c7164cc913be1ce7f95cbecdabda61eb2ccd89008524af306fb7f5031" -dependencies = [ - "bitflags", - "cc", - "cfg-if 1.0.0", - "libc", - "memoffset", -] - [[package]] name = "nom" version = "6.2.1" @@ -2817,12 +2794,8 @@ name = "setup1-verifier" version = "0.4.0" dependencies = [ "anyhow", - "chrono", - "ctrlc", - "futures-util", "hex", "http", - "lazy_static", "phase1", "phase1-cli", "phase1-coordinator", @@ -2831,7 +2804,6 @@ dependencies = [ "reqwest", "serde", "serde_json", - "serial_test", "setup-utils", "setup1-shared", "snarkvm-algorithms", diff --git a/phase1-coordinator/src/coordinator.rs b/phase1-coordinator/src/coordinator.rs index 88031055..c6d9d26f 100644 --- a/phase1-coordinator/src/coordinator.rs +++ b/phase1-coordinator/src/coordinator.rs @@ -934,6 +934,34 @@ where } } + /// Returns previous contribution, current contribution and next contribution paths + pub fn get_chunk_locators_for_verifier( + &self, + participant: &Participant, + chunk_id: u64, + contribution_id: u64, + ) -> Result { + if !participant.is_verifier() { + return Err(CoordinatorError::ExpectedVerifier); + } + let round = Self::load_current_round(&self.storage)?; + round.get_chunk_locators_for_verifier(&self.storage, participant, chunk_id, contribution_id) + } + + /// Initialize the files for the next challenge + pub fn initialize_verifier_response_files( + &mut self, + participant: &Participant, + chunk_id: u64, + locators: &LockedLocators, + ) -> Result<(), CoordinatorError> { + if !participant.is_verifier() { + return Err(CoordinatorError::ExpectedVerifier); + } + let round = Self::load_current_round(&self.storage)?; + round.initialize_verifier_response_files(&self.environment, &mut self.storage, participant, chunk_id, locators) + } + /// /// Attempts to add a contribution for the given chunk ID from the given participant. /// @@ -1154,7 +1182,9 @@ where }; // Remove the invalid next challenge file from storage. - self.storage.remove(&next_challenge)?; + if self.storage.exists(&next_challenge) { + self.storage.remove(&next_challenge)?; + } error!("{}", error); Err(error) diff --git a/phase1-coordinator/src/objects/round.rs b/phase1-coordinator/src/objects/round.rs index 129f3c87..740c56dc 100644 --- a/phase1-coordinator/src/objects/round.rs +++ b/phase1-coordinator/src/objects/round.rs @@ -629,17 +629,7 @@ impl Round { )?; } Participant::Verifier(_) => { - // Initialize the next challenge file. - storage.initialize( - Locator::ContributionFile(locked_locators.next_contribution.clone()), - Object::contribution_file_size(environment, chunk_id, true), - )?; - - // Initialize the contribution file signature. - storage.initialize( - Locator::ContributionFileSignature(locked_locators.next_contribution_file_signature.clone()), - Object::contribution_file_signature_size(true), - )?; + return Err(CoordinatorError::ExpectedContributor); } }; @@ -647,6 +637,101 @@ impl Round { Ok(locked_locators) } + /// Initialize the files for the next challenge + pub fn initialize_verifier_response_files( + &self, + environment: &Environment, + storage: &mut impl Storage, + participant: &Participant, + chunk_id: u64, + locators: &LockedLocators, + ) -> Result<(), CoordinatorError> { + if !participant.is_verifier() { + return Err(CoordinatorError::ExpectedVerifier); + } + // Initialize the next challenge file. + storage.initialize( + Locator::ContributionFile(locators.next_contribution.clone()), + Object::contribution_file_size(environment, chunk_id, true), + )?; + + // Initialize the contribution file signature. + storage.initialize( + Locator::ContributionFileSignature(locators.next_contribution_file_signature.clone()), + Object::contribution_file_signature_size(true), + )?; + + Ok(()) + } + + /// Returns previous contribution, current contribution and next contribution paths + pub(crate) fn get_chunk_locators_for_verifier( + &self, + storage: &impl Storage, + participant: &Participant, + chunk_id: u64, + contribution_id: u64, + ) -> Result { + if !participant.is_verifier() { + return Err(CoordinatorError::ExpectedVerifier); + } + + // Fetch the current round height. + let current_round_height = self.round_height(); + // Fetch the chunk corresponding to the given chunk ID. + let chunk = self.chunk(chunk_id)?; + // Fetch the current contribution ID. + let current_contribution_id = chunk.current_contribution_id(); + + if current_contribution_id == 0 { + return Err(CoordinatorError::ChunkCannotLockZeroContributions { chunk_id }); + } + + if current_contribution_id != contribution_id { + tracing::error!( + "Error getting locators for chunk {}, current contribution {}, requested contribution {}", + chunk_id, + current_contribution_id, + contribution_id, + ); + return Err(CoordinatorError::ContributionIdMismatch); + } + + // Fetch the previous contribution locator. + let previous_contribution = + ContributionLocator::new(current_round_height, chunk_id, current_contribution_id - 1, true); + + // This call enforces a strict check that the + // current contribution locator exist and + // has not been verified yet. + let current_contribution = self.current_contribution_locator(storage, chunk_id, false)?; + + tracing::debug!("Obtained response locator for a verifier: {:?}", current_contribution); + + // Fetch whether this is the final contribution of the specified chunk. + let is_final_contribution = chunk.only_contributions_complete(self.expected_number_of_contributions()); + // Fetch the next contribution locator and its contribution file signature locator. + let (next_contribution, next_contribution_file_signature) = match is_final_contribution { + // This is the final contribution in the chunk. + true => ( + ContributionLocator::new(current_round_height + 1, chunk_id, 0, true), + ContributionSignatureLocator::new(current_round_height + 1, chunk_id, 0, true), + ), + // This is a typical contribution in the chunk. + false => ( + ContributionLocator::new(current_round_height, chunk_id, current_contribution_id, true), + ContributionSignatureLocator::new(current_round_height, chunk_id, current_contribution_id, true), + ), + }; + + Ok(LockedLocators { + previous_contribution, + current_contribution, + next_contribution, + next_contribution_file_signature, + }) + } + /// /// Updates the contribution corresponding to a given chunk ID and /// contribution ID as verified. diff --git a/setup1-contributor/Cargo.toml b/setup1-contributor/Cargo.toml index da55bceb..1e1c1dcb 100644 --- a/setup1-contributor/Cargo.toml +++ b/setup1-contributor/Cargo.toml @@ -11,7 +11,7 @@ edition = "2018" phase1 = { path = "../phase1", features = ["parallel"] } phase1-cli = { path = "../phase1-cli", features = ["parallel"] } phase1-coordinator = { path = "../phase1-coordinator", features = ["operator", "parallel"]} -setup1-shared = { version = "0.1", path = "../setup1-shared" } +setup1-shared = { version = "0.1", path = "../setup1-shared", features = ["twitter"] } setup-utils = { path = "../setup-utils", features = ["parallel"] } snarkvm-dpc = { git = "https://github.com/AleoHQ/snarkVM", rev = "fc997c" } diff --git a/setup1-shared/Cargo.toml b/setup1-shared/Cargo.toml index 09d93377..4c24fbf6 100644 --- a/setup1-shared/Cargo.toml +++ b/setup1-shared/Cargo.toml @@ -7,9 +7,10 @@ edition = "2018" [features] default = [] async_message = ["tokio"] +twitter = ["egg-mode"] [dependencies] -egg-mode = "0.16" +egg-mode = { version = "0.16", optional = true } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" tokio = { version = "1.9", features = ["io-util"], optional = true } diff --git a/setup1-shared/src/structures.rs b/setup1-shared/src/structures.rs index 1e26edef..3fbddd0f 100644 --- a/setup1-shared/src/structures.rs +++ b/setup1-shared/src/structures.rs @@ -49,6 +49,7 @@ impl PublicSettings { /// on a contributor's behalf by the coordinator. #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] +#[cfg(feature = "twitter")] pub struct TwitterInfo { pub request_token: egg_mode::KeyPair, pub pin: String, diff --git a/setup1-verifier/Cargo.toml b/setup1-verifier/Cargo.toml index 0be24c08..8b135a4d 100644 --- a/setup1-verifier/Cargo.toml +++ b/setup1-verifier/Cargo.toml @@ -21,9 +21,6 @@ snarkvm-curves = { git = "https://github.com/AleoHQ/snarkVM.git", rev = "fc997c" snarkvm-utilities = { git = "https://github.com/AleoHQ/snarkVM", rev = "fc997c" } anyhow = { version = "1.0.32" } -chrono = { version = "0.4", features = ["serde"] } -ctrlc = { version = "3.1.7" } -futures-util = { version = "0.3.5" } hex = { version = "0.4.2" } http = "0.2" rand = { version = "0.8" } @@ -32,12 +29,10 @@ serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0" } structopt = "0.3.21" thiserror = { version = "1.0" } -tokio = { version = "1.9", features = ["macros", "rt-multi-thread", "signal"] } +tokio = { version = "1.9", features = ["macros", "rt-multi-thread"] } tracing = { version = "0.1.26" } tracing-subscriber = { version = "0.2" } url = "2.2.2" [dev-dependencies] -lazy_static = { version = "1.4.0" } rand_xorshift = { version = "0.3" } -serial_test = { version = "0.5" } diff --git a/setup1-verifier/src/coordinator_requests.rs b/setup1-verifier/src/coordinator_requests.rs index c2117d43..12007c2f 100644 --- a/setup1-verifier/src/coordinator_requests.rs +++ b/setup1-verifier/src/coordinator_requests.rs @@ -1,150 +1,9 @@ -use crate::{errors::VerifierError, objects::LockResponse, utils::AleoAuthentication, verifier::Verifier}; -use snarkvm_dpc::{parameters::testnet2::Testnet2Parameters, Address}; +use crate::{errors::VerifierError, utils::AleoAuthentication, verifier::Verifier}; use reqwest::Client; -use tracing::{debug, error, info}; +use tracing::{error, info}; impl Verifier { - /// - /// Attempts to join the coordinator queue - /// - /// On success, this function returns `true`. - /// - /// On failure, this function returns a `VerifierError`. - /// - pub(crate) async fn join_queue(&self) -> Result { - let coordinator_api_url = &self.coordinator_api_url; - - let aleo_address = Address::::from_view_key(&self.view_key)?.to_string(); - - let method = "post"; - let path = "/v1/queue/verifier/join"; - - let authentication = AleoAuthentication::authenticate(&self.view_key, &method, &path)?; - - info!("Attempting to join as verifier join the queue as {}", aleo_address); - - match Client::new() - .post(coordinator_api_url.join(path).expect("Should create a path")) - .header(http::header::AUTHORIZATION, authentication.to_string()) - .header(http::header::CONTENT_LENGTH, 0) - .send() - .await - { - Ok(response) => { - if !response.status().is_success() { - error!("Verifier failed to join the queue"); - return Err(VerifierError::FailedToJoinQueue); - } - - // Parse the lock response - let queue_response = serde_json::from_slice::(&*response.bytes().await?)?; - info!("{} joined the queue with status {}", aleo_address, queue_response); - Ok(queue_response) - } - Err(_) => { - error!("Request ({}) to join the queue failed", path); - return Err(VerifierError::FailedRequest( - path.to_string(), - coordinator_api_url.to_string(), - )); - } - } - } - - /// - /// Attempts to acquire the lock on a chunk. - /// - /// On success, this function returns the `LockResponse`. - /// - /// On failure, this function returns a `VerifierError`. - /// - pub(crate) async fn lock_chunk(&self) -> Result { - let coordinator_api_url = &self.coordinator_api_url; - let method = "post"; - let path = "/v1/verifier/try_lock"; - - let authentication = AleoAuthentication::authenticate(&self.view_key, &method, &path)?; - - info!("Verifier attempting to lock a chunk"); - - match Client::new() - .post(coordinator_api_url.join(path).expect("Should create a path")) - .header(http::header::AUTHORIZATION, authentication.to_string()) - .header(http::header::CONTENT_LENGTH, 0) - .send() - .await - { - Ok(response) => { - if !response.status().is_success() { - error!("Verifier failed to acquire a lock on a chunk"); - return Err(VerifierError::FailedLock); - } - - // Parse the lock response - let json_response = response.bytes().await?; - let lock_response = serde_json::from_slice::(&*json_response)?; - debug!("Decoded verifier lock response: {:#?}", lock_response); - info!("Verifier locked chunk {}", lock_response.chunk_id); - - Ok(lock_response) - } - Err(_) => { - error!("Request ({}) to lock a chunk failed", path); - return Err(VerifierError::FailedRequest( - path.to_string(), - coordinator_api_url.to_string(), - )); - } - } - } - - /// - /// Attempts to run verification in the current round for a given `chunk_id` - /// - /// This assumes that a valid challenge file has already been uploaded to the - /// coordinator at the given `verified_locator`. - /// - /// On success, the coordinator returns an { "status": "ok" } response. - /// - /// On failure, this function returns a `VerifierError`. - /// - pub(crate) async fn verify_contribution(&self, chunk_id: u64) -> Result { - let coordinator_api_url = &self.coordinator_api_url; - let method = "post"; - let path = format!("/v1/verifier/try_verify/{}", chunk_id); - - info!("Verifier running verification of a contribution at chunk {}", chunk_id); - - let signature_path = format!("{}", path.replace("./", "")); - let authentication = AleoAuthentication::authenticate(&self.view_key, &method, &signature_path)?; - match Client::new() - .post(coordinator_api_url.join(&path).expect("Should create a path")) - .header(http::header::AUTHORIZATION, authentication.to_string()) - .header(http::header::CONTENT_LENGTH, 0) - .send() - .await - { - Ok(response) => { - if !response.status().is_success() { - error!("Failed to verify the challenge at chunk {}", chunk_id); - return Err(VerifierError::FailedVerification(chunk_id)); - } - - info!("Verifier successfully verified a contribution on chunk {}", chunk_id); - - Ok(response.text().await?) - } - Err(_) => { - error!("Request ({}) to verify a contribution failed.", path); - return Err(VerifierError::FailedRequest( - path.to_string(), - coordinator_api_url.to_string(), - )); - } - } - } - /// /// Attempts to download the unverified response file from the coordinator at /// a given `response_locator` @@ -206,7 +65,7 @@ impl Verifier { ) -> Result, VerifierError> { let coordinator_api_url = &self.coordinator_api_url; let method = "get"; - let path = format!("/v1/download/challenge/{}/{}", chunk_id, contribution_id); + let path = format!("/v1/download/verifier_challenge/{}/{}", chunk_id, contribution_id); info!("Verifier downloading a challenge file at {} ", path); diff --git a/setup1-verifier/src/errors.rs b/setup1-verifier/src/errors.rs index dbbf5ce3..88464e50 100644 --- a/setup1-verifier/src/errors.rs +++ b/setup1-verifier/src/errors.rs @@ -12,9 +12,6 @@ pub enum VerifierError { #[error("Failed to download a challenge at {}", _0)] FailedChallengeDownload(String), - #[error("Failed to lock a chunk")] - FailedLock, - #[error("Request {} sent to {} errored", _0, _1)] FailedRequest(String, String), @@ -24,12 +21,6 @@ pub enum VerifierError { #[error("Failed to upload a new challenge file to {}", _0)] FailedChallengeUpload(String), - #[error("The coordinator failed to verify the uploaded challenge file at chunk {}", _0)] - FailedVerification(u64), - - #[error("Failed to join the queue")] - FailedToJoinQueue, - #[error("Mismatched response hashes")] MismatchedResponseHashes, diff --git a/setup1-verifier/src/main.rs b/setup1-verifier/src/main.rs index ea6f1ee7..c32d685d 100644 --- a/setup1-verifier/src/main.rs +++ b/setup1-verifier/src/main.rs @@ -9,8 +9,6 @@ use url::Url; mod coordinator_requests; mod errors; -mod objects; -mod tasks; mod utils; mod verifier; @@ -77,23 +75,14 @@ async fn main() { SetupKind::Universal => universal(), }; - let storage_prefix = format!("{:?}", public_settings.setup).to_lowercase(); - let tasks_storage_path = format!("{}_verifier.tasks", storage_prefix); - let raw_view_key = std::fs::read_to_string(options.view_key).expect("View key not found"); let view_key = ViewKey::::from_str(&raw_view_key).expect("Invalid view key"); let address = Address::from_view_key(&view_key).expect("Address not derived correctly"); // Initialize the verifier info!("Initializing verifier..."); - let verifier = Verifier::new( - options.api_url.clone(), - view_key, - address, - environment, - tasks_storage_path, - ) - .expect("Failed to initialize verifier"); + let verifier = + Verifier::new(options.api_url.clone(), view_key, address, environment).expect("Failed to initialize verifier"); verifier.start_verifier().await; } diff --git a/setup1-verifier/src/objects.rs b/setup1-verifier/src/objects.rs deleted file mode 100644 index f5d4e136..00000000 --- a/setup1-verifier/src/objects.rs +++ /dev/null @@ -1,44 +0,0 @@ -use serde::{Deserialize, Serialize}; - -/// -/// This lock response bundles the data required for the verifier -/// to perform a valid verification. -/// -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] -pub struct LockResponse { - /// The chunk id - #[serde(alias = "chunkId")] - pub chunk_id: u64, - - /// The contribution id - #[serde(alias = "contributionId")] - pub contribution_id: u64, - - /// Indicator if the chunk was locked - pub locked: bool, - - /// The participant id related to the lock - #[serde(alias = "participantID")] - pub participant_id: String, - - #[serde(alias = "challengeLocator")] - pub challenge_locator: String, - - #[serde(alias = "challengeChunkId")] - pub challenge_chunk_id: u64, - - #[serde(alias = "challengeContributionId")] - pub challenge_contribution_id: u64, - - #[serde(alias = "responseLocator")] - pub response_locator: String, - - #[serde(alias = "nextChallengeLocator")] - pub next_challenge_locator: String, - - #[serde(alias = "nextChallengeChunkId")] - pub next_challenge_chunk_id: u64, - - #[serde(alias = "nextChallengeContributionId")] - pub next_challenge_contribution_id: u64, -} diff --git a/setup1-verifier/src/tasks.rs b/setup1-verifier/src/tasks.rs deleted file mode 100644 index 7815de06..00000000 --- a/setup1-verifier/src/tasks.rs +++ /dev/null @@ -1,256 +0,0 @@ -use std::collections::VecDeque; - -use serde::{Deserialize, Serialize}; -use tracing::warn; - -use crate::{ - objects::LockResponse, - utils::{read_from_file, write_to_file}, -}; - -/// -/// The list of chunks that the verifier needs to verify. -/// -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] -pub struct Tasks { - /// Ordered queue of lock response tasks. - pub(crate) queue: VecDeque, -} - -impl Tasks { - /// - /// Returns the list of assigned tasks. - /// - pub fn get_tasks(&self) -> &VecDeque { - &self.queue - } - - /// - /// Returns `true` if there are no tasks in the queue. - /// Otherwise, return `false` - /// - pub fn is_empty(&self) -> bool { - self.queue.is_empty() - } - - /// - /// Returns the first task in the list if there are tasks in the queue. - /// This task is then added to the back of the queue. - /// - pub fn next_task(&mut self) -> Option { - let task = self.queue.pop_front(); - - if let Some(task) = &task { - self.add_task(task.clone()); - } - - task - } - - /// - /// Add a task to the queue. - /// - pub fn add_task(&mut self, task: LockResponse) { - self.queue.push_back(task); - } - - /// - /// Removes a task from the queue if it exists. - /// - pub fn remove_task(&mut self, task: &LockResponse) { - self.queue.retain(|t| t != task); - } - - /// - /// Read tasks from a stored file. Returns a list of empty tasks if - /// the file could not be read. - /// - pub fn load(file_path: &str) -> Self { - // Read tasks from a file - match read_from_file(file_path) { - Ok(file) => match serde_json::from_slice(&file) { - Ok(tasks) => tasks, - Err(err) => { - warn!("Failed to read tasks from {} {}", file_path, err); - Tasks::default() - } - }, - Err(_) => Tasks::default(), - } - } - - /// - /// Writes the current tasks to disk if there are tasks in the queue. - /// - pub fn store(&self, file_path: &str) -> anyhow::Result<()> { - if !self.is_empty() { - // Write tasks to disk. - let task_bytes = serde_json::to_vec_pretty(&self)?; - write_to_file(file_path, task_bytes); - } - - Ok(()) - } -} - -impl std::default::Default for Tasks { - fn default() -> Self { - Self { queue: VecDeque::new() } - } -} - -#[cfg(test)] -mod tests { - use std::path::Path; - - use lazy_static::lazy_static; - use serial_test::serial; - - use super::*; - use crate::utils::remove_file_if_exists; - - const TEST_TASK_FILE: &str = "TEST.tasks"; - - lazy_static! { - pub static ref TASK_1: LockResponse = LockResponse { - chunk_id: 1, - contribution_id: 0, - locked: true, - participant_id: "test_participant_1".to_string(), - challenge_locator: "test_challenge_locator_1".to_string(), - challenge_chunk_id: 0, - challenge_contribution_id: 0, - response_locator: "test_response_locator_1".to_string(), - next_challenge_locator: "test_next_challenge_locator_1".to_string(), - next_challenge_chunk_id: 2, - next_challenge_contribution_id: 0, - }; - pub static ref TASK_2: LockResponse = LockResponse { - chunk_id: 2, - contribution_id: 0, - locked: true, - participant_id: "test_participant_2".to_string(), - challenge_locator: "test_challenge_locator_2".to_string(), - challenge_chunk_id: 1, - challenge_contribution_id: 0, - response_locator: "test_response_locator_2".to_string(), - next_challenge_locator: "test_next_challenge_locator_2".to_string(), - next_challenge_chunk_id: 3, - next_challenge_contribution_id: 0, - }; - pub static ref TASK_3: LockResponse = LockResponse { - chunk_id: 3, - contribution_id: 0, - locked: true, - participant_id: "test_participant_3".to_string(), - challenge_locator: "test_challenge_locator_3".to_string(), - challenge_chunk_id: 2, - challenge_contribution_id: 0, - response_locator: "test_response_locator_3".to_string(), - next_challenge_locator: "test_next_challenge_locator_3".to_string(), - next_challenge_chunk_id: 4, - next_challenge_contribution_id: 0, - }; - } - - #[test] - #[serial] - pub fn test_assign_tasks() { - let mut tasks = Tasks::default(); - assert_eq!(0, tasks.get_tasks().len()); - - tasks.add_task(TASK_1.clone()); - assert_eq!(1, tasks.get_tasks().len()); - assert!(tasks.get_tasks().contains(&TASK_1)); - - tasks.add_task(TASK_2.clone()); - assert_eq!(2, tasks.get_tasks().len()); - assert!(tasks.get_tasks().contains(&TASK_2)); - - tasks.add_task(TASK_3.clone()); - assert_eq!(3, tasks.get_tasks().len()); - assert!(tasks.get_tasks().contains(&TASK_3)); - } - - #[test] - #[serial] - pub fn test_next_tasks() { - let mut tasks = Tasks::default(); - - tasks.add_task(TASK_1.clone()); - tasks.add_task(TASK_2.clone()); - tasks.add_task(TASK_3.clone()); - - assert_eq!(&*TASK_1, &tasks.next_task().unwrap()); - assert_eq!(&*TASK_2, &tasks.next_task().unwrap()); - assert_eq!(&*TASK_3, &tasks.next_task().unwrap()); - - // Check that the tasks have looped. - - assert_eq!(&*TASK_1, &tasks.next_task().unwrap()); - assert_eq!(&*TASK_2, &tasks.next_task().unwrap()); - assert_eq!(&*TASK_3, &tasks.next_task().unwrap()); - } - - #[test] - #[serial] - pub fn test_remove_tasks() { - let mut tasks = Tasks::default(); - - tasks.add_task(TASK_1.clone()); - tasks.add_task(TASK_2.clone()); - tasks.add_task(TASK_3.clone()); - - tasks.remove_task(&TASK_1); - assert_eq!(2, tasks.get_tasks().len()); - assert!(!tasks.get_tasks().contains(&TASK_1)); - - tasks.remove_task(&TASK_2); - assert_eq!(1, tasks.get_tasks().len()); - assert!(!tasks.get_tasks().contains(&TASK_2)); - - tasks.remove_task(&TASK_3); - assert_eq!(0, tasks.get_tasks().len()); - assert!(!tasks.get_tasks().contains(&TASK_3)); - } - - #[test] - #[serial] - pub fn test_store_tasks() { - remove_file_if_exists(TEST_TASK_FILE); - let mut tasks = Tasks::default(); - - tasks.add_task(TASK_1.clone()); - tasks.add_task(TASK_2.clone()); - tasks.add_task(TASK_3.clone()); - - let path = Path::new(TEST_TASK_FILE); - - assert!(!path.exists()); - assert!(tasks.store(TEST_TASK_FILE).is_ok()); - assert!(path.exists()); - - remove_file_if_exists(TEST_TASK_FILE); - } - - #[test] - #[serial] - pub fn test_load_tasks() { - let mut tasks = Tasks::default(); - - tasks.add_task(TASK_1.clone()); - tasks.add_task(TASK_2.clone()); - - assert!(tasks.store(TEST_TASK_FILE).is_ok()); - let loaded_tasks = Tasks::load(TEST_TASK_FILE); - assert_eq!(tasks, loaded_tasks); - - tasks.add_task(TASK_3.clone()); - - assert!(tasks.store(TEST_TASK_FILE).is_ok()); - let loaded_tasks = Tasks::load(TEST_TASK_FILE); - assert_eq!(tasks, loaded_tasks); - - remove_file_if_exists(TEST_TASK_FILE); - } -} diff --git a/setup1-verifier/src/utils/logger.rs b/setup1-verifier/src/utils/logger.rs index 34cd7b73..7cb1374f 100644 --- a/setup1-verifier/src/utils/logger.rs +++ b/setup1-verifier/src/utils/logger.rs @@ -1,10 +1,14 @@ -use tracing_subscriber::{EnvFilter, FmtSubscriber}; +use tracing_subscriber::{filter::Directive, EnvFilter, FmtSubscriber}; + +fn directive(text: &str) -> Directive { + text.parse() + .unwrap_or_else(|_| panic!("Failed to parse log filter directive: {}", text)) +} /// Initialize logger from RUST_LOG environment variable pub fn init_logger() { - let subscriber = FmtSubscriber::builder() - .with_env_filter(EnvFilter::from_default_env()) - .finish(); + let filter = EnvFilter::from_default_env().add_directive(directive("hyper=off")); + let subscriber = FmtSubscriber::builder().with_env_filter(filter).finish(); tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed"); } diff --git a/setup1-verifier/src/utils/mod.rs b/setup1-verifier/src/utils/mod.rs index 646b2a34..96c233f3 100644 --- a/setup1-verifier/src/utils/mod.rs +++ b/setup1-verifier/src/utils/mod.rs @@ -4,7 +4,7 @@ pub use authentication::*; pub mod logger; pub use logger::*; -use std::{fs, io::Read, path::Path}; +use std::{fs, path::Path}; use tracing::{error, trace}; /// @@ -22,16 +22,16 @@ pub fn write_to_file(locator: &str, file_bytes: Vec) { } } -/// -/// This function reads the bytes from a file at a given path. -/// -pub fn read_from_file(locator: &str) -> anyhow::Result> { - let mut buffer = Vec::new(); - let mut file = fs::File::open(locator)?; - file.read_to_end(&mut buffer)?; - - Ok(buffer) -} +// /// +// /// This function reads the bytes from a file at a given path. +// /// +// pub fn read_from_file(locator: &str) -> anyhow::Result> { +// let mut buffer = Vec::new(); +// let mut file = fs::File::open(locator)?; +// file.read_to_end(&mut buffer)?; +// +// Ok(buffer) +// } /// /// This function creates the `locator` path's parent directories if it diff --git a/setup1-verifier/src/verifier.rs b/setup1-verifier/src/verifier.rs index cbf2949d..884539e7 100644 --- a/setup1-verifier/src/verifier.rs +++ b/setup1-verifier/src/verifier.rs @@ -1,8 +1,7 @@ -use crate::{ - errors::VerifierError, - objects::LockResponse, - tasks::Tasks, - utils::{authentication::AleoAuthentication, create_parent_directory, remove_file_if_exists, write_to_file}, +use std::{ + fs, + str::FromStr, + time::{Duration, Instant}, }; use phase1::helpers::CurveKind; @@ -17,28 +16,39 @@ use setup_utils::calculate_hash; use snarkvm_curves::{bls12_377::Bls12_377, bw6_761::BW6_761}; use snarkvm_dpc::{parameters::testnet2::Testnet2Parameters, Address, ViewKey}; -use chrono::Utc; -use std::{fs, str::FromStr, sync::Arc, thread::sleep, time::Duration}; -use tokio::{signal, sync::Mutex}; -use tracing::{debug, error, info, trace, warn}; +use serde::{Deserialize, Serialize}; +use tracing::{debug, error, info}; use url::Url; +use crate::{ + errors::VerifierError, + utils::{authentication::AleoAuthentication, create_parent_directory, remove_file_if_exists, write_to_file}, +}; + +const NO_TASKS_DELAY: Duration = Duration::from_secs(5); +const UPLOAD_TASK_ERROR_DELAY: Duration = Duration::from_secs(5); + /// Returns a pretty print of the given hash bytes for logging. -macro_rules! pretty_hash { - ($hash:expr) => {{ - let mut output = format!("\n\n"); - for line in $hash.chunks(16) { - output += "\t"; - for section in line.chunks(4) { - for b in section { - output += &format!("{:02x}", b); - } - output += " "; +fn pretty_hash(input: &[u8]) -> String { + let mut output = format!("\n\n"); + for line in input.chunks(16) { + output += "\t"; + for section in line.chunks(4) { + for b in section { + output += &format!("{:02x}", b); } - output += "\n"; + output += " "; } - output - }}; + output += "\n"; + } + output +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct AssignedTask { + pub round_id: u64, + pub chunk_id: u64, + pub contribution_id: u64, } /// @@ -58,12 +68,6 @@ pub struct Verifier { /// The coordinator environment pub(crate) environment: Environment, - - /// The list of cached tasks. - pub(crate) tasks: Arc>, - - /// The path where tasks will be stored. - pub(crate) tasks_storage_path: String, } // Manual implementation, since ViewKey doesn't implement Clone @@ -75,8 +79,6 @@ impl Clone for Verifier { view_key, verifier: self.verifier.clone(), environment: self.environment.clone(), - tasks: self.tasks.clone(), - tasks_storage_path: self.tasks_storage_path.clone(), } } } @@ -90,7 +92,6 @@ impl Verifier { view_key: ViewKey, address: Address, environment: Environment, - tasks_storage_path: String, ) -> Result { let verifier_id = address.to_string(); @@ -99,84 +100,9 @@ impl Verifier { view_key, verifier: Participant::Verifier(verifier_id), environment, - tasks: Arc::new(Mutex::new(Tasks::load(&tasks_storage_path))), - tasks_storage_path, }) } - /// - /// Initializes a listener to handle the shutdown signal. - /// - #[inline] - pub async fn shutdown_listener(self) -> anyhow::Result<()> { - signal::ctrl_c().await.expect("Failed to listen for control+c"); - - warn!("\n\nATTENTION - Verifier is shutting down...\n"); - - // Acquire the tasks lock. - let tasks = self.tasks.lock().await; - trace!("Verifier has acquired the tasks lock"); - - // Store the verifier tasks to disk. - tasks.store(&self.tasks_storage_path)?; - - // Print the verifier tasks - let tasks = serde_json::to_string_pretty(&*tasks).unwrap(); - - info!("\n\nVerifier tasks at Shutdown\n\n{}\n", tasks); - info!("\n\nVerifier has safely shutdown.\n\nGoodbye.\n"); - - std::process::exit(0); - } - - /// - /// The function attempts to fetch a task from the queue. If there are - /// no tasks in the queue, then the verifier will request a lock from - /// the coordinator. - /// - #[inline] - pub async fn get_task(&self) -> Result { - // Acquire the tasks lock. - let mut tasks = self.tasks.lock().await; - - // Attempt to fetch a task or lock a chunk. - let lock_response = match tasks.next_task() { - Some(lock_response) => lock_response, - None => { - let task = self.lock_chunk().await?; - tasks.add_task(task.clone()); - task - } - }; - - // Write tasks to disk. - tasks.store(&self.tasks_storage_path)?; - - Ok(lock_response) - } - - /// - /// Clear a task from the queue. If the queue is empty, clear the storage. - /// - #[inline] - pub async fn clear_task(&self, task: &LockResponse) -> Result<(), VerifierError> { - // Acquire the tasks lock. - let mut tasks = self.tasks.lock().await; - - // Remove the given task from `tasks`. - tasks.remove_task(task); - - if tasks.is_empty() { - // If there are no tasks, delete the stored tasks file. - remove_file_if_exists(&self.tasks_storage_path); - } else { - // Otherwise, update the stored file - tasks.store(&self.tasks_storage_path)?; - } - - Ok(()) - } - /// /// Downloads the challenge file from the coordinator and stores it to the verifier filesystem. /// Returns the hash of the downloaded response file. Otherwise, returns a `VerifierError` @@ -200,9 +126,9 @@ impl Verifier { ); // Write the challenge file to disk. - write_to_file(&challenge_locator, challenge_file); + fs::write(&challenge_locator, challenge_file)?; - debug!("The challenge hash is {}", pretty_hash!(&challenge_hash)); + debug!("The challenge hash is {}", pretty_hash(&challenge_hash)); Ok(challenge_hash.to_vec()) } @@ -232,7 +158,7 @@ impl Verifier { // Write the response to a local file write_to_file(&response_locator, response_file); - debug!("The response hash is {}", pretty_hash!(&response_hash)); + debug!("The response hash is {}", pretty_hash(&response_hash)); Ok(response_hash.to_vec()) } @@ -252,7 +178,7 @@ impl Verifier { // Compute the next challenge hash using the next challenge file. let next_challenge_hash = calculate_hash(&next_challenge_file); - debug!("The next challenge hash is {}", pretty_hash!(&next_challenge_hash)); + debug!("The next challenge hash is {}", pretty_hash(&next_challenge_hash)); Ok((next_challenge_file, next_challenge_hash.to_vec())) } @@ -267,7 +193,7 @@ impl Verifier { challenge_file_locator: &str, response_locator: &str, next_challenge_locator: &str, - ) -> i64 { + ) -> u128 { // Create the parent directory for the `next_challenge_locator` if it doesn't already exist. create_parent_directory(&next_challenge_locator); // Remove the `next_challenge_locator` if it already exists. @@ -278,9 +204,7 @@ impl Verifier { let compressed_challenge = self.environment.compressed_inputs(); let compressed_response = self.environment.compressed_outputs(); - info!("Running verification on chunk {}", chunk_id); - - let start = Utc::now(); + let start = Instant::now(); match settings.curve() { CurveKind::Bls12_377 => transform_pok_and_correctness( compressed_challenge, @@ -301,17 +225,8 @@ impl Verifier { &phase1_chunked_parameters!(BW6_761, settings, chunk_id), ), }; - let stop = Utc::now(); - - let contribution_duration = stop.timestamp_millis() - start.timestamp_millis(); - - info!( - "Verification on chunk {} completed in {} seconds", - chunk_id, - contribution_duration / 1000 - ); - contribution_duration + start.elapsed().as_millis() } /// @@ -328,8 +243,8 @@ impl Verifier { }; // Check that the response hash matches the next challenge hash. - debug!("The response hash is {}", pretty_hash!(&response_hash)); - debug!("The saved response hash is {}", pretty_hash!(&saved_response_hash)); + debug!("The response hash is {}", pretty_hash(&response_hash)); + debug!("The saved response hash is {}", pretty_hash(&saved_response_hash)); if response_hash != saved_response_hash { error!("Response hash does not match the saved response hash."); return Err(VerifierError::MismatchedResponseHashes); @@ -405,32 +320,23 @@ impl Verifier { /// After completion or error, the loop waits 5 seconds and starts again. /// pub async fn start_verifier(&self) { - // Initialize the shutdown listener - let verifier = self.clone(); - tokio::task::spawn(async move { - let _ = verifier.shutdown_listener().await; - }); - // Initialize the verifier loop. loop { + let task = match self.get_task().await { + Some(task) => task, + None => { + tokio::time::sleep(NO_TASKS_DELAY).await; + continue; + } + }; + + info!("Got a task: {:?}", task); + // Run the verification operations. - if let Err(error) = self.try_verify().await { + if let Err(error) = self.try_verify(&task).await { error!("Error while verifying {}", error); - - // Clearing and obtaining new tasks - tracing::warn!("Clearing tasks"); - let tasks_lock = self.tasks.lock().await; - let current_tasks = tasks_lock.get_tasks().clone(); - drop(tasks_lock); // lock is required to clear the tasks - for task in current_tasks { - if let Err(error) = self.clear_task(&task).await { - tracing::error!("Error clearing task: {}", error); - } - } + tokio::time::sleep(UPLOAD_TASK_ERROR_DELAY).await; } - - // Sleep for 5 seconds in between iterations. - sleep(Duration::from_secs(5)); } } @@ -448,51 +354,33 @@ impl Verifier { /// 9. Attempts to apply the verification in the ceremony /// - Request to the coordinator to run `try_verify` /// - pub async fn try_verify(&self) -> Result<(), VerifierError> { - // Attempt to fetch a task from the queue or lock a chunk from the coordinator. - let lock_response = match self.get_task().await { - Ok(lock_response) => lock_response, - Err(err) => { - // If there are no tasks, attempt to join the queue for the next round. - self.join_queue().await?; - - return Err(err); - } - }; - - info!("Attempting to verify chunk {}", lock_response.chunk_id); - - // Deserialize the lock response. - let LockResponse { - chunk_id, - contribution_id, - locked: _, - participant_id: _, - challenge_locator, - challenge_chunk_id, - challenge_contribution_id, - response_locator, - next_challenge_locator, - next_challenge_chunk_id, - next_challenge_contribution_id, - } = &lock_response; + pub async fn try_verify(&self, task: &AssignedTask) -> Result<(), VerifierError> { + let chunk_id = task.chunk_id; + let contribution_id = task.contribution_id; + let challenge_locator = "challenge"; + let response_locator = "response"; + let next_challenge_locator = "next_challenge"; // Download and process the challenge file. let challenge_hash = self - .process_challenge_file(*challenge_chunk_id, *challenge_contribution_id, &challenge_locator) + .process_challenge_file(chunk_id, contribution_id, &challenge_locator) .await?; // Download and process the response file. let response_hash = self - .process_response_file(*chunk_id, *contribution_id, &response_locator) + .process_response_file(chunk_id, contribution_id, &response_locator) .await?; // Run verification on a chunk with the given locators. - let _duration = self.run_verification( - *chunk_id, - &challenge_locator, - &response_locator, - &next_challenge_locator, + info!( + "Running verification on chunk {} contribution {}", + chunk_id, contribution_id + ); + + let duration = self.run_verification(chunk_id, &challenge_locator, &response_locator, &next_challenge_locator); + info!( + "Verification on chunk {} contribution {} completed in {} ms", + chunk_id, contribution_id, duration, ); // Fetch the next challenge file from the filesystem. @@ -509,21 +397,67 @@ impl Verifier { next_challenge_file, )?; - // Upload the signature and new challenge file to `next_challenge_locator`. - self.upload_next_challenge_locator_file( - *next_challenge_chunk_id, - *next_challenge_contribution_id, - signature_and_next_challenge_bytes, - ) - .await?; - // Attempt to perform the verification with the uploaded challenge file at `next_challenge_locator`. - self.verify_contribution(*chunk_id).await?; - - // Clear the task from the cache. - self.clear_task(&lock_response).await?; + // Upload the signature and new challenge file + self.upload_next_challenge_locator_file(chunk_id, contribution_id, signature_and_next_challenge_bytes) + .await?; Ok(()) } + + /// + /// Gets a task from a coordinator. If error happens, logs + /// error and returns None + /// + async fn get_task(&self) -> Option { + let coordinator_api_url = &self.coordinator_api_url; + let method = "post"; + let path = "/v1/verifier/get_task"; + + // It's better to panic here and stop the verifier, because + // such an error is unexpected and signals about + // logic errors in authentication + let authentication = AleoAuthentication::authenticate(&self.view_key, &method, &path).expect(&format!( + "Failed to authenticate with method: {}, path: {}", + method, path + )); + + info!("Asking for a new task"); + + match reqwest::Client::new() + .post(coordinator_api_url.join(path).expect("Should create a path")) + .header(http::header::AUTHORIZATION, authentication.to_string()) + .header(http::header::CONTENT_LENGTH, 0) + .send() + .await + { + Ok(response) => { + if !response.status().is_success() { + error!("Failed to get a new task, status: {}", response.status(),); + return None; + } + + // Parse the lock response + let bytes = match response.bytes().await { + Ok(bytes) => bytes.to_vec(), + Err(e) => { + error!("Error reading response body: {}", &e); + return None; + } + }; + match serde_json::from_slice(&bytes) { + Ok(maybe_task) => maybe_task, + Err(e) => { + error!("Error deserializing response: {}", e); + None + } + } + } + Err(_) => { + error!("Request ({}) to get a task failed", path); + None + } + } + } } #[cfg(test)] @@ -552,7 +486,6 @@ mod tests { view_key, address, environment.into(), - "TEST_VERIFIER.tasks".to_string(), ) .unwrap() }