diff --git a/common/src/block.rs b/common/src/block.rs index 944b8989..84b7a419 100644 --- a/common/src/block.rs +++ b/common/src/block.rs @@ -23,7 +23,7 @@ pub type BlockHash = [u8; 32]; pub type BlockId = u64; pub type TimeStamp = u64; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] pub struct BlockHeader { pub block_id: BlockId, pub prev_block_hash: BlockHash, @@ -32,15 +32,23 @@ pub struct BlockHeader { pub signature: nssa::Signature, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] pub struct BlockBody { pub transactions: Vec, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] +pub enum BedrockStatus { + Pending, + Safe, + Finalized, +} + +#[derive(Debug, BorshSerialize, BorshDeserialize)] pub struct Block { pub header: BlockHeader, pub body: BlockBody, + pub bedrock_status: BedrockStatus, } #[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] @@ -52,7 +60,7 @@ pub struct HashableBlockData { } impl HashableBlockData { - pub fn into_block(self, signing_key: &nssa::PrivateKey) -> Block { + pub fn into_pending_block(self, signing_key: &nssa::PrivateKey) -> Block { let data_bytes = borsh::to_vec(&self).unwrap(); let signature = nssa::Signature::new(signing_key, &data_bytes); let hash = OwnHasher::hash(&data_bytes); @@ -67,6 +75,7 @@ impl HashableBlockData { body: BlockBody { transactions: self.transactions, }, + bedrock_status: BedrockStatus::Pending, } } } diff --git a/common/src/test_utils.rs b/common/src/test_utils.rs index 7e3c0ba8..1125b86e 100644 --- a/common/src/test_utils.rs +++ b/common/src/test_utils.rs @@ -30,7 +30,7 @@ pub fn produce_dummy_block( transactions, }; - block_data.into_block(&sequencer_sign_key_for_testing()) + block_data.into_pending_block(&sequencer_sign_key_for_testing()) } pub fn produce_dummy_empty_transaction() -> EncodedTransaction { diff --git a/sequencer_core/src/block_store.rs b/sequencer_core/src/block_store.rs index 67535022..cd9aa194 100644 --- a/sequencer_core/src/block_store.rs +++ b/sequencer_core/src/block_store.rs @@ -46,7 +46,7 @@ impl SequencerBlockStore { } pub fn get_block_at_id(&self, id: u64) -> Result { - Ok(self.dbio.get_block(id)?.into_block(&self.signing_key)) + Ok(self.dbio.get_block(id)?) } pub fn put_block_at_id(&mut self, block: Block) -> Result<()> { @@ -113,7 +113,7 @@ mod tests { transactions: vec![], }; - let genesis_block = genesis_block_hashable_data.into_block(&signing_key); + let genesis_block = genesis_block_hashable_data.into_pending_block(&signing_key); // Start an empty node store let mut node_store = SequencerBlockStore::open_db_with_genesis(path, Some(genesis_block), signing_key) diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index 561f5ef6..a7a16826 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -53,7 +53,7 @@ impl SequencerCore { }; let signing_key = nssa::PrivateKey::try_new(config.signing_key).unwrap(); - let genesis_block = hashable_data.into_block(&signing_key); + let genesis_block = hashable_data.into_pending_block(&signing_key); // Sequencer should panic if unable to open db, // as fixing this issue may require actions non-native to program scope @@ -196,7 +196,7 @@ impl SequencerCore { let block = hashable_data .clone() - .into_block(self.block_store.signing_key()); + .into_pending_block(self.block_store.signing_key()); self.block_store.put_block_at_id(block)?; diff --git a/storage/src/lib.rs b/storage/src/lib.rs index 87b78705..883684c2 100644 --- a/storage/src/lib.rs +++ b/storage/src/lib.rs @@ -1,6 +1,6 @@ use std::{path::Path, sync::Arc}; -use common::block::{Block, HashableBlockData}; +use common::block::Block; use error::DbError; use rocksdb::{ BoundColumnFamily, ColumnFamilyDescriptor, DBWithThreadMode, MultiThreaded, Options, @@ -26,6 +26,8 @@ pub const DB_META_FIRST_BLOCK_IN_DB_KEY: &str = "first_block_in_db"; pub const DB_META_LAST_BLOCK_IN_DB_KEY: &str = "last_block_in_db"; /// Key base for storing metainformation which describe if first block has been set pub const DB_META_FIRST_BLOCK_SET_KEY: &str = "first_block_set"; +/// Key base for storing metainformation about the last finalized block on Bedrock +pub const DB_META_LAST_FINALIZED_BLOCK_ID: &str = "last_finalized_block_id"; /// Key base for storing snapshot which describe block id pub const DB_SNAPSHOT_BLOCK_ID_KEY: &str = "block_id"; @@ -75,6 +77,7 @@ impl RocksDBIO { dbio.put_meta_first_block_in_db(block)?; dbio.put_meta_is_first_block_set()?; dbio.put_meta_last_block_in_db(block_id)?; + dbio.put_meta_last_finalized_block_id(None)?; Ok(dbio) } else { @@ -232,6 +235,28 @@ impl RocksDBIO { Ok(()) } + pub fn put_meta_last_finalized_block_id(&self, block_id: Option) -> DbResult<()> { + let cf_meta = self.meta_column(); + self.db + .put_cf( + &cf_meta, + borsh::to_vec(&DB_META_LAST_FINALIZED_BLOCK_ID).map_err(|err| { + DbError::borsh_cast_message( + err, + Some("Failed to serialize DB_META_LAST_FINALIZED_BLOCK_ID".to_string()), + ) + })?, + borsh::to_vec(&block_id).map_err(|err| { + DbError::borsh_cast_message( + err, + Some("Failed to serialize last block id".to_string()), + ) + })?, + ) + .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; + Ok(()) + } + pub fn put_meta_is_first_block_set(&self) -> DbResult<()> { let cf_meta = self.meta_column(); self.db @@ -269,7 +294,7 @@ impl RocksDBIO { Some("Failed to serialize block id".to_string()), ) })?, - borsh::to_vec(&HashableBlockData::from(block)).map_err(|err| { + borsh::to_vec(&block).map_err(|err| { DbError::borsh_cast_message( err, Some("Failed to serialize block data".to_string()), @@ -280,7 +305,7 @@ impl RocksDBIO { Ok(()) } - pub fn get_block(&self, block_id: u64) -> DbResult { + pub fn get_block(&self, block_id: u64) -> DbResult { let cf_block = self.block_column(); let res = self .db @@ -296,14 +321,12 @@ impl RocksDBIO { .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; if let Some(data) = res { - Ok( - borsh::from_slice::(&data).map_err(|serr| { - DbError::borsh_cast_message( - serr, - Some("Failed to deserialize block data".to_string()), - ) - })?, - ) + Ok(borsh::from_slice::(&data).map_err(|serr| { + DbError::borsh_cast_message( + serr, + Some("Failed to deserialize block data".to_string()), + ) + })?) } else { Err(DbError::db_interaction_error( "Block on this id not found".to_string(),