diff --git a/migrations/postgres/V500__leaf2_migration.sql b/migrations/postgres/V500__leaf2_migration.sql new file mode 100644 index 000000000..69f562df7 --- /dev/null +++ b/migrations/postgres/V500__leaf2_migration.sql @@ -0,0 +1,15 @@ +CREATE TABLE leaf2 +( + height BIGINT PRIMARY KEY REFERENCES header (height) ON DELETE CASCADE, + hash VARCHAR NOT NULL UNIQUE, + block_hash VARCHAR NOT NULL REFERENCES header (hash) ON DELETE CASCADE, + leaf JSONB NOT NULL, + qc JSONB NOT NULL +); + +CREATE TABLE leaf_migration ( + id SERIAL PRIMARY KEY, + completed bool NOT NULL DEFAULT false +); + +INSERT INTO leaf_migration ("completed") VALUES (false); \ No newline at end of file diff --git a/migrations/sqlite/V300__leaf2_migration.sql b/migrations/sqlite/V300__leaf2_migration.sql new file mode 100644 index 000000000..ce22030d5 --- /dev/null +++ b/migrations/sqlite/V300__leaf2_migration.sql @@ -0,0 +1,15 @@ +CREATE TABLE leaf2 +( + height BIGINT PRIMARY KEY REFERENCES header (height) ON DELETE CASCADE, + hash VARCHAR NOT NULL UNIQUE, + block_hash VARCHAR NOT NULL REFERENCES header (hash) ON DELETE CASCADE, + leaf JSONB NOT NULL, + qc JSONB NOT NULL +); + +CREATE TABLE leaf_migration ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + completed bool NOT NULL DEFAULT false +); + +INSERT INTO leaf_migration ("completed") VALUES (false); \ No newline at end of file diff --git a/src/availability.rs b/src/availability.rs index aeaed53fc..e3cdd2886 100644 --- a/src/availability.rs +++ b/src/availability.rs @@ -513,7 +513,7 @@ mod test { use async_lock::RwLock; use committable::Committable; use futures::future::FutureExt; - use hotshot_types::{data::Leaf, simple_certificate::QuorumCertificate}; + use hotshot_types::{data::Leaf2, simple_certificate::QuorumCertificate2}; use portpicker::pick_unused_port; use serde::de::DeserializeOwned; use std::{fmt::Debug, time::Duration}; @@ -883,9 +883,9 @@ mod test { ); // mock up some consensus data. - let leaf = Leaf::::genesis(&Default::default(), &Default::default()).await; + let leaf = Leaf2::::genesis(&Default::default(), &Default::default()).await; let qc = - QuorumCertificate::genesis::(&Default::default(), &Default::default()) + QuorumCertificate2::genesis::(&Default::default(), &Default::default()) .await; let leaf = LeafQueryData::new(leaf, qc).unwrap(); let block = BlockQueryData::new(leaf.header().clone(), MockPayload::genesis()); diff --git a/src/availability/query_data.rs b/src/availability/query_data.rs index b06f1aa5f..fe001a50a 100644 --- a/src/availability/query_data.rs +++ b/src/availability/query_data.rs @@ -13,8 +13,8 @@ use crate::{types::HeightIndexed, Header, Metadata, Payload, Transaction, VidCommon, VidShare}; use committable::{Commitment, Committable}; use hotshot_types::{ - data::Leaf, - simple_certificate::QuorumCertificate, + data::{Leaf, Leaf2}, + simple_certificate::QuorumCertificate2, traits::{ self, block_contents::{BlockHeader, GENESIS_VID_NUM_STORAGE_NODES}, @@ -28,8 +28,8 @@ use serde::{de::DeserializeOwned, Deserialize, Serialize}; use snafu::{ensure, Snafu}; use std::fmt::Debug; -pub type LeafHash = Commitment>; -pub type QcHash = Commitment>; +pub type LeafHash = Commitment>; +pub type QcHash = Commitment>; /// A block hash is the hash of the block header. /// @@ -192,8 +192,8 @@ pub trait QueryablePayload: traits::BlockPayload { #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] #[serde(bound = "")] pub struct LeafQueryData { - pub(crate) leaf: Leaf, - pub(crate) qc: QuorumCertificate, + pub(crate) leaf: Leaf2, + pub(crate) qc: QuorumCertificate2, } #[derive(Clone, Debug, Snafu)] @@ -212,13 +212,13 @@ impl LeafQueryData { /// /// Fails with an [`InconsistentLeafError`] if `qc` does not reference `leaf`. pub fn new( - mut leaf: Leaf, - qc: QuorumCertificate, + mut leaf: Leaf2, + qc: QuorumCertificate2, ) -> Result> { // TODO: Replace with the new `commit` function in HotShot. Add an `upgrade_lock` parameter // and a `HsVer: Versions` bound, then call `leaf.commit(upgrade_lock).await`. This will // require updates in callers and relevant types as well. - let leaf_commit = as Committable>::commit(&leaf); + let leaf_commit = as Committable>::commit(&leaf); ensure!( qc.data.leaf_commit == leaf_commit, InconsistentLeafSnafu { @@ -239,16 +239,16 @@ impl LeafQueryData { instance_state: &Types::InstanceState, ) -> Self { Self { - leaf: Leaf::genesis(validated_state, instance_state).await, - qc: QuorumCertificate::genesis::(validated_state, instance_state).await, + leaf: Leaf2::genesis(validated_state, instance_state).await, + qc: QuorumCertificate2::genesis::(validated_state, instance_state).await, } } - pub fn leaf(&self) -> &Leaf { + pub fn leaf(&self) -> &Leaf2 { &self.leaf } - pub fn qc(&self) -> &QuorumCertificate { + pub fn qc(&self) -> &QuorumCertificate2 { &self.qc } @@ -260,7 +260,7 @@ impl LeafQueryData { // TODO: Replace with the new `commit` function in HotShot. Add an `upgrade_lock` parameter // and a `HsVer: Versions` bound, then call `leaf.commit(upgrade_lock).await`. This will // require updates in callers and relevant types as well. - as Committable>::commit(&self.leaf) + as Committable>::commit(&self.leaf) } pub fn block_hash(&self) -> BlockHash { diff --git a/src/data_source.rs b/src/data_source.rs index 412b6dc96..3d739d98d 100644 --- a/src/data_source.rs +++ b/src/data_source.rs @@ -133,7 +133,7 @@ pub mod availability_tests { }; use committable::Committable; use futures::stream::StreamExt; - use hotshot_types::data::Leaf; + use hotshot_types::data::Leaf2; use std::collections::HashMap; use std::fmt::Debug; use std::ops::{Bound, RangeBounds}; @@ -148,7 +148,7 @@ pub mod availability_tests { assert_eq!(leaf.height(), i as u64); assert_eq!( leaf.hash(), - as Committable>::commit(&leaf.leaf) + as Committable>::commit(&leaf.leaf) ); // Check indices. @@ -550,11 +550,10 @@ pub mod persistence_tests { setup_test, }, types::HeightIndexed, - Leaf, }; use committable::Committable; use hotshot_example_types::state_types::{TestInstanceState, TestValidatedState}; - use hotshot_types::simple_certificate::QuorumCertificate; + use hotshot_types::{data::Leaf2, simple_certificate::QuorumCertificate2}; #[tokio::test(flavor = "multi_thread")] pub async fn test_revert() @@ -571,12 +570,12 @@ pub mod persistence_tests { let ds = D::connect(&storage).await; // Mock up some consensus data. - let mut qc = QuorumCertificate::::genesis::( + let mut qc = QuorumCertificate2::::genesis::( &TestValidatedState::default(), &TestInstanceState::default(), ) .await; - let mut leaf = Leaf::::genesis( + let mut leaf = Leaf2::::genesis( &TestValidatedState::default(), &TestInstanceState::default(), ) @@ -584,7 +583,7 @@ pub mod persistence_tests { // Increment the block number, to distinguish this block from the genesis block, which // already exists. leaf.block_header_mut().block_number += 1; - qc.data.leaf_commit = as Committable>::commit(&leaf); + qc.data.leaf_commit = as Committable>::commit(&leaf); let block = BlockQueryData::new(leaf.block_header().clone(), MockPayload::genesis()); let leaf = LeafQueryData::new(leaf, qc).unwrap(); @@ -623,12 +622,12 @@ pub mod persistence_tests { let ds = D::connect(&storage).await; // Mock up some consensus data. - let mut qc = QuorumCertificate::::genesis::( + let mut qc = QuorumCertificate2::::genesis::( &TestValidatedState::default(), &TestInstanceState::default(), ) .await; - let mut leaf = Leaf::::genesis( + let mut leaf = Leaf2::::genesis( &TestValidatedState::default(), &TestInstanceState::default(), ) @@ -636,7 +635,7 @@ pub mod persistence_tests { // Increment the block number, to distinguish this block from the genesis block, which // already exists. leaf.block_header_mut().block_number += 1; - qc.data.leaf_commit = as Committable>::commit(&leaf); + qc.data.leaf_commit = as Committable>::commit(&leaf); let block = BlockQueryData::new(leaf.block_header().clone(), MockPayload::genesis()); let leaf = LeafQueryData::new(leaf, qc).unwrap(); @@ -686,12 +685,12 @@ pub mod persistence_tests { let ds = D::connect(&storage).await; // Mock up some consensus data. - let mut mock_qc = QuorumCertificate::::genesis::( + let mut mock_qc = QuorumCertificate2::::genesis::( &TestValidatedState::default(), &TestInstanceState::default(), ) .await; - let mut mock_leaf = Leaf::::genesis( + let mut mock_leaf = Leaf2::::genesis( &TestValidatedState::default(), &TestInstanceState::default(), ) @@ -699,7 +698,7 @@ pub mod persistence_tests { // Increment the block number, to distinguish this block from the genesis block, which // already exists. mock_leaf.block_header_mut().block_number += 1; - mock_qc.data.leaf_commit = as Committable>::commit(&mock_leaf); + mock_qc.data.leaf_commit = as Committable>::commit(&mock_leaf); let block = BlockQueryData::new(mock_leaf.block_header().clone(), MockPayload::genesis()); let leaf = LeafQueryData::new(mock_leaf.clone(), mock_qc.clone()).unwrap(); @@ -725,7 +724,7 @@ pub mod persistence_tests { // Get a mutable transaction again, insert different data. mock_leaf.block_header_mut().block_number += 1; - mock_qc.data.leaf_commit = as Committable>::commit(&mock_leaf); + mock_qc.data.leaf_commit = as Committable>::commit(&mock_leaf); let block = BlockQueryData::new(mock_leaf.block_header().clone(), MockPayload::genesis()); let leaf = LeafQueryData::new(mock_leaf, mock_qc).unwrap(); diff --git a/src/data_source/storage/sql.rs b/src/data_source/storage/sql.rs index 0a0e025aa..8c329e1f7 100644 --- a/src/data_source/storage/sql.rs +++ b/src/data_source/storage/sql.rs @@ -22,15 +22,23 @@ use crate::{ status::HasMetrics, QueryError, QueryResult, }; +use anyhow::Context; use async_trait::async_trait; use chrono::Utc; -use hotshot_types::traits::metrics::Metrics; +use committable::Committable; +use hotshot_types::{ + data::{Leaf, Leaf2}, + simple_certificate::{QuorumCertificate, QuorumCertificate2}, + traits::{metrics::Metrics, node_implementation::NodeType}, +}; + use itertools::Itertools; use log::LevelFilter; #[cfg(not(feature = "embedded-db"))] use futures::future::FutureExt; +use serde_json::Value; #[cfg(not(feature = "embedded-db"))] use sqlx::postgres::{PgConnectOptions, PgSslMode}; #[cfg(feature = "embedded-db")] @@ -614,7 +622,114 @@ impl HasMetrics for SqlStorage { } } +struct Leaf2Row { + height: i64, + hash: String, + block_hash: String, + leaf2: Value, + qc2: Value, +} + impl SqlStorage { + pub async fn migrate_leaf1_to_leaf2(&self) -> anyhow::Result<()> { + let mut offset = 0; + let limit = 10000; + + loop { + let mut tx = self.read().await.map_err(|err| QueryError::Error { + message: err.to_string(), + })?; + + let (is_migration_completed,) = + query_as::<(bool,)>("SELECT completed from leaf_migration LIMIT 1 ") + .fetch_one(tx.as_mut()) + .await?; + + if is_migration_completed { + tracing::info!("leaf1 to leaf2 migration already completed"); + return Ok(()); + } + + let rows = QueryBuilder::default() + .query(&format!( + "SELECT leaf, qc FROM leaf ORDER BY height LIMIT {} OFFSET {}", + limit, offset + )) + .fetch_all(tx.as_mut()) + .await?; + + drop(tx); + + if rows.is_empty() { + tracing::info!("no leaf1 rows found"); + return Ok(()); + } + + let mut leaf_rows = Vec::new(); + + for row in rows.iter() { + let leaf1 = row.try_get("leaf")?; + let qc = row.try_get("qc")?; + let leaf1: Leaf = serde_json::from_value(leaf1)?; + let qc: QuorumCertificate = serde_json::from_value(qc)?; + + let leaf2: Leaf2 = leaf1.into(); + let qc2: QuorumCertificate2 = qc.to_qc2(); + + let commit = leaf2.commit(); + + let leaf2_json = + serde_json::to_value(leaf2.clone()).context("failed to serialize leaf2")?; + let qc2_json = serde_json::to_value(qc2).context("failed to serialize QC2")?; + + leaf_rows.push(Leaf2Row { + height: leaf2.height() as i64, + hash: commit.to_string(), + block_hash: leaf2.block_header().commit().to_string(), + leaf2: leaf2_json, + qc2: qc2_json, + }) + } + + let mut query_builder: sqlx::QueryBuilder = + sqlx::QueryBuilder::new("INSERT INTO leaf2 (height, hash, block_hash, leaf, qc) "); + + query_builder.push_values(leaf_rows.into_iter(), |mut b, row| { + b.push_bind(row.height) + .push_bind(row.hash) + .push_bind(row.block_hash) + .push_bind(row.leaf2) + .push_bind(row.qc2); + }); + + let query = query_builder.build(); + + let mut tx = self.write().await.map_err(|err| QueryError::Error { + message: err.to_string(), + })?; + + query.execute(tx.as_mut()).await?; + + tx.commit().await?; + + if rows.len() < limit { + break; + } + + offset += limit; + } + + let mut tx = self.write().await.map_err(|err| QueryError::Error { + message: err.to_string(), + })?; + + tx.upsert("leaf_migration", ["completed"], ["id"], [(true,)]) + .await?; + + tx.commit().await?; + Ok(()) + } + async fn get_minimum_height(&self) -> QueryResult> { let mut tx = self.read().await.map_err(|err| QueryError::Error { message: err.to_string(), @@ -1101,19 +1216,32 @@ pub mod testing { // These tests run the `postgres` Docker image, which doesn't work on Windows. #[cfg(all(test, not(target_os = "windows")))] mod test { + use committable::{Commitment, CommitmentBoundsArkless}; use hotshot_example_types::{ node_types::TestVersions, state_types::{TestInstanceState, TestValidatedState}, }; - use std::time::Duration; + use hotshot_types::{ + data::{QuorumProposal, ViewNumber}, + traits::{ + block_contents::{vid_commitment, BlockHeader}, + node_implementation::ConsensusTime, + }, + }; + use hotshot_types::{simple_vote::QuorumData, traits::BlockPayload}; + use std::{marker::PhantomData, time::Duration}; use tokio::time::sleep; use super::{testing::TmpDb, *}; use crate::{ - availability::LeafQueryData, + availability::{LeafQueryData, QueryableHeader}, data_source::storage::{pruning::PrunedHeightStorage, UpdateAvailabilityStorage}, - testing::{mocks::MockTypes, setup_test}, + testing::{ + mocks::{MockHeader, MockPayload, MockTypes}, + setup_test, + }, }; + use hotshot_types::traits::EncodeBytes; #[tokio::test(flavor = "multi_thread")] async fn test_migrations() { @@ -1397,4 +1525,123 @@ mod test { ); } } + + #[tokio::test(flavor = "multi_thread")] + async fn test_leaf_migration() { + setup_test(); + + let num_leaves = 200; + let db = TmpDb::init().await; + + let storage = SqlStorage::connect(db.config()).await.unwrap(); + + for i in 0..num_leaves { + let view = ViewNumber::new(i); + let validated_state = TestValidatedState::default(); + let instance_state = TestInstanceState::default(); + + let (payload, metadata) = >::from_transactions( + [], + &validated_state, + &instance_state, + ) + .await + .unwrap(); + let builder_commitment = + >::builder_commitment(&payload, &metadata); + let payload_bytes = payload.encode(); + + let payload_commitment = vid_commitment(&payload_bytes, 4); + + let mut block_header = >::genesis( + &instance_state, + payload_commitment, + builder_commitment, + metadata, + ); + + block_header.block_number = i; + + let null_quorum_data = QuorumData { + leaf_commit: Commitment::>::default_commitment_no_preimage(), + }; + + let mut qc = QuorumCertificate::new( + null_quorum_data.clone(), + null_quorum_data.commit(), + view, + None, + PhantomData, + ); + + let quorum_proposal = QuorumProposal { + block_header, + view_number: view, + justify_qc: qc.clone(), + upgrade_certificate: None, + proposal_certificate: None, + }; + + let mut leaf = Leaf::from_quorum_proposal(&quorum_proposal); + leaf.fill_block_payload(payload, 4).unwrap(); + qc.data.leaf_commit = as Committable>::commit(&leaf); + + let height = leaf.height() as i64; + let hash = as Committable>::commit(&leaf).to_string(); + let header = leaf.block_header(); + + let header_json = serde_json::to_value(header) + .context("failed to serialize header") + .unwrap(); + + let payload_commitment = + >::payload_commitment(header); + let mut tx = storage.write().await.unwrap(); + + tx.upsert( + "header", + ["height", "hash", "payload_hash", "data", "timestamp"], + ["height"], + [( + height, + leaf.block_header().commit().to_string(), + payload_commitment.to_string(), + header_json, + leaf.block_header().timestamp() as i64, + )], + ) + .await + .unwrap(); + + let leaf_json = serde_json::to_value(leaf.clone()).expect("failed to serialize leaf"); + let qc_json = serde_json::to_value(qc).expect("failed to serialize QC"); + tx.upsert( + "leaf", + ["height", "hash", "block_hash", "leaf", "qc"], + ["height"], + [( + height, + hash, + header.commit().to_string(), + leaf_json, + qc_json, + )], + ) + .await + .unwrap(); + tx.commit().await.unwrap(); + } + + storage + .migrate_leaf1_to_leaf2::() + .await + .expect("failed to migrate"); + let mut tx = storage.read().await.unwrap(); + let (count,) = query_as::<(i64,)>("SELECT COUNT(*) from leaf2") + .fetch_one(tx.as_mut()) + .await + .unwrap(); + + assert_eq!(count as u64, num_leaves, "not all leaves migrated"); + } } diff --git a/src/data_source/storage/sql/queries.rs b/src/data_source/storage/sql/queries.rs index 157da31dd..570ec4ff5 100644 --- a/src/data_source/storage/sql/queries.rs +++ b/src/data_source/storage/sql/queries.rs @@ -20,12 +20,13 @@ use crate::{ VidCommonQueryData, }, data_source::storage::{PayloadMetadata, VidCommonMetadata}, - Header, Leaf, Payload, QueryError, QueryResult, + Header, Payload, QueryError, QueryResult, }; use anyhow::Context; use derivative::Derivative; use hotshot_types::{ - simple_certificate::QuorumCertificate, + data::Leaf2, + simple_certificate::QuorumCertificate2, traits::{ block_contents::{BlockHeader, BlockPayload}, node_implementation::NodeType, @@ -171,10 +172,10 @@ where { fn from_row(row: &'r ::Row) -> sqlx::Result { let leaf = row.try_get("leaf")?; - let leaf: Leaf = serde_json::from_value(leaf).decode_error("malformed leaf")?; + let leaf: Leaf2 = serde_json::from_value(leaf).decode_error("malformed leaf")?; let qc = row.try_get("qc")?; - let qc: QuorumCertificate = + let qc: QuorumCertificate2 = serde_json::from_value(qc).decode_error("malformed QC")?; Ok(Self { leaf, qc }) diff --git a/src/data_source/storage/sql/queries/availability.rs b/src/data_source/storage/sql/queries/availability.rs index 2ea7eea7c..4c252ac0b 100644 --- a/src/data_source/storage/sql/queries/availability.rs +++ b/src/data_source/storage/sql/queries/availability.rs @@ -49,7 +49,7 @@ where }; let row = query .query(&format!( - "SELECT {LEAF_COLUMNS} FROM leaf WHERE {where_clause}" + "SELECT {LEAF_COLUMNS} FROM leaf2 WHERE {where_clause}" )) .fetch_one(self.as_mut()) .await?; @@ -173,7 +173,7 @@ where { let mut query = QueryBuilder::default(); let where_clause = query.bounds_to_where_clause(range, "height")?; - let sql = format!("SELECT {LEAF_COLUMNS} FROM leaf {where_clause} ORDER BY height"); + let sql = format!("SELECT {LEAF_COLUMNS} FROM leaf2 {where_clause} ORDER BY height"); Ok(query .query(&sql) .fetch(self.as_mut()) @@ -341,7 +341,7 @@ where async fn first_available_leaf(&mut self, from: u64) -> QueryResult> { let row = query(&format!( - "SELECT {LEAF_COLUMNS} FROM leaf WHERE height >= $1 ORDER BY height LIMIT 1" + "SELECT {LEAF_COLUMNS} FROM leaf2 WHERE height >= $1 ORDER BY height LIMIT 1" )) .bind(from as i64) .fetch_one(self.as_mut()) diff --git a/src/data_source/storage/sql/queries/node.rs b/src/data_source/storage/sql/queries/node.rs index ca8874c17..26e76abbb 100644 --- a/src/data_source/storage/sql/queries/node.rs +++ b/src/data_source/storage/sql/queries/node.rs @@ -155,7 +155,7 @@ where // need to select the total number of VID rows and the number of present VID rows with a // NULL share. let sql = "SELECT l.max_height, l.total_leaves, p.null_payloads, v.total_vid, vn.null_vid, pruned_height FROM - (SELECT max(leaf.height) AS max_height, count(*) AS total_leaves FROM leaf) AS l, + (SELECT max(leaf2.height) AS max_height, count(*) AS total_leaves FROM leaf2) AS l, (SELECT count(*) AS null_payloads FROM payload WHERE data IS NULL) AS p, (SELECT count(*) AS total_vid FROM vid) AS v, (SELECT count(*) AS null_vid FROM vid WHERE share IS NULL) AS vn, diff --git a/src/data_source/storage/sql/transaction.rs b/src/data_source/storage/sql/transaction.rs index 9bc4faaee..d3dde15be 100644 --- a/src/data_source/storage/sql/transaction.rs +++ b/src/data_source/storage/sql/transaction.rs @@ -481,7 +481,7 @@ where let leaf_json = serde_json::to_value(leaf.leaf()).context("failed to serialize leaf")?; let qc_json = serde_json::to_value(leaf.qc()).context("failed to serialize QC")?; self.upsert( - "leaf", + "leaf2", ["height", "hash", "block_hash", "leaf", "qc"], ["height"], [( diff --git a/src/data_source/update.rs b/src/data_source/update.rs index 72a0daacc..351155c05 100644 --- a/src/data_source/update.rs +++ b/src/data_source/update.rs @@ -24,7 +24,7 @@ use futures::future::Future; use hotshot::types::{Event, EventType}; use hotshot_types::event::LeafInfo; use hotshot_types::{ - data::{Leaf, Leaf2, QuorumProposal}, + data::Leaf2, traits::{ block_contents::{BlockHeader, BlockPayload, EncodeBytes, GENESIS_VID_NUM_STORAGE_NODES}, node_implementation::{ConsensusTime, NodeType}, @@ -34,26 +34,6 @@ use hotshot_types::{ use jf_vid::VidScheme; use std::iter::once; -fn downgrade_leaf(leaf2: Leaf2) -> Leaf { - // TODO do we still need some check here? - // `drb_seed` no longer exists on `Leaf2` - // if leaf2.drb_seed != [0; 32] && leaf2.drb_result != [0; 32] { - // panic!("Downgrade of Leaf2 to Leaf will lose DRB information!"); - // } - let quorum_proposal = QuorumProposal { - block_header: leaf2.block_header().clone(), - view_number: leaf2.view_number(), - justify_qc: leaf2.justify_qc().to_qc(), - upgrade_certificate: leaf2.upgrade_certificate(), - proposal_certificate: None, - }; - let mut leaf = Leaf::from_quorum_proposal(&quorum_proposal); - if let Some(payload) = leaf2.block_payload() { - leaf.fill_block_payload_unchecked(payload); - } - leaf -} - /// An extension trait for types which implement the update trait for each API module. /// /// If a type implements [UpdateAvailabilityData] and @@ -113,25 +93,23 @@ where }, ) in qcs.zip(leaf_chain.iter().rev()) { - let leaf = downgrade_leaf(leaf2.clone()); - let qc = qc2.to_qc(); - let height = leaf.block_header().block_number(); - let leaf_data = match LeafQueryData::new(leaf.clone(), qc.clone()) { + let height = leaf2.block_header().block_number(); + let leaf_data = match LeafQueryData::new(leaf2.clone(), qc2.clone()) { Ok(leaf) => leaf, Err(err) => { tracing::error!( height, - ?leaf, + ?leaf2, ?qc, "inconsistent leaf; cannot append leaf information: {err:#}" ); - return Err(leaf.block_header().block_number()); + return Err(leaf2.block_header().block_number()); } }; - let block_data = leaf + let block_data = leaf2 .block_payload() - .map(|payload| BlockQueryData::new(leaf.block_header().clone(), payload)); + .map(|payload| BlockQueryData::new(leaf2.block_header().clone(), payload)); if block_data.is_none() { tracing::info!(height, "block not available at decide"); } @@ -139,17 +117,17 @@ where let (vid_common, vid_share) = if let Some(vid_share) = vid_share { ( Some(VidCommonQueryData::new( - leaf.block_header().clone(), + leaf2.block_header().clone(), vid_share.common.clone(), )), Some(vid_share.share.clone()), ) - } else if leaf.view_number().u64() == 0 { + } else if leaf2.view_number().u64() == 0 { // HotShot does not run VID in consensus for the genesis block. In this case, // the block payload is guaranteed to always be empty, so VID isn't really // necessary. But for consistency, we will still store the VID dispersal data, // computing it ourselves based on the well-known genesis VID commitment. - match genesis_vid(&leaf) { + match genesis_vid(leaf2) { Ok((common, share)) => (Some(common), Some(share)), Err(err) => { tracing::warn!("failed to compute genesis VID: {err:#}"); @@ -168,7 +146,7 @@ where .await { tracing::error!(height, "failed to append leaf information: {err:#}"); - return Err(leaf.block_header().block_number()); + return Err(leaf2.block_header().block_number()); } } } @@ -177,7 +155,7 @@ where } fn genesis_vid( - leaf: &Leaf, + leaf: &Leaf2, ) -> anyhow::Result<(VidCommonQueryData, VidShare)> { let payload = Payload::::empty().0; let bytes = payload.encode(); diff --git a/src/lib.rs b/src/lib.rs index d334f59d2..68160b5ee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -597,7 +597,7 @@ mod test { use async_trait::async_trait; use atomic_store::{load_store::BincodeLoadStore, AtomicStore, AtomicStoreLoader, RollingLog}; use futures::future::FutureExt; - use hotshot_types::simple_certificate::QuorumCertificate; + use hotshot_types::{data::Leaf2, simple_certificate::QuorumCertificate2}; use portpicker::pick_unused_port; use std::ops::{Bound, RangeBounds}; use std::time::Duration; @@ -811,9 +811,9 @@ mod test { .unwrap(); // Mock up some data and add a block to the store. - let leaf = Leaf::::genesis(&Default::default(), &Default::default()).await; + let leaf = Leaf2::::genesis(&Default::default(), &Default::default()).await; let qc = - QuorumCertificate::genesis::(&Default::default(), &Default::default()) + QuorumCertificate2::genesis::(&Default::default(), &Default::default()) .await; let leaf = LeafQueryData::new(leaf, qc).unwrap(); let block = BlockQueryData::new(leaf.header().clone(), MockPayload::genesis());