Skip to content

Commit

Permalink
store next epoch qc
Browse files Browse the repository at this point in the history
  • Loading branch information
imabdulbasit committed Dec 20, 2024
1 parent 60f1427 commit 0fa1f3f
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 13 deletions.
5 changes: 5 additions & 0 deletions sequencer/api/migrations/postgres/V402__next_epoch_qc.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CREATE TABLE next_epoch_quorum_certificate (
id bool PRIMARY KEY DEFAULT true,
data BYTEA
);
REVOKE DELETE, TRUNCATE ON next_epoch_quorum_certificate FROM public;
4 changes: 4 additions & 0 deletions sequencer/api/migrations/sqlite/V203__next_epoch_qc.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CREATE TABLE next_epoch_quorum_certificate (
id bool PRIMARY KEY DEFAULT true,
data BLOB
);
71 changes: 66 additions & 5 deletions sequencer/src/persistence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ mod testing {
#[cfg(test)]
#[espresso_macros::generic_tests]
mod persistence_tests {
use std::collections::BTreeMap;
use std::{collections::BTreeMap, marker::PhantomData};

use anyhow::bail;
use async_lock::RwLock;
use committable::Committable;
use committable::{Commitment, Committable};
use espresso_types::{
traits::{EventConsumer, NullEventConsumer, PersistenceOptions},
Event, Leaf, Leaf2, NodeState, PubKey, SeqTypes, ValidatedState,
Expand All @@ -58,9 +58,9 @@ mod persistence_tests {
data::{DaProposal, EpochNumber, QuorumProposal2, VidDisperseShare, ViewNumber},
drb::{INITIAL_DRB_RESULT, INITIAL_DRB_SEED_INPUT},
event::{EventType, HotShotAction, LeafInfo},
message::Proposal,
simple_certificate::{QuorumCertificate, UpgradeCertificate},
simple_vote::UpgradeProposalData,
message::{Proposal, UpgradeLock},
simple_certificate::{NextEpochQuorumCertificate2, QuorumCertificate, UpgradeCertificate},
simple_vote::{NextEpochQuorumData2, QuorumData2, UpgradeProposalData, VersionedVoteData},
traits::{block_contents::vid_commitment, node_implementation::ConsensusTime, EncodeBytes},
vid::vid_scheme,
};
Expand Down Expand Up @@ -560,6 +560,67 @@ mod persistence_tests {
assert_eq!(view_number, new_view_number_for_certificate);
}

#[tokio::test(flavor = "multi_thread")]
pub async fn test_next_epoch_quorum_certificate<P: TestablePersistence>() {
setup_test();

let tmp = P::tmp_storage().await;
let storage = P::connect(&tmp).await;

// test that next epoch qc2 does not exist
assert_eq!(
storage.load_next_epoch_quorum_certificate().await.unwrap(),
None
);

let upgrade_lock = UpgradeLock::<SeqTypes, TestVersions>::new();

let genesis_view = ViewNumber::genesis();

let data: NextEpochQuorumData2<SeqTypes> = QuorumData2 {
leaf_commit: Leaf2::genesis(&ValidatedState::default(), &NodeState::default())
.await
.commit(),
epoch: EpochNumber::new(1),
}
.into();

let versioned_data =
VersionedVoteData::new_infallible(data.clone(), genesis_view, &upgrade_lock).await;

let bytes: [u8; 32] = versioned_data.commit().into();

let next_epoch_qc = NextEpochQuorumCertificate2::new(
data,
Commitment::from_raw(bytes),
genesis_view,
None,
PhantomData,
);

let res = storage
.store_next_epoch_quorum_certificate(next_epoch_qc.clone())
.await;
assert!(res.is_ok());

let res = storage.load_next_epoch_quorum_certificate().await.unwrap();
let view_number = res.unwrap().view_number;
assert_eq!(view_number, ViewNumber::genesis());

let new_view_number_for_qc = ViewNumber::new(50);
let mut new_qc = next_epoch_qc.clone();
new_qc.view_number = new_view_number_for_qc;

let res = storage
.store_next_epoch_quorum_certificate(new_qc.clone())
.await;
assert!(res.is_ok());

let res = storage.load_next_epoch_quorum_certificate().await.unwrap();
let view_number = res.unwrap().view_number;
assert_eq!(view_number, new_view_number_for_qc);
}

#[tokio::test(flavor = "multi_thread")]
pub async fn test_decide_with_failing_event_consumer<P: TestablePersistence>() {
#[derive(Clone, Copy, Debug)]
Expand Down
43 changes: 42 additions & 1 deletion sequencer/src/persistence/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ use hotshot_types::{
data::{DaProposal, QuorumProposal, QuorumProposal2, VidDisperseShare},
event::{Event, EventType, HotShotAction, LeafInfo},
message::{convert_proposal, Proposal},
simple_certificate::{QuorumCertificate, QuorumCertificate2, UpgradeCertificate},
simple_certificate::{
NextEpochQuorumCertificate2, QuorumCertificate, QuorumCertificate2, UpgradeCertificate,
},
traits::{
block_contents::{BlockHeader, BlockPayload},
node_implementation::ConsensusTime,
Expand Down Expand Up @@ -166,6 +168,10 @@ impl Inner {
self.path.join("upgrade_certificate")
}

fn next_epoch_qc(&self) -> PathBuf {
self.path.join("next_epoch_quorum_certificate")
}

/// Overwrite a file if a condition is met.
///
/// The file at `path`, if it exists, is opened in read mode and passed to `pred`. If `pred`
Expand Down Expand Up @@ -841,6 +847,41 @@ impl SequencerPersistence for Persistence {
)
}

async fn store_next_epoch_quorum_certificate(
&self,
high_qc: NextEpochQuorumCertificate2<SeqTypes>,
) -> anyhow::Result<()> {
let mut inner = self.inner.write().await;
let path = &inner.next_epoch_qc();

inner.replace(
path,
|_| {
// Always overwrite the previous file.
Ok(true)
},
|mut file| {
let bytes = bincode::serialize(&high_qc).context("serializing next epoch qc")?;
file.write_all(&bytes)?;
Ok(())
},
)
}

async fn load_next_epoch_quorum_certificate(
&self,
) -> anyhow::Result<Option<NextEpochQuorumCertificate2<SeqTypes>>> {
let inner = self.inner.read().await;
let path = inner.next_epoch_qc();
if !path.is_file() {
return Ok(None);
}
let bytes = fs::read(&path).context("read")?;
Ok(Some(
bincode::deserialize(&bytes).context("deserialize next epoch qc")?,
))
}

async fn migrate_consensus(
&self,
_migrate_leaf: fn(Leaf) -> Leaf2,
Expand Down
15 changes: 14 additions & 1 deletion sequencer/src/persistence/no_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use hotshot_types::{
data::{DaProposal, QuorumProposal, QuorumProposal2, VidDisperseShare},
event::{Event, EventType, HotShotAction, LeafInfo},
message::Proposal,
simple_certificate::{QuorumCertificate2, UpgradeCertificate},
simple_certificate::{NextEpochQuorumCertificate2, QuorumCertificate2, UpgradeCertificate},
utils::View,
vid::VidSchemeType,
};
Expand Down Expand Up @@ -170,4 +170,17 @@ impl SequencerPersistence for NoStorage {
) -> anyhow::Result<()> {
Ok(())
}

async fn store_next_epoch_quorum_certificate(
&self,
_high_qc: NextEpochQuorumCertificate2<SeqTypes>,
) -> anyhow::Result<()> {
Ok(())
}

async fn load_next_epoch_quorum_certificate(
&self,
) -> anyhow::Result<Option<NextEpochQuorumCertificate2<SeqTypes>>> {
Ok(None)
}
}
38 changes: 37 additions & 1 deletion sequencer/src/persistence/sql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ use hotshot_types::{
data::{DaProposal, QuorumProposal, QuorumProposal2, VidDisperseShare},
event::{Event, EventType, HotShotAction, LeafInfo},
message::{convert_proposal, Proposal},
simple_certificate::{QuorumCertificate, QuorumCertificate2, UpgradeCertificate},
simple_certificate::{
NextEpochQuorumCertificate2, QuorumCertificate, QuorumCertificate2, UpgradeCertificate,
},
traits::{
block_contents::{BlockHeader, BlockPayload},
node_implementation::ConsensusTime,
Expand Down Expand Up @@ -1308,6 +1310,40 @@ impl SequencerPersistence for Persistence {
// TODO: https://github.com/EspressoSystems/espresso-sequencer/issues/2357
Ok(())
}

async fn store_next_epoch_quorum_certificate(
&self,
high_qc: NextEpochQuorumCertificate2<SeqTypes>,
) -> anyhow::Result<()> {
let qc2_bytes = bincode::serialize(&high_qc).context("serializing next epoch qc")?;
let mut tx = self.db.write().await?;
tx.upsert(
"next_epoch_quorum_certificate",
["id", "data"],
["id"],
[(true, qc2_bytes)],
)
.await?;
tx.commit().await
}

async fn load_next_epoch_quorum_certificate(
&self,
) -> anyhow::Result<Option<NextEpochQuorumCertificate2<SeqTypes>>> {
let result = self
.db
.read()
.await?
.fetch_optional("SELECT * FROM next_epoch_quorum_certificate where id = true")
.await?;

result
.map(|row| {
let bytes: Vec<u8> = row.get("data");
anyhow::Result::<_>::Ok(bincode::deserialize(&bytes)?)
})
.transpose()
}
}

#[async_trait]
Expand Down
20 changes: 15 additions & 5 deletions types/src/v0/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -497,8 +497,10 @@ pub trait SequencerPersistence: Sized + Send + Sync + Clone + 'static {
}
};

// TODO load from storage
let next_epoch_high_qc = None;
let next_epoch_high_qc = self
.load_next_epoch_quorum_certificate()
.await
.context("loading next epoch qc")?;
let (leaf, high_qc, anchor_view) = match self
.load_anchor_leaf()
.await
Expand Down Expand Up @@ -697,6 +699,15 @@ pub trait SequencerPersistence: Sized + Send + Sync + Clone + 'static {
None => Ok(ViewNumber::genesis()),
}
}

async fn store_next_epoch_quorum_certificate(
&self,
high_qc: NextEpochQuorumCertificate2<SeqTypes>,
) -> anyhow::Result<()>;

async fn load_next_epoch_quorum_certificate(
&self,
) -> anyhow::Result<Option<NextEpochQuorumCertificate2<SeqTypes>>>;
}

#[async_trait]
Expand Down Expand Up @@ -836,10 +847,9 @@ impl<P: SequencerPersistence> Storage<SeqTypes> for Arc<P> {

async fn update_next_epoch_high_qc2(
&self,
_high_qc: NextEpochQuorumCertificate2<SeqTypes>,
high_qc: NextEpochQuorumCertificate2<SeqTypes>,
) -> anyhow::Result<()> {
// TODO
Ok(())
(**self).store_next_epoch_quorum_certificate(high_qc).await
}
}

Expand Down

0 comments on commit 0fa1f3f

Please sign in to comment.