From 1be1c0b7824553b2fa4e1cadd3b9efd2fcbe9019 Mon Sep 17 00:00:00 2001 From: mdelle1 <108158289+mdelle1@users.noreply.github.com> Date: Mon, 19 Feb 2024 18:38:14 -0500 Subject: [PATCH 01/12] Adds quorum check before advancing from odd and even rounds in BFT --- node/bft/src/bft.rs | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/node/bft/src/bft.rs b/node/bft/src/bft.rs index 7662f27b7f..571bfa6cea 100644 --- a/node/bft/src/bft.rs +++ b/node/bft/src/bft.rs @@ -322,6 +322,14 @@ impl BFT { committee: Committee, current_round: u64, ) -> bool { + // Retrieve the authors for the current round. + let authors = certificates.into_iter().map(|c| c.author()).collect(); + // Check if quorum threshold is reached. + let is_quorum = committee.is_quorum_threshold_reached(&authors); + if !is_quorum { + info!("BFT failed to advance to the next round - quorum threshold not reached in even round {current_round}. "); + return false; + } // If the leader certificate is set for the current even round, return 'true'. if let Some(leader_certificate) = self.leader_certificate.read().as_ref() { if leader_certificate.round() == current_round { @@ -330,11 +338,8 @@ impl BFT { } // If the timer has expired, and we can achieve quorum threshold (2f + 1) without the leader, return 'true'. if self.is_timer_expired() { - debug!("BFT (timer expired) - Checking for quorum threshold (without the leader)"); - // Retrieve the certificate authors. - let authors = certificates.into_iter().map(|c| c.author()).collect(); - // Determine if the quorum threshold is reached. - return committee.is_quorum_threshold_reached(&authors); + debug!("BFT (timer expired) - Advancing from round {current_round} to the next round (without the leader)"); + return true; } // Otherwise, return 'false'. false @@ -363,14 +368,6 @@ impl BFT { error!("BFT does not compute stakes for the leader certificate in an even round"); return false; } - - // Retrieve the leader certificate. - let Some(leader_certificate) = self.leader_certificate.read().clone() else { - // If there is no leader certificate for the previous round, return 'true'. - return true; - }; - // Retrieve the leader certificate ID. - let leader_certificate_id = leader_certificate.id(); // Retrieve the certificates for the current round. let current_certificates = self.storage().get_certificates_for_round(current_round); // Retrieve the committee lookback for the current round. @@ -381,7 +378,21 @@ impl BFT { return false; } }; - + // Retrieve the authors of the current certificates. + let authors = current_certificates.clone().into_iter().map(|c| c.author()).collect(); + // Check if quorum threshold is reached. + let is_quorum = previous_committee.clone().is_quorum_threshold_reached(&authors); + if !is_quorum { + info!("BFT failed to advance to the next round - quorum threshold not reached in odd round {current_round}. "); + return false; + } + // Retrieve the leader certificate. + let Some(leader_certificate) = self.leader_certificate.read().clone() else { + // If there is no leader certificate for the previous round, return 'true'. + return true; + }; + // Retrieve the leader certificate ID. + let leader_certificate_id = leader_certificate.id(); // Compute the stake for the leader certificate. let (stake_with_leader, stake_without_leader) = self.compute_stake_for_leader_certificate(leader_certificate_id, current_certificates, &committee_lookback); From 5883484b435449c966d5688050c3b995fb64fb3f Mon Sep 17 00:00:00 2001 From: mdelle1 <108158289+mdelle1@users.noreply.github.com> Date: Mon, 19 Feb 2024 19:04:28 -0500 Subject: [PATCH 02/12] Uses committee lookback --- node/bft/src/bft.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/bft/src/bft.rs b/node/bft/src/bft.rs index 571bfa6cea..7df2d5ddd4 100644 --- a/node/bft/src/bft.rs +++ b/node/bft/src/bft.rs @@ -381,7 +381,7 @@ impl BFT { // Retrieve the authors of the current certificates. let authors = current_certificates.clone().into_iter().map(|c| c.author()).collect(); // Check if quorum threshold is reached. - let is_quorum = previous_committee.clone().is_quorum_threshold_reached(&authors); + let is_quorum = committee_lookback.clone().is_quorum_threshold_reached(&authors); if !is_quorum { info!("BFT failed to advance to the next round - quorum threshold not reached in odd round {current_round}. "); return false; From 68d11b0460d1ea734559f84489fe5549a8f68c2d Mon Sep 17 00:00:00 2001 From: raychu86 <14917648+raychu86@users.noreply.github.com> Date: Thu, 22 Feb 2024 18:03:11 -0800 Subject: [PATCH 03/12] nit --- node/bft/src/bft.rs | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/node/bft/src/bft.rs b/node/bft/src/bft.rs index 7df2d5ddd4..91a29e2a50 100644 --- a/node/bft/src/bft.rs +++ b/node/bft/src/bft.rs @@ -322,13 +322,14 @@ impl BFT { committee: Committee, current_round: u64, ) -> bool { - // Retrieve the authors for the current round. + // Retrieve the authors for the current round. let authors = certificates.into_iter().map(|c| c.author()).collect(); - // Check if quorum threshold is reached. - let is_quorum = committee.is_quorum_threshold_reached(&authors); - if !is_quorum { - info!("BFT failed to advance to the next round - quorum threshold not reached in even round {current_round}. "); - return false; + // Check if quorum threshold is reached. + if !committee.is_quorum_threshold_reached(&authors) { + info!( + "BFT failed to advance to the next round - quorum threshold not reached in even round {current_round}. " + ); + return false; } // If the leader certificate is set for the current even round, return 'true'. if let Some(leader_certificate) = self.leader_certificate.read().as_ref() { @@ -339,7 +340,7 @@ impl BFT { // If the timer has expired, and we can achieve quorum threshold (2f + 1) without the leader, return 'true'. if self.is_timer_expired() { debug!("BFT (timer expired) - Advancing from round {current_round} to the next round (without the leader)"); - return true; + return true; } // Otherwise, return 'false'. false @@ -378,13 +379,14 @@ impl BFT { return false; } }; - // Retrieve the authors of the current certificates. + // Retrieve the authors of the current certificates. let authors = current_certificates.clone().into_iter().map(|c| c.author()).collect(); - // Check if quorum threshold is reached. - let is_quorum = committee_lookback.clone().is_quorum_threshold_reached(&authors); - if !is_quorum { - info!("BFT failed to advance to the next round - quorum threshold not reached in odd round {current_round}. "); - return false; + // Check if quorum threshold is reached. + if !committee_lookback.is_quorum_threshold_reached(&authors) { + info!( + "BFT failed to advance to the next round - quorum threshold not reached in odd round {current_round}. " + ); + return false; } // Retrieve the leader certificate. let Some(leader_certificate) = self.leader_certificate.read().clone() else { From 2078b11e83da9d748b91770ae948c9873c640a01 Mon Sep 17 00:00:00 2001 From: raychu86 <14917648+raychu86@users.noreply.github.com> Date: Thu, 22 Feb 2024 18:06:08 -0800 Subject: [PATCH 04/12] Update logs --- node/bft/src/bft.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/node/bft/src/bft.rs b/node/bft/src/bft.rs index 91a29e2a50..3ea0cd4b67 100644 --- a/node/bft/src/bft.rs +++ b/node/bft/src/bft.rs @@ -326,9 +326,7 @@ impl BFT { let authors = certificates.into_iter().map(|c| c.author()).collect(); // Check if quorum threshold is reached. if !committee.is_quorum_threshold_reached(&authors) { - info!( - "BFT failed to advance to the next round - quorum threshold not reached in even round {current_round}. " - ); + debug!("BFT failed to reach quorum threshold in even round {current_round}"); return false; } // If the leader certificate is set for the current even round, return 'true'. @@ -383,9 +381,7 @@ impl BFT { let authors = current_certificates.clone().into_iter().map(|c| c.author()).collect(); // Check if quorum threshold is reached. if !committee_lookback.is_quorum_threshold_reached(&authors) { - info!( - "BFT failed to advance to the next round - quorum threshold not reached in odd round {current_round}. " - ); + debug!("BFT failed reach quorum threshold in odd round {current_round}. "); return false; } // Retrieve the leader certificate. From 044ff0c516ee7aa6cc2caf060cd9200470ddd3b3 Mon Sep 17 00:00:00 2001 From: mdelle1 <108158289+mdelle1@users.noreply.github.com> Date: Mon, 11 Mar 2024 11:54:59 -0400 Subject: [PATCH 05/12] Updates unit tests for advancing from even and odd rounds --- node/bft/src/bft.rs | 119 ++++++++++++++++++++++++++++++++------------ 1 file changed, 87 insertions(+), 32 deletions(-) diff --git a/node/bft/src/bft.rs b/node/bft/src/bft.rs index 3ea0cd4b67..a351b5c282 100644 --- a/node/bft/src/bft.rs +++ b/node/bft/src/bft.rs @@ -906,34 +906,52 @@ mod tests { fn test_is_leader_quorum_odd() -> Result<()> { let rng = &mut TestRng::default(); - // Sample the test instance. - let (_, account, ledger, storage) = sample_test_instance(None, 10, rng); - assert_eq!(storage.max_gc_rounds(), 10); - - // Initialize the BFT. - let bft = BFT::new(account, storage, ledger, None, &[], None)?; - assert!(bft.is_timer_expired()); // 0 + 5 < now() + // Sample batch certificates. + let mut certificates = IndexSet::new(); + certificates.insert(snarkvm::ledger::narwhal::batch_certificate::test_helpers::sample_batch_certificate_for_round_with_previous_certificate_ids(1, IndexSet::new(), rng)); + certificates.insert(snarkvm::ledger::narwhal::batch_certificate::test_helpers::sample_batch_certificate_for_round_with_previous_certificate_ids(1, IndexSet::new(), rng)); + certificates.insert(snarkvm::ledger::narwhal::batch_certificate::test_helpers::sample_batch_certificate_for_round_with_previous_certificate_ids(1, IndexSet::new(), rng)); + certificates.insert(snarkvm::ledger::narwhal::batch_certificate::test_helpers::sample_batch_certificate_for_round_with_previous_certificate_ids(1, IndexSet::new(), rng)); + + // Initialize the committee. + let committee = snarkvm::ledger::committee::test_helpers::sample_committee_for_round_and_members( + 1, + vec![ + certificates[0].author(), + certificates[1].author(), + certificates[2].author(), + certificates[3].author(), + ], + rng, + ); + // Initialize the ledger. + let ledger = Arc::new(MockLedgerService::new(committee.clone())); + // Initialize the storage. + let storage = Storage::new(ledger.clone(), Arc::new(BFTMemoryService::new()), 10); + // Initialize the account. + let account = Account::new(rng)?; + // Initialize the BFT. + let bft = BFT::new(account.clone(), storage.clone(), ledger.clone(), None, &[], None)?; + assert!(bft.is_timer_expired()); + // Ensure this call succeeds on an odd round. + let result = bft.is_leader_quorum_or_nonleaders_available(1); + // If timer has expired but quorum threshold is not reached, return 'false'. + assert!(!result); + // Insert certificates into storage. + for certificate in certificates.iter() { + storage.testing_only_insert_certificate_testing_only(certificate.clone()); + } // Ensure this call succeeds on an odd round. let result = bft.is_leader_quorum_or_nonleaders_available(1); assert!(result); // no previous leader certificate - // Set the leader certificate. let leader_certificate = sample_batch_certificate(rng); *bft.leader_certificate.write() = Some(leader_certificate); - // Ensure this call succeeds on an odd round. let result = bft.is_leader_quorum_or_nonleaders_available(1); assert!(result); // should now fall through to the end of function - // Set the timer to now(). - bft.leader_certificate_timer.store(now(), Ordering::SeqCst); - assert!(!bft.is_timer_expired()); - - // Ensure this call succeeds on an odd round. - let result = bft.is_leader_quorum_or_nonleaders_available(1); - // Should now return false, as the timer is not expired. - assert!(!result); // should now fall through to end of function Ok(()) } @@ -983,27 +1001,64 @@ mod tests { #[test] #[tracing_test::traced_test] fn test_is_even_round_ready() -> Result<()> { + use crate::MAX_LEADER_CERTIFICATE_DELAY_IN_SECS; let rng = &mut TestRng::default(); - // Sample the test instance. - let (committee, account, ledger, storage) = sample_test_instance(Some(2), 10, rng); - assert_eq!(committee.starting_round(), 2); - assert_eq!(storage.current_round(), 2); - assert_eq!(storage.max_gc_rounds(), 10); - - // Initialize the BFT. - let bft = BFT::new(account, storage, ledger, None, &[], None)?; - - let result = bft.is_even_round_ready_for_next_round(IndexSet::new(), committee.clone(), 2); - assert!(!result); + // Sample batch certificates. + let mut certificates = IndexSet::new(); + certificates.insert(sample_batch_certificate_for_round(2, rng)); + certificates.insert(sample_batch_certificate_for_round(2, rng)); + certificates.insert(sample_batch_certificate_for_round(2, rng)); + certificates.insert(sample_batch_certificate_for_round(2, rng)); + + // Initialize the committee. + let committee = snarkvm::ledger::committee::test_helpers::sample_committee_for_round_and_members( + 2, + vec![ + certificates[0].author(), + certificates[1].author(), + certificates[2].author(), + certificates[3].author(), + ], + rng, + ); + // Initialize the ledger. + let ledger = Arc::new(MockLedgerService::new(committee.clone())); + // Initialize the storage. + let storage = Storage::new(ledger.clone(), Arc::new(BFTMemoryService::new()), 10); + // Initialize the account. + let account = Account::new(rng)?; + // Initialize the BFT. + let bft = BFT::new(account.clone(), storage.clone(), ledger.clone(), None, &[], None)?; // Set the leader certificate. let leader_certificate = sample_batch_certificate_for_round(2, rng); *bft.leader_certificate.write() = Some(leader_certificate); - - let result = bft.is_even_round_ready_for_next_round(IndexSet::new(), committee, 2); - // If leader certificate is set, we should be ready for next round. - assert!(result); + let result = bft.is_even_round_ready_for_next_round(IndexSet::new(), committee.clone(), 2); + // If leader certificate is set but quorum threshold is not reached, we are not ready for the next round. + assert!(!result); + // Once quorum threshold is reached, we are ready for the next round. + let result = bft.is_even_round_ready_for_next_round(certificates.clone(), committee.clone(), 2); + assert!(result); + + // Initialize a new BFT. + let bft_timer = BFT::new(account.clone(), storage.clone(), ledger.clone(), None, &[], None)?; + // If the leader certificate is not set and the timer has not expired, we are not ready for the next round. + let result = bft_timer.is_even_round_ready_for_next_round(certificates.clone(), committee.clone(), 2); + if !bft_timer.is_timer_expired() { + assert!(!result); + } + // Wait for the timer to expire. + let leader_certificate_timeout = std::time::Duration::from_millis(MAX_LEADER_CERTIFICATE_DELAY_IN_SECS as u64 * 1000); + std::thread::sleep(leader_certificate_timeout); + // Once the leader certificate timer has expired and quorum threshold is reached, we are ready to advance to the next round. + let result = bft_timer.is_even_round_ready_for_next_round(certificates.clone(), committee.clone(), 2); + if bft_timer.is_timer_expired() { + assert!(result); + } else { + assert!(!result); + } + Ok(()) } From 0fcd8900f114d4b8513526e6dc801f532362a281 Mon Sep 17 00:00:00 2001 From: raychu86 <14917648+raychu86@users.noreply.github.com> Date: Mon, 11 Mar 2024 16:57:44 -0700 Subject: [PATCH 06/12] nit --- node/bft/src/bft.rs | 73 ++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/node/bft/src/bft.rs b/node/bft/src/bft.rs index a351b5c282..386ad94404 100644 --- a/node/bft/src/bft.rs +++ b/node/bft/src/bft.rs @@ -857,10 +857,7 @@ impl BFT { #[cfg(test)] mod tests { - use crate::{ - helpers::{now, Storage}, - BFT, - }; + use crate::{helpers::Storage, BFT, MAX_LEADER_CERTIFICATE_DELAY_IN_SECS}; use snarkos_account::Account; use snarkos_node_bft_ledger_service::MockLedgerService; use snarkos_node_bft_storage_service::BFTMemoryService; @@ -874,7 +871,7 @@ mod tests { use anyhow::Result; use indexmap::IndexSet; - use std::sync::{atomic::Ordering, Arc}; + use std::sync::Arc; type CurrentNetwork = snarkvm::console::network::MainnetV0; @@ -906,13 +903,13 @@ mod tests { fn test_is_leader_quorum_odd() -> Result<()> { let rng = &mut TestRng::default(); - // Sample batch certificates. - let mut certificates = IndexSet::new(); - certificates.insert(snarkvm::ledger::narwhal::batch_certificate::test_helpers::sample_batch_certificate_for_round_with_previous_certificate_ids(1, IndexSet::new(), rng)); - certificates.insert(snarkvm::ledger::narwhal::batch_certificate::test_helpers::sample_batch_certificate_for_round_with_previous_certificate_ids(1, IndexSet::new(), rng)); - certificates.insert(snarkvm::ledger::narwhal::batch_certificate::test_helpers::sample_batch_certificate_for_round_with_previous_certificate_ids(1, IndexSet::new(), rng)); - certificates.insert(snarkvm::ledger::narwhal::batch_certificate::test_helpers::sample_batch_certificate_for_round_with_previous_certificate_ids(1, IndexSet::new(), rng)); - + // Sample batch certificates. + let mut certificates = IndexSet::new(); + certificates.insert(snarkvm::ledger::narwhal::batch_certificate::test_helpers::sample_batch_certificate_for_round_with_previous_certificate_ids(1, IndexSet::new(), rng)); + certificates.insert(snarkvm::ledger::narwhal::batch_certificate::test_helpers::sample_batch_certificate_for_round_with_previous_certificate_ids(1, IndexSet::new(), rng)); + certificates.insert(snarkvm::ledger::narwhal::batch_certificate::test_helpers::sample_batch_certificate_for_round_with_previous_certificate_ids(1, IndexSet::new(), rng)); + certificates.insert(snarkvm::ledger::narwhal::batch_certificate::test_helpers::sample_batch_certificate_for_round_with_previous_certificate_ids(1, IndexSet::new(), rng)); + // Initialize the committee. let committee = snarkvm::ledger::committee::test_helpers::sample_committee_for_round_and_members( 1, @@ -931,14 +928,14 @@ mod tests { let storage = Storage::new(ledger.clone(), Arc::new(BFTMemoryService::new()), 10); // Initialize the account. let account = Account::new(rng)?; - // Initialize the BFT. + // Initialize the BFT. let bft = BFT::new(account.clone(), storage.clone(), ledger.clone(), None, &[], None)?; assert!(bft.is_timer_expired()); // Ensure this call succeeds on an odd round. let result = bft.is_leader_quorum_or_nonleaders_available(1); // If timer has expired but quorum threshold is not reached, return 'false'. - assert!(!result); - // Insert certificates into storage. + assert!(!result); + // Insert certificates into storage. for certificate in certificates.iter() { storage.testing_only_insert_certificate_testing_only(certificate.clone()); } @@ -1001,16 +998,15 @@ mod tests { #[test] #[tracing_test::traced_test] fn test_is_even_round_ready() -> Result<()> { - use crate::MAX_LEADER_CERTIFICATE_DELAY_IN_SECS; let rng = &mut TestRng::default(); - // Sample batch certificates. - let mut certificates = IndexSet::new(); - certificates.insert(sample_batch_certificate_for_round(2, rng)); - certificates.insert(sample_batch_certificate_for_round(2, rng)); - certificates.insert(sample_batch_certificate_for_round(2, rng)); - certificates.insert(sample_batch_certificate_for_round(2, rng)); - + // Sample batch certificates. + let mut certificates = IndexSet::new(); + certificates.insert(sample_batch_certificate_for_round(2, rng)); + certificates.insert(sample_batch_certificate_for_round(2, rng)); + certificates.insert(sample_batch_certificate_for_round(2, rng)); + certificates.insert(sample_batch_certificate_for_round(2, rng)); + // Initialize the committee. let committee = snarkvm::ledger::committee::test_helpers::sample_committee_for_round_and_members( 2, @@ -1029,36 +1025,37 @@ mod tests { let storage = Storage::new(ledger.clone(), Arc::new(BFTMemoryService::new()), 10); // Initialize the account. let account = Account::new(rng)?; - // Initialize the BFT. + // Initialize the BFT. let bft = BFT::new(account.clone(), storage.clone(), ledger.clone(), None, &[], None)?; // Set the leader certificate. let leader_certificate = sample_batch_certificate_for_round(2, rng); *bft.leader_certificate.write() = Some(leader_certificate); let result = bft.is_even_round_ready_for_next_round(IndexSet::new(), committee.clone(), 2); - // If leader certificate is set but quorum threshold is not reached, we are not ready for the next round. + // If leader certificate is set but quorum threshold is not reached, we are not ready for the next round. assert!(!result); - // Once quorum threshold is reached, we are ready for the next round. + // Once quorum threshold is reached, we are ready for the next round. let result = bft.is_even_round_ready_for_next_round(certificates.clone(), committee.clone(), 2); - assert!(result); + assert!(result); - // Initialize a new BFT. + // Initialize a new BFT. let bft_timer = BFT::new(account.clone(), storage.clone(), ledger.clone(), None, &[], None)?; // If the leader certificate is not set and the timer has not expired, we are not ready for the next round. let result = bft_timer.is_even_round_ready_for_next_round(certificates.clone(), committee.clone(), 2); - if !bft_timer.is_timer_expired() { - assert!(!result); + if !bft_timer.is_timer_expired() { + assert!(!result); } - // Wait for the timer to expire. - let leader_certificate_timeout = std::time::Duration::from_millis(MAX_LEADER_CERTIFICATE_DELAY_IN_SECS as u64 * 1000); - std::thread::sleep(leader_certificate_timeout); - // Once the leader certificate timer has expired and quorum threshold is reached, we are ready to advance to the next round. + // Wait for the timer to expire. + let leader_certificate_timeout = + std::time::Duration::from_millis(MAX_LEADER_CERTIFICATE_DELAY_IN_SECS as u64 * 1000); + std::thread::sleep(leader_certificate_timeout); + // Once the leader certificate timer has expired and quorum threshold is reached, we are ready to advance to the next round. let result = bft_timer.is_even_round_ready_for_next_round(certificates.clone(), committee.clone(), 2); - if bft_timer.is_timer_expired() { - assert!(result); + if bft_timer.is_timer_expired() { + assert!(result); } else { - assert!(!result); + assert!(!result); } - + Ok(()) } From c9e9d01cfc6bc01ace87567d082a5383dc3a6e57 Mon Sep 17 00:00:00 2001 From: raychu86 <14917648+raychu86@users.noreply.github.com> Date: Mon, 11 Mar 2024 17:16:43 -0700 Subject: [PATCH 07/12] Clarify documentation --- node/bft/src/bft.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/node/bft/src/bft.rs b/node/bft/src/bft.rs index 5cf16cc236..cfa14536b9 100644 --- a/node/bft/src/bft.rs +++ b/node/bft/src/bft.rs @@ -323,10 +323,9 @@ impl BFT { self.is_even_round_ready_for_next_round(current_certificates, committee_lookback, current_round) } - /// Returns 'true' under one of the following conditions: - /// - If the leader certificate is set for the current even round, - /// - The timer for the leader certificate has expired, and we can - /// achieve quorum threshold (2f + 1) without the leader. + /// Returns 'true' if the quorum threshold is reached for this round under one of the following conditions: + /// - If the leader certificate is set for the current even round. + /// - The timer for the leader certificate has expired. fn is_even_round_ready_for_next_round( &self, certificates: IndexSet>, @@ -360,9 +359,8 @@ impl BFT { self.leader_certificate_timer.load(Ordering::SeqCst) + MAX_LEADER_CERTIFICATE_DELAY_IN_SECS <= now() } - /// Returns 'true' if any of the following conditions hold: - /// - The leader certificate is 'None'. - /// - The leader certificate reached quorum threshold `(2f + 1)` (in the previous certificates in the current round). + /// Returns 'true' if the quorum threshold is reached for this round under one of the following conditions: + /// - The leader certificate is `None`. /// - The leader certificate is not included up to availability threshold `(f + 1)` (in the previous certificates of the current round). /// - The leader certificate timer has expired. fn is_leader_quorum_or_nonleaders_available(&self, odd_round: u64) -> bool { @@ -853,6 +851,7 @@ mod tests { use snarkos_node_bft_ledger_service::MockLedgerService; use snarkos_node_bft_storage_service::BFTMemoryService; use snarkvm::{ + console::account::{Address, PrivateKey}, ledger::{ committee::Committee, narwhal::batch_certificate::test_helpers::{sample_batch_certificate, sample_batch_certificate_for_round}, @@ -861,7 +860,7 @@ mod tests { }; use anyhow::Result; - use indexmap::IndexSet; + use indexmap::{IndexMap, IndexSet}; use std::sync::Arc; type CurrentNetwork = snarkvm::console::network::MainnetV0; From 52ae8c06ce34aae613e68f250b7b0acdaf8d3b2a Mon Sep 17 00:00:00 2001 From: Raymond Chu <14917648+raychu86@users.noreply.github.com> Date: Tue, 12 Mar 2024 16:46:39 -0700 Subject: [PATCH 08/12] Update node/bft/src/bft.rs Co-authored-by: Howard Wu <9260812+howardwu@users.noreply.github.com> Signed-off-by: Raymond Chu <14917648+raychu86@users.noreply.github.com> --- node/bft/src/bft.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/bft/src/bft.rs b/node/bft/src/bft.rs index cfa14536b9..01dfd34745 100644 --- a/node/bft/src/bft.rs +++ b/node/bft/src/bft.rs @@ -323,7 +323,7 @@ impl BFT { self.is_even_round_ready_for_next_round(current_certificates, committee_lookback, current_round) } - /// Returns 'true' if the quorum threshold is reached for this round under one of the following conditions: + /// Returns 'true' if the quorum threshold `(2f + 1)` is reached for this round under one of the following conditions: /// - If the leader certificate is set for the current even round. /// - The timer for the leader certificate has expired. fn is_even_round_ready_for_next_round( From 4d713c02ecf66636bdd170aea1a29f81afae084d Mon Sep 17 00:00:00 2001 From: Raymond Chu <14917648+raychu86@users.noreply.github.com> Date: Tue, 12 Mar 2024 16:46:43 -0700 Subject: [PATCH 09/12] Update node/bft/src/bft.rs Co-authored-by: Howard Wu <9260812+howardwu@users.noreply.github.com> Signed-off-by: Raymond Chu <14917648+raychu86@users.noreply.github.com> --- node/bft/src/bft.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/bft/src/bft.rs b/node/bft/src/bft.rs index 01dfd34745..4c679a0a4c 100644 --- a/node/bft/src/bft.rs +++ b/node/bft/src/bft.rs @@ -359,7 +359,7 @@ impl BFT { self.leader_certificate_timer.load(Ordering::SeqCst) + MAX_LEADER_CERTIFICATE_DELAY_IN_SECS <= now() } - /// Returns 'true' if the quorum threshold is reached for this round under one of the following conditions: + /// Returns 'true' if the quorum threshold `(2f + 1)` is reached for this round under one of the following conditions: /// - The leader certificate is `None`. /// - The leader certificate is not included up to availability threshold `(f + 1)` (in the previous certificates of the current round). /// - The leader certificate timer has expired. From aaae7412ada1f9da5c4da1796f66dea404a187f0 Mon Sep 17 00:00:00 2001 From: Raymond Chu <14917648+raychu86@users.noreply.github.com> Date: Tue, 12 Mar 2024 16:47:03 -0700 Subject: [PATCH 10/12] Update node/bft/src/bft.rs Co-authored-by: Howard Wu <9260812+howardwu@users.noreply.github.com> Signed-off-by: Raymond Chu <14917648+raychu86@users.noreply.github.com> --- node/bft/src/bft.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/node/bft/src/bft.rs b/node/bft/src/bft.rs index 4c679a0a4c..b5fb9fc3dc 100644 --- a/node/bft/src/bft.rs +++ b/node/bft/src/bft.rs @@ -398,11 +398,9 @@ impl BFT { // If there is no leader certificate for the previous round, return 'true'. return true; }; - // Retrieve the leader certificate ID. - let leader_certificate_id = leader_certificate.id(); // Compute the stake for the leader certificate. let (stake_with_leader, stake_without_leader) = - self.compute_stake_for_leader_certificate(leader_certificate_id, current_certificates, &committee_lookback); + self.compute_stake_for_leader_certificate(leader_certificate.id(), current_certificates, &committee_lookback); // Return 'true' if any of the following conditions hold: stake_with_leader >= committee_lookback.availability_threshold() || stake_without_leader >= committee_lookback.quorum_threshold() From fdea46a7b67db9acbcea21f281856aa30193fcac Mon Sep 17 00:00:00 2001 From: mdelle1 <108158289+mdelle1@users.noreply.github.com> Date: Wed, 13 Mar 2024 11:14:56 -0400 Subject: [PATCH 11/12] Update logs --- node/bft/src/bft.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/bft/src/bft.rs b/node/bft/src/bft.rs index b5fb9fc3dc..0a81fbc4bc 100644 --- a/node/bft/src/bft.rs +++ b/node/bft/src/bft.rs @@ -226,7 +226,7 @@ impl BFT { if let Some(leader_certificate) = self.leader_certificate.read().as_ref() { // Ensure the state of the leader certificate is consistent with the BFT being ready. if !is_ready { - error!(is_ready, "BFT - A leader certificate was found, but 'is_ready' is false"); + debug!(is_ready, "BFT - A leader certificate was found, but 'is_ready' is false"); } // Log the leader election. let leader_round = leader_certificate.round(); From b564967fb4abb57549e6297e5da801430d9d2fe3 Mon Sep 17 00:00:00 2001 From: raychu86 <14917648+raychu86@users.noreply.github.com> Date: Wed, 13 Mar 2024 10:26:30 -0700 Subject: [PATCH 12/12] cargo fmt --- node/bft/src/bft.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/node/bft/src/bft.rs b/node/bft/src/bft.rs index 0a81fbc4bc..d19ff3080b 100644 --- a/node/bft/src/bft.rs +++ b/node/bft/src/bft.rs @@ -399,8 +399,11 @@ impl BFT { return true; }; // Compute the stake for the leader certificate. - let (stake_with_leader, stake_without_leader) = - self.compute_stake_for_leader_certificate(leader_certificate.id(), current_certificates, &committee_lookback); + let (stake_with_leader, stake_without_leader) = self.compute_stake_for_leader_certificate( + leader_certificate.id(), + current_certificates, + &committee_lookback, + ); // Return 'true' if any of the following conditions hold: stake_with_leader >= committee_lookback.availability_threshold() || stake_without_leader >= committee_lookback.quorum_threshold()