Skip to content

Commit

Permalink
Handle eQC formed after shared consensus state has been updated
Browse files Browse the repository at this point in the history
  • Loading branch information
lukaszrzasik committed Mar 5, 2025
1 parent 3b34e15 commit 2bf744e
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 73 deletions.
65 changes: 0 additions & 65 deletions hotshot-task-impls/src/consensus/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use async_broadcast::{Receiver, Sender};
use async_lock::RwLock;
use async_trait::async_trait;
use either::Either;
use hotshot_task::task::TaskState;
use hotshot_types::{
consensus::OuterConsensus,
Expand Down Expand Up @@ -143,70 +142,6 @@ impl<TYPES: NodeType, I: NodeImplementation<TYPES>, V: Versions> ConsensusTaskSt
tracing::debug!("Failed to handle Timeout event; error = {e}");
}
}
HotShotEvent::Qc2Formed(Either::Left(quorum_cert)) => {
let cert_view = quorum_cert.view_number();
if !self.upgrade_lock.epochs_enabled(cert_view).await {
tracing::debug!("QC2 formed but epochs not enabled. Do nothing");
return Ok(());
}
if !self
.consensus
.read()
.await
.is_leaf_extended(quorum_cert.data.leaf_commit)
{
tracing::debug!("We formed QC but not eQC. Do nothing");
return Ok(());
}

let consensus_reader = self.consensus.read().await;
let Some(next_epoch_qc) = consensus_reader.next_epoch_high_qc() else {
tracing::debug!("We formed the current epoch eQC but we don't have the next epoch eQC at all.");
return Ok(());
};
if quorum_cert.view_number() != next_epoch_qc.view_number()
|| quorum_cert.data != *next_epoch_qc.data
{
tracing::debug!("We formed the current epoch eQC but we don't have the corresponding next epoch eQC.");
return Ok(());
}
drop(consensus_reader);

broadcast_event(
Arc::new(HotShotEvent::ExtendedQc2Formed(quorum_cert.clone())),
&sender,
)
.await;
}
HotShotEvent::NextEpochQc2Formed(Either::Left(next_epoch_qc)) => {
let cert_view = next_epoch_qc.view_number();
if !self.upgrade_lock.epochs_enabled(cert_view).await {
tracing::debug!("Next epoch QC2 formed but epochs not enabled. Do nothing");
return Ok(());
}
if !self
.consensus
.read()
.await
.is_leaf_extended(next_epoch_qc.data.leaf_commit)
{
tracing::debug!("We formed next epoch QC but not eQC. Do nothing");
return Ok(());
}

let consensus_reader = self.consensus.read().await;
let high_qc = consensus_reader.high_qc();
if high_qc.view_number() != next_epoch_qc.view_number()
|| high_qc.data != *next_epoch_qc.data
{
tracing::debug!("We formed the current epoch eQC but we don't have the corresponding next epoch eQC.");
return Ok(());
}
let high_qc = high_qc.clone();
drop(consensus_reader);

broadcast_event(Arc::new(HotShotEvent::ExtendedQc2Formed(high_qc)), &sender).await;
}
HotShotEvent::ExtendedQc2Formed(eqc) => {
let cert_view = eqc.view_number();
let cert_block_number = self
Expand Down
65 changes: 57 additions & 8 deletions hotshot-task-impls/src/quorum_proposal/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,25 @@ use std::{
time::{Duration, Instant},
};

use crate::{
events::HotShotEvent,
helpers::{broadcast_event, parent_leaf_and_state, wait_for_next_epoch_qc},
quorum_proposal::{QuorumProposalTaskState, UpgradeLock, Versions},
};
use anyhow::{ensure, Context, Result};
use async_broadcast::{Receiver, Sender};
use async_lock::RwLock;
use committable::Committable;
use committable::{Commitment, Committable};
use hotshot_task::dependency_task::HandleDepOutput;
use hotshot_types::{
consensus::{CommitmentAndMetadata, OuterConsensus},
data::{Leaf2, QuorumProposal2, QuorumProposalWrapper, VidDisperse, ViewChangeEvidence2},
message::Proposal,
simple_certificate::{QuorumCertificate2, UpgradeCertificate},
traits::{
block_contents::BlockHeader, election::Membership, node_implementation::NodeType,
block_contents::BlockHeader,
election::Membership,
node_implementation::{NodeImplementation, NodeType},
signature_key::SignatureKey,
},
utils::{is_last_block_in_epoch, option_epoch_from_block_number},
Expand All @@ -35,12 +42,6 @@ use hotshot_utils::anytrace::*;
use tracing::instrument;
use vbs::version::StaticVersionType;

use crate::{
events::HotShotEvent,
helpers::{broadcast_event, parent_leaf_and_state, wait_for_next_epoch_qc},
quorum_proposal::{UpgradeLock, Versions},
};

/// Proposal dependency types. These types represent events that precipitate a proposal.
#[derive(PartialEq, Debug)]
pub(crate) enum ProposalDependency {
Expand Down Expand Up @@ -500,3 +501,51 @@ impl<TYPES: NodeType, V: Versions> HandleDepOutput for ProposalDependencyHandle<
}
}
}

pub(super) async fn handle_eqc_formed<
TYPES: NodeType,
I: NodeImplementation<TYPES>,
V: Versions,
>(
cert_view: TYPES::View,
leaf_commit: Commitment<Leaf2<TYPES>>,
task_state: &QuorumProposalTaskState<TYPES, I, V>,
event_sender: &Sender<Arc<HotShotEvent<TYPES>>>,
) {
if !task_state.upgrade_lock.epochs_enabled(cert_view).await {
tracing::debug!("QC2 formed but epochs not enabled. Do nothing");
return;
}
if !task_state
.consensus
.read()
.await
.is_leaf_extended(leaf_commit)
{
tracing::debug!("We formed QC but not eQC. Do nothing");
return;
}

let consensus_reader = task_state.consensus.read().await;
let current_epoch_qc = consensus_reader.high_qc();
let Some(next_epoch_qc) = consensus_reader.next_epoch_high_qc() else {
tracing::debug!("We formed the eQC but we don't have the next epoch eQC at all.");
return;
};
if current_epoch_qc.view_number() != next_epoch_qc.view_number()
|| current_epoch_qc.data != *next_epoch_qc.data
{
tracing::debug!(
"We formed the eQC but the current and next epoch QCs do not correspond to each other."
);
return;
}
let current_epoch_qc_clone = current_epoch_qc.clone();
drop(consensus_reader);

broadcast_event(
Arc::new(HotShotEvent::ExtendedQc2Formed(current_epoch_qc_clone)),
event_sender,
)
.await;
}
13 changes: 13 additions & 0 deletions hotshot-task-impls/src/quorum_proposal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use tracing::instrument;

use self::handlers::{ProposalDependency, ProposalDependencyHandle};
use crate::events::HotShotEvent;
use crate::quorum_proposal::handlers::handle_eqc_formed;

mod handlers;

Expand Down Expand Up @@ -437,6 +438,10 @@ impl<TYPES: NodeType, I: NodeImplementation<TYPES>, V: Versions>
.await
.wrap()
.context(error!("Failed to update high QC in storage!"))?;

handle_eqc_formed(qc.view_number(), qc.data.leaf_commit, self, &event_sender)
.await;

let view_number = qc.view_number() + 1;
self.create_dependency_task_if_new(
view_number,
Expand Down Expand Up @@ -598,6 +603,14 @@ impl<TYPES: NodeType, I: NodeImplementation<TYPES>, V: Versions>
.await
.wrap()
.context(error!("Failed to update next epoch high QC in storage!"))?;

handle_eqc_formed(
next_epoch_qc.view_number(),
next_epoch_qc.data.leaf_commit,
self,
&event_sender,
)
.await;
}
_ => {}
}
Expand Down

0 comments on commit 2bf744e

Please sign in to comment.