Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ZKS-02] Use committee lookback in consensus #3065

Merged
merged 13 commits into from
Feb 10, 2024
Merged
116 changes: 58 additions & 58 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ default-features = false

[workspace.dependencies.snarkvm]
git = "https://github.com/AleoHQ/snarkVM.git"
rev = "dbe4c95"
rev = "2d062ce"
#version = "=0.16.18"
features = [ "circuit", "console", "rocks" ]

Expand Down
13 changes: 8 additions & 5 deletions node/bft/ledger-service/src/ledger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,18 +143,21 @@ impl<N: Network, C: ConsensusStorage<N>> LedgerService<N> for CoreLedgerService<
}
}

/// Returns the previous committee for the given round.
/// If the previous round is in the future, then the current committee is returned.
fn get_previous_committee_for_round(&self, round: u64) -> Result<Committee<N>> {
/// Returns the committee lookback for the given round.
/// If the committee lookback round is in the future, then the current committee is returned.
fn get_committee_lookback_for_round(&self, round: u64) -> Result<Committee<N>> {
// Get the round number for the previous committee. Note, we subtract 2 from odd rounds,
// because committees are updated in even rounds.
let previous_round = match round % 2 == 0 {
true => round.saturating_sub(1),
false => round.saturating_sub(2),
};

// Retrieve the committee for the previous round.
self.get_committee_for_round(previous_round)
// Get the committee lookback round.
let committee_lookback_round = previous_round.saturating_sub(Committee::<N>::COMMITTEE_LOOKBACK_RANGE);

// Retrieve the committee for the committee lookback round.
self.get_committee_for_round(committee_lookback_round)
}

/// Returns `true` if the ledger contains the given certificate ID in block history.
Expand Down
4 changes: 2 additions & 2 deletions node/bft/ledger-service/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ impl<N: Network> LedgerService<N> for MockLedgerService<N> {
Ok(self.committee.clone())
}

/// Returns the previous committee for the given round.
fn get_previous_committee_for_round(&self, _round: u64) -> Result<Committee<N>> {
/// Returns the committee lookback for the given round.
fn get_committee_lookback_for_round(&self, _round: u64) -> Result<Committee<N>> {
Ok(self.committee.clone())
}

Expand Down
6 changes: 3 additions & 3 deletions node/bft/ledger-service/src/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ impl<N: Network> LedgerService<N> for ProverLedgerService<N> {
bail!("Committee for round {round} does not exist in prover")
}

/// Returns the previous committee for the given round.
/// If the previous round is in the future, then the current committee is returned.
fn get_previous_committee_for_round(&self, round: u64) -> Result<Committee<N>> {
/// Returns the committee lookback for the given round.
/// If the committee lookback round is in the future, then the current committee is returned.
fn get_committee_lookback_for_round(&self, round: u64) -> Result<Committee<N>> {
bail!("Previous committee for round {round} does not exist in prover")
}

Expand Down
6 changes: 3 additions & 3 deletions node/bft/ledger-service/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ pub trait LedgerService<N: Network>: Debug + Send + Sync {
/// If the given round is in the future, then the current committee is returned.
fn get_committee_for_round(&self, round: u64) -> Result<Committee<N>>;

/// Returns the previous committee for the given round.
/// If the previous round is in the future, then the current committee is returned.
fn get_previous_committee_for_round(&self, round: u64) -> Result<Committee<N>>;
/// Returns the committee lookback for the given round.
/// If the committee lookback round is in the future, then the current committee is returned.
fn get_committee_lookback_for_round(&self, round: u64) -> Result<Committee<N>>;

/// Returns `true` if the ledger contains the given certificate ID.
fn contains_certificate(&self, certificate_id: &Field<N>) -> Result<bool>;
Expand Down
5 changes: 3 additions & 2 deletions node/bft/ledger-service/src/translucent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,9 @@ impl<N: Network, C: ConsensusStorage<N>> LedgerService<N> for TranslucentLedgerS
self.inner.get_committee_for_round(round)
}

fn get_previous_committee_for_round(&self, round: u64) -> Result<Committee<N>> {
self.inner.get_previous_committee_for_round(round)
/// Returns the committee lookback for the given round.
fn get_committee_lookback_for_round(&self, round: u64) -> Result<Committee<N>> {
self.inner.get_committee_lookback_for_round(round)
}

/// Returns `true` if the ledger contains the given certificate ID in block history.
Expand Down
38 changes: 19 additions & 19 deletions node/bft/src/bft.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,16 +291,16 @@ impl<N: Network> BFT<N> {
return false;
}

// Retrieve the previous committee of the current round.
let previous_committee = match self.ledger().get_previous_committee_for_round(current_round) {
// Retrieve the committee lookback of the current round.
let committee_lookback = match self.ledger().get_committee_lookback_for_round(current_round) {
Ok(committee) => committee,
Err(e) => {
error!("BFT failed to retrieve the previous committee for the even round {current_round} - {e}");
error!("BFT failed to retrieve the committee lookback for the even round {current_round} - {e}");
return false;
}
};
// Determine the leader of the current round.
let leader = match previous_committee.get_leader(current_round) {
let leader = match committee_lookback.get_leader(current_round) {
Ok(leader) => leader,
Err(e) => {
error!("BFT failed to compute the leader for the even round {current_round} - {e}");
Expand All @@ -311,7 +311,7 @@ impl<N: Network> BFT<N> {
let leader_certificate = current_certificates.iter().find(|certificate| certificate.author() == leader);
*self.leader_certificate.write() = leader_certificate.cloned();

self.is_even_round_ready_for_next_round(current_certificates, previous_committee, current_round)
self.is_even_round_ready_for_next_round(current_certificates, committee_lookback, current_round)
}

/// Returns 'true' under one of the following conditions:
Expand Down Expand Up @@ -375,21 +375,21 @@ impl<N: Network> BFT<N> {
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 previous committee of the current round.
let previous_committee = match self.ledger().get_previous_committee_for_round(current_round) {
// Retrieve the committee lookback for the current round.
let committee_lookback = match self.ledger().get_committee_lookback_for_round(current_round) {
Ok(committee) => committee,
Err(e) => {
error!("BFT failed to retrieve the previous committee for the odd round {current_round} - {e}");
error!("BFT failed to retrieve the committee lookback for the odd round {current_round} - {e}");
return false;
}
};

// 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, &previous_committee);
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 >= previous_committee.availability_threshold()
|| stake_without_leader >= previous_committee.quorum_threshold()
stake_with_leader >= committee_lookback.availability_threshold()
|| stake_without_leader >= committee_lookback.quorum_threshold()
|| self.is_timer_expired()
}

Expand Down Expand Up @@ -448,12 +448,12 @@ impl<N: Network> BFT<N> {
return Ok(());
}

// Retrieve the previous committee for the commit round.
let Ok(previous_committee) = self.ledger().get_previous_committee_for_round(commit_round) else {
bail!("BFT failed to retrieve the committee for commit round {commit_round}");
// Retrieve the committee lookback for the commit round.
let Ok(committee_lookback) = self.ledger().get_committee_lookback_for_round(commit_round) else {
bail!("BFT failed to retrieve the committee with lag for commit round {commit_round}");
};
// Compute the leader for the commit round.
let Ok(leader) = previous_committee.get_leader(commit_round) else {
let Ok(leader) = committee_lookback.get_leader(commit_round) else {
bail!("BFT failed to compute the leader for commit round {commit_round}");
};
// Retrieve the leader certificate for the commit round.
Expand All @@ -476,7 +476,7 @@ impl<N: Network> BFT<N> {
})
.collect();
// Check if the leader is ready to be committed.
if !previous_committee.is_availability_threshold_reached(&authors) {
if !committee_lookback.is_availability_threshold_reached(&authors) {
// If the leader is not ready to be committed, return early.
trace!("BFT is not ready to commit {commit_round}");
return Ok(());
Expand Down Expand Up @@ -508,14 +508,14 @@ impl<N: Network> BFT<N> {
for round in (self.dag.read().last_committed_round() + 2..=leader_round.saturating_sub(2)).rev().step_by(2)
{
// Retrieve the previous committee for the leader round.
let previous_committee = match self.ledger().get_previous_committee_for_round(round) {
let previous_committee_lookback = match self.ledger().get_committee_lookback_for_round(round) {
Ok(committee) => committee,
Err(e) => {
bail!("BFT failed to retrieve the previous committee for the even round {round} - {e}");
bail!("BFT failed to retrieve a previous committee lookback for the even round {round} - {e}");
}
};
// Compute the leader address for the leader round.
let leader = match previous_committee.get_leader(round) {
let leader = match previous_committee_lookback.get_leader(round) {
Ok(leader) => leader,
Err(e) => {
bail!("BFT failed to compute the leader for the even round {round} - {e}");
Expand Down
4 changes: 2 additions & 2 deletions node/bft/src/gateway.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,13 +327,13 @@ impl<N: Network> Gateway<N> {

/// Returns `true` if the given address is an authorized validator.
pub fn is_authorized_validator_address(&self, validator_address: Address<N>) -> bool {
// Determine if the validator address is a member of the previous or current committee.
// Determine if the validator address is a member of the committee lookback or the current committee.
// We allow leniency in this validation check in order to accommodate these two scenarios:
// 1. New validators should be able to connect immediately once bonded as a committee member.
// 2. Existing validators must remain connected until they are no longer bonded as a committee member.
// (i.e. meaning they must stay online until the next block has been produced)
self.ledger
.get_previous_committee_for_round(self.ledger.latest_round())
.get_committee_lookback_for_round(self.ledger.latest_round())
.map_or(false, |committee| committee.is_committee_member(validator_address))
|| self
.ledger
Expand Down
24 changes: 12 additions & 12 deletions node/bft/src/helpers/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,12 +340,12 @@ impl<N: Network> Storage<N> {
bail!("Batch for round {round} already exists in storage {gc_log}")
}

// Retrieve the previous committee for the batch round.
let Ok(previous_committee) = self.ledger.get_previous_committee_for_round(round) else {
bail!("Storage failed to retrieve the committee for round {round} {gc_log}")
// Retrieve the committee lookback for the batch round.
let Ok(committee_lookback) = self.ledger.get_committee_lookback_for_round(round) else {
bail!("Storage failed to retrieve the committee lookback for round {round} {gc_log}")
};
// Ensure the author is in the committee.
if !previous_committee.is_committee_member(batch_header.author()) {
if !committee_lookback.is_committee_member(batch_header.author()) {
bail!("Author {} is not in the committee for round {round} {gc_log}", batch_header.author())
}

Expand All @@ -362,16 +362,16 @@ impl<N: Network> Storage<N> {
let previous_round = round.saturating_sub(1);
// Check if the previous round is within range of the GC round.
if previous_round > gc_round {
// Retrieve the committee for the previous round.
let Ok(previous_committee) = self.ledger.get_previous_committee_for_round(previous_round) else {
// Retrieve the committee lookback for the previous round.
let Ok(previous_committee_lookback) = self.ledger.get_committee_lookback_for_round(previous_round) else {
bail!("Missing committee for the previous round {previous_round} in storage {gc_log}")
};
// Ensure the previous round certificates exists in storage.
if !self.contains_certificates_for_round(previous_round) {
bail!("Missing certificates for the previous round {previous_round} in storage {gc_log}")
}
// Ensure the number of previous certificate IDs is at or below the number of committee members.
if batch_header.previous_certificate_ids().len() > previous_committee.num_members() {
if batch_header.previous_certificate_ids().len() > previous_committee_lookback.num_members() {
bail!("Too many previous certificates for round {round} {gc_log}")
}
// Initialize a set of the previous authors.
Expand All @@ -397,7 +397,7 @@ impl<N: Network> Storage<N> {
previous_authors.insert(previous_certificate.author());
}
// Ensure the previous certificates have reached the quorum threshold.
if !previous_committee.is_quorum_threshold_reached(&previous_authors) {
if !previous_committee_lookback.is_quorum_threshold_reached(&previous_authors) {
bail!("Previous certificates for a batch in round {round} did not reach quorum threshold {gc_log}")
}
}
Expand Down Expand Up @@ -447,8 +447,8 @@ impl<N: Network> Storage<N> {
// Check the timestamp for liveness.
check_timestamp_for_liveness(certificate.timestamp())?;

// Retrieve the previous committee for the batch round.
let Ok(previous_committee) = self.ledger.get_previous_committee_for_round(round) else {
// Retrieve the committee lookback for the batch round.
let Ok(committee_lookback) = self.ledger.get_committee_lookback_for_round(round) else {
bail!("Storage failed to retrieve the committee for round {round} {gc_log}")
};

Expand All @@ -462,15 +462,15 @@ impl<N: Network> Storage<N> {
// Retrieve the signer.
let signer = signature.to_address();
// Ensure the signer is in the committee.
if !previous_committee.is_committee_member(signer) {
if !committee_lookback.is_committee_member(signer) {
bail!("Signer {signer} is not in the committee for round {round} {gc_log}")
}
// Append the signer.
signers.insert(signer);
}

// Ensure the signatures have reached the quorum threshold.
if !previous_committee.is_quorum_threshold_reached(&signers) {
if !committee_lookback.is_quorum_threshold_reached(&signers) {
bail!("Signatures for a batch in round {round} did not reach quorum threshold {gc_log}")
}
Ok(missing_transmissions)
Expand Down
2 changes: 0 additions & 2 deletions node/bft/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@ pub const MEMORY_POOL_PORT: u16 = 5000; // port

/// The maximum number of milliseconds to wait before proposing a batch.
pub const MAX_BATCH_DELAY_IN_MS: u64 = 2500; // ms
/// The maximum number of rounds to store before garbage collecting.
pub const MAX_GC_ROUNDS: u64 = 50; // rounds
/// The maximum number of seconds allowed for the leader to send their certificate.
pub const MAX_LEADER_CERTIFICATE_DELAY_IN_SECS: i64 = 2 * MAX_BATCH_DELAY_IN_MS as i64 / 1000; // seconds
/// The maximum number of seconds before the timestamp is considered expired.
Expand Down
Loading